Author: Stephan <[email protected]>
Branch:
Changeset: r90:7becdec85414
Date: 2011-05-27 13:08 +0200
http://bitbucket.org/pypy/lang-js/changeset/7becdec85414/
Log: removed STORE_<OPERATION> bytecodes and unified assignment handling
diff --git a/js/astbuilder.py b/js/astbuilder.py
--- a/js/astbuilder.py
+++ b/js/astbuilder.py
@@ -144,7 +144,6 @@
else:
return self.binaryop(node)
-
def literalop(self, node):
pos = self.get_pos(node);
value = node.children[0].additional_info
@@ -167,23 +166,15 @@
return self.UNOP_TO_CLS[op.additional_info](pos, child)
def _dispatch_assignment(self, pos, left, atype, prepost):
- from js.operations import Identifier, Member, MemberDot,\
- VariableIdentifier
+ from js.operations import Identifier, Member, MemberDot,
VariableIdentifier
- if isinstance(left, Identifier):
- return operations.SimpleAssignment(pos, left, None, atype, prepost)
- elif isinstance(left, VariableIdentifier):
- # XXX exchange to VariableAssignment
- return operations.SimpleAssignment(pos, left, None, atype,
- prepost)
- elif isinstance(left, Member):
- return operations.MemberAssignment(pos, left.left, left.expr,
- None, atype, prepost)
- elif isinstance(left, MemberDot):
- return operations.MemberDotAssignment(pos, left.left, left.name,
- None, atype, prepost)
+ is_post = prepost == 'post'
+ if isinstance(left, Identifier) or isinstance(left,
VariableIdentifier):
+ return operations.AssignmentOperation(pos, left, None, atype,
is_post)
+ elif isinstance(left, Member) or isinstance(left, MemberDot):
+ return operations.MemberAssignmentOperation(pos, left, None,
atype, is_post)
else:
- return operations.SimpleIncrement(pos, left, atype)
+ raise FakeParseError(pos, "invalid lefthand expression")
def visit_postfixexpression(self, node):
op = node.children[1]
@@ -336,23 +327,17 @@
return left
def visit_assignmentexpression(self, node):
- from js.operations import Identifier, Member, MemberDot,\
- VariableIdentifier
+ from js.operations import Identifier, VariableIdentifier, Member,
MemberDot
+
pos = self.get_pos(node)
left = self.dispatch(node.children[0])
- atype = node.children[1].additional_info
+ operation = node.children[1].additional_info
right = self.dispatch(node.children[2])
- if isinstance(left, Identifier):
- return operations.SimpleAssignment(pos, left, right, atype)
- elif isinstance(left, VariableIdentifier):
- # XXX exchange to VariableAssignment
- return operations.SimpleAssignment(pos, left, right, atype)
- elif isinstance(left, Member):
- return operations.MemberAssignment(pos, left.left, left.expr,
- right, atype)
- elif isinstance(left, MemberDot):
- return operations.MemberDotAssignment(pos, left.left, left.name,
- right, atype)
+
+ if isinstance(left, Identifier) or isinstance(left,
VariableIdentifier):
+ return operations.AssignmentOperation(pos, left, right, operation)
+ elif isinstance(left, Member) or isinstance(left, MemberDot):
+ return operations.MemberAssignmentOperation(pos, left, right,
operation)
else:
raise FakeParseError(pos, "invalid lefthand expression")
visit_assignmentexpressionnoin = visit_assignmentexpression
diff --git a/js/jscode.py b/js/jscode.py
--- a/js/jscode.py
+++ b/js/jscode.py
@@ -131,15 +131,7 @@
return opcode
emit._annspecialcase_ = 'specialize:arg(1)'
- def emit_store(self, operation, identifier):
- opcode = store_opcodes[operation](identifier)
- self.opcodes.append(opcode)
- return opcode
- def emit_store_member(self, operation):
- opcode = store_member_opcodes[operation]()
- self.opcodes.append(opcode)
- return opcode
def unpop(self):
if self.opcodes and isinstance(self.opcodes[-1], POP):
@@ -436,23 +428,10 @@
return 'LOAD_OBJECT %d' % (self.counter,)
class LOAD_MEMBER(Opcode):
- def __init__(self, name):
- self.name = name
-
def eval(self, ctx, stack):
w_obj = stack.pop().ToObject(ctx)
- stack.append(w_obj.Get(ctx, self.name))
- #stack.append(W_Reference(self.name, w_obj))
-
- def __repr__(self):
- return 'LOAD_MEMBER "%s"' % (self.name,)
-
-class LOAD_ELEMENT(Opcode):
- def eval(self, ctx, stack):
name = stack.pop().ToString(ctx)
- w_obj = stack.pop().ToObject(ctx)
stack.append(w_obj.Get(ctx, name))
- #stack.append(W_Reference(name, w_obj))
class COMMA(BaseUnaryOperation):
def eval(self, ctx, stack):
@@ -565,10 +544,16 @@
stack.append(newbool(not stack.pop().ToBoolean()))
class INCR(BaseUnaryOperation):
- pass
+ def eval(self, ctx, stack):
+ value = stack.pop()
+ newvalue = increment(ctx, value)
+ stack.append(newvalue)
class DECR(BaseUnaryOperation):
- pass
+ def eval(self, ctx, stack):
+ value = stack.pop()
+ newvalue = decrement(ctx, value)
+ stack.append(newvalue)
class GT(BaseBinaryComparison):
def decision(self, ctx, op1, op2):
@@ -602,192 +587,27 @@
def decision(self, ctx, op1, op2):
return newbool(not StrictEC(ctx, op1, op2))
-
-class BaseStoreMember(Opcode):
+class STORE_MEMBER(Opcode):
def eval(self, ctx, stack):
left = stack.pop()
- elem = stack.pop()
+ member = stack.pop()
value = stack.pop()
- name = elem.ToString(ctx)
- value = self.operation(ctx, left, name, value)
+ name = member.ToString(ctx)
left.ToObject(ctx).Put(ctx, name, value)
stack.append(value)
-class STORE_MEMBER(BaseStoreMember):
- def operation(self, ctx, left, elem, value):
- return value
-
-class BaseStoreMemberAssign(BaseStoreMember):
- def operation(self, ctx, left, name, value):
- prev = left.Get(ctx, name)
- return self.decision(ctx, value, prev)
-
-class STORE_MEMBER_ADD(BaseStoreMemberAssign):
- def decision(self, ctx, value, prev):
- return plus(ctx, value, prev)
-
-class BaseStoreMemberBitOp(BaseStoreMemberAssign):
- def decision(self, ctx, value, prev):
- op0 = value.ToInt32(ctx)
- op1 = prev.ToInt32(ctx)
- return W_IntNumber(self.bitop(op0, op1))
-
-class STORE_MEMBER_BITXOR(BaseStoreMemberBitOp):
- def bitop(self, op0, op1):
- return op0 ^ op1
-
-class STORE_MEMBER_BITAND(BaseStoreMemberBitOp):
- def bitop(self, op0, op1):
- return op0 & op1
-
-class STORE_MEMBER_BITOR(BaseStoreMemberBitOp):
- def bitop(self, op0, op1):
- return op0 | op1
-
-class BaseStoreMemberPost(Opcode):
- def eval(self, ctx, stack):
- left = stack.pop()
- elem = stack.pop()
- name = elem.ToString(ctx)
- prev = value = left.ToObject(ctx).Get(ctx, name)
- value = self.operation(ctx, value)
- left.ToObject(ctx).Put(ctx, name, value)
- stack.append(prev)
-
-class STORE_MEMBER_POSTINCR(BaseStoreMemberPost):
- def operation(self, ctx, value):
- return increment(ctx, value)
-
-class STORE_MEMBER_POSTDECR(BaseStoreMemberPost):
- def operation(self, ctx, value):
- return decrement(ctx, value)
-
-class BaseStoreMemberPre(Opcode):
- def eval(self, ctx, stack):
- left = stack.pop()
- elem = stack.pop()
- name = elem.ToString(ctx)
- value = left.ToObject(ctx).Get(ctx, name)
- value = self.operation(ctx, value)
- left.ToObject(ctx).Put(ctx, name, value)
- stack.append(value)
-
-class STORE_MEMBER_PREINCR(BaseStoreMemberPre):
- def operation(self, ctx, value):
- return increment(ctx, value)
-
-class STORE_MEMBER_PREDECR(BaseStoreMemberPre):
- def operation(self, ctx, value):
- return decrement(ctx, value)
-
-class STORE_MEMBER_SUB(BaseStoreMemberAssign):
- def decision(self, ctx, value, prev):
- return sub(ctx, prev, value)
-
-class BaseStore(Opcode):
+class STORE(Opcode):
_immutable_fields_ = ['name']
def __init__(self, name):
self.name = name
def eval(self, ctx, stack):
- value = self.process(ctx, self.name, stack)
+ value = stack.top()
ctx.assign(self.name, value)
def __repr__(self):
return '%s "%s"' % (self.__class__.__name__, self.name)
-class STORE(BaseStore):
- def process(self, ctx, name, stack):
- return stack.top()
-
-class BaseAssignOper(BaseStore):
- def process(self, ctx, name, stack):
- right = stack.pop()
- left = ctx.resolve_identifier(ctx, name)
- result = self.operation(ctx, left, right)
- stack.append(result)
- return result
-
-class BaseAssignBitOper(BaseStore):
- def process(self, ctx, name, stack):
- right = stack.pop().ToInt32(ctx)
- left = ctx.resolve_identifier(ctx, name).ToInt32(ctx)
- result = self.operation(ctx, left, right)
- stack.append(result)
- return result
-
-class STORE_ADD(BaseAssignOper):
- def operation(self, ctx, left, right):
- return plus(ctx, left, right)
-
-class STORE_SUB(BaseAssignOper):
- def operation(self, ctx, left, right):
- return sub(ctx, left, right)
-
-class STORE_MUL(BaseAssignOper):
- def operation(self, ctx, left, right):
- return mult(ctx, left, right)
-
-class STORE_DIV(BaseAssignOper):
- def operation(self, ctx, left, right):
- return division(ctx, left, right)
-
-class STORE_MOD(BaseAssignOper):
- def operation(self, ctx, left, right):
- return mod(ctx, left, right)
-
-class STORE_BITAND(BaseAssignBitOper):
- def operation(self, ctx, op1, op2):
- return W_IntNumber(op1&op2)
-
-class STORE_BITOR(BaseAssignBitOper):
- def operation(self, ctx, op1, op2):
- return W_IntNumber(op1|op2)
-
-class STORE_BITXOR(BaseAssignBitOper):
- def operation(self, ctx, op1, op2):
- return W_IntNumber(op1^op2)
-
-class STORE_BITRSH(BaseAssignBitOper):
- def operation(self, ctx, op1, op2):
- return W_IntNumber(op1 >> op2)
-
-class STORE_POSTINCR(BaseStore):
- def process(self, ctx, name, stack):
- value = ctx.resolve_identifier(ctx, name)
- num = value.ToNumber(ctx)
- newval = W_FloatNumber(num + 1)
-
- stack.append(W_FloatNumber(num))
- return newval
-
-class STORE_POSTDECR(BaseStore):
- def process(self, ctx, name, stack):
- value = ctx.resolve_identifier(ctx, name)
- num = value.ToNumber(ctx)
- newval = W_FloatNumber(num - 1)
-
- stack.append(W_FloatNumber(num))
- return newval
-
-class STORE_PREINCR(BaseStore):
- def process(self, ctx, name, stack):
- value = ctx.resolve_identifier(ctx, name)
- num = value.ToNumber(ctx)
- newval = W_FloatNumber(num + 1)
-
- stack.append(newval)
- return newval
-
-class STORE_PREDECR(BaseStore):
- def process(self, ctx, name, stack):
- value = ctx.resolve_identifier(ctx, name)
- num = value.ToNumber(ctx)
- newval = W_FloatNumber(num - 1)
-
- stack.append(newval)
- return newval
-
class LABEL(Opcode):
def __init__(self, num):
self.num = num
@@ -1045,8 +865,4 @@
store_opcodes = {}
store_member_opcodes = {}
for name, value in OpcodeMap.items():
- if name.startswith('STORE_MEMBER'):
- store_member_opcodes[name] = value
- elif name.startswith('STORE'):
- store_opcodes[name] = value
setattr(opcodes, name, value)
diff --git a/js/operations.py b/js/operations.py
--- a/js/operations.py
+++ b/js/operations.py
@@ -121,14 +121,6 @@
element.emit(bytecode)
bytecode.emit('LOAD_ARRAY', len(self.nodes))
-class Assignment(Expression):
- def _get_name(self):
- addoper = OPERANDS[self.operand]
- if addoper:
- addoper = '_' + self.prefix.upper() + addoper
- else:
- addoper = ''
- return addoper
OPERANDS = {
'=' : '',
@@ -142,83 +134,82 @@
'&=' : 'BITAND',
'|=' : 'BITOR',
'^=' : 'BITXOR',
- '>>=' : 'BITRSH'
+ '>>=' : 'RSH'
}
-class SimpleIncrement(Expression):
- def __init__(self, pos, left, atype):
- self.pos = pos
- self.left = left
- self.atype = atype
+# OPERANDS.values() is not staic enough
+OPERATIONS = unrolling_iterable(['ADD', 'SUB', 'MUL', 'DIV', 'MOD', 'BITAND',
'BITOR', 'BITXOR', 'BITNOT', 'URSH', 'RSH', 'LSH', 'INCR', 'DECR'])
+
+class BaseAssignment(Expression):
+ noops = ['=']
+
+ def has_operation(self):
+ return self.operand not in self.noops
+
+ def post_operation(self):
+ return self.post
def emit(self, bytecode):
- self.left.emit(bytecode)
- if self.atype == '++':
- bytecode.emit('INCR')
- elif self.atype == '--':
- bytecode.emit('DECR')
+ if self.has_operation():
+ self.left.emit(bytecode)
+ if self.post_operation():
+ bytecode.emit('DUP')
+ self.right.emit(bytecode)
+ self.emit_operation(bytecode)
+ else:
+ self.right.emit(bytecode)
-class SimpleAssignment(Assignment):
- def __init__(self, pos, left, right, operand, prefix=''):
+ self.emit_store(bytecode)
+
+ if self.post_operation():
+ bytecode.emit('POP')
+
+ def emit_operation(self, bytecode):
+ # calls to bytecode.emit have to be very very very static
+ operation = self.get_operation()
+ for op in OPERATIONS:
+ if op == operation:
+ bytecode.emit(op)
+
+ def emit_store(self, bytecode):
+ raise NotImplementedError
+
+ def get_operation(self):
+ operation = OPERANDS[self.operand]
+ return operation
+
+class AssignmentOperation(BaseAssignment):
+ def __init__(self, pos, left, right, operand, post = False):
+ self.left = left
self.identifier = left.get_literal()
self.right = right
+ if self.right is None:
+ self.right = Empty(pos)
self.pos = pos
self.operand = operand
- self.prefix = prefix
+ self.post = post
- def emit(self, bytecode):
- if self.right is not None:
- self.right.emit(bytecode)
- bytecode_name = 'STORE' + self._get_name()
- bytecode.emit_store(bytecode_name, self.identifier)
+ def emit_store(self, bytecode):
+ bytecode.emit('STORE', self.identifier)
-class VariableAssignment(Assignment):
- def __init__(self, pos, left, right, operand):
- xxx # shall never land here for now
- self.identifier = left.identifier
+class MemberAssignmentOperation(BaseAssignment):
+ def __init__(self, pos, left, right, operand, post = False):
+ self.pos = pos
+ self.left = left
self.right = right
- self.pos = pos
+ if right is None:
+ self.right = Empty(pos)
+
self.operand = operand
- self.depth = left.depth
- def emit(self, bytecode):
- self.right.emit(bytecode)
- bytecode.emit('STORE_VAR', self.depth, self.identifier)
+ self.w_object = self.left.left
+ self.expr = self.left.expr
+ self.post = post
-class MemberAssignment(Assignment):
- def __init__(self, pos, what, item, right, operand, prefix=''):
- # XXX we can optimise here what happens if what is identifier,
- # but let's leave it alone for now
- self.pos = pos
- self.what = what
- self.item = item
- self.right = right
- self.operand = operand
- self.prefix = prefix
-
- def emit(self, bytecode):
- if self.right is not None:
- self.right.emit(bytecode)
- self.item.emit(bytecode)
- self.what.emit(bytecode)
- bytecode.emit_store_member('STORE_MEMBER' + self._get_name())
-
-class MemberDotAssignment(Assignment):
- def __init__(self, pos, what, name, right, operand, prefix=''):
- self.pos = pos
- self.what = what
- self.itemname = name
- self.right = right
- self.operand = operand
- self.prefix = prefix
-
- def emit(self, bytecode):
- # XXX optimize this a bit
- if self.right is not None:
- self.right.emit(bytecode)
- bytecode.emit('LOAD_STRINGCONSTANT', self.itemname)
- self.what.emit(bytecode)
- bytecode.emit_store_member('STORE_MEMBER' + self._get_name())
+ def emit_store(self, bytecode):
+ self.expr.emit(bytecode)
+ self.w_object.emit(bytecode)
+ bytecode.emit('STORE_MEMBER')
class Block(Statement):
def __init__(self, pos, nodes):
@@ -290,9 +281,9 @@
return "Member %s[%s]" % (repr(self.left), repr(self.expr))
def emit(self, bytecode):
+ self.expr.emit(bytecode)
self.left.emit(bytecode)
- self.expr.emit(bytecode)
- bytecode.emit('LOAD_ELEMENT')
+ bytecode.emit('LOAD_MEMBER')
class MemberDot(Expression):
"this is for object.name"
@@ -300,13 +291,15 @@
self.name = name.get_literal()
self.left = left
self.pos = pos
+ self.expr = String(pos, "'%s'" % (self.name))
def __repr__(self):
return "MemberDot %s.%s" % (repr(self.left), self.name)
def emit(self, bytecode):
+ bytecode.emit_str(self.name)
self.left.emit(bytecode)
- bytecode.emit('LOAD_MEMBER', self.name)
+ bytecode.emit('LOAD_MEMBER')
class FunctionStatement(Statement):
def __init__(self, pos, name, params, body):
diff --git a/js/test/test_interp.py b/js/test/test_interp.py
--- a/js/test/test_interp.py
+++ b/js/test/test_interp.py
@@ -268,6 +268,8 @@
yield assertv, "var x = 3; x += 4; x;", 7
yield assertv, "x = 8; x -= 3; x;", 5
yield assertv, "x = {}; x.x = 3; x.x += 8; x.x", 8+3
+ yield assertv, "x = []; x[2] = 1; x[2]++;", 1
+ yield assertv, "x = []; x[2] = 1; x[2]++; x[2]", 2
def test_object_creation():
yield assertv, """
diff --git a/js/test/test_parser.py b/js/test/test_parser.py
--- a/js/test/test_parser.py
+++ b/js/test/test_parser.py
@@ -364,12 +364,8 @@
'ADD',
'LOAD_INTCONSTANT 6',
'SUB'])
- self.check('++5', [
- 'LOAD_INTCONSTANT 5',
- 'INCR'])
- self.check('5--', [
- 'LOAD_INTCONSTANT 5',
- 'DECR'])
+ py.test.raises(FakeParseError, self.check, '++5', [])
+ py.test.raises(FakeParseError, self.check, '--5', [])
self.check('"hello " + \'world\'',
['LOAD_STRINGCONSTANT "hello "',
'LOAD_STRINGCONSTANT "world"',
@@ -377,9 +373,9 @@
def test_member(self):
self.check('a["b"]',
- ['LOAD_VARIABLE "a"',
- 'LOAD_STRINGCONSTANT "b"',
- 'LOAD_ELEMENT'])
+ ['LOAD_STRINGCONSTANT "b"',
+ 'LOAD_VARIABLE "a"',
+ 'LOAD_MEMBER'])
class TestToAstStatement(BaseTestToAST):
def setup_class(cls):
@@ -482,8 +478,9 @@
'POP'])
def test_member(self):
- self.check('a.b', ['LOAD_VARIABLE "a"',
- 'LOAD_MEMBER "b"',
+ self.check('a.b', ['LOAD_STRINGCONSTANT "b"',
+ 'LOAD_VARIABLE "a"',
+ 'LOAD_MEMBER',
'POP'])
self.check('a.b = 3', ['LOAD_INTCONSTANT 3',
'LOAD_STRINGCONSTANT "b"',
@@ -493,23 +490,54 @@
def test_different_assignments(self):
self.check('x += y', [
+ 'LOAD_VARIABLE "x"',
'LOAD_VARIABLE "y"',
- 'STORE_ADD "x"',
+ 'ADD',
+ 'STORE "x"',
'POP'])
- self.check('x++', ['STORE_POSTINCR "x"',
- 'POP'])
+ self.check('x++', [
+ 'LOAD_VARIABLE "x"',
+ 'DUP',
+ 'INCR',
+ 'STORE "x"',
+ 'POP',
+ 'POP'])
+ self.check('x.y++', [
+ 'LOAD_STRINGCONSTANT "y"',
+ 'LOAD_VARIABLE "x"',
+ 'LOAD_MEMBER',
+ 'DUP',
+ 'INCR',
+ 'LOAD_STRINGCONSTANT "y"',
+ 'LOAD_VARIABLE "x"',
+ 'STORE_MEMBER',
+ 'POP',
+ 'POP'])
self.check('++x[2]', [
'LOAD_INTCONSTANT 2',
'LOAD_VARIABLE "x"',
- 'STORE_MEMBER_PREINCR',
+ 'LOAD_MEMBER',
+ 'INCR',
+ 'LOAD_INTCONSTANT 2',
+ 'LOAD_VARIABLE "x"',
+ 'STORE_MEMBER',
'POP'])
self.check('x.y -= 2',
- ['LOAD_INTCONSTANT 2',
+ ['LOAD_STRINGCONSTANT "y"',
+ 'LOAD_VARIABLE "x"',
+ 'LOAD_MEMBER',
+ 'LOAD_INTCONSTANT 2',
+ 'SUB',
'LOAD_STRINGCONSTANT "y"',
'LOAD_VARIABLE "x"',
- 'STORE_MEMBER_SUB',
+ 'STORE_MEMBER',
'POP'])
+ def test_variable_assign(self):
+ self.check('x=1;', ['LOAD_INTCONSTANT 1', 'STORE "x"', 'POP'])
+ self.check('var x; x = 1;', ['DECLARE_VAR "x"', 'LOAD_INTCONSTANT 1',
'STORE "x"', 'POP'])
+ self.check('var x=1;', ['DECLARE_VAR "x"', 'LOAD_INTCONSTANT 1',
'STORE "x"', 'POP'])
+ self.check('x+=1;', ['LOAD_VARIABLE "x"','LOAD_INTCONSTANT 1', 'ADD',
'STORE "x"', 'POP'])
def test_retlast_pop_removal():
jscode = JsCode()
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit