from __future__ import unicode_literals
import re
import datetime
from . desc import *
from . simplex import *
from . conversions import *
from pyjsparser import PyJsParser
import six
if six . PY2 :
from itertools import izip
else :
izip = zip
def Type ( obj ) :
return obj . TYPE
# 8.6.2
class PyJs ( object ) :
TYPE = ' Object '
IS_CONSTRUCTOR = False
prototype = None
Class = None
extensible = True
value = None
own = { }
def get_member ( self , unconverted_prop ) :
return self . get ( to_string ( unconverted_prop ) )
def put_member ( self , unconverted_prop , val ) :
return self . put ( to_string ( unconverted_prop ) , val )
def get ( self , prop ) :
assert type ( prop ) == unicode
cand = self . get_property ( prop )
if cand is None :
return undefined
if is_data_descriptor ( cand ) :
return cand [ ' value ' ]
if is_undefined ( cand [ ' get ' ] ) :
return undefined
return cand [ ' get ' ] . call ( self )
def get_own_property ( self , prop ) :
assert type ( prop ) == unicode
# takes py returns py
return self . own . get ( prop )
def get_property ( self , prop ) :
assert type ( prop ) == unicode
# take py returns py
cand = self . get_own_property ( prop )
if cand :
return cand
if self . prototype is not None :
return self . prototype . get_property ( prop )
def put ( self , prop , val , throw = False ) :
assert type ( prop ) == unicode
# takes py, returns none
if not self . can_put ( prop ) :
if throw :
raise MakeError ( ' TypeError ' , ' Could not define own property ' )
return
own_desc = self . get_own_property ( prop )
if is_data_descriptor ( own_desc ) :
self . own [ prop ] [ ' value ' ] = val
return
desc = self . get_property ( prop )
if is_accessor_descriptor ( desc ) :
desc [ ' set ' ] . call (
self , ( val , ) ) # calling setter on own or inherited element
else : # new property
self . own [ prop ] = {
' value ' : val ,
' writable ' : True ,
' configurable ' : True ,
' enumerable ' : True
}
def can_put ( self , prop ) : # to check
assert type ( prop ) == unicode , type ( prop )
# takes py returns py
desc = self . get_own_property ( prop )
if desc : # if we have this property
if is_accessor_descriptor ( desc ) :
return is_callable (
desc [ ' set ' ] ) # Check if setter method is defined
else : # data desc
return desc [ ' writable ' ]
if self . prototype is None :
return self . extensible
inherited = self . prototype . get_property ( prop )
if inherited is None :
return self . extensible
if is_accessor_descriptor ( inherited ) :
return not is_undefined ( inherited [ ' set ' ] )
elif self . extensible :
return inherited [ ' writable ' ] # weird...
return False
def has_property ( self , prop ) :
assert type ( prop ) == unicode
# takes py returns Py
return self . get_property ( prop ) is not None
def delete ( self , prop , throw = False ) :
assert type ( prop ) == unicode
# takes py, returns py
desc = self . get_own_property ( prop )
if desc is None :
return True
if desc [ ' configurable ' ] :
del self . own [ prop ]
return True
if throw :
raise MakeError ( ' TypeError ' , ' Could not define own property ' )
return False
def default_value ( self , hint = None ) :
order = ( ' valueOf ' , ' toString ' )
if hint == ' String ' or ( hint is None and self . Class == ' Date ' ) :
order = ( ' toString ' , ' valueOf ' )
for meth_name in order :
method = self . get ( meth_name )
if method is not None and is_callable ( method ) :
cand = method . call ( self , ( ) )
if is_primitive ( cand ) :
return cand
raise MakeError ( ' TypeError ' ,
' Cannot convert object to primitive value ' )
def define_own_property (
self , prop , desc ,
throw ) : # Internal use only. External through Object
assert type ( prop ) == unicode
# takes Py, returns Py
# prop must be a Py string. Desc is either a descriptor or accessor.
# Messy method - raw translation from Ecma spec to prevent any bugs. # todo check this
current = self . get_own_property ( prop )
extensible = self . extensible
if not current : # We are creating a new OWN property
if not extensible :
if throw :
raise MakeError ( ' TypeError ' ,
' Could not define own property ' )
return False
# extensible must be True
if is_data_descriptor ( desc ) or is_generic_descriptor ( desc ) :
DEFAULT_DATA_DESC = {
' value ' : undefined , # undefined
' writable ' : False ,
' enumerable ' : False ,
' configurable ' : False
}
DEFAULT_DATA_DESC . update ( desc )
self . own [ prop ] = DEFAULT_DATA_DESC
else :
DEFAULT_ACCESSOR_DESC = {
' get ' : undefined , # undefined
' set ' : undefined , # undefined
' enumerable ' : False ,
' configurable ' : False
}
DEFAULT_ACCESSOR_DESC . update ( desc )
self . own [ prop ] = DEFAULT_ACCESSOR_DESC
return True
# therefore current exists!
if not desc or desc == current : # We don't need to change anything.
return True
configurable = current [ ' configurable ' ]
if not configurable : # Prevent changing params
if desc . get ( ' configurable ' ) :
if throw :
raise MakeError ( ' TypeError ' ,
' Could not define own property ' )
return False
if ' enumerable ' in desc and desc [ ' enumerable ' ] != current [
' enumerable ' ] :
if throw :
raise MakeError ( ' TypeError ' ,
' Could not define own property ' )
return False
if is_generic_descriptor ( desc ) :
pass
elif is_data_descriptor ( current ) != is_data_descriptor ( desc ) :
# we want to change the current type of property
if not configurable :
if throw :
raise MakeError ( ' TypeError ' ,
' Could not define own property ' )
return False
if is_data_descriptor ( current ) : # from data to setter
del current [ ' value ' ]
del current [ ' writable ' ]
current [ ' set ' ] = undefined # undefined
current [ ' get ' ] = undefined # undefined
else : # from setter to data
del current [ ' set ' ]
del current [ ' get ' ]
current [ ' value ' ] = undefined # undefined
current [ ' writable ' ] = False
elif is_data_descriptor ( current ) and is_data_descriptor ( desc ) :
if not configurable :
if not current [ ' writable ' ] and desc . get ( ' writable ' ) :
if throw :
raise MakeError ( ' TypeError ' ,
' Could not define own property ' )
return False
if not current [ ' writable ' ] and ' value ' in desc and current [
' value ' ] != desc [ ' value ' ] :
if throw :
raise MakeError ( ' TypeError ' ,
' Could not define own property ' )
return False
elif is_accessor_descriptor ( current ) and is_accessor_descriptor ( desc ) :
if not configurable :
if ' set ' in desc and desc [ ' set ' ] != current [ ' set ' ] :
if throw :
raise MakeError ( ' TypeError ' ,
' Could not define own property ' )
return False
if ' get ' in desc and desc [ ' get ' ] != current [ ' get ' ] :
if throw :
raise MakeError ( ' TypeError ' ,
' Could not define own property ' )
return False
current . update ( desc )
return True
def create ( self , args , space ) :
''' Generally not a constructor, raise an error '''
raise MakeError ( ' TypeError ' , ' %s is not a constructor ' % self . Class )
def get_member (
self , prop , space
) : # general member getter, prop has to be unconverted prop. it is it can be any value
typ = type ( self )
if typ not in PRIMITIVES : # most likely getter for object
return self . get_member (
prop
) # <- object can implement this to support faster prop getting. ex array.
elif typ == unicode : # then probably a String
if type ( prop ) == float and is_finite ( prop ) :
index = int ( prop )
if index == prop and 0 < = index < len ( self ) :
return self [ index ]
s_prop = to_string ( prop )
if s_prop == ' length ' :
return float ( len ( self ) )
elif s_prop . isdigit ( ) :
index = int ( s_prop )
if 0 < = index < len ( self ) :
return self [ index ]
# use standard string prototype
return space . StringPrototype . get ( s_prop )
# maybe an index
elif typ == float :
# use standard number prototype
return space . NumberPrototype . get ( to_string ( prop ) )
elif typ == bool :
return space . BooleanPrototype . get ( to_string ( prop ) )
elif typ is UNDEFINED_TYPE :
raise MakeError ( ' TypeError ' ,
" Cannot read property ' %s ' of undefined " % prop )
elif typ is NULL_TYPE :
raise MakeError ( ' TypeError ' ,
" Cannot read property ' %s ' of null " % prop )
else :
raise RuntimeError ( ' Unknown type! - ' + repr ( typ ) )
def get_member_dot ( self , prop , space ) :
# dot member getter, prop has to be unicode
typ = type ( self )
if typ not in PRIMITIVES : # most likely getter for object
return self . get ( prop )
elif typ == unicode : # then probably a String
if prop == ' length ' :
return float ( len ( self ) )
elif prop . isdigit ( ) :
index = int ( prop )
if 0 < = index < len ( self ) :
return self [ index ]
else :
# use standard string prototype
return space . StringPrototype . get ( prop )
# maybe an index
elif typ == float :
# use standard number prototype
return space . NumberPrototype . get ( prop )
elif typ == bool :
return space . BooleanPrototype . get ( prop )
elif typ in ( UNDEFINED_TYPE , NULL_TYPE ) :
raise MakeError ( ' TypeError ' ,
" Cannot read property ' %s ' of undefined " % prop )
else :
raise RuntimeError ( ' Unknown type! - ' + repr ( typ ) )
# Object
class PyJsObject ( PyJs ) :
TYPE = ' Object '
Class = ' Object '
def __init__ ( self , prototype = None ) :
self . prototype = prototype
self . own = { }
def _init ( self , props , vals ) :
i = 0
for prop , kind in props :
if prop in self . own : # just check... probably will not happen very often.
if is_data_descriptor ( self . own [ prop ] ) :
if kind != ' i ' :
raise MakeError (
' SyntaxError ' ,
' Invalid object initializer! Duplicate property name " %s " '
% prop )
else :
if kind == ' i ' or ( kind == ' g ' and ' get ' in self . own [ prop ]
) or ( kind == ' s '
and ' set ' in self . own [ prop ] ) :
raise MakeError (
' SyntaxError ' ,
' Invalid object initializer! Duplicate setter/getter of prop: " %s " '
% prop )
if kind == ' i ' : # init
self . own [ prop ] = {
' value ' : vals [ i ] ,
' writable ' : True ,
' enumerable ' : True ,
' configurable ' : True
}
elif kind == ' g ' : # get
self . define_own_property ( prop , {
' get ' : vals [ i ] ,
' enumerable ' : True ,
' configurable ' : True
} , False )
elif kind == ' s ' : # get
self . define_own_property ( prop , {
' get ' : vals [ i ] ,
' enumerable ' : True ,
' configurable ' : True
} , False )
else :
raise RuntimeError (
' Invalid property kind - %s . Expected one of i, g, s. ' %
repr ( kind ) )
i + = 1
def _set_props ( self , prop_descs ) :
for prop , desc in six . iteritems ( prop_descs ) :
self . define_own_property ( prop , desc )
# Array
# todo Optimise Array - extremely slow due to index conversions from str to int and back etc.
# solution - make get and put methods callable with any type of prop and handle conversions from inside
# if not array then use to_string(prop). In array if prop is integer then just use it
# also consider removal of these stupid writable, enumerable etc for ints.
class PyJsArray ( PyJs ) :
Class = ' Array '
def __init__ ( self , length , prototype = None ) :
self . prototype = prototype
self . own = {
' length ' : {
' value ' : float ( length ) ,
' writable ' : True ,
' enumerable ' : False ,
' configurable ' : False
}
}
def _init ( self , elements ) :
for i , ele in enumerate ( elements ) :
if ele is None : continue
self . own [ unicode ( i ) ] = {
' value ' : ele ,
' writable ' : True ,
' enumerable ' : True ,
' configurable ' : True
}
def put ( self , prop , val , throw = False ) :
assert type ( val ) != int
# takes py, returns none
if not self . can_put ( prop ) :
if throw :
raise MakeError ( ' TypeError ' , ' Could not define own property ' )
return
own_desc = self . get_own_property ( prop )
if is_data_descriptor ( own_desc ) :
self . define_own_property ( prop , { ' value ' : val } , False )
return
desc = self . get_property ( prop )
if is_accessor_descriptor ( desc ) :
desc [ ' set ' ] . call (
self , ( val , ) ) # calling setter on own or inherited element
else : # new property
self . define_own_property (
prop , {
' value ' : val ,
' writable ' : True ,
' configurable ' : True ,
' enumerable ' : True
} , False )
def define_own_property ( self , prop , desc , throw ) :
assert type ( desc . get ( ' value ' ) ) != int
old_len_desc = self . get_own_property ( ' length ' )
old_len = old_len_desc [ ' value ' ] # value is js type so convert to py.
if prop == ' length ' :
if ' value ' not in desc :
return PyJs . define_own_property ( self , prop , desc , False )
new_len = to_uint32 ( desc [ ' value ' ] )
if new_len != to_number ( desc [ ' value ' ] ) :
raise MakeError ( ' RangeError ' , ' Invalid range! ' )
new_desc = dict ( ( k , v ) for k , v in six . iteritems ( desc ) )
new_desc [ ' value ' ] = float ( new_len )
if new_len > = old_len :
return PyJs . define_own_property ( self , prop , new_desc , False )
if not old_len_desc [ ' writable ' ] :
return False
if ' writable ' not in new_desc or new_desc [ ' writable ' ] == True :
new_writable = True
else :
new_writable = False
new_desc [ ' writable ' ] = True
if not PyJs . define_own_property ( self , prop , new_desc , False ) :
return False
if new_len < old_len :
# not very efficient for sparse arrays, so using different method for sparse:
if old_len > 30 * len ( self . own ) :
for ele in self . own . keys ( ) :
if ele . isdigit ( ) and int ( ele ) > = new_len :
if not self . delete (
ele
) : # if failed to delete set len to current len and reject.
new_desc [ ' value ' ] = old_len + 1.
if not new_writable :
new_desc [ ' writable ' ] = False
PyJs . define_own_property (
self , prop , new_desc , False )
return False
old_len = new_len
else : # standard method
while new_len < old_len :
old_len - = 1
if not self . delete (
unicode ( int ( old_len ) )
) : # if failed to delete set len to current len and reject.
new_desc [ ' value ' ] = old_len + 1.
if not new_writable :
new_desc [ ' writable ' ] = False
PyJs . define_own_property ( self , prop , new_desc ,
False )
return False
if not new_writable :
self . own [ ' length ' ] [ ' writable ' ] = False
return True
elif prop . isdigit ( ) :
index = to_uint32 ( prop )
if index > = old_len and not old_len_desc [ ' writable ' ] :
return False
if not PyJs . define_own_property ( self , prop , desc , False ) :
return False
if index > = old_len :
old_len_desc [ ' value ' ] = index + 1.
return True
else :
return PyJs . define_own_property ( self , prop , desc , False )
def to_list ( self ) :
return [
self . get ( str ( e ) ) for e in xrange ( self . get ( ' length ' ) . to_uint32 ( ) )
]
# database with compiled patterns. Js pattern -> Py pattern.
REGEXP_DB = { }
class PyJsRegExp ( PyJs ) :
Class = ' RegExp '
def __init__ ( self , body , flags , prototype = None ) :
self . prototype = prototype
self . glob = True if ' g ' in flags else False
self . ignore_case = re . IGNORECASE if ' i ' in flags else 0
self . multiline = re . MULTILINE if ' m ' in flags else 0
self . value = body
if ( body , flags ) in REGEXP_DB :
self . pat = REGEXP_DB [ body , flags ]
else :
comp = None
try :
# converting JS regexp pattern to Py pattern.
possible_fixes = [ ( u ' [] ' , u ' [ \0 ] ' ) , ( u ' [^] ' , u ' [^ \0 ] ' ) ,
( u ' nofix1791 ' , u ' nofix1791 ' ) ]
reg = self . value
for fix , rep in possible_fixes :
comp = PyJsParser ( ) . _interpret_regexp ( reg , flags )
#print 'reg -> comp', reg, '->', comp
try :
self . pat = re . compile (
comp , self . ignore_case | self . multiline )
#print reg, '->', comp
break
except :
reg = reg . replace ( fix , rep )
# print 'Fix', fix, '->', rep, '=', reg
else :
raise Exception ( )
REGEXP_DB [ body , flags ] = self . pat
except :
#print 'Invalid pattern...', self.value, comp
raise MakeError (
' SyntaxError ' ,
' Invalid RegExp pattern: %s -> %s ' % ( repr ( self . value ) ,
repr ( comp ) ) )
# now set own properties:
self . own = {
' source ' : {
' value ' : self . value ,
' enumerable ' : False ,
' writable ' : False ,
' configurable ' : False
} ,
' global ' : {
' value ' : self . glob ,
' enumerable ' : False ,
' writable ' : False ,
' configurable ' : False
} ,
' ignoreCase ' : {
' value ' : bool ( self . ignore_case ) ,
' enumerable ' : False ,
' writable ' : False ,
' configurable ' : False
} ,
' multiline ' : {
' value ' : bool ( self . multiline ) ,
' enumerable ' : False ,
' writable ' : False ,
' configurable ' : False
} ,
' lastIndex ' : {
' value ' : 0. ,
' enumerable ' : False ,
' writable ' : True ,
' configurable ' : False
}
}
def match ( self , string , pos ) :
''' string is of course a py string '''
return self . pat . match ( string , int ( pos ) )
class PyJsError ( PyJs ) :
Class = ' Error '
extensible = True
def __init__ ( self , message = None , prototype = None ) :
self . prototype = prototype
self . own = { }
if message is not None :
self . put ( ' message ' , to_string ( message ) )
self . own [ ' message ' ] [ ' enumerable ' ] = False
class PyJsDate ( PyJs ) :
Class = ' Date '
UTCToLocal = None # todo UTC to local should be imported!
def __init__ ( self , value , prototype = None ) :
self . value = value
self . own = { }
self . prototype = prototype
# todo fix this problematic datetime part
def to_local_dt ( self ) :
return datetime . datetime . utcfromtimestamp (
self . UTCToLocal ( self . value ) / / 1000 )
def to_utc_dt ( self ) :
return datetime . datetime . utcfromtimestamp ( self . value / / 1000 )
def local_strftime ( self , pattern ) :
if self . value is NaN :
return ' Invalid Date '
try :
dt = self . to_local_dt ( )
except :
raise MakeError (
' TypeError ' ,
' unsupported date range. Will fix in future versions ' )
try :
return dt . strftime ( pattern )
except :
raise MakeError (
' TypeError ' ,
' Could not generate date string from this date (limitations of python.datetime) '
)
def utc_strftime ( self , pattern ) :
if self . value is NaN :
return ' Invalid Date '
try :
dt = self . to_utc_dt ( )
except :
raise MakeError (
' TypeError ' ,
' unsupported date range. Will fix in future versions ' )
try :
return dt . strftime ( pattern )
except :
raise MakeError (
' TypeError ' ,
' Could not generate date string from this date (limitations of python.datetime) '
)
# Scope class it will hold all the variables accessible to user
class Scope ( PyJs ) :
Class = ' Global '
extensible = True
IS_CHILD_SCOPE = True
THIS_BINDING = None
space = None
exe = None
# todo speed up!
# in order to speed up this very important class the top scope should behave differently than
# child scopes, child scope should not have this property descriptor thing because they cant be changed anyway
# they are all confugurable= False
def __init__ ( self , scope , space , parent = None ) :
""" Doc """
self . space = space
self . prototype = parent
if type ( scope ) is not dict :
assert parent is not None , ' You initialised the WITH_SCOPE without a parent scope. '
self . own = scope
self . is_with_scope = True
else :
self . is_with_scope = False
if parent is None :
# global, top level scope
self . own = { }
for k , v in six . iteritems ( scope ) :
# set all the global items
self . define_own_property (
k , {
' value ' : v ,
' configurable ' : False ,
' writable ' : False ,
' enumerable ' : False
} , False )
else :
# not global, less powerful but faster closure.
self . own = scope # simple dictionary which maps name directly to js object.
self . par = super ( Scope , self )
self . stack = [ ]
def register ( self , var ) :
# registered keeps only global registered variables
if self . prototype is None :
# define in global scope
if var in self . own :
self . own [ var ] [ ' configurable ' ] = False
else :
self . define_own_property (
var , {
' value ' : undefined ,
' configurable ' : False ,
' writable ' : True ,
' enumerable ' : True
} , False )
elif var not in self . own :
# define in local scope since it has not been defined yet
self . own [ var ] = undefined # default value
def registers ( self , vars ) :
""" register multiple variables """
for var in vars :
self . register ( var )
def put ( self , var , val , throw = False ) :
if self . prototype is None :
desc = self . own . get ( var ) # global scope
if desc is None :
self . par . put ( var , val , False )
else :
if desc [ ' writable ' ] : # todo consider getters/setters
desc [ ' value ' ] = val
else :
if self . is_with_scope :
if self . own . has_property ( var ) :
return self . own . put ( var , val , throw = throw )
else :
return self . prototype . put ( var , val )
# trying to put in local scope
# we dont know yet in which scope we should place this var
elif var in self . own :
self . own [ var ] = val
return val
else :
# try to put in the lower scope since we cant put in this one (var wasn't registered)
return self . prototype . put ( var , val )
def get ( self , var , throw = False ) :
if self . prototype is not None :
if self . is_with_scope :
cand = None if not self . own . has_property (
var ) else self . own . get ( var )
else :
# fast local scope
cand = self . own . get ( var )
if cand is None :
return self . prototype . get ( var , throw )
return cand
# slow, global scope
if var not in self . own :
# try in ObjectPrototype...
if var in self . space . ObjectPrototype . own :
return self . space . ObjectPrototype . get ( var )
if throw :
raise MakeError ( ' ReferenceError ' , ' %s is not defined ' % var )
return undefined
cand = self . own [ var ] . get ( ' value ' )
return cand if cand is not None else self . own [ var ] [ ' get ' ] . call ( self )
def delete ( self , var , throw = False ) :
if self . prototype is not None :
if self . is_with_scope :
if self . own . has_property ( var ) :
return self . own . delete ( var )
elif var in self . own :
return False
return self . prototype . delete ( var )
# we are in global scope here. Must exist and be configurable to delete
if var not in self . own :
# this var does not exist, why do you want to delete it???
return True
if self . own [ var ] [ ' configurable ' ] :
del self . own [ var ]
return True
# not configurable, cant delete
return False
def get_new_arguments_obj ( args , space ) :
obj = space . NewObject ( )
obj . Class = ' Arguments '
obj . define_own_property (
' length ' , {
' value ' : float ( len ( args ) ) ,
' writable ' : True ,
' enumerable ' : False ,
' configurable ' : True
} , False )
for i , e in enumerate ( args ) :
obj . put ( unicode ( i ) , e )
return obj
#Function
class PyJsFunction ( PyJs ) :
Class = ' Function '
source = ' { [native code] } '
IS_CONSTRUCTOR = True
def __init__ ( self ,
code ,
ctx ,
params ,
name ,
space ,
is_declaration ,
definitions ,
prototype = None ) :
self . prototype = prototype
self . own = { }
self . code = code
if type (
self . code
) == int : # just a label pointing to the beginning of the code.
self . is_native = False
else :
self . is_native = True # python function
self . ctx = ctx
self . params = params
self . arguments_in_params = ' arguments ' in params
self . definitions = definitions
# todo remove this check later
for p in params :
assert p in self . definitions
self . name = name
self . space = space
self . is_declaration = is_declaration
#set own property length to the number of arguments
self . own [ ' length ' ] = {
' value ' : float ( len ( params ) ) ,
' writable ' : False ,
' enumerable ' : False ,
' configurable ' : False
}
if name :
self . own [ ' name ' ] = {
' value ' : name ,
' writable ' : False ,
' enumerable ' : False ,
' configurable ' : True
}
if not self . is_native : # set prototype for user defined functions
# constructor points to this function
proto = space . NewObject ( )
proto . own [ ' constructor ' ] = {
' value ' : self ,
' writable ' : True ,
' enumerable ' : False ,
' configurable ' : True
}
self . own [ ' prototype ' ] = {
' value ' : proto ,
' writable ' : True ,
' enumerable ' : False ,
' configurable ' : False
}
# todo set up throwers on callee and arguments if in strict mode
def call ( self , this , args = ( ) ) :
''' Dont use this method from inside bytecode to call other bytecode. '''
if self . is_native :
_args = SpaceTuple (
args
) # we have to do that unfortunately to pass all the necessary info to the funcs
_args . space = self . space
return self . code (
this , _args
) # must return valid js object - undefined, null, float, unicode, bool, or PyJs
else :
return self . space . exe . _call ( self , this ,
args ) # will run inside bytecode
def has_instance ( self , other ) :
# I am not sure here so instanceof may not work lol.
if not is_object ( other ) :
return False
proto = self . get ( ' prototype ' )
if not is_object ( proto ) :
raise MakeError (
' TypeError ' ,
' Function has non-object prototype in instanceof check ' )
while True :
other = other . prototype
if not other : # todo make sure that the condition is not None or null
return False
if other is proto :
return True
def create ( self , args , space ) :
proto = self . get ( ' prototype ' )
if not is_object ( proto ) :
proto = space . ObjectPrototype
new = PyJsObject ( prototype = proto )
res = self . call ( new , args )
if is_object ( res ) :
return res
return new
def _generate_my_context ( self , this , args ) :
my_ctx = Scope (
dict ( izip ( self . params , args ) ) , self . space , parent = self . ctx )
my_ctx . registers ( self . definitions )
my_ctx . THIS_BINDING = this
if not self . arguments_in_params :
my_ctx . own [ ' arguments ' ] = get_new_arguments_obj ( args , self . space )
if not self . is_declaration and self . name and self . name not in my_ctx . own :
my_ctx . own [
self .
name ] = self # this should be immutable binding but come on!
return my_ctx
class SpaceTuple :
def __init__ ( self , tup ) :
self . tup = tup
def __len__ ( self ) :
return len ( self . tup )
def __getitem__ ( self , item ) :
return self . tup [ item ]
def __iter__ ( self ) :
return iter ( self . tup )