155 lines
3.8 KiB
Python
155 lines
3.8 KiB
Python
"""
|
|
|
|
"""
|
|
|
|
from functools import partial
|
|
import lark
|
|
from utils import utils, constants as c
|
|
|
|
|
|
class ListingTransformer(lark.Transformer):
|
|
"""
|
|
Transforms content parsed by grammar_listing.lark further.
|
|
Used for the developer and inspirations list.
|
|
"""
|
|
|
|
def unquoted_value(self, x):
|
|
return x[0].value.strip()
|
|
|
|
def quoted_value(self, x):
|
|
return x[0].value[1:-1].strip() # remove quotation marks and strip whitespaces
|
|
|
|
def property(self, x):
|
|
"""
|
|
Key is first part, values are following.
|
|
:param x:
|
|
:return:
|
|
"""
|
|
return x[0].value, x[1:]
|
|
|
|
def name(self, x):
|
|
"""
|
|
The name part is treated as a property with key "Name"
|
|
:param x:
|
|
:return:
|
|
"""
|
|
return 'Name', x[0].value.strip()
|
|
|
|
def entry(self, x):
|
|
"""
|
|
All (key, value) tuples are inserted into a dictionary.
|
|
:param x:
|
|
:return:
|
|
"""
|
|
d = {}
|
|
for key, value in x:
|
|
if key in d:
|
|
raise RuntimeError('Key in entry appears twice')
|
|
d[key] = value
|
|
return d
|
|
|
|
def start(self, x):
|
|
return x
|
|
|
|
|
|
# transformer
|
|
class EntryTransformer(lark.Transformer):
|
|
|
|
def unquoted_value(self, x):
|
|
return x[0].value.strip()
|
|
|
|
def quoted_value(self, x):
|
|
return x[0].value[1:-1].strip() # remove quotation marks
|
|
|
|
def comment_value(self, x):
|
|
return x[0].value[1:-1].strip() # remove parenthesis
|
|
|
|
def value(self, x):
|
|
if len(x) == 1:
|
|
v = ValueWithComment(value=x[0])
|
|
else:
|
|
v = ValueWithComment(value=x[0], comment=x[1])
|
|
return v
|
|
|
|
def property(self, x):
|
|
"""
|
|
The key of a property will be converted to lower case and the value part is the second part
|
|
:param x:
|
|
:return:
|
|
"""
|
|
return x[0].value.strip(), x[1:]
|
|
|
|
def title(self, x):
|
|
return 'Title', x[0].value.strip()
|
|
|
|
def note(self, x):
|
|
"""
|
|
Optional
|
|
:param x:
|
|
:return:
|
|
"""
|
|
if not x:
|
|
raise lark.Discard
|
|
return 'Note', ''.join((x.value for x in x))
|
|
|
|
def building(self, x):
|
|
return 'Building', x
|
|
|
|
def start(self, x):
|
|
return x
|
|
|
|
|
|
class ValueWithComment:
|
|
"""
|
|
All our property values can have (optional) comments. This is the class that represents them to us and implements
|
|
equality and 'in' operator functionality purely on the value.
|
|
"""
|
|
|
|
def __init__(self, value, comment=None):
|
|
self.value = value
|
|
self.comment = comment
|
|
|
|
def is_empty(self):
|
|
return self.value == ''
|
|
|
|
def startswith(self, str):
|
|
return self.value.startswith(str)
|
|
|
|
def __contains__(self, item):
|
|
return item in self.value
|
|
|
|
def __eq__(self, other):
|
|
return self.value == other
|
|
|
|
def __repr__(self):
|
|
if self.comment:
|
|
return '{} ({})'.format(self.value, self.comment)
|
|
else:
|
|
return '{}'.format(self.value)
|
|
|
|
def parse(parser, transformer, content):
|
|
tree = parser.parse(content)
|
|
value = transformer.transform(tree)
|
|
return value
|
|
|
|
|
|
def create(grammar, Transformer):
|
|
parser = lark.Lark(grammar, debug=False, parser='lalr')
|
|
transformer = Transformer()
|
|
return partial(parse, parser, transformer)
|
|
|
|
|
|
def read_and_parse(content_file: str, grammar_file: str, Transformer: lark.Transformer):
|
|
"""
|
|
Reads a content file and a grammar file and parses the content with the grammar following by
|
|
transforming the parsed output and returning the transformed result.
|
|
:param content_file:
|
|
:param grammar_file:
|
|
:param transformer:
|
|
:return:
|
|
"""
|
|
grammar = utils.read_text(grammar_file)
|
|
parse = create(grammar, Transformer)
|
|
|
|
content = utils.read_text(content_file)
|
|
return parse(content) |