79 lines
2.5 KiB
Rust
79 lines
2.5 KiB
Rust
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<ParsedLine>,
|
|
impls: &mut Vec<(Sym, Tok<String>)>,
|
|
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(())
|
|
}
|