Resolve all placeholders before patching. Allows direct links (#0=#=0).
Definitions and references can be made in any order. Cyclic placeholders resolve to #<undefined>, as do ones without definitions.
This commit is contained in:
parent
48eb22d15b
commit
902c489b90
40
reader.c
40
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_weak_box(reader_state_t *state);
|
||||||
|
|
||||||
static value_t read_definition(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 next_char(reader_state_t *state);
|
||||||
static void skip_whitespace(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 bool is_placeholder(reader_state_t *state, value_t value);
|
||||||
static value_t get_placeholder(reader_state_t *state, fixnum_t ref);
|
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 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 value_t patch_placeholders(reader_state_t *state, value_t v);
|
||||||
|
|
||||||
static void tree_replace(value_t *in, value_t oldval, value_t newval);
|
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':
|
case '0' ... '9':
|
||||||
return read_definition(state);
|
return read_definition(state);
|
||||||
case '=':
|
case '=':
|
||||||
return read_backref(state);
|
return read_placeholder(state);
|
||||||
default:
|
default:
|
||||||
release_assert(NOTREACHED("Invalid character in special value."));
|
release_assert(NOTREACHED("Invalid character in special value."));
|
||||||
return UNDEFINED;
|
return UNDEFINED;
|
||||||
|
|
@ -493,14 +493,13 @@ static value_t read_definition(reader_state_t *state)
|
||||||
|
|
||||||
register_gc_root(&place_root, get_placeholder(state, ref));
|
register_gc_root(&place_root, get_placeholder(state, ref));
|
||||||
v = read_one_value(state);
|
v = read_one_value(state);
|
||||||
release_assert(!is_placeholder(state, v));
|
|
||||||
set_placeholder(state, place_root.value, v);
|
set_placeholder(state, place_root.value, v);
|
||||||
unregister_gc_root(&place_root);
|
unregister_gc_root(&place_root);
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
static value_t read_backref(reader_state_t *state)
|
static value_t read_placeholder(reader_state_t *state)
|
||||||
{
|
{
|
||||||
next_char(state);
|
next_char(state);
|
||||||
skip_whitespace(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;
|
_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));
|
for (bool changed = true; changed; changed = false)
|
||||||
|
|
||||||
if (is_placeholder(state, _CADR(place)))
|
|
||||||
{
|
{
|
||||||
value_t other_place = _CADR(place);
|
/* On each cycle, placeholder cycles/lists should come one link closer to self or actual value.
|
||||||
_CADR(place) = UNDEFINED;
|
* Self-links indicate cycles and are replaced with UNDEFINED.
|
||||||
_CADR(place) = finalize_placeholder(state, other_place);
|
* 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)
|
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))
|
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;
|
return v;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue