Example #1
0
def compile_if(context, ast):
    # compile the condition
    assert (isinstance(ast, ast_objects.If))
    compile_any(context, ast.condition)
    # add true
    t = context.register_constant(objects.Boolean(True))
    context.emit(bytecode.LOAD_CONST, t)
    # compare the condition to true
    context.emit(bytecode.BINARY_EQ, bytecode.NO_ARG)

    # condition:
    # jump if zero (false): false block
    # true block
    # jump to end
    # false block

    # TODO: let jump target labels, not values! store the name of the jump
    # in a constant and then reference that constant name, which can contain the
    # jump position and be updated if need be

    context.emit(bytecode.JUMP_IF_ZERO, 0)
    # make a note of the instruction we'll have to change
    false_jump = len(context.instructions) - 1
    # then add the true block
    compile_any(context, ast.body)
    # then a jump from the true block to after the false block
    context.emit(bytecode.JUMP, 0)
    # the start of the false block is the current length
    false_block = len(context.instructions)
    # so set the false block jump to that point
    context.instructions[false_jump] = (context.instructions[false_jump][0],
                                        false_block)
    compile_any(context, ast.else_body)
    # get the point we're at now
    after_false = len(context.instructions)
    # then change the true jump to point here
    context.instructions[false_block - 1] = (context.instructions[false_block -
                                                                  1][0],
                                             after_false)
Example #2
0
def compile_while(context, ast):
    assert(isinstance(ast, ast_objects.While))
    condition_pos = len(context.instructions)
    compile_any(context, ast.condition)
    # add true
    t = context.register_constant(objects.Boolean(True))
    context.emit(bytecode.LOAD_CONST,t)
    # compare the condition to true
    context.emit(bytecode.BINARY_EQ,bytecode.NO_ARG)
    
    # condition:
    # jump if zero (false): after the block
    # block
    # jump to condition
    
    # this will point to after the end
    context.emit(bytecode.JUMP_IF_ZERO,0)
    # make a note of the instruction we'll have to change
    false_jump = len(context.instructions) - 1
    compile_any(context,ast.body)
    context.emit(bytecode.JUMP,condition_pos)
    after_block = len(context.instructions)
    context.instructions[false_jump] = (context.instructions[false_jump][0],after_block)
Example #3
0
def compile_boolean(context, ast):
    assert(isinstance(ast,ast_objects.Boolean))
    value = objects.Boolean(ast.value)
    index = context.register_constant(value)
    
    context.emit(bytecode.LOAD_CONST,index)
Example #4
0
    def interpret(self, byte_code, args=[]):

        pc = 0  # program counter
        stack = []
        variables = [objects.Null()] * 255

        assert (len(args) == len(byte_code.arguments))

        # print "(running %s)" % byte_code.name

        # copy args into inner context
        for i in range(0, len(args)):
            # TODO: this doesn't make sense, indexes change I think?
            # Make sure these aren't getting overwritten
            index = byte_code.arguments[i]
            # print "(arg %s going into %s)" % (args[i].dump(),index)
            byte_code.variables[index] = objects.Variable("arg", args[i])

        self.last_bc += byte_code.dump(True)

        while pc < len(byte_code.instructions):

            # the type of instruction and arg (a tuple)
            opcode, arg = byte_code.instructions[pc]

            # print "(%s %s %s)" % (pc, bytecode.reverse[opcode], arg)

            # then increment
            pc += 1

            if opcode == bytecode.LOAD_CONST:
                # grab a value from our constants and add to stack
                value = byte_code.constants[arg]
                stack.append(value)

            elif opcode == bytecode.LOAD_VARIABLE:
                var = byte_code.variables[arg]
                assert (isinstance(var, objects.Variable))
                # print "- appending value %s" % var.value.dump()
                stack.append(var.value)

            elif opcode == bytecode.STORE_VARIABLE:
                value = stack.pop()
                oldvar = byte_code.variables.get(arg, None)
                if isinstance(oldvar, objects.Variable):
                    byte_code.variables[arg] = objects.Variable(
                        oldvar.name, value)
                else:
                    byte_code.variables[arg] = objects.Variable("arg", value)
                stack.append(value)

            elif opcode == bytecode.STORE_ARRAY:
                values = []
                for i in range(arg):
                    values.append(stack.pop())
                stack.append(objects.Array(values))

            elif opcode == bytecode.STORE_DICT:
                values = objects.r_dict(objects.dict_eq, objects.dict_hash)
                for i in range(arg):
                    values[stack.pop()] = stack.pop()
                stack.append(objects.Dict(values))

            elif opcode == bytecode.PRINT:
                value = stack.pop()
                print(value.to_string())
                stack.append(objects.Null())

            elif opcode == bytecode.INDEX:
                left = stack.pop()
                right = stack.pop()
                result = left.index(right)
                stack.append(result)

            elif opcode == bytecode.BINARY_ADD:
                right = stack.pop()
                left = stack.pop()
                result = left.add(right)
                stack.append(result)

            elif opcode == bytecode.BINARY_SUB:
                right = stack.pop()
                left = stack.pop()
                result = left.sub(right)
                stack.append(result)

            elif opcode == bytecode.BINARY_MUL:
                right = stack.pop()
                left = stack.pop()
                result = left.mul(right)
                stack.append(result)

            elif opcode == bytecode.BINARY_DIV:
                right = stack.pop()
                left = stack.pop()
                result = left.div(right)
                stack.append(result)

            elif opcode == bytecode.BINARY_NEQ:
                right = stack.pop()
                left = stack.pop()
                result = left.equals(right)
                result.boolvalue = not result.boolvalue
                stack.append(result)

            elif opcode == bytecode.BINARY_EQ:
                right = stack.pop()
                left = stack.pop()
                result = left.equals(right)
                stack.append(result)

            elif opcode == bytecode.BINARY_GT:
                right = stack.pop()
                left = stack.pop()
                result = left.gt(right)
                stack.append(result)

            elif opcode == bytecode.BINARY_GTE:
                right = stack.pop()
                left = stack.pop()
                result = left.gte(right)
                stack.append(result)

            elif opcode == bytecode.BINARY_LT:
                right = stack.pop()
                left = stack.pop()
                result = left.lt(right)
                stack.append(result)

            elif opcode == bytecode.BINARY_LTE:
                right = stack.pop()
                left = stack.pop()
                result = left.lte(right)
                stack.append(result)

            elif opcode == bytecode.RETURN:
                if arg == 1:
                    if len(stack) > 0:
                        result = stack.pop()
                        return result
                    return objects.Null()

            elif opcode == bytecode.JUMP_IF_NOT_ZERO:
                val = stack.pop()
                assert (isinstance(val, objects.BaseBox))

                result = val.equals(objects.Boolean(True))
                assert (isinstance(result, objects.Boolean))
                if result.value:
                    pc = arg

            elif opcode == bytecode.JUMP_IF_ZERO:
                val = stack.pop()
                assert (isinstance(val, objects.BaseBox))
                result = val.equals(objects.Boolean(True))
                assert (isinstance(result, objects.Boolean))
                if not result.value:
                    pc = arg

            elif opcode == bytecode.JUMP:
                pc = arg

            elif opcode == bytecode.CALL:
                assert (isinstance(byte_code.variables[arg], objects.Variable))
                val = byte_code.variables[arg].value
                if isinstance(val, objects.Function):
                    func = val.code
                    self.copy_context(byte_code, func)
                    args = []
                    if len(func.arguments) > len(stack):
                        raise Exception("Not enough arguments")

                    for i in range(0, len(func.arguments)):
                        args.append(stack.pop())
                    stack.append(self.interpret(func, args))
                elif isinstance(val, objects.ExternalFunction):
                    # call
                    func = val.fn
                    arglen = val.args
                    args = []
                    for i in range(0, arglen):
                        args.append(stack.pop())
                    result = func(args)
                    stack.append(result)
                else:
                    raise Exception("Not a function")
        return stack[len(stack) - 1]