diff --git a/compiler/erg_common/dict.rs b/compiler/erg_common/dict.rs index 98920f17..6785e9d4 100644 --- a/compiler/erg_common/dict.rs +++ b/compiler/erg_common/dict.rs @@ -153,6 +153,14 @@ impl Dict { self.dict.get_mut(k) } + pub fn get_key_value(&self, k: &Q) -> Option<(&K, &V)> + where + K: Borrow, + Q: Hash + Eq, + { + self.dict.get_key_value(k) + } + #[inline] pub fn contains_key(&self, k: &Q) -> bool where diff --git a/compiler/erg_common/error.rs b/compiler/erg_common/error.rs index e00438bc..4b0df9f5 100644 --- a/compiler/erg_common/error.rs +++ b/compiler/erg_common/error.rs @@ -203,9 +203,9 @@ impl From<&str> for ErrorKind { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Location { RangePair { - ln_begin: usize, + ln_first: (usize, usize), col_first: (usize, usize), - ln_end: usize, + ln_second: (usize, usize), col_second: (usize, usize), }, Range { @@ -240,16 +240,19 @@ impl Location { pub fn pair(lhs: Self, rhs: Self) -> Self { Self::RangePair { - ln_begin: lhs.ln_begin().unwrap(), + ln_first: (lhs.ln_begin().unwrap(), lhs.ln_end().unwrap()), col_first: (lhs.col_begin().unwrap(), lhs.col_end().unwrap()), - ln_end: rhs.ln_end().unwrap(), + ln_second: (rhs.ln_begin().unwrap(), rhs.ln_end().unwrap()), col_second: (rhs.col_begin().unwrap(), rhs.col_end().unwrap()), } } pub const fn ln_begin(&self) -> Option { match self { - Self::RangePair { ln_begin, .. } + Self::RangePair { + ln_first: (ln_begin, _), + .. + } | Self::Range { ln_begin, .. } | Self::LineRange(ln_begin, _) | Self::Line(ln_begin) => Some(*ln_begin), @@ -259,7 +262,10 @@ impl Location { pub const fn ln_end(&self) -> Option { match self { - Self::RangePair { ln_end, .. } + Self::RangePair { + ln_second: (_, ln_end), + .. + } | Self::Range { ln_end, .. } | Self::LineRange(ln_end, _) | Self::Line(ln_end) => Some(*ln_end), @@ -351,6 +357,41 @@ impl ErrorCore { pub const VBAR_UNICODE: &str = "│"; pub const VBAR_BREAK_UNICODE: &str = "·"; +fn format_code_and_pointer( + e: &E, + ln_begin: usize, + ln_end: usize, + col_begin: usize, + col_end: usize, +) -> String { + let codes = if e.input() == &Input::REPL { + vec![e.input().reread()] + } else { + e.input().reread_lines(ln_begin, ln_end) + }; + let mut res = CYAN.to_string(); + let final_step = ln_end - ln_begin; + for (i, lineno) in (ln_begin..=ln_end).enumerate() { + let mut pointer = " ".repeat(lineno.to_string().len() + 2); // +2 means `| ` + if i == 0 && i == final_step { + pointer += &" ".repeat(col_begin); + pointer += &"^".repeat(cmp::max(1, col_end - col_begin)); + } else if i == 0 { + pointer += &" ".repeat(col_begin); + pointer += &"^".repeat(cmp::max(1, codes[i].len() - col_begin)); + } else if i == final_step { + pointer += &"^".repeat(col_end); + } else { + pointer += &"^".repeat(cmp::max(1, codes[i].len())); + } + res += &format!( + "{lineno}{VBAR_UNICODE} {code}\n{pointer}\n", + code = codes[i] + ); + } + res + RESET +} + /// format: /// ```console /// Error[#{.errno}]: File {file}, line {.loc (as line)}, in {.caused_by} @@ -430,13 +471,15 @@ pub trait ErrorDisplay { Location::Range { ln_begin, ln_end, .. } if ln_begin == ln_end => format!(", line {ln_begin}"), - Location::RangePair { - ln_begin, ln_end, .. - } - | Location::Range { + Location::Range { ln_begin, ln_end, .. } | Location::LineRange(ln_begin, ln_end) => format!(", line {ln_begin}..{ln_end}"), + Location::RangePair { + ln_first: (l1, l2), + ln_second: (l3, l4), + .. + } => format!(", line {l1}..{l2}, {l3}..{l4}"), Location::Line(lineno) => format!(", line {lineno}"), Location::Unknown => "".to_string(), }; @@ -454,40 +497,27 @@ pub trait ErrorDisplay { fn format_code_and_pointer(&self) -> String { match self.core().loc { - Location::RangePair { .. } => todo!(), + Location::RangePair { + ln_first, + col_first, + ln_second, + col_second, + } => { + format_code_and_pointer(self, ln_first.0, ln_first.1, col_first.0, col_first.1) + + &format_code_and_pointer( + self, + ln_second.0, + ln_second.1, + col_second.0, + col_second.1, + ) + } Location::Range { ln_begin, col_begin, ln_end, col_end, - } => { - let codes = if self.input() == &Input::REPL { - vec![self.input().reread()] - } else { - self.input().reread_lines(ln_begin, ln_end) - }; - let mut res = CYAN.to_string(); - let final_step = ln_end - ln_begin; - for (i, lineno) in (ln_begin..=ln_end).enumerate() { - let mut pointer = " ".repeat(lineno.to_string().len() + 2); // +2 means `| ` - if i == 0 && i == final_step { - pointer += &" ".repeat(col_begin); - pointer += &"^".repeat(cmp::max(1, col_end - col_begin)); - } else if i == 0 { - pointer += &" ".repeat(col_begin); - pointer += &"^".repeat(cmp::max(1, codes[i].len() - col_begin)); - } else if i == final_step { - pointer += &"^".repeat(col_end); - } else { - pointer += &"^".repeat(cmp::max(1, codes[i].len())); - } - res += &format!( - "{lineno}{VBAR_UNICODE} {code}\n{pointer}\n", - code = codes[i] - ); - } - res + RESET - } + } => format_code_and_pointer(self, ln_begin, ln_end, col_begin, col_end), Location::LineRange(ln_begin, ln_end) => { let codes = if self.input() == &Input::REPL { vec![self.input().reread()] diff --git a/compiler/erg_common/opcode.rs b/compiler/erg_common/opcode.rs index 53fdcbfc..61d66882 100644 --- a/compiler/erg_common/opcode.rs +++ b/compiler/erg_common/opcode.rs @@ -63,6 +63,7 @@ pub enum Opcode { PRINT_EXPR = 70, LOAD_BUILD_CLASS = 71, LOAD_ASSERTION_ERROR = 74, + LIST_TO_TUPLE = 82, RETURN_VALUE = 83, /* ↓ These opcodes take an arg */ STORE_NAME = 90, @@ -101,8 +102,10 @@ pub enum Opcode { LOAD_DEREF = 136, STORE_DEREF = 137, CALL_FUNCTION_KW = 141, + CALL_FUNCTION_EX = 142, LOAD_METHOD = 160, CALL_METHOD = 161, + LIST_EXTEND = 162, // Erg-specific opcodes (must have a unary `ERG_`) // Define in descending order from 219, 255 ERG_POP_NTH = 196, @@ -205,6 +208,7 @@ impl From for Opcode { 70 => PRINT_EXPR, 71 => LOAD_BUILD_CLASS, 74 => LOAD_ASSERTION_ERROR, + 82 => LIST_TO_TUPLE, 83 => RETURN_VALUE, /* ↓ These opcodes take an arg */ 90 => STORE_NAME, @@ -243,8 +247,10 @@ impl From for Opcode { 136 => LOAD_DEREF, 137 => STORE_DEREF, 141 => CALL_FUNCTION_KW, + 142 => CALL_FUNCTION_EX, 160 => LOAD_METHOD, 161 => CALL_METHOD, + 162 => LIST_EXTEND, // Erg-specific opcodes 196 => ERG_POP_NTH, 197 => ERG_PEEK_NTH, diff --git a/compiler/erg_common/traits.rs b/compiler/erg_common/traits.rs index d0065756..e65b2990 100644 --- a/compiler/erg_common/traits.rs +++ b/compiler/erg_common/traits.rs @@ -407,7 +407,10 @@ pub trait Locational { fn ln_begin(&self) -> Option { match self.loc() { - Location::RangePair { ln_begin, .. } + Location::RangePair { + ln_first: (ln_begin, _), + .. + } | Location::Range { ln_begin, .. } | Location::LineRange(ln_begin, _) => Some(ln_begin), Location::Line(lineno) => Some(lineno), @@ -417,7 +420,10 @@ pub trait Locational { fn ln_end(&self) -> Option { match self.loc() { - Location::RangePair { ln_end, .. } + Location::RangePair { + ln_second: (_, ln_end), + .. + } | Location::Range { ln_end, .. } | Location::LineRange(_, ln_end) => Some(ln_end), Location::Line(lineno) => Some(lineno), diff --git a/compiler/erg_compiler/codegen.rs b/compiler/erg_compiler/codegen.rs index 641357e3..f86b82cb 100644 --- a/compiler/erg_compiler/codegen.rs +++ b/compiler/erg_compiler/codegen.rs @@ -32,7 +32,7 @@ use crate::error::{CompileError, CompileErrors, CompileResult}; use crate::hir::AttrDef; use crate::hir::Attribute; use crate::hir::{ - Accessor, Args, Array, Block, Call, ClassDef, Def, DefBody, Expr, Literal, Local, Signature, + Accessor, Args, Array, Block, Call, ClassDef, DefBody, Expr, Literal, Local, PosArg, Signature, SubrSignature, Tuple, VarSignature, HIR, }; use AccessKind::*; @@ -202,7 +202,7 @@ fn convert_to_python_attr(class: &str, uniq_obj_name: Option<&str>, name: Str) - ("Array!", _, "push!") => Str::ever("append"), ("Complex" | "Real" | "Int" | "Nat" | "Float", _, "Real") => Str::ever("real"), ("Complex" | "Real" | "Int" | "Nat" | "Float", _, "Imag") => Str::ever("imag"), - (_, _, "new" | "__new__") => Str::ever("__call__"), + (_, _, "__new__") => Str::ever("__call__"), ("StringIO!", _, "getvalue!") => Str::ever("getvalue"), ("Module", Some("importlib"), "reload!") => Str::ever("reload"), ("Module", Some("random"), "randint!") => Str::ever("randint"), @@ -446,7 +446,7 @@ impl CodeGenerator { self.stack_inc(); } - fn local_search(&self, name: &str, acc_kind: AccessKind) -> Option { + fn local_search(&self, name: &str, _acc_kind: AccessKind) -> Option { let current_is_toplevel = self.cur_block() == self.toplevel_block(); if let Some(idx) = self .cur_block_codeobj() @@ -454,11 +454,7 @@ impl CodeGenerator { .iter() .position(|n| &**n == name) { - if current_is_toplevel || !acc_kind.is_local() { - Some(Name::local(idx)) - } else { - Some(Name::global(idx)) - } + Some(Name::local(idx)) } else if let Some(idx) = self .cur_block_codeobj() .varnames @@ -667,6 +663,8 @@ impl CodeGenerator { } } + /// Ergの文法として、属性への代入は存在しない(必ずオブジェクトはすべての属性を初期化しなくてはならないため) + /// この関数はPythonへ落とし込むときに使う fn store_acc(&mut self, acc: Accessor) { log!(info "entered {} ({acc})", fn_name!()); match acc { @@ -719,6 +717,11 @@ impl CodeGenerator { .non_defaults .iter() .map(|p| p.inspect().map(|s| &s[..]).unwrap_or("_")) + .chain(if let Some(var_args) = ¶ms.var_args { + vec![var_args.inspect().map(|s| &s[..]).unwrap_or("_")] + } else { + vec![] + }) .chain( params .defaults @@ -783,7 +786,7 @@ impl CodeGenerator { self.emit_store_instr(sig.ident, Name); } - fn emit_subr_def(&mut self, sig: SubrSignature, body: DefBody) { + fn emit_subr_def(&mut self, class_name: Option<&str>, sig: SubrSignature, body: DefBody) { log!(info "entered {} ({sig} = {})", fn_name!(), body.block); let name = sig.ident.inspect().clone(); let mut opcode_flag = 0u8; @@ -800,7 +803,11 @@ impl CodeGenerator { self.write_arg(cellvars_len); opcode_flag += 8; } - self.emit_load_const(name.clone()); + if let Some(class) = class_name { + self.emit_load_const(Str::from(format!("{class}.{name}"))); + } else { + self.emit_load_const(name); + } self.write_instr(MAKE_FUNCTION); self.write_arg(opcode_flag); // stack_dec: + -> @@ -989,12 +996,15 @@ impl CodeGenerator { Expr::Accessor(Accessor::Local(local)) => { self.emit_call_local(local, call.args).unwrap() } - other => todo!("calling {other}"), + other => { + self.codegen_expr(other); + self.emit_args(call.args, Name); + } } } } - fn emit_call_local(&mut self, local: Local, mut args: Args) -> CompileResult<()> { + fn emit_call_local(&mut self, local: Local, args: Args) -> CompileResult<()> { log!(info "entered {}", fn_name!()); match &local.inspect()[..] { "assert" => self.emit_assert_instr(args), @@ -1008,33 +1018,13 @@ impl CodeGenerator { self.emit_load_name_instr(ident).unwrap_or_else(|e| { self.errs.push(e); }); - let argc = args.len(); - let mut kws = Vec::with_capacity(args.kw_len()); - while let Some(arg) = args.try_remove_pos(0) { - self.codegen_expr(arg.expr); - } - while let Some(arg) = args.try_remove_kw(0) { - kws.push(ValueObj::Str(arg.keyword.content.clone())); - self.codegen_expr(arg.expr); - } - let kwsc = if !kws.is_empty() { - let kws_tuple = ValueObj::from(kws); - self.emit_load_const(kws_tuple); - self.write_instr(CALL_FUNCTION_KW); - 1 - } else { - self.write_instr(CALL_FUNCTION); - 0 - }; - self.write_arg(argc as u8); - // (1 (subroutine) + argc + kwsc) input objects -> 1 return object - self.stack_dec_n((1 + argc + kwsc) - 1); + self.emit_args(args, Name); Ok(()) } } } - fn emit_call_method(&mut self, obj: Expr, method_name: Token, mut args: Args) { + fn emit_call_method(&mut self, obj: Expr, method_name: Token, args: Args) { log!(info "entered {}", fn_name!()); if &method_name.inspect()[..] == "update!" { return self.emit_call_update(obj, args); @@ -1050,11 +1040,29 @@ impl CodeGenerator { .unwrap_or_else(|err| { self.errs.push(err); }); + self.emit_args(args, Method); + } + + fn emit_args(&mut self, mut args: Args, kind: AccessKind) { let argc = args.len(); + let pos_len = args.pos_args.len(); let mut kws = Vec::with_capacity(args.kw_len()); while let Some(arg) = args.try_remove_pos(0) { self.codegen_expr(arg.expr); } + if let Some(var_args) = &args.var_args { + if pos_len > 0 { + self.write_instr(Opcode::BUILD_LIST); + self.write_arg(pos_len as u8); + } + self.codegen_expr(var_args.expr.clone()); + if pos_len > 0 { + self.write_instr(Opcode::LIST_EXTEND); + self.write_arg(1); + self.write_instr(Opcode::LIST_TO_TUPLE); + self.write_arg(0); + } + } while let Some(arg) = args.try_remove_kw(0) { kws.push(ValueObj::Str(arg.keyword.content.clone())); self.codegen_expr(arg.expr); @@ -1063,13 +1071,27 @@ impl CodeGenerator { let kws_tuple = ValueObj::from(kws); self.emit_load_const(kws_tuple); self.write_instr(CALL_FUNCTION_KW); + self.write_arg(argc as u8); 1 } else { - self.write_instr(CALL_METHOD); + if args.var_args.is_some() { + self.write_instr(CALL_FUNCTION_EX); + if kws.is_empty() { + self.write_arg(0); + } else { + self.write_arg(1); + } + } else { + if kind.is_method() { + self.write_instr(CALL_METHOD); + } else { + self.write_instr(CALL_FUNCTION); + } + self.write_arg(argc as u8); + } 0 }; - self.write_arg(argc as u8); - // (1 (method) + argc + kwsc) input objects -> 1 return object + // (1 (subroutine) + argc + kwsc) input objects -> 1 return object self.stack_dec_n((1 + argc + kwsc) - 1); } @@ -1149,7 +1171,7 @@ impl CodeGenerator { } Expr::Accessor(acc) => self.codegen_acc(acc), Expr::Def(def) => match def.sig { - Signature::Subr(sig) => self.emit_subr_def(sig, def.body), + Signature::Subr(sig) => self.emit_subr_def(None, sig, def.body), Signature::Var(sig) => self.emit_var_def(sig, def.body), }, Expr::ClassDef(class) => self.emit_class_def(class), @@ -1420,14 +1442,17 @@ impl CodeGenerator { let mod_name = self.toplevel_block_codeobj().name.clone(); self.emit_load_const(mod_name); self.emit_store_instr(Identifier::public("__module__"), Name); - self.emit_load_const(name); + self.emit_load_const(name.clone()); self.emit_store_instr(Identifier::public("__qualname__"), Name); + self.emit_init_method(&class.sig, class.__new__.clone()); if class.need_to_gen_new { - self.emit_auto_new(&class.sig, class.__new__); + self.emit_new_func(&class.sig, class.__new__); } - // TODO: サブルーチンはT.subという書式でSTORE for def in class.private_methods.into_iter() { - self.codegen_expr(Expr::Def(def)); + match def.sig { + Signature::Subr(sig) => self.emit_subr_def(Some(&name[..]), sig, def.body), + Signature::Var(sig) => self.emit_var_def(sig, def.body), + } // TODO: discard if self.cur_block().stack_len == 1 { self.emit_pop_top(); @@ -1435,7 +1460,10 @@ impl CodeGenerator { } for mut def in class.public_methods.into_iter() { def.sig.ident_mut().dot = Some(Token::dummy()); - self.codegen_expr(Expr::Def(def)); + match def.sig { + Signature::Subr(sig) => self.emit_subr_def(Some(&name[..]), sig, def.body), + Signature::Var(sig) => self.emit_var_def(sig, def.body), + } // TODO: discard if self.cur_block().stack_len == 1 { self.emit_pop_top(); @@ -1474,9 +1502,10 @@ impl CodeGenerator { unit.codeobj } - fn emit_auto_new(&mut self, sig: &Signature, __new__: Type) { + fn emit_init_method(&mut self, sig: &Signature, __new__: Type) { log!(info "entered {}", fn_name!()); let line = sig.ln_begin().unwrap(); + let class_name = sig.ident().inspect(); let ident = Identifier::public_with_line(Token::dummy(), Str::ever("__init__"), line); let param_name = fresh_varname(); let param = VarName::from_str_and_line(Str::from(param_name.clone()), line); @@ -1484,7 +1513,7 @@ impl CodeGenerator { let self_param = VarName::from_str_and_line(Str::ever("self"), line); let self_param = ParamSignature::new(ParamPattern::VarName(self_param), None, None); let params = Params::new(vec![self_param, param], None, vec![], None); - let sig = Signature::Subr(SubrSignature::new(ident, params.clone(), __new__.clone())); + let subr_sig = SubrSignature::new(ident, params.clone(), __new__.clone()); let mut attrs = vec![]; match __new__.non_default_params().unwrap()[0].typ() { // {x = Int; y = Int} @@ -1519,8 +1548,49 @@ impl CodeGenerator { } let block = Block::new(attrs); let body = DefBody::new(Token::dummy(), block, DefId(0)); - let init_def = Def::new(sig, body.clone()); - self.codegen_expr(Expr::Def(init_def)); + self.emit_subr_def(Some(class_name), subr_sig, body); + } + + /// ```python + /// class C: + /// # __new__ => __call__ + /// def new(x): return C.__call__(x) + /// ``` + fn emit_new_func(&mut self, sig: &Signature, __new__: Type) { + log!(info "entered {}", fn_name!()); + let class_name = sig.ident().inspect(); + let line = sig.ln_begin().unwrap(); + let ident = Identifier::public_with_line(Token::dummy(), Str::ever("new"), line); + let param_name = fresh_varname(); + let param = VarName::from_str_and_line(Str::from(param_name.clone()), line); + let param = ParamSignature::new(ParamPattern::VarName(param), None, None); + let sig = SubrSignature::new( + ident, + Params::new(vec![param], None, vec![], None), + __new__.clone(), + ); + let arg = PosArg::new(Expr::Accessor(Accessor::local( + Token::symbol_with_line(¶m_name[..], line), + Type::Failure, + ))); + let class = Expr::Accessor(Accessor::local( + Token::symbol_with_line(class_name, line), + Type::Failure, + )); + let class_new = Expr::Accessor(Accessor::attr( + class, + Token::symbol_with_line("__new__", line), + Type::Failure, + )); + let call = Expr::Call(Call::new( + class_new, + None, + Args::new(vec![arg], None, vec![], None), + Type::Failure, + )); + let block = Block::new(vec![call]); + let body = DefBody::new(Token::dummy(), block, DefId(0)); + self.emit_subr_def(Some(&class_name[..]), sig, body); } fn codegen_block(&mut self, block: Block, opt_name: Option, params: Vec) -> CodeObj { diff --git a/compiler/erg_compiler/context/inquire.rs b/compiler/erg_compiler/context/inquire.rs index 012dc4ee..d0a33aed 100644 --- a/compiler/erg_compiler/context/inquire.rs +++ b/compiler/erg_compiler/context/inquire.rs @@ -80,6 +80,10 @@ impl Context { }) } + pub(crate) fn get_local_kv(&self, name: &str) -> Option<(&VarName, &VarInfo)> { + self.locals.get_key_value(name) + } + fn get_context( &self, obj: &hir::Expr, diff --git a/compiler/erg_compiler/context/mod.rs b/compiler/erg_compiler/context/mod.rs index 923955a1..038f0cfa 100644 --- a/compiler/erg_compiler/context/mod.rs +++ b/compiler/erg_compiler/context/mod.rs @@ -490,6 +490,20 @@ impl Context { Self::poly_class(name, vec![], super_classes, super_traits, level) } + #[inline] + pub fn methods>(name: S, level: usize) -> Self { + Self::with_capacity( + name.into(), + ContextKind::MethodDefs, + vec![], + None, + vec![], + vec![], + 2, + level, + ) + } + #[inline] pub fn poly_patch>( name: S, diff --git a/compiler/erg_compiler/context/register.rs b/compiler/erg_compiler/context/register.rs index 02496b44..4727933b 100644 --- a/compiler/erg_compiler/context/register.rs +++ b/compiler/erg_compiler/context/register.rs @@ -508,6 +508,7 @@ impl Context { Ok(()) } + /// e.g. .new fn register_auto_impl( &mut self, name: &'static str, @@ -524,6 +525,23 @@ impl Context { } } + /// e.g. ::__new__ + fn register_fixed_auto_impl( + &mut self, + name: &'static str, + t: Type, + muty: Mutability, + vis: Visibility, + ) { + let name = VarName::from_static(name); + if self.locals.get(&name).is_some() { + panic!("already registered: {name}"); + } else { + self.locals + .insert(name, VarInfo::new(t, muty, vis, VarKind::FixedAuto, None)); + } + } + fn _register_gen_decl(&mut self, name: VarName, t: Type, vis: Visibility) { if self.decls.get(&name).is_some() { panic!("already registered: {name}"); @@ -577,11 +595,13 @@ impl Context { if gen.t.is_monomorphic() { let super_traits = gen.impls.iter().map(|to| to.typ().clone()).collect(); let mut ctx = Self::mono_class(gen.t.name(), vec![], super_traits, self.level); + let mut methods = Self::methods(gen.t.name(), self.level); let require = gen.require_or_sup.typ().clone(); let new_t = func1(require, gen.t.clone()); - ctx.register_auto_impl("__new__", new_t.clone(), Immutable, Private); + methods.register_fixed_auto_impl("__new__", new_t.clone(), Immutable, Private); // 必要なら、ユーザーが独自に上書きする - ctx.register_auto_impl("new", new_t, Immutable, Public); + methods.register_auto_impl("new", new_t, Immutable, Public); + ctx.method_defs.push((gen.t.clone(), methods)); self.register_gen_mono_type(gen, ctx, Const); } else { todo!() @@ -593,6 +613,7 @@ impl Context { let super_traits = gen.impls.iter().map(|to| to.typ().clone()).collect(); let mut ctx = Self::mono_class(gen.t.name(), super_classes, super_traits, self.level); + let mut methods = Self::methods(gen.t.name(), self.level); if let Some(sup) = self.rec_get_const_obj(&gen.require_or_sup.typ().name()) { let sup = enum_unwrap!(sup, ValueObj::Type); let param_t = match sup { @@ -607,9 +628,15 @@ impl Context { param_t.clone() }; let new_t = func1(param_t, gen.t.clone()); - ctx.register_auto_impl("__new__", new_t.clone(), Immutable, Private); + methods.register_fixed_auto_impl( + "__new__", + new_t.clone(), + Immutable, + Private, + ); // 必要なら、ユーザーが独自に上書きする - ctx.register_auto_impl("new", new_t, Immutable, Public); + methods.register_auto_impl("new", new_t, Immutable, Public); + ctx.method_defs.push((gen.t.clone(), methods)); self.register_gen_mono_type(gen, ctx, Const); } else { todo!("super class not found") diff --git a/compiler/erg_compiler/error.rs b/compiler/erg_compiler/error.rs index 2fffd1aa..55544d16 100644 --- a/compiler/erg_compiler/error.rs +++ b/compiler/erg_compiler/error.rs @@ -331,6 +331,30 @@ impl TyCheckError { ) } + pub fn duplicate_definition_error( + errno: usize, + loc: Location, + caused_by: Str, + name: &str, + ) -> Self { + let name = readable_name(name); + Self::new( + ErrorCore::new( + errno, + NameError, + loc, + switch_lang!( + "japanese" => format!("{name}は既に定義されています"), + "simplified_chinese" => format!("{name}已定义"), + "traditional_chinese" => format!("{name}已定義"), + "english" => format!("{name} is already defined"), + ), + Option::::None, + ), + caused_by, + ) + } + pub fn violate_decl_error( errno: usize, loc: Location, diff --git a/compiler/erg_compiler/hir.rs b/compiler/erg_compiler/hir.rs index cc289072..80305a0a 100644 --- a/compiler/erg_compiler/hir.rs +++ b/compiler/erg_compiler/hir.rs @@ -119,6 +119,7 @@ impl KwArg { #[derive(Debug, Clone)] pub struct Args { pub pos_args: Vec, + pub var_args: Option>, pub kw_args: Vec, paren: Option<(Token, Token)>, } @@ -128,6 +129,10 @@ impl NestedDisplay for Args { if !self.pos_args.is_empty() { fmt_lines(self.pos_args.iter(), f, level)?; } + if let Some(var_args) = &self.var_args { + writeln!(f, "...")?; + var_args.fmt_nest(f, level)?; + } if !self.kw_args.is_empty() { fmt_lines(self.kw_args.iter(), f, level)?; } @@ -139,6 +144,7 @@ impl From> for Args { fn from(exprs: Vec) -> Self { Self { pos_args: exprs.into_iter().map(PosArg::new).collect(), + var_args: None, kw_args: Vec::new(), paren: None, } @@ -167,30 +173,33 @@ impl Locational for Args { // impl_stream!(Args, KwArg, kw_args); impl Args { - pub const fn new( + pub fn new( pos_args: Vec, + var_args: Option, kw_args: Vec, paren: Option<(Token, Token)>, ) -> Self { Self { pos_args, + var_args: var_args.map(Box::new), kw_args, paren, } } - pub const fn empty() -> Self { - Self::new(vec![], vec![], None) + pub fn empty() -> Self { + Self::new(vec![], None, vec![], None) } #[inline] pub fn len(&self) -> usize { - self.pos_args.len() + self.kw_args.len() + let var_argc = if self.var_args.is_none() { 0 } else { 1 }; + self.pos_args.len() + var_argc + self.kw_args.len() } #[inline] pub fn is_empty(&self) -> bool { - self.pos_args.is_empty() && self.kw_args.is_empty() + self.pos_args.is_empty() && self.var_args.is_none() && self.kw_args.is_empty() } #[inline] @@ -1338,7 +1347,7 @@ pub struct ClassDef { pub kind: TypeKind, pub sig: Signature, pub require_or_sup: Box, - /// The type of `new` and `__new__` that is automatically defined if not defined + /// The type of `new` that is automatically defined if not defined pub need_to_gen_new: bool, pub __new__: Type, pub private_methods: RecordAttrs, diff --git a/compiler/erg_compiler/link.rs b/compiler/erg_compiler/link.rs index 2ddbbba8..cb5deee2 100644 --- a/compiler/erg_compiler/link.rs +++ b/compiler/erg_compiler/link.rs @@ -50,12 +50,12 @@ impl Linker { Expr::Methods(methods) => match &methods.class { TypeSpec::PreDeclTy(PreDeclTypeSpec::Simple(simple)) => { if let Some(pos) = self.def_root_pos_map.get(simple.name.inspect()) { - let mut type_def = match new.remove(*pos) { - Expr::ClassDef(type_def) => type_def, + let mut class_def = match new.remove(*pos) { + Expr::ClassDef(class_def) => class_def, _ => unreachable!(), }; - type_def.methods_list.push(methods); - new.insert(*pos, Expr::ClassDef(type_def)); + class_def.methods_list.push(methods); + new.insert(*pos, Expr::ClassDef(class_def)); } else { log!("{}", simple.name.inspect()); log!("{}", self.def_root_pos_map); diff --git a/compiler/erg_compiler/lower.rs b/compiler/erg_compiler/lower.rs index e777cfdf..b36ae4ee 100644 --- a/compiler/erg_compiler/lower.rs +++ b/compiler/erg_compiler/lower.rs @@ -330,6 +330,7 @@ impl ASTLowerer { let (pos_args, kw_args, paren) = call.args.deconstruct(); let mut hir_args = hir::Args::new( Vec::with_capacity(pos_args.len()), + None, Vec::with_capacity(kw_args.len()), paren, ); @@ -368,7 +369,7 @@ impl ASTLowerer { &[], &self.ctx.name, )?; - let args = hir::Args::new(args, vec![], None); + let args = hir::Args::new(args, None, vec![], None); Ok(hir::Call::new(class, Some(method_name), args, sig_t)) } @@ -570,10 +571,33 @@ impl ASTLowerer { } } match self.ctx.pop() { - Ok(ctx) => { - self.check_override(&class, &ctx); + Ok(methods) => { + self.check_override(&class, &methods); if let Some((_, class_root)) = self.ctx.rec_get_mut_nominal_type_ctx(&class) { - class_root.method_defs.push((class, ctx)); + for (newly_defined_name, _vi) in methods.locals.iter() { + for (_, already_defined_methods) in class_root.method_defs.iter_mut() { + // TODO: 特殊化なら同じ名前でもOK + // TODO: 定義のメソッドもエラー表示 + if let Some((_already_defined_name, already_defined_vi)) = + already_defined_methods + .get_local_kv(&newly_defined_name.inspect()) + { + if already_defined_vi.kind != VarKind::Auto { + self.errs.push(LowerError::duplicate_definition_error( + line!() as usize, + newly_defined_name.loc(), + methods.name.clone(), + newly_defined_name.inspect(), + )); + } else { + already_defined_methods + .locals + .remove(&newly_defined_name.inspect()[..]); + } + } + } + } + class_root.method_defs.push((class, methods)); } else { todo!() } @@ -589,8 +613,11 @@ impl ASTLowerer { .unwrap(); let type_obj = enum_unwrap!(self.ctx.rec_get_const_obj(hir_def.sig.ident().inspect()).unwrap(), ValueObj::Type:(TypeObj::Generated:(_))); // vi.t.non_default_params().unwrap()[0].typ().clone() - let (__new__, need_to_gen_new) = if let Some(vi) = ctx.get_current_scope_var("new") { - (vi.t.clone(), vi.kind == VarKind::Auto) + let (__new__, need_to_gen_new) = if let (Some(dunder_new_vi), Some(new_vi)) = ( + ctx.get_current_scope_var("__new__"), + ctx.get_current_scope_var("new"), + ) { + (dunder_new_vi.t.clone(), new_vi.kind == VarKind::Auto) } else { todo!() }; diff --git a/compiler/erg_compiler/varinfo.rs b/compiler/erg_compiler/varinfo.rs index e88339c1..5bb4fb11 100644 --- a/compiler/erg_compiler/varinfo.rs +++ b/compiler/erg_compiler/varinfo.rs @@ -68,6 +68,7 @@ pub enum VarKind { default: DefaultInfo, }, Auto, + FixedAuto, DoesNotExist, Builtin, } diff --git a/compiler/erg_parser/ast.rs b/compiler/erg_parser/ast.rs index 4bc36505..db3312d8 100644 --- a/compiler/erg_parser/ast.rs +++ b/compiler/erg_parser/ast.rs @@ -2236,9 +2236,6 @@ pub enum ParamPattern { // DataPack(ParamDataPackPattern), Ref(VarName), RefMut(VarName), - // e.g. `a` of `[...a, b] = [1, 2, 3]` (a == [1, 2], b == 3) - // `b` of `[a, ...b] = [1, 2, 3]` (a == 1, b == [2, 3]) - VarArgs(VarName), } impl NestedDisplay for ParamPattern { @@ -2252,20 +2249,17 @@ impl NestedDisplay for ParamPattern { Self::Record(record) => write!(f, "{}", record), Self::Ref(var_name) => write!(f, "ref {}", var_name), Self::RefMut(var_name) => write!(f, "ref! {}", var_name), - Self::VarArgs(var_name) => write!(f, "...{}", var_name), } } } impl_display_from_nested!(ParamPattern); -impl_locational_for_enum!(ParamPattern; Discard, VarName, Lit, Array, Tuple, Record, Ref, RefMut, VarArgs); +impl_locational_for_enum!(ParamPattern; Discard, VarName, Lit, Array, Tuple, Record, Ref, RefMut); impl ParamPattern { pub const fn inspect(&self) -> Option<&Str> { match self { - Self::VarName(n) | Self::VarArgs(n) | Self::Ref(n) | Self::RefMut(n) => { - Some(n.inspect()) - } + Self::VarName(n) | Self::Ref(n) | Self::RefMut(n) => Some(n.inspect()), _ => None, } } @@ -2277,9 +2271,7 @@ impl ParamPattern { pub fn is_procedural(&self) -> bool { match self { Self::Discard(_) => true, - Self::VarName(n) | Self::VarArgs(n) | Self::Ref(n) | Self::RefMut(n) => { - n.is_procedural() - } + Self::VarName(n) | Self::Ref(n) | Self::RefMut(n) => n.is_procedural(), _ => false, } } @@ -2287,7 +2279,7 @@ impl ParamPattern { pub fn is_const(&self) -> bool { match self { Self::Discard(_) => true, - Self::VarName(n) | Self::VarArgs(n) | Self::Ref(n) | Self::RefMut(n) => n.is_const(), + Self::VarName(n) | Self::Ref(n) | Self::RefMut(n) => n.is_const(), _ => false, } } @@ -2381,7 +2373,11 @@ impl Locational for Params { } else if !self.non_defaults.is_empty() { Location::concat(&self.non_defaults[0], self.non_defaults.last().unwrap()) } else if let Some(var_args) = &self.var_args { - Location::concat(var_args.as_ref(), self.defaults.last().unwrap()) + if !self.defaults.is_empty() { + Location::concat(var_args.as_ref(), self.defaults.last().unwrap()) + } else { + var_args.loc() + } } else if !self.defaults.is_empty() { Location::concat(&self.defaults[0], self.defaults.last().unwrap()) } else { diff --git a/examples/class.er b/examples/class.er index 7b49dd21..8320aaab 100644 --- a/examples/class.er +++ b/examples/class.er @@ -7,9 +7,12 @@ Point3D = Inherit Point2D, Additional := {z = Int} Point3D. # Overloading is prohibited by default. Remove this decorator and check for errors. @Override - new x, y, z = Point3D::__new__ {x; y; z} + new x, y, z = + Point3D::__new__ {x; y; z} @Override norm self = self::x**2 + self::y**2 + self::z**2 -p = Point3D.new {x = 1; y = 2; z = 3} -print! p.norm() +p = Point2D.new {x = 1; y = 2} +print! p, p.norm() +q = Point3D.new 1, 2, 3 +print! q, q.norm()