From a4867498087017a17473b54f2441fd3600550c20 Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Sun, 14 Nov 2010 09:22:49 +0100 Subject: [PATCH] SupyML: change the variable lifetime (and make it work), and the managment (not tested) --- SupyML/README.txt | 6 ++-- SupyML/plugin.py | 81 +++++++++++++++++++++++++++++++++-------------- SupyML/test.py | 9 ++++-- 3 files changed, 65 insertions(+), 31 deletions(-) diff --git a/SupyML/README.txt b/SupyML/README.txt index 876eca3..91d17a9 100644 --- a/SupyML/README.txt +++ b/SupyML/README.txt @@ -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 --------------- diff --git a/SupyML/plugin.py b/SupyML/plugin.py index de99fcb..ed8d9b2 100644 --- a/SupyML/plugin.py +++ b/SupyML/plugin.py @@ -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 tag""" - return '' + 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(''):-len('')] + 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): """ - + Executes the """ parser = SupyMLParser(self, irc, msg, code) if world.testing and len(parser.warnings) != 0: print parser.warnings - + eval=wrap(eval, ['text']) SupyML = internationalizeDocstring(SupyML) diff --git a/SupyML/test.py b/SupyML/test.py index 31902a8..438316d 100644 --- a/SupyML/test.py +++ b/SupyML/test.py @@ -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 4 5', 'true') + self.assertResponse('SupyML eval 4 5', 'true') def testNoMoreThanOneAnswer(self): self.assertResponse('SupyML eval ' @@ -95,24 +97,25 @@ class SupyMLTestCase(ChannelPluginTestCase): '' '' '', - 'bar') + 'barbar') def testWhile(self): self.assertResponse('SupyML eval ' '' - 'bar' + '4' '' '' '' ' 5' '' '' + '5' '' 'bar' '' '' '', - 'bar'*5) + 'barbar') # vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: