diff --git a/compiler/erg_common/lib.rs b/compiler/erg_common/lib.rs index 2b3c4cfc2..08db90163 100644 --- a/compiler/erg_common/lib.rs +++ b/compiler/erg_common/lib.rs @@ -82,6 +82,7 @@ pub fn fmt_indent(s: String, depth: usize) -> String { s.split('\n').map(|s| indent.clone() + s).collect() } +/// 複数のオブジェクトからなるハッシュを得たい場合はタプルか配列で渡す pub fn get_hash(t: &T) -> usize { let mut s = fxhash::FxHasher::default(); t.hash(&mut s); diff --git a/compiler/erg_compiler/codegen.rs b/compiler/erg_compiler/codegen.rs index 7be43bd4a..28d434557 100644 --- a/compiler/erg_compiler/codegen.rs +++ b/compiler/erg_compiler/codegen.rs @@ -17,8 +17,8 @@ use erg_common::{ use erg_type::codeobj::{CodeObj, CodeObjFlags}; use Opcode::*; -use erg_parser::ast::{Identifier, ParamPattern, Params, VarName, VarPattern}; -use erg_parser::token::{Token, TokenCategory, TokenKind}; +use erg_parser::ast::{Identifier, ParamPattern, Params, VarName}; +use erg_parser::token::{Token, TokenKind}; use erg_type::value::ValueObj; use erg_type::{HasType, TypeCode, TypePair}; @@ -680,50 +680,20 @@ impl CodeGenerator { .collect() } - fn emit_var_pat(&mut self, pat: VarPattern, op: &Token) { - match pat { - VarPattern::Ident(ident) => { - if op.category_is(TokenCategory::DefOp) { - self.emit_store_instr(ident, Name); - } else { - todo!() - } - } - VarPattern::Array(a) => { - if op.category_is(TokenCategory::DefOp) { - // TODO: UNPACK_EX - self.write_instr(UNPACK_SEQUENCE); - self.write_arg(a.len() as u8); - self.stack_inc_n(a.len() - 1); - for sig in a.into_iter() { - self.emit_var_pat(sig.pat, op); - } - } else { - switch_unreachable!() - } - } - _ => todo!(), - } - } - fn emit_mono_type_def(&mut self, sig: VarSignature, body: DefBody) { self.write_instr(Opcode::LOAD_BUILD_CLASS); self.write_arg(0); self.stack_inc(); - let ident = match sig.pat { - VarPattern::Ident(ident) => ident, - _ => todo!(), - }; - let code = self.codegen_typedef_block(ident.inspect().clone(), body.block); + let code = self.codegen_typedef_block(sig.inspect().clone(), body.block); self.emit_load_const(code); - self.emit_load_const(ident.inspect().clone()); + self.emit_load_const(sig.inspect().clone()); self.write_instr(Opcode::MAKE_FUNCTION); self.write_arg(0); - self.emit_load_const(ident.inspect().clone()); + self.emit_load_const(sig.inspect().clone()); self.write_instr(Opcode::CALL_FUNCTION); self.write_arg(2); self.stack_dec_n((1 + 2) - 1); - self.emit_store_instr(ident, Name); + self.emit_store_instr(sig.ident, Name); } fn emit_var_def(&mut self, sig: VarSignature, mut body: DefBody) { @@ -735,7 +705,7 @@ impl CodeGenerator { } else { self.codegen_frameless_block(body.block, vec![]); } - self.emit_var_pat(sig.pat, &body.op); + self.emit_store_instr(sig.ident, Name); } fn emit_subr_def(&mut self, sig: SubrSignature, body: DefBody) { @@ -1026,7 +996,7 @@ impl CodeGenerator { } fn codegen_expr(&mut self, expr: Expr) { - if expr.ln_begin().unwrap() > self.cur_block().prev_lineno { + if expr.ln_begin().unwrap_or_else(|| panic!("{expr}")) > self.cur_block().prev_lineno { let sd = self.cur_block().lasti - self.cur_block().prev_lasti; let ld = expr.ln_begin().unwrap() - self.cur_block().prev_lineno; if ld != 0 { @@ -1058,33 +1028,9 @@ impl CodeGenerator { } match expr { Expr::Lit(lit) => { - self.emit_load_const(lit.data); - } - Expr::Accessor(Accessor::Local(local)) => { - self.emit_load_name_instr(Identifier::new(None, VarName::new(local.name))) - .unwrap_or_else(|err| { - self.errs.push(err); - }); - } - Expr::Accessor(Accessor::Public(public)) => { - let ident = Identifier::new(Some(public.dot), VarName::new(public.name)); - self.emit_load_name_instr(ident).unwrap_or_else(|err| { - self.errs.push(err); - }); - } - Expr::Accessor(Accessor::Attr(a)) => { - let class = a.obj.ref_t().name(); - let uniq_obj_name = a.obj.__name__().map(Str::rc); - self.codegen_expr(*a.obj); - self.emit_load_attr_instr( - &class, - uniq_obj_name.as_ref().map(|s| &s[..]), - a.name.content.clone(), - ) - .unwrap_or_else(|err| { - self.errs.push(err); - }); + self.emit_load_const(lit.value); } + Expr::Accessor(acc) => self.codegen_acc(acc), Expr::Def(def) => match def.sig { Signature::Subr(sig) => self.emit_subr_def(sig, def.body), Signature::Var(sig) => self.emit_var_def(sig, def.body), @@ -1255,9 +1201,7 @@ impl CodeGenerator { // record name, let it be anonymous self.emit_load_const("Record"); for field in rec.attrs.iter() { - self.emit_load_const(ValueObj::Str( - field.sig.ident().unwrap().inspect().clone(), - )); + self.emit_load_const(ValueObj::Str(field.sig.ident().inspect().clone())); } self.write_instr(BUILD_LIST); self.write_arg(attrs_len as u8); @@ -1295,6 +1239,50 @@ impl CodeGenerator { } } + fn codegen_acc(&mut self, acc: Accessor) { + match acc { + Accessor::Local(local) => { + self.emit_load_name_instr(Identifier::new(None, VarName::new(local.name))) + .unwrap_or_else(|err| { + self.errs.push(err); + }); + } + Accessor::Public(public) => { + let ident = Identifier::new(Some(public.dot), VarName::new(public.name)); + self.emit_load_name_instr(ident).unwrap_or_else(|err| { + self.errs.push(err); + }); + } + Accessor::Attr(a) => { + let class = a.obj.ref_t().name(); + let uniq_obj_name = a.obj.__name__().map(Str::rc); + self.codegen_expr(*a.obj); + self.emit_load_attr_instr( + &class, + uniq_obj_name.as_ref().map(|s| &s[..]), + a.name.content.clone(), + ) + .unwrap_or_else(|err| { + self.errs.push(err); + }); + } + Accessor::TupleAttr(t_attr) => { + self.codegen_expr(*t_attr.obj); + self.emit_load_const(t_attr.index.value); + self.write_instr(BINARY_SUBSCR); + self.write_arg(0); + self.stack_dec(); + } + Accessor::Subscr(subscr) => { + self.codegen_expr(*subscr.obj); + self.codegen_expr(*subscr.index); + self.write_instr(BINARY_SUBSCR); + self.write_arg(0); + self.stack_dec(); + } + } + } + /// forブロックなどで使う fn codegen_frameless_block(&mut self, block: Block, params: Vec) { for param in params { @@ -1440,6 +1428,9 @@ impl CodeGenerator { print_point = self.cur_block().lasti; self.emit_load_name_instr(Identifier::public("print")) .unwrap(); + // Consistency will be taken later (when NOP replacing) + // 後で(NOP書き換え時)整合性を取る + self.stack_dec(); } for expr in hir.module.into_iter() { self.codegen_expr(expr); @@ -1450,14 +1441,15 @@ impl CodeGenerator { } self.cancel_pop_top(); // 最後の値は戻り値として取っておく if self.input().is_repl() { - if self.cur_block().stack_len == 1 { + if self.cur_block().stack_len == 0 { // remains `print`, nothing to be printed self.edit_code(print_point, Opcode::NOP as usize); } else { + self.stack_inc(); self.write_instr(CALL_FUNCTION); self.write_arg(1_u8); } - self.stack_dec(); + self.stack_dec_n(self.cur_block().stack_len as usize); } if self.cur_block().stack_len == 0 { self.emit_load_const(ValueObj::None); diff --git a/compiler/erg_compiler/context/inquire.rs b/compiler/erg_compiler/context/inquire.rs index b7f0847ba..ef80bec70 100644 --- a/compiler/erg_compiler/context/inquire.rs +++ b/compiler/erg_compiler/context/inquire.rs @@ -6,7 +6,7 @@ use erg_common::dict::Dict; use erg_common::error::ErrorCore; use erg_common::levenshtein::levenshtein; use erg_common::set::Set; -use erg_common::traits::{Locational, Stream}; +use erg_common::traits::Locational; use erg_common::vis::{Field, Visibility}; use erg_common::Str; use erg_common::{enum_unwrap, fmt_option, fmt_slice, log, set}; @@ -36,48 +36,24 @@ use Visibility::*; impl Context { pub(crate) fn validate_var_sig_t( &self, - sig: &ast::VarSignature, + ident: &ast::Identifier, + t_spec: Option<&ast::TypeSpec>, body_t: &Type, mode: RegistrationMode, ) -> TyCheckResult<()> { - let spec_t = self.instantiate_var_sig_t(sig, None, mode)?; - match &sig.pat { - ast::VarPattern::Discard(token) => { - if self - .sub_unify(body_t, &spec_t, None, Some(sig.loc())) - .is_err() - { - return Err(TyCheckError::type_mismatch_error( - line!() as usize, - token.loc(), - self.caused_by(), - "_", - &spec_t, - body_t, - )); - } - } - ast::VarPattern::Ident(ident) => { - if self - .sub_unify(body_t, &spec_t, None, Some(sig.loc())) - .is_err() - { - return Err(TyCheckError::type_mismatch_error( - line!() as usize, - ident.loc(), - self.caused_by(), - ident.inspect(), - &spec_t, - body_t, - )); - } - } - ast::VarPattern::Array(a) => { - for (elem, inf_elem_t) in a.iter().zip(body_t.inner_ts().iter()) { - self.validate_var_sig_t(elem, inf_elem_t, mode)?; - } - } - _ => todo!(), + let spec_t = self.instantiate_var_sig_t(t_spec, None, mode)?; + if self + .sub_unify(body_t, &spec_t, None, Some(ident.loc())) + .is_err() + { + return Err(TyCheckError::type_mismatch_error( + line!() as usize, + ident.loc(), + self.caused_by(), + ident.inspect(), + &spec_t, + body_t, + )); } Ok(()) } diff --git a/compiler/erg_compiler/context/instantiate.rs b/compiler/erg_compiler/context/instantiate.rs index b7eb867d9..d110edbaa 100644 --- a/compiler/erg_compiler/context/instantiate.rs +++ b/compiler/erg_compiler/context/instantiate.rs @@ -370,17 +370,17 @@ impl ConstTemplate { impl Context { pub(crate) fn instantiate_var_sig_t( &self, - sig: &ast::VarSignature, + t_spec: Option<&TypeSpec>, opt_eval_t: Option, mode: RegistrationMode, ) -> TyCheckResult { - let spec_t = if let Some(s) = sig.t_spec.as_ref() { + let spec_t = if let Some(s) = t_spec { self.instantiate_typespec(s, mode)? } else { free_var(self.level, Constraint::type_of(Type)) }; if let Some(eval_t) = opt_eval_t { - self.sub_unify(&eval_t, &spec_t, None, sig.t_spec.as_ref().map(|s| s.loc()))?; + self.sub_unify(&eval_t, &spec_t, None, t_spec.map(|s| s.loc()))?; } Ok(spec_t) } diff --git a/compiler/erg_compiler/context/register.rs b/compiler/erg_compiler/context/register.rs index cb1a38c47..edd58295a 100644 --- a/compiler/erg_compiler/context/register.rs +++ b/compiler/erg_compiler/context/register.rs @@ -1,6 +1,6 @@ use std::option::Option; // conflicting to Type::Option -use erg_common::traits::{Locational, Stream}; +use erg_common::traits::Locational; use erg_common::vis::Visibility; use erg_common::Str; use erg_common::{enum_unwrap, get_hash, log, set}; @@ -45,16 +45,7 @@ impl Context { } } - pub(crate) fn declare_var( - &mut self, - sig: &ast::VarSignature, - opt_t: Option, - id: Option, - ) -> TyCheckResult<()> { - self.declare_var_pat(sig, opt_t, id) - } - - fn declare_var_pat( + fn declare_var( &mut self, sig: &ast::VarSignature, opt_t: Option, @@ -81,24 +72,13 @@ impl Context { } let vis = ident.vis(); let kind = id.map_or(VarKind::Declared, VarKind::Defined); - let sig_t = self.instantiate_var_sig_t(sig, opt_t, PreRegister)?; + let sig_t = + self.instantiate_var_sig_t(sig.t_spec.as_ref(), opt_t, PreRegister)?; self.decls .insert(ident.name.clone(), VarInfo::new(sig_t, muty, vis, kind)); Ok(()) } } - ast::VarPattern::Array(a) => { - if let Some(opt_ts) = opt_t.and_then(|t| t.non_default_params().cloned()) { - for (elem, p) in a.iter().zip(opt_ts.into_iter()) { - self.declare_var_pat(elem, Some(p.ty), None)?; - } - } else { - for elem in a.iter() { - self.declare_var_pat(elem, None, None)?; - } - } - Ok(()) - } _ => todo!(), } } @@ -136,53 +116,34 @@ impl Context { Ok(()) } - pub(crate) fn assign_var( - &mut self, - sig: &ast::VarSignature, - id: DefId, - body_t: &Type, - ) -> TyCheckResult<()> { - self.assign_var_sig(sig, body_t, id) - } - - fn assign_var_sig( + pub(crate) fn assign_var_sig( &mut self, sig: &ast::VarSignature, body_t: &Type, id: DefId, ) -> TyCheckResult<()> { - self.validate_var_sig_t(sig, body_t, Normal)?; - let muty = Mutability::from(&sig.inspect().unwrap()[..]); + let ident = match &sig.pat { + ast::VarPattern::Ident(ident) => ident, + _ => todo!(), + }; + self.validate_var_sig_t(ident, sig.t_spec.as_ref(), body_t, Normal)?; + let muty = Mutability::from(&ident.inspect()[..]); let generalized = self.generalize_t(body_t.clone()); - match &sig.pat { - ast::VarPattern::Discard(_token) => Ok(()), - ast::VarPattern::Ident(ident) => { - if self.registered(ident.inspect(), ident.is_const()) { - Err(TyCheckError::reassign_error( - line!() as usize, - ident.loc(), - self.caused_by(), - ident.inspect(), - )) - } else { - if self.decls.remove(ident.inspect()).is_some() { - // something to do? - } - let vis = ident.vis(); - let vi = VarInfo::new(generalized, muty, vis, VarKind::Defined(id)); - self.locals.insert(ident.name.clone(), vi); - Ok(()) - } - } - ast::VarPattern::Array(arr) => { - for (elem, inf) in arr.iter().zip(generalized.inner_ts().iter()) { - let id = DefId(get_hash(&(&self.name, elem))); - self.assign_var_sig(elem, inf, id)?; - } - Ok(()) + if self.registered(ident.inspect(), ident.is_const()) { + Err(TyCheckError::reassign_error( + line!() as usize, + ident.loc(), + self.caused_by(), + ident.inspect(), + )) + } else { + if self.decls.remove(ident.inspect()).is_some() { + // something to do? } - ast::VarPattern::Tuple(_) => todo!(), - ast::VarPattern::Record { .. } => todo!(), + let vis = ident.vis(); + let vi = VarInfo::new(generalized, muty, vis, VarKind::Defined(id)); + self.locals.insert(ident.name.clone(), vi); + Ok(()) } } @@ -225,46 +186,8 @@ impl Context { Ok(()) } } - ast::ParamPattern::Array(arr) => { - let mut array_nth = 0; - let array_outer = if let Some(outer) = outer { - ParamIdx::nested(outer, nth) - } else { - ParamIdx::Nth(nth) - }; - if let Some(decl_t) = opt_decl_t { - for (elem, p) in arr - .elems - .non_defaults - .iter() - .zip(decl_t.ty.non_default_params().unwrap()) - { - self.assign_param(elem, Some(array_outer.clone()), array_nth, Some(p))?; - array_nth += 1; - } - for (elem, p) in arr - .elems - .defaults - .iter() - .zip(decl_t.ty.default_params().unwrap()) - { - self.assign_param(elem, Some(array_outer.clone()), array_nth, Some(p))?; - array_nth += 1; - } - } else { - for elem in arr.elems.non_defaults.iter() { - self.assign_param(elem, Some(array_outer.clone()), array_nth, None)?; - array_nth += 1; - } - for elem in arr.elems.defaults.iter() { - self.assign_param(elem, Some(array_outer.clone()), array_nth, None)?; - array_nth += 1; - } - } - Ok(()) - } ast::ParamPattern::Lit(_) => Ok(()), - _ => todo!(), + _ => unreachable!(), } } @@ -427,8 +350,8 @@ impl Context { ) -> TyCheckResult<()> { match mod_name { hir::Expr::Lit(lit) => { - if self.rec_subtype_of(&lit.data.class(), &Str) { - let name = enum_unwrap!(lit.data.clone(), ValueObj::Str); + if self.rec_subtype_of(&lit.value.class(), &Str) { + let name = enum_unwrap!(lit.value.clone(), ValueObj::Str); match &name[..] { "math" => { self.mods.insert(var_name.clone(), Self::init_py_math_mod()); diff --git a/compiler/erg_compiler/context/tyvar.rs b/compiler/erg_compiler/context/tyvar.rs index 0dfcfaffc..56c67295c 100644 --- a/compiler/erg_compiler/context/tyvar.rs +++ b/compiler/erg_compiler/context/tyvar.rs @@ -384,8 +384,14 @@ impl Context { hir::Accessor::Attr(attr) => { self.deref_expr_t(&mut attr.obj)?; } + hir::Accessor::TupleAttr(attr) => { + self.deref_expr_t(&mut attr.obj)?; + } + hir::Accessor::Subscr(subscr) => { + self.deref_expr_t(&mut subscr.obj)?; + self.deref_expr_t(&mut subscr.index)?; + } hir::Accessor::Local(_) | hir::Accessor::Public(_) => {} - _ => todo!(), } Ok(()) } diff --git a/compiler/erg_compiler/effectcheck.rs b/compiler/erg_compiler/effectcheck.rs index 3167e1858..c411c5017 100644 --- a/compiler/erg_compiler/effectcheck.rs +++ b/compiler/erg_compiler/effectcheck.rs @@ -114,16 +114,8 @@ impl SideEffectChecker { fn check_def(&mut self, def: &Def) { let name_and_vis = match &def.sig { - Signature::Var(var) => - // TODO: visibility - { - if let Some(name) = var.inspect() { - (name.clone(), Private) - } else { - (Str::ever("::"), Private) - } - } - Signature::Subr(subr) => (subr.ident.inspect().clone(), Private), + Signature::Var(var) => (var.inspect().clone(), var.vis()), + Signature::Subr(subr) => (subr.ident.inspect().clone(), subr.ident.vis()), }; self.path_stack.push(name_and_vis); // TODO: support raw identifier (``) diff --git a/compiler/erg_compiler/hir.rs b/compiler/erg_compiler/hir.rs index 100d6cdc4..bc10c6945 100644 --- a/compiler/erg_compiler/hir.rs +++ b/compiler/erg_compiler/hir.rs @@ -11,7 +11,7 @@ use erg_common::{ impl_stream_for_wrapper, }; -use erg_parser::ast::{fmt_lines, DefId, Identifier, Params, VarPattern}; +use erg_parser::ast::{fmt_lines, DefId, Identifier, Params}; use erg_parser::token::{Token, TokenKind}; use erg_type::constructors::{array, tuple}; @@ -24,8 +24,8 @@ use crate::eval::type_from_token_kind; #[derive(Debug, Clone)] pub struct Literal { - pub data: ValueObj, // for constant folding - pub token: Token, // for Locational + pub value: ValueObj, + pub token: Token, // for Locational t: Type, } @@ -33,7 +33,7 @@ impl_t!(Literal); impl NestedDisplay for Literal { fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result { - write!(f, "{}", self.token) + write!(f, "{} (: {})", self.token.content, self.t) } } @@ -51,7 +51,7 @@ impl From for Literal { let data = ValueObj::from_str(type_from_token_kind(token.kind), token.content.clone()); Self { t: data.t(), - data, + value: data, token, } } @@ -369,10 +369,38 @@ impl Attribute { } } +/// e.g. obj.0, obj.1 +#[derive(Clone, Debug)] +pub struct TupleAttribute { + pub obj: Box, + pub index: Literal, + t: Type, +} + +impl NestedDisplay for TupleAttribute { + fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, _level: usize) -> std::fmt::Result { + write!(f, "({}).{}", self.obj, self.index) + } +} + +impl_display_from_nested!(TupleAttribute); +impl_locational!(TupleAttribute, obj, index); +impl_t!(TupleAttribute); + +impl TupleAttribute { + pub fn new(obj: Expr, index: Literal, t: Type) -> Self { + Self { + obj: Box::new(obj), + index, + t, + } + } +} + #[derive(Debug, Clone)] pub struct Subscript { - obj: Box, - index: Box, + pub(crate) obj: Box, + pub(crate) index: Box, t: Type, } @@ -401,13 +429,14 @@ pub enum Accessor { Local(Local), Public(Public), Attr(Attribute), + TupleAttr(TupleAttribute), Subscr(Subscript), } -impl_nested_display_for_enum!(Accessor; Local, Public, Attr, Subscr); +impl_nested_display_for_enum!(Accessor; Local, Public, Attr, TupleAttr, Subscr); impl_display_from_nested!(Accessor); -impl_locational_for_enum!(Accessor; Local, Public, Attr, Subscr); -impl_t_for_enum!(Accessor; Local, Public, Attr, Subscr); +impl_locational_for_enum!(Accessor; Local, Public, Attr, TupleAttr, Subscr); +impl_t_for_enum!(Accessor; Local, Public, Attr, TupleAttr, Subscr); impl Accessor { pub const fn local(symbol: Token, t: Type) -> Self { @@ -433,6 +462,10 @@ impl Accessor { .obj .var_full_name() .map(|n| n + "." + readable_name(attr.name.inspect())), + Self::TupleAttr(t_attr) => t_attr + .obj + .var_full_name() + .map(|n| n + "." + t_attr.index.token.inspect()), Self::Subscr(_) | Self::Public(_) => todo!(), } } @@ -711,7 +744,7 @@ impl Record { pub fn new(l_brace: Token, r_brace: Token, attrs: RecordAttrs) -> Self { let rec = attrs .iter() - .map(|def| (Field::from(def.sig.ident().unwrap()), def.body.block.t())) + .map(|def| (Field::from(def.sig.ident()), def.body.block.t())) .collect(); let t = Type::Record(rec); Self { @@ -724,7 +757,7 @@ impl Record { pub fn push(&mut self, attr: Def) { let t = enum_unwrap!(&mut self.t, Type::Record); - t.insert(Field::from(attr.sig.ident().unwrap()), attr.body.block.t()); + t.insert(Field::from(attr.sig.ident()), attr.body.block.t()); self.attrs.push(attr); } } @@ -951,30 +984,30 @@ impl Locational for Block { #[derive(Debug, Clone, Hash)] pub struct VarSignature { - pub pat: VarPattern, + pub ident: Identifier, pub t: Type, } impl NestedDisplay for VarSignature { fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result { - write!(f, "{}(: {})", self.pat, self.t) + write!(f, "{}(: {})", self.ident, self.t) } } impl_display_from_nested!(VarSignature); -impl_locational!(VarSignature, pat, pat); +impl_locational!(VarSignature, ident); impl VarSignature { - pub const fn new(pat: VarPattern, t: Type) -> Self { - Self { pat, t } + pub const fn new(ident: Identifier, t: Type) -> Self { + Self { ident, t } } - pub fn inspect(&self) -> Option<&Str> { - self.pat.inspect() + pub fn inspect(&self) -> &Str { + self.ident.inspect() } pub fn vis(&self) -> Visibility { - self.pat.vis() + self.ident.vis() } } @@ -1057,29 +1090,29 @@ impl Signature { pub fn is_const(&self) -> bool { match self { - Self::Var(v) => v.pat.is_const(), + Self::Var(v) => v.ident.is_const(), Self::Subr(s) => s.ident.is_const(), } } pub fn is_procedural(&self) -> bool { match self { - Self::Var(v) => v.pat.is_procedural(), + Self::Var(v) => v.ident.is_procedural(), Self::Subr(s) => s.ident.is_procedural(), } } pub const fn vis(&self) -> Visibility { match self { - Self::Var(v) => v.pat.vis(), + Self::Var(v) => v.ident.vis(), Self::Subr(s) => s.ident.vis(), } } - pub fn ident(&self) -> Option<&Identifier> { + pub fn ident(&self) -> &Identifier { match self { - Self::Var(v) => v.pat.ident(), - Self::Subr(s) => Some(&s.ident), + Self::Var(v) => &v.ident, + Self::Subr(s) => &s.ident, } } } diff --git a/compiler/erg_compiler/lower.rs b/compiler/erg_compiler/lower.rs index b74b474db..e7039edca 100644 --- a/compiler/erg_compiler/lower.rs +++ b/compiler/erg_compiler/lower.rs @@ -3,9 +3,9 @@ //! ASTLowerer(ASTからHIRへの変換器)を実装 use erg_common::color::{GREEN, RED, RESET}; use erg_common::error::Location; -use erg_common::get_hash; use erg_common::traits::{Locational, Stream}; use erg_common::vis::Visibility; +use erg_common::{enum_unwrap, get_hash}; use erg_common::{fn_name, log, switch_lang}; use erg_parser::ast; @@ -234,38 +234,61 @@ impl ASTLowerer { fn lower_acc(&mut self, acc: ast::Accessor) -> LowerResult { log!("[DEBUG] entered {}({acc})", fn_name!()); match acc { - ast::Accessor::Local(n) => { + ast::Accessor::Local(local) => { // `match` is an untypable special form // `match`は型付け不可能な特殊形式 - let (t, __name__) = if &n.inspect()[..] == "match" { + let (t, __name__) = if &local.inspect()[..] == "match" { (Type::Failure, None) } else { ( - self.ctx.rec_get_var_t(&n.symbol, Private, &self.ctx.name)?, - self.ctx.get_local_uniq_obj_name(&n.symbol), + self.ctx + .rec_get_var_t(&local.symbol, Private, &self.ctx.name)?, + self.ctx.get_local_uniq_obj_name(&local.symbol), ) }; - let acc = hir::Accessor::Local(hir::Local::new(n.symbol, __name__, t)); + let acc = hir::Accessor::Local(hir::Local::new(local.symbol, __name__, t)); Ok(acc) } - ast::Accessor::Public(n) => { + ast::Accessor::Public(public) => { let (t, __name__) = ( - self.ctx.rec_get_var_t(&n.symbol, Public, &self.ctx.name)?, - self.ctx.get_local_uniq_obj_name(&n.symbol), + self.ctx + .rec_get_var_t(&public.symbol, Public, &self.ctx.name)?, + self.ctx.get_local_uniq_obj_name(&public.symbol), ); - let public = hir::Public::new(n.dot, n.symbol, __name__, t); + let public = hir::Public::new(public.dot, public.symbol, __name__, t); let acc = hir::Accessor::Public(public); Ok(acc) } - ast::Accessor::Attr(a) => { - let obj = self.lower_expr(*a.obj)?; + ast::Accessor::Attr(attr) => { + let obj = self.lower_expr(*attr.obj)?; let t = self .ctx - .rec_get_attr_t(&obj, &a.name.symbol, &self.ctx.name)?; - let acc = hir::Accessor::Attr(hir::Attribute::new(obj, a.name.symbol, t)); + .rec_get_attr_t(&obj, &attr.name.symbol, &self.ctx.name)?; + let acc = hir::Accessor::Attr(hir::Attribute::new(obj, attr.name.symbol, t)); + Ok(acc) + } + ast::Accessor::TupleAttr(t_attr) => { + let obj = self.lower_expr(*t_attr.obj)?; + let index = hir::Literal::from(t_attr.index.token); + let n = enum_unwrap!(index.value, ValueObj::Nat); + let t = enum_unwrap!( + obj.ref_t().typarams().get(n as usize).unwrap().clone(), + TyParam::Type + ); + let acc = hir::Accessor::TupleAttr(hir::TupleAttribute::new(obj, index, *t)); + Ok(acc) + } + ast::Accessor::Subscr(subscr) => { + let obj = self.lower_expr(*subscr.obj)?; + let index = self.lower_expr(*subscr.index)?; + // FIXME: 配列とは限らない! + let t = enum_unwrap!( + obj.ref_t().typarams().get(0).unwrap().clone(), + TyParam::Type + ); + let acc = hir::Accessor::Subscr(hir::Subscript::new(obj, index, *t)); Ok(acc) } - _ => todo!(), } } @@ -385,16 +408,21 @@ impl ASTLowerer { fn lower_def(&mut self, def: ast::Def) -> LowerResult { log!("[DEBUG] entered {}({})", fn_name!(), def.sig); - // FIXME: Instant - self.ctx - .grow(def.sig.name_as_str(), ContextKind::Instant, Private)?; - let res = match def.sig { - ast::Signature::Subr(sig) => self.lower_subr_def(sig, def.body), - ast::Signature::Var(sig) => self.lower_var_def(sig, def.body), - }; - // TODO: Context上の関数に型境界情報を追加 - self.pop_append_errs(); - res + if let Some(name) = def.sig.name_as_str() { + self.ctx.grow(name, ContextKind::Instant, Private)?; + let res = match def.sig { + ast::Signature::Subr(sig) => self.lower_subr_def(sig, def.body), + ast::Signature::Var(sig) => self.lower_var_def(sig, def.body), + }; + // TODO: Context上の関数に型境界情報を追加 + self.pop_append_errs(); + res + } else { + match def.sig { + ast::Signature::Subr(sig) => self.lower_subr_def(sig, def.body), + ast::Signature::Var(sig) => self.lower_var_def(sig, def.body), + } + } } fn lower_var_def( @@ -413,9 +441,14 @@ impl ASTLowerer { .unwrap() .get_current_scope_var(sig.inspect().unwrap()) .map(|vi| vi.t.clone()); - let name = sig.pat.inspect().unwrap(); + let ident = match &sig.pat { + ast::VarPattern::Ident(ident) => ident, + _ => unreachable!(), + }; if let Some(expect_body_t) = opt_expect_body_t { - if let Err(e) = self.return_t_check(sig.loc(), name, &expect_body_t, found_body_t) { + if let Err(e) = + self.return_t_check(sig.loc(), ident.inspect(), &expect_body_t, found_body_t) + { self.errs.push(e); } } @@ -425,24 +458,20 @@ impl ASTLowerer { .outer .as_mut() .unwrap() - .assign_var(&sig, id, found_body_t)?; + .assign_var_sig(&sig, found_body_t, id)?; match block.first().unwrap() { hir::Expr::Call(call) => { - if let ast::VarPattern::Ident(ident) = &sig.pat { - if call.is_import_call() { - self.ctx - .outer - .as_mut() - .unwrap() - .import_mod(&ident.name, &call.args.pos_args.first().unwrap().expr)?; - } - } else { - todo!() + if call.is_import_call() { + self.ctx + .outer + .as_mut() + .unwrap() + .import_mod(&ident.name, &call.args.pos_args.first().unwrap().expr)?; } } _other => {} } - let sig = hir::VarSignature::new(sig.pat, found_body_t.clone()); + let sig = hir::VarSignature::new(ident.clone(), found_body_t.clone()); let body = hir::DefBody::new(body.op, block, body.id); Ok(hir::Def::new(hir::Signature::Var(sig), body)) } diff --git a/compiler/erg_compiler/ownercheck.rs b/compiler/erg_compiler/ownercheck.rs index 74ab83533..eebf658e4 100644 --- a/compiler/erg_compiler/ownercheck.rs +++ b/compiler/erg_compiler/ownercheck.rs @@ -87,13 +87,7 @@ impl OwnershipChecker { log!("define: {}", def.sig); self.define(def); let name = match &def.sig { - Signature::Var(var) => { - if let Some(name) = var.inspect() { - name.clone() - } else { - Str::ever("::") - } - } + Signature::Var(var) => var.inspect().clone(), Signature::Subr(subr) => subr.ident.inspect().clone(), }; self.path_stack.push((name, def.sig.vis())); @@ -102,33 +96,7 @@ impl OwnershipChecker { self.check_block(&def.body.block); self.path_stack.pop(); } - Expr::Accessor(Accessor::Local(local)) => { - self.check_if_dropped(local.inspect(), local.loc()); - if expr.ref_t().is_mut() && ownership.is_owned() { - log!( - "drop: {} (in {})", - local.inspect(), - local.ln_begin().unwrap_or(0) - ); - self.drop(local.inspect(), expr.loc()); - } - } - Expr::Accessor(Accessor::Public(public)) => { - self.check_if_dropped(public.inspect(), public.loc()); - if expr.ref_t().is_mut() && ownership.is_owned() { - log!( - "drop: {} (in {})", - public.inspect(), - public.ln_begin().unwrap_or(0) - ); - self.drop(public.inspect(), expr.loc()); - } - } - Expr::Accessor(Accessor::Attr(a)) => { - // REVIEW: is ownership the same? - self.check_expr(&a.obj, ownership) - } - Expr::Accessor(_a) => todo!(), + Expr::Accessor(acc) => self.check_acc(acc, ownership), // TODO: referenced Expr::Call(call) => { let args_ownership = call.signature_t().unwrap().args_ownership(); @@ -222,6 +190,42 @@ impl OwnershipChecker { } } + fn check_acc(&mut self, acc: &Accessor, ownership: Ownership) { + match acc { + Accessor::Local(local) => { + self.check_if_dropped(local.inspect(), local.loc()); + if acc.ref_t().is_mut() && ownership.is_owned() { + log!( + "drop: {} (in {})", + local.inspect(), + local.ln_begin().unwrap_or(0) + ); + self.drop(local.inspect(), acc.loc()); + } + } + Accessor::Public(public) => { + self.check_if_dropped(public.inspect(), public.loc()); + if acc.ref_t().is_mut() && ownership.is_owned() { + log!( + "drop: {} (in {})", + public.inspect(), + public.ln_begin().unwrap_or(0) + ); + self.drop(public.inspect(), acc.loc()); + } + } + Accessor::Attr(attr) => { + // REVIEW: is ownership the same? + self.check_expr(&attr.obj, ownership) + } + Accessor::TupleAttr(t_attr) => self.check_expr(&t_attr.obj, ownership), + Accessor::Subscr(subscr) => { + self.check_expr(&subscr.obj, ownership); + self.check_expr(&subscr.index, ownership); + } + } + } + /// TODO: このメソッドを呼ぶとき、スコープを再帰的に検索する #[inline] fn current_scope(&mut self) -> &mut LocalVars { @@ -246,9 +250,9 @@ impl OwnershipChecker { fn define(&mut self, def: &Def) { match &def.sig { Signature::Var(sig) => { - for name in sig.pat.inspects() { - self.current_scope().alive_vars.insert(name.clone()); - } + self.current_scope() + .alive_vars + .insert(sig.inspect().clone()); } Signature::Subr(sig) => { self.current_scope() diff --git a/compiler/erg_parser/ast.rs b/compiler/erg_parser/ast.rs index 8a83a85f8..1875321b8 100644 --- a/compiler/erg_parser/ast.rs +++ b/compiler/erg_parser/ast.rs @@ -42,7 +42,7 @@ pub struct Literal { impl NestedDisplay for Literal { fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result { - write!(f, "{}", self.token) + write!(f, "{}", self.token.content) } } @@ -57,6 +57,15 @@ impl From for Literal { } impl Literal { + pub const fn new(token: Token) -> Self { + Self { token } + } + + pub fn nat(n: usize, line: usize) -> Self { + let token = Token::new(TokenKind::NatLit, Str::from(n.to_string()), line, 0); + Self { token } + } + #[inline] pub fn is(&self, kind: TokenKind) -> bool { self.token.is(kind) @@ -224,8 +233,16 @@ impl Local { Self { symbol } } - pub fn dummy(name: &'static str) -> Self { - Self::new(Token::from_str(TokenKind::Symbol, name)) + pub fn static_dummy(name: &'static str) -> Self { + Self::new(Token::static_symbol(name)) + } + + pub fn dummy(name: &str) -> Self { + Self::new(Token::symbol(name)) + } + + pub fn dummy_with_line(name: &str, line: usize) -> Self { + Self::new(Token::new(TokenKind::Symbol, Str::rc(name), line, 0)) } // &strにするとクローンしたいときにアロケーションコストがかかるので&Strのままで @@ -326,8 +343,8 @@ impl TupleAttribute { #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Subscript { - obj: Box, - index: Box, + pub obj: Box, + pub index: Box, } impl NestedDisplay for Subscript { @@ -1640,6 +1657,10 @@ impl VarName { Self(Token::from_str(TokenKind::Symbol, &symbol)) } + pub fn from_str_and_line(symbol: Str, line: usize) -> Self { + Self(Token::new(TokenKind::Symbol, &symbol, line, 0)) + } + #[inline] pub fn is_const(&self) -> bool { self.0 @@ -1720,6 +1741,10 @@ impl Identifier { Self::new(None, VarName::from_str(name)) } + pub fn private_with_line(name: Str, line: usize) -> Self { + Self::new(None, VarName::from_str_and_line(name, line)) + } + pub fn is_const(&self) -> bool { self.name.is_const() } @@ -2407,10 +2432,10 @@ impl_display_from_nested!(Signature); impl_locational_for_enum!(Signature; Var, Subr); impl Signature { - pub fn name_as_str(&self) -> &Str { + pub fn name_as_str(&self) -> Option<&Str> { match self { - Self::Var(var) => var.pat.inspect().unwrap(), - Self::Subr(subr) => subr.ident.inspect(), + Self::Var(var) => var.pat.inspect(), + Self::Subr(subr) => Some(subr.ident.inspect()), } } diff --git a/compiler/erg_parser/desugar.rs b/compiler/erg_parser/desugar.rs index a7c069d24..a0337b702 100644 --- a/compiler/erg_parser/desugar.rs +++ b/compiler/erg_parser/desugar.rs @@ -8,28 +8,45 @@ use erg_common::set::Set; use erg_common::traits::{Locational, Stream}; use erg_common::Str; -use erg_common::{enum_unwrap, set}; +use erg_common::{enum_unwrap, get_hash, set}; use crate::ast::{ - Accessor, Args, Block, Call, Def, DefBody, Expr, Lambda, LambdaSignature, Module, ParamPattern, - ParamSignature, Params, PosArg, Signature, SubrSignature, TypeBoundSpecs, VarName, VarPattern, + Accessor, Args, Block, Call, Def, DefBody, DefId, Expr, Identifier, Lambda, LambdaSignature, + Literal, Local, Module, ParamPattern, ParamSignature, Params, PosArg, Signature, SubrSignature, + TypeBoundSpecs, VarName, VarPattern, VarSignature, }; use crate::token::{Token, TokenKind}; +#[derive(Debug, Clone, PartialEq, Eq)] +enum BufIndex<'s> { + Array(usize), + Tuple(usize), + Record(&'s str), +} + #[derive(Debug)] pub struct Desugarer { desugared: Set, + var_id: usize, } impl Desugarer { pub fn new() -> Desugarer { Self { desugared: Set::default(), + var_id: 0, } } + fn fresh_var_name(&mut self) -> String { + let var_name = format!("%v{}", self.var_id); + self.var_id += 1; + var_name + } + pub fn desugar(&mut self, module: Module) -> Module { - self.desugar_multiple_pattern_def(module) + let module = self.desugar_multiple_pattern_def(module); + self.desugar_pattern(module) } fn desugar_ubar_lambda(&self, _module: Module) -> Module { @@ -156,19 +173,62 @@ impl Desugarer { /// `[i, j] = l` -> `i = l[0]; j = l[1]` /// `[i, [j, k]] = l` -> `i = l[0]; j = l[1][0]; k = l[1][1]` /// `(i, j) = t` -> `i = t.0; j = t.1` - fn desugar_nest_vars_pattern(&self, mut module: Module) -> Module { + /// `{i; j} = s` -> `i = s.i; j = s.j` + fn desugar_pattern(&mut self, mut module: Module) -> Module { let mut new = Module::with_capacity(module.len()); while let Some(chunk) = module.lpop() { match chunk { Expr::Def(def) => { - if let Signature::Var(v) = &def.sig { + if let Signature::Var(v) = def.sig { match &v.pat { - VarPattern::Array(_a) => {} - VarPattern::Record(_r) => {} + VarPattern::Tuple(tup) => { + let buf_name = self.fresh_var_name(); + let buf_sig = Signature::Var(VarSignature::new( + VarPattern::Ident(Identifier::private_with_line( + Str::rc(&buf_name), + v.ln_begin().unwrap(), + )), + v.t_spec, + )); + let buf_def = Def::new(buf_sig, def.body); + new.push(Expr::Def(buf_def)); + for (n, elem) in tup.elems.iter().enumerate() { + self.desugar_nested_var_pattern( + &mut new, + elem, + &buf_name, + BufIndex::Tuple(n), + ); + } + } + VarPattern::Array(arr) => { + let buf_name = self.fresh_var_name(); + let buf_sig = Signature::Var(VarSignature::new( + VarPattern::Ident(Identifier::private_with_line( + Str::rc(&buf_name), + v.ln_begin().unwrap(), + )), + v.t_spec, + )); + let buf_def = Def::new(buf_sig, def.body); + new.push(Expr::Def(buf_def)); + for (n, elem) in arr.elems.iter().enumerate() { + self.desugar_nested_var_pattern( + &mut new, + elem, + &buf_name, + BufIndex::Array(n), + ); + } + } + VarPattern::Record(_rec) => todo!(), + VarPattern::Ident(_i) => { + let def = Def::new(Signature::Var(v), def.body); + new.push(Expr::Def(def)); + } _ => {} } } - new.push(Expr::Def(def)); } other => { new.push(other); @@ -178,9 +238,77 @@ impl Desugarer { new } - /// `{i; j} = s` -> `i = s.i; j = s.j` - fn desugar_record_pattern(&self, _mod: Module) -> Module { - todo!() + fn desugar_nested_var_pattern( + &mut self, + new_module: &mut Module, + sig: &VarSignature, + buf_name: &str, + buf_index: BufIndex, + ) { + let obj = Expr::local(buf_name, sig.ln_begin().unwrap(), sig.col_begin().unwrap()); + let acc = match buf_index { + BufIndex::Tuple(n) => { + Accessor::tuple_attr(obj, Literal::nat(n, sig.ln_begin().unwrap())) + } + BufIndex::Array(n) => { + Accessor::subscr(obj, Expr::Lit(Literal::nat(n, sig.ln_begin().unwrap()))) + } + BufIndex::Record(attr) => { + Accessor::attr(obj, Local::dummy_with_line(attr, sig.ln_begin().unwrap())) + } + }; + let id = DefId(get_hash(&(&acc, buf_name))); + let block = Block::new(vec![Expr::Accessor(acc)]); + let op = Token::from_str(TokenKind::Equal, "="); + let body = DefBody::new(op, block, id); + match &sig.pat { + VarPattern::Tuple(tup) => { + let buf_name = self.fresh_var_name(); + let buf_sig = Signature::Var(VarSignature::new( + VarPattern::Ident(Identifier::private_with_line( + Str::rc(&buf_name), + sig.ln_begin().unwrap(), + )), + None, + )); + let buf_def = Def::new(buf_sig, body); + new_module.push(Expr::Def(buf_def)); + for (n, elem) in tup.elems.iter().enumerate() { + self.desugar_nested_var_pattern( + new_module, + elem, + &buf_name, + BufIndex::Tuple(n), + ); + } + } + VarPattern::Array(arr) => { + let buf_name = self.fresh_var_name(); + let buf_sig = Signature::Var(VarSignature::new( + VarPattern::Ident(Identifier::private_with_line( + Str::rc(&buf_name), + sig.ln_begin().unwrap(), + )), + None, + )); + let buf_def = Def::new(buf_sig, body); + new_module.push(Expr::Def(buf_def)); + for (n, elem) in arr.elems.iter().enumerate() { + self.desugar_nested_var_pattern( + new_module, + elem, + &buf_name, + BufIndex::Array(n), + ); + } + } + VarPattern::Record(_rec) => todo!(), + VarPattern::Ident(_ident) => { + let def = Def::new(Signature::Var(sig.clone()), body); + new_module.push(Expr::Def(def)); + } + _ => {} + } } /// `F(I | I > 0)` -> `F(I: {I: Int | I > 0})` @@ -192,6 +320,10 @@ impl Desugarer { fn desugar_trait_parameter(&self, _mod: Module) -> Module { todo!() } + + fn desugar_decorators(&self, _mod: Module) -> Module { + todo!() + } } impl Default for Desugarer { diff --git a/compiler/erg_parser/parse.rs b/compiler/erg_parser/parse.rs index 625d8fc4b..e22a02d58 100644 --- a/compiler/erg_parser/parse.rs +++ b/compiler/erg_parser/parse.rs @@ -738,59 +738,6 @@ impl Parser { Ok(acc) } - fn try_reduce_elems_pattern(&mut self) -> ParseResult { - debug_call_info!(self); - let mut elems = Vars::empty(); - match self.peek() { - Some(t) if t.is_block_op() => { - self.level -= 1; - return Ok(Vars::empty()); - } - Some(_) => { - let elem = self.try_reduce_var_sig().map_err(|_| self.stack_dec())?; - elems.push(elem); - } - _ => { - self.level -= 1; - let err = self.skip_and_throw_syntax_err(caused_by!()); - self.errs.push(err); - return Err(()); - } - } - loop { - match self.peek() { - Some(t) if t.is(Comma) => { - self.skip(); - let elem = self.try_reduce_var_sig().map_err(|_| self.stack_dec())?; - elems.push(elem); - } - Some(t) if t.category_is(TC::BinOp) => { - log!("[DEBUG] error caused by: {}", fn_name!()); - let err = ParseError::syntax_error( - line!() as usize, - t.loc(), - switch_lang!( - "japanese" => "左辺値の中で中置演算子は使えません", - "simplified_chinese" => "二元运算符不能用于左值", - "traditional_chinese" => "二元運算符不能用於左值", - "english" => "Binary operators cannot be used in left-values", - ), - None, - ); - self.next_expr(); - self.level -= 1; - self.errs.push(err); - return Err(()); - } - _ => { - break; - } - } - } - self.level -= 1; - Ok(elems) - } - fn opt_reduce_params(&mut self) -> Option> { match self.peek() { Some(t) @@ -983,8 +930,14 @@ impl Parser { Some(t) if t.is(LSqBr) => { let l_sqbr = self.lpop(); let elems = self - .try_reduce_elems_pattern() + .try_reduce_var_pattern() .map_err(|_| self.stack_dec())?; + let elems = match elems { + VarPattern::Tuple(tuple) if tuple.paren.is_none() => { + Vars::new(tuple.elems.elems) + } + other => Vars::new(vec![VarSignature::new(other, None)]), + }; if self.cur_is(RSqBr) { let r_sqbr = self.lpop(); self.level -= 1; @@ -1022,6 +975,24 @@ impl Parser { Err(()) } } + Some(t) if t.category_is(TC::BinOp) || t.category_is(TC::UnaryOp) => { + log!("[DEBUG] error caused by: {}", fn_name!()); + let err = ParseError::syntax_error( + line!() as usize, + t.loc(), + switch_lang!( + "japanese" => "左辺値の中で演算子は使えません", + "simplified_chinese" => "运算符不能用于左值", + "traditional_chinese" => "運算符不能用於左值", + "english" => "Operators cannot be used in left-values", + ), + None, + ); + self.next_expr(); + self.level -= 1; + self.errs.push(err); + return Err(()); + } _ => { self.level -= 1; let err = self.skip_and_throw_syntax_err(caused_by!()); @@ -2017,7 +1988,22 @@ impl Parser { return Err(()); } let arr = match inner { - ArrayInner::Normal(elems) => Array::Normal(NormalArray::new(l_sqbr, r_sqbr, elems)), + ArrayInner::Normal(mut elems) => { + let elems = if elems + .pos_args() + .get(0) + .map(|pos| match &pos.expr { + Expr::Tuple(tup) => tup.paren().is_none(), + _ => false, + }) + .unwrap_or(false) + { + enum_unwrap!(elems.remove_pos(0).expr, Expr::Tuple:(Tuple::Normal:(_))).elems + } else { + elems + }; + Array::Normal(NormalArray::new(l_sqbr, r_sqbr, elems)) + } ArrayInner::WithLength(elem, len) => { Array::WithLength(ArrayWithLength::new(l_sqbr, r_sqbr, elem, len)) }