Update reader to fix corner-cases in the placeholder/back-reference system.
This commit is contained in:
parent
fb248d9235
commit
48eb22d15b
5
gc.h
5
gc.h
|
|
@ -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;
|
||||||
|
|
|
||||||
66
reader.c
66
reader.c
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue