Add semantic actions to create models, add str for models

This commit is contained in:
Midgard 2020-01-26 01:29:19 +01:00
parent edb1677523
commit 37e3799985
Signed by: midgard
GPG key ID: 511C112F1331BBB4
4 changed files with 119 additions and 26 deletions

View file

@ -41,7 +41,7 @@ block =
; ;
base_block = base_block =
kind:'base' s ~ 'base' s ~
id:identifier ':' s >attributes id:identifier ':' s >attributes
n n
choices:{ indent_choice_block } choices:{ indent_choice_block }
@ -55,7 +55,6 @@ indent_choice_entry = n '\t\t' >choice_entry ;
# Toplevel choice definitions # Toplevel choice definitions
choice_block = choice_block =
kind:`choice_declaration`
id:identifier ':' s >attributes entries:{ noindent_choice_entry } id:identifier ':' s >attributes entries:{ noindent_choice_entry }
n n
; ;

View file

@ -4,7 +4,8 @@ from glob import glob
from os import path, walk from os import path, walk
from tatsu import parse as tatsu_parse from tatsu import parse as tatsu_parse
import itertools import itertools
from .models import Location from .models import Location, Choice, Option, Dish
import operator
# TODO Use proper way to get resources, see https://stackoverflow.com/a/10935674 # TODO Use proper way to get resources, see https://stackoverflow.com/a/10935674
@ -12,20 +13,64 @@ with open(path.join(path.dirname(__file__), "hlds.tatsu")) as fh:
GRAMMAR = fh.read() GRAMMAR = fh.read()
def kind_equal_to(compare_to): def filter_instance(cls, iterable):
return lambda item: item["kind"] == compare_to return [item for item in iterable if isinstance(item, cls)]
class HldsSemanticActions:
def location(self, ast):
return Location(
ast["id"],
name=ast["name"],
attributes={att["key"]: att["value"] for att in ast["attributes"]},
dishes=filter_instance(Dish, ast["items_"]),
)
def base_block(self, ast):
return Dish(
ast["id"],
name=ast["name"],
description=ast["description"],
price=ast["price"],
tags=ast["tags"] if ast["tags"] else [],
choices=ast["choices"],
)
def choice_block(self, ast):
return Choice(
ast["id"],
name=ast["name"],
description=ast["description"],
options=ast["entries"],
)
def indent_choice_block(self, ast):
if ast["kind"] == "declaration":
return self.choice_block(ast)
else:
return ast
def indent_choice_entry(self, ast):
return Option(
ast["id"],
name=ast["name"],
description=ast["description"],
price=ast["price"],
tags=ast["tags"],
)
def price(self, ast):
return "{0[currency]} {0[value]}".format(ast)
def _default(self, ast):
return ast
SEMANTICS = HldsSemanticActions()
def parse(menu): def parse(menu):
parsed = tatsu_parse(GRAMMAR, menu) parsed = tatsu_parse(GRAMMAR, menu, semantics=SEMANTICS)
return parsed return parsed
return dict((
*((att["key"], att["value"]) for att in parsed["attributes"]),
("id", parsed["id"]),
("name", parsed["name"]),
("choices", (kind_equal_to("choice_declaration"), parsed["items_"])),
("bases", (kind_equal_to("base"), parsed["items_"])),
))
def parse_file(filename): def parse_file(filename):

View file

@ -3,27 +3,77 @@
from typing import List from typing import List
def _format_tags(tags):
return (
" :: {}".format(" ".join(["{" + tag + "}" for tag in tags]))
if tags else
""
)
class Option: class Option:
def __init__(self, id_, name, description): def __init__(self, id_, *, name, description, price, tags):
self.id = id_ self.id = id_
self.name = name self.name = name
self.description = description self.description = description
self.price = price
self.tags = tags
def __str__(self):
return "{0.id}: {0.name}{1}{2}{3}".format(
self,
" -- {}".format(self.description) if self.description else "",
_format_tags(self.tags),
" {}".format(self.price) if self.price else ""
)
class Choice: class Choice:
def __init__(self, id_, name, description, options): def __init__(self, id_, *, name, description, options):
self.id = id_ self.id = id_
self.name = name self.name = name
self.description = description self.description = description
self.options: List[Option] = options self.options: List[Option] = options
def __str__(self):
return "{0.id}: {0.name}{1}\n\t\t{2}".format(
self,
" -- {}".format(self.description) if self.description else "",
"\n\t\t".join(map(str, self.options))
)
class Location:
def __init__(self, id_, name, properties, choices, bases): class Dish:
def __init__(self, id_, *, name, description, price, tags, choices):
self.id = id_ self.id = id_
self.name = name self.name = name
self.properties = properties self.description = description
self.price = price
self.tags = tags
self.choices: List[Choice] = choices self.choices: List[Choice] = choices
self.bases = bases
def __str__(self):
return "{0.id}: {0.name}{1}{2}{3}\n\t{4}".format(
self,
" -- {}".format(self.description) if self.description else "",
_format_tags(self.tags),
" {}".format(self.price) if self.price else "",
"\n\t".join(map(str, self.choices))
)
class Location:
def __init__(self, id_, *, name, attributes, dishes):
self.id = id_
self.name = name
self.attributes = attributes
self.dishes: List[Dish] = dishes
def __str__(self):
return "============================\n{0.id}: {0.name}\n============================\n\n{1}".format(
self,
"\n\n".join(map(str, self.dishes))
)

View file

@ -14,14 +14,13 @@ With filenames as arguments, parse those files as HLDS.
{} --help Print this help text""" {} --help Print this help text"""
def definitions():
from app.hlds.definitions import location_definitions
return location_definitions
def main(filenames): def main(filenames):
locations = parse_files(filenames) if filenames else definitions() if filenames:
print(json.dumps(asjson(locations), indent="\t")) location_definitions = parse_files(filenames)
else:
from app.hlds.definitions import location_definitions
print("\n\n".join(map(str, location_definitions)))
if __name__ == "__main__": if __name__ == "__main__":