Added support for defining macros in Rust within the macro system
Also fixed a lot of bugs
This commit is contained in:
79
orchid-std/src/macros/ph_lexer.rs
Normal file
79
orchid-std/src/macros/ph_lexer.rs
Normal file
@@ -0,0 +1,79 @@
|
||||
use orchid_api_derive::Coding;
|
||||
use orchid_base::error::{OrcRes, mk_errv};
|
||||
use orchid_base::format::FmtUnit;
|
||||
use orchid_base::parse::{name_char, name_start};
|
||||
use orchid_extension::atom::Atomic;
|
||||
use orchid_extension::atom_thin::{ThinAtom, ThinVariant};
|
||||
use orchid_extension::lexer::{LexContext, Lexer, err_not_applicable};
|
||||
use orchid_extension::system::SysCtx;
|
||||
use orchid_extension::tree::{GenTokTree, x_tok};
|
||||
|
||||
use crate::macros::mactree::{Ph, PhKind};
|
||||
|
||||
#[derive(Clone, Coding)]
|
||||
pub struct PhAtom(orchid_api::TStr, PhKind);
|
||||
impl PhAtom {
|
||||
pub async fn to_full(&self, ctx: &SysCtx) -> Ph {
|
||||
Ph { kind: self.1, name: ctx.i().ex(self.0).await }
|
||||
}
|
||||
}
|
||||
impl Atomic for PhAtom {
|
||||
type Data = Self;
|
||||
type Variant = ThinVariant;
|
||||
}
|
||||
impl ThinAtom for PhAtom {
|
||||
async fn print(&self, ctx: SysCtx) -> FmtUnit {
|
||||
Ph { name: ctx.i().ex(self.0).await, kind: self.1 }.to_string().into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct PhLexer;
|
||||
impl Lexer for PhLexer {
|
||||
const CHAR_FILTER: &'static [std::ops::RangeInclusive<char>] = &['$'..='$', '.'..='.'];
|
||||
async fn lex<'a>(line: &'a str, ctx: &'a LexContext<'a>) -> OrcRes<(&'a str, GenTokTree)> {
|
||||
let (tail, name, phkind) = if let Some(tail) = line.strip_prefix("$")
|
||||
&& tail.starts_with(name_start)
|
||||
{
|
||||
let name = tail.split_once(|c| !name_char(c)).map_or("", |(h, _)| h);
|
||||
let tail = tail.split_at(name.len()).1;
|
||||
(tail, name, PhKind::Scalar)
|
||||
} else {
|
||||
async fn name_and_prio<'a>(
|
||||
tail: &'a str,
|
||||
ctx: &'a LexContext<'a>,
|
||||
) -> OrcRes<(&'a str, u8, &'a str)> {
|
||||
let name = tail.split_once(|c| !name_char(c)).map_or("", |(h, _)| h);
|
||||
let tail = tail.split_at(name.len()).1;
|
||||
let (prio, tail) = match tail.strip_prefix(":") {
|
||||
None => (0, tail),
|
||||
Some(tail) => {
|
||||
let prio = tail.split_once(|c: char| c.is_ascii_digit()).map_or("", |(h, _)| h);
|
||||
let tail = tail.split_at(prio.len()).1;
|
||||
if let Ok(prio_num) = prio.parse::<u8>() {
|
||||
(prio_num, tail)
|
||||
} else {
|
||||
return Err(mk_errv(
|
||||
ctx.ctx.i().i("Invalid priority, must be 0-255").await,
|
||||
format!("{prio} is not a valid placeholder priority"),
|
||||
[ctx.pos_lt(prio.len(), tail)],
|
||||
));
|
||||
}
|
||||
},
|
||||
};
|
||||
Ok((name, prio, tail))
|
||||
}
|
||||
if let Some(tail) = line.strip_prefix("..$") {
|
||||
let (name, priority, tail) = name_and_prio(tail, ctx).await?;
|
||||
(tail, name, PhKind::Vector { at_least_one: false, priority })
|
||||
} else if let Some(tail) = line.strip_prefix("...$") {
|
||||
let (name, priority, tail) = name_and_prio(tail, ctx).await?;
|
||||
(tail, name, PhKind::Vector { at_least_one: true, priority })
|
||||
} else {
|
||||
return Err(err_not_applicable(ctx.ctx.i()).await);
|
||||
}
|
||||
};
|
||||
let ph_atom = PhAtom(ctx.ctx.i().i::<String>(name).await.to_api(), phkind);
|
||||
Ok((tail, x_tok(ph_atom).await.at(ctx.pos_tt(line, tail))))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user