refactor(ltm): rename loops to nested
parent
ba320a4250
commit
0ef51ccada
|
@ -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,
|
ltm_err ltm_template_compile_n(ltm_template **out, const char *template,
|
||||||
size_t len);
|
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
|
#endif
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
typedef enum ltm_placeholder_type {
|
typedef enum ltm_placeholder_type {
|
||||||
ltm_placeholder_type_invalid = 0,
|
ltm_placeholder_type_invalid = 0,
|
||||||
ltm_placeholder_type_var,
|
ltm_placeholder_type_var,
|
||||||
ltm_placeholder_type_loop_start,
|
ltm_placeholder_type_nested_start,
|
||||||
ltm_placeholder_type_loop_end,
|
ltm_placeholder_type_nested_end,
|
||||||
} ltm_placeholder_type;
|
} ltm_placeholder_type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,7 +29,7 @@ typedef struct ltm_placeholder {
|
||||||
typedef enum ltm_template_block_type {
|
typedef enum ltm_template_block_type {
|
||||||
ltm_template_block_type_literal = 0,
|
ltm_template_block_type_literal = 0,
|
||||||
ltm_template_block_type_var,
|
ltm_template_block_type_var,
|
||||||
ltm_template_block_type_loop,
|
ltm_template_block_type_nested,
|
||||||
} ltm_template_block_type;
|
} 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
|
* 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 ltm_template {
|
||||||
struct {
|
struct {
|
||||||
|
@ -66,13 +66,41 @@ struct ltm_template {
|
||||||
} names;
|
} names;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate a new `ltm_template`.
|
||||||
|
*/
|
||||||
ltm_err ltm_template_init(ltm_template **out);
|
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,
|
ltm_err ltm_template_name_append(ltm_template *template, const char *s,
|
||||||
size_t len, size_t index);
|
size_t len, size_t index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append a block to the template's list.
|
||||||
|
*/
|
||||||
ltm_err ltm_template_block_append(ltm_template *template,
|
ltm_err ltm_template_block_append(ltm_template *template,
|
||||||
ltm_template_block_type type, void *data,
|
ltm_template_block_type type, void *data,
|
||||||
size_t len);
|
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
|
#endif
|
||||||
|
|
|
@ -55,7 +55,7 @@ ltm_err ltm_template_block_append(ltm_template *template,
|
||||||
block->data.ptr = data;
|
block->data.ptr = data;
|
||||||
block->data.len = len;
|
block->data.len = len;
|
||||||
break;
|
break;
|
||||||
case ltm_template_block_type_loop:
|
case ltm_template_block_type_nested:
|
||||||
block->data.ptr = data;
|
block->data.ptr = data;
|
||||||
break;
|
break;
|
||||||
// For the other cases, we explicitely ignore the data and len arguments
|
// For the other cases, we explicitely ignore the data and len arguments
|
||||||
|
|
|
@ -79,9 +79,9 @@ static bool ltm_template_next_placeholder(ltm_placeholder *ph, const char *s,
|
||||||
size_t ident_len = temp - ident;
|
size_t ident_len = temp - ident;
|
||||||
|
|
||||||
if (strncmp("start", ident, ident_len) == 0) {
|
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) {
|
} else if (strncmp("end", ident, ident_len) == 0) {
|
||||||
ph->type = ltm_placeholder_type_loop_end;
|
ph->type = ltm_placeholder_type_nested_end;
|
||||||
} else {
|
} else {
|
||||||
ph->type = ltm_placeholder_type_invalid;
|
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_RES(ltm_template_init(&template));
|
||||||
|
|
||||||
ltm_placeholder ph;
|
ltm_placeholder ph;
|
||||||
bool in_loop = false;
|
bool in_nested = false;
|
||||||
const char *loop_start = NULL, *loop_name = NULL;
|
const char *nested_start = NULL, *nested_name = NULL;
|
||||||
size_t loop_depth = 0, loop_name_len = 0;
|
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)) {
|
while (ltm_template_next_placeholder(&ph, s, len)) {
|
||||||
// Add part before placeholder as literal
|
// Add part before placeholder as literal
|
||||||
if (!in_loop && (ph.start != s)) {
|
if (!in_nested && (ph.start != s)) {
|
||||||
LTM_RES(ltm_template_block_append(
|
LTM_RES(ltm_template_block_append(
|
||||||
template, ltm_template_block_type_literal, (void *)s, ph.start - s));
|
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:
|
case ltm_placeholder_type_invalid:
|
||||||
return ltm_err_invalid_template;
|
return ltm_err_invalid_template;
|
||||||
case ltm_placeholder_type_var:
|
case ltm_placeholder_type_var:
|
||||||
if (!in_loop) {
|
if (!in_nested) {
|
||||||
LTM_RES(ltm_template_block_append(template, ltm_template_block_type_var,
|
LTM_RES(ltm_template_block_append(template, ltm_template_block_type_var,
|
||||||
NULL, 0));
|
NULL, 0));
|
||||||
LTM_RES(ltm_template_name_append(template, ph.name.s, ph.name.len,
|
LTM_RES(ltm_template_name_append(template, ph.name.s, ph.name.len,
|
||||||
template->blocks.len - 1));
|
template->blocks.len - 1));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ltm_placeholder_type_loop_start:
|
case ltm_placeholder_type_nested_start:
|
||||||
if (!in_loop) {
|
if (!in_nested) {
|
||||||
loop_start = ph.end + 1;
|
nested_start = ph.end + 1;
|
||||||
loop_depth = cur_loop_depth;
|
nested_depth = cur_nested_depth;
|
||||||
loop_name = ph.name.s;
|
nested_name = ph.name.s;
|
||||||
loop_name_len = ph.name.len;
|
nested_name_len = ph.name.len;
|
||||||
in_loop = true;
|
in_nested = true;
|
||||||
}
|
}
|
||||||
cur_loop_depth++;
|
cur_nested_depth++;
|
||||||
break;
|
break;
|
||||||
case ltm_placeholder_type_loop_end:
|
case ltm_placeholder_type_nested_end:
|
||||||
// This means there's more loop end placeholders than loop starts
|
// This means there's more nested end placeholders than nested starts
|
||||||
if (cur_loop_depth == 0) {
|
if (cur_nested_depth == 0) {
|
||||||
return ltm_err_invalid_template;
|
return ltm_err_invalid_template;
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_loop_depth--;
|
cur_nested_depth--;
|
||||||
|
|
||||||
if (in_loop && (cur_loop_depth == loop_depth)) {
|
if (in_nested && (cur_nested_depth == nested_depth)) {
|
||||||
size_t loop_len = ph.start - loop_start;
|
size_t nested_len = ph.start - nested_start;
|
||||||
ltm_template *loop_template;
|
ltm_template *nested_template;
|
||||||
LTM_RES(ltm_template_compile_n(&loop_template, loop_start, loop_len));
|
LTM_RES(
|
||||||
|
ltm_template_compile_n(&nested_template, nested_start, nested_len));
|
||||||
LTM_RES(ltm_template_block_append(
|
LTM_RES(ltm_template_block_append(
|
||||||
template, ltm_template_block_type_loop, loop_template, 0));
|
template, ltm_template_block_type_nested, nested_template, 0));
|
||||||
LTM_RES(ltm_template_name_append(template, loop_name, loop_name_len,
|
LTM_RES(ltm_template_name_append(template, nested_name, nested_name_len,
|
||||||
template->blocks.len - 1));
|
template->blocks.len - 1));
|
||||||
|
|
||||||
in_loop = false;
|
in_nested = false;
|
||||||
}
|
}
|
||||||
// We encountered a loop end without a start
|
// We encountered a nested end without a start
|
||||||
else if (!in_loop) {
|
else if (!in_nested) {
|
||||||
return ltm_err_invalid_template;
|
return ltm_err_invalid_template;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -160,8 +161,8 @@ ltm_err ltm_template_compile_n(ltm_template **out, const char *s, size_t len) {
|
||||||
s = ph.end + 1;
|
s = ph.end + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unfinished loop
|
// Unfinished nested
|
||||||
if (in_loop) {
|
if (in_nested) {
|
||||||
return ltm_err_invalid_template;
|
return ltm_err_invalid_template;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ void test_single_placeholder_trailing() {
|
||||||
TEST_CHECK(template->names.arr[0].index == 1);
|
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 }}";
|
const char *s = "abc {{ l start }}some content {{ var }} {{ l end }}";
|
||||||
|
|
||||||
ltm_template *template;
|
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.ptr == s);
|
||||||
TEST_CHECK(template->blocks.arr[0].data.len == 4);
|
TEST_CHECK(template->blocks.arr[0].data.len == 4);
|
||||||
|
|
||||||
TEST_CHECK(template->blocks.arr[1].type == ltm_template_block_type_loop);
|
TEST_CHECK(template->blocks.arr[1].type == ltm_template_block_type_nested);
|
||||||
ltm_template *loop_template = template->blocks.arr[1].data.ptr;
|
ltm_template *nested_template = template->blocks.arr[1].data.ptr;
|
||||||
|
|
||||||
TEST_CHECK(loop_template->blocks.len == 3);
|
TEST_CHECK(nested_template->blocks.len == 3);
|
||||||
TEST_CHECK(loop_template->blocks.arr[0].type == ltm_template_block_type_literal);
|
TEST_CHECK(nested_template->blocks.arr[0].type == ltm_template_block_type_literal);
|
||||||
TEST_CHECK(loop_template->blocks.arr[0].data.ptr == s + 17);
|
TEST_CHECK(nested_template->blocks.arr[0].data.ptr == s + 17);
|
||||||
TEST_CHECK(loop_template->blocks.arr[0].data.len == 13);
|
TEST_CHECK(nested_template->blocks.arr[0].data.len == 13);
|
||||||
TEST_CHECK(loop_template->blocks.arr[1].type == ltm_template_block_type_var);
|
TEST_CHECK(nested_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(nested_template->blocks.arr[2].type == ltm_template_block_type_literal);
|
||||||
TEST_CHECK(loop_template->blocks.arr[2].data.ptr == s + 39);
|
TEST_CHECK(nested_template->blocks.arr[2].data.ptr == s + 39);
|
||||||
TEST_CHECK(loop_template->blocks.arr[2].data.len == 1);
|
TEST_CHECK(nested_template->blocks.arr[2].data.len == 1);
|
||||||
|
|
||||||
TEST_CHECK(loop_template->names.len == 1);
|
TEST_CHECK(nested_template->names.len == 1);
|
||||||
TEST_CHECK(loop_template->names.arr[0].name.s == s + 33);
|
TEST_CHECK(nested_template->names.arr[0].name.s == s + 33);
|
||||||
TEST_CHECK(loop_template->names.arr[0].name.len == 3);
|
TEST_CHECK(nested_template->names.arr[0].name.len == 3);
|
||||||
TEST_CHECK(loop_template->names.arr[0].index == 1);
|
TEST_CHECK(nested_template->names.arr[0].index == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_unclosed_placeholder() {
|
void test_unclosed_placeholder() {
|
||||||
|
@ -95,7 +95,7 @@ void test_unclosed_placeholder() {
|
||||||
TEST_CHECK(ltm_template_compile(&template, s) == ltm_err_invalid_template);
|
TEST_CHECK(ltm_template_compile(&template, s) == ltm_err_invalid_template);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_unclosed_loop() {
|
void test_unclosed_nested() {
|
||||||
ltm_template *template;
|
ltm_template *template;
|
||||||
|
|
||||||
const char *s = "abc {{ var start }} {{ hello }}";
|
const char *s = "abc {{ var start }} {{ hello }}";
|
||||||
|
@ -105,8 +105,8 @@ void test_unclosed_loop() {
|
||||||
TEST_LIST = {
|
TEST_LIST = {
|
||||||
{ "template single placeholder", test_single_placeholder },
|
{ "template single placeholder", test_single_placeholder },
|
||||||
{ "template single placeholder trailing", test_single_placeholder_trailing },
|
{ "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 placeholder", test_unclosed_placeholder },
|
||||||
{ "template unclosed loop", test_unclosed_loop },
|
{ "template unclosed nested", test_unclosed_nested },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue