use std::rc::Rc; use hashbrown::HashMap; use orchid_base::error::{OrcRes, mk_errv}; use orchid_base::interner::is; use orchid_base::parse::{Comment, Parsed, expect_end, try_pop_no_fluff}; use orchid_base::sym; use orchid_base::tree::Token; use orchid_extension::coroutine_exec::exec; use orchid_extension::gen_expr::{call, new_atom, sym_ref}; use orchid_extension::parser::{PSnippet, ParsCtx, ParsedLine, Parser}; use crate::std::protocol::parse_impls::parse_impls; use crate::std::protocol::types::Tag; #[derive(Default)] pub struct AsProtoParser; impl Parser for AsProtoParser { const LINE_HEAD: &'static str = "as_proto"; async fn parse<'a>( pcx: ParsCtx<'a>, exported: bool, cmts: Vec, line: PSnippet<'a>, ) -> OrcRes> { let Parsed { output: body_tt, tail } = try_pop_no_fluff(line).await?; expect_end(tail).await?; if exported { return Err(mk_errv( is("Exported internal line").await, "as_proto cannot be exported, the type shares the enclosing module's visibility", [line.sr().pos()], )); } let mut lines = Vec::new(); let mut impls = Vec::new(); parse_impls(&pcx, &mut lines, &mut impls, body_tt).await?; let id = pcx.module(); let proto_tag_name = is("__protocol_tag__").await; let proto_tag_path = id.suffix([proto_tag_name.clone()]).await; lines.push(ParsedLine::cnst(&line.sr(), &cmts, true, proto_tag_name, async |_ccx| { exec(async move |mut h| { let mut new_impls = HashMap::new(); for (k, v) in impls { new_impls.insert(k.clone(), h.register(sym_ref(id.suffix([v]).await)).await); } new_atom(Tag { id, impls: Rc::new(new_impls) }) }) .await })); lines.push(ParsedLine::cnst(&line.sr(), [], false, is("resolve").await, async move |_| { call(sym_ref(sym!(std::protocol::resolve)), [sym_ref(proto_tag_path)]) })); Ok(lines) } } #[derive(Default)] pub struct ProtoParser; impl Parser for ProtoParser { const LINE_HEAD: &'static str = "proto"; async fn parse<'a>( ctx: ParsCtx<'a>, exported: bool, cmts: Vec, line: PSnippet<'a>, ) -> OrcRes> { let Parsed { output: name_tt, tail } = try_pop_no_fluff(line).await?; let Token::Name(name) = &name_tt.tok else { return Err(mk_errv(is("missing name for type").await, "A type needs a name", [name_tt .sr() .pos()])); }; let lines = AsProtoParser::parse(ctx, false, cmts.clone(), tail).await?; Ok(vec![ParsedLine::module(&line.sr(), &cmts, exported, name, true, lines)]) } }