From b910e00a473f36f55f36ab42f375f1cdca8a263d Mon Sep 17 00:00:00 2001 From: Roberto Alsina Date: Wed, 12 Jul 2023 20:37:55 -0300 Subject: [PATCH 01/12] cleanup --- shortcodes.h | 6 +++++- shortcodes.rl | 7 ------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/shortcodes.h b/shortcodes.h index 72fa89f..ddb37ec 100644 --- a/shortcodes.h +++ b/shortcodes.h @@ -1,12 +1,16 @@ #ifndef SHORTCODES_H #define SHORTCODES_H + +// A chunk is a reference to a piece of string +// from "start" relative to its start +// and goes on for len characters. struct chunk { int start, len; }; - typedef struct chunk chunk; +// Describes a parsed shortcode struct shortcode { chunk whole; diff --git a/shortcodes.rl b/shortcodes.rl index a11ba58..0270940 100644 --- a/shortcodes.rl +++ b/shortcodes.rl @@ -129,10 +129,3 @@ shortcode *parse(char *input) { return sc_list; } - -// int main(int argc, char **argv) { -// parse( -// "bbb{{% sarasa sar1 sar2 \"sar3\" %}}ccc" -// "{{< c1 arg2 >}}foobar{{% /c1%}}aaa{{% sarasa name=\"pepe\" %}}"); -// return 0; -// }; -- 2.45.2 From 5350dbd12640ba132bc1cc193f80fde94ec2503e Mon Sep 17 00:00:00 2001 From: Roberto Alsina Date: Wed, 12 Jul 2023 21:58:39 -0300 Subject: [PATCH 02/12] Initial implementation (everything broke) --- shortcodes.h | 28 ++++++++++++- shortcodes.rl | 14 ++++--- tests.c | 112 +++++++++++++++++++++++++------------------------- 3 files changed, 91 insertions(+), 63 deletions(-) diff --git a/shortcodes.h b/shortcodes.h index ddb37ec..1c88d01 100644 --- a/shortcodes.h +++ b/shortcodes.h @@ -10,6 +10,14 @@ struct chunk }; typedef struct chunk chunk; +// An error +struct sc_error +{ + int position; + int code; +}; +typedef struct sc_error sc_error; + // Describes a parsed shortcode struct shortcode { @@ -23,5 +31,23 @@ struct shortcode }; typedef struct shortcode shortcode; -shortcode *parse(char *); +struct sc_result +{ + shortcode sc[100]; + sc_error errors[10]; + int errcount; +}; +typedef struct sc_result sc_result; + +// Error codes + +/* You are closing the wrong shortcode. +Example: + +{{% foo %}} {{% /bar %}} +*/ +#define ERR_MISMATCHED_CLOSING_TAG 1 + + +sc_result parse(char *); #endif diff --git a/shortcodes.rl b/shortcodes.rl index 0270940..0f9d263 100644 --- a/shortcodes.rl +++ b/shortcodes.rl @@ -1,7 +1,6 @@ #include #include "shortcodes.h" - %%{ machine shortcode; @@ -93,8 +92,10 @@ start + sc_list[c_sc-1].name.start, start + sc_list[c_sc].name.start, sc_list[c_sc-1].name.len) !=0) - { - return NULL; + { + result.errors[result.errcount].position = p-start; + result.errors[result.errcount].code = ERR_MISMATCHED_CLOSING_TAG; + result.errcount++; } // Reuse this shortcode entry for next one sc_list[c_sc].name.start = 0; @@ -105,7 +106,7 @@ }%% -shortcode *parse(char *input) { +sc_result parse(char *input) { %%write data; char *eof, *ts, *te = 0; @@ -115,7 +116,8 @@ shortcode *parse(char *input) { char *p = input; char *pe = p + strlen(input); - shortcode sc_list[1000]; + sc_result result; + shortcode *sc_list = result.sc; int c_sc = 0; int sc_start = 0; @@ -127,5 +129,5 @@ shortcode *parse(char *input) { %% write init; %% write exec; - return sc_list; + return sc_result; } diff --git a/tests.c b/tests.c index e8f3875..162a812 100755 --- a/tests.c +++ b/tests.c @@ -6,10 +6,11 @@ Describe(parse); BeforeEach(parse) {} AfterEach(parse) {} -shortcode *result; +sc_result result; str s; -chunk_s(char *buffer, chunk c){ +chunk_s(char *buffer, chunk c) +{ str_copyb(&s, buffer + c.start, c.len); } @@ -18,7 +19,7 @@ Ensure(parse, empty_string) char *input = ""; result = parse(input); // This means no shortcodes in it - assert_that(result[0].name.len, is_equal_to(0)); + assert_that(result.sc[0].name.len, is_equal_to(0)); } Ensure(parse, simple_shortcode) @@ -26,15 +27,15 @@ Ensure(parse, simple_shortcode) char *input = "foobar {{% shortcode %}}blah"; result = parse(input); // Only 1 shortcode - assert_that(result[1].name.len, is_equal_to(0)); + assert_that(result.sc[1].name.len, is_equal_to(0)); // It's a simple one called shortcode, no args - chunk_s(input, result[0].name); + chunk_s(input, result.sc[0].name); assert_that(s.s, is_equal_to_string("shortcode")); - assert_that(result[0].matching, is_equal_to(0)); - assert_that(result[0].argcount, is_equal_to(0)); + assert_that(result.sc[0].matching, is_equal_to(0)); + assert_that(result.sc[0].argcount, is_equal_to(0)); // The whole shortcode is the whole thing - chunk_s(input, result[0].whole); + chunk_s(input, result.sc[0].whole); assert_that(s.s, is_equal_to_string("{{% shortcode %}}")); } @@ -43,7 +44,7 @@ Ensure(parse, mismatched_brackets) char *input = "foobar {{% shortcode >}}blah"; result = parse(input); // No shortcodes - assert_that(result[0].name.len, is_equal_to(0)); + assert_that(result.sc[0].name.len, is_equal_to(0)); } Ensure(parse, mismatched_brackets_inside_data_are_ok) @@ -51,10 +52,10 @@ Ensure(parse, mismatched_brackets_inside_data_are_ok) char *input = "foobar {{% sc %}} >}}blah {{% /sc %}} "; result = parse(input); // 1 shortcode - assert_that(result[1].name.len, is_equal_to(0)); - chunk_s(input, result[0].whole); + assert_that(result.sc[1].name.len, is_equal_to(0)); + chunk_s(input, result.sc[0].whole); assert_that(s.s, is_equal_to_string("{{% sc %}} >}}blah {{% /sc %}}")); - chunk_s(input, result[0].data); + chunk_s(input, result.sc[0].data); assert_that(s.s, is_equal_to_string(" >}}blah ")); } @@ -63,10 +64,10 @@ Ensure(parse, mismatched_brackets_in_qval_are_ok) char *input = "foobar {{% sc \">}}blah\" %}} {{% /sc %}}"; result = parse(input); // 1 shortcode - assert_that(result[1].name.len, is_equal_to(0)); - chunk_s(input, result[0].whole); + assert_that(result.sc[1].name.len, is_equal_to(0)); + chunk_s(input, result.sc[0].whole); assert_that(s.s, is_equal_to_string("{{% sc \">}}blah\" %}} {{% /sc %}}")); - chunk_s(input, result[0].argvals[0]); + chunk_s(input, result.sc[0].argvals[0]); assert_that(s.s, is_equal_to_string(">}}blah")); } @@ -75,15 +76,15 @@ Ensure(parse, inner_spaces_optional) char *input = "foobar {{% shortcode%}}blah"; result = parse(input); // Only 1 shortcode - assert_that(result[1].name.len, is_equal_to(0)); + assert_that(result.sc[1].name.len, is_equal_to(0)); // It's a simple one called shortcode, no args - chunk_s(input, result[0].name); + chunk_s(input, result.sc[0].name); assert_that(s.s, is_equal_to_string("shortcode")); - assert_that(result[0].matching, is_equal_to(0)); - assert_that(result[0].argcount, is_equal_to(0)); + assert_that(result.sc[0].matching, is_equal_to(0)); + assert_that(result.sc[0].argcount, is_equal_to(0)); // The whole shortcode is the whole thing - chunk_s(input, result[0].whole); + chunk_s(input, result.sc[0].whole); assert_that(s.s, is_equal_to_string("{{% shortcode%}}")); } @@ -92,13 +93,13 @@ Ensure(parse, name_can_be_path) char *input = "foobar {{% shortcode/foo/bar %}}blah"; result = parse(input); // Only 1 shortcode - assert_that(result[1].name.len, is_equal_to(0)); + assert_that(result.sc[1].name.len, is_equal_to(0)); // It's a simple one called shortcode, no args - chunk_s(input, result[0].name); + chunk_s(input, result.sc[0].name); assert_that(s.s, is_equal_to_string("shortcode/foo/bar")); - assert_that(result[0].matching, is_equal_to(0)); - assert_that(result[0].argcount, is_equal_to(0)); + assert_that(result.sc[0].matching, is_equal_to(0)); + assert_that(result.sc[0].argcount, is_equal_to(0)); } Ensure(parse, multiple_shortcodes) @@ -106,23 +107,23 @@ Ensure(parse, multiple_shortcodes) char *input = "foobar {{% shortcode %}}blah {{}}blahblah"; result = parse(input); // 2 shortcodes - assert_that(result[2].name.len, is_equal_to(0)); + assert_that(result.sc[2].name.len, is_equal_to(0)); // It's a simple one called shortcode, no args - chunk_s(input, result[0].name); + chunk_s(input, result.sc[0].name); assert_that(s.s, is_equal_to_string("shortcode")); - assert_that(result[0].matching, is_equal_to(0)); - assert_that(result[0].argcount, is_equal_to(0)); + assert_that(result.sc[0].matching, is_equal_to(0)); + assert_that(result.sc[0].argcount, is_equal_to(0)); // The whole shortcode is the whole thing - chunk_s(input, result[0].whole); + chunk_s(input, result.sc[0].whole); assert_that(s.s, is_equal_to_string("{{% shortcode %}}")); // It's a simple one called sc2, no args - chunk_s(input, result[1].name); + chunk_s(input, result.sc[1].name); assert_that(s.s, is_equal_to_string("sc2")); - assert_that(result[1].matching, is_equal_to(0)); - assert_that(result[1].argcount, is_equal_to(0)); + assert_that(result.sc[1].matching, is_equal_to(0)); + assert_that(result.sc[1].argcount, is_equal_to(0)); // The whole shortcode is the whole thing - chunk_s(input, result[1].whole); + chunk_s(input, result.sc[1].whole); assert_that(s.s, is_equal_to_string("{{}}")); } @@ -132,18 +133,18 @@ Ensure(parse, matching_shortcode) result = parse(input); // Only 1 shortcode - assert_that(result[1].name.len, is_equal_to(0)); + assert_that(result.sc[1].name.len, is_equal_to(0)); // It's a matching one called shortcode, no args - chunk_s(input, result[0].name); + chunk_s(input, result.sc[0].name); assert_that(s.s, is_equal_to_string("shortcode")); - assert_that(result[0].matching, is_equal_to(1)); - assert_that(result[0].argcount, is_equal_to(0)); + assert_that(result.sc[0].matching, is_equal_to(1)); + assert_that(result.sc[0].argcount, is_equal_to(0)); // data is the stuff between the shortcode tags - chunk_s(input, result[0].data); + chunk_s(input, result.sc[0].data); assert_that(s.s, is_equal_to_string("foo bar")); // The whole shortcode is the whole thing - chunk_s(input, result[0].whole); + chunk_s(input, result.sc[0].whole); assert_that(s.s, is_equal_to_string("{{% shortcode %}}foo bar{{% /shortcode %}}")); } @@ -152,41 +153,41 @@ Ensure(parse, shortcode_args) char *input = "foobar {{% shortcode foo \"bar\" 42 bat=v1 baz=\"v2\" %}}blah"; result = parse(input); // Only 1 shortcode - assert_that(result[1].name.len, is_equal_to(0)); + assert_that(result.sc[1].name.len, is_equal_to(0)); // The whole shortcode is the whole thing - chunk_s(input, result[0].whole); + chunk_s(input, result.sc[0].whole); assert_that(s.s, is_equal_to_string("{{% shortcode foo \"bar\" 42 bat=v1 baz=\"v2\" %}}")); // Name is shortcode - chunk_s(input, result[0].name); + chunk_s(input, result.sc[0].name); assert_that(s.s, is_equal_to_string("shortcode")); - assert_that(result[0].matching, is_equal_to(0)); + assert_that(result.sc[0].matching, is_equal_to(0)); // Has 5 args - assert_that(result[0].argcount, is_equal_to(5)); + assert_that(result.sc[0].argcount, is_equal_to(5)); // Arg1 is foo, no name - assert_that(result[0].argnames[0].len, is_equal_to(0)); - chunk_s(input, result[0].argvals[0]); + assert_that(result.sc[0].argnames[0].len, is_equal_to(0)); + chunk_s(input, result.sc[0].argvals[0]); assert_that(s.s, is_equal_to_string("foo")); // Arg2 is bar, no name - assert_that(result[0].argnames[1].len, is_equal_to(0)); - chunk_s(input, result[0].argvals[1]); + assert_that(result.sc[0].argnames[1].len, is_equal_to(0)); + chunk_s(input, result.sc[0].argvals[1]); assert_that(s.s, is_equal_to_string("bar")); // Arg3 is 42, no name - assert_that(result[0].argnames[2].len, is_equal_to(0)); - chunk_s(input, result[0].argvals[2]); + assert_that(result.sc[0].argnames[2].len, is_equal_to(0)); + chunk_s(input, result.sc[0].argvals[2]); assert_that(s.s, is_equal_to_string("42")); // Arg4 is bat=v1 - chunk_s(input, result[0].argnames[3]); + chunk_s(input, result.sc[0].argnames[3]); assert_that(s.s, is_equal_to_string("bat")); - chunk_s(input, result[0].argvals[3]); + chunk_s(input, result.sc[0].argvals[3]); assert_that(s.s, is_equal_to_string("v1")); // Arg5 is baz=v2 - chunk_s(input, result[0].argnames[4]); + chunk_s(input, result.sc[0].argnames[4]); assert_that(s.s, is_equal_to_string("baz")); - chunk_s(input, result[0].argvals[4]); + chunk_s(input, result.sc[0].argvals[4]); assert_that(s.s, is_equal_to_string("v2")); } @@ -195,10 +196,9 @@ Ensure(parse, escaped_shortcode) char *input = "foobar \\{{% shortcode %}}"; result = parse(input); // No shortcodes - assert_that(result[0].name.len, is_equal_to(0)); + assert_that(result.sc[0].name.len, is_equal_to(0)); } - int main(int argc, char **argv) { str_init(&s); -- 2.45.2 From f471642f437d3573f83ea46e5b50adc874293ec7 Mon Sep 17 00:00:00 2001 From: Roberto Alsina Date: Wed, 12 Jul 2023 22:08:16 -0300 Subject: [PATCH 03/12] use cgreen-runner --- Makefile | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 3f7c5ba..5465144 100644 --- a/Makefile +++ b/Makefile @@ -1,16 +1,14 @@ -CC=tcc +CC=gcc all: tests -run: shortcodes - ./shortcodes shortcodes.c: shortcodes.rl ragel -G2 shortcodes.rl -o shortcodes.c -shortcodes: shortcodes.c - $(CC) shortcodes.c -g -o shortcodes -tests: shortcodes.c shortcodes.h tests.c - $(CC) tests.c shortcodes.c -lbg -lcgreen -g -o tests -test: tests - ./tests +%.o: %.c + $(CC) -fPIC -c -o $@ $^ +tests.so: shortcodes.o tests.o + $(CC) -shared -o $@ $^ -lbg -lcgreen +test: tests.so + cgreen-runner $^ clean: - rm -f shortcodes shortcodes.c + rm -f shortcodes.c *.o *.so -.PHONY: test run +.PHONY: test -- 2.45.2 From 47ee73edbebb760c4b62d584b3ea3dbcc9087d94 Mon Sep 17 00:00:00 2001 From: Roberto Alsina Date: Wed, 12 Jul 2023 22:22:22 -0300 Subject: [PATCH 04/12] tests pass again --- Makefile | 17 ++++++++++------- shortcodes.h | 3 ++- shortcodes.rl | 5 +---- tests.c | 19 +++++++++++-------- 4 files changed, 24 insertions(+), 20 deletions(-) diff --git a/Makefile b/Makefile index 5465144..705f735 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,17 @@ CC=gcc all: tests shortcodes.c: shortcodes.rl - ragel -G2 shortcodes.rl -o shortcodes.c + ragel -G2 -L shortcodes.rl -o shortcodes.c %.o: %.c - $(CC) -fPIC -c -o $@ $^ + $(CC) -fPIC -c -o $@ $^ -g tests.so: shortcodes.o tests.o - $(CC) -shared -o $@ $^ -lbg -lcgreen -test: tests.so - cgreen-runner $^ + $(CC) -shared -g -o $@ $^ -lbg -lcgreen +test-binary: shortcodes.c tests.c + $(CC) -g -o tests shortcodes.c tests.c -DMAIN=1 -lbg -lcgreen clean: rm -f shortcodes.c *.o *.so - -.PHONY: test +test: tests.so + cgreen-runner $^ +debug: + cgreen-debug tests.so +.PHONY: test debug diff --git a/shortcodes.h b/shortcodes.h index 1c88d01..3153a00 100644 --- a/shortcodes.h +++ b/shortcodes.h @@ -46,8 +46,9 @@ Example: {{% foo %}} {{% /bar %}} */ -#define ERR_MISMATCHED_CLOSING_TAG 1 +#define ERR_MISMATCHED_CLOSING_TAG 1; sc_result parse(char *); + #endif diff --git a/shortcodes.rl b/shortcodes.rl index 0f9d263..075c395 100644 --- a/shortcodes.rl +++ b/shortcodes.rl @@ -120,14 +120,11 @@ sc_result parse(char *input) { shortcode *sc_list = result.sc; int c_sc = 0; - int sc_start = 0; - int sc_end = 0; - char *mark = p; char *data_mark = p; %% write init; %% write exec; - return sc_result; + return result; } diff --git a/tests.c b/tests.c index 162a812..1dfca35 100755 --- a/tests.c +++ b/tests.c @@ -9,7 +9,7 @@ AfterEach(parse) {} sc_result result; str s; -chunk_s(char *buffer, chunk c) +void chunk_s(char *buffer, chunk c) { str_copyb(&s, buffer + c.start, c.len); } @@ -191,14 +191,16 @@ Ensure(parse, shortcode_args) assert_that(s.s, is_equal_to_string("v2")); } -Ensure(parse, escaped_shortcode) -{ - char *input = "foobar \\{{% shortcode %}}"; - result = parse(input); - // No shortcodes - assert_that(result.sc[0].name.len, is_equal_to(0)); -} +// BUG? +// Ensure(parse, escaped_shortcode) +// { +// char *input = "foobar \\{{% shortcode %}}"; +// result = parse(input); +// // No shortcodes +// assert_that(result.sc[0].name.len, is_equal_to(0)); +// } +#ifdef MAIN int main(int argc, char **argv) { str_init(&s); @@ -218,3 +220,4 @@ int main(int argc, char **argv) // add_test_with_context(suite, parse, escaped_shortcode); return run_test_suite(suite, create_text_reporter()); } +#endif \ No newline at end of file -- 2.45.2 From 96f08fcaa09be14c30cc5387a490455dfdcdefd5 Mon Sep 17 00:00:00 2001 From: Roberto Alsina Date: Wed, 12 Jul 2023 22:23:33 -0300 Subject: [PATCH 05/12] back to tcc --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 705f735..4c6b7fd 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -CC=gcc +CC=tcc all: tests shortcodes.c: shortcodes.rl ragel -G2 -L shortcodes.rl -o shortcodes.c -- 2.45.2 From f6e775474df2112c2553f416508c0fea1600bb92 Mon Sep 17 00:00:00 2001 From: Roberto Alsina Date: Wed, 12 Jul 2023 22:26:21 -0300 Subject: [PATCH 06/12] makefile tweaks --- Makefile | 6 ++---- tests.c | 0 2 files changed, 2 insertions(+), 4 deletions(-) mode change 100755 => 100644 tests.c diff --git a/Makefile b/Makefile index 4c6b7fd..caf1ba9 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -CC=tcc +CC=gcc all: tests shortcodes.c: shortcodes.rl ragel -G2 -L shortcodes.rl -o shortcodes.c @@ -6,10 +6,8 @@ shortcodes.c: shortcodes.rl $(CC) -fPIC -c -o $@ $^ -g tests.so: shortcodes.o tests.o $(CC) -shared -g -o $@ $^ -lbg -lcgreen -test-binary: shortcodes.c tests.c - $(CC) -g -o tests shortcodes.c tests.c -DMAIN=1 -lbg -lcgreen clean: - rm -f shortcodes.c *.o *.so + rm -f shortcodes.c *.o *.so tests test: tests.so cgreen-runner $^ debug: diff --git a/tests.c b/tests.c old mode 100755 new mode 100644 -- 2.45.2 From 35acfee0b6218b83d3c59c345ccbe41517469844 Mon Sep 17 00:00:00 2001 From: Roberto Alsina Date: Thu, 13 Jul 2023 07:44:49 -0300 Subject: [PATCH 07/12] housekeeping --- .gitignore | 1 + TODO.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4eedc61..be65bcd 100644 --- a/.gitignore +++ b/.gitignore @@ -54,3 +54,4 @@ dkms.conf shortcodes.c shortcodes tests +.cgreen* diff --git a/TODO.md b/TODO.md index b889f4c..cfc7576 100644 --- a/TODO.md +++ b/TODO.md @@ -11,5 +11,5 @@ * Add self-closing shortcodes `{{< foo />}}` (also, how TF do they work?) * Add inline shortcodes `{{< time.inline >}}{{ now }}{{< /time.inline >}}` - +* Start integrating with Crystal * ~~Detect mismatched start/end like {{% foo >}}~~ -- 2.45.2 From 4dcd067ca7f5860f12ecd2867a499bb049200f54 Mon Sep 17 00:00:00 2001 From: Roberto Alsina Date: Thu, 13 Jul 2023 20:59:35 -0300 Subject: [PATCH 08/12] Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index caf1ba9..fcb96f2 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CC=gcc -all: tests +all: test shortcodes.c: shortcodes.rl ragel -G2 -L shortcodes.rl -o shortcodes.c %.o: %.c -- 2.45.2 From 34a16bd6bdf1d5cdf0586fbd43cdcc02b145042c Mon Sep 17 00:00:00 2001 From: Roberto Alsina Date: Thu, 13 Jul 2023 21:24:37 -0300 Subject: [PATCH 09/12] Add error reporting/checking --- Makefile | 6 ++---- shortcodes.h | 8 +++----- shortcodes.rl | 3 +++ tests.c | 4 ++++ 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index fcb96f2..51674c2 100644 --- a/Makefile +++ b/Makefile @@ -2,10 +2,8 @@ CC=gcc all: test shortcodes.c: shortcodes.rl ragel -G2 -L shortcodes.rl -o shortcodes.c -%.o: %.c - $(CC) -fPIC -c -o $@ $^ -g -tests.so: shortcodes.o tests.o - $(CC) -shared -g -o $@ $^ -lbg -lcgreen +tests.so: shortcodes.c tests.c + $(CC) -fPIC -shared -g -o $@ $^ -lbg -lcgreen clean: rm -f shortcodes.c *.o *.so tests test: tests.so diff --git a/shortcodes.h b/shortcodes.h index 3153a00..01840b9 100644 --- a/shortcodes.h +++ b/shortcodes.h @@ -1,5 +1,4 @@ -#ifndef SHORTCODES_H -#define SHORTCODES_H +#pragma once // A chunk is a reference to a piece of string // from "start" relative to its start @@ -46,9 +45,8 @@ Example: {{% foo %}} {{% /bar %}} */ -#define ERR_MISMATCHED_CLOSING_TAG 1; +#define ERR_MISMATCHED_CLOSING_TAG 1 +#define ERR_MISMATCHED_BRACKET 2 sc_result parse(char *); - -#endif diff --git a/shortcodes.rl b/shortcodes.rl index 075c395..cd76fb4 100644 --- a/shortcodes.rl +++ b/shortcodes.rl @@ -58,6 +58,9 @@ // Since it's mismatched, remove the name sc_list[c_sc].name.start = 0; sc_list[c_sc].name.len=0; + result.errors[result.errcount].position = p-start-2; + result.errors[result.errcount].code = ERR_MISMATCHED_BRACKET; + result.errcount++; }; shortcode = ((start_p content end_p) | (start_b content end_b)) diff --git a/tests.c b/tests.c index 1dfca35..8526604 100644 --- a/tests.c +++ b/tests.c @@ -45,6 +45,10 @@ Ensure(parse, mismatched_brackets) result = parse(input); // No shortcodes assert_that(result.sc[0].name.len, is_equal_to(0)); + assert_that(result.errcount, is_equal_to(1)); + assert_that(result.errors[0].code, is_equal_to(ERR_MISMATCHED_BRACKET)); + str_copyb(&s, input + result.errors[0].position, 3); + assert_that(s.s, is_equal_to_string(">}}")); } Ensure(parse, mismatched_brackets_inside_data_are_ok) -- 2.45.2 From 62fd9b50296dc6abba77637e64fd17d02b9a1989 Mon Sep 17 00:00:00 2001 From: Roberto Alsina Date: Thu, 13 Jul 2023 21:57:47 -0300 Subject: [PATCH 10/12] Add closing tag error reporting --- Makefile | 2 +- shortcodes.h | 10 +++++----- shortcodes.rl | 11 +++++++---- tests.c | 46 +++++++++++++++++++++++----------------------- 4 files changed, 36 insertions(+), 33 deletions(-) diff --git a/Makefile b/Makefile index 51674c2..e5e1f6d 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CC=gcc all: test shortcodes.c: shortcodes.rl - ragel -G2 -L shortcodes.rl -o shortcodes.c + ragel -G2 shortcodes.rl -o shortcodes.c tests.so: shortcodes.c tests.c $(CC) -fPIC -shared -g -o $@ $^ -lbg -lcgreen clean: diff --git a/shortcodes.h b/shortcodes.h index 01840b9..254ae73 100644 --- a/shortcodes.h +++ b/shortcodes.h @@ -5,15 +5,15 @@ // and goes on for len characters. struct chunk { - int start, len; + unsigned int start, len; }; typedef struct chunk chunk; // An error struct sc_error { - int position; - int code; + unsigned int position; + unsigned int code; }; typedef struct sc_error sc_error; @@ -26,7 +26,7 @@ struct shortcode char matching; chunk argnames[100]; chunk argvals[100]; - int argcount; + unsigned int argcount; }; typedef struct shortcode shortcode; @@ -34,7 +34,7 @@ struct sc_result { shortcode sc[100]; sc_error errors[10]; - int errcount; + unsigned int errcount; }; typedef struct sc_result sc_result; diff --git a/shortcodes.rl b/shortcodes.rl index cd76fb4..15a7ad0 100644 --- a/shortcodes.rl +++ b/shortcodes.rl @@ -87,8 +87,6 @@ matched_shortcode = (shortcode any* closing_shortcode) @ { - sc_list[c_sc-1].matching = 1; - sc_list[c_sc-1].whole.len = p-start-sc_list[c_sc-1].whole.start + 1; if ( sc_list[c_sc-1].name.len != sc_list[c_sc].name.len || strncmp( @@ -96,11 +94,16 @@ start + sc_list[c_sc].name.start, sc_list[c_sc-1].name.len) !=0) { - result.errors[result.errcount].position = p-start; + result.errors[result.errcount].position = + sc_list[c_sc].whole.start; result.errors[result.errcount].code = ERR_MISMATCHED_CLOSING_TAG; result.errcount++; + } else { + // The previous shortcode is matching (mark it) + sc_list[c_sc-1].matching = 1; + sc_list[c_sc-1].whole.len = p-start-sc_list[c_sc-1].whole.start + 1; } - // Reuse this shortcode entry for next one + // Reuse the closing shortcode tag entry for next one sc_list[c_sc].name.start = 0; sc_list[c_sc].name.len=0; }; diff --git a/tests.c b/tests.c index 8526604..f4753b0 100644 --- a/tests.c +++ b/tests.c @@ -20,6 +20,7 @@ Ensure(parse, empty_string) result = parse(input); // This means no shortcodes in it assert_that(result.sc[0].name.len, is_equal_to(0)); + assert_that(result.errcount, is_equal_to(0)); } Ensure(parse, simple_shortcode) @@ -37,8 +38,22 @@ Ensure(parse, simple_shortcode) // The whole shortcode is the whole thing chunk_s(input, result.sc[0].whole); assert_that(s.s, is_equal_to_string("{{% shortcode %}}")); + assert_that(result.errcount, is_equal_to(0)); } +Ensure(parse, mismatched_tags) +{ + char *input = "foobar {{% shortcode %}}blah{{% /foo %}}"; + result = parse(input); + // No shortcodes + assert_that(result.sc[0].name.len, is_equal_to(0)); + assert_that(result.errcount, is_equal_to(1)); + assert_that(result.errors[0].code, is_equal_to(ERR_MISMATCHED_CLOSING_TAG)); + str_copyb(&s, input + result.errors[0].position, 8); + assert_that(s.s, is_equal_to_string("{{% /foo")); +} + + Ensure(parse, mismatched_brackets) { char *input = "foobar {{% shortcode >}}blah"; @@ -61,6 +76,7 @@ Ensure(parse, mismatched_brackets_inside_data_are_ok) assert_that(s.s, is_equal_to_string("{{% sc %}} >}}blah {{% /sc %}}")); chunk_s(input, result.sc[0].data); assert_that(s.s, is_equal_to_string(" >}}blah ")); + assert_that(result.errcount, is_equal_to(0)); } Ensure(parse, mismatched_brackets_in_qval_are_ok) @@ -73,6 +89,7 @@ Ensure(parse, mismatched_brackets_in_qval_are_ok) assert_that(s.s, is_equal_to_string("{{% sc \">}}blah\" %}} {{% /sc %}}")); chunk_s(input, result.sc[0].argvals[0]); assert_that(s.s, is_equal_to_string(">}}blah")); + assert_that(result.errcount, is_equal_to(0)); } Ensure(parse, inner_spaces_optional) @@ -90,6 +107,7 @@ Ensure(parse, inner_spaces_optional) // The whole shortcode is the whole thing chunk_s(input, result.sc[0].whole); assert_that(s.s, is_equal_to_string("{{% shortcode%}}")); + assert_that(result.errcount, is_equal_to(0)); } Ensure(parse, name_can_be_path) @@ -104,6 +122,7 @@ Ensure(parse, name_can_be_path) assert_that(s.s, is_equal_to_string("shortcode/foo/bar")); assert_that(result.sc[0].matching, is_equal_to(0)); assert_that(result.sc[0].argcount, is_equal_to(0)); + assert_that(result.errcount, is_equal_to(0)); } Ensure(parse, multiple_shortcodes) @@ -129,6 +148,7 @@ Ensure(parse, multiple_shortcodes) // The whole shortcode is the whole thing chunk_s(input, result.sc[1].whole); assert_that(s.s, is_equal_to_string("{{}}")); + assert_that(result.errcount, is_equal_to(0)); } Ensure(parse, matching_shortcode) @@ -150,6 +170,7 @@ Ensure(parse, matching_shortcode) // The whole shortcode is the whole thing chunk_s(input, result.sc[0].whole); assert_that(s.s, is_equal_to_string("{{% shortcode %}}foo bar{{% /shortcode %}}")); + assert_that(result.errcount, is_equal_to(0)); } Ensure(parse, shortcode_args) @@ -193,6 +214,7 @@ Ensure(parse, shortcode_args) assert_that(s.s, is_equal_to_string("baz")); chunk_s(input, result.sc[0].argvals[4]); assert_that(s.s, is_equal_to_string("v2")); + assert_that(result.errcount, is_equal_to(0)); } // BUG? @@ -202,26 +224,4 @@ Ensure(parse, shortcode_args) // result = parse(input); // // No shortcodes // assert_that(result.sc[0].name.len, is_equal_to(0)); -// } - -#ifdef MAIN -int main(int argc, char **argv) -{ - str_init(&s); - TestSuite *suite = create_test_suite(); - add_test_with_context(suite, parse, empty_string); - add_test_with_context(suite, parse, simple_shortcode); - add_test_with_context(suite, parse, mismatched_brackets); - add_test_with_context(suite, parse, mismatched_brackets_inside_data_are_ok); - add_test_with_context(suite, parse, mismatched_brackets_in_qval_are_ok); - add_test_with_context(suite, parse, name_can_be_path); - add_test_with_context(suite, parse, inner_spaces_optional); - add_test_with_context(suite, parse, multiple_shortcodes); - add_test_with_context(suite, parse, matching_shortcode); - add_test_with_context(suite, parse, shortcode_args); - - // Bugs - // add_test_with_context(suite, parse, escaped_shortcode); - return run_test_suite(suite, create_text_reporter()); -} -#endif \ No newline at end of file +// } \ No newline at end of file -- 2.45.2 From 7ead97a5e7b2dca1fb5c558fa0d6cb4f5478d05b Mon Sep 17 00:00:00 2001 From: Roberto Alsina Date: Thu, 13 Jul 2023 22:02:45 -0300 Subject: [PATCH 11/12] Finished with error reporting for now --- shortcodes.h | 7 +++++++ shortcodes.rl | 5 ++--- tests.c | 31 +++++++++++++++---------------- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/shortcodes.h b/shortcodes.h index 254ae73..4b7336a 100644 --- a/shortcodes.h +++ b/shortcodes.h @@ -33,6 +33,7 @@ typedef struct shortcode shortcode; struct sc_result { shortcode sc[100]; + unsigned int sccount; sc_error errors[10]; unsigned int errcount; }; @@ -46,6 +47,12 @@ Example: {{% foo %}} {{% /bar %}} */ #define ERR_MISMATCHED_CLOSING_TAG 1 + +/* You are using mismatched brackets. +Example: + +{{% foo >}} +*/ #define ERR_MISMATCHED_BRACKET 2 diff --git a/shortcodes.rl b/shortcodes.rl index 15a7ad0..1588bce 100644 --- a/shortcodes.rl +++ b/shortcodes.rl @@ -103,9 +103,7 @@ sc_list[c_sc-1].matching = 1; sc_list[c_sc-1].whole.len = p-start-sc_list[c_sc-1].whole.start + 1; } - // Reuse the closing shortcode tag entry for next one - sc_list[c_sc].name.start = 0; - sc_list[c_sc].name.len=0; + // Do NOT increase c_sc }; main := (any* (shortcode | matched_shortcode | mismatched))*; @@ -132,5 +130,6 @@ sc_result parse(char *input) { %% write init; %% write exec; + result.sccount = c_sc; return result; } diff --git a/tests.c b/tests.c index f4753b0..43e5184 100644 --- a/tests.c +++ b/tests.c @@ -19,7 +19,7 @@ Ensure(parse, empty_string) char *input = ""; result = parse(input); // This means no shortcodes in it - assert_that(result.sc[0].name.len, is_equal_to(0)); + assert_that(result.sccount, is_equal_to(0)); assert_that(result.errcount, is_equal_to(0)); } @@ -28,7 +28,7 @@ Ensure(parse, simple_shortcode) char *input = "foobar {{% shortcode %}}blah"; result = parse(input); // Only 1 shortcode - assert_that(result.sc[1].name.len, is_equal_to(0)); + assert_that(result.sccount, is_equal_to(1)); // It's a simple one called shortcode, no args chunk_s(input, result.sc[0].name); @@ -45,25 +45,24 @@ Ensure(parse, mismatched_tags) { char *input = "foobar {{% shortcode %}}blah{{% /foo %}}"; result = parse(input); - // No shortcodes - assert_that(result.sc[0].name.len, is_equal_to(0)); + // One shortcode, one error + assert_that(result.sccount, is_equal_to(1)); assert_that(result.errcount, is_equal_to(1)); assert_that(result.errors[0].code, is_equal_to(ERR_MISMATCHED_CLOSING_TAG)); str_copyb(&s, input + result.errors[0].position, 8); - assert_that(s.s, is_equal_to_string("{{% /foo")); + assert_that(s.s, is_equal_to_string("{{% /foo")); } - Ensure(parse, mismatched_brackets) { char *input = "foobar {{% shortcode >}}blah"; result = parse(input); - // No shortcodes - assert_that(result.sc[0].name.len, is_equal_to(0)); + // No shortcodes, 1 error + assert_that(result.sccount, is_equal_to(0)); assert_that(result.errcount, is_equal_to(1)); assert_that(result.errors[0].code, is_equal_to(ERR_MISMATCHED_BRACKET)); str_copyb(&s, input + result.errors[0].position, 3); - assert_that(s.s, is_equal_to_string(">}}")); + assert_that(s.s, is_equal_to_string(">}}")); } Ensure(parse, mismatched_brackets_inside_data_are_ok) @@ -71,7 +70,7 @@ Ensure(parse, mismatched_brackets_inside_data_are_ok) char *input = "foobar {{% sc %}} >}}blah {{% /sc %}} "; result = parse(input); // 1 shortcode - assert_that(result.sc[1].name.len, is_equal_to(0)); + assert_that(result.sccount, is_equal_to(1)); chunk_s(input, result.sc[0].whole); assert_that(s.s, is_equal_to_string("{{% sc %}} >}}blah {{% /sc %}}")); chunk_s(input, result.sc[0].data); @@ -84,7 +83,7 @@ Ensure(parse, mismatched_brackets_in_qval_are_ok) char *input = "foobar {{% sc \">}}blah\" %}} {{% /sc %}}"; result = parse(input); // 1 shortcode - assert_that(result.sc[1].name.len, is_equal_to(0)); + assert_that(result.sccount, is_equal_to(1)); chunk_s(input, result.sc[0].whole); assert_that(s.s, is_equal_to_string("{{% sc \">}}blah\" %}} {{% /sc %}}")); chunk_s(input, result.sc[0].argvals[0]); @@ -97,7 +96,7 @@ Ensure(parse, inner_spaces_optional) char *input = "foobar {{% shortcode%}}blah"; result = parse(input); // Only 1 shortcode - assert_that(result.sc[1].name.len, is_equal_to(0)); + assert_that(result.sccount, is_equal_to(1)); // It's a simple one called shortcode, no args chunk_s(input, result.sc[0].name); @@ -115,7 +114,7 @@ Ensure(parse, name_can_be_path) char *input = "foobar {{% shortcode/foo/bar %}}blah"; result = parse(input); // Only 1 shortcode - assert_that(result.sc[1].name.len, is_equal_to(0)); + assert_that(result.sccount, is_equal_to(1)); // It's a simple one called shortcode, no args chunk_s(input, result.sc[0].name); @@ -130,7 +129,7 @@ Ensure(parse, multiple_shortcodes) char *input = "foobar {{% shortcode %}}blah {{}}blahblah"; result = parse(input); // 2 shortcodes - assert_that(result.sc[2].name.len, is_equal_to(0)); + assert_that(result.sccount, is_equal_to(2)); // It's a simple one called shortcode, no args chunk_s(input, result.sc[0].name); @@ -157,7 +156,7 @@ Ensure(parse, matching_shortcode) result = parse(input); // Only 1 shortcode - assert_that(result.sc[1].name.len, is_equal_to(0)); + assert_that(result.sccount, is_equal_to(1)); // It's a matching one called shortcode, no args chunk_s(input, result.sc[0].name); @@ -178,7 +177,7 @@ Ensure(parse, shortcode_args) char *input = "foobar {{% shortcode foo \"bar\" 42 bat=v1 baz=\"v2\" %}}blah"; result = parse(input); // Only 1 shortcode - assert_that(result.sc[1].name.len, is_equal_to(0)); + assert_that(result.sccount, is_equal_to(1)); // The whole shortcode is the whole thing chunk_s(input, result.sc[0].whole); -- 2.45.2 From d022b0700cb38b44351b71e782b07f7dfae352a9 Mon Sep 17 00:00:00 2001 From: Roberto Alsina Date: Thu, 13 Jul 2023 22:03:33 -0300 Subject: [PATCH 12/12] todo --- TODO.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TODO.md b/TODO.md index cfc7576..29c5223 100644 --- a/TODO.md +++ b/TODO.md @@ -2,7 +2,6 @@ ## Things That May Get Done -* Produce decent error structures * Inform tag type (% or <) in result * Handle other kinds of quotes * Handle escaping quote characters @@ -12,4 +11,5 @@ (also, how TF do they work?) * Add inline shortcodes `{{< time.inline >}}{{ now }}{{< /time.inline >}}` * Start integrating with Crystal +* ~~Produce decent error structures~~ * ~~Detect mismatched start/end like {{% foo >}}~~ -- 2.45.2