diff --git a/patacrep/data/examples/songs/chords.sgc b/patacrep/data/examples/songs/chords.sgc new file mode 100644 index 00000000..a1076a44 --- /dev/null +++ b/patacrep/data/examples/songs/chords.sgc @@ -0,0 +1,17 @@ +{language: english} +{columns: 1} +{title: Chords testing} +{subtitle: Test of the chords specification and LaTeX translation} + +[A]Simple +[Bb]Bémol +[C#]Dièse +[Adim]dim +[Dmaj]maj +[Em3]m chiffre +[G4]Nombre +[Emaj3]maj et nombre +[Absus8]bémol, sus et nombre +[A/A]Deux notes +[F/Fb]Deux notes, bémol +[B/C#]Deux notes, dièse diff --git a/patacrep/songs/chordpro/ast.py b/patacrep/songs/chordpro/ast.py index b82b46a9..033103a7 100644 --- a/patacrep/songs/chordpro/ast.py +++ b/patacrep/songs/chordpro/ast.py @@ -122,12 +122,28 @@ class Chord(LineElement): _template = "chord" - def __init__(self, value): + def __init__(self, todo_note, todo_diesebemol, todo_mdimmajsus, todo_chiffre, todo_chordbis): super().__init__() - self.value = value + self.todo_note = todo_note + self.todo_diesebemol = todo_diesebemol + self.todo_mdimmajsus = todo_mdimmajsus + self.todo_chiffre = todo_chiffre + self.todo_chordbis = todo_chordbis def __str__(self): - return "[{}]".format(self.value) + text = "" + text += self.todo_note + if self.todo_diesebemol is not None: + text += self.todo_diesebemol + if self.todo_mdimmajsus is not None: + text += self.todo_mdimmajsus + if self.todo_chiffre is not None: + text += str(self.todo_chiffre) + if self.todo_chordbis is not None: + text += "/" + self.todo_chordbis[0] + if self.todo_chordbis[1] is not None: + text += self.todo_chordbis[1] + return "[{}]".format(text) class Verse(AST): """A verse (or bridge, or chorus)""" diff --git a/patacrep/songs/chordpro/data/latex/content_chord.tex b/patacrep/songs/chordpro/data/latex/content_chord.tex index bd2bd8b8..f6639511 100644 --- a/patacrep/songs/chordpro/data/latex/content_chord.tex +++ b/patacrep/songs/chordpro/data/latex/content_chord.tex @@ -1 +1,13 @@ -\[(( content.value ))] +\[ + ((- content.todo_note -)) + (* if content.todo_diesebemol == '#' *)#(* endif -*) + (* if content.todo_diesebemol == 'b' *)&(* endif -*) + (* if content.todo_mdimmajsus *)((content.todo_mdimmajsus))(* endif -*) + (* if content.todo_chiffre *)((content.todo_chiffre))(* endif -*) + (* if content.todo_chordbis -*) + / + ((- content.todo_chordbis[0] -)) + (* if content.todo_chordbis[1] == '#' *)#(* endif -*) + (* if content.todo_chordbis[1] == 'b' *)&(* endif -*) + (* endif -*) +] diff --git a/patacrep/songs/chordpro/lexer.py b/patacrep/songs/chordpro/lexer.py index 7f1582e6..de7422b4 100644 --- a/patacrep/songs/chordpro/lexer.py +++ b/patacrep/songs/chordpro/lexer.py @@ -9,7 +9,11 @@ LOGGER = logging.getLogger() tokens = ( 'LBRACE', 'RBRACE', - 'CHORD', + 'TODONOTE', + 'TODODIESEBEMOL', + 'TODOMDIMMAJSUS', + 'TODOCHIFFRE', + 'TODOSLASH', 'NEWLINE', 'COLON', 'WORD', @@ -39,7 +43,11 @@ class ChordProLexer: t_SPACE = r'[ \t]+' - t_chord_CHORD = r'[A-G7#m]+' + t_chord_TODONOTE = r'[A-G]' + t_chord_TODODIESEBEMOL = r'[#b]' + t_chord_TODOMDIMMAJSUS = r'(maj|dim|m|sus)' + t_chord_TODOCHIFFRE = r'[2-9]' + t_chord_TODOSLASH = r'/' t_directive_SPACE = r'[ \t]+' t_directive_KEYWORD = r'[a-zA-Z_]+' diff --git a/patacrep/songs/chordpro/syntax.py b/patacrep/songs/chordpro/syntax.py index fdcf9b72..d7711564 100644 --- a/patacrep/songs/chordpro/syntax.py +++ b/patacrep/songs/chordpro/syntax.py @@ -11,6 +11,7 @@ LOGGER = logging.getLogger() class ChordproParser(Parser): """ChordPro parser class""" + # pylint: disable=too-many-public-methods start = "song" @@ -23,7 +24,6 @@ class ChordproParser(Parser): """song : block song | empty """ - #if isinstance(symbols[1], str): if len(symbols) == 2: symbols[0] = ast.Song(self.filename) else: @@ -108,8 +108,48 @@ class ChordproParser(Parser): @staticmethod def p_chord(symbols): - """chord : CHORD""" - symbols[0] = ast.Chord(symbols[1]) + """chord : TODONOTE chordtododiesebemol chordtodomdimmajsus chordtodochiffre chordtodoautre""" + symbols[0] = ast.Chord( + symbols[1], + symbols[2], + symbols[3], + symbols[4], + symbols[5], + ) + + @staticmethod + def p_chordtododiesebemol(symbols): + """chordtododiesebemol : TODODIESEBEMOL + | empty + """ + symbols[0] = symbols[1] + + @staticmethod + def p_chordtodomdimmajsus(symbols): + """chordtodomdimmajsus : TODOMDIMMAJSUS + | empty + """ + symbols[0] = symbols[1] + + @staticmethod + def p_chordtodochiffre(symbols): + """chordtodochiffre : TODOCHIFFRE + | empty + """ + if symbols[1] is None: + symbols[0] = symbols[1] + else: + symbols[0] = int(symbols[1]) + + @staticmethod + def p_chordtodoautre(symbols): + """chordtodoautre : TODOSLASH TODONOTE chordtododiesebemol + | empty + """ + if len(symbols) == 2: + symbols[0] = None + else: + symbols[0] = (symbols[2], symbols[3]) @staticmethod def p_chorus(symbols): diff --git a/patacrep/songs/chordpro/test/chords.sgc b/patacrep/songs/chordpro/test/chords.sgc new file mode 100644 index 00000000..1eb5b2da --- /dev/null +++ b/patacrep/songs/chordpro/test/chords.sgc @@ -0,0 +1,12 @@ +[A]Simple +[Bb]Bémol +[C#]Dièse +[Adim]dim +[Dmaj]maj +[Em3]m chiffre +[G4]Nombre +[Emaj3]maj et nombre +[Absus8]bémol, sus et nombre +[A/A]Deux notes +[F/Fb]Deux notes, bémol +[B/C#]Deux notes, dièse diff --git a/patacrep/songs/chordpro/test/chords.txt b/patacrep/songs/chordpro/test/chords.txt new file mode 100644 index 00000000..ad96f2c8 --- /dev/null +++ b/patacrep/songs/chordpro/test/chords.txt @@ -0,0 +1,15 @@ +======== +{start_of_verse} + [A]Simple + [Bb]Bémol + [C#]Dièse + [Adim]dim + [Dmaj]maj + [Em3]m chiffre + [G4]Nombre + [Emaj3]maj et nombre + [Absus8]bémol, sus et nombre + [A/A]Deux notes + [F/Fb]Deux notes, bémol + [B/C#]Deux notes, dièse +{end_of_verse}