#[macro_export]
macro_rules! make_parser {
($lang:ident, [$($arg:ident),*], $body:block) => {
fn parser<'src, 'cache, 'interner,'borrow,'extra, Err>(
$(
$arg: impl $crate::chumsky_ext::BuilderParser<
'src, 'cache, 'interner,'borrow, (), Err, $lang
> + Clone + 'extra
),*
) -> $crate::impl_type!($lang)
where
Err: $crate::chumsky::error::Error<'src, &'src str> + 'extra,
'interner: 'cache,
'borrow: 'interner,
'src: 'extra,
'cache: 'extra
{
use inktree::chumsky_ext::*;
use inktree::chumsky::prelude::*;
$body
}
};
}
#[macro_export]
macro_rules! impl_type {
($lang:ident) => {
impl ::inktree::chumsky_ext::BuilderParser<
'src, 'cache, 'interner,'borrow, (), Err, $lang
> + Clone + 'extra
};
}
#[macro_export]
macro_rules! make_anchored_parser {
($lang:ident, [$($anchor:ident),*], [$($param:ident),*], $body:block) => {
fn anchored_parser<'src, 'cache, 'interner,'borrow,'extra, Err>(
$(
$anchor: $crate::impl_type!($lang),
)*
$(
$param: $crate::impl_type!($lang),
)*
) -> $crate::impl_type!($lang)
where
Err: $crate::chumsky::error::Error<'src, &'src str> + 'extra,
'interner: 'cache,
'borrow: 'interner,
'src: 'extra,
'cache: 'extra
{
use inktree::chumsky_ext::*;
use inktree::chumsky::prelude::*;
$body
}
};
}
#[macro_export]
macro_rules! parseable {
($lang_name:ident::$name:ident, [$($param:ident),*], $body:block) => {
impl ::inktree::Parseable for $name {
type Syntax = $lang_name;
inktree::make_parser!($lang_name, [$($param),*], $body);
}
};
}
#[macro_export]
macro_rules! token {
($lang_name:ident :: $name:ident, $body:block) => {
pub(crate) struct $name;
$crate::parseable!($lang_name::$name, [], {
use $crate::chumsky::Parser;
use $crate::chumsky::prelude::*;
use $crate::chumsky_ext::*;
$body.as_token($lang_name::$name)
});
};
($lang_name:ident :: $name:ident, $body:block, has_extras) => {
pub(crate) struct $name;
$crate::parseable!($lang_name::$name, [], {
use $crate::chumsky::Parser;
use $crate::chumsky::prelude::*;
use $crate::chumsky_ext::*;
$lang_name::sink($body.as_token($lang_name::$name))
});
};
}
#[macro_export]
macro_rules! static_token {
($lang_name:ident :: $name:ident, $text:literal) => {
struct $name;
$crate::parseable!($lang_name::$name, [], {
use $crate::chumsky::prelude::*;
use $crate::chumsky_ext::*;
just($text).as_static_token($lang_name::$name)
});
};
($lang_name:ident :: $name:ident, $text:literal, has_extras) => {
struct $name;
$crate::parseable!($lang_name::$name, [], {
use $crate::chumsky::prelude::*;
use $crate::chumsky_ext::*;
$lang_name::sink(just($text).as_static_token($lang_name::$name))
});
};
}
#[macro_export]
macro_rules! make_sink {
($lang:ident, [$($extra:ident),+ $(,)?]) => {
impl $lang {
fn sink<'src, 'cache, 'interner,'borrow,'extra, Err>(
parser: $crate::impl_type!($lang)
) -> $crate::impl_type!($lang)
where
Err: $crate::chumsky::error::Error<'src, &'src str> + 'extra,
'interner: 'cache,
'borrow: 'interner,
'cache: 'extra,
'src: 'extra,
{
use $crate::chumsky::prelude::*;
use $crate::chumsky_ext::*;
let extras = choice((
$(
$extra::parser(),
)*
));
extras.repeated().ignore_then(parser)
}
}
};
}
#[macro_export]
macro_rules! define_pratt_ext {
(
$lang_name:ident,
prefix: [ $( ($p_prec:literal, $p_parser:expr) ),* $(,)? ],
infix: [ $( ($i_prec:literal, $i_assoc:ident, $i_parser:expr) ),* $(,)? ],
postfix:[ $( ($x_prec:literal, $x_parser:expr) ),* $(,)? ]
) => {
#[derive(Clone)]
pub struct PrattExt_<Atom> {
atom: Atom,
kind: $lang_name,
}
pub type PrattExt<Atom> = ::inktree::chumsky::extension::v1::Ext<PrattExt_<Atom>>;
pub fn pratt_ext<Atom>(atom: Atom, kind: $lang_name) -> PrattExt<Atom> {
::inktree::chumsky::extension::v1::Ext(PrattExt_ { atom, kind })
}
impl<'src, 'cache, 'interner, 'borrow,'extra, Err, Atom>
::inktree::chumsky::extension::v1::ExtParser<
'src,
&'src str,
(),
::inktree::chumsky_ext::GreenExtra<'cache, 'interner, 'borrow, Err, $lang_name>,
> for PrattExt_<Atom>
where
Err: ::inktree::chumsky::error::Error<'src, &'src str> + 'extra,
Atom: ::inktree::chumsky_ext::BuilderParser<
'src, 'cache, 'interner, 'borrow, (), Err, $lang_name
> + Clone,
{
fn parse(
&self,
inp: &mut ::inktree::chumsky::input::InputRef<'src,'_,&'src str,::inktree::chumsky_ext::GreenExtra<'cache, 'interner, 'borrow, Err, $lang_name>>,
) -> Result<(), Err> {
use ::inktree::engine::Builder;
use ::inktree::chumsky_ext::*;
fn go<'src, 'cache, 'interner, 'borrow,'extra, Err, Atom>(
inp: &mut ::inktree::chumsky::input::InputRef<
'src,
'_,
&'src str,
::inktree::chumsky_ext::GreenExtra<'cache, 'interner, 'borrow, Err, $lang_name>,
>,
atom: &Atom,
kind: $lang_name,
min_power: u16,
) -> Result<::inktree::cstree::build::Checkpoint, Err>
where
Err: ::inktree::chumsky::error::Error<'src, &'src str> + 'extra,
Atom: ::inktree::chumsky_ext::BuilderParser<
'src, 'cache, 'interner, 'borrow, (), Err, $lang_name
> + Clone,
{
use $crate::chumsky::pratt::*;
let mut lhs_cp = inp.parse(&atom.clone().with_cp())?;
loop {
let checkpoint = inp.save();
$(
if let Ok(_) = inp.parse($p_parser) {
let rhs_cp = go(inp, atom, kind, $p_prec)?;
let builder = inp.state();
builder.start_node_at(rhs_cp, kind);
builder.finish_node();
lhs_cp = rhs_cp;
continue;
}
)*
$(
if let Ok(_) = inp.parse($i_parser) {
if $i_prec < min_power {
inp.rewind(checkpoint);
break;
}
let next_min = $crate::pratt_next_min_power!($i_prec, $i_assoc);
let rhs_cp = go(inp, atom, kind, next_min)?;
let builder= inp.state();
builder.start_node_at(lhs_cp, kind);
builder.finish_node();
lhs_cp = rhs_cp;
continue;
}
)*
$(
if let Ok(_) = inp.parse($x_parser) {
if $x_prec < min_power {
inp.rewind(checkpoint);
break;
}
let builder = inp.state();
builder.start_node_at(lhs_cp, kind);
builder.finish_node();
continue;
}
)*
inp.rewind(checkpoint);
break;
}
Ok(lhs_cp)
}
let cp = inp.state().checkpoint();
let _root_cp = go(inp, &self.atom, self.kind, 0)?;
let builder = inp.state();
builder.start_node_at(cp, self.kind);
builder.finish_node();
Ok(())
}
}
};
}
#[macro_export]
macro_rules! pratt_next_min_power {
( $prec:expr, Left ) => {
$prec + 1
};
( $prec:expr, Right ) => {
$prec
};
( $prec:expr, None ) => {
compile_error!("Associativity::None not supported yet in pratt_next_min_power!");
};
}