From: Christian Heller Date: Thu, 10 Jun 2021 20:54:48 +0000 (+0200) Subject: Refactor parser code. X-Git-Url: https://plomlompom.com/repos/%7B%7B%20web_path%20%7D%7D/decks/%7B%7Bprefix%7D%7D/static/balance?a=commitdiff_plain;h=refs%2Fheads%2Fmaster;p=plomrogue2 Refactor parser code. --- diff --git a/plomrogue/game.py b/plomrogue/game.py index b76860a..cb749cf 100755 --- a/plomrogue/game.py +++ b/plomrogue/game.py @@ -2,7 +2,6 @@ from plomrogue.errors import GameError, PlayError from plomrogue.io import GameIO from plomrogue.misc import quote from plomrogue.mapping import YX, MapGeometrySquare, MapGeometryHex, Map -import string import datetime @@ -123,6 +122,7 @@ import os class Game(GameBase): def __init__(self, save_file, *args, **kwargs): + import string from plomrogue.misc import Terrain super().__init__(*args, **kwargs) self.changed = True @@ -159,9 +159,11 @@ class Game(GameBase): if os.path.exists(self.io.save_file): if not os.path.isfile(self.io.save_file): raise GameError('save file path refers to non-file') + self.io.train_parser() def register_thing_type(self, thing_type): self._register_object(thing_type, 'thing_type', 'Thing_') + self.io.train_parser() def register_task(self, task): self._register_object(task, 'task', 'Task_') @@ -190,20 +192,6 @@ class Game(GameBase): return False return True - def get_string_options(self, string_option_type): - if string_option_type == 'direction': - return self.map_geometry.directions - elif string_option_type == 'direction+here': - return ['HERE'] + self.map_geometry.directions - elif string_option_type == 'char': - return [c for c in - string.digits + string.ascii_letters + string.punctuation + ' '] - elif string_option_type == 'map_geometry': - return ['Hex', 'Square'] - elif string_option_type == 'thing_type': - return self.thing_types.keys() - return None - def get_default_spawn_point(self): import random if len(self.spawn_points) == 0: @@ -646,6 +634,7 @@ class Game(GameBase): self.portals = {} self.admin_passwords = [] self.map_geometry = map_geometry + self.io.train_parser() self.map_control_passwords = {'X': 'secret'} self.get_map(YX(0, 0)) self.get_map(YX(0, 0), 'control') diff --git a/plomrogue/io.py b/plomrogue/io.py index 438b8b6..490706e 100644 --- a/plomrogue/io.py +++ b/plomrogue/io.py @@ -13,6 +13,18 @@ class GameIO(): self.save_file = save_file self.servers = [] + def train_parser(self): + import string + self.parser.string_options = { + 'map_geometry': {'Hex', 'Square'}, + 'char': [c for c in + string.digits + string.ascii_letters + string.punctuation + + ' '], + 'direction': self.game.map_geometry.directions, + 'direction+here': ['HERE'] + self.game.map_geometry.directions, + 'thing_type': self.game.thing_types.keys() + } + def loop(self, q): """Handle commands coming through queue q, run game, send results back. diff --git a/plomrogue/parser.py b/plomrogue/parser.py index 302733d..51f5cc2 100644 --- a/plomrogue/parser.py +++ b/plomrogue/parser.py @@ -6,6 +6,7 @@ class Parser: def __init__(self, game=None): self.game = game + self.string_options = {} def tokenize(self, msg): """Parse msg string into tokens. @@ -73,16 +74,17 @@ class Parser: x = get_axis_position_from_argument('X', tokens[1]) return YX(y, x) - def parse(self, msg): + def parse(self, msg, replace_newline=True): """Parse msg as call to function, return function with args tuple. Respects function signature defined in function's .argtypes attribute. - Throws out messages with any but a small list of acceptable characters. + Refuses messages with any but a small list of acceptable characters. """ import string - msg = msg.replace('\n', ' ') # Inserted by some tablet keyboards. + if replace_newline: + msg = msg.replace('\n', ' ') # Inserted by some tablet keyboards. legal_chars = string.digits + string.ascii_letters +\ string.punctuation + ' ' + 'ÄäÖöÜüߧ' + 'éèáàô' + '–…' for c in msg: @@ -151,12 +153,10 @@ class Parser: elif tmpl == string_string: args += [arg] elif tmpl[:len(string_string) + 1] == string_string + ':': - if not hasattr(self.game, 'get_string_options'): - raise ArgError('No string option directory.') string_option_type = tmpl[len(string_string) + 1:] - options = self.game.get_string_options(string_option_type) - if options is None: - raise ArgError('Unknown string option type.') + if not string_option_type in self.string_options.keys(): + raise ArgError('Unknown string option type: %s' % string_option_type) + options = self.string_options[string_option_type] if arg not in options: msg = 'Argument #%s must be one of: %s' % (i + 1, options) raise ArgError(msg) diff --git a/rogue_chat_curses.py b/rogue_chat_curses.py index 91418f6..4f6981d 100755 --- a/rogue_chat_curses.py +++ b/rogue_chat_curses.py @@ -302,6 +302,7 @@ cmd_TASKS.argtypes = 'string' def cmd_THING_TYPE(game, thing_type, symbol_hint): game.thing_types[thing_type] = symbol_hint + game.train_parser() cmd_THING_TYPE.argtypes = 'string char' def cmd_THING_INSTALLED(game, thing_id): @@ -383,13 +384,14 @@ class Game(GameBase): self.portals_new = {} self.terrains = {} self.player = None + self.parser = Parser(self) + self.train_parser() - def get_string_options(self, string_option_type): - if string_option_type == 'map_geometry': - return ['Hex', 'Square'] - elif string_option_type == 'thing_type': - return self.thing_types.keys() - return None + def train_parser(self): + self.parser.string_options = { + 'map_geometry': {'Hex', 'Square'}, + 'thing_type': self.thing_types.keys() + } def get_command(self, command_name): from functools import partial @@ -497,7 +499,6 @@ class RogueChatTUI(TUI): self.socket = ClientSocket(host, self.socket_log) self.game = Game() self.game.tui = self - self.parser = Parser(self.game) self.login_name = None self.map_mode = 'terrain + things' self.password = 'foo' @@ -589,6 +590,10 @@ class RogueChatTUI(TUI): super().__init__(*args, **kwargs) def update_on_connect(self): + self.game.thing_types = {} + self.game.terrains = {} + self.game.train_parser() + self.is_admin = False self.socket.send('TASKS') self.socket.send('TERRAINS') self.socket.send('THING_TYPES') @@ -1093,7 +1098,7 @@ class RogueChatTUI(TUI): self.draw_face_popup() def handle_server_message(self, msg): - command, args = self.parser.parse(msg) + command, args = self.game.parser.parse(msg) command(*args) def on_each_loop_start(self):