aboutsummaryrefslogtreecommitdiffstats
path: root/src/mds-kbdc/compile-layout.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mds-kbdc/compile-layout.c')
-rw-r--r--src/mds-kbdc/compile-layout.c307
1 files changed, 281 insertions, 26 deletions
diff --git a/src/mds-kbdc/compile-layout.c b/src/mds-kbdc/compile-layout.c
index d75e423..62eb925 100644
--- a/src/mds-kbdc/compile-layout.c
+++ b/src/mds-kbdc/compile-layout.c
@@ -95,6 +95,15 @@ static int compile_subtree(mds_kbdc_tree_t* restrict tree);
+static int check_function_calls_in_literal(const mds_kbdc_tree_t* restrict tree,
+ const char* restrict raw, size_t lineoff)
+{
+ (void) tree;
+ (void) raw;
+ (void) lineoff;
+ return 0; /* TODO */
+}
+
static char32_t* parse_string(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff)
{
(void) tree;
@@ -442,7 +451,7 @@ 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* tree)
+static int check_marco_calls(const mds_kbdc_tree_t* restrict tree)
{
#define t(...) if (rc |= r = (__VA_ARGS__), r < 0) return r
const mds_kbdc_tree_macro_t* macro;
@@ -456,7 +465,7 @@ static int check_marco_calls(mds_kbdc_tree_t* tree)
{
case C(INCLUDE):
t (mds_kbdc_include_stack_push(&(tree->include), &data));
- t (r = compile_subtree(tree->include.inner), mds_kbdc_include_stack_pop(data), r);
+ t (r = check_marco_calls(tree->include.inner), mds_kbdc_include_stack_pop(data), r);
break;
case C(FOR):
@@ -484,6 +493,182 @@ static int check_marco_calls(mds_kbdc_tree_t* tree)
/**
+ * Check that all called functions in a for-statement are already defined
+ *
+ * @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)
+{
+#define t(...) if (rc |= r = check_function_calls_in_literal(__VA_ARGS__), r < 0) return r
+ 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++);
+
+ t ((const mds_kbdc_tree_t*)tree, tree->first, lineoff_first);
+ t ((const mds_kbdc_tree_t*)tree, tree->last, lineoff_last);
+
+ return rc;
+#undef t
+}
+
+
+/**
+ * Check that all called functions in an if-statement are already defined
+ *
+ * @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)
+{
+ size_t lineoff;
+ char* restrict code = result->source_code->real_lines[tree->loc_line];
+
+ for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++);
+ return check_function_calls_in_literal((const mds_kbdc_tree_t*)tree, tree->condition, lineoff);
+}
+
+
+/**
+ * Check that all called functions in a key-combination are already defined
+ *
+ * @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)
+{
+ return check_function_calls_in_literal((const mds_kbdc_tree_t*)tree, tree->keys, tree->loc_end);
+}
+
+
+/**
+ * Check that all called functions in a string are already defined
+ *
+ * @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)
+{
+ return check_function_calls_in_literal((const mds_kbdc_tree_t*)tree, tree->string, tree->loc_end);
+}
+
+
+/**
+ * Check that all called functions are already defined
+ *
+ * @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)
+{
+#define t(...) if (rc |= r = (__VA_ARGS__), r < 0) return r
+ 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;
+#undef t
+}
+
+
+/**
+ * Check that a callable's name-suffix is correct
+ *
+ * @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)
+{
+ const char* restrict name = strchr(tree->name, '/');
+ const char* restrict code = result->source_code->real_lines[tree->loc_line];
+
+ if (name == NULL)
+ {
+ NEW_ERROR(tree, includes_ptr, ERROR, "name-suffix is missing");
+ goto name_error;
+ }
+ if (*++name == '\0')
+ {
+ NEW_ERROR(tree, includes_ptr, ERROR, "empty name-suffix");
+ goto name_error;
+ }
+ if (!strcmp(name, "0"))
+ return 0;
+ if (*name == '\0')
+ {
+ NEW_ERROR(tree, includes_ptr, ERROR, "leading zero in name-suffix");
+ goto name_error;
+ }
+ for (; *name; name++)
+ if ((*name < '0') || ('0' < *name))
+ {
+ NEW_ERROR(tree, includes_ptr, ERROR, "name-suffix may only contain digits");
+ goto name_error;
+ }
+
+ return 0;
+ pfail:
+ 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;
+}
+
+
+/**
* Compile a function
*
* @param tree The tree to compile
@@ -491,19 +676,22 @@ static int check_marco_calls(mds_kbdc_tree_t* 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
int r;
- fail_if ((r = check_marco_calls(tree->inner), r));
- if (r)
- tree->processed = PROCESS_LEVEL;
+ t (check_name_suffix((struct mds_kbdc_tree_callable*)tree));
- return 0; /* TODO */
+ /* TODO check for redefinition */
+
+ t (check_marco_calls(tree->inner));
+ t (check_function_calls(tree->inner));
+
+ /* TODO add definition */
+
+ return 0;
pfail:
return -1;
-
- /* Check redefinition */
- /* Check the suffix in the name */
- /* Check for forward- and self-references */
+#undef t
}
@@ -515,19 +703,22 @@ static int compile_function(mds_kbdc_tree_function_t* restrict tree)
*/
static int compile_macro(mds_kbdc_tree_macro_t* restrict tree)
{
- int r;
+#define t(expr) fail_if ((r = (expr), r < 0)); if (r) tree->processed = PROCESS_LEVEL
+ int r;
- fail_if ((r = check_marco_calls(tree->inner), r));
- if (r)
- tree->processed = PROCESS_LEVEL;
+ t (check_name_suffix((struct mds_kbdc_tree_callable*)tree));
- return 0; /* TODO */
+ /* TODO check for redefinition */
+
+ t (check_marco_calls(tree->inner));
+ t (check_function_calls(tree->inner));
+
+ /* TODO add definition */
+
+ return 0;
pfail:
return -1;
-
- /* Check redefinition */
- /* Check the suffix in the name */
- /* Check for forward-references */
+#undef t
}
@@ -642,30 +833,49 @@ 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;
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;
- fail_if (let(variable, NULL, tree->value, NULL, 0, 0));
+ fail_if ((value = mds_kbdc_tree_dup(tree->value), value == NULL));
+ fail_if (compile_subtree(value));
+ if ((tree->processed = value->processed) == PROCESS_LEVEL)
+ return 0;
+
+ fail_if (let(variable, NULL, value, NULL, 0, 0));
+
+ free(value);
return 0;
- pfail:
- return -1;
+ FAIL_BEGIN;
+ free(value);
+ FAIL_END;
}
+/*
+ * `compile_keys`, `compile_string`, `compile_array` and `evaluate_element`
+ * are do only compilation subprocedures that may alter the compiled nodes.
+ * This is because (1) `compile_let`, `compile_map` and `compile_macro_call`
+ * needs the compiled values, and (2) only duplicates of nodes of types
+ * `C(KEYS)`, `C(STRING)` and `C(ARRAY)` are compiled, as they can only be
+ * found with `C(LET)`-, `C(MAP)`- and `C(MACRO_CALL)`-nodes.
+ */
+
+
/**
- * Evaluate an element or argument in a mapping-, value-statement or macro call
+ * Evaluate an element or argument in a mapping-, value-, let-statement or macro call
*
* @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* node)
+static int evaluate_element(mds_kbdc_tree_t* restrict node)
{
- char32_t* data = NULL;
+ char32_t* restrict data = NULL;
int bad = 0;
for (; node; node = node->next)
@@ -676,6 +886,7 @@ static int evaluate_element(mds_kbdc_tree_t* node)
fail_if ((data = parse_keys(node, node->keys.keys, node->loc_start), data == NULL));
free(node->string.string);
node->string.string = string_encode(data);
+ free(data);
fail_if (node->string.string == NULL);
bad |= (node->processed == PROCESS_LEVEL);
}
@@ -687,6 +898,47 @@ static int evaluate_element(mds_kbdc_tree_t* node)
/**
+ * Compile a key-combination
+ *
+ * @param tree The tree to compile
+ * @return Zero on success, -1 on error
+ */
+static int compile_keys(mds_kbdc_tree_keys_t* restrict tree)
+{
+ return evaluate_element((mds_kbdc_tree_t*)tree) < 0 ? -1 : 0;
+}
+
+
+/**
+ * Compile a string
+ *
+ * @param tree The tree to compile
+ * @return Zero on success, -1 on error
+ */
+static int compile_string(mds_kbdc_tree_string_t* restrict tree)
+{
+ return evaluate_element((mds_kbdc_tree_t*)tree) < 0 ? -1 : 0;
+}
+
+
+/**
+ * Compile an array
+ *
+ * @param tree The tree to compile
+ * @return Zero on success, -1 on error
+ */
+static int compile_array(mds_kbdc_tree_array_t* restrict tree)
+{
+ int r = evaluate_element(tree->elements);
+ if (r < 0)
+ return -1;
+ if (r)
+ tree->processed = PROCESS_LEVEL;
+ return 0;
+}
+
+
+/**
* Compile a mapping- or value-statement
*
* @param tree The tree to compile
@@ -799,6 +1051,9 @@ static int compile_subtree(mds_kbdc_tree_t* restrict tree)
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;