diff --git a/compiler/erg_compiler/lower.rs b/compiler/erg_compiler/lower.rs index 8744315d..498e1421 100644 --- a/compiler/erg_compiler/lower.rs +++ b/compiler/erg_compiler/lower.rs @@ -1368,6 +1368,21 @@ impl ASTLowerer { Ok(hir::PatchDef::new(hir_def.sig, base, hir_methods)) } + fn lower_attr_def(&mut self, attr_def: ast::AttrDef) -> LowerResult { + log!(info "entered {}({attr_def})", fn_name!()); + let attr = self.lower_acc(attr_def.attr)?; + let expr = self.lower_expr(*attr_def.expr)?; + if let Err(err) = self.var_result_t_check( + attr.loc(), + &Str::from(attr.show()), + attr.ref_t(), + expr.ref_t(), + ) { + self.errs.push(err); + } + Ok(hir::AttrDef::new(attr, hir::Block::new(vec![expr]))) + } + fn register_trait_impl( &mut self, class: &Type, @@ -1748,6 +1763,7 @@ impl ASTLowerer { ast::Expr::Def(def) => Ok(hir::Expr::Def(self.lower_def(def)?)), ast::Expr::ClassDef(defs) => Ok(hir::Expr::ClassDef(self.lower_class_def(defs)?)), ast::Expr::PatchDef(defs) => Ok(hir::Expr::PatchDef(self.lower_patch_def(defs)?)), + ast::Expr::AttrDef(adef) => Ok(hir::Expr::AttrDef(self.lower_attr_def(adef)?)), ast::Expr::TypeAsc(tasc) => Ok(hir::Expr::TypeAsc(self.lower_type_asc(tasc)?)), other => todo!("{other}"), } diff --git a/compiler/erg_parser/ast.rs b/compiler/erg_parser/ast.rs index a34225d7..8baff5aa 100644 --- a/compiler/erg_parser/ast.rs +++ b/compiler/erg_parser/ast.rs @@ -3385,6 +3385,33 @@ impl Def { } } +/// This is not necessary for Erg syntax, but necessary for mapping ASTs in Python +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct AttrDef { + pub attr: Accessor, + pub expr: Box, +} + +impl NestedDisplay for AttrDef { + fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result { + self.attr.fmt_nest(f, level)?; + writeln!(f, " = ")?; + self.expr.fmt_nest(f, level + 1) + } +} + +impl_display_from_nested!(AttrDef); +impl_locational!(AttrDef, attr, expr); + +impl AttrDef { + pub fn new(attr: Accessor, expr: Expr) -> Self { + Self { + attr, + expr: Box::new(expr), + } + } +} + /// e.g. /// ```python /// T = Class ... @@ -3495,11 +3522,12 @@ pub enum Expr { Methods(Methods), ClassDef(ClassDef), PatchDef(PatchDef), + AttrDef(AttrDef), } -impl_nested_display_for_chunk_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Set, Record, BinOp, UnaryOp, Call, DataPack, Lambda, TypeAsc, Def, Methods, ClassDef, PatchDef); +impl_nested_display_for_chunk_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Set, Record, BinOp, UnaryOp, Call, DataPack, Lambda, TypeAsc, Def, Methods, ClassDef, PatchDef, AttrDef); impl_display_from_nested!(Expr); -impl_locational_for_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Set, Record, BinOp, UnaryOp, Call, DataPack, Lambda, TypeAsc, Def, Methods, ClassDef, PatchDef); +impl_locational_for_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Set, Record, BinOp, UnaryOp, Call, DataPack, Lambda, TypeAsc, Def, Methods, ClassDef, PatchDef, AttrDef); impl Expr { pub fn is_match_call(&self) -> bool { diff --git a/compiler/erg_parser/desugar.rs b/compiler/erg_parser/desugar.rs index 58fb4d5f..9621f18b 100644 --- a/compiler/erg_parser/desugar.rs +++ b/compiler/erg_parser/desugar.rs @@ -12,14 +12,14 @@ use erg_common::Str; use erg_common::{enum_unwrap, get_hash, log, set}; use crate::ast::{ - Accessor, Args, Array, ArrayComprehension, ArrayTypeSpec, ArrayWithLength, BinOp, Block, Call, - ClassAttr, ClassAttrs, ClassDef, ConstExpr, DataPack, Def, DefBody, DefId, Dict, Expr, - Identifier, KeyValue, KwArg, Lambda, LambdaSignature, Literal, Methods, MixedRecord, Module, - NonDefaultParamSignature, NormalArray, NormalDict, NormalRecord, NormalSet, NormalTuple, - ParamPattern, ParamRecordAttr, Params, PatchDef, PosArg, Record, RecordAttrOrIdent, - RecordAttrs, Set as astSet, SetWithLength, Signature, SubrSignature, Tuple, TupleTypeSpec, - TypeAppArgs, TypeBoundSpecs, TypeSpec, TypeSpecWithOp, UnaryOp, VarName, VarPattern, - VarRecordAttr, VarSignature, + Accessor, Args, Array, ArrayComprehension, ArrayTypeSpec, ArrayWithLength, AttrDef, BinOp, + Block, Call, ClassAttr, ClassAttrs, ClassDef, ConstExpr, DataPack, Def, DefBody, DefId, Dict, + Expr, Identifier, KeyValue, KwArg, Lambda, LambdaSignature, Literal, Methods, MixedRecord, + Module, NonDefaultParamSignature, NormalArray, NormalDict, NormalRecord, NormalSet, + NormalTuple, ParamPattern, ParamRecordAttr, Params, PatchDef, PosArg, Record, + RecordAttrOrIdent, RecordAttrs, Set as astSet, SetWithLength, Signature, SubrSignature, Tuple, + TupleTypeSpec, TypeAppArgs, TypeBoundSpecs, TypeSpec, TypeSpecWithOp, UnaryOp, VarName, + VarPattern, VarRecordAttr, VarSignature, }; use crate::token::{Token, TokenKind, COLON, DOT}; @@ -73,6 +73,29 @@ impl Desugarer { Args::new(pos_args, kw_args, paren) } + fn perform_desugar_acc(mut desugar: impl FnMut(Expr) -> Expr, acc: Accessor) -> Accessor { + match acc { + Accessor::Ident(ident) => Accessor::Ident(ident), + Accessor::Attr(attr) => desugar(*attr.obj).attr(attr.ident), + Accessor::TupleAttr(tup) => { + let obj = desugar(*tup.obj); + obj.tuple_attr(tup.index) + } + Accessor::Subscr(sub) => { + let obj = desugar(*sub.obj); + let index = desugar(*sub.index); + obj.subscr(index, sub.r_sqbr) + } + Accessor::TypeApp(tapp) => { + let obj = desugar(*tapp.obj); + let args = Self::desugar_args(desugar, tapp.type_args.args); + let type_args = + TypeAppArgs::new(tapp.type_args.l_vbar, args, tapp.type_args.r_vbar); + obj.type_app(type_args) + } + } + } + fn perform_desugar(mut desugar: impl FnMut(Expr) -> Expr, expr: Expr) -> Expr { match expr { Expr::Lit(_) => expr, @@ -234,6 +257,11 @@ impl Desugarer { .collect(); Expr::PatchDef(PatchDef::new(def, methods)) } + Expr::AttrDef(adef) => { + let expr = desugar(*adef.expr); + let attr = Self::perform_desugar_acc(desugar, adef.attr); + Expr::AttrDef(AttrDef::new(attr, expr)) + } Expr::Lambda(lambda) => { let mut chunks = vec![]; for chunk in lambda.body.into_iter() { @@ -267,29 +295,7 @@ impl Desugarer { let new_attrs = ClassAttrs::from(new_attrs); Expr::Methods(Methods::new(method_defs.class, method_defs.vis, new_attrs)) } - Expr::Accessor(acc) => { - let acc = match acc { - Accessor::Ident(ident) => Accessor::Ident(ident), - Accessor::Attr(attr) => desugar(*attr.obj).attr(attr.ident), - Accessor::TupleAttr(tup) => { - let obj = desugar(*tup.obj); - obj.tuple_attr(tup.index) - } - Accessor::Subscr(sub) => { - let obj = desugar(*sub.obj); - let index = desugar(*sub.index); - obj.subscr(index, sub.r_sqbr) - } - Accessor::TypeApp(tapp) => { - let obj = desugar(*tapp.obj); - let args = Self::desugar_args(desugar, tapp.type_args.args); - let type_args = - TypeAppArgs::new(tapp.type_args.l_vbar, args, tapp.type_args.r_vbar); - obj.type_app(type_args) - } - }; - Expr::Accessor(acc) - } + Expr::Accessor(acc) => Expr::Accessor(Self::perform_desugar_acc(desugar, acc)), } }