+bool
+typecheck_grob (SCM symbol, SCM value)
+{
+ if (Unpure_pure_container *upc = Unpure_pure_container::unsmob (value))
+ return typecheck_grob (symbol, upc->unpure_part ())
+ && typecheck_grob (symbol, upc->pure_part ());
+ return ly_is_procedure (value)
+ || Simple_closure::is_smob (value)
+ || type_check_assignment (symbol, value, ly_symbol2scm ("backend-type?"));
+}
+
+class Grob_properties : public Simple_smob<Grob_properties>
+{
+public:
+ SCM mark_smob ();
+ static const char type_p_name_[];
+private:
+ friend class Grob_property_info;
+ friend SCM ly_make_grob_properties (SCM);
+ // alist_ may contain unexpanded nested overrides
+ SCM alist_;
+ // based_on_ is the cooked_ value from the next higher context that
+ // alist_ is based on
+ SCM based_on_;
+ // cooked_ is a version of alist_ where nested overrides have been
+ // expanded
+ SCM cooked_;
+ // cooked_from_ is the value of alist_ from which the expansion has
+ // been done
+ SCM cooked_from_;
+ // nested_ is a count of nested overrides in alist_
+ int nested_;
+
+ Grob_properties (SCM alist, SCM based_on) :
+ alist_ (alist), based_on_ (based_on),
+ // if the constructor was called with lists possibly containing
+ // partial overrides, we would need to initialize with based_on in
+ // order to trigger an initial update. But this should never
+ // happen, so we initialize straight with alist.
+ cooked_ (alist), cooked_from_ (alist), nested_ (0) { }
+};
+
+const char Grob_properties::type_p_name_[] = "ly:grob-properties?";
+