Merge github.com:orangeduck/mpc
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -8,3 +8,4 @@ examples/maths
|
||||
examples/smallc
|
||||
examples/foobar
|
||||
examples/tree_traversal
|
||||
build/*
|
||||
73
Makefile
73
Makefile
@@ -1,7 +1,10 @@
|
||||
|
||||
CC = gcc
|
||||
STND=-ansi
|
||||
CFLAGS = $(STND) -pedantic -O3 -g -Wall -Werror -Wextra -Wformat=2 -Wshadow \
|
||||
PROJ = mpc
|
||||
CC ?= gcc
|
||||
STD ?= -ansi
|
||||
DIST = build
|
||||
MKDIR ?= mkdir -p
|
||||
PREFIX ?= /usr/local
|
||||
CFLAGS ?= $(STD) -pedantic -O3 -g -Wall -Werror -Wextra -Wformat=2 -Wshadow \
|
||||
-Wno-long-long -Wno-overlength-strings -Wno-format-nonliteral -Wcast-align \
|
||||
-Wwrite-strings -Wstrict-prototypes -Wold-style-definition -Wredundant-decls \
|
||||
-Wnested-externs -Wmissing-include-dirs -Wswitch-default
|
||||
@@ -10,15 +13,59 @@ TESTS = $(wildcard tests/*.c)
|
||||
EXAMPLES = $(wildcard examples/*.c)
|
||||
EXAMPLESEXE = $(EXAMPLES:.c=)
|
||||
|
||||
all: $(EXAMPLESEXE) check
|
||||
.PHONY: all check clean libs $(DIST)/$(PROJ).pc
|
||||
|
||||
check: $(TESTS) mpc.c
|
||||
$(CC) $(filter-out -Werror, $(CFLAGS)) $^ -lm -o test
|
||||
./test
|
||||
all: $(EXAMPLESEXE) check
|
||||
|
||||
$(DIST):
|
||||
$(MKDIR) $(DIST)/examples
|
||||
|
||||
check: $(DIST)/test-file $(DIST)/test-static $(DIST)/test-dynamic
|
||||
./$(DIST)/test-file
|
||||
./$(DIST)/test-static
|
||||
LD_LIBRARY_PATH=$(DIST) ./$(DIST)/test-dynamic
|
||||
|
||||
$(DIST)/test-file: $(TESTS) $(PROJ).c $(PROJ).h tests/ptest.h
|
||||
$(CC) $(filter-out -Werror, $(CFLAGS)) $(TESTS) $(PROJ).c -lm -o $(DIST)/test-file
|
||||
|
||||
$(DIST)/test-dynamic: $(TESTS) $(DIST)/lib$(PROJ).so $(PROJ).h tests/ptest.h
|
||||
$(CC) $(filter-out -Werror, $(CFLAGS)) $(TESTS) -lm -L$(DIST) -l$(PROJ) -o $(DIST)/test-dynamic
|
||||
|
||||
$(DIST)/test-static: $(TESTS) $(DIST)/lib$(PROJ).a $(PROJ).h tests/ptest.h
|
||||
$(CC) $(filter-out -Werror, $(CFLAGS)) $(TESTS) -lm -L$(DIST) -l$(PROJ) -static -o $(DIST)/test-static
|
||||
|
||||
examples/%: $(DIST) examples/%.c $(PROJ).c $(PROJ).h
|
||||
$(CC) $(CFLAGS) $(filter-out $(DIST) $(PROJ).h, $^) -lm -o $(DIST)/$@
|
||||
|
||||
$(DIST)/lib$(PROJ).so: $(PROJ).c $(PROJ).h
|
||||
ifneq ($(OS),Windows_NT)
|
||||
$(CC) $(CFLAGS) -fPIC -shared $(PROJ).c -o $(DIST)/lib$(PROJ).so
|
||||
else
|
||||
$(CC) $(CFLAGS) -shared $(PROJ).c -o $(DIST)/lib$(PROJ).so
|
||||
endif
|
||||
|
||||
$(DIST)/lib$(PROJ).a: $(PROJ).c $(PROJ).h
|
||||
$(CC) $(CFLAGS) -c $(PROJ).c -o $(DIST)/$(PROJ).o
|
||||
$(AR) rcs $(DIST)/lib$(PROJ).a $(DIST)/$(PROJ).o
|
||||
|
||||
libs: $(DIST)/lib$(PROJ).so $(DIST)/lib$(PROJ).a
|
||||
|
||||
$(DIST)/$(PROJ).pc: $(DIST) $(PROJ).pc
|
||||
cp $(PROJ).pc $(DIST)/$(PROJ).pc
|
||||
sed -i '1i\prefix=$(PREFIX)/' $(DIST)/$(PROJ).pc
|
||||
|
||||
examples/%: examples/%.c mpc.c
|
||||
$(CC) $(CFLAGS) $^ -lm -o $@
|
||||
|
||||
clean:
|
||||
rm -rf test examples/doge examples/lispy examples/maths examples/smallc \
|
||||
examples/foobar examples/tree_traversal
|
||||
rm -rf -- $(DIST)
|
||||
|
||||
install: all
|
||||
install -d -m644 $(DESTDIR)$(PREFIX)/{include,lib/pkgconfig,share/$(PROJ)}
|
||||
install -m755 -t $(DESTDIR)$(PREFIX)/lib $(DIST)/lib*
|
||||
install -m644 -t $(DESTDIR)$(PREFIX)/share/$(PROJ) $(PROJ).{c,h}
|
||||
install -m644 $(PROJ).h $(DESTDIR)$(PREFIX)/include/$(PROJ).h
|
||||
install -m644 $(DIST)/$(PROJ).pc $(DESTDIR)$(PREFIX)/lib/pkgconfig/$(PROJ).pc
|
||||
|
||||
uninstall:
|
||||
rm -rf -- \
|
||||
$(DESTDIR)$(PREFIX)/include/$(PROJ).h \
|
||||
$(DESTDIR)$(PREFIX)/share/$(PROJ)/$(PROJ).{c,h} \
|
||||
$(DESTDIR)$(PREFIX)/lib/lib$(PROJ).{so,a}
|
||||
|
||||
80
README.md
80
README.md
@@ -1,7 +1,7 @@
|
||||
Micro Parser Combinators
|
||||
========================
|
||||
|
||||
Version 0.8.8
|
||||
Version 0.9.0
|
||||
|
||||
|
||||
About
|
||||
@@ -116,7 +116,7 @@ Basic Parsers
|
||||
|
||||
All the following functions construct new basic parsers of the type `mpc_parser_t *`. All of those parsers return a newly allocated `char *` with the character(s) they manage to match. If unsuccessful they will return an error. They have the following functionality.
|
||||
|
||||
* * *
|
||||
* * *
|
||||
|
||||
```c
|
||||
mpc_parser_t *mpc_any(void);
|
||||
@@ -124,7 +124,7 @@ mpc_parser_t *mpc_any(void);
|
||||
|
||||
Matches any individual character
|
||||
|
||||
* * *
|
||||
* * *
|
||||
|
||||
```c
|
||||
mpc_parser_t *mpc_char(char c);
|
||||
@@ -283,7 +283,7 @@ Run a parser on the contents of some file.
|
||||
Combinators
|
||||
-----------
|
||||
|
||||
Combinators are functions that take one or more parsers and return a new parser of some given functionality.
|
||||
Combinators are functions that take one or more parsers and return a new parser of some given functionality.
|
||||
|
||||
These combinators work independently of exactly what data type the parser(s) supplied as input return. In languages such as Haskell ensuring you don't input one type of data into a parser requiring a different type is done by the compiler. But in C we don't have that luxury. So it is at the discretion of the programmer to ensure that he or she deals correctly with the outputs of different parser types.
|
||||
|
||||
@@ -312,13 +312,13 @@ Returns a parser that applies function `f` (optionality taking extra input `x`)
|
||||
* * *
|
||||
|
||||
```c
|
||||
mpc_parser_t *mpc_check(mpc_parser_t *a, mpc_check_t f, const char *e);
|
||||
mpc_parser_t *mpc_check_with(mpc_parser_t *a, mpc_check_with_t f, void *x, const char *e);
|
||||
mpc_parser_t *mpc_checkf(mpc_parser_t *a, mpc_check_t f, const char *fmt, ...);
|
||||
mpc_parser_t *mpc_check_withf(mpc_parser_t *a, mpc_check_with_t f, void *x, const char *fmt, ...);
|
||||
mpc_parser_t *mpc_check(mpc_parser_t *a, mpc_dtor_t da, mpc_check_t f, const char *e);
|
||||
mpc_parser_t *mpc_check_with(mpc_parser_t *a, mpc_dtor_t da, mpc_check_with_t f, void *x, const char *e);
|
||||
mpc_parser_t *mpc_checkf(mpc_parser_t *a, mpc_dtor_t da, mpc_check_t f, const char *fmt, ...);
|
||||
mpc_parser_t *mpc_check_withf(mpc_parser_t *a, mpc_dtor_t da, mpc_check_with_t f, void *x, const char *fmt, ...);
|
||||
```
|
||||
|
||||
Returns a parser that applies function `f` (optionally taking extra input `x`) to the result of parser `a`. If `f` returns non-zero, then the parser succeeds and returns the value of `a` (possibly modified by `f`). If `f` returns zero, then the parser fails with message `e`.
|
||||
Returns a parser that applies function `f` (optionally taking extra input `x`) to the result of parser `a`. If `f` returns non-zero, then the parser succeeds and returns the value of `a` (possibly modified by `f`). If `f` returns zero, then the parser fails with message `e`, and the result of `a` is destroyed with the destructor `da`.
|
||||
|
||||
* * *
|
||||
|
||||
@@ -556,9 +556,9 @@ To ease the task of undefining and then deleting parsers `mpc_cleanup` can be us
|
||||
mpc_parser_t *mpc_copy(mpc_parser_t *a);
|
||||
```
|
||||
|
||||
This function makes a copy of a parser `a`. This can be useful when you want to
|
||||
use a parser as input for some other parsers multiple times without retaining
|
||||
it.
|
||||
This function makes a copy of a parser `a`. This can be useful when you want to
|
||||
use a parser as input for some other parsers multiple times without retaining
|
||||
it.
|
||||
|
||||
* * *
|
||||
|
||||
@@ -567,11 +567,11 @@ mpc_parser_t *mpc_re(const char *re);
|
||||
mpc_parser_t *mpc_re_mode(const char *re, int mode);
|
||||
```
|
||||
|
||||
This function takes as input the regular expression `re` and builds a parser
|
||||
for it. With the `mpc_re_mode` function optional mode flags can also be given.
|
||||
Available flags are `MPC_RE_MULTILINE` / `MPC_RE_M` where the start of input
|
||||
character `^` also matches the beginning of new lines and the end of input `$`
|
||||
character also matches new lines, and `MPC_RE_DOTALL` / `MPC_RE_S` where the
|
||||
This function takes as input the regular expression `re` and builds a parser
|
||||
for it. With the `mpc_re_mode` function optional mode flags can also be given.
|
||||
Available flags are `MPC_RE_MULTILINE` / `MPC_RE_M` where the start of input
|
||||
character `^` also matches the beginning of new lines and the end of input `$`
|
||||
character also matches new lines, and `MPC_RE_DOTALL` / `MPC_RE_S` where the
|
||||
any character token `.` also matches newlines (by default it doesn't).
|
||||
|
||||
|
||||
@@ -626,7 +626,7 @@ Useful Parsers
|
||||
|
||||
<tr><td><code>mpc_startswith(mpc_parser_t *a);</code></td><td>Matches the start of input followed by <code>a</code></td></tr>
|
||||
<tr><td><code>mpc_endswith(mpc_parser_t *a, mpc_dtor_t da);</code></td><td>Matches <code>a</code> followed by the end of input</td></tr>
|
||||
<tr><td><code>mpc_whole(mpc_parser_t *a, mpc_dtor_t da);</code></td><td>Matches the start of input, <code>a</code>, and the end of input</td></tr>
|
||||
<tr><td><code>mpc_whole(mpc_parser_t *a, mpc_dtor_t da);</code></td><td>Matches the start of input, <code>a</code>, and the end of input</td></tr>
|
||||
<tr><td><code>mpc_stripl(mpc_parser_t *a);</code></td><td>Matches <code>a</code> first consuming any whitespace to the left</td></tr>
|
||||
<tr><td><code>mpc_stripr(mpc_parser_t *a);</code></td><td>Matches <code>a</code> then consumes any whitespace to the right</td></tr>
|
||||
<tr><td><code>mpc_strip(mpc_parser_t *a);</code></td><td>Matches <code>a</code> consuming any surrounding whitespace</td></tr>
|
||||
@@ -707,17 +707,17 @@ We start with a fold function that will fold two `int *` into a new `int *` base
|
||||
|
||||
```c
|
||||
mpc_val_t *fold_maths(int n, mpc_val_t **xs) {
|
||||
|
||||
|
||||
int **vs = (int**)xs;
|
||||
|
||||
|
||||
if (strcmp(xs[1], "*") == 0) { *vs[0] *= *vs[2]; }
|
||||
if (strcmp(xs[1], "/") == 0) { *vs[0] /= *vs[2]; }
|
||||
if (strcmp(xs[1], "%") == 0) { *vs[0] %= *vs[2]; }
|
||||
if (strcmp(xs[1], "+") == 0) { *vs[0] += *vs[2]; }
|
||||
if (strcmp(xs[1], "-") == 0) { *vs[0] -= *vs[2]; }
|
||||
|
||||
|
||||
free(xs[1]); free(xs[2]);
|
||||
|
||||
|
||||
return xs[0];
|
||||
}
|
||||
```
|
||||
@@ -730,14 +730,14 @@ mpc_parser_t *Factor = mpc_new("factor");
|
||||
mpc_parser_t *Term = mpc_new("term");
|
||||
mpc_parser_t *Maths = mpc_new("maths");
|
||||
|
||||
mpc_define(Expr, mpc_or(2,
|
||||
mpc_define(Expr, mpc_or(2,
|
||||
mpc_and(3, fold_maths,
|
||||
Factor, mpc_oneof("+-"), Factor,
|
||||
free, free),
|
||||
Factor
|
||||
));
|
||||
|
||||
mpc_define(Factor, mpc_or(2,
|
||||
mpc_define(Factor, mpc_or(2,
|
||||
mpc_and(3, fold_maths,
|
||||
Term, mpc_oneof("*/"), Term,
|
||||
free, free),
|
||||
@@ -781,6 +781,8 @@ The syntax for this is defined as follows.
|
||||
<tr><td><code>'a' | 'b'</code></td><td>Either <code>'a'</code> is required, or <code>'b'</code> is required.</td></tr>
|
||||
<tr><td><code>'a'*</code></td><td>Zero or more <code>'a'</code> are required.</td></tr>
|
||||
<tr><td><code>'a'+</code></td><td>One or more <code>'a'</code> are required.</td></tr>
|
||||
<tr><td><code>'a'?</code></td><td>Zero or one <code>'a'</code> is required.</td></tr>
|
||||
<tr><td><code>'a'{x}</code></td><td>Exactly <code>x</code> (integer) copies of <code>'a'</code> are required.</td></tr>
|
||||
<tr><td><code><abba></code></td><td>The rule called <code>abba</code> is required.</td></tr>
|
||||
</table>
|
||||
|
||||
@@ -825,17 +827,17 @@ This opens and reads in the contents of the file given by `filename` and passes
|
||||
Case Study - Tokenizer
|
||||
======================
|
||||
|
||||
Another common task we might be interested in doing is tokenizing some block of
|
||||
Another common task we might be interested in doing is tokenizing some block of
|
||||
text (splitting the text into individual elements) and performing some function
|
||||
on each one of these elements as it is read. We can do this with `mpc` too.
|
||||
|
||||
First, we can build a regular expression which parses an individual token. For
|
||||
example if our tokens are identifiers, integers, commas, periods and colons we
|
||||
could build something like this `mpc_re("\\s*([a-zA-Z_]+|[0-9]+|,|\\.|:)")`.
|
||||
Next we can strip any whitespace, and add a callback function using `mpc_apply`
|
||||
which gets called every time this regex is parsed successfully
|
||||
`mpc_apply(mpc_strip(mpc_re("\\s*([a-zA-Z_]+|[0-9]+|,|\\.|:)")), print_token)`.
|
||||
Finally we can surround all of this in `mpc_many` to parse it zero or more
|
||||
First, we can build a regular expression which parses an individual token. For
|
||||
example if our tokens are identifiers, integers, commas, periods and colons we
|
||||
could build something like this `mpc_re("\\s*([a-zA-Z_]+|[0-9]+|,|\\.|:)")`.
|
||||
Next we can strip any whitespace, and add a callback function using `mpc_apply`
|
||||
which gets called every time this regex is parsed successfully
|
||||
`mpc_apply(mpc_strip(mpc_re("\\s*([a-zA-Z_]+|[0-9]+|,|\\.|:)")), print_token)`.
|
||||
Finally we can surround all of this in `mpc_many` to parse it zero or more
|
||||
times. The final code might look something like this:
|
||||
|
||||
```c
|
||||
@@ -847,16 +849,16 @@ static mpc_val_t *print_token(mpc_val_t *x) {
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
const char *input = " hello 4352 , \n foo.bar \n\n test:ing ";
|
||||
|
||||
|
||||
mpc_parser_t* Tokens = mpc_many(
|
||||
mpcf_all_free,
|
||||
mpcf_all_free,
|
||||
mpc_apply(mpc_strip(mpc_re("\\s*([a-zA-Z_]+|[0-9]+|,|\\.|:)")), print_token));
|
||||
|
||||
|
||||
mpc_result_t r;
|
||||
mpc_parse("input", input, Tokens, &r);
|
||||
|
||||
|
||||
mpc_delete(Tokens);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
@@ -875,7 +877,7 @@ Token: ':'
|
||||
Token: 'ing'
|
||||
```
|
||||
|
||||
By extending the regex we can easily extend this to parse many more types of
|
||||
By extending the regex we can easily extend this to parse many more types of
|
||||
tokens and quickly and easily build a tokenizer for whatever language we are
|
||||
interested in.
|
||||
|
||||
@@ -991,5 +993,3 @@ When parsing from a grammar, the abstract syntax tree is tagged with different t
|
||||
If you have a rule in your grammar called `string`, `char` or `regex`, you may encounter some confusion. This is because nodes will be tagged with (for example) `string` _either_ if they are a string primitive, _or_ if they were parsed via your `string` rule. If you are detecting node type using something like `strstr`, in this situation it might break. One solution to this is to always check that `string` is the innermost tag to test for string primitives, or to rename your rule called `string` to something that doesn't conflict.
|
||||
|
||||
Yes it is annoying but its probably not going to change!
|
||||
|
||||
|
||||
|
||||
@@ -31,4 +31,4 @@ int main(int argc, char **argv) {
|
||||
mpc_delete(Line);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
19
mpc.h
19
mpc.h
@@ -43,7 +43,7 @@ typedef struct {
|
||||
char *filename;
|
||||
char *failure;
|
||||
char **expected;
|
||||
char recieved;
|
||||
char received;
|
||||
} mpc_err_t;
|
||||
|
||||
void mpc_err_delete(mpc_err_t *e);
|
||||
@@ -129,10 +129,10 @@ mpc_parser_t *mpc_expect(mpc_parser_t *a, const char *e);
|
||||
mpc_parser_t *mpc_expectf(mpc_parser_t *a, const char *fmt, ...);
|
||||
mpc_parser_t *mpc_apply(mpc_parser_t *a, mpc_apply_t f);
|
||||
mpc_parser_t *mpc_apply_to(mpc_parser_t *a, mpc_apply_to_t f, void *x);
|
||||
mpc_parser_t *mpc_check(mpc_parser_t *a, mpc_check_t f, const char *e);
|
||||
mpc_parser_t *mpc_check_with(mpc_parser_t *a, mpc_check_with_t f, void *x, const char *e);
|
||||
mpc_parser_t *mpc_checkf(mpc_parser_t *a, mpc_check_t f, const char *fmt, ...);
|
||||
mpc_parser_t *mpc_check_withf(mpc_parser_t *a, mpc_check_with_t f, void *x, const char *fmt, ...);
|
||||
mpc_parser_t *mpc_check(mpc_parser_t *a, mpc_dtor_t da, mpc_check_t f, const char *e);
|
||||
mpc_parser_t *mpc_check_with(mpc_parser_t *a, mpc_dtor_t da, mpc_check_with_t f, void *x, const char *e);
|
||||
mpc_parser_t *mpc_checkf(mpc_parser_t *a, mpc_dtor_t da, mpc_check_t f, const char *fmt, ...);
|
||||
mpc_parser_t *mpc_check_withf(mpc_parser_t *a, mpc_dtor_t da, mpc_check_with_t f, void *x, const char *fmt, ...);
|
||||
|
||||
mpc_parser_t *mpc_not(mpc_parser_t *a, mpc_dtor_t da);
|
||||
mpc_parser_t *mpc_not_lift(mpc_parser_t *a, mpc_dtor_t da, mpc_ctor_t lf);
|
||||
@@ -204,7 +204,7 @@ mpc_parser_t *mpc_whole(mpc_parser_t *a, mpc_dtor_t da);
|
||||
mpc_parser_t *mpc_stripl(mpc_parser_t *a);
|
||||
mpc_parser_t *mpc_stripr(mpc_parser_t *a);
|
||||
mpc_parser_t *mpc_strip(mpc_parser_t *a);
|
||||
mpc_parser_t *mpc_tok(mpc_parser_t *a);
|
||||
mpc_parser_t *mpc_tok(mpc_parser_t *a);
|
||||
mpc_parser_t *mpc_sym(const char *s);
|
||||
mpc_parser_t *mpc_total(mpc_parser_t *a, mpc_dtor_t da);
|
||||
|
||||
@@ -258,6 +258,7 @@ mpc_val_t *mpcf_snd_free(int n, mpc_val_t** xs);
|
||||
mpc_val_t *mpcf_trd_free(int n, mpc_val_t** xs);
|
||||
mpc_val_t *mpcf_all_free(int n, mpc_val_t** xs);
|
||||
|
||||
mpc_val_t *mpcf_freefold(int n, mpc_val_t** xs);
|
||||
mpc_val_t *mpcf_strfold(int n, mpc_val_t** xs);
|
||||
mpc_val_t *mpcf_maths(int n, mpc_val_t** xs);
|
||||
|
||||
@@ -275,7 +276,7 @@ enum {
|
||||
|
||||
mpc_parser_t *mpc_re(const char *re);
|
||||
mpc_parser_t *mpc_re_mode(const char *re, int mode);
|
||||
|
||||
|
||||
/*
|
||||
** AST
|
||||
*/
|
||||
@@ -373,8 +374,8 @@ void mpc_optimise(mpc_parser_t *p);
|
||||
void mpc_stats(mpc_parser_t *p);
|
||||
|
||||
int mpc_test_pass(mpc_parser_t *p, const char *s, const void *d,
|
||||
int(*tester)(const void*, const void*),
|
||||
mpc_dtor_t destructor,
|
||||
int(*tester)(const void*, const void*),
|
||||
mpc_dtor_t destructor,
|
||||
void(*printer)(const void*));
|
||||
|
||||
int mpc_test_fail(mpc_parser_t *p, const char *s, const void *d,
|
||||
|
||||
8
mpc.pc
Normal file
8
mpc.pc
Normal file
@@ -0,0 +1,8 @@
|
||||
libdir=${prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: mpc
|
||||
Description: Library for creating parser combinators
|
||||
Version: 0.9.0
|
||||
Libs: -L${libdir} -lmpc
|
||||
Cflags: -I${includedir}
|
||||
@@ -12,7 +12,7 @@ static int check_is(mpc_val_t** x, void* t) {
|
||||
void test_check(void) {
|
||||
int success;
|
||||
mpc_result_t r;
|
||||
mpc_parser_t* p = mpc_check(mpc_or(2, mpc_char('a'), mpc_char('b')), check_is_a, "Expected 'a'");
|
||||
mpc_parser_t* p = mpc_check(mpc_or(2, mpc_char('a'), mpc_char('b')), free, check_is_a, "Expected 'a'");
|
||||
|
||||
success = mpc_parse("test", "a", p, &r);
|
||||
PT_ASSERT(success);
|
||||
@@ -30,7 +30,7 @@ void test_check(void) {
|
||||
void test_check_with(void) {
|
||||
int success;
|
||||
mpc_result_t r;
|
||||
mpc_parser_t* p = mpc_check_with(mpc_or(2, mpc_char('a'), mpc_char('b')), check_is, (void*)"a", "Expected 'a'");
|
||||
mpc_parser_t* p = mpc_check_with(mpc_or(2, mpc_char('a'), mpc_char('b')), free, check_is, (void*)"a", "Expected 'a'");
|
||||
|
||||
success = mpc_parse("test", "a", p, &r);
|
||||
PT_ASSERT(success);
|
||||
@@ -48,7 +48,7 @@ void test_check_with(void) {
|
||||
void test_checkf(void) {
|
||||
int success;
|
||||
mpc_result_t r;
|
||||
mpc_parser_t* p = mpc_checkf(mpc_or(2, mpc_char('a'), mpc_char('b')), check_is_a, "Expected '%s'", "a");
|
||||
mpc_parser_t* p = mpc_checkf(mpc_or(2, mpc_char('a'), mpc_char('b')), free, check_is_a, "Expected '%s'", "a");
|
||||
|
||||
success = mpc_parse("test", "a", p, &r);
|
||||
PT_ASSERT(success);
|
||||
@@ -66,7 +66,7 @@ void test_checkf(void) {
|
||||
void test_check_withf(void) {
|
||||
int success;
|
||||
mpc_result_t r;
|
||||
mpc_parser_t* p = mpc_check_withf(mpc_or(2, mpc_char('a'), mpc_char('b')), check_is, (void*)"a", "Expected '%s'", "a");
|
||||
mpc_parser_t* p = mpc_check_withf(mpc_or(2, mpc_char('a'), mpc_char('b')), free, check_is, (void*)"a", "Expected '%s'", "a");
|
||||
|
||||
success = mpc_parse("test", "a", p, &r);
|
||||
PT_ASSERT(success);
|
||||
|
||||
108
tests/core.c
108
tests/core.c
@@ -12,7 +12,7 @@ static void strprint(const void* x) { printf("'%s'", (char*)x); }
|
||||
void test_ident(void) {
|
||||
|
||||
/* ^[a-zA-Z_][a-zA-Z0-9_]*$ */
|
||||
|
||||
|
||||
mpc_parser_t* Ident = mpc_whole(
|
||||
mpc_and(2, mpcf_strfold,
|
||||
mpc_or(2, mpc_alpha(), mpc_underscore()),
|
||||
@@ -20,7 +20,7 @@ void test_ident(void) {
|
||||
free),
|
||||
free
|
||||
);
|
||||
|
||||
|
||||
PT_ASSERT(mpc_test_pass(Ident, "test", "test", streq, free, strprint));
|
||||
PT_ASSERT(mpc_test_fail(Ident, " blah", "", streq, free, strprint));
|
||||
PT_ASSERT(mpc_test_pass(Ident, "anoth21er", "anoth21er", streq, free, strprint));
|
||||
@@ -28,99 +28,99 @@ void test_ident(void) {
|
||||
PT_ASSERT(mpc_test_fail(Ident, "some spaces", "", streq, free, strprint));
|
||||
PT_ASSERT(mpc_test_fail(Ident, "", "", streq, free, strprint));
|
||||
PT_ASSERT(mpc_test_fail(Ident, "18nums", "", streq, free, strprint));
|
||||
|
||||
|
||||
mpc_delete(Ident);
|
||||
|
||||
}
|
||||
|
||||
void test_maths(void) {
|
||||
|
||||
mpc_parser_t *Expr, *Factor, *Term, *Maths;
|
||||
|
||||
mpc_parser_t *Expr, *Factor, *Term, *Maths;
|
||||
int r0 = 1, r1 = 5, r2 = 13, r3 = 0, r4 = 2;
|
||||
|
||||
|
||||
Expr = mpc_new("expr");
|
||||
Factor = mpc_new("factor");
|
||||
Term = mpc_new("term");
|
||||
Maths = mpc_new("maths");
|
||||
|
||||
mpc_define(Expr, mpc_or(2,
|
||||
mpc_define(Expr, mpc_or(2,
|
||||
mpc_and(3, mpcf_maths, Factor, mpc_oneof("*/"), Factor, free, free),
|
||||
Factor
|
||||
));
|
||||
|
||||
mpc_define(Factor, mpc_or(2,
|
||||
|
||||
mpc_define(Factor, mpc_or(2,
|
||||
mpc_and(3, mpcf_maths, Term, mpc_oneof("+-"), Term, free, free),
|
||||
Term
|
||||
));
|
||||
|
||||
mpc_define(Term, mpc_or(2,
|
||||
|
||||
mpc_define(Term, mpc_or(2,
|
||||
mpc_int(),
|
||||
mpc_parens(Expr, free)
|
||||
));
|
||||
|
||||
|
||||
mpc_define(Maths, mpc_whole(Expr, free));
|
||||
|
||||
|
||||
PT_ASSERT(mpc_test_pass(Maths, "1", &r0, int_eq, free, int_print));
|
||||
PT_ASSERT(mpc_test_pass(Maths, "(5)", &r1, int_eq, free, int_print));
|
||||
PT_ASSERT(mpc_test_pass(Maths, "(4*2)+5", &r2, int_eq, free, int_print));
|
||||
PT_ASSERT(mpc_test_fail(Maths, "a", &r3, int_eq, free, int_print));
|
||||
PT_ASSERT(mpc_test_fail(Maths, "2b+4", &r4, int_eq, free, int_print));
|
||||
|
||||
|
||||
mpc_cleanup(4, Expr, Factor, Term, Maths);
|
||||
}
|
||||
|
||||
void test_strip(void) {
|
||||
|
||||
|
||||
mpc_parser_t *Stripperl = mpc_apply(mpc_many(mpcf_strfold, mpc_any()), mpcf_strtriml);
|
||||
mpc_parser_t *Stripperr = mpc_apply(mpc_many(mpcf_strfold, mpc_any()), mpcf_strtrimr);
|
||||
mpc_parser_t *Stripper = mpc_apply(mpc_many(mpcf_strfold, mpc_any()), mpcf_strtrim);
|
||||
|
||||
|
||||
PT_ASSERT(mpc_test_pass(Stripperl, " asdmlm dasd ", "asdmlm dasd ", streq, free, strprint));
|
||||
PT_ASSERT(mpc_test_pass(Stripperr, " asdmlm dasd ", " asdmlm dasd", streq, free, strprint));
|
||||
PT_ASSERT(mpc_test_pass(Stripper, " asdmlm dasd ", "asdmlm dasd", streq, free, strprint));
|
||||
|
||||
|
||||
mpc_delete(Stripperl);
|
||||
mpc_delete(Stripperr);
|
||||
mpc_delete(Stripper);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void test_repeat(void) {
|
||||
|
||||
|
||||
int success;
|
||||
mpc_result_t r;
|
||||
mpc_parser_t *p = mpc_count(3, mpcf_strfold, mpc_digit(), free);
|
||||
|
||||
|
||||
success = mpc_parse("test", "046", p, &r);
|
||||
PT_ASSERT(success);
|
||||
PT_ASSERT_STR_EQ(r.output, "046");
|
||||
free(r.output);
|
||||
|
||||
|
||||
success = mpc_parse("test", "046aa", p, &r);
|
||||
PT_ASSERT(success);
|
||||
PT_ASSERT_STR_EQ(r.output, "046");
|
||||
free(r.output);
|
||||
|
||||
|
||||
success = mpc_parse("test", "04632", p, &r);
|
||||
PT_ASSERT(success);
|
||||
PT_ASSERT_STR_EQ(r.output, "046");
|
||||
free(r.output);
|
||||
|
||||
|
||||
success = mpc_parse("test", "04", p, &r);
|
||||
PT_ASSERT(!success);
|
||||
mpc_err_delete(r.error);
|
||||
|
||||
|
||||
mpc_delete(p);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void test_copy(void) {
|
||||
|
||||
|
||||
int success;
|
||||
mpc_result_t r;
|
||||
mpc_parser_t* p = mpc_or(2, mpc_char('a'), mpc_char('b'));
|
||||
mpc_parser_t* q = mpc_and(2, mpcf_strfold, p, mpc_copy(p), free);
|
||||
|
||||
|
||||
success = mpc_parse("test", "aa", q, &r);
|
||||
PT_ASSERT(success);
|
||||
PT_ASSERT_STR_EQ(r.output, "aa");
|
||||
@@ -130,26 +130,26 @@ void test_copy(void) {
|
||||
PT_ASSERT(success);
|
||||
PT_ASSERT_STR_EQ(r.output, "bb");
|
||||
free(r.output);
|
||||
|
||||
|
||||
success = mpc_parse("test", "ab", q, &r);
|
||||
PT_ASSERT(success);
|
||||
PT_ASSERT_STR_EQ(r.output, "ab");
|
||||
free(r.output);
|
||||
|
||||
|
||||
success = mpc_parse("test", "ba", q, &r);
|
||||
PT_ASSERT(success);
|
||||
PT_ASSERT_STR_EQ(r.output, "ba");
|
||||
free(r.output);
|
||||
|
||||
|
||||
success = mpc_parse("test", "c", p, &r);
|
||||
PT_ASSERT(!success);
|
||||
mpc_err_delete(r.error);
|
||||
|
||||
|
||||
mpc_delete(mpc_copy(p));
|
||||
mpc_delete(mpc_copy(q));
|
||||
|
||||
|
||||
mpc_delete(q);
|
||||
|
||||
|
||||
}
|
||||
|
||||
static int line_count = 0;
|
||||
@@ -162,23 +162,23 @@ static mpc_val_t* read_line(mpc_val_t* line) {
|
||||
void test_reader(void) {
|
||||
|
||||
mpc_parser_t* Line = mpc_many(
|
||||
mpcf_strfold,
|
||||
mpcf_strfold,
|
||||
mpc_apply(mpc_re("[^\\n]*(\\n|$)"), read_line));
|
||||
|
||||
|
||||
line_count = 0;
|
||||
|
||||
PT_ASSERT(mpc_test_pass(Line,
|
||||
"hello\nworld\n\nthis\nis\ndan",
|
||||
PT_ASSERT(mpc_test_pass(Line,
|
||||
"hello\nworld\n\nthis\nis\ndan",
|
||||
"hello\nworld\n\nthis\nis\ndan", streq, free, strprint));
|
||||
|
||||
|
||||
PT_ASSERT(line_count == 6);
|
||||
|
||||
|
||||
line_count = 0;
|
||||
|
||||
PT_ASSERT(mpc_test_pass(Line,
|
||||
"abcHVwufvyuevuy3y436782\n\n\nrehre\nrew\n-ql.;qa\neg",
|
||||
|
||||
PT_ASSERT(mpc_test_pass(Line,
|
||||
"abcHVwufvyuevuy3y436782\n\n\nrehre\nrew\n-ql.;qa\neg",
|
||||
"abcHVwufvyuevuy3y436782\n\n\nrehre\nrew\n-ql.;qa\neg", streq, free, strprint));
|
||||
|
||||
|
||||
PT_ASSERT(line_count == 7);
|
||||
|
||||
mpc_delete(Line);
|
||||
@@ -194,32 +194,32 @@ static mpc_val_t *print_token(mpc_val_t *x) {
|
||||
}
|
||||
|
||||
void test_tokens(void) {
|
||||
|
||||
|
||||
mpc_parser_t* Tokens = mpc_many(
|
||||
mpcf_strfold,
|
||||
mpcf_strfold,
|
||||
mpc_apply(mpc_strip(mpc_re("\\s*([a-zA-Z_]+|[0-9]+|,|\\.|:)")), print_token));
|
||||
|
||||
|
||||
token_count = 0;
|
||||
|
||||
PT_ASSERT(mpc_test_pass(Tokens,
|
||||
" hello 4352 , \n foo.bar \n\n test:ing ",
|
||||
PT_ASSERT(mpc_test_pass(Tokens,
|
||||
" hello 4352 , \n foo.bar \n\n test:ing ",
|
||||
"hello4352,foo.bartest:ing", streq, free, strprint));
|
||||
|
||||
|
||||
PT_ASSERT(token_count == 9);
|
||||
|
||||
mpc_delete(Tokens);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void test_eoi(void) {
|
||||
|
||||
|
||||
mpc_parser_t* Line = mpc_re("[^\\n]*$");
|
||||
|
||||
|
||||
PT_ASSERT(mpc_test_pass(Line, "blah", "blah", streq, free, strprint));
|
||||
PT_ASSERT(mpc_test_pass(Line, "blah\n", "blah\n", streq, free, strprint));
|
||||
|
||||
|
||||
mpc_delete(Line);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void suite_core(void) {
|
||||
|
||||
126
tests/ptest.c
126
tests/ptest.c
@@ -35,7 +35,7 @@ enum {
|
||||
YELLOW = 6,
|
||||
WHITE = 7,
|
||||
GRAY = 8,
|
||||
|
||||
|
||||
LIGHT_BLUE = 9,
|
||||
LIGHT_GREEN = 10,
|
||||
LIGHT_AQUA = 11,
|
||||
@@ -43,7 +43,7 @@ enum {
|
||||
LIGHT_PURPLE = 13,
|
||||
LIGHT_YELLOW = 14,
|
||||
LIGHT_WHITE = 15,
|
||||
|
||||
|
||||
DEFAULT = 16
|
||||
};
|
||||
|
||||
@@ -55,16 +55,16 @@ static WORD defaults;
|
||||
static int defaults_loaded = 0;
|
||||
|
||||
static void pt_color(int color) {
|
||||
|
||||
|
||||
HANDLE cnsl = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
|
||||
if (!defaults_loaded) {
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
GetConsoleScreenBufferInfo(cnsl, &info);
|
||||
defaults = info.wAttributes;
|
||||
defaults_loaded = 1;
|
||||
}
|
||||
|
||||
|
||||
SetConsoleTextAttribute(cnsl, color == DEFAULT ? defaults : color);
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ static const char* colors[] = {
|
||||
"\x1B[39m",
|
||||
};
|
||||
|
||||
static void pt_color(int color) {
|
||||
static void pt_color(int color) {
|
||||
printf("%s", colors[color]);
|
||||
}
|
||||
|
||||
@@ -107,27 +107,27 @@ static char assert_err_buff[MAX_ERROR];
|
||||
static int assert_err_num = 0;
|
||||
|
||||
void pt_assert_run(int result, const char* expr, const char* file, int line) {
|
||||
|
||||
|
||||
num_asserts++;
|
||||
test_passing = test_passing && result;
|
||||
|
||||
|
||||
if (result) {
|
||||
num_assert_passes++;
|
||||
} else {
|
||||
sprintf(assert_err_buff,
|
||||
" %i. Assert [ %s ] (%s:%i)\n",
|
||||
sprintf(assert_err_buff,
|
||||
" %i. Assert [ %s ] (%s:%i)\n",
|
||||
assert_err_num+1, expr, file, line );
|
||||
strcat(assert_err, assert_err_buff);
|
||||
assert_err_num++;
|
||||
num_assert_fails++;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void ptest_signal(int sig) {
|
||||
|
||||
test_passing = 0;
|
||||
|
||||
|
||||
switch( sig ) {
|
||||
case SIGFPE: sprintf(assert_err_buff,
|
||||
" %i. Division by Zero\n", assert_err_num+1);
|
||||
@@ -140,18 +140,18 @@ static void ptest_signal(int sig) {
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
|
||||
assert_err_num++;
|
||||
strcat(assert_err, assert_err_buff);
|
||||
|
||||
pt_color(RED);
|
||||
|
||||
pt_color(RED);
|
||||
printf("Failed! \n\n%s\n", assert_err);
|
||||
pt_color(DEFAULT);
|
||||
|
||||
|
||||
puts(" | Stopping Execution.");
|
||||
fflush(stdout);
|
||||
exit(0);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* Tests */
|
||||
@@ -160,27 +160,27 @@ static void pt_title_case(char* output, const char* input) {
|
||||
|
||||
int space = 1;
|
||||
unsigned int i;
|
||||
|
||||
|
||||
strcpy(output, input);
|
||||
|
||||
|
||||
for(i = 0; i < strlen(output); i++) {
|
||||
|
||||
if (output[i] == '_' || output[i] == ' ') {
|
||||
space = 1;
|
||||
output[i] = ' ';
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (space && output[i] >= 'a' && output[i] <= 'z') {
|
||||
space = 0;
|
||||
output[i] = output[i] - 32;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
space = 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
@@ -200,24 +200,24 @@ void pt_add_test(void (*func)(void), const char* name, const char* suite) {
|
||||
test_t test;
|
||||
|
||||
if (num_tests == MAX_TESTS) {
|
||||
printf("ERROR: Exceeded maximum test count of %i!\n",
|
||||
printf("ERROR: Exceeded maximum test count of %i!\n",
|
||||
MAX_TESTS); abort();
|
||||
}
|
||||
|
||||
|
||||
if (strlen(name) >= MAX_NAME) {
|
||||
printf("ERROR: Test name '%s' too long (Maximum is %i characters)\n",
|
||||
printf("ERROR: Test name '%s' too long (Maximum is %i characters)\n",
|
||||
name, MAX_NAME); abort();
|
||||
}
|
||||
|
||||
|
||||
if (strlen(suite) >= MAX_NAME) {
|
||||
printf("ERROR: Test suite '%s' too long (Maximum is %i characters)\n",
|
||||
printf("ERROR: Test suite '%s' too long (Maximum is %i characters)\n",
|
||||
suite, MAX_NAME); abort();
|
||||
}
|
||||
|
||||
|
||||
test.func = func;
|
||||
pt_title_case(test.name, name);
|
||||
pt_title_case(test.suite, suite);
|
||||
|
||||
|
||||
tests[num_tests] = test;
|
||||
num_tests++;
|
||||
}
|
||||
@@ -239,7 +239,7 @@ static clock_t start, end;
|
||||
static char current_suite[MAX_NAME];
|
||||
|
||||
int pt_run(void) {
|
||||
|
||||
|
||||
int i;
|
||||
double total;
|
||||
test_t test;
|
||||
@@ -252,18 +252,18 @@ int pt_run(void) {
|
||||
puts(" | |");
|
||||
puts(" | Daniel Holden (contact@theorangeduck.com) |");
|
||||
puts(" +-------------------------------------------+");
|
||||
|
||||
|
||||
signal(SIGFPE, ptest_signal);
|
||||
signal(SIGILL, ptest_signal);
|
||||
signal(SIGSEGV, ptest_signal);
|
||||
|
||||
|
||||
start = clock();
|
||||
strcpy(current_suite, "");
|
||||
|
||||
|
||||
for(i = 0; i < num_tests; i++) {
|
||||
|
||||
test = tests[i];
|
||||
|
||||
|
||||
/* Check for transition to a new suite */
|
||||
if (strcmp(test.suite, current_suite)) {
|
||||
|
||||
@@ -275,25 +275,25 @@ int pt_run(void) {
|
||||
num_suites_fails++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
suite_passing = 1;
|
||||
strcpy(current_suite, test.suite);
|
||||
printf("\n\n ===== %s =====\n\n", current_suite);
|
||||
}
|
||||
|
||||
|
||||
/* Run Test */
|
||||
|
||||
|
||||
test_passing = 1;
|
||||
strcpy(assert_err, "");
|
||||
strcpy(assert_err_buff, "");
|
||||
assert_err_num = 0;
|
||||
printf(" | %s ... ", test.name);
|
||||
fflush(stdout);
|
||||
|
||||
|
||||
test.func();
|
||||
|
||||
|
||||
suite_passing = suite_passing && test_passing;
|
||||
|
||||
|
||||
if (test_passing) {
|
||||
num_tests_passes++;
|
||||
pt_color(GREEN);
|
||||
@@ -301,56 +301,56 @@ int pt_run(void) {
|
||||
pt_color(DEFAULT);
|
||||
} else {
|
||||
num_tests_fails++;
|
||||
pt_color(RED);
|
||||
pt_color(RED);
|
||||
printf("Failed! \n\n%s\n", assert_err);
|
||||
pt_color(DEFAULT);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (suite_passing) {
|
||||
num_suites_passes++;
|
||||
} else {
|
||||
num_suites_fails++;
|
||||
}
|
||||
|
||||
|
||||
end = clock();
|
||||
|
||||
|
||||
puts("");
|
||||
puts(" +---------------------------------------------------+");
|
||||
puts(" | Summary |");
|
||||
puts(" +---------++------------+-------------+-------------+");
|
||||
|
||||
|
||||
printf(" | Suites ||");
|
||||
pt_color(YELLOW); printf(" Total %4d ", num_suites);
|
||||
pt_color(YELLOW); printf(" Total %4d ", num_suites);
|
||||
pt_color(DEFAULT); putchar('|');
|
||||
pt_color(GREEN); printf(" Passed %4d ", num_suites_passes);
|
||||
pt_color(GREEN); printf(" Passed %4d ", num_suites_passes);
|
||||
pt_color(DEFAULT); putchar('|');
|
||||
pt_color(RED); printf(" Failed %4d ", num_suites_fails);
|
||||
pt_color(RED); printf(" Failed %4d ", num_suites_fails);
|
||||
pt_color(DEFAULT); puts("|");
|
||||
|
||||
|
||||
printf(" | Tests ||");
|
||||
pt_color(YELLOW); printf(" Total %4d ", num_tests);
|
||||
pt_color(YELLOW); printf(" Total %4d ", num_tests);
|
||||
pt_color(DEFAULT); putchar('|');
|
||||
pt_color(GREEN); printf(" Passed %4d ", num_tests_passes);
|
||||
pt_color(GREEN); printf(" Passed %4d ", num_tests_passes);
|
||||
pt_color(DEFAULT); putchar('|');
|
||||
pt_color(RED); printf(" Failed %4d ", num_tests_fails);
|
||||
pt_color(RED); printf(" Failed %4d ", num_tests_fails);
|
||||
pt_color(DEFAULT); puts("|");
|
||||
|
||||
|
||||
printf(" | Asserts ||");
|
||||
pt_color(YELLOW); printf(" Total %4d ", num_asserts);
|
||||
pt_color(YELLOW); printf(" Total %4d ", num_asserts);
|
||||
pt_color(DEFAULT); putchar('|');
|
||||
pt_color(GREEN); printf(" Passed %4d ", num_assert_passes);
|
||||
pt_color(GREEN); printf(" Passed %4d ", num_assert_passes);
|
||||
pt_color(DEFAULT); putchar('|');
|
||||
pt_color(RED); printf(" Failed %4d ", num_assert_fails);
|
||||
pt_color(RED); printf(" Failed %4d ", num_assert_fails);
|
||||
pt_color(DEFAULT); puts("|");
|
||||
|
||||
|
||||
puts(" +---------++------------+-------------+-------------+");
|
||||
puts("");
|
||||
|
||||
|
||||
total = (double)(end - start) / CLOCKS_PER_SEC;
|
||||
|
||||
|
||||
printf(" Total Running Time: %0.3fs\n\n", total);
|
||||
|
||||
|
||||
if (num_suites_fails > 0) { return 1; } else { return 0; }
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ void test_regex_basic(void) {
|
||||
re3 = mpc_re("abc(abdd)?");
|
||||
re4 = mpc_re("ab|c(abdd)?");
|
||||
re5 = mpc_re("abc(ab|dd)+g$");
|
||||
|
||||
|
||||
PT_ASSERT(regex_test_pass(re0, "abc", "abc"));
|
||||
PT_ASSERT(regex_test_pass(re0, "bcd", "bcd"));
|
||||
PT_ASSERT(regex_test_fail(re0, "bc", "bc"));
|
||||
@@ -35,7 +35,7 @@ void test_regex_basic(void) {
|
||||
PT_ASSERT(regex_test_pass(re2, "abcabab", "abcabab"));
|
||||
PT_ASSERT(regex_test_pass(re2, "abcababd", "abcabab"));
|
||||
PT_ASSERT(regex_test_pass(re5, "abcddg", "abcddg"));
|
||||
|
||||
|
||||
mpc_delete(re0);
|
||||
mpc_delete(re1);
|
||||
mpc_delete(re2);
|
||||
@@ -57,47 +57,47 @@ void test_regex_boundary(void) {
|
||||
PT_ASSERT(regex_test_pass(re0, "foo.", "foo"));
|
||||
PT_ASSERT(regex_test_pass(re0, "foo)", "foo"));
|
||||
PT_ASSERT(regex_test_pass(re0, "foo baz", "foo"));
|
||||
|
||||
|
||||
PT_ASSERT(regex_test_fail(re0, "foobar", "foo"));
|
||||
PT_ASSERT(regex_test_fail(re0, "foo3", "foo"));
|
||||
|
||||
|
||||
PT_ASSERT(regex_test_pass(re1, "foo", "foo"));
|
||||
PT_ASSERT(regex_test_pass(re1, " foo", " foo"));
|
||||
PT_ASSERT(regex_test_fail(re1, "wfoo", "foo"));
|
||||
|
||||
|
||||
PT_ASSERT(regex_test_pass(re2, "python", "python"));
|
||||
PT_ASSERT(regex_test_pass(re2, "py3", "py3"));
|
||||
PT_ASSERT(regex_test_pass(re2, "py2", "py2"));
|
||||
PT_ASSERT(regex_test_fail(re2, "py", "py"));
|
||||
PT_ASSERT(regex_test_fail(re2, "py.", "py."));
|
||||
PT_ASSERT(regex_test_fail(re2, "py!", "py!"));
|
||||
|
||||
|
||||
mpc_delete(re0);
|
||||
mpc_delete(re1);
|
||||
mpc_delete(re2);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void test_regex_range(void) {
|
||||
|
||||
mpc_parser_t *re0, *re1, *re2, *re3;
|
||||
|
||||
|
||||
re0 = mpc_re("abg[abcdef]");
|
||||
re1 = mpc_re("y*[a-z]");
|
||||
re2 = mpc_re("zz(p+)?[A-Z_0\\]123]*");
|
||||
re3 = mpc_re("^[^56hy].*$");
|
||||
|
||||
|
||||
/* TODO: Testing */
|
||||
|
||||
|
||||
mpc_delete(re0);
|
||||
mpc_delete(re1);
|
||||
mpc_delete(re2);
|
||||
mpc_delete(re3);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void test_regex_string(void) {
|
||||
|
||||
|
||||
mpc_parser_t *re0 = mpc_re("\"(\\\\.|[^\"])*\"");
|
||||
|
||||
PT_ASSERT(regex_test_pass(re0, "\"there\"", "\"there\""));
|
||||
@@ -110,26 +110,26 @@ void test_regex_string(void) {
|
||||
}
|
||||
|
||||
void test_regex_lisp_comment(void) {
|
||||
|
||||
|
||||
mpc_parser_t *re0 = mpc_re(";[^\\n\\r]*");
|
||||
|
||||
PT_ASSERT(regex_test_pass(re0, ";comment", ";comment"));
|
||||
PT_ASSERT(regex_test_pass(re0, ";i am the\nman", ";i am the"));
|
||||
|
||||
|
||||
mpc_delete(re0);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void test_regex_newline(void) {
|
||||
|
||||
|
||||
mpc_parser_t *re0 = mpc_re("[a-z]*");
|
||||
|
||||
PT_ASSERT(regex_test_pass(re0, "hi", "hi"));
|
||||
PT_ASSERT(regex_test_pass(re0, "hi\nk", "hi"));
|
||||
PT_ASSERT(regex_test_fail(re0, "hi\nk", "hi\nk"));
|
||||
|
||||
|
||||
mpc_delete(re0);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void test_regex_multiline(void) {
|
||||
@@ -142,13 +142,13 @@ void test_regex_multiline(void) {
|
||||
PT_ASSERT(regex_test_fail(re0, "45234", "45234"));
|
||||
PT_ASSERT(regex_test_fail(re0, "\n45234", "\n45234"));
|
||||
PT_ASSERT(regex_test_pass(re0, "\n45234", "\n"));
|
||||
|
||||
|
||||
mpc_delete(re0);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void test_regex_dotall(void) {
|
||||
|
||||
|
||||
mpc_parser_t *re0 = mpc_re_mode("^.*$", MPC_RE_DEFAULT);
|
||||
mpc_parser_t *re1 = mpc_re_mode("^.*$", MPC_RE_DOTALL);
|
||||
|
||||
@@ -157,16 +157,16 @@ void test_regex_dotall(void) {
|
||||
PT_ASSERT(regex_test_fail(re0, "he\nllo\n", "he"));
|
||||
PT_ASSERT(regex_test_pass(re0, "34njaksdklmasd", "34njaksdklmasd"));
|
||||
PT_ASSERT(regex_test_fail(re0, "34njaksd\nklmasd", "34njaksd"));
|
||||
|
||||
|
||||
PT_ASSERT(regex_test_pass(re1, "hello", "hello"));
|
||||
PT_ASSERT(regex_test_pass(re1, "hello\n", "hello\n"));
|
||||
PT_ASSERT(regex_test_pass(re1, "he\nllo\n", "he\nllo\n"));
|
||||
PT_ASSERT(regex_test_pass(re1, "34njaksdklmasd", "34njaksdklmasd"));
|
||||
PT_ASSERT(regex_test_pass(re1, "34njaksd\nklmasd", "34njaksd\nklmasd"));
|
||||
|
||||
|
||||
mpc_delete(re0);
|
||||
mpc_delete(re1);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void suite_regex(void) {
|
||||
|
||||
Reference in New Issue
Block a user