From 48eb22d15baf195a2c6b5ebfe1b501ce39e5b605 Mon Sep 17 00:00:00 2001 From: Jesse McDonald Date: Sat, 14 Nov 2009 16:54:47 -0600 Subject: [PATCH] Update reader to fix corner-cases in the placeholder/back-reference system. --- gc.h | 5 +++++ reader.c | 66 +++++++++++++++++++++++++++++++++++--------------------- 2 files changed, 47 insertions(+), 24 deletions(-) diff --git a/gc.h b/gc.h index 51beaef..bacc2cc 100644 --- a/gc.h +++ b/gc.h @@ -224,6 +224,11 @@ static inline bool is_nil(value_t v) return v == NIL; } +static inline bool is_undefined(value_t v) +{ + return v == UNDEFINED; +} + static inline value_t boolean_value(bool b) { return b ? TRUE_VALUE : FALSE_VALUE; diff --git a/reader.c b/reader.c index fe9d476..5d821d5 100644 --- a/reader.c +++ b/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 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 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 void set_placeholder(value_t place, value_t value); + static void tree_replace(value_t *in, value_t oldval, value_t newval); value_t read_value(FILE *f) @@ -489,9 +491,10 @@ static value_t read_definition(reader_state_t *state) release_assert(state->ch == '='); 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); - set_placeholder(place_root.value, v); + release_assert(!is_placeholder(state, v)); + set_placeholder(state, place_root.value, v); unregister_gc_root(&place_root); 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); - state->ref_alist.value = cons(fixnum_value(ref), state->ref_alist.value); - return state->ref_alist.value; + for (value_t item = state->ref_alist.value; !is_nil(item); item = _CDDR(item)) + { + if (value == item) + return true; + } + return false; } static value_t get_placeholder(reader_state_t *state, fixnum_t 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) return item; - else - item = _CDDR(item); } - release_assert(NOTREACHED("Back-reference without definition!")); - return UNDEFINED; + /* No existing placeholder with that number; create a new one. */ + 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) { - 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)) { - tree_replace(&v, item, _CADR(item)); - item = _CDDR(item); + tree_replace(&v, item, finalize_placeholder(state, item)); } return v; } -static void set_placeholder(value_t place, value_t value) -{ - CAR(CDR(place)) = value; -} - typedef struct seen_value { value_t value;