Files
orchid/orchid-std/src/std/protocol/parse_impls.rs
Lawrence Bethlenfalvy f38193edcc
All checks were successful
Rust / build (push) Successful in 4m8s
Protocols and operators mostly
2026-01-21 22:22:58 +01:00

80 lines
2.4 KiB
Rust

use itertools::{Itertools, chain};
use orchid_base::error::{OrcRes, mk_errv};
use orchid_base::interner::{IStr, is};
use orchid_base::name::Sym;
use orchid_base::parse::{
Import, 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(
_: &ParsCtx<'_>,
lines: &mut Vec<ParsedLine>,
impls: &mut Vec<(Sym, IStr)>,
body_tt: &PTokTree,
) -> OrcRes<()> {
let body = match &body_tt.tok {
Token::S(Paren::Round, body) => line_items(Snippet::new(body_tt, body)).await,
Token::S(ptyp, _) => {
return Err(mk_errv(
is("Incorrect paren type").await,
format!("Expected () block, found {ptyp}"),
[body_tt.sr().pos()],
));
},
_ => {
return Err(
token_errv(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(line, is("impl").await).await {
let Parsed { tail, output: name_tt } = parse_multiname(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().await, sr.clone()),
Ok(Some(Import { name: None, sr, .. })) => {
return Err(mk_errv(
is("impl line with globstar").await,
"::* is not permitted in a protocol impl",
[sr.pos()],
));
},
Err(e) => {
return Err(mk_errv(
is("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(tail, is("as").await).await?;
let cnst_name = is(&format!("{}{}", lines.len(), name.iter().join("__"))).await;
lines.push(ParsedLine {
comments,
sr: line.sr(),
kind: ParsedLineKind::Rec(Vec::from_iter(chain![
[Token::Name(is("let").await).at(line.sr())],
[Token::Name(cnst_name.clone()).at(name_sr)],
[Token::Name(is("=").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(())
}