From beca01c826ee51c9ee6d5eadd7e5ef10f7fb9f58 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Fri, 18 Mar 2022 23:36:18 +0100 Subject: Methods --- src/parse/incremental.rs | 8 ++--- src/parse/mod.rs | 94 ++++++++++++++++++++++++------------------------ src/parse/parser.rs | 11 +++++- src/parse/tokens.rs | 6 ++-- 4 files changed, 64 insertions(+), 55 deletions(-) (limited to 'src/parse') diff --git a/src/parse/incremental.rs b/src/parse/incremental.rs index 468f344e..a2ba502b 100644 --- a/src/parse/incremental.rs +++ b/src/parse/incremental.rs @@ -4,7 +4,8 @@ use std::sync::Arc; use crate::syntax::{Green, GreenNode, NodeKind}; use super::{ - is_newline, parse, reparse_block, reparse_content, reparse_markup_elements, TokenMode, + is_newline, parse, reparse_code_block, reparse_content_block, + reparse_markup_elements, TokenMode, }; /// Allows partial refreshs of the [`Green`] node tree. @@ -210,12 +211,12 @@ impl Reparser<'_> { } let (newborns, terminated, amount) = match mode { - ReparseMode::Code => reparse_block( + ReparseMode::Code => reparse_code_block( &prefix, &self.src[newborn_span.start ..], newborn_span.len(), ), - ReparseMode::Content => reparse_content( + ReparseMode::Content => reparse_content_block( &prefix, &self.src[newborn_span.start ..], newborn_span.len(), @@ -344,7 +345,6 @@ mod tests { test("this~is -- in my opinion -- spectacular", 8 .. 10, "---", 5 .. 25); test("understanding `code` is complicated", 15 .. 15, "C ", 14 .. 22); test("{ let x = g() }", 10 .. 12, "f(54", 0 .. 17); - test("a #let rect with (fill: eastern)\nb", 16 .. 31, " (stroke: conifer", 2 .. 34); test(r#"a ```typst hello``` b"#, 16 .. 17, "", 2 .. 18); test(r#"a ```typst hello```"#, 16 .. 17, "", 2 .. 18); test("#for", 4 .. 4, "//", 0 .. 6); diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 5eaba8b0..58b81521 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -31,7 +31,7 @@ pub fn parse(src: &str) -> Arc { /// Reparse a code block. /// /// Returns `Some` if all of the input was consumed. -pub fn reparse_block( +pub fn reparse_code_block( prefix: &str, src: &str, end_pos: usize, @@ -41,7 +41,7 @@ pub fn reparse_block( return None; } - block(&mut p); + code_block(&mut p); let (mut green, terminated) = p.consume()?; let first = green.remove(0); @@ -55,7 +55,7 @@ pub fn reparse_block( /// Reparse a content block. /// /// Returns `Some` if all of the input was consumed. -pub fn reparse_content( +pub fn reparse_content_block( prefix: &str, src: &str, end_pos: usize, @@ -65,7 +65,7 @@ pub fn reparse_content( return None; } - content(&mut p); + content_block(&mut p); let (mut green, terminated) = p.consume()?; let first = green.remove(0); @@ -236,8 +236,8 @@ fn markup_node(p: &mut Parser, at_start: &mut bool) { | NodeKind::Include => markup_expr(p), // Code and content block. - NodeKind::LeftBrace => block(p), - NodeKind::LeftBracket => content(p), + NodeKind::LeftBrace => code_block(p), + NodeKind::LeftBracket => content_block(p), NodeKind::Error(_, _) => p.eat(), _ => p.unexpected(), @@ -364,7 +364,7 @@ fn expr_prec(p: &mut Parser, atomic: bool, min_prec: usize) -> ParseResult { // Exclamation mark, parenthesis or bracket means this is a function // call. if let Some(NodeKind::LeftParen | NodeKind::LeftBracket) = p.peek_direct() { - call(p, marker)?; + func_call(p, marker)?; continue; } @@ -372,8 +372,9 @@ fn expr_prec(p: &mut Parser, atomic: bool, min_prec: usize) -> ParseResult { break; } - if p.at(&NodeKind::With) { - with_expr(p, marker)?; + if p.at(&NodeKind::Dot) { + method_call(p, marker)?; + continue; } let op = if p.eat_if(&NodeKind::Not) { @@ -432,8 +433,8 @@ fn primary(p: &mut Parser, atomic: bool) -> ParseResult { // Structures. Some(NodeKind::LeftParen) => parenthesized(p, atomic), - Some(NodeKind::LeftBrace) => Ok(block(p)), - Some(NodeKind::LeftBracket) => Ok(content(p)), + Some(NodeKind::LeftBrace) => Ok(code_block(p)), + Some(NodeKind::LeftBracket) => Ok(content_block(p)), // Keywords. Some(NodeKind::Let) => let_expr(p), @@ -671,7 +672,7 @@ fn params(p: &mut Parser, marker: Marker) { } /// Parse a code block: `{...}`. -fn block(p: &mut Parser) { +fn code_block(p: &mut Parser) { p.perform(NodeKind::CodeBlock, |p| { p.start_group(Group::Brace); while !p.eof() { @@ -689,7 +690,7 @@ fn block(p: &mut Parser) { } // Parse a content block: `[...]`. -fn content(p: &mut Parser) { +fn content_block(p: &mut Parser) { p.perform(NodeKind::ContentBlock, |p| { p.start_group(Group::Bracket); markup(p, true); @@ -698,8 +699,17 @@ fn content(p: &mut Parser) { } /// Parse a function call. -fn call(p: &mut Parser, callee: Marker) -> ParseResult { - callee.perform(p, NodeKind::CallExpr, |p| args(p, true, true)) +fn func_call(p: &mut Parser, callee: Marker) -> ParseResult { + callee.perform(p, NodeKind::FuncCall, |p| args(p, true, true)) +} + +/// Parse a method call. +fn method_call(p: &mut Parser, marker: Marker) -> ParseResult { + marker.perform(p, NodeKind::MethodCall, |p| { + p.eat_assert(&NodeKind::Dot); + ident(p)?; + args(p, true, true) + }) } /// Parse the arguments to a function call. @@ -721,21 +731,13 @@ fn args(p: &mut Parser, direct: bool, brackets: bool) -> ParseResult { } while brackets && p.peek_direct() == Some(&NodeKind::LeftBracket) { - content(p); + content_block(p); } }); Ok(()) } -/// Parse a with expression. -fn with_expr(p: &mut Parser, marker: Marker) -> ParseResult { - marker.perform(p, NodeKind::WithExpr, |p| { - p.eat_assert(&NodeKind::With); - args(p, false, false) - }) -} - /// Parse a let expression. fn let_expr(p: &mut Parser) -> ParseResult { p.perform(NodeKind::LetExpr, |p| { @@ -744,30 +746,26 @@ fn let_expr(p: &mut Parser) -> ParseResult { let marker = p.marker(); ident(p)?; - if p.at(&NodeKind::With) { - with_expr(p, marker)?; - } else { - // If a parenthesis follows, this is a function definition. - let has_params = p.peek_direct() == Some(&NodeKind::LeftParen); - if has_params { - let marker = p.marker(); - p.start_group(Group::Paren); - collection(p); - p.end_group(); - params(p, marker); - } + // If a parenthesis follows, this is a function definition. + let has_params = p.peek_direct() == Some(&NodeKind::LeftParen); + if has_params { + let marker = p.marker(); + p.start_group(Group::Paren); + collection(p); + p.end_group(); + params(p, marker); + } - if p.eat_if(&NodeKind::Eq) { - expr(p)?; - } else if has_params { - // Function definitions must have a body. - p.expected("body"); - } + if p.eat_if(&NodeKind::Eq) { + expr(p)?; + } else if has_params { + // Function definitions must have a body. + p.expected("body"); + } - // Rewrite into a closure expression if it's a function definition. - if has_params { - marker.end(p, NodeKind::ClosureExpr); - } + // Rewrite into a closure expression if it's a function definition. + if has_params { + marker.end(p, NodeKind::ClosureExpr); } Ok(()) @@ -931,8 +929,8 @@ fn return_expr(p: &mut Parser) -> ParseResult { /// Parse a control flow body. fn body(p: &mut Parser) -> ParseResult { match p.peek() { - Some(NodeKind::LeftBracket) => Ok(content(p)), - Some(NodeKind::LeftBrace) => Ok(block(p)), + Some(NodeKind::LeftBracket) => Ok(content_block(p)), + Some(NodeKind::LeftBrace) => Ok(code_block(p)), _ => { p.expected("body"); Err(ParseError) diff --git a/src/parse/parser.rs b/src/parse/parser.rs index 33cf489c..63ba4918 100644 --- a/src/parse/parser.rs +++ b/src/parse/parser.rs @@ -352,7 +352,16 @@ impl<'s> Parser<'s> { match self.groups.last().map(|group| group.kind) { Some(Group::Strong | Group::Emph) => n >= 2, - Some(Group::Expr | Group::Imports) => n >= 1, + Some(Group::Imports) => n >= 1, + Some(Group::Expr) if n >= 1 => { + // Allow else and method call to continue on next line. + self.groups.iter().nth_back(1).map(|group| group.kind) + != Some(Group::Brace) + || !matches!( + self.tokens.clone().next(), + Some(NodeKind::Else | NodeKind::Dot) + ) + } _ => false, } } diff --git a/src/parse/tokens.rs b/src/parse/tokens.rs index 752714fd..0c05d770 100644 --- a/src/parse/tokens.rs +++ b/src/parse/tokens.rs @@ -10,6 +10,7 @@ use crate::syntax::{ErrorPos, NodeKind}; use crate::util::EcoString; /// An iterator over the tokens of a string of source code. +#[derive(Clone)] pub struct Tokens<'s> { /// The underlying scanner. s: Scanner<'s>, @@ -184,6 +185,7 @@ impl<'s> Tokens<'s> { '=' => NodeKind::Eq, '<' => NodeKind::Lt, '>' => NodeKind::Gt, + '.' if self.s.check_or(true, |n| !n.is_ascii_digit()) => NodeKind::Dot, // Identifiers. c if is_id_start(c) => self.ident(start), @@ -572,7 +574,6 @@ fn keyword(ident: &str) -> Option { "not" => NodeKind::Not, "and" => NodeKind::And, "or" => NodeKind::Or, - "with" => NodeKind::With, "let" => NodeKind::Let, "set" => NodeKind::Set, "show" => NodeKind::Show, @@ -859,6 +860,7 @@ mod tests { t!(Code: "-" => Minus); t!(Code[" a1"]: "*" => Star); t!(Code[" a1"]: "/" => Slash); + t!(Code[" a/"]: "." => Dot); t!(Code: "=" => Eq); t!(Code: "==" => EqEq); t!(Code: "!=" => ExclEq); @@ -875,7 +877,7 @@ mod tests { // Test combinations. t!(Code: "<=>" => LtEq, Gt); - t!(Code[" a/"]: "..." => Dots, Invalid(".")); + t!(Code[" a/"]: "..." => Dots, Dot); // Test hyphen as symbol vs part of identifier. t!(Code[" /"]: "-1" => Minus, Int(1)); -- cgit v1.2.3