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