Merge branch 'master' into language-reference-count
This commit is contained in:
commit
c4142737ec
3 changed files with 159 additions and 44 deletions
|
|
@ -30,71 +30,88 @@ fn test_corpus_for_bash(seed: usize) {
|
|||
"bash - corpus - commands - Quoted Heredocs",
|
||||
"bash - corpus - commands - Heredocs with weird characters",
|
||||
]),
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
#[test_with_seed(retry=10, seed=*START_SEED, seed_fn=new_seed)]
|
||||
fn test_corpus_for_c(seed: usize) {
|
||||
test_language_corpus("c", seed, None);
|
||||
test_language_corpus("c", seed, None, None);
|
||||
}
|
||||
|
||||
#[test_with_seed(retry=10, seed=*START_SEED, seed_fn=new_seed)]
|
||||
fn test_corpus_for_cpp(seed: usize) {
|
||||
test_language_corpus("cpp", seed, None);
|
||||
test_language_corpus("cpp", seed, None, None);
|
||||
}
|
||||
|
||||
#[test_with_seed(retry=10, seed=*START_SEED, seed_fn=new_seed)]
|
||||
fn test_corpus_for_embedded_template(seed: usize) {
|
||||
test_language_corpus("embedded-template", seed, None);
|
||||
test_language_corpus("embedded-template", seed, None, None);
|
||||
}
|
||||
|
||||
#[test_with_seed(retry=10, seed=*START_SEED, seed_fn=new_seed)]
|
||||
fn test_corpus_for_go(seed: usize) {
|
||||
test_language_corpus("go", seed, None);
|
||||
test_language_corpus("go", seed, None, None);
|
||||
}
|
||||
|
||||
#[test_with_seed(retry=10, seed=*START_SEED, seed_fn=new_seed)]
|
||||
fn test_corpus_for_html(seed: usize) {
|
||||
test_language_corpus("html", seed, None);
|
||||
test_language_corpus("html", seed, None, None);
|
||||
}
|
||||
|
||||
#[test_with_seed(retry=10, seed=*START_SEED, seed_fn=new_seed)]
|
||||
fn test_corpus_for_javascript(seed: usize) {
|
||||
test_language_corpus("javascript", seed, None);
|
||||
test_language_corpus("javascript", seed, None, None);
|
||||
}
|
||||
|
||||
#[test_with_seed(retry=10, seed=*START_SEED, seed_fn=new_seed)]
|
||||
fn test_corpus_for_typescript(seed: usize) {
|
||||
test_language_corpus("typescript", seed, None, Some("typescript"));
|
||||
}
|
||||
|
||||
#[test_with_seed(retry=10, seed=*START_SEED, seed_fn=new_seed)]
|
||||
fn test_corpus_for_json(seed: usize) {
|
||||
test_language_corpus("json", seed, None);
|
||||
test_language_corpus("json", seed, None, None);
|
||||
}
|
||||
|
||||
#[test_with_seed(retry=10, seed=*START_SEED, seed_fn=new_seed)]
|
||||
fn test_corpus_for_php(seed: usize) {
|
||||
test_language_corpus("php", seed, None);
|
||||
test_language_corpus("php", seed, None, Some("php"));
|
||||
}
|
||||
|
||||
#[test_with_seed(retry=10, seed=*START_SEED, seed_fn=new_seed)]
|
||||
fn test_corpus_for_python(seed: usize) {
|
||||
test_language_corpus("python", seed, None);
|
||||
test_language_corpus("python", seed, None, None);
|
||||
}
|
||||
|
||||
#[test_with_seed(retry=10, seed=*START_SEED, seed_fn=new_seed)]
|
||||
fn test_corpus_for_ruby(seed: usize) {
|
||||
test_language_corpus("ruby", seed, None);
|
||||
test_language_corpus("ruby", seed, None, None);
|
||||
}
|
||||
|
||||
#[test_with_seed(retry=10, seed=*START_SEED, seed_fn=new_seed)]
|
||||
fn test_corpus_for_rust(seed: usize) {
|
||||
test_language_corpus("rust", seed, None);
|
||||
test_language_corpus("rust", seed, None, None);
|
||||
}
|
||||
|
||||
fn test_language_corpus(language_name: &str, start_seed: usize, skipped: Option<&[&str]>) {
|
||||
fn test_language_corpus(
|
||||
language_name: &str,
|
||||
start_seed: usize,
|
||||
skipped: Option<&[&str]>,
|
||||
subdir: Option<&str>,
|
||||
) {
|
||||
let subdir = subdir.unwrap_or_default();
|
||||
|
||||
let grammars_dir = fixtures_dir().join("grammars");
|
||||
let error_corpus_dir = fixtures_dir().join("error_corpus");
|
||||
let template_corpus_dir = fixtures_dir().join("template_corpus");
|
||||
let mut corpus_dir = grammars_dir.join(language_name).join("corpus");
|
||||
let mut corpus_dir = grammars_dir.join(language_name).join(subdir).join("corpus");
|
||||
if !corpus_dir.is_dir() {
|
||||
corpus_dir = grammars_dir.join(language_name).join("test").join("corpus");
|
||||
corpus_dir = grammars_dir
|
||||
.join(language_name)
|
||||
.join(subdir)
|
||||
.join("test")
|
||||
.join("corpus");
|
||||
}
|
||||
|
||||
let error_corpus_file = error_corpus_dir.join(&format!("{}_errors.txt", language_name));
|
||||
|
|
@ -112,7 +129,12 @@ fn test_language_corpus(language_name: &str, start_seed: usize, skipped: Option<
|
|||
|
||||
let mut skipped = skipped.map(|x| HashMap::<&str, usize>::from_iter(x.iter().map(|x| (*x, 0))));
|
||||
|
||||
let language = get_language(language_name);
|
||||
let language_path = if subdir.is_empty() {
|
||||
language_name.to_string()
|
||||
} else {
|
||||
format!("{language_name}/{subdir}")
|
||||
};
|
||||
let language = get_language(&language_path);
|
||||
let mut failure_count = 0;
|
||||
|
||||
let log_seed = env::var("TREE_SITTER_LOG_SEED").is_ok();
|
||||
|
|
|
|||
|
|
@ -842,78 +842,88 @@ class Language {
|
|||
const operator = steps[0].value;
|
||||
let isPositive = true;
|
||||
let matchAll = true;
|
||||
let captureName;
|
||||
switch (operator) {
|
||||
case 'any-not-eq?':
|
||||
isPositive = false;
|
||||
matchAll = false;
|
||||
case 'any-eq?':
|
||||
matchAll = false;
|
||||
case 'not-eq?':
|
||||
isPositive = false;
|
||||
case 'any-eq?':
|
||||
case 'eq?':
|
||||
if (steps.length !== 3) throw new Error(
|
||||
`Wrong number of arguments to \`#eq?\` predicate. Expected 2, got ${steps.length - 1}`
|
||||
`Wrong number of arguments to \`#${operator}\` predicate. Expected 2, got ${steps.length - 1}`
|
||||
);
|
||||
if (steps[1].type !== 'capture') throw new Error(
|
||||
`First argument of \`#eq?\` predicate must be a capture. Got "${steps[1].value}"`
|
||||
`First argument of \`#${operator}\` predicate must be a capture. Got "${steps[1].value}"`
|
||||
);
|
||||
matchAll = !operator.startsWith('any-');
|
||||
if (steps[2].type === 'capture') {
|
||||
const captureName1 = steps[1].name;
|
||||
const captureName2 = steps[2].name;
|
||||
textPredicates[i].push(function(captures) {
|
||||
textPredicates[i].push(function (captures) {
|
||||
let nodes_1 = [];
|
||||
let nodes_2 = [];
|
||||
for (const c of captures) {
|
||||
if (c.name === captureName1) nodes_1.push(c.node);
|
||||
if (c.name === captureName2) nodes_2.push(c.node);
|
||||
}
|
||||
let compare = (n1, n2, positive) => {
|
||||
return positive ?
|
||||
n1.text === n2.text :
|
||||
n1.text !== n2.text;
|
||||
};
|
||||
return matchAll
|
||||
? nodes_1.every(n1 => nodes_2.some(n2 => n1.text === n2.text)) === isPositive
|
||||
: nodes_1.some(n1 => nodes_2.some(n2 => n1.text === n2.text)) === isPositive;
|
||||
? nodes_1.every(n1 => nodes_2.some(n2 => compare(n1, n2, isPositive)))
|
||||
: nodes_1.some(n1 => nodes_2.some(n2 => compare(n1, n2, isPositive)));
|
||||
});
|
||||
} else {
|
||||
const captureName = steps[1].name;
|
||||
captureName = steps[1].name;
|
||||
const stringValue = steps[2].value;
|
||||
textPredicates[i].push(function(captures) {
|
||||
let matches = (n) => n.text === stringValue;
|
||||
let doesNotMatch = (n) => n.text !== stringValue;
|
||||
textPredicates[i].push(function (captures) {
|
||||
let nodes = [];
|
||||
for (const c of captures) {
|
||||
if (c.name === captureName) nodes.push(c.node);
|
||||
}
|
||||
let test = isPositive ? matches : doesNotMatch;
|
||||
return matchAll
|
||||
? nodes.every(n => n.text === stringValue) === isPositive
|
||||
: nodes.some(n => n.text === stringValue) === isPositive;
|
||||
? nodes.every(test)
|
||||
: nodes.some(test);
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case 'not-any-match?':
|
||||
isPositive = false;
|
||||
matchAll = false;
|
||||
case 'any-match?':
|
||||
matchAll = false;
|
||||
case 'not-match?':
|
||||
isPositive = false;
|
||||
case 'match?':
|
||||
case "any-not-match?":
|
||||
case "not-match?":
|
||||
isPositive = false;
|
||||
case "any-match?":
|
||||
case "match?":
|
||||
if (steps.length !== 3) throw new Error(
|
||||
`Wrong number of arguments to \`#match?\` predicate. Expected 2, got ${steps.length - 1}.`
|
||||
`Wrong number of arguments to \`#${operator}\` predicate. Expected 2, got ${steps.length - 1}.`
|
||||
);
|
||||
if (steps[1].type !== 'capture') throw new Error(
|
||||
`First argument of \`#match?\` predicate must be a capture. Got "${steps[1].value}".`
|
||||
`First argument of \`#${operator}\` predicate must be a capture. Got "${steps[1].value}".`
|
||||
);
|
||||
if (steps[2].type !== 'string') throw new Error(
|
||||
`Second argument of \`#match?\` predicate must be a string. Got @${steps[2].value}.`
|
||||
`Second argument of \`#${operator}\` predicate must be a string. Got @${steps[2].value}.`
|
||||
);
|
||||
const captureName = steps[1].name;
|
||||
captureName = steps[1].name;
|
||||
const regex = new RegExp(steps[2].value);
|
||||
textPredicates[i].push(function(captures) {
|
||||
matchAll = !operator.startsWith('any-');
|
||||
textPredicates[i].push(function (captures) {
|
||||
const nodes = [];
|
||||
for (const c of captures) {
|
||||
if (c.name === captureName) nodes.push(c.node.text);
|
||||
}
|
||||
let test = (text, positive) => {
|
||||
return positive ?
|
||||
regex.test(text) :
|
||||
!regex.test(text);
|
||||
};
|
||||
if (nodes.length === 0) return !isPositive;
|
||||
return matchAll
|
||||
? nodes.every(text => regex.test(text)) === isPositive
|
||||
: nodes.some(text => regex.test(text)) === isPositive;
|
||||
? nodes.every(text => test(text, isPositive))
|
||||
: nodes.some(text => test(text, isPositive))
|
||||
});
|
||||
break;
|
||||
|
||||
|
|
@ -957,7 +967,7 @@ class Language {
|
|||
}
|
||||
captureName = steps[1].name;
|
||||
const values = steps.slice(2).map(s => s.value);
|
||||
textPredicates[i].push(function(captures) {
|
||||
textPredicates[i].push(function (captures) {
|
||||
const nodes = [];
|
||||
for (const c of captures) {
|
||||
if (c.name === captureName) nodes.push(c.node.text);
|
||||
|
|
|
|||
|
|
@ -259,6 +259,89 @@ describe("Query", () => {
|
|||
const captures = query.captures(tree.rootNode, null, null, {matchLimit: 32});
|
||||
assert.ok(query.didExceedMatchLimit());
|
||||
});
|
||||
|
||||
it("handles quantified captures properly", () => {
|
||||
let captures;
|
||||
|
||||
tree = parser.parse(`
|
||||
/// foo
|
||||
/// bar
|
||||
/// baz
|
||||
`);
|
||||
|
||||
query = JavaScript.query(`
|
||||
(
|
||||
(comment)+ @foo
|
||||
(#any-eq? @foo "/// foo")
|
||||
)
|
||||
`);
|
||||
|
||||
let expectCount = (tree, queryText, expectedCount) => {
|
||||
query = JavaScript.query(queryText);
|
||||
captures = query.captures(tree.rootNode, null, null);
|
||||
assert.equal(captures.length, expectedCount);
|
||||
};
|
||||
|
||||
expectCount(
|
||||
tree,
|
||||
` ( (comment)+ @foo (#any-eq? @foo "/// foo") ) `,
|
||||
3
|
||||
);
|
||||
|
||||
expectCount(
|
||||
tree,
|
||||
` ( (comment)+ @foo (#eq? @foo "/// foo") ) `,
|
||||
0
|
||||
);
|
||||
|
||||
expectCount(
|
||||
tree,
|
||||
` ( (comment)+ @foo (#any-not-eq? @foo "/// foo") ) `,
|
||||
3
|
||||
);
|
||||
|
||||
expectCount(
|
||||
tree,
|
||||
` ( (comment)+ @foo (#not-eq? @foo "/// foo") ) `,
|
||||
0
|
||||
);
|
||||
|
||||
expectCount(
|
||||
tree,
|
||||
` ( (comment)+ @foo (#match? @foo "^/// foo") ) `,
|
||||
0
|
||||
);
|
||||
|
||||
expectCount(
|
||||
tree,
|
||||
` ( (comment)+ @foo (#any-match? @foo "^/// foo") ) `,
|
||||
3
|
||||
);
|
||||
|
||||
expectCount(
|
||||
tree,
|
||||
` ( (comment)+ @foo (#not-match? @foo "^/// foo") ) `,
|
||||
0
|
||||
);
|
||||
|
||||
expectCount(
|
||||
tree,
|
||||
` ( (comment)+ @foo (#not-match? @foo "fsdfsdafdfs") ) `,
|
||||
3
|
||||
);
|
||||
|
||||
expectCount(
|
||||
tree,
|
||||
` ( (comment)+ @foo (#any-not-match? @foo "^///") ) `,
|
||||
0
|
||||
);
|
||||
|
||||
expectCount(
|
||||
tree,
|
||||
` ( (comment)+ @foo (#any-not-match? @foo "^/// foo") ) `,
|
||||
3
|
||||
);
|
||||
})
|
||||
});
|
||||
|
||||
describe(".predicatesForPattern(index)", () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue