[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