aboutsummaryrefslogtreecommitdiffstats
path: root/src/mds-kbdc/compile-layout.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/mds-kbdc/compile-layout.c3745
1 files changed, 1855 insertions, 1890 deletions
diff --git a/src/mds-kbdc/compile-layout.c b/src/mds-kbdc/compile-layout.c
index 199e870..8eb832b 100644
--- a/src/mds-kbdc/compile-layout.c
+++ b/src/mds-kbdc/compile-layout.c
@@ -34,12 +34,12 @@
/**
* This process's value for `mds_kbdc_tree_t.processed`
*/
-#define PROCESS_LEVEL 6
+#define PROCESS_LEVEL 6
/**
* Tree type constant shortener
*/
-#define C(TYPE) MDS_KBDC_TREE_TYPE_##TYPE
+#define C(TYPE) MDS_KBDC_TREE_TYPE_##TYPE
/**
* Add an error with “included from here”-notes and, unless
@@ -50,36 +50,34 @@
* @param ...:const char*, ... Error description format string and arguments
* @scope error:mds_kbdc_parse_error_t* Variable where the new error will be stored
*/
-#define NEW_ERROR(NODE, SEVERITY, ...) \
- do \
- { \
- NEW_ERROR_WITH_INCLUDES(NODE, includes_ptr, SEVERITY, __VA_ARGS__); \
- if (strcmp(#SEVERITY, "NOTE")) \
- DUMP_CALL_STACK; \
- } \
- while (0)
+#define NEW_ERROR(NODE, SEVERITY, ...)\
+ do {\
+ NEW_ERROR_WITH_INCLUDES(NODE, includes_ptr, SEVERITY, __VA_ARGS__);\
+ if (strcmp(#SEVERITY, "NOTE"))\
+ DUMP_CALL_STACK;\
+ } while (0)
/**
* Beginning of failure clause
*/
-#define FAIL_BEGIN fail: saved_errno = errno
+#define FAIL_BEGIN fail: saved_errno = errno
/**
* End of failure clause
*/
-#define FAIL_END return errno = saved_errno, -1
+#define FAIL_END return errno = saved_errno, -1
/**
* Variable whether the latest created error is stored
*/
-static mds_kbdc_parse_error_t* error;
+static mds_kbdc_parse_error_t *error;
/**
* The parameter of `compile_layout`
*/
-static mds_kbdc_parsed_t* restrict result;
+static mds_kbdc_parsed_t *restrict result;
/**
* 3: `return` is being processed
@@ -101,12 +99,12 @@ static int multiple_variants = 0;
*
* (We will not look too hard.)
*/
-static mds_kbdc_tree_t* last_value_statement = NULL;
+static mds_kbdc_tree_t *last_value_statement = NULL;
/**
* Address of the current return value
*/
-static char32_t** current_return_value = NULL;
+static char32_t **current_return_value = NULL;
/**
* Whether ‘\set/3’ has been called
@@ -121,7 +119,7 @@ static int have_side_effect = 0;
* @param tree The tree to compile
* @return Zero on success, -1 on error
*/
-static int compile_subtree(mds_kbdc_tree_t* restrict tree);
+static int compile_subtree(mds_kbdc_tree_t *restrict tree);
/**
* Check that a function used in a part of a literal is defined
@@ -133,8 +131,8 @@ static int compile_subtree(mds_kbdc_tree_t* restrict tree);
* @param rc Success status output parameter: zero on success,
* -1 on error, 1 if an undefined function is used
*/
-static void check_function_call(const mds_kbdc_tree_t* restrict tree, const char* restrict raw,
- size_t lineoff, const char* restrict* restrict end, int* restrict rc);
+static void check_function_call(const mds_kbdc_tree_t *restrict tree, const char *restrict raw,
+ size_t lineoff, const char *restrict *restrict end, int *restrict rc);
/**
* Parse an argument in a function call
@@ -146,8 +144,8 @@ static void check_function_call(const mds_kbdc_tree_t* restrict tree, const char
* @param value Output parameter for the value to which the argument evaulates
* @return Zero on success, -1 on error
*/
-static int parse_function_argument(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff,
- const char* restrict* restrict end, char32_t** restrict value);
+static int parse_function_argument(mds_kbdc_tree_t *restrict tree, const char *restrict raw, size_t lineoff,
+ const char *restrict *restrict end, char32_t **restrict value);
@@ -167,37 +165,36 @@ static int parse_function_argument(mds_kbdc_tree_t* restrict tree, const char* r
* but could easily be mistaked for one that does
* @return Zero on success, -1 on error
*/
-static int let(size_t variable, const char32_t* restrict string, const mds_kbdc_tree_t* restrict value,
- mds_kbdc_tree_t* restrict statement, size_t lineoff, int possibile_shadow_attempt)
+static int
+let(size_t variable, const char32_t *restrict string, const mds_kbdc_tree_t *restrict value,
+ mds_kbdc_tree_t *restrict statement, size_t lineoff, int possibile_shadow_attempt)
{
- mds_kbdc_tree_t* tree = NULL;
- int saved_errno;
-
- /* Warn if this is a possible shadow attempt. */
- if (possibile_shadow_attempt && variables_let_will_override(variable) && statement &&
- (variables_has_been_used_in_for(variable) == 0) && (statement->processed != PROCESS_LEVEL))
- {
- statement->processed = PROCESS_LEVEL;
- NEW_ERROR(statement, WARNING, "does not shadow existing definition");
- error->start = lineoff;
- error->end = lineoff + (size_t)snprintf(NULL, 0, "\\%zu", variable);
- }
-
- /* Duplicate value. */
- if (value)
- fail_if (tree = mds_kbdc_tree_dup(value), tree == NULL);
- if (value == NULL)
- {
- fail_if (tree = mds_kbdc_tree_create(C(COMPILED_STRING)), tree == NULL);
- fail_if ((tree->compiled_string.string = string_dup(string)) == NULL);
- }
-
- /* Assign variable. */
- fail_if (variables_let(variable, tree));
- return 0;
- FAIL_BEGIN;
- mds_kbdc_tree_free(tree);
- FAIL_END;
+ mds_kbdc_tree_t *tree = NULL;
+ int saved_errno;
+
+ /* Warn if this is a possible shadow attempt. */
+ if (possibile_shadow_attempt && variables_let_will_override(variable) && statement &&
+ !variables_has_been_used_in_for(variable) && statement->processed != PROCESS_LEVEL) {
+ statement->processed = PROCESS_LEVEL;
+ NEW_ERROR(statement, WARNING, "does not shadow existing definition");
+ error->start = lineoff;
+ error->end = lineoff + (size_t)snprintf(NULL, 0, "\\%zu", variable);
+ }
+
+ /* Duplicate value. */
+ if (value) {
+ fail_if (!(tree = mds_kbdc_tree_dup(value)));
+ } else {
+ fail_if (!(tree = mds_kbdc_tree_create(C(COMPILED_STRING))));
+ fail_if (!(tree->compiled_string.string = string_dup(string)));
+ }
+
+ /* Assign variable. */
+ fail_if (variables_let(variable, tree));
+ return 0;
+ FAIL_BEGIN;
+ mds_kbdc_tree_free(tree);
+ FAIL_END;
}
@@ -212,48 +209,47 @@ static int let(size_t variable, const char32_t* restrict string, const mds_kbdc_
* @param end The offset on the line where the function call ends
* @return Zero on success, -1 on error, 1 if the call is invalid
*/
-static int check_set_3_get_2_call(mds_kbdc_tree_t* restrict tree, int is_set, const char32_t* variable_arg,
- const char32_t* index_arg, size_t start, size_t end)
+static int
+check_set_3_get_2_call(mds_kbdc_tree_t *restrict tree, int is_set, const char32_t *variable_arg,
+ const char32_t *index_arg, size_t start, size_t end)
{
-#define F (is_set ? "set/3" : "get/2")
-#define FUN_ERROR(...) \
- do \
- { \
- NEW_ERROR(__VA_ARGS__); \
- error->start = start; \
- error->end = end; \
- return 1; \
- } \
- while(0);
-
- mds_kbdc_tree_t* variable;
- mds_kbdc_tree_t* element;
- size_t index, arg_count;
-
- if ((variable_arg[0] <= 0) || (variable_arg[1] != -1))
- FUN_ERROR(tree, ERROR, "first argument in call to function ‘%s’ must be a variable index", F);
-
- if ((index_arg[0] < 0) || (index_arg[1] != -1))
- FUN_ERROR(tree, ERROR, "second argument in call to function ‘%s’ must be an element index", F);
-
- variable = variables_get((size_t)*variable_arg);
- if (variable == NULL)
- FUN_ERROR(tree, ERROR, "‘\\%zu’ is not declared", (size_t)*variable_arg);
- if (variable->type != C(ARRAY))
- FUN_ERROR(tree, ERROR, "‘\\%zu’ is not an array", (size_t)*variable_arg);
-
- arg_count = index = (size_t)*index_arg;
- element = variable->array.elements;
- while (element && index--)
- element = element->next;
-
- if (element == NULL)
- FUN_ERROR(tree, ERROR, "‘\\%zu’ does not hold %zu %s",
- (size_t)*variable_arg, arg_count + 1, arg_count ? "elements" : "element");
-
- return 0;
- fail:
- return -1;
+#define F (is_set ? "set/3" : "get/2")
+#define FUN_ERROR(...)\
+ do {\
+ NEW_ERROR(__VA_ARGS__);\
+ error->start = start;\
+ error->end = end;\
+ return 1;\
+ } while(0);
+
+ mds_kbdc_tree_t *variable;
+ mds_kbdc_tree_t *element;
+ size_t index, arg_count;
+
+ if (variable_arg[0] <= 0 || variable_arg[1] != -1)
+ FUN_ERROR(tree, ERROR, "first argument in call to function ‘%s’ must be a variable index", F);
+
+ if (index_arg[0] < 0 || index_arg[1] != -1)
+ FUN_ERROR(tree, ERROR, "second argument in call to function ‘%s’ must be an element index", F);
+
+ variable = variables_get((size_t)*variable_arg);
+ if (!variable)
+ FUN_ERROR(tree, ERROR, "‘\\%zu’ is not declared", (size_t)*variable_arg);
+ if (variable->type != C(ARRAY))
+ FUN_ERROR(tree, ERROR, "‘\\%zu’ is not an array", (size_t)*variable_arg);
+
+ arg_count = index = (size_t)*index_arg;
+ element = variable->array.elements;
+ while (element && index--)
+ element = element->next;
+
+ if (!element)
+ FUN_ERROR(tree, ERROR, "‘\\%zu’ does not hold %zu %s",
+ (size_t)*variable_arg, arg_count + 1, arg_count ? "elements" : "element");
+
+ return 0;
+fail:
+ return -1;
#undef FUN_ERROR
#undef F
}
@@ -274,125 +270,118 @@ static int check_set_3_get_2_call(mds_kbdc_tree_t* restrict tree, int is_set, co
* as containing an error
* @return Zero on success, -1 on error
*/
-static int call_function(mds_kbdc_tree_t* restrict tree, const char* restrict name,
- const char32_t** restrict arguments, size_t start, size_t end,
- char32_t** restrict return_value)
+static int
+call_function(mds_kbdc_tree_t *restrict tree, const char *restrict name, const char32_t **restrict arguments,
+ size_t start, size_t end, char32_t **restrict return_value)
{
-#define FUN_ERROR(...) \
- do \
- { \
- NEW_ERROR(__VA_ARGS__); \
- error->start = start; \
- error->end = end; \
- tree->processed = PROCESS_LEVEL; \
- free(*return_value), *return_value = NULL; \
- goto done; \
- } \
- while(0);
-
- size_t i, arg_count = 0, empty_count = 0;
- char32_t** old_return_value;
- mds_kbdc_tree_function_t* function = NULL;
- mds_kbdc_include_stack_t* function_include_stack = NULL;
- mds_kbdc_include_stack_t* our_include_stack = NULL;
- int r, is_set, builtin, saved_errno;
-
- /* Push call-stack. */
- mds_kbdc_call_stack_push(tree, start, end);
-
- /* Count the number of arguments we have. */
- while (arguments[arg_count])
- arg_count++;
-
- /* Push return-stack. */
- *return_value = NULL;
- old_return_value = current_return_value;
- current_return_value = return_value;
-
- /* Get function definition. */
- builtin = builtin_function_defined(name, arg_count);
- if (builtin == 0)
- callables_get(name, arg_count, (mds_kbdc_tree_t**)&function, &function_include_stack);
- if ((builtin == 0) && (function == NULL))
- FUN_ERROR(tree, ERROR, "function ‘%s/%zu’ has not been defined yet", name, arg_count);
-
-
- /* Call non-builtin function. */
- if (builtin == 0)
- {
- /* Push call stack and set parameters. */
- variables_stack_push();
- for (i = 0; i < arg_count; i++)
- fail_if (let(i + 1, arguments[i], NULL, NULL, 0, 0));
-
- /* Switch include-stack to the function's. */
- fail_if (our_include_stack = mds_kbdc_include_stack_save(), our_include_stack == NULL);
- fail_if (mds_kbdc_include_stack_restore(function_include_stack));
-
- /* Call the function. */
- fail_if (compile_subtree(function->inner));
-
- /* Switch back the include-stack to ours. */
- fail_if (mds_kbdc_include_stack_restore(our_include_stack));
- mds_kbdc_include_stack_free(our_include_stack), our_include_stack = NULL;
-
- /* Pop call stack. */
- variables_stack_pop();
-
- /* Check that the function returned a value. */
- if (*return_value == NULL)
- FUN_ERROR(tree, ERROR, "function ‘%s/%zu’ did not return a value", name, arg_count);
-
- goto done;
- }
-
-
- /* Call builtin function. */
-
- /* Check argument sanity. */
- is_set = (arg_count == 3) && !strcmp(name, "set");
- if (is_set || ((arg_count == 2) && !strcmp(name, "get")))
- {
- fail_if (r = check_set_3_get_2_call(tree, is_set, arguments[0], arguments[1], start, end), r < 0);
- if (r)
- {
- tree->processed = PROCESS_LEVEL;
- free(*return_value), *return_value = NULL;
- goto done;
+#define FUN_ERROR(...)\
+ do {\
+ NEW_ERROR(__VA_ARGS__);\
+ error->start = start;\
+ error->end = end;\
+ tree->processed = PROCESS_LEVEL;\
+ free(*return_value), *return_value = NULL;\
+ goto done;\
+ } while(0);
+
+ size_t i, arg_count = 0, empty_count = 0;
+ char32_t **old_return_value;
+ mds_kbdc_tree_function_t *function = NULL;
+ mds_kbdc_include_stack_t *function_include_stack = NULL;
+ mds_kbdc_include_stack_t *our_include_stack = NULL;
+ int r, is_set, builtin, saved_errno;
+
+ /* Push call-stack. */
+ mds_kbdc_call_stack_push(tree, start, end);
+
+ /* Count the number of arguments we have. */
+ while (arguments[arg_count])
+ arg_count++;
+
+ /* Push return-stack. */
+ *return_value = NULL;
+ old_return_value = current_return_value;
+ current_return_value = return_value;
+
+ /* Get function definition. */
+ builtin = builtin_function_defined(name, arg_count);
+ if (!builtin)
+ callables_get(name, arg_count, (mds_kbdc_tree_t**)&function, &function_include_stack);
+ if (!builtin && !function)
+ FUN_ERROR(tree, ERROR, "function ‘%s/%zu’ has not been defined yet", name, arg_count);
+
+
+ /* Call non-builtin function. */
+ if (!builtin) {
+ /* Push call stack and set parameters. */
+ variables_stack_push();
+ for (i = 0; i < arg_count; i++)
+ fail_if (let(i + 1, arguments[i], NULL, NULL, 0, 0));
+
+ /* Switch include-stack to the function's. */
+ fail_if (our_include_stack = mds_kbdc_include_stack_save(), our_include_stack == NULL);
+ fail_if (mds_kbdc_include_stack_restore(function_include_stack));
+
+ /* Call the function. */
+ fail_if (compile_subtree(function->inner));
+
+ /* Switch back the include-stack to ours. */
+ fail_if (mds_kbdc_include_stack_restore(our_include_stack));
+ mds_kbdc_include_stack_free(our_include_stack), our_include_stack = NULL;
+
+ /* Pop call stack. */
+ variables_stack_pop();
+
+ /* Check that the function returned a value. */
+ if (!*return_value)
+ FUN_ERROR(tree, ERROR, "function ‘%s/%zu’ did not return a value", name, arg_count);
+
+ goto done;
}
- }
- else
- {
- for (i = 0; i < arg_count; i++)
- empty_count += string_length(arguments[i]) == 0;
- if (empty_count && (empty_count != arg_count))
- FUN_ERROR(tree, ERROR,
- "built-in function ‘%s/%zu’ requires that either none of"
- " the arguments are empty strings or that all of them are",
- name, arg_count);
- }
-
- /* Call the function. */
- *return_value = builtin_function_invoke(name, arg_count, arguments);
- fail_if (*return_value == NULL);
- have_side_effect |= is_set;
- /* XXX ideally, we want to make sure it is in a scope that actually brings side-effects. */
-
-
- done:
- /* Pop call-stack. */
- mds_kbdc_call_stack_pop();
-
- /* Pop return-stack. */
- current_return_value = old_return_value;
- return 0;
-
- FAIL_BEGIN;
- mds_kbdc_call_stack_pop();
- mds_kbdc_include_stack_free(our_include_stack);
- free(*return_value), *return_value = NULL;
- current_return_value = old_return_value;
- FAIL_END;
+
+
+ /* Call builtin function. */
+
+ /* Check argument sanity. */
+ is_set = arg_count == 3 && !strcmp(name, "set");
+ if (is_set || (arg_count == 2 && !strcmp(name, "get"))) {
+ fail_if (r = check_set_3_get_2_call(tree, is_set, arguments[0], arguments[1], start, end), r < 0);
+ if (r) {
+ tree->processed = PROCESS_LEVEL;
+ free(*return_value), *return_value = NULL;
+ goto done;
+ }
+ } else {
+ for (i = 0; i < arg_count; i++)
+ empty_count += !string_length(arguments[i]);
+ if (empty_count && empty_count != arg_count)
+ FUN_ERROR(tree, ERROR,
+ "built-in function ‘%s/%zu’ requires that either none of"
+ " the arguments are empty strings or that all of them are",
+ name, arg_count);
+ }
+
+ /* Call the function. */
+ *return_value = builtin_function_invoke(name, arg_count, arguments);
+ fail_if (!*return_value);
+ have_side_effect |= is_set;
+ /* XXX ideally, we want to make sure it is in a scope that actually brings side-effects. */
+
+
+done:
+ /* Pop call-stack. */
+ mds_kbdc_call_stack_pop();
+
+ /* Pop return-stack. */
+ current_return_value = old_return_value;
+ return 0;
+
+ FAIL_BEGIN;
+ mds_kbdc_call_stack_pop();
+ mds_kbdc_include_stack_free(our_include_stack);
+ free(*return_value), *return_value = NULL;
+ current_return_value = old_return_value;
+ FAIL_END;
#undef FUN_ERROR
}
@@ -408,102 +397,99 @@ static int call_function(mds_kbdc_tree_t* restrict tree, const char* restrict na
* @param end Output parameter for the end of the escape
* @return The text the escape represents, `NULL` on error
*/
-static char32_t* parse_function_call(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff,
- int* restrict escape, const char* restrict* restrict end)
+static char32_t *
+parse_function_call(mds_kbdc_tree_t *restrict tree, const char *restrict raw, size_t lineoff,
+ int *restrict escape, const char *restrict *restrict end)
{
-#define R(LOWER, UPPER) (((LOWER) <= c) && (c <= (UPPER)))
-#define GROW_ARGS \
- if (arguments_ptr == arguments_size) \
- fail_if (xxrealloc(old_arguments, arguments, arguments_size += 4, char32_t*))
-
- const char* restrict bracket = raw + 1;
- char32_t* rc = NULL;
- const char32_t** restrict arguments_;
- char32_t** restrict arguments = NULL;
- char32_t** restrict old_arguments = NULL;
- size_t arguments_ptr = 0, arguments_size = 0;
- char* restrict name;
- char c;
- int r, saved_errno = 0;
-
- /* Find the opening bracket associated with the function call and validate the escape. */
- for (; c = *bracket, 1; bracket++)
- if ((c == '_') || R('0', '9') || R('a', 'z') || R('A', 'Z'));
- else if (c == '(')
- break;
- else
- {
- *end = bracket;
- if (tree->processed != PROCESS_LEVEL)
- NEW_ERROR(tree, ERROR, "invalid escape");
- goto error;
- }
-
- /* Copy the name of the function. */
- name = alloca((size_t)(bracket - raw) * sizeof(char));
- memcpy(name, raw + 1, (size_t)(bracket - raw - 1) * sizeof(char));
- name[bracket - raw - 1] = 0;
-
- /* Get arguments. */
- for (*end = ++bracket;;)
- {
- while (**end == ' ')
- (*end)++;
- GROW_ARGS;
- arguments[arguments_ptr] = NULL;
- if (**end == ')')
- {
- *escape = 0;
- (*end)++;
- arguments_ptr++;
- break;
+#define R(LOWER, UPPER) ((LOWER) <= c && c <= (UPPER))
+#define GROW_ARGS\
+ if (arguments_ptr == arguments_size)\
+ fail_if (xxrealloc(old_arguments, arguments, arguments_size += 4, char32_t*))
+
+ const char *restrict bracket = raw + 1;
+ char32_t *rc = NULL;
+ const char32_t **restrict arguments_;
+ char32_t **restrict arguments = NULL;
+ char32_t **restrict old_arguments = NULL;
+ size_t arguments_ptr = 0, arguments_size = 0;
+ char *restrict name;
+ char c;
+ int r, saved_errno = 0;
+
+ /* Find the opening bracket associated with the function call and validate the escape. */
+ for (; c = *bracket, 1; bracket++) {
+ if (c == '_' || R('0', '9') || R('a', 'z') || R('A', 'Z'));
+ else if (c == '(') {
+ break;
+ } else {
+ *end = bracket;
+ if (tree->processed != PROCESS_LEVEL)
+ NEW_ERROR(tree, ERROR, "invalid escape");
+ goto error;
+ }
}
- else if (**end == '\0')
- {
- if (tree->processed != PROCESS_LEVEL)
- NEW_ERROR(tree, ERROR, "incomplete function call");
- goto error;
+
+ /* Copy the name of the function. */
+ name = alloca((size_t)(bracket - raw) * sizeof(char));
+ memcpy(name, raw + 1, (size_t)(bracket - raw - 1) * sizeof(char));
+ name[bracket - raw - 1] = 0;
+
+ /* Get arguments. */
+ for (*end = ++bracket;;) {
+ while (**end == ' ')
+ (*end)++;
+ GROW_ARGS;
+ arguments[arguments_ptr] = NULL;
+ if (**end == ')') {
+ *escape = 0;
+ (*end)++;
+ arguments_ptr++;
+ break;
+ } else if (!**end) {
+ if (tree->processed != PROCESS_LEVEL)
+ NEW_ERROR(tree, ERROR, "incomplete function call");
+ goto error;
+ }
+ r = parse_function_argument(tree, *end, lineoff + (size_t)(*end - raw), end, arguments + arguments_ptr++);
+ fail_if (r < 0);
}
- r = parse_function_argument(tree, *end, lineoff + (size_t)(*end - raw), end, arguments + arguments_ptr++);
- fail_if (r < 0);
- }
-
- /* Call the function. */
- if (tree->processed == PROCESS_LEVEL)
- goto stop;
- arguments_ = alloca(arguments_ptr * sizeof(const char32_t*));
- memcpy(arguments_, arguments, arguments_ptr * sizeof(const char32_t*));
- fail_if (call_function(tree, name, arguments_, lineoff, lineoff + (size_t)(*end - raw), &rc));
- if (rc == NULL)
- goto stop;
-
- goto done;
-
- error:
- error->start = lineoff;
- error->end = lineoff + (size_t)(*end - raw);
- stop:
- *escape = 0;
- tree->processed = PROCESS_LEVEL;
- fail_if (xmalloc(rc, 1, char32_t));
- *rc = -1;
- goto done;
-
- fail:
- saved_errno = errno;
- free(rc);
- if (old_arguments)
- arguments = old_arguments;
- while (arguments_ptr--)
- free(arguments[arguments_ptr]);
- free(arguments);
- rc = NULL;
- done:
- while (arguments_ptr--)
- free(arguments[arguments_ptr]);
- free(arguments);
- errno = saved_errno;
- return rc;
+
+ /* Call the function. */
+ if (tree->processed == PROCESS_LEVEL)
+ goto stop;
+ arguments_ = alloca(arguments_ptr * sizeof(const char32_t*));
+ memcpy(arguments_, arguments, arguments_ptr * sizeof(const char32_t*));
+ fail_if (call_function(tree, name, arguments_, lineoff, lineoff + (size_t)(*end - raw), &rc));
+ if (!rc)
+ goto stop;
+
+ goto done;
+
+error:
+ error->start = lineoff;
+ error->end = lineoff + (size_t)(*end - raw);
+stop:
+ *escape = 0;
+ tree->processed = PROCESS_LEVEL;
+ fail_if (xmalloc(rc, 1, char32_t));
+ *rc = -1;
+ goto done;
+
+fail:
+ saved_errno = errno;
+ free(rc);
+ if (old_arguments)
+ arguments = old_arguments;
+ while (arguments_ptr--)
+ free(arguments[arguments_ptr]);
+ free(arguments);
+ rc = NULL;
+done:
+ while (arguments_ptr--)
+ free(arguments[arguments_ptr]);
+ free(arguments);
+ errno = saved_errno;
+ return rc;
#undef GROW_ARGS
#undef R
}
@@ -520,41 +506,39 @@ static char32_t* parse_function_call(mds_kbdc_tree_t* restrict tree, const char*
* -1 on error, 1 if an undefined function is used
* @return The number of arguments the part of the literal contains
*/
-static size_t check_function_calls_in_literal_(const mds_kbdc_tree_t* restrict tree,
- const char* restrict raw, size_t lineoff,
- const char* restrict* restrict end, int* restrict rc)
+static size_t
+check_function_calls_in_literal_(const mds_kbdc_tree_t *restrict tree, const char *restrict raw,
+ size_t lineoff, const char *restrict *restrict end, int *restrict rc)
{
-#define R(LOWER, UPPER) (((LOWER) <= c) && (c <= (UPPER)))
- const char* restrict raw_ = raw;
- size_t count = 0;
- int space = 1, quote = 0, escape = 0;
- char c;
-
- while ((c = *raw++))
- {
- if (space && !strchr(" )", c))
- space = 0, count++;
-
- if (escape)
- {
- escape = 0;
- if (((c == '_') || R('a', 'z') || R('A', 'Z')) && (c != 'u'))
- /* \u*() is disallowed because \u* is used for hexadecimal representation. */
- if (check_function_call(tree, raw - 2, lineoff + (size_t)(raw - 2 - raw_), &raw, rc), *rc < 0)
- break;
- }
- else if (c == '\\') escape = 1;
- else if (c == '"') quote ^= 1;
- else if (!quote)
- {
- space = (c == ' ');
- if (c == ')')
- break;
+#define R(LOWER, UPPER) ((LOWER) <= c && c <= (UPPER))
+ const char *restrict raw_ = raw;
+ size_t count = 0;
+ int space = 1, quote = 0, escape = 0;
+ char c;
+
+ while ((c = *raw++)) {
+ if (space && !strchr(" )", c))
+ space = 0, count++;
+
+ if (escape) {
+ escape = 0;
+ if ((c == '_' || R('a', 'z') || R('A', 'Z')) && c != 'u')
+ /* \u*() is disallowed because \u* is used for hexadecimal representation. */
+ if (check_function_call(tree, raw - 2, lineoff + (size_t)(raw - 2 - raw_), &raw, rc), *rc < 0)
+ break;
+ } else if (c == '\\') {
+ escape = 1;
+ } else if (c == '"') {
+ quote ^= 1;
+ } else if (!quote) {
+ space = c == ' ';
+ if (c == ')')
+ break;
+ }
}
- }
-
- *end = raw;
- return count;
+
+ *end = raw;
+ return count;
#undef R
}
@@ -569,45 +553,46 @@ static size_t check_function_calls_in_literal_(const mds_kbdc_tree_t* restrict t
* @param rc Success status output parameter: zero on success,
* -1 on error, 1 if an undefined function is used
*/
-static void check_function_call(const mds_kbdc_tree_t* restrict tree, const char* restrict raw,
- size_t lineoff, const char* restrict* restrict end, int* restrict rc)
+static void
+check_function_call(const mds_kbdc_tree_t *restrict tree, const char *restrict raw,
+ size_t lineoff, const char *restrict *restrict end, int *restrict rc)
{
- mds_kbdc_tree_t* function = NULL;
- mds_kbdc_include_stack_t* _function_include_stack;
- char* restrict bracket = strchr(raw, '(');
- char* restrict name;
- size_t arg_count;
-
- /* Check that it is a function call by check that it has an opening bracket. */
- if (bracket == NULL)
- {
- *end = raw + strlen(raw);
- return;
- }
-
- /* Copy the name of the function. */
- name = alloca((size_t)(bracket - raw) * sizeof(char));
- memcpy(name, raw + 1, (size_t)(bracket - raw - 1) * sizeof(char));
- name[bracket++ - raw - 1] = 0;
-
- /* Get the number of arguments used, and check function calls there too. */
- arg_count = check_function_calls_in_literal_(tree, bracket, lineoff + (size_t)(bracket - raw), end, rc);
- if (*rc < 0) return;
-
- /* Check that the function is defined. */
- if (builtin_function_defined(name, arg_count))
- return;
- callables_get(name, arg_count, &function, &_function_include_stack);
- if (function != NULL)
- return;
- *rc |= 1;
- NEW_ERROR(tree, ERROR, "function ‘%s/%zu’ has not been defined yet", name, arg_count);
- error->start = lineoff;
- error->end = lineoff + (size_t)(*end - raw);
- return;
-
- fail:
- *rc |= -1;
+ mds_kbdc_tree_t *function = NULL;
+ mds_kbdc_include_stack_t *_function_include_stack;
+ char *restrict bracket = strchr(raw, '(');
+ char *restrict name;
+ size_t arg_count;
+
+ /* Check that it is a function call by check that it has an opening bracket. */
+ if (!bracket) {
+ *end = raw + strlen(raw);
+ return;
+ }
+
+ /* Copy the name of the function. */
+ name = alloca((size_t)(bracket - raw) * sizeof(char));
+ memcpy(name, raw + 1, (size_t)(bracket - raw - 1) * sizeof(char));
+ name[bracket++ - raw - 1] = 0;
+
+ /* Get the number of arguments used, and check function calls there too. */
+ arg_count = check_function_calls_in_literal_(tree, bracket, lineoff + (size_t)(bracket - raw), end, rc);
+ if (*rc < 0)
+ return;
+
+ /* Check that the function is defined. */
+ if (builtin_function_defined(name, arg_count))
+ return;
+ callables_get(name, arg_count, &function, &_function_include_stack);
+ if (function)
+ return;
+ *rc |= 1;
+ NEW_ERROR(tree, ERROR, "function ‘%s/%zu’ has not been defined yet", name, arg_count);
+ error->start = lineoff;
+ error->end = lineoff + (size_t)(*end - raw);
+ return;
+
+fail:
+ *rc |= -1;
}
@@ -619,14 +604,15 @@ static void check_function_call(const mds_kbdc_tree_t* restrict tree, const char
* @param lineoff The offset on the line where the literal beings
* @return Zero on success, -1 on error, 1 if an undefined function is used
*/
-static int check_function_calls_in_literal(const mds_kbdc_tree_t* restrict tree,
- const char* restrict raw, size_t lineoff)
+static int
+check_function_calls_in_literal(const mds_kbdc_tree_t *restrict tree,
+ const char *restrict raw, size_t lineoff)
{
- int rc = 0;
- (void) check_function_calls_in_literal_(tree, raw, lineoff, &raw, &rc);
- fail_if (rc < 0);
- fail:
- return rc;
+ int rc = 0;
+ (void) check_function_calls_in_literal_(tree, raw, lineoff, &raw, &rc);
+ fail_if (rc < 0);
+fail:
+ return rc;
}
@@ -641,102 +627,98 @@ static int check_function_calls_in_literal(const mds_kbdc_tree_t* restrict tree,
* @param end Output parameter for the end of the escape
* @return The text the escape represents, `NULL` on error
*/
-static char32_t* parse_escape(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff,
- int* restrict escape, const char* restrict* restrict end)
+static char32_t *
+parse_escape(mds_kbdc_tree_t *restrict tree, const char *restrict raw, size_t lineoff,
+ int *restrict escape, const char *restrict *restrict end)
{
-#define R(LOWER, UPPER) (((LOWER) <= c) && (c <= (UPPER)))
-#define CR(COND, LOWER, UPPER) ((*escape == (COND)) && R(LOWER, UPPER))
-#define VARIABLE (int)(raw - raw_) - (c == '.'), raw_
-#define RETURN_ERROR(...) \
- do \
- { \
- NEW_ERROR(__VA_ARGS__); \
- error->start = lineoff; \
- error->end = lineoff + (size_t)(raw - raw_); \
- tree->processed = PROCESS_LEVEL; \
- *escape = 0; \
- if (rc) \
- goto done; \
- fail_if (xmalloc(rc, 1, char32_t)); \
- *rc = -1; \
- goto done; \
- } \
- while (0)
-
- const char* restrict raw_ = raw++;
- char c = *raw++;
- uintmax_t numbuf = 0;
- char32_t* rc = NULL;
- mds_kbdc_tree_t* value;
- int have = 0, saved_errno;
-
-
- /* Get escape type. */
- if (c == '0')
- /* Octal representation. */
- *escape = 8, have = 1;
- else if (c == 'u')
- /* Hexadecimal representation. */
- *escape = 16;
- else if (R('1', '9'))
- /* Variable dereference. */
- *escape = 10, have = 1, numbuf = (uintmax_t)(c - '0');
- else if ((c == '_') || R('a', 'z') || R('A', 'Z'))
- /* Function call. */
- *escape = 100;
- else
- RETURN_ERROR(tree, ERROR, "invalid escape");
-
-
- /* Read escape. */
- if (*escape == 100)
- /* Function call. */
- {
- fail_if (rc = parse_function_call(tree, raw_, lineoff, escape, end), rc == NULL);
- return rc;
- }
- /* Octal or hexadecimal representation, or variable dereference. */
- for (; (c = *raw); have = 1, raw++)
- if (CR( 8, '0', '7')) numbuf = 8 * numbuf + (c & 15);
- else if (CR(16, '0', '9')) numbuf = 16 * numbuf + (c & 15);
- else if (CR(16, 'a', 'f')) numbuf = 16 * numbuf + (c & 15) + 9;
- else if (CR(16, 'A', 'F')) numbuf = 16 * numbuf + (c & 15) + 9;
- else if (CR(10, '0', '9')) numbuf = 10 * numbuf + (c & 15);
- else break;
- if (c == '.')
- raw++;
- if (have == 0)
- RETURN_ERROR(tree, ERROR, "invalid escape");
-
-
- /* Evaluate escape. */
- if (*escape == 10)
- {
- /* Variable dereference. */
- if (value = variables_get((size_t)numbuf), value == NULL)
- RETURN_ERROR(tree, ERROR, "variable ‘%.*s’ is not defined", VARIABLE);
- if (value->type == C(ARRAY))
- RETURN_ERROR(tree, ERROR, "variable ‘%.*s’ is an array", VARIABLE);
- if (value->type != C(COMPILED_STRING))
- NEW_ERROR(tree, INTERNAL_ERROR, "variable ‘%.*s’ is of impossible type", VARIABLE);
- fail_if (rc = string_dup(value->compiled_string.string), rc == NULL);
- }
- else
- {
- /* Octal or hexadecimal representation. */
- fail_if (xmalloc(rc, 2, char32_t));
- rc[0] = (char32_t)numbuf, rc[1] = -1;
- }
-
-
- done:
- *escape = 0;
- *end = raw;
- return rc;
- fail:
- saved_errno = errno;
- free(rc);
- return errno = saved_errno, NULL;
+#define R(LOWER, UPPER) ((LOWER) <= c && c <= (UPPER))
+#define CR(COND, LOWER, UPPER) (*escape == (COND) && R(LOWER, UPPER))
+#define VARIABLE (int)(raw - raw_) - (c == '.'), raw_
+#define RETURN_ERROR(...)\
+ do {\
+ NEW_ERROR(__VA_ARGS__);\
+ error->start = lineoff;\
+ error->end = lineoff + (size_t)(raw - raw_);\
+ tree->processed = PROCESS_LEVEL;\
+ *escape = 0;\
+ if (rc)\
+ goto done;\
+ fail_if (xmalloc(rc, 1, char32_t));\
+ *rc = -1;\
+ goto done;\
+ } while (0)
+
+ const char* restrict raw_ = raw++;
+ char c = *raw++;
+ uintmax_t numbuf = 0;
+ char32_t* rc = NULL;
+ mds_kbdc_tree_t* value;
+ int have = 0, saved_errno;
+
+
+ /* Get escape type. */
+ if (c == '0')
+ /* Octal representation. */
+ *escape = 8, have = 1;
+ else if (c == 'u')
+ /* Hexadecimal representation. */
+ *escape = 16;
+ else if (R('1', '9'))
+ /* Variable dereference. */
+ *escape = 10, have = 1, numbuf = (uintmax_t)(c - '0');
+ else if (c == '_' || R('a', 'z') || R('A', 'Z'))
+ /* Function call. */
+ *escape = 100;
+ else
+ RETURN_ERROR(tree, ERROR, "invalid escape");
+
+
+ /* Read escape. */
+ if (*escape == 100) {
+ /* Function call. */
+ fail_if (rc = parse_function_call(tree, raw_, lineoff, escape, end), rc == NULL);
+ return rc;
+ }
+ /* Octal or hexadecimal representation, or variable dereference. */
+ for (; (c = *raw); have = 1, raw++) {
+ if (CR( 8, '0', '7')) numbuf = 8 * numbuf + (c & 15);
+ else if (CR(16, '0', '9')) numbuf = 16 * numbuf + (c & 15);
+ else if (CR(16, 'a', 'f')) numbuf = 16 * numbuf + (c & 15) + 9;
+ else if (CR(16, 'A', 'F')) numbuf = 16 * numbuf + (c & 15) + 9;
+ else if (CR(10, '0', '9')) numbuf = 10 * numbuf + (c & 15);
+ else break;
+ }
+ if (c == '.')
+ raw++;
+ if (have == 0)
+ RETURN_ERROR(tree, ERROR, "invalid escape");
+
+
+ /* Evaluate escape. */
+ if (*escape == 10) {
+ /* Variable dereference. */
+ if (!(value = variables_get((size_t)numbuf)))
+ RETURN_ERROR(tree, ERROR, "variable ‘%.*s’ is not defined", VARIABLE);
+ if (value->type == C(ARRAY))
+ RETURN_ERROR(tree, ERROR, "variable ‘%.*s’ is an array", VARIABLE);
+ if (value->type != C(COMPILED_STRING))
+ NEW_ERROR(tree, INTERNAL_ERROR, "variable ‘%.*s’ is of impossible type", VARIABLE);
+ fail_if (!(rc = string_dup(value->compiled_string.string)));
+ } else {
+ /* Octal or hexadecimal representation. */
+ fail_if (xmalloc(rc, 2, char32_t));
+ rc[0] = (char32_t)numbuf, rc[1] = -1;
+ }
+
+
+done:
+ *escape = 0;
+ *end = raw;
+ return rc;
+fail:
+ saved_errno = errno;
+ free(rc);
+ return errno = saved_errno, NULL;
#undef RETURN_ERROR
#undef VARIABLE
#undef CR
@@ -752,127 +734,114 @@ static char32_t* parse_escape(mds_kbdc_tree_t* restrict tree, const char* restri
* @param lineoff The offset on the line where the string beings
* @return The string as pure text, `NULL` on error
*/
-static char32_t* parse_quoted_string(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff)
+static char32_t *
+parse_quoted_string(mds_kbdc_tree_t *restrict tree, const char *restrict raw, size_t lineoff)
{
-#define GROW_BUF \
- if (buf_ptr == buf_size) \
- fail_if (xxrealloc(old_buf, buf, buf_size += 16, char))
-#define COPY \
- n = string_length(subrc); \
- fail_if (xxrealloc(old_rc, rc, rc_ptr + n, char32_t)); \
- memcpy(rc + rc_ptr, subrc, n * sizeof(char32_t)), rc_ptr += n; \
- free(subrc), subrc = NULL
-#define STORE \
- if (buf_ptr) \
- do \
- { \
- GROW_BUF; \
- buf[buf_ptr] = '\0', buf_ptr = 0; \
- fail_if (subrc = string_decode(buf), subrc == NULL); \
- COPY; \
- } \
- while (0)
-#define CHAR_ERROR(...) \
- do \
- { \
- NEW_ERROR(__VA_ARGS__); \
- error->end = lineoff + (size_t)(raw - raw_); \
- error->start = error->end - 1; \
- } \
- while (0)
-
- const char* restrict raw_ = raw;
- char32_t* restrict subrc = NULL;
- char32_t* restrict rc = NULL;
- char32_t* restrict old_rc = NULL;
- char* restrict buf = NULL;
- char* restrict old_buf = NULL;
- size_t rc_ptr = 0, n;
- size_t buf_ptr = 0, buf_size = 0;
- size_t escoff = 0;
- int quote = 0, escape = 0;
- char c;
- int saved_errno;
-
- /* Parse the string. */
- while ((c = *raw++))
- if (escape && quote && strchr("()[]{}<>\"\\,", c))
- {
- /* Buffer UTF-8 text for convertion to UTF-32. */
- GROW_BUF;
- buf[buf_ptr++] = c;
- escape = 0;
- }
- else if (escape)
- {
- /* Parse escape. */
- raw -= 2, escoff = lineoff + (size_t)(raw - raw_);
- subrc = parse_escape(tree, raw, escoff, &escape, &raw);
- fail_if (subrc == NULL);
- COPY;
- }
- else if (c == '"')
- {
- /* Close or open quote, of it got closed, convert the buffered UTF-8 text to UTF-32. */
- if (quote ^= 1) continue;
- if ((quote == 1) && (raw != raw_ + 1))
- CHAR_ERROR(tree, WARNING, "strings should either be unquoted or unclosed in one large quoted");
- STORE;
- }
- else if (c == '\\')
- {
- /* Convert the buffered UTF-8 text to UTF-32, and start an escape. */
- STORE;
- escape = 1;
- }
- else if ((quote == 0) && (tree->processed != PROCESS_LEVEL))
- {
- /* Only escapes may be used without quotes, if the string contains quotes. */
- if (*raw_ == '"')
- CHAR_ERROR(tree, ERROR, "only escapes may be outside quotes in quoted strings");
- else
- CHAR_ERROR(tree, ERROR, "mixing numericals and escapes is not allowed");
- tree->processed = PROCESS_LEVEL;
- }
- else
- {
- /* Buffer UTF-8 text for convertion to UTF-32. */
- GROW_BUF;
- buf[buf_ptr++] = c;
- }
-
- /* Check that no escape is incomplete. */
- if (escape && (tree->processed != PROCESS_LEVEL))
- {
- NEW_ERROR(tree, ERROR, "incomplete escape");
- error->start = escoff;
- error->end = lineoff + strlen(raw_);
- tree->processed = PROCESS_LEVEL;
- }
-
- /* Check that the quote is complete. */
- if (quote && (tree->processed != PROCESS_LEVEL))
- {
- NEW_ERROR(tree, ERROR, "quote is not closed");
- error->start = lineoff;
- error->end = lineoff + strlen(raw_);
- tree->processed = PROCESS_LEVEL;
- }
-
- /* Shrink or grow to string to its minimal size, and -1-terminate it. */
- fail_if (xxrealloc(old_rc, rc, rc_ptr + 1, char32_t));
- rc[rc_ptr] = -1;
-
- free(buf);
- return rc;
- fail:
- saved_errno = errno;
- free(subrc);
- free(old_rc);
- free(old_buf);
- free(rc);
- free(buf);
- return errno = saved_errno, NULL;
+#define GROW_BUF\
+ if (buf_ptr == buf_size)\
+ fail_if (xxrealloc(old_buf, buf, buf_size += 16, char))
+#define COPY\
+ n = string_length(subrc);\
+ fail_if (xxrealloc(old_rc, rc, rc_ptr + n, char32_t));\
+ memcpy(rc + rc_ptr, subrc, n * sizeof(char32_t)), rc_ptr += n;\
+ free(subrc), subrc = NULL
+#define STORE\
+ do {\
+ if (buf_ptr) {\
+ GROW_BUF;\
+ buf[buf_ptr] = '\0', buf_ptr = 0;\
+ fail_if (!(subrc = string_decode(buf)));\
+ COPY;\
+ }\
+ } while (0)
+#define CHAR_ERROR(...)\
+ do {\
+ NEW_ERROR(__VA_ARGS__);\
+ error->end = lineoff + (size_t)(raw - raw_);\
+ error->start = error->end - 1;\
+ } while (0)
+
+ const char *restrict raw_ = raw;
+ char32_t *restrict subrc = NULL;
+ char32_t *restrict rc = NULL;
+ char32_t *restrict old_rc = NULL;
+ char *restrict buf = NULL;
+ char *restrict old_buf = NULL;
+ size_t rc_ptr = 0, n;
+ size_t buf_ptr = 0, buf_size = 0;
+ size_t escoff = 0;
+ int quote = 0, escape = 0;
+ char c;
+ int saved_errno;
+
+ /* Parse the string. */
+ while ((c = *raw++)) {
+ if (escape && quote && strchr("()[]{}<>\"\\,", c)) {
+ /* Buffer UTF-8 text for convertion to UTF-32. */
+ GROW_BUF;
+ buf[buf_ptr++] = c;
+ escape = 0;
+ } else if (escape) {
+ /* Parse escape. */
+ raw -= 2, escoff = lineoff + (size_t)(raw - raw_);
+ subrc = parse_escape(tree, raw, escoff, &escape, &raw);
+ fail_if (!subrc);
+ COPY;
+ } else if (c == '"') {
+ /* Close or open quote, of it got closed, convert the buffered UTF-8 text to UTF-32. */
+ if ((quote ^= 1))
+ continue;
+ if (quote == 1 && raw != raw_ + 1)
+ CHAR_ERROR(tree, WARNING, "strings should either be unquoted or unclosed in one large quoted");
+ STORE;
+ } else if (c == '\\') {
+ /* Convert the buffered UTF-8 text to UTF-32, and start an escape. */
+ STORE;
+ escape = 1;
+ } else if (!quote && tree->processed != PROCESS_LEVEL) {
+ /* Only escapes may be used without quotes, if the string contains quotes. */
+ if (*raw_ == '"')
+ CHAR_ERROR(tree, ERROR, "only escapes may be outside quotes in quoted strings");
+ else
+ CHAR_ERROR(tree, ERROR, "mixing numericals and escapes is not allowed");
+ tree->processed = PROCESS_LEVEL;
+ } else {
+ /* Buffer UTF-8 text for convertion to UTF-32. */
+ GROW_BUF;
+ buf[buf_ptr++] = c;
+ }
+ }
+
+ /* Check that no escape is incomplete. */
+ if (escape && tree->processed != PROCESS_LEVEL) {
+ NEW_ERROR(tree, ERROR, "incomplete escape");
+ error->start = escoff;
+ error->end = lineoff + strlen(raw_);
+ tree->processed = PROCESS_LEVEL;
+ }
+
+ /* Check that the quote is complete. */
+ if (quote && tree->processed != PROCESS_LEVEL) {
+ NEW_ERROR(tree, ERROR, "quote is not closed");
+ error->start = lineoff;
+ error->end = lineoff + strlen(raw_);
+ tree->processed = PROCESS_LEVEL;
+ }
+
+ /* Shrink or grow to string to its minimal size, and -1-terminate it. */
+ fail_if (xxrealloc(old_rc, rc, rc_ptr + 1, char32_t));
+ rc[rc_ptr] = -1;
+
+ free(buf);
+ return rc;
+fail:
+ saved_errno = errno;
+ free(subrc);
+ free(old_rc);
+ free(old_buf);
+ free(rc);
+ free(buf);
+ return errno = saved_errno, NULL;
#undef CHAR_ERROR
#undef STORE
#undef COPY
@@ -888,37 +857,36 @@ static char32_t* parse_quoted_string(mds_kbdc_tree_t* restrict tree, const char*
* @param lineoff The offset on the line where the string beings
* @return The string as pure text, `NULL` on error
*/
-static char32_t* parse_unquoted_string(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff)
+static char32_t *
+parse_unquoted_string(mds_kbdc_tree_t *restrict tree, const char *restrict raw, size_t lineoff)
{
-#define R(LOWER, UPPER) (((LOWER) <= c) && (c <= (UPPER)))
-#define CHAR_ERROR(...) \
- do \
- { \
- NEW_ERROR(__VA_ARGS__); \
- error->end = lineoff + (size_t)(raw - raw_); \
- error->start = error->end - 1; \
- tree->processed = PROCESS_LEVEL; \
- goto done; \
- } \
- while (0)
-
- const char* restrict raw_ = raw;
- char32_t* rc;
- char32_t buf = 0;
- char c;
-
- while ((c = *raw++))
- if (R('0', '9')) buf = 10 * buf + (c & 15);
- else if (c == '\\') CHAR_ERROR(tree, ERROR, "mixing numericals and escapes is not allowed");
- else if (c == '"') CHAR_ERROR(tree, ERROR, "mixing numericals and quotes is not allowed");
- else CHAR_ERROR(tree, ERROR, "stray ‘%c’", c); /* XXX support multibyte */
-
- done:
- fail_if (xmalloc(rc, 2, char32_t));
- return rc[0] = buf, rc[1] = -1, rc;
+#define R(LOWER, UPPER) ((LOWER) <= c && c <= (UPPER))
+#define CHAR_ERROR(...)\
+ do {\
+ NEW_ERROR(__VA_ARGS__);\
+ error->end = lineoff + (size_t)(raw - raw_);\
+ error->start = error->end - 1;\
+ tree->processed = PROCESS_LEVEL;\
+ goto done;\
+ } while (0)
+
+ const char *restrict raw_ = raw;
+ char32_t *rc, buf = 0;
+ char c;
+
+ while ((c = *raw++)) {
+ if (R('0', '9')) buf = 10 * buf + (c & 15);
+ else if (c == '\\') CHAR_ERROR(tree, ERROR, "mixing numericals and escapes is not allowed");
+ else if (c == '"') CHAR_ERROR(tree, ERROR, "mixing numericals and quotes is not allowed");
+ else CHAR_ERROR(tree, ERROR, "stray ‘%c’", c); /* XXX support multibyte */
+ }
+
+done:
+ fail_if (xmalloc(rc, 2, char32_t));
+ return rc[0] = buf, rc[1] = -1, rc;
- fail:
- return NULL;
+fail:
+ return NULL;
#undef CHAR_ERROR
#undef R
}
@@ -932,15 +900,16 @@ static char32_t* parse_unquoted_string(mds_kbdc_tree_t* restrict tree, const cha
* @param lineoff The offset on the line where the string beings
* @return The string as pure text, `NULL` on error
*/
-static char32_t* parse_string(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff)
+static char32_t *
+parse_string(mds_kbdc_tree_t *restrict tree, const char *restrict raw, size_t lineoff)
{
- mds_kbdc_tree_t* old_last_value_statement = last_value_statement;
- char32_t* rc = (strchr("\"\\", *raw) ? parse_quoted_string : parse_unquoted_string)(tree, raw, lineoff);
- last_value_statement = old_last_value_statement;
- fail_if (rc == NULL);
- return rc;
- fail:
- return NULL;
+ mds_kbdc_tree_t *old_last_value_statement = last_value_statement;
+ char32_t *rc = (strchr("\"\\", *raw) ? parse_quoted_string : parse_unquoted_string)(tree, raw, lineoff);
+ last_value_statement = old_last_value_statement;
+ fail_if (!rc);
+ return rc;
+fail:
+ return NULL;
}
@@ -952,120 +921,108 @@ static char32_t* parse_string(mds_kbdc_tree_t* restrict tree, const char* restri
* @param lineoff The offset on the line where the string beings
* @return The string as pure text, `NULL` on error
*/
-static char32_t* parse_keys(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff)
+static char32_t *
+parse_keys(mds_kbdc_tree_t *restrict tree, const char *restrict raw, size_t lineoff)
{
-#define GROW_BUF \
- if (buf_ptr == buf_size) \
- fail_if (xxrealloc(old_buf, buf, buf_size += 16, char))
-#define COPY \
- n = string_length(subrc); \
- fail_if (xxrealloc(old_rc, rc, rc_ptr + n, char32_t)); \
- memcpy(rc + rc_ptr, subrc, n * sizeof(char32_t)), rc_ptr += n; \
- free(subrc), subrc = NULL
-#define STORE \
- if (buf_ptr) \
- do \
- { \
- GROW_BUF; \
- buf[buf_ptr] = '\0', buf_ptr = 0; \
- fail_if (subrc = string_decode(buf), subrc == NULL); \
- COPY; \
- } \
- while (0)
-#define SPECIAL(VAL) \
- STORE; \
- fail_if (xxrealloc(old_rc, rc, rc_ptr + 1, char32_t)); \
- rc[rc_ptr++] = -(VAL + 1)
-
- mds_kbdc_tree_t* old_last_value_statement = last_value_statement;
- const char* restrict raw_ = raw++;
- char32_t* restrict subrc = NULL;
- char32_t* restrict rc = NULL;
- char32_t* restrict old_rc = NULL;
- char* restrict buf = NULL;
- char* restrict old_buf = NULL;
- size_t rc_ptr = 0, n;
- size_t buf_ptr = 0, buf_size = 0;
- size_t escoff = 0;
- int escape = 0, quote = 0;
- char c;
- int saved_errno;
-
- /* Parse the string. */
- while (c = *raw++, c && *raw)
- if (escape && strchr("()[]{}<>\"\\,", c))
- {
- /* Buffer UTF-8 text for convertion to UTF-32. */
- GROW_BUF;
- buf[buf_ptr++] = c;
- escape = 0;
- }
- else if (escape)
- {
- /* Parse escape. */
- raw -= 2, escoff = lineoff + (size_t)(raw - raw_);
- subrc = parse_escape(tree, raw, escoff, &escape, &raw);
- fail_if (subrc == NULL);
- COPY;
- }
- else if (c == '\\')
- {
- /* Convert the buffered UTF-8 text to UTF-32, and start an escape. */
+#define GROW_BUF\
+ if (buf_ptr == buf_size)\
+ fail_if (xxrealloc(old_buf, buf, buf_size += 16, char))
+#define COPY\
+ n = string_length(subrc);\
+ fail_if (xxrealloc(old_rc, rc, rc_ptr + n, char32_t));\
+ memcpy(rc + rc_ptr, subrc, n * sizeof(char32_t)), rc_ptr += n;\
+ free(subrc), subrc = NULL
+#define STORE\
+ do {\
+ if (buf_ptr) {\
+ GROW_BUF;\
+ buf[buf_ptr] = '\0', buf_ptr = 0;\
+ fail_if (!(subrc = string_decode(buf)));\
+ COPY;\
+ }\
+ } while (0)
+#define SPECIAL(VAL)\
+ STORE;\
+ fail_if (xxrealloc(old_rc, rc, rc_ptr + 1, char32_t));\
+ rc[rc_ptr++] = -(VAL + 1)
+
+ mds_kbdc_tree_t *old_last_value_statement = last_value_statement;
+ const char *restrict raw_ = raw++;
+ char32_t *restrict subrc = NULL;
+ char32_t *restrict rc = NULL;
+ char32_t *restrict old_rc = NULL;
+ char *restrict buf = NULL;
+ char *restrict old_buf = NULL;
+ size_t rc_ptr = 0, n;
+ size_t buf_ptr = 0, buf_size = 0;
+ size_t escoff = 0;
+ int escape = 0, quote = 0;
+ char c;
+ int saved_errno;
+
+ /* Parse the string. */
+ while (c = *raw++, c && *raw) {
+ if (escape && strchr("()[]{}<>\"\\,", c)) {
+ /* Buffer UTF-8 text for convertion to UTF-32. */
+ GROW_BUF;
+ buf[buf_ptr++] = c;
+ escape = 0;
+ } else if (escape) {
+ /* Parse escape. */
+ raw -= 2, escoff = lineoff + (size_t)(raw - raw_);
+ subrc = parse_escape(tree, raw, escoff, &escape, &raw);
+ fail_if (!subrc);
+ COPY;
+ } else if (c == '\\') {
+ /* Convert the buffered UTF-8 text to UTF-32, and start an escape. */
+ STORE;
+ escape = 1;
+ } else if (c == ',' && !quote) {
+ /* Sequence in key-combination. */
+ SPECIAL(1);
+ } else if (c == '"') {
+ /* String in key-combination. */
+ quote ^= 1;
+ SPECIAL(2);
+ } else {
+ /* Buffer UTF-8 text for convertion to UTF-32. */
+ GROW_BUF;
+ buf[buf_ptr++] = c;
+ }
+ }
STORE;
- escape = 1;
- }
- else if ((c == ',') && !quote)
- {
- /* Sequence in key-combination. */
- SPECIAL(1);
- }
- else if (c == '"')
- {
- /* String in key-combination. */
- quote ^= 1;
- SPECIAL(2);
- }
- else
- {
- /* Buffer UTF-8 text for convertion to UTF-32. */
- GROW_BUF;
- buf[buf_ptr++] = c;
- }
- STORE;
-
- /* Check that no escape is incomplete. */
- if (escape && (tree->processed != PROCESS_LEVEL))
- {
- NEW_ERROR(tree, ERROR, "incomplete escape");
- error->start = lineoff + (size_t)(strrchr(raw_, '\\') - raw_);
- error->end = lineoff + strlen(raw_);
- tree->processed = PROCESS_LEVEL;
- }
-
- /* Check that key-combination is complete. */
- if ((c != '>') && (tree->processed != PROCESS_LEVEL))
- {
- NEW_ERROR(tree, ERROR, "key-combination is not closed");
- error->start = lineoff;
- error->end = lineoff + strlen(raw_);
- tree->processed = PROCESS_LEVEL;
- }
-
- /* Shrink or grow to string to its minimal size, and -1-terminate it. */
- fail_if (xxrealloc(old_rc, rc, rc_ptr + 1, char32_t));
- rc[rc_ptr] = -1;
-
- free(buf);
- return last_value_statement = old_last_value_statement, rc;
- fail:
- saved_errno = errno;
- free(subrc);
- free(old_rc);
- free(old_buf);
- free(rc);
- free(buf);
- errno = saved_errno;
- return last_value_statement = old_last_value_statement, NULL;
+
+ /* Check that no escape is incomplete. */
+ if (escape && tree->processed != PROCESS_LEVEL) {
+ NEW_ERROR(tree, ERROR, "incomplete escape");
+ error->start = lineoff + (size_t)(strrchr(raw_, '\\') - raw_);
+ error->end = lineoff + strlen(raw_);
+ tree->processed = PROCESS_LEVEL;
+ }
+
+ /* Check that key-combination is complete. */
+ if (c != '>' && tree->processed != PROCESS_LEVEL) {
+ NEW_ERROR(tree, ERROR, "key-combination is not closed");
+ error->start = lineoff;
+ error->end = lineoff + strlen(raw_);
+ tree->processed = PROCESS_LEVEL;
+ }
+
+ /* Shrink or grow to string to its minimal size, and -1-terminate it. */
+ fail_if (xxrealloc(old_rc, rc, rc_ptr + 1, char32_t));
+ rc[rc_ptr] = -1;
+
+ free(buf);
+ return last_value_statement = old_last_value_statement, rc;
+fail:
+ saved_errno = errno;
+ free(subrc);
+ free(old_rc);
+ free(old_buf);
+ free(rc);
+ free(buf);
+ errno = saved_errno;
+ return last_value_statement = old_last_value_statement, NULL;
#undef SPECIAL
#undef STORE
#undef COPY
@@ -1081,54 +1038,55 @@ static char32_t* parse_keys(mds_kbdc_tree_t* restrict tree, const char* restrict
* @param lineoff The offset on the line where the variable string begins
* @return The index of the variable, zero on error
*/
-static size_t parse_variable(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff)
+static size_t
+parse_variable(mds_kbdc_tree_t *restrict tree, const char *restrict raw, size_t lineoff)
{
- size_t var, n;
- const char* restrict raw_ = raw;
- char* restrict dotless;
-
- /* The variable must begin with \. */
- if (*raw++ != '\\') goto bad;
- /* Zero is not a valid varible, nor may there be leading zeroes or be empty. */
- if (*raw == '0') goto bad;
- if (*raw == '.') goto bad;
- if (*raw == '\0') goto bad;
- for (; *raw; raw++)
- /* Check that the variable consists only of digits. */
- if (('0' <= *raw) && (*raw <= '9'));
- /* However, it may end with a dot. */
- else if ((raw[0] == '.') && (raw[1] == '\0'))
- break;
- else
- goto bad;
-
- /* Parse the variable string and check that it did not overflow. */
- n = (size_t)(raw - raw_);
- dotless = alloca((n + 1) * sizeof(char));
- memcpy(dotless, raw_, n * sizeof(char)), dotless[n] = '\0';
- var = atoz(dotless + 1);
- if (strlen(dotless + 1) != (size_t)snprintf(NULL, 0, "%zu", var))
- fail_if ((errno = ERANGE));
- if (var == 0)
- {
- NEW_ERROR(tree, INTERNAL_ERROR,
- "parsed a variable string to be 0, which should not be possible");
- error->start = lineoff;
- error->end = lineoff + strlen(raw_);
- tree->processed = PROCESS_LEVEL;
- return 1;
- }
- return var;
- fail:
- return 0;
-
- bad:
- /* Report an error but return a variable index if the variable-string is invalid. */
- NEW_ERROR(tree, ERROR, "not a variable");
- error->start = lineoff;
- error->end = lineoff + strlen(raw_);
- tree->processed = PROCESS_LEVEL;
- return 1;
+ size_t var, n;
+ const char *restrict raw_ = raw;
+ char *restrict dotless;
+
+ /* The variable must begin with \. */
+ if (*raw++ != '\\') goto bad;
+ /* Zero is not a valid varible, nor may there be leading zeroes or be empty. */
+ if (*raw == '0') goto bad;
+ if (*raw == '.') goto bad;
+ if (*raw == '\0') goto bad;
+ for (; *raw; raw++) {
+ /* Check that the variable consists only of digits. */
+ if ('0' <= *raw && *raw <= '9')
+ /* However, it may end with a dot. */;
+ else if (raw[0] == '.' && raw[1] == '\0')
+ break;
+ else
+ goto bad;
+ }
+
+ /* Parse the variable string and check that it did not overflow. */
+ n = (size_t)(raw - raw_);
+ dotless = alloca((n + 1) * sizeof(char));
+ memcpy(dotless, raw_, n * sizeof(char)), dotless[n] = '\0';
+ var = atoz(dotless + 1);
+ if (strlen(dotless + 1) != (size_t)snprintf(NULL, 0, "%zu", var))
+ fail_if ((errno = ERANGE));
+ if (!var) {
+ NEW_ERROR(tree, INTERNAL_ERROR,
+ "parsed a variable string to be 0, which should not be possible");
+ error->start = lineoff;
+ error->end = lineoff + strlen(raw_);
+ tree->processed = PROCESS_LEVEL;
+ return 1;
+ }
+ return var;
+fail:
+ return 0;
+
+bad:
+ /* Report an error but return a variable index if the variable-string is invalid. */
+ NEW_ERROR(tree, ERROR, "not a variable");
+ error->start = lineoff;
+ error->end = lineoff + strlen(raw_);
+ tree->processed = PROCESS_LEVEL;
+ return 1;
}
@@ -1142,63 +1100,65 @@ static size_t parse_variable(mds_kbdc_tree_t* restrict tree, const char* restric
* @param value Output parameter for the value to which the argument evaulates
* @return Zero on success, -1 on error
*/
-static int parse_function_argument(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff,
- const char* restrict* restrict end, char32_t** restrict value)
+static int
+parse_function_argument(mds_kbdc_tree_t *restrict tree, const char *restrict raw, size_t lineoff,
+ const char *restrict *restrict end, char32_t **restrict value)
{
- size_t size = strlen(raw), ptr = 0, call_end = 0;
- int escape = 0, quote = 0;
- char* raw_argument = NULL;
- int saved_errno;
-
- /* Find the span of the argument. */
- while (ptr < size)
- {
- char c = raw[ptr++];
-
- /* Escapes may be longer than one character,
- but only the first can affect the parsing. */
- if (escape) escape = 0;
- /* Nested function and nested quotes can appear. */
- else if (ptr <= call_end) ;
- /* Quotes end with the same symbols as they start with,
- and quotes automatically escape brackets. */
- /* \ can either start a functon call or an escape. */
- else if (c == '\\')
- {
- /* It may not be an escape, but registering it
- as an escape cannot harm us since we only
- skip the first character, and a function call
- cannot be that short. */
- escape = 1;
- /* Nested quotes can appear at function calls. */
- call_end = get_end_of_call(raw, ptr, size);
- }
- /* " is the quote symbol. */
- else if (quote) quote = (c != '"');
- else if (c == '"') quote = 1;
- /* End of argument? */
- else if (strchr(" )", c))
- {
- ptr--;
- break;
+ size_t size = strlen(raw), ptr = 0, call_end = 0;
+ int escape = 0, quote = 0, saved_errno;
+ char *raw_argument = NULL;
+ char c;
+
+ /* Find the span of the argument. */
+ while (ptr < size) {
+ c = raw[ptr++];
+
+ /* Escapes may be longer than one character,
+ but only the first can affect the parsing. */
+ if (escape)
+ escape = 0;
+ /* Nested function and nested quotes can appear. */
+ else if (ptr <= call_end)
+ ;
+ /* Quotes end with the same symbols as they start with,
+ and quotes automatically escape brackets. */
+ /* \ can either start a functon call or an escape. */
+ else if (c == '\\') {
+ /* It may not be an escape, but registering it
+ as an escape cannot harm us since we only
+ skip the first character, and a function call
+ cannot be that short. */
+ escape = 1;
+ /* Nested quotes can appear at function calls. */
+ call_end = get_end_of_call(raw, ptr, size);
+ }
+ /* " is the quote symbol. */
+ else if (quote)
+ quote = (c != '"');
+ else if (c == '"')
+ quote = 1;
+ /* End of argument? */
+ else if (strchr(" )", c)) {
+ ptr--;
+ break;
+ }
}
- }
- *end = raw + ptr;
-
- /* Copy the argument so that we have a NUL-terminates string. */
- fail_if (xmalloc(raw_argument, ptr + 1, char));
- memcpy(raw_argument, raw, ptr * sizeof(char));
- raw_argument[ptr] = '\0';
-
- /* Evaluate argument. */
- *value = parse_string(tree, raw_argument, lineoff);
- fail_if (*value == NULL);
-
- free(raw_argument);
- return 0;
- FAIL_BEGIN;
- free(raw_argument);
- FAIL_END;
+ *end = raw + ptr;
+
+ /* Copy the argument so that we have a NUL-terminates string. */
+ fail_if (xmalloc(raw_argument, ptr + 1, char));
+ memcpy(raw_argument, raw, ptr * sizeof(char));
+ raw_argument[ptr] = '\0';
+
+ /* Evaluate argument. */
+ *value = parse_string(tree, raw_argument, lineoff);
+ fail_if (!*value);
+
+ free(raw_argument);
+ return 0;
+ FAIL_BEGIN;
+ free(raw_argument);
+ FAIL_END;
}
@@ -1209,13 +1169,13 @@ static int parse_function_argument(mds_kbdc_tree_t* restrict tree, const char* r
* @param macro_include_stack The include-stack for the macro
* @return Zero on success, -1 on error
*/
-static int set_macro(mds_kbdc_tree_macro_t* restrict macro,
- mds_kbdc_include_stack_t* macro_include_stack)
+static int
+set_macro(mds_kbdc_tree_macro_t *restrict macro, mds_kbdc_include_stack_t *macro_include_stack)
{
- fail_if (callables_set(macro->name, 0, (mds_kbdc_tree_t*)macro, macro_include_stack));
- return 0;
- fail:
- return -1;
+ fail_if (callables_set(macro->name, 0, (mds_kbdc_tree_t *)macro, macro_include_stack));
+ return 0;
+fail:
+ return -1;
}
@@ -1226,10 +1186,11 @@ static int set_macro(mds_kbdc_tree_macro_t* restrict macro,
* @param macro Output parameter for the macro, `NULL` if not found
* @param macro_include_stack Output parameter for the include-stack for the macro
*/
-static void get_macro_lax(const char* restrict macro_name, mds_kbdc_tree_macro_t** restrict macro,
- mds_kbdc_include_stack_t** restrict macro_include_stack)
+static void
+get_macro_lax(const char *restrict macro_name, mds_kbdc_tree_macro_t **restrict macro,
+ mds_kbdc_include_stack_t **restrict macro_include_stack)
{
- callables_get(macro_name, 0, (mds_kbdc_tree_t**)macro, macro_include_stack);
+ callables_get(macro_name, 0, (mds_kbdc_tree_t **)macro, macro_include_stack);
}
@@ -1246,29 +1207,29 @@ static void get_macro_lax(const char* restrict macro_name, mds_kbdc_tree_macro_t
* @param macro_include_stack Output parameter for the include-stack for the macro
* @return Zero on success, -1 on error
*/
-static int get_macro(mds_kbdc_tree_macro_call_t* restrict macro_call,
- mds_kbdc_tree_macro_t** restrict macro,
- mds_kbdc_include_stack_t** restrict macro_include_stack)
+static int
+get_macro(mds_kbdc_tree_macro_call_t *restrict macro_call,
+ mds_kbdc_tree_macro_t **restrict macro,
+ mds_kbdc_include_stack_t **restrict macro_include_stack)
{
- char* code = result->source_code->lines[macro_call->loc_line];
- char* end = code + strlen(code) - 1;
-
- get_macro_lax(macro_call->name, macro, macro_include_stack);
- if (*macro == NULL)
- {
- NEW_ERROR(macro_call, ERROR, "macro ‘%s’ has not been defined yet", macro_call->name);
- while (*end == ' ')
- end--;
- error->end = (size_t)(++end - code);
- macro_call->processed = PROCESS_LEVEL;
- return 0;
- }
- if ((*macro)->processed == PROCESS_LEVEL)
- *macro = NULL;
-
- return 0;
- fail:
- return -1;
+ char *code = result->source_code->lines[macro_call->loc_line];
+ char *end = code + strlen(code) - 1;
+
+ get_macro_lax(macro_call->name, macro, macro_include_stack);
+ if (!*macro) {
+ NEW_ERROR(macro_call, ERROR, "macro ‘%s’ has not been defined yet", macro_call->name);
+ while (*end == ' ')
+ end--;
+ error->end = (size_t)(++end - code);
+ macro_call->processed = PROCESS_LEVEL;
+ return 0;
+ }
+ if ((*macro)->processed == PROCESS_LEVEL)
+ *macro = NULL;
+
+ return 0;
+fail:
+ return -1;
}
@@ -1279,20 +1240,21 @@ static int get_macro(mds_kbdc_tree_macro_call_t* restrict macro_call,
* @param function_include_stack The include-stack for the function
* @return Zero on success, -1 on error
*/
-static int set_function(mds_kbdc_tree_function_t* restrict function,
- mds_kbdc_include_stack_t* function_include_stack)
+static int
+set_function(mds_kbdc_tree_function_t *restrict function,
+ mds_kbdc_include_stack_t *function_include_stack)
{
- char* suffixless = function->name;
- char* suffix_start = strchr(suffixless, '/');
- size_t arg_count = atoz(suffix_start + 1);
- int r;
-
- *suffix_start = '\0';
- r = callables_set(suffixless, arg_count, (mds_kbdc_tree_t*)function, function_include_stack);
- fail_if (*suffix_start = '/', r);
- return 0;
- fail:
- return -1;
+ char *suffixless = function->name;
+ char *suffix_start = strchr(suffixless, '/');
+ size_t arg_count = atoz(suffix_start + 1);
+ int r;
+
+ *suffix_start = '\0';
+ r = callables_set(suffixless, arg_count, (mds_kbdc_tree_t *)function, function_include_stack);
+ fail_if (*suffix_start = '/', r);
+ return 0;
+fail:
+ return -1;
}
@@ -1304,11 +1266,12 @@ static int set_function(mds_kbdc_tree_function_t* restrict function,
* @param function Output parameter for the function, `NULL` if not found
* @param function_include_stack Output parameter for the include-stack for the function
*/
-static void get_function_lax(const char* restrict function_name, size_t arg_count,
- mds_kbdc_tree_function_t** restrict function,
- mds_kbdc_include_stack_t** restrict function_include_stack)
+static void
+get_function_lax(const char *restrict function_name, size_t arg_count,
+ mds_kbdc_tree_function_t **restrict function,
+ mds_kbdc_include_stack_t **restrict function_include_stack)
{
- callables_get(function_name, arg_count, (mds_kbdc_tree_t**)function, function_include_stack);
+ callables_get(function_name, arg_count, (mds_kbdc_tree_t **)function, function_include_stack);
}
@@ -1318,21 +1281,23 @@ static void get_function_lax(const char* restrict function_name, size_t arg_coun
* @param value The value the function should return
* @return Zero on success, 1 if no function is currently being called
*/
-static int set_return_value(char32_t* restrict value)
+static int
+set_return_value(char32_t *restrict value)
{
- if (current_return_value == NULL)
- return free(value), 1;
- free(*current_return_value);
- *current_return_value = value;
- return 0;
+ if (!current_return_value)
+ return free(value), 1;
+ free(*current_return_value);
+ *current_return_value = value;
+ return 0;
}
-static int add_mapping(mds_kbdc_tree_map_t* restrict mapping, mds_kbdc_include_stack_t* restrict include_stack)
+static int
+add_mapping(mds_kbdc_tree_map_t *restrict mapping, mds_kbdc_include_stack_t *restrict include_stack)
{
- mds_kbdc_tree_free((mds_kbdc_tree_t*)mapping);
- mds_kbdc_include_stack_free(include_stack);
- return 0; /* TODO */
+ mds_kbdc_tree_free((mds_kbdc_tree_t *)mapping);
+ mds_kbdc_include_stack_free(include_stack);
+ return 0; /* TODO */
}
@@ -1346,23 +1311,24 @@ static int add_mapping(mds_kbdc_tree_map_t* restrict mapping, mds_kbdc_include_s
* @param tree The tree to compile
* @return Zero on success, -1 on error
*/
-static int compile_include(mds_kbdc_tree_include_t* restrict tree)
+static int
+compile_include(mds_kbdc_tree_include_t *restrict tree)
{
- void* data;
- int r;
- fail_if (mds_kbdc_include_stack_push(tree, &data));
- r = compile_subtree(tree->inner);
- mds_kbdc_include_stack_pop(data);
-
- /* For simplicity we set `last_value_statement` on includes,
- * so we are sure `last_value_statement` has the same
- * include-stack as its overriding statement. */
- last_value_statement = NULL;
-
- fail_if (r);
- return 0;
- fail:
- return -1;
+ void *data;
+ int r;
+ fail_if (mds_kbdc_include_stack_push(tree, &data));
+ r = compile_subtree(tree->inner);
+ mds_kbdc_include_stack_pop(data);
+
+ /* For simplicity we set `last_value_statement` on includes,
+ * so we are sure `last_value_statement` has the same
+ * include-stack as its overriding statement. */
+ last_value_statement = NULL;
+
+ fail_if (r);
+ return 0;
+fail:
+ return -1;
}
@@ -1372,39 +1338,39 @@ static int compile_include(mds_kbdc_tree_include_t* restrict tree)
* @param tree The tree to compile
* @return Zero on success, -1 on error
*/
-static int compile_language(mds_kbdc_tree_information_language_t* restrict tree)
+static int
+compile_language(mds_kbdc_tree_information_language_t *restrict tree)
{
- size_t lineoff;
- char* restrict code = result->source_code->real_lines[tree->loc_line];
- char32_t* restrict data = NULL;
- char** old = NULL;
- int saved_errno;
-
- /* Make sure the language-list fits another entry. */
- if (result->languages_ptr == result->languages_size)
- {
- result->languages_size = result->languages_size ? (result->languages_size << 1) : 1;
- fail_if (xxrealloc(old, result->languages, result->languages_size, char*));
- }
-
- /* Locate the first character in the language-string. */
- for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++);
- /* Evaluate function calls, variable dereferences and escapes in the language-string. */
- fail_if (data = parse_string((mds_kbdc_tree_t*)tree, tree->data, lineoff), data == NULL);
- if (tree->processed == PROCESS_LEVEL)
- return free(data), 0;
- /* We want the string in UTF-8, not UTF-16. */
- fail_if (code = string_encode(data), code == NULL);
- free(data);
-
- /* Add the language to the language-list. */
- result->languages[result->languages_ptr++] = code;
-
- return 0;
- FAIL_BEGIN;
- free(old);
- free(data);
- FAIL_END;
+ size_t lineoff;
+ char *restrict code = result->source_code->real_lines[tree->loc_line];
+ char32_t *restrict data = NULL;
+ char **old = NULL;
+ int saved_errno;
+
+ /* Make sure the language-list fits another entry. */
+ if (result->languages_ptr == result->languages_size) {
+ result->languages_size = result->languages_size ? (result->languages_size << 1) : 1;
+ fail_if (xxrealloc(old, result->languages, result->languages_size, char*));
+ }
+
+ /* Locate the first character in the language-string. */
+ for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++);
+ /* Evaluate function calls, variable dereferences and escapes in the language-string. */
+ fail_if (!(data = parse_string((mds_kbdc_tree_t*)tree, tree->data, lineoff)));
+ if (tree->processed == PROCESS_LEVEL)
+ return free(data), 0;
+ /* We want the string in UTF-8, not UTF-16. */
+ fail_if (!(code = string_encode(data)));
+ free(data);
+
+ /* Add the language to the language-list. */
+ result->languages[result->languages_ptr++] = code;
+
+ return 0;
+ FAIL_BEGIN;
+ free(old);
+ free(data);
+ FAIL_END;
}
@@ -1414,39 +1380,39 @@ static int compile_language(mds_kbdc_tree_information_language_t* restrict tree)
* @param tree The tree to compile
* @return Zero on success, -1 on error
*/
-static int compile_country(mds_kbdc_tree_information_country_t* restrict tree)
+static int
+compile_country(mds_kbdc_tree_information_country_t *restrict tree)
{
- size_t lineoff;
- char* restrict code = result->source_code->real_lines[tree->loc_line];
- char32_t* restrict data = NULL;
- char** old = NULL;
- int saved_errno;
-
- /* Make sure the country-list fits another entry. */
- if (result->countries_ptr == result->countries_size)
- {
- result->countries_size = result->countries_size ? (result->countries_size << 1) : 1;
- fail_if (xxrealloc(old, result->countries, result->countries_size, char*));
- }
-
- /* Locate the first character in the country-string. */
- for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++);
- /* Evaluate function calls, variable dereferences and escapes in the country-string. */
- fail_if (data = parse_string((mds_kbdc_tree_t*)tree, tree->data, lineoff), data == NULL);
- if (tree->processed == PROCESS_LEVEL)
- return free(data), 0;
- /* We want the string in UTF-8, not UTF-16. */
- fail_if (code = string_encode(data), code == NULL);
- free(data);
-
- /* Add the country to the country-list. */
- result->countries[result->countries_ptr++] = code;
-
- return 0;
- FAIL_BEGIN;
- free(old);
- free(data);
- FAIL_END;
+ size_t lineoff;
+ char *restrict code = result->source_code->real_lines[tree->loc_line];
+ char32_t *restrict data = NULL;
+ char **old = NULL;
+ int saved_errno;
+
+ /* Make sure the country-list fits another entry. */
+ if (result->countries_ptr == result->countries_size) {
+ result->countries_size = result->countries_size ? (result->countries_size << 1) : 1;
+ fail_if (xxrealloc(old, result->countries, result->countries_size, char *));
+ }
+
+ /* Locate the first character in the country-string. */
+ for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++);
+ /* Evaluate function calls, variable dereferences and escapes in the country-string. */
+ fail_if (!(data = parse_string((mds_kbdc_tree_t*)tree, tree->data, lineoff)));
+ if (tree->processed == PROCESS_LEVEL)
+ return free(data), 0;
+ /* We want the string in UTF-8, not UTF-16. */
+ fail_if (!(code = string_encode(data)));
+ free(data);
+
+ /* Add the country to the country-list. */
+ result->countries[result->countries_ptr++] = code;
+
+ return 0;
+ FAIL_BEGIN;
+ free(old);
+ free(data);
+ FAIL_END;
}
@@ -1456,39 +1422,39 @@ static int compile_country(mds_kbdc_tree_information_country_t* restrict tree)
* @param tree The tree to compile
* @return Zero on success, -1 on error
*/
-static int compile_variant(mds_kbdc_tree_information_variant_t* restrict tree)
+static int
+compile_variant(mds_kbdc_tree_information_variant_t *restrict tree)
{
- size_t lineoff;
- char* restrict code = result->source_code->real_lines[tree->loc_line];
- char32_t* restrict data = NULL;
- int saved_errno;
-
- /* Make sure the variant has not already been set. */
- if (result->variant)
- {
- if (multiple_variants == 0)
- NEW_ERROR(tree, ERROR, "only one ‘variant’ is allowed");
- multiple_variants = 1;
- return 0;
- }
-
- /* Locate the first character in the variant-string. */
- for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++);
- /* Evaluate function calls, variable dereferences and escapes in the variant-string. */
- fail_if (data = parse_string((mds_kbdc_tree_t*)tree, tree->data, lineoff), data == NULL);
- if (tree->processed == PROCESS_LEVEL)
- return free(data), 0;
- /* We want the string in UTF-8, not UTF-16. */
- fail_if (code = string_encode(data), code == NULL);
- free(data);
-
- /* Store the variant. */
- result->variant = code;
-
- return 0;
- FAIL_BEGIN;
- free(data);
- FAIL_END;
+ size_t lineoff;
+ char *restrict code = result->source_code->real_lines[tree->loc_line];
+ char32_t *restrict data = NULL;
+ int saved_errno;
+
+ /* Make sure the variant has not already been set. */
+ if (result->variant) {
+ if (!multiple_variants)
+ NEW_ERROR(tree, ERROR, "only one ‘variant’ is allowed");
+ multiple_variants = 1;
+ return 0;
+ }
+
+ /* Locate the first character in the variant-string. */
+ for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++);
+ /* Evaluate function calls, variable dereferences and escapes in the variant-string. */
+ fail_if (!(data = parse_string((mds_kbdc_tree_t*)tree, tree->data, lineoff)));
+ if (tree->processed == PROCESS_LEVEL)
+ return free(data), 0;
+ /* We want the string in UTF-8, not UTF-16. */
+ fail_if (!(code = string_encode(data)));
+ free(data);
+
+ /* Store the variant. */
+ result->variant = code;
+
+ return 0;
+ FAIL_BEGIN;
+ free(data);
+ FAIL_END;
}
@@ -1498,54 +1464,50 @@ static int compile_variant(mds_kbdc_tree_information_variant_t* restrict tree)
* @param tree The tree to compile
* @return Zero on success, -1 on error
*/
-static int compile_have(mds_kbdc_tree_assumption_have_t* restrict tree)
+static int
+compile_have(mds_kbdc_tree_assumption_have_t *restrict tree)
{
- mds_kbdc_tree_t* node = tree->data;
- char32_t* data = NULL;
- char32_t** old = NULL;
- size_t new_size = 0;
- int saved_errno;
-
- /* Make sure we can fit all assumption in the assumption list (part 1/2). */
- new_size = (node->type == C(STRING)) ? result->assumed_strings_size : result->assumed_keys_size;
- new_size = new_size ? (new_size << 1) : 1;
-
- if (node->type == C(STRING))
- {
- /* Evaluate function calls, variable dereferences and escapes in the string. */
- fail_if (data = parse_string(node, node->string.string, node->loc_start), data == NULL);
- if (node->processed == PROCESS_LEVEL)
- return free(data), 0;
- /* Make sure we can fit all strings in the assumption list (part 2/2). */
- if (result->assumed_strings_ptr == result->assumed_strings_size)
- {
- fail_if (xxrealloc(old, result->assumed_strings, new_size, char32_t*));
- result->assumed_strings_size = new_size;
+ mds_kbdc_tree_t *node = tree->data;
+ char32_t *data = NULL, **old = NULL;
+ size_t new_size = 0;
+ int saved_errno;
+
+ /* Make sure we can fit all assumption in the assumption list (part 1/2). */
+ new_size = (node->type == C(STRING)) ? result->assumed_strings_size : result->assumed_keys_size;
+ new_size = new_size ? (new_size << 1) : 1;
+
+ if (node->type == C(STRING)) {
+ /* Evaluate function calls, variable dereferences and escapes in the string. */
+ fail_if (!(data = parse_string(node, node->string.string, node->loc_start)));
+ if (node->processed == PROCESS_LEVEL)
+ return free(data), 0;
+ /* Make sure we can fit all strings in the assumption list (part 2/2). */
+ if (result->assumed_strings_ptr == result->assumed_strings_size)
+ {
+ fail_if (xxrealloc(old, result->assumed_strings, new_size, char32_t*));
+ result->assumed_strings_size = new_size;
+ }
+ /* Add the assumption to the list. */
+ result->assumed_strings[result->assumed_strings_ptr++] = data;
+ } else {
+ /* Evaluate function calls, variable dereferences and escapes in the key-combination. */
+ fail_if (!(data = parse_keys(node, node->keys.keys, node->loc_start)));
+ if (node->processed == PROCESS_LEVEL)
+ return free(data), 0;
+ /* Make sure we can fit all key-combinations in the assumption list (part 2/2). */
+ if (result->assumed_keys_ptr == result->assumed_keys_size) {
+ fail_if (xxrealloc(old, result->assumed_keys, new_size, char32_t*));
+ result->assumed_keys_size = new_size;
+ }
+ /* Add the assumption to the list. */
+ result->assumed_keys[result->assumed_keys_ptr++] = data;
}
- /* Add the assumption to the list. */
- result->assumed_strings[result->assumed_strings_ptr++] = data;
- }
- else
- {
- /* Evaluate function calls, variable dereferences and escapes in the key-combination. */
- fail_if (data = parse_keys(node, node->keys.keys, node->loc_start), data == NULL);
- if (node->processed == PROCESS_LEVEL)
- return free(data), 0;
- /* Make sure we can fit all key-combinations in the assumption list (part 2/2). */
- if (result->assumed_keys_ptr == result->assumed_keys_size)
- {
- fail_if (xxrealloc(old, result->assumed_keys, new_size, char32_t*));
- result->assumed_keys_size = new_size;
- }
- /* Add the assumption to the list. */
- result->assumed_keys[result->assumed_keys_ptr++] = data;
- }
-
- return 0;
- FAIL_BEGIN;
- free(old);
- free(data);
- FAIL_END;
+
+ return 0;
+ FAIL_BEGIN;
+ free(old);
+ free(data);
+ FAIL_END;
}
@@ -1555,47 +1517,46 @@ static int compile_have(mds_kbdc_tree_assumption_have_t* restrict tree)
* @param tree The tree to compile
* @return Zero on success, -1 on error
*/
-static int compile_have_chars(mds_kbdc_tree_assumption_have_chars_t* restrict tree)
+static int
+compile_have_chars(mds_kbdc_tree_assumption_have_chars_t *restrict tree)
{
- size_t lineoff;
- char* restrict code = result->source_code->real_lines[tree->loc_line];
- char32_t* restrict data = NULL;
- char32_t** old = NULL;
- char32_t* restrict character;
- size_t n;
- int saved_errno;
-
- /* Locate the first character in the list. */
- for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++);
- /* Evaluate function calls, variable dereferences
- and escapes in the charcter list. */
- fail_if (data = parse_string((mds_kbdc_tree_t*)tree, tree->chars, lineoff), data == NULL);
- if (tree->processed == PROCESS_LEVEL)
- return free(data), 0;
-
- /* Make sure we can fit all characters in the assumption list. */
- for (n = 0; data[n] >= 0; n++);
- if (result->assumed_strings_ptr + n > result->assumed_strings_size)
- {
- result->assumed_strings_size += n;
- fail_if (xxrealloc(old, result->assumed_strings, result->assumed_strings_size, char32_t*));
- }
-
- /* Add all characters to the assumption list. */
- while (n--)
- {
- fail_if (xmalloc(character, 2, char32_t));
- character[0] = data[n];
- character[1] = -1;
- result->assumed_strings[result->assumed_strings_ptr++] = character;
- }
-
- free(data);
- return 0;
- FAIL_BEGIN;
- free(data);
- free(old);
- FAIL_END;
+ size_t lineoff;
+ char *restrict code = result->source_code->real_lines[tree->loc_line];
+ char32_t *restrict data = NULL;
+ char32_t **old = NULL;
+ char32_t *restrict character;
+ size_t n;
+ int saved_errno;
+
+ /* Locate the first character in the list. */
+ for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++);
+ /* Evaluate function calls, variable dereferences
+ and escapes in the charcter list. */
+ fail_if (!(data = parse_string((mds_kbdc_tree_t*)tree, tree->chars, lineoff)));
+ if (tree->processed == PROCESS_LEVEL)
+ return free(data), 0;
+
+ /* Make sure we can fit all characters in the assumption list. */
+ for (n = 0; data[n] >= 0; n++);
+ if (result->assumed_strings_ptr + n > result->assumed_strings_size) {
+ result->assumed_strings_size += n;
+ fail_if (xxrealloc(old, result->assumed_strings, result->assumed_strings_size, char32_t *));
+ }
+
+ /* Add all characters to the assumption list. */
+ while (n--) {
+ fail_if (xmalloc(character, 2, char32_t));
+ character[0] = data[n];
+ character[1] = -1;
+ result->assumed_strings[result->assumed_strings_ptr++] = character;
+ }
+
+ free(data);
+ return 0;
+ FAIL_BEGIN;
+ free(data);
+ free(old);
+ FAIL_END;
}
@@ -1605,88 +1566,85 @@ static int compile_have_chars(mds_kbdc_tree_assumption_have_chars_t* restrict tr
* @param tree The tree to compile
* @return Zero on success, -1 on error
*/
-static int compile_have_range(mds_kbdc_tree_assumption_have_range_t* restrict tree)
+static int
+compile_have_range(mds_kbdc_tree_assumption_have_range_t *restrict tree)
{
- size_t lineoff_first;
- size_t lineoff_last;
- char* restrict code = result->source_code->real_lines[tree->loc_line];
- char32_t* restrict first = NULL;
- char32_t* restrict last = NULL;
- char32_t** old = NULL;
- char32_t* restrict character;
- size_t n;
- int saved_errno;
-
-
- /* Locate the first characters of both bound strings. */
- for (lineoff_first = tree->loc_end; code[lineoff_first] == ' '; lineoff_first++);
- for (lineoff_last = lineoff_first + strlen(tree->first); code[lineoff_last] == ' '; lineoff_last++);
-
- /* Duplicate bounds and evaluate function calls,
- variable dereferences and escapes in the bounds. */
- fail_if (first = parse_string((mds_kbdc_tree_t*)tree, tree->first, lineoff_first), first == NULL);
- fail_if (last = parse_string((mds_kbdc_tree_t*)tree, tree->last, lineoff_last), last == NULL);
-
- /* Did one of the bound not evaluate, then stop. */
- if (tree->processed == PROCESS_LEVEL)
- goto done;
-
-
- /* Check that the primary bound is single-character. */
- if ((first[0] == -1) || (first[1] != -1))
- {
- NEW_ERROR(tree, ERROR, "iteration boundary must be a single character string");
- error->start = lineoff_first, lineoff_first = 0;
- error->end = error->start + strlen(tree->first);
- }
- /* Check that the secondary bound is single-character. */
- if ((last[0] == -1) || (last[1] != -1))
- {
- NEW_ERROR(tree, ERROR, "iteration boundary must be a single character string");
- error->start = lineoff_last, lineoff_last = 0;
- error->end = error->start + strlen(tree->last);
- }
-
- /* Was one of the bounds not single-character, then stop. */
- if ((lineoff_first == 0) || (lineoff_last == 0))
- goto done;
-
-
- /* If the range is descending, swap the bounds so it is ascending.
- (This cannot be done in for-loops as that may cause side-effects
- to be created in the wrong order.) */
- if (*first > *last)
- *first ^= *last, *last ^= *first, *first ^= *last;
-
- /* Make sure we can fit all characters in the assumption list. */
- n = (size_t)(*last - *first) + 1;
- if (result->assumed_strings_ptr + n > result->assumed_strings_size)
- {
- result->assumed_strings_size += n;
- fail_if (xxrealloc(old, result->assumed_strings, result->assumed_strings_size, char32_t*));
- }
-
- /* Add all characters to the assumption list. */
- for (;;)
- {
- fail_if (xmalloc(character, 2, char32_t));
- character[0] = *first;
- character[1] = -1;
- result->assumed_strings[result->assumed_strings_ptr++] = character;
- /* Bounds are inclusive. */
- if ((*first)++ == *last)
- break;
- }
-
- done:
- free(first);
- free(last);
- return 0;
- FAIL_BEGIN;
- free(first);
- free(last);
- free(old);
- FAIL_END;
+ size_t lineoff_first;
+ size_t lineoff_last;
+ char *restrict code = result->source_code->real_lines[tree->loc_line];
+ char32_t *restrict first = NULL;
+ char32_t *restrict last = NULL;
+ char32_t **old = NULL;
+ char32_t *restrict character;
+ size_t n;
+ int saved_errno;
+
+
+ /* Locate the first characters of both bound strings. */
+ for (lineoff_first = tree->loc_end; code[lineoff_first] == ' '; lineoff_first++);
+ for (lineoff_last = lineoff_first + strlen(tree->first); code[lineoff_last] == ' '; lineoff_last++);
+
+ /* Duplicate bounds and evaluate function calls,
+ variable dereferences and escapes in the bounds. */
+ fail_if (!(first = parse_string((mds_kbdc_tree_t*)tree, tree->first, lineoff_first)));
+ fail_if (!(last = parse_string((mds_kbdc_tree_t*)tree, tree->last, lineoff_last)));
+
+ /* Did one of the bound not evaluate, then stop. */
+ if (tree->processed == PROCESS_LEVEL)
+ goto done;
+
+
+ /* Check that the primary bound is single-character. */
+ if (first[0] == -1 || first[1] != -1) {
+ NEW_ERROR(tree, ERROR, "iteration boundary must be a single character string");
+ error->start = lineoff_first, lineoff_first = 0;
+ error->end = error->start + strlen(tree->first);
+ }
+ /* Check that the secondary bound is single-character. */
+ if (last[0] == -1 || last[1] != -1) {
+ NEW_ERROR(tree, ERROR, "iteration boundary must be a single character string");
+ error->start = lineoff_last, lineoff_last = 0;
+ error->end = error->start + strlen(tree->last);
+ }
+
+ /* Was one of the bounds not single-character, then stop. */
+ if (!lineoff_first || !lineoff_last)
+ goto done;
+
+
+ /* If the range is descending, swap the bounds so it is ascending.
+ (This cannot be done in for-loops as that may cause side-effects
+ to be created in the wrong order.) */
+ if (*first > *last)
+ *first ^= *last, *last ^= *first, *first ^= *last;
+
+ /* Make sure we can fit all characters in the assumption list. */
+ n = (size_t)(*last - *first) + 1;
+ if (result->assumed_strings_ptr + n > result->assumed_strings_size) {
+ result->assumed_strings_size += n;
+ fail_if (xxrealloc(old, result->assumed_strings, result->assumed_strings_size, char32_t *));
+ }
+
+ /* Add all characters to the assumption list. */
+ for (;;) {
+ fail_if (xmalloc(character, 2, char32_t));
+ character[0] = *first;
+ character[1] = -1;
+ result->assumed_strings[result->assumed_strings_ptr++] = character;
+ /* Bounds are inclusive. */
+ if ((*first)++ == *last)
+ break;
+ }
+
+done:
+ free(first);
+ free(last);
+ return 0;
+ FAIL_BEGIN;
+ free(first);
+ free(last);
+ free(old);
+ FAIL_END;
}
@@ -1696,47 +1654,48 @@ static int compile_have_range(mds_kbdc_tree_assumption_have_range_t* restrict tr
* @param tree The tree to evaluate
* @return Zero on success, -1 on error, 1 if an undefined macro is used
*/
-static int check_marco_calls(mds_kbdc_tree_t* restrict tree)
+static int
+check_marco_calls(mds_kbdc_tree_t *restrict tree)
{
-#define t(...) fail_if (rc |= r = (__VA_ARGS__), r < 0)
- mds_kbdc_tree_macro_t* _macro;
- mds_kbdc_include_stack_t* _macro_include_stack;
- void* data;
- int r, rc = 0;
- again:
- if (tree == NULL)
- return rc;
-
- switch (tree->type)
- {
- case C(INCLUDE):
- t (mds_kbdc_include_stack_push(&(tree->include), &data));
- t (r = check_marco_calls(tree->include.inner), mds_kbdc_include_stack_pop(data), r);
- break;
-
- case C(FOR):
- t (check_marco_calls(tree->for_.inner));
- break;
-
- case C(IF):
- t (check_marco_calls(tree->if_.inner));
- t (check_marco_calls(tree->if_.otherwise));
- break;
-
- case C(MACRO_CALL):
- t (get_macro(&(tree->macro_call), &_macro, &_macro_include_stack));
- break;
-
- default:
- break;
- }
-
- tree = tree->next;
- goto again;
- fail:
- return -1;
- (void) _macro;
- (void) _macro_include_stack;
+#define t(...) fail_if (rc |= r = (__VA_ARGS__), r < 0)
+ mds_kbdc_tree_macro_t *_macro;
+ mds_kbdc_include_stack_t *_macro_include_stack;
+ void *data;
+ int r, rc = 0;
+
+again:
+ if (!tree)
+ return rc;
+
+ switch (tree->type) {
+ case C(INCLUDE):
+ t (mds_kbdc_include_stack_push(&(tree->include), &data));
+ t (r = check_marco_calls(tree->include.inner), mds_kbdc_include_stack_pop(data), r);
+ break;
+
+ case C(FOR):
+ t (check_marco_calls(tree->for_.inner));
+ break;
+
+ case C(IF):
+ t (check_marco_calls(tree->if_.inner));
+ t (check_marco_calls(tree->if_.otherwise));
+ break;
+
+ case C(MACRO_CALL):
+ t (get_macro(&(tree->macro_call), &_macro, &_macro_include_stack));
+ break;
+
+ default:
+ break;
+ }
+
+ tree = tree->next;
+ goto again;
+fail:
+ return -1;
+ (void) _macro;
+ (void) _macro_include_stack;
#undef t
}
@@ -1747,24 +1706,25 @@ static int check_marco_calls(mds_kbdc_tree_t* restrict tree)
* @param tree The tree to evaluate
* @return Zero on success, -1 on error, 1 if an undefined function is used
*/
-static int check_function_calls_in_for(const mds_kbdc_tree_for_t* restrict tree)
+static int
+check_function_calls_in_for(const mds_kbdc_tree_for_t *restrict tree)
{
-#define t(...) fail_if (rc |= r = check_function_calls_in_literal(__VA_ARGS__), r < 0)
- size_t lineoff_first;
- size_t lineoff_last;
- char* restrict code = result->source_code->real_lines[tree->loc_line];
- int r, rc = 0;
-
- for (lineoff_first = tree->loc_end; code[lineoff_first] == ' '; lineoff_first++);
- for (lineoff_last = lineoff_first + strlen(tree->first); code[lineoff_last] == ' '; lineoff_last++);
- for (lineoff_last += strlen("to"); code[lineoff_last] == ' '; lineoff_last++);
-
- t ((const mds_kbdc_tree_t*)tree, tree->first, lineoff_first);
- t ((const mds_kbdc_tree_t*)tree, tree->last, lineoff_last);
-
- return rc;
- fail:
- return -1;
+#define t(...) fail_if (rc |= r = check_function_calls_in_literal(__VA_ARGS__), r < 0)
+ size_t lineoff_first;
+ size_t lineoff_last;
+ char *restrict code = result->source_code->real_lines[tree->loc_line];
+ int r, rc = 0;
+
+ for (lineoff_first = tree->loc_end; code[lineoff_first] == ' '; lineoff_first++);
+ for (lineoff_last = lineoff_first + strlen(tree->first); code[lineoff_last] == ' '; lineoff_last++);
+ for (lineoff_last += strlen("to"); code[lineoff_last] == ' '; lineoff_last++);
+
+ t ((const mds_kbdc_tree_t *)tree, tree->first, lineoff_first);
+ t ((const mds_kbdc_tree_t *)tree, tree->last, lineoff_last);
+
+ return rc;
+fail:
+ return -1;
#undef t
}
@@ -1775,17 +1735,18 @@ static int check_function_calls_in_for(const mds_kbdc_tree_for_t* restrict tree)
* @param tree The tree to evaluate
* @return Zero on success, -1 on error, 1 if an undefined function is used
*/
-static int check_function_calls_in_if(const mds_kbdc_tree_if_t* restrict tree)
+static int
+check_function_calls_in_if(const mds_kbdc_tree_if_t *restrict tree)
{
- size_t lineoff;
- char* restrict code = result->source_code->real_lines[tree->loc_line];
- int r;
-
- for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++);
- r = check_function_calls_in_literal((const mds_kbdc_tree_t*)tree, tree->condition, lineoff);
- fail_if (r < 0);
- fail:
- return r;
+ size_t lineoff;
+ char *restrict code = result->source_code->real_lines[tree->loc_line];
+ int r;
+
+ for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++);
+ r = check_function_calls_in_literal((const mds_kbdc_tree_t *)tree, tree->condition, lineoff);
+ fail_if (r < 0);
+fail:
+ return r;
}
@@ -1795,13 +1756,14 @@ static int check_function_calls_in_if(const mds_kbdc_tree_if_t* restrict tree)
* @param tree The tree to evaluate
* @return Zero on success, -1 on error, 1 if an undefined function is used
*/
-static int check_function_calls_in_keys(const mds_kbdc_tree_keys_t* restrict tree)
+static int
+check_function_calls_in_keys(const mds_kbdc_tree_keys_t *restrict tree)
{
- int r;
- r = check_function_calls_in_literal((const mds_kbdc_tree_t*)tree, tree->keys, tree->loc_start);
- fail_if (r < 0);
- fail:
- return r;
+ int r;
+ r = check_function_calls_in_literal((const mds_kbdc_tree_t *)tree, tree->keys, tree->loc_start);
+ fail_if (r < 0);
+fail:
+ return r;
}
@@ -1811,13 +1773,14 @@ static int check_function_calls_in_keys(const mds_kbdc_tree_keys_t* restrict tre
* @param tree The tree to evaluate
* @return Zero on success, -1 on error, 1 if an undefined function is used
*/
-static int check_function_calls_in_string(const mds_kbdc_tree_string_t* restrict tree)
+static int
+check_function_calls_in_string(const mds_kbdc_tree_string_t *restrict tree)
{
- int r;
- r = check_function_calls_in_literal((const mds_kbdc_tree_t*)tree, tree->string, tree->loc_start);
- fail_if (r < 0);
- fail:
- return r;
+ int r;
+ r = check_function_calls_in_literal((const mds_kbdc_tree_t *)tree, tree->string, tree->loc_start);
+ fail_if (r < 0);
+fail:
+ return r;
}
@@ -1827,46 +1790,47 @@ static int check_function_calls_in_string(const mds_kbdc_tree_string_t* restrict
* @param tree The tree to evaluate
* @return Zero on success, -1 on error, 1 if an undefined function is used
*/
-static int check_function_calls(const mds_kbdc_tree_t* restrict tree)
+static int
+check_function_calls(const mds_kbdc_tree_t *restrict tree)
{
-#define t(...) fail_if (rc |= r = (__VA_ARGS__), r < 0)
- void* data;
- int r, rc = 0;
- again:
- if (tree == NULL)
- return rc;
-
- switch (tree->type)
- {
- case C(INCLUDE):
- t (mds_kbdc_include_stack_push(&(tree->include), &data));
- t (r = check_function_calls(tree->include.inner), mds_kbdc_include_stack_pop(data), r);
- break;
-
- case C(FOR):
- t (check_function_calls_in_for(&(tree->for_)));
- t (check_function_calls(tree->for_.inner));
- break;
-
- case C(IF):
- t (check_function_calls_in_if(&(tree->if_)));
- t (check_function_calls(tree->if_.inner));
- t (check_function_calls(tree->if_.otherwise));
- break;
-
- case C(LET): t (check_function_calls(tree->let.value)); break;
- case C(ARRAY): t (check_function_calls(tree->array.elements)); break;
- case C(KEYS): t (check_function_calls_in_keys(&(tree->keys))); break;
- case C(STRING): t (check_function_calls_in_string(&(tree->string))); break;
- case C(MAP): t (check_function_calls(tree->map.sequence)); break;
- default:
- break;
- }
-
- tree = tree->next;
- goto again;
- fail:
- return -1;
+#define t(...) fail_if (rc |= r = (__VA_ARGS__), r < 0)
+ void *data;
+ int r, rc = 0;
+
+again:
+ if (!tree)
+ return rc;
+
+ switch (tree->type) {
+ case C(INCLUDE):
+ t (mds_kbdc_include_stack_push(&(tree->include), &data));
+ t (r = check_function_calls(tree->include.inner), mds_kbdc_include_stack_pop(data), r);
+ break;
+
+ case C(FOR):
+ t (check_function_calls_in_for(&(tree->for_)));
+ t (check_function_calls(tree->for_.inner));
+ break;
+
+ case C(IF):
+ t (check_function_calls_in_if(&(tree->if_)));
+ t (check_function_calls(tree->if_.inner));
+ t (check_function_calls(tree->if_.otherwise));
+ break;
+
+ case C(LET): t (check_function_calls(tree->let.value)); break;
+ case C(ARRAY): t (check_function_calls(tree->array.elements)); break;
+ case C(KEYS): t (check_function_calls_in_keys(&(tree->keys))); break;
+ case C(STRING): t (check_function_calls_in_string(&(tree->string))); break;
+ case C(MAP): t (check_function_calls(tree->map.sequence)); break;
+ default:
+ break;
+ }
+
+ tree = tree->next;
+ goto again;
+fail:
+ return -1;
#undef t
}
@@ -1877,52 +1841,50 @@ static int check_function_calls(const mds_kbdc_tree_t* restrict tree)
* @param tree The tree to inspect
* @return Zero on sucess, -1 on error, 1 if the name-suffix in invalid
*/
-static int check_name_suffix(struct mds_kbdc_tree_callable* restrict tree)
+static int
+check_name_suffix(struct mds_kbdc_tree_callable *restrict tree)
{
- const char* restrict name = strchr(tree->name, '/');
- const char* restrict code = result->source_code->real_lines[tree->loc_line];
-
- /* A "/" must exist in the name to tell us how many parameters there are. */
- if (name == NULL)
- {
- NEW_ERROR(tree, ERROR, "name-suffix is missing");
- goto name_error;
- }
- /* Do not let the suffix by just "/". */
- if (*++name == '\0')
- {
- NEW_ERROR(tree, ERROR, "empty name-suffix");
- goto name_error;
- }
-
- /* We are all good if the suffix is simply "/0" */
- if (!strcmp(name, "0"))
- return 0;
-
- /* The suffix may not have leading zeroes. */
- if (*name == '0')
- {
- NEW_ERROR(tree, ERROR, "leading zero in name-suffix");
- goto name_error;
- }
- /* The suffix must be a decimal, non-negative number. */
- for (; *name; name++)
- if ((*name < '0') || ('9' < *name))
- {
- NEW_ERROR(tree, ERROR, "name-suffix may only contain digits");
- goto name_error;
- }
-
- return 0;
- fail:
- return -1;
- name_error:
- error->start = tree->loc_end;
- while (code[error->start] == ' ')
- error->start++;
- error->end = error->start + strlen(tree->name);
- tree->processed = PROCESS_LEVEL;
- return 1;
+ const char *restrict name = strchr(tree->name, '/');
+ const char *restrict code = result->source_code->real_lines[tree->loc_line];
+
+ /* A "/" must exist in the name to tell us how many parameters there are. */
+ if (!name) {
+ NEW_ERROR(tree, ERROR, "name-suffix is missing");
+ goto name_error;
+ }
+ /* Do not let the suffix by just "/". */
+ if (!*++name) {
+ NEW_ERROR(tree, ERROR, "empty name-suffix");
+ goto name_error;
+ }
+
+ /* We are all good if the suffix is simply "/0" */
+ if (!strcmp(name, "0"))
+ return 0;
+
+ /* The suffix may not have leading zeroes. */
+ if (*name == '0') {
+ NEW_ERROR(tree, ERROR, "leading zero in name-suffix");
+ goto name_error;
+ }
+ /* The suffix must be a decimal, non-negative number. */
+ for (; *name; name++) {
+ if (*name < '0' || '9' < *name) {
+ NEW_ERROR(tree, ERROR, "name-suffix may only contain digits");
+ goto name_error;
+ }
+ }
+
+ return 0;
+fail:
+ return -1;
+name_error:
+ error->start = tree->loc_end;
+ while (code[error->start] == ' ')
+ error->start++;
+ error->end = error->start + strlen(tree->name);
+ tree->processed = PROCESS_LEVEL;
+ return 1;
}
@@ -1932,67 +1894,67 @@ static int check_name_suffix(struct mds_kbdc_tree_callable* restrict tree)
* @param tree The tree to compile
* @return Zero on success, -1 on error
*/
-static int compile_function(mds_kbdc_tree_function_t* restrict tree)
+static int
+compile_function(mds_kbdc_tree_function_t *restrict tree)
{
-#define t(expr) fail_if (r = (expr), r < 0); if (r) tree->processed = PROCESS_LEVEL
- mds_kbdc_tree_function_t* function;
- mds_kbdc_include_stack_t* function_include_stack;
- mds_kbdc_include_stack_t* our_include_stack = NULL;
- char* suffixless;
- char* suffix_start = NULL;
- size_t arg_count;
- int r, saved_errno;
-
- /* Check that the suffix if properly formatted. */
- t (check_name_suffix((struct mds_kbdc_tree_callable*)tree));
- if (r) return 0;
-
- /* Get the function's name without suffix, and parse the suffix. */
- suffixless = tree->name;
- suffix_start = strchr(suffixless, '/');
- *suffix_start++ = '\0';
- arg_count = atoz(suffix_start--);
-
- /* Check that the function is not already defined as a builtin function. */
- if (builtin_function_defined(suffixless, arg_count))
- {
- NEW_ERROR(tree, ERROR, "function ‘%s/%zu’ is already defined as a builtin function",
- tree->name, arg_count);
- *suffix_start = '/';
- return 0;
- }
- /* Check that the function is not already defined,
- the include-stack is used in the error-clause as
- well as later when we list the function as defined. */
- get_function_lax(suffixless, arg_count, &function, &function_include_stack);
- fail_if (our_include_stack = mds_kbdc_include_stack_save(), our_include_stack == NULL);
- if (function)
- {
- *suffix_start = '/';
- NEW_ERROR(tree, ERROR, "function ‘%s’ is already defined", tree->name);
- fail_if (mds_kbdc_include_stack_restore(function_include_stack));
- NEW_ERROR(function, NOTE, "previously defined here");
- fail_if (mds_kbdc_include_stack_restore(our_include_stack));
- mds_kbdc_include_stack_free(our_include_stack);
- return 0;
- }
-
- /* Check the the function does not call macros or functions
- * before they are defined, otherwise they may get defined
- * between the definition of the function and calls to it. */
- t (check_marco_calls(tree->inner));
- t (check_function_calls(tree->inner));
-
- /* List the function as defined. */
- *suffix_start = '/', suffix_start = NULL;
- t (set_function(tree, our_include_stack));
-
- return 0;
- FAIL_BEGIN;
- if (suffix_start)
- *suffix_start = '/';
- mds_kbdc_include_stack_free(our_include_stack);
- FAIL_END;
+#define t(expr) do { fail_if (r = (expr), r < 0); if (r) tree->processed = PROCESS_LEVEL; } while (0)
+ mds_kbdc_tree_function_t *function;
+ mds_kbdc_include_stack_t *function_include_stack;
+ mds_kbdc_include_stack_t *our_include_stack = NULL;
+ char *suffixless;
+ char *suffix_start = NULL;
+ size_t arg_count;
+ int r, saved_errno;
+
+ /* Check that the suffix if properly formatted. */
+ t (check_name_suffix((struct mds_kbdc_tree_callable*)tree));
+ if (r)
+ return 0;
+
+ /* Get the function's name without suffix, and parse the suffix. */
+ suffixless = tree->name;
+ suffix_start = strchr(suffixless, '/');
+ *suffix_start++ = '\0';
+ arg_count = atoz(suffix_start--);
+
+ /* Check that the function is not already defined as a builtin function. */
+ if (builtin_function_defined(suffixless, arg_count)) {
+ NEW_ERROR(tree, ERROR, "function ‘%s/%zu’ is already defined as a builtin function",
+ tree->name, arg_count);
+ *suffix_start = '/';
+ return 0;
+ }
+ /* Check that the function is not already defined,
+ the include-stack is used in the error-clause as
+ well as later when we list the function as defined. */
+ get_function_lax(suffixless, arg_count, &function, &function_include_stack);
+ fail_if (!(our_include_stack = mds_kbdc_include_stack_save(), our_include_stack));
+ if (function) {
+ *suffix_start = '/';
+ NEW_ERROR(tree, ERROR, "function ‘%s’ is already defined", tree->name);
+ fail_if (mds_kbdc_include_stack_restore(function_include_stack));
+ NEW_ERROR(function, NOTE, "previously defined here");
+ fail_if (mds_kbdc_include_stack_restore(our_include_stack));
+ mds_kbdc_include_stack_free(our_include_stack);
+ return 0;
+ }
+
+ /* Check the the function does not call macros or functions
+ * before they are defined, otherwise they may get defined
+ * between the definition of the function and calls to it. */
+ t (check_marco_calls(tree->inner));
+ t (check_function_calls(tree->inner));
+
+ /* List the function as defined. */
+ *suffix_start = '/', suffix_start = NULL;
+ t (set_function(tree, our_include_stack));
+
+ return 0;
+ FAIL_BEGIN;
+ if (suffix_start)
+ *suffix_start = '/';
+ mds_kbdc_include_stack_free(our_include_stack);
+ FAIL_END;
#undef t
}
@@ -2003,46 +1965,47 @@ static int compile_function(mds_kbdc_tree_function_t* restrict tree)
* @param tree The tree to compile
* @return Zero on success, -1 on error
*/
-static int compile_macro(mds_kbdc_tree_macro_t* restrict tree)
+static int
+compile_macro(mds_kbdc_tree_macro_t *restrict tree)
{
-#define t(expr) fail_if (r = (expr), r < 0); if (r) tree->processed = PROCESS_LEVEL
- mds_kbdc_tree_macro_t* macro;
- mds_kbdc_include_stack_t* macro_include_stack;
- mds_kbdc_include_stack_t* our_include_stack = NULL;
- int r, saved_errno;
-
- /* Check that the suffix if properly formatted. */
- t (check_name_suffix((struct mds_kbdc_tree_callable*)tree));
- if (r) return 0;
-
- /* Check that the macro is not already defined,
- the include-stack is used in the error-clause as
- well as later when we list the macro as defined. */
- fail_if (our_include_stack = mds_kbdc_include_stack_save(), our_include_stack == NULL);
- get_macro_lax(tree->name, &macro, &macro_include_stack);
- if (macro)
- {
- NEW_ERROR(tree, ERROR, "macro ‘%s’ is already defined", tree->name);
- fail_if (mds_kbdc_include_stack_restore(macro_include_stack));
- NEW_ERROR(macro, NOTE, "previously defined here");
- fail_if (mds_kbdc_include_stack_restore(our_include_stack));
- mds_kbdc_include_stack_free(our_include_stack);
- return 0;
- }
-
- /* Check the the macro does not call macros or functions
- * before they are defined, otherwise they may get defined
- * between the definition of the macro and calls to it. */
- t (check_marco_calls(tree->inner));
- t (check_function_calls(tree->inner));
-
- /* List the macro as defined. */
- t (set_macro(tree, our_include_stack));
-
- return 0;
- FAIL_BEGIN;
- mds_kbdc_include_stack_free(our_include_stack);
- FAIL_END;
+#define t(expr) do { fail_if (r = (expr), r < 0); if (r) tree->processed = PROCESS_LEVEL; } while (0)
+ mds_kbdc_tree_macro_t *macro;
+ mds_kbdc_include_stack_t *macro_include_stack;
+ mds_kbdc_include_stack_t *our_include_stack = NULL;
+ int r, saved_errno;
+
+ /* Check that the suffix if properly formatted. */
+ t (check_name_suffix((struct mds_kbdc_tree_callable*)tree));
+ if (r)
+ return 0;
+
+ /* Check that the macro is not already defined,
+ the include-stack is used in the error-clause as
+ well as later when we list the macro as defined. */
+ fail_if (!(our_include_stack = mds_kbdc_include_stack_save()));
+ get_macro_lax(tree->name, &macro, &macro_include_stack);
+ if (macro) {
+ NEW_ERROR(tree, ERROR, "macro ‘%s’ is already defined", tree->name);
+ fail_if (mds_kbdc_include_stack_restore(macro_include_stack));
+ NEW_ERROR(macro, NOTE, "previously defined here");
+ fail_if (mds_kbdc_include_stack_restore(our_include_stack));
+ mds_kbdc_include_stack_free(our_include_stack);
+ return 0;
+ }
+
+ /* Check the the macro does not call macros or functions
+ * before they are defined, otherwise they may get defined
+ * between the definition of the macro and calls to it. */
+ t (check_marco_calls(tree->inner));
+ t (check_function_calls(tree->inner));
+
+ /* List the macro as defined. */
+ t (set_macro(tree, our_include_stack));
+
+ return 0;
+ FAIL_BEGIN;
+ mds_kbdc_include_stack_free(our_include_stack);
+ FAIL_END;
#undef t
}
@@ -2053,94 +2016,92 @@ static int compile_macro(mds_kbdc_tree_macro_t* restrict tree)
* @param tree The tree to compile
* @return Zero on success, -1 on error
*/
-static int compile_for(mds_kbdc_tree_for_t* restrict tree)
+static int
+compile_for(mds_kbdc_tree_for_t *restrict tree)
{
- size_t lineoff_first;
- size_t lineoff_last;
- size_t lineoff_var;
- char* restrict code = result->source_code->real_lines[tree->loc_line];
- char32_t* restrict first = NULL;
- char32_t* restrict last = NULL;
- char32_t diff;
- char32_t character[2];
- size_t variable;
- int possible_shadow = 1, saved_errno;
-
-
- last_value_statement = NULL;
-
-
- /* Locate the first character of the primary bound's string. */
- for (lineoff_first = tree->loc_end; code[lineoff_first] == ' '; lineoff_first++);
- /* Locate the first character of the secondary bound's string. */
- for (lineoff_last = lineoff_first + strlen(tree->first); code[lineoff_last] == ' '; lineoff_last++);
- for (lineoff_last += strlen("to"); code[lineoff_last] == ' '; lineoff_last++);
- /* Locate the first character of the select variable. */
- for (lineoff_var = lineoff_last + strlen(tree->last); code[lineoff_var] == ' '; lineoff_var++);
- for (lineoff_var += strlen("as"); code[lineoff_var] == ' '; lineoff_var++);
-
- /* Duplicate bounds and evaluate function calls,
- variable dereferences and escapes in the bounds. */
- fail_if (first = parse_string((mds_kbdc_tree_t*)tree, tree->first, lineoff_first), first == NULL);
- fail_if (last = parse_string((mds_kbdc_tree_t*)tree, tree->last, lineoff_last), last == NULL);
- /* Get the index of the selected variable. */
- fail_if (variable = parse_variable((mds_kbdc_tree_t*)tree, tree->variable, lineoff_var), variable == 0);
-
- /* Did one of the bound not evaluate, then stop. */
- if (tree->processed == PROCESS_LEVEL)
- goto done;
-
-
- /* Check that the primary bound is single-character. */
- if ((first[0] == -1) || (first[1] != -1))
- {
- NEW_ERROR(tree, ERROR, "iteration boundary must be a single character string");
- error->start = lineoff_first, lineoff_first = 0;
- error->end = error->start + strlen(tree->first);
- }
- /* Check that the secondary bound is single-character. */
- if ((last[0] == -1) || (last[1] != -1))
- {
- NEW_ERROR(tree, ERROR, "iteration boundary must be a single character string");
- error->start = lineoff_last, lineoff_last = 0;
- error->end = error->start + strlen(tree->last);
- }
-
- /* Was one of the bounds not single-character, then stop. */
- if ((lineoff_first == 0) || (lineoff_last == 0))
- goto done;
-
-
- /* Iterate over the loop for as long as a `return` or `break` has not
- been encountered (without being caught elsewhere). */
- character[1] = -1;
- for (diff = (*first > *last) ? -1 : +1; break_level < 2; *first += diff)
- {
- break_level = 0;
- character[0] = *first;
- fail_if (let(variable, character, NULL, (mds_kbdc_tree_t*)tree, lineoff_var, possible_shadow));
- possible_shadow = 0;
- fail_if (compile_subtree(tree->inner));
- /* Bounds are inclusive. */
- if (*first == *last)
- break;
- }
- fail_if (variables_was_used_in_for(variable));
-
- /* Catch `break` and `continue`, they may not propagate further. */
- if (break_level < 3)
- break_level = 0;
-
-
- done:
- last_value_statement = NULL;
- free(first);
- free(last);
- return 0;
- FAIL_BEGIN;
- free(first);
- free(last);
- FAIL_END;
+ size_t lineoff_first;
+ size_t lineoff_last;
+ size_t lineoff_var;
+ char *restrict code = result->source_code->real_lines[tree->loc_line];
+ char32_t *restrict first = NULL;
+ char32_t *restrict last = NULL;
+ char32_t diff;
+ char32_t character[2];
+ size_t variable;
+ int possible_shadow = 1, saved_errno;
+
+
+ last_value_statement = NULL;
+
+
+ /* Locate the first character of the primary bound's string. */
+ for (lineoff_first = tree->loc_end; code[lineoff_first] == ' '; lineoff_first++);
+ /* Locate the first character of the secondary bound's string. */
+ for (lineoff_last = lineoff_first + strlen(tree->first); code[lineoff_last] == ' '; lineoff_last++);
+ for (lineoff_last += strlen("to"); code[lineoff_last] == ' '; lineoff_last++);
+ /* Locate the first character of the select variable. */
+ for (lineoff_var = lineoff_last + strlen(tree->last); code[lineoff_var] == ' '; lineoff_var++);
+ for (lineoff_var += strlen("as"); code[lineoff_var] == ' '; lineoff_var++);
+
+ /* Duplicate bounds and evaluate function calls,
+ variable dereferences and escapes in the bounds. */
+ fail_if (!(first = parse_string((mds_kbdc_tree_t*)tree, tree->first, lineoff_first)));
+ fail_if (!(last = parse_string((mds_kbdc_tree_t*)tree, tree->last, lineoff_last)));
+ /* Get the index of the selected variable. */
+ fail_if (variable = parse_variable((mds_kbdc_tree_t*)tree, tree->variable, lineoff_var), variable == 0);
+
+ /* Did one of the bound not evaluate, then stop. */
+ if (tree->processed == PROCESS_LEVEL)
+ goto done;
+
+
+ /* Check that the primary bound is single-character. */
+ if (first[0] == -1 || first[1] != -1) {
+ NEW_ERROR(tree, ERROR, "iteration boundary must be a single character string");
+ error->start = lineoff_first, lineoff_first = 0;
+ error->end = error->start + strlen(tree->first);
+ }
+ /* Check that the secondary bound is single-character. */
+ if (last[0] == -1 || last[1] != -1) {
+ NEW_ERROR(tree, ERROR, "iteration boundary must be a single character string");
+ error->start = lineoff_last, lineoff_last = 0;
+ error->end = error->start + strlen(tree->last);
+ }
+
+ /* Was one of the bounds not single-character, then stop. */
+ if (!lineoff_first || !lineoff_last)
+ goto done;
+
+
+ /* Iterate over the loop for as long as a `return` or `break` has not
+ been encountered (without being caught elsewhere). */
+ character[1] = -1;
+ for (diff = (*first > *last) ? -1 : +1; break_level < 2; *first += diff) {
+ break_level = 0;
+ character[0] = *first;
+ fail_if (let(variable, character, NULL, (mds_kbdc_tree_t*)tree, lineoff_var, possible_shadow));
+ possible_shadow = 0;
+ fail_if (compile_subtree(tree->inner));
+ /* Bounds are inclusive. */
+ if (*first == *last)
+ break;
+ }
+ fail_if (variables_was_used_in_for(variable));
+
+ /* Catch `break` and `continue`, they may not propagate further. */
+ if (break_level < 3)
+ break_level = 0;
+
+
+done:
+ last_value_statement = NULL;
+ free(first);
+ free(last);
+ return 0;
+ FAIL_BEGIN;
+ free(first);
+ free(last);
+ FAIL_END;
}
@@ -2150,36 +2111,37 @@ static int compile_for(mds_kbdc_tree_for_t* restrict tree)
* @param tree The tree to compile
* @return Zero on success, -1 on error
*/
-static int compile_if(mds_kbdc_tree_if_t* restrict tree)
+static int
+compile_if(mds_kbdc_tree_if_t *restrict tree)
{
- size_t lineoff;
- char* restrict code = result->source_code->real_lines[tree->loc_line];
- char32_t* restrict data = NULL;
- int ok, saved_errno;
- size_t i;
-
- last_value_statement = NULL;
-
- /* Locate the first character in the condition. */
- for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++);
- /* Evaluate function calls, variable dereferences and escapes in the condition. */
- fail_if (data = parse_string((mds_kbdc_tree_t*)tree, tree->condition, lineoff), data == NULL);
- if (tree->processed == PROCESS_LEVEL)
- return free(data), 0;
-
- /* Evaluate whether the evaluted value is true. */
- for (ok = 1, i = 0; data[i] >= 0; i++)
- ok &= !!(data[i]);
- free(data), data = NULL;;
-
- /* Compile the appropriate clause. */
- ok = compile_subtree(ok ? tree->inner : tree->otherwise);
- last_value_statement = NULL;
- fail_if (ok < 0);
- return 0;
- FAIL_BEGIN;
- free(data);
- FAIL_END;
+ size_t lineoff;
+ char *restrict code = result->source_code->real_lines[tree->loc_line];
+ char32_t *restrict data = NULL;
+ int ok, saved_errno;
+ size_t i;
+
+ last_value_statement = NULL;
+
+ /* Locate the first character in the condition. */
+ for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++);
+ /* Evaluate function calls, variable dereferences and escapes in the condition. */
+ fail_if (!(data = parse_string((mds_kbdc_tree_t*)tree, tree->condition, lineoff)));
+ if (tree->processed == PROCESS_LEVEL)
+ return free(data), 0;
+
+ /* Evaluate whether the evaluted value is true. */
+ for (ok = 1, i = 0; data[i] >= 0; i++)
+ ok &= !!(data[i]);
+ free(data), data = NULL;;
+
+ /* Compile the appropriate clause. */
+ ok = compile_subtree(ok ? tree->inner : tree->otherwise);
+ last_value_statement = NULL;
+ fail_if (ok < 0);
+ return 0;
+ FAIL_BEGIN;
+ free(data);
+ FAIL_END;
}
@@ -2189,35 +2151,36 @@ static int compile_if(mds_kbdc_tree_if_t* restrict tree)
* @param tree The tree to compile
* @return Zero on success, -1 on error
*/
-static int compile_let(mds_kbdc_tree_let_t* restrict tree)
+static int
+compile_let(mds_kbdc_tree_let_t *restrict tree)
{
- size_t lineoff;
- char* restrict code = result->source_code->real_lines[tree->loc_line];
- mds_kbdc_tree_t* value = NULL;
- size_t variable;
- int saved_errno;
-
- /* Get the index of the selected variable. */
- for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++);
- fail_if (variable = parse_variable((mds_kbdc_tree_t*)tree, tree->variable, lineoff), variable == 0);
- if (tree->processed == PROCESS_LEVEL)
- return 0;
-
- /* Duplicate arguments and evaluate function calls,
- variable dereferences and escapes in the value. */
- fail_if (value = mds_kbdc_tree_dup(tree->value), value == NULL);
- fail_if (compile_subtree(value));
- if ((tree->processed = value->processed) == PROCESS_LEVEL)
- return mds_kbdc_tree_free(value), 0;
-
- /* Set the value of the variable. */
- fail_if (let(variable, NULL, value, NULL, 0, 0));
-
- mds_kbdc_tree_free(value);
- return 0;
- FAIL_BEGIN;
- free(value);
- FAIL_END;
+ size_t lineoff;
+ char *restrict code = result->source_code->real_lines[tree->loc_line];
+ mds_kbdc_tree_t* value = NULL;
+ size_t variable;
+ int saved_errno;
+
+ /* Get the index of the selected variable. */
+ for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++);
+ fail_if (!(variable = parse_variable((mds_kbdc_tree_t *)tree, tree->variable, lineoff)));
+ if (tree->processed == PROCESS_LEVEL)
+ return 0;
+
+ /* Duplicate arguments and evaluate function calls,
+ variable dereferences and escapes in the value. */
+ fail_if (!(value = mds_kbdc_tree_dup(tree->value)));
+ fail_if (compile_subtree(value));
+ if ((tree->processed = value->processed) == PROCESS_LEVEL)
+ return mds_kbdc_tree_free(value), 0;
+
+ /* Set the value of the variable. */
+ fail_if (let(variable, NULL, value, NULL, 0, 0));
+
+ mds_kbdc_tree_free(value);
+ return 0;
+ FAIL_BEGIN;
+ free(value);
+ FAIL_END;
}
@@ -2237,26 +2200,26 @@ static int compile_let(mds_kbdc_tree_let_t* restrict tree)
* @param node The element to evaluate
* @return Zero on success, -1 on error, 1 if the element is invalid
*/
-static int evaluate_element(mds_kbdc_tree_t* restrict node)
+static int
+evaluate_element(mds_kbdc_tree_t *restrict node)
{
- char32_t* restrict data = NULL;
- int bad = 0;
-
- for (; node; node = node->next)
- {
- if (node->type == C(STRING))
- fail_if (data = parse_string(node, node->string.string, node->loc_start), data == NULL);
- if (node->type == C(KEYS))
- fail_if (data = parse_keys(node, node->keys.keys, node->loc_start), data == NULL);
- free(node->string.string);
- node->type = (node->type == C(STRING)) ? C(COMPILED_STRING) : C(COMPILED_KEYS);
- node->compiled_string.string = data;
- bad |= (node->processed == PROCESS_LEVEL);
- }
-
- return bad;
- fail:
- return -1;
+ char32_t *restrict data = NULL;
+ int bad = 0;
+
+ for (; node; node = node->next) {
+ if (node->type == C(STRING))
+ fail_if (!(data = parse_string(node, node->string.string, node->loc_start)));
+ if (node->type == C(KEYS))
+ fail_if (!(data = parse_keys(node, node->keys.keys, node->loc_start)));
+ free(node->string.string);
+ node->type = (node->type == C(STRING)) ? C(COMPILED_STRING) : C(COMPILED_KEYS);
+ node->compiled_string.string = data;
+ bad |= (node->processed == PROCESS_LEVEL);
+ }
+
+ return bad;
+fail:
+ return -1;
}
@@ -2266,12 +2229,13 @@ static int evaluate_element(mds_kbdc_tree_t* restrict node)
* @param tree The tree to compile
* @return Zero on success, -1 on error
*/
-static int compile_keys(mds_kbdc_tree_keys_t* restrict tree)
+static int
+compile_keys(mds_kbdc_tree_keys_t *restrict tree)
{
- fail_if (evaluate_element((mds_kbdc_tree_t*)tree) < 0);
- return 0;
- fail:
- return -1;
+ fail_if (evaluate_element((mds_kbdc_tree_t *)tree) < 0);
+ return 0;
+fail:
+ return -1;
}
@@ -2281,12 +2245,13 @@ static int compile_keys(mds_kbdc_tree_keys_t* restrict tree)
* @param tree The tree to compile
* @return Zero on success, -1 on error
*/
-static int compile_string(mds_kbdc_tree_string_t* restrict tree)
+static int
+compile_string(mds_kbdc_tree_string_t *restrict tree)
{
- fail_if (evaluate_element((mds_kbdc_tree_t*)tree) < 0);
- return 0;
- fail:
- return -1;
+ fail_if (evaluate_element((mds_kbdc_tree_t *)tree) < 0);
+ return 0;
+fail:
+ return -1;
}
@@ -2296,15 +2261,16 @@ static int compile_string(mds_kbdc_tree_string_t* restrict tree)
* @param tree The tree to compile
* @return Zero on success, -1 on error
*/
-static int compile_array(mds_kbdc_tree_array_t* restrict tree)
+static int
+compile_array(mds_kbdc_tree_array_t *restrict tree)
{
- int r = evaluate_element(tree->elements);
- fail_if (r < 0);
- if (r)
- tree->processed = PROCESS_LEVEL;
- return 0;
- fail:
- return -1;
+ int r = evaluate_element(tree->elements);
+ fail_if (r < 0);
+ if (r)
+ tree->processed = PROCESS_LEVEL;
+ return 0;
+fail:
+ return -1;
}
@@ -2316,27 +2282,28 @@ static int compile_array(mds_kbdc_tree_array_t* restrict tree)
* @return Zero on success, -1 on error, 1 if any of
* the elements contain a NULL character
*/
-static int check_nonnul(mds_kbdc_tree_t* restrict tree)
+static int
+check_nonnul(mds_kbdc_tree_t *restrict tree)
{
- const char32_t* restrict string;
- int rc = 0;
- again:
- if (tree == NULL)
- return rc;
-
- for (string = tree->compiled_string.string; *string != -1; string++)
- if (*string == 0)
- {
- NEW_ERROR(tree, ERROR, "NULL characters are not allowed in mappings");
- tree->processed = PROCESS_LEVEL;
- rc = 1;
- break;
- }
-
- tree = tree->next;
- goto again;
- fail:
- return -1;
+ const char32_t *restrict string;
+ int rc = 0;
+again:
+ if (!tree)
+ return rc;
+
+ for (string = tree->compiled_string.string; *string != -1; string++) {
+ if (!*string) {
+ NEW_ERROR(tree, ERROR, "NULL characters are not allowed in mappings");
+ tree->processed = PROCESS_LEVEL;
+ rc = 1;
+ break;
+ }
+ }
+
+ tree = tree->next;
+ goto again;
+fail:
+ return -1;
}
@@ -2346,115 +2313,112 @@ static int check_nonnul(mds_kbdc_tree_t* restrict tree)
* @param tree The tree to compile
* @return Zero on success, -1 on error
*/
-static int compile_map(mds_kbdc_tree_map_t* restrict tree)
+static int
+compile_map(mds_kbdc_tree_map_t *restrict tree)
{
- int bad = 0, old_have_side_effect = have_side_effect;
- mds_kbdc_include_stack_t* restrict include_stack = NULL;
- mds_kbdc_tree_t* seq = NULL;
- mds_kbdc_tree_t* res = NULL;
- mds_kbdc_tree_t* old_seq = tree->sequence;
- mds_kbdc_tree_t* old_res = tree->result;
- mds_kbdc_tree_map_t* dup_map = NULL;
- int r, saved_errno;
- mds_kbdc_tree_t* previous_last_value_statement = last_value_statement;
-
- have_side_effect = 0;
-
- /* Duplicate arguments and evaluate function calls,
- variable dereferences and escapes in the mapping
- input sequence. */
- fail_if (seq = mds_kbdc_tree_dup(old_seq), seq == NULL);
- fail_if (bad |= evaluate_element(seq), bad < 0);
-
- /* Duplicate arguments and evaluate function calls,
- variable dereferences and escapes in the mapping
- output sequence, unless this is a value-statement. */
- if (tree->result)
- {
- fail_if (res = mds_kbdc_tree_dup(old_res), res == NULL);
- fail_if (bad |= evaluate_element(res), bad < 0);
- }
-
- /* Stop if any of the mapping-arguments could not be evaluated. */
- if (bad)
- goto done;
-
-
- if (tree->result)
- {
- /* Mapping-statement. */
-
- /* Check for invalid characters in the mapping-arguments. */
- fail_if (bad |= check_nonnul(seq), bad < 0);
- fail_if (bad |= check_nonnul(res), bad < 0);
- if (bad)
- goto done;
-
- /* Duplicate the mapping-statement but give it the evaluated mapping-arguments. */
- tree->sequence = NULL;
- tree->result = NULL;
- fail_if (dup_map = &(mds_kbdc_tree_dup((mds_kbdc_tree_t*)tree)->map), dup_map == NULL);
- tree->sequence = old_seq, dup_map->sequence = seq, seq = NULL;
- tree->result = old_res, dup_map->result = res, res = NULL;
-
- /* Enlist the mapping for assembling. */
- fail_if (include_stack = mds_kbdc_include_stack_save(), include_stack == NULL);
- fail_if (add_mapping(dup_map, include_stack));
-
- goto done;
- }
-
-
- /* Value-statement */
-
- /* Save this statement so we can warn later if it is unnecessary,
- * `set_return_value` will set it to `NULL` if there are side-effects,
- * which would make this statement necessary (unless the overridding
- * statement has identical side-effect, but we will not check for that).
- * For simplicity, we do not store the include-stack, instead, we reset
- * `last_value_statement` to `NULL` when we visit an include-statement. */
- last_value_statement = (mds_kbdc_tree_t*)tree;
-
- /* Add the value statement */
- r = set_return_value(seq->compiled_string.string);
- seq->compiled_string.string = NULL;
-
- /* Check that the value-statement is inside a function call, or has
- side-effects by directly or indirectly calling ‘\set/3’ on an
- array that is not shadowed by an inner function- or macro-call. */
- if (r && !have_side_effect)
- {
- NEW_ERROR(tree, ERROR, "value-statement outside function without side-effects");
- tree->processed = PROCESS_LEVEL;
- }
- if (have_side_effect)
- last_value_statement = NULL;
-
- /* Check whether we made a previous value-statement unnecessary. */
- if (previous_last_value_statement)
- {
- /* For simplicity we set `last_value_statement` on includes,
- * so we are sure `last_value_statement` has the same include-stack. */
-
- NEW_ERROR(previous_last_value_statement, WARNING, "value-statement has no effects");
- NEW_ERROR(tree, NOTE, "overridden here");
- }
-
-
- done:
- mds_kbdc_tree_free(seq);
- mds_kbdc_tree_free(res);
- have_side_effect |= old_have_side_effect;
- return 0;
- FAIL_BEGIN;
- mds_kbdc_include_stack_free(include_stack);
- mds_kbdc_tree_free((mds_kbdc_tree_t*)dup_map);
- mds_kbdc_tree_free(seq);
- mds_kbdc_tree_free(res);
- tree->sequence = old_seq;
- tree->result = old_res;
- have_side_effect = old_have_side_effect;
- FAIL_END;
+ int bad = 0, old_have_side_effect = have_side_effect;
+ mds_kbdc_include_stack_t *restrict include_stack = NULL;
+ mds_kbdc_tree_t *seq = NULL;
+ mds_kbdc_tree_t *res = NULL;
+ mds_kbdc_tree_t *old_seq = tree->sequence;
+ mds_kbdc_tree_t *old_res = tree->result;
+ mds_kbdc_tree_map_t *dup_map = NULL;
+ int r, saved_errno;
+ mds_kbdc_tree_t *previous_last_value_statement = last_value_statement;
+
+ have_side_effect = 0;
+
+ /* Duplicate arguments and evaluate function calls,
+ variable dereferences and escapes in the mapping
+ input sequence. */
+ fail_if (!(seq = mds_kbdc_tree_dup(old_seq)));
+ fail_if ((bad |= evaluate_element(seq)) < 0);
+
+ /* Duplicate arguments and evaluate function calls,
+ variable dereferences and escapes in the mapping
+ output sequence, unless this is a value-statement. */
+ if (tree->result) {
+ fail_if (!(res = mds_kbdc_tree_dup(old_res)));
+ fail_if ((bad |= evaluate_element(res)) < 0);
+ }
+
+ /* Stop if any of the mapping-arguments could not be evaluated. */
+ if (bad)
+ goto done;
+
+
+ if (tree->result) {
+ /* Mapping-statement. */
+
+ /* Check for invalid characters in the mapping-arguments. */
+ fail_if ((bad |= check_nonnul(seq)) < 0);
+ fail_if ((bad |= check_nonnul(res)) < 0);
+ if (bad)
+ goto done;
+
+ /* Duplicate the mapping-statement but give it the evaluated mapping-arguments. */
+ tree->sequence = NULL;
+ tree->result = NULL;
+ fail_if (!(dup_map = &mds_kbdc_tree_dup((mds_kbdc_tree_t *)tree)->map));
+ tree->sequence = old_seq, dup_map->sequence = seq, seq = NULL;
+ tree->result = old_res, dup_map->result = res, res = NULL;
+
+ /* Enlist the mapping for assembling. */
+ fail_if (!(include_stack = mds_kbdc_include_stack_save()));
+ fail_if (add_mapping(dup_map, include_stack));
+
+ goto done;
+ }
+
+
+ /* Value-statement */
+
+ /* Save this statement so we can warn later if it is unnecessary,
+ * `set_return_value` will set it to `NULL` if there are side-effects,
+ * which would make this statement necessary (unless the overridding
+ * statement has identical side-effect, but we will not check for that).
+ * For simplicity, we do not store the include-stack, instead, we reset
+ * `last_value_statement` to `NULL` when we visit an include-statement. */
+ last_value_statement = (mds_kbdc_tree_t *)tree;
+
+ /* Add the value statement */
+ r = set_return_value(seq->compiled_string.string);
+ seq->compiled_string.string = NULL;
+
+ /* Check that the value-statement is inside a function call, or has
+ side-effects by directly or indirectly calling ‘\set/3’ on an
+ array that is not shadowed by an inner function- or macro-call. */
+ if (r && !have_side_effect) {
+ NEW_ERROR(tree, ERROR, "value-statement outside function without side-effects");
+ tree->processed = PROCESS_LEVEL;
+ }
+ if (have_side_effect)
+ last_value_statement = NULL;
+
+ /* Check whether we made a previous value-statement unnecessary. */
+ if (previous_last_value_statement) {
+ /* For simplicity we set `last_value_statement` on includes,
+ * so we are sure `last_value_statement` has the same include-stack. */
+
+ NEW_ERROR(previous_last_value_statement, WARNING, "value-statement has no effects");
+ NEW_ERROR(tree, NOTE, "overridden here");
+ }
+
+
+done:
+ mds_kbdc_tree_free(seq);
+ mds_kbdc_tree_free(res);
+ have_side_effect |= old_have_side_effect;
+ return 0;
+ FAIL_BEGIN;
+ mds_kbdc_include_stack_free(include_stack);
+ mds_kbdc_tree_free((mds_kbdc_tree_t*)dup_map);
+ mds_kbdc_tree_free(seq);
+ mds_kbdc_tree_free(res);
+ tree->sequence = old_seq;
+ tree->result = old_res;
+ have_side_effect = old_have_side_effect;
+ FAIL_END;
}
@@ -2464,70 +2428,71 @@ static int compile_map(mds_kbdc_tree_map_t* restrict tree)
* @param tree The tree to compile
* @return Zero on success, -1 on error
*/
-static int compile_macro_call(mds_kbdc_tree_macro_call_t* restrict tree)
+static int
+compile_macro_call(mds_kbdc_tree_macro_call_t *restrict tree)
{
- mds_kbdc_tree_t* arg = NULL;
- mds_kbdc_tree_t* arg_;
- mds_kbdc_tree_macro_t* macro;
- mds_kbdc_include_stack_t* macro_include_stack;
- mds_kbdc_include_stack_t* our_include_stack = NULL;
- size_t variable = 0;
- int bad, saved_errno;
-
- last_value_statement = NULL;
-
- /* Push call-stack. */
- mds_kbdc_call_stack_push((mds_kbdc_tree_t*)tree, tree->loc_start, tree->loc_end);
-
- /* Duplicate arguments and evaluate function calls,
- variable dereferences and escapes in the macro
- call arguments. */
- if (tree->arguments)
- fail_if (arg = mds_kbdc_tree_dup(tree->arguments), arg == NULL);
- fail_if (bad = evaluate_element(arg), bad < 0);
- if (bad)
- return mds_kbdc_tree_free(arg), 0;
-
- /* Get the macro's subtree and include-stack, if it has
- not been defined `get_macro` will add an error message
- and return `NULL`. */
- fail_if (get_macro(tree, &macro, &macro_include_stack));
- if (macro == NULL)
- goto done;
-
-
- /* Push variable-stack and set parameters. */
- variables_stack_push();
- for (arg_ = arg; arg_; arg_ = arg_->next)
- fail_if (let(++variable, NULL, arg_, NULL, 0, 0));
-
- /* Switch include-stack to the macro's. */
- fail_if (our_include_stack = mds_kbdc_include_stack_save(), our_include_stack == NULL);
- fail_if (mds_kbdc_include_stack_restore(macro_include_stack));
-
- /* Call the macro. */
- fail_if (compile_subtree(macro->inner));
-
- /* Switch back the include-stack to ours. */
- fail_if (mds_kbdc_include_stack_restore(our_include_stack));
- mds_kbdc_include_stack_free(our_include_stack), our_include_stack = NULL;
-
- /* Pop variable-stack. */
- variables_stack_pop();
-
- done:
- /* Pop call-stack. */
- mds_kbdc_call_stack_pop();
-
- last_value_statement = NULL;
- break_level = 0;
- mds_kbdc_tree_free(arg);
- return 0;
- FAIL_BEGIN;
- mds_kbdc_call_stack_pop();
- mds_kbdc_tree_free(arg);
- mds_kbdc_include_stack_free(our_include_stack);
- FAIL_END;
+ mds_kbdc_tree_t *arg = NULL;
+ mds_kbdc_tree_t *arg_;
+ mds_kbdc_tree_macro_t *macro;
+ mds_kbdc_include_stack_t *macro_include_stack;
+ mds_kbdc_include_stack_t *our_include_stack = NULL;
+ size_t variable = 0;
+ int bad, saved_errno;
+
+ last_value_statement = NULL;
+
+ /* Push call-stack. */
+ mds_kbdc_call_stack_push((mds_kbdc_tree_t *)tree, tree->loc_start, tree->loc_end);
+
+ /* Duplicate arguments and evaluate function calls,
+ variable dereferences and escapes in the macro
+ call arguments. */
+ if (tree->arguments)
+ fail_if (!(arg = mds_kbdc_tree_dup(tree->arguments)));
+ fail_if (bad = evaluate_element(arg), bad < 0);
+ if (bad)
+ return mds_kbdc_tree_free(arg), 0;
+
+ /* Get the macro's subtree and include-stack, if it has
+ not been defined `get_macro` will add an error message
+ and return `NULL`. */
+ fail_if (get_macro(tree, &macro, &macro_include_stack));
+ if (!macro)
+ goto done;
+
+
+ /* Push variable-stack and set parameters. */
+ variables_stack_push();
+ for (arg_ = arg; arg_; arg_ = arg_->next)
+ fail_if (let(++variable, NULL, arg_, NULL, 0, 0));
+
+ /* Switch include-stack to the macro's. */
+ fail_if (!(our_include_stack = mds_kbdc_include_stack_save()));
+ fail_if (mds_kbdc_include_stack_restore(macro_include_stack));
+
+ /* Call the macro. */
+ fail_if (compile_subtree(macro->inner));
+
+ /* Switch back the include-stack to ours. */
+ fail_if (mds_kbdc_include_stack_restore(our_include_stack));
+ mds_kbdc_include_stack_free(our_include_stack), our_include_stack = NULL;
+
+ /* Pop variable-stack. */
+ variables_stack_pop();
+
+done:
+ /* Pop call-stack. */
+ mds_kbdc_call_stack_pop();
+
+ last_value_statement = NULL;
+ break_level = 0;
+ mds_kbdc_tree_free(arg);
+ return 0;
+ FAIL_BEGIN;
+ mds_kbdc_call_stack_pop();
+ mds_kbdc_tree_free(arg);
+ mds_kbdc_include_stack_free(our_include_stack);
+ FAIL_END;
}
@@ -2537,64 +2502,64 @@ static int compile_macro_call(mds_kbdc_tree_macro_call_t* restrict tree)
* @param tree The tree to compile
* @return Zero on success, -1 on error
*/
-static int compile_subtree(mds_kbdc_tree_t* restrict tree)
+static int
+compile_subtree(mds_kbdc_tree_t *restrict tree)
{
-#define t(expr) fail_if ((expr) < 0)
-#define c(type) t (compile_##type(&(tree->type)))
-#define c_(type) t (compile_##type(&(tree->type##_)))
- again:
- if (tree == NULL)
- return 0;
-
- if (tree->processed == PROCESS_LEVEL)
- /* An error has occurred here before, let's skip it so
- * we do not deluge the user with errors. */
- goto next;
-
- switch (tree->type)
- {
- case C(INFORMATION):
- t (compile_subtree(tree->information.inner));
- break;
- case C(INFORMATION_LANGUAGE): c (language); break;
- case C(INFORMATION_COUNTRY): c (country); break;
- case C(INFORMATION_VARIANT): c (variant); break;
- case C(INCLUDE): c (include); break;
- case C(FUNCTION): c (function); break;
- case C(MACRO): c (macro); break;
- case C(ASSUMPTION):
- if (includes_ptr == 0)
- fail_if (compile_subtree(tree->assumption.inner));
- break;
- case C(ASSUMPTION_HAVE): c (have); break;
- case C(ASSUMPTION_HAVE_CHARS): c (have_chars); break;
- case C(ASSUMPTION_HAVE_RANGE): c (have_range); break;
- case C(FOR): c_ (for); break;
- case C(IF): c_ (if); break;
- case C(LET): c (let); break;
- case C(KEYS): c (keys); break;
- case C(STRING): c (string); break;
- case C(ARRAY): c (array); break;
- case C(MAP): c (map); break;
- case C(MACRO_CALL): c (macro_call); break;
- case C(RETURN): break_level = 3; break;
- case C(BREAK): break_level = 2; break;
- case C(CONTINUE): break_level = 1; break;
- default:
- break;
- }
-
+#define t(expr) fail_if ((expr) < 0)
+#define c(type) t (compile_##type(&tree->type))
+#define c_(type) t (compile_##type(&tree->type##_))
+again:
+ if (!tree)
+ return 0;
+
+ if (tree->processed == PROCESS_LEVEL)
+ /* An error has occurred here before, let's skip it so
+ * we do not deluge the user with errors. */
+ goto next;
+
+ switch (tree->type) {
+ case C(INFORMATION):
+ t (compile_subtree(tree->information.inner));
+ break;
+ case C(INFORMATION_LANGUAGE): c (language); break;
+ case C(INFORMATION_COUNTRY): c (country); break;
+ case C(INFORMATION_VARIANT): c (variant); break;
+ case C(INCLUDE): c (include); break;
+ case C(FUNCTION): c (function); break;
+ case C(MACRO): c (macro); break;
+ case C(ASSUMPTION):
+ if (!includes_ptr)
+ fail_if (compile_subtree(tree->assumption.inner));
+ break;
+ case C(ASSUMPTION_HAVE): c (have); break;
+ case C(ASSUMPTION_HAVE_CHARS): c (have_chars); break;
+ case C(ASSUMPTION_HAVE_RANGE): c (have_range); break;
+ case C(FOR): c_ (for); break;
+ case C(IF): c_ (if); break;
+ case C(LET): c (let); break;
+ case C(KEYS): c (keys); break;
+ case C(STRING): c (string); break;
+ case C(ARRAY): c (array); break;
+ case C(MAP): c (map); break;
+ case C(MACRO_CALL): c (macro_call); break;
+ case C(RETURN): break_level = 3; break;
+ case C(BREAK): break_level = 2; break;
+ case C(CONTINUE): break_level = 1; break;
+ default:
+ break;
+ }
+
next:
- if (break_level)
- /* If a `continue`, `break` or `return` has been encountered,
- * we are done here and should return to whence we came and
- * let the subcompiler of that construct deal with it. */
- return 0;
-
- tree = tree->next;
- goto again;
- fail:
- return -1;
+ if (break_level)
+ /* If a `continue`, `break` or `return` has been encountered,
+ * we are done here and should return to whence we came and
+ * let the subcompiler of that construct deal with it. */
+ return 0;
+
+ tree = tree->next;
+ goto again;
+fail:
+ return -1;
#undef c_
#undef c
#undef t
@@ -2607,23 +2572,24 @@ static int compile_subtree(mds_kbdc_tree_t* restrict tree)
* @param result_ `result` from `eliminate_dead_code`, will be updated
* @return -1 if an error occursed that cannot be stored in `result`, zero otherwise
*/
-int compile_layout(mds_kbdc_parsed_t* restrict result_)
+int
+compile_layout(mds_kbdc_parsed_t *restrict result_)
{
- int r, saved_errno;
- result = result_;
- mds_kbdc_include_stack_begin(result_);
- mds_kbdc_call_stack_begin(result_);
- r = compile_subtree(result_->tree);
- saved_errno = errno;
- mds_kbdc_call_stack_end();
- mds_kbdc_include_stack_end();
- variables_terminate();
- callables_terminate();
- errno = saved_errno;
- fail_if (r);
- return 0;
- fail:
- return -1;
+ int r, saved_errno;
+ result = result_;
+ mds_kbdc_include_stack_begin(result_);
+ mds_kbdc_call_stack_begin(result_);
+ r = compile_subtree(result_->tree);
+ saved_errno = errno;
+ mds_kbdc_call_stack_end();
+ mds_kbdc_include_stack_end();
+ variables_terminate();
+ callables_terminate();
+ errno = saved_errno;
+ fail_if (r);
+ return 0;
+fail:
+ return -1;
}
@@ -2633,4 +2599,3 @@ int compile_layout(mds_kbdc_parsed_t* restrict result_)
#undef NEW_ERROR
#undef C
#undef PROCESS_LEVEL
-