mirror of https://github.com/patacrep/patacrep.git
Luthaf
10 years ago
3 changed files with 166 additions and 3 deletions
@ -0,0 +1,71 @@ |
|||
# -*- coding: utf-8 -*- |
|||
"""Abstract Syntax Tree for ChordPro code.""" |
|||
|
|||
class AST: |
|||
"""Base class for the tree.""" |
|||
# pylint: disable=no-init |
|||
metadata = None |
|||
|
|||
@classmethod |
|||
def init_metadata(cls): |
|||
"""Clear metadata |
|||
|
|||
As this attribute is a class attribute, it as to be reset at each new |
|||
parsing. |
|||
""" |
|||
cls.metadata = { |
|||
'@languages': set(), |
|||
} |
|||
|
|||
class Expression(AST): |
|||
"""ChordPro expression""" |
|||
|
|||
def __init__(self, value): |
|||
super().__init__() |
|||
self.content = [value] |
|||
|
|||
def prepend(self, value): |
|||
"""Add a value at the beginning of the content list.""" |
|||
if value is not None: |
|||
self.content.insert(0, value) |
|||
return self |
|||
|
|||
def __str__(self): |
|||
return "".join([str(item) for item in self.content]) |
|||
|
|||
class SongPart(AST): |
|||
"""ChordPro start_of/end_of command |
|||
|
|||
{start_of_chorus}, {end_of_tab}, {eov} ... |
|||
""" |
|||
|
|||
class Type: |
|||
CHORUS = ("chorus", |
|||
"start_of_chorus", "end_of_chorus", |
|||
"soc", "eoc") |
|||
VERSE = ("verse", |
|||
"start_of_verse", "end_of_verse", |
|||
"sov", "eov") |
|||
BRIDGE = ("bridge", |
|||
"start_of_bridge", "end_of_bridge", |
|||
"sob", "eob") |
|||
TAB = ("tab", |
|||
"start_of_tab", "end_of_tab", |
|||
"sot", "eot") |
|||
|
|||
def __init__(self, name): |
|||
if "_" in name: |
|||
self.init_long_form(name) |
|||
else: |
|||
self.init_short_form(name) |
|||
|
|||
def __str__(self): |
|||
return self.name |
|||
|
|||
def init_short_form(self, name): |
|||
self.type = "" |
|||
|
|||
def init_long_form(self, name): |
|||
self.type = "" |
|||
|
|||
|
@ -0,0 +1,88 @@ |
|||
# -*- coding: utf-8 -*- |
|||
"""ChordPro parser""" |
|||
|
|||
import logging |
|||
import ply.yacc as yacc |
|||
|
|||
from patacrep.chordpro.lexer import tokens, ChordProLexer |
|||
from patacrep.chordpro import ast |
|||
from patacrep.errors import SongbookError |
|||
|
|||
LOGGER = logging.getLogger() |
|||
|
|||
class ParsingError(SongbookError): |
|||
"""Parsing error.""" |
|||
|
|||
def __init__(self, message): |
|||
super().__init__(self) |
|||
self.message = message |
|||
|
|||
def __str__(self): |
|||
return self.message |
|||
|
|||
|
|||
class Parser: |
|||
"""ChordPro parser class""" |
|||
|
|||
def __init__(self, filename=None): |
|||
self.tokens = tokens |
|||
self.filename = filename |
|||
|
|||
@staticmethod |
|||
def __find_column(token): |
|||
"""Return the column of ``token``.""" |
|||
last_cr = token.lexer.lexdata.rfind('\n', 0, token.lexpos) |
|||
if last_cr < 0: |
|||
last_cr = 0 |
|||
column = (token.lexpos - last_cr) + 1 |
|||
return column |
|||
|
|||
def p_error(self, token): |
|||
"""Manage parsing errors.""" |
|||
LOGGER.error("Error in file {}, line {}:{}.".format( |
|||
str(self.filename), |
|||
token.lineno, |
|||
self.__find_column(token), |
|||
) |
|||
) |
|||
|
|||
@staticmethod |
|||
def p_expression(symbols): |
|||
"""expression : brackets expression |
|||
| braces expression |
|||
| command expression |
|||
| NEWLINE expression |
|||
| word expression |
|||
| SPACE expression |
|||
| empty |
|||
""" |
|||
if len(symbols) == 3: |
|||
if symbols[2] is None: |
|||
symbols[0] = ast.Expression(symbols[1]) |
|||
else: |
|||
symbols[0] = symbols[2].prepend(symbols[1]) |
|||
else: |
|||
symbols[0] = None |
|||
|
|||
@staticmethod |
|||
def p_empty(__symbols): |
|||
"""empty :""" |
|||
return None |
|||
|
|||
@staticmethod |
|||
def p_brackets(symbols): |
|||
"""brackets : LBRACKET expression RBRACKET""" |
|||
symbols[0] = symbols[2] |
|||
|
|||
@staticmethod |
|||
def p_braces(symbols): |
|||
"""braces : LBRACE expression COLON expression RBRACE""" |
|||
symbols[0] = symbols[2] |
|||
|
|||
|
|||
def parsesong(string, filename=None): |
|||
"""Parse song and return its metadata.""" |
|||
return yacc.yacc(module=Parser(filename)).parse( |
|||
string, |
|||
lexer=ChordProLexer().lexer, |
|||
) |
Loading…
Reference in new issue