use std::ops::RangeInclusive; use futures::FutureExt; use itertools::chain; use orchid_base::error::{OrcRes, mk_errv}; use orchid_base::parse::ParseCtx; use orchid_base::tokens::PARENS; use orchid_base::tree::Paren; use orchid_extension::lexer::{LexContext, Lexer, err_not_applicable}; use orchid_extension::parser::p_tree2gen; use orchid_extension::tree::{GenTok, GenTokTree, x_tok}; use crate::macros::instantiate_tpl::InstantiateTplCall; use crate::macros::let_line::parse_tok; use crate::macros::mactree::{MacTok, MacTree, MacTreeSeq}; #[derive(Default)] pub struct MacTreeLexer; impl Lexer for MacTreeLexer { const CHAR_FILTER: &'static [RangeInclusive] = &['\''..='\'']; async fn lex<'a>(tail: &'a str, lctx: &'a LexContext<'a>) -> OrcRes<(&'a str, GenTokTree)> { let Some(tail2) = tail.strip_prefix('\'') else { return Err(err_not_applicable().await); }; let tail3 = tail2.trim_start(); let mut args = Vec::new(); return match mac_tree(tail3, &mut args, lctx).await { Ok((tail4, mactree)) => { let range = lctx.pos_tt(tail, tail4); let tok = match &args[..] { [] => x_tok(mactree).await, _ => { let instantiate_tpl_call = InstantiateTplCall { argc: args.len(), argv: vec![], tpl: mactree }; let call = chain!([x_tok(instantiate_tpl_call).await.at(range.clone())], args); GenTok::S(Paren::Round, call.collect()) }, }; Ok((tail4, tok.at(range))) }, Err(e) => Ok((tail2, GenTok::Bottom(e).at(lctx.pos_lt(1, tail2)))), }; async fn mac_tree<'a>( tail: &'a str, args: &mut Vec, ctx: &'a LexContext<'a>, ) -> OrcRes<(&'a str, MacTree)> { for (lp, rp, paren) in PARENS { let Some(mut body_tail) = tail.strip_prefix(*lp) else { continue }; let mut items = Vec::new(); return loop { let tail2 = body_tail.trim_start(); if let Some(tail3) = tail2.strip_prefix(*rp) { let tok = MacTok::S(*paren, MacTreeSeq::new(items)); break Ok((tail3, tok.at(ctx.pos_tt(tail, tail3).pos()))); } else if tail2.is_empty() { return Err(mk_errv( ctx.i().i("Unclosed block").await, format!("Expected closing {rp}"), [ctx.pos_lt(1, tail)], )); } let (new_tail, new_item) = mac_tree(tail2, args, ctx).boxed_local().await?; body_tail = new_tail; items.push(new_item); }; } if let Some(tail2) = tail.strip_prefix("$") { let (tail3, sub) = ctx.recurse(tail2).await?; let sr = ctx.pos_tt(tail, tail3); args.push(p_tree2gen(sub)); return Ok((tail3, MacTok::Slot.at(sr.pos()))); } if let Some(tail2) = tail.strip_prefix("\\") { let tail2 = tail2.trim_start(); let (mut tail3, param) = mac_tree(tail2, args, ctx).boxed_local().await?; let mut body = Vec::new(); loop { let tail4 = tail3.trim_start(); if tail4.is_empty() || tail4.starts_with(|c| ")]}".contains(c)) { break; }; let (tail5, body_tok) = mac_tree(tail4, args, ctx).boxed_local().await?; body.push(body_tok); tail3 = tail5; } Ok((tail3, MacTok::Lambda(param, MacTreeSeq::new(body)).at(ctx.pos_tt(tail, tail3).pos()))) } else { let (tail2, sub) = ctx.recurse(tail).await?; let parsed = parse_tok(&sub, ctx).await.expect("Unexpected invalid token"); Ok((tail2, parsed)) } } } }