SupyML: change the variable lifetime (and make it work), and the <while> managment (not tested)

master
Valentin Lorentz 2010-11-14 09:22:49 +01:00
parent dfca8e3a34
commit a486749808
3 changed files with 65 additions and 31 deletions

View File

@ -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
--------------- ---------------

View File

@ -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)

View File

@ -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: