256 lines
6.8 KiB
JavaScript
256 lines
6.8 KiB
JavaScript
lunr.QueryParser = function (str, query) {
|
|
this.lexer = new lunr.QueryLexer (str)
|
|
this.query = query
|
|
this.currentClause = {}
|
|
this.lexemeIdx = 0
|
|
}
|
|
|
|
lunr.QueryParser.prototype.parse = function () {
|
|
this.lexer.run()
|
|
this.lexemes = this.lexer.lexemes
|
|
|
|
var state = lunr.QueryParser.parseClause
|
|
|
|
while (state) {
|
|
state = state(this)
|
|
}
|
|
|
|
return this.query
|
|
}
|
|
|
|
lunr.QueryParser.prototype.peekLexeme = function () {
|
|
return this.lexemes[this.lexemeIdx]
|
|
}
|
|
|
|
lunr.QueryParser.prototype.consumeLexeme = function () {
|
|
var lexeme = this.peekLexeme()
|
|
this.lexemeIdx += 1
|
|
return lexeme
|
|
}
|
|
|
|
lunr.QueryParser.prototype.nextClause = function () {
|
|
var completedClause = this.currentClause
|
|
this.query.clause(completedClause)
|
|
this.currentClause = {}
|
|
}
|
|
|
|
lunr.QueryParser.parseClause = function (parser) {
|
|
var lexeme = parser.peekLexeme()
|
|
|
|
if (lexeme == undefined) {
|
|
return
|
|
}
|
|
|
|
switch (lexeme.type) {
|
|
case lunr.QueryLexer.PRESENCE:
|
|
return lunr.QueryParser.parsePresence
|
|
case lunr.QueryLexer.FIELD:
|
|
return lunr.QueryParser.parseField
|
|
case lunr.QueryLexer.TERM:
|
|
return lunr.QueryParser.parseTerm
|
|
default:
|
|
var errorMessage = "expected either a field or a term, found " + lexeme.type
|
|
|
|
if (lexeme.str.length >= 1) {
|
|
errorMessage += " with value '" + lexeme.str + "'"
|
|
}
|
|
|
|
throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)
|
|
}
|
|
}
|
|
|
|
lunr.QueryParser.parsePresence = function (parser) {
|
|
var lexeme = parser.consumeLexeme()
|
|
|
|
if (lexeme == undefined) {
|
|
return
|
|
}
|
|
|
|
switch (lexeme.str) {
|
|
case "-":
|
|
parser.currentClause.presence = lunr.Query.presence.PROHIBITED
|
|
break
|
|
case "+":
|
|
parser.currentClause.presence = lunr.Query.presence.REQUIRED
|
|
break
|
|
default:
|
|
var errorMessage = "unrecognised presence operator'" + lexeme.str + "'"
|
|
throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)
|
|
}
|
|
|
|
var nextLexeme = parser.peekLexeme()
|
|
|
|
if (nextLexeme == undefined) {
|
|
var errorMessage = "expecting term or field, found nothing"
|
|
throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)
|
|
}
|
|
|
|
switch (nextLexeme.type) {
|
|
case lunr.QueryLexer.FIELD:
|
|
return lunr.QueryParser.parseField
|
|
case lunr.QueryLexer.TERM:
|
|
return lunr.QueryParser.parseTerm
|
|
default:
|
|
var errorMessage = "expecting term or field, found '" + nextLexeme.type + "'"
|
|
throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end)
|
|
}
|
|
}
|
|
|
|
lunr.QueryParser.parseField = function (parser) {
|
|
var lexeme = parser.consumeLexeme()
|
|
|
|
if (lexeme == undefined) {
|
|
return
|
|
}
|
|
|
|
if (parser.query.allFields.indexOf(lexeme.str) == -1) {
|
|
var possibleFields = parser.query.allFields.map(function (f) { return "'" + f + "'" }).join(', '),
|
|
errorMessage = "unrecognised field '" + lexeme.str + "', possible fields: " + possibleFields
|
|
|
|
throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)
|
|
}
|
|
|
|
parser.currentClause.fields = [lexeme.str]
|
|
|
|
var nextLexeme = parser.peekLexeme()
|
|
|
|
if (nextLexeme == undefined) {
|
|
var errorMessage = "expecting term, found nothing"
|
|
throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)
|
|
}
|
|
|
|
switch (nextLexeme.type) {
|
|
case lunr.QueryLexer.TERM:
|
|
return lunr.QueryParser.parseTerm
|
|
default:
|
|
var errorMessage = "expecting term, found '" + nextLexeme.type + "'"
|
|
throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end)
|
|
}
|
|
}
|
|
|
|
lunr.QueryParser.parseTerm = function (parser) {
|
|
var lexeme = parser.consumeLexeme()
|
|
|
|
if (lexeme == undefined) {
|
|
return
|
|
}
|
|
|
|
parser.currentClause.term = lexeme.str.toLowerCase()
|
|
|
|
if (lexeme.str.indexOf("*") != -1) {
|
|
parser.currentClause.usePipeline = false
|
|
}
|
|
|
|
var nextLexeme = parser.peekLexeme()
|
|
|
|
if (nextLexeme == undefined) {
|
|
parser.nextClause()
|
|
return
|
|
}
|
|
|
|
switch (nextLexeme.type) {
|
|
case lunr.QueryLexer.TERM:
|
|
parser.nextClause()
|
|
return lunr.QueryParser.parseTerm
|
|
case lunr.QueryLexer.FIELD:
|
|
parser.nextClause()
|
|
return lunr.QueryParser.parseField
|
|
case lunr.QueryLexer.EDIT_DISTANCE:
|
|
return lunr.QueryParser.parseEditDistance
|
|
case lunr.QueryLexer.BOOST:
|
|
return lunr.QueryParser.parseBoost
|
|
case lunr.QueryLexer.PRESENCE:
|
|
parser.nextClause()
|
|
return lunr.QueryParser.parsePresence
|
|
default:
|
|
var errorMessage = "Unexpected lexeme type '" + nextLexeme.type + "'"
|
|
throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end)
|
|
}
|
|
}
|
|
|
|
lunr.QueryParser.parseEditDistance = function (parser) {
|
|
var lexeme = parser.consumeLexeme()
|
|
|
|
if (lexeme == undefined) {
|
|
return
|
|
}
|
|
|
|
var editDistance = parseInt(lexeme.str, 10)
|
|
|
|
if (isNaN(editDistance)) {
|
|
var errorMessage = "edit distance must be numeric"
|
|
throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)
|
|
}
|
|
|
|
parser.currentClause.editDistance = editDistance
|
|
|
|
var nextLexeme = parser.peekLexeme()
|
|
|
|
if (nextLexeme == undefined) {
|
|
parser.nextClause()
|
|
return
|
|
}
|
|
|
|
switch (nextLexeme.type) {
|
|
case lunr.QueryLexer.TERM:
|
|
parser.nextClause()
|
|
return lunr.QueryParser.parseTerm
|
|
case lunr.QueryLexer.FIELD:
|
|
parser.nextClause()
|
|
return lunr.QueryParser.parseField
|
|
case lunr.QueryLexer.EDIT_DISTANCE:
|
|
return lunr.QueryParser.parseEditDistance
|
|
case lunr.QueryLexer.BOOST:
|
|
return lunr.QueryParser.parseBoost
|
|
case lunr.QueryLexer.PRESENCE:
|
|
parser.nextClause()
|
|
return lunr.QueryParser.parsePresence
|
|
default:
|
|
var errorMessage = "Unexpected lexeme type '" + nextLexeme.type + "'"
|
|
throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end)
|
|
}
|
|
}
|
|
|
|
lunr.QueryParser.parseBoost = function (parser) {
|
|
var lexeme = parser.consumeLexeme()
|
|
|
|
if (lexeme == undefined) {
|
|
return
|
|
}
|
|
|
|
var boost = parseInt(lexeme.str, 10)
|
|
|
|
if (isNaN(boost)) {
|
|
var errorMessage = "boost must be numeric"
|
|
throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)
|
|
}
|
|
|
|
parser.currentClause.boost = boost
|
|
|
|
var nextLexeme = parser.peekLexeme()
|
|
|
|
if (nextLexeme == undefined) {
|
|
parser.nextClause()
|
|
return
|
|
}
|
|
|
|
switch (nextLexeme.type) {
|
|
case lunr.QueryLexer.TERM:
|
|
parser.nextClause()
|
|
return lunr.QueryParser.parseTerm
|
|
case lunr.QueryLexer.FIELD:
|
|
parser.nextClause()
|
|
return lunr.QueryParser.parseField
|
|
case lunr.QueryLexer.EDIT_DISTANCE:
|
|
return lunr.QueryParser.parseEditDistance
|
|
case lunr.QueryLexer.BOOST:
|
|
return lunr.QueryParser.parseBoost
|
|
case lunr.QueryLexer.PRESENCE:
|
|
parser.nextClause()
|
|
return lunr.QueryParser.parsePresence
|
|
default:
|
|
var errorMessage = "Unexpected lexeme type '" + nextLexeme.type + "'"
|
|
throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end)
|
|
}
|
|
}
|