96 lines
3.3 KiB
Rust
96 lines
3.3 KiB
Rust
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<char>] = &['\''..='\''];
|
|
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<GenTokTree>,
|
|
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))
|
|
}
|
|
}
|
|
}
|
|
}
|