Fix more bugs
This commit is contained in:
@@ -21,7 +21,10 @@ fn expand_rule(rule: &crate::Rule, input: &tt::Subtree) -> Result<tt::Subtree, E
|
||||
if !input.is_eof() {
|
||||
return Err(ExpandError::UnexpectedToken);
|
||||
}
|
||||
expand_subtree(&rule.rhs, &bindings, &mut Vec::new())
|
||||
|
||||
let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new(), var_expanded: false };
|
||||
|
||||
expand_subtree(&rule.rhs, &mut ctx)
|
||||
}
|
||||
|
||||
/// The actual algorithm for expansion is not too hard, but is pretty tricky.
|
||||
@@ -225,7 +228,7 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings,
|
||||
crate::TokenTree::Repeat(crate::Repeat { subtree, kind, separator }) => {
|
||||
// Dirty hack to make macro-expansion terminate.
|
||||
// This should be replaced by a propper macro-by-example implementation
|
||||
let mut limit = 128;
|
||||
let mut limit = 65536;
|
||||
let mut counter = 0;
|
||||
|
||||
let mut memento = input.save();
|
||||
@@ -236,6 +239,7 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings,
|
||||
counter += 1;
|
||||
limit -= 1;
|
||||
if limit == 0 {
|
||||
log::warn!("match_lhs excced in repeat pattern exceed limit => {:#?}\n{:#?}\n{:#?}\n{:#?}", subtree, input, kind, separator);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -303,15 +307,21 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings,
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ExpandCtx<'a> {
|
||||
bindings: &'a Bindings,
|
||||
nesting: Vec<usize>,
|
||||
var_expanded: bool,
|
||||
}
|
||||
|
||||
fn expand_subtree(
|
||||
template: &crate::Subtree,
|
||||
bindings: &Bindings,
|
||||
nesting: &mut Vec<usize>,
|
||||
ctx: &mut ExpandCtx,
|
||||
) -> Result<tt::Subtree, ExpandError> {
|
||||
let token_trees = template
|
||||
.token_trees
|
||||
.iter()
|
||||
.map(|it| expand_tt(it, bindings, nesting))
|
||||
.map(|it| expand_tt(it, ctx))
|
||||
.collect::<Result<Vec<_>, ExpandError>>()?;
|
||||
|
||||
Ok(tt::Subtree { token_trees, delimiter: template.delimiter })
|
||||
@@ -333,26 +343,43 @@ fn reduce_single_token(mut subtree: tt::Subtree) -> tt::TokenTree {
|
||||
|
||||
fn expand_tt(
|
||||
template: &crate::TokenTree,
|
||||
bindings: &Bindings,
|
||||
nesting: &mut Vec<usize>,
|
||||
ctx: &mut ExpandCtx,
|
||||
) -> Result<tt::TokenTree, ExpandError> {
|
||||
let res: tt::TokenTree = match template {
|
||||
crate::TokenTree::Subtree(subtree) => expand_subtree(subtree, bindings, nesting)?.into(),
|
||||
crate::TokenTree::Subtree(subtree) => expand_subtree(subtree, ctx)?.into(),
|
||||
crate::TokenTree::Repeat(repeat) => {
|
||||
let mut token_trees: Vec<tt::TokenTree> = Vec::new();
|
||||
nesting.push(0);
|
||||
ctx.nesting.push(0);
|
||||
// Dirty hack to make macro-expansion terminate.
|
||||
// This should be replaced by a propper macro-by-example implementation
|
||||
let mut limit = 128;
|
||||
let mut limit = 65536;
|
||||
let mut has_seps = 0;
|
||||
let mut counter = 0;
|
||||
|
||||
while let Ok(t) = expand_subtree(&repeat.subtree, bindings, nesting) {
|
||||
limit -= 1;
|
||||
if limit == 0 {
|
||||
let mut some_var_expanded = false;
|
||||
ctx.var_expanded = false;
|
||||
|
||||
while let Ok(t) = expand_subtree(&repeat.subtree, ctx) {
|
||||
// if no var expaned in the child, we count it as a fail
|
||||
if !ctx.var_expanded {
|
||||
break;
|
||||
}
|
||||
let idx = nesting.pop().unwrap();
|
||||
nesting.push(idx + 1);
|
||||
some_var_expanded = true;
|
||||
ctx.var_expanded = false;
|
||||
|
||||
counter += 1;
|
||||
limit -= 1;
|
||||
if limit == 0 {
|
||||
log::warn!(
|
||||
"expand_tt excced in repeat pattern exceed limit => {:#?}\n{:#?}",
|
||||
template,
|
||||
ctx
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
let idx = ctx.nesting.pop().unwrap();
|
||||
ctx.nesting.push(idx + 1);
|
||||
token_trees.push(reduce_single_token(t).into());
|
||||
|
||||
if let Some(ref sep) = repeat.separator {
|
||||
@@ -374,12 +401,23 @@ fn expand_tt(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let crate::RepeatKind::ZeroOrOne = repeat.kind {
|
||||
break;
|
||||
}
|
||||
}
|
||||
nesting.pop().unwrap();
|
||||
|
||||
ctx.var_expanded = some_var_expanded;
|
||||
|
||||
ctx.nesting.pop().unwrap();
|
||||
for _ in 0..has_seps {
|
||||
token_trees.pop();
|
||||
}
|
||||
|
||||
if crate::RepeatKind::OneOrMore == repeat.kind && counter == 0 {
|
||||
return Err(ExpandError::UnexpectedToken);
|
||||
}
|
||||
|
||||
// Check if it is a singel token subtree without any delimiter
|
||||
// e.g {Delimiter:None> ['>'] /Delimiter:None>}
|
||||
reduce_single_token(tt::Subtree { token_trees, delimiter: tt::Delimiter::None })
|
||||
@@ -396,7 +434,8 @@ fn expand_tt(
|
||||
tt::Leaf::from(tt::Ident { text: "$crate".into(), id: TokenId::unspecified() })
|
||||
.into()
|
||||
} else {
|
||||
let tkn = bindings.get(&v.text, nesting)?.clone();
|
||||
let tkn = ctx.bindings.get(&v.text, &ctx.nesting)?.clone();
|
||||
ctx.var_expanded = true;
|
||||
|
||||
if let tt::TokenTree::Subtree(subtree) = tkn {
|
||||
reduce_single_token(subtree)
|
||||
|
||||
Reference in New Issue
Block a user