use ilo::ast::Span;
use ilo::lexer;
use ilo::parser::{self, ParseError};
fn parse_first_err(src: &str) -> Option<ParseError> {
let tokens = lexer::lex(src).ok()?;
let pairs = tokens
.into_iter()
.map(|(t, r)| {
(
t,
Span {
start: r.start,
end: r.end,
},
)
})
.collect::<Vec<_>>();
parser::parse(pairs).1.into_iter().next()
}
fn lex_err_suggestion(src: &str) -> String {
match lexer::lex(src) {
Err(e) => e.suggestion,
Ok(_) => String::new(),
}
}
#[test]
fn typed_brace_lambda_emits_paren_form_hint() {
let err = parse_first_err("f xs:Ln>Ln;flt {x:n> >x 0} xs").expect("expected an error");
assert_eq!(err.code, "ILO-P001", "got {:?}", err);
let hint = err.hint.unwrap_or_default();
assert!(
hint.contains("(x:t>r;body)") && hint.contains("{x> body}"),
"hint must name both canonical forms; got: {hint}"
);
assert!(
hint.contains("flt (x:"),
"hint must include a call-site rewrite for the typed-paren form; got: {hint}"
);
}
#[test]
fn backslash_typed_lambda_emits_canonical_form_hint() {
let s = lex_err_suggestion(r"f xs:Ln>Ln;flt \x:n>>x 0 xs");
assert!(!s.is_empty(), "expected an ILO-L001 hint");
assert!(
s.contains("(x:t>r;body)") && s.contains("{x> body}"),
"hint must name both canonical forms; got: {s}"
);
assert!(
s.contains("map (x:") || s.contains("flt (x:") || s.contains("(x:n>n"),
"hint must include a concrete call-site rewrite; got: {s}"
);
}
#[test]
fn fn_keyword_inline_lambda_emits_canonical_form_hint() {
let err = parse_first_err("f xs:Ln>Ln;flt fn x:n>n;>x 0 xs").expect("expected an error");
assert_eq!(err.code, "ILO-P009", "got {:?}", err);
let hint = err.hint.unwrap_or_default();
assert!(
hint.contains("(p:t>r;body)") && hint.contains("{p> body}"),
"hint must name both canonical forms; got: {hint}"
);
assert!(
hint.contains("flt (x:") || hint.contains("flt {x>"),
"hint must include a call-site rewrite; got: {hint}"
);
}
#[test]
fn canonical_paren_lambda_still_parses() {
assert!(parse_first_err("f xs:Ln>Ln;flt (x:n>b;>x 0) xs").is_none());
}
#[test]
fn canonical_bare_brace_lambda_still_parses() {
assert!(parse_first_err("f xs:Ln>Ln;flt {x> >x 0} xs").is_none());
}