diff --git a/compiler/erg_parser/ast.rs b/compiler/erg_parser/ast.rs index 7bbae434..cc897cd3 100644 --- a/compiler/erg_parser/ast.rs +++ b/compiler/erg_parser/ast.rs @@ -2283,6 +2283,15 @@ impl LambdaSignature { bounds, } } + + pub fn do_sig(do_symbol: &Token) -> Self { + let parens = Some((do_symbol.clone(), do_symbol.clone())); + Self::new( + Params::new(vec![], vec![], parens), + None, + TypeBoundSpecs::empty(), + ) + } } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] diff --git a/compiler/erg_parser/parse.rs b/compiler/erg_parser/parse.rs index 5813d873..92f555be 100644 --- a/compiler/erg_parser/parse.rs +++ b/compiler/erg_parser/parse.rs @@ -53,6 +53,7 @@ enum PosOrKwArg { pub enum Side { LhsAssign, LhsLambda, + Do, Rhs, } @@ -156,6 +157,15 @@ impl Parser { /// `(Rhs) , (LhsLambda) ->` /// `(Rhs) (LhsLambda) -> (Rhs);` fn cur_side(&self) -> Side { + match self.peek() { + Some(t) => { + let name = &t.inspect()[..]; + if name == "do" || name == "do!" { + return Side::Do; + } + } + _ => {} + } // 以降に=, ->などがないならすべて右辺値 let opt_equal_pos = self.tokens.iter().skip(1).position(|t| t.is(Equal)); let opt_arrow_pos = self @@ -1655,6 +1665,29 @@ impl Parser { Ok(Lambda::new(sig, op, body, self.counter)) } + fn try_reduce_do_block(&mut self) -> ParseResult { + debug_call_info!(self); + let do_symbol = self.lpop(); + let sig = LambdaSignature::do_sig(&do_symbol); + let op = match &do_symbol.inspect()[..] { + "do" => Token::from_str(FuncArrow, "->"), + "do!" => Token::from_str(ProcArrow, "=>"), + _ => todo!(), + }; + if self.cur_is(Colon) { + self.lpop(); + let body = self.try_reduce_block().map_err(|_| self.stack_dec())?; + self.counter.inc(); + self.level -= 1; + Ok(Lambda::new(sig, op, body, self.counter)) + } else { + let expr = self.try_reduce_expr().map_err(|_| self.stack_dec())?; + let block = Block::new(vec![expr]); + self.level -= 1; + Ok(Lambda::new(sig, op, block, self.counter)) + } + } + fn try_reduce_expr(&mut self) -> ParseResult { debug_call_info!(self); let mut stack = Vec::::new(); @@ -1669,6 +1702,11 @@ impl Parser { self.level -= 1; Ok(Expr::Lambda(lambda)) } + Side::Do => { + let lambda = self.try_reduce_do_block().map_err(|_| self.stack_dec())?; + self.level -= 1; + Ok(Expr::Lambda(lambda)) + } Side::Rhs => { stack.push(ExprOrOp::Expr( self.try_reduce_bin_lhs().map_err(|_| self.stack_dec())?, diff --git a/examples/side_effect.er b/examples/side_effect.er index 98d5000a..237edf0a 100644 --- a/examples/side_effect.er +++ b/examples/side_effect.er @@ -1,7 +1,7 @@ if True, () -> log "hello" if! True, () => print! "hello" # if True, () => print! "hello" # this should cause a type error -if True, () -> +if True, do: _x = "aaa" + input!() # this should cause an effect error print! "hello" # this should cause an effect error