[Mpuls-commits] r369 - in wasko/trunk: . waskaweb/lib waskaweb/model
scm-commit@wald.intevation.org
scm-commit at wald.intevation.org
Thu Mar 12 14:36:02 CET 2009
Author: teichmann
Date: 2009-03-12 14:35:59 +0100 (Thu, 12 Mar 2009)
New Revision: 369
Added:
wasko/trunk/waskaweb/model/exprtree.py
Modified:
wasko/trunk/ChangeLog.txt
wasko/trunk/waskaweb/lib/renderer.py
wasko/trunk/waskaweb/model/__init__.py
wasko/trunk/waskaweb/model/data.py
wasko/trunk/waskaweb/model/semantic.py
Log:
New tree based expression engine
Modified: wasko/trunk/ChangeLog.txt
===================================================================
--- wasko/trunk/ChangeLog.txt 2009-03-12 13:31:11 UTC (rev 368)
+++ wasko/trunk/ChangeLog.txt 2009-03-12 13:35:59 UTC (rev 369)
@@ -1,3 +1,17 @@
+2009-03-12 Sascha L. Teichmann <teichmann at intevation.de>
+
+ * waskaweb/model/exprtree.py: New tree based implementation
+ of the expression engine. The old stack based one is deprecated.
+ Added a 'known' function to figure out if values are different
+ from None and 'unknown'
+
+ * waskaweb/model/__init__.py: Moved UNKNOWN_INT and UNKNOWN_DATE
+ to module to prevent circular imports.
+
+ * waskaweb/model/data.py: Use new tree based expression engine.
+
+ * waskaweb/model/semantic.py, waskaweb/lib/renderer.py: Fixed import.
+
2009-03-12 Torsten Irlaender <torsten.irlaender at intevation.de>
Fixed issue25
Modified: wasko/trunk/waskaweb/lib/renderer.py
===================================================================
--- wasko/trunk/waskaweb/lib/renderer.py 2009-03-12 13:31:11 UTC (rev 368)
+++ wasko/trunk/waskaweb/lib/renderer.py 2009-03-12 13:35:59 UTC (rev 369)
@@ -32,7 +32,7 @@
import waskaweb.model.data as data
-from waskaweb.model.semantic import UNKNOWN_DATE, UNKNOWN_INT
+from waskaweb.model import UNKNOWN_DATE, UNKNOWN_INT
from filters import NA
Modified: wasko/trunk/waskaweb/model/__init__.py
===================================================================
--- wasko/trunk/waskaweb/model/__init__.py 2009-03-12 13:31:11 UTC (rev 368)
+++ wasko/trunk/waskaweb/model/__init__.py 2009-03-12 13:35:59 UTC (rev 369)
@@ -21,3 +21,14 @@
# within the programme Kompetenzagenturen (Durchfuehrungsphase) funded by
# the Bundesministerium fuer Familie, Senioren, Frauen und Jugend and
# European Social Fund resources.
+
+from datetime import date
+
+UNKNOWN_INT = -9999999
+UNKNOWN_DATE = date(1, 1, 1)
+
+
+
+
+
+
Modified: wasko/trunk/waskaweb/model/data.py
===================================================================
--- wasko/trunk/waskaweb/model/data.py 2009-03-12 13:31:11 UTC (rev 368)
+++ wasko/trunk/waskaweb/model/data.py 2009-03-12 13:35:59 UTC (rev 369)
@@ -35,7 +35,7 @@
VISIT_IGNORE_CHILDREN, \
VISIT_CONTINUE
-from expr import Expr
+from exprtree import Expr
import sys
import os
Added: wasko/trunk/waskaweb/model/exprtree.py
===================================================================
--- wasko/trunk/waskaweb/model/exprtree.py 2009-03-12 13:31:11 UTC (rev 368)
+++ wasko/trunk/waskaweb/model/exprtree.py 2009-03-12 13:35:59 UTC (rev 369)
@@ -0,0 +1,320 @@
+#!/usr/bin/env python
+# -*- coding: latin1 -*-
+#
+# Copyright 2007, 2008, 2009 Intevation GmbH, Germany, <info at intevation.de>
+#
+# This file is part of mpuls WASKA (CoMPUter-based case fiLeS -
+# Web-Anwendungs-Server fuer Kompetenzagenturen).
+#
+# mpuls WASKA is free software: you can redistribute it and/or modify it under
+# the terms of the GNU Affero General Public License as published by the
+# Free Software Foundation, either version 3 of the License, or (at your
+# option) any later version.
+#
+# mpuls WASKA is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+# License for more details.
+#
+# You should have received a copy of the GNU Affero General Public
+# License along with mpuls WASKA. If not, see <http://www.gnu.org/licenses/>.
+#
+# mpuls WASKA has been developed on behalf of the
+# Projekttraeger im Deutschen Zentrum fuer Luft- und Raumfahrt e.V. (PT-DLR)
+# within the programme Kompetenzagenturen (Durchfuehrungsphase) funded by
+# the Bundesministerium fuer Familie, Senioren, Frauen und Jugend and
+# European Social Fund resources.
+#
+# Authors:
+# Sascha L. Teichmann <teichmann at intevation.de>
+#
+
+import sys
+import re
+import codecs
+import traceback
+
+from datetime import date
+from types import StringTypes
+
+from waskaweb.model import UNKNOWN_DATE, UNKNOWN_INT
+
+FLT_RE = re.compile(r'^([-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)$')
+INT_RE = re.compile(r'^([-+]?[0-9]+)$')
+VAR_RE = re.compile(r'^\$(\w+)$')
+
+from shlex import split as lexsplit
+
+class Node(object):
+
+ def __init__(self):
+ pass
+
+ def eval(self, ctx):
+ return None
+
+class Unary(Node):
+
+ def __init__(self, a = None):
+ Node.__init__(self)
+ self.a = a
+
+ def __repr__(self):
+ return "%s(%s)" % (
+ self.__class__.__name__,
+ repr(self.a))
+
+class Binary(Unary):
+
+ def __init__(self, a = None, b = None):
+ Unary.__init__(self, a)
+ self.b = b
+
+ def __repr__(self):
+ return "%s(%s, %s)" % (
+ self.__class__.__name__,
+ repr(self.a),
+ repr(self.b))
+
+class OperatorUnary(Unary):
+
+ def __init__(self, a, operator):
+ Unary.__init__(self, a)
+ self.operator = operator
+
+ def eval(self, ctx):
+ return self.operator(self.a.eval(ctx))
+
+ def __repr__(self):
+ return "%s[%s](%s)" % (
+ self.__class__.__name__,
+ self.operator.__name__,
+ repr(self.a))
+
+class OperatorBinary(Binary):
+
+ def __init__(self, a, b, operator):
+ Binary.__init__(self, a, b)
+ self.operator = operator
+
+ def eval(self, ctx):
+ return self.operator(self.a.eval(ctx), self.b.eval(ctx))
+
+ def __repr__(self):
+ return "%s[%s](%s, %s)" % (
+ self.__class__.__name__,
+ self.operator.__name__,
+ repr(self.a),
+ repr(self.b))
+
+class Not(Unary):
+
+ def eval(self, ctx):
+ return not self.a.eval(ctx)
+
+class And(Binary):
+
+ def eval(self, ctx):
+ ea = self.a.eval(ctx)
+ if not ea: return False
+ return bool(self.b.eval(ctx))
+
+class Or(Binary):
+
+ def eval(self, ctx):
+ return self.a.eval(ctx) and True or bool(self.b.eval(ctx))
+
+class Var(Node):
+
+ def __init__(self, var_name):
+ self.var_name = var_name
+
+ def eval(self, ctx):
+ return ctx.vars[self.var_name]
+
+ def __repr__(self):
+ return "var(%s)" % (self.var_name)
+
+class Const(Node):
+
+ def __init__(self, const):
+ self.const = const
+
+ def eval(self, ctx):
+ return self.const
+
+ def __repr__(self):
+ return "const(%s)" % repr(self.const)
+
+class Today(Node):
+
+ def eval(self):
+ return date.today()
+
+class DateNode(Node):
+
+ def __init__(self, year, month, day):
+ self.day = day
+ self.month = month
+ self.year = year
+
+ def eval(self, ctx):
+ day = self.day.eval(ctx)
+ month = self.mounth.eval(ctx)
+ year = self.year.eval(ctx)
+ return date(year, month, day)
+
+class Out(Node):
+
+ def __init__(self, parent):
+ self.parent = parent
+
+ def eval(self, ctx):
+ e = self.parent(ctx)
+ print repr(e)
+ return e
+
+class IThenElse(Node):
+
+ def __init__(self, q, a, b):
+ self.q = q
+ self.a = a
+ self.b = b
+
+ def eval(self, ctx):
+ if self.q.eval(ctx): return self.a.eval(ctx)
+ return self.b.eval(ctx)
+
+def ADD(a, b): return a + b
+def MINUS(a, b): return a - b
+def MUL(a, b): return a * b
+def DIV(a, b): return a / b
+def MOD(a, b): return a % b
+def POW(a, b): return a ** b
+def EQ(a, b): return a == b
+def NE(a, b): return a != b
+def GT(a, b): return a > b
+def LT(a, b): return a < b
+def LE(a, b): return a <= b
+def GE(a, b): return a >= b
+def MIN(a, b): return min(a, b)
+def MAX(a, b): return max(a, b)
+def INT(a): return int(a)
+def FLOAT(a): return float(a)
+def STR(a): return str(a)
+def LEN(a): return len(a)
+def ABS(a): return abs(a)
+def NOT(a): return not a
+def ISSET(a): return not a is None
+def TYPE(a): return type(a)
+
+def KNOWN(a):
+ return not (
+ a is None \
+ or a == UNKNOWN_INT \
+ or a == UNKNOWN_DATE \
+ or (type(a) in StringTypes and not a))
+
+NODE_FACTORIES = {
+ '+': lambda s: OperatorBinary(s.pop(), s.pop(), ADD),
+ '-': lambda s: OperatorBinary(s.pop(-2), s.pop(), MINUS),
+ '*': lambda s: OperatorBinary(s.pop(), s.pop(), MUL),
+ '/': lambda s: OperatorBinary(s.pop(-2), s.pop(), DIV),
+ '%': lambda s: OperatorBinary(s.pop(-2), s.pop(), MOD),
+ '**': lambda s: OperatorBinary(s.pop(-2), s.pop(), POW),
+ '==': lambda s: OperatorBinary(s.pop(), s.pop(), EQ),
+ '!=': lambda s: OperatorBinary(s.pop(), s.pop(), NE),
+ '>': lambda s: OperatorBinary(s.pop(-2), s.pop(), GT),
+ '<': lambda s: OperatorBinary(s.pop(-2), s.pop(), LT),
+ '<=': lambda s: OperatorBinary(s.pop(-2), s.pop(), LE),
+ '>=': lambda s: OperatorBinary(s.pop(-2), s.pop(), GE),
+ 'min': lambda s: OperatorBinary(s.pop(), s.pop(), MIN),
+ 'max': lambda s: OperatorBinary(s.pop(), s.pop(), MAX),
+ 'int': lambda s: OperatorUnary(s.pop(), INT),
+ 'float': lambda s: OperatorUnary(s.pop(), FLOAT),
+ 'str': lambda s: OperatorUnary(s.pop(), STR),
+ 'len': lambda s: OperatorUnary(s.pop(), LEN),
+ 'abs': lambda s: OperatorUnary(s.pop(), ABS),
+ 'not': lambda s: OperatorUnary(s.pop(), NOT),
+ 'isset': lambda s: OperatorUnary(s.pop(), ISSET),
+ 'known': lambda s: OperatorUnary(s.pop(), KNOWN),
+ 'type': lambda s: OperatorUnary(s.pop(), TYPE),
+ 'and': lambda s: And(s.pop(-2), s.pop()),
+ 'or': lambda s: Or(s.pop(-2), s.pop()),
+ 'today': lambda s: Today(),
+ 'date': lambda s: DateNode(s.pop(), s.pop(), s.pop()),
+ '.': lambda s: Out(s.pop()),
+ '?': lambda s: IThenElse(s.pop(), s.pop(), s.pop())
+}
+
+class EvalContext(object):
+
+ def __init__(self, vars):
+ self.vars = vars
+
+class Expr(object):
+
+ def __init__(self, expr):
+ self.expr = expr
+ self.prog = None
+ self.depends = None
+
+ def evaluate(self, vars=None):
+ if self.prog is None:
+ self.compile()
+
+ ctx = EvalContext(vars)
+ try:
+ return self.prog.eval(ctx)
+ except:
+ traceback.print_exc(file = sys.stderr)
+ print >> sys.stderr, "Expr: ", repr(self.prog)
+ raise
+
+ def compile(self):
+ depends = set()
+
+ stack = []
+
+ # XXX: shlex does not support unicode -> ascii
+ encoder = codecs.getencoder("ascii")
+ for token in lexsplit(encoder(self.expr)[0]):
+ token = unicode(token)
+ m = VAR_RE.match(token)
+ if m:
+ var = m.group(1)
+ stack.append(Var(var))
+ depends.add(var)
+ continue
+ m = INT_RE.match(token)
+ if m:
+ stack.append(Const(int(m.group(1))))
+ continue
+ m = FLT_RE.match(token)
+ if m:
+ stack.append(Const(float(m.group(1))))
+ continue
+ try:
+ stack.append(NODE_FACTORIES[token](stack))
+ except KeyError:
+ stack.append(Const(token))
+
+ self.prog = stack and stack[0] or None
+ self.depends = depends
+
+ def getDependencies(self):
+ if self.depends is None:
+ self.compile()
+ return self.depends
+
+#def main():
+# for arg in sys.argv[1:]:
+# expr = Expr(arg)
+# vars = { 'a': 3 }
+# result = expr.evaluate(vars)
+# print str(result)
+#
+#if __name__ == "__main__":
+# main()
+
+# vim:set ts=4 sw=4 si et sta sts=4:
Modified: wasko/trunk/waskaweb/model/semantic.py
===================================================================
--- wasko/trunk/waskaweb/model/semantic.py 2009-03-12 13:31:11 UTC (rev 368)
+++ wasko/trunk/waskaweb/model/semantic.py 2009-03-12 13:35:59 UTC (rev 369)
@@ -38,14 +38,13 @@
#from waskaweb.lib.helpers import safe_unicode
+
+from waskaweb.model import UNKNOWN_INT, UNKNOWN_DATE
+
def safe_unicode(s):
return s
-UNKNOWN_INT = -9999999
-UNKNOWN_DATE = date(1, 1, 1)
-
-
class ErrorItem:
def __init__(self, page=None, bad=None, name=None):
More information about the Mpuls-commits
mailing list