def optimize_apply(self, env, compiler, args): #1. ((lambda () body)) => body if len(self.params)==0: return self.body.optimize(env, compiler) #2. (lamda x: ...x...)(y) => (lambda : ... y ...)() bindings = {} new_params, new_args = (), () for i, p in enumerate(self.params): arg = args[i] if arg.side_effects(): new_params += (p,) new_args += (arg,) continue else: ref_count = compiler.ref_count.get(p, 0) if ref_count==0: continue elif ref_count==1: bindings[p] = arg else: if arg.code_size()*ref_count>MAX_EXTEND_CODE_SIZE: # a(...y...), and a is (lamda ...x...: ...x...), #then convert as above if code size is ok. new_params += (p,) new_args += (arg,) else: bindings[p] = arg if new_params: if bindings: return Apply(self.new(new_params, self.body.subst(bindings).optimize(env, compiler)), tuple(arg.optimize(env, compiler) for arg in new_args)) else: if len(new_params)!=len(self.params): Apply(self.new(new_params, self.body.subst(bindings).optimize(env, compiler)), tuple(arg.optimize(env, compiler) for arg in new_args)) else: return Apply(self.new(new_params, self.body.optimize(env, compiler)), optimize_args(new_args, env, compiler)) else: if bindings: return self.body.subst(bindings).optimize(env, compiler) else: return self.body.optimize(env, compiler)
def optimize(self, env, compiler): args = optimize_args(self.args, env, compiler) if isinstance(self.caller, Var): if self.caller not in compiler.recursive_call_path: caller = self.caller.optimize(env, compiler) if isinstance(caller, Lamda): compiler.recursive_call_path.append(self.caller) result = caller.optimize_apply(env, compiler, args) compiler.recursive_call_path.pop() return result else: return self.__class__(caller, args) else: return self.__class__(self.caller, args) elif isinstance(self.caller, Lamda): return self.caller.optimize_apply(env, compiler, args) else: caller = self.caller.optimize(env, compiler) if isinstance(caller, Lamda): return caller.optimize_apply(env, compiler, args) else: return self.__class__(caller, args)