+def paren_matcher (n):
+ # poor man's matched paren scanning, gives up
+ # after n+1 levels. Matches any string with balanced
+ # parens inside; add the outer parens yourself if needed.
+ # Nongreedy.
+ return r"[^()]*?(?:\("*n+r"[^()]*?"+r"\)[^()]*?)*?"*n
+ return
+
+def undollar_scm (m):
+ return re.sub (r"\$(.?)", r"\1", m.group (0))
+
+def undollar_embedded (m):
+ str = re.sub (r"#\$", "#", m.group (1))
+ # poor man's matched paren scanning after #, gives up
+ # after 25 levels.
+ str = re.sub ("#`?\("+paren_matcher (25)+"\)", undollar_scm, str)
+ return m.string[m.start (0):m.start (1)] + str + m.string[m.end (1):m.end (0)]
+
+def strip_export (str):
+ return re.sub (r"\(ly:export\s+(" + paren_matcher (25) + r")\)",
+ r"\1", str)
+
+def export_puller (m):
+ if not re.search (r"ly:export\s+", m.group (0)):
+ return m.group (0)
+ return "$" + strip_export (m.string[m.start (0)+1:m.end (0)])
+
+def ugly_function_rewriter (m):
+ return m.string[m.start(0):m.start(1)] + strip_export (m.group (1)) + m.string[m.end(1):m.end(0)]
+
+should_really_be_music_function = "(?:\
+set-time-signature|empty-music|add-grace-property|\
+remove-grace-property|set-accidental-style)"
+
+def record_ugly (m):
+ global should_really_be_music_function
+ if not re.match (should_really_be_music_function, m.group (1)) \
+ and re.search (r"ly:export\s+", m.group (2)):
+ should_really_be_music_function = \
+ should_really_be_music_function[:-1] + "|" + m.group (1) + ")"
+ return m.group (0)
+
+@rule ((2, 15, 18), "#$ -> #, ly:export -> $")
+def conv (str):
+ str = re.sub (r"(?s)#@?\{(.*?)#@?\}", undollar_embedded, str)
+ str = re.sub (r"#\(define(?:-public)?\s+\(([-a-zA-Z]+)"
+ + r"\b[^()]*?\)(" + paren_matcher (25)
+ + r")\)", record_ugly, str)
+ str = re.sub (r"\(define(?:-public)?\s+\(" + should_really_be_music_function
+ + r"\b[^()]*\)(" + paren_matcher (25)
+ + r")\)", ugly_function_rewriter, str)
+ str = re.sub (r"#(?=\(" + should_really_be_music_function + ")", "$", str)
+ str = re.sub (r"#\(markup\*(?=\s)", r"$(markup", str)
+ str = re.sub ("#\("+paren_matcher (25)+"\)", export_puller, str)
+ if re.search (r"\(ly:export\s+", str):
+ stderr_write (NOT_SMART % "ly:export")
+ return str
+
+@rule ((2, 15, 19), r"$(set-time-signature ...) -> \time")
+def conv (str):
+ str = re.sub (r"\$\(set-time-signature\s+([0-9]+)\s+([0-9]+)\s*\)",
+ r"\\time \1/\2", str)
+ str = re.sub (r"\$\(set-time-signature\s+([0-9]+)\s+([0-9]+)\s+(" +
+ paren_matcher (5) + r")\)", r"\\time #\3 \1/\2", str)
+ if re.search (r"\(set-time-signature\s+", str):
+ stderr_write (NOT_SMART % "set-time-signature")
+ return str
+
+@rule ((2, 15, 20), r"$(set-accidental-style ...) -> \accidentalStyle")
+def conv (str):
+ str = re.sub (r"\$\(set-accidental-style\s+'([-a-z]+)\)",
+ r'\\accidentalStyle "\1"', str)
+ str = re.sub (r"\$\(set-accidental-style\s+'([-a-z]+)\s+'([-A-Za-z]+)\s*\)",
+ r'''\\accidentalStyle #'\2 "\1"''', str)
+ str = re.sub (r"(@funindex\s+)set-accidental-style",
+ r"\1\\accidentalStyle", str)
+ return str
+
+def brace_matcher (n):
+ # poor man's matched brace scanning, gives up
+ # after n+1 levels. Matches any string with balanced
+ # braces inside; add the outer braces yourself if needed.
+ # Nongreedy.
+ return r"[^{}]*?(?:{"*n+r"[^{}]*?"+r"}[^{}]*?)*?"*n
+
+matchstring = r'"(?:[^"\\]|\\.)*"'
+matcharg = (r"\s+(?:[$#]['`]?\s*(?:[a-zA-Z]\S*|" + matchstring + r"|\("
+ + paren_matcher(20) + r"\))|" + matchstring + r"|\\[a-z_A-Z]+)")
+matchmarkup = (r'(?:\\markup\s*(?:{' + brace_matcher (20) +r'}|' +
+ matchstring + r'|(?:\\[a-z_A-Z][a-z_A-Z-]*(?:' + matcharg +
+ r')*?\s*)*(?:' + matchstring + "|{" + brace_matcher (20) +
+ "}))|" + matchstring + ")")
+
+@rule((2, 15, 25), r"\(auto)?Footnote(Grob)? -> \footnote")
+def conv (str):
+ # The following replacement includes the final markup argument in
+ # the match in order to better avoid touching the equally named
+ # markup function. The other functions have unique names, so
+ # there is no point in including their last, possibly complex
+ # argument in the match.
+ str = re.sub (r"\\footnote(" + matcharg + (r")(\s*" + matchmarkup)*2 + ")",
+ r"\\footnote\2\1\3", str)
+ str = re.sub (r"\\footnoteGrob"+("(" + matcharg + ")")*2 + r"(\s*" + matchmarkup + ")",
+ r"\\footnote\3\2\1", str)
+ str = re.sub (r"\\autoFootnoteGrob" + ("(" + matcharg + ")")*2,
+ r"\\footnote\2\1", str)
+ str = re.sub (r"\\autoFootnote",
+ r"\\footnote", str)
+ return str