SupyML: Add nesting control
parent
4a7d2ec9ef
commit
078bc676ae
|
@ -55,5 +55,7 @@ SupyML = conf.registerPlugin('SupyML')
|
||||||
# conf.registerGlobalValue(SupyML, 'someConfigVariableName',
|
# conf.registerGlobalValue(SupyML, 'someConfigVariableName',
|
||||||
# registry.Boolean(False, _("""Help for 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:
|
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
|
||||||
|
|
|
@ -32,6 +32,7 @@ import re
|
||||||
import copy
|
import copy
|
||||||
import time
|
import time
|
||||||
import Queue
|
import Queue
|
||||||
|
import supybot.conf as conf
|
||||||
from xml.dom import minidom
|
from xml.dom import minidom
|
||||||
import supybot.world as world
|
import supybot.world as world
|
||||||
import supybot.utils as utils
|
import supybot.utils as utils
|
||||||
|
@ -60,6 +61,9 @@ class LoopError(Exception):
|
||||||
class LoopTypeIsMissing(Exception):
|
class LoopTypeIsMissing(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class MaximumNodesNumberExceeded(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
parseMessage = re.compile('\w+: (?P<content>.*)')
|
parseMessage = re.compile('\w+: (?P<content>.*)')
|
||||||
class FakeIrc():
|
class FakeIrc():
|
||||||
def __init__(self, irc):
|
def __init__(self, irc):
|
||||||
|
@ -87,19 +91,25 @@ class FakeIrc():
|
||||||
return getattr(self.__dict__['_irc'], name)
|
return getattr(self.__dict__['_irc'], name)
|
||||||
|
|
||||||
class SupyMLParser:
|
class SupyMLParser:
|
||||||
def __init__(self, plugin, irc, msg, code):
|
def __init__(self, plugin, irc, msg, code, maxNodes):
|
||||||
self._plugin = plugin
|
self._plugin = plugin
|
||||||
self._irc = irc
|
self._irc = irc
|
||||||
self._msg = msg
|
self._msg = msg
|
||||||
self._code = code
|
self._code = code
|
||||||
self.warnings = []
|
self.warnings = []
|
||||||
|
self._maxNodes = maxNodes
|
||||||
|
self.nodesCount = 0
|
||||||
self.data = self._parse(code)
|
self.data = self._parse(code)
|
||||||
|
|
||||||
|
def _startNode(self):
|
||||||
|
self.nodesCount += 1
|
||||||
|
if self.nodesCount >= self._maxNodes:
|
||||||
|
raise MaximumNodesNumberExceeded()
|
||||||
|
|
||||||
def _run(self, code):
|
def _run(self, code):
|
||||||
"""Runs the command using Supybot engine"""
|
"""Runs the command using Supybot engine"""
|
||||||
tokens = callbacks.tokenize(str(code))
|
tokens = callbacks.tokenize(str(code))
|
||||||
fakeIrc = FakeIrc(self._irc)
|
fakeIrc = FakeIrc(self._irc)
|
||||||
# TODO : add nested level
|
|
||||||
self._plugin.Proxy(fakeIrc, self._msg, tokens)
|
self._plugin.Proxy(fakeIrc, self._msg, tokens)
|
||||||
self.rawData = fakeIrc._rawData
|
self.rawData = fakeIrc._rawData
|
||||||
# TODO : don't wait if the plugin is not threaded
|
# TODO : don't wait if the plugin is not threaded
|
||||||
|
@ -108,6 +118,7 @@ class SupyMLParser:
|
||||||
|
|
||||||
def _parse(self, code, variables={}):
|
def _parse(self, code, variables={}):
|
||||||
"""Returns a dom object from the code."""
|
"""Returns a dom object from the code."""
|
||||||
|
self._startNode()
|
||||||
dom = minidom.parseString(code)
|
dom = minidom.parseString(code)
|
||||||
output = self._processDocument(dom, variables)
|
output = self._processDocument(dom, variables)
|
||||||
return output
|
return output
|
||||||
|
@ -126,6 +137,7 @@ class SupyMLParser:
|
||||||
return node.data
|
return node.data
|
||||||
output = node.nodeName + ' '
|
output = node.nodeName + ' '
|
||||||
for childNode in node.childNodes:
|
for childNode in node.childNodes:
|
||||||
|
self._startNode()
|
||||||
if not repr(node) == repr(childNode.parentNode):
|
if not repr(node) == repr(childNode.parentNode):
|
||||||
continue
|
continue
|
||||||
if childNode.nodeName == 'loop':
|
if childNode.nodeName == 'loop':
|
||||||
|
@ -204,7 +216,8 @@ class SupyML(callbacks.Plugin):
|
||||||
"""<SupyML script>
|
"""<SupyML script>
|
||||||
|
|
||||||
Executes the <SupyML script>"""
|
Executes the <SupyML script>"""
|
||||||
parser = SupyMLParser(self, irc, msg, code)
|
parser = SupyMLParser(self, irc, msg, code,
|
||||||
|
self.registryValue('maxnodes')+2)
|
||||||
if world.testing and len(parser.warnings) != 0:
|
if world.testing and len(parser.warnings) != 0:
|
||||||
print parser.warnings
|
print parser.warnings
|
||||||
if parser.rawData is not None:
|
if parser.rawData is not None:
|
||||||
|
|
|
@ -36,7 +36,7 @@ class SupyMLTestCase(ChannelPluginTestCase):
|
||||||
#################################
|
#################################
|
||||||
# Utilities
|
# Utilities
|
||||||
def _getIfAnswerIsEqual(self, msg):
|
def _getIfAnswerIsEqual(self, msg):
|
||||||
time.sleep(0.2)
|
time.sleep(0.1)
|
||||||
m = self.irc.takeMsg()
|
m = self.irc.takeMsg()
|
||||||
while m is not None:
|
while m is not None:
|
||||||
if repr(m) == repr(msg):
|
if repr(m) == repr(msg):
|
||||||
|
@ -137,5 +137,16 @@ class SupyMLTestCase(ChannelPluginTestCase):
|
||||||
'</echo>',
|
'</echo>',
|
||||||
'45')
|
'45')
|
||||||
|
|
||||||
|
def testMaxNesting(self):
|
||||||
|
self.assertNotError('SupyML eval ' +
|
||||||
|
'<echo>'*30+
|
||||||
|
'foo' +
|
||||||
|
'</echo>'*30
|
||||||
|
)
|
||||||
|
self.assertError('SupyML eval ' +
|
||||||
|
'<echo>'*31+
|
||||||
|
'foo' +
|
||||||
|
'</echo>'*31
|
||||||
|
)
|
||||||
|
|
||||||
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
|
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
|
||||||
|
|
Loading…
Reference in New Issue