[pypy-commit] lang-js default: new object model, works!!!

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


Author: Stephan <stephan at stzal.com>
Branch: 
Changeset: r158:1321f8e7e4ff
Date: 2011-12-13 13:52 +0100
http://bitbucket.org/pypy/lang-js/changeset/1321f8e7e4ff/

Log:	new object model, works!!!

diff too long, truncating to 2000 out of 2242 lines

diff --git a/js/baseop.py b/js/baseop.py
--- a/js/baseop.py
+++ b/js/baseop.py
@@ -222,6 +222,7 @@
         raise ThrowException(W_String('it is not a constructor'))
     try:
         res = obj.Construct(args=args)
+        return res
     except JsTypeError:
         raise ThrowException(W_String('it is not a constructor'))
     return res
diff --git a/js/builtins.py b/js/builtins.py
--- a/js/builtins.py
+++ b/js/builtins.py
@@ -1,13 +1,10 @@
-import math
 import time
-from pypy.rlib import rrandom
-random = rrandom.Random(int(time.time()))
 
 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,\
+     W_FloatNumber, W_String, W_Builtin, w_Null, newbool,\
      isnull_or_undefined, W_PrimitiveObject, W_ListObject, W_Number,\
-     DONT_DELETE, DONT_ENUM, READ_ONLY, INTERNAL
+     DONT_DELETE, DONT_ENUM, READ_ONLY, INTERNAL, _w
 from js.execution import ThrowException, JsTypeError
 
 from js.jsparser import parse, ParseError
@@ -42,29 +39,28 @@
     return t
 
 def make_loadjs(interp):
-    def f(args, this):
+    def f(this, *args):
         filename = str(args[0].ToString())
         t = load_file(filename)
         interp.run(t)
         return w_Undefined
     return f
 
-class W_Eval(W_NewBuiltin):
-    def __init__(self, ctx):
-        W_NewBuiltin.__init__(self)
-        self.ctx = ctx
+# 15.1.2.1
+from js.jsobj import W_BasicFunction
+class W__Eval(W_BasicFunction):
+    def ToString(self):
+        return "function eval() { [native code] }"
 
-    length = 1
     def Call(self, args=[], this=None):
-        if len(args) >= 1:
-            arg0 = args[0]
-            if  isinstance(arg0, W_String):
-                src = arg0.ToString()
-            else:
-                return arg0
-        else:
+        if len(args) == 0:
             return w_Undefined
 
+        arg0 = args[0]
+        if  not isinstance(arg0, W_String):
+            return arg0
+
+        src = arg0.ToString()
         try:
             node = eval_source(src, 'evalcode')
         except ParseError, e:
@@ -73,7 +69,7 @@
         bytecode = JsCode()
         node.emit(bytecode)
         func = bytecode.make_js_function()
-        return func.run(self.ctx)
+        return func.run(self._context_)
 
 class W_ParseInt(W_NewBuiltin):
     length = 1
@@ -117,18 +113,6 @@
             temp.append(chr(i))
         return W_String(''.join(temp))
 
-class W_CharAt(W_NewBuiltin):
-    length = 1
-    def Call(self, args=[], this=None):
-        string = this.ToString()
-        if len(args)>=1:
-            pos = args[0].ToInt32()
-            if (not pos >=0) or (pos > len(string) - 1):
-                return W_String('')
-        else:
-            return W_String('')
-        return W_String(string[pos])
-
 class W_CharCodeAt(W_NewBuiltin):
     def Call(self, args=[], this=None):
         string = this.ToString()
@@ -317,11 +301,14 @@
                 '}'
 class W_FToString(W_NewBuiltin):
     def Call(self, args=[], this=None):
-        assert isinstance(this, W_PrimitiveObject)
-        if this.Class == 'Function':
+        from js.jsobj import W__Function
+        if isinstance(this, W_PrimitiveObject):
+            if this.Class == 'Function':
+                return W_String(functionstring)
+        if isinstance(this, W__Function):
             return W_String(functionstring)
-        else:
-            raise JsTypeError('this is not a function object')
+
+        raise JsTypeError('this is not a function object')
 
 class W_Apply(W_NewBuiltin):
     def __init__(self, ctx):
@@ -370,7 +357,6 @@
             raise JsTypeError('Wrong type')
         return W_String(this.Value.ToString())
 
-
 class W_NumberValueToString(W_ValueToString):
     mytype = 'number'
 
@@ -380,115 +366,6 @@
 class W_StringValueToString(W_ValueToString):
     mytype = 'string'
 
-class W_ArrayToString(W_NewBuiltin):
-    length = 0
-    def Call(self, args=[], this=None):
-        return W_String(common_join(this, sep=','))
-
-class W_ArrayJoin(W_NewBuiltin):
-    length = 1
-    def Call(self, args=[], this=None):
-        if len(args) >= 1 and not args[0] is w_Undefined:
-            sep = args[0].ToString()
-        else:
-            sep = ','
-
-        return W_String(common_join(this, sep))
-
-class W_ArrayPush(W_NewBuiltin):
-    def Call(self, args=[], this=None):
-        n = this.Get('length').ToUInt32()
-        for arg in args:
-            this.Put(str(n), arg)
-            n += 1
-        j = W_IntNumber(n)
-        this.Put('length', j);
-        return j
-
-class W_ArrayPop(W_NewBuiltin):
-    def Call(self, args=[], this=None):
-        len = this.Get('length').ToUInt32()
-        if(len == 0):
-            return w_Undefined
-        else:
-            indx = len-1
-            indxstr = str(indx)
-            element = this.Get(indxstr)
-            this.Delete(indxstr)
-            this.Put('length', W_IntNumber(indx))
-            return element
-
-class W_ArrayReverse(W_NewBuiltin):
-    length = 0
-    def Call(self, args=[], this=None):
-        r2 = this.Get('length').ToUInt32()
-        k = r_uint(0)
-        r3 = r_uint(math.floor( float(r2)/2.0 ))
-        if r3 == k:
-            return this
-
-        while k < r3:
-            r6 = r2 - k - 1
-            r7 = str(k)
-            r8 = str(r6)
-
-            r9 = this.Get(r7)
-            r10 = this.Get(r8)
-
-            this.Put(r7, r10)
-            this.Put(r8, r9)
-            k += 1
-
-        return this
-
-class W_ArraySort(W_NewBuiltin):
-    length = 1
-    #XXX: further optimize this function
-    def Call(self, args=[], this=None):
-        length = this.Get('length').ToUInt32()
-
-        # According to ECMA-262 15.4.4.11, non-existing properties always come after
-        # existing values. Undefined is always greater than any other value.
-        # So we create a list of non-undefined values, sort them, and append undefined again.
-        values = []
-        undefs = r_uint(0)
-
-        for i in range(length):
-            P = str(i)
-            if not this.HasProperty(P):
-                # non existing property
-                continue
-            obj = this.Get(str(i))
-            if obj is w_Undefined:
-                undefs += 1
-                continue
-            values.append(obj)
-
-        # sort all values
-        if len(args) > 0 and args[0] is not w_Undefined:
-            sorter = Sorter(values, compare_fn=args[0])
-        else:
-            sorter = Sorter(values)
-        sorter.sort()
-
-        # put sorted values back
-        values = sorter.list
-        for i in range(len(values)):
-            this.Put(str(i), values[i])
-
-        # append undefined values
-        newlength = len(values)
-        while undefs > 0:
-            undefs -= 1
-            this.Put(str(newlength), w_Undefined)
-            newlength += 1
-
-        # delete non-existing elements on the end
-        while length > newlength:
-            this.Delete(str(newlength))
-            newlength += 1
-        return this
-
 class W_NativeObject(W_Object):
     def __init__(self, Class, Prototype, Value=w_Undefined):
         W_Object.__init__(self, Prototype, Class, Value)
@@ -501,18 +378,11 @@
         v = int(time.time()*1000)
         return create_object('Date', Value = W_IntNumber(v))
 
-def pypy_repr(args, this):
+def pypy_repr(this, *args):
     o = args[0]
-    t = 'Unknown'
-    if isinstance(o, W_FloatNumber):
-        t = 'W_FloatNumber'
-    elif isinstance(o, W_IntNumber):
-        t = 'W_IntNumber'
-    elif isinstance(o, W_Number):
-        t = 'W_Number'
-    return W_String(t)
+    return W_String(repr(o))
 
-def put_values(ctx, obj, dictvalues):
+def put_values(obj, dictvalues):
     for key,value in dictvalues.iteritems():
         obj.Put(key, value)
 
@@ -556,14 +426,14 @@
 def writer(x):
     print x
 
-def printjs(args, this):
+def printjs(this, *args):
     writer(",".join([i.ToString() for i in args]))
     return w_Undefined
 
 def noop(*args):
     return w_Undefined
 
-def isnanjs(args, this):
+def isnanjs(this, *args):
     if len(args) < 1:
         return newbool(True)
     return newbool(isnan(args[0].ToNumber()))
@@ -577,54 +447,9 @@
     else:
         return newbool(True)
 
-def absjs(args, this):
-    val = args[0]
-    if isinstance(val, W_IntNumber):
-        if val.ToInteger() > 0:
-            return val # fast path
-        return W_IntNumber(-val.ToInteger())
-    return W_FloatNumber(abs(args[0].ToNumber()))
-
-def floorjs(args, this):
-    if len(args) < 1:
-        return W_FloatNumber(NAN)
-
-    val = args[0].ToNumber()
-
-    pos = math.floor(val)
-    if isnan(val):
-        pos = INFINITY
-
-    return W_FloatNumber(pos)
-
-def roundjs(args, this):
-    return floorjs(args, this)
-
-def powjs(args, this):
-    return W_FloatNumber(math.pow(args[0].ToNumber(), args[1].ToNumber()))
-
-def sqrtjs(args, this):
-    return W_FloatNumber(math.sqrt(args[0].ToNumber()))
-
-def logjs(args, this):
-    return W_FloatNumber(math.log(args[0].ToNumber()))
-
 def versionjs(args, this):
     return w_Undefined
 
-def randomjs(args, this):
-    return W_FloatNumber(random.random())
-
-def minjs(args, this):
-    a = args[0].ToNumber()
-    b = args[1].ToNumber()
-    return W_FloatNumber(min(a, b))
-
-def maxjs(args, this):
-    a = args[0].ToNumber()
-    b = args[1].ToNumber()
-    return W_FloatNumber(max(a, b))
-
 def _ishex(ch):
     return ((ch >= 'a' and ch <= 'f') or (ch >= '0' and ch <= '9') or
             (ch >= 'A' and ch <= 'F'))
@@ -665,42 +490,41 @@
             return self.Construct()
 
     def Construct(self, args=[]):
-        if (len(args) >= 1 and not args[0] is w_Undefined and not
-            args[0] is w_Null):
+        if (len(args) >= 1 and not args[0] is w_Undefined and not args[0] is w_Null):
             # XXX later we could separate builtins and normal objects
             return args[0].ToObject()
         return create_object('Object')
 
-class W_BooleanObject(W_NativeObject):
-    def Call(self, args=[], this=None):
-        if len(args) >= 1 and not isnull_or_undefined(args[0]):
-            return newbool(args[0].ToBoolean())
-        else:
-            return newbool(False)
+#class W_BooleanObject(W_NativeObject):
+    #def Call(self, args=[], this=None):
+        #if len(args) >= 1 and not isnull_or_undefined(args[0]):
+            #return newbool(args[0].ToBoolean())
+        #else:
+            #return newbool(False)
 
-    def Construct(self, args=[]):
-        if len(args) >= 1 and not isnull_or_undefined(args[0]):
-            Value = newbool(args[0].ToBoolean())
-            return create_object('Boolean', Value = Value)
-        return create_object('Boolean', Value = newbool(False))
+    #def Construct(self, args=[]):
+        #if len(args) >= 1 and not isnull_or_undefined(args[0]):
+            #Value = newbool(args[0].ToBoolean())
+            #return create_object('Boolean', Value = Value)
+        #return create_object('Boolean', Value = newbool(False))
 
-class W_NumberObject(W_NativeObject):
-    def Call(self, args=[], this=None):
-        if len(args) >= 1 and not isnull_or_undefined(args[0]):
-            return W_FloatNumber(args[0].ToNumber())
-        elif len(args) >= 1 and args[0] is w_Undefined:
-            return W_FloatNumber(NAN)
-        else:
-            return W_FloatNumber(0.0)
+#class W_NumberObject(W_NativeObject):
+    #def Call(self, args=[], this=None):
+        #if len(args) >= 1 and not isnull_or_undefined(args[0]):
+            #return W_FloatNumber(args[0].ToNumber())
+        #elif len(args) >= 1 and args[0] is w_Undefined:
+            #return W_FloatNumber(NAN)
+        #else:
+            #return W_FloatNumber(0.0)
 
-    def ToNumber(self):
-        return 0.0
+    #def ToNumber(self):
+        #return 0.0
 
-    def Construct(self, args=[]):
-        if len(args) >= 1 and not isnull_or_undefined(args[0]):
-            Value = W_FloatNumber(args[0].ToNumber())
-            return create_object('Number', Value = Value)
-        return create_object('Number', Value = W_FloatNumber(0.0))
+    #def Construct(self, args=[]):
+        #if len(args) >= 1 and not isnull_or_undefined(args[0]):
+            #Value = W_FloatNumber(args[0].ToNumber())
+            #return create_object('Number', Value = Value)
+        #return create_object('Number', Value = W_FloatNumber(0.0))
 
 class W_StringObject(W_NativeObject):
     length = 1
@@ -720,31 +544,31 @@
 def create_array(elements=[]):
     # TODO do not get array prototype from global context?
     #proto = ctx.get_global().Get('Array').Get('prototype')
-    from js.builtins import get_builtin_prototype
-    proto = get_builtin_prototype('Array')
-    assert isinstance(proto, W_PrimitiveObject)
-    array = W_Array(Prototype=proto, Class = proto.Class)
-    i = 0
+    #from js.builtins import get_builtin_prototype
+    #proto = get_builtin_prototype('Array')
+    #assert isinstance(proto, W_PrimitiveObject)
+    array = W__Array()
+    #i = 0
     while i < len(elements):
         array.Put(str(i), elements[i])
         i += 1
 
     return array
 
-class W_ArrayObject(W_NativeObject):
-    def __init__(self, Class, Prototype):
-        W_NativeObject.__init__(self, Class, Prototype, None )
+#class W_ArrayObject(W_NativeObject):
+    #def __init__(self, Class, Prototype):
+        #W_NativeObject.__init__(self, Class, Prototype, None )
 
-    def Call(self, args=[], this=None):
-        if len(args) == 1 and isinstance(args[0], W_Number):
-            array = create_array()
-            array.Put('length', args[0])
-        else:
-            array = create_array(args)
-        return array
+    #def Call(self, args=[], this=None):
+        #if len(args) == 1 and isinstance(args[0], W_Number):
+            #array = create_array()
+            #array.Put('length', args[0])
+        #else:
+            #array = create_array(args)
+        #return array
 
-    def Construct(self, args=[]):
-        return self.Call(args)
+    #def Construct(self, args=[]):
+        #return self.Call(args)
 
 _builtin_prototypes = {}
 def get_builtin_prototype(name):
@@ -756,219 +580,330 @@
 def _register_builtin_prototype(name, obj):
     _builtin_prototypes[name] = obj
 
+def new_native_function(ctx, function, name = None):
+    from js.jscode import Js_NativeFunction
+    from js.jsobj import W__Function
+    return W__Function(ctx, Js_NativeFunction(function, name))
+
+# 15.7.4.2
+def number_to_string(this, *args):
+    # TODO radix, see 15.7.4.2
+    return this.ToString()
+
 def setup_builtins(interp):
+    def put_native_function(obj, name, func):
+        obj.Put(name, new_native_function(ctx, func, name))
+
     allon = DONT_ENUM | DONT_DELETE | READ_ONLY
     from js.jsexecution_context import make_global_context
+
     ctx = make_global_context()
     w_Global = ctx.to_context_object()
 
-    w_ObjPrototype = W_Object(Prototype=None, Class='Object')
+    from js.jsobj import W_BasicObject, W__Object
+    w_ObjectPrototype = W_BasicObject()
+    W__Object._prototype_ = w_ObjectPrototype
 
-    w_Function = W_Function(ctx, Class='Function', Prototype=w_ObjPrototype)
-    w_FncPrototype = W_Function(ctx, Class='Function', Prototype=w_ObjPrototype)#W_Object(Prototype=None, Class='Function')
+    from js.jscode import Js_NativeFunction
+    from js.jsobj import W__Function
 
-    w_Function.Put('length', W_IntNumber(1), flags = allon)
+    # 15.3.4
+    import js.builtins_function as function_builtins
+    w_FunctionPrototype = new_native_function(ctx, function_builtins.empty, 'Empty')
+    w_FunctionPrototype._prototype_ = w_ObjectPrototype
+
+    # 15.3.3.1
+    W__Function._prototype_ = w_FunctionPrototype
+
+    from js.jsobj import W_FunctionConstructor
+    W_FunctionConstructor._prototype_ = w_FunctionPrototype
+
+    w_Function = W_FunctionConstructor(ctx)
+    w_Function.Put('constructor', w_Function, DONT_ENUM)
+
     w_Global.Put('Function', w_Function)
 
-    w_Object = W_ObjectObject('Object', w_FncPrototype)
-    w_Object.Put('prototype', w_ObjPrototype, flags = allon)
-    w_Object.Put('length', W_IntNumber(1), flags = allon)
-    w_Global.Prototype = w_ObjPrototype
+    from js.jsobj import W_ObjectConstructor
+    # 15.2.3
+    W_ObjectConstructor._prototype_ = w_FunctionPrototype
+    w_Object = W_ObjectConstructor()
 
-    w_Object.Put('prototype', w_ObjPrototype, flags = allon)
+    # 15.2.3.1
+    w_Object.Put('prototype', w_ObjectPrototype, flags = allon)
+    w_Object.Put('length', _w(1), flags = allon)
     w_Global.Put('Object', w_Object)
 
-    w_Function.Put('prototype', w_FncPrototype, flags = allon)
-    w_Function.Put('constructor', w_Function, flags=allon)
+    w_ObjectPrototype.Put('__proto__', w_Null)
+    # 15.2.4.1
+    w_ObjectPrototype.Put('constructor', w_Object)
 
-    toString = W_ToString()
+    # 15.2.4.2
+    import js.builtins_object as object_builtins
+    put_native_function(w_Object, 'toString', object_builtins.to_string)
+    put_native_function(w_Object, 'toLocaleString', object_builtins.to_string)
+    put_native_function(w_Object, 'valueOf', object_builtins.value_of)
 
-    put_values(ctx, w_ObjPrototype, {
-        'constructor': w_Object,
-        '__proto__': w_Null,
-        'toString': toString,
-        'toLocaleString': toString,
-        'valueOf': W_ValueOf(),
-        'hasOwnProperty': W_HasOwnProperty(),
-        'isPrototypeOf': W_IsPrototypeOf(),
-        'propertyIsEnumerable': W_PropertyIsEnumerable(),
-    })
-    _register_builtin_prototype('Object', w_ObjPrototype)
+    #put_values(w_ObjPrototype, {
+        #'constructor': w_Object,
+        #'__proto__': w_Null,
+        #'toString': toString,
+        #'toLocaleString': toString,
+        #'valueOf': W_ValueOf(),
+        #'hasOwnProperty': W_HasOwnProperty(),
+        #'isPrototypeOf': W_IsPrototypeOf(),
+        #'propertyIsEnumerable': W_PropertyIsEnumerable(),
+    #})
 
-    #properties of the function prototype
-    put_values(ctx, w_FncPrototype, {
-        'constructor': w_Function,
-        '__proto__': w_FncPrototype,
-        'toString': W_FToString(),
-        'apply': W_Apply(ctx),
-        'call': W_Call(ctx),
-        'arguments': w_Null,
-        'valueOf': W_ValueOf(),
-    })
-    _register_builtin_prototype('Function', w_FncPrototype)
+    #15.3.3.2
+    w_Function.Put('length', _w(1), flags = allon)
 
-    w_Boolean = W_BooleanObject('Boolean', w_FncPrototype)
-    w_Boolean.Put('constructor', w_FncPrototype, flags = allon)
-    w_Boolean.Put('length', W_IntNumber(1), flags = allon)
+    # 15.3.4.1
+    w_FunctionPrototype.Put('constructor', w_Function)
 
-    w_BoolPrototype = create_object('Object', Value=newbool(False))
-    w_BoolPrototype.Class = 'Boolean'
+    # 15.3.4.2
+    import js.builtins_function as function_builtins
+    put_native_function(w_FunctionPrototype, 'toString', function_builtins.to_string)
 
-    put_values(ctx, w_BoolPrototype, {
-        'constructor': w_FncPrototype,
-        '__proto__': w_ObjPrototype,
-        'toString': W_BooleanValueToString(),
-        'valueOf': get_value_of('Boolean')(),
-    })
-    _register_builtin_prototype('Boolean', w_BoolPrototype)
 
-    w_Boolean.Put('prototype', w_BoolPrototype, flags = allon)
+    ##properties of the function prototype
+    #put_values(w_FncPrototype, {
+        #'constructor': w_Function,
+        #'__proto__': w_FncPrototype,
+        #'toString': W_FToString(),
+        #'apply': W_Apply(ctx),
+        #'call': W_Call(ctx),
+        #'arguments': w_Null,
+        #'valueOf': W_ValueOf(),
+    #})
+
+    # 15.6.2
+    from js.jsobj import W_BooleanConstructor
+    w_Boolean = W_BooleanConstructor(ctx)
     w_Global.Put('Boolean', w_Boolean)
 
-    #Number
-    w_Number = W_NumberObject('Number', w_FncPrototype)
+    # 15.6.4
+    from js.jsobj import W_BooleanObject
+    w_BooleanPrototype = W_BooleanObject(False)
+    w_BooleanPrototype._prototype_ = W__Object._prototype_
 
-    w_empty_fun = w_Function.Call(args=[W_String('')])
+    # 15.6.4.1
+    w_BooleanPrototype.Put('constructor', w_Boolean)
 
-    w_NumPrototype = create_object('Object', Value=W_FloatNumber(0.0))
-    w_NumPrototype.Class = 'Number'
-    put_values(ctx, w_NumPrototype, {
-        'constructor': w_Number,
-        '__proto__': w_empty_fun,
-        'toString': W_NumberValueToString(),
-        'valueOf': get_value_of('Number')(),
-    })
-    _register_builtin_prototype('Number', w_NumPrototype)
+    import js.builtins_boolean as boolean_builtins
+    # 15.6.4.2
+    put_native_function(w_BooleanPrototype, 'toString', boolean_builtins.to_string)
 
-    put_values(ctx, w_Number, {
-        'constructor': w_FncPrototype,
-        'prototype': w_NumPrototype,
-        '__proto__': w_FncPrototype,
-        'length'   : W_IntNumber(1),
-    })
-    f = w_Number._get_property_flags('prototype') | READ_ONLY
-    w_Number._set_property_flags('prototype', f)
-    w_Number.Put('MAX_VALUE', W_FloatNumber(1.7976931348623157e308), flags = READ_ONLY | DONT_DELETE)
-    w_Number.Put('MIN_VALUE', W_FloatNumber(0), flags = READ_ONLY | DONT_DELETE)
-    w_Number.Put('NaN', W_FloatNumber(NAN), flags = READ_ONLY | DONT_DELETE)
-    # ^^^ this is exactly in test case suite
-    w_Number.Put('POSITIVE_INFINITY', W_FloatNumber(INFINITY), flags = READ_ONLY | DONT_DELETE)
-    w_Number.Put('NEGATIVE_INFINITY', W_FloatNumber(-INFINITY), flags = READ_ONLY | DONT_DELETE)
+    # 15.6.3.1
+    W_BooleanObject._prototype_ = w_BooleanPrototype
 
+    #put_values(w_BoolPrototype, {
+        #'constructor': w_FncPrototype,
+        #'__proto__': w_ObjPrototype,
+        #'toString': W_BooleanValueToString(),
+        #'valueOf': get_value_of('Boolean')(),
+    #})
 
+    # 15.7.2
+    from js.jsobj import W_NumberConstructor
+    w_Number = W_NumberConstructor(ctx)
     w_Global.Put('Number', w_Number)
 
+    # 15.7.4
+    from js.jsobj import W_NumericObject
+    w_NumberPrototype = W_NumericObject(0)
+    w_NumberPrototype._prototype_ = W__Object._prototype_
+
+    # 15.7.4.1
+    w_NumberPrototype.Put('constructor', w_NumberPrototype)
+
+    # 15.7.4.2
+    w_NumberPrototype.Put('toString', new_native_function(ctx, number_to_string, 'toString'))
+
+    # 15.7.3.1
+    w_Number.Put('prototype', w_NumberPrototype)
+    W_NumericObject._prototype_ = w_NumberPrototype
+
+    # 15.7.3.2
+    w_Number.Put('MAX_VALUE', _w(1.7976931348623157e308), flags = READ_ONLY | DONT_DELETE)
+
+    # 15.7.3.3
+    w_Number.Put('MIN_VALUE', _w(5e-320), flags = READ_ONLY | DONT_DELETE)
+
+    # 15.7.3.4
+    w_NAN = _w(NAN)
+    w_Number.Put('NaN', w_NAN, flags = READ_ONLY | DONT_DELETE)
+
+    # 15.7.3.5
+    w_POSITIVE_INFINITY = _w(INFINITY)
+    w_Number.Put('POSITIVE_INFINITY', w_POSITIVE_INFINITY, flags = READ_ONLY | DONT_DELETE)
+
+    # 15.7.3.6
+    w_NEGATIVE_INFINITY = _w(-INFINITY)
+    w_Number.Put('NEGATIVE_INFINITY', w_NEGATIVE_INFINITY, flags = READ_ONLY | DONT_DELETE)
 
     #String
-    w_String = W_StringObject('String', w_FncPrototype)
-
-    w_StrPrototype = create_object('Object', Value=W_String(''))
-    w_StrPrototype.Class = 'String'
-    w_StrPrototype.Put('length', W_IntNumber(0))
-
-    put_values(ctx, w_StrPrototype, {
-        'constructor': w_String,
-        '__proto__': w_StrPrototype,
-        'toString': W_StringValueToString(),
-        'valueOf': get_value_of('String')(),
-        'charAt': W_CharAt(),
-        'charCodeAt': W_CharCodeAt(),
-        'concat': W_Concat(),
-        'indexOf': W_IndexOf(),
-        'lastIndexOf': W_LastIndexOf(),
-        'substring': W_Substring(),
-        'split': W_Split(),
-        'toLowerCase': W_ToLowerCase(),
-        'toUpperCase': W_ToUpperCase()
-    })
-    _register_builtin_prototype('String', w_StrPrototype)
-
-    w_String.Put('prototype', w_StrPrototype, flags=allon)
-    w_String.Put('fromCharCode', W_FromCharCode())
+    # 15.5.1
+    from js.jsobj import W_StringConstructor
+    w_String = W_StringConstructor(ctx)
     w_Global.Put('String', w_String)
 
-    w_Array = W_ArrayObject('Array', w_FncPrototype)
+    # 15.5.4
+    from js.jsobj import W_StringObject
+    w_StringPrototype = W_StringObject('')
+    w_StringPrototype._prototype_ = W__Object._prototype_
 
-    w_ArrPrototype = W_Array(Prototype=w_ObjPrototype)
+    # 15.5.3.1
+    W_StringObject._prototype_ = w_StringPrototype
 
-    put_values(ctx, w_ArrPrototype, {
-        'constructor': w_FncPrototype,
-        '__proto__': w_ArrPrototype,
-        'toString': W_ArrayToString(),
-        'join': W_ArrayJoin(),
-        'reverse': W_ArrayReverse(),
-        'sort': W_ArraySort(),
-        'push': W_ArrayPush(),
-        'pop': W_ArrayPop(),
-    })
-    _register_builtin_prototype('Array', w_ArrPrototype)
+    # 15.5.4.1
+    w_StringPrototype.Put('constructor', w_String)
 
-    w_Array.Put('prototype', w_ArrPrototype, flags = allon)
-    w_Array.Put('__proto__', w_FncPrototype, flags = allon)
-    w_Array.Put('length', W_IntNumber(1), flags = allon)
+    import js.builtins_string as string_builtins
+    # 15.5.4.4
+    put_native_function(w_StringPrototype, 'charAt', string_builtins.char_at)
+
+
+    #put_values(w_StrPrototype, {
+        #'constructor': w_String,
+        #'__proto__': w_StrPrototype,
+        #'toString': W_StringValueToString(),
+        #'valueOf': get_value_of('String')(),
+        #'charAt': W_CharAt(),
+        #'charCodeAt': W_CharCodeAt(),
+        #'concat': W_Concat(),
+        #'indexOf': W_IndexOf(),
+        #'lastIndexOf': W_LastIndexOf(),
+        #'substring': W_Substring(),
+        #'split': W_Split(),
+        #'toLowerCase': W_ToLowerCase(),
+        #'toUpperCase': W_ToUpperCase()
+    #})
+    #_register_builtin_prototype('String', w_StrPrototype)
+
+    #w_String.Put('prototype', w_StrPrototype, flags=allon)
+    #w_String.Put('fromCharCode', W_FromCharCode())
+    #w_Global.Put('String', w_String)
+
+    from js.jsobj import W_ArrayConstructor, W__Array
+    w_Array = W_ArrayConstructor()
+
+    # 15.4.4
+    w_ArrayPrototype = W__Array()
+    w_ArrayPrototype._prototype_ = W__Object._prototype_
+
+    # 15.4.4.1
+    w_ArrayPrototype.Put('constructor', w_Array)
+
+    import js.builtins_array as array_builtins
+    # 15.4.4.2
+    put_native_function(w_ArrayPrototype, 'toString', array_builtins.to_string)
+    # 15.4.4.5
+    put_native_function(w_ArrayPrototype, 'join', array_builtins.join)
+    # 15.4.4.6
+    put_native_function(w_ArrayPrototype, 'pop', array_builtins.pop)
+    # 15.4.4.7
+    put_native_function(w_ArrayPrototype, 'push', array_builtins.push)
+
+    # 15.4.3.1
+    W__Array._prototype_ = w_ArrayPrototype
+
+    #put_values(w_ArrPrototype, {
+        #'constructor': w_FncPrototype,
+        #'__proto__': w_ArrPrototype,
+        #'toString': W_ArrayToString(),
+        #'join': W_ArrayJoin(),
+        #'reverse': W_ArrayReverse(),
+        #'sort': W_ArraySort(),
+        #'push': W_ArrayPush(),
+        #'pop': W_ArrayPop(),
+    #})
+
+    #w_Array._prototype_ = w_FunctionPrototype
+    #w_Array.Put('__proto__', w_FunctionPrototype, flags = allon)
+
+    #w_Array.Put('length', _w(1), flags = allon)
     w_Global.Put('Array', w_Array)
 
 
     #Math
-    w_math = W_Object(Class='Math')
-    w_Global.Put('Math', w_math)
-    w_math.Put('__proto__',  w_ObjPrototype)
-    w_math.Put('prototype', w_ObjPrototype, flags = allon)
-    w_math.Put('abs', W_Builtin(absjs, Class='function'))
-    w_math.Put('floor', W_Builtin(floorjs, Class='function'))
-    w_math.Put('round', W_Builtin(roundjs, Class='function'))
-    w_math.Put('pow', W_Builtin(powjs, Class='function'))
-    w_math.Put('sqrt', W_Builtin(sqrtjs, Class='function'))
-    w_math.Put('log', W_Builtin(logjs, Class='function'))
-    w_math.Put('E', W_FloatNumber(math.e), flags=allon)
-    w_math.Put('LN2', W_FloatNumber(math.log(2)), flags=allon)
-    w_math.Put('LN10', W_FloatNumber(math.log(10)), flags=allon)
-    log2e = math.log(math.e) / math.log(2) # rpython supports log with one argument only
-    w_math.Put('LOG2E', W_FloatNumber(log2e), flags=allon)
-    w_math.Put('LOG10E', W_FloatNumber(math.log10(math.e)), flags=allon)
-    w_math.Put('PI', W_FloatNumber(math.pi), flags=allon)
-    w_math.Put('SQRT1_2', W_FloatNumber(math.sqrt(0.5)), flags=allon)
-    w_math.Put('SQRT2', W_FloatNumber(math.sqrt(2)), flags=allon)
-    w_math.Put('random', W_Builtin(randomjs, Class='function'))
-    w_math.Put('min', W_Builtin(minjs, Class='function'))
-    w_math.Put('max', W_Builtin(maxjs, Class='function'))
-    w_Global.Put('version', W_Builtin(versionjs), flags=allon)
+    from js.jsobj import W_Math
+    # 15.8
+    w_Math = W_Math()
+    w_Global.Put('Math', w_Math)
 
-    #Date
-    w_Date = W_DateObject('Date', w_FncPrototype)
+    #w_math.Put('__proto__',  w_ObjPrototype)
 
-    w_DatePrototype = create_object('Object', Value=W_String(''))
-    w_DatePrototype.Class = 'Date'
+    import js.builtins_math as math_builtins
+    put_native_function(w_Math, 'abs', math_builtins.abs)
+    put_native_function(w_Math, 'floor', math_builtins.floor)
+    put_native_function(w_Math, 'random', math_builtins.random)
+    put_native_function(w_Math, 'min', math_builtins.min)
+    put_native_function(w_Math, 'max', math_builtins.max)
 
-    put_values(ctx, w_DatePrototype, {
-        '__proto__': w_DatePrototype,
-        'valueOf': get_value_of('Date')(),
-        'getTime': get_value_of('Date')()
-    })
-    _register_builtin_prototype('Date', w_DatePrototype)
+    #w_math.Put('round', W_Builtin(roundjs, Class='function'))
+    #w_math.Put('pow', W_Builtin(powjs, Class='function'))
+    #w_math.Put('sqrt', W_Builtin(sqrtjs, Class='function'))
+    #w_math.Put('log', W_Builtin(logjs, Class='function'))
+    #w_math.Put('E', W_FloatNumber(math.e), flags=allon)
+    #w_math.Put('LN2', W_FloatNumber(math.log(2)), flags=allon)
+    #w_math.Put('LN10', W_FloatNumber(math.log(10)), flags=allon)
+    #log2e = math.log(math.e) / math.log(2) # rpython supports log with one argument only
+    #w_math.Put('LOG2E', W_FloatNumber(log2e), flags=allon)
+    #w_math.Put('LOG10E', W_FloatNumber(math.log10(math.e)), flags=allon)
+    #w_math.Put('PI', W_FloatNumber(math.pi), flags=allon)
+    #w_math.Put('SQRT1_2', W_FloatNumber(math.sqrt(0.5)), flags=allon)
+    #w_math.Put('SQRT2', W_FloatNumber(math.sqrt(2)), flags=allon)
+    #w_math.Put('random', W_Builtin(randomjs, Class='function'))
+    #w_math.Put('min', W_Builtin(minjs, Class='function'))
+    #w_math.Put('max', W_Builtin(maxjs, Class='function'))
+    #w_Global.Put('version', W_Builtin(versionjs), flags=allon)
 
-    w_Date.Put('prototype', w_DatePrototype, flags=allon)
+    ##Date
+    #w_Date = W_DateObject('Date', w_FncPrototype)
 
-    w_Global.Put('Date', w_Date)
+    #w_DatePrototype = create_object('Object', Value=W_String(''))
+    #w_DatePrototype.Class = 'Date'
 
-    w_Global.Put('NaN', W_FloatNumber(NAN), flags = DONT_ENUM | DONT_DELETE)
-    w_Global.Put('Infinity', W_FloatNumber(INFINITY), flags = DONT_ENUM | DONT_DELETE)
+    #put_values(w_DatePrototype, {
+        #'__proto__': w_DatePrototype,
+        #'valueOf': get_value_of('Date')(),
+        #'getTime': get_value_of('Date')()
+    #})
+    #_register_builtin_prototype('Date', w_DatePrototype)
+
+    #w_Date.Put('prototype', w_DatePrototype, flags=allon)
+    #w_Global.Put('Date', w_Date)
+
+    # 15.1.1.1
+    w_Global.Put('NaN', w_NAN, flags = DONT_ENUM | DONT_DELETE)
+
+    # 15.1.1.2
+    w_Global.Put('Infinity', w_POSITIVE_INFINITY, flags = DONT_ENUM | DONT_DELETE)
+
+    # 15.1.1.3
     w_Global.Put('undefined', w_Undefined, flags = DONT_ENUM | DONT_DELETE)
-    w_Global.Put('eval', W_Eval(ctx))
-    w_Global.Put('parseInt', W_ParseInt())
-    w_Global.Put('parseFloat', W_ParseFloat())
-    w_Global.Put('isNaN', W_Builtin(isnanjs))
-    w_Global.Put('isFinite', W_Builtin(isfinitejs))
-    w_Global.Put('print', W_Builtin(printjs))
-    w_Global.Put('alert', W_Builtin(noop))
-    w_Global.Put('unescape', W_Builtin(unescapejs))
+
+    # 15.1.2.1
+    w_Global.Put('eval', W__Eval(ctx))
+
+    #w_Global.Put('parseInt', W_ParseInt())
+    #w_Global.Put('parseFloat', W_ParseFloat())
+    #w_Global.Put('isFinite', W_Builtin(isfinitejs))
+
+    w_Global.Put('isNaN',new_native_function(ctx, isnanjs))
+    w_Global.Put('print', new_native_function(ctx, printjs))
+
+    #w_Global.Put('alert', W_Builtin(noop))
+    #w_Global.Put('unescape', W_Builtin(unescapejs))
 
     w_Global.Put('this', w_Global)
 
-    # debugging
+    ## debugging
     if not we_are_translated():
-        w_Global.Put('pypy_repr', W_Builtin(pypy_repr))
+        put_native_function(w_Global, 'pypy_repr', pypy_repr)
 
-    w_Global.Put('load', W_Builtin(make_loadjs(interp)))
+    put_native_function(w_Global, 'load', make_loadjs(interp))
+    #w_Global.Put('load', W_Builtin(make_loadjs(interp)))
 
-    return (ctx, w_Global, w_Object)
+    #return (ctx, w_Global, w_Object)
+    return (ctx, w_Global, None)
diff --git a/js/builtins_array.py b/js/builtins_array.py
new file mode 100644
--- /dev/null
+++ b/js/builtins_array.py
@@ -0,0 +1,148 @@
+from js.jsobj import isnull_or_undefined, _w
+
+# 15.4.4.7
+def push(this, *args):
+    from collections import deque
+    o = this.ToObject()
+    lenVal = o.Get('length')
+    n = lenVal.ToUInt32()
+    items = deque(args)
+
+    while(items):
+        e = items.popleft()
+        o.Put(str(n), e)
+        n = n + 1
+
+    o.set_length(n)
+
+    return o
+
+# 15.4.4.2
+def to_string(this, *args):
+    array = this.ToObject()
+    func = array.Get('join')
+    if func.IsCallable():
+        return func.Call([], this = this)
+    else:
+        return object_to_string(this)
+
+# 15.4.4.5
+def join(this, *args):
+    o = this.ToObject()
+    lenVal = o.Get('length')
+    length = lenVal.ToUInt32()
+
+    sep = ','
+    if (len(args) > 0):
+        sep = args[0].ToString()
+
+    if length == 0:
+        return ''
+
+    element0 = o.Get('0')
+    if isnull_or_undefined(element0):
+        return ''
+
+    r = element0.ToString()
+
+    k = 1
+
+    while(k < length):
+        s = r + sep
+        element = o.Get(str(k))
+        if isnull_or_undefined(element):
+            n = ''
+        else:
+            n = element.ToString()
+        r = s + n
+        k = k + 1
+
+    return r
+
+# 15.4.4.6
+def pop(this, *args):
+    o = this.ToObject()
+    lenVal = o.Get('length')
+    l = lenVal.ToUInt32()
+
+    if l == 0:
+        o.Put('length', _w(0))
+        return w_Undefined
+    else:
+        indx = l - 1
+        indxs = str(indx)
+        element = o.Get(indxs)
+        o.Delete(indxs)
+        o.Put('length', _w(indx))
+        return element
+
+#class W_ArrayReverse(W_NewBuiltin):
+    #length = 0
+    #def Call(self, args=[], this=None):
+        #r2 = this.Get('length').ToUInt32()
+        #k = r_uint(0)
+        #r3 = r_uint(math.floor( float(r2)/2.0 ))
+        #if r3 == k:
+            #return this
+
+        #while k < r3:
+            #r6 = r2 - k - 1
+            #r7 = str(k)
+            #r8 = str(r6)
+
+            #r9 = this.Get(r7)
+            #r10 = this.Get(r8)
+
+            #this.Put(r7, r10)
+            #this.Put(r8, r9)
+            #k += 1
+
+        #return this
+
+#class W_ArraySort(W_NewBuiltin):
+    #length = 1
+    ##XXX: further optimize this function
+    #def Call(self, args=[], this=None):
+        #length = this.Get('length').ToUInt32()
+
+        ## According to ECMA-262 15.4.4.11, non-existing properties always come after
+        ## existing values. Undefined is always greater than any other value.
+        ## So we create a list of non-undefined values, sort them, and append undefined again.
+        #values = []
+        #undefs = r_uint(0)
+
+        #for i in range(length):
+            #P = str(i)
+            #if not this.HasProperty(P):
+                ## non existing property
+                #continue
+            #obj = this.Get(str(i))
+            #if obj is w_Undefined:
+                #undefs += 1
+                #continue
+            #values.append(obj)
+
+        ## sort all values
+        #if len(args) > 0 and args[0] is not w_Undefined:
+            #sorter = Sorter(values, compare_fn=args[0])
+        #else:
+            #sorter = Sorter(values)
+        #sorter.sort()
+
+        ## put sorted values back
+        #values = sorter.list
+        #for i in range(len(values)):
+            #this.Put(str(i), values[i])
+
+        ## append undefined values
+        #newlength = len(values)
+        #while undefs > 0:
+            #undefs -= 1
+            #this.Put(str(newlength), w_Undefined)
+            #newlength += 1
+
+        ## delete non-existing elements on the end
+        #while length > newlength:
+            #this.Delete(str(newlength))
+            #newlength += 1
+        #return this
diff --git a/js/builtins_boolean.py b/js/builtins_boolean.py
new file mode 100644
--- /dev/null
+++ b/js/builtins_boolean.py
@@ -0,0 +1,4 @@
+# 15.6.4.2
+def to_string(this, *args):
+    # TODO throw type error
+    return this.ToString()
diff --git a/js/builtins_function.py b/js/builtins_function.py
new file mode 100644
--- /dev/null
+++ b/js/builtins_function.py
@@ -0,0 +1,6 @@
+def to_string(this, *args):
+    return this.ToString()
+
+def empty(this, *args):
+    from js.jsobj import w_Undefined
+    return w_Undefined
diff --git a/js/builtins_math.py b/js/builtins_math.py
new file mode 100644
--- /dev/null
+++ b/js/builtins_math.py
@@ -0,0 +1,56 @@
+import math
+from js.jsobj import W_IntNumber
+
+from pypy.rlib.rfloat import NAN, INFINITY, isnan, isinf
+
+def floor(this, *args):
+    if len(args) < 1:
+        return NAN
+
+    val = args[0].ToNumber()
+
+    pos = math.floor(val)
+    if isnan(val):
+        pos = INFINITY
+
+    return pos
+
+def abs(this, *args):
+    val = args[0]
+    if isinstance(val, W_IntNumber):
+        if val.ToInteger() > 0:
+            return val # fast path
+        return -val.ToInteger()
+    return abs(args[0].ToNumber())
+
+def rounds(args, this):
+    return floorjs(args, this)
+
+def pow(args, this):
+    return math.pow(args[0].ToNumber(), args[1].ToNumber())
+
+def sqrt(args, this):
+    return math.sqrt(args[0].ToNumber())
+
+def log(args, this):
+    return math.log(args[0].ToNumber())
+
+py_min = min
+def min(this, *args):
+    a = args[0].ToNumber()
+    b = args[1].ToNumber()
+    return py_min(a, b)
+
+py_max = max
+def max(this, *args):
+    a = args[0].ToNumber()
+    b = args[1].ToNumber()
+    return py_max(a, b)
+
+import time
+from pypy.rlib import rrandom
+_random = rrandom.Random(int(time.time()))
+
+def random(this, *args):
+    return _random.random()
+
diff --git a/js/builtins_object.py b/js/builtins_object.py
new file mode 100644
--- /dev/null
+++ b/js/builtins_object.py
@@ -0,0 +1,5 @@
+def to_string(this, *args):
+    return "[object %s]" % (this.Class(), )
+
+def value_of(this, *args):
+    return this
diff --git a/js/builtins_string.py b/js/builtins_string.py
new file mode 100644
--- /dev/null
+++ b/js/builtins_string.py
@@ -0,0 +1,9 @@
+def char_at(this, *args):
+    string = this.ToString()
+    if len(args)>=1:
+        pos = args[0].ToInt32()
+        if (not pos >=0) or (pos > len(string) - 1):
+            return ''
+    else:
+        return ''
+    return string[pos]
diff --git a/js/interpreter.py b/js/interpreter.py
--- a/js/interpreter.py
+++ b/js/interpreter.py
@@ -27,6 +27,6 @@
             self._code = bytecode
         func = bytecode.make_js_function()
         if interactive:
-            return func.run(self.global_context)
+            return func._run_with_context(self.global_context)
         else:
-            func.run(self.global_context)
+            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
@@ -12,6 +12,8 @@
                      w_Undefined, W_Boolean
 from pypy.rlib.streamio import open_file_as_stream
 
+sys.setrecursionlimit(100)
+
 import code
 sys.ps1 = 'js> '
 sys.ps2 = '... '
@@ -33,18 +35,18 @@
 
 DEBUG = False
 
-def debugjs(ctx, args, this):
+def debugjs(this, *args):
     global DEBUG
     DEBUG = not DEBUG
     return W_Boolean(DEBUG)
 
-def tracejs(ctx, args, this):
+def tracejs(this, *args):
     arguments = args
     import pdb
     pdb.set_trace()
     return w_Undefined
 
-def quitjs(ctx, args, this):
+def quitjs(this, *args):
     sys.exit(0)
 
 class JSInterpreter(code.InteractiveConsole):
@@ -52,9 +54,10 @@
         code.InteractiveConsole.__init__(self, locals, filename)
         self.interpreter = Interpreter()
         ctx = self.interpreter.global_context
-        self.interpreter.w_Global.Put('quit', W_Builtin(quitjs))
-        self.interpreter.w_Global.Put('trace', W_Builtin(tracejs))
-        self.interpreter.w_Global.Put('debug', W_Builtin(debugjs))
+        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)
@@ -75,9 +78,9 @@
                 try:
                     if DEBUG:
                         print repr(res)
-                    print res.ToString(self.interpreter.w_Global)
+                    print res.ToString()
                 except ThrowException, exc:
-                    print exc.exception.ToString(self.interpreter.w_Global)
+                    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
@@ -3,8 +3,8 @@
 from pypy.rlib.jit import JitDriver, purefunction
 
 from js.execution import JsTypeError, ReturnException, ThrowException
-from js.opcodes import opcodes, POP, LABEL, BaseJump, WITH_START, WITH_END
-from js.jsobj import W_Root, W_String
+from js.opcodes import opcodes, LABEL, BaseJump, WITH_START, WITH_END
+from js.jsobj import W_Root, W_String, _w
 
 from pypy.rlib import jit, debug
 
@@ -111,17 +111,26 @@
         return self.emit('LOAD_INTCONSTANT', i)
 
     def unpop(self):
+        from js.opcodes import POP
         if self.opcodes and isinstance(self.opcodes[-1], POP):
             self.opcodes.pop()
             return True
         else:
             return False
 
+    def returns(self):
+        from js.opcodes import RETURN
+        if self.opcodes and isinstance(self.opcodes[-1], RETURN):
+            return True
+        return False
+
     def unpop_or_undefined(self):
         if not self.unpop():
             self.emit('LOAD_UNDEFINED')
+        #elif not self.returns():
+            #self.emit('LOAD_UNDEFINED')
 
-    def make_js_function(self, name='__dont_care__', params=None):
+    def make_js_function(self, name='__dont_care__', params=[]):
         self.unpop_or_undefined()
 
         if self.has_labels:
@@ -129,6 +138,9 @@
 
         return JsFunction(name, params, self)
 
+    def ToJsFunction(self, name='__dont_care__', params=[]):
+        return self.make_js_function(name, params)
+
     def remove_labels(self):
         """ Basic optimization to remove all labels and change
         jumps to addresses. Necessary to run code at all
@@ -166,43 +178,112 @@
     ctx.stack_pointer = old_stack_pointer
     ctx.stack = old_stack
 
-class JsFunction(object):
+class Js__Function(object):
+    name = 'anonymous'
+    code = ''
+    params = []
+
+    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
+    def f(this, args):
+        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._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()
+        return self._code_.estimated_stack_size()
 
     def local_variables(self):
         if self.scope:
             return self.scope.local_variables
 
-    def run(self, ctx, check_stack=True, save_stack=True):
+    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:
-            r = self.run_bytecode(ctx, check_stack)
-            return r
+            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 _get_opcode(self, pc):
-        assert pc >= 0
-        return self.opcodes[pc]
-
-    def run_block(self, ctx, pc=0):
+    def _run_bytecode(self, ctx, pc=0):
         while True:
             jitdriver.jit_merge_point(pc=pc, self=self, ctx=ctx)
             if pc >= len(self.opcodes):
@@ -234,15 +315,8 @@
                 pc += 1
 
             if isinstance(opcode, WITH_START):
-                pc = self.run_block(opcode.newctx, pc)
+                pc = self._run_bytecode(opcode.newctx, pc)
             elif isinstance(opcode, WITH_END):
                 break
 
         return pc
-
-    def run_bytecode(self, ctx, check_stack=True):
-        self.run_block(ctx)
-        if check_stack:
-            ctx.check_stack()
-
-        return ctx.top()
diff --git a/js/jsobj.py b/js/jsobj.py
--- a/js/jsobj.py
+++ b/js/jsobj.py
@@ -37,7 +37,7 @@
     def ToBoolean(self):
         return False
 
-    def ToPrimitive(self, hint=""):
+    def ToPrimitive(self, hint = None):
         return self
 
     def ToString(self):
@@ -174,6 +174,344 @@
             pass
         return True
 
+class W_BasicObject(W__Root):
+    _immutable_fields_ = ['_class_', '_prototype_', '_primitive_value_']
+    _type_ = 'object'
+    _class_ = 'Object'
+    _prototype_ = w_Undefined
+
+    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)
+
+    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())
+
+    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):
+        return self._prototype_
+
+    def Class(self):
+        return self._class_
+
+    def ToBoolean(self):
+        return True
+
+    def ToNumber(self):
+        return self.ToPrimitive('Number').ToNumber()
+
+    def ToString(self):
+        return self.ToPrimitive('String').ToString()
+
+    def ToPrimitive(self, hint = None):
+        return self.DefaultValue(hint)
+
+    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
+            # TODO: this is only for compability
+            if isinstance(p, W_PrimitiveObject):
+                res = p.Call(this = self)
+                if isinstance(res, W_Root):
+                    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
+
+    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)
+
+    def Put(self, P, V, flags = 0):
+        # 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
+
+        if not self.CanPut(P): 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)
+        self._primitive_value_ = _w(primitive_value)
+
+    def PrimitiveValue(self):
+        return self._primitive_value_
+
+    def ToString(self):
+        return self.PrimitiveValue().ToString()
+
+class W_BooleanObject(W__PrimitiveObject):
+    _class_ = 'Boolean'
+
+    def ToString(self):
+        return self.PrimitiveValue().ToString()
+
+class W_NumericObject(W__PrimitiveObject):
+    _class_ = 'Number'
+
+class W_StringObject(W__PrimitiveObject):
+    _class_ = 'String'
+
+class W__Object(W_BasicObject):
+    def ToString(self):
+        try:
+            res = self.ToPrimitive('String')
+        except JsTypeError:
+            return "[object %s]" % (self.Class() ,)
+        return res.ToString()
+
+class W_ObjectConstructor(W_BasicObject):
+    def __init__(self):
+        W_BasicObject.__init__(self)
+
+    def ToString(self):
+        return "function Object() { [native code] }"
+
+    def IsCallable(self):
+        return True
+
+    def Call(self, args=[], this=None):
+        return self.Construct(args)
+
+    def Construct(self, args=[]):
+        if len(args) >= 1 and not isnull_or_undefined(args[0]):
+            return args[0].ToObject()
+
+        obj = W__Object()
+        return obj
+
+class W_BasicFunction(W_BasicObject):
+    _class_ = 'Function'
+    _type_ = 'function'
+    _immutable_fields_ = ['_context_']
+
+    def __init__(self, context):
+        W_BasicObject.__init__(self)
+        self._context_ = context
+
+    def Call(self, args=[], this=None):
+        raise NotImplementedError(self.__class__)
+
+    # 13.2.2
+    def Construct(self, args=[]):
+        obj = W__Object()
+        proto = self.Get('prototype')
+        if isinstance(proto, W_BasicObject) or isinstance(proto, W_PrimitiveObject):
+            obj._prototype_ = proto
+        else:
+            # would love to test this
+            # but I fail to find a case that falls into this
+            obj._prototype_ = W__Object._prototype_
+
+
+        try: #this is a hack to be compatible to spidermonkey
+            self.Call(args, this=obj)
+        except ReturnException, e:
+            result = e.value
+            if isinstance(result, W_BasicObject) or isinstance(result, W_PrimitiveObject):
+                return result
+        return obj
+
+    def IsCallable(self):
+        return True
+
+class W_FunctionConstructor(W_BasicFunction):
+    def __init__(self, ctx):
+        W_BasicFunction.__init__(self, ctx)
+
+    def ToString(self):
+        return "function Function() { [native code] }"
+
+    def Call(self, args=[], this=None):
+        from js.jsparser import parse
+        from js.jscode import JsCode
+        from js.astbuilder import make_ast_builder
+
+        # 15.3.2.1
+        functioncode = "function () { }"
+        tam = len(args)
+        if tam >= 1:
+            fbody  = args[tam-1].ToString()
+            argslist = []
+            for i in range(tam-1):
+                argslist.append(args[i].ToString())
+            fargs = ','.join(argslist)
+            functioncode = "return function (%s) {%s}"%(fargs, fbody)
+        #remove program and sourcelements node
+        funcnode = parse(functioncode).children[0].children[0]
+        builder = make_ast_builder()
+        ast = builder.dispatch(funcnode)
+        bytecode = JsCode()
+        ast.emit(bytecode)
+        func = bytecode.make_js_function()
+        func2 = func.run(self._context_)
+        return func2
+
+    # TODO
+    def Construct(self, args=[]):
+        return self.Call(args, this=None)
+
+# 15.7.2
+class W_NumberConstructor(W_BasicFunction):
+    # 15.7.1.1
+    def Call(self, args=[], this=None):
+        if len(args) >= 1 and not isnull_or_undefined(args[0]):
+            return _w(args[0].ToNumber())
+        elif len(args) >= 1 and args[0] is w_Undefined:
+            return _w(NAN)
+        else:
+            return _w(0.0)
+
+    # 15.7.2.1
+    def Construct(self, args=[]):
+        return self.Call(args).ToObject()
+
+# 15.5.2
+class W_StringConstructor(W_BasicFunction):
+    def Call(self, args=[], this=None):
+        assert False
+        return w_Undefined
+
+    def Construct(self, args=[]):
+        return self.Call(args).ToObject()
+
+# 15.6.2
+class W_BooleanConstructor(W_BasicFunction):
+    def Call(self, args=[], this=None):
+        if len(args) >= 1 and not isnull_or_undefined(args[0]):
+            return _w(args[0].ToBoolean())
+        else:
+            return _w(False)
+
+    def Construct(self, args=[]):
+        return self.Call(args).ToObject()
+
+class W__Function(W_BasicFunction):
+    _immutable_fields_ = ['_function_']
+
+    def __init__(self, context, function):
+        W_BasicFunction.__init__(self, context)
+        self._function_ = function
+
+    def Call(self, args=[], this=None):
+        result = self._function_.run(self._context_, args, this)
+        return result
+
+    def ToString(self):
+        return self._function_.ToString()
+
 class W_PrimitiveObject(W_Root):
     _immutable_fields_ = ['Class', 'Prototype', 'Scope', 'Value']
     def __init__(self, Prototype=None, Class='Object', Value=w_Undefined):
@@ -437,11 +775,29 @@
     def __repr__(self):
         return str(self.property_map)
 
-class W_Array(W_ListObject):
-    def __init__(self, Prototype=None, Class='Array', Value=w_Undefined):
-        W_ListObject.__init__(self, Prototype, Class, Value)
-        self.Put('length', W_IntNumber(0), flags = DONT_DELETE)
-        self.length = r_uint(0)
+class W_ArrayConstructor(W_BasicObject):
+    def IsCallable(self):
+        return True
+
+    def Call(self, args=[], this=None):
+        if len(args) == 1 and isinstance(args[0], W_Number):
+            array = W__Array()
+        else:
+            array = W__Array()
+            for index, obj in enumerate(args):
+                array.Put(str(index), obj)
+        return array
+
+    def Construct(self, args=[]):
+        return self.Call(args)
+
+class W__Array(W_BasicObject):
+    _class_ = 'Array'
+    length = r_uint(0)
+
+    def __init__(self):
+        W_BasicObject.__init__(self)
+        self.Put('length', _w(0), flags = DONT_DELETE)
 
     def set_length(self, newlength):
         if newlength < self.length:
@@ -452,8 +808,8 @@
                     self._delete_property(key)
                 i += 1
 
-        self.length = newlength
-        self._set_property_value('length', W_FloatNumber(newlength))
+        self.length = int(newlength)
+        self._set_property_value('length', _w(self.length))
 
     def Put(self, P, V, flags = 0):
         if not self.CanPut(P): return
@@ -482,6 +838,10 @@
                 raise RangeError()
             self.set_length(arrayindex+1)
 
+# 15.8
+class W_Math(W__Object):
+    _class_ = 'Math'
+
 class W_Boolean(W__Primitive):
     _immutable_fields_ = ['_boolval_']
     _type_ = 'boolean'
@@ -494,8 +854,7 @@
         return 'W_Bool(%s)' % (str(self._boolval_), )
 
     def ToObject(self):
-        # TODO
-        return create_object('Boolean', Value=self)
+        return W_BooleanObject(self)
 
     def ToString(self):
         if self._boolval_ == True:
@@ -522,10 +881,7 @@
         return 'W_String(%s)' % (repr(self._strval_),)
 
     def ToObject(self):
-        # TODO
-        o = create_object('String', Value=self)
-        o.Put('length', W_IntNumber(len(self._strval_)), flags = READ_ONLY | DONT_DELETE | DONT_ENUM)
-        return o
+        return W_StringObject(self)
 
     def ToString(self):
         return self._strval_
@@ -556,9 +912,9 @@
     """
     _type_ = 'number'
 
+    # 9.9
     def ToObject(self):
-        # TODO
-        return create_object('Number', Value=self)
+        return W_NumericObject(self)
 
     def ToBoolean(self):
         num = self.ToNumber()
@@ -672,10 +1028,13 @@
     #proto = ctx.get_global().Get(prototypename).Get('prototype')
     from js.builtins import get_builtin_prototype
     proto = get_builtin_prototype(prototypename)
+    obj = W__Object()
     # TODO get Object prototype from interp.w_Object
-    assert isinstance(proto, W_PrimitiveObject)
-    obj = W_Object(Prototype=proto, Class = proto.Class, Value = Value)
-    obj.Put('__proto__', proto, DONT_ENUM | DONT_DELETE | READ_ONLY)
+    #if isinstance(proto, W_PrimitiveObject):
+    #    obj = W_Object(Prototype=proto, Class = proto.Class, Value = Value)
+    #elif isinstance(proto, W_BasicObject):
+    #    obj = W_Object(Prototype=proto, Class = proto.Class(), Value = Value)
+    #obj.Put('__proto__', proto, DONT_ENUM | DONT_DELETE | READ_ONLY)
     return obj
 
 def isnull_or_undefined(obj):
@@ -714,3 +1073,18 @@
     if val:
         return w_True
     return w_False
+
+def _w(value):
+    if isinstance(value, W___Root):
+        return value
+    elif isinstance(value, bool):
+        return newbool(value)
+    elif isinstance(value, int):
+        return W_IntNumber(value)
+    elif isinstance(value, float):
+        return W_FloatNumber(value)
+    elif isinstance(value, str):
+        return W_String(value)
+    elif value is None:
+        return w_Null
+    raise TypeError(value)
diff --git a/js/opcodes.py b/js/opcodes.py
--- a/js/opcodes.py
+++ b/js/opcodes.py
@@ -1,7 +1,7 @@
 from js.jsobj import W_IntNumber, W_FloatNumber, W_String,\
-     W_Array, W_PrimitiveObject, ActivationObject,\
+     W_PrimitiveObject, ActivationObject,\
      create_object, W_Object, w_Undefined, newbool,\
-     w_True, w_False, W_List, w_Null, W_Iterator, W_Root, W_CallableObject
+     w_True, w_False, W_List, w_Null, W_Iterator, W_Root, W__Function
 import js.jsobj as jsobj
 from js.execution import JsTypeError, ReturnException, ThrowException
 from js.baseop import plus, sub, compare, AbstractEC, StrictEC,\
@@ -122,11 +122,12 @@
         self.counter = counter
 
     def eval(self, ctx):
-        proto = ctx.get_global().Get('Array').Get('prototype')
+        #proto = ctx.get_global().Get('Array').Get('prototype')
         # TODO get array prototype?
         # builtins make_array??
-        assert isinstance(proto, W_PrimitiveObject)
-        array = W_Array(Prototype=proto, Class = proto.Class)
+        #assert isinstance(proto, W_PrimitiveObject)
+        from js.jsobj import W__Array
+        array = W__Array()
         for i in range(self.counter):
             array.Put(str(self.counter - i - 1), ctx.pop())
         ctx.append(array)
@@ -158,13 +159,14 @@
 
     def eval(self, ctx):
         #proto = ctx.get_global().Get('Function').Get('prototype')
-        from js.builtins import get_builtin_prototype
-        proto = get_builtin_prototype('Function')
-        w_func = W_CallableObject(ctx, proto, self.funcobj)
-        w_func.Put('length', W_IntNumber(len(self.funcobj.params)))
-        w_obj = create_object('Object')
-        w_obj.Put('constructor', w_func, flags = jsobj.DONT_ENUM)
-        w_func.Put('prototype', w_obj)
+        #from js.builtins import get_builtin_prototype
+        #proto = get_builtin_prototype('Function')
+        w_func = W__Function(ctx, self.funcobj)


More information about the pypy-commit mailing list