fix: hectic C: template parse sections
This commit is contained in:
@@ -1390,6 +1390,7 @@ static Json *json_parse_value__(POSITION_INFO_DECLARATION, const char **s, Arena
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// FIXME(yukkop): **s changes in the function. Need to fix.
|
||||
Json *json_parse__(POSITION_INFO_DECLARATION, Arena *arena, const char **s) {
|
||||
// Function entry logging with DEBUG level
|
||||
raise_message(LOG_LEVEL_DEBUG, POSITION_INFO,
|
||||
@@ -1508,7 +1509,7 @@ char *json_to_string_with_opts__(POSITION_INFO_DECLARATION, Arena *arena, const
|
||||
"FORMAT: Processing JSON array elements");
|
||||
|
||||
while (child) {
|
||||
char *child_str = json_to_string_with_opts__(file, func, line, arena, child, raw);
|
||||
char *child_str = json_to_string_with_opts__(POSITION_INFO, arena, child, raw);
|
||||
if (child_str) {
|
||||
ptr += sprintf(ptr, "%s", child_str);
|
||||
} else {
|
||||
@@ -2390,7 +2391,7 @@ TemplateNode new_template_node__(TemplateNodeType type, TemplateValue *value) {
|
||||
return node;
|
||||
}
|
||||
|
||||
TemplateResult template_parse__(POSITION_INFO_DECLARATION, Arena *arena, const char **s, const TemplateConfig *config);
|
||||
TemplateResult template_parse__(POSITION_INFO_DECLARATION, Arena *arena, const char **s, const TemplateConfig *config, bool inner_parse);
|
||||
|
||||
TemplateResult template_parse_interpolation__(POSITION_INFO_DECLARATION, Arena *arena, const char **s_ptr, const TemplateConfig *config) {
|
||||
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "PARSE: Interpolation");
|
||||
@@ -2443,10 +2444,9 @@ TemplateResult template_parse_section__(POSITION_INFO_DECLARATION, Arena *arena,
|
||||
const char *iterator_start = *s;
|
||||
|
||||
while (**s != '\0') {
|
||||
if (**s == ' ' || **s == '\n' || **s == '\t' || strncmp(*s, config->Syntax.Section.source->data, config->Syntax.Section.source->len) == 0) break;
|
||||
TEMPLATE_ASSERT_SYNTAX(config->Syntax.Braces.close->data, "Unexpected section end", TEMPLATE_ERROR_UNEXPECTED_SECTION_END);
|
||||
if (isspace(**s) || strncmp(*s, config->Syntax.Section.source->data, config->Syntax.Section.source->len) == 0) break;
|
||||
TEMPLATE_ASSERT_SYNTAX(config->Syntax.Braces.open->data, "Nested tag in section element name", TEMPLATE_ERROR_NESTED_SECTION_ITERATOR);
|
||||
|
||||
TEMPLATE_ASSERT_SYNTAX(config->Syntax.Braces.close->data, "Unexpected section end", TEMPLATE_ERROR_UNEXPECTED_SECTION_END);
|
||||
(*s)++;
|
||||
}
|
||||
|
||||
@@ -2455,27 +2455,37 @@ TemplateResult template_parse_section__(POSITION_INFO_DECLARATION, Arena *arena,
|
||||
|
||||
// Find the collection name
|
||||
*s = skip_whitespace(*s);
|
||||
*s += config->Syntax.Section.source->len;
|
||||
*s = skip_whitespace(*s);
|
||||
const char *collection_start = *s;
|
||||
|
||||
while (**s != '\0') {
|
||||
if (**s == ' ' || **s == '\n' || **s == '\t' || strncmp(*s, config->Syntax.Section.begin->data, config->Syntax.Section.begin->len) == 0) break;
|
||||
if (isspace(**s) || strncmp(*s, config->Syntax.Section.begin->data, config->Syntax.Section.begin->len) == 0) break;
|
||||
TEMPLATE_ASSERT_SYNTAX(config->Syntax.Braces.open->data, "Nested tag in section collection", TEMPLATE_ERROR_NESTED_SECTION_ITERATOR);
|
||||
TEMPLATE_ASSERT_SYNTAX(config->Syntax.Braces.close->data, "Unexpected section end", TEMPLATE_ERROR_UNEXPECTED_SECTION_END);
|
||||
TEMPLATE_ASSERT_SYNTAX(config->Syntax.Braces.open->data, "Nested tag in section iterator", TEMPLATE_ERROR_NESTED_SECTION_ITERATOR);
|
||||
|
||||
(*s)++;
|
||||
}
|
||||
|
||||
size_t collection_len = *s - collection_start;
|
||||
result.Result.some->value->section.collection = arena_strncpy__(POSITION_INFO, arena, collection_start, collection_len);
|
||||
|
||||
// Skip to the body
|
||||
*s = skip_whitespace(*s);
|
||||
|
||||
// Parse the body
|
||||
TemplateResult body_result = template_parse__(POSITION_INFO, arena, s, config);
|
||||
TemplateResult body_result = template_parse__(POSITION_INFO, arena, s, config, true);
|
||||
if (body_result.type == RESULT_ERROR) {
|
||||
return body_result;
|
||||
}
|
||||
|
||||
result.Result.some->value->section.body = body_result.Result.some;
|
||||
|
||||
// Skip to the end of the section
|
||||
*s = skip_whitespace(*s);
|
||||
if (strncmp(*s, config->Syntax.Braces.close->data, config->Syntax.Braces.close->len) != 0) {
|
||||
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "PARSE: Expected section end");
|
||||
return RESULT_ERROR(TemplateResult, TEMPLATE_ERROR_UNEXPECTED_SECTION_END, "Expected section end");
|
||||
}
|
||||
*s_ptr = *s + config->Syntax.Braces.close->len;
|
||||
|
||||
return result;
|
||||
@@ -2497,15 +2507,20 @@ TemplateResult template_parse_include__(POSITION_INFO_DECLARATION, Arena *arena,
|
||||
const char *include_start = *s;
|
||||
|
||||
while (**s != '\0') {
|
||||
if (**s == ' ' || **s == '\n' || **s == '\t' || strncmp(*s, config->Syntax.Braces.close->data, config->Syntax.Braces.close->len) == 0) break;
|
||||
if (isspace(**s) || strncmp(*s, config->Syntax.Braces.close->data, config->Syntax.Braces.close->len) == 0) break;
|
||||
TEMPLATE_ASSERT_SYNTAX(config->Syntax.Braces.open->data, "Nested tag in include", TEMPLATE_ERROR_NESTED_INCLUDE);
|
||||
|
||||
(*s)++;
|
||||
}
|
||||
|
||||
size_t include_len = *s - include_start;
|
||||
result.Result.some->value->include.key = arena_strncpy__(POSITION_INFO, arena, include_start, include_len);
|
||||
|
||||
// Skip to the end of the include
|
||||
*s = skip_whitespace(*s);
|
||||
if (strncmp(*s, config->Syntax.Braces.close->data, config->Syntax.Braces.close->len) != 0) {
|
||||
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "PARSE: Expected include end");
|
||||
return RESULT_ERROR(TemplateResult, TEMPLATE_ERROR_UNEXPECTED_INCLUDE_END, "Expected include end");
|
||||
}
|
||||
*s_ptr = *s + config->Syntax.Braces.close->len;
|
||||
|
||||
return result;
|
||||
@@ -2518,6 +2533,7 @@ TemplateResult template_parse_execute__(POSITION_INFO_DECLARATION, Arena *arena,
|
||||
|
||||
const char **s = s_ptr;
|
||||
|
||||
// Skip to the content of the execute
|
||||
*s += config->Syntax.Braces.open->len;
|
||||
*s = skip_whitespace(*s);
|
||||
*s += config->Syntax.Execute.invoke->len;
|
||||
@@ -2525,7 +2541,9 @@ TemplateResult template_parse_execute__(POSITION_INFO_DECLARATION, Arena *arena,
|
||||
*s = skip_whitespace(*s);
|
||||
const char *code_start = *s;
|
||||
|
||||
while (strncmp(*s, config->Syntax.Braces.close->data, config->Syntax.Braces.close->len) == 0) {
|
||||
// Find the end of the code
|
||||
while (**s != '\0') {
|
||||
if (strncmp(*s, config->Syntax.Braces.close->data, config->Syntax.Braces.close->len) == 0) break;
|
||||
TEMPLATE_ASSERT_SYNTAX(config->Syntax.Braces.open->data, "Nested tag in execute", TEMPLATE_ERROR_NESTED_EXECUTE);
|
||||
(*s)++;
|
||||
}
|
||||
@@ -2533,12 +2551,17 @@ TemplateResult template_parse_execute__(POSITION_INFO_DECLARATION, Arena *arena,
|
||||
size_t code_len = *s - code_start;
|
||||
result.Result.some->value->execute.code = arena_strncpy__(POSITION_INFO, arena, code_start, code_len);
|
||||
|
||||
// Skip to the end of the execute
|
||||
if (strncmp(*s, config->Syntax.Braces.close->data, config->Syntax.Braces.close->len) != 0) {
|
||||
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "PARSE: Expected execute end");
|
||||
return RESULT_ERROR(TemplateResult, TEMPLATE_ERROR_UNEXPECTED_EXECUTE_END, "Expected execute end");
|
||||
}
|
||||
*s_ptr = *s + config->Syntax.Braces.close->len;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
TemplateResult template_parse__(POSITION_INFO_DECLARATION, Arena *arena, const char **s, const TemplateConfig *config) {
|
||||
TemplateResult template_parse__(POSITION_INFO_DECLARATION, Arena *arena, const char **s, const TemplateConfig *config, bool inner_parse) {
|
||||
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "PARSE: Iteration start");
|
||||
|
||||
if (!template_validate_config__(POSITION_INFO, config)) {
|
||||
@@ -2561,7 +2584,13 @@ TemplateResult template_parse__(POSITION_INFO_DECLARATION, Arena *arena, const c
|
||||
|
||||
int open_brace_len = config->Syntax.Braces.open->len;
|
||||
|
||||
|
||||
while (*s && **s != '\0') {
|
||||
// Check for closing brace if this is inner parse
|
||||
if (inner_parse && strncmp(*s, config->Syntax.Braces.close->data, config->Syntax.Braces.close->len) == 0) {
|
||||
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "PARSE: Found closing brace in inner parse");
|
||||
break;
|
||||
}
|
||||
if (strncmp(*s, config->Syntax.Braces.open->data, open_brace_len) == 0) {
|
||||
if (start != *s) {
|
||||
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "PARSE: Text node: %s", arena_strncpy__(POSITION_INFO, DISPOSABLE_ARENA, start, *s - start));
|
||||
@@ -2796,7 +2825,7 @@ char *template_node_to_json_str__(POSITION_INFO_DECLARATION, Arena *arena, const
|
||||
node->value->section.collection);
|
||||
char *body_str = template_node_to_json_str__(POSITION_INFO, arena, node->value->section.body, depth + 1);
|
||||
if (body_str) {
|
||||
APPEND(",\"body\":%s", body_str);
|
||||
APPEND(",\"body\":[%s]", body_str);
|
||||
}
|
||||
break;
|
||||
case TEMPLATE_NODE_INTERPOLATE:
|
||||
|
||||
@@ -97,22 +97,24 @@ void set_output_color_mode(ColorMode mode);
|
||||
|
||||
typedef enum {
|
||||
HECTIC_ERROR_NONE = 0,
|
||||
TEMPLATE_ERROR_NONE = 985567,
|
||||
TEMPLATE_ERROR_UNKNOWN_TAG = 985568,
|
||||
TEMPLATE_ERROR_NESTED_INTERPOLATION = 985569,
|
||||
TEMPLATE_ERROR_NESTED_SECTION_ITERATOR = 985570,
|
||||
TEMPLATE_ERROR_UNEXPECTED_SECTION_END = 985571,
|
||||
TEMPLATE_ERROR_NESTED_INCLUDE = 985572,
|
||||
TEMPLATE_ERROR_NESTED_EXECUTE = 985573,
|
||||
TEMPLATE_ERROR_INVALID_CONFIG = 985574,
|
||||
TEMPLATE_ERROR_OUT_OF_MEMORY = 985575,
|
||||
LOGGER_ERROR_INVALID_RULES_STRING = 985576,
|
||||
LOGGER_ERROR_OUT_OF_MEMORY = 985577,
|
||||
DEBUG_TO_JSON_PARSE_NO_EQUAL_SIGN_ERROR = 985578,
|
||||
DEBUG_TO_JSON_PARSE_NO_STRUCT_NAME_ERROR = 985579,
|
||||
DEBUG_TO_JSON_PARSE_LEFT_OPERAND_ERROR = 985580,
|
||||
DEBUG_TO_JSON_PARSE_NO_START_ERROR = 985581,
|
||||
DEBUG_TO_JSON_PARSE_NO_END_ERROR = 985582,
|
||||
TEMPLATE_ERROR_NONE = 900000,
|
||||
TEMPLATE_ERROR_UNKNOWN_TAG = 900001,
|
||||
TEMPLATE_ERROR_NESTED_INTERPOLATION = 900002,
|
||||
TEMPLATE_ERROR_NESTED_SECTION_ITERATOR = 900003,
|
||||
TEMPLATE_ERROR_UNEXPECTED_SECTION_END = 900004,
|
||||
TEMPLATE_ERROR_NESTED_INCLUDE = 900005,
|
||||
TEMPLATE_ERROR_NESTED_EXECUTE = 900006,
|
||||
TEMPLATE_ERROR_INVALID_CONFIG = 900007,
|
||||
TEMPLATE_ERROR_OUT_OF_MEMORY = 900008,
|
||||
TEMPLATE_ERROR_UNEXPECTED_INCLUDE_END = 900009,
|
||||
TEMPLATE_ERROR_UNEXPECTED_EXECUTE_END = 900010,
|
||||
LOGGER_ERROR_INVALID_RULES_STRING = 800001,
|
||||
LOGGER_ERROR_OUT_OF_MEMORY = 800002,
|
||||
DEBUG_TO_JSON_PARSE_NO_EQUAL_SIGN_ERROR = 700003,
|
||||
DEBUG_TO_JSON_PARSE_NO_STRUCT_NAME_ERROR = 700004,
|
||||
DEBUG_TO_JSON_PARSE_LEFT_OPERAND_ERROR = 700005,
|
||||
DEBUG_TO_JSON_PARSE_NO_START_ERROR = 700006,
|
||||
DEBUG_TO_JSON_PARSE_NO_END_ERROR = 700007,
|
||||
} HecticErrorCode;
|
||||
|
||||
// Define color macros based on output type
|
||||
@@ -814,7 +816,7 @@ struct TemplateNode {
|
||||
|
||||
RESULT(Template, TemplateNode);
|
||||
|
||||
TemplateResult template_parse__(const char *file, const char *func, int line, Arena *arena, const char **s, const TemplateConfig *config);
|
||||
TemplateResult template_parse__(const char *file, const char *func, int line, Arena *arena, const char **s, const TemplateConfig *config, bool inner_parse);
|
||||
|
||||
TemplateConfig template_default_config__(const char *file, const char *func, int line, Arena *arena);
|
||||
|
||||
@@ -822,7 +824,7 @@ char *template_node_to_debug_str__(const char *file, const char *func, int line,
|
||||
|
||||
char *template_node_to_json_str__(const char *file, const char *func, int line, Arena *arena, const TemplateNode *node, int depth);
|
||||
|
||||
#define template_parse(arena, s, config) template_parse__(__FILE__, __func__, __LINE__, arena, s, config)
|
||||
#define template_parse(arena, s, config) template_parse__(__FILE__, __func__, __LINE__, arena, s, config, false)
|
||||
|
||||
#define template_default_config(arena) template_default_config__(__FILE__, __func__, __LINE__, arena)
|
||||
|
||||
|
||||
@@ -151,12 +151,24 @@ static void simplest_test_template_parse(Arena *arena, TemplateConfig *config) {
|
||||
|
||||
TemplateNode node = RESULT_SOME_VALUE(template_result);
|
||||
|
||||
char *result_str;
|
||||
{ // some debug output
|
||||
Arena *debug_arena = DISPOSABLE_ARENA;
|
||||
const char *json_str = TEMPLATE_NODE_TO_JSON_STR(debug_arena, &node);
|
||||
Json *json = json_parse(debug_arena, &json_str);
|
||||
raise_notice("json_str: \n%s", JSON_TO_PRETTY_STR(debug_arena, json));
|
||||
result_str = arena_strdup(arena, JSON_TO_PRETTY_STR(debug_arena, json));
|
||||
}
|
||||
|
||||
assert(strcmp(result_str,
|
||||
"[\n"
|
||||
" {\n"
|
||||
" \"type\": \"TEXT\",\n"
|
||||
" \"content\": {\n"
|
||||
" \"content\": \"{{ name }}\"\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"]") == 0);
|
||||
}
|
||||
|
||||
static void simplest_interpolation_test_template_parse(Arena *arena, TemplateConfig *config) {
|
||||
@@ -171,12 +183,62 @@ static void simplest_interpolation_test_template_parse(Arena *arena, TemplateCon
|
||||
|
||||
TemplateNode node = RESULT_SOME_VALUE(template_result);
|
||||
|
||||
char *result_str;
|
||||
{ // some debug output
|
||||
Arena *debug_arena = DISPOSABLE_ARENA;
|
||||
const char *json_str = TEMPLATE_NODE_TO_JSON_STR(debug_arena, &node);
|
||||
Json *json = json_parse(debug_arena, &json_str);
|
||||
raise_log("json_str: \n%s", json_str);
|
||||
raise_notice("json_str: \n%s", JSON_TO_PRETTY_STR(debug_arena, json));
|
||||
result_str = arena_strdup(arena, JSON_TO_PRETTY_STR(debug_arena, json));
|
||||
}
|
||||
|
||||
assert(strcmp(result_str,
|
||||
"[\n"
|
||||
" {\n"
|
||||
" \"type\": \"INTERPOLATE\",\n"
|
||||
" \"content\": {\n"
|
||||
" \"key\": \"name\"\n"
|
||||
" }\n"
|
||||
" },\n"
|
||||
" {\n"
|
||||
" \"type\": \"TEXT\",\n"
|
||||
" \"content\": {\n"
|
||||
" \"content\": \" \"\n"
|
||||
" }\n"
|
||||
" },\n"
|
||||
" {\n"
|
||||
" \"type\": \"INTERPOLATE\",\n"
|
||||
" \"content\": {\n"
|
||||
" \"key\": \"name2\"\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"]") == 0);
|
||||
}
|
||||
|
||||
static void simplest_separator_test_template_parse(Arena *arena, TemplateConfig *config) {
|
||||
const char *template_str = "{%"
|
||||
" for item in items"
|
||||
" {% name %} {% item.name %}"
|
||||
" %}"
|
||||
""
|
||||
" {% name2 %}";
|
||||
|
||||
TemplateResult template_result = template_parse(arena, &template_str, config);
|
||||
|
||||
if (IS_RESULT_ERROR(template_result)) {
|
||||
raise_exception("template_parse failed");
|
||||
return;
|
||||
}
|
||||
|
||||
TemplateNode node = RESULT_SOME_VALUE(template_result);
|
||||
|
||||
{ // some debug output
|
||||
Arena *debug_arena = DISPOSABLE_ARENA;
|
||||
const char *json_str = TEMPLATE_NODE_TO_JSON_STR(debug_arena, &node);
|
||||
raise_log("json_str: \n%s", json_str);
|
||||
Json *json = json_parse(debug_arena, &json_str);
|
||||
raise_notice("json_str: \n%s", JSON_TO_PRETTY_STR(debug_arena, json));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,6 +270,10 @@ int main(void) {
|
||||
printf("%sTest 3: simplest_interpolation_test_template_parse passed%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_RESET));
|
||||
arena_reset(&arena);
|
||||
|
||||
simplest_separator_test_template_parse(&arena, &config);
|
||||
printf("%sTest 4: simplest_separator_test_template_parse passed%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_RESET));
|
||||
arena_reset(&arena);
|
||||
|
||||
logger_free();
|
||||
arena_free(&config_arena);
|
||||
arena_free(&arena);
|
||||
|
||||
Reference in New Issue
Block a user