/*
This file is part of LilyPond, the GNU music typesetter.
- Copyright (C) 2011 Mike Solomon <mike@apollinemike.com>
+ Copyright (C) 2011--2014 Mike Solomon <mike@mikesolomon.org>
LilyPond is free software: you can redistribute it and/or modify
#include "grob.hh"
static scm_t_bits unpure_pure_container_tag;
+static scm_t_bits unpure_pure_call_tag;
+// Used for rerouting a function of (grob start end) to one of
+// (grob)
bool
is_unpure_pure_container (SCM s)
return (SCM_NIMP (s) && SCM_CELL_TYPE (s) == unpure_pure_container_tag);
}
+bool
+is_unchanging_unpure_pure_container (SCM s)
+// A container that has the same callback for both 'pure' and 'unpure' lookups
+// and which ignores the 'start' and 'end' columnns.
+// Such a callback will give the same answer for tentative or final layouts.
+{
+ LY_ASSERT_TYPE (is_unpure_pure_container, s, 1);
+ SCM pure_part = SCM_SMOB_OBJECT_2 (s);
+ return (SCM_UNBNDP (pure_part));
+}
+
SCM
unpure_pure_container_unpure_part (SCM smob)
{
LY_ASSERT_TYPE (is_unpure_pure_container, smob, 1);
- return (SCM) SCM_CELL_WORD_1 (smob);
+ return SCM_SMOB_OBJECT (smob);
}
SCM
unpure_pure_container_pure_part (SCM smob)
{
LY_ASSERT_TYPE (is_unpure_pure_container, smob, 1);
- return (SCM) SCM_CELL_WORD_2 (smob);
+ SCM res = SCM_SMOB_OBJECT_2 (smob);
+
+ if (!SCM_UNBNDP (res))
+ return res;
+
+ SCM_NEWSMOB (res, unpure_pure_call_tag,
+ SCM_UNPACK (unpure_pure_container_unpure_part (smob)));
+ return res;
}
LY_DEFINE (ly_unpure_pure_container_p, "ly:unpure-pure-container?",
LY_DEFINE (ly_make_unpure_pure_container, "ly:make-unpure-pure-container",
1, 1, 0, (SCM unpure, SCM pure),
"Make an unpure-pure container. @var{unpure} should be an unpure"
- " expression, and @var{pure} should be a pure expression. If @var{pure}"
- " is ommitted, the value of @var{unpure} will be used twice.")
+ " expression, and @var{pure} should be a pure expression. If @var{pure}"
+ " is omitted, the value of @var{unpure} will be used twice,"
+ " except that a callback is given two extra arguments"
+ " that are ignored for the sake of pure calculations.")
{
SCM z;
- if (pure == SCM_UNDEFINED)
+ if (SCM_UNBNDP (pure) && !ly_is_procedure (unpure))
pure = unpure;
SCM_NEWSMOB2 (z, unpure_pure_container_tag, SCM_UNPACK (unpure), SCM_UNPACK (pure));
{
scm_puts ("#<unpure-pure-container ", port);
scm_display (unpure_pure_container_unpure_part (s), port);
- scm_puts (" ", port);
- scm_display (unpure_pure_container_pure_part (s), port);
+ if (!SCM_UNBNDP (SCM_SMOB_OBJECT_2 (s)))
+ {
+ scm_puts (" ", port);
+ scm_display (unpure_pure_container_pure_part (s), port);
+ }
scm_puts (" >", port);
return 1;
}
SCM
-pure_mark (SCM pure)
+pure_mark (SCM smob)
{
- scm_gc_mark (unpure_pure_container_unpure_part (pure));
- scm_gc_mark (unpure_pure_container_pure_part (pure));
- return pure;
+ scm_gc_mark (SCM_SMOB_OBJECT (smob));
+ return SCM_SMOB_OBJECT_2 (smob);
+}
+
+// Function signature has two fixed arguments so that dropping two
+// will always work: if we have fewer to start with, it will trigger
+// wrong-number-of-args in a sensible location rather than making
+// drop-right barf.
+
+SCM
+apply_unpure_pure (SCM clo, SCM arg1, SCM arg2, SCM rest)
+{
+ return scm_apply_0 (SCM_SMOB_OBJECT (clo),
+ scm_call_2 (ly_lily_module_constant ("drop-right"),
+ scm_cons2 (arg1, arg2, rest),
+ scm_from_int (2)));
}
+
void init_unpure_pure_container ()
{
unpure_pure_container_tag = scm_make_smob_type ("unpure-pure-container", 0);
scm_set_smob_mark (unpure_pure_container_tag, pure_mark);
scm_set_smob_print (unpure_pure_container_tag, print_unpure_pure_container);
+ unpure_pure_call_tag = scm_make_smob_type ("unpure-pure-call", 0);
+ scm_set_smob_mark (unpure_pure_call_tag, scm_markcdr);
+ scm_set_smob_apply (unpure_pure_call_tag,
+ (scm_t_subr) apply_unpure_pure, 2, 0, 1);
};
ADD_SCM_INIT_FUNC (unpure_pure_container, init_unpure_pure_container);