diff --git a/reader.c b/reader.c index 5d821d5..50f4e81 100644 --- a/reader.c +++ b/reader.c @@ -30,7 +30,7 @@ static value_t read_struct(reader_state_t *state); static value_t read_weak_box(reader_state_t *state); static value_t read_definition(reader_state_t *state); -static value_t read_backref(reader_state_t *state); +static value_t read_placeholder(reader_state_t *state); static void next_char(reader_state_t *state); static void skip_whitespace(reader_state_t *state); @@ -38,7 +38,7 @@ static void skip_whitespace(reader_state_t *state); static bool is_placeholder(reader_state_t *state, value_t value); static value_t get_placeholder(reader_state_t *state, fixnum_t ref); static void set_placeholder(reader_state_t *state, value_t place, value_t value); -static value_t finalize_placeholder(reader_state_t *state, value_t place); +static void finalize_placeholders(reader_state_t *state); static value_t patch_placeholders(reader_state_t *state, value_t v); static void tree_replace(value_t *in, value_t oldval, value_t newval); @@ -144,7 +144,7 @@ static value_t read_special(reader_state_t *state) case '0' ... '9': return read_definition(state); case '=': - return read_backref(state); + return read_placeholder(state); default: release_assert(NOTREACHED("Invalid character in special value.")); return UNDEFINED; @@ -493,14 +493,13 @@ static value_t read_definition(reader_state_t *state) register_gc_root(&place_root, get_placeholder(state, ref)); v = read_one_value(state); - release_assert(!is_placeholder(state, v)); set_placeholder(state, place_root.value, v); unregister_gc_root(&place_root); return v; } -static value_t read_backref(reader_state_t *state) +static value_t read_placeholder(reader_state_t *state) { next_char(state); skip_whitespace(state); @@ -552,25 +551,36 @@ static void set_placeholder(reader_state_t *state, value_t place, value_t value) _CADR(place) = value; } -static value_t finalize_placeholder(reader_state_t *state, value_t place) +static void finalize_placeholders(reader_state_t *state) { - assert(is_placeholder(state, place)); - - if (is_placeholder(state, _CADR(place))) + for (bool changed = true; changed; changed = false) { - value_t other_place = _CADR(place); - _CADR(place) = UNDEFINED; - _CADR(place) = finalize_placeholder(state, other_place); + /* On each cycle, placeholder cycles/lists should come one link closer to self or actual value. + * Self-links indicate cycles and are replaced with UNDEFINED. + * We're done when no placeholders link to other placeholders. */ + for (value_t item = state->ref_alist.value; !is_nil(item); item = _CDDR(item)) + { + if (_CADR(item) == item) + { + _CADR(item) = UNDEFINED; + changed = true; + } + else if (is_placeholder(state, _CADR(item))) + { + _CADR(item) = _CADR(_CADR(item)); + changed = true; + } + } } - - return _CADR(place); } static value_t patch_placeholders(reader_state_t *state, value_t v) { + finalize_placeholders(state); + for (value_t item = state->ref_alist.value; !is_nil(item); item = _CDDR(item)) { - tree_replace(&v, item, finalize_placeholder(state, item)); + tree_replace(&v, item, _CADR(item)); } return v;