Commits

Alex Gaynor  committed 3e4544d

Added support for compiling if.

  • Participants
  • Parent commits 519911a

Comments (0)

Files changed (4)

File minijs/astcompiler.py

         for arg in args:
             self.data.append(chr(arg))
 
+    def emit_conditional_jump(self, bc):
+        pos = len(self.data)
+        self.emit(bc, 0)
+        return pos + 1
+
+    def patch_jump(self, pos):
+        self.data[pos] = chr(len(self.data))
+
     def create_name(self, name):
         if name not in self.names:
             self.names[name] = len(self.names)

File minijs/consts.py

 # name, arguments, stack effect
 BYTECODES = [
     ("LOAD_CONST", 1, +1),
+
+    ("LOAD_NAME", 1, +1),
     ("STORE_NAME", 1, 0),
+
+    ("BINARY_ADD", 0, -1),
+    ("BINARY_SUB", 0, -1),
+    ("BINARY_MUL", 0, -1),
+    ("BINARY_DIV", 0, -1),
+
+    ("JUMP_IF_FALSE", 1, -1),
+
     ("DISCARD_TOP", 0, -1),
+
     ("RETURN_NULL", 0, 0),
 ]
 
     BYTECODE_NAMES.append(bc_name)
     BYTECODE_NUM_ARGS.append(num_args)
     BYTECODE_STACK_EFFECT.append(stack_effect)
-del i, bc_name, num_args, stack_effect, module
+del i, bc_name, num_args, stack_effect, module
+
+BINOP_BYTECODE = {
+    "+": BINARY_ADD,
+    "-": BINARY_SUB,
+    "*": BINARY_MUL,
+    "/": BINARY_DIV,
+}

File minijs/parser.py

         self.cond = cond
         self.body = body
 
+    def compile(self, ctx):
+        self.cond.compile(ctx)
+        pos = ctx.emit_conditional_jump(consts.JUMP_IF_FALSE)
+        self.body.compile(ctx)
+        ctx.patch_jump(pos)
+
 class While(Node):
     def __init__(self, cond, body):
         self.cnod = cond
         self.lhs = lhs
         self.rhs = rhs
 
+    def compile(self, ctx):
+        self.lhs.compile(ctx)
+        self.rhs.compile(ctx)
+        ctx.emit(consts.BINOP_BYTECODE[self.op])
+
 class Variable(Node):
     def __init__(self, var):
         self.var = var
 
+    def compile(self, ctx):
+        ctx.emit(consts.LOAD_NAME, ctx.create_name(self.var))
+
 class ConstantFloat(Node):
     def __init__(self, floatval):
         self.floatval = floatval

File tests/test_compiler.py

 class TestCompiler(object):
     def assert_compiles(self, space, source, expected_bytecode):
         bc = space.compile(source)
-        expected = [
-            line.strip()
-            for line in expected_bytecode.splitlines()
-            if line.strip()
-        ]
+        expected = []
+        for line in expected_bytecode.splitlines():
+            if "#" in line:
+                line = line[:line.index("#")]
+            line = line.strip()
+            if line:
+                expected.append(line)
 
         actual = []
         i = 0
         """)
         [c] = bc.consts
         assert c.floatval == 3
-        assert bc.max_stackdepth == 1
+        assert bc.max_stackdepth == 1
+
+    def test_addition(self, space):
+        self.assert_compiles(space, "a + 2;", """
+        LOAD_NAME 0
+        LOAD_CONST 0
+        BINARY_ADD
+        DISCARD_TOP
+        RETURN_NULL
+        """)
+
+    def test_binops(self, space):
+        self.assert_compiles(space, "(2 * 4) - (3 / 4);", """
+        LOAD_CONST 0
+        LOAD_CONST 1
+        BINARY_MUL
+        LOAD_CONST 2
+        LOAD_CONST 3 # should be 1 after we merge consts
+        BINARY_DIV
+        BINARY_SUB
+        DISCARD_TOP
+        RETURN_NULL
+        """)
+
+    def test_if(self, space):
+        self.assert_compiles(space, "if (3) { 2 + 2; }", """
+        LOAD_CONST 0
+        JUMP_IF_FALSE 10
+        LOAD_CONST 1
+        LOAD_CONST 2 # will be 1 after merge consts
+        BINARY_ADD
+        DISCARD_TOP
+        RETURN_NULL
+        """)