refactor(ltm): rename loops to nested

Jef Roosens 2023-12-16 16:29:08 +01:00
parent 1e34cb8c2d
commit 6f817307cf
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
5 changed files with 112 additions and 54 deletions

View File

@ -28,4 +28,33 @@ ltm_err ltm_template_compile(ltm_template **out, const char *template);
ltm_err ltm_template_compile_n(ltm_template **out, const char *template,
size_t len);
/**
* Represents a specific instance of a template.
*/
typedef struct ltm_instance ltm_instance;
/**
* Create a new instance of the given template.
*/
ltm_err ltm_template_instantiate(ltm_instance **out,
const ltm_template *template);
typedef enum ltm_instance_block_type {
ltm_instance_block_type_buf = 0,
} ltm_instance_block_type;
/**
* Add a new variable to the template.
*/
ltm_err ltm_instance_block_add_var(ltm_instance *instance, const char *name,
ltm_instance_block_type type, void *data,
size_t len);
/**
* Add a new nested instance to the instance, returning a handle to the nested
* instance.
*/
ltm_err ltm_instance_block_add_nested(ltm_instance **out,
ltm_instance *instance, const char *name);
#endif

View File

@ -6,8 +6,8 @@
typedef enum ltm_placeholder_type {
ltm_placeholder_type_invalid = 0,
ltm_placeholder_type_var,
ltm_placeholder_type_loop_start,
ltm_placeholder_type_loop_end,
ltm_placeholder_type_nested_start,
ltm_placeholder_type_nested_end,
} ltm_placeholder_type;
/**
@ -29,7 +29,7 @@ typedef struct ltm_placeholder {
typedef enum ltm_template_block_type {
ltm_template_block_type_literal = 0,
ltm_template_block_type_var,
ltm_template_block_type_loop,
ltm_template_block_type_nested,
} ltm_template_block_type;
/**
@ -53,7 +53,7 @@ typedef struct ltm_template_block_name {
/**
* Represents a compiled template. A template consists of a list of blocks, of
* which some have names that can be indexed (e.g. variables, loops).
* which some have names that can be indexed (e.g. variables, nested templates).
*/
struct ltm_template {
struct {
@ -66,13 +66,41 @@ struct ltm_template {
} names;
};
/**
* Allocate a new `ltm_template`.
*/
ltm_err ltm_template_init(ltm_template **out);
/**
* Append a name to the template's list.
*/
ltm_err ltm_template_name_append(ltm_template *template, const char *s,
size_t len, size_t index);
/**
* Append a block to the template's list.
*/
ltm_err ltm_template_block_append(ltm_template *template,
ltm_template_block_type type, void *data,
size_t len);
typedef struct ltm_instance_block {
ltm_instance_block_type type;
struct {
void *ptr;
size_t len;
} data;
struct ltm_instance_block *next;
} ltm_instance_block;
struct ltm_instance {
struct {
ltm_instance_block *head;
ltm_instance_block *tail;
ltm_instance_block *current;
} blocks;
// How many bytes of the current block have been written
size_t written;
};
#endif

View File

@ -55,7 +55,7 @@ ltm_err ltm_template_block_append(ltm_template *template,
block->data.ptr = data;
block->data.len = len;
break;
case ltm_template_block_type_loop:
case ltm_template_block_type_nested:
block->data.ptr = data;
break;
// For the other cases, we explicitely ignore the data and len arguments

View File

@ -79,9 +79,9 @@ static bool ltm_template_next_placeholder(ltm_placeholder *ph, const char *s,
size_t ident_len = temp - ident;
if (strncmp("start", ident, ident_len) == 0) {
ph->type = ltm_placeholder_type_loop_start;
ph->type = ltm_placeholder_type_nested_start;
} else if (strncmp("end", ident, ident_len) == 0) {
ph->type = ltm_placeholder_type_loop_end;
ph->type = ltm_placeholder_type_nested_end;
} else {
ph->type = ltm_placeholder_type_invalid;
}
@ -95,15 +95,15 @@ ltm_err ltm_template_compile_n(ltm_template **out, const char *s, size_t len) {
LTM_RES(ltm_template_init(&template));
ltm_placeholder ph;
bool in_loop = false;
const char *loop_start = NULL, *loop_name = NULL;
size_t loop_depth = 0, loop_name_len = 0;
bool in_nested = false;
const char *nested_start = NULL, *nested_name = NULL;
size_t nested_depth = 0, nested_name_len = 0;
size_t cur_loop_depth = 0;
size_t cur_nested_depth = 0;
while (ltm_template_next_placeholder(&ph, s, len)) {
// Add part before placeholder as literal
if (!in_loop && (ph.start != s)) {
if (!in_nested && (ph.start != s)) {
LTM_RES(ltm_template_block_append(
template, ltm_template_block_type_literal, (void *)s, ph.start - s));
}
@ -113,44 +113,45 @@ ltm_err ltm_template_compile_n(ltm_template **out, const char *s, size_t len) {
case ltm_placeholder_type_invalid:
return ltm_err_invalid_template;
case ltm_placeholder_type_var:
if (!in_loop) {
if (!in_nested) {
LTM_RES(ltm_template_block_append(template, ltm_template_block_type_var,
NULL, 0));
LTM_RES(ltm_template_name_append(template, ph.name.s, ph.name.len,
template->blocks.len - 1));
}
break;
case ltm_placeholder_type_loop_start:
if (!in_loop) {
loop_start = ph.end + 1;
loop_depth = cur_loop_depth;
loop_name = ph.name.s;
loop_name_len = ph.name.len;
in_loop = true;
case ltm_placeholder_type_nested_start:
if (!in_nested) {
nested_start = ph.end + 1;
nested_depth = cur_nested_depth;
nested_name = ph.name.s;
nested_name_len = ph.name.len;
in_nested = true;
}
cur_loop_depth++;
cur_nested_depth++;
break;
case ltm_placeholder_type_loop_end:
// This means there's more loop end placeholders than loop starts
if (cur_loop_depth == 0) {
case ltm_placeholder_type_nested_end:
// This means there's more nested end placeholders than nested starts
if (cur_nested_depth == 0) {
return ltm_err_invalid_template;
}
cur_loop_depth--;
cur_nested_depth--;
if (in_loop && (cur_loop_depth == loop_depth)) {
size_t loop_len = ph.start - loop_start;
ltm_template *loop_template;
LTM_RES(ltm_template_compile_n(&loop_template, loop_start, loop_len));
if (in_nested && (cur_nested_depth == nested_depth)) {
size_t nested_len = ph.start - nested_start;
ltm_template *nested_template;
LTM_RES(
ltm_template_compile_n(&nested_template, nested_start, nested_len));
LTM_RES(ltm_template_block_append(
template, ltm_template_block_type_loop, loop_template, 0));
LTM_RES(ltm_template_name_append(template, loop_name, loop_name_len,
template, ltm_template_block_type_nested, nested_template, 0));
LTM_RES(ltm_template_name_append(template, nested_name, nested_name_len,
template->blocks.len - 1));
in_loop = false;
in_nested = false;
}
// We encountered a loop end without a start
else if (!in_loop) {
// We encountered a nested end without a start
else if (!in_nested) {
return ltm_err_invalid_template;
}
break;
@ -160,8 +161,8 @@ ltm_err ltm_template_compile_n(ltm_template **out, const char *s, size_t len) {
s = ph.end + 1;
}
// Unfinished loop
if (in_loop) {
// Unfinished nested
if (in_nested) {
return ltm_err_invalid_template;
}

View File

@ -50,7 +50,7 @@ void test_single_placeholder_trailing() {
TEST_CHECK(template->names.arr[0].index == 1);
}
void test_single_loop() {
void test_single_nested() {
const char *s = "abc {{ l start }}some content {{ var }} {{ l end }}";
ltm_template *template;
@ -67,22 +67,22 @@ void test_single_loop() {
TEST_CHECK(template->blocks.arr[0].data.ptr == s);
TEST_CHECK(template->blocks.arr[0].data.len == 4);
TEST_CHECK(template->blocks.arr[1].type == ltm_template_block_type_loop);
ltm_template *loop_template = template->blocks.arr[1].data.ptr;
TEST_CHECK(template->blocks.arr[1].type == ltm_template_block_type_nested);
ltm_template *nested_template = template->blocks.arr[1].data.ptr;
TEST_CHECK(loop_template->blocks.len == 3);
TEST_CHECK(loop_template->blocks.arr[0].type == ltm_template_block_type_literal);
TEST_CHECK(loop_template->blocks.arr[0].data.ptr == s + 17);
TEST_CHECK(loop_template->blocks.arr[0].data.len == 13);
TEST_CHECK(loop_template->blocks.arr[1].type == ltm_template_block_type_var);
TEST_CHECK(loop_template->blocks.arr[2].type == ltm_template_block_type_literal);
TEST_CHECK(loop_template->blocks.arr[2].data.ptr == s + 39);
TEST_CHECK(loop_template->blocks.arr[2].data.len == 1);
TEST_CHECK(nested_template->blocks.len == 3);
TEST_CHECK(nested_template->blocks.arr[0].type == ltm_template_block_type_literal);
TEST_CHECK(nested_template->blocks.arr[0].data.ptr == s + 17);
TEST_CHECK(nested_template->blocks.arr[0].data.len == 13);
TEST_CHECK(nested_template->blocks.arr[1].type == ltm_template_block_type_var);
TEST_CHECK(nested_template->blocks.arr[2].type == ltm_template_block_type_literal);
TEST_CHECK(nested_template->blocks.arr[2].data.ptr == s + 39);
TEST_CHECK(nested_template->blocks.arr[2].data.len == 1);
TEST_CHECK(loop_template->names.len == 1);
TEST_CHECK(loop_template->names.arr[0].name.s == s + 33);
TEST_CHECK(loop_template->names.arr[0].name.len == 3);
TEST_CHECK(loop_template->names.arr[0].index == 1);
TEST_CHECK(nested_template->names.len == 1);
TEST_CHECK(nested_template->names.arr[0].name.s == s + 33);
TEST_CHECK(nested_template->names.arr[0].name.len == 3);
TEST_CHECK(nested_template->names.arr[0].index == 1);
}
void test_unclosed_placeholder() {
@ -95,7 +95,7 @@ void test_unclosed_placeholder() {
TEST_CHECK(ltm_template_compile(&template, s) == ltm_err_invalid_template);
}
void test_unclosed_loop() {
void test_unclosed_nested() {
ltm_template *template;
const char *s = "abc {{ var start }} {{ hello }}";
@ -105,8 +105,8 @@ void test_unclosed_loop() {
TEST_LIST = {
{ "template single placeholder", test_single_placeholder },
{ "template single placeholder trailing", test_single_placeholder_trailing },
{ "template single loop", test_single_loop },
{ "template single nested", test_single_nested },
{ "template unclosed placeholder", test_unclosed_placeholder },
{ "template unclosed loop", test_unclosed_loop },
{ "template unclosed nested", test_unclosed_nested },
{ NULL, NULL }
};