feat(ltm): some more work on the parser
parent
95788f22e3
commit
0bc8fc8273
|
@ -19,8 +19,8 @@
|
||||||
|
|
||||||
typedef enum ltm_err {
|
typedef enum ltm_err {
|
||||||
ltm_err_ok = 0,
|
ltm_err_ok = 0,
|
||||||
ltm_invalid_template,
|
ltm_err_invalid_template,
|
||||||
ltm_failed_alloc,
|
ltm_err_failed_alloc,
|
||||||
} ltm_err;
|
} ltm_err;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -25,6 +25,7 @@ ltm_err ltm_template_compile(ltm_template **out, const char *template);
|
||||||
* @param template char buffer containing the template
|
* @param template char buffer containing the template
|
||||||
* @param len length of the char buffer
|
* @param len length of the char buffer
|
||||||
*/
|
*/
|
||||||
ltm_err ltm_template_compile_n(ltm_template **out, const char *template, size_t len);
|
ltm_err ltm_template_compile_n(ltm_template **out, const char *template,
|
||||||
|
size_t len);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
#include "ltm/template.h"
|
#include "ltm/template.h"
|
||||||
|
|
||||||
typedef enum ltm_placeholder_type {
|
typedef enum ltm_placeholder_type {
|
||||||
ltm_placeholder_type_var = 0,
|
ltm_placeholder_type_invalid = 0,
|
||||||
|
ltm_placeholder_type_var,
|
||||||
ltm_placeholder_type_loop_start,
|
ltm_placeholder_type_loop_start,
|
||||||
ltm_placeholder_type_loop_end,
|
ltm_placeholder_type_loop_end,
|
||||||
} ltm_placeholder_type;
|
} ltm_placeholder_type;
|
||||||
|
@ -15,7 +16,10 @@ typedef enum ltm_placeholder_type {
|
||||||
typedef struct ltm_placeholder {
|
typedef struct ltm_placeholder {
|
||||||
const char *start;
|
const char *start;
|
||||||
const char *end;
|
const char *end;
|
||||||
const char *name;
|
struct {
|
||||||
|
const char *s;
|
||||||
|
size_t len;
|
||||||
|
} name;
|
||||||
ltm_placeholder_type type;
|
ltm_placeholder_type type;
|
||||||
} ltm_placeholder;
|
} ltm_placeholder;
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "ltm/common.h"
|
#include "ltm/common.h"
|
||||||
|
@ -8,7 +9,7 @@ ltm_err ltm_template_init(ltm_template **out) {
|
||||||
ltm_template *template = calloc(1, sizeof(ltm_template));
|
ltm_template *template = calloc(1, sizeof(ltm_template));
|
||||||
|
|
||||||
if (template == NULL) {
|
if (template == NULL) {
|
||||||
return ltm_failed_alloc;
|
return ltm_err_failed_alloc;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out = template;
|
*out = template;
|
||||||
|
@ -16,7 +17,8 @@ ltm_err ltm_template_init(ltm_template **out) {
|
||||||
return ltm_err_ok;
|
return ltm_err_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
ltm_err ltm_template_next_placeholder(ltm_placeholder *ph, const char *s, size_t len) {
|
bool ltm_template_next_placeholder(ltm_placeholder *ph, const char *s,
|
||||||
|
size_t len) {
|
||||||
ph->start = memchr(s, '{', len - 1);
|
ph->start = memchr(s, '{', len - 1);
|
||||||
|
|
||||||
if ((ph->start != NULL) && (ph->start[1] == '{')) {
|
if ((ph->start != NULL) && (ph->start[1] == '{')) {
|
||||||
|
@ -26,62 +28,119 @@ ltm_err ltm_template_next_placeholder(ltm_placeholder *ph, const char *s, size_t
|
||||||
|
|
||||||
// Non-terminated placeholders aren't valid
|
// Non-terminated placeholders aren't valid
|
||||||
if ((ph->end == NULL) || (ph->end[1] != '}')) {
|
if ((ph->end == NULL) || (ph->end[1] != '}')) {
|
||||||
return ltm_invalid_template;
|
ph->type = ltm_placeholder_type_invalid;
|
||||||
}
|
|
||||||
} else {
|
return true;
|
||||||
ph->end = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ltm_err_ok;
|
// End should point to final character
|
||||||
|
ph->end++;
|
||||||
|
|
||||||
|
// Parse the words
|
||||||
|
ph->name.s = ph->start + 2;
|
||||||
|
|
||||||
|
while ((*ph->name.s == ' ') && (ph->name.s != ph->end - 1)) {
|
||||||
|
ph->name.s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Placeholder is empty
|
||||||
|
if (ph->name.s == ph->end - 1) {
|
||||||
|
ph->type = ltm_placeholder_type_invalid;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *ident = ph->name.s;
|
||||||
|
|
||||||
|
while ((*ident != ' ') && (ident != ph->end - 1)) {
|
||||||
|
ident++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ph->name.len = ident - ph->name.s;
|
||||||
|
|
||||||
|
while ((*ident == ' ') && (ident != ph->end - 1)) {
|
||||||
|
ident++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ident == ph->end - 1) {
|
||||||
|
ph->type = ltm_placeholder_type_var;
|
||||||
|
} else {
|
||||||
|
// Further parse the identifier
|
||||||
|
const char *temp = ident;
|
||||||
|
|
||||||
|
while ((*temp != ' ') && (temp != ph->end - 1)) {
|
||||||
|
temp++;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ident_len = temp - ident;
|
||||||
|
|
||||||
|
if (strncmp("loop", ident, ident_len) == 0) {
|
||||||
|
ph->type = ltm_placeholder_type_loop_start;
|
||||||
|
} else if (strncmp("end", ident, ident_len) == 0) {
|
||||||
|
ph->type = ltm_placeholder_type_loop_end;
|
||||||
|
} else {
|
||||||
|
ph->type = ltm_placeholder_type_invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ltm_err ltm_template_compile_n(ltm_template **out, const char *s, size_t len) {
|
ltm_err ltm_template_compile_n(ltm_template **out, const char *s, size_t len) {
|
||||||
ltm_template *template;
|
ltm_template *template;
|
||||||
LTM_RES(ltm_template_init(&template));
|
LTM_RES(ltm_template_init(&template));
|
||||||
|
|
||||||
const char *start, *end;
|
ltm_placeholder ph;
|
||||||
|
bool in_loop = false;
|
||||||
|
const char *loop_start = NULL;
|
||||||
|
size_t loop_depth = 0;
|
||||||
|
size_t cur_loop_depth = 0;
|
||||||
|
|
||||||
while (((start = memchr(s, '{', len - 1)) != NULL) && (start[1] == '{')) {
|
// TODO to ensure the loops are balanced, we should count how many loop starts
|
||||||
size_t new_len = len - (start - s);
|
// we have seen and only match a loop end if the number matches; this way, we
|
||||||
|
// can allow arbitrarily nested loops
|
||||||
|
|
||||||
// Non-terminated placeholders aren't valid
|
while (ltm_template_next_placeholder(&ph, s, len)) {
|
||||||
if (((end = memchr(start + 2, '}', new_len - 3)) == NULL) || (end[1] != '}')) {
|
switch (ph.type) {
|
||||||
return ltm_invalid_template;
|
case ltm_placeholder_type_invalid:
|
||||||
|
return ltm_err_invalid_template;
|
||||||
|
case ltm_placeholder_type_var:
|
||||||
|
// TODO add var block
|
||||||
|
break;
|
||||||
|
case ltm_placeholder_type_loop_start:
|
||||||
|
if (!in_loop) {
|
||||||
|
loop_start = ph.end + 1;
|
||||||
|
in_loop = true;
|
||||||
|
loop_depth = cur_loop_depth;
|
||||||
|
}
|
||||||
|
cur_loop_depth++;
|
||||||
|
break;
|
||||||
|
case ltm_placeholder_type_loop_end:
|
||||||
|
cur_loop_depth--;
|
||||||
|
|
||||||
|
if (in_loop && (cur_loop_depth == loop_depth)) {
|
||||||
|
size_t loop_len = ph.end - loop_start;
|
||||||
|
// TODO recursive call to compile
|
||||||
|
|
||||||
|
in_loop = false;
|
||||||
|
}
|
||||||
|
// We encountered a loop end without a start
|
||||||
|
else {
|
||||||
|
return ltm_err_invalid_template;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO actually parse placeholders
|
len -= ph.end + 1 - ph.start;
|
||||||
const char *word = start + 2;
|
s = ph.end + 1;
|
||||||
|
|
||||||
while ((*word == ' ') && (word != end)) {
|
|
||||||
word++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The placeholder is empty
|
// Unfinished loop
|
||||||
if (word == end) {
|
if (in_loop) {
|
||||||
return ltm_invalid_template;
|
return ltm_err_invalid_template;
|
||||||
}
|
|
||||||
|
|
||||||
const char *word2 = word;
|
|
||||||
|
|
||||||
while ((*word2 != ' ') && (word2 != end)) {
|
|
||||||
word2++;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t word_len = word2 - word;
|
|
||||||
|
|
||||||
if (word2 != end) {
|
|
||||||
while ((*word2 == ' ') && (word2 != end)) {
|
|
||||||
word2++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only one word, so it's a variable
|
|
||||||
if (word2 == end) {
|
|
||||||
// TODO register variable block
|
|
||||||
}
|
|
||||||
|
|
||||||
len = len - (end + 2 - s);
|
|
||||||
s = end + 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ltm_err_ok;
|
return ltm_err_ok;
|
||||||
|
|
Loading…
Reference in New Issue