From 37e3799985cf9fe67bcbd5c7f1fa591d6f94c068 Mon Sep 17 00:00:00 2001 From: Midgard Date: Sun, 26 Jan 2020 01:29:19 +0100 Subject: [PATCH] Add semantic actions to create models, add str for models --- app/hlds/hlds.tatsu | 3 +- app/hlds/loader.py | 67 +++++++++++++++++++++++++++++++++++++-------- app/hlds/models.py | 62 +++++++++++++++++++++++++++++++++++++---- parse_hlds.py | 13 ++++----- 4 files changed, 119 insertions(+), 26 deletions(-) diff --git a/app/hlds/hlds.tatsu b/app/hlds/hlds.tatsu index 78b4080..bff6d7e 100644 --- a/app/hlds/hlds.tatsu +++ b/app/hlds/hlds.tatsu @@ -41,7 +41,7 @@ block = ; base_block = - kind:'base' s ~ + 'base' s ~ id:identifier ':' s >attributes n choices:{ indent_choice_block } @@ -55,7 +55,6 @@ indent_choice_entry = n '\t\t' >choice_entry ; # Toplevel choice definitions choice_block = - kind:`choice_declaration` id:identifier ':' s >attributes entries:{ noindent_choice_entry } n ; diff --git a/app/hlds/loader.py b/app/hlds/loader.py index 88a5038..647e502 100644 --- a/app/hlds/loader.py +++ b/app/hlds/loader.py @@ -4,7 +4,8 @@ from glob import glob from os import path, walk from tatsu import parse as tatsu_parse 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 @@ -12,20 +13,64 @@ with open(path.join(path.dirname(__file__), "hlds.tatsu")) as fh: GRAMMAR = fh.read() -def kind_equal_to(compare_to): - return lambda item: item["kind"] == compare_to +def filter_instance(cls, iterable): + 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): - parsed = tatsu_parse(GRAMMAR, menu) + parsed = tatsu_parse(GRAMMAR, menu, semantics=SEMANTICS) 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): diff --git a/app/hlds/models.py b/app/hlds/models.py index b8638d0..6b948b8 100644 --- a/app/hlds/models.py +++ b/app/hlds/models.py @@ -3,27 +3,77 @@ from typing import List +def _format_tags(tags): + return ( + " :: {}".format(" ".join(["{" + tag + "}" for tag in tags])) + if tags else + "" + ) + + class Option: - def __init__(self, id_, name, description): + def __init__(self, id_, *, name, description, price, tags): self.id = id_ self.name = name 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: - def __init__(self, id_, name, description, options): + def __init__(self, id_, *, name, description, options): self.id = id_ self.name = name self.description = description 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.name = name - self.properties = properties + self.description = description + self.price = price + self.tags = tags 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)) + ) diff --git a/parse_hlds.py b/parse_hlds.py index babe2bb..95028b3 100755 --- a/parse_hlds.py +++ b/parse_hlds.py @@ -14,14 +14,13 @@ With filenames as arguments, parse those files as HLDS. {} --help Print this help text""" -def definitions(): - from app.hlds.definitions import location_definitions - return location_definitions - - def main(filenames): - locations = parse_files(filenames) if filenames else definitions() - print(json.dumps(asjson(locations), indent="\t")) + if filenames: + location_definitions = parse_files(filenames) + else: + from app.hlds.definitions import location_definitions + + print("\n\n".join(map(str, location_definitions))) if __name__ == "__main__":