wasm: Allow arbitrary predicates in queries
This commit is contained in:
parent
47d607da8d
commit
28a779d6a0
2 changed files with 66 additions and 10 deletions
|
|
@ -44,6 +44,8 @@ class Parser {
|
|||
delete() {
|
||||
C._ts_parser_delete(this[0]);
|
||||
C._free(this[1]);
|
||||
this[0] = 0;
|
||||
this[1] = 0;
|
||||
}
|
||||
|
||||
setLanguage(language) {
|
||||
|
|
@ -163,6 +165,7 @@ class Tree {
|
|||
|
||||
delete() {
|
||||
C._ts_tree_delete(this[0]);
|
||||
this[0] = 0;
|
||||
}
|
||||
|
||||
edit(edit) {
|
||||
|
|
@ -506,6 +509,7 @@ class TreeCursor {
|
|||
delete() {
|
||||
marshalTreeCursor(this);
|
||||
C._ts_tree_cursor_delete_wasm(this.tree[0]);
|
||||
this[0] = this[1] = this[2] = 0;
|
||||
}
|
||||
|
||||
reset(node) {
|
||||
|
|
@ -716,6 +720,7 @@ class Language {
|
|||
const assertedProperties = new Array(patternCount);
|
||||
const refutedProperties = new Array(patternCount);
|
||||
const predicates = new Array(patternCount);
|
||||
const textPredicates = new Array(patternCount);
|
||||
for (let i = 0; i < patternCount; i++) {
|
||||
const predicatesAddress = C._ts_query_predicates_for_pattern(
|
||||
address,
|
||||
|
|
@ -725,6 +730,7 @@ class Language {
|
|||
const stepCount = getValue(TRANSFER_BUFFER, 'i32');
|
||||
|
||||
predicates[i] = [];
|
||||
textPredicates[i] = [];
|
||||
|
||||
const steps = [];
|
||||
let stepAddress = predicatesAddress;
|
||||
|
|
@ -756,7 +762,7 @@ class Language {
|
|||
if (steps[2].type === 'capture') {
|
||||
const captureName1 = steps[1].name;
|
||||
const captureName2 = steps[2].name;
|
||||
predicates[i].push(function(captures) {
|
||||
textPredicates[i].push(function(captures) {
|
||||
let node1, node2
|
||||
for (const c of captures) {
|
||||
if (c.name === captureName1) node1 = c.node;
|
||||
|
|
@ -767,7 +773,7 @@ class Language {
|
|||
} else {
|
||||
const captureName = steps[1].name;
|
||||
const stringValue = steps[2].value;
|
||||
predicates[i].push(function(captures) {
|
||||
textPredicates[i].push(function(captures) {
|
||||
for (const c of captures) {
|
||||
if (c.name === captureName) {
|
||||
return (c.node.text === stringValue) === isPositive;
|
||||
|
|
@ -790,7 +796,7 @@ class Language {
|
|||
);
|
||||
const captureName = steps[1].name;
|
||||
const regex = new RegExp(steps[2].value);
|
||||
predicates[i].push(function(captures) {
|
||||
textPredicates[i].push(function(captures) {
|
||||
for (const c of captures) {
|
||||
if (c.name === captureName) return regex.test(c.node.text);
|
||||
}
|
||||
|
|
@ -823,7 +829,7 @@ class Language {
|
|||
break;
|
||||
|
||||
default:
|
||||
throw new Error(`Unknown query predicate \`#${steps[0].value}\``);
|
||||
predicates[i].push({operator, operands: steps.slice(1)});
|
||||
}
|
||||
|
||||
steps.length = 0;
|
||||
|
|
@ -840,6 +846,7 @@ class Language {
|
|||
INTERNAL,
|
||||
address,
|
||||
captureNames,
|
||||
textPredicates,
|
||||
predicates,
|
||||
Object.freeze(setProperties),
|
||||
Object.freeze(assertedProperties),
|
||||
|
|
@ -888,12 +895,13 @@ class Language {
|
|||
|
||||
class Query {
|
||||
constructor(
|
||||
internal, address, captureNames, predicates,
|
||||
internal, address, captureNames, textPredicates, predicates,
|
||||
setProperties, assertedProperties, refutedProperties
|
||||
) {
|
||||
assertInternal(internal);
|
||||
this[0] = address;
|
||||
this.captureNames = captureNames;
|
||||
this.textPredicates = textPredicates;
|
||||
this.predicates = predicates;
|
||||
this.setProperties = setProperties;
|
||||
this.assertedProperties = assertedProperties;
|
||||
|
|
@ -902,6 +910,7 @@ class Query {
|
|||
|
||||
delete() {
|
||||
C._ts_query_delete(this[0]);
|
||||
this[0] = 0;
|
||||
}
|
||||
|
||||
matches(node, startPosition, endPosition) {
|
||||
|
|
@ -932,7 +941,7 @@ class Query {
|
|||
|
||||
const captures = new Array(captureCount);
|
||||
address = unmarshalCaptures(this, node.tree, address, captures);
|
||||
if (this.predicates[pattern].every(p => p(captures))) {
|
||||
if (this.textPredicates[pattern].every(p => p(captures))) {
|
||||
result[i] = {pattern, captures};
|
||||
const setProperties = this.setProperties[pattern];
|
||||
if (setProperties) result[i].setProperties = setProperties;
|
||||
|
|
@ -979,7 +988,7 @@ class Query {
|
|||
captures.length = captureCount
|
||||
address = unmarshalCaptures(this, node.tree, address, captures);
|
||||
|
||||
if (this.predicates[pattern].every(p => p(captures))) {
|
||||
if (this.textPredicates[pattern].every(p => p(captures))) {
|
||||
const capture = captures[captureIndex];
|
||||
const setProperties = this.setProperties[pattern];
|
||||
if (setProperties) capture.setProperties = setProperties;
|
||||
|
|
@ -994,6 +1003,10 @@ class Query {
|
|||
C._free(startAddress);
|
||||
return result;
|
||||
}
|
||||
|
||||
predicatesForPattern(patternIndex) {
|
||||
return this.predicates[patternIndex]
|
||||
}
|
||||
}
|
||||
|
||||
function getText(tree, startIndex, endIndex) {
|
||||
|
|
|
|||
|
|
@ -45,9 +45,6 @@ describe("Query", () => {
|
|||
assert.throws(() => {
|
||||
JavaScript.query("((identifier) @a (eq? @a @a @a))");
|
||||
}, "Wrong number of arguments to `#eq?` predicate. Expected 2, got 3");
|
||||
assert.throws(() => {
|
||||
JavaScript.query("((identifier) @a (#something-else? @a))");
|
||||
}, "Unknown query predicate `#something-else?`");
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -207,6 +204,52 @@ describe("Query", () => {
|
|||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".predicatesForPattern(index)", () => {
|
||||
it("returns all of the predicates as objects", () => {
|
||||
query = JavaScript.query(`
|
||||
(
|
||||
(binary_expression
|
||||
left: (identifier) @a
|
||||
right: (identifier) @b)
|
||||
(#something? @a @b)
|
||||
(#match? @a "c")
|
||||
(#something-else? @a "A" @b "B")
|
||||
)
|
||||
|
||||
((identifier) @c
|
||||
(#hello! @c))
|
||||
|
||||
"if" @d
|
||||
`);
|
||||
|
||||
assert.deepEqual(query.predicatesForPattern(0), [
|
||||
{
|
||||
operator: "something?",
|
||||
operands: [
|
||||
{ type: "capture", name: "a" },
|
||||
{ type: "capture", name: "b" },
|
||||
],
|
||||
},
|
||||
{
|
||||
operator: "something-else?",
|
||||
operands: [
|
||||
{ type: "capture", name: "a" },
|
||||
{ type: "string", value: "A" },
|
||||
{ type: "capture", name: "b" },
|
||||
{ type: "string", value: "B" },
|
||||
],
|
||||
},
|
||||
]);
|
||||
assert.deepEqual(query.predicatesForPattern(1), [
|
||||
{
|
||||
operator: "hello!",
|
||||
operands: [{ type: "capture", name: "c" }],
|
||||
},
|
||||
]);
|
||||
assert.deepEqual(query.predicatesForPattern(2), []);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function formatMatches(matches) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue