aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mds-kbdc/make-tree.c138
1 files changed, 135 insertions, 3 deletions
diff --git a/src/mds-kbdc/make-tree.c b/src/mds-kbdc/make-tree.c
index e807df2..d646fc3 100644
--- a/src/mds-kbdc/make-tree.c
+++ b/src/mds-kbdc/make-tree.c
@@ -431,6 +431,99 @@
while (0)
+/**
+ * Parse a sequence in a mapping
+ */
+#define SEQUENCE \
+ do /* for(;;) */ \
+ { \
+ while (*line && (*line == ' ')) \
+ line++; \
+ if ((*line == '\0') || (*line == ':')) \
+ break; \
+ if (*line == '(') \
+ { \
+ NEW_NODE(unordered, UNORDERED); \
+ node->loc_end = node->loc_start + 1; \
+ BRANCH(")"); \
+ line++; \
+ } \
+ else if (*line == '[') \
+ { \
+ NEW_NODE(alternation, ALTERNATION); \
+ node->loc_end = node->loc_start + 1; \
+ BRANCH("]"); \
+ line++; \
+ } \
+ else if (*line == '.') \
+ { \
+ NEW_NODE(nothing, NOTHING); \
+ node->loc_end = node->loc_start + 1; \
+ LEAF; \
+ line++; \
+ } \
+ else if (strchr("])", *line)) \
+ { \
+ end = line + 1; \
+ prev_end_char = *end, *end = '\0'; \
+ if (stack_ptr == stack_orig) \
+ { \
+ NEW_ERROR(1, ERROR, "runaway ‘%s’", line); \
+ } \
+ else \
+ { \
+ stack_ptr--; \
+ if (strcmp(line, keyword_stack[stack_ptr])) \
+ { \
+ NEW_ERROR(1, ERROR, "expected ‘%s’ but got ‘%s’", keyword_stack[stack_ptr], line); \
+ } \
+ tree_stack[stack_ptr] = &(tree_stack[stack_ptr][0]->next); \
+ } \
+ *end = prev_end_char; \
+ line++; \
+ } \
+ else if (*line == '<') \
+ { \
+ NEW_NODE(keys, KEYS); \
+ NO_JUMP; \
+ /* TODO (keys); */ \
+ LEAF; \
+ node->loc_end = (size_t)(line - source_code.lines[line_i]); \
+ } \
+ else \
+ { \
+ NEW_NODE(string, STRING); \
+ NO_JUMP; \
+ CHARS(string); \
+ LEAF; \
+ node->loc_end = (size_t)(line - source_code.lines[line_i]); \
+ } \
+ } \
+ while (1)
+
+
+/**
+ * Change the scopes created in `SEQUENCE` has all been popped
+ *
+ * @param stack_orig:size_t The size of the stack when `SEQUENCE` was called
+ */
+#define SEQUENCE_FULLY_POPPED(stack_orig) \
+ do \
+ { \
+ if (stack_ptr == stack_orig) \
+ break; \
+ end = line + 1; \
+ NEW_ERROR(1, ERROR, "premature end of sequence"); \
+ for (; stack_ptr > stack_orig; stack_ptr--) \
+ { \
+ NEW_ERROR(1, NOTE, "missing associated ‘%s’", keyword_stack[stack_ptr]); \
+ error->start = tree_stack[stack_ptr][0]->loc_start; \
+ error->end = tree_stack[stack_ptr][0]->loc_end; \
+ } \
+ } \
+ while (0)
+
+
/**
* Parse a file into a syntex tree
@@ -490,8 +583,20 @@ int parse_to_tree(const char* restrict filename, mds_kbdc_tree_t** restrict resu
/* TODO '\t':s should be expanded into ' ':s. */
/* Allocate stacks needed to parse the tree. */
- fail_if (xmalloc(keyword_stack, source_code.line_count, const char*));
- fail_if (xmalloc(tree_stack, source_code.line_count + 1, mds_kbdc_tree_t**));
+ {
+ /* The maxium line-length is needed because lines can have there own stacking,
+ * like sequence mapping lines, additionally, let statements can have one array. */
+ size_t max_line_length = 0, cur_line_length;
+ for (line_i = 0, line_n = source_code.line_count; line_i < line_n; line_i++)
+ {
+ cur_line_length = strlen(source_code.lines[line_i]);
+ if (max_line_length < cur_line_length)
+ max_line_length = cur_line_length;
+ }
+
+ fail_if (xmalloc(keyword_stack, source_code.line_count + max_line_length, const char*));
+ fail_if (xmalloc(tree_stack, source_code.line_count + max_line_length + 1, mds_kbdc_tree_t**));
+ }
/* Create a node-slot for the tree root. */
*tree_stack = result;
@@ -752,7 +857,34 @@ int parse_to_tree(const char* restrict filename, mds_kbdc_tree_t** restrict resu
tree_stack[stack_ptr] = &(tree_stack[stack_ptr][0]->next);
}
else if (strchr("\"<([", *line) || strchr(line, '('))
- ; /* TODO */
+ {
+ size_t stack_orig = stack_ptr + 1;
+#define node supernode
+#define inner sequence
+ NEW_NODE(map, MAP);
+ BRANCH(":");
+#undef inner
+#undef node
+ SEQUENCE;
+ SEQUENCE_FULLY_POPPED(stack_orig);
+ stack_ptr--;
+ *end = prev_end_char;
+ if (*line++ != ':')
+ continue;
+#define node supernode
+#define inner result
+ BRANCH(":");
+#undef inner
+#undef node
+ SEQUENCE;
+ SEQUENCE_FULLY_POPPED(stack_orig);
+ stack_ptr--;
+ *end = prev_end_char;
+ if (*line == '\0')
+ continue;
+ end = line + strlen(line), prev_end_char = *end;
+ NEW_ERROR(1, ERROR, "too many parameters");
+ }
else if (strchr("}", *line))
{
NEW_ERROR(1, ERROR, "runaway ‘%c’", *line);