summaryrefslogtreecommitdiff
path: root/src/parse
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-03-18 23:36:18 +0100
committerLaurenz <laurmaedje@gmail.com>2022-03-18 23:43:58 +0100
commitbeca01c826ee51c9ee6d5eadd7e5ef10f7fb9f58 (patch)
treee0ebb40b8775bba3b4be7bc47dceda3d349e2ac0 /src/parse
parent77d153d315a2a5909840ebcd47491e4cef14428b (diff)
Methods
Diffstat (limited to 'src/parse')
-rw-r--r--src/parse/incremental.rs8
-rw-r--r--src/parse/mod.rs94
-rw-r--r--src/parse/parser.rs11
-rw-r--r--src/parse/tokens.rs6
4 files changed, 64 insertions, 55 deletions
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<GreenNode> {
/// 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<NodeKind> {
"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));