[Zope-CVS] CVS: Packages/pypes/pypes - expression.py:1.3

Casey Duncan casey at zope.com
Sat Jan 31 00:24:01 EST 2004


Update of /cvs-repository/Packages/pypes/pypes
In directory cvs.zope.org:/tmp/cvs-serv16271

Modified Files:
	expression.py 
Log Message:
Implement freeOperands method and simple expression __call__
make sure expression tests are run by runtests


=== Packages/pypes/pypes/expression.py 1.2 => 1.3 ===
--- Packages/pypes/pypes/expression.py:1.2	Fri Jan 30 00:41:37 2004
+++ Packages/pypes/pypes/expression.py	Sat Jan 31 00:23:30 2004
@@ -16,6 +16,8 @@
 $Id:S"""
 
 import sys
+import __builtin__
+from sets import Set
 from compiler import parse, ast
 
 class Expression:
@@ -30,25 +32,63 @@
         """
         self._expr = expr
         self._tree = parse(expr, mode='eval')
-        self._ns = {}
+        self._bindings = {}
         if namespace is not None:
             for name in self.names():
                 try:
-                    self._ns[name] = namespace[name]
+                    self._bindings[name] = namespace[name]
                 except KeyError:
                     pass
     
     def names(self, _tree=None, _names=None):
-        """Return a list of the names used in the expression"""
+        """Return a set of the names used in the expression"""
         if _tree is None:
             _tree = self._tree
         if _names is None:
-            _names = []
+            _names = Set()
+        if isinstance(_tree, ast.Name):
+            _names.add(_tree.name)
         for node in _tree.getChildNodes():
             if isinstance(node, ast.Name):
-                _names.append(node.name)
+                _names.add(node.name)
             self.names(node, _names)
         return _names
+    
+    def freeOperands(self, free_names=[], _tree=None, _nodes=None):
+        """Return a list of ast nodes cooresponding to top-level operands with
+        free variables not in the expression's bound  namespace or builtins,
+        excepting names supplied in free_names. These operands are satisfied by
+        names supplied when the expression is executed, which makes them
+        interesting to machinery intending to apply the expression.
+
+        These nodes are the right and left sides of comparisons, or single
+        nodes used in truth tests. Note that only top-level comparison nodes
+        are decended to find operands. Nested comparisons are therefore
+        themselves considered whole operands.  
+        """
+        if _tree is None:
+            _tree = self._tree
+        if _nodes is None:
+            _nodes = []
+        all_names = (
+            Set(self._bindings.keys() + dir(__builtin__)) - Set(free_names))
+        for node in _tree.getChildNodes():
+            if isinstance(node, (ast.And, ast.Or, ast.Not)):
+                self.freeOperands(free_names, node, _nodes)
+            elif isinstance(node, ast.Compare):
+                for operand in node.getChildNodes():
+                    if Set(self.names(operand)) - all_names:
+                        _nodes.append(operand)     
+            elif Set(self.names(node)) - all_names:
+                _nodes.append(node)
+        return _nodes
+    
+    def __call__(self, namespace={}):
+        """Evaluate the expression with the namespace provided and return the
+        result. The provided namespace extends and overrides names bound to
+        the expression when constructed.
+        """
+        return eval(self._expr, self._bindings, namespace)
     
     def __str__(self):
         return "Expression('%s')" % self._expr




More information about the Zope-CVS mailing list