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
-----------------
When setting a new variable, the variable is readable and writable in the
node where it is created, and in the child nodes.
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.
When creating/setting/editing a variable or its value, the changes are
available everywhere in the source code.
About the names
---------------

View File

@ -30,9 +30,10 @@
import re
import copy
import time
import Queue
import supybot.world as world
from xml.dom import minidom
import supybot.world as world
import supybot.utils as utils
from supybot.commands import *
from supybot.irclib import IrcMsgQueue
@ -50,10 +51,20 @@ except:
_ = lambda x:x
internationalizeDocstring = lambda x:x
class ParseError(Exception):
pass
class LoopError(Exception):
pass
class LoopTypeIsMissing(Exception):
pass
class FakeIrc():
def __init__(self, irc):
self._irc = irc
self._message = ''
self._data = ''
def error(self, message):
message = message
self._data = message
@ -74,56 +85,57 @@ class SupyMLParser:
self._msg = msg
self._code = code
self.warnings = []
self._parse()
self._parse(code)
def _run(self, code, proxify):
"""Runs the command using Supybot engine"""
tokens = callbacks.tokenize(str(code))
if proxify:
fakeIrc = FakeIrc(self._irc)
# TODO : add nested level
else:
fakeIrc = self._irc
self._plugin.Proxy(fakeIrc, self._msg, tokens)
if proxify:
# TODO : don't wait if the plugin is not threaded
time.sleep(0.1)
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"""
for childNode in dom.childNodes:
if isinstance(childNode, minidom.Element):
self._processNode(childNode, {}, False)
output = self._processNode(childNode, variables, proxify)
return output
def _processNode(self, node, variables, proxifyIrc=True):
"""Returns the value of an internapreted node.
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
used, datas are sent to IRC, and this function will return None."""
if isinstance(node, minidom.Text):
return node.data
output = node.nodeName + ' '
newVariables = copy.deepcopy(variables)
for childNode in node.childNodes:
if not repr(node) == repr(childNode.parentNode):
print "CONTINUING"
continue
if childNode.nodeName == 'loop':
output += self._processLoop(childNode, newVariables)
output += self._processLoop(childNode, variables)
elif childNode.nodeName == 'if':
output += self._processId(childNode, newVariables)
output += self._processId(childNode, variables)
elif childNode.nodeName == 'var':
output += self._processVar(childNode, newVariables)
output += self._processVar(childNode, variables)
elif childNode.nodeName == 'set':
output += self._processSet(childNode, newVariables)
output += self._processSet(childNode, variables)
else:
output += self._processNode(childNode, newVariables) or ''
for key in variables:
variables[key] = newVariables[key]
output += self._processNode(childNode, variables) or ''
value = self._run(output, proxifyIrc)
return value
@ -143,13 +155,34 @@ class SupyMLParser:
try:
return variables[variableName]
except KeyError:
self.warnings.append('Access to non-existing variable: %s' %
self.warnings.append('Access to non-existing variable: %s' %
variableName)
return ''
def _processLoop(self, node, variables):
"""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):
if len(variableName) == 0:
@ -165,12 +198,12 @@ class SupyML(callbacks.Plugin):
#threaded = True
def eval(self, irc, msg, args, code):
"""<SupyML script>
Executes the <SupyML script>"""
parser = SupyMLParser(self, irc, msg, code)
if world.testing and len(parser.warnings) != 0:
print parser.warnings
eval=wrap(eval, ['text'])
SupyML = internationalizeDocstring(SupyML)

View File

@ -55,6 +55,8 @@ class SupyMLTestCase(ChannelPluginTestCase):
answer = ircmsgs.IrcMsg(prefix="", command="PRIVMSG",
args=('ProgVal', 'test wants me to tell you: foo'))
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):
self.assertResponse('SupyML eval '
@ -95,24 +97,25 @@ class SupyMLTestCase(ChannelPluginTestCase):
'<var name="foo" />'
'</echo>'
'</echo>',
'bar')
'barbar')
def testWhile(self):
self.assertResponse('SupyML eval '
'<echo>'
'<set name="foo">bar</set>'
'<set name="foo">4</set>'
'<loop>'
'<while>'
'<nne>'
'<var name="foo" /> 5'
'</nne>'
'</while>'
'<set name="foo">5</set>'
'<echo>'
'bar'
'</echo>'
'</loop>'
'</echo>',
'bar'*5)
'barbar')
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: