Browse Source

Directives are allowed only on their own line (with nothing else on this line)

Better error handling of the parser.
pull/112/head
Louis 9 years ago
parent
commit
33328e789f
  1. 6
      patacrep/data/examples/songs/tests/newline.sgc
  2. 6
      patacrep/songs/chordpro/ast.py
  3. 61
      patacrep/songs/chordpro/syntax.py
  4. 2
      test/test_chordpro/newline.html
  5. 2
      test/test_chordpro/newline.sgc
  6. 2
      test/test_chordpro/newline.source
  7. 2
      test/test_chordpro/newline.tex

6
patacrep/data/examples/songs/tests/newline.sgc

@ -32,4 +32,8 @@ New lines can also
{newline}
Be surrounded by spaces
New lines can {newline} appear in the middle of a line
New lines cannot have text before them {newline}
{newline} New lines cannot have text after them
New lines cannot be {newline} surrounded by text.

6
patacrep/songs/chordpro/ast.py

@ -60,9 +60,9 @@ class Line(AST):
_template = "line"
def __init__(self):
def __init__(self, *items):
super().__init__()
self.line = []
self.line = list(items)
def __iter__(self):
yield from self.line
@ -310,7 +310,7 @@ class Directive(AST):
return self.keyword
def __str__(self):
return self.argument
return str(self.argument)
@property
def inline(self):

61
patacrep/songs/chordpro/syntax.py

@ -1,5 +1,6 @@
"""ChordPro parser"""
import logging
import ply.yacc as yacc
import re
@ -7,6 +8,8 @@ from patacrep.songs.syntax import Parser
from patacrep.songs.chordpro import ast
from patacrep.songs.chordpro.lexer import tokens, ChordProLexer
LOGGER = logging.getLogger()
class ChordproParser(Parser):
"""ChordPro parser class"""
# pylint: disable=too-many-public-methods
@ -18,6 +21,19 @@ class ChordproParser(Parser):
self.tokens = tokens
self.song = ast.Song(filename)
self.filename = filename
self.parser = yacc.yacc(
module=self,
debug=0,
write_tables=0,
)
def parse(self, *args, **kwargs):
"""Parse file
This is a shortcut to `yacc.yacc(...).parse()`. The arguments are
transmitted to this method.
"""
return self.parser.parse(*args, **kwargs)
def p_song(self, symbols):
"""song : block song
@ -32,6 +48,7 @@ class ChordproParser(Parser):
def p_block(symbols):
"""block : SPACE block
| line ENDOFLINE
| line_error ENDOFLINE
| chorus ENDOFLINE
| tab ENDOFLINE
| bridge ENDOFLINE
@ -167,20 +184,35 @@ class ChordproParser(Parser):
else:
symbols[0] = None
@staticmethod
def p_line_error(symbols):
"""line_error : error directive"""
LOGGER.error("Directive can only be preceded or followed by spaces")
symbols[0] = ast.Line()
@staticmethod
def p_line(symbols):
"""line : word line_next
| chord line_next
| directive line_next
| directive maybespace
"""
symbols[0] = symbols[2].prepend(symbols[1])
if isinstance(symbols[2], ast.Line):
# Line with words, etc.
symbols[0] = symbols[2].prepend(symbols[1])
else:
# Directive
if symbols[1] is None:
# Meta directive. Nothing to do
symbols[0] = ast.Line()
else:
# Inline directive
symbols[0] = ast.Line(symbols[1])
@staticmethod
def p_line_next(symbols):
"""line_next : word line_next
| space line_next
| chord line_next
| directive line_next
| empty
"""
if len(symbols) == 2:
@ -212,6 +244,7 @@ class ChordproParser(Parser):
@staticmethod
def p_chorus_content(symbols):
"""chorus_content : line ENDOFLINE chorus_content
| line_error ENDOFLINE chorus_content
| SPACE chorus_content
| empty
"""
@ -231,6 +264,7 @@ class ChordproParser(Parser):
@staticmethod
def p_bridge_content(symbols):
"""bridge_content : line ENDOFLINE bridge_content
| line_error ENDOFLINE bridge_content
| SPACE bridge_content
| empty
"""
@ -267,13 +301,18 @@ class ChordproParser(Parser):
"""empty :"""
symbols[0] = None
def p_error(self, token):
super().p_error(token)
while True:
token = self.parser.token()
if not token or token.type == "ENDOFLINE":
break
self.parser.errok()
return token
def parse_song(content, filename=None):
"""Parse song and return its metadata."""
return yacc.yacc(
module=ChordproParser(filename),
debug=0,
write_tables=0,
).parse(
content,
lexer=ChordProLexer(filename=filename).lexer,
)
return ChordproParser(filename).parse(
content,
lexer=ChordProLexer(filename=filename).lexer,
)

2
test/test_chordpro/newline.html

@ -45,6 +45,6 @@
</p>
<p class="verse">
New lines can't appear in the middle of a line
New lines cannot
</p>
</div>

2
test/test_chordpro/newline.sgc

@ -38,4 +38,4 @@ New lines can also
Be surrounded by spaces
New lines can {newline} appear in the middle of a line
New lines cannot

2
test/test_chordpro/newline.source

@ -29,4 +29,4 @@ New lines can also
{newline}
Be surrounded by spaces
New lines can {newline} appear in the middle of a line
New lines cannot {newline} appear in the middle of a line

2
test/test_chordpro/newline.tex

@ -55,7 +55,7 @@
\begin{verse}
New lines can ~\\ appear in the middle of a line
New lines cannot
\end{verse}
\endsong

Loading…
Cancel
Save