home · contact · privacy
Refactor parser code. master
authorChristian Heller <c.heller@plomlompom.de>
Thu, 10 Jun 2021 20:54:48 +0000 (22:54 +0200)
committerChristian Heller <c.heller@plomlompom.de>
Thu, 10 Jun 2021 20:54:48 +0000 (22:54 +0200)
plomrogue/game.py
plomrogue/io.py
plomrogue/parser.py
rogue_chat_curses.py

index b76860aa5ff7954c802c63334d22367a9acb7ffa..cb749cffa939f38c3672945fb240ae3d6e3aef79 100755 (executable)
@@ -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
 from plomrogue.io import GameIO
 from plomrogue.misc import quote
 from plomrogue.mapping import YX, MapGeometrySquare, MapGeometryHex, Map
-import string
 import datetime
 
 
 import datetime
 
 
@@ -123,6 +122,7 @@ import os
 class Game(GameBase):
 
     def __init__(self, save_file, *args, **kwargs):
 class Game(GameBase):
 
     def __init__(self, save_file, *args, **kwargs):
+        import string
         from plomrogue.misc import Terrain
         super().__init__(*args, **kwargs)
         self.changed = True
         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')
         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_')
 
     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_')
 
     def register_task(self, task):
         self._register_object(task, 'task', 'Task_')
@@ -190,20 +192,6 @@ class Game(GameBase):
                 return False
         return True
 
                 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:
     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.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')
         self.map_control_passwords = {'X': 'secret'}
         self.get_map(YX(0, 0))
         self.get_map(YX(0, 0), 'control')
index 438b8b6e1301e4da584127382629791ce87756b6..490706eefd9fe2ef203632dd6b255180839fd252 100644 (file)
@@ -13,6 +13,18 @@ class GameIO():
         self.save_file = save_file
         self.servers = []
 
         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.
 
     def loop(self, q):
         """Handle commands coming through queue q, run game, send results back.
 
index 302733d0322a69c9592276b94239b626debcb4c3..51f5cc20390ac71c50b5b1baae7f53fcd7c12bdd 100644 (file)
@@ -6,6 +6,7 @@ class Parser:
 
     def __init__(self, game=None):
         self.game = game
 
     def __init__(self, game=None):
         self.game = game
+        self.string_options = {}
 
     def tokenize(self, msg):
         """Parse msg string into tokens.
 
     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)
 
         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.
 
         """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
 
         """
         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:
         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 + ':':
             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:]
                 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)
                 if arg not in options:
                     msg = 'Argument #%s must be one of: %s' % (i + 1, options)
                     raise ArgError(msg)
index 91418f61f6820fa0e1ad5e89503dc8114c177322..4f6981df553696fb7d865f76453463a819e580dd 100755 (executable)
@@ -302,6 +302,7 @@ cmd_TASKS.argtypes = 'string'
 
 def cmd_THING_TYPE(game, thing_type, symbol_hint):
     game.thing_types[thing_type] = symbol_hint
 
 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):
 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.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
 
     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.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'
         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):
         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')
         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):
                 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):
         command(*args)
 
     def on_each_loop_start(self):