SupyML: change the variable lifetime (and make it work), and the <while> managment (not tested)
parent
dfca8e3a34
commit
a486749808
|
@ -32,10 +32,8 @@ numerics, but it is their own problems.
|
||||||
Variable lifetime
|
Variable lifetime
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
When setting a new variable, the variable is readable and writable in the
|
When creating/setting/editing a variable or its value, the changes are
|
||||||
node where it is created, and in the child nodes.
|
available everywhere in the source code.
|
||||||
If a child node write a variable defined in a parent node, the new value of
|
|
||||||
the variable will be available in the parent node.
|
|
||||||
|
|
||||||
About the names
|
About the names
|
||||||
---------------
|
---------------
|
||||||
|
|
|
@ -30,9 +30,10 @@
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import copy
|
import copy
|
||||||
|
import time
|
||||||
import Queue
|
import Queue
|
||||||
import supybot.world as world
|
|
||||||
from xml.dom import minidom
|
from xml.dom import minidom
|
||||||
|
import supybot.world as world
|
||||||
import supybot.utils as utils
|
import supybot.utils as utils
|
||||||
from supybot.commands import *
|
from supybot.commands import *
|
||||||
from supybot.irclib import IrcMsgQueue
|
from supybot.irclib import IrcMsgQueue
|
||||||
|
@ -50,10 +51,20 @@ except:
|
||||||
_ = lambda x:x
|
_ = lambda x:x
|
||||||
internationalizeDocstring = lambda x:x
|
internationalizeDocstring = lambda x:x
|
||||||
|
|
||||||
|
class ParseError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class LoopError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class LoopTypeIsMissing(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
class FakeIrc():
|
class FakeIrc():
|
||||||
def __init__(self, irc):
|
def __init__(self, irc):
|
||||||
self._irc = irc
|
self._irc = irc
|
||||||
self._message = ''
|
self._message = ''
|
||||||
|
self._data = ''
|
||||||
def error(self, message):
|
def error(self, message):
|
||||||
message = message
|
message = message
|
||||||
self._data = message
|
self._data = message
|
||||||
|
@ -74,56 +85,57 @@ class SupyMLParser:
|
||||||
self._msg = msg
|
self._msg = msg
|
||||||
self._code = code
|
self._code = code
|
||||||
self.warnings = []
|
self.warnings = []
|
||||||
self._parse()
|
self._parse(code)
|
||||||
|
|
||||||
def _run(self, code, proxify):
|
def _run(self, code, proxify):
|
||||||
"""Runs the command using Supybot engine"""
|
"""Runs the command using Supybot engine"""
|
||||||
tokens = callbacks.tokenize(str(code))
|
tokens = callbacks.tokenize(str(code))
|
||||||
if proxify:
|
if proxify:
|
||||||
fakeIrc = FakeIrc(self._irc)
|
fakeIrc = FakeIrc(self._irc)
|
||||||
|
# TODO : add nested level
|
||||||
else:
|
else:
|
||||||
fakeIrc = self._irc
|
fakeIrc = self._irc
|
||||||
self._plugin.Proxy(fakeIrc, self._msg, tokens)
|
self._plugin.Proxy(fakeIrc, self._msg, tokens)
|
||||||
if proxify:
|
if proxify:
|
||||||
|
# TODO : don't wait if the plugin is not threaded
|
||||||
|
time.sleep(0.1)
|
||||||
return fakeIrc._data
|
return fakeIrc._data
|
||||||
|
|
||||||
def _parse(self):
|
|
||||||
"""Returns a dom object from self._code."""
|
|
||||||
dom = minidom.parseString(self._code)
|
|
||||||
return self._processDocument(dom)
|
|
||||||
|
|
||||||
def _processDocument(self, dom):
|
def _parse(self, code, variables={}, proxify=False):
|
||||||
|
"""Returns a dom object from the code."""
|
||||||
|
dom = minidom.parseString(code)
|
||||||
|
output = self._processDocument(dom, variables, proxify)
|
||||||
|
return output
|
||||||
|
|
||||||
|
def _processDocument(self, dom, variables={}, proxify=False):
|
||||||
"""Handles the root node and call child nodes"""
|
"""Handles the root node and call child nodes"""
|
||||||
for childNode in dom.childNodes:
|
for childNode in dom.childNodes:
|
||||||
if isinstance(childNode, minidom.Element):
|
if isinstance(childNode, minidom.Element):
|
||||||
self._processNode(childNode, {}, False)
|
output = self._processNode(childNode, variables, proxify)
|
||||||
|
return output
|
||||||
|
|
||||||
def _processNode(self, node, variables, proxifyIrc=True):
|
def _processNode(self, node, variables, proxifyIrc=True):
|
||||||
"""Returns the value of an internapreted node.
|
"""Returns the value of an internapreted node.
|
||||||
|
|
||||||
Takes an optional attribute, passed to self._run() that mean if the
|
Takes an optional attribute, passed to self._run() that mean if the
|
||||||
Irc object should be proxified. If it is not, the real Irc object is
|
Irc object should be proxified. If it is not, the real Irc object is
|
||||||
used, datas are sent to IRC, and this function will return None."""
|
used, datas are sent to IRC, and this function will return None."""
|
||||||
if isinstance(node, minidom.Text):
|
if isinstance(node, minidom.Text):
|
||||||
return node.data
|
return node.data
|
||||||
output = node.nodeName + ' '
|
output = node.nodeName + ' '
|
||||||
newVariables = copy.deepcopy(variables)
|
|
||||||
for childNode in node.childNodes:
|
for childNode in node.childNodes:
|
||||||
if not repr(node) == repr(childNode.parentNode):
|
if not repr(node) == repr(childNode.parentNode):
|
||||||
print "CONTINUING"
|
|
||||||
continue
|
continue
|
||||||
if childNode.nodeName == 'loop':
|
if childNode.nodeName == 'loop':
|
||||||
output += self._processLoop(childNode, newVariables)
|
output += self._processLoop(childNode, variables)
|
||||||
elif childNode.nodeName == 'if':
|
elif childNode.nodeName == 'if':
|
||||||
output += self._processId(childNode, newVariables)
|
output += self._processId(childNode, variables)
|
||||||
elif childNode.nodeName == 'var':
|
elif childNode.nodeName == 'var':
|
||||||
output += self._processVar(childNode, newVariables)
|
output += self._processVar(childNode, variables)
|
||||||
elif childNode.nodeName == 'set':
|
elif childNode.nodeName == 'set':
|
||||||
output += self._processSet(childNode, newVariables)
|
output += self._processSet(childNode, variables)
|
||||||
else:
|
else:
|
||||||
output += self._processNode(childNode, newVariables) or ''
|
output += self._processNode(childNode, variables) or ''
|
||||||
for key in variables:
|
|
||||||
variables[key] = newVariables[key]
|
|
||||||
value = self._run(output, proxifyIrc)
|
value = self._run(output, proxifyIrc)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
@ -143,13 +155,34 @@ class SupyMLParser:
|
||||||
try:
|
try:
|
||||||
return variables[variableName]
|
return variables[variableName]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
self.warnings.append('Access to non-existing variable: %s' %
|
self.warnings.append('Access to non-existing variable: %s' %
|
||||||
variableName)
|
variableName)
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
def _processLoop(self, node, variables):
|
def _processLoop(self, node, variables):
|
||||||
"""Handles the <loop> tag"""
|
"""Handles the <loop> tag"""
|
||||||
return '<NOT IMPLEMENTED>'
|
loopType = None
|
||||||
|
loopCond = 'false'
|
||||||
|
loopContent = ''
|
||||||
|
output = ''
|
||||||
|
for childNode in node.childNodes:
|
||||||
|
if loopType is None and childNode.nodeName not in ('while'):
|
||||||
|
raise LoopTypeIsMissing(node.toxml())
|
||||||
|
elif loopType is None:
|
||||||
|
loopType = childNode.nodeName
|
||||||
|
loopCond = childNode.toxml()[len('<while>'):-len('</while>')]
|
||||||
|
else:
|
||||||
|
loopContent += childNode.toxml()
|
||||||
|
if loopType == 'while':
|
||||||
|
try:
|
||||||
|
while utils.str.toBool(self._parse(loopCond, variables, True)):
|
||||||
|
output += self._parse(loopContent)
|
||||||
|
except AttributeError: # toBool() failed
|
||||||
|
pass
|
||||||
|
except ValueError: # toBool() failed
|
||||||
|
pass
|
||||||
|
return output
|
||||||
|
|
||||||
|
|
||||||
def _checkVariableName(self, variableName):
|
def _checkVariableName(self, variableName):
|
||||||
if len(variableName) == 0:
|
if len(variableName) == 0:
|
||||||
|
@ -165,12 +198,12 @@ class SupyML(callbacks.Plugin):
|
||||||
#threaded = True
|
#threaded = True
|
||||||
def eval(self, irc, msg, args, code):
|
def eval(self, irc, msg, args, code):
|
||||||
"""<SupyML script>
|
"""<SupyML script>
|
||||||
|
|
||||||
Executes the <SupyML script>"""
|
Executes the <SupyML script>"""
|
||||||
parser = SupyMLParser(self, irc, msg, code)
|
parser = SupyMLParser(self, irc, msg, code)
|
||||||
if world.testing and len(parser.warnings) != 0:
|
if world.testing and len(parser.warnings) != 0:
|
||||||
print parser.warnings
|
print parser.warnings
|
||||||
|
|
||||||
eval=wrap(eval, ['text'])
|
eval=wrap(eval, ['text'])
|
||||||
SupyML = internationalizeDocstring(SupyML)
|
SupyML = internationalizeDocstring(SupyML)
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,8 @@ class SupyMLTestCase(ChannelPluginTestCase):
|
||||||
answer = ircmsgs.IrcMsg(prefix="", command="PRIVMSG",
|
answer = ircmsgs.IrcMsg(prefix="", command="PRIVMSG",
|
||||||
args=('ProgVal', 'test wants me to tell you: foo'))
|
args=('ProgVal', 'test wants me to tell you: foo'))
|
||||||
self.failIf(self._getIfAnswerIsEqual(answer) == False)
|
self.failIf(self._getIfAnswerIsEqual(answer) == False)
|
||||||
|
self.assertResponse('SupyML eval <nne>4 5</nne>', 'true')
|
||||||
|
self.assertResponse('SupyML eval <echo><nne>4 5</nne></echo>', 'true')
|
||||||
|
|
||||||
def testNoMoreThanOneAnswer(self):
|
def testNoMoreThanOneAnswer(self):
|
||||||
self.assertResponse('SupyML eval '
|
self.assertResponse('SupyML eval '
|
||||||
|
@ -95,24 +97,25 @@ class SupyMLTestCase(ChannelPluginTestCase):
|
||||||
'<var name="foo" />'
|
'<var name="foo" />'
|
||||||
'</echo>'
|
'</echo>'
|
||||||
'</echo>',
|
'</echo>',
|
||||||
'bar')
|
'barbar')
|
||||||
|
|
||||||
def testWhile(self):
|
def testWhile(self):
|
||||||
self.assertResponse('SupyML eval '
|
self.assertResponse('SupyML eval '
|
||||||
'<echo>'
|
'<echo>'
|
||||||
'<set name="foo">bar</set>'
|
'<set name="foo">4</set>'
|
||||||
'<loop>'
|
'<loop>'
|
||||||
'<while>'
|
'<while>'
|
||||||
'<nne>'
|
'<nne>'
|
||||||
'<var name="foo" /> 5'
|
'<var name="foo" /> 5'
|
||||||
'</nne>'
|
'</nne>'
|
||||||
'</while>'
|
'</while>'
|
||||||
|
'<set name="foo">5</set>'
|
||||||
'<echo>'
|
'<echo>'
|
||||||
'bar'
|
'bar'
|
||||||
'</echo>'
|
'</echo>'
|
||||||
'</loop>'
|
'</loop>'
|
||||||
'</echo>',
|
'</echo>',
|
||||||
'bar'*5)
|
'barbar')
|
||||||
|
|
||||||
|
|
||||||
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
|
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79:
|
||||||
|
|
Loading…
Reference in New Issue