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)
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)
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)
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]