Exemplo n.º 1
0
 def test_prefer_unhelpful(self):
     wrong = {"correct": False}
     also_wrong = {"correct": False}
     correct = lambda obj: obj["correct"]
     token = parser.OneOf([("foo", wrong), ("foo", also_wrong)],
                          prefer=correct)
     self.assertRaises(parser.AmbiguityError, token.parseString, "foo")
Exemplo n.º 2
0
 def test_prefer_filter(self):
     preferred = {"correct": True}
     also_preferred = {"correct": True}
     wrong = {"correct": False}
     correct = lambda obj: obj["correct"]
     token = parser.OneOf(
         [("foo", preferred), ("foo", also_preferred), ("foo", wrong)],
         prefer=correct)
     try:
         token.parseString("foo")
         self.fail("Expected AmbiguityError")
     except parser.AmbiguityError as e:
         self.assertIn(("foo", preferred), e.matches)
         self.assertIn(("foo", also_preferred), e.matches)
         self.assertNotIn(("foo", wrong), e.matches)
Exemplo n.º 3
0
 def test_easy(self):
     result = object()
     token = parser.OneOf([("foo", result), ("bar", object())])
     self.assert_parse(token, "foo", result)
Exemplo n.º 4
0
 def test_pattern(self):
     result = object()
     token = parser.OneOf(
         [("1", object()), ("12", result), ("12x", object())],
         pattern=pyp.Word(pyp.nums))
     self.assertEqual(token.parseString("12x", parseAll=False)[0], result)
Exemplo n.º 5
0
 def test_prefer_disambiguate(self):
     result = {"correct": True}
     wrong = {"correct": False}
     correct = lambda obj: obj["correct"]
     token = parser.OneOf([("foo", result), ("foo", wrong)], prefer=correct)
     self.assert_parse(token, "foo", result)
Exemplo n.º 6
0
 def test_partial_but_exact(self):
     token = parser.OneOf([("foo", object()), ("bar", object())], exact=True)
     self.assertRaises(parser.NotFoundError, token.parseString, "f",
                       parseAll=True)
Exemplo n.º 7
0
 def test_notfound(self):
     self.assertRaises(parser.NotFoundError,
                       parser.OneOf([("foo", object())]).parseString,
                       "bar", parseAll=True)
Exemplo n.º 8
0
 def test_prefer_full_case_insensitive(self):
     result = object()
     token = parser.OneOf([("foo", result), ("foobar", object())],
                          exact=False)
     self.assert_parse(token, "Foo", result)
Exemplo n.º 9
0
 def test_full_ambiguous(self):
     token = parser.OneOf([("foo", object()), ("foo", object())],
                          exact=False)
     self.assertRaises(parser.AmbiguityError, token.parseString, "foo",
                       parseAll=True)
Exemplo n.º 10
0
 def test_partial(self):
     result = object()
     token = parser.OneOf([("foo", result), ("bar", object())], exact=False)
     self.assert_parse(token, "f", result)
Exemplo n.º 11
0
    def handle(self, player, line):
        """
        Parse the input line for a command and arguments, reporting any errors
        or unresolvable ambiguity.
        """

        line = line.strip()
        if not line:
            return

        split_line = line.split(None, 1)
        if len(split_line) == 1:
            split_line.append("")
        first, rest_of_line = split_line

        name = ""
        command = None

        # Check for nospace commands
        nospace_matches = []
        for command in all_commands():
            for name in command().nospace_names:
                # We can't use find_by_name because we don't know where the
                # nospace command ends.
                if line.startswith(name):
                    # No partial matching, for the same reason.
                    nospace_matches.append((name, command))
        if len(nospace_matches) == 1:
            name, command = nospace_matches[0]
            if len(line) > len(name):
                arguments = line[len(name):]
            else:
                arguments = ""

        try:
            try:
                if len(nospace_matches) > 1:
                    raise parser.AmbiguityError(line, 0, parser.Command.errmsg,
                                                parser.Command,
                                                nospace_matches)

                # Check for normal command matches
                pattern = parser.CommandName(fullOnly=True)("command")
                parse_result = pattern.parseString(first, parseAll=True)
                matched = parse_result["command"]
                arguments = rest_of_line
                if nospace_matches:
                    # We found a regular command, but already had a nospace
                    # command.
                    raise parser.AmbiguityError(line, 0, parser.Command.errmsg,
                                                parser.Command,
                                                nospace_matches + [matched])
                else:
                    name, command = parse_result["command"]
            except parser.NotFoundError as e:
                # No commands match, what about exits?
                exits = [(exit.name, exit)
                         for exit in db.find_all(lambda x: x.type == 'exit' and
                                                 x.location == player.location)
                         ]
                try:
                    pattern = parser.OneOf(exits)("exit").setName("exit")
                    parse_result = pattern.parseString(first, parseAll=True)
                    # OneOf(exits) parsed, so exactly one exit matches.
                    if not nospace_matches:
                        command = commands.world.Go
                        arguments = first
                except parser.AmbiguityError as f:
                    # Multiple exits match and no full commands do.
                    if not nospace_matches:
                        player.send(f.verbose())
                        return
                    # At this point there can only be one nospace command.
                    # Let it fall all the way through to execution.
                except parser.NotFoundError as _:
                    raise e

        except parser.NotFoundError as e:
            if not nospace_matches:
                message = e.verbose()
                # Check whether a require_full command would have matched
                rf_commands = [c for c in all_commands() if c.require_full]
                # (ignoring perfect matches because we would have already seen
                # them)
                rf_matches = utils.find_by_name(e.pstr,
                                                rf_commands,
                                                attributes=["names"])[1]
                if len(rf_matches) == 1:
                    rf_name, rf_command = rf_matches[0]
                    message += (" (If you mean \"{},\" you'll need to use the "
                                "whole command name.)".format(rf_name))
                elif rf_matches:
                    rf_names = [c[0] for c in rf_matches]
                    message += (" (If you meant one of these, you'll need to "
                                "use the whole command name: {}.)".format(
                                    ", ".join(rf_names)))
                player.send(message)
                return

        except parser.AmbiguityError as e:
            # it's not clear from the name which command the user intended,
            # so see if any of their argument specs match what we got
            parsable_matches = []
            for possible_name, possible_command in e.matches + nospace_matches:
                try:
                    if nospace_matches and ((possible_name, possible_command)
                                            == nospace_matches[0]):
                        test_arguments = line.split(possible_name, 1)[1]
                    else:
                        test_arguments = rest_of_line
                    pattern = possible_command.args(player)
                    args = pattern.parseString(test_arguments, parseAll=True)
                    parsable_matches.append((possible_name, possible_command))
                except pyparsing.ParseException:
                    # user probably didn't intend this command; skip it.
                    pass
                except utils.UserError:
                    parsable_matches.append((possible_name, possible_command))
            if len(parsable_matches) == 1:
                name, command = parsable_matches[0]
                if len(line) > len(name):
                    if parsable_matches[0] in nospace_matches:
                        arguments = line[len(name):]
                    else:
                        arguments = rest_of_line
                else:
                    arguments = ""
            else:
                if parsable_matches:
                    # we can at least narrow the field a little
                    e.matches = parsable_matches
                player.send(e.verbose())
                return

        # okay! we have a command! let's parse it.
        try:
            args = command.args(player).parseString(arguments, parseAll=True)
            command().execute(player, args)
        except utils.UserError as e:
            if hasattr(e, "verbose"):
                player.send(e.verbose())
            else:
                player.send(str(e))
        except pyparsing.ParseException as e:
            usages = command().usages
            if len(usages) > 1:
                from commands.help import Usage
                player.send("Usage:")
                Usage().execute(player, {"command": (name, command)},
                                tabs=True)
            else:
                player.send("Usage: " + usages[0])
            player.send("(Try \"help {}\" for more help.)".format(name))
Exemplo n.º 12
0
 def args(cls, player):
     return pyp.Optional(
         parser.OneOf(channels.all())("channel").setName("channel") +
         pyp.Optional(parser.Text("text")))