lilypond-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Implement optional music function arguments (issue 5023044)


From: David Kastrup
Subject: Re: Implement optional music function arguments (issue 5023044)
Date: Wed, 21 Sep 2011 08:27:34 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/24.0.50 (gnu/linux)

address@hidden writes:

> I'd be lying if I said I understood everything going on here, but I
> think I get the gist.

Same here.

> I like moving this way!
>
> I like the approach of simplifying things.
>
> I like having optional predicates, and optional predicates with
> defaults.
>
> I will trust you that it is O(n) and that all the shift-reduce conflicts
> have been resolved.

No need to trust: I was talking about O(n) concerning the number of
rules.  Since there are no longer rules with EXPECT_A EXPECT_B
_combinations_, adding new types will add a number of rules to the
grammar that is proportional to the number of new types.

The cost is that one needs to either
a) have a precedence rule for _every_ terminal symbol that may start a
   function argument
b) be prepared to ignore a large number of shift/reduce conflicts.

There are also two restrictions that may be arbitrary:
a) if you leave out an optional argument, all immediately following
optional arguments are also skipped.  The reason is that I don't want a
puzzle game for filling optional arguments into a list of argument types
A A B C A C .  If you get arguments A C in the input, where will they
end up?
b) the last argument needs to be non-optional.  Otherwise a call ending
with five optional arguments can look five syntactic arguments ahead in
the input before deciding it does not want any.

I don't actually think that the parser can deal with this kind of
lookahead, so this may cut down expectations to a more reasonable level.

As to performance: that is more or less O(n*l) where n is input size and
l is the average lookahead piling up.  Lookahead is pretty much limited:
this mostly assigns arguments left to right, skipping optional argument
lists once the first input does not fit.

I wanted the code to be simpler but that is really hard.  Anyway, here
is an application:

afterGrace =
#(define-music-function (parser location main dur grace)
  (ly:music? (ly:duration?) ly:music?)
   (_i "Create @var{grace} note(s) after a @var{main} music expression.
An optional duration between the expressions gives the point of time where the 
grace notes are placed.
")
   (let ((main-length (ly:music-length main))
         (fraction  (ly:parser-lookup parser 'afterGraceFraction)))
     (make-simultaneous-music
      (list
       main
       (make-sequential-music
        (list

         (make-music 'SkipMusic
                     'duration (or dur
                                (ly:make-duration
                                0 0
                                (* (ly:moment-main-numerator main-length)
                                   (car fraction))
                                (* (ly:moment-main-denominator main-length)
                                   (cdr fraction)))))
         (make-music 'GraceMusic
                     'element grace)))))))

\new Voice { \afterGrace { c'1 } { c'16 d' }
             \afterGrace { c'1 } 1*7/8 { c'16 d' }
             \afterGrace { c'1} 4 {c'16 d' }
             \afterGrace c'2 {c'16 d'} d'2}
As you can see when comparing with the original in
ly/music-functions-init.ly, the source code is minimally more complex.
Since the default duration needs to be calculated at run time when left
unspecified, we let the optional argument default to #f (defaults are no
longer checked for the correct type, so this works) and splice in the
default calculation with (or dur ...).

> I'm not a parser expert, so it doesn't mean much coming from me, but I
> think this looks good.

Neither am I.

> http://codereview.appspot.com/5023044/

-- 
David Kastrup

reply via email to

[Prev in Thread] Current Thread [Next in Thread]