From 078bc676ae6ae7fafeef8890f2bfad03ef981e61 Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Sun, 14 Nov 2010 15:06:17 +0100 Subject: [PATCH] SupyML: Add nesting control --- SupyML/config.py | 2 ++ SupyML/plugin.py | 19 ++++++++++++++++--- SupyML/test.py | 13 ++++++++++++- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/SupyML/config.py b/SupyML/config.py index 9d5aefe..cf0b88d 100644 --- a/SupyML/config.py +++ b/SupyML/config.py @@ -55,5 +55,7 @@ SupyML = conf.registerPlugin('SupyML') # conf.registerGlobalValue(SupyML, 'someConfigVariableName', # registry.Boolean(False, _("""Help for someConfigVariableName."""))) +conf.registerGlobalValue(SupyML, 'maxnodes', registry.Integer(30, """Determines + the maximum number of nodes processed by the 'SupyML eval' command.""")) # vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: diff --git a/SupyML/plugin.py b/SupyML/plugin.py index a4ff712..f43672e 100644 --- a/SupyML/plugin.py +++ b/SupyML/plugin.py @@ -32,6 +32,7 @@ import re import copy import time import Queue +import supybot.conf as conf from xml.dom import minidom import supybot.world as world import supybot.utils as utils @@ -60,6 +61,9 @@ class LoopError(Exception): class LoopTypeIsMissing(Exception): pass +class MaximumNodesNumberExceeded(Exception): + pass + parseMessage = re.compile('\w+: (?P.*)') class FakeIrc(): def __init__(self, irc): @@ -87,19 +91,25 @@ class FakeIrc(): return getattr(self.__dict__['_irc'], name) class SupyMLParser: - def __init__(self, plugin, irc, msg, code): + def __init__(self, plugin, irc, msg, code, maxNodes): self._plugin = plugin self._irc = irc self._msg = msg self._code = code self.warnings = [] + self._maxNodes = maxNodes + self.nodesCount = 0 self.data = self._parse(code) + def _startNode(self): + self.nodesCount += 1 + if self.nodesCount >= self._maxNodes: + raise MaximumNodesNumberExceeded() + def _run(self, code): """Runs the command using Supybot engine""" tokens = callbacks.tokenize(str(code)) fakeIrc = FakeIrc(self._irc) - # TODO : add nested level self._plugin.Proxy(fakeIrc, self._msg, tokens) self.rawData = fakeIrc._rawData # TODO : don't wait if the plugin is not threaded @@ -108,6 +118,7 @@ class SupyMLParser: def _parse(self, code, variables={}): """Returns a dom object from the code.""" + self._startNode() dom = minidom.parseString(code) output = self._processDocument(dom, variables) return output @@ -126,6 +137,7 @@ class SupyMLParser: return node.data output = node.nodeName + ' ' for childNode in node.childNodes: + self._startNode() if not repr(node) == repr(childNode.parentNode): continue if childNode.nodeName == 'loop': @@ -204,7 +216,8 @@ class SupyML(callbacks.Plugin): """ Executes the """ - parser = SupyMLParser(self, irc, msg, code) + parser = SupyMLParser(self, irc, msg, code, + self.registryValue('maxnodes')+2) if world.testing and len(parser.warnings) != 0: print parser.warnings if parser.rawData is not None: diff --git a/SupyML/test.py b/SupyML/test.py index 8baacb3..909a8eb 100644 --- a/SupyML/test.py +++ b/SupyML/test.py @@ -36,7 +36,7 @@ class SupyMLTestCase(ChannelPluginTestCase): ################################# # Utilities def _getIfAnswerIsEqual(self, msg): - time.sleep(0.2) + time.sleep(0.1) m = self.irc.takeMsg() while m is not None: if repr(m) == repr(msg): @@ -137,5 +137,16 @@ class SupyMLTestCase(ChannelPluginTestCase): '', '45') + def testMaxNesting(self): + self.assertNotError('SupyML eval ' + + ''*30+ + 'foo' + + ''*30 + ) + self.assertError('SupyML eval ' + + ''*31+ + 'foo' + + ''*31 + ) # vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: