def resume_compilation(self): lambda_walker = SkeletonWalker(self.walker) w_formals = self.expr_list[0] lambda_body = self.expr_list[1:] # decoding lambda arguments and test them arg_list = [] w_rest = scmlist2py(w_formals, arg_list) for w_argname in arg_list: if not w_argname.is_symbol(): raise SchemeSyntaxError('lambda -- formal varargs should be ' 'nothing but a symbol, got %s' % w_argname.to_string()) lambda_walker.nb_args = len(arg_list) # set positional argcount if w_rest.is_null(): lambda_walker.varargs_p = False else: if not w_rest.is_symbol(): raise SchemeSyntaxError('lambda -- formal varargs should be ' 'nothing but a symbol, got %s' % w_rest.to_string()) else: lambda_walker.varargs_p = True # fill in the frame slots using those arguments for w_argname in arg_list: frame_slot_repr = FrameValueRepr(lambda_walker.alloc_frame_slot()) lambda_walker.local_variables[w_argname.to_string()] \ = frame_slot_repr # if vararg if lambda_walker.varargs_p: frame_slot_repr = FrameValueRepr(lambda_walker.alloc_frame_slot()) lambda_walker.local_variables[w_rest.to_string()] \ = frame_slot_repr # compile the body. XXX: create a global skeleton table like lua? lambda_walker.visit_list_of_expr(lambda_body) w_lambda_skeleton = lambda_walker.to_closure_skeleton() self.walker.instrs[self.instrindex] = BuildClosure( self.dest_val_repr.to_index(), self.walker.new_skel_slot(w_lambda_skeleton))
def visit_application(self, w_proc, w_args, flag): lst = [] w_rest = scmlist2py(w_args, lst) if not w_rest.is_null(): raise SchemeSyntaxError('application -- not a well-formed list') # allocate len(lst) + 1 frame slots # XXX: ensure they sit together. proc_slot = FrameValueRepr(self.alloc_frame_slot()) arg_slots = [FrameValueRepr(self.alloc_frame_slot()) for i in xrange(len(lst))] # evaluate the proc and the args proc_visit_flag = CompilationFlag(0, desired_destination=proc_slot) proc_val_repr = self.visit(w_proc, proc_visit_flag) self.set_frame_slot(proc_slot, proc_val_repr) # could be no-op for i in xrange(len(lst)): # since enumerate is not supported in RPython... w_expr = lst[i] dest_slot = arg_slots[i] arg_visit_flag = CompilationFlag(0, desired_destination=dest_slot) arg_val_repr = self.visit(w_expr, arg_visit_flag) self.set_frame_slot(dest_slot, arg_val_repr) if flag.has_dest(): result_value_repr = flag.get_dest() else: result_value_repr = FrameValueRepr(self.alloc_frame_slot()) # call and return if flag.has_tco(): self.emit(TailCall(result_value_repr.to_index(), proc_slot.to_index(), len(lst))) else: self.emit(Call(result_value_repr.to_index(), proc_slot.to_index(), len(lst))) return result_value_repr
def visit_special_form(self, w_proc, w_args, flag): sval = w_proc.to_string() if sval == 'define': # @see visit_binding lst = [] w_rest = scmlist2py(w_args, lst) if len(lst) != 2 or not w_rest.is_null(): # (define name expr) raise SchemeSyntaxError, 'define require 2 args' w_name = lst[0] if not w_name.is_symbol(): raise SchemeSyntaxError, ('define require the first arg ' 'to be symbol -- got %s' % w_name.to_string()) w_expr = lst[1] value_repr = self.visit(w_expr) self.visit_binding(w_name, value_repr) # create binding for define return ConstValueRepr(self.new_const_slot(w_unspecified)) elif sval == 'set!': lst = [] w_rest = scmlist2py(w_args, lst) if len(lst) != 2 or not w_rest.is_null(): # (define name expr) raise SchemeSyntaxError, 'set! require 2 args' w_name = lst[0] if not w_name.is_symbol(): raise SchemeSyntaxError, ('set! require the first arg ' 'to be symbol -- got %s' % w_name.to_string()) w_expr = lst[1] value_repr = self.visit(w_expr) self.visit_rebind(w_name, value_repr) # change binding for define return ConstValueRepr(self.new_const_slot(w_unspecified)) elif sval == 'if': # (if pred iftrue [else]) if flag.has_dest(): result_value_repr = flag.get_dest() else: result_value_repr = FrameValueRepr(self.alloc_frame_slot()) lst = [] w_rest = scmlist2py(w_args, lst) if len(lst) not in (2, 3) or not w_rest.is_null(): raise SchemeSyntaxError, 'if require 2 to 3 args' w_pred = lst[0] w_iftrue = lst[1] # predicate value repr # XXX: Note that this is a temporary variable and can be reused # if we return this frame slot to the allocator. pred_local_val = self.cast_to_local(self.visit(w_pred)) # saved instr index, for jump to else iftrue_branch_instr_index = len(self.instrs) self.instrs.append(None) # branch length to be calculated # if_true instrs iftrue_result_repr = self.visit(w_iftrue, flag) self.set_frame_slot(result_value_repr, iftrue_result_repr) iftrue_branch_jumpby = (len(self.instrs) - iftrue_branch_instr_index) self.instrs[iftrue_branch_instr_index] = BranchIfFalse( pred_local_val.to_index(), iftrue_branch_jumpby) iffalse_branch_instr_index = len(self.instrs) self.instrs.append(None) # branch length to be calculated if len(lst) == 2: self.set_frame_slot(result_value_repr, ConstValueRepr(self.new_const_slot(w_unspecified))) else: # has else w_iffalse = lst[2] iffalse_result_repr = self.visit(w_iffalse, flag) self.set_frame_slot(result_value_repr, iffalse_result_repr) iffalse_branch_jumpby = (len(self.instrs) - iffalse_branch_instr_index - 1) self.instrs[iffalse_branch_instr_index] = Branch( iffalse_branch_jumpby) return result_value_repr elif sval == 'quote': # (quote datum) lst = [] w_rest = scmlist2py(w_args, lst) if len(lst) != 1 or not w_rest.is_null(): raise SchemeSyntaxError, 'quote require 1 arg' return ConstValueRepr(self.new_const_slot(lst[0])) elif sval == 'lambda': lst = [] w_rest = scmlist2py(w_args, lst) if not w_rest.is_null(): raise SchemeSyntaxError, 'lambda -- not a well-formed list' if len(lst) < 2: raise SchemeSyntaxError, 'lambda -- missing expression' if flag.has_dest(): frame_val_repr = flag.get_dest() else: frame_val_repr = FrameValueRepr(self.alloc_frame_slot()) current_instr_pos = len(self.instrs) self.instrs.append(None) # compile the lambdas in the end self.deferred_lambdas.append(DeferredLambdaCompilation( self, lst, current_instr_pos, frame_val_repr)) return frame_val_repr elif sval == 'begin': lst = [] w_rest = scmlist2py(w_args, lst) if not w_rest.is_null(): raise SchemeSyntaxError, 'begin -- not a well-formed list' for i, w_expr in enumerate(lst): if i != len(lst) - 1: self.visit(w_expr) else: return self.visit(w_expr, flag) # when there is no args: return unspecified return ConstValueRepr(self.new_const_slot(w_unspecified)) else: raise ValueError, 'not a special form'