mirror of
https://github.com/HigherOrderCO/Bend.git
synced 2024-11-05 04:51:40 +03:00
Merge pull request #120 from HigherOrderCO/bug/sc-354/hvm-lang-showing-multiple-errors-instead
[sc-354] Improve parsing to not show "multiple errors"
This commit is contained in:
commit
f10d4c66c1
@ -4,7 +4,7 @@ use chumsky::{
|
||||
extra,
|
||||
input::{SpannedInput, Stream, ValueInput},
|
||||
prelude::{Input, Rich},
|
||||
primitive::{choice, just},
|
||||
primitive::{choice, end, just},
|
||||
recursive::recursive,
|
||||
select,
|
||||
span::SimpleSpan,
|
||||
@ -66,7 +66,13 @@ fn soft_keyword<'a, I>(keyword: &'a str) -> impl Parser<'a, I, (), extra::Err<Ri
|
||||
where
|
||||
I: ValueInput<'a, Token = Token, Span = SimpleSpan>,
|
||||
{
|
||||
name().try_map(move |Name(nam), span| if nam == keyword { Ok(()) } else { Err(Rich::custom(span, "")) })
|
||||
name().try_map(move |Name(nam), span| {
|
||||
if nam == keyword {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Rich::custom(span, format!("Expected `{keyword}`, found `{nam}`")))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn name<'a, I>() -> impl Parser<'a, I, Name, extra::Err<Rich<'a, Token>>>
|
||||
@ -334,14 +340,48 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
fn rule<'a, I>() -> impl Parser<'a, I, (Name, Rule), extra::Err<Rich<'a, Token>>>
|
||||
fn rule_pattern<'a, I>() -> impl Parser<'a, I, (Name, Vec<Pattern>), extra::Err<Rich<'a, Token>>>
|
||||
where
|
||||
I: ValueInput<'a, Token = Token, Span = SimpleSpan>,
|
||||
{
|
||||
let lhs = name().then(pattern().repeated().collect()).boxed();
|
||||
let lhs = choice((lhs.clone(), lhs.clone().delimited_by(just(Token::LParen), just(Token::RParen))));
|
||||
choice((lhs.clone(), lhs.clone().delimited_by(just(Token::LParen), just(Token::RParen))))
|
||||
.then_ignore(just(Token::Equals))
|
||||
}
|
||||
|
||||
lhs.then_ignore(just(Token::Equals)).then(term()).map(|((name, pats), body)| (name, Rule { pats, body }))
|
||||
/// This rule always emits an error when it parses successfully
|
||||
/// It is used to report a parsing error that would be unclear otherwise
|
||||
fn rule_body_missing_paren<'a, I>()
|
||||
-> impl Parser<'a, I, ((Name, Vec<Pattern>), Term), extra::Err<Rich<'a, Token>>>
|
||||
where
|
||||
I: ValueInput<'a, Token = Token, Span = SimpleSpan>,
|
||||
{
|
||||
let terms = tag(Tag::Static)
|
||||
.then(term())
|
||||
.foldl(term().and_is(soft_keyword("data").not()).repeated().at_least(1), |(tag, fun), arg| {
|
||||
(tag.clone(), Term::App { tag, fun: Box::new(fun), arg: Box::new(arg) })
|
||||
});
|
||||
|
||||
let end_of_rule = end().or(soft_keyword("data")).rewind();
|
||||
|
||||
rule_pattern()
|
||||
.then(terms)
|
||||
.map(|(rule, (_, app))| (rule, app))
|
||||
.then_ignore(end_of_rule)
|
||||
.validate(|((name, pats), term), span, emit| {
|
||||
emit.emit(Rich::custom(span, format!("Missing Parenthesis around rule `{}` body", name)));
|
||||
((name, pats), term)
|
||||
})
|
||||
.boxed()
|
||||
}
|
||||
|
||||
fn rule<'a, I>() -> impl Parser<'a, I, (Name, Rule), extra::Err<Rich<'a, Token>>>
|
||||
where
|
||||
I: ValueInput<'a, Token = Token, Span = SimpleSpan>,
|
||||
{
|
||||
rule_body_missing_paren()
|
||||
.or(rule_pattern().then(term()))
|
||||
.map(|((name, pats), body)| (name, Rule { pats, body }))
|
||||
}
|
||||
|
||||
fn datatype<'a, I>() -> impl Parser<'a, I, (Name, Adt), extra::Err<Rich<'a, Token>>>
|
||||
@ -370,7 +410,7 @@ where
|
||||
{
|
||||
let top_level = choice((datatype().map(TopLevel::Adt), rule().map(TopLevel::Rule)));
|
||||
|
||||
top_level.repeated().collect::<Vec<_>>().try_map(|program, span| {
|
||||
top_level.repeated().collect::<Vec<_>>().validate(|program, span, emit| {
|
||||
let mut book = Book::new();
|
||||
|
||||
// Collect rules and adts into a book
|
||||
@ -390,17 +430,17 @@ where
|
||||
if let Entry::Vacant(e) = book.ctrs.entry(ctr) {
|
||||
e.insert(nam.clone());
|
||||
} else {
|
||||
return Err(Rich::custom(span, format!("Repeated constructor '{}'", nam)));
|
||||
emit.emit(Rich::custom(span, format!("Repeated constructor '{}'", nam)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(Rich::custom(span, format!("Repeated datatype '{}'", nam)));
|
||||
emit.emit(Rich::custom(span, format!("Repeated datatype '{}'", nam)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(book)
|
||||
book
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -155,6 +155,14 @@ fn flatten_rules() {
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_file() {
|
||||
run_golden_test_dir(function_name!(), &|code| {
|
||||
let book = do_parse_book(code)?;
|
||||
Ok(book.to_string())
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_pattern_match() {
|
||||
run_golden_test_dir(function_name!(), &|code| {
|
||||
|
1
tests/golden_tests/parse_file/missing_paren.hvm
Normal file
1
tests/golden_tests/parse_file/missing_paren.hvm
Normal file
@ -0,0 +1 @@
|
||||
main = * *
|
3
tests/golden_tests/parse_file/missing_paren_then_adt.hvm
Normal file
3
tests/golden_tests/parse_file/missing_paren_then_adt.hvm
Normal file
@ -0,0 +1,3 @@
|
||||
main = * * * *
|
||||
|
||||
data Foo = Bar
|
@ -0,0 +1,5 @@
|
||||
data Foo = A
|
||||
|
||||
main = A B
|
||||
|
||||
data Foo = B
|
2
tests/golden_tests/parse_file/repeated_adt_name.hvm
Normal file
2
tests/golden_tests/parse_file/repeated_adt_name.hvm
Normal file
@ -0,0 +1,2 @@
|
||||
data Foo = A
|
||||
data Foo = B
|
5
tests/snapshots/parse_file__missing_paren.hvm.snap
Normal file
5
tests/snapshots/parse_file__missing_paren.hvm.snap
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/parse_file/missing_paren.hvm
|
||||
---
|
||||
Missing Parenthesis around rule `main` body
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/parse_file/missing_paren_then_adt.hvm
|
||||
---
|
||||
Missing Parenthesis around rule `main` body
|
@ -0,0 +1,6 @@
|
||||
---
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/parse_file/multiple_parsing_errors.hvm
|
||||
---
|
||||
Missing Parenthesis around rule `main` body
|
||||
Repeated datatype 'Foo'
|
5
tests/snapshots/parse_file__repeated_adt_name.hvm.snap
Normal file
5
tests/snapshots/parse_file__repeated_adt_name.hvm.snap
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
source: tests/golden_tests.rs
|
||||
input_file: tests/golden_tests/parse_file/repeated_adt_name.hvm
|
||||
---
|
||||
Repeated datatype 'Foo'
|
Loading…
Reference in New Issue
Block a user