mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-16 21:15:18 +03:00
Auto merge of #96263 - Dylan-DPC:rollup-0eofl13, r=Dylan-DPC
Rollup of 5 pull requests Successful merges: - #90630 (Create real parser for search queries) - #96193 ([fuchsia] Add implementation for `current_exe`) - #96196 (Remove assertion that all paths in `ShouldRun` exist) - #96228 (Fix locations for intrinsics impls and change to links) - #96236 (Add an explicit `Span` field to `OutlivesConstraint`) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
@@ -156,6 +156,7 @@ fn next(&mut self) -> Option<Self::Item> {
|
||||
sup: self.static_region,
|
||||
sub: next_static_idx.into(),
|
||||
locations: Locations::All(DUMMY_SP),
|
||||
span: DUMMY_SP,
|
||||
category: ConstraintCategory::Internal,
|
||||
variance_info: VarianceDiagInfo::default(),
|
||||
})
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_middle::mir::ConstraintCategory;
|
||||
use rustc_middle::ty::{RegionVid, VarianceDiagInfo};
|
||||
use rustc_span::Span;
|
||||
use std::fmt;
|
||||
use std::ops::Index;
|
||||
|
||||
@@ -87,6 +88,12 @@ pub struct OutlivesConstraint<'tcx> {
|
||||
/// Where did this constraint arise?
|
||||
pub locations: Locations,
|
||||
|
||||
/// The `Span` associated with the creation of this constraint.
|
||||
/// This should be used in preference to obtaining the span from
|
||||
/// `locations`, since the `locations` may give a poor span
|
||||
/// in some cases (e.g. converting a constraint from a promoted).
|
||||
pub span: Span,
|
||||
|
||||
/// What caused this constraint?
|
||||
pub category: ConstraintCategory,
|
||||
|
||||
|
||||
@@ -74,14 +74,18 @@ fn for_each_constraint(
|
||||
let mut constraints: Vec<_> = self.constraints.outlives().iter().collect();
|
||||
constraints.sort_by_key(|c| (c.sup, c.sub));
|
||||
for constraint in &constraints {
|
||||
let OutlivesConstraint { sup, sub, locations, category, variance_info: _ } = constraint;
|
||||
let OutlivesConstraint { sup, sub, locations, category, span, variance_info: _ } =
|
||||
constraint;
|
||||
let (name, arg) = match locations {
|
||||
Locations::All(span) => {
|
||||
("All", tcx.sess.source_map().span_to_embeddable_string(*span))
|
||||
}
|
||||
Locations::Single(loc) => ("Single", format!("{:?}", loc)),
|
||||
};
|
||||
with_msg(&format!("{:?}: {:?} due to {:?} at {}({})", sup, sub, category, name, arg))?;
|
||||
with_msg(&format!(
|
||||
"{:?}: {:?} due to {:?} at {}({}) ({:?}",
|
||||
sup, sub, category, name, arg, span
|
||||
))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1733,7 +1733,7 @@ fn check_member_constraints(
|
||||
|
||||
crate fn retrieve_closure_constraint_info(
|
||||
&self,
|
||||
body: &Body<'tcx>,
|
||||
_body: &Body<'tcx>,
|
||||
constraint: &OutlivesConstraint<'tcx>,
|
||||
) -> BlameConstraint<'tcx> {
|
||||
let loc = match constraint.locations {
|
||||
@@ -1760,7 +1760,7 @@ fn check_member_constraints(
|
||||
.unwrap_or(BlameConstraint {
|
||||
category: constraint.category,
|
||||
from_closure: false,
|
||||
cause: ObligationCause::dummy_with_span(body.source_info(loc).span),
|
||||
cause: ObligationCause::dummy_with_span(constraint.span),
|
||||
variance_info: constraint.variance_info,
|
||||
})
|
||||
}
|
||||
@@ -1869,6 +1869,7 @@ fn check_member_constraints(
|
||||
sup: r,
|
||||
sub: constraint.min_choice,
|
||||
locations: Locations::All(p_c.definition_span),
|
||||
span: p_c.definition_span,
|
||||
category: ConstraintCategory::OpaqueType,
|
||||
variance_info: ty::VarianceDiagInfo::default(),
|
||||
};
|
||||
@@ -2017,7 +2018,7 @@ fn check_member_constraints(
|
||||
category: constraint.category,
|
||||
from_closure: false,
|
||||
cause: ObligationCause::new(
|
||||
constraint.locations.span(body),
|
||||
constraint.span,
|
||||
CRATE_HIR_ID,
|
||||
cause_code.clone(),
|
||||
),
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
use rustc_middle::ty::TypeFoldable;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
use crate::{
|
||||
constraints::OutlivesConstraint,
|
||||
@@ -26,6 +26,7 @@
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
locations: Locations,
|
||||
span: Span,
|
||||
category: ConstraintCategory,
|
||||
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
|
||||
}
|
||||
@@ -38,6 +39,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
locations: Locations,
|
||||
span: Span,
|
||||
category: ConstraintCategory,
|
||||
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
|
||||
) -> Self {
|
||||
@@ -49,6 +51,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
||||
implicit_region_bound,
|
||||
param_env,
|
||||
locations,
|
||||
span,
|
||||
category,
|
||||
constraints,
|
||||
}
|
||||
@@ -153,6 +156,7 @@ fn add_outlives(&mut self, sup: ty::RegionVid, sub: ty::RegionVid) {
|
||||
self.constraints.outlives_constraints.push(OutlivesConstraint {
|
||||
locations: self.locations,
|
||||
category: self.category,
|
||||
span: self.span,
|
||||
sub,
|
||||
sup,
|
||||
variance_info: ty::VarianceDiagInfo::default(),
|
||||
|
||||
@@ -316,6 +316,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
self.implicit_region_bound,
|
||||
self.param_env,
|
||||
Locations::All(DUMMY_SP),
|
||||
DUMMY_SP,
|
||||
ConstraintCategory::Internal,
|
||||
&mut self.constraints,
|
||||
)
|
||||
|
||||
@@ -235,6 +235,7 @@ pub(crate) fn normalize_and_add_constraints(&mut self, t: Ty<'tcx>) -> Fallible<
|
||||
Some(self.implicit_region_bound),
|
||||
self.param_env,
|
||||
Locations::All(DUMMY_SP),
|
||||
DUMMY_SP,
|
||||
ConstraintCategory::Internal,
|
||||
&mut self.borrowck_context.constraints,
|
||||
)
|
||||
|
||||
@@ -1141,6 +1141,7 @@ fn push_region_constraints(
|
||||
Some(self.implicit_region_bound),
|
||||
self.param_env,
|
||||
locations,
|
||||
locations.span(self.body),
|
||||
category,
|
||||
&mut self.borrowck_context.constraints,
|
||||
)
|
||||
@@ -2401,6 +2402,7 @@ fn add_reborrow_constraint(
|
||||
sup: ref_region.to_region_vid(),
|
||||
sub: borrow_region.to_region_vid(),
|
||||
locations: location.to_locations(),
|
||||
span: location.to_locations().span(body),
|
||||
category,
|
||||
variance_info: ty::VarianceDiagInfo::default(),
|
||||
});
|
||||
|
||||
@@ -116,6 +116,7 @@ fn push_outlives(
|
||||
sup,
|
||||
sub,
|
||||
locations: self.locations,
|
||||
span: self.locations.span(self.type_checker.body),
|
||||
category: self.category,
|
||||
variance_info: info,
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Compiler intrinsics.
|
||||
//!
|
||||
//! The corresponding definitions are in `compiler/rustc_codegen_llvm/src/intrinsic.rs`.
|
||||
//! The corresponding const implementations are in `compiler/rustc_mir/src/interpret/intrinsics.rs`
|
||||
//! The corresponding definitions are in <https://github.com/rust-lang/rust/blob/master/compiler/rustc_codegen_llvm/src/intrinsic.rs>.
|
||||
//! The corresponding const implementations are in <https://github.com/rust-lang/rust/blob/master/compiler/rustc_const_eval/src/interpret/intrinsics.rs>.
|
||||
//!
|
||||
//! # Const intrinsics
|
||||
//!
|
||||
@@ -10,8 +10,8 @@
|
||||
//!
|
||||
//! In order to make an intrinsic usable at compile-time, one needs to copy the implementation
|
||||
//! from <https://github.com/rust-lang/miri/blob/master/src/shims/intrinsics.rs> to
|
||||
//! `compiler/rustc_mir/src/interpret/intrinsics.rs` and add a
|
||||
//! `#[rustc_const_unstable(feature = "foo", issue = "01234")]` to the intrinsic.
|
||||
//! <https://github.com/rust-lang/rust/blob/master/compiler/rustc_const_eval/src/interpret/intrinsics.rs> and add a
|
||||
//! `#[rustc_const_unstable(feature = "const_such_and_such", issue = "01234")]` to the intrinsic declaration.
|
||||
//!
|
||||
//! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute,
|
||||
//! the intrinsic's attribute must be `rustc_const_stable`, too. Such a change should not be done
|
||||
|
||||
@@ -427,7 +427,7 @@ pub fn current_exe() -> io::Result<PathBuf> {
|
||||
crate::fs::read_to_string("sys:exe").map(PathBuf::from)
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "fuchsia", target_os = "l4re"))]
|
||||
#[cfg(target_os = "l4re")]
|
||||
pub fn current_exe() -> io::Result<PathBuf> {
|
||||
use crate::io::ErrorKind;
|
||||
Err(io::const_io_error!(ErrorKind::Unsupported, "Not yet implemented!"))
|
||||
@@ -451,6 +451,26 @@ pub fn current_exe() -> io::Result<PathBuf> {
|
||||
super::unsupported::unsupported()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "fuchsia")]
|
||||
pub fn current_exe() -> io::Result<PathBuf> {
|
||||
use crate::io::ErrorKind;
|
||||
|
||||
#[cfg(test)]
|
||||
use realstd::env;
|
||||
|
||||
#[cfg(not(test))]
|
||||
use crate::env;
|
||||
|
||||
let exe_path = env::args().next().ok_or(io::const_io_error!(
|
||||
ErrorKind::Uncategorized,
|
||||
"an executable path was not found because no arguments were provided through argv"
|
||||
))?;
|
||||
let path = PathBuf::from(exe_path);
|
||||
|
||||
// Prepend the current working directory to the path if it's not absolute.
|
||||
if !path.is_absolute() { getcwd().map(|cwd| cwd.join(path)) } else { Ok(path) }
|
||||
}
|
||||
|
||||
pub struct Env {
|
||||
iter: vec::IntoIter<(OsString, OsString)>,
|
||||
}
|
||||
|
||||
@@ -388,11 +388,13 @@ pub fn paths(mut self, paths: &[&str]) -> Self {
|
||||
paths
|
||||
.iter()
|
||||
.map(|p| {
|
||||
assert!(
|
||||
self.builder.src.join(p).exists(),
|
||||
"`should_run.paths` should correspond to real on-disk paths - use `alias` if there is no relevant path: {}",
|
||||
p
|
||||
);
|
||||
// FIXME(#96188): make sure this is actually a path.
|
||||
// This currently breaks for paths within submodules.
|
||||
//assert!(
|
||||
// self.builder.src.join(p).exists(),
|
||||
// "`should_run.paths` should correspond to real on-disk paths - use `alias` if there is no relevant path: {}",
|
||||
// p
|
||||
//);
|
||||
TaskPath { path: p.into(), kind: Some(self.kind) }
|
||||
})
|
||||
.collect(),
|
||||
|
||||
@@ -8,10 +8,34 @@ function initSearch(searchIndex){}
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* raw: string,
|
||||
* query: string,
|
||||
* type: string,
|
||||
* id: string,
|
||||
* name: string,
|
||||
* fullPath: Array<string>,
|
||||
* pathWithoutLast: Array<string>,
|
||||
* pathLast: string,
|
||||
* generics: Array<QueryElement>,
|
||||
* }}
|
||||
*/
|
||||
var QueryElement;
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* pos: number,
|
||||
* totalElems: number,
|
||||
* typeFilter: (null|string),
|
||||
* userQuery: string,
|
||||
* }}
|
||||
*/
|
||||
var ParserState;
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* original: string,
|
||||
* userQuery: string,
|
||||
* typeFilter: number,
|
||||
* elems: Array<QueryElement>,
|
||||
* args: Array<QueryElement>,
|
||||
* returned: Array<QueryElement>,
|
||||
* foundElems: number,
|
||||
* }}
|
||||
*/
|
||||
var ParsedQuery;
|
||||
@@ -30,3 +54,30 @@ var ParsedQuery;
|
||||
* }}
|
||||
*/
|
||||
var Row;
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* in_args: Array<Object>,
|
||||
* returned: Array<Object>,
|
||||
* others: Array<Object>,
|
||||
* query: ParsedQuery,
|
||||
* }}
|
||||
*/
|
||||
var ResultsTable;
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* desc: string,
|
||||
* displayPath: string,
|
||||
* fullPath: string,
|
||||
* href: string,
|
||||
* id: number,
|
||||
* lev: number,
|
||||
* name: string,
|
||||
* normalizedName: string,
|
||||
* parent: (Object|undefined),
|
||||
* path: string,
|
||||
* ty: number,
|
||||
* }}
|
||||
*/
|
||||
var Results;
|
||||
|
||||
@@ -61,15 +61,6 @@ function printTab(nb) {
|
||||
});
|
||||
}
|
||||
|
||||
function removeEmptyStringsFromArray(x) {
|
||||
for (var i = 0, len = x.length; i < len; ++i) {
|
||||
if (x[i] === "") {
|
||||
x.splice(i, 1);
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A function to compute the Levenshtein distance between two strings
|
||||
* Licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported
|
||||
@@ -133,11 +124,436 @@ window.initSearch = function(rawSearchIndex) {
|
||||
searchState.input.value = params.search || "";
|
||||
}
|
||||
|
||||
function isWhitespace(c) {
|
||||
return " \t\n\r".indexOf(c) !== -1;
|
||||
}
|
||||
|
||||
function isSpecialStartCharacter(c) {
|
||||
return "<\"".indexOf(c) !== -1;
|
||||
}
|
||||
|
||||
function isEndCharacter(c) {
|
||||
return ",>-".indexOf(c) !== -1;
|
||||
}
|
||||
|
||||
function isStopCharacter(c) {
|
||||
return isWhitespace(c) || isEndCharacter(c);
|
||||
}
|
||||
|
||||
function isErrorCharacter(c) {
|
||||
return "()".indexOf(c) !== -1;
|
||||
}
|
||||
|
||||
function itemTypeFromName(typename) {
|
||||
for (var i = 0, len = itemTypes.length; i < len; ++i) {
|
||||
if (itemTypes[i] === typename) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error("Unknown type filter `" + typename + "`");
|
||||
}
|
||||
|
||||
/**
|
||||
* If we encounter a `"`, then we try to extract the string from it until we find another `"`.
|
||||
*
|
||||
* This function will throw an error in the following cases:
|
||||
* * There is already another string element.
|
||||
* * We are parsing a generic argument.
|
||||
* * There is more than one element.
|
||||
* * There is no closing `"`.
|
||||
*
|
||||
* @param {ParsedQuery} query
|
||||
* @param {ParserState} parserState
|
||||
* @param {boolean} isInGenerics
|
||||
*/
|
||||
function getStringElem(query, parserState, isInGenerics) {
|
||||
if (isInGenerics) {
|
||||
throw new Error("`\"` cannot be used in generics");
|
||||
} else if (query.literalSearch) {
|
||||
throw new Error("Cannot have more than one literal search element");
|
||||
} else if (parserState.totalElems - parserState.genericsElems > 0) {
|
||||
throw new Error("Cannot use literal search when there is more than one element");
|
||||
}
|
||||
parserState.pos += 1;
|
||||
var start = parserState.pos;
|
||||
var end = getIdentEndPosition(parserState);
|
||||
if (parserState.pos >= parserState.length) {
|
||||
throw new Error("Unclosed `\"`");
|
||||
} else if (parserState.userQuery[end] !== "\"") {
|
||||
throw new Error(`Unexpected \`${parserState.userQuery[end]}\` in a string element`);
|
||||
} else if (start === end) {
|
||||
throw new Error("Cannot have empty string element");
|
||||
}
|
||||
// To skip the quote at the end.
|
||||
parserState.pos += 1;
|
||||
query.literalSearch = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `true` if the current parser position is starting with "::".
|
||||
*
|
||||
* @param {ParserState} parserState
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
function isPathStart(parserState) {
|
||||
return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) == '::';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `true` if the current parser position is starting with "->".
|
||||
*
|
||||
* @param {ParserState} parserState
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
function isReturnArrow(parserState) {
|
||||
return parserState.userQuery.slice(parserState.pos, parserState.pos + 2) == '->';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `true` if the given `c` character is valid for an ident.
|
||||
*
|
||||
* @param {string} c
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
function isIdentCharacter(c) {
|
||||
return (
|
||||
c === '_' ||
|
||||
(c >= '0' && c <= '9') ||
|
||||
(c >= 'a' && c <= 'z') ||
|
||||
(c >= 'A' && c <= 'Z'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `true` if the given `c` character is a separator.
|
||||
*
|
||||
* @param {string} c
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
function isSeparatorCharacter(c) {
|
||||
return c === "," || isWhitespaceCharacter(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `true` if the given `c` character is a whitespace.
|
||||
*
|
||||
* @param {string} c
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
function isWhitespaceCharacter(c) {
|
||||
return c === " " || c === "\t";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ParsedQuery} query
|
||||
* @param {ParserState} parserState
|
||||
* @param {string} name - Name of the query element.
|
||||
* @param {Array<QueryElement>} generics - List of generics of this query element.
|
||||
*
|
||||
* @return {QueryElement} - The newly created `QueryElement`.
|
||||
*/
|
||||
function createQueryElement(query, parserState, name, generics, isInGenerics) {
|
||||
if (name === '*' || (name.length === 0 && generics.length === 0)) {
|
||||
return;
|
||||
}
|
||||
if (query.literalSearch && parserState.totalElems - parserState.genericsElems > 0) {
|
||||
throw new Error("You cannot have more than one element if you use quotes");
|
||||
}
|
||||
var pathSegments = name.split("::");
|
||||
if (pathSegments.length > 1) {
|
||||
for (var i = 0, len = pathSegments.length; i < len; ++i) {
|
||||
var pathSegment = pathSegments[i];
|
||||
|
||||
if (pathSegment.length === 0) {
|
||||
if (i === 0) {
|
||||
throw new Error("Paths cannot start with `::`");
|
||||
} else if (i + 1 === len) {
|
||||
throw new Error("Paths cannot end with `::`");
|
||||
}
|
||||
throw new Error("Unexpected `::::`");
|
||||
}
|
||||
}
|
||||
}
|
||||
// In case we only have something like `<p>`, there is no name.
|
||||
if (pathSegments.length === 0 || (pathSegments.length === 1 && pathSegments[0] === "")) {
|
||||
throw new Error("Found generics without a path");
|
||||
}
|
||||
parserState.totalElems += 1;
|
||||
if (isInGenerics) {
|
||||
parserState.genericsElems += 1;
|
||||
}
|
||||
return {
|
||||
name: name,
|
||||
fullPath: pathSegments,
|
||||
pathWithoutLast: pathSegments.slice(0, pathSegments.length - 1),
|
||||
pathLast: pathSegments[pathSegments.length - 1],
|
||||
generics: generics,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* This function goes through all characters until it reaches an invalid ident character or the
|
||||
* end of the query. It returns the position of the last character of the ident.
|
||||
*
|
||||
* @param {ParserState} parserState
|
||||
*
|
||||
* @return {integer}
|
||||
*/
|
||||
function getIdentEndPosition(parserState) {
|
||||
var end = parserState.pos;
|
||||
while (parserState.pos < parserState.length) {
|
||||
var c = parserState.userQuery[parserState.pos];
|
||||
if (!isIdentCharacter(c)) {
|
||||
if (isErrorCharacter(c)) {
|
||||
throw new Error(`Unexpected \`${c}\``);
|
||||
} else if (
|
||||
isStopCharacter(c) ||
|
||||
isSpecialStartCharacter(c) ||
|
||||
isSeparatorCharacter(c))
|
||||
{
|
||||
break;
|
||||
}
|
||||
// If we allow paths ("str::string" for example).
|
||||
else if (c === ":") {
|
||||
if (!isPathStart(parserState)) {
|
||||
break;
|
||||
}
|
||||
// Skip current ":".
|
||||
parserState.pos += 1;
|
||||
} else {
|
||||
throw new Error(`Unexpected \`${c}\``);
|
||||
}
|
||||
}
|
||||
parserState.pos += 1;
|
||||
end = parserState.pos;
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ParsedQuery} query
|
||||
* @param {ParserState} parserState
|
||||
* @param {Array<QueryElement>} elems - This is where the new {QueryElement} will be added.
|
||||
* @param {boolean} isInGenerics
|
||||
*/
|
||||
function getNextElem(query, parserState, elems, isInGenerics) {
|
||||
var generics = [];
|
||||
|
||||
var start = parserState.pos;
|
||||
var end;
|
||||
// We handle the strings on their own mostly to make code easier to follow.
|
||||
if (parserState.userQuery[parserState.pos] === "\"") {
|
||||
start += 1;
|
||||
getStringElem(query, parserState, isInGenerics);
|
||||
end = parserState.pos - 1;
|
||||
} else {
|
||||
end = getIdentEndPosition(parserState);
|
||||
}
|
||||
if (parserState.pos < parserState.length &&
|
||||
parserState.userQuery[parserState.pos] === "<")
|
||||
{
|
||||
if (isInGenerics) {
|
||||
throw new Error("Unexpected `<` after `<`");
|
||||
} else if (start >= end) {
|
||||
throw new Error("Found generics without a path");
|
||||
}
|
||||
parserState.pos += 1;
|
||||
getItemsBefore(query, parserState, generics, ">");
|
||||
}
|
||||
if (start >= end && generics.length === 0) {
|
||||
return;
|
||||
}
|
||||
elems.push(
|
||||
createQueryElement(
|
||||
query,
|
||||
parserState,
|
||||
parserState.userQuery.slice(start, end),
|
||||
generics,
|
||||
isInGenerics
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function parses the next query element until it finds `endChar`, calling `getNextElem`
|
||||
* to collect each element.
|
||||
*
|
||||
* If there is no `endChar`, this function will implicitly stop at the end without raising an
|
||||
* error.
|
||||
*
|
||||
* @param {ParsedQuery} query
|
||||
* @param {ParserState} parserState
|
||||
* @param {Array<QueryElement>} elems - This is where the new {QueryElement} will be added.
|
||||
* @param {string} endChar - This function will stop when it'll encounter this
|
||||
* character.
|
||||
*/
|
||||
function getItemsBefore(query, parserState, elems, endChar) {
|
||||
var foundStopChar = true;
|
||||
|
||||
while (parserState.pos < parserState.length) {
|
||||
var c = parserState.userQuery[parserState.pos];
|
||||
if (c === endChar) {
|
||||
break;
|
||||
} else if (isSeparatorCharacter(c)) {
|
||||
parserState.pos += 1;
|
||||
foundStopChar = true;
|
||||
continue;
|
||||
} else if (c === ":" && isPathStart(parserState)) {
|
||||
throw new Error("Unexpected `::`: paths cannot start with `::`");
|
||||
} else if (c === ":" || isEndCharacter(c)) {
|
||||
var extra = "";
|
||||
if (endChar === ">") {
|
||||
extra = "`<`";
|
||||
} else if (endChar === "") {
|
||||
extra = "`->`";
|
||||
}
|
||||
throw new Error("Unexpected `" + c + "` after " + extra);
|
||||
}
|
||||
if (!foundStopChar) {
|
||||
if (endChar !== "") {
|
||||
throw new Error(`Expected \`,\`, \` \` or \`${endChar}\`, found \`${c}\``);
|
||||
}
|
||||
throw new Error(`Expected \`,\` or \` \`, found \`${c}\``);
|
||||
}
|
||||
var posBefore = parserState.pos;
|
||||
getNextElem(query, parserState, elems, endChar === ">");
|
||||
// This case can be encountered if `getNextElem` encounted a "stop character" right from
|
||||
// the start. For example if you have `,,` or `<>`. In this case, we simply move up the
|
||||
// current position to continue the parsing.
|
||||
if (posBefore === parserState.pos) {
|
||||
parserState.pos += 1;
|
||||
}
|
||||
foundStopChar = false;
|
||||
}
|
||||
// We are either at the end of the string or on the `endChar`` character, let's move forward
|
||||
// in any case.
|
||||
parserState.pos += 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the type filter doesn't have unwanted characters like `<>` (which are ignored
|
||||
* if empty).
|
||||
*
|
||||
* @param {ParserState} parserState
|
||||
*/
|
||||
function checkExtraTypeFilterCharacters(parserState) {
|
||||
var query = parserState.userQuery;
|
||||
|
||||
for (var pos = 0; pos < parserState.pos; ++pos) {
|
||||
if (!isIdentCharacter(query[pos]) && !isWhitespaceCharacter(query[pos])) {
|
||||
throw new Error(`Unexpected \`${query[pos]}\` in type filter`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the provided `query` input to fill `parserState`. If it encounters an error while
|
||||
* parsing `query`, it'll throw an error.
|
||||
*
|
||||
* @param {ParsedQuery} query
|
||||
* @param {ParserState} parserState
|
||||
*/
|
||||
function parseInput(query, parserState) {
|
||||
var c, before;
|
||||
var foundStopChar = true;
|
||||
|
||||
while (parserState.pos < parserState.length) {
|
||||
c = parserState.userQuery[parserState.pos];
|
||||
if (isStopCharacter(c)) {
|
||||
foundStopChar = true;
|
||||
if (isSeparatorCharacter(c)) {
|
||||
parserState.pos += 1;
|
||||
continue;
|
||||
} else if (c === "-" || c === ">") {
|
||||
if (isReturnArrow(parserState)) {
|
||||
break;
|
||||
}
|
||||
throw new Error(`Unexpected \`${c}\` (did you mean \`->\`?)`);
|
||||
}
|
||||
throw new Error(`Unexpected \`${c}\``);
|
||||
} else if (c === ":" && !isPathStart(parserState)) {
|
||||
if (parserState.typeFilter !== null) {
|
||||
throw new Error("Unexpected `:`");
|
||||
}
|
||||
if (query.elems.length === 0) {
|
||||
throw new Error("Expected type filter before `:`");
|
||||
} else if (query.elems.length !== 1 || parserState.totalElems !== 1) {
|
||||
throw new Error("Unexpected `:`");
|
||||
} else if (query.literalSearch) {
|
||||
throw new Error("You cannot use quotes on type filter");
|
||||
}
|
||||
checkExtraTypeFilterCharacters(parserState);
|
||||
// The type filter doesn't count as an element since it's a modifier.
|
||||
parserState.typeFilter = query.elems.pop().name;
|
||||
parserState.pos += 1;
|
||||
parserState.totalElems = 0;
|
||||
query.literalSearch = false;
|
||||
foundStopChar = true;
|
||||
continue;
|
||||
}
|
||||
if (!foundStopChar) {
|
||||
if (parserState.typeFilter !== null) {
|
||||
throw new Error(`Expected \`,\`, \` \` or \`->\`, found \`${c}\``);
|
||||
}
|
||||
throw new Error(`Expected \`,\`, \` \`, \`:\` or \`->\`, found \`${c}\``);
|
||||
}
|
||||
before = query.elems.length;
|
||||
getNextElem(query, parserState, query.elems, false);
|
||||
if (query.elems.length === before) {
|
||||
// Nothing was added, weird... Let's increase the position to not remain stuck.
|
||||
parserState.pos += 1;
|
||||
}
|
||||
foundStopChar = false;
|
||||
}
|
||||
while (parserState.pos < parserState.length) {
|
||||
c = parserState.userQuery[parserState.pos];
|
||||
if (isReturnArrow(parserState)) {
|
||||
parserState.pos += 2;
|
||||
// Get returned elements.
|
||||
getItemsBefore(query, parserState, query.returned, "");
|
||||
// Nothing can come afterward!
|
||||
if (query.returned.length === 0) {
|
||||
throw new Error("Expected at least one item after `->`");
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
parserState.pos += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the user search input and returns an empty `ParsedQuery`.
|
||||
*
|
||||
* @param {string} userQuery
|
||||
*
|
||||
* @return {ParsedQuery}
|
||||
*/
|
||||
function newParsedQuery(userQuery) {
|
||||
return {
|
||||
original: userQuery,
|
||||
userQuery: userQuery.toLowerCase(),
|
||||
typeFilter: NO_TYPE_FILTER,
|
||||
elems: [],
|
||||
returned: [],
|
||||
// Total number of "top" elements (does not include generics).
|
||||
foundElems: 0,
|
||||
literalSearch: false,
|
||||
error: null,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an URL with search parameters.
|
||||
*
|
||||
* @param {string} search - The current search being performed.
|
||||
* @param {string|null} filterCrates - The current filtering crate (if any).
|
||||
*
|
||||
* @return {string}
|
||||
*/
|
||||
function buildUrl(search, filterCrates) {
|
||||
@@ -167,33 +583,139 @@ window.initSearch = function(rawSearchIndex) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the query and returns a list of results for each results tab.
|
||||
* @param {Object} query - The user query
|
||||
* @param {Array<string>} searchWords - The list of search words to query against
|
||||
* @param {string} [filterCrates] - Crate to search in
|
||||
* @return {{
|
||||
* in_args: Array<?>,
|
||||
* returned: Array<?>,
|
||||
* others: Array<?>
|
||||
* }}
|
||||
* Parses the query.
|
||||
*
|
||||
* The supported syntax by this parser is as follow:
|
||||
*
|
||||
* ident = *(ALPHA / DIGIT / "_")
|
||||
* path = ident *(DOUBLE-COLON ident)
|
||||
* arg = path [generics]
|
||||
* arg-without-generic = path
|
||||
* type-sep = COMMA/WS *(COMMA/WS)
|
||||
* nonempty-arg-list = *(type-sep) arg *(type-sep arg) *(type-sep)
|
||||
* nonempty-arg-list-without-generics = *(type-sep) arg-without-generic
|
||||
* *(type-sep arg-without-generic) *(type-sep)
|
||||
* generics = OPEN-ANGLE-BRACKET [ nonempty-arg-list-without-generics ] *(type-sep)
|
||||
* CLOSE-ANGLE-BRACKET/EOF
|
||||
* return-args = RETURN-ARROW *(type-sep) nonempty-arg-list
|
||||
*
|
||||
* exact-search = [type-filter *WS COLON] [ RETURN-ARROW ] *WS QUOTE ident QUOTE [ generics ]
|
||||
* type-search = [type-filter *WS COLON] [ nonempty-arg-list ] [ return-args ]
|
||||
*
|
||||
* query = *WS (exact-search / type-search) *WS
|
||||
*
|
||||
* type-filter = (
|
||||
* "mod" /
|
||||
* "externcrate" /
|
||||
* "import" /
|
||||
* "struct" /
|
||||
* "enum" /
|
||||
* "fn" /
|
||||
* "type" /
|
||||
* "static" /
|
||||
* "trait" /
|
||||
* "impl" /
|
||||
* "tymethod" /
|
||||
* "method" /
|
||||
* "structfield" /
|
||||
* "variant" /
|
||||
* "macro" /
|
||||
* "primitive" /
|
||||
* "associatedtype" /
|
||||
* "constant" /
|
||||
* "associatedconstant" /
|
||||
* "union" /
|
||||
* "foreigntype" /
|
||||
* "keyword" /
|
||||
* "existential" /
|
||||
* "attr" /
|
||||
* "derive" /
|
||||
* "traitalias")
|
||||
*
|
||||
* OPEN-ANGLE-BRACKET = "<"
|
||||
* CLOSE-ANGLE-BRACKET = ">"
|
||||
* COLON = ":"
|
||||
* DOUBLE-COLON = "::"
|
||||
* QUOTE = %x22
|
||||
* COMMA = ","
|
||||
* RETURN-ARROW = "->"
|
||||
*
|
||||
* ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
|
||||
* DIGIT = %x30-39
|
||||
* WS = %x09 / " "
|
||||
*
|
||||
* @param {string} val - The user query
|
||||
*
|
||||
* @return {ParsedQuery} - The parsed query
|
||||
*/
|
||||
function execQuery(query, searchWords, filterCrates) {
|
||||
function itemTypeFromName(typename) {
|
||||
for (var i = 0, len = itemTypes.length; i < len; ++i) {
|
||||
if (itemTypes[i] === typename) {
|
||||
return i;
|
||||
function parseQuery(userQuery) {
|
||||
userQuery = userQuery.trim();
|
||||
var parserState = {
|
||||
length: userQuery.length,
|
||||
pos: 0,
|
||||
// Total number of elements (includes generics).
|
||||
totalElems: 0,
|
||||
genericsElems: 0,
|
||||
typeFilter: null,
|
||||
userQuery: userQuery.toLowerCase(),
|
||||
};
|
||||
var query = newParsedQuery(userQuery);
|
||||
|
||||
try {
|
||||
parseInput(query, parserState);
|
||||
if (parserState.typeFilter !== null) {
|
||||
var typeFilter = parserState.typeFilter;
|
||||
if (typeFilter === "const") {
|
||||
typeFilter = "constant";
|
||||
}
|
||||
query.typeFilter = itemTypeFromName(typeFilter);
|
||||
}
|
||||
return NO_TYPE_FILTER;
|
||||
} catch (err) {
|
||||
query = newParsedQuery(userQuery);
|
||||
query.error = err.message;
|
||||
query.typeFilter = -1;
|
||||
return query;
|
||||
}
|
||||
|
||||
var valLower = query.query.toLowerCase(),
|
||||
val = valLower,
|
||||
typeFilter = itemTypeFromName(query.type),
|
||||
results = {}, results_in_args = {}, results_returned = {},
|
||||
split = valLower.split("::");
|
||||
if (!query.literalSearch) {
|
||||
// If there is more than one element in the query, we switch to literalSearch in any
|
||||
// case.
|
||||
query.literalSearch = parserState.totalElems > 1;
|
||||
}
|
||||
query.foundElems = query.elems.length + query.returned.length;
|
||||
return query;
|
||||
}
|
||||
|
||||
removeEmptyStringsFromArray(split);
|
||||
/**
|
||||
* Creates the query results.
|
||||
*
|
||||
* @param {Array<Result>} results_in_args
|
||||
* @param {Array<Result>} results_returned
|
||||
* @param {Array<Result>} results_in_args
|
||||
* @param {ParsedQuery} parsedQuery
|
||||
*
|
||||
* @return {ResultsTable}
|
||||
*/
|
||||
function createQueryResults(results_in_args, results_returned, results_others, parsedQuery) {
|
||||
return {
|
||||
"in_args": results_in_args,
|
||||
"returned": results_returned,
|
||||
"others": results_others,
|
||||
"query": parsedQuery,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the parsed query and builds a {ResultsTable}.
|
||||
*
|
||||
* @param {ParsedQuery} parsedQuery - The parsed user query
|
||||
* @param {Object} searchWords - The list of search words to query against
|
||||
* @param {Object} [filterCrates] - Crate to search in if defined
|
||||
*
|
||||
* @return {ResultsTable}
|
||||
*/
|
||||
function execQuery(parsedQuery, searchWords, filterCrates) {
|
||||
var results_others = {}, results_in_args = {}, results_returned = {};
|
||||
|
||||
function transformResults(results) {
|
||||
var duplicates = {};
|
||||
@@ -227,6 +749,7 @@ window.initSearch = function(rawSearchIndex) {
|
||||
}
|
||||
|
||||
function sortResults(results, isType) {
|
||||
var userQuery = parsedQuery.userQuery;
|
||||
var ar = [];
|
||||
for (var entry in results) {
|
||||
if (hasOwnPropertyRustdoc(results, entry)) {
|
||||
@@ -246,8 +769,8 @@ window.initSearch = function(rawSearchIndex) {
|
||||
var a, b;
|
||||
|
||||
// sort by exact match with regard to the last word (mismatch goes later)
|
||||
a = (aaa.word !== val);
|
||||
b = (bbb.word !== val);
|
||||
a = (aaa.word !== userQuery);
|
||||
b = (bbb.word !== userQuery);
|
||||
if (a !== b) { return a - b; }
|
||||
|
||||
// Sort by non levenshtein results and then levenshtein results by the distance
|
||||
@@ -309,6 +832,12 @@ window.initSearch = function(rawSearchIndex) {
|
||||
return 0;
|
||||
});
|
||||
|
||||
var nameSplit = null;
|
||||
if (parsedQuery.elems.length === 1) {
|
||||
var hasPath = typeof parsedQuery.elems[0].path === "undefined";
|
||||
nameSplit = hasPath ? null : parsedQuery.elems[0].path;
|
||||
}
|
||||
|
||||
for (var i = 0, len = results.length; i < len; ++i) {
|
||||
result = results[i];
|
||||
|
||||
@@ -320,215 +849,222 @@ window.initSearch = function(rawSearchIndex) {
|
||||
path = result.item.path.toLowerCase(),
|
||||
parent = result.item.parent;
|
||||
|
||||
if (!isType && !validateResult(name, path, split, parent)) {
|
||||
if (!isType && !validateResult(name, path, nameSplit, parent)) {
|
||||
result.id = -1;
|
||||
}
|
||||
}
|
||||
return transformResults(results);
|
||||
}
|
||||
|
||||
function extractGenerics(val) {
|
||||
val = val.toLowerCase();
|
||||
if (val.indexOf("<") !== -1) {
|
||||
var values = val.substring(val.indexOf("<") + 1, val.lastIndexOf(">"));
|
||||
return {
|
||||
name: val.substring(0, val.indexOf("<")),
|
||||
generics: values.split(/\s*,\s*/),
|
||||
};
|
||||
/**
|
||||
* This function checks if the object (`row`) generics match the given type (`elem`)
|
||||
* generics. If there are no generics on `row`, `defaultLev` is returned.
|
||||
*
|
||||
* @param {Row} row - The object to check.
|
||||
* @param {QueryElement} elem - The element from the parsed query.
|
||||
* @param {integer} defaultLev - This is the value to return in case there are no generics.
|
||||
*
|
||||
* @return {integer} - Returns the best match (if any) or `MAX_LEV_DISTANCE + 1`.
|
||||
*/
|
||||
function checkGenerics(row, elem, defaultLev) {
|
||||
if (row.length <= GENERICS_DATA || row[GENERICS_DATA].length === 0) {
|
||||
return elem.generics.length === 0 ? defaultLev : MAX_LEV_DISTANCE + 1;
|
||||
} else if (row[GENERICS_DATA].length > 0 && row[GENERICS_DATA][0][NAME] === "") {
|
||||
if (row.length > GENERICS_DATA) {
|
||||
return checkGenerics(row[GENERICS_DATA][0], elem, defaultLev);
|
||||
}
|
||||
return elem.generics.length === 0 ? defaultLev : MAX_LEV_DISTANCE + 1;
|
||||
}
|
||||
return {
|
||||
name: val,
|
||||
generics: [],
|
||||
};
|
||||
}
|
||||
|
||||
function checkGenerics(obj, val) {
|
||||
// The names match, but we need to be sure that all generics kinda
|
||||
// match as well.
|
||||
var tmp_lev, elem_name;
|
||||
if (val.generics.length > 0) {
|
||||
if (obj.length > GENERICS_DATA &&
|
||||
obj[GENERICS_DATA].length >= val.generics.length) {
|
||||
var elems = Object.create(null);
|
||||
var elength = obj[GENERICS_DATA].length;
|
||||
for (var x = 0; x < elength; ++x) {
|
||||
if (!elems[obj[GENERICS_DATA][x][NAME]]) {
|
||||
elems[obj[GENERICS_DATA][x][NAME]] = 0;
|
||||
}
|
||||
elems[obj[GENERICS_DATA][x][NAME]] += 1;
|
||||
}
|
||||
var total = 0;
|
||||
var done = 0;
|
||||
// We need to find the type that matches the most to remove it in order
|
||||
// to move forward.
|
||||
var vlength = val.generics.length;
|
||||
for (x = 0; x < vlength; ++x) {
|
||||
var lev = MAX_LEV_DISTANCE + 1;
|
||||
var firstGeneric = val.generics[x];
|
||||
var match = null;
|
||||
if (elems[firstGeneric]) {
|
||||
match = firstGeneric;
|
||||
lev = 0;
|
||||
} else {
|
||||
for (elem_name in elems) {
|
||||
tmp_lev = levenshtein(elem_name, firstGeneric);
|
||||
if (tmp_lev < lev) {
|
||||
lev = tmp_lev;
|
||||
match = elem_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (match !== null) {
|
||||
elems[match] -= 1;
|
||||
if (elems[match] == 0) {
|
||||
delete elems[match];
|
||||
}
|
||||
total += lev;
|
||||
done += 1;
|
||||
} else {
|
||||
var elem_name;
|
||||
if (elem.generics.length > 0 && row[GENERICS_DATA].length >= elem.generics.length) {
|
||||
var elems = Object.create(null);
|
||||
for (var x = 0, length = row[GENERICS_DATA].length; x < length; ++x) {
|
||||
elem_name = row[GENERICS_DATA][x][NAME];
|
||||
if (elem_name === "") {
|
||||
// Pure generic, needs to check into it.
|
||||
if (checkGenerics(
|
||||
row[GENERICS_DATA][x], elem, MAX_LEV_DISTANCE + 1) !== 0) {
|
||||
return MAX_LEV_DISTANCE + 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
return Math.ceil(total / done);
|
||||
if (elems[elem_name] === undefined) {
|
||||
elems[elem_name] = 0;
|
||||
}
|
||||
elems[elem_name] += 1;
|
||||
}
|
||||
// We need to find the type that matches the most to remove it in order
|
||||
// to move forward.
|
||||
for (x = 0, length = elem.generics.length; x < length; ++x) {
|
||||
var generic = elem.generics[x];
|
||||
var match = null;
|
||||
if (elems[generic.name]) {
|
||||
match = generic.name;
|
||||
} else {
|
||||
for (elem_name in elems) {
|
||||
if (!hasOwnPropertyRustdoc(elems, elem_name)) {
|
||||
continue;
|
||||
}
|
||||
if (elem_name === generic) {
|
||||
match = elem_name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (match === null) {
|
||||
return MAX_LEV_DISTANCE + 1;
|
||||
}
|
||||
elems[match] -= 1;
|
||||
if (elems[match] === 0) {
|
||||
delete elems[match];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return MAX_LEV_DISTANCE + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function checks if the object (`obj`) matches the given type (`val`) and its
|
||||
* This function checks if the object (`row`) matches the given type (`elem`) and its
|
||||
* generics (if any).
|
||||
*
|
||||
* @param {Object} obj
|
||||
* @param {string} val
|
||||
* @param {Row} row
|
||||
* @param {QueryElement} elem - The element from the parsed query.
|
||||
*
|
||||
* @return {integer} - Returns a Levenshtein distance to the best match.
|
||||
*/
|
||||
function checkIfInGenerics(row, elem) {
|
||||
var lev = MAX_LEV_DISTANCE + 1;
|
||||
for (var x = 0, length = row[GENERICS_DATA].length; x < length && lev !== 0; ++x) {
|
||||
lev = Math.min(
|
||||
checkType(row[GENERICS_DATA][x], elem, true),
|
||||
lev
|
||||
);
|
||||
}
|
||||
return lev;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function checks if the object (`row`) matches the given type (`elem`) and its
|
||||
* generics (if any).
|
||||
*
|
||||
* @param {Row} row
|
||||
* @param {QueryElement} elem - The element from the parsed query.
|
||||
* @param {boolean} literalSearch
|
||||
*
|
||||
* @return {integer} - Returns a Levenshtein distance to the best match. If there is
|
||||
* no match, returns `MAX_LEV_DISTANCE + 1`.
|
||||
*/
|
||||
function checkType(obj, val, literalSearch) {
|
||||
var lev_distance = MAX_LEV_DISTANCE + 1;
|
||||
var tmp_lev = MAX_LEV_DISTANCE + 1;
|
||||
var len, x, firstGeneric;
|
||||
if (obj[NAME] === val.name) {
|
||||
if (literalSearch) {
|
||||
if (val.generics && val.generics.length !== 0) {
|
||||
if (obj.length > GENERICS_DATA &&
|
||||
obj[GENERICS_DATA].length > 0) {
|
||||
var elems = Object.create(null);
|
||||
len = obj[GENERICS_DATA].length;
|
||||
for (x = 0; x < len; ++x) {
|
||||
if (!elems[obj[GENERICS_DATA][x][NAME]]) {
|
||||
elems[obj[GENERICS_DATA][x][NAME]] = 0;
|
||||
}
|
||||
elems[obj[GENERICS_DATA][x][NAME]] += 1;
|
||||
}
|
||||
function checkType(row, elem, literalSearch) {
|
||||
if (row[NAME].length === 0) {
|
||||
// This is a pure "generic" search, no need to run other checks.
|
||||
if (row.length > GENERICS_DATA) {
|
||||
return checkIfInGenerics(row, elem);
|
||||
}
|
||||
return MAX_LEV_DISTANCE + 1;
|
||||
}
|
||||
|
||||
len = val.generics.length;
|
||||
for (x = 0; x < len; ++x) {
|
||||
firstGeneric = val.generics[x];
|
||||
if (elems[firstGeneric]) {
|
||||
elems[firstGeneric] -= 1;
|
||||
} else {
|
||||
// Something wasn't found and this is a literal search so
|
||||
// abort and return a "failing" distance.
|
||||
return MAX_LEV_DISTANCE + 1;
|
||||
}
|
||||
}
|
||||
// Everything was found, success!
|
||||
var lev = levenshtein(row[NAME], elem.name);
|
||||
if (literalSearch) {
|
||||
if (lev !== 0) {
|
||||
// The name didn't match, let's try to check if the generics do.
|
||||
if (elem.generics.length === 0) {
|
||||
var checkGeneric = (row.length > GENERICS_DATA &&
|
||||
row[GENERICS_DATA].length > 0);
|
||||
if (checkGeneric && row[GENERICS_DATA].findIndex(function(tmp_elem) {
|
||||
return tmp_elem[NAME] === elem.name;
|
||||
}) !== -1) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return MAX_LEV_DISTANCE + 1;
|
||||
} else if (elem.generics.length > 0) {
|
||||
return checkGenerics(row, elem, MAX_LEV_DISTANCE + 1);
|
||||
}
|
||||
return 0;
|
||||
} else if (row.length > GENERICS_DATA) {
|
||||
if (elem.generics.length === 0) {
|
||||
if (lev === 0) {
|
||||
return 0;
|
||||
}
|
||||
// The name didn't match so we now check if the type we're looking for is inside
|
||||
// the generics!
|
||||
lev = checkIfInGenerics(row, elem);
|
||||
// Now whatever happens, the returned distance is "less good" so we should mark
|
||||
// it as such, and so we add 0.5 to the distance to make it "less good".
|
||||
return lev + 0.5;
|
||||
} else if (lev > MAX_LEV_DISTANCE) {
|
||||
// So our item's name doesn't match at all and has generics.
|
||||
//
|
||||
// Maybe it's present in a sub generic? For example "f<A<B<C>>>()", if we're
|
||||
// looking for "B<C>", we'll need to go down.
|
||||
return checkIfInGenerics(row, elem);
|
||||
} else {
|
||||
// At this point, the name kinda match and we have generics to check, so
|
||||
// let's go!
|
||||
var tmp_lev = checkGenerics(row, elem, lev);
|
||||
if (tmp_lev > MAX_LEV_DISTANCE) {
|
||||
return MAX_LEV_DISTANCE + 1;
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
// If the type has generics but don't match, then it won't return at this point.
|
||||
// Otherwise, `checkGenerics` will return 0 and it'll return.
|
||||
if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length !== 0) {
|
||||
tmp_lev = checkGenerics(obj, val);
|
||||
if (tmp_lev <= MAX_LEV_DISTANCE) {
|
||||
return tmp_lev;
|
||||
}
|
||||
}
|
||||
// We compute the median value of both checks and return it.
|
||||
return (tmp_lev + lev) / 2;
|
||||
}
|
||||
} else if (literalSearch) {
|
||||
var found = false;
|
||||
if ((!val.generics || val.generics.length === 0) &&
|
||||
obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
|
||||
found = obj[GENERICS_DATA].some(
|
||||
function(gen) {
|
||||
return gen[NAME] === val.name;
|
||||
});
|
||||
}
|
||||
return found ? 0 : MAX_LEV_DISTANCE + 1;
|
||||
} else if (elem.generics.length > 0) {
|
||||
// In this case, we were expecting generics but there isn't so we simply reject this
|
||||
// one.
|
||||
return MAX_LEV_DISTANCE + 1;
|
||||
}
|
||||
lev_distance = Math.min(levenshtein(obj[NAME], val.name), lev_distance);
|
||||
if (lev_distance <= MAX_LEV_DISTANCE) {
|
||||
// The generics didn't match but the name kinda did so we give it
|
||||
// a levenshtein distance value that isn't *this* good so it goes
|
||||
// into the search results but not too high.
|
||||
lev_distance = Math.ceil((checkGenerics(obj, val) + lev_distance) / 2);
|
||||
}
|
||||
if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
|
||||
// We can check if the type we're looking for is inside the generics!
|
||||
var olength = obj[GENERICS_DATA].length;
|
||||
for (x = 0; x < olength; ++x) {
|
||||
tmp_lev = Math.min(levenshtein(obj[GENERICS_DATA][x][NAME], val.name), tmp_lev);
|
||||
}
|
||||
if (tmp_lev !== 0) {
|
||||
// If we didn't find a good enough result, we go check inside the generics of
|
||||
// the generics.
|
||||
for (x = 0; x < olength && tmp_lev !== 0; ++x) {
|
||||
tmp_lev = Math.min(
|
||||
checkType(obj[GENERICS_DATA][x], val, literalSearch),
|
||||
tmp_lev
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now whatever happens, the returned distance is "less good" so we should mark it
|
||||
// as such, and so we add 1 to the distance to make it "less good".
|
||||
return Math.min(lev_distance, tmp_lev) + 1;
|
||||
// No generics on our query or on the target type so we can return without doing
|
||||
// anything else.
|
||||
return lev;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function checks if the object (`obj`) has an argument with the given type (`val`).
|
||||
* This function checks if the object (`row`) has an argument with the given type (`elem`).
|
||||
*
|
||||
* @param {Object} obj
|
||||
* @param {string} val
|
||||
* @param {boolean} literalSearch
|
||||
* @param {Row} row
|
||||
* @param {QueryElement} elem - The element from the parsed query.
|
||||
* @param {integer} typeFilter
|
||||
*
|
||||
* @return {integer} - Returns a Levenshtein distance to the best match. If there is no
|
||||
* match, returns `MAX_LEV_DISTANCE + 1`.
|
||||
*/
|
||||
function findArg(obj, val, literalSearch, typeFilter) {
|
||||
var lev_distance = MAX_LEV_DISTANCE + 1;
|
||||
function findArg(row, elem, typeFilter) {
|
||||
var lev = MAX_LEV_DISTANCE + 1;
|
||||
|
||||
if (obj && obj.type && obj.type[INPUTS_DATA] && obj.type[INPUTS_DATA].length > 0) {
|
||||
var length = obj.type[INPUTS_DATA].length;
|
||||
if (row && row.type && row.type[INPUTS_DATA] && row.type[INPUTS_DATA].length > 0) {
|
||||
var length = row.type[INPUTS_DATA].length;
|
||||
for (var i = 0; i < length; i++) {
|
||||
var tmp = obj.type[INPUTS_DATA][i];
|
||||
var tmp = row.type[INPUTS_DATA][i];
|
||||
if (!typePassesFilter(typeFilter, tmp[1])) {
|
||||
continue;
|
||||
}
|
||||
tmp = checkType(tmp, val, literalSearch);
|
||||
if (tmp === 0) {
|
||||
lev = Math.min(lev, checkType(tmp, elem, parsedQuery.literalSearch));
|
||||
if (lev === 0) {
|
||||
return 0;
|
||||
} else if (literalSearch) {
|
||||
continue;
|
||||
}
|
||||
lev_distance = Math.min(tmp, lev_distance);
|
||||
}
|
||||
}
|
||||
return literalSearch ? MAX_LEV_DISTANCE + 1 : lev_distance;
|
||||
return parsedQuery.literalSearch ? MAX_LEV_DISTANCE + 1 : lev;
|
||||
}
|
||||
|
||||
function checkReturned(obj, val, literalSearch, typeFilter) {
|
||||
var lev_distance = MAX_LEV_DISTANCE + 1;
|
||||
/**
|
||||
* This function checks if the object (`row`) returns the given type (`elem`).
|
||||
*
|
||||
* @param {Row} row
|
||||
* @param {QueryElement} elem - The element from the parsed query.
|
||||
* @param {integer} typeFilter
|
||||
*
|
||||
* @return {integer} - Returns a Levenshtein distance to the best match. If there is no
|
||||
* match, returns `MAX_LEV_DISTANCE + 1`.
|
||||
*/
|
||||
function checkReturned(row, elem, typeFilter) {
|
||||
var lev = MAX_LEV_DISTANCE + 1;
|
||||
|
||||
if (obj && obj.type && obj.type.length > OUTPUT_DATA) {
|
||||
var ret = obj.type[OUTPUT_DATA];
|
||||
if (row && row.type && row.type.length > OUTPUT_DATA) {
|
||||
var ret = row.type[OUTPUT_DATA];
|
||||
if (typeof ret[0] === "string") {
|
||||
ret = [ret];
|
||||
}
|
||||
@@ -537,16 +1073,13 @@ window.initSearch = function(rawSearchIndex) {
|
||||
if (!typePassesFilter(typeFilter, tmp[1])) {
|
||||
continue;
|
||||
}
|
||||
tmp = checkType(tmp, val, literalSearch);
|
||||
if (tmp === 0) {
|
||||
lev = Math.min(lev, checkType(tmp, elem, parsedQuery.literalSearch));
|
||||
if (lev === 0) {
|
||||
return 0;
|
||||
} else if (literalSearch) {
|
||||
continue;
|
||||
}
|
||||
lev_distance = Math.min(tmp, lev_distance);
|
||||
}
|
||||
}
|
||||
return literalSearch ? MAX_LEV_DISTANCE + 1 : lev_distance;
|
||||
return parsedQuery.literalSearch ? MAX_LEV_DISTANCE + 1 : lev;
|
||||
}
|
||||
|
||||
function checkPath(contains, lastElem, ty) {
|
||||
@@ -621,13 +1154,14 @@ window.initSearch = function(rawSearchIndex) {
|
||||
}
|
||||
|
||||
function handleAliases(ret, query, filterCrates) {
|
||||
var lowerQuery = query.toLowerCase();
|
||||
// We separate aliases and crate aliases because we want to have current crate
|
||||
// aliases to be before the others in the displayed results.
|
||||
var aliases = [];
|
||||
var crateAliases = [];
|
||||
if (filterCrates !== null) {
|
||||
if (ALIASES[filterCrates] && ALIASES[filterCrates][query.search]) {
|
||||
var query_aliases = ALIASES[filterCrates][query.search];
|
||||
if (ALIASES[filterCrates] && ALIASES[filterCrates][lowerQuery]) {
|
||||
var query_aliases = ALIASES[filterCrates][lowerQuery];
|
||||
var len = query_aliases.length;
|
||||
for (var i = 0; i < len; ++i) {
|
||||
aliases.push(createAliasFromItem(searchIndex[query_aliases[i]]));
|
||||
@@ -635,9 +1169,9 @@ window.initSearch = function(rawSearchIndex) {
|
||||
}
|
||||
} else {
|
||||
Object.keys(ALIASES).forEach(function(crate) {
|
||||
if (ALIASES[crate][query.search]) {
|
||||
if (ALIASES[crate][lowerQuery]) {
|
||||
var pushTo = crate === window.currentCrate ? crateAliases : aliases;
|
||||
var query_aliases = ALIASES[crate][query.search];
|
||||
var query_aliases = ALIASES[crate][lowerQuery];
|
||||
var len = query_aliases.length;
|
||||
for (var i = 0; i < len; ++i) {
|
||||
pushTo.push(createAliasFromItem(searchIndex[query_aliases[i]]));
|
||||
@@ -658,7 +1192,7 @@ window.initSearch = function(rawSearchIndex) {
|
||||
aliases.sort(sortFunc);
|
||||
|
||||
var pushFunc = function(alias) {
|
||||
alias.alias = query.raw;
|
||||
alias.alias = query;
|
||||
var res = buildHrefAndPath(alias);
|
||||
alias.displayPath = pathSplitter(res[0]);
|
||||
alias.fullPath = alias.displayPath + alias.name;
|
||||
@@ -674,208 +1208,237 @@ window.initSearch = function(rawSearchIndex) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This function adds the given result into the provided `res` map if it matches the
|
||||
* This function adds the given result into the provided `results` map if it matches the
|
||||
* following condition:
|
||||
*
|
||||
* * If it is a "literal search" (`isExact`), then `lev` must be 0.
|
||||
* * If it is a "literal search" (`parsedQuery.literalSearch`), then `lev` must be 0.
|
||||
* * If it is not a "literal search", `lev` must be <= `MAX_LEV_DISTANCE`.
|
||||
*
|
||||
* The `res` map contains information which will be used to sort the search results:
|
||||
* The `results` map contains information which will be used to sort the search results:
|
||||
*
|
||||
* * `fullId` is a `string`` used as the key of the object we use for the `res` map.
|
||||
* * `fullId` is a `string`` used as the key of the object we use for the `results` map.
|
||||
* * `id` is the index in both `searchWords` and `searchIndex` arrays for this element.
|
||||
* * `index` is an `integer`` used to sort by the position of the word in the item's name.
|
||||
* * `lev` is the main metric used to sort the search results.
|
||||
*
|
||||
* @param {boolean} isExact
|
||||
* @param {Object} res
|
||||
* @param {Results} results
|
||||
* @param {string} fullId
|
||||
* @param {integer} id
|
||||
* @param {integer} index
|
||||
* @param {integer} lev
|
||||
*/
|
||||
function addIntoResults(isExact, res, fullId, id, index, lev) {
|
||||
if (lev === 0 || (!isExact && lev <= MAX_LEV_DISTANCE)) {
|
||||
if (res[fullId] !== undefined) {
|
||||
var result = res[fullId];
|
||||
function addIntoResults(results, fullId, id, index, lev) {
|
||||
if (lev === 0 || (!parsedQuery.literalSearch && lev <= MAX_LEV_DISTANCE)) {
|
||||
if (results[fullId] !== undefined) {
|
||||
var result = results[fullId];
|
||||
if (result.dontValidate || result.lev <= lev) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
res[fullId] = {
|
||||
results[fullId] = {
|
||||
id: id,
|
||||
index: index,
|
||||
dontValidate: isExact,
|
||||
dontValidate: parsedQuery.literalSearch,
|
||||
lev: lev,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// quoted values mean literal search
|
||||
var nSearchWords = searchWords.length;
|
||||
var i, it;
|
||||
var ty;
|
||||
var fullId;
|
||||
var returned;
|
||||
var in_args;
|
||||
var len;
|
||||
if ((val.charAt(0) === "\"" || val.charAt(0) === "'") &&
|
||||
val.charAt(val.length - 1) === val.charAt(0))
|
||||
{
|
||||
val = extractGenerics(val.substr(1, val.length - 2));
|
||||
for (i = 0; i < nSearchWords; ++i) {
|
||||
if (filterCrates !== null && searchIndex[i].crate !== filterCrates) {
|
||||
continue;
|
||||
}
|
||||
in_args = findArg(searchIndex[i], val, true, typeFilter);
|
||||
returned = checkReturned(searchIndex[i], val, true, typeFilter);
|
||||
ty = searchIndex[i];
|
||||
fullId = ty.id;
|
||||
|
||||
if (searchWords[i] === val.name
|
||||
&& typePassesFilter(typeFilter, searchIndex[i].ty)) {
|
||||
addIntoResults(true, results, fullId, i, -1, 0);
|
||||
}
|
||||
addIntoResults(true, results_in_args, fullId, i, -1, in_args);
|
||||
addIntoResults(true, results_returned, fullId, i, -1, returned);
|
||||
/**
|
||||
* This function is called in case the query is only one element (with or without generics).
|
||||
* This element will be compared to arguments' and returned values' items and also to items.
|
||||
*
|
||||
* Other important thing to note: since there is only one element, we use levenshtein
|
||||
* distance for name comparisons.
|
||||
*
|
||||
* @param {Row} row
|
||||
* @param {integer} pos - Position in the `searchIndex`.
|
||||
* @param {QueryElement} elem - The element from the parsed query.
|
||||
* @param {Results} results_others - Unqualified results (not in arguments nor in
|
||||
* returned values).
|
||||
* @param {Results} results_in_args - Matching arguments results.
|
||||
* @param {Results} results_returned - Matching returned arguments results.
|
||||
*/
|
||||
function handleSingleArg(
|
||||
row,
|
||||
pos,
|
||||
elem,
|
||||
results_others,
|
||||
results_in_args,
|
||||
results_returned
|
||||
) {
|
||||
if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
|
||||
return;
|
||||
}
|
||||
query.inputs = [val];
|
||||
query.output = val;
|
||||
query.search = val;
|
||||
// searching by type
|
||||
} else if (val.search("->") > -1) {
|
||||
var trimmer = function(s) { return s.trim(); };
|
||||
var parts = val.split("->").map(trimmer);
|
||||
var input = parts[0];
|
||||
// sort inputs so that order does not matter
|
||||
var inputs = input.split(",").map(trimmer).sort();
|
||||
for (i = 0, len = inputs.length; i < len; ++i) {
|
||||
inputs[i] = extractGenerics(inputs[i]);
|
||||
var lev, lev_add = 0, index = -1;
|
||||
var fullId = row.id;
|
||||
|
||||
var in_args = findArg(row, elem, parsedQuery.typeFilter);
|
||||
var returned = checkReturned(row, elem, parsedQuery.typeFilter);
|
||||
|
||||
addIntoResults(results_in_args, fullId, pos, index, in_args);
|
||||
addIntoResults(results_returned, fullId, pos, index, returned);
|
||||
|
||||
if (!typePassesFilter(parsedQuery.typeFilter, row.ty)) {
|
||||
return;
|
||||
}
|
||||
var output = extractGenerics(parts[1]);
|
||||
var searchWord = searchWords[pos];
|
||||
|
||||
for (i = 0; i < nSearchWords; ++i) {
|
||||
if (filterCrates !== null && searchIndex[i].crate !== filterCrates) {
|
||||
continue;
|
||||
if (parsedQuery.literalSearch) {
|
||||
if (searchWord === elem.name) {
|
||||
addIntoResults(results_others, fullId, pos, -1, 0);
|
||||
}
|
||||
var type = searchIndex[i].type;
|
||||
ty = searchIndex[i];
|
||||
if (!type) {
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
// No need to check anything else if it's a "pure" generics search.
|
||||
if (elem.name.length === 0) {
|
||||
if (row.type !== null) {
|
||||
lev = checkGenerics(row.type, elem, MAX_LEV_DISTANCE + 1);
|
||||
addIntoResults(results_others, fullId, pos, index, lev);
|
||||
}
|
||||
fullId = ty.id;
|
||||
return;
|
||||
}
|
||||
|
||||
returned = checkReturned(ty, output, true, NO_TYPE_FILTER);
|
||||
if (output.name === "*" || returned === 0) {
|
||||
in_args = false;
|
||||
var is_module = false;
|
||||
|
||||
if (input === "*") {
|
||||
is_module = true;
|
||||
} else {
|
||||
var firstNonZeroDistance = 0;
|
||||
for (it = 0, len = inputs.length; it < len; it++) {
|
||||
var distance = checkType(type, inputs[it], true);
|
||||
if (distance > 0) {
|
||||
firstNonZeroDistance = distance;
|
||||
break;
|
||||
}
|
||||
}
|
||||
in_args = firstNonZeroDistance;
|
||||
}
|
||||
addIntoResults(true, results_in_args, fullId, i, -1, in_args);
|
||||
addIntoResults(true, results_returned, fullId, i, -1, returned);
|
||||
if (is_module) {
|
||||
addIntoResults(true, results, fullId, i, -1, 0);
|
||||
}
|
||||
if (elem.fullPath.length > 1) {
|
||||
lev = checkPath(elem.pathWithoutLast, elem.pathLast, row);
|
||||
if (lev > MAX_LEV_DISTANCE || (parsedQuery.literalSearch && lev !== 0)) {
|
||||
return;
|
||||
} else if (lev > 0) {
|
||||
lev_add = lev / 10;
|
||||
}
|
||||
}
|
||||
query.inputs = inputs.map(function(input) {
|
||||
return input.name;
|
||||
});
|
||||
query.output = output.name;
|
||||
} else {
|
||||
query.inputs = [val];
|
||||
query.output = val;
|
||||
query.search = val;
|
||||
// gather matching search results up to a certain maximum
|
||||
val = val.replace(/_/g, "");
|
||||
|
||||
var valGenerics = extractGenerics(val);
|
||||
|
||||
var paths = valLower.split("::");
|
||||
removeEmptyStringsFromArray(paths);
|
||||
val = paths[paths.length - 1];
|
||||
var contains = paths.slice(0, paths.length > 1 ? paths.length - 1 : 1);
|
||||
|
||||
var lev, j;
|
||||
for (j = 0; j < nSearchWords; ++j) {
|
||||
ty = searchIndex[j];
|
||||
if (!ty || (filterCrates !== null && ty.crate !== filterCrates)) {
|
||||
continue;
|
||||
if (searchWord.indexOf(elem.pathLast) > -1 ||
|
||||
row.normalizedName.indexOf(elem.pathLast) > -1)
|
||||
{
|
||||
// filter type: ... queries
|
||||
if (!results_others[fullId] !== undefined) {
|
||||
index = row.normalizedName.indexOf(elem.pathLast);
|
||||
}
|
||||
var lev_add = 0;
|
||||
if (paths.length > 1) {
|
||||
lev = checkPath(contains, paths[paths.length - 1], ty);
|
||||
if (lev > MAX_LEV_DISTANCE) {
|
||||
continue;
|
||||
} else if (lev > 0) {
|
||||
lev_add = lev / 10;
|
||||
}
|
||||
}
|
||||
lev = levenshtein(searchWord, elem.pathLast);
|
||||
lev += lev_add;
|
||||
if (lev > 0 && elem.pathLast.length > 2 && searchWord.indexOf(elem.pathLast) > -1)
|
||||
{
|
||||
if (elem.pathLast.length < 6) {
|
||||
lev = 1;
|
||||
} else {
|
||||
lev = 0;
|
||||
}
|
||||
}
|
||||
if (lev > MAX_LEV_DISTANCE) {
|
||||
return;
|
||||
} else if (index !== -1 && elem.fullPath.length < 2) {
|
||||
lev -= 1;
|
||||
}
|
||||
if (lev < 0) {
|
||||
lev = 0;
|
||||
}
|
||||
addIntoResults(results_others, fullId, pos, index, lev);
|
||||
}
|
||||
|
||||
returned = MAX_LEV_DISTANCE + 1;
|
||||
in_args = MAX_LEV_DISTANCE + 1;
|
||||
var index = -1;
|
||||
// we want lev results to go lower than others
|
||||
lev = MAX_LEV_DISTANCE + 1;
|
||||
fullId = ty.id;
|
||||
/**
|
||||
* This function is called in case the query has more than one element. In this case, it'll
|
||||
* try to match the items which validates all the elements. For `aa -> bb` will look for
|
||||
* functions which have a parameter `aa` and has `bb` in its returned values.
|
||||
*
|
||||
* @param {Row} row
|
||||
* @param {integer} pos - Position in the `searchIndex`.
|
||||
* @param {Object} results
|
||||
*/
|
||||
function handleArgs(row, pos, results) {
|
||||
if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (searchWords[j].indexOf(split[i]) > -1 ||
|
||||
searchWords[j].indexOf(val) > -1 ||
|
||||
ty.normalizedName.indexOf(val) > -1)
|
||||
{
|
||||
// filter type: ... queries
|
||||
if (typePassesFilter(typeFilter, ty.ty) && results[fullId] === undefined) {
|
||||
index = ty.normalizedName.indexOf(val);
|
||||
}
|
||||
}
|
||||
if ((lev = levenshtein(searchWords[j], val)) <= MAX_LEV_DISTANCE) {
|
||||
if (typePassesFilter(typeFilter, ty.ty)) {
|
||||
lev += 1;
|
||||
var totalLev = 0;
|
||||
var nbLev = 0;
|
||||
var lev;
|
||||
|
||||
// If the result is too "bad", we return false and it ends this search.
|
||||
function checkArgs(elems, callback) {
|
||||
for (var i = 0, len = elems.length; i < len; ++i) {
|
||||
var elem = elems[i];
|
||||
// There is more than one parameter to the query so all checks should be "exact"
|
||||
lev = callback(row, elem, NO_TYPE_FILTER);
|
||||
if (lev <= 1) {
|
||||
nbLev += 1;
|
||||
totalLev += lev;
|
||||
} else {
|
||||
lev = MAX_LEV_DISTANCE + 1;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
in_args = findArg(ty, valGenerics, false, typeFilter);
|
||||
returned = checkReturned(ty, valGenerics, false, typeFilter);
|
||||
return true;
|
||||
}
|
||||
if (!checkArgs(parsedQuery.elems, findArg)) {
|
||||
return;
|
||||
}
|
||||
if (!checkArgs(parsedQuery.returned, checkReturned)) {
|
||||
return;
|
||||
}
|
||||
|
||||
lev += lev_add;
|
||||
if (lev > 0 && val.length > 3 && searchWords[j].indexOf(val) > -1) {
|
||||
if (val.length < 6) {
|
||||
lev -= 1;
|
||||
} else {
|
||||
lev = 0;
|
||||
if (nbLev === 0) {
|
||||
return;
|
||||
}
|
||||
lev = Math.round(totalLev / nbLev);
|
||||
addIntoResults(results, row.id, pos, 0, lev);
|
||||
}
|
||||
|
||||
function innerRunQuery() {
|
||||
var elem, i, nSearchWords, in_returned, row;
|
||||
|
||||
if (parsedQuery.foundElems === 1) {
|
||||
if (parsedQuery.elems.length === 1) {
|
||||
elem = parsedQuery.elems[0];
|
||||
for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
|
||||
// It means we want to check for this element everywhere (in names, args and
|
||||
// returned).
|
||||
handleSingleArg(
|
||||
searchIndex[i],
|
||||
i,
|
||||
elem,
|
||||
results_others,
|
||||
results_in_args,
|
||||
results_returned
|
||||
);
|
||||
}
|
||||
} else if (parsedQuery.returned.length === 1) {
|
||||
// We received one returned argument to check, so looking into returned values.
|
||||
elem = parsedQuery.returned[0];
|
||||
for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
|
||||
row = searchIndex[i];
|
||||
in_returned = checkReturned(row, elem, parsedQuery.typeFilter);
|
||||
addIntoResults(results_returned, row.id, i, -1, in_returned);
|
||||
}
|
||||
}
|
||||
addIntoResults(false, results_in_args, fullId, j, index, in_args);
|
||||
addIntoResults(false, results_returned, fullId, j, index, returned);
|
||||
if (typePassesFilter(typeFilter, ty.ty) &&
|
||||
(index !== -1 || lev <= MAX_LEV_DISTANCE)) {
|
||||
if (index !== -1 && paths.length < 2) {
|
||||
lev = 0;
|
||||
}
|
||||
addIntoResults(false, results, fullId, j, index, lev);
|
||||
} else if (parsedQuery.foundElems > 0) {
|
||||
var container = results_others;
|
||||
// In the special case where only a "returned" information is available, we want to
|
||||
// put the information into the "results_returned" dict.
|
||||
if (parsedQuery.returned.length !== 0 && parsedQuery.elems.length === 0) {
|
||||
container = results_returned;
|
||||
}
|
||||
for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) {
|
||||
handleArgs(searchIndex[i], i, container);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var ret = {
|
||||
"in_args": sortResults(results_in_args, true),
|
||||
"returned": sortResults(results_returned, true),
|
||||
"others": sortResults(results, false),
|
||||
};
|
||||
handleAliases(ret, query, filterCrates);
|
||||
if (parsedQuery.error === null) {
|
||||
innerRunQuery();
|
||||
}
|
||||
|
||||
var ret = createQueryResults(
|
||||
sortResults(results_in_args, true),
|
||||
sortResults(results_returned, true),
|
||||
sortResults(results_others, false),
|
||||
parsedQuery);
|
||||
handleAliases(ret, parsedQuery.original.replace(/"/g, ""), filterCrates);
|
||||
if (parsedQuery.error !== null && ret.others.length !== 0) {
|
||||
// It means some doc aliases were found so let's "remove" the error!
|
||||
ret.query.error = null;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -892,9 +1455,13 @@ window.initSearch = function(rawSearchIndex) {
|
||||
* @param {string} path - The path of the result
|
||||
* @param {string} keys - The keys to be used (["file", "open"])
|
||||
* @param {Object} parent - The parent of the result
|
||||
*
|
||||
* @return {boolean} - Whether the result is valid or not
|
||||
*/
|
||||
function validateResult(name, path, keys, parent) {
|
||||
if (!keys || !keys.length) {
|
||||
return true;
|
||||
}
|
||||
for (var i = 0, len = keys.length; i < len; ++i) {
|
||||
// each check is for validation so we negate the conditions and invalidate
|
||||
if (!(
|
||||
@@ -913,30 +1480,6 @@ window.initSearch = function(rawSearchIndex) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a string into a query object.
|
||||
*
|
||||
* @param {string} raw - The text that the user typed.
|
||||
* @returns {ParsedQuery}
|
||||
*/
|
||||
function getQuery(raw) {
|
||||
var matches, type = "", query;
|
||||
query = raw;
|
||||
|
||||
matches = query.match(/^(fn|mod|struct|enum|trait|type|const|macro)\s*:\s*/i);
|
||||
if (matches) {
|
||||
type = matches[1].replace(/^const$/, "constant");
|
||||
query = query.substring(matches[0].length);
|
||||
}
|
||||
|
||||
return {
|
||||
raw: raw,
|
||||
query: query,
|
||||
type: type,
|
||||
id: query + type
|
||||
};
|
||||
}
|
||||
|
||||
function nextTab(direction) {
|
||||
var next = (searchState.currentTab + direction + 3) % searchState.focusedByTab.length;
|
||||
searchState.focusedByTab[searchState.currentTab] = document.activeElement;
|
||||
@@ -1088,11 +1631,11 @@ window.initSearch = function(rawSearchIndex) {
|
||||
link.appendChild(wrapper);
|
||||
output.appendChild(link);
|
||||
});
|
||||
} else {
|
||||
} else if (query.error === null) {
|
||||
output.className = "search-failed" + extraClass;
|
||||
output.innerHTML = "No results :(<br/>" +
|
||||
"Try on <a href=\"https://duckduckgo.com/?q=" +
|
||||
encodeURIComponent("rust " + query.query) +
|
||||
encodeURIComponent("rust " + query.userQuery) +
|
||||
"\">DuckDuckGo</a>?<br/><br/>" +
|
||||
"Or try looking in one of these:<ul><li>The <a " +
|
||||
"href=\"https://doc.rust-lang.org/reference/index.html\">Rust Reference</a> " +
|
||||
@@ -1115,6 +1658,11 @@ window.initSearch = function(rawSearchIndex) {
|
||||
return "<button>" + text + " <div class=\"count\">(" + nbElems + ")</div></button>";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ResultsTable} results
|
||||
* @param {boolean} go_to_first
|
||||
* @param {string} filterCrates
|
||||
*/
|
||||
function showResults(results, go_to_first, filterCrates) {
|
||||
var search = searchState.outputElement();
|
||||
if (go_to_first || (results.others.length === 1
|
||||
@@ -1132,13 +1680,15 @@ window.initSearch = function(rawSearchIndex) {
|
||||
elem.click();
|
||||
return;
|
||||
}
|
||||
var query = getQuery(searchState.input.value);
|
||||
if (results.query === undefined) {
|
||||
results.query = parseQuery(searchState.input.value);
|
||||
}
|
||||
|
||||
currentResults = query.id;
|
||||
currentResults = results.query.userQuery;
|
||||
|
||||
var ret_others = addTab(results.others, query, true);
|
||||
var ret_in_args = addTab(results.in_args, query, false);
|
||||
var ret_returned = addTab(results.returned, query, false);
|
||||
var ret_others = addTab(results.others, results.query, true);
|
||||
var ret_in_args = addTab(results.in_args, results.query, false);
|
||||
var ret_returned = addTab(results.returned, results.query, false);
|
||||
|
||||
// Navigate to the relevant tab if the current tab is empty, like in case users search
|
||||
// for "-> String". If they had selected another tab previously, they have to click on
|
||||
@@ -1164,11 +1714,19 @@ window.initSearch = function(rawSearchIndex) {
|
||||
}
|
||||
crates += `</select>`;
|
||||
}
|
||||
var output = `<div id="search-settings">
|
||||
<h1 class="search-results-title">Results for ${escape(query.query)} ` +
|
||||
(query.type ? " (type: " + escape(query.type) + ")" : "") + "</h1>" +
|
||||
crates +
|
||||
`</div><div id="titles">` +
|
||||
|
||||
var typeFilter = "";
|
||||
if (results.query.typeFilter !== NO_TYPE_FILTER) {
|
||||
typeFilter = " (type: " + escape(itemTypes[results.query.typeFilter]) + ")";
|
||||
}
|
||||
|
||||
var output = `<div id="search-settings">` +
|
||||
`<h1 class="search-results-title">Results for ${escape(results.query.userQuery)}` +
|
||||
`${typeFilter}</h1> in ${crates} </div>`;
|
||||
if (results.query.error !== null) {
|
||||
output += `<h3>Query parser error: "${results.query.error}".</h3>`;
|
||||
}
|
||||
output += `<div id="titles">` +
|
||||
makeTabHeader(0, "In Names", ret_others[1]) +
|
||||
makeTabHeader(1, "In Parameters", ret_in_args[1]) +
|
||||
makeTabHeader(2, "In Return Types", ret_returned[1]) +
|
||||
@@ -1196,28 +1754,6 @@ window.initSearch = function(rawSearchIndex) {
|
||||
printTab(currentTab);
|
||||
}
|
||||
|
||||
function execSearch(query, searchWords, filterCrates) {
|
||||
query = query.raw.trim();
|
||||
var results = {
|
||||
"in_args": [],
|
||||
"returned": [],
|
||||
"others": [],
|
||||
};
|
||||
|
||||
if (query.length !== 0) {
|
||||
var tmp = execQuery(getQuery(query), searchWords, filterCrates);
|
||||
|
||||
results.in_args.push(tmp.in_args);
|
||||
results.returned.push(tmp.returned);
|
||||
results.others.push(tmp.others);
|
||||
}
|
||||
return {
|
||||
"in_args": results.in_args[0],
|
||||
"returned": results.returned[0],
|
||||
"others": results.others[0],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a search based on the current state of the search input element
|
||||
* and display the results.
|
||||
@@ -1226,17 +1762,14 @@ window.initSearch = function(rawSearchIndex) {
|
||||
*/
|
||||
function search(e, forced) {
|
||||
var params = searchState.getQueryStringParams();
|
||||
var query = getQuery(searchState.input.value.trim());
|
||||
var query = parseQuery(searchState.input.value.trim());
|
||||
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
if (query.query.length === 0) {
|
||||
return;
|
||||
}
|
||||
if (!forced && query.id === currentResults) {
|
||||
if (query.query.length > 0) {
|
||||
if (!forced && query.userQuery === currentResults) {
|
||||
if (query.userQuery.length > 0) {
|
||||
putBackSearch();
|
||||
}
|
||||
return;
|
||||
@@ -1251,13 +1784,12 @@ window.initSearch = function(rawSearchIndex) {
|
||||
}
|
||||
|
||||
// Update document title to maintain a meaningful browser history
|
||||
searchState.title = "Results for " + query.query + " - Rust";
|
||||
searchState.title = "Results for " + query.original + " - Rust";
|
||||
|
||||
// Because searching is incremental by character, only the most
|
||||
// recent search query is added to the browser history.
|
||||
if (searchState.browserSupportsHistoryApi()) {
|
||||
var newURL = buildUrl(query.raw, filterCrates);
|
||||
|
||||
var newURL = buildUrl(query.original, filterCrates);
|
||||
if (!history.state && !params.search) {
|
||||
history.pushState(null, "", newURL);
|
||||
} else {
|
||||
@@ -1265,8 +1797,10 @@ window.initSearch = function(rawSearchIndex) {
|
||||
}
|
||||
}
|
||||
|
||||
showResults(execSearch(query, searchWords, filterCrates),
|
||||
params["go_to_first"], filterCrates);
|
||||
showResults(
|
||||
execQuery(query, searchWords, filterCrates),
|
||||
params.go_to_first,
|
||||
filterCrates);
|
||||
}
|
||||
|
||||
function buildIndex(rawSearchIndex) {
|
||||
|
||||
@@ -25,14 +25,14 @@
|
||||
| '_#2r live at {bb0[0..=1]}
|
||||
| '_#3r live at {bb0[0..=1]}
|
||||
| '_#4r live at {bb0[0..=1]}
|
||||
| '_#1r: '_#6r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27)
|
||||
| '_#1r: '_#8r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55)
|
||||
| '_#2r: '_#7r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43)
|
||||
| '_#3r: '_#9r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67)
|
||||
| '_#6r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27)
|
||||
| '_#7r: '_#2r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43)
|
||||
| '_#8r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55)
|
||||
| '_#9r: '_#3r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67)
|
||||
| '_#1r: '_#6r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27) ($DIR/named-lifetimes-basic.rs:12:26: 12:27 (#0)
|
||||
| '_#1r: '_#8r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55) ($DIR/named-lifetimes-basic.rs:12:54: 12:55 (#0)
|
||||
| '_#2r: '_#7r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43) ($DIR/named-lifetimes-basic.rs:12:42: 12:43 (#0)
|
||||
| '_#3r: '_#9r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67) ($DIR/named-lifetimes-basic.rs:12:66: 12:67 (#0)
|
||||
| '_#6r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27) ($DIR/named-lifetimes-basic.rs:12:26: 12:27 (#0)
|
||||
| '_#7r: '_#2r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43) ($DIR/named-lifetimes-basic.rs:12:42: 12:43 (#0)
|
||||
| '_#8r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55) ($DIR/named-lifetimes-basic.rs:12:54: 12:55 (#0)
|
||||
| '_#9r: '_#3r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67) ($DIR/named-lifetimes-basic.rs:12:66: 12:67 (#0)
|
||||
|
|
||||
fn use_x(_1: &'_#6r mut i32, _2: &'_#7r u32, _3: &'_#8r u32, _4: &'_#9r u32) -> bool {
|
||||
debug w => _1; // in scope 0 at $DIR/named-lifetimes-basic.rs:12:26: 12:27
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
| '_#3r live at {bb1[0]}
|
||||
| '_#4r live at {bb1[1..=3]}
|
||||
| '_#5r live at {bb1[4..=7], bb2[0..=2]}
|
||||
| '_#3r: '_#4r due to Assignment at Single(bb1[0])
|
||||
| '_#4r: '_#5r due to Assignment at Single(bb1[3])
|
||||
| '_#3r: '_#4r due to Assignment at Single(bb1[0]) ($DIR/region-subtyping-basic.rs:18:13: 18:18 (#0)
|
||||
| '_#4r: '_#5r due to Assignment at Single(bb1[3]) ($DIR/region-subtyping-basic.rs:19:13: 19:14 (#0)
|
||||
|
|
||||
fn main() -> () {
|
||||
let mut _0: (); // return place in scope 0 at $DIR/region-subtyping-basic.rs:16:11: 16:11
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
| '_#3r live at {bb1[0]}
|
||||
| '_#4r live at {bb1[1..=3]}
|
||||
| '_#5r live at {bb1[4..=7], bb2[0..=2]}
|
||||
| '_#3r: '_#4r due to Assignment at Single(bb1[0])
|
||||
| '_#4r: '_#5r due to Assignment at Single(bb1[3])
|
||||
| '_#3r: '_#4r due to Assignment at Single(bb1[0]) ($DIR/region-subtyping-basic.rs:18:13: 18:18 (#0)
|
||||
| '_#4r: '_#5r due to Assignment at Single(bb1[3]) ($DIR/region-subtyping-basic.rs:19:13: 19:14 (#0)
|
||||
|
|
||||
fn main() -> () {
|
||||
let mut _0: (); // return place in scope 0 at $DIR/region-subtyping-basic.rs:16:11: 16:11
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
| '_#1r live at {bb0[0..=22]}
|
||||
| '_#3r live at {bb0[10]}
|
||||
| '_#4r live at {bb0[11]}
|
||||
| '_#3r: '_#4r due to Assignment at Single(bb0[10])
|
||||
| '_#3r: '_#4r due to Assignment at Single(bb0[10]) ($DIR/storage_ranges.rs:6:17: 6:25 (#0)
|
||||
|
|
||||
fn main() -> () {
|
||||
let mut _0: (); // return place in scope 0 at $DIR/storage_ranges.rs:3:11: 3:11
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// exact-check
|
||||
|
||||
const QUERY = 'hashmap';
|
||||
const QUERY = '"hashmap"';
|
||||
const FILTER_CRATE = 'core';
|
||||
|
||||
const EXPECTED = {
|
||||
|
||||
@@ -0,0 +1,365 @@
|
||||
const QUERY = [
|
||||
'<P>',
|
||||
'-> <P>',
|
||||
'a<"P">',
|
||||
'"P" "P"',
|
||||
'P "P"',
|
||||
'"p" p',
|
||||
'"const": p',
|
||||
"a<:a>",
|
||||
"a<::a>",
|
||||
"((a))",
|
||||
"(p -> p",
|
||||
"::a::b",
|
||||
"a::::b",
|
||||
"a::b::",
|
||||
":a",
|
||||
"a b:",
|
||||
"a (b:",
|
||||
"_:",
|
||||
"a-bb",
|
||||
"a>bb",
|
||||
"ab'",
|
||||
"a->",
|
||||
'"p" <a>',
|
||||
'"p" a<a>',
|
||||
"a,<",
|
||||
"aaaaa<>b",
|
||||
"fn:aaaaa<>b",
|
||||
"->a<>b",
|
||||
"a<->",
|
||||
"a:: a",
|
||||
"a ::a",
|
||||
"a<a>:",
|
||||
"a<>:",
|
||||
"a,:",
|
||||
" a<> :",
|
||||
"mod : :",
|
||||
];
|
||||
|
||||
const PARSED = [
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "<P>",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "<p>",
|
||||
error: "Found generics without a path",
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "-> <P>",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "-> <p>",
|
||||
error: "Found generics without a path",
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "a<\"P\">",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a<\"p\">",
|
||||
error: "`\"` cannot be used in generics",
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "\"P\" \"P\"",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "\"p\" \"p\"",
|
||||
error: "Cannot have more than one literal search element",
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "P \"P\"",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "p \"p\"",
|
||||
error: "Cannot use literal search when there is more than one element",
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "\"p\" p",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "\"p\" p",
|
||||
error: "You cannot have more than one element if you use quotes",
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "\"const\": p",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "\"const\": p",
|
||||
error: "You cannot use quotes on type filter",
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "a<:a>",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a<:a>",
|
||||
error: "Unexpected `:` after `<`",
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "a<::a>",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a<::a>",
|
||||
error: "Unexpected `::`: paths cannot start with `::`",
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "((a))",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "((a))",
|
||||
error: "Unexpected `(`",
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "(p -> p",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "(p -> p",
|
||||
error: "Unexpected `(`",
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "::a::b",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "::a::b",
|
||||
error: "Paths cannot start with `::`",
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "a::::b",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a::::b",
|
||||
error: "Unexpected `::::`",
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "a::b::",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a::b::",
|
||||
error: "Paths cannot end with `::`",
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: ":a",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: ":a",
|
||||
error: "Expected type filter before `:`",
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "a b:",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a b:",
|
||||
error: "Unexpected `:`",
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "a (b:",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a (b:",
|
||||
error: "Unexpected `(`",
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "_:",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "_:",
|
||||
error: "Unknown type filter `_`",
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "a-bb",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a-bb",
|
||||
error: "Unexpected `-` (did you mean `->`?)",
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "a>bb",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a>bb",
|
||||
error: "Unexpected `>` (did you mean `->`?)",
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "ab'",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "ab'",
|
||||
error: "Unexpected `'`",
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "a->",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a->",
|
||||
error: "Expected at least one item after `->`",
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: '"p" <a>',
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: '"p" <a>',
|
||||
error: "Found generics without a path",
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: '"p" a<a>',
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: '"p" a<a>',
|
||||
error: "You cannot have more than one element if you use quotes",
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: 'a,<',
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: 'a,<',
|
||||
error: 'Found generics without a path',
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: 'aaaaa<>b',
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: 'aaaaa<>b',
|
||||
error: 'Expected `,`, ` `, `:` or `->`, found `b`',
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: 'fn:aaaaa<>b',
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: 'fn:aaaaa<>b',
|
||||
error: 'Expected `,`, ` ` or `->`, found `b`',
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: '->a<>b',
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: '->a<>b',
|
||||
error: 'Expected `,` or ` `, found `b`',
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: 'a<->',
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: 'a<->',
|
||||
error: 'Unexpected `-` after `<`',
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: 'a:: a',
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: 'a:: a',
|
||||
error: 'Paths cannot end with `::`',
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: 'a ::a',
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: 'a ::a',
|
||||
error: 'Paths cannot start with `::`',
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "a<a>:",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a<a>:",
|
||||
error: 'Unexpected `:`',
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "a<>:",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a<>:",
|
||||
error: 'Unexpected `<` in type filter',
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "a,:",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a,:",
|
||||
error: 'Unexpected `,` in type filter',
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "a<> :",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a<> :",
|
||||
error: 'Unexpected `<` in type filter',
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "mod : :",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "mod : :",
|
||||
error: 'Unexpected `:`',
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,43 @@
|
||||
const QUERY = ['fn:foo', 'enum : foo', 'macro<f>:foo'];
|
||||
|
||||
const PARSED = [
|
||||
{
|
||||
elems: [{
|
||||
name: "foo",
|
||||
fullPath: ["foo"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "foo",
|
||||
generics: [],
|
||||
}],
|
||||
foundElems: 1,
|
||||
original: "fn:foo",
|
||||
returned: [],
|
||||
typeFilter: 5,
|
||||
userQuery: "fn:foo",
|
||||
error: null,
|
||||
},
|
||||
{
|
||||
elems: [{
|
||||
name: "foo",
|
||||
fullPath: ["foo"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "foo",
|
||||
generics: [],
|
||||
}],
|
||||
foundElems: 1,
|
||||
original: "enum : foo",
|
||||
returned: [],
|
||||
typeFilter: 4,
|
||||
userQuery: "enum : foo",
|
||||
error: null,
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "macro<f>:foo",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "macro<f>:foo",
|
||||
error: "Unexpected `:`",
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,62 @@
|
||||
const QUERY = ['A<B<C<D>, E>', 'p<> u8', '"p"<a>'];
|
||||
|
||||
const PARSED = [
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: 'A<B<C<D>, E>',
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: 'a<b<c<d>, e>',
|
||||
error: 'Unexpected `<` after `<`',
|
||||
},
|
||||
{
|
||||
elems: [
|
||||
{
|
||||
name: "p",
|
||||
fullPath: ["p"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "p",
|
||||
generics: [],
|
||||
},
|
||||
{
|
||||
name: "u8",
|
||||
fullPath: ["u8"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "u8",
|
||||
generics: [],
|
||||
},
|
||||
],
|
||||
foundElems: 2,
|
||||
original: "p<> u8",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "p<> u8",
|
||||
error: null,
|
||||
},
|
||||
{
|
||||
elems: [
|
||||
{
|
||||
name: "p",
|
||||
fullPath: ["p"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "p",
|
||||
generics: [
|
||||
{
|
||||
name: "a",
|
||||
fullPath: ["a"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "a",
|
||||
generics: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
foundElems: 1,
|
||||
original: '"p"<a>',
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: '"p"<a>',
|
||||
error: null,
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,27 @@
|
||||
const QUERY = ['R<P>'];
|
||||
|
||||
const PARSED = [
|
||||
{
|
||||
elems: [{
|
||||
name: "r",
|
||||
fullPath: ["r"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "r",
|
||||
generics: [
|
||||
{
|
||||
name: "p",
|
||||
fullPath: ["p"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "p",
|
||||
generics: [],
|
||||
},
|
||||
],
|
||||
}],
|
||||
foundElems: 1,
|
||||
original: "R<P>",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "r<p>",
|
||||
error: null,
|
||||
}
|
||||
];
|
||||
@@ -0,0 +1,90 @@
|
||||
const QUERY = ['A::B', 'A::B,C', 'A::B<f>,C', 'mod::a'];
|
||||
|
||||
const PARSED = [
|
||||
{
|
||||
elems: [{
|
||||
name: "a::b",
|
||||
fullPath: ["a", "b"],
|
||||
pathWithoutLast: ["a"],
|
||||
pathLast: "b",
|
||||
generics: [],
|
||||
}],
|
||||
foundElems: 1,
|
||||
original: "A::B",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a::b",
|
||||
error: null,
|
||||
},
|
||||
{
|
||||
elems: [
|
||||
{
|
||||
name: "a::b",
|
||||
fullPath: ["a", "b"],
|
||||
pathWithoutLast: ["a"],
|
||||
pathLast: "b",
|
||||
generics: [],
|
||||
},
|
||||
{
|
||||
name: "c",
|
||||
fullPath: ["c"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "c",
|
||||
generics: [],
|
||||
},
|
||||
],
|
||||
foundElems: 2,
|
||||
original: 'A::B,C',
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: 'a::b,c',
|
||||
error: null,
|
||||
},
|
||||
{
|
||||
elems: [
|
||||
{
|
||||
name: "a::b",
|
||||
fullPath: ["a", "b"],
|
||||
pathWithoutLast: ["a"],
|
||||
pathLast: "b",
|
||||
generics: [
|
||||
{
|
||||
name: "f",
|
||||
fullPath: ["f"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "f",
|
||||
generics: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "c",
|
||||
fullPath: ["c"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "c",
|
||||
generics: [],
|
||||
},
|
||||
],
|
||||
foundElems: 2,
|
||||
original: 'A::B<f>,C',
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: 'a::b<f>,c',
|
||||
error: null,
|
||||
},
|
||||
{
|
||||
elems: [{
|
||||
name: "mod::a",
|
||||
fullPath: ["mod", "a"],
|
||||
pathWithoutLast: ["mod"],
|
||||
pathLast: "a",
|
||||
generics: [],
|
||||
}],
|
||||
foundElems: 1,
|
||||
original: "mod::a",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "mod::a",
|
||||
error: null,
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,87 @@
|
||||
const QUERY = [
|
||||
'-> "p"',
|
||||
'"p",',
|
||||
'"p" -> a',
|
||||
'"a" -> "p"',
|
||||
'->"-"',
|
||||
'"a',
|
||||
'""',
|
||||
];
|
||||
|
||||
const PARSED = [
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 1,
|
||||
original: '-> "p"',
|
||||
returned: [{
|
||||
name: "p",
|
||||
fullPath: ["p"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "p",
|
||||
generics: [],
|
||||
}],
|
||||
typeFilter: -1,
|
||||
userQuery: '-> "p"',
|
||||
error: null,
|
||||
},
|
||||
{
|
||||
elems: [{
|
||||
name: "p",
|
||||
fullPath: ["p"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "p",
|
||||
generics: [],
|
||||
}],
|
||||
foundElems: 1,
|
||||
original: '"p",',
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: '"p",',
|
||||
error: null,
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: '"p" -> a',
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: '"p" -> a',
|
||||
error: "You cannot have more than one element if you use quotes",
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: '"a" -> "p"',
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: '"a" -> "p"',
|
||||
error: "Cannot have more than one literal search element",
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: '->"-"',
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: '->"-"',
|
||||
error: 'Unexpected `-` in a string element',
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: '"a',
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: '"a',
|
||||
error: 'Unclosed `"`',
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: '""',
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: '""',
|
||||
error: 'Cannot have empty string element',
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,78 @@
|
||||
const QUERY = ['-> F<P>', '-> P', '->,a', 'aaaaa->a'];
|
||||
|
||||
const PARSED = [
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 1,
|
||||
original: "-> F<P>",
|
||||
returned: [{
|
||||
name: "f",
|
||||
fullPath: ["f"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "f",
|
||||
generics: [
|
||||
{
|
||||
name: "p",
|
||||
fullPath: ["p"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "p",
|
||||
generics: [],
|
||||
},
|
||||
],
|
||||
}],
|
||||
typeFilter: -1,
|
||||
userQuery: "-> f<p>",
|
||||
error: null,
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 1,
|
||||
original: "-> P",
|
||||
returned: [{
|
||||
name: "p",
|
||||
fullPath: ["p"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "p",
|
||||
generics: [],
|
||||
}],
|
||||
typeFilter: -1,
|
||||
userQuery: "-> p",
|
||||
error: null,
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 1,
|
||||
original: "->,a",
|
||||
returned: [{
|
||||
name: "a",
|
||||
fullPath: ["a"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "a",
|
||||
generics: [],
|
||||
}],
|
||||
typeFilter: -1,
|
||||
userQuery: "->,a",
|
||||
error: null,
|
||||
},
|
||||
{
|
||||
elems: [{
|
||||
name: "aaaaa",
|
||||
fullPath: ["aaaaa"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "aaaaa",
|
||||
generics: [],
|
||||
}],
|
||||
foundElems: 2,
|
||||
original: "aaaaa->a",
|
||||
returned: [{
|
||||
name: "a",
|
||||
fullPath: ["a"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "a",
|
||||
generics: [],
|
||||
}],
|
||||
typeFilter: -1,
|
||||
userQuery: "aaaaa->a",
|
||||
error: null,
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,206 @@
|
||||
// ignore-tidy-tab
|
||||
|
||||
const QUERY = [
|
||||
'aaaaaa b',
|
||||
'a b',
|
||||
'a,b',
|
||||
'a\tb',
|
||||
'a<b c>',
|
||||
'a<b,c>',
|
||||
'a<b\tc>',
|
||||
];
|
||||
|
||||
const PARSED = [
|
||||
{
|
||||
elems: [
|
||||
{
|
||||
name: 'aaaaaa',
|
||||
fullPath: ['aaaaaa'],
|
||||
pathWithoutLast: [],
|
||||
pathLast: 'aaaaaa',
|
||||
generics: [],
|
||||
},
|
||||
{
|
||||
name: 'b',
|
||||
fullPath: ['b'],
|
||||
pathWithoutLast: [],
|
||||
pathLast: 'b',
|
||||
generics: [],
|
||||
},
|
||||
],
|
||||
foundElems: 2,
|
||||
original: "aaaaaa b",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "aaaaaa b",
|
||||
error: null,
|
||||
},
|
||||
{
|
||||
elems: [
|
||||
{
|
||||
name: 'a',
|
||||
fullPath: ['a'],
|
||||
pathWithoutLast: [],
|
||||
pathLast: 'a',
|
||||
generics: [],
|
||||
},
|
||||
{
|
||||
name: 'b',
|
||||
fullPath: ['b'],
|
||||
pathWithoutLast: [],
|
||||
pathLast: 'b',
|
||||
generics: [],
|
||||
},
|
||||
],
|
||||
foundElems: 2,
|
||||
original: "a b",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a b",
|
||||
error: null,
|
||||
},
|
||||
{
|
||||
elems: [
|
||||
{
|
||||
name: 'a',
|
||||
fullPath: ['a'],
|
||||
pathWithoutLast: [],
|
||||
pathLast: 'a',
|
||||
generics: [],
|
||||
},
|
||||
{
|
||||
name: 'b',
|
||||
fullPath: ['b'],
|
||||
pathWithoutLast: [],
|
||||
pathLast: 'b',
|
||||
generics: [],
|
||||
},
|
||||
],
|
||||
foundElems: 2,
|
||||
original: "a,b",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a,b",
|
||||
error: null,
|
||||
},
|
||||
{
|
||||
elems: [
|
||||
{
|
||||
name: 'a',
|
||||
fullPath: ['a'],
|
||||
pathWithoutLast: [],
|
||||
pathLast: 'a',
|
||||
generics: [],
|
||||
},
|
||||
{
|
||||
name: 'b',
|
||||
fullPath: ['b'],
|
||||
pathWithoutLast: [],
|
||||
pathLast: 'b',
|
||||
generics: [],
|
||||
},
|
||||
],
|
||||
foundElems: 2,
|
||||
original: "a\tb",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a\tb",
|
||||
error: null,
|
||||
},
|
||||
{
|
||||
elems: [
|
||||
{
|
||||
name: 'a',
|
||||
fullPath: ['a'],
|
||||
pathWithoutLast: [],
|
||||
pathLast: 'a',
|
||||
generics: [
|
||||
{
|
||||
name: 'b',
|
||||
fullPath: ['b'],
|
||||
pathWithoutLast: [],
|
||||
pathLast: 'b',
|
||||
generics: [],
|
||||
},
|
||||
{
|
||||
name: 'c',
|
||||
fullPath: ['c'],
|
||||
pathWithoutLast: [],
|
||||
pathLast: 'c',
|
||||
generics: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
foundElems: 1,
|
||||
original: "a<b c>",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a<b c>",
|
||||
error: null,
|
||||
},
|
||||
{
|
||||
elems: [
|
||||
{
|
||||
name: 'a',
|
||||
fullPath: ['a'],
|
||||
pathWithoutLast: [],
|
||||
pathLast: 'a',
|
||||
generics: [
|
||||
{
|
||||
name: 'b',
|
||||
fullPath: ['b'],
|
||||
pathWithoutLast: [],
|
||||
pathLast: 'b',
|
||||
generics: [],
|
||||
},
|
||||
{
|
||||
name: 'c',
|
||||
fullPath: ['c'],
|
||||
pathWithoutLast: [],
|
||||
pathLast: 'c',
|
||||
generics: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
foundElems: 1,
|
||||
original: "a<b,c>",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a<b,c>",
|
||||
error: null,
|
||||
},
|
||||
{
|
||||
elems: [
|
||||
{
|
||||
name: 'a',
|
||||
fullPath: ['a'],
|
||||
pathWithoutLast: [],
|
||||
pathLast: 'a',
|
||||
generics: [
|
||||
{
|
||||
name: 'b',
|
||||
fullPath: ['b'],
|
||||
pathWithoutLast: [],
|
||||
pathLast: 'b',
|
||||
generics: [],
|
||||
},
|
||||
{
|
||||
name: 'c',
|
||||
fullPath: ['c'],
|
||||
pathWithoutLast: [],
|
||||
pathLast: 'c',
|
||||
generics: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
foundElems: 1,
|
||||
original: "a<b\tc>",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a<b\tc>",
|
||||
error: null,
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,123 @@
|
||||
// This test is mostly to check that the parser still kinda outputs something
|
||||
// (and doesn't enter an infinite loop!) even though the query is completely
|
||||
// invalid.
|
||||
const QUERY = [
|
||||
'a b',
|
||||
'a b',
|
||||
'a,b(c)',
|
||||
'aaa,a',
|
||||
',,,,',
|
||||
'mod :',
|
||||
'mod\t:',
|
||||
];
|
||||
|
||||
const PARSED = [
|
||||
{
|
||||
elems: [
|
||||
{
|
||||
name: "a",
|
||||
fullPath: ["a"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "a",
|
||||
generics: [],
|
||||
},
|
||||
{
|
||||
name: "b",
|
||||
fullPath: ["b"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "b",
|
||||
generics: [],
|
||||
},
|
||||
],
|
||||
foundElems: 2,
|
||||
original: "a b",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a b",
|
||||
error: null,
|
||||
},
|
||||
{
|
||||
elems: [
|
||||
{
|
||||
name: "a",
|
||||
fullPath: ["a"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "a",
|
||||
generics: [],
|
||||
},
|
||||
{
|
||||
name: "b",
|
||||
fullPath: ["b"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "b",
|
||||
generics: [],
|
||||
},
|
||||
],
|
||||
foundElems: 2,
|
||||
original: "a b",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a b",
|
||||
error: null,
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: "a,b(c)",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "a,b(c)",
|
||||
error: "Unexpected `(`",
|
||||
},
|
||||
{
|
||||
elems: [
|
||||
{
|
||||
name: "aaa",
|
||||
fullPath: ["aaa"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "aaa",
|
||||
generics: [],
|
||||
},
|
||||
{
|
||||
name: "a",
|
||||
fullPath: ["a"],
|
||||
pathWithoutLast: [],
|
||||
pathLast: "a",
|
||||
generics: [],
|
||||
},
|
||||
],
|
||||
foundElems: 2,
|
||||
original: "aaa,a",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: "aaa,a",
|
||||
error: null,
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: ",,,,",
|
||||
returned: [],
|
||||
typeFilter: -1,
|
||||
userQuery: ",,,,",
|
||||
error: null,
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: 'mod :',
|
||||
returned: [],
|
||||
typeFilter: 0,
|
||||
userQuery: 'mod :',
|
||||
error: null,
|
||||
},
|
||||
{
|
||||
elems: [],
|
||||
foundElems: 0,
|
||||
original: 'mod\t:',
|
||||
returned: [],
|
||||
typeFilter: 0,
|
||||
userQuery: 'mod\t:',
|
||||
error: null,
|
||||
},
|
||||
];
|
||||
@@ -1,4 +1,7 @@
|
||||
// ignore-order
|
||||
|
||||
const QUERY = '"error"';
|
||||
const FILTER_CRATE = 'std';
|
||||
|
||||
const EXPECTED = {
|
||||
'others': [
|
||||
@@ -6,7 +9,12 @@ const EXPECTED = {
|
||||
{ 'path': 'std::fmt', 'name': 'Error' },
|
||||
{ 'path': 'std::io', 'name': 'Error' },
|
||||
],
|
||||
'in_args': [],
|
||||
'in_args': [
|
||||
{ 'path': 'std::fmt::Error', 'name': 'eq' },
|
||||
{ 'path': 'std::fmt::Error', 'name': 'cmp' },
|
||||
{ 'path': 'std::fmt::Error', 'name': 'partial_cmp' },
|
||||
|
||||
],
|
||||
'returned': [
|
||||
{ 'path': 'std::fmt::LowerExp', 'name': 'fmt' },
|
||||
],
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
const QUERY = 'struct:Vec';
|
||||
const QUERY = 'struct:VecD';
|
||||
|
||||
const EXPECTED = {
|
||||
'others': [
|
||||
{ 'path': 'std::vec', 'name': 'Vec' },
|
||||
{ 'path': 'std::collections', 'name': 'VecDeque' },
|
||||
{ 'path': 'std::vec', 'name': 'Vec' },
|
||||
],
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// exact-check
|
||||
|
||||
const QUERY = 'macro:print';
|
||||
const FILTER_CRATE = 'std';
|
||||
|
||||
const EXPECTED = {
|
||||
'others': [
|
||||
@@ -9,6 +10,8 @@ const EXPECTED = {
|
||||
{ 'path': 'std', 'name': 'println' },
|
||||
{ 'path': 'std', 'name': 'eprintln' },
|
||||
{ 'path': 'std::pin', 'name': 'pin' },
|
||||
{ 'path': 'core::pin', 'name': 'pin' },
|
||||
{ 'path': 'std::future', 'name': 'join' },
|
||||
{ 'path': 'std', 'name': 'line' },
|
||||
{ 'path': 'std', 'name': 'write' },
|
||||
],
|
||||
};
|
||||
|
||||
@@ -4,6 +4,6 @@ const EXPECTED = {
|
||||
'others': [
|
||||
{ 'path': 'std::vec::Vec', 'name': 'new' },
|
||||
{ 'path': 'std::vec::Vec', 'name': 'ne' },
|
||||
{ 'path': 'std::rc::Rc', 'name': 'ne' },
|
||||
{ 'path': 'alloc::vec::Vec', 'name': 'ne' },
|
||||
],
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// exact-check
|
||||
|
||||
const QUERY = 'true';
|
||||
const QUERY = '"true"';
|
||||
|
||||
const FILTER_CRATE = 'doc_alias_filter';
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ const QUERY = [
|
||||
|
||||
const EXPECTED = [
|
||||
{
|
||||
// StructItem
|
||||
'others': [
|
||||
{
|
||||
'path': 'doc_alias',
|
||||
@@ -38,6 +39,7 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
// StructFieldItem
|
||||
'others': [
|
||||
{
|
||||
'path': 'doc_alias::Struct',
|
||||
@@ -49,6 +51,7 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
// StructMethodItem
|
||||
'others': [
|
||||
{
|
||||
'path': 'doc_alias::Struct',
|
||||
@@ -76,6 +79,7 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
// ImplTraitFunction
|
||||
'others': [
|
||||
{
|
||||
'path': 'doc_alias::Struct',
|
||||
@@ -87,6 +91,7 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
// EnumItem
|
||||
'others': [
|
||||
{
|
||||
'path': 'doc_alias',
|
||||
@@ -98,6 +103,7 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
// VariantItem
|
||||
'others': [
|
||||
{
|
||||
'path': 'doc_alias::Enum',
|
||||
@@ -109,6 +115,7 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
// EnumMethodItem
|
||||
'others': [
|
||||
{
|
||||
'path': 'doc_alias::Enum',
|
||||
@@ -120,6 +127,7 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
// TypedefItem
|
||||
'others': [
|
||||
{
|
||||
'path': 'doc_alias',
|
||||
@@ -131,6 +139,7 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
// TraitItem
|
||||
'others': [
|
||||
{
|
||||
'path': 'doc_alias',
|
||||
@@ -142,6 +151,7 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
// TraitTypeItem
|
||||
'others': [
|
||||
{
|
||||
'path': 'doc_alias::Trait',
|
||||
@@ -153,6 +163,7 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
// AssociatedConstItem
|
||||
'others': [
|
||||
{
|
||||
'path': 'doc_alias::Trait',
|
||||
@@ -164,6 +175,7 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
// TraitFunctionItem
|
||||
'others': [
|
||||
{
|
||||
'path': 'doc_alias::Trait',
|
||||
@@ -175,6 +187,7 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
// FunctionItem
|
||||
'others': [
|
||||
{
|
||||
'path': 'doc_alias',
|
||||
@@ -186,6 +199,7 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
// ModuleItem
|
||||
'others': [
|
||||
{
|
||||
'path': 'doc_alias',
|
||||
@@ -197,6 +211,7 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
// ConstItem
|
||||
'others': [
|
||||
{
|
||||
'path': 'doc_alias',
|
||||
@@ -212,6 +227,7 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
// StaticItem
|
||||
'others': [
|
||||
{
|
||||
'path': 'doc_alias',
|
||||
@@ -223,6 +239,7 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
// UnionItem
|
||||
'others': [
|
||||
{
|
||||
'path': 'doc_alias',
|
||||
@@ -240,6 +257,7 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
// UnionFieldItem
|
||||
'others': [
|
||||
{
|
||||
'path': 'doc_alias::Union',
|
||||
@@ -251,6 +269,7 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
// UnionMethodItem
|
||||
'others': [
|
||||
{
|
||||
'path': 'doc_alias::Union',
|
||||
@@ -262,6 +281,7 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
// MacroItem
|
||||
'others': [
|
||||
{
|
||||
'path': 'doc_alias',
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
// exact-check
|
||||
|
||||
const QUERY = [
|
||||
'"R<P>"',
|
||||
'R<P>',
|
||||
'"P"',
|
||||
'P',
|
||||
'"ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti>"',
|
||||
'ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti>',
|
||||
'TraitCat',
|
||||
'TraitDog',
|
||||
'Result<String>',
|
||||
];
|
||||
|
||||
const EXPECTED = [
|
||||
{
|
||||
// R<P>
|
||||
'returned': [
|
||||
{ 'path': 'generics', 'name': 'alef' },
|
||||
],
|
||||
@@ -19,6 +21,7 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
// "P"
|
||||
'others': [
|
||||
{ 'path': 'generics', 'name': 'P' },
|
||||
],
|
||||
@@ -30,29 +33,41 @@ const EXPECTED = [
|
||||
],
|
||||
},
|
||||
{
|
||||
// P
|
||||
'returned': [
|
||||
{ 'path': 'generics', 'name': 'alef' },
|
||||
{ 'path': 'generics', 'name': 'bet' },
|
||||
],
|
||||
'in_args': [
|
||||
{ 'path': 'generics', 'name': 'alpha' },
|
||||
{ 'path': 'generics', 'name': 'beta' },
|
||||
],
|
||||
},
|
||||
{
|
||||
// "ExtraCreditStructMulti"<ExtraCreditInnerMulti, ExtraCreditInnerMulti>
|
||||
'in_args': [
|
||||
{ 'path': 'generics', 'name': 'extracreditlabhomework' },
|
||||
],
|
||||
'returned': [],
|
||||
},
|
||||
{
|
||||
// TraitCat
|
||||
'in_args': [
|
||||
{ 'path': 'generics', 'name': 'gamma' },
|
||||
],
|
||||
},
|
||||
{
|
||||
// TraitDog
|
||||
'in_args': [
|
||||
{ 'path': 'generics', 'name': 'gamma' },
|
||||
],
|
||||
},
|
||||
{
|
||||
// Result<String>
|
||||
'others': [],
|
||||
'returned': [
|
||||
{ 'path': 'generics', 'name': 'super_soup' },
|
||||
],
|
||||
'in_args': [
|
||||
{ 'path': 'generics', 'name': 'super_soup' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -24,3 +24,5 @@ pub trait TraitCat {}
|
||||
pub trait TraitDog {}
|
||||
|
||||
pub fn gamma<T: TraitCat + TraitDog>(t: T) {}
|
||||
|
||||
pub fn super_soup(s: Result<String, i32>) -> Result<String, i32> { s }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
error: implementation of `FnOnce` is not general enough
|
||||
--> $DIR/rfc1623.rs:36:8
|
||||
--> $DIR/rfc1623.rs:32:8
|
||||
|
|
||||
LL | f: &id,
|
||||
| ^^^ implementation of `FnOnce` is not general enough
|
||||
|
||||
@@ -1,63 +1,35 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/rfc1623.rs:29:35
|
||||
--> $DIR/rfc1623.rs:32:8
|
||||
|
|
||||
LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
|
||||
| ___________________________________^
|
||||
LL | |
|
||||
LL | |
|
||||
LL | |
|
||||
... |
|
||||
LL | |
|
||||
LL | | };
|
||||
| |_^ one type is more general than the other
|
||||
LL | f: &id,
|
||||
| ^^^ one type is more general than the other
|
||||
|
|
||||
= note: expected type `for<'a, 'b> Fn<(&'a Foo<'b>,)>`
|
||||
found type `Fn<(&Foo<'_>,)>`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/rfc1623.rs:29:35
|
||||
--> $DIR/rfc1623.rs:32:8
|
||||
|
|
||||
LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
|
||||
| ___________________________________^
|
||||
LL | |
|
||||
LL | |
|
||||
LL | |
|
||||
... |
|
||||
LL | |
|
||||
LL | | };
|
||||
| |_^ one type is more general than the other
|
||||
LL | f: &id,
|
||||
| ^^^ one type is more general than the other
|
||||
|
|
||||
= note: expected type `for<'a, 'b> Fn<(&'a Foo<'b>,)>`
|
||||
found type `Fn<(&Foo<'_>,)>`
|
||||
|
||||
error: implementation of `FnOnce` is not general enough
|
||||
--> $DIR/rfc1623.rs:29:35
|
||||
--> $DIR/rfc1623.rs:32:8
|
||||
|
|
||||
LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
|
||||
| ___________________________________^
|
||||
LL | |
|
||||
LL | |
|
||||
LL | |
|
||||
... |
|
||||
LL | |
|
||||
LL | | };
|
||||
| |_^ implementation of `FnOnce` is not general enough
|
||||
LL | f: &id,
|
||||
| ^^^ implementation of `FnOnce` is not general enough
|
||||
|
|
||||
= note: `fn(&'2 Foo<'_>) -> &'2 Foo<'_> {id::<&'2 Foo<'_>>}` must implement `FnOnce<(&'1 Foo<'b>,)>`, for any lifetime `'1`...
|
||||
= note: ...but it actually implements `FnOnce<(&'2 Foo<'_>,)>`, for some specific lifetime `'2`
|
||||
|
||||
error: implementation of `FnOnce` is not general enough
|
||||
--> $DIR/rfc1623.rs:29:35
|
||||
--> $DIR/rfc1623.rs:32:8
|
||||
|
|
||||
LL | static SOME_STRUCT: &SomeStruct = &SomeStruct {
|
||||
| ___________________________________^
|
||||
LL | |
|
||||
LL | |
|
||||
LL | |
|
||||
... |
|
||||
LL | |
|
||||
LL | | };
|
||||
| |_^ implementation of `FnOnce` is not general enough
|
||||
LL | f: &id,
|
||||
| ^^^ implementation of `FnOnce` is not general enough
|
||||
|
|
||||
= note: `fn(&Foo<'2>) -> &Foo<'2> {id::<&Foo<'2>>}` must implement `FnOnce<(&'a Foo<'1>,)>`, for any lifetime `'1`...
|
||||
= note: ...but it actually implements `FnOnce<(&Foo<'2>,)>`, for some specific lifetime `'2`
|
||||
|
||||
@@ -27,14 +27,14 @@ fn id<T>(t: T) -> T {
|
||||
}
|
||||
|
||||
static SOME_STRUCT: &SomeStruct = &SomeStruct {
|
||||
//[nll]~^ ERROR mismatched types
|
||||
//[nll]~| ERROR mismatched types
|
||||
//[nll]~| ERROR implementation of `FnOnce` is not general enough
|
||||
//[nll]~| ERROR implementation of `FnOnce` is not general enough
|
||||
foo: &Foo { bools: &[false, true] },
|
||||
bar: &Bar { bools: &[true, true] },
|
||||
f: &id,
|
||||
//[base]~^ ERROR implementation of `FnOnce` is not general enough
|
||||
//[nll]~^^ ERROR mismatched types
|
||||
//[nll]~| ERROR mismatched types
|
||||
//[nll]~| ERROR implementation of `FnOnce` is not general enough
|
||||
//[nll]~| ERROR implementation of `FnOnce` is not general enough
|
||||
};
|
||||
|
||||
// very simple test for a 'static static with default lifetime
|
||||
|
||||
+149
-21
@@ -58,7 +58,8 @@ function extractFunction(content, functionName) {
|
||||
} while (pos < content.length && content[pos] !== '/' && content[pos - 1] !== '*');
|
||||
|
||||
// Eat quoted strings
|
||||
} else if (content[pos] === '"' || content[pos] === "'" || content[pos] === "`") {
|
||||
} else if ((content[pos] === '"' || content[pos] === "'" || content[pos] === "`") &&
|
||||
(pos === 0 || content[pos - 1] !== '/')) {
|
||||
stop = content[pos];
|
||||
do {
|
||||
if (content[pos] === '\\') {
|
||||
@@ -269,8 +270,13 @@ function loadSearchJsAndIndex(searchJs, searchIndex, storageJs, crate) {
|
||||
// execQuery last parameter is built in buildIndex.
|
||||
// buildIndex requires the hashmap from search-index.
|
||||
var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult",
|
||||
"handleAliases", "getQuery", "buildIndex", "execQuery", "execSearch",
|
||||
"removeEmptyStringsFromArray"];
|
||||
"buildIndex", "execQuery", "parseQuery", "createQueryResults",
|
||||
"isWhitespace", "isSpecialStartCharacter", "isStopCharacter",
|
||||
"parseInput", "getItemsBefore", "getNextElem", "createQueryElement",
|
||||
"isReturnArrow", "isPathStart", "getStringElem", "newParsedQuery",
|
||||
"itemTypeFromName", "isEndCharacter", "isErrorCharacter",
|
||||
"isIdentCharacter", "isSeparatorCharacter", "getIdentEndPosition",
|
||||
"checkExtraTypeFilterCharacters", "isWhitespaceCharacter"];
|
||||
|
||||
const functions = ["hasOwnPropertyRustdoc", "onEach"];
|
||||
ALIASES = {};
|
||||
@@ -286,12 +292,99 @@ function loadSearchJsAndIndex(searchJs, searchIndex, storageJs, crate) {
|
||||
return [loaded, index];
|
||||
}
|
||||
|
||||
// This function checks if `expected` has all the required fields needed for the checks.
|
||||
function checkNeededFields(fullPath, expected, error_text, queryName, position) {
|
||||
let fieldsToCheck;
|
||||
if (fullPath.length === 0) {
|
||||
fieldsToCheck = [
|
||||
"foundElems",
|
||||
"original",
|
||||
"returned",
|
||||
"typeFilter",
|
||||
"userQuery",
|
||||
"error",
|
||||
];
|
||||
} else if (fullPath.endsWith("elems") || fullPath.endsWith("generics")) {
|
||||
fieldsToCheck = [
|
||||
"name",
|
||||
"fullPath",
|
||||
"pathWithoutLast",
|
||||
"pathLast",
|
||||
"generics",
|
||||
];
|
||||
} else {
|
||||
fieldsToCheck = [];
|
||||
}
|
||||
for (var i = 0; i < fieldsToCheck.length; ++i) {
|
||||
const field = fieldsToCheck[i];
|
||||
if (!expected.hasOwnProperty(field)) {
|
||||
let text = `${queryName}==> Mandatory key \`${field}\` is not present`;
|
||||
if (fullPath.length > 0) {
|
||||
text += ` in field \`${fullPath}\``;
|
||||
if (position != null) {
|
||||
text += ` (position ${position})`;
|
||||
}
|
||||
}
|
||||
error_text.push(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function valueCheck(fullPath, expected, result, error_text, queryName) {
|
||||
if (Array.isArray(expected)) {
|
||||
for (var i = 0; i < expected.length; ++i) {
|
||||
checkNeededFields(fullPath, expected[i], error_text, queryName, i);
|
||||
if (i >= result.length) {
|
||||
error_text.push(`${queryName}==> EXPECTED has extra value in array from field ` +
|
||||
`\`${fullPath}\` (position ${i}): \`${JSON.stringify(expected[i])}\``);
|
||||
} else {
|
||||
valueCheck(fullPath + '[' + i + ']', expected[i], result[i], error_text, queryName);
|
||||
}
|
||||
}
|
||||
for (; i < result.length; ++i) {
|
||||
error_text.push(`${queryName}==> RESULT has extra value in array from field ` +
|
||||
`\`${fullPath}\` (position ${i}): \`${JSON.stringify(result[i])}\` ` +
|
||||
'compared to EXPECTED');
|
||||
}
|
||||
} else if (expected !== null && typeof expected !== "undefined" &&
|
||||
expected.constructor == Object)
|
||||
{
|
||||
for (const key in expected) {
|
||||
if (!expected.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
if (!result.hasOwnProperty(key)) {
|
||||
error_text.push('==> Unknown key "' + key + '"');
|
||||
break;
|
||||
}
|
||||
const obj_path = fullPath + (fullPath.length > 0 ? '.' : '') + key;
|
||||
valueCheck(obj_path, expected[key], result[key], error_text, queryName);
|
||||
}
|
||||
} else {
|
||||
expectedValue = JSON.stringify(expected);
|
||||
resultValue = JSON.stringify(result);
|
||||
if (expectedValue != resultValue) {
|
||||
error_text.push(`${queryName}==> Different values for field \`${fullPath}\`:\n` +
|
||||
`EXPECTED: \`${expectedValue}\`\nRESULT: \`${resultValue}\``);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function runParser(query, expected, loaded, loadedFile, queryName) {
|
||||
var error_text = [];
|
||||
checkNeededFields("", expected, error_text, queryName, null);
|
||||
if (error_text.length === 0) {
|
||||
valueCheck('', expected, loaded.parseQuery(query), error_text, queryName);
|
||||
}
|
||||
return error_text;
|
||||
}
|
||||
|
||||
function runSearch(query, expected, index, loaded, loadedFile, queryName) {
|
||||
const filter_crate = loadedFile.FILTER_CRATE;
|
||||
const ignore_order = loadedFile.ignore_order;
|
||||
const exact_check = loadedFile.exact_check;
|
||||
|
||||
var results = loaded.execSearch(loaded.getQuery(query), index, filter_crate);
|
||||
var results = loaded.execQuery(loaded.parseQuery(query), index, filter_crate);
|
||||
var error_text = [];
|
||||
|
||||
for (var key in expected) {
|
||||
@@ -353,40 +446,75 @@ function checkResult(error_text, loadedFile, displaySuccess) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
function runChecks(testFile, loaded, index) {
|
||||
var testFileContent = readFile(testFile) + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;';
|
||||
if (testFileContent.indexOf("FILTER_CRATE") !== -1) {
|
||||
testFileContent += "exports.FILTER_CRATE = FILTER_CRATE;";
|
||||
} else {
|
||||
testFileContent += "exports.FILTER_CRATE = null;";
|
||||
}
|
||||
var loadedFile = loadContent(testFileContent);
|
||||
|
||||
const expected = loadedFile.EXPECTED;
|
||||
function runCheck(loadedFile, key, callback) {
|
||||
const expected = loadedFile[key];
|
||||
const query = loadedFile.QUERY;
|
||||
|
||||
if (Array.isArray(query)) {
|
||||
if (!Array.isArray(expected)) {
|
||||
console.log("FAILED");
|
||||
console.log("==> If QUERY variable is an array, EXPECTED should be an array too");
|
||||
console.log(`==> If QUERY variable is an array, ${key} should be an array too`);
|
||||
return 1;
|
||||
} else if (query.length !== expected.length) {
|
||||
console.log("FAILED");
|
||||
console.log("==> QUERY variable should have the same length as EXPECTED");
|
||||
console.log(`==> QUERY variable should have the same length as ${key}`);
|
||||
return 1;
|
||||
}
|
||||
for (var i = 0; i < query.length; ++i) {
|
||||
var error_text = runSearch(query[i], expected[i], index, loaded, loadedFile,
|
||||
"[ query `" + query[i] + "`]");
|
||||
var error_text = callback(query[i], expected[i], "[ query `" + query[i] + "`]");
|
||||
if (checkResult(error_text, loadedFile, false) !== 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
console.log("OK");
|
||||
return 0;
|
||||
} else {
|
||||
var error_text = callback(query, expected, "");
|
||||
if (checkResult(error_text, loadedFile, true) !== 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
var error_text = runSearch(query, expected, index, loaded, loadedFile, "");
|
||||
return checkResult(error_text, loadedFile, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
function runChecks(testFile, loaded, index) {
|
||||
var checkExpected = false;
|
||||
var checkParsed = false;
|
||||
var testFileContent = readFile(testFile) + 'exports.QUERY = QUERY;';
|
||||
|
||||
if (testFileContent.indexOf("FILTER_CRATE") !== -1) {
|
||||
testFileContent += "exports.FILTER_CRATE = FILTER_CRATE;";
|
||||
} else {
|
||||
testFileContent += "exports.FILTER_CRATE = null;";
|
||||
}
|
||||
|
||||
if (testFileContent.indexOf("\nconst EXPECTED") !== -1) {
|
||||
testFileContent += 'exports.EXPECTED = EXPECTED;';
|
||||
checkExpected = true;
|
||||
}
|
||||
if (testFileContent.indexOf("\nconst PARSED") !== -1) {
|
||||
testFileContent += 'exports.PARSED = PARSED;';
|
||||
checkParsed = true;
|
||||
}
|
||||
if (!checkParsed && !checkExpected) {
|
||||
console.log("FAILED");
|
||||
console.log("==> At least `PARSED` or `EXPECTED` is needed!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
const loadedFile = loadContent(testFileContent);
|
||||
var res = 0;
|
||||
|
||||
if (checkExpected) {
|
||||
res += runCheck(loadedFile, "EXPECTED", (query, expected, text) => {
|
||||
return runSearch(query, expected, index, loaded, loadedFile, text);
|
||||
});
|
||||
}
|
||||
if (checkParsed) {
|
||||
res += runCheck(loadedFile, "PARSED", (query, expected, text) => {
|
||||
return runParser(query, expected, loaded, loadedFile, text);
|
||||
});
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function load_files(doc_folder, resource_suffix, crate) {
|
||||
|
||||
Reference in New Issue
Block a user