rustdoc-search: add search query syntax Fn(T) -> U
This is implemented, in addition to the ML-style one, because Rust does it. If we don't, we'll never hear the end of it. This commit also refactors some duplicate parts of the parser into a dedicated function.
This commit is contained in:
parent
23e931fd07
commit
7b926555b7
6 changed files with 530 additions and 81 deletions
|
@ -153,16 +153,26 @@ will match these queries:
|
||||||
|
|
||||||
But it *does not* match `Result<Vec, u8>` or `Result<u8<Vec>>`.
|
But it *does not* match `Result<Vec, u8>` or `Result<u8<Vec>>`.
|
||||||
|
|
||||||
|
To search for a function that accepts a function as a parameter,
|
||||||
|
like `Iterator::all`, wrap the nested signature in parenthesis,
|
||||||
|
as in [`Iterator<T>, (T -> bool) -> bool`][iterator-all].
|
||||||
|
You can also search for a specific closure trait,
|
||||||
|
such as `Iterator<T>, (FnMut(T) -> bool) -> bool`,
|
||||||
|
but you need to know which one you want.
|
||||||
|
|
||||||
|
[iterator-all]: ../../std/vec/struct.Vec.html?search=Iterator<T>%2C+(T+->+bool)+->+bool&filter-crate=std
|
||||||
|
|
||||||
### Primitives with Special Syntax
|
### Primitives with Special Syntax
|
||||||
|
|
||||||
| Shorthand | Explicit names |
|
| Shorthand | Explicit names |
|
||||||
| --------- | ------------------------------------------------ |
|
| ---------------- | ------------------------------------------------- |
|
||||||
| `[]` | `primitive:slice` and/or `primitive:array` |
|
| `[]` | `primitive:slice` and/or `primitive:array` |
|
||||||
| `[T]` | `primitive:slice<T>` and/or `primitive:array<T>` |
|
| `[T]` | `primitive:slice<T>` and/or `primitive:array<T>` |
|
||||||
| `()` | `primitive:unit` and/or `primitive:tuple` |
|
| `()` | `primitive:unit` and/or `primitive:tuple` |
|
||||||
| `(T)` | `T` |
|
| `(T)` | `T` |
|
||||||
| `(T,)` | `primitive:tuple<T>` |
|
| `(T,)` | `primitive:tuple<T>` |
|
||||||
| `!` | `primitive:never` |
|
| `!` | `primitive:never` |
|
||||||
|
| `(T, U -> V, W)` | `fn(T, U) -> (V, W)`, `Fn`, `FnMut`, and `FnOnce` |
|
||||||
|
|
||||||
When searching for `[]`, Rustdoc will return search results with either slices
|
When searching for `[]`, Rustdoc will return search results with either slices
|
||||||
or arrays. If you know which one you want, you can force it to return results
|
or arrays. If you know which one you want, you can force it to return results
|
||||||
|
@ -182,6 +192,10 @@ results for types that match tuples, even though it also matches the type on
|
||||||
its own. That is, `(u32)` matches `(u32,)` for the exact same reason that it
|
its own. That is, `(u32)` matches `(u32,)` for the exact same reason that it
|
||||||
also matches `Result<u32, Error>`.
|
also matches `Result<u32, Error>`.
|
||||||
|
|
||||||
|
The `->` operator has lower precedence than comma. If it's not wrapped
|
||||||
|
in brackets, it delimits the return value for the function being searched for.
|
||||||
|
To search for functions that take functions as parameters, use parenthesis.
|
||||||
|
|
||||||
### Limitations and quirks of type-based search
|
### Limitations and quirks of type-based search
|
||||||
|
|
||||||
Type-based search is still a buggy, experimental, work-in-progress feature.
|
Type-based search is still a buggy, experimental, work-in-progress feature.
|
||||||
|
@ -220,9 +234,6 @@ Most of these limitations should be addressed in future version of Rustdoc.
|
||||||
|
|
||||||
* Searching for lifetimes is not supported.
|
* Searching for lifetimes is not supported.
|
||||||
|
|
||||||
* It's impossible to search for closures based on their parameters or
|
|
||||||
return values.
|
|
||||||
|
|
||||||
* It's impossible to search based on the length of an array.
|
* It's impossible to search based on the length of an array.
|
||||||
|
|
||||||
## Item filtering
|
## Item filtering
|
||||||
|
@ -239,19 +250,21 @@ Item filters can be used in both name-based and type signature-based searches.
|
||||||
|
|
||||||
```text
|
```text
|
||||||
ident = *(ALPHA / DIGIT / "_")
|
ident = *(ALPHA / DIGIT / "_")
|
||||||
path = ident *(DOUBLE-COLON ident) [!]
|
path = ident *(DOUBLE-COLON ident) [BANG]
|
||||||
slice-like = OPEN-SQUARE-BRACKET [ nonempty-arg-list ] CLOSE-SQUARE-BRACKET
|
slice-like = OPEN-SQUARE-BRACKET [ nonempty-arg-list ] CLOSE-SQUARE-BRACKET
|
||||||
tuple-like = OPEN-PAREN [ nonempty-arg-list ] CLOSE-PAREN
|
tuple-like = OPEN-PAREN [ nonempty-arg-list ] CLOSE-PAREN
|
||||||
arg = [type-filter *WS COLON *WS] (path [generics] / slice-like / tuple-like / [!])
|
arg = [type-filter *WS COLON *WS] (path [generics] / slice-like / tuple-like)
|
||||||
type-sep = COMMA/WS *(COMMA/WS)
|
type-sep = COMMA/WS *(COMMA/WS)
|
||||||
nonempty-arg-list = *(type-sep) arg *(type-sep arg) *(type-sep)
|
nonempty-arg-list = *(type-sep) arg *(type-sep arg) *(type-sep) [ return-args ]
|
||||||
generic-arg-list = *(type-sep) arg [ EQUAL arg ] *(type-sep arg [ EQUAL arg ]) *(type-sep)
|
generic-arg-list = *(type-sep) arg [ EQUAL arg ] *(type-sep arg [ EQUAL arg ]) *(type-sep)
|
||||||
generics = OPEN-ANGLE-BRACKET [ generic-arg-list ] *(type-sep)
|
normal-generics = OPEN-ANGLE-BRACKET [ generic-arg-list ] *(type-sep)
|
||||||
CLOSE-ANGLE-BRACKET
|
CLOSE-ANGLE-BRACKET
|
||||||
|
fn-like-generics = OPEN-PAREN [ nonempty-arg-list ] CLOSE-PAREN [ RETURN-ARROW arg ]
|
||||||
|
generics = normal-generics / fn-like-generics
|
||||||
return-args = RETURN-ARROW *(type-sep) nonempty-arg-list
|
return-args = RETURN-ARROW *(type-sep) nonempty-arg-list
|
||||||
|
|
||||||
exact-search = [type-filter *WS COLON] [ RETURN-ARROW ] *WS QUOTE ident QUOTE [ generics ]
|
exact-search = [type-filter *WS COLON] [ RETURN-ARROW ] *WS QUOTE ident QUOTE [ generics ]
|
||||||
type-search = [ nonempty-arg-list ] [ return-args ]
|
type-search = [ nonempty-arg-list ]
|
||||||
|
|
||||||
query = *WS (exact-search / type-search) *WS
|
query = *WS (exact-search / type-search) *WS
|
||||||
|
|
||||||
|
@ -296,6 +309,7 @@ QUOTE = %x22
|
||||||
COMMA = ","
|
COMMA = ","
|
||||||
RETURN-ARROW = "->"
|
RETURN-ARROW = "->"
|
||||||
EQUAL = "="
|
EQUAL = "="
|
||||||
|
BANG = "!"
|
||||||
|
|
||||||
ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
|
ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
|
||||||
DIGIT = %x30-39
|
DIGIT = %x30-39
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// ignore-tidy-filelength
|
||||||
/* global addClass, getNakedUrl, getSettingValue */
|
/* global addClass, getNakedUrl, getSettingValue */
|
||||||
/* global onEachLazy, removeClass, searchState, browserSupportsHistoryApi, exports */
|
/* global onEachLazy, removeClass, searchState, browserSupportsHistoryApi, exports */
|
||||||
|
|
||||||
|
@ -578,7 +579,10 @@ function initSearch(rawSearchIndex) {
|
||||||
// Syntactically, bindings are parsed as generics,
|
// Syntactically, bindings are parsed as generics,
|
||||||
// but the query engine treats them differently.
|
// but the query engine treats them differently.
|
||||||
if (gen.bindingName !== null) {
|
if (gen.bindingName !== null) {
|
||||||
bindings.set(gen.bindingName.name, [gen, ...gen.bindingName.generics]);
|
if (gen.name !== null) {
|
||||||
|
gen.bindingName.generics.unshift(gen);
|
||||||
|
}
|
||||||
|
bindings.set(gen.bindingName.name, gen.bindingName.generics);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -678,6 +682,38 @@ function initSearch(rawSearchIndex) {
|
||||||
return end;
|
return end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getFilteredNextElem(query, parserState, elems, isInGenerics) {
|
||||||
|
const start = parserState.pos;
|
||||||
|
if (parserState.userQuery[parserState.pos] === ":" && !isPathStart(parserState)) {
|
||||||
|
throw ["Expected type filter before ", ":"];
|
||||||
|
}
|
||||||
|
getNextElem(query, parserState, elems, isInGenerics);
|
||||||
|
if (parserState.userQuery[parserState.pos] === ":" && !isPathStart(parserState)) {
|
||||||
|
if (parserState.typeFilter !== null) {
|
||||||
|
throw [
|
||||||
|
"Unexpected ",
|
||||||
|
":",
|
||||||
|
" (expected path after type filter ",
|
||||||
|
parserState.typeFilter + ":",
|
||||||
|
")",
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (elems.length === 0) {
|
||||||
|
throw ["Expected type filter before ", ":"];
|
||||||
|
} else if (query.literalSearch) {
|
||||||
|
throw ["Cannot use quotes on type filter"];
|
||||||
|
}
|
||||||
|
// The type filter doesn't count as an element since it's a modifier.
|
||||||
|
const typeFilterElem = elems.pop();
|
||||||
|
checkExtraTypeFilterCharacters(start, parserState);
|
||||||
|
parserState.typeFilter = typeFilterElem.name;
|
||||||
|
parserState.pos += 1;
|
||||||
|
parserState.totalElems -= 1;
|
||||||
|
query.literalSearch = false;
|
||||||
|
getNextElem(query, parserState, elems, isInGenerics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {ParsedQuery} query
|
* @param {ParsedQuery} query
|
||||||
* @param {ParserState} parserState
|
* @param {ParserState} parserState
|
||||||
|
@ -752,6 +788,32 @@ function initSearch(rawSearchIndex) {
|
||||||
}
|
}
|
||||||
parserState.pos += 1;
|
parserState.pos += 1;
|
||||||
getItemsBefore(query, parserState, generics, ">");
|
getItemsBefore(query, parserState, generics, ">");
|
||||||
|
} else if (parserState.pos < parserState.length &&
|
||||||
|
parserState.userQuery[parserState.pos] === "("
|
||||||
|
) {
|
||||||
|
if (start >= end) {
|
||||||
|
throw ["Found generics without a path"];
|
||||||
|
}
|
||||||
|
if (parserState.isInBinding) {
|
||||||
|
throw ["Unexpected ", "(", " after ", "="];
|
||||||
|
}
|
||||||
|
parserState.pos += 1;
|
||||||
|
const typeFilter = parserState.typeFilter;
|
||||||
|
parserState.typeFilter = null;
|
||||||
|
getItemsBefore(query, parserState, generics, ")");
|
||||||
|
skipWhitespace(parserState);
|
||||||
|
if (isReturnArrow(parserState)) {
|
||||||
|
parserState.pos += 2;
|
||||||
|
skipWhitespace(parserState);
|
||||||
|
getFilteredNextElem(query, parserState, generics, isInGenerics);
|
||||||
|
generics[generics.length - 1].bindingName = makePrimitiveElement("output");
|
||||||
|
} else {
|
||||||
|
generics.push(makePrimitiveElement(null, {
|
||||||
|
bindingName: makePrimitiveElement("output"),
|
||||||
|
typeFilter: null,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
parserState.typeFilter = typeFilter;
|
||||||
}
|
}
|
||||||
if (isStringElem) {
|
if (isStringElem) {
|
||||||
skipWhitespace(parserState);
|
skipWhitespace(parserState);
|
||||||
|
@ -811,7 +873,6 @@ function initSearch(rawSearchIndex) {
|
||||||
function getItemsBefore(query, parserState, elems, endChar) {
|
function getItemsBefore(query, parserState, elems, endChar) {
|
||||||
let foundStopChar = true;
|
let foundStopChar = true;
|
||||||
let foundSeparator = false;
|
let foundSeparator = false;
|
||||||
let start = parserState.pos;
|
|
||||||
|
|
||||||
// If this is a generic, keep the outer item's type filter around.
|
// If this is a generic, keep the outer item's type filter around.
|
||||||
const oldTypeFilter = parserState.typeFilter;
|
const oldTypeFilter = parserState.typeFilter;
|
||||||
|
@ -874,24 +935,6 @@ function initSearch(rawSearchIndex) {
|
||||||
continue;
|
continue;
|
||||||
} else if (c === ":" && isPathStart(parserState)) {
|
} else if (c === ":" && isPathStart(parserState)) {
|
||||||
throw ["Unexpected ", "::", ": paths cannot start with ", "::"];
|
throw ["Unexpected ", "::", ": paths cannot start with ", "::"];
|
||||||
} else if (c === ":") {
|
|
||||||
if (parserState.typeFilter !== null) {
|
|
||||||
throw ["Unexpected ", ":"];
|
|
||||||
}
|
|
||||||
if (elems.length === 0) {
|
|
||||||
throw ["Expected type filter before ", ":"];
|
|
||||||
} else if (query.literalSearch) {
|
|
||||||
throw ["Cannot use quotes on type filter"];
|
|
||||||
}
|
|
||||||
// The type filter doesn't count as an element since it's a modifier.
|
|
||||||
const typeFilterElem = elems.pop();
|
|
||||||
checkExtraTypeFilterCharacters(start, parserState);
|
|
||||||
parserState.typeFilter = typeFilterElem.name;
|
|
||||||
parserState.pos += 1;
|
|
||||||
parserState.totalElems -= 1;
|
|
||||||
query.literalSearch = false;
|
|
||||||
foundStopChar = true;
|
|
||||||
continue;
|
|
||||||
} else if (isEndCharacter(c)) {
|
} else if (isEndCharacter(c)) {
|
||||||
throw ["Unexpected ", c, " after ", extra];
|
throw ["Unexpected ", c, " after ", extra];
|
||||||
}
|
}
|
||||||
|
@ -926,8 +969,7 @@ function initSearch(rawSearchIndex) {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
const posBefore = parserState.pos;
|
const posBefore = parserState.pos;
|
||||||
start = parserState.pos;
|
getFilteredNextElem(query, parserState, elems, endChar !== "");
|
||||||
getNextElem(query, parserState, elems, endChar !== "");
|
|
||||||
if (endChar !== "" && parserState.pos >= parserState.length) {
|
if (endChar !== "" && parserState.pos >= parserState.length) {
|
||||||
throw ["Unclosed ", extra];
|
throw ["Unclosed ", extra];
|
||||||
}
|
}
|
||||||
|
@ -1004,7 +1046,6 @@ function initSearch(rawSearchIndex) {
|
||||||
*/
|
*/
|
||||||
function parseInput(query, parserState) {
|
function parseInput(query, parserState) {
|
||||||
let foundStopChar = true;
|
let foundStopChar = true;
|
||||||
let start = parserState.pos;
|
|
||||||
|
|
||||||
while (parserState.pos < parserState.length) {
|
while (parserState.pos < parserState.length) {
|
||||||
const c = parserState.userQuery[parserState.pos];
|
const c = parserState.userQuery[parserState.pos];
|
||||||
|
@ -1022,29 +1063,6 @@ function initSearch(rawSearchIndex) {
|
||||||
throw ["Unexpected ", c, " after ", parserState.userQuery[parserState.pos - 1]];
|
throw ["Unexpected ", c, " after ", parserState.userQuery[parserState.pos - 1]];
|
||||||
}
|
}
|
||||||
throw ["Unexpected ", c];
|
throw ["Unexpected ", c];
|
||||||
} else if (c === ":" && !isPathStart(parserState)) {
|
|
||||||
if (parserState.typeFilter !== null) {
|
|
||||||
throw [
|
|
||||||
"Unexpected ",
|
|
||||||
":",
|
|
||||||
" (expected path after type filter ",
|
|
||||||
parserState.typeFilter + ":",
|
|
||||||
")",
|
|
||||||
];
|
|
||||||
} else if (query.elems.length === 0) {
|
|
||||||
throw ["Expected type filter before ", ":"];
|
|
||||||
} else if (query.literalSearch) {
|
|
||||||
throw ["Cannot use quotes on type filter"];
|
|
||||||
}
|
|
||||||
// The type filter doesn't count as an element since it's a modifier.
|
|
||||||
const typeFilterElem = query.elems.pop();
|
|
||||||
checkExtraTypeFilterCharacters(start, parserState);
|
|
||||||
parserState.typeFilter = typeFilterElem.name;
|
|
||||||
parserState.pos += 1;
|
|
||||||
parserState.totalElems -= 1;
|
|
||||||
query.literalSearch = false;
|
|
||||||
foundStopChar = true;
|
|
||||||
continue;
|
|
||||||
} else if (c === " ") {
|
} else if (c === " ") {
|
||||||
skipWhitespace(parserState);
|
skipWhitespace(parserState);
|
||||||
continue;
|
continue;
|
||||||
|
@ -1080,8 +1098,7 @@ function initSearch(rawSearchIndex) {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
const before = query.elems.length;
|
const before = query.elems.length;
|
||||||
start = parserState.pos;
|
getFilteredNextElem(query, parserState, query.elems, false);
|
||||||
getNextElem(query, parserState, query.elems, false);
|
|
||||||
if (query.elems.length === before) {
|
if (query.elems.length === before) {
|
||||||
// Nothing was added, weird... Let's increase the position to not remain stuck.
|
// Nothing was added, weird... Let's increase the position to not remain stuck.
|
||||||
parserState.pos += 1;
|
parserState.pos += 1;
|
||||||
|
|
|
@ -195,7 +195,7 @@ const PARSED = [
|
||||||
original: "a (b:",
|
original: "a (b:",
|
||||||
returned: [],
|
returned: [],
|
||||||
userQuery: "a (b:",
|
userQuery: "a (b:",
|
||||||
error: "Expected `,`, `:` or `->`, found `(`",
|
error: "Unclosed `(`",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
query: "_:",
|
query: "_:",
|
||||||
|
@ -357,7 +357,16 @@ const PARSED = [
|
||||||
original: "a,:",
|
original: "a,:",
|
||||||
returned: [],
|
returned: [],
|
||||||
userQuery: "a,:",
|
userQuery: "a,:",
|
||||||
error: 'Unexpected `,` in type filter (before `:`)',
|
error: 'Expected type filter before `:`',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: "a!:",
|
||||||
|
elems: [],
|
||||||
|
foundElems: 0,
|
||||||
|
original: "a!:",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "a!:",
|
||||||
|
error: 'Unexpected `!` in type filter (before `:`)',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
query: " a<> :",
|
query: " a<> :",
|
||||||
|
@ -366,7 +375,7 @@ const PARSED = [
|
||||||
original: "a<> :",
|
original: "a<> :",
|
||||||
returned: [],
|
returned: [],
|
||||||
userQuery: "a<> :",
|
userQuery: "a<> :",
|
||||||
error: 'Unexpected `<` in type filter (before `:`)',
|
error: 'Expected `,`, `:` or `->` after `>`, found `:`',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
query: "mod : :",
|
query: "mod : :",
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
const PARSED = [
|
const PARSED = [
|
||||||
|
// ML-style HOF
|
||||||
{
|
{
|
||||||
query: "(-> F<P>)",
|
query: "(-> F<P>)",
|
||||||
elems: [{
|
elems: [{
|
||||||
|
@ -373,4 +374,339 @@ const PARSED = [
|
||||||
userQuery: "x, trait:(aaaaa, b -> a)",
|
userQuery: "x, trait:(aaaaa, b -> a)",
|
||||||
error: null,
|
error: null,
|
||||||
},
|
},
|
||||||
|
// Rust-style HOF
|
||||||
|
{
|
||||||
|
query: "Fn () -> F<P>",
|
||||||
|
elems: [{
|
||||||
|
name: "fn",
|
||||||
|
fullPath: ["fn"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "fn",
|
||||||
|
generics: [],
|
||||||
|
bindings: [
|
||||||
|
[
|
||||||
|
"output",
|
||||||
|
[{
|
||||||
|
name: "f",
|
||||||
|
fullPath: ["f"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "f",
|
||||||
|
generics: [
|
||||||
|
{
|
||||||
|
name: "p",
|
||||||
|
fullPath: ["p"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "p",
|
||||||
|
generics: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
typeFilter: -1,
|
||||||
|
}],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
typeFilter: -1,
|
||||||
|
}],
|
||||||
|
foundElems: 1,
|
||||||
|
original: "Fn () -> F<P>",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "fn () -> f<p>",
|
||||||
|
error: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: "FnMut() -> P",
|
||||||
|
elems: [{
|
||||||
|
name: "fnmut",
|
||||||
|
fullPath: ["fnmut"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "fnmut",
|
||||||
|
generics: [],
|
||||||
|
bindings: [
|
||||||
|
[
|
||||||
|
"output",
|
||||||
|
[{
|
||||||
|
name: "p",
|
||||||
|
fullPath: ["p"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "p",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: -1,
|
||||||
|
}],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
typeFilter: -1,
|
||||||
|
}],
|
||||||
|
foundElems: 1,
|
||||||
|
original: "FnMut() -> P",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "fnmut() -> p",
|
||||||
|
error: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: "(FnMut() -> P)",
|
||||||
|
elems: [{
|
||||||
|
name: "fnmut",
|
||||||
|
fullPath: ["fnmut"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "fnmut",
|
||||||
|
generics: [],
|
||||||
|
bindings: [
|
||||||
|
[
|
||||||
|
"output",
|
||||||
|
[{
|
||||||
|
name: "p",
|
||||||
|
fullPath: ["p"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "p",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: -1,
|
||||||
|
}],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
typeFilter: -1,
|
||||||
|
}],
|
||||||
|
foundElems: 1,
|
||||||
|
original: "(FnMut() -> P)",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "(fnmut() -> p)",
|
||||||
|
error: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: "Fn(F<P>)",
|
||||||
|
elems: [{
|
||||||
|
name: "fn",
|
||||||
|
fullPath: ["fn"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "fn",
|
||||||
|
generics: [{
|
||||||
|
name: "f",
|
||||||
|
fullPath: ["f"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "f",
|
||||||
|
generics: [
|
||||||
|
{
|
||||||
|
name: "p",
|
||||||
|
fullPath: ["p"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "p",
|
||||||
|
generics: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
typeFilter: -1,
|
||||||
|
}],
|
||||||
|
bindings: [
|
||||||
|
[
|
||||||
|
"output",
|
||||||
|
[],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
typeFilter: -1,
|
||||||
|
}],
|
||||||
|
foundElems: 1,
|
||||||
|
original: "Fn(F<P>)",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "fn(f<p>)",
|
||||||
|
error: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: "primitive:fnonce(aaaaa, b) -> a",
|
||||||
|
elems: [{
|
||||||
|
name: "fnonce",
|
||||||
|
fullPath: ["fnonce"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "fnonce",
|
||||||
|
generics: [
|
||||||
|
{
|
||||||
|
name: "aaaaa",
|
||||||
|
fullPath: ["aaaaa"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "aaaaa",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "b",
|
||||||
|
fullPath: ["b"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "b",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: -1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
bindings: [
|
||||||
|
[
|
||||||
|
"output",
|
||||||
|
[{
|
||||||
|
name: "a",
|
||||||
|
fullPath: ["a"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "a",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: -1,
|
||||||
|
}],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
typeFilter: 1,
|
||||||
|
}],
|
||||||
|
foundElems: 1,
|
||||||
|
original: "primitive:fnonce(aaaaa, b) -> a",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "primitive:fnonce(aaaaa, b) -> a",
|
||||||
|
error: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: "primitive:fnonce(aaaaa, keyword:b) -> trait:a",
|
||||||
|
elems: [{
|
||||||
|
name: "fnonce",
|
||||||
|
fullPath: ["fnonce"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "fnonce",
|
||||||
|
generics: [
|
||||||
|
{
|
||||||
|
name: "aaaaa",
|
||||||
|
fullPath: ["aaaaa"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "aaaaa",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "b",
|
||||||
|
fullPath: ["b"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "b",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
bindings: [
|
||||||
|
[
|
||||||
|
"output",
|
||||||
|
[{
|
||||||
|
name: "a",
|
||||||
|
fullPath: ["a"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "a",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: 10,
|
||||||
|
}],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
typeFilter: 1,
|
||||||
|
}],
|
||||||
|
foundElems: 1,
|
||||||
|
original: "primitive:fnonce(aaaaa, keyword:b) -> trait:a",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "primitive:fnonce(aaaaa, keyword:b) -> trait:a",
|
||||||
|
error: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: "x, trait:fn(aaaaa, b -> a)",
|
||||||
|
elems: [
|
||||||
|
{
|
||||||
|
name: "x",
|
||||||
|
fullPath: ["x"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "x",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "fn",
|
||||||
|
fullPath: ["fn"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "fn",
|
||||||
|
generics: [
|
||||||
|
{
|
||||||
|
name: "->",
|
||||||
|
fullPath: ["->"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "->",
|
||||||
|
generics: [
|
||||||
|
{
|
||||||
|
name: "aaaaa",
|
||||||
|
fullPath: ["aaaaa"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "aaaaa",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "b",
|
||||||
|
fullPath: ["b"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "b",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: -1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
bindings: [
|
||||||
|
[
|
||||||
|
"output",
|
||||||
|
[{
|
||||||
|
name: "a",
|
||||||
|
fullPath: ["a"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "a",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: -1,
|
||||||
|
}],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
typeFilter: -1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
bindings: [
|
||||||
|
[
|
||||||
|
"output",
|
||||||
|
[],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
typeFilter: 10,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
foundElems: 2,
|
||||||
|
original: "x, trait:fn(aaaaa, b -> a)",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "x, trait:fn(aaaaa, b -> a)",
|
||||||
|
error: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: 'a,b(c)',
|
||||||
|
elems: [
|
||||||
|
{
|
||||||
|
name: "a",
|
||||||
|
fullPath: ["a"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "a",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "b",
|
||||||
|
fullPath: ["b"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "b",
|
||||||
|
generics: [{
|
||||||
|
name: "c",
|
||||||
|
fullPath: ["c"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "c",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: -1,
|
||||||
|
}],
|
||||||
|
bindings: [
|
||||||
|
[
|
||||||
|
"output",
|
||||||
|
[],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
typeFilter: -1,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
foundElems: 2,
|
||||||
|
original: "a,b(c)",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "a,b(c)",
|
||||||
|
error: null,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
|
@ -37,15 +37,6 @@ const PARSED = [
|
||||||
userQuery: "a b",
|
userQuery: "a b",
|
||||||
error: null,
|
error: null,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
query: 'a,b(c)',
|
|
||||||
elems: [],
|
|
||||||
foundElems: 0,
|
|
||||||
original: "a,b(c)",
|
|
||||||
returned: [],
|
|
||||||
userQuery: "a,b(c)",
|
|
||||||
error: "Expected `,`, `:` or `->`, found `(`",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
query: 'aaa,a',
|
query: 'aaa,a',
|
||||||
elems: [
|
elems: [
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
// exact-check
|
// exact-check
|
||||||
|
|
||||||
const EXPECTED = [
|
const EXPECTED = [
|
||||||
|
// not a HOF query
|
||||||
|
{
|
||||||
|
'query': 'u32 -> !',
|
||||||
|
'others': [],
|
||||||
|
},
|
||||||
|
|
||||||
// ML-style higher-order function notation
|
// ML-style higher-order function notation
|
||||||
{
|
{
|
||||||
'query': 'bool, (u32 -> !) -> ()',
|
'query': 'bool, (u32 -> !) -> ()',
|
||||||
|
@ -53,11 +59,6 @@ const EXPECTED = [
|
||||||
{"path": "hof", "name": "fn_once"},
|
{"path": "hof", "name": "fn_once"},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
'query': 'u32 -> !',
|
|
||||||
// not a HOF query
|
|
||||||
'others': [],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
'query': '(str, str -> i8) -> ()',
|
'query': '(str, str -> i8) -> ()',
|
||||||
'others': [
|
'others': [
|
||||||
|
@ -91,4 +92,85 @@ const EXPECTED = [
|
||||||
// params and return are not the same
|
// params and return are not the same
|
||||||
'others': [],
|
'others': [],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Rust-style higher-order function notation
|
||||||
|
{
|
||||||
|
'query': 'bool, fn(u32) -> ! -> ()',
|
||||||
|
'others': [
|
||||||
|
{"path": "hof", "name": "fn_ptr"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': 'u8, fnonce(u32) -> ! -> ()',
|
||||||
|
'others': [
|
||||||
|
{"path": "hof", "name": "fn_once"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': 'u8, fn(u32) -> ! -> ()',
|
||||||
|
// fnonce != fn
|
||||||
|
'others': [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': 'i8, fnmut(u32) -> ! -> ()',
|
||||||
|
'others': [
|
||||||
|
{"path": "hof", "name": "fn_mut"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': 'i8, fn(u32) -> ! -> ()',
|
||||||
|
// fnmut != fn
|
||||||
|
'others': [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': 'char, fn(u32) -> ! -> ()',
|
||||||
|
'others': [
|
||||||
|
{"path": "hof", "name": "fn_"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': 'char, fnmut(u32) -> ! -> ()',
|
||||||
|
// fn != fnmut
|
||||||
|
'others': [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': 'fn(first<u32>) -> ! -> ()',
|
||||||
|
'others': [
|
||||||
|
{"path": "hof", "name": "fn_ptr"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': 'fnonce(second<u32>) -> ! -> ()',
|
||||||
|
'others': [
|
||||||
|
{"path": "hof", "name": "fn_once"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': 'fnmut(third<u32>) -> ! -> ()',
|
||||||
|
'others': [
|
||||||
|
{"path": "hof", "name": "fn_mut"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': 'fn(u32) -> ! -> ()',
|
||||||
|
'others': [
|
||||||
|
// fn matches primitive:fn and trait:Fn
|
||||||
|
{"path": "hof", "name": "fn_"},
|
||||||
|
{"path": "hof", "name": "fn_ptr"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': 'trait:fn(u32) -> ! -> ()',
|
||||||
|
'others': [
|
||||||
|
// fn matches primitive:fn and trait:Fn
|
||||||
|
{"path": "hof", "name": "fn_"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': 'primitive:fn(u32) -> ! -> ()',
|
||||||
|
'others': [
|
||||||
|
// fn matches primitive:fn and trait:Fn
|
||||||
|
{"path": "hof", "name": "fn_ptr"},
|
||||||
|
],
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue