#[allow(clippy::crate_in_macro_def)]
#[macro_export]
macro_rules! define_node_enum {
(
// parser state
$($parser_state:ident)::+
=>
// variants
$( crate::$($node_name:ident)::+ ),* $(,)?
) => {
paste::paste! {
#[derive(Debug, Clone, PartialEq)]
pub enum Node {
$([< $($node_name:camel)+ >](
crate::$($node_name)::+
),
)*
}
impl bluegum::Bluegum for Node {
fn node(&self, b: &mut bluegum::Builder) {
b.name("Node")
.field("id", format!("{:?}",&self))
.debug("Help", "For the full node use `node_with_state`");
}
}
impl<'nodes>
bluegum::BluegumWithState<crate::Printer<'nodes>>
for Node {
#[allow(unused)]
fn node_with_state(
&self,
b: &mut bluegum::Builder,
state: &crate::Printer<'nodes>,
) {
(state.pre_callback)(b, self);
match self {
$(
| Node :: [< $($node_name:camel)+ >](node) => {
node.node_with_state(b,state);
}
),*
| _ => {
b.name("Node");
}
}
(state.post_callback)(b, self);
}
}
impl Node {
#[allow(unused)]
pub fn get_id(
&self,
) -> crate::NodeId {
match self {
$(
| Node :: [< $($node_name:camel)+ >](node) => {
node.get_id()
}
),*
}
}
}
#[allow(unused)]
impl Node {
#[allow(clippy::result_unit_err)]
pub fn validate(
&self,
ast: &crate::AST,
) -> crate::Result<()> {
match self {
$(
| Node :: [< $($node_name:camel)+ >](node) => node.validate(ast),
)*
| _ => {
Ok(())
}
}
}
pub fn get_node_name(&self) -> String {
match self {
$(
| Node :: [< $($node_name:camel)+ >](node) => stringify!([<$($node_name:camel)+>]).to_string(),
)*
}
}
pub fn get_syntax(&self) -> crate::cst::CstNodeId {
match self {
$(
| Node :: [< $($node_name:camel)+ >](node) => node.get_syntax(),
)*
}
}
#[allow(unused)]
$(
pub fn [< match_ $($node_name:snake)_+ >]
(
&self,
ast: &crate::AST,
) -> Option<& crate::$($node_name)::+ >{
match &self {
| crate::Node :: [< $($node_name:camel)+ >](node) => Some(node),
| _ => {
None
}
}
}
)*
}
$(
impl crate::$($node_name)::+ {
pub fn from_node(node: &crate::Node) -> Option<& crate::$($node_name)::+ > {
match node {
| crate::Node :: [< $($node_name:camel)+ >](node) => Some(node),
| _ => {
None
}
}
}
}
)*
}
};
}
#[allow(clippy::crate_in_macro_def)]
#[macro_export]
macro_rules! group {
(@option delimiter None) => {
None
};
(@option delimiter $Delimiter:ident) => {
Some(crate::cst::group::DelimitedBy::$Delimiter)
};
(@option separator None) => {
None
};
(@option separator $Separator:ident) => {
Some(crate::cst::group::SeparatedBy::$Separator)
};
(
$state:ident,
$syntax:ident,
$(delimiter: $Delimiter:ident , )?
$(separator: $Separator:ident , )?
$(leading_separator: $leading_separator:expr , )?
$(trailing_separator: $trailing_separator:expr , )?
=> $handler:path
) => {{
if let Some(crate::cst::Node::Group{
node: crate::cst::Group {
$( delimiter: $crate::group!(@option delimiter $Delimiter), )?
$( separator: $crate::group!(@option separator $Separator), )?
$(leading_separator: $leading_separator, )?
$(trailing_separator: $trailing_separator, )?
nodes,
..
},
..
}) = $state.load(&$syntax) {
nodes
.get()
.iter()
.map(|syntax| $handler($state, *syntax))
.collect::<Vec<_>>()
}
else {
vec![$handler($state, $syntax)]
}
}};
}
#[allow(clippy::crate_in_macro_def)]
#[macro_export]
macro_rules! try_group {
(@allow_empty true ) => { Some(vec![]) as Option<Vec<_>> };
(@allow_empty) => { None as Option<Vec<_>> };
(
$state:ident,
$node:ident,
$(delimiter: $Delimiter:ident , )?
$(separator: $Separator:ident , )?
$(leading_separator: $leading_separator:expr , )?
$(trailing_separator: $trailing_separator:expr , )?
$(allow_empty: $allow_empty:ident , )?
=> $handler:path
) => {{
match $node {
| crate::cst::Node::Group{
node: crate::cst::Group {
$( delimiter: $crate::group!(@option delimiter $Delimiter), )?
$( separator: $crate::group!(@option separator $Separator), )?
is_empty: true,
..
},
..
} => {
$crate::try_group!(
@allow_empty $( $allow_empty )?)
},
| crate::cst::Node::Group{
node: crate::cst::Group {
$( delimiter: $crate::group!(@option delimiter $Delimiter), )?
$( separator: $crate::group!(@option separator $Separator), )?
$(leading_separator: $leading_separator, )?
$(trailing_separator: $trailing_separator, )?
is_empty: false,
nodes,
..
},
..
} => {
Some(nodes
.get()
.iter()
.map(|syntax| $handler($state, *syntax))
.collect::<Vec<_>>())
},
| _ => None as Option<Vec<_>>,
}
}};
}
pub trait LowerConfig {
type State;
type SyntaxId: Copy;
type SyntaxNode;
type NodeId;
}
pub trait Lower<C: LowerConfig> {
fn must_parse(state: &mut C::State, syntax: C::SyntaxId) -> C::NodeId;
fn try_parse(
state: &mut C::State,
syntax: C::SyntaxId,
node: &C::SyntaxNode,
) -> Option<C::NodeId>;
}
pub trait LowerMany<C: LowerConfig> {
fn must_parse_many(
state: &mut C::State,
syntax: C::SyntaxId,
) -> Vec<C::NodeId>;
fn try_parse_many(
state: &mut C::State,
syntax: C::SyntaxId,
node: &C::SyntaxNode,
) -> Option<Vec<C::NodeId>>;
}