+// This converts an alist with nested overrides in it to a proper
+// alist. The number of nested overrides is known in advance,
+// everything up to the last nested override is copied, the tail is
+// shared.
+//
+// The first nalist index has to be a symbol since the conversion
+// relies on eq? comparisons, uses some special non-symbol values for
+// special purposes, and does validity checking indexed by symbols.
+// Subindexing can be done with equal?-comparable indexes, however.
+
+SCM
+nalist_to_alist (SCM nalist, int nested)
+{
+ if (!nested)
+ return nalist;
+ SCM copied = SCM_EOL;
+ SCM partials = SCM_EOL;
+ // partials is a alist of partial overrides
+ while (nested)
+ {
+ SCM elt = scm_car (nalist);
+ nalist = scm_cdr (nalist);
+ SCM key = scm_car (elt);
+ if (!scm_is_symbol (key))
+ --nested;
+ if (scm_is_bool (key))
+ {
+ if (scm_is_false (key))
+ continue;
+ elt = scm_cdr (elt);
+ key = scm_car (elt);
+ }
+ if (scm_is_pair (key))
+ // nested override: record for key in partial
+ {
+ SCM pair = scm_sloppy_assq (scm_car (key), partials);
+ if (scm_is_false (pair))
+ partials = scm_acons (scm_car (key), scm_list_1 (elt),
+ partials);
+ else
+ scm_set_cdr_x (pair, scm_cons (elt, scm_cdr (pair)));
+ continue;
+ }
+ assert (scm_is_symbol (key));
+ // plain override: apply any known corresponding partials
+ SCM pair = assq_pop_x (key, &partials);
+ if (scm_is_true (pair))
+ {
+ SCM value = scm_cdr (elt);
+ for (SCM pp = scm_cdr (pair); scm_is_pair (pp); pp = scm_cdr (pp))
+ value = nested_property_alist (value, scm_cdaar (pp), scm_cdar (pp));
+ copied = scm_acons (key, value, copied);
+ }
+ else
+ copied = scm_cons (elt, copied);
+ }
+ // Now need to work off the remaining partials. All of them are
+ // unique, so we can push them to `copied' after resolving without
+ // losing information.
+
+ for (;scm_is_pair (partials); partials = scm_cdr (partials))
+ {
+ SCM pair = scm_car (partials);
+ SCM key = scm_car (pair);
+ SCM elt = scm_sloppy_assq (key, nalist);
+ SCM value = SCM_EOL;
+ if (scm_is_true (elt))
+ value = scm_cdr (elt);
+
+ for (SCM pp = scm_cdr (pair); scm_is_pair (pp); pp = scm_cdr (pp))
+ value = nested_property_alist (value, scm_cdaar (pp), scm_cdar (pp));
+
+ copied = scm_acons (key, value, copied);
+ }
+ return fast_reverse_x (copied, nalist);
+}
+
+#if 0
+// Alternative approach: don't unfold those partial overrides while
+// they are part of contexts but instead use a special accessor for
+// subproperties in the grob. Not used or tested for now.
+
+SCM
+nassq_ref (SCM key, SCM nalist, SCM fallback)
+{
+ SCM partials = SCM_EOL;
+ // partials is list of partial overrides for the given property
+ for (SCM p = nalist; scm_is_pair (p); p = scm_cdr (p))
+ {
+ SCM elt = scm_car (p);
+ SCM pkey = scm_car (elt);
+ if (scm_is_pair (pkey))
+ {
+ if (scm_is_eq (scm_car (pkey), key))
+ partials = scm_cons (elt, partials);
+ }
+ else if (scm_is_eq (pkey, key))
+ {
+ SCM value = scm_cdr (elt);
+ for (; scm_is_pair (partials); partials = scm_cdr (partials))
+ {
+ value = nested_property_alist (value, scm_cdaar (partials),
+ scm_cdar (partials));
+ }
+ return value;
+ }
+ }
+ if (scm_is_pair (partials))
+ {
+ // Bit of a quandary here: we have only subproperty overrides
+ // but no main property. Could be a programming error, but we
+ // instead override an empty list.
+ SCM value = nested_create_alist (scm_cdaar (partials), scm_cdar (partials));
+ partials = scm_cdr (partials);
+ for (; scm_is_pair (partials); partials = scm_cdr (partials))
+ value = nested_property_alist (value, scm_cdaar (partials),
+ scm_cdar (partials));
+ return value;
+ }
+ return SCM_UNBNDP (fallback) ? SCM_EOL : fallback;
+}
+
+// Also needed for this approach to make sense: an accessor for true
+// subproperties.
+SCM
+nassq_nested_ref (SCM key, SCM subpath, SCM nalist, SCM fallback);
+// To be implemented
+
+#endif