diff options
Diffstat (limited to 'src/parse/mod.rs')
| -rw-r--r-- | src/parse/mod.rs | 105 |
1 files changed, 14 insertions, 91 deletions
diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 7880dd7a..912a34d0 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -1,5 +1,6 @@ //! Parsing and tokenization. +mod collection; mod lines; mod parser; mod resolve; @@ -15,10 +16,11 @@ pub use tokens::*; use std::str::FromStr; use crate::color::RgbaColor; -use crate::diag::{Deco, Pass}; -use crate::eval::DictKey; +use crate::diag::Pass; use crate::syntax::*; +use collection::{arguments, parenthesized}; + /// Parse a string of source code. pub fn parse(src: &str) -> Pass<SynTree> { let mut p = Parser::new(src); @@ -153,6 +155,9 @@ fn block_expr(p: &mut Parser) -> Option<Expr> { p.push_mode(TokenMode::Header); p.start_group(Group::Brace); let expr = expr(p); + while !p.eof() { + p.diag_unexpected(); + } p.pop_mode(); p.end_group(); expr @@ -161,7 +166,7 @@ fn block_expr(p: &mut Parser) -> Option<Expr> { /// Parse a parenthesized function call. fn paren_call(p: &mut Parser, name: Spanned<Ident>) -> ExprCall { p.start_group(Group::Paren); - let args = p.span(|p| dict_contents(p).0); + let args = p.span(arguments); p.end_group(); ExprCall { name, args } } @@ -184,16 +189,16 @@ fn bracket_call(p: &mut Parser) -> ExprCall { p.end_group(); if p.peek() == Some(Token::LeftBracket) { - let expr = p.span(|p| Expr::Lit(Lit::Content(bracket_body(p)))); - inner.span.expand(expr.span); - inner.v.args.v.0.push(LitDictEntry { key: None, expr }); + let body = p.span(|p| Expr::Lit(Lit::Content(bracket_body(p)))); + inner.span.expand(body.span); + inner.v.args.v.push(Argument::Pos(body)); } while let Some(mut top) = outer.pop() { let span = inner.span; let node = inner.map(|c| SynNode::Expr(Expr::Call(c))); let expr = Expr::Lit(Lit::Content(vec![node])).with_span(span); - top.v.args.v.0.push(LitDictEntry { key: None, expr }); + top.v.args.v.push(Argument::Pos(expr)); inner = top; } @@ -215,9 +220,9 @@ fn bracket_subheader(p: &mut Parser) -> ExprCall { Ident(String::new()).with_span(start) }); - let args = p.span(|p| dict_contents(p).0); - + let args = p.span(arguments); p.end_group(); + ExprCall { name, args } } @@ -231,75 +236,6 @@ fn bracket_body(p: &mut Parser) -> SynTree { tree } -/// Parse the contents of a dictionary. -fn dict_contents(p: &mut Parser) -> (LitDict, bool) { - let mut dict = LitDict::new(); - let mut missing_coma = None; - let mut comma_and_keyless = true; - - while !p.eof() { - if let Some(entry) = dict_entry(p) { - let behind = entry.expr.span.end; - if let Some(pos) = missing_coma.take() { - p.diag_expected_at("comma", pos); - } - - if let Some(key) = &entry.key { - comma_and_keyless = false; - p.deco(Deco::Name.with_span(key.span)); - } - - dict.0.push(entry); - if p.eof() { - break; - } - - if p.eat_if(Token::Comma) { - comma_and_keyless = false; - } else { - missing_coma = Some(behind); - } - } - } - - let coercible = comma_and_keyless && !dict.0.is_empty(); - (dict, coercible) -} - -/// Parse a single entry in a dictionary. -fn dict_entry(p: &mut Parser) -> Option<LitDictEntry> { - if let Some(ident) = p.span_if(ident) { - match p.peek() { - // Key-value pair. - Some(Token::Colon) => { - p.eat_assert(Token::Colon); - p.span_if(expr).map(|expr| LitDictEntry { - key: Some(ident.map(|id| DictKey::Str(id.0))), - expr, - }) - } - - // Function call. - Some(Token::LeftParen) => Some(LitDictEntry { - key: None, - expr: { - let start = ident.span.start; - let call = paren_call(p, ident); - Expr::Call(call).with_span(start .. p.last_end()) - }, - }), - - // Just an identifier. - _ => Some(LitDictEntry { - key: None, - expr: ident.map(|id| Expr::Lit(Lit::Ident(id))), - }), - } - } else { - p.span_if(expr).map(|expr| LitDictEntry { key: None, expr }) - } -} - /// Parse an expression: `term (+ term)*`. fn expr(p: &mut Parser) -> Option<Expr> { binops(p, term, |token| match token { @@ -418,19 +354,6 @@ fn content(p: &mut Parser) -> SynTree { tree } -/// Parse a parenthesized expression: `(a + b)`, `(1, name: "value"). -fn parenthesized(p: &mut Parser) -> Expr { - p.start_group(Group::Paren); - let (dict, coercible) = dict_contents(p); - let expr = if coercible { - dict.0.into_iter().next().expect("dict is coercible").expr.v - } else { - Expr::Lit(Lit::Dict(dict)) - }; - p.end_group(); - expr -} - /// Parse an identifier. fn ident(p: &mut Parser) -> Option<Ident> { p.eat_map(|token| match token { |
