Attempt to implement ranking of rules when none matches perfectly (wip)

This commit is contained in:
Florian Diebold 2020-03-13 15:18:17 +01:00 committed by Florian Diebold
parent b973158aeb
commit 6305d094ac
3 changed files with 51 additions and 11 deletions

View file

@ -811,7 +811,44 @@ mod tests {
} }
" "
), ),
@"[]" @r###"
[
CompletionItem {
label: "m!",
source_range: [145; 145),
delete: [145; 145),
insert: "m!($0)",
kind: Macro,
detail: "macro_rules! m",
},
CompletionItem {
label: "quux(…)",
source_range: [145; 145),
delete: [145; 145),
insert: "quux(${1:x})$0",
kind: Function,
lookup: "quux",
detail: "fn quux(x: i32)",
trigger_call_info: true,
},
CompletionItem {
label: "x",
source_range: [145; 145),
delete: [145; 145),
insert: "x",
kind: Binding,
detail: "i32",
},
CompletionItem {
label: "y",
source_range: [145; 145),
delete: [145; 145),
insert: "y",
kind: Binding,
detail: "i32",
},
]
"###
); );
} }

View file

@ -14,24 +14,27 @@ pub(crate) fn expand(
rules: &crate::MacroRules, rules: &crate::MacroRules,
input: &tt::Subtree, input: &tt::Subtree,
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
let (mut result, mut err) = (tt::Subtree::default(), Some(ExpandError::NoMatchingRule)); let (mut result, mut left_over, mut err) = (tt::Subtree::default(), usize::max_value(), Some(ExpandError::NoMatchingRule));
for rule in &rules.rules { for rule in &rules.rules {
let (res, e) = expand_rule(rule, input); let ((res, left), e) = expand_rule(rule, input);
if e.is_none() { if e.is_none() {
// if we find a rule that applies without errors, we're done // if we find a rule that applies without errors, we're done
return (res, None); return (res, None);
} }
// TODO decide which result is better // use the rule if we matched more tokens
result = res; if left < left_over {
err = e; result = res;
err = e;
left_over = left;
}
} }
(result, err) (result, err)
} }
fn expand_rule(rule: &crate::Rule, input: &tt::Subtree) -> ExpandResult<tt::Subtree> { fn expand_rule(rule: &crate::Rule, input: &tt::Subtree) -> ExpandResult<(tt::Subtree, usize)> {
let (bindings, bindings_err) = dbg!(matcher::match_(&rule.lhs, input)); let ((bindings, left_over), bindings_err) = dbg!(matcher::match_(&rule.lhs, input));
let (res, transcribe_err) = dbg!(transcriber::transcribe(&rule.rhs, &bindings)); let (res, transcribe_err) = dbg!(transcriber::transcribe(&rule.rhs, &bindings));
(res, bindings_err.or(transcribe_err)) ((res, left_over), bindings_err.or(transcribe_err))
} }
/// The actual algorithm for expansion is not too hard, but is pretty tricky. /// The actual algorithm for expansion is not too hard, but is pretty tricky.

View file

@ -65,7 +65,7 @@ macro_rules! bail {
}; };
} }
pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> ExpandResult<Bindings> { pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> ExpandResult<(Bindings, usize)> {
assert!(pattern.delimiter == None); assert!(pattern.delimiter == None);
let mut res = Bindings::default(); let mut res = Bindings::default();
@ -77,7 +77,7 @@ pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> ExpandResult<B
err = Some(err!("leftover tokens")); err = Some(err!("leftover tokens"));
} }
(res, err) ((res, src.len()), err)
} }
fn match_subtree( fn match_subtree(