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

Reply via email to