[pypy-commit] lang-js default: wip

stepahn noreply at buildbot.pypy.org
Fri Dec 28 11:33:20 CET 2012


Author: Stephan <stephan at stzal.com>
Branch: 
Changeset: r180:404b48509ba2
Date: 2012-05-01 13:20 +0200
http://bitbucket.org/pypy/lang-js/changeset/404b48509ba2/

Log:	wip

diff too long, truncating to 2000 out of 4637 lines

diff --git a/js/astbuilder.py b/js/astbuilder.py
--- a/js/astbuilder.py
+++ b/js/astbuilder.py
@@ -8,97 +8,147 @@
 def _get_root_map():
     return ROOT_MAP
 
-class Scope(object):
-    _immutable_fields_ = ['local_variables']
+#class Scope(object):
+#    _immutable_fields_ = ['local_variables']
+#    def __init__(self):
+#        self.local_variables = ROOT_MAP
+#        self.declared_variables = []
+#
+#    def __repr__(self):
+#        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):
+#            self.local_variables = self.local_variables.add(identifier)
+#
+#    def declare_local(self, identifier):
+#        if not self.is_local(identifier):
+#            self.add_local(identifier)
+#            if not identifier in self.declared_variables:
+#                self.declared_variables.append(identifier)
+#
+#    def is_local(self, identifier):
+#        return self.local_variables.lookup(identifier) != self.local_variables.NOT_FOUND
+#
+#    def get_local(self, identifier):
+#        idx = self.local_variables.lookup(identifier)
+#        if idx == self.local_variables.NOT_FOUND:
+#            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.append(GlobalScope())
+#
+#    def current_scope(self):
+#        if not self._scopes:
+#            return None
+#        else:
+#            return self._scopes[-1]
+#
+#    def new_scope(self):
+#        self._scopes.append(Scope())
+#
+#    def end_scope(self):
+#        self._scopes.pop()
+#
+#    def declarations(self):
+#        if self.scope_present():
+#            return self.current_scope().declared_variables
+#        else:
+#            return []
+#
+#    def is_local(self, identifier):
+#        return self.scope_present() == True and self.current_scope().is_local(identifier) == True
+#
+#    def scope_present(self):
+#        return self.current_scope() is not None
+#
+#    def add_local(self, identifier):
+#        if self.scope_present():
+#            self.current_scope().add_local(identifier)
+#
+#    def declare_local(self, identifier):
+#        if self.scope_present():
+#            self.current_scope().declare_local(identifier)
+#
+#    def get_local(self, identifier):
+#        return self.current_scope().get_local(identifier)
+
+class SymbolMap(object):
     def __init__(self):
-        self.local_variables = ROOT_MAP
-        self.declared_variables = []
+        self.functions = {}
+        self.variables = {}
+        self.symbols = {}
+        self.parameters = {}
+        self.next_index = 0
 
-    def __repr__(self):
-        return '%s: %s; %s' % (object.__repr__(self), repr(self.local_variables), repr(self.declared_variables))
+    def add_symbol(self, identifyer):
+        assert identifyer is not None
+        if identifyer not in self.symbols:
+            self.symbols[identifyer] = self.next_index
+            self.next_index += 1
+        return self.symbols[identifyer]
 
-    def add_local(self, identifier):
-        if not self.is_local(identifier):
-            self.local_variables = self.local_variables.add(identifier)
+    def add_variable(self, identifyer):
+        idx = self.add_symbol(identifyer)
 
-    def declare_local(self, identifier):
-        if not self.is_local(identifier):
-            self.add_local(identifier)
-            if not identifier in self.declared_variables:
-                self.declared_variables.append(identifier)
-
-    def is_local(self, identifier):
-        return self.local_variables.lookup(identifier) != self.local_variables.NOT_FOUND
-
-    def get_local(self, identifier):
-        idx = self.local_variables.lookup(identifier)
-        if idx == self.local_variables.NOT_FOUND:
-            raise ValueError
+        if identifyer not in self.variables:
+            self.variables[identifyer] = idx
         return idx
 
-class GlobalScope(Scope):
-    def add_local(self, identifier):
-        pass
+    def add_function(self, identifyer):
+        idx = self.add_symbol(identifyer)
 
-    def declare_local(self, identifier):
-        if not identifier in self.declared_variables:
-            self.declared_variables.append(identifier)
+        if identifyer not in self.functions:
+            self.functions[identifyer] = idx
+        return idx
 
-    def is_local(self, identifier):
-        return False
+    def add_parameter(self, identifyer):
+        idx = self.add_symbol(identifyer)
 
-    def get_local(self, identifier):
-        raise ValueError
+        if identifyer not in self.parameters:
+            self.parameters[identifyer] = idx
+        return idx
 
-class EvalScope(GlobalScope):
-    def declare_local(self, identifier):
-        pass
+    def get_index(self, identifyer):
+        return self.symbols[identifyer]
 
-class Scopes(object):
-    def __init__(self):
-        self._scopes = []
-        self._scopes.append(GlobalScope())
+    def get_symbols(self):
+        return self.symbols.keys()
 
-    def current_scope(self):
-        if not self._scopes:
-            return None
-        else:
-            return self._scopes[-1]
+    def get_symbol(self, index):
+        for symbol, idx in self.symbols.items():
+            if idx == index:
+                return symbol
 
-    def new_scope(self):
-        self._scopes.append(Scope())
-
-    def end_scope(self):
-        self._scopes.pop()
-
-    def declarations(self):
-        if self.scope_present():
-            return self.current_scope().declared_variables
-        else:
-            return []
-
-    def is_local(self, identifier):
-        return self.scope_present() == True and self.current_scope().is_local(identifier) == True
-
-    def scope_present(self):
-        return self.current_scope() is not None
-
-    def add_local(self, identifier):
-        if self.scope_present():
-            self.current_scope().add_local(identifier)
-
-    def declare_local(self, identifier):
-        if self.scope_present():
-            self.current_scope().declare_local(identifier)
-
-    def get_local(self, identifier):
-        return self.current_scope().get_local(identifier)
+empty_symbols = SymbolMap()
 
 class FakeParseError(Exception):
     def __init__(self, pos, msg):
         self.pos = pos
         self.msg = msg
 
+
 class ASTBuilder(RPythonVisitor):
     BINOP_TO_CLS = {
         '+': operations.Plus,
@@ -143,12 +193,58 @@
 
     def __init__(self):
         self.funclists = []
-        self.scopes = Scopes()
+        self.scopes = []
         self.sourcename = ""
         RPythonVisitor.__init__(self)
+        self.depth = -1
+
+    def enter_scope(self):
+        self.depth = self.depth + 1
+
+        new_scope = SymbolMap()
+        self.scopes.append(new_scope)
+        #print 'starting new scope %d' % (self.depth, )
+
+    def declare_symbol(self, symbol):
+        idx = self.scopes[-1].add_symbol(symbol)
+        #print 'symbol "%s"@%d in scope %d' % (symbol, idx, self.depth,)
+        return idx
+
+    def declare_variable(self, symbol):
+        idx = self.scopes[-1].add_variable(symbol)
+        #print 'var declaration "%s"@%d in scope %d' % (symbol, idx, self.depth,)
+        return idx
+
+    def declare_function(self, symbol, funcobj):
+        self.funclists[-1][symbol] = funcobj
+        idx = self.scopes[-1].add_function(symbol)
+        #print 'func declaration "%s"@%d in scope %d' % (symbol, idx, self.depth,)
+        return idx
+
+    def declare_parameter(self, symbol):
+        idx = self.scopes[-1].add_parameter(symbol)
+        print 'parameter declaration "%s"@%d in scope %d' % (symbol, idx, self.depth,)
+        return idx
+
+    def exit_scope(self):
+        self.depth = self.depth - 1
+        self.scopes.pop()
+        #print 'closing scope, returning to %d' % (self.depth, )
+
+    def current_scope_variables(self):
+        return self.current_scope().variables.keys()
+
+    def current_scope_parameters(self):
+        return self.current_scope().parameters.keys()
+
+    def current_scope(self):
+        try:
+            return self.scopes[-1]
+        except IndexError:
+            return None
 
     def set_sourcename(self, sourcename):
-        self.sourcename = sourcename #XXX I should call this
+        self.stsourcename = sourcename #XXX I should call this
 
     def get_pos(self, node):
         value = ''
@@ -296,7 +392,7 @@
         pos = self.get_pos(node)
         nodes = [self.dispatch(child) for child in node.children]
         for node in nodes:
-            self.scopes.add_local(node.name)
+            self.declare_parameter(node.name)
         return operations.ArgumentList(pos, nodes)
 
     def visit_variabledeclarationlist(self, node):
@@ -309,8 +405,10 @@
         pos = self.get_pos(node)
         l = node.children[0]
         if l.symbol == "IDENTIFIERNAME":
+            identifier = l.additional_info
+            index = self.declare_symbol(identifier)
             lpos = self.get_pos(l)
-            left = operations.Identifier(lpos, l.additional_info)
+            left = operations.Identifier(lpos, identifier, index)
         else:
             left = self.dispatch(l)
         right = self.dispatch(node.children[1])
@@ -319,15 +417,18 @@
     def visit_IDENTIFIERNAME(self, node):
         pos = self.get_pos(node)
         name = node.additional_info
-        if self.scopes.is_local(name):
-            local = self.scopes.get_local(name)
-            return operations.LocalIdentifier(pos, name, local)
-        return operations.Identifier(pos, name)
+        index = self.declare_symbol(name)
+        #if self.scopes.is_local(name):
+            #local = self.scopes.get_local(name)
+            #return operations.LocalIdentifier(pos, name, local)
+        return operations.Identifier(pos, name, index)
 
     def visit_program(self, node):
+        self.enter_scope()
         pos = self.get_pos(node)
         body = self.dispatch(node.children[0])
-        return operations.Program(pos, body)
+        scope = self.current_scope()
+        return operations.Program(pos, body, scope)
 
     def visit_variablestatement(self, node):
         pos = self.get_pos(node)
@@ -348,28 +449,45 @@
             if node is not None:
                 nodes.append(node)
         # XXX is this still needed or can it be dropped?
-        var_decl = self.scopes.declarations()
+        #var_decl = self.scopes.declarations()
+        var_decl = self.current_scope_variables()
         func_decl = self.funclists.pop()
+        #func_decl = self.scopes.functions.keys()
         return operations.SourceElements(pos, var_decl, func_decl, nodes, self.sourcename)
 
     def functioncommon(self, node, declaration=True):
-        self.scopes.new_scope()
+        self.enter_scope()
+
         pos = self.get_pos(node)
         i=0
         identifier, i = self.get_next_expr(node, i)
         parameters, i = self.get_next_expr(node, i)
         functionbody, i = self.get_next_expr(node, i)
-        if parameters is None:
-            p = []
-        else:
-            p = [pident.get_literal() for pident in parameters.nodes]
-        funcobj = operations.FunctionStatement(pos, identifier, p, functionbody, self.scopes.current_scope())
-        self.scopes.end_scope()
+
+        #params = []
+        #if parameters is not None:
+        #    params = [pident.get_literal() for pident in parameters.nodes]
+
+        params = self.current_scope_parameters()
+
+        funcname = None
+        if identifier is not None:
+            funcname = identifier.get_literal()
+
+        scope = self.current_scope()
+
+        self.exit_scope()
+
+        funcindex = None
+
         if declaration:
-            n = identifier.get_literal()
-            # XXX functions are local variables too
-            self.scopes.add_local(n)
-            self.funclists[-1][n] = funcobj
+            funcindex = self.declare_symbol(funcname)
+
+        funcobj = operations.FunctionStatement(pos, funcname, funcindex, functionbody, scope)
+
+        if declaration:
+            self.declare_function(funcname, funcobj)
+
         return funcobj
 
     def visit_functiondeclaration(self, node):
@@ -383,17 +501,17 @@
         pos = self.get_pos(node)
         identifier = self.dispatch(node.children[0])
         identifier_name = identifier.get_literal()
-        self.scopes.declare_local(identifier_name)
+        index = self.declare_variable(identifier_name)
         if len(node.children) > 1:
             expr = self.dispatch(node.children[1])
         else:
             expr = None
 
-        if self.scopes.is_local(identifier_name):
-            local = self.scopes.get_local(identifier_name)
-            return operations.LocalVariableDeclaration(pos, identifier, local, expr)
-        else:
-            return operations.VariableDeclaration(pos, identifier, expr)
+        #if self.scopes.is_local(identifier_name):
+        #    local = self.scopes.get_local(identifier_name)
+        #    return operations.LocalVariableDeclaration(pos, identifier, local, expr)
+        #else:
+        return operations.VariableDeclaration(pos, identifier, index, expr)
     visit_variabledeclarationnoin = visit_variabledeclaration
 
     def visit_expressionstatement(self, node):
@@ -425,8 +543,9 @@
         return isinstance(obj, Member) or isinstance(obj, MemberDot)
 
     def is_local_identifier(self, obj):
-        from js.operations import LocalIdentifier
-        return isinstance(obj, LocalIdentifier)
+        #from js.operations import LocalIdentifier
+        #return isinstance(obj, LocalIdentifier)
+        return False
 
     def visit_assignmentexpression(self, node):
 
@@ -438,7 +557,9 @@
         if self.is_local_identifier(left):
             return operations.LocalAssignmentOperation(pos, left, right, operation)
         elif self.is_identifier(left):
-            return operations.AssignmentOperation(pos, left, right, operation)
+            identifier = left.get_literal()
+            index = self.declare_symbol(identifier)
+            return operations.AssignmentOperation(pos, left, identifier, index, right, operation)
         elif self.is_member(left):
             return operations.MemberAssignmentOperation(pos, left, right, operation)
         else:
@@ -615,7 +736,8 @@
 
     def visit_primaryexpression(self, node):
         pos = self.get_pos(node)
-        return operations.This(pos, 'this')
+        index = self.declare_symbol('this')
+        return operations.This(pos, 'this', index)
 
     def visit_withstatement(self, node):
         pos = self.get_pos(node)
@@ -627,10 +749,10 @@
 
 # XXX this is somewhat hackish
 def new_ast_builder():
-    b = ASTBUILDER
-    b.funclists = []
-    b.scopes = Scopes()
-    b.sourcename = ""
+    b = ASTBuilder() #ASTBUILDER
+    #b.funclists = []
+    #b.scopes = Scopes()
+    #b.sourcename = ""
     return b
 
 def make_ast_builder(sourcename = ''):
@@ -642,3 +764,14 @@
     b = make_ast_builder(sourcename)
     b.scopes._scopes = [EvalScope()]
     return b
+
+def parse_tree_to_ast(parse_tree):
+    builder = make_ast_builder()
+    tree = builder.dispatch(parse_tree)
+    return tree
+
+def parse_to_ast(code):
+    from js.jsparser import parse, ParseError
+    parse_tree = parse(code)
+    ast = parse_tree_to_ast(parse_tree)
+    return ast
diff --git a/js/bench/v8/v1/run.js b/js/bench/v8/v1/run.js
--- a/js/bench/v8/v1/run.js
+++ b/js/bench/v8/v1/run.js
@@ -27,6 +27,7 @@
 
 
 load('base.js');
+load('looping.js');
 load('richards.js');
 load('deltablue.js');
 load('crypto.js');
diff --git a/js/builtins.py b/js/builtins.py
--- a/js/builtins.py
+++ b/js/builtins.py
@@ -267,6 +267,9 @@
     from js.jsobj import W__Function
     return W__Function(ctx, Js_NativeFunction(function, name))
 
+def setup(w_global):
+    pass
+
 def setup_builtins(interp):
     def put_native_function(obj, name, func):
         obj.Put(name, new_native_function(ctx, func, name))
diff --git a/js/environment_record.py b/js/environment_record.py
new file mode 100644
--- /dev/null
+++ b/js/environment_record.py
@@ -0,0 +1,134 @@
+from js.jsobj import w_Undefined
+
+class EnvironmentRecord(object):
+    def __init__(self):
+        pass
+
+    def has_binding(self, identifier):
+        return False
+
+    def create_mutuable_binding(self, identifier, deletable):
+        pass
+
+    def set_mutable_binding(self, identifier, value, strict=False):
+        pass
+
+    def get_binding_value(self, identifier, strict=False):
+        pass
+
+    def delete_binding(self, identifier):
+        pass
+
+    def implicit_this_value(self):
+        pass
+
+class DeclarativeEnvironmentRecord(EnvironmentRecord):
+    def __init__(self):
+        EnvironmentRecord.__init__(self)
+        self.bindings = {}
+        self.mutable_bindings = {}
+
+    def _is_mutable_binding(self, identifier):
+        return self.mutable_bindings.get(identifier, False) == True
+
+    def _set_mutable_binding(self, identifier):
+        self.mutable_bindings[identifier] = True
+
+    # 10.2.1.1.1
+    def has_binding(self, identifier):
+        return self.bindings.has_key(identifier)
+
+    # 10.2.1.1.2
+    def create_mutuable_binding(self, identifier, deletable):
+        assert not self.has_binding(identifier)
+        self.bindings[identifier] = w_Undefined
+        self._set_mutable_binding(identifier)
+
+    # 10.2.1.1.3
+    def set_mutable_binding(self, identifier, value, strict=False):
+        assert self.has_binding(identifier)
+        if not self._is_mutable_binding(identifier):
+            raise JsTypeError('immutable binding')
+        self.bindings[identifier] = value
+
+    # 10.2.1.1.4
+    def get_binding_value(self, identifier, strict=False):
+        assert self.has_binding(identifier)
+        if not identifier in self.bindings:
+            if strict:
+                raise JsReferenceError
+            else:
+                return w_Undefined
+        return self.bindings.get(identifier)
+
+    # 10.2.1.1.5
+    def delete_binding(self, identifier):
+        raise NotImplementedError(self.__class__)
+
+    # 10.2.1.1.6
+    def implicit_this_value(self):
+        return w_Undefined
+
+    # 10.2.1.1.7
+    def create_immutable_bining(self, identifier):
+        raise NotImplementedError(self.__class__)
+
+    def initialize_immutable_binding(self, identifier, value):
+        raise NotImplementedError(self.__class__)
+
+class ObjectEnvironmentRecord(EnvironmentRecord):
+    provide_this = False
+
+    def __init__(self, obj, provide_this = False):
+        self.binding_object = obj
+        if provide_this is True:
+            self.provide_this = True
+
+    # 10.2.1.2.1
+    def has_binding(self, n):
+        bindings = self.binding_object
+        return bindings.has_property(n)
+
+    # 10.2.1.2.2
+    def create_mutuable_binding(self, n, d):
+        bindings = self.binding_object
+        assert bindings.has_property(n) is False
+        if d is True:
+            config_value = False
+        else:
+            config_value = True
+
+        from js.jsobj import PropertyDescriptor
+        desc = PropertyDescriptor(value = w_Undefined, writable = True, enumerable = True, configurable = config_value)
+        bindings.define_own_property(n, desc, True)
+
+    # 10.2.1.2.3
+    def set_mutable_binding(self, n, v, s = False):
+        bindings = self.binding_object
+        bindings.put(n, v, s)
+
+    # 10.2.1.2.4
+    def get_binding_value(self, n, s = False):
+        bindings = self.binding_object
+        value = bindings.has_property(n)
+        if value is False:
+            if s is False:
+                return w_Undefined
+            else:
+                raise JsReferenceError(self.__class__)
+
+        return bindings.get(n)
+
+    # 10.2.1.2.5
+    def delete_binding(self, n):
+        bindings = self.binding_object
+        return bindings.delete(n, False)
+
+    # 10.2.1.2.6
+    def implicit_this_value(self):
+        if self.provide_this is True:
+            return self.binding_object
+        return w_Undefined
+
+class GlobalEnvironmentRecord(ObjectEnvironmentRecord):
+    pass
diff --git a/js/execution.py b/js/execution.py
--- a/js/execution.py
+++ b/js/execution.py
@@ -27,4 +27,7 @@
 class JsTypeError(JsBaseExcept):
     pass
 
+class JsReferenceError(JsBaseExcept):
+    pass
+
 class RangeError(JsBaseExcept): pass
diff --git a/js/execution_context.py b/js/execution_context.py
new file mode 100644
--- /dev/null
+++ b/js/execution_context.py
@@ -0,0 +1,177 @@
+from js.jsobj import w_Undefined
+
+_global_object_ = None
+
+def get_global_object():
+    return GlobalExecutionContext.global_object
+
+class ExecutionContext(object):
+    def __init__(self):
+        self._stack_ = []
+        self._lexical_environment_ = None
+        self._variable_environment_ = None
+        self._this_binding_ = None
+
+    def declaration_binding_initialization(self, env, code, arguments = []):
+        configurable_bindings = code.configurable_bindings
+
+        n = 0
+        arg_count = len(arguments)
+
+        names = code.params()
+        for arg_name in names:
+            n += 1
+            if n > arg_count:
+                v = w_Undefined
+            else:
+                v = arguments[n-1]
+            arg_already_declared = env.has_binding(arg_name)
+            if arg_already_declared is False:
+                env.create_mutuable_binding(arg_name, configurable_bindings)
+            env.set_mutable_binding(arg_name, v)
+
+        func_declarations = code.functions()
+        for fn in func_declarations:
+            fo = None
+            func_already_declared = env.has_binding(fn)
+            if func_already_declared is False:
+                env.create_mutuable_binding(fn, configurable_bindings)
+            else:
+                pass #see 10.5 5.e
+            env.set_mutable_binding(fn, fo)
+
+        var_declarations = code.variables()
+        for dn in var_declarations:
+            var_already_declared = env.has_binding(dn)
+            if var_already_declared == False:
+                env.create_mutuable_binding(dn, configurable_bindings)
+                env.set_mutable_binding(dn, w_Undefined)
+
+    def stack_append(self, value):
+        self._stack_.append(value)
+
+    def stack_pop(self):
+        return self._stack_.pop()
+
+    def stack_top(self):
+        return self._stack_[-1]
+
+    def stack_pop_n(self, n):
+        if n < 1:
+            return []
+
+        i = -1 * n
+        r = self._stack_[i:]
+        s = self._stack_[:i]
+        self._stack_  = s
+        return r
+
+    def run(self):
+        raise NotImplementedError(self.__class__)
+
+    def get_value(self, index):
+        raise NotImplementedError(self.__class__)
+
+    def set_value(self, index, value):
+        raise NotImplementedError(self.__class__)
+
+    def this_binding(self):
+        return self._this_binding_
+
+    def variable_environment(self):
+        return self._variable_environment_
+
+    def lexical_environment(self):
+        return self._lexical_environment_
+
+class GlobalExecutionContext(ExecutionContext):
+    global_object = None
+    def __init__(self, code, global_object):
+        ExecutionContext.__init__(self)
+        self.code = code
+
+        from js.lexical_environment import ObjectEnvironment
+        localEnv = ObjectEnvironment(global_object)
+        self._lexical_environment_ = localEnv
+        self._variable_environment_ = localEnv
+        GlobalExecutionContext.global_object = global_object
+        self._this_binding_ = global_object
+
+        self.declaration_binding_initialization(self._variable_environment_.environment_record, self.code)
+
+    def run(self):
+        return self.code.run(self)
+
+    def _symbol_for_index(self, index):
+        sym = self.code.symbol_for_index(index)
+        assert sym is not None
+        return sym
+
+    def get_ref(self, index):
+        symbol = self._symbol_for_index(index)
+        lex_env = self.lexical_environment()
+        ref = lex_env.get_identifier_reference(symbol)
+        return ref
+
+    #def get_value(self, index):
+        #env = self.variable_environment()
+        #env_record = env.environment_record
+        #identifier = self._symbol_for_index(index)
+        #value = env_record.get_binding_value(identifier)
+        #return value
+
+    #def set_value(self, index, value):
+        #env = self.variable_environment()
+        #env_record = env.environment_record
+        #identifier = self._symbol_for_index(index)
+        #env_record.set_mutable_binding(identifier, value)
+
+class EvalExecutionContext(ExecutionContext):
+    pass
+
+class FunctionExecutionContext(ExecutionContext):
+    def __init__(self, function, this, argument_values, scope = None):
+        ExecutionContext.__init__(self)
+        self.function = function
+        self.arguments = argument_values
+
+        from js.lexical_environment import DeclarativeEnvironment
+        localEnv = DeclarativeEnvironment(scope)
+        self._lexical_environment_ = localEnv
+        self._variable_environment_ = localEnv
+
+        self._this_binding_ = this
+
+        self.symbol_slots = {}
+        self.declaration_binding_initialization(self._variable_environment_.environment_record, self.function, self.arguments)
+
+    def run(self):
+        self._bind_symbols()
+        return self.function.run(self)
+
+    def _bind_symbols(self):
+        lex_env = self.variable_environment()
+        for symbol in self.function.symbols():
+            idx = self._index_for_symbol(symbol)
+            ref = lex_env.get_identifier_reference(symbol)
+            self.symbol_slots[idx] = ref
+
+    def _index_for_symbol(self, symbol):
+        return self.function.index_for_symbol(symbol)
+
+    def get_ref(self, index):
+        ref = self.symbol_slots[index]
+        return ref
+
+    #def get_value(self, index):
+        #ref = self.get_ref(index)
+        #env_record = ref.base_value
+        #identifier = ref.referenced
+        #value = env_record.get_binding_value(identifier)
+        #return value
+
+    #def set_value(self, index, value):
+        #ref = self.symbol_slots[index]
+        #env_record = ref.base_value
+        #identifier = ref.referenced
+        #env_record.set_mutable_binding(identifier, value)
diff --git a/js/interpreter.py b/js/interpreter.py
--- a/js/interpreter.py
+++ b/js/interpreter.py
@@ -16,17 +16,39 @@
 class Interpreter(object):
     """Creates a js interpreter"""
     def __init__(self):
-        self.global_context, self.w_Global, self.w_Object = js.builtins.setup_builtins(self)
+        from js.jsobj import W_BasicObject
+        self.global_object = W_BasicObject()
 
-    def run(self, script, interactive=False):
-        """run the interpreter"""
-        bytecode = JsCode()
-        script.emit(bytecode)
-        if not we_are_translated():
-            # debugging
-            self._code = bytecode
-        func = bytecode.make_js_function()
-        if interactive:
-            return func._run_with_context(self.global_context)
-        else:
-            func._run_with_context(self.global_context)
+    def run_ast(self, ast):
+        symbol_map = ast.symbol_map
+
+        from js.jscode import ast_to_bytecode
+        code = ast_to_bytecode(ast, symbol_map)
+
+        return self.run(code)
+
+    def run_src(self, src):
+        from js.astbuilder import parse_to_ast
+        ast = parse_to_ast(src)
+        return self.run_ast(ast)
+
+    def run(self, code, interactive=False):
+        from js.functions import JsGlobalCode
+        c = JsGlobalCode(code)
+
+        from js.execution_context import GlobalExecutionContext
+        ctx = GlobalExecutionContext(c, self.global_object)
+
+        return ctx.run()
+
+        #"""run the interpreter"""
+        #bytecode = JsCode()
+        #script.emit(bytecode)
+        #if not we_are_translated():
+            ## debugging
+            #self._code = bytecode
+        #func = bytecode.make_js_function()
+        #if interactive:
+        #    return func._run_with_context(self.global_context)
+        #else:
+        #    func._run_with_context(self.global_context)
diff --git a/js/js_interactive.py b/js/js_interactive.py
--- a/js/js_interactive.py
+++ b/js/js_interactive.py
@@ -52,11 +52,11 @@
     def __init__(self, locals=None, filename="<console>"):
         code.InteractiveConsole.__init__(self, locals, filename)
         self.interpreter = Interpreter()
-        ctx = self.interpreter.global_context
-        from builtins import new_native_function
-        self.interpreter.w_Global.Put('quit', new_native_function(ctx, quitjs))
-        self.interpreter.w_Global.Put('trace', new_native_function(ctx, tracejs))
-        self.interpreter.w_Global.Put('debug', new_native_function(ctx, debugjs))
+        #ctx = self.interpreter.global_context
+        #from builtins import new_native_function
+        #self.interpreter.w_Global.Put('quit', new_native_function(ctx, quitjs))
+        #self.interpreter.w_Global.Put('trace', new_native_function(ctx, tracejs))
+        #self.interpreter.w_Global.Put('debug', new_native_function(ctx, debugjs))
 
     def runcodefromfile(self, filename):
         f = open_file_as_stream(filename)
@@ -70,16 +70,15 @@
         traceback.
         """
         try:
-            res = self.interpreter.run(ast, interactive=True)
-            if DEBUG:
-                print self.interpreter._code
-            if res not in (None, w_Undefined):
-                try:
-                    if DEBUG:
-                        print repr(res)
-                    print res.ToString()
-                except ThrowException, exc:
-                    print exc.exception.ToString()
+            res = self.interpreter.run_ast(ast)
+            #if DEBUG:
+                #print self.interpreter._code
+            try:
+                #if DEBUG:
+                    #print repr(res)
+                print res.ToString()
+            except ThrowException, exc:
+                print exc.exception.ToString()
         except SystemExit:
             raise
         except ThrowException, exc:
diff --git a/js/jscode.py b/js/jscode.py
--- a/js/jscode.py
+++ b/js/jscode.py
@@ -2,9 +2,9 @@
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.rlib.jit import JitDriver, purefunction
 
-from js.execution import JsTypeError, ReturnException, ThrowException
+from js.execution import JsTypeError, ReturnException, ThrowException, JsReferenceError
 from js.opcodes import opcodes, LABEL, BaseJump, WITH_START, WITH_END
-from js.jsobj import W_Root, W_String, _w
+from js.jsobj import W_Root, W_String, _w, w_Null, w_Undefined
 
 from pypy.rlib import jit, debug
 
@@ -14,24 +14,48 @@
     except IndexError:
         return "???"
 
-jitdriver = JitDriver(greens=['pc', 'self'], reds=['ctx'], get_printable_location = get_printable_location, virtualizables=['ctx'])
+#jitdriver = JitDriver(greens=['pc', 'self'], reds=['ctx'], get_printable_location = get_printable_location, virtualizables=['ctx'])
+
+def ast_to_bytecode(ast, symbol_map):
+    bytecode = JsCode(symbol_map)
+    ast.emit(bytecode)
+    return bytecode
 
 class AlreadyRun(Exception):
     pass
 
+from js.astbuilder import empty_symbols
+
 class JsCode(object):
     """ That object stands for code of a single javascript function
     """
-    def __init__(self):
+    def __init__(self, symbol_map = empty_symbols):
         self.opcodes = []
         self.label_count = 0
         self.has_labels = True
         self.startlooplabel = []
         self.endlooplabel = []
         self.updatelooplabel = []
-        from js.astbuilder import Scope
-        self.scope = Scope()
         self._estimated_stack_size = -1
+        self._symbols = symbol_map
+
+    def variables(self):
+        return self._symbols.variables.keys()
+
+    def functions(self):
+        return self._symbols.functions.keys()
+
+    def index_for_symbol(self, symbol):
+        return self._symbols.get_index(symbol)
+
+    def symbols(self):
+        return self._symbols.get_symbols()
+
+    def symbol_for_index(self, index):
+        return self._symbols.get_symbol(index)
+
+    def params(self):
+        return self._symbols.parameters.keys()
 
     @jit.elidable
     def estimated_stack_size(self):
@@ -124,22 +148,25 @@
             return True
         return False
 
+    def unlabel(self):
+        if self.has_labels:
+            self.remove_labels()
+
     def unpop_or_undefined(self):
         if not self.unpop():
             self.emit('LOAD_UNDEFINED')
-        #elif not self.returns():
-            #self.emit('LOAD_UNDEFINED')
+        elif not self.returns():
+            self.emit('LOAD_UNDEFINED')
 
-    def make_js_function(self, name='__dont_care__', params=[]):
+    def to_function_opcodes(self):
         self.unpop_or_undefined()
+        self.unlabel()
+        return self.opcodes
 
-        if self.has_labels:
-            self.remove_labels()
-
-        return JsFunction(name, params, self)
-
-    def ToJsFunction(self, name='__dont_care__', params=[]):
-        return self.make_js_function(name, params)
+    def to_global_opcodes(self):
+        self.unpop()
+        self.unlabel()
+        return self.opcodes
 
     def remove_labels(self):
         """ Basic optimization to remove all labels and change
@@ -161,60 +188,9 @@
                 op.where = labels[op.where]
         self.has_labels = False
 
-    def __repr__(self):
-        return "\n".join([repr(i) for i in self.opcodes])
+    #def __repr__(self):
+        #return "\n".join([repr(i) for i in self.opcodes])
 
- at jit.dont_look_inside
-def _save_stack(ctx, size):
-    old_stack = ctx.stack
-    old_stack_pointer = ctx.stack_pointer
-
-    ctx._init_stack(size)
-    return old_stack, old_stack_pointer
-
- at jit.dont_look_inside
-def _restore_stack(ctx, state):
-    old_stack, old_stack_pointer = state
-    ctx.stack_pointer = old_stack_pointer
-    ctx.stack = old_stack
-
-class Js__Function(object):
-    name = 'anonymous'
-    code = ''
-    params = []
-
-    def __init__(self):
-        pass
-
-    def run(self, ctx, args=[], this=None):
-        raise NotImplementedError
-
-    def estimated_stack_size(self):
-        return 2
-
-    def local_variables(self):
-        return None
-
-    def ToString(self):
-        if self.name is not None:
-            return 'function %s() { [native code] }' % (self.name, )
-        else:
-            return 'function () { [native code] }'
-
-class Js_NativeFunction(Js__Function):
-    def __init__(self, function, name = None):
-        if name is not None:
-            self.name = name
-        self._function_ = _native_function(function)
-
-    def run(self, ctx, args=[], this=None):
-        return self._function_(this, args)
-
-    def ToString(self):
-        if self.name is not None:
-            return 'function %s() { [native code] }' % (self.name, )
-        else:
-            return 'function () { [native code] }'
 
 def _native_function(fn):
     from js.jsobj import _w
@@ -222,104 +198,3 @@
         res = fn(this, args)
         return _w(res)
     return f
-
-class JsFunction(Js__Function):
-    _immutable_fields_ = ["opcodes[*]", 'name', 'params', 'code', 'scope']
-
-    def __init__(self, name, params, code):
-        Js__Function.__init__(self)
-        from pypy.rlib.debug import make_sure_not_resized
-        self.name = name
-        self.params = params
-        self._code_ = code
-        self.opcodes = make_sure_not_resized(code.opcodes[:])
-        self.scope = code.scope
-
-    def estimated_stack_size(self):
-        return self._code_.estimated_stack_size()
-
-    def local_variables(self):
-        if self.scope:
-            return self.scope.local_variables
-
-    def ToString(self):
-        return 'function () {}'
-
-    def _get_opcode(self, pc):
-        assert pc >= 0
-        return self.opcodes[pc]
-
-    @jit.unroll_safe
-    def run(self, ctx, args=[], this=None):
-        from js.jsexecution_context import make_activation_context, make_function_context
-
-        from js.jsobj import W_Arguments, w_Undefined
-        w_Arguments = W_Arguments(self, args)
-        act = make_activation_context(ctx, this, w_Arguments)
-        newctx = make_function_context(act, self)
-
-        paramn = len(self.params)
-        for i in range(paramn):
-            paramname = self.params[i]
-            try:
-                value = args[i]
-            except IndexError:
-                value = w_Undefined
-            newctx.declare_variable(paramname)
-            newctx.assign(paramname, value)
-
-        return self._run_with_context(ctx=newctx, save_stack = False)
-
-    def _run_with_context(self, ctx, check_stack=True, save_stack=True):
-        state = ([], 0)
-        if save_stack:
-            state = _save_stack(ctx, self.estimated_stack_size())
-
-        try:
-            self._run_bytecode(ctx)
-            if check_stack:
-                ctx.check_stack()
-            return ctx.top()
-        except ReturnException, e:
-            return e.value
-        finally:
-            if save_stack:
-                _restore_stack(ctx, state)
-
-    def _run_bytecode(self, ctx, pc=0):
-        while True:
-            jitdriver.jit_merge_point(pc=pc, self=self, ctx=ctx)
-            if pc >= len(self.opcodes):
-                break
-
-            opcode = self._get_opcode(pc)
-            #if we_are_translated():
-            #    #this is an optimization strategy for translated code
-            #    #on top of cpython it destroys the performance
-            #    #besides, this code might be completely wrong
-            #    for name, op in opcode_unrolling:
-            #        opcode = hint(opcode, deepfreeze=True)
-            #        if isinstance(opcode, op):
-            #            result = opcode.eval(ctx, stack)
-            #            assert result is None
-            #            break
-            #else:
-            result = opcode.eval(ctx)
-            assert result is None
-
-            if isinstance(opcode, BaseJump):
-                new_pc = opcode.do_jump(ctx, pc)
-                condition = new_pc < pc
-                pc = new_pc
-                if condition:
-                    jitdriver.can_enter_jit(pc=pc, self=self, ctx=ctx)
-                continue
-            else:
-                pc += 1
-
-            if isinstance(opcode, WITH_START):
-                pc = self._run_bytecode(opcode.newctx, pc)
-            elif isinstance(opcode, WITH_END):
-                break
-
-        return pc
diff --git a/js/jsobj.py b/js/jsobj.py
--- a/js/jsobj.py
+++ b/js/jsobj.py
@@ -16,16 +16,7 @@
 READ_ONLY = RO = 4 # ReadOnly
 INTERNAL = IT = 8 # Internal
 
-
-class SeePage(NotImplementedError):
-    pass
-
-class W___Root(object):
-    #_settled_ = True
-    def __init__(self):
-        pass
-
-class W__Root(W___Root):
+class W_Root(object):
     #_settled_ = True
     #_attrs_ = []
     _type_ = ''
@@ -33,101 +24,32 @@
     def __str__(self):
         return self.ToString()
 
-    def type(self):
-        return self._type_
+    #def type(self):
+        #return self._type_
 
-    def ToBoolean(self):
-        return False
+    #def ToBoolean(self):
+        #return False
 
-    def ToPrimitive(self, hint = None):
-        return self
+    #def ToPrimitive(self, hint = None):
+        #return self
 
-    def ToString(self):
-        return ''
+    #def ToString(self):
+        #return ''
 
-    def ToObject(self):
-        raise JsTypeError
+    #def ToObject(self):
+        #raise JsTypeError
 
-    def ToNumber(self):
-        return 0.0
+    #def ToNumber(self):
+        #return 0.0
 
-    def ToInteger(self):
-        return int(self.ToNumber())
+    #def ToInteger(self):
+        #return int(self.ToNumber())
 
-    def ToInt32(self):
-        return r_int32(self.ToInteger())
 
-    def ToUInt32(self):
-        return r_uint32(self.ToInteger())
-
-class W_Root(W___Root):
-    #_settled_ = True
-    #_attrs_ = []
-    def __init__(self):
-        pass
-
-    def tolist(self):
-        raise JsTypeError('arrayArgs is not an Array or Arguments object')
-
-    def ToBoolean(self):
-        raise NotImplementedError(self.__class__)
-
-    def ToPrimitive(self, hint=""):
-        return self
-
-    def ToString(self):
-        return ''
-
-    def ToObject(self):
-        # XXX should raise not implemented
-        return self
-
-    def ToNumber(self):
-        return 0.0
-
-    def ToInteger(self):
-        return int(self.ToNumber())
-
-    def ToInt32(self):
-        return r_int32(int(self.ToNumber()))
-
-    def ToUInt32(self):
-        return r_uint32(0)
-
-    def Get(self, P):
-        raise NotImplementedError(self.__class__)
-
-    def Put(self, P, V, flags = 0):
-        raise NotImplementedError(self.__class__)
-
-    def PutValue(self, w):
-        pass
-
-    def CanPut(self, P):
-        return False
-
-    def Call(self, args=[], this=None):
-        raise NotImplementedError(self.__class__)
-
-    def __str__(self):
-        return self.ToString()
-
-    def type(self):
-        raise NotImplementedError(self.__class__)
-
-    def GetPropertyName(self):
-        raise NotImplementedError(self.__class__)
-
-    def HasProperty(self, identifier):
-        return False
-
-    def Delete(self, name):
-        return False
-
-class W__Primitive(W__Root):
+class W_Primitive(W_Root):
     pass
 
-class W_Undefined(W__Primitive):
+class W_Undefined(W_Primitive):
     _type_ = 'undefined'
     def ToInteger(self):
         return 0
@@ -138,7 +60,7 @@
     def ToString(self):
         return self._type_
 
-class W_Null(W__Primitive):
+class W_Null(W_Primitive):
     _type_ = 'null'
 
     def ToBoolean(self):
@@ -150,110 +72,433 @@
 w_Undefined = W_Undefined()
 w_Null = W_Null()
 
-class W_ContextObject(W_Root):
-    def __init__(self, ctx):
-        self.context = ctx
+# 8.6.1
+class Property(object):
+    value = w_Undefined
+    getter = w_Undefined
+    setter = w_Undefined
+    writable = False
+    enumerable = False
+    configurable = False
 
-    def __repr__(self):
-        return '<W_ContextObject (%s)>' % (repr(self.context),)
+    def __init__(self, value = None, writable = None, getter = None, setter = None, enumerable = None, configurable = None):
+        if value is not None:
+            self.value = value
+        if writable is not None:
+            self.writable = writable
+        if getter is not None:
+            self.get = getter
+        if setter is not None:
+            self.setter = setter
+        if writable is not None:
+            self.writable = writable
+        if configurable is not None:
+            self.configurable = configurable
 
-    def Get(self, name):
-        try:
-            return self.context.get_property_value(name)
-        except KeyError:
-            from js.jsobj import w_Undefined
-            return w_Undefined
+    def is_data_property(self):
+        return False
 
-    def Put(self, P, V, flags = 0):
-        self.context.put(P, V)
+    def is_accessor_property(self):
+        return False
 
-    def Delete(self, name):
-        try:
-            if self.context.get_property_flags(name) & DONT_DELETE:
-                return False
-            self.context.delete_identifier(name)
-        except KeyError:
-            pass
+    def update_with(self, other):
+        if other.value is not None:
+            self.value = other.value
+        if other.writable is not None:
+            self.writable = other.writable
+        if other.getter is not None:
+            self.getter = other.getter
+        if other.setter is not None:
+            self.setter = other.setter
+        if other.writable is not None:
+            self.writable = other.writable
+        if other.configurable is not None:
+            self.configurable = other.configurable
+
+class DataProperty(Property):
+    def __init__(self, value = None, writable = None, enumerable = None, configurable = None):
+        Property.__init__(self, value = value, writable = writable, enumerable = enumerable, configurable = configurable)
+
+    def is_data_property(self):
         return True
 
-class W_BasicObject(W__Root):
-    _immutable_fields_ = ['_class_', '_prototype_', '_primitive_value_']
+class AccessorProperty(Property):
+    def __init__(self, getter = None, setter = None, enumerable = None, configurable = None):
+        Property.__init__(self, getter = None, setter = None, enumerable = enumerable, configurable = configurable)
+
+    def is_accessor_property(self):
+        return True
+
+def is_data_descriptor(desc):
+    if desc is w_Undefined:
+        return False
+    return desc.is_data_descriptor()
+
+def is_accessor_descriptor(desc):
+    if desc is w_Undefined:
+        return False
+    return desc.is_accessor_descriptor()
+
+def is_generic_descriptor(desc):
+    if desc is w_Undefined:
+        return False
+    return desc.is_generic_descriptor()
+
+# 8.10
+class PropertyDescriptor(object):
+    value = None
+    writable = None
+    getter = None
+    setter = None
+    configurable = None
+    enumerable = None
+
+    def __init__(self, value = None, writable = None, getter = None, setter = None, configurable = None, enumerable = None):
+        self.value = value
+        self.writable = writable
+        self.getter = getter
+        self.setter = setter
+        self.configurable = configurable
+        self.enumerable = enumerable
+
+    def is_accessor_descriptor(self):
+        return self.getter is not None and self.setter is not None
+
+    def is_data_descriptor(self):
+        return self.value is not None and self.writable is not None
+
+    def is_generic_descriptor(self):
+        return self.is_accessor_descriptor() is False and self.is_data_descriptor() is False
+
+    def is_empty(self):
+        return self.getter is None\
+            and self.setter is None\
+            and self.value is None\
+            and self.writable is None\
+            and self.enumerable is None\
+            and self.configurable is None
+
+    def __eq__(self, other):
+        assert isinstance(other, PropertyDescriptor)
+
+        if self.setter is not None and self.setter != other.setter:
+            return False
+
+        if self.getter is not None and self.getter != other.getter:
+            return False
+
+        if self.writable is not None and self.writable != other.writable:
+            return False
+
+        if self.value is not None and self.value != other.value:
+            return False
+
+        if self.configurable is not None and self.configurable != other.configurable:
+            return False
+
+        if self.enumerable is not None and self.enumerable != other.enumerable:
+            return False
+
+    def update_with(self, other):
+        assert isinstance(other, PropertyDescriptor)
+
+        if other.enumerable is not None:
+            self.enumerable = other.enumerable
+
+        if other.configurable is not None:
+            self.configurable = other.configurable
+
+        if other.value is not None:
+            self.value = other.value
+
+        if other.writable is not None:
+            self.writable = other.writable
+
+        if other.getter is not None:
+            self.getter = other.getter
+
+        if other.setter is not None:
+            self.setter = other.setter
+
+class PropertyIdenfidier(object):
+    def __init__(self, name, descriptor):
+        self.name = name
+        self.descriptor = descriptor
+
+class W_BasicObject(W_Root):
+    #_immutable_fields_ = ['_class_', '_prototype_', '_primitive_value_']
     _type_ = 'object'
     _class_ = 'Object'
     _prototype_ = w_Undefined
+    _extensible_ = True
 
     def __init__(self):
-        W__Root.__init__(self)
-        self._property_map = root_map()
-        self._property_values = []
-        #self._set_property('prototype', self._prototype_, DONT_ENUM | DONT_DELETE)
+        W_Root.__init__(self)
+        self._properties_ = {}
 
     def __repr__(self):
-        #keys = self._property_map.keys()
-        #values = [str(i) for i in self._property_values], str(dict(zip(keys, values)))
-        return "%s: %s" % (object.__repr__(self), self.Class())
+        return "%s: %s" % (object.__repr__(self), self.klass())
 
-    def _set_property(self, name, value, flags):
-        if self._property_map.lookup(name) == self._property_map.NOT_FOUND:
-            self._property_map = self._property_map.add(name, flags)
-        self._set_property_value(name, value)
-        self._set_property_flags(name, flags)
 
-    def _set_property_value(self, name, value):
-        idx = self._property_map.lookup(name)
-        l = len(self._property_values)
-
-        if l <= idx:
-            self._property_values = self._property_values + ([None] * (idx - l + 1))
-
-        self._property_values[idx] = value
-
-    def _set_property_flags(self, name, flags):
-        self._property_map = self._property_map.set_flags(name, flags)
-
-    def _get_property_value(self, name):
-        idx = self._property_map.lookup(name)
-        if idx == self._property_map.NOT_FOUND:
-            raise KeyError
-        return self._property_values[idx]
-
-    def _get_property_keys(self):
-        return self._property_map.keys()
-
-    def _get_property_flags(self, name):
-        flag = self._property_map.lookup_flag(name)
-        if flag == self._property_map.NOT_FOUND:
-            raise KeyError
-        return flag
-
-    def _has_property(self, name):
-        return self._property_map.lookup(name) != self._property_map.NOT_FOUND
-
-    @jit.unroll_safe
-    def _delete_property(self, name):
-        idx = self._property_map.lookup(name)
-        old_map = self._property_map
-        new_map = self._property_map.delete(name)
-        new_keys = new_map.keys()
-        new_values = [None] * len(new_keys)
-        old_values = self._property_values
-
-        for key in new_keys:
-            old_index = old_map.lookup(key)
-            new_index = new_map.lookup(key)
-            new_values[new_index] = old_values[old_index]
-
-        self._property_values = new_values
-        self._property_map = new_map
-
-    #########
-
-    def Prototype(self):
+    ##########
+    # 8.6.2 Object Internal Properties and Methods
+    def prototype(self):
         return self._prototype_
 
-    def Class(self):
+    def klass(self):
         return self._class_
 
+    def extensible(self):
+        return self._extensible_
+
+    # 8.12.3
+    def get(self, p):
+        desc = self.get_property(p)
+
+        if desc is w_Undefined:
+            return w_Undefined
+
+        if is_data_descriptor(desc):
+            return desc.value
+
+        getter = desc.getter
+        if getter is w_Undefined:
+            return w_Undefined
+
+        # return getter.call(this = self)
+        raise NotImplementedError(self.__class__)
+
+    # 8.12.1
+    def get_own_property(self, p):
+        if p not in self._properties_:
+            return w_Undefined
+
+        d = PropertyDescriptor()
+        x = self._properties_[p]
+
+        if x.is_data_property():
+            d.value = x.value
+            d.writable = x.writable
+        elif x.is_accessor_property:
+            d.setter = x.setter
+            d.getter = x.getter
+
+        d.enumerable = x.enumerable
+        d.configurable = x.configurable
+        return d
+
+    # 8.12.2
+    def get_property(self, p):
+        prop = self.get_own_property(p)
+        if prop is not w_Undefined:
+            return prop
+        proto = self.prototype()
+
+        if proto is w_Undefined:
+            return w_Undefined
+
+        return proto.get_property(p)
+
+    # 8.12.5
+    def put(self, p, v, throw = False):
+        if self.can_put(p) is False:
+            if throw is True:
+                raise JsTypeError(self.__class__)
+
+        own_desc = self.get_own_property(p)
+        if is_data_descriptor(own_desc):
+            value_desc = PropertyDescriptor(value = v)
+            self.define_own_property(p, value_desc, throw)
+            return
+
+        desc = self.get_property(p)
+        if is_accessor_descriptor(desc):
+            setter = desc.setter
+            assert setter is not None
+            # setter.call(this = self, v)
+            raise NotImplementedError(self.__class__)
+        else:
+            new_desc = PropertyDescriptor(value = v, writable = True, configurable = True, enumerable = True)
+            self.define_own_property(p, new_desc, throw)
+
+    # 8.12.4
+    def can_put(self, p):
+        desc = self.get_own_property(p)
+        if desc is not w_Undefined:
+            if is_accessor_descriptor(desc):
+                if desc.setter is w_Undefined:
+                    return False
+                else:
+                    return True
+            return desc.writable
+
+        proto = self.prototype()
+
+        if proto is w_Null or proto is w_Undefined:
+            return self.extensible()
+
+        inherited = proto.GetProperty(p)
+        if inherited is w_Undefined:
+            return self.extensible()
+
+        if is_accessor_descriptor(inherited):
+            if inherited.setter is w_Undefined:
+                return False
+            else:
+                return True
+        else:
+            if self.extensible() is False:
+                return False
+            else:
+                return inherited.writable
+
+    # 8.12.6
+    def has_property(self, p):
+        desc = self.get_property(p)
+        if desc is w_Undefined:
+            return False
+        return True
+
+    # 8.12.7
+    def delete(self, p, throw):
+        desc = self.get_own_property(p)
+        if desc is w_Undefined:
+            return True
+        if desc.configurable:
+            del self._properties_[p]
+            return True
+
+        if throw is True:
+            raise JsTypeError(self.__class__)
+
+    # 8.12.8
+    def default_value(self, hint = 'Number'):
+        if hint == 'String':
+            res = self._default_value_string_()
+            if res is None:
+                res = self._default_value_number_()
+        else:
+            res = self._default_value_number_()
+            if res is None:
+                res = self._default_value_string_()
+
+        if res is not None:
+            return res
+
+        raise JsTypeError(self.__class__)
+
+    def _default_value_string_(self):
+        to_string = self.get('toString')
+        if to_string.is_callable():
+            _str = to_string.call(this = self)
+            if isinstance(_str, W_Primitive):
+                return _str
+
+    def _default_value_number_(self):
+        value_of = self.get('valueOf')
+        if value_of.is_callable():
+            val = to_string.call(this = self)
+            if isinstance(val, W_Primitive):
+                return val
+
+    # 8.12.9
+    def define_own_property(self, p, desc, throw = False):
+        def reject():
+            if throw:
+                raise JsTypeError(self.__class__)
+            else:
+                return False
+
+        current = self.get_own_property(p)
+        extensible = self.extensible()
+        # 3.
+        if current is w_Undefined and extensible is False:
+            return reject()
+        # 4.
+        if current is w_Undefined and extensible is True:
+            # 4.a
+            if is_generic_descriptor(desc) or is_data_descriptor(desc):
+                new_prop = DataProperty(\
+                    value = desc.value,\
+                    writable = desc.writable,\
+                    enumerable = desc.enumerable,\
+                    configurable = desc.configurable\
+                )
+                self._properties_[p] = new_prop
+            # 4.b
+            else:
+                assert is_accessor_descriptor(desc) is True
+                new_prop = AccessorProperty(\
+                    getter = desc.getter,\
+                    setter = desc.setter,\
+                    enumerable = desc.enumerable,
+                    configurable = desc.configurable\
+                )
+                self._properties_[p] = new_prop
+            # 4.c
+            return True
+
+        # 5.
+        if desc.is_empty():
+            return True
+
+        # 6.
+        if desc == current:
+            return True
+
+        # 7.
+        if current.configurable is False:
+            if desc.configurable is True:
+                return reject()
+            if desc.enumerable is not None and current.enumerable != desc.enumerable:
+                return reject()
+
+        # 8.
+        if is_generic_descriptor(desc):
+            pass
+        # 9.
+        elif is_data_descriptor(current) != is_data_descriptor(desc):
+            # 9.a
+            if current.configurable is False:
+                return reject()
+            # 9.b
+            if is_data_descriptor(current):
+                raise NotImplementedError(self.__class__)
+            # 9.c
+            else:
+                raise NotImplementedError(self.__class__)
+        # 10
+        elif is_data_descriptor(current) and is_data_descriptor(current):
+            # 10.a
+            if current.configurable is False:
+                # 10.a.i
+                if current.writable is False and desc.writable is True:
+                    return reject()
+                # 10.a.ii
+                if current.writable is False:
+                    if desc.value is not None and desc.value != current.value:
+                        return reject()
+            # 10.b
+            else:
+                pass
+        # 11
+        elif is_accessor_descriptor(current) and is_accessor_descriptor(desc):
+            # 11.a
+            if current.configurable is False:
+                # 11.a.i
+                if desc.setter is not None and desc.setter != current.setter:
+                    return reject()
+                # 11.a.ii
+                if desc.getter is not None and desc.getter != current.getter:
+                    return reject()
+        # 12
+        prop = self._properties_[p]
+        prop.update_with(desc)
+
+        # 13
+        return True
+
+    ##########
     def ToBoolean(self):
         return True
 
@@ -269,78 +514,6 @@
     def ToObject(self):
         return self
 
-    ##########
-
-    def IsCallable(self):
-        return False
-
-    def DefaultValue(self, hint = 'Number'):
-        props = ['valueOf', 'toString']
-        if hint == 'String':
-            props = ['toString', 'valueOf']
-
-        for prop in props:
-            p = self.Get(prop)
-            if isinstance(p, W_BasicObject) and p.IsCallable():
-                res = p.Call(this = self)
-                if isinstance(res, W__Primitive):
-                    return res
-
-        raise JsTypeError
-
-    def Get(self, P):
-        try:
-            return self._get_property_value(P)
-        except KeyError:
-            if isnull_or_undefined(self.Prototype()):
-                return w_Undefined
-
-        assert self.Prototype() is not self
-        return self.Prototype().Get(P) # go down the prototype chain
-
-    # 8.12.4
-    def CanPut(self, P):
-        if self._has_property(P):
-            if self._get_property_flags(P) & READ_ONLY: return False
-            return True
-
-        if isnull_or_undefined(self.Prototype()): return True
-
-        assert self.Prototype() is not self
-        return self.Prototype().CanPut(P)
-
-    # 8.12.5
-    def Put(self, P, V, flags = 0):
-        if not self.CanPut(P): return
-
-        # TODO: ???
-        if self._has_property(P):
-            self._set_property_value(P, V)
-            f = self._get_property_flags(P) | flags
-            self._set_property_flags(P, f)
-            return
-
-        self._set_property(P, V, flags)
-
-    def GetPropertyName(self):
-        raise NotImplementedError(self.__class__)
-
-    def HasProperty(self, P):
-        if self._has_property(P): return True
-
-        if isnull_or_undefined(self.Prototype()): return False
-
-        assert self.Prototype() is not self
-        return self.Prototype().HasProperty(P)
-
-    def Delete(self, P):
-        if self._has_property(P):
-            if self._get_property_flags(P) & DONT_DELETE:
-                return False
-            self._delete_property(P)
-            return True
-        return True
-
 class W__PrimitiveObject(W_BasicObject):
     def __init__(self, primitive_value):
         W_BasicObject.__init__(self)
@@ -402,11 +575,10 @@
 class W_BasicFunction(W_BasicObject):
     _class_ = 'Function'
     _type_ = 'function'
-    _immutable_fields_ = ['_context_']
+    #_immutable_fields_ = ['_context_']
 
-    def __init__(self, context):
+    def __init__(self):
         W_BasicObject.__init__(self)
-        self._context_ = context
 
     def Call(self, args=[], this=None):
         raise NotImplementedError(self.__class__)
@@ -434,6 +606,9 @@
     def IsCallable(self):
         return True
 
+    def Scope(self):
+        return self._context_
+
 class W_FunctionConstructor(W_BasicFunction):
     def __init__(self, ctx):
         W_BasicFunction.__init__(self, ctx)
@@ -521,12 +696,18 @@
 class W__Function(W_BasicFunction):
     _immutable_fields_ = ['_function_']
 
-    def __init__(self, context, function):
-        W_BasicFunction.__init__(self, context)
+    def __init__(self, function, context):
+        W_BasicFunction.__init__(self)
         self._function_ = function
+        self._context_ = context
 
     def Call(self, args=[], this=None):
-        result = self._function_.run(self._context_, args, this)
+        f = self._function_
+        scope = self.Scope()
+
+        from js.execution_context import FunctionExecutionContext
+        ctx = FunctionExecutionContext(f, this, args, scope)
+        result = ctx.run()
         return result
 
     def ToString(self):
@@ -616,12 +797,12 @@
 class W_Math(W__Object):
     _class_ = 'Math'
 


More information about the pypy-commit mailing list