feat: implement methods declaration syntax

This commit is contained in:
Shunsuke Shibayama 2023-02-17 01:26:04 +09:00
parent a694880ff4
commit b4b02fd0f6
5 changed files with 82 additions and 11 deletions

View file

@ -2150,7 +2150,7 @@ impl ASTLowerer {
graph.add_node_if_none(path);
}
let ast = Reorderer::new(self.cfg.clone())
.reorder(ast)
.reorder(ast, mode)
.map_err(|errs| {
IncompleteArtifact::new(None, errs, LowerWarnings::from(self.warns.take_all()))
})?;

View file

@ -4,7 +4,10 @@ use erg_common::log;
use erg_common::traits::{Locational, Stream};
use erg_common::Str;
use erg_parser::ast::{ClassDef, Expr, Methods, Module, PatchDef, PreDeclTypeSpec, TypeSpec, AST};
use erg_parser::ast::{
Accessor, ClassAttr, ClassDef, Expr, Methods, Module, PatchDef, PreDeclTypeSpec,
TypeAscription, TypeSpec, AST,
};
use crate::error::{TyCheckError, TyCheckErrors};
@ -28,7 +31,7 @@ impl Reorderer {
}
}
pub fn reorder(mut self, ast: AST) -> Result<AST, TyCheckErrors> {
pub fn reorder(mut self, ast: AST, mode: &str) -> Result<AST, TyCheckErrors> {
log!(info "the reordering process has started.");
let mut new = vec![];
for chunk in ast.module.into_iter() {
@ -66,12 +69,17 @@ impl Reorderer {
}
Expr::Methods(methods) => match &methods.class {
TypeSpec::PreDeclTy(PreDeclTypeSpec::Simple(simple)) => {
self.link_methods(simple.ident.inspect().clone(), &mut new, methods)
self.link_methods(simple.ident.inspect().clone(), &mut new, methods, mode)
}
TypeSpec::TypeApp { spec, .. } => {
if let TypeSpec::PreDeclTy(PreDeclTypeSpec::Simple(simple)) = spec.as_ref()
{
self.link_methods(simple.ident.inspect().clone(), &mut new, methods)
self.link_methods(
simple.ident.inspect().clone(),
&mut new,
methods,
mode,
)
} else {
let similar_name = self
.def_root_pos_map
@ -103,7 +111,54 @@ impl Reorderer {
}
}
fn link_methods(&mut self, name: Str, new: &mut Vec<Expr>, methods: Methods) {
/// ```erg
/// C.
/// x: Int
/// f: (self: Self) -> Int
/// ```
/// ↓
/// ```erg
/// C.x: Int
/// C.y: (self: C) -> Int
/// ```
fn flatten_method_decls(&mut self, new: &mut Vec<Expr>, methods: Methods) {
let class = methods.class_as_expr.as_ref();
for method in methods.attrs.into_iter() {
match method {
ClassAttr::Decl(decl) => {
let Expr::Accessor(Accessor::Ident(ident)) = *decl.expr else {
self.errs.push(TyCheckError::syntax_error(
self.cfg.input.clone(),
line!() as usize,
decl.expr.loc(),
"".into(),
"".into(),
None
));
continue;
};
let expr = class.clone().attr_expr(ident);
let decl = TypeAscription::new(expr, decl.t_spec);
new.push(Expr::TypeAscription(decl));
}
ClassAttr::Doc(doc) => {
new.push(Expr::Literal(doc));
}
ClassAttr::Def(def) => {
self.errs.push(TyCheckError::syntax_error(
self.cfg.input.clone(),
line!() as usize,
def.loc(),
"".into(),
"".into(),
None,
));
}
}
}
}
fn link_methods(&mut self, name: Str, new: &mut Vec<Expr>, methods: Methods, mode: &str) {
if let Some(pos) = self.def_root_pos_map.get(&name) {
match new.remove(*pos) {
Expr::ClassDef(mut class_def) => {
@ -116,6 +171,8 @@ impl Reorderer {
}
_ => unreachable!(),
}
} else if mode == "declare" {
self.flatten_method_decls(new, methods);
} else {
let similar_name = self
.def_root_pos_map

View file

@ -3670,6 +3670,7 @@ impl ReDef {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Methods {
pub class: TypeSpec,
pub class_as_expr: Box<Expr>,
pub vis: Token, // `.` or `::`
pub attrs: ClassAttrs,
}
@ -3685,8 +3686,13 @@ impl_display_from_nested!(Methods);
impl_locational!(Methods, class, attrs);
impl Methods {
pub const fn new(class: TypeSpec, vis: Token, attrs: ClassAttrs) -> Self {
Self { class, vis, attrs }
pub fn new(class: TypeSpec, class_as_expr: Expr, vis: Token, attrs: ClassAttrs) -> Self {
Self {
class,
class_as_expr: Box::new(class_as_expr),
vis,
attrs,
}
}
}

View file

@ -303,7 +303,12 @@ impl Desugarer {
}
}
let new_attrs = ClassAttrs::from(new_attrs);
Expr::Methods(Methods::new(method_defs.class, method_defs.vis, new_attrs))
Expr::Methods(Methods::new(
method_defs.class,
*method_defs.class_as_expr,
method_defs.vis,
new_attrs,
))
}
Expr::Accessor(acc) => Expr::Accessor(Self::perform_desugar_acc(desugar, acc)),
Expr::Dummy(exprs) => {

View file

@ -1039,6 +1039,9 @@ impl Parser {
Expr::TypeAscription(tasc) => {
attrs.push(ClassAttr::Decl(tasc));
}
Expr::Literal(lit) if lit.is_doc_comment() => {
attrs.push(ClassAttr::Doc(lit));
}
other => {
self.errs
.push(ParseError::simple_syntax_error(0, other.loc()));
@ -1054,9 +1057,9 @@ impl Parser {
}
}
let attrs = ClassAttrs::from(attrs);
let class = Self::expr_to_type_spec(class).map_err(|e| self.errs.push(e))?;
let t_spec = Self::expr_to_type_spec(class.clone()).map_err(|e| self.errs.push(e))?;
debug_exit_info!(self);
Ok(Methods::new(class, vis, attrs))
Ok(Methods::new(t_spec, class, vis, attrs))
}
fn try_reduce_do_block(&mut self) -> ParseResult<Lambda> {