diff --git a/compiler/erg_compiler/codegen.rs b/compiler/erg_compiler/codegen.rs index c01da9d7..09e1f654 100644 --- a/compiler/erg_compiler/codegen.rs +++ b/compiler/erg_compiler/codegen.rs @@ -2074,13 +2074,24 @@ impl PyCodeGenerator { fn emit_call_method(&mut self, obj: Expr, method_name: Identifier, args: Args) { log!(info "entered {}", fn_name!()); - if &method_name.inspect()[..] == "update!" { - if self.py_version.minor >= Some(11) { - return self.emit_call_update_311(obj, args); - } else { - return self.emit_call_update_310(obj, args); + match &method_name.inspect()[..] { + "update!" => { + if self.py_version.minor >= Some(11) { + return self.emit_call_update_311(obj, args); + } else { + return self.emit_call_update_310(obj, args); + } } - } else if let Some(func_name) = debind(&method_name) { + "return" if obj.ref_t().is_callable() => { + return self.emit_return_instr(args); + } + // TODO: create `Generator` type + "yield" /* if obj.ref_t().is_callable() */ => { + return self.emit_yield_instr(args); + } + _ => {} + } + if let Some(func_name) = debind(&method_name) { return self.emit_call_fake_method(obj, func_name, method_name, args); } let is_py_api = method_name.is_py_api(); @@ -2198,6 +2209,29 @@ impl PyCodeGenerator { self.emit_load_const(ValueObj::None); } + // TODO: use exception + fn emit_return_instr(&mut self, mut args: Args) { + log!(info "entered {}", fn_name!()); + if args.is_empty() { + self.emit_load_const(ValueObj::None); + } else { + self.emit_expr(args.remove(0)); + } + self.write_instr(RETURN_VALUE); + self.write_arg(0); + } + + fn emit_yield_instr(&mut self, mut args: Args) { + log!(info "entered {}", fn_name!()); + if args.is_empty() { + self.emit_load_const(ValueObj::None); + } else { + self.emit_expr(args.remove(0)); + } + self.write_instr(YIELD_VALUE); + self.write_arg(0); + } + /// 1.abs() => abs(1) fn emit_call_fake_method( &mut self, diff --git a/compiler/erg_compiler/context/initialize/mod.rs b/compiler/erg_compiler/context/initialize/mod.rs index 124f331d..160c4929 100644 --- a/compiler/erg_compiler/context/initialize/mod.rs +++ b/compiler/erg_compiler/context/initialize/mod.rs @@ -1612,6 +1612,14 @@ impl Context { None, ))); range.register_builtin_const("__getitem__", Public, get_item); + let mut g_callable = Self::builtin_mono_class("GenericCallable", 2); + g_callable.register_superclass(Obj, &obj); + let t_return = fn1_met(mono("GenericCallable"), Obj, Never).quantify(); + g_callable.register_builtin_impl("return", t_return, Immutable, Public); + let mut g_generator = Self::builtin_mono_class("GenericGenerator", 2); + g_generator.register_superclass(mono("GenericCallable"), &g_callable); + let t_yield = fn1_met(mono("GenericGenerator"), Obj, Never).quantify(); + g_generator.register_builtin_impl("yield", t_yield, Immutable, Public); /* Proc */ let mut proc = Self::builtin_mono_class("Proc", 2); proc.register_superclass(Obj, &obj); @@ -1698,6 +1706,20 @@ impl Context { self.register_builtin_type(mono("File!"), file_mut, vis, Const, Some("File")); self.register_builtin_type(array_mut_t, array_mut_, vis, Const, Some("list")); self.register_builtin_type(set_mut_t, set_mut_, vis, Const, Some("set")); + self.register_builtin_type( + mono("GenericCallable"), + g_callable, + vis, + Const, + Some("Callable"), + ); + self.register_builtin_type( + mono("GenericGenerator"), + g_generator, + vis, + Const, + Some("Generator"), + ); if !self.cfg.python_compatible_mode { self.register_builtin_type(module_t, module, vis, Const, Some("ModuleType")); self.register_builtin_type(mono("Obj!"), obj_mut, vis, Const, Some("object"));