use itertools::{Itertools, chain}; use orchid_base::error::{OrcRes, mk_errv}; use orchid_base::interner::Tok; use orchid_base::name::Sym; use orchid_base::parse::{ Import, ParseCtx, Parsed, Snippet, expect_tok, line_items, parse_multiname, token_errv, }; use orchid_base::tree::{Paren, Token}; use orchid_extension::parser::{ PTokTree, ParsCtx, ParsedLine, ParsedLineKind, p_tree2gen, p_v2gen, }; pub async fn parse_impls( ctx: &ParsCtx<'_>, lines: &mut Vec, impls: &mut Vec<(Sym, Tok)>, body_tt: &PTokTree, ) -> OrcRes<()> { let i = ctx.i().clone(); let body = match &body_tt.tok { Token::S(Paren::Round, body) => line_items(ctx, Snippet::new(body_tt, body)).await, Token::S(ptyp, _) => return Err(mk_errv( i.i("Incorrect paren type").await, format!("Expected () block, found {ptyp}"), [body_tt.sr().pos()], )), _ => return Err( token_errv(ctx, body_tt, "Expected body", |s| { format!("Expected (impl ...) block, found {s}") }) .await, ), }; for Parsed { tail: line, output: comments } in body { if let Ok(Parsed { tail, .. }) = expect_tok(ctx, line, i.i("impl").await).await { let Parsed { tail, output: name_tt } = parse_multiname(ctx, tail).await?; let (name, name_sr) = match name_tt.into_iter().at_most_one() { Ok(None) => panic!("multiname is always at least one name"), Ok(Some(ref n @ Import { name: Some(_), ref sr, .. })) => (n.clone().mspath().to_sym(&i).await, sr.clone()), Ok(Some(Import { name: None, sr, .. })) => return Err(mk_errv( i.i("impl line with globstar").await, "::* is not permitted in a protocol impl", [sr.pos()], )), Err(e) => return Err(mk_errv( i.i("Impl line with multiple protocol names").await, "::() is not permitted in a protocol impl", e.map(|i| i.sr.pos()), )), }; let Parsed { tail, .. } = expect_tok(ctx, tail, i.i("as").await).await?; let cnst_name = i.i(&format!("{}{}", lines.len(), name.iter().join("__"))).await; lines.push(ParsedLine { comments, sr: line.sr(), kind: ParsedLineKind::Rec(Vec::from_iter(chain![ [Token::Name(i.i("let").await).at(line.sr())], [Token::Name(cnst_name.clone()).at(name_sr)], [Token::Name(i.i("=").await).at(line.sr())], tail.iter().cloned().map(p_tree2gen), ])), }); impls.push((name, cnst_name)); } else { lines.push(ParsedLine { sr: line.sr(), comments, kind: ParsedLineKind::Rec(p_v2gen(line.to_vec())), }); } } Ok(()) }