From ac788f2082711161ec8208eede04d9a2bae02241 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Fri, 22 Jan 2021 17:16:42 +0100 Subject: =?UTF-8?q?Many=20more=20expressions=20=F0=9F=A5=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Boolean, equality, comparison and assignment expression parsing and evaluation. --- src/parse/collection.rs | 4 +- src/parse/mod.rs | 179 ++++++++++++++++++++++++------------------------ 2 files changed, 90 insertions(+), 93 deletions(-) (limited to 'src/parse') diff --git a/src/parse/collection.rs b/src/parse/collection.rs index 58fd91ae..95ca9847 100644 --- a/src/parse/collection.rs +++ b/src/parse/collection.rs @@ -1,5 +1,4 @@ use super::*; -use crate::diag::Deco; /// Parse the arguments to a function call. pub fn arguments(p: &mut Parser) -> ExprArgs { @@ -54,9 +53,8 @@ fn argument(p: &mut Parser) -> Option { let first = p.span_if(expr)?; if p.eat_if(Token::Colon) { if let Expr::Ident(ident) = first.v { - let expr = p.span_if(expr)?; let name = ident.with_span(first.span); - p.deco(Deco::Name.with_span(name.span)); + let expr = p.span_if(expr)?; Some(Argument::Named(Named { name, expr })) } else { p.diag(error!(first.span, "expected identifier")); diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 622223fa..00512c3f 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -49,7 +49,7 @@ fn node(p: &mut Parser, at_start: &mut bool) -> Option { let node = match p.peek()? { // Bracket call. Token::LeftBracket => { - return Some(Node::Expr(bracket_call(p))); + return Some(Node::Expr(bracket_call(p)?)); } // Code block. @@ -153,22 +153,30 @@ fn unicode_escape(p: &mut Parser, token: TokenUnicodeEscape) -> String { } /// Parse a bracketed function call. -fn bracket_call(p: &mut Parser) -> Expr { +fn bracket_call(p: &mut Parser) -> Option { p.start_group(Group::Bracket, TokenMode::Code); // One header is guaranteed, but there may be more (through chaining). let mut outer = vec![]; - let mut inner = p.span(bracket_subheader); + let mut inner = p.span_if(bracket_subheader); while p.eat_if(Token::Pipe) { - outer.push(inner); - inner = p.span(bracket_subheader); + if let Some(new) = p.span_if(bracket_subheader) { + outer.extend(inner); + inner = Some(new); + } } p.end_group(); - if p.peek() == Some(Token::LeftBracket) { - let body = p.span(|p| Expr::Template(bracket_body(p))); + let body = if p.peek() == Some(Token::LeftBracket) { + Some(p.span(|p| Expr::Template(bracket_body(p)))) + } else { + None + }; + + let mut inner = inner?; + if let Some(body) = body { inner.span.expand(body.span); inner.v.args.v.push(Argument::Pos(body)); } @@ -181,28 +189,25 @@ fn bracket_call(p: &mut Parser) -> Expr { inner = top; } - Expr::Call(inner.v) + Some(Expr::Call(inner.v)) } /// Parse one subheader of a bracketed function call. -fn bracket_subheader(p: &mut Parser) -> ExprCall { +fn bracket_subheader(p: &mut Parser) -> Option { p.start_group(Group::Subheader, TokenMode::Code); - let start = p.next_start(); - let name = p.span_if(ident).unwrap_or_else(|| { - let what = "function name"; - if p.eof() { - p.expected_at(what, start); - } else { - p.expected(what); - } - Ident(String::new()).with_span(start) - }); + let name = p.span_if(ident); + if name.is_none() { + p.expected("function name"); + } let args = p.span(arguments); p.end_group(); - ExprCall { name, args } + Some(ExprCall { + callee: Box::new(name?.map(Expr::Ident)), + args, + }) } /// Parse the body of a bracketed function call. @@ -213,78 +218,66 @@ fn bracket_body(p: &mut Parser) -> Tree { tree } -/// Parse a block expression: `{...}`. -fn block(p: &mut Parser) -> Option { - p.start_group(Group::Brace, TokenMode::Code); - let expr = p.span_if(expr); - while !p.eof() { - p.unexpected(); - } - p.end_group(); - Some(Expr::Block(Box::new(expr?))) -} - -/// Parse an expression: `term (+ term)*`. -fn expr(p: &mut Parser) -> Option { - binops(p, term, |token| match token { - Token::Plus => Some(BinOp::Add), - Token::Hyph => Some(BinOp::Sub), +/// Parse an identifier. +fn ident(p: &mut Parser) -> Option { + p.eat_map(|token| match token { + Token::Ident(id) => Some(Ident(id.into())), _ => None, }) } -/// Parse a term: `factor (* factor)*`. -fn term(p: &mut Parser) -> Option { - binops(p, factor, |token| match token { - Token::Star => Some(BinOp::Mul), - Token::Slash => Some(BinOp::Div), - _ => None, - }) +/// Parse an expression. +fn expr(p: &mut Parser) -> Option { + expr_with(p, 0) } -/// Parse binary operations of the from `a ( b)*`. -fn binops( - p: &mut Parser, - operand: fn(&mut Parser) -> Option, - op: fn(Token) -> Option, -) -> Option { - let mut lhs = p.span_if(operand)?; - - while let Some(op) = p.span_if(|p| p.eat_map(op)) { - if let Some(rhs) = p.span_if(operand) { - let span = lhs.span.join(rhs.span); - let expr = Expr::Binary(ExprBinary { - lhs: Box::new(lhs), - op, - rhs: Box::new(rhs), - }); - lhs = expr.with_span(span); - } else { +/// Parse an expression with operators having at least the minimum precedence. +fn expr_with(p: &mut Parser, min_prec: usize) -> Option { + let mut lhs = match p.span_if(|p| p.eat_map(UnOp::from_token)) { + Some(op) => { + let prec = op.v.precedence(); + let expr = p.span_if(|p| expr_with(p, prec))?; + let span = op.span.join(expr.span); + let unary = Expr::Unary(ExprUnary { op, expr: Box::new(expr) }); + unary.with_span(span) + } + None => p.span_if(primary)?, + }; + + loop { + let op = match p.peek().and_then(BinOp::from_token) { + Some(binop) => binop, + None => break, + }; + + let mut prec = op.precedence(); + if prec < min_prec { break; } - } - Some(lhs.v) -} + match op.associativity() { + Associativity::Left => prec += 1, + Associativity::Right => {} + } -/// Parse a factor of the form `-?value`. -fn factor(p: &mut Parser) -> Option { - let op = |token| match token { - Token::Plus => Some(UnOp::Pos), - Token::Hyph => Some(UnOp::Neg), - _ => None, - }; + let op = op.with_span(p.peek_span()); + p.eat(); - if let Some(op) = p.span_if(|p| p.eat_map(op)) { - p.span_if(factor) - .map(|expr| Expr::Unary(ExprUnary { op, expr: Box::new(expr) })) - } else { - value(p) + let rhs = match p.span_if(|p| expr_with(p, prec)) { + Some(rhs) => Box::new(rhs), + None => break, + }; + + let span = lhs.span.join(rhs.span); + let binary = Expr::Binary(ExprBinary { lhs: Box::new(lhs), op, rhs }); + lhs = binary.with_span(span); } + + Some(lhs.v) } -/// Parse a value. -fn value(p: &mut Parser) -> Option { +/// Parse a primary expression. +fn primary(p: &mut Parser) -> Option { let expr = match p.peek() { // Template. Some(Token::LeftBracket) => { @@ -342,19 +335,25 @@ fn template(p: &mut Parser) -> Expr { Expr::Template(tree) } +/// Parse a block expression: `{...}`. +fn block(p: &mut Parser) -> Option { + p.start_group(Group::Brace, TokenMode::Code); + let expr = p.span_if(expr); + while !p.eof() { + p.unexpected(); + } + p.end_group(); + Some(Expr::Block(Box::new(expr?))) +} + /// Parse a parenthesized function call. fn paren_call(p: &mut Parser, name: Spanned) -> Expr { p.start_group(Group::Paren, TokenMode::Code); let args = p.span(arguments); p.end_group(); - Expr::Call(ExprCall { name, args }) -} - -/// Parse an identifier. -fn ident(p: &mut Parser) -> Option { - p.eat_map(|token| match token { - Token::Ident(id) => Some(Ident(id.into())), - _ => None, + Expr::Call(ExprCall { + callee: Box::new(name.map(Expr::Ident)), + args, }) } @@ -388,14 +387,14 @@ fn stmt_let(p: &mut Parser) -> Option { if p.eat_if(Token::Eq) { rhs = p.span_if(expr); } + + if !p.eof() { + p.expected_at("semicolon or line break", p.last_end()); + } } else { p.expected("identifier"); } - if !p.eof() { - p.expected_at("semicolon or line break", p.last_end()); - } - p.end_group(); Some(Expr::Let(ExprLet { pat: pat?, expr: rhs.map(Box::new) })) -- cgit v1.2.3