Update reader to fix corner-cases in the placeholder/back-reference system.

This commit is contained in:
Jesse D. McDonald 2009-11-14 16:54:47 -06:00
parent fb248d9235
commit 48eb22d15b
2 changed files with 47 additions and 24 deletions

5
gc.h
View File

@ -224,6 +224,11 @@ static inline bool is_nil(value_t v)
return v == NIL; return v == NIL;
} }
static inline bool is_undefined(value_t v)
{
return v == UNDEFINED;
}
static inline value_t boolean_value(bool b) static inline value_t boolean_value(bool b)
{ {
return b ? TRUE_VALUE : FALSE_VALUE; return b ? TRUE_VALUE : FALSE_VALUE;

View File

@ -35,10 +35,12 @@ static value_t read_backref(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);
static value_t make_placeholder(reader_state_t *state, fixnum_t ref); 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 value_t finalize_placeholder(reader_state_t *state, value_t 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);
static void set_placeholder(value_t place, value_t value);
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);
value_t read_value(FILE *f) value_t read_value(FILE *f)
@ -489,9 +491,10 @@ static value_t read_definition(reader_state_t *state)
release_assert(state->ch == '='); release_assert(state->ch == '=');
next_char(state); next_char(state);
register_gc_root(&place_root, make_placeholder(state, ref)); register_gc_root(&place_root, get_placeholder(state, ref));
v = read_one_value(state); v = read_one_value(state);
set_placeholder(place_root.value, v); release_assert(!is_placeholder(state, v));
set_placeholder(state, place_root.value, v);
unregister_gc_root(&place_root); unregister_gc_root(&place_root);
return v; return v;
@ -516,48 +519,63 @@ static value_t read_backref(reader_state_t *state)
} }
} }
static value_t make_placeholder(reader_state_t *state, fixnum_t ref) static bool is_placeholder(reader_state_t *state, value_t value)
{ {
state->ref_alist.value = cons(UNDEFINED, state->ref_alist.value); for (value_t item = state->ref_alist.value; !is_nil(item); item = _CDDR(item))
state->ref_alist.value = cons(fixnum_value(ref), state->ref_alist.value); {
return state->ref_alist.value; if (value == item)
return true;
}
return false;
} }
static value_t get_placeholder(reader_state_t *state, fixnum_t ref) static value_t get_placeholder(reader_state_t *state, fixnum_t ref)
{ {
value_t refval = fixnum_value(ref); value_t refval = fixnum_value(ref);
value_t item = state->ref_alist.value;
while (!is_nil(item)) for (value_t item = state->ref_alist.value; !is_nil(item); item = _CDDR(item))
{ {
if (_CAR(item) == refval) if (_CAR(item) == refval)
return item; return item;
else
item = _CDDR(item);
} }
release_assert(NOTREACHED("Back-reference without definition!")); /* No existing placeholder with that number; create a new one. */
return UNDEFINED; state->ref_alist.value = cons(UNDEFINED, state->ref_alist.value);
state->ref_alist.value = cons(refval, state->ref_alist.value);
return state->ref_alist.value;
}
static void set_placeholder(reader_state_t *state, value_t place, value_t value)
{
assert(is_placeholder(state, place));
release_assert(is_undefined(_CADR(place)));
_CADR(place) = value;
}
static value_t finalize_placeholder(reader_state_t *state, value_t place)
{
assert(is_placeholder(state, place));
if (is_placeholder(state, _CADR(place)))
{
value_t other_place = _CADR(place);
_CADR(place) = UNDEFINED;
_CADR(place) = finalize_placeholder(state, other_place);
}
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)
{ {
value_t item = state->ref_alist.value; for (value_t item = state->ref_alist.value; !is_nil(item); item = _CDDR(item))
while (!is_nil(item))
{ {
tree_replace(&v, item, _CADR(item)); tree_replace(&v, item, finalize_placeholder(state, item));
item = _CDDR(item);
} }
return v; return v;
} }
static void set_placeholder(value_t place, value_t value)
{
CAR(CDR(place)) = value;
}
typedef struct seen_value typedef struct seen_value
{ {
value_t value; value_t value;