diff options
| author | Mattias Andrée <maandree@operamail.com> | 2014-12-05 13:05:52 +0100 | 
|---|---|---|
| committer | Mattias Andrée <maandree@operamail.com> | 2014-12-05 13:05:52 +0100 | 
| commit | 2dc2586316e38052be949d4059613ff511c19ffb (patch) | |
| tree | 882a2fddf8552909b3adef225f28d64e704ea9ed /src/mds-kbdc | |
| parent | mds-kbdc: ... (diff) | |
| download | mds-2dc2586316e38052be949d4059613ff511c19ffb.tar.gz mds-2dc2586316e38052be949d4059613ff511c19ffb.tar.bz2 mds-2dc2586316e38052be949d4059613ff511c19ffb.tar.xz | |
mds-kbdc: m + comments
Signed-off-by: Mattias Andrée <maandree@operamail.com>
Diffstat (limited to '')
| -rw-r--r-- | src/mds-kbdc/compile-layout.c | 191 | 
1 files changed, 170 insertions, 21 deletions
| diff --git a/src/mds-kbdc/compile-layout.c b/src/mds-kbdc/compile-layout.c index f77daff..f49e3c2 100644 --- a/src/mds-kbdc/compile-layout.c +++ b/src/mds-kbdc/compile-layout.c @@ -156,6 +156,7 @@ static int set_macro(const mds_kbdc_tree_macro_t* restrict macro,  {    (void) macro;    (void) macro_include_stack; +  mds_kbdc_include_stack_free(macro_include_stack);    return 0; /* TODO */  } @@ -186,6 +187,7 @@ static int set_function(const mds_kbdc_tree_function_t* restrict function,  {    (void) function;    (void) function_include_stack; +  mds_kbdc_include_stack_free(function_include_stack);    return 0; /* TODO */  } @@ -247,16 +249,24 @@ static int compile_language(mds_kbdc_tree_information_language_t* restrict tree)    char** old = NULL;    int saved_errno; -  for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); -   +  /* 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; @@ -281,17 +291,24 @@ static int compile_country(mds_kbdc_tree_information_country_t* restrict tree)    char** old = NULL;    int saved_errno; -  for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); -   +  /* 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; @@ -315,6 +332,7 @@ static int compile_variant(mds_kbdc_tree_information_variant_t* restrict tree)    char32_t* restrict data = NULL;    int saved_errno; +  /* Make sure the variant has not already been set. */    if (result->variant)      {        if (multiple_variants == 0) @@ -323,10 +341,17 @@ static int compile_variant(mds_kbdc_tree_information_variant_t* restrict tree)        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; @@ -347,29 +372,37 @@ 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 = (node->type == C(STRING)) ? result->assumed_strings_size : result->assumed_keys_size; +  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, char*));        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), 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, char*));        result->assumed_keys_size = new_size; +      /* Add the assumption to the list. */        result->assumed_keys[result->assumed_keys_ptr++] = data;      } @@ -397,16 +430,23 @@ static int compile_have_chars(mds_kbdc_tree_assumption_have_chars_t* restrict tr    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)); -  for (n = 0; data[n] >= 0; n++); +  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, char*));      } +  /* Add all characters to the assumption list. */    while (n--)      {        fail_if (xmalloc(character, 2, char32_t)); @@ -442,21 +482,29 @@ static int compile_have_range(mds_kbdc_tree_assumption_have_range_t* restrict tr    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] < 0) || (first[1] >= 0))      {        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] < 0) || (last[1] >= 0))      {        NEW_ERROR(tree, ERROR, "iteration boundary must be a single character string"); @@ -464,20 +512,26 @@ static int compile_have_range(mds_kbdc_tree_assumption_have_range_t* restrict tr        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, char*));      } +  /* Add all characters to the assumption list. */    while (*first != *last)      {        fail_if (xmalloc(character, 2, char32_t)); @@ -671,23 +725,30 @@ 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') || ('0' < *name))        { @@ -725,19 +786,25 @@ static int compile_function(mds_kbdc_tree_function_t* restrict tree)    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)); +  /* Get the function's name without suffix, and parse the suffix. */    suffixless = tree->name;    suffix_start = strchr(suffixless, '/');    *suffix_start++ = '\0';    arg_count = (size_t)atoll(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’ is already defined as a builtin function", tree->name);        *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. */    fail_if (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) @@ -751,9 +818,13 @@ static int compile_function(mds_kbdc_tree_function_t* restrict tree)        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)); @@ -781,10 +852,13 @@ static int compile_macro(mds_kbdc_tree_macro_t* restrict tree)    mds_kbdc_include_stack_t* our_include_stack = NULL;    int r, saved_errno; -  fail_if ((our_include_stack = mds_kbdc_include_stack_save(), our_include_stack == NULL)); -   +  /* Check that the suffix if properly formatted. */    t (check_name_suffix((struct mds_kbdc_tree_callable*)tree)); +  /* 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));    t (get_macro_lax(tree->name, ¯o, ¯o_include_stack));    if (macro)      { @@ -796,9 +870,13 @@ static int compile_macro(mds_kbdc_tree_macro_t* restrict tree)        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; @@ -828,25 +906,36 @@ static int compile_for(mds_kbdc_tree_for_t* restrict tree)    size_t variable;    int saved_errno; +   +  /* 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->variable); 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] < 0) || (first[1] >= 0))      {        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] < 0) || (last[1] >= 0))      {        NEW_ERROR(tree, ERROR, "iteration boundary must be a single character string"); @@ -854,9 +943,13 @@ static int compile_for(mds_kbdc_tree_for_t* restrict tree)        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; (*first != *last) && (break_level < 2); *first += diff)      { @@ -866,9 +959,11 @@ static int compile_for(mds_kbdc_tree_for_t* restrict tree)        fail_if (compile_subtree(tree->inner));      } +  /* Catch `break` and `continue`, they may not propagate further. */    if (break_level < 3)      break_level = 0; +     done:    free(first);    free(last); @@ -894,11 +989,14 @@ static int compile_if(mds_kbdc_tree_if_t* restrict tree)    int ok, saved_errno;    size_t i; +  /* 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)); -  fail_if (tree->processed == PROCESS_LEVEL); +  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); @@ -924,16 +1022,20 @@ static int compile_let(mds_kbdc_tree_let_t* restrict tree)    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 0; +  /* Set the value of the variable. */    fail_if (let(variable, NULL, value, NULL, 0, 0));    free(value); @@ -1075,46 +1177,71 @@ static int compile_map(mds_kbdc_tree_map_t* restrict tree)    char32_t* data = NULL;    int r, saved_errno; +  /* 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 = seq;        tree->result = res;        fail_if ((dup_map = &(mds_kbdc_tree_dup((mds_kbdc_tree_t*)tree)->map), dup_map = NULL));        tree->sequence = old_seq, seq = NULL;        tree->result = old_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;      } -  else +   +   +  /* Value-statement */ +   +  /* Add the value statement */ +  data = string_decode(seq->string.string); +  fail_if (data == NULL); +  fail_if ((r = set_return_value(data), r < 0)); +  data = 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)      { -      data = string_decode(seq->string.string); -      fail_if (data == NULL); -      fail_if ((r = set_return_value(data), r < 0)); -      data = NULL; -      if (r) -	{ -	  NEW_ERROR(tree, ERROR, "value-statement outside function without side-effects"); -	  tree->processed = PROCESS_LEVEL; -	} +      NEW_ERROR(tree, ERROR, "value-statement outside function without side-effects"); +      tree->processed = PROCESS_LEVEL;      } +  /* TODO warn if tree->next is also a value-statement, unless this value has side-effect */ +   +     done:    mds_kbdc_tree_free(seq);    mds_kbdc_tree_free(res); @@ -1147,25 +1274,42 @@ static int compile_macro_call(mds_kbdc_tree_macro_call_t* restrict tree)    size_t variable;    int bad, saved_errno; +  /* Duplicate arguments and evaluate function calls, +     variable dereferences and escapes in the macro +     call arguments. */    fail_if ((arg = mds_kbdc_tree_dup(tree->arguments), arg = NULL));    fail_if ((bad = evaluate_element(arg), bad < 0));    if (bad)      return 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, ¯o, ¯o_include_stack));    if (macro == NULL)      goto done; +   +  /* Push call stack and set parameters. */    fail_if (push_stack());    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 call stack. */    fail_if (pop_stack()); +     done:    break_level = 0;    mds_kbdc_tree_free(arg); @@ -1194,6 +1338,8 @@ static int compile_subtree(mds_kbdc_tree_t* restrict tree)      return 0;    if (tree->processed == PROCESS_LEVEL) +    /* An error has occurred here before, lets skip it so +     * we do not deluge the user with errors. */      goto next;    switch (tree->type) @@ -1230,6 +1376,9 @@ static int compile_subtree(mds_kbdc_tree_t* restrict tree)   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; | 
