WIP: Enable to declare in class methods definitions

This commit is contained in:
Shunsuke Shibayama 2022-11-07 17:37:46 +09:00
parent 60956a590e
commit 14b143778f
5 changed files with 143 additions and 53 deletions

View file

@ -1098,24 +1098,35 @@ impl ASTLowerer {
}
let kind = ContextKind::MethodDefs(impl_trait.as_ref().map(|(t, _)| t.clone()));
self.ctx.grow(&class.local_name(), kind, Private, None);
for def in methods.defs.iter_mut() {
if methods.vis.is(TokenKind::Dot) {
def.sig.ident_mut().unwrap().dot = Some(Token::new(
TokenKind::Dot,
".",
def.sig.ln_begin().unwrap(),
def.sig.col_begin().unwrap(),
));
}
self.ctx.preregister_def(def)?;
}
for def in methods.defs.into_iter() {
match self.lower_def(def) {
Ok(def) => {
hir_methods.push(hir::Expr::Def(def));
for attr in methods.attrs.iter_mut() {
match attr {
ast::ClassAttr::Def(def) => {
if methods.vis.is(TokenKind::Dot) {
def.sig.ident_mut().unwrap().dot = Some(Token::new(
TokenKind::Dot,
".",
def.sig.ln_begin().unwrap(),
def.sig.col_begin().unwrap(),
));
}
self.ctx.preregister_def(def)?;
}
Err(errs) => {
self.errs.extend(errs.into_iter());
ast::ClassAttr::Decl(_decl) => {}
}
}
for attr in methods.attrs.into_iter() {
match attr {
ast::ClassAttr::Def(def) => match self.lower_def(def) {
Ok(def) => {
hir_methods.push(hir::Expr::Def(def));
}
Err(errs) => {
self.errs.extend(errs.into_iter());
}
},
ast::ClassAttr::Decl(decl) => {
let decl = self.lower_type_asc(decl)?;
hir_methods.push(hir::Expr::TypeAsc(decl));
}
}
}
@ -1590,6 +1601,10 @@ impl ASTLowerer {
res
}
fn declare_class_def(&mut self, _class_def: ast::ClassDef) -> LowerResult<hir::ClassDef> {
todo!()
}
fn fake_lower_obj(&self, obj: ast::Expr) -> LowerResult<hir::Expr> {
match obj {
ast::Expr::Accessor(ast::Accessor::Ident(ident)) => {
@ -1748,12 +1763,9 @@ impl ASTLowerer {
log!(info "entered {}", fn_name!());
match expr {
ast::Expr::Def(def) => Ok(hir::Expr::Def(self.declare_alias_or_import(def)?)),
ast::Expr::ClassDef(defs) => Err(LowerErrors::from(LowerError::feature_error(
self.cfg.input.clone(),
defs.loc(),
"class declaration",
self.ctx.caused_by(),
))),
ast::Expr::ClassDef(class_def) => {
Ok(hir::Expr::ClassDef(self.declare_class_def(class_def)?))
}
ast::Expr::TypeAsc(tasc) => Ok(hir::Expr::TypeAsc(self.declare_ident(tasc)?)),
ast::Expr::Call(call)
if call

View file

@ -704,6 +704,60 @@ impl_nested_display_for_enum!(Dict; Normal, Comprehension);
impl_display_for_enum!(Dict; Normal, Comprehension);
impl_locational_for_enum!(Dict; Normal, Comprehension);
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ClassAttr {
Def(Def),
Decl(TypeAscription),
}
impl_nested_display_for_enum!(ClassAttr; Def, Decl);
impl_display_for_enum!(ClassAttr; Def, Decl);
impl_locational_for_enum!(ClassAttr; Def, Decl);
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ClassAttrs(Vec<ClassAttr>);
impl NestedDisplay for ClassAttrs {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
fmt_lines(self.0.iter(), f, level)?;
writeln!(f)
}
}
impl Locational for ClassAttrs {
fn loc(&self) -> Location {
Location::concat(self.0.first().unwrap(), self.0.last().unwrap())
}
}
impl From<Vec<ClassAttr>> for ClassAttrs {
fn from(attrs: Vec<ClassAttr>) -> Self {
Self(attrs)
}
}
impl ClassAttrs {
pub const fn new(attrs: Vec<ClassAttr>) -> Self {
Self(attrs)
}
pub fn iter(&self) -> impl Iterator<Item = &ClassAttr> {
self.0.iter()
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut ClassAttr> {
self.0.iter_mut()
}
}
impl IntoIterator for ClassAttrs {
type Item = ClassAttr;
type IntoIter = <Vec<ClassAttr> as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct RecordAttrs(Vec<Def>);
@ -3194,23 +3248,23 @@ impl Def {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Methods {
pub class: TypeSpec,
pub vis: Token, // `.` or `::`
pub defs: RecordAttrs, // TODO: allow declaration
pub vis: Token, // `.` or `::`
pub attrs: ClassAttrs,
}
impl NestedDisplay for Methods {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
writeln!(f, "{}{}", self.class, self.vis.content)?;
self.defs.fmt_nest(f, level + 1)
self.attrs.fmt_nest(f, level + 1)
}
}
impl_display_from_nested!(Methods);
impl_locational!(Methods, class, defs);
impl_locational!(Methods, class, attrs);
impl Methods {
pub const fn new(class: TypeSpec, vis: Token, defs: RecordAttrs) -> Self {
Self { class, vis, defs }
pub const fn new(class: TypeSpec, vis: Token, attrs: ClassAttrs) -> Self {
Self { class, vis, attrs }
}
}

View file

@ -12,11 +12,12 @@ use erg_common::{enum_unwrap, get_hash, log, set};
use crate::ast::{
Accessor, Args, Array, ArrayComprehension, ArrayTypeSpec, ArrayWithLength, BinOp, Block, Call,
ConstExpr, DataPack, Def, DefBody, DefId, Dict, Expr, Identifier, KeyValue, KwArg, Lambda,
LambdaSignature, Literal, Methods, Module, NonDefaultParamSignature, NormalArray, NormalDict,
NormalRecord, NormalSet, NormalTuple, ParamPattern, Params, PosArg, Record, RecordAttrs,
Set as astSet, SetWithLength, ShortenedRecord, Signature, SubrSignature, Tuple, TypeBoundSpecs,
TypeSpec, TypeSpecWithOp, UnaryOp, VarName, VarPattern, VarRecordAttr, VarSignature,
ClassAttr, ClassAttrs, ConstExpr, DataPack, Def, DefBody, DefId, Dict, Expr, Identifier,
KeyValue, KwArg, Lambda, LambdaSignature, Literal, Methods, Module, NonDefaultParamSignature,
NormalArray, NormalDict, NormalRecord, NormalSet, NormalTuple, ParamPattern, Params, PosArg,
Record, RecordAttrs, Set as astSet, SetWithLength, ShortenedRecord, Signature, SubrSignature,
Tuple, TypeBoundSpecs, TypeSpec, TypeSpecWithOp, UnaryOp, VarName, VarPattern, VarRecordAttr,
VarSignature,
};
use crate::token::{Token, TokenKind};
@ -204,17 +205,25 @@ impl Desugarer {
expr.type_asc_expr(tasc.op, tasc.t_spec)
}
Expr::Methods(method_defs) => {
let mut new_defs = vec![];
for def in method_defs.defs.into_iter() {
let mut new_attrs = vec![];
for attr in method_defs.attrs.into_iter() {
let mut chunks = vec![];
for chunk in def.body.block.into_iter() {
chunks.push(desugar(chunk));
match attr {
ClassAttr::Def(def) => {
for chunk in def.body.block.into_iter() {
chunks.push(desugar(chunk));
}
let body = DefBody::new(def.body.op, Block::new(chunks), def.body.id);
new_attrs.push(ClassAttr::Def(Def::new(def.sig, body)));
}
ClassAttr::Decl(decl) => {
let expr = desugar(*decl.expr);
new_attrs.push(ClassAttr::Decl(expr.type_asc(decl.op, decl.t_spec)));
}
}
let body = DefBody::new(def.body.op, Block::new(chunks), def.body.id);
new_defs.push(Def::new(def.sig, body));
}
let new_defs = RecordAttrs::from(new_defs);
Expr::Methods(Methods::new(method_defs.class, method_defs.vis, new_defs))
let new_attrs = ClassAttrs::from(new_attrs);
Expr::Methods(Methods::new(method_defs.class, method_defs.vis, new_attrs))
}
// TODO: Accessor
other => other,

View file

@ -813,14 +813,18 @@ impl Parser {
let first = self
.try_reduce_chunk(false, false)
.map_err(|_| self.stack_dec())?;
let Some(first) = option_enum_unwrap!(first, Expr::Def) else {
// self.restore();
self.level -= 1;
let err = self.skip_and_throw_syntax_err(caused_by!());
self.errs.push(err);
return Err(());
let first = match first {
Expr::Def(def) => ClassAttr::Def(def),
Expr::TypeAsc(tasc) => ClassAttr::Decl(tasc),
_ => {
// self.restore();
self.level -= 1;
let err = self.skip_and_throw_syntax_err(caused_by!());
self.errs.push(err);
return Err(());
}
};
let mut defs = vec![first];
let mut attrs = vec![first];
loop {
match self.peek() {
Some(t) if t.is(Newline) && self.nth_is(1, Dedent) => {
@ -838,7 +842,10 @@ impl Parser {
.map_err(|_| self.stack_dec())?;
match def {
Expr::Def(def) => {
defs.push(def);
attrs.push(ClassAttr::Def(def));
}
Expr::TypeAsc(tasc) => {
attrs.push(ClassAttr::Decl(tasc));
}
other => {
self.errs
@ -854,10 +861,10 @@ impl Parser {
}
}
}
let defs = RecordAttrs::from(defs);
let attrs = ClassAttrs::from(attrs);
let class = Self::expr_to_type_spec(class).map_err(|e| self.errs.push(e))?;
self.level -= 1;
Ok(Methods::new(class, vis, defs))
Ok(Methods::new(class, vis, attrs))
}
fn try_reduce_do_block(&mut self) -> ParseResult<Lambda> {

View file

@ -3,5 +3,13 @@
.C: ClassType
# or .C.__call__: Int -> .C
.C.__call__: (x: Int,) -> .C
.C.__call__: (x: Int) -> .C
.C.f: (self: .C, y: Int) -> Int
#[
# Class declaration syntax
.C: ClassType {.x = Int}
.C.
__call__: (x: Int) -> .C
f: (self: .C, y: Int) -> Int
]#