[Zope-Checkins] CVS: Zope2 - Eval.py:1.1.2.7

shane@digicool.com shane@digicool.com
Thu, 26 Apr 2001 18:20:28 -0400 (EDT)


Update of /cvs-repository/Zope2/lib/python/RestrictedPython
In directory korak:/tmp/cvs-serv10732

Modified Files:
      Tag: RestrictedPythonBranch
	Eval.py 
Log Message:
Made it possible to optimize unrestricted expressions.



--- Updated File Eval.py in package Zope2 --
--- Eval.py	2001/04/26 19:13:39	1.1.2.6
+++ Eval.py	2001/04/26 22:20:26	1.1.2.7
@@ -95,12 +95,17 @@
 
 def default_read_guard(ob):
     # No restrictions.
-    return ob 
+    return ob
 
+PROFILE = 0
+
 class RestrictionCapableEval:
     """A base class for restricted code.
     """
     globals = {'__builtins__': {}}
+    rcode = None  # restricted
+    ucode = None  # unrestricted
+    used = None
 
     def __init__(self, expr):
         """Create a restricted expression
@@ -111,33 +116,71 @@
 
           globals -- A global namespace.
         """
-        global compile_restricted_eval
-        if compile_restricted_eval is None:
-            # Late binding because this will import the whole
-            # compiler suite.
-            from RestrictedPython import compile_restricted_eval
-
         expr = strip(expr)
         self.__name__ = expr
         expr = translate(expr, nltosp)
         self.expr = expr
-        self.code, err, warn, used = compile_restricted_eval(expr, '<string>')
-        if err:
-            raise SyntaxError, err[0]
-        self.used = tuple(used.keys())
+
+    def prepRestrictedCode(self):
+        if self.rcode is None:
+            global compile_restricted_eval
+            if compile_restricted_eval is None:
+                # Late binding because this will import the whole
+                # compiler suite.
+                from RestrictedPython import compile_restricted_eval
+
+            if PROFILE:
+                from time import clock
+                start = clock()
+            co, err, warn, used = compile_restricted_eval(
+                self.expr, '<string>')
+            if PROFILE:
+                end = clock()
+                print 'prepRestrictedCode: %d ms for %s' % (
+                    (end - start) * 1000, `self.expr`)
+            if err:
+                raise SyntaxError, err[0]
+            self.used = tuple(used.keys())
+            self.rcode = co
+
+    def prepUnrestrictedCode(self):
+        if self.ucode is None:
+            co = compile(self.expr, '<string>', 'eval')
+            if self.used is None:
+                names=list(co.co_names)
+                used={}
+                i=0
+                code=co.co_code
+                l=len(code)
+                LOAD_NAME=101   
+                HAVE_ARGUMENT=90        
+                while(i < l):
+                    c=ord(code[i])
+                    if c==LOAD_NAME:
+                        name=names[ord(code[i+1])+256*ord(code[i+2])]
+                        used[name]=1
+                        i=i+3
+                    elif c >= HAVE_ARGUMENT: i=i+3
+                    else: i=i+1
+                self.used=tuple(used.keys())
+            self.ucode=co
 
     def eval(self, mapping):
+        self.prepRestrictedCode()
+        code = self.rcode
         d = {'_read_': default_read_guard}
+        d.update(self.globals)
+        has_key = d.has_key
         for name in self.used:
             try:
-                d[name] = mapping[name]
+                if not has_key(name):
+                    d[name] = mapping[name]
             except KeyError:
                 # Swallow KeyErrors since the expression
                 # might not actually need the name.  If it
                 # does need the name, a NameError will occur.
                 pass
-        d.update(self.globals)
-        return eval(self.code, d)
+        return eval(code, d)
 
     def __call__(self, **kw):
         return self.eval(kw)