Browse Source

[chordpro] Chords parsing is less strict

pull/79/head
Louis 9 years ago
parent
commit
821030dba5
  1. 19
      patacrep/songs/chordpro/ast.py
  2. 11
      patacrep/songs/chordpro/data/chordpro/content_chord
  3. 13
      patacrep/songs/chordpro/data/latex/content_chord
  4. 2
      patacrep/songs/chordpro/lexer.py
  5. 48
      patacrep/songs/chordpro/syntax.py
  6. 2
      patacrep/songs/chordpro/test/invalid_chord.sgc
  7. 4
      patacrep/songs/chordpro/test/invalid_chord.source
  8. 2
      patacrep/songs/chordpro/test/invalid_chord.tex
  9. 6
      patacrep/songs/chordpro/test/invalid_customchord.source

19
patacrep/songs/chordpro/ast.py

@ -145,24 +145,9 @@ class Chord(AST):
_template = "chord"
def __init__(
self,
key,
alteration=None,
modifier=None,
addnote=None,
basskey=None,
bassalteration=None,
star=None,
):
def __init__(self, chord):
# pylint: disable=too-many-arguments
self.key = key
self.alteration = alteration
self.modifier = modifier
self.addnote = addnote
self.basskey = basskey
self.bassalteration = bassalteration
self.star = star
self.chord = chord
class Verse(AST):
"""A verse (or bridge, or chorus)"""

11
patacrep/songs/chordpro/data/chordpro/content_chord

@ -1,10 +1 @@
((- content.key -))
(* if content.alteration *)(( content.alteration ))(* endif -*)
(* if content.modifier *)((content.modifier))(* endif -*)
(* if content.addnote *)((content.addnote))(* endif -*)
(* if content.basskey -*)
/
((- content.basskey -))
(* if content.bassalteration *)(( content.bassalteration ))(* endif -*)
(* if content.star *)*(* endif -*)
(* endif -*)
((- content.chord -))

13
patacrep/songs/chordpro/data/latex/content_chord

@ -1,12 +1 @@
((- content.key -))
(* if content.alteration == '#' *)#(* endif -*)
(* if content.alteration == 'b' *)&(* endif -*)
(* if content.modifier *)((content.modifier))(* endif -*)
(* if content.addnote *)((content.addnote))(* endif -*)
(* if content.basskey -*)
/
((- content.basskey -))
(* if content.bassalteration == '#' *)#(* endif -*)
(* if content.bassalteration == 'b' *)&(* endif -*)
(* if content.star *)*(* endif -*)
(* endif -*)
((- content.chord|replace("b", "&") -))

2
patacrep/songs/chordpro/lexer.py

@ -39,7 +39,7 @@ class ChordProLexer:
t_SPACE = r'[ \t]+'
t_chord_CHORD = r'[A-G#bmajdisus+*2-9/ ]+'
t_chord_CHORD = r'[^\]]+'
t_directive_SPACE = r'[ \t]+'
t_directive_KEYWORD = r'[a-zA-Z_]+'

48
patacrep/songs/chordpro/syntax.py

@ -7,24 +7,6 @@ from patacrep.songs.syntax import Parser
from patacrep.songs.chordpro import ast
from patacrep.songs.chordpro.lexer import tokens, ChordProLexer
CHORD_RE = re.compile(
r"""
^
(?P<key>[A-G])
(?P<alteration>[b#])?
(?P<modifier>(maj|sus|dim|m|\+))?
(?P<addnote>[2-9])?
(
/
(?P<basskey>[A-G])
(?P<bassalteration>[b#])?
)?
(?P<star>\*)?
$
""",
re.VERBOSE
)
class ChordproParser(Parser):
"""ChordPro parser class"""
# pylint: disable=too-many-public-methods
@ -69,17 +51,17 @@ class ChordproParser(Parser):
"""
symbols[0] = None
def _parse_define(self, groups, *, symbols):
@staticmethod
def _parse_define(groups):
"""Parse a `{define: KEY base-fret BASE frets FRETS fingers FINGERS}` directive
Return a :class:`ast.Define` object.
"""
# pylint: disable=too-many-branches
key = list(self._parse_chords(groups['key'], symbols=symbols))
if len(key) != 1:
if not groups['key'].strip():
return None
else:
key = key[0]
key = ast.Chord(groups['key'].strip())
if groups['basefret'] is None:
basefret = None
@ -151,7 +133,7 @@ class ChordproParser(Parser):
symbols[0] = ast.Error()
return
symbols[0] = self._parse_define(match.groupdict(), symbols=symbols)
symbols[0] = self._parse_define(match.groupdict())
if symbols[0] is None:
self.error(
line=symbols.lexer.lineno,
@ -207,24 +189,10 @@ class ChordproParser(Parser):
"""space : SPACE"""
symbols[0] = ast.Space()
def _parse_chords(self, string, *, symbols):
"""Parse a list of chords.
Iterate over :class:`ast.Chord` objects.
"""
for chord in string.split():
match = CHORD_RE.match(chord)
if match is None:
self.error(
line=symbols.lexer.lineno,
message="Invalid chord '{}'.".format(chord),
)
continue
yield ast.Chord(**match.groupdict())
def p_chord(self, symbols):
@staticmethod
def p_chord(symbols):
"""chord : CHORD"""
symbols[0] = ast.ChordList(*list(self._parse_chords(symbols[1], symbols=symbols)))
symbols[0] = ast.ChordList(*[ast.Chord(chord) for chord in symbols[1].split()])
@staticmethod
def p_chorus(symbols):

2
patacrep/songs/chordpro/test/invalid_chord.sgc

@ -2,6 +2,4 @@
{start_of_verse}
This is invalid.
This [A]too.
And []as well.
{end_of_verse}

4
patacrep/songs/chordpro/test/invalid_chord.source

@ -1,3 +1 @@
This is [H] invalid.
This [A@]too.
And [Amm]as well.
This is [] invalid.

2
patacrep/songs/chordpro/test/invalid_chord.tex

@ -8,8 +8,6 @@
\begin{verse}
This is invalid.
This \[A]too.
And as well.
\end{verse}
\endsong

6
patacrep/songs/chordpro/test/invalid_customchord.source

@ -1,5 +1,5 @@
{define : }
{define: H base-fret 7 frets 0 1 3 3 x x}
{define: E4 base-fret H frets 0 1 3 3 x x}
{define: E4 base-fret 7 frets 0 1 3 3 x A}
{define: base-fret 7 frets 0 1 3 3 x x}
{define: E4 base-fret frets 0 1 3 3 x x}
{define: E4 base-fret H frets 0 1 3 3 x A}
{define: E5 base-fret 7 frets 0 1 3 3 x x fingers - 1 2 3 - A}

Loading…
Cancel
Save