mirror of
https://github.com/HigherOrderCO/Bend.git
synced 2024-08-16 07:10:37 +03:00
Merge pull request #572 from HigherOrderCO/463-dont-allow-mixed-indentation
#463 Dont allow mixed indentation
This commit is contained in:
commit
d6ccce5819
@ -7,6 +7,11 @@ and this project does not currently adhere to a particular versioning scheme.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Changed
|
||||
|
||||
- Improve error messages for redefinition of types and objects. ([#485][gh-485])
|
||||
- Don't allow tabs to be used for indentation or spacing. ([#463][gh-463])
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed readback of numeric operations. ([#467][gh-467])
|
||||
@ -88,10 +93,12 @@ and this project does not currently adhere to a particular versioning scheme.
|
||||
[0.2.35]: https://github.com/HigherOrderCO/Bend/releases/tag/0.2.35
|
||||
[gh-424]: https://github.com/HigherOrderCO/Bend/issues/424
|
||||
[gh-451]: https://github.com/HigherOrderCO/Bend/issues/451
|
||||
[gh-463]: https://github.com/HigherOrderCO/Bend/issues/463
|
||||
[gh-465]: https://github.com/HigherOrderCO/Bend/issues/465
|
||||
[gh-466]: https://github.com/HigherOrderCO/Bend/issues/466
|
||||
[gh-467]: https://github.com/HigherOrderCO/Bend/issues/467
|
||||
[gh-479]: https://github.com/HigherOrderCO/Bend/issues/479
|
||||
[gh-485]: https://github.com/HigherOrderCO/Bend/issues/485
|
||||
[gh-502]: https://github.com/HigherOrderCO/Bend/issues/502
|
||||
[gh-526]: https://github.com/HigherOrderCO/Bend/issues/526
|
||||
[gh-528]: https://github.com/HigherOrderCO/Bend/issues/528
|
||||
|
@ -65,7 +65,7 @@ impl<'a> TermParser<'a> {
|
||||
|
||||
pub fn parse_book(&mut self, default_book: Book, builtin: bool) -> ParseResult<Book> {
|
||||
let mut book = default_book;
|
||||
let mut indent = self.advance_newlines();
|
||||
let mut indent = self.advance_newlines()?;
|
||||
let mut last_rule = None;
|
||||
while !self.is_eof() {
|
||||
let ini_idx = *self.index();
|
||||
@ -115,7 +115,7 @@ impl<'a> TermParser<'a> {
|
||||
let (nam, adt) = self.parse_datatype(builtin)?;
|
||||
let end_idx = *self.index();
|
||||
self.with_ctx(book.add_adt(nam, adt), ini_idx, end_idx)?;
|
||||
indent = self.advance_newlines();
|
||||
indent = self.advance_newlines()?;
|
||||
last_rule = None;
|
||||
continue;
|
||||
}
|
||||
@ -145,7 +145,7 @@ impl<'a> TermParser<'a> {
|
||||
// Adding the first rule of a new definition
|
||||
book.defs.insert(name.clone(), Definition { name: name.clone(), rules: vec![rule], builtin });
|
||||
}
|
||||
indent = self.advance_newlines();
|
||||
indent = self.advance_newlines()?;
|
||||
last_rule = Some(name);
|
||||
}
|
||||
|
||||
@ -864,34 +864,38 @@ pub trait ParserCommons<'a>: Parser<'a> {
|
||||
}
|
||||
|
||||
fn consume_new_line(&mut self) -> ParseResult<()> {
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
self.try_consume_exactly("\r");
|
||||
self.labelled(|p| p.consume_exactly("\n"), "newline")
|
||||
}
|
||||
|
||||
/// Skips trivia, returns the number of trivia characters skipped in the last line.
|
||||
fn advance_newlines(&mut self) -> Indent {
|
||||
fn advance_newlines(&mut self) -> ParseResult<Indent> {
|
||||
loop {
|
||||
let num_spaces = self.advance_trivia_inline();
|
||||
let num_spaces = self.advance_trivia_inline()?;
|
||||
if self.peek_one() == Some('\r') {
|
||||
self.advance_one();
|
||||
}
|
||||
if self.peek_one() == Some('\n') {
|
||||
self.advance_one();
|
||||
} else if self.is_eof() {
|
||||
return Indent::Eof;
|
||||
return Ok(Indent::Eof);
|
||||
} else {
|
||||
return Indent::Val(num_spaces);
|
||||
return Ok(Indent::Val(num_spaces));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Advances the parser to the next non-trivia character in the same line.
|
||||
/// Returns how many characters were advanced.
|
||||
fn advance_trivia_inline(&mut self) -> isize {
|
||||
fn advance_trivia_inline(&mut self) -> ParseResult<isize> {
|
||||
let mut char_count = 0;
|
||||
while let Some(c) = self.peek_one() {
|
||||
if " \t".contains(c) {
|
||||
if c == '\t' {
|
||||
let idx = *self.index();
|
||||
return self.with_ctx(Err("Tabs are not accepted for indentation.".to_string()), idx, idx);
|
||||
}
|
||||
if " ".contains(c) {
|
||||
self.advance_one();
|
||||
char_count += 1;
|
||||
continue;
|
||||
@ -909,12 +913,13 @@ pub trait ParserCommons<'a>: Parser<'a> {
|
||||
}
|
||||
break;
|
||||
}
|
||||
char_count
|
||||
Ok(char_count)
|
||||
}
|
||||
|
||||
/// Skips until the next non-trivia character in the same line.
|
||||
fn skip_trivia_inline(&mut self) {
|
||||
self.advance_trivia_inline();
|
||||
fn skip_trivia_inline(&mut self) -> ParseResult<()> {
|
||||
self.advance_trivia_inline()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn expected_spanned<T>(&mut self, exp: &str, ini_idx: usize, end_idx: usize) -> ParseResult<T> {
|
||||
|
@ -79,7 +79,7 @@ impl<'a> PyParser<'a> {
|
||||
///
|
||||
fn parse_simple_expr(&mut self, inline: bool) -> ParseResult<Expr> {
|
||||
if inline {
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
} else {
|
||||
self.skip_trivia();
|
||||
}
|
||||
@ -133,7 +133,7 @@ impl<'a> PyParser<'a> {
|
||||
|
||||
// postfixes
|
||||
if inline {
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
} else {
|
||||
self.skip_trivia();
|
||||
}
|
||||
@ -335,7 +335,7 @@ impl<'a> PyParser<'a> {
|
||||
}
|
||||
|
||||
if inline {
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
} else {
|
||||
self.skip_trivia();
|
||||
}
|
||||
@ -373,7 +373,7 @@ impl<'a> PyParser<'a> {
|
||||
fn parse_infix_expr(&mut self, prec: usize, inline: bool) -> ParseResult<Expr> {
|
||||
maybe_grow(|| {
|
||||
if inline {
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
} else {
|
||||
self.skip_trivia();
|
||||
}
|
||||
@ -382,7 +382,7 @@ impl<'a> PyParser<'a> {
|
||||
}
|
||||
let mut lhs = self.parse_infix_expr(prec + 1, inline)?;
|
||||
if inline {
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
} else {
|
||||
self.skip_trivia();
|
||||
}
|
||||
@ -391,7 +391,7 @@ impl<'a> PyParser<'a> {
|
||||
self.try_parse_oper().unwrap();
|
||||
let rhs = self.parse_infix_expr(prec + 1, inline)?;
|
||||
lhs = Expr::Opr { op, lhs: Box::new(lhs), rhs: Box::new(rhs) };
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@ -401,7 +401,7 @@ impl<'a> PyParser<'a> {
|
||||
}
|
||||
|
||||
fn consume_indent_at_most(&mut self, expected: Indent) -> ParseResult<Indent> {
|
||||
let got = self.advance_newlines();
|
||||
let got = self.advance_newlines()?;
|
||||
match (expected, got) {
|
||||
(_, Indent::Eof) => Ok(Indent::Eof),
|
||||
(Indent::Val(expected), Indent::Val(got)) if got <= expected => Ok(Indent::Val(got)),
|
||||
@ -410,7 +410,7 @@ impl<'a> PyParser<'a> {
|
||||
}
|
||||
|
||||
fn consume_indent_exactly(&mut self, expected: Indent) -> ParseResult<()> {
|
||||
let got = self.advance_newlines();
|
||||
let got = self.advance_newlines()?;
|
||||
match (expected, got) {
|
||||
(Indent::Eof, Indent::Eof) => Ok(()),
|
||||
(Indent::Val(expected), Indent::Val(got)) if got == expected => Ok(()),
|
||||
@ -453,18 +453,18 @@ impl<'a> PyParser<'a> {
|
||||
let ini_idx = *self.index();
|
||||
let pat = self.parse_assign_pattern()?;
|
||||
let end_idx = *self.index();
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
|
||||
// Assignment
|
||||
if self.starts_with("=") {
|
||||
self.advance_one();
|
||||
let val = self.parse_expr(true)?;
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
self.try_consume_exactly(";");
|
||||
if !self.is_eof() {
|
||||
self.consume_new_line()?;
|
||||
}
|
||||
let nxt_indent = self.advance_newlines();
|
||||
let nxt_indent = self.advance_newlines()?;
|
||||
if nxt_indent == *indent {
|
||||
let (nxt, nxt_indent) = self.parse_statement(indent)?;
|
||||
let stmt = Stmt::Assign { pat, val: Box::new(val), nxt: Some(Box::new(nxt)) };
|
||||
@ -478,7 +478,7 @@ impl<'a> PyParser<'a> {
|
||||
if self.starts_with("<-") {
|
||||
self.consume("<-")?;
|
||||
let val = self.parse_expr(true)?;
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
self.try_consume_exactly(";");
|
||||
self.consume_indent_exactly(*indent)?;
|
||||
let (nxt, nxt_indent) = self.parse_statement(indent)?;
|
||||
@ -494,7 +494,7 @@ impl<'a> PyParser<'a> {
|
||||
}
|
||||
if let Some(op) = self.parse_in_place_op()? {
|
||||
let val = self.parse_expr(true)?;
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
self.try_consume_exactly(";");
|
||||
self.consume_indent_exactly(*indent)?;
|
||||
let (nxt, nxt_indent) = self.parse_statement(indent)?;
|
||||
@ -506,7 +506,7 @@ impl<'a> PyParser<'a> {
|
||||
}
|
||||
|
||||
fn parse_in_place_op(&mut self) -> ParseResult<Option<InPlaceOp>> {
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
let op = if self.starts_with("+=") {
|
||||
self.consume("+=")?;
|
||||
Some(InPlaceOp::Add)
|
||||
@ -539,18 +539,18 @@ impl<'a> PyParser<'a> {
|
||||
|
||||
fn parse_return(&mut self) -> ParseResult<(Stmt, Indent)> {
|
||||
let term = self.parse_expr(true)?;
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
self.try_consume_exactly(";");
|
||||
if !self.is_eof() {
|
||||
self.consume_new_line()?;
|
||||
}
|
||||
let indent = self.advance_newlines();
|
||||
let indent = self.advance_newlines()?;
|
||||
Ok((Stmt::Return { term: Box::new(term) }, indent))
|
||||
}
|
||||
|
||||
fn parse_if(&mut self, indent: &mut Indent) -> ParseResult<(Stmt, Indent)> {
|
||||
let cond = self.parse_expr(true)?;
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
self.consume_exactly(":")?;
|
||||
indent.enter_level();
|
||||
|
||||
@ -564,7 +564,7 @@ impl<'a> PyParser<'a> {
|
||||
let mut elifs = Vec::new();
|
||||
while self.try_parse_keyword("elif") {
|
||||
let cond = self.parse_expr(true)?;
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
self.consume_exactly(":")?;
|
||||
indent.enter_level();
|
||||
self.consume_indent_exactly(*indent)?;
|
||||
@ -577,7 +577,7 @@ impl<'a> PyParser<'a> {
|
||||
elifs.push((cond, then));
|
||||
}
|
||||
self.parse_keyword("else")?;
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
self.consume_exactly(":")?;
|
||||
indent.enter_level();
|
||||
|
||||
@ -609,7 +609,7 @@ impl<'a> PyParser<'a> {
|
||||
|
||||
fn parse_match(&mut self, indent: &mut Indent) -> ParseResult<(Stmt, Indent)> {
|
||||
let (bnd, arg) = self.parse_match_arg()?;
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
let (with_bnd, with_arg) = self.parse_with_clause()?;
|
||||
self.consume_new_line()?;
|
||||
indent.enter_level();
|
||||
@ -638,7 +638,7 @@ impl<'a> PyParser<'a> {
|
||||
let arg = self.parse_expr(true)?;
|
||||
let end_idx = *self.index();
|
||||
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
match (arg, self.starts_with("=")) {
|
||||
(Expr::Var { nam }, true) => {
|
||||
self.advance_one();
|
||||
@ -651,7 +651,7 @@ impl<'a> PyParser<'a> {
|
||||
}
|
||||
|
||||
fn parse_with_clause(&mut self) -> ParseResult<(Vec<Option<Name>>, Vec<Expr>)> {
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
let res = if self.try_parse_keyword("with") {
|
||||
self.list_like(|p| p.parse_with_arg(), "", ":", ",", true, 1)?.into_iter().unzip()
|
||||
} else {
|
||||
@ -663,7 +663,7 @@ impl<'a> PyParser<'a> {
|
||||
|
||||
fn parse_with_arg(&mut self) -> ParseResult<(Option<Name>, Expr)> {
|
||||
let bind = self.parse_bend_name()?;
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
if self.try_consume("=") {
|
||||
let arg = self.parse_expr(false)?;
|
||||
Ok((Some(bind), arg))
|
||||
@ -674,14 +674,14 @@ impl<'a> PyParser<'a> {
|
||||
|
||||
fn parse_match_case(&mut self, indent: &mut Indent) -> ParseResult<(MatchArm, Indent)> {
|
||||
self.parse_keyword("case")?;
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
let pat = if self.try_consume_exactly("_") {
|
||||
None
|
||||
} else {
|
||||
let nam = self.labelled(|p| p.parse_bend_name(), "name or '_'")?;
|
||||
Some(nam)
|
||||
};
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
self.consume_exactly(":")?;
|
||||
self.consume_new_line()?;
|
||||
indent.enter_level();
|
||||
@ -696,7 +696,7 @@ impl<'a> PyParser<'a> {
|
||||
|
||||
fn parse_switch(&mut self, indent: &mut Indent) -> ParseResult<(Stmt, Indent)> {
|
||||
let (bnd, arg) = self.parse_match_arg()?;
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
let (with_bnd, with_arg) = self.parse_with_clause()?;
|
||||
indent.enter_level();
|
||||
|
||||
@ -741,7 +741,7 @@ impl<'a> PyParser<'a> {
|
||||
|
||||
fn parse_switch_case(&mut self, indent: &mut Indent) -> ParseResult<(Option<u32>, Stmt, Indent)> {
|
||||
self.parse_keyword("case")?;
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
let case = if let Some(c) = self.peek_one() {
|
||||
match c {
|
||||
'_' => {
|
||||
@ -755,7 +755,7 @@ impl<'a> PyParser<'a> {
|
||||
return self.expected("number or '_'")?;
|
||||
};
|
||||
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
self.consume_exactly(":")?;
|
||||
self.consume_new_line()?;
|
||||
indent.enter_level();
|
||||
@ -772,7 +772,7 @@ impl<'a> PyParser<'a> {
|
||||
fn parse_fold(&mut self, indent: &mut Indent) -> ParseResult<(Stmt, Indent)> {
|
||||
// Actually identical to match, except the return
|
||||
let (bind, arg) = self.parse_match_arg()?;
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
let (with_bnd, with_arg) = self.parse_with_clause()?;
|
||||
self.consume_new_line()?;
|
||||
indent.enter_level();
|
||||
@ -811,7 +811,7 @@ impl<'a> PyParser<'a> {
|
||||
self.consume_indent_exactly(*indent)?;
|
||||
self.parse_keyword("when")?;
|
||||
let cond = self.parse_expr(true)?;
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
self.consume_exactly(":")?;
|
||||
self.consume_new_line()?;
|
||||
indent.enter_level();
|
||||
@ -824,7 +824,7 @@ impl<'a> PyParser<'a> {
|
||||
return self.expected_indent(*indent, nxt_indent);
|
||||
}
|
||||
self.parse_keyword("else")?;
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
self.consume_exactly(":")?;
|
||||
self.consume_new_line()?;
|
||||
indent.enter_level();
|
||||
@ -862,9 +862,9 @@ impl<'a> PyParser<'a> {
|
||||
/// <bod>
|
||||
/// <nxt>?
|
||||
fn parse_with(&mut self, indent: &mut Indent) -> ParseResult<(Stmt, Indent)> {
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
let typ = self.parse_bend_name()?;
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
self.consume_exactly(":")?;
|
||||
self.consume_new_line()?;
|
||||
indent.enter_level();
|
||||
@ -911,7 +911,7 @@ impl<'a> PyParser<'a> {
|
||||
// Chn pattern
|
||||
if self.starts_with("$") {
|
||||
self.advance_one();
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
let nam = self.parse_bend_name()?;
|
||||
return Ok(AssignPattern::Chn(nam));
|
||||
}
|
||||
@ -932,13 +932,13 @@ impl<'a> PyParser<'a> {
|
||||
|
||||
/// "open" {typ} ":" {var} ";"? {nxt}
|
||||
fn parse_open(&mut self, indent: &mut Indent) -> ParseResult<(Stmt, Indent)> {
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
let typ = self.labelled(|p| p.parse_bend_name(), "type name")?;
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
self.consume_exactly(":")?;
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
let var = self.labelled(|p| p.parse_bend_name(), "variable name")?;
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
self.try_consume_exactly(";");
|
||||
self.consume_new_line()?;
|
||||
self.consume_indent_exactly(*indent)?;
|
||||
@ -948,13 +948,13 @@ impl<'a> PyParser<'a> {
|
||||
}
|
||||
|
||||
fn parse_use(&mut self, indent: &mut Indent) -> ParseResult<(Stmt, Indent)> {
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
let nam = self.parse_bend_name()?;
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
self.consume_exactly("=")?;
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
let bod = self.parse_expr(true)?;
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
self.try_consume_exactly(";");
|
||||
self.consume_new_line()?;
|
||||
self.consume_indent_exactly(*indent)?;
|
||||
@ -970,15 +970,15 @@ impl<'a> PyParser<'a> {
|
||||
return self.with_ctx(Err(msg), idx, idx + 1);
|
||||
}
|
||||
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
let name = self.parse_top_level_name()?;
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
let params = if self.starts_with("(") {
|
||||
self.list_like(|p| p.parse_bend_name(), "(", ")", ",", true, 0)?
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
self.consume_exactly(":")?;
|
||||
self.consume_new_line()?;
|
||||
indent.enter_level();
|
||||
@ -998,9 +998,9 @@ impl<'a> PyParser<'a> {
|
||||
return self.with_ctx(Err(msg), idx, idx + 1);
|
||||
}
|
||||
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
let typ_name = self.parse_top_level_name()?;
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
self.consume_exactly(":")?;
|
||||
self.consume_new_line()?;
|
||||
indent.enter_level();
|
||||
@ -1025,7 +1025,7 @@ impl<'a> PyParser<'a> {
|
||||
let ctr_name = self.parse_top_level_name()?;
|
||||
let ctr_name = Name::new(format!("{typ_name}/{ctr_name}"));
|
||||
let mut fields = Vec::new();
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
if self.starts_with("{") {
|
||||
fields = self.list_like(|p| p.parse_variant_field(), "{", "}", ",", true, 0)?;
|
||||
}
|
||||
@ -1039,9 +1039,9 @@ impl<'a> PyParser<'a> {
|
||||
return self.with_ctx(Err(msg), idx, idx + 1);
|
||||
}
|
||||
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
let name = self.parse_top_level_name()?;
|
||||
self.skip_trivia_inline();
|
||||
self.skip_trivia_inline()?;
|
||||
let fields = if self.starts_with("{") {
|
||||
self.list_like(|p| p.parse_variant_field(), "{", "}", ",", true, 0)?
|
||||
} else {
|
||||
@ -1050,7 +1050,7 @@ impl<'a> PyParser<'a> {
|
||||
if !self.is_eof() {
|
||||
self.consume_new_line()?;
|
||||
}
|
||||
let nxt_indent = self.advance_newlines();
|
||||
let nxt_indent = self.advance_newlines()?;
|
||||
Ok((Variant { name, fields }, nxt_indent))
|
||||
}
|
||||
|
||||
|
3
tests/golden_tests/parse_file/tab.bend
Normal file
3
tests/golden_tests/parse_file/tab.bend
Normal file
@ -0,0 +1,3 @@
|
||||
def main:
|
||||
x = 2
|
||||
return x + 1
|
8
tests/snapshots/parse_file__tab.bend.snap
Normal file
8
tests/snapshots/parse_file__tab.bend.snap
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/parse_file/tab.bend
|
||||
---
|
||||
[4m[1m[31mErrors:[0m
|
||||
In tests/golden_tests/parse_file/tab.bend :
|
||||
Tabs are not accepted for indentation.
|
||||
[0m 2 | [4m[31m[0m x = 2[0m
|
Loading…
Reference in New Issue
Block a user