xchoose: added further error handling

This commit is contained in:
braph
2016-09-06 13:23:46 +02:00
parent 8ab4e8cdd4
commit abb6494acf

View File

@@ -280,21 +280,58 @@ def command_dice(argv, **args):
} }
@pluginfunction('xchoose', 'chooses randomly between arguments', ptypes.COMMAND, ratelimit_class=RATE_INTERACTIVE) @pluginfunction('xchoose', 'chooses randomly between nested option groups', ptypes.COMMAND, ratelimit_class=RATE_INTERACTIVE)
def command_xchoose(argv, **args): def command_xchoose(argv, **args):
class ChooseTree():
def __init__(self, item=None):
self.item = item
self.tree = None
self.closed = False
# opening our root node
if self.item is None:
self.open()
def open(self):
if self.tree is None:
self.tree = []
elif self.closed:
raise Exception("cannot re-open group for item '%s'" % (self.item))
def close(self):
if self.tree is None:
raise Exception("close on unopened bracket")
elif len(self.tree) == 0:
raise Exception("item '%s' has a group without sub options" % (self.item))
else:
self.closed = True
def last(self):
return self.tree[-1]
def choose(self):
if self.item:
yield self.item
if self.tree:
sel = random.choice(self.tree)
for sub in sel.choose():
yield sub
def add(self, item):
self.tree.append( ChooseTree(item) )
# because of error handling we're nesting this function here # because of error handling we're nesting this function here
def xchoose(line): def xchoose(line):
pos = 0
item = '' item = ''
quote = None quote = None
choose_tree = [] choose_tree = ChooseTree()
choose_stack = [ choose_tree ] choose_stack = [ choose_tree ]
bracket_stack = [] bracket_stack = []
for c in line: for pos, c in enumerate(line, 1):
pos += 1 try:
if quote: if quote:
if c == quote: if c == quote:
quote = None quote = None
@@ -303,62 +340,66 @@ def command_xchoose(argv, **args):
elif c == ' ': elif c == ' ':
if item: if item:
choose_stack[-1].append( (item, []) ) choose_stack[-1].add(item)
item = '' item = ''
elif c == '(' or c == '[' or c == '{' or c == '<': elif c in ('(', '[', '{', '<'):
if item: if item:
choose_stack[-1].append( (item, []) ) choose_stack[-1].add(item)
item = '' item = ''
if not choose_stack[-1]: try:
raise Exception("Missing option before bracket (at pos {:d})".format(pos)) last = choose_stack[-1].last()
last.open()
choose_stack.append( choose_stack[-1][-1][1] ) choose_stack.append(last)
bracket_stack.append(c) bracket_stack.append(c)
except IndexError:
raise Exception("cannot open group without preceding option")
elif c == ')' or c == ']' or c == '}' or c == '>': elif c in (')', ']', '}', '>'):
if not bracket_stack: if not bracket_stack:
raise Exception("Missing leading bracket for '{}'".format(c)) raise Exception("missing leading bracket for '%s'" % (c))
opening_bracket = bracket_stack.pop(-1) opening_bracket = bracket_stack.pop(-1)
wanted_closing_bracket = { '(':')', '[':']', '{':'}', '<':'>' }[opening_bracket] wanted_closing_bracket = { '(':')', '[':']', '{':'}', '<':'>' }[opening_bracket]
if c != wanted_closing_bracket: if c != wanted_closing_bracket:
raise Exception("Bracket mismatch. Wanted bracket '{}' but got '{}'".format( raise Exception("bracket mismatch, wanted bracket '%s' but got '%s'" % (
wanted_closing_bracket, c)) wanted_closing_bracket, c))
if item: if item:
choose_stack[-1].append( (item, []) ) choose_stack[-1].add(item)
item = '' item = ''
choose_stack[-1].close()
choose_stack.pop(-1) choose_stack.pop(-1)
elif c == '"' or c == "'": elif c in ('"', "'"):
quote = c quote = c
else: else:
item += c item += c
except Exception as e:
raise Exception("%s (at pos %d)" % (e, pos))
if bracket_stack: if bracket_stack:
raise Exception("Missing closing bracket for '{}'".format(bracket_stack[-1])) raise Exception("missing closing bracket for '%s'" % (bracket_stack[-1]))
if quote:
raise Exception("missing closing quote (%s)" % (quote))
if item: if item:
choose_stack[-1].append( (item, []) ) choose_stack[-1].add(item)
def tree_choice(tree): return ' '.join(choose_tree.choose())
sel = random.choice(tree)
yield sel[0]
if sel[1]:
for sub in tree_choice(sel[1]):
yield sub
return ' '.join(tree_choice(choose_tree))
# start of command_xchoose # start of command_xchoose
line = re.sub('.*xchoose ', '', args['data']) line = re.sub('.*xchoose *', '', args['data'])
if not line:
return {
'msg': '%s: %s' % (args['reply_user'], 'missing options')
}
try: try:
return { return {
'msg': '%s: %s' % (args['reply_user'], xchoose(line)) 'msg': '%s: %s' % (args['reply_user'], xchoose(line))