summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/eval/call.rs28
-rw-r--r--src/parse/mod.rs10
-rw-r--r--src/parse/parser.rs85
3 files changed, 72 insertions, 51 deletions
diff --git a/src/eval/call.rs b/src/eval/call.rs
index 8e75f17c..5b0628a8 100644
--- a/src/eval/call.rs
+++ b/src/eval/call.rs
@@ -73,7 +73,7 @@ impl Args {
where
T: Cast<Spanned<Value>>,
{
- self.pos.iter_mut().find_map(move |slot| try_cast(ctx, slot))
+ (0 .. self.pos.len()).find_map(move |i| try_cast(ctx, &mut self.pos, i))
}
/// Find and remove the first convertible positional argument, producing an
@@ -97,7 +97,16 @@ impl Args {
where
T: Cast<Spanned<Value>>,
{
- self.pos.iter_mut().filter_map(move |slot| try_cast(ctx, slot))
+ let mut i = 0;
+ std::iter::from_fn(move || {
+ while i < self.pos.len() {
+ if let Some(val) = try_cast(ctx, &mut self.pos, i) {
+ return Some(val);
+ }
+ i += 1;
+ }
+ None
+ })
}
/// Convert and remove the value for the given named argument, producing an
@@ -163,17 +172,26 @@ where
/// Try to cast the value in the slot into `T`, putting it back if the
/// conversion fails.
-fn try_cast<T>(ctx: &mut EvalContext, slot: &mut Spanned<Value>) -> Option<T>
+fn try_cast<T>(
+ ctx: &mut EvalContext,
+ vec: &mut Vec<Spanned<Value>>,
+ i: usize,
+) -> Option<T>
where
T: Cast<Spanned<Value>>,
{
// Replace with error placeholder when conversion works since error values
// are ignored when generating "unexpected argument" errors.
- let value = std::mem::replace(slot, Spanned::zero(Value::Error));
+ let slot = &mut vec[i];
+ let value = std::mem::replace(slot, Spanned::zero(Value::None));
let span = value.span;
match T::cast(value) {
- CastResult::Ok(t) => Some(t),
+ CastResult::Ok(t) => {
+ vec.remove(i);
+ Some(t)
+ }
CastResult::Warn(t, m) => {
+ vec.remove(i);
ctx.diag(warning!(span, "{}", m));
Some(t)
}
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index b6836d38..7c92185d 100644
--- a/src/parse/mod.rs
+++ b/src/parse/mod.rs
@@ -117,7 +117,7 @@ fn heading(p: &mut Parser) -> NodeHeading {
// Parse the heading contents.
let mut contents = vec![];
- while p.check(|t| !matches!(t, Token::Space(n) if n > 0)) {
+ while p.check(|t| !matches!(t, Token::Space(n) if n >= 1)) {
if let Some(node) = p.span_if(|p| node(p, &mut false)) {
contents.push(node);
}
@@ -388,8 +388,8 @@ fn string(p: &mut Parser, token: TokenStr) -> String {
/// Parse a let expresion.
fn expr_let(p: &mut Parser) -> Option<Expr> {
p.push_mode(TokenMode::Code);
- p.start_group(Group::Terminated);
p.eat_assert(Token::Let);
+ p.start_group(Group::Expr);
let pat = p.span_if(ident);
let mut rhs = None;
@@ -404,11 +404,11 @@ fn expr_let(p: &mut Parser) -> Option<Expr> {
p.diag_expected("identifier");
}
- while !p.eof() {
- p.diag_unexpected();
+ p.pop_mode();
+ if !p.eof() {
+ p.diag_expected("semicolon or line break");
}
- p.pop_mode();
p.end_group();
pat.map(|pat| Expr::Let(ExprLet { pat, expr: rhs }))
}
diff --git a/src/parse/parser.rs b/src/parse/parser.rs
index 2b5fe720..8c27c8f7 100644
--- a/src/parse/parser.rs
+++ b/src/parse/parser.rs
@@ -112,16 +112,14 @@ impl<'s> Parser<'s> {
/// # Panics
/// This panics if the next token does not start the given group.
pub fn start_group(&mut self, group: Group) {
+ self.groups.push(group);
match group {
Group::Paren => self.eat_assert(Token::LeftParen),
Group::Bracket => self.eat_assert(Token::LeftBracket),
Group::Brace => self.eat_assert(Token::LeftBrace),
- Group::Subheader => {}
- Group::Terminated => {}
+ Group::Expr => self.repeek(),
+ Group::Subheader => self.repeek(),
}
-
- self.groups.push(group);
- self.repeek();
}
/// Ends the parsing of a group and returns the span of the whole group.
@@ -129,26 +127,21 @@ impl<'s> Parser<'s> {
/// # Panics
/// This panics if no group was started.
pub fn end_group(&mut self) {
- // Check that we are indeed at the end of the group.
- debug_assert_eq!(self.peek(), None, "unfinished group");
-
let group = self.groups.pop().expect("no started group");
self.repeek();
- let end = match group {
- Group::Paren => Some(Token::RightParen),
- Group::Bracket => Some(Token::RightBracket),
- Group::Brace => Some(Token::RightBrace),
- Group::Subheader => None,
- Group::Terminated => Some(Token::Semicolon),
+ let (end, required) = match group {
+ Group::Paren => (Token::RightParen, true),
+ Group::Bracket => (Token::RightBracket, true),
+ Group::Brace => (Token::RightBrace, true),
+ Group::Expr => (Token::Semicolon, false),
+ Group::Subheader => return,
};
- if let Some(token) = end {
- if self.next == Some(token) {
- self.bump();
- } else {
- self.diag(error!(self.next_start, "expected {}", token.name()));
- }
+ if self.next == Some(end) {
+ self.bump();
+ } else if required {
+ self.diag(error!(self.next_start, "expected {}", end.name()));
}
}
@@ -169,7 +162,7 @@ impl<'s> Parser<'s> {
where
F: FnOnce(&mut Self) -> Option<T>,
{
- self.span(|p| f(p)).transpose()
+ self.span(f).transpose()
}
/// Consume the next token.
@@ -269,17 +262,21 @@ impl<'s> Parser<'s> {
match self.tokens.mode() {
TokenMode::Markup => {}
- TokenMode::Code => {
- while matches!(
- self.next,
- Some(Token::Space(_)) |
- Some(Token::LineComment(_)) |
- Some(Token::BlockComment(_))
- ) {
- self.next_start = self.tokens.pos();
- self.next = self.tokens.next();
+ TokenMode::Code => loop {
+ match self.next {
+ Some(Token::Space(n)) => {
+ if n >= 1 && self.groups.last() == Some(&Group::Expr) {
+ break;
+ }
+ }
+ Some(Token::LineComment(_)) => {}
+ Some(Token::BlockComment(_)) => {}
+ _ => break,
}
- }
+
+ self.next_start = self.tokens.pos();
+ self.next = self.tokens.next();
+ },
}
self.repeek();
@@ -287,16 +284,22 @@ impl<'s> Parser<'s> {
fn repeek(&mut self) {
self.peeked = self.next;
- if self.groups.contains(&match self.next {
- Some(Token::RightParen) => Group::Paren,
- Some(Token::RightBracket) => Group::Bracket,
- Some(Token::RightBrace) => Group::Brace,
- Some(Token::Pipe) => Group::Subheader,
- Some(Token::Semicolon) => Group::Terminated,
+ let token = match self.next {
+ Some(token) => token,
+ None => return,
+ };
+
+ match token {
+ Token::RightParen if self.groups.contains(&Group::Paren) => {}
+ Token::RightBracket if self.groups.contains(&Group::Bracket) => {}
+ Token::RightBrace if self.groups.contains(&Group::Brace) => {}
+ Token::Semicolon if self.groups.contains(&Group::Expr) => {}
+ Token::Space(n) if n >= 1 && self.groups.last() == Some(&Group::Expr) => {}
+ Token::Pipe if self.groups.contains(&Group::Subheader) => {}
_ => return,
- }) {
- self.peeked = None;
}
+
+ self.peeked = None;
}
}
@@ -316,9 +319,9 @@ pub enum Group {
Bracket,
/// A curly-braced group: `{...}`.
Brace,
+ /// A group ended by a semicolon or a line break: `;`, `\n`.
+ Expr,
/// A group ended by a chained subheader or a closing bracket:
/// `... >>`, `...]`.
Subheader,
- /// A group ended by a semicolon: `;`.
- Terminated,
}