def compile_functiondeclaration(context, ast): assert(isinstance(ast,ast_objects.FunctionDeclaration)) # new context, but need access to outer context ctx = Context() fn_index = context.register_variable(ast.name) for v in context.constants: ctx.constants.append(v) for k, v in context.variables.iteritems(): ctx.variables[k] = v indexes = [] if type(ast.args) is not ast_objects.Null: for arg in reversed(ast.args.get_statements()): assert(isinstance(arg,ast_objects.Variable)) name = str(arg.getname()) index = ctx.register_variable(name) indexes.append(index) #context.emit(bytecode.STORE_VARIABLE, index) compile_block(ctx,ast.block) fn = ctx.build(indexes, name=ast.name) context.variables[fn_index] = objects.Variable(ast.name,objects.Function(ast.name,fn)) ctx.variables[fn_index] = objects.Variable(ast.name,objects.Function(ast.name,fn)) context.emit(bytecode.LOAD_VARIABLE,fn_index)
def import_prelude(self): index = self.context.register_variable("print") self.context.variables[index] = objects.Variable( "print", objects.ExternalFunction("print", prelude.print_fn, 1)) index = self.context.register_variable("readline") self.context.variables[index] = objects.Variable( "readline", objects.ExternalFunction("readline", prelude.readline, 1))
def register_variable(self, name): index = len(self.variables) self.variables[index] = objects.Variable(name,objects.Null()) return 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]