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