use crate::parse::builder::GrammarBuilder;
use crate::types::IntoSyntaxKind;
type BuilderChoice = Box<dyn FnOnce(&mut GrammarBuilder)>;
pub struct LeftAssocInfixLevel<'a, K: ?Sized> {
pub level_name: &'static str,
pub lower_level_name: &'static str,
pub ops: &'a [&'static str],
pub node_kind: &'a K,
pub wrapper_kind: Option<&'a K>,
pub rhs_field: Option<&'static str>,
pub rhs_wrapper_kind: Option<&'a K>,
}
pub fn left_assoc_infix_level<K: IntoSyntaxKind + Clone + 'static>(
g: &mut GrammarBuilder,
cfg: &LeftAssocInfixLevel<'_, K>,
) {
let level_name = cfg.level_name;
let lower_level_name = cfg.lower_level_name;
let ops = cfg.ops;
let node_kind = cfg.node_kind;
let wrapper_kind = cfg.wrapper_kind;
let rhs_field = cfg.rhs_field;
let rhs_wrapper_kind = cfg.rhs_wrapper_kind;
g.parser_rule(level_name, |g| {
let body = |g: &mut GrammarBuilder| {
g.call(lower_level_name);
g.zero_or_more({
let node_kind = node_kind.clone();
let rhs_wrapper_kind = rhs_wrapper_kind.cloned();
move |g: &mut GrammarBuilder| {
g.node(node_kind.clone(), |g| {
let mut alternatives: Vec<BuilderChoice> = Vec::new();
for op in ops {
let op = *op;
let lower = lower_level_name;
let rhs_wrapper_kind = rhs_wrapper_kind.clone();
alternatives.push(Box::new(move |g| {
g.call(op);
if let (Some(field), Some(wk)) =
(rhs_field, rhs_wrapper_kind.as_ref())
{
g.node_with_field(wk.clone(), field, |g| {
g.call(lower);
});
} else {
g.call(lower);
}
}));
}
g.choices(alternatives);
});
}
});
};
match wrapper_kind {
Some(wk) => g.node(wk.clone(), body),
None => body(g),
}
});
}
pub fn right_assoc_infix_level<K: IntoSyntaxKind + Clone + 'static>(
g: &mut GrammarBuilder,
level_name: &'static str,
lower_level_name: &'static str,
op_rule: &'static str,
node_kind: &K,
rhs_field: Option<&'static str>,
rhs_wrapper_kind: Option<&K>,
) {
g.parser_rule(level_name, |g| {
let lower = lower_level_name;
let op = op_rule;
let level = level_name;
let kind = node_kind.clone();
let rhs_wrapper_kind = rhs_wrapper_kind.cloned();
g.choices(vec![
Box::new(move |g| {
g.node(kind.clone(), |g| {
g.call(lower);
g.call(op);
if let (Some(field), Some(wk)) = (rhs_field, rhs_wrapper_kind.as_ref()) {
g.node_with_field(wk.clone(), field, |g| {
g.call(level);
});
} else {
g.call(level);
}
});
}),
Box::new(move |g| {
g.call(lower_level_name);
}),
]);
});
}
pub fn postfix_chain(
g: &mut GrammarBuilder,
level_name: &'static str,
operand_rule: &'static str,
postfix_rule: &'static str,
) {
g.parser_rule(level_name, |g| {
g.call(operand_rule);
g.zero_or_more(|g| {
g.call(postfix_rule);
});
});
}
pub fn separated_rule_list(
g: &mut GrammarBuilder,
list_name: &'static str,
elem_rule: &'static str,
sep_rule: &'static str,
) {
g.parser_rule(list_name, |g| {
let elem = elem_rule;
let sep = sep_rule;
g.separated(
|g| {
g.call(elem);
},
|g| {
g.call(sep);
},
);
});
}
pub fn separated1_rule_list(
g: &mut GrammarBuilder,
list_name: &'static str,
elem_rule: &'static str,
sep_rule: &'static str,
) {
g.parser_rule(list_name, |g| {
let elem = elem_rule;
let sep = sep_rule;
g.separated1(
|g| {
g.call(elem);
},
|g| {
g.call(sep);
},
);
});
}