aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/mds-kbdc/compile-layout.c5
-rw-r--r--src/mds-kbdc/variables.c58
-rw-r--r--src/mds-kbdc/variables.h15
3 files changed, 74 insertions, 4 deletions
diff --git a/src/mds-kbdc/compile-layout.c b/src/mds-kbdc/compile-layout.c
index 8eac14c..477ba33 100644
--- a/src/mds-kbdc/compile-layout.c
+++ b/src/mds-kbdc/compile-layout.c
@@ -167,8 +167,8 @@ static int let(size_t variable, const char32_t* restrict string, const mds_kbdc_
int saved_errno;
/* Warn if this is a possible shadow attempt. */
- if (possibile_shadow_attempt && variables_let_will_override(variable) &&
- statement && (statement->processed != PROCESS_LEVEL))
+ 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");
@@ -2110,6 +2110,7 @@ static int compile_for(mds_kbdc_tree_for_t* restrict tree)
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)
diff --git a/src/mds-kbdc/variables.c b/src/mds-kbdc/variables.c
index 155edd7..4d4f941 100644
--- a/src/mds-kbdc/variables.c
+++ b/src/mds-kbdc/variables.c
@@ -41,11 +41,18 @@ typedef struct variable
struct variable* restrict previous;
/**
- * The original scope the current shadow
- * of the variable was created in
+ * The original scope in which the current
+ * shadow of the variable was created
*/
size_t scope;
+ /**
+ * The latest scope the in which the
+ * variable has been used in a for-loop,
+ * `~0' if never, or below `scope`
+ */
+ size_t used_in_for;
+
} variable_t;
@@ -173,6 +180,7 @@ int variables_let(size_t variable, mds_kbdc_tree_t* restrict value)
variables[variable]->value = value;
variables[variable]->previous = previous;
variables[variable]->scope = current_scope;
+ variables[variable]->used_in_for = (size_t)(~0LL);
}
return 0;
@@ -197,3 +205,49 @@ mds_kbdc_tree_t* variables_get(size_t variable)
return variables[variable]->value;
}
+
+/**
+ * Mark a variable as having been unsed in a for-loop in the current scope
+ *
+ * @param variable The variable index, must already be defined
+ * @return Zero on success, -1 on error
+ */
+int variables_was_used_in_for(size_t variable)
+{
+ variable_t* previous;
+
+ /* Already marked. */
+ if (variables[variable]->used_in_for == current_scope)
+ return 0;
+
+ /* Not marked. */
+ if (variables[variable]->used_in_for == (size_t)(~0LL))
+ return variables[variable]->used_in_for = current_scope, 0;
+
+ /* Marked for another scope. */
+ previous = variables[variable];
+ if (xmalloc(variables[variable], 1, variable_t))
+ fail_if (variables[variable] = previous, 1);
+ variables[variable]->value = mds_kbdc_tree_dup(previous->value);
+ fail_if (variables[variable]->value == NULL);
+ variables[variable]->previous = previous;
+ variables[variable]->scope = current_scope;
+ variables[variable]->used_in_for = current_scope;
+
+ return 0;
+ fail:
+ return -1;
+}
+
+
+/**
+ * Check whether a variable has been used in a for-loop in the current scope
+ *
+ * @param variable The variable index, must already be defined
+ * @return Whether `variables_was_used_in_for` has been unused on the variable
+ */
+int variables_has_been_used_in_for(size_t variable)
+{
+ return variables[variable]->used_in_for == current_scope;
+}
+
diff --git a/src/mds-kbdc/variables.h b/src/mds-kbdc/variables.h
index c01c163..c678c59 100644
--- a/src/mds-kbdc/variables.h
+++ b/src/mds-kbdc/variables.h
@@ -74,6 +74,21 @@ int variables_let(size_t variable, mds_kbdc_tree_t* restrict value);
*/
mds_kbdc_tree_t* variables_get(size_t variable) __attribute__((pure));
+/**
+ * Mark a variable as having been unsed in a for-loop in the current scope
+ *
+ * @param variable The variable index, must already be defined
+ * @return Zero on success, -1 on error
+ */
+int variables_was_used_in_for(size_t variable);
+
+/**
+ * Check whether a variable has been used in a for-loop in the current scope
+ *
+ * @param variable The variable index, must already be defined
+ * @return Whether `variables_was_used_in_for` has been unused on the variable
+ */
+int variables_has_been_used_in_for(size_t variable) __attribute__((pure));
#endif