diff --git a/compiler/erg_parser/ast.rs b/compiler/erg_parser/ast.rs index ccd1a611..692d0722 100644 --- a/compiler/erg_parser/ast.rs +++ b/compiler/erg_parser/ast.rs @@ -2138,10 +2138,55 @@ impl ParamTuplePattern { } } +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct ParamRecordAttr { + pub lhs: Identifier, + pub rhs: ParamSignature, +} + +impl NestedDisplay for ParamRecordAttr { + fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result { + write!(f, "{} = {}", self.lhs, self.rhs) + } +} + +impl_display_from_nested!(ParamRecordAttr); +impl_locational!(ParamRecordAttr, lhs, rhs); + +impl ParamRecordAttr { + pub const fn new(lhs: Identifier, rhs: ParamSignature) -> Self { + Self { lhs, rhs } + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct ParamRecordAttrs { + pub(crate) elems: Vec, +} + +impl NestedDisplay for ParamRecordAttrs { + fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result { + write!(f, "{}", fmt_vec_split_with(&self.elems, "; ")) + } +} + +impl_display_from_nested!(ParamRecordAttrs); +impl_stream!(ParamRecordAttrs, ParamRecordAttr, elems); + +impl ParamRecordAttrs { + pub const fn new(elems: Vec) -> Self { + Self { elems } + } + + pub const fn empty() -> Self { + Self::new(vec![]) + } +} + #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct ParamRecordPattern { l_brace: Token, - pub(crate) elems: Params, + pub(crate) elems: ParamRecordAttrs, r_brace: Token, } @@ -2155,7 +2200,7 @@ impl_display_from_nested!(ParamRecordPattern); impl_locational!(ParamRecordPattern, l_brace, r_brace); impl ParamRecordPattern { - pub const fn new(l_brace: Token, elems: Params, r_brace: Token) -> Self { + pub const fn new(l_brace: Token, elems: ParamRecordAttrs, r_brace: Token) -> Self { Self { l_brace, elems, diff --git a/compiler/erg_parser/parse.rs b/compiler/erg_parser/parse.rs index 2e57decc..96307fa3 100644 --- a/compiler/erg_parser/parse.rs +++ b/compiler/erg_parser/parse.rs @@ -309,18 +309,21 @@ impl Parser { self.level -= 1; return Ok(block); } + assert!(self.cur_is(Newline)); + self.skip(); + assert!(self.cur_is(Indent)); + self.skip(); loop { match self.peek() { + Some(t) if t.is(Newline) && self.nth_is(1, Dedent) => { + let nl = self.lpop(); + self.skip(); + self.restore(nl); + break; + } Some(t) if t.category_is(TC::Separator) => { self.skip(); } - Some(t) if t.is(Indent) => { - self.skip(); - } - Some(t) if t.is(Dedent) => { - self.skip(); - break; - } Some(t) if t.is(EOF) => { break; } @@ -391,7 +394,7 @@ impl Parser { fn try_reduce_acc(&mut self) -> ParseResult { debug_call_info!(self); let mut acc = match self.peek() { - Some(t) if t.is(Symbol) => Accessor::local(self.lpop()), + Some(t) if t.is(Symbol) || t.is(UBar) => Accessor::local(self.lpop()), Some(t) if t.is(Dot) => { let dot = self.lpop(); let maybe_symbol = self.lpop(); @@ -609,7 +612,8 @@ impl Parser { || t.category_is(TC::UnaryOp) || t.is(LParen) || t.is(LSqBr) - || t.is(LBrace) => + || t.is(LBrace) + || t.is(UBar) => { Some(self.try_reduce_args()) } @@ -670,18 +674,6 @@ impl Parser { } debug_power_assert!(self.cur_is(Indent)); self.skip(); - if !args.kw_is_empty() { - args.push_kw(self.try_reduce_kw_arg().map_err(|_| self.stack_dec())?); - } else { - match self.try_reduce_arg().map_err(|_| self.stack_dec())? { - PosOrKwArg::Pos(arg) => { - args.push_pos(arg); - } - PosOrKwArg::Kw(arg) => { - args.push_kw(arg); - } - } - } } Some(t) if t.is(Comma) => { self.skip(); @@ -704,14 +696,24 @@ impl Parser { } } } - Some(t) if t.is(Newline) && colon_style => { - while self.cur_is(Newline) { - self.skip(); - } - if self.cur_is(Dedent) { - self.skip(); + Some(t) if t.is(RParen) => { + rp = Some(self.lpop()); + let (pos_args, kw_args, _) = args.deconstruct(); + args = Args::new(pos_args, kw_args, Some((lp.unwrap(), rp.unwrap()))); + break; + } + Some(t) if t.is(Newline) => { + if !colon_style { break; } + let last = self.lpop(); + if self.cur_is(Dedent) { + self.skip(); + self.restore(last); + break; + } + } + Some(_) if colon_style => { if !args.kw_is_empty() { args.push_kw(self.try_reduce_kw_arg().map_err(|_| self.stack_dec())?); } else { @@ -725,12 +727,6 @@ impl Parser { } } } - Some(t) if t.is(RParen) => { - rp = Some(self.lpop()); - let (pos_args, kw_args, _) = args.deconstruct(); - args = Args::new(pos_args, kw_args, Some((lp.unwrap(), rp.unwrap()))); - break; - } _ => { break; } @@ -853,13 +849,15 @@ impl Parser { let mut defs = vec![first]; loop { match self.peek() { + Some(t) if t.is(Newline) && self.nth_is(1, Dedent) => { + let nl = self.lpop(); + self.skip(); + self.restore(nl); + break; + } Some(t) if t.category_is(TC::Separator) => { self.skip(); } - Some(t) if t.is(Dedent) => { - self.skip(); - break; - } Some(_) => { let def = self.try_reduce_chunk(false).map_err(|_| self.stack_dec())?; match def { @@ -906,6 +904,7 @@ impl Parser { } } + /// chunk = normal expr + def fn try_reduce_chunk(&mut self, winding: bool) -> ParseResult { debug_call_info!(self); let mut stack = Vec::::new(); @@ -1140,6 +1139,7 @@ impl Parser { } } + /// chunk = expr + def /// winding: true => parse paren-less tuple fn try_reduce_expr(&mut self, winding: bool) -> ParseResult { debug_call_info!(self); @@ -1326,7 +1326,7 @@ impl Parser { } } } - Some(t) if t.is(Symbol) || t.is(Dot) => { + Some(t) if t.is(Symbol) || t.is(Dot) || t.is(UBar) => { let call_or_acc = self .try_reduce_call_or_acc() .map_err(|_| self.stack_dec())?; @@ -1721,7 +1721,11 @@ impl Parser { debug_call_info!(self); match accessor { Accessor::Ident(ident) => { - let pat = VarPattern::Ident(ident); + let pat = if &ident.inspect()[..] == "_" { + VarPattern::Discard(ident.name.into_token()) + } else { + VarPattern::Ident(ident) + }; self.level -= 1; Ok(VarSignature::new(pat, None)) } @@ -2055,10 +2059,41 @@ impl Parser { fn convert_record_to_param_record_pat( &mut self, - _record: Record, + record: Record, ) -> ParseResult { debug_call_info!(self); - todo!() + match record { + Record::Normal(rec) => { + let mut pats = vec![]; + for mut attr in rec.attrs.into_iter() { + let lhs = + option_enum_unwrap!(attr.sig, Signature::Var).unwrap_or_else(|| todo!()); + let lhs = + option_enum_unwrap!(lhs.pat, VarPattern::Ident).unwrap_or_else(|| todo!()); + assert_eq!(attr.body.block.len(), 1); + let rhs = option_enum_unwrap!(attr.body.block.remove(0), Expr::Accessor) + .unwrap_or_else(|| todo!()); + let rhs = self + .convert_accessor_to_param_sig(rhs) + .map_err(|_| self.stack_dec())?; + pats.push(ParamRecordAttr::new(lhs, rhs)); + } + let attrs = ParamRecordAttrs::new(pats); + self.level -= 1; + Ok(ParamRecordPattern::new(rec.l_brace, attrs, rec.r_brace)) + } + Record::Shortened(rec) => { + let mut pats = vec![]; + for ident in rec.idents.into_iter() { + let rhs = + ParamSignature::new(ParamPattern::VarName(ident.name.clone()), None, None); + pats.push(ParamRecordAttr::new(ident.clone(), rhs)); + } + let attrs = ParamRecordAttrs::new(pats); + self.level -= 1; + Ok(ParamRecordPattern::new(rec.l_brace, attrs, rec.r_brace)) + } + } } fn convert_tuple_to_param_tuple_pat(&mut self, tuple: Tuple) -> ParseResult { @@ -2147,7 +2182,11 @@ impl Parser { debug_call_info!(self); match accessor { Accessor::Ident(ident) => { - let pat = ParamPattern::VarName(ident.name); + let pat = if &ident.name.inspect()[..] == "_" { + ParamPattern::Discard(ident.name.into_token()) + } else { + ParamPattern::VarName(ident.name) + }; self.level -= 1; Ok(ParamSignature::new(pat, None, None)) } @@ -2186,10 +2225,18 @@ impl Parser { fn convert_type_asc_to_lambda_sig( &mut self, - _tasc: TypeAscription, + tasc: TypeAscription, ) -> ParseResult { debug_call_info!(self); - todo!() + let sig = self + .convert_rhs_to_param(*tasc.expr, true) + .map_err(|_| self.stack_dec())?; + self.level -= 1; + Ok(LambdaSignature::new( + Params::new(vec![sig], None, vec![], None), + None, + TypeBoundSpecs::empty(), + )) } fn convert_rhs_to_type_spec(&mut self, rhs: Expr) -> ParseResult { diff --git a/examples/control.er b/examples/control.er index 94fc8b12..7fc6d0a7 100644 --- a/examples/control.er +++ b/examples/control.er @@ -15,10 +15,10 @@ sum = match a: [x, y, z] -> x + y + z (x, y, z) -> x + y + z {x; y; z} -> x + y + z - i: Int -> i + (i: Int) -> i _ -> panic "unknown object" -for! 0.., i => +for! 0..1000, i => print! "i = {i}" if i >= 100: do return break() diff --git a/examples/enum.er b/examples/enum.er index 84036916..bba146a9 100644 --- a/examples/enum.er +++ b/examples/enum.er @@ -1,26 +1,25 @@ LitExpr = Class {.i = Int}, Impl := Show LitExpr. new i = Self::__new__ {.i;} - show &self = "{self.i}" + show self = "{self.i}" AddExpr = Class {.lhs = Expr, .rhs = Expr}, Impl := Show AddExpr. new lhs, rhs = Self::__new__ {.lhs; .rhs} - show &self = "{self.lhs} + {self.rhs}" + show self = "{self.lhs} + {self.rhs}" SubExpr = Class {.lhs = Expr, .rhs = Expr}, Impl := Show SubExpr. new lhs, rhs = Self::__new__ {.lhs; .rhs} - show &self = "{self.lhs} - {self.rhs}" + show self = "{self.lhs} - {self.rhs}" PosExpr = Class {.expr = Expr}, Impl := Show PosExpr. new expr = Self::__new__ {.expr;} - show &self = "+{self.expr}" + show self = "+{self.expr}" NegExpr = Class {.expr = Expr}, Impl := Show NegExpr. new expr = Self::__new__ {.expr;} - show &self = "-{self.expr}" + show self = "-{self.expr}" -Expr = Enum: - LitExpr +Expr = Enum LitExpr: AddExpr SubExpr NegExpr @@ -29,11 +28,11 @@ Expr. add = Self.cons(AddExpr) eval self = match self: - l: Expr.LitExpr -> l.i - a: Expr.AddExpr -> a.lhs + a.rhs - s: Expr.SubExpr -> s.lhs - s.rhs - p: Expr.PosExpr -> p.expr - n: Expr.NegExpr -> -n.expr + (l: Expr.LitExpr) -> l.i + (a: Expr.AddExpr) -> a.lhs + a.rhs + (s: Expr.SubExpr) -> s.lhs - s.rhs + (p: Expr.PosExpr) -> p.expr + (n: Expr.NegExpr) -> -n.expr expr = Expr.add Expr.lit(1), Expr.lit(2) print! expr # 1 + 2