On Monday 16 October 2006 23:41, Erik Sandberg wrote:
>
> I have a clearer plan for context defs now: We could represent each context
> def as a Context object, which is used as a template for new contexts.
> E.g., the Voice context_def in engraver-init.ly defines a Context object
> with various engravers and properties in it, and when a new Voice is
> created during interpretation, the template voice is clone()d, and linked
> into the context tree.
>
> This requires a good mechanism for context cloning, which preserves
> translators and context properties. This can be achieved using signals,
> much like the AnnounceNewContext mechanism: Context::clone sends a
> CloneContext event, containing a reference to the newly created context.
> When the translator group hears this event, it clones itself and all
> translators, and connects the clones to the new context (this should be
> sufficient to preserve \consists etc.)
>
> This suggestion does still not make clear how to separate
> translator-specific and context-hierarchy-specific information, but we can
> wait with that separation.
>
> Plan:
> - create a Context::clone, which copies nothing.
> - replace lots of references to Context_def with references to a Context
> which references that context_def.
> - add hooks for translator groups (CloneContext event)
> - incrementally stuff out from context def to context and translator group.
> This includes the commands \consists, \remove, \type,\override, \revert,
> \set and \tempo.

Hi,

I have started working on this, a first refactoring is attached. Many 
references to Context_defs have been replaced with references to a Context 
('template context'), and a new Context::instantiate intends to replace 
Context_def::instantiate in the future.

In addition, I changed the protection of context keys so that unprotect and 
creation happens in the same scope. I also changed some constness, to make 
key unprotection const correct.

The work so far only aims on softcoding context-def definitions 
as music expressions, this is not much related to the original problem of 
separating definitions for contexts and translators. I think the latter can 
be done by creating a context-init.ly, which is a translator-neutral common 
base for {engraver,performer}-init.ly and recording-group-emulate.

My idea is that in
\context { \name "Staff" \consists "Foo_engraver" }
the { ... } is a music expression, and \context is a music function, which:
- creates a special context (a 'template context').
- interprets the expression in the template context. During interpretation, 
the template context is treated as a bottom context with no parents or 
children. No listeners will listen to the context, so any non-\applycontext 
music will have no effect, and will probably give warnings.
- return the template context in its final state.


However, while I wrote this, I have been thinking about an alternative 
solution to the same problem, which is cleaner but less efficient: We could 
let context_def simply be a music expression which is inserted before any 
music in the context. So e.g., \context Staff { c4 } would be equivalent to 
creating a new, blank context and interpret { \Staff c4 } in it.

A problem with this approach is that all property, \override and \consists 
operations have to be re-iterated for each newly created context. This 
doesn't need to take much time (quote-like constructs could be used to cache 
the result of music interpretation), but the problem is that the size of 
music streams would explode: Each Staff creation will send a bunch of 
\consists and \set events to the new context, this may result in grotesque 
music stream sizes if << \\ >> is used a lot. This weakness is at the same 
time a strength, because music streams will be completely self-contained in a 
natural way (currently they rely on knowledge about context_defs). The 
concept of context_defs will be kept entirely on the iterator side, which is 
very nice IMO. OTOH, it may be more difficult for non-lilypond applications to 
distinguish between e.g. staff contexts and voice contexts, since that info 
is not part of the CreateContext stream event.

Any comments / ideas / opinions?

-- 
Erik
Index: lily/context-def.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/context-def.cc,v
retrieving revision 1.66
diff -u -r1.66 context-def.cc
--- lily/context-def.cc	1 Sep 2006 10:02:46 -0000	1.66
+++ lily/context-def.cc	1 Nov 2006 11:56:45 -0000
@@ -191,25 +191,25 @@
   return name;
 }
 
-vector<Context_def*>
+vector<Context *>
 Context_def::path_to_acceptable_context (SCM type_sym, Output_def *odef) const
 {
   assert (scm_is_symbol (type_sym));
 
   SCM accepted = get_accepted (SCM_EOL);
 
-  vector<Context_def*> accepteds;
+  vector<Context *> accepteds;
   for (SCM s = accepted; scm_is_pair (s); s = scm_cdr (s))
-    if (Context_def *t = unsmob_context_def (find_context_def (odef,
-							       scm_car (s))))
+    if (Context *t = find_template_context (odef,
+					    scm_car (s)))
       accepteds.push_back (t);
 
-  vector<Context_def*> best_result;
+  vector<Context *> best_result;
   for (vsize i = 0; i < accepteds.size (); i++)
     {
       /* do not check aliases, because \context Staff should not
 	 create RhythmicStaff. */
-      if (ly_is_equal (accepteds[i]->get_context_name (), type_sym))
+      if (ly_is_equal (accepteds[i]->context_name_symbol (), type_sym))
 	{
 	  best_result.push_back (accepteds[i]);
 	  return best_result;
@@ -219,14 +219,14 @@
   vsize best_depth = INT_MAX;
   for (vsize i = 0; i < accepteds.size (); i++)
     {
-      Context_def *g = accepteds[i];
+      Context_def *g = unsmob_context_def (accepteds[i]->get_definition ());
 
-      vector<Context_def*> result
+      vector<Context *> result
 	= g->path_to_acceptable_context (type_sym, odef);
       if (result.size () && result.size () < best_depth)
 	{
 	  best_depth = result.size ();
-	  result.insert (result.begin (), g);
+	  result.insert (result.begin (), accepteds[i]);
 	  best_result = result;
 	}
     }
@@ -258,6 +258,7 @@
   return l1;
 }
 
+/* TODO: junk */
 Context *
 Context_def::instantiate (SCM ops, Object_key const *key)
 {
Index: lily/context-key-manager.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/context-key-manager.cc,v
retrieving revision 1.1
diff -u -r1.1 context-key-manager.cc
--- lily/context-key-manager.cc	12 Feb 2006 16:40:02 -0000	1.1
+++ lily/context-key-manager.cc	1 Nov 2006 11:56:45 -0000
@@ -25,7 +25,7 @@
 }
 
 
-Object_key const *
+Object_key *
 Context_key_manager::get_context_key (Moment now, string type, string id)
 {
   if (!use_object_keys)
Index: lily/context.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/context.cc,v
retrieving revision 1.91
diff -u -r1.91 context.cc
--- lily/context.cc	20 Oct 2006 17:31:46 -0000	1.91
+++ lily/context.cc	1 Nov 2006 11:56:45 -0000
@@ -12,6 +12,7 @@
 #include "dispatcher.hh"
 #include "global-context.hh"
 #include "international.hh"
+#include "lilypond-key.hh"
 #include "ly-smobs.icc"
 #include "main.hh"
 #include "output-def.hh"
@@ -52,6 +53,24 @@
   assert (false);
 }
 
+Context *
+Context::instantiate (Object_key const *key) const
+{
+  if (this->daddy_context_ || this->context_list_ != SCM_EOL)
+    programming_error ("Instantiating non-template context");
+
+  Context *ctx = new Context (key);
+
+  ctx->definition_ = this->definition_;
+  ctx->definition_mods_ = this->definition_mods_;
+  ctx->aliases_ = this->aliases_;
+  Scheme_hash_table *props = new Scheme_hash_table (*properties_dict ());
+  ctx->properties_scm_ = props->unprotect ();
+  ctx->accepts_list_ = this->accepts_list_;
+
+  return ctx;
+}
+
 Scheme_hash_table *
 Context::properties_dict () const
 {
@@ -92,12 +111,6 @@
   event_source_->unprotect ();
   events_below_ = new Dispatcher ();
   events_below_->unprotect ();
-
-  /*
-    UGH UGH
-    const correctness.
-  */
-  key_manager_.unprotect();
 }
 
 /* TODO:  this shares code with find_create_context ().  */
@@ -114,7 +127,7 @@
   /*
     TODO: use accepts_list_.
   */
-  vector<Context_def*> path
+  vector<Context *> path
     = unsmob_context_def (definition_)->path_to_acceptable_context (name, get_output_def ());
 
   if (path.size ())
@@ -177,7 +190,7 @@
   /*
     TODO: use accepts_list_.
   */
-  vector<Context_def*> path
+  vector<Context *> path
     = unsmob_context_def (definition_)->path_to_acceptable_context (n, get_output_def ());
 
   if (path.size ())
@@ -267,18 +280,20 @@
   SCM ops = ev->get_property ("ops");
   SCM type_scm = ev->get_property ("type");
   string type = ly_symbol2string (type_scm);
-  Object_key const *key = key_manager_.get_context_key (now_mom(), type, id);
+  Object_key *key = key_manager_.get_context_key (now_mom(), type, id);
   
-  vector<Context_def*> path
+  vector<Context *> path
     = unsmob_context_def (definition_)->path_to_acceptable_context (type_scm, get_output_def ());
   if (path.size () != 1)
     {
-      programming_error (_f ("Invalid CreateContext event: Cannot create %s context", type.c_str ()));
+      ev->origin ()->warning (_f ("Invalid CreateContext event: Cannot create %s context", type.c_str ()));
       return;
     }
-  Context_def *cdef = path[0];
   
-  Context *new_context = cdef->instantiate (ops, key);
+  Context *new_context = path[0]->instantiate (key);
+  if (key)
+    key->unprotect ();
+  new_context->definition_mods_ = ops;
 
   new_context->id_string_ = id;
   
@@ -321,7 +336,7 @@
 }
 
 Context *
-Context::create_context (Context_def *cdef,
+Context::create_context (Context *tpl,
 			 string id,
 			 SCM ops)
 {
@@ -336,7 +351,7 @@
      infant_event_ to create a return value. */
   send_stream_event (this, "CreateContext", 0,
                      ly_symbol2scm ("ops"), ops,
-                     ly_symbol2scm ("type"), cdef->get_context_name (),
+                     ly_symbol2scm ("type"), tpl->context_name_symbol (),
                      ly_symbol2scm ("id"), scm_makfrom0str (id.c_str ()));
   event_source_->
     remove_listener (GET_LISTENER (acknowledge_infant),
@@ -379,18 +394,16 @@
   if (!is_bottom_context ())
     {
       SCM nm = default_child_context_name ();
-      SCM st = find_context_def (get_output_def (), nm);
-
+      Context *tpl = find_template_context (get_output_def (), nm);
       string name = ly_symbol2string (nm);
-      Context_def *t = unsmob_context_def (st);
-      if (!t)
+      Context *c = tpl ? create_context (tpl, "", SCM_EOL) : 0;
+      if (!c)
 	{
-	  warning (_f ("can't find or create: `%s'", name.c_str ()));
-	  t = unsmob_context_def (this->definition_);
+	  /* no path to bottom context -- give up */
+	  error (_f ("Context `%s' can't create default child `%s'", context_name ().c_str (), name.c_str ()));
 	}
 
-      Context *tg = create_context (t, "", SCM_EOL);
-      return tg->get_default_interpreter ();
+      return c->get_default_interpreter ();
     }
   return this;
 }
@@ -456,7 +469,7 @@
   if (sym == ly_symbol2scm ("Bottom")
       && !scm_is_pair (accepts_list_))
     return true;
-  if (sym == unsmob_context_def (definition_)->get_context_name ())
+  if (sym == context_name_symbol ())
     return true;
 
   return scm_c_memq (sym, aliases_) != SCM_BOOL_F;
Index: lily/dispatcher.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/dispatcher.cc,v
retrieving revision 1.6
diff -u -r1.6 dispatcher.cc
--- lily/dispatcher.cc	19 Sep 2006 12:33:53 -0000	1.6
+++ lily/dispatcher.cc	1 Nov 2006 11:56:45 -0000
@@ -69,7 +69,7 @@
   SCM class_symbol = ev->get_property ("class");
   if (!scm_symbol_p (class_symbol))
     {
-      warning (_f ("Event class should be a symbol"));
+      ev->origin ()->warning (_f ("Event class should be a symbol"));
       return;
     }
 
Index: lily/global-context-scheme.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/global-context-scheme.cc,v
retrieving revision 1.16
diff -u -r1.16 global-context-scheme.cc
--- lily/global-context-scheme.cc	1 Sep 2006 11:57:55 -0000	1.16
+++ lily/global-context-scheme.cc	1 Nov 2006 11:56:45 -0000
@@ -8,6 +8,7 @@
 #include "cpu-timer.hh"
 #include "global-context.hh"
 #include "international.hh"
+#include "lilypond-key.hh"
 #include "main.hh"
 #include "music-iterator.hh"
 #include "music-output.hh"
@@ -63,7 +64,11 @@
   SCM_ASSERT_TYPE (odef, output_def, SCM_ARG1, __FUNCTION__,
 		   "Output definition");
 
-  Global_context *glob = new Global_context (odef, unsmob_key (key));
+  Lilypond_context_key *gkey = new Lilypond_context_key (unsmob_key (key),
+							 Moment (0),
+							 "Global", "", 0);
+  Global_context *glob = new Global_context (odef, gkey);
+  gkey->unprotect ();
 
   if (!glob)
     {
Index: lily/global-context.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/global-context.cc,v
retrieving revision 1.45
diff -u -r1.45 global-context.cc
--- lily/global-context.cc	26 Sep 2006 10:54:17 -0000	1.45
+++ lily/global-context.cc	1 Nov 2006 11:56:45 -0000
@@ -22,9 +22,7 @@
 #include "warn.hh"
 
 Global_context::Global_context (Output_def *o, Object_key *key)
-  : Context (new Lilypond_context_key (key,
-				       Moment (0),
-				       "Global", "", 0))
+  : Context (key)
 {
   output_def_ = o;
   definition_ = find_context_def (o, ly_symbol2scm ("Global"));
Index: lily/output-def-scheme.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/output-def-scheme.cc,v
retrieving revision 1.12
diff -u -r1.12 output-def-scheme.cc
--- lily/output-def-scheme.cc	6 Feb 2006 01:13:58 -0000	1.12
+++ lily/output-def-scheme.cc	1 Nov 2006 11:56:45 -0000
@@ -12,6 +12,7 @@
 #include "output-def.hh"
 #include "ly-module.hh"
 #include "context-def.hh"
+#include "context.hh"
 #include "lily-parser.hh"
 
 LY_DEFINE (ly_layout_lookup, "ly:output-def-lookup",
@@ -74,10 +75,13 @@
   SCM ell = SCM_EOL;
   for (SCM s = al; scm_is_pair (s); s = scm_cdr (s))
     {
-      Context_def *td = unsmob_context_def (scm_cdar (s));
+      Context *c = unsmob_context (scm_cdar (s));
       SCM key = scm_caar (s);
-      if (td && key == td->get_context_name ())
-	ell = scm_cons (scm_cons (key, td->to_alist ()), ell);
+      if (c && key == c->context_name_symbol ())
+	{
+	  Context_def *cd = unsmob_context_def (c->get_definition ());
+	  ell = scm_cons (scm_cons (key, cd->to_alist ()), ell);
+	}
     }
   return ell;
 }
Index: lily/output-def.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/output-def.cc,v
retrieving revision 1.27
diff -u -r1.27 output-def.cc
--- lily/output-def.cc	11 Feb 2006 11:35:17 -0000	1.27
+++ lily/output-def.cc	1 Nov 2006 11:56:45 -0000
@@ -74,15 +74,14 @@
 }
 
 void
-assign_context_def (Output_def * m, SCM transdef)
+assign_context_def (Output_def * m, SCM ctx_template)
 {
-  Context_def *tp = unsmob_context_def (transdef);
-  assert (tp);
+  Context *c = unsmob_context (ctx_template);
 
-  if (tp)
+  if (c)
     {
-      SCM sym = tp->get_context_name ();
-      m->set_variable (sym, transdef);
+      SCM sym = c->context_name_symbol ();
+      m->set_variable (sym, ctx_template);
     }  
 }
 
@@ -90,8 +89,14 @@
 SCM
 find_context_def (Output_def const *m, SCM name)
 {  
-  Context_def *cd = unsmob_context_def (m->lookup_variable (name));
-  return cd ? cd->self_scm () : SCM_EOL;
+  Context *c = find_template_context (m, name);
+  return c->get_definition ();
+}
+
+Context *
+find_template_context (Output_def const *m, SCM name)
+{
+  return unsmob_context (m->lookup_variable (name));
 }
 
 int
Index: lily/parser.yy
===================================================================
RCS file: /sources/lilypond/lilypond/lily/parser.yy,v
retrieving revision 1.535
diff -u -r1.535 parser.yy
--- lily/parser.yy	20 Oct 2006 20:51:48 -0000	1.535
+++ lily/parser.yy	1 Nov 2006 11:56:45 -0000
@@ -72,6 +72,7 @@
 using namespace std;
 
 #include "book.hh"
+#include "context.hh"
 #include "context-def.hh"
 #include "dimensions.hh"
 #include "file-path.hh"
@@ -81,6 +82,7 @@
 #include "lily-lexer.hh"
 #include "lily-parser.hh"
 #include "lilypond-input-version.hh"
+#include "lilypond-key.hh"
 #include "main.hh"
 #include "misc.hh"
 #include "music.hh"
@@ -590,9 +592,16 @@
 	;
 
 context_def_spec_block:
-	CONTEXT '{' context_def_spec_body '}'
-		{
-		$$ = $3;
+	CONTEXT '{' context_def_spec_body '}' {
+		/* TODO: junk context_def, let context_def_spec_body return a context */
+		Context_def *cdef = unsmob_context_def ($3);
+		Lilypond_context_key *key =
+			new Lilypond_context_key (NULL, Moment (0),
+						  ly_symbol2string (cdef->get_context_name ()).c_str (),
+						  "", 0);
+		Context *c = cdef->instantiate (SCM_EOL, key);
+		key->unprotect ();
+		$$ = c->unprotect ();
 	}
 	;
 
@@ -606,7 +615,8 @@
 		unsmob_context_def ($$)->origin ()->set_spot (@$);
 	}
 	| context_def_spec_body GROBDESCRIPTIONS embedded_scm {
-		Context_def*td = unsmob_context_def ($$);
+		$$ = $1;
+		Context_def *td = unsmob_context_def ($$);
 
 		for (SCM p = $3; scm_is_pair (p); p = scm_cdr (p)) {
 			SCM tag = scm_caar (p);
@@ -786,7 +796,8 @@
 
 	}
 	| output_def_body context_def_spec_block	{
-		assign_context_def ($$, $2);
+		$$ = $1;
+		assign_context_def ($1, $2);
 	}
 	| output_def_body error {
 
@@ -2330,12 +2341,21 @@
 		*destination = sid;
 		return NUMBER_IDENTIFIER;
 	} else if (unsmob_context_def (sid)) {
+		/* TODO: eliminate this case */
 		Context_def *def= unsmob_context_def (sid)->clone ();
 
 		*destination = def->self_scm ();
 		def->unprotect ();
 		
 		return CONTEXT_DEF_IDENTIFIER;
+	} else if (unsmob_context (sid)) {
+		Context *c = unsmob_context (sid);
+		Context_def *def= unsmob_context_def (c->get_definition ())->clone ();
+
+		*destination = def->self_scm ();
+		def->unprotect ();
+		
+		return CONTEXT_DEF_IDENTIFIER;
 	} else if (unsmob_score (sid)) {
 		Score *score = new Score (*unsmob_score (sid));
 		*destination = score->self_scm ();
Index: lily/include/context-def.hh
===================================================================
RCS file: /sources/lilypond/lilypond/lily/include/context-def.hh,v
retrieving revision 1.21
diff -u -r1.21 context-def.hh
--- lily/include/context-def.hh	15 Oct 2006 11:30:06 -0000	1.21
+++ lily/include/context-def.hh	1 Nov 2006 11:56:45 -0000
@@ -46,8 +46,8 @@
 
   VIRTUAL_COPY_CONSTRUCTOR(Context_def, Context_def);
 
-  vector<Context_def*> path_to_acceptable_context (SCM type_string,
-						      Output_def *) const;
+  vector<Context *> path_to_acceptable_context (SCM type_string,
+						Output_def *) const;
   Context *instantiate (SCM extra_ops, Object_key const *);
 
   SCM to_alist () const;
Index: lily/include/context-key-manager.hh
===================================================================
RCS file: /sources/lilypond/lilypond/lily/include/context-key-manager.hh,v
retrieving revision 1.1
diff -u -r1.1 context-key-manager.hh
--- lily/include/context-key-manager.hh	12 Feb 2006 16:40:02 -0000	1.1
+++ lily/include/context-key-manager.hh	1 Nov 2006 11:56:45 -0000
@@ -35,7 +35,7 @@
   Object_key const *key () const { return key_; }
   Object_key const *create_grob_key (Moment, string);
   Object_key const *get_grob_key (Moment, string);
-  Object_key const *get_context_key (Moment, string, string);
+  Object_key *get_context_key (Moment, string, string);
 };
 
 #endif /* CONTEXT_KEY_MANAGER_HH */
Index: lily/include/context.hh
===================================================================
RCS file: /sources/lilypond/lilypond/lily/include/context.hh,v
retrieving revision 1.45
diff -u -r1.45 context.hh
--- lily/include/context.hh	15 Oct 2006 11:30:06 -0000	1.45
+++ lily/include/context.hh	1 Nov 2006 11:56:45 -0000
@@ -83,6 +83,7 @@
   Translator_group *implementation () const { return implementation_; }
   Context *get_parent_context () const;
   Context (Object_key const *);
+  Context *instantiate (Object_key const *key) const;
 
   /* properties:  */
   SCM internal_get_property (SCM name_sym) const;
@@ -96,7 +97,7 @@
   void internal_set_property (SCM var_sym, SCM value);
 #endif
 
-  Context *create_context (Context_def *, string, SCM);
+  Context *create_context (Context *, string, SCM);
   DECLARE_LISTENER (create_context_from_event);
   DECLARE_LISTENER (acknowledge_infant);
   DECLARE_LISTENER (remove_context);
Index: lily/include/output-def.hh
===================================================================
RCS file: /sources/lilypond/lilypond/lily/include/output-def.hh,v
retrieving revision 1.22
diff -u -r1.22 output-def.hh
--- lily/include/output-def.hh	15 Oct 2006 11:30:06 -0000	1.22
+++ lily/include/output-def.hh	1 Nov 2006 11:56:45 -0000
@@ -67,6 +67,7 @@
 SCM get_font_table (Output_def *def);
 void assign_context_def (Output_def *m, SCM transdef);
 SCM find_context_def (Output_def const *m, SCM name);
+Context *find_template_context (Output_def const *m, SCM name);
 
 Interval line_dimensions_int (Output_def*def, int);
  
_______________________________________________
lilypond-devel mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/lilypond-devel

Reply via email to