diff --git a/src/parse_error.rs b/src/parse_error.rs index 7d8b4ad72d..ba47ec3e7b 100644 --- a/src/parse_error.rs +++ b/src/parse_error.rs @@ -5,6 +5,7 @@ pub enum ParseError { ExtraTokens(Span), ExtraPositional(Span), UnexpectedEof(String, Span), + Unclosed(String, Span), UnknownStatement(Span), Mismatch(String, Span), VariableNotFound(Span), diff --git a/src/parser.rs b/src/parser.rs index fa19dd3a01..ce62381d61 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -102,6 +102,7 @@ pub enum Expr { Operator(Operator), BinaryOp(Box, Box, Box), //lhs, op, rhs Subexpression(Box), + Block(Box), Garbage, } @@ -539,6 +540,17 @@ impl ParserWorkingSet { } if bytes.ends_with(b")") { end -= 1; + } else { + error = error.or_else(|| { + Some(ParseError::Unclosed( + ")".into(), + Span { + start: end, + end: end + 1, + file_id: span.file_id, + }, + )) + }); } let span = Span { @@ -552,8 +564,6 @@ impl ParserWorkingSet { let (output, err) = lex(&source[..end], span.file_id, start, crate::LexMode::Normal); error = error.or(err); - println!("parsing subexpression: {:?} {:?}", output, error); - let (output, err) = lite_parse(&output); error = error.or(err); @@ -570,6 +580,60 @@ impl ParserWorkingSet { ) } + pub fn parse_block_expression(&mut self, span: Span) -> (Expression, Option) { + let bytes = self.get_span_contents(span); + let mut error = None; + + let mut start = span.start; + let mut end = span.end; + + if bytes.starts_with(b"{") { + start += 1; + } + if bytes.ends_with(b"}") { + end -= 1; + } else { + error = error.or_else(|| { + Some(ParseError::Unclosed( + "}".into(), + Span { + start: end, + end: end + 1, + file_id: span.file_id, + }, + )) + }); + } + + let span = Span { + start, + end, + file_id: span.file_id, + }; + + let source = self.get_file_contents(span.file_id); + + let (output, err) = lex(&source[..end], span.file_id, start, crate::LexMode::Normal); + error = error.or(err); + + let (output, err) = lite_parse(&output); + error = error.or(err); + + let (output, err) = self.parse_block(&output); + error = error.or(err); + + println!("{:?} {:?}", output, error); + + ( + Expression { + expr: Expr::Block(Box::new(output)), + ty: Type::Unknown, + span, + }, + error, + ) + } + pub fn parse_arg( &mut self, span: Span, @@ -580,6 +644,15 @@ impl ParserWorkingSet { return self.parse_dollar_expr(span); } else if bytes.starts_with(b"(") { return self.parse_full_column_path(span); + } else if bytes.starts_with(b"{") { + if shape != SyntaxShape::Block && shape != SyntaxShape::Any { + // FIXME: need better errors + return ( + garbage(span), + Some(ParseError::Mismatch("not a block".into(), span)), + ); + } + return self.parse_block_expression(span); } match shape { @@ -603,6 +676,7 @@ impl ParserWorkingSet { ) } } + SyntaxShape::Block => self.parse_block_expression(span), SyntaxShape::Any => { let shapes = vec![ SyntaxShape::Int,