[pypy-commit] lang-js default: fixed ASTBuilder scoping to work with eval

stepahn noreply at buildbot.pypy.org
Fri Dec 28 11:32:18 CET 2012


Author: Stephan <stephan at stzal.com>
Branch: 
Changeset: r121:183292ceb28a
Date: 2011-09-06 19:11 +0200
http://bitbucket.org/pypy/lang-js/changeset/183292ceb28a/

Log:	fixed ASTBuilder scoping to work with eval

diff --git a/js/astbuilder.py b/js/astbuilder.py
--- a/js/astbuilder.py
+++ b/js/astbuilder.py
@@ -11,7 +11,7 @@
         self.declared_variables = []
 
     def __repr__(self):
-        return 'Scope ' + repr(self.local_variables)
+        return '%s: %s; %s' % (object.__repr__(self), repr(self.local_variables), repr(self.declared_variables))
 
     def add_local(self, identifier):
         if not self.is_local(identifier):
@@ -32,26 +32,46 @@
             raise ValueError
         return idx
 
+class GlobalScope(Scope):
+    def add_local(self, identifier):
+        pass
+
+    def declare_local(self, identifier):
+        if not identifier in self.declared_variables:
+            self.declared_variables.append(identifier)
+
+    def is_local(self, identifier):
+        return False
+
+    def get_local(self, identifier):
+        raise ValueError
+
+class EvalScope(GlobalScope):
+    def declare_local(self, identifier):
+        pass
+
 class Scopes(object):
     def __init__(self):
-        self.scopes = []
+        self._scopes = []
+        self._scopes.append(GlobalScope())
 
     def current_scope(self):
-        if not self.scopes:
+        if not self._scopes:
             return None
         else:
-            return self.scopes[-1]
+            return self._scopes[-1]
 
     def new_scope(self):
-        self.scopes.append(Scope())
+        self._scopes.append(Scope())
 
     def end_scope(self):
-        self.scopes.pop()
+        self._scopes.pop()
 
     def declarations(self):
         if self.scope_present():
             return self.current_scope().declared_variables
-        return []
+        else:
+            return []
 
     def is_local(self, identifier):
         return self.scope_present() == True and self.current_scope().is_local(identifier) == True
@@ -118,7 +138,6 @@
     }
 
     def __init__(self):
-        self.varlists = []
         self.funclists = []
         self.scopes = Scopes()
         self.sourcename = ""
@@ -318,18 +337,14 @@
 
     def visit_sourceelements(self, node):
         pos = self.get_pos(node)
-        self.varlists.append({})
         self.funclists.append({})
         nodes=[]
         for child in node.children:
             node = self.dispatch(child)
             if node is not None:
                 nodes.append(node)
+        # XXX is this still needed or can it be dropped?
         var_decl = self.scopes.declarations()
-        if not var_decl:
-            var_decl = self.varlists.pop().keys()
-        else:
-            self.varlists.pop()
         func_decl = self.funclists.pop()
         return operations.SourceElements(pos, var_decl, func_decl, nodes, self.sourcename)
 
@@ -365,7 +380,6 @@
         identifier = self.dispatch(node.children[0])
         identifier_name = identifier.get_literal()
         self.scopes.declare_local(identifier_name)
-        self.varlists[-1][identifier_name] = None
         if len(node.children) > 1:
             expr = self.dispatch(node.children[1])
         else:
@@ -605,3 +619,22 @@
         body = self.dispatch(node.children[1])
         return operations.With(pos, identifier, body)
 
+ASTBUILDER = ASTBuilder()
+
+# XXX this is somewhat hackish
+def new_ast_builder():
+    b = ASTBUILDER
+    b.funclists = []
+    b.scopes = Scopes()
+    b.sourcename = ""
+    return b
+
+def make_ast_builder(sourcename = ''):
+    b = new_ast_builder() #ASTBuilder()
+    b.set_sourcename(sourcename)
+    return b
+
+def make_eval_ast_builder(sourcename = ''):
+    b = make_ast_builder(sourcename)
+    b.scopes._scopes = [EvalScope()]
+    return b
diff --git a/js/interpreter.py b/js/interpreter.py
--- a/js/interpreter.py
+++ b/js/interpreter.py
@@ -3,7 +3,7 @@
 from pypy.rlib import rrandom
 random = rrandom.Random(int(time.time()))
 from js.jsparser import parse, ParseError
-from js.astbuilder import ASTBuilder
+from js.astbuilder import make_ast_builder, make_eval_ast_builder
 from js.jsobj import W_Object,\
      w_Undefined, W_NewBuiltin, W_IntNumber, w_Null, create_object, W_Boolean,\
      W_FloatNumber, W_String, W_Builtin, W_Array, w_Null, newbool,\
@@ -20,8 +20,6 @@
 from pypy.rlib.listsort import TimSort
 from pypy.rlib import jit
 
-ASTBUILDER = ASTBuilder()
-
 def writer(x):
     print x
 
@@ -36,8 +34,14 @@
 @jit.dont_look_inside
 def load_source(script_source, sourcename):
     temp_tree = parse(script_source)
-    ASTBUILDER.sourcename = sourcename
-    return ASTBUILDER.dispatch(temp_tree)
+    builder = make_ast_builder()
+    return builder.dispatch(temp_tree)
+
+ at jit.dont_look_inside
+def eval_source(script_source, sourcename):
+    temp_tree = parse(script_source)
+    builder = make_eval_ast_builder()
+    return builder.dispatch(temp_tree)
 
 def load_file(filename):
     f = open_file_as_stream(filename)
@@ -147,7 +151,7 @@
             return w_Undefined
 
         try:
-            node = load_source(src, 'evalcode')
+            node = eval_source(src, 'evalcode')
         except ParseError, e:
             raise ThrowException(W_String('SyntaxError: '+str(e)))
 
@@ -335,7 +339,8 @@
             functioncode = "function () {}"
         #remove program and sourcelements node
         funcnode = parse(functioncode).children[0].children[0]
-        ast = ASTBUILDER.dispatch(funcnode)
+        builder = make_ast_builder()
+        ast = builder.dispatch(funcnode)
         bytecode = JsCode()
         ast.emit(bytecode)
         func = bytecode.make_js_function()
diff --git a/js/jscode.py b/js/jscode.py
--- a/js/jscode.py
+++ b/js/jscode.py
@@ -112,9 +112,7 @@
         if self.has_labels:
             self.remove_labels()
 
-        #import pdb; pdb.set_trace()
         return JsFunction(name, params, self)
-        #return JsFunction(name, params, self.opcodes[:])
 
     def remove_labels(self):
         """ Basic optimization to remove all labels and change


More information about the pypy-commit mailing list