Created
February 3, 2025 16:43
-
-
Save niemyjski/d852115272cfb0a4515616384208ea16 to your computer and use it in GitHub Desktop.
peggyjs lucene parser - wip
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { parse } from './LuceneQueryParser'; | |
export function getTerms(query: string): string[] { | |
const ast = parse(query); | |
if (!ast) { | |
return []; | |
} | |
const terms = new Set<string>(); | |
const traverse = (node: null | object): void => { | |
if (!node || typeof node !== 'object') { | |
return; | |
} | |
if ('left' in node && 'right' in node) { | |
traverse(node.left as object); | |
traverse(node.right as object); | |
return; | |
} | |
if ('field' in node && typeof node.field === 'string') { | |
terms.add(node.field); | |
} | |
}; | |
traverse(ast); | |
return Array.from(terms); | |
} | |
export function getTermValues(query: string): Array<{ term: string; value: string }> { | |
{ | |
const ast = parse(query); | |
if (!ast) { | |
return []; | |
} | |
const termValues: { term: string; value: string }[] = []; | |
const buildRawQuery = (node: null | object): string => { | |
if (!node || typeof node !== 'object') { | |
return ''; | |
} | |
if ('left' in node && 'right' in node) { | |
const leftQuery = buildRawQuery(node.left as object); | |
const rightQuery = buildRawQuery(node.right as object); | |
let query = 'operator' in node && node.operator ? `${leftQuery} ${node.operator} ${rightQuery}` : `${leftQuery} ${rightQuery}`; | |
if ('hasParens' in node && node.hasParens) { | |
query = `(${query})`; | |
} | |
if ('prefix' in node && node.prefix) { | |
query = node.prefix + query; | |
} | |
if ('isNegated' in node && node.isNegated) { | |
query = '-' + query; | |
} | |
if ('boost' in node && node.boost) { | |
query = query + `^${node.boost}`; | |
} | |
return query; | |
} | |
if ('field' in node && 'term' in node) { | |
let termValue = node.term || ''; | |
const prefix = 'prefix' in node && node.prefix ? node.prefix : ''; | |
const negation = 'isNegated' in node && node.isNegated ? '-' : ''; | |
// Wrap term appropriately. | |
if ('isQuotedTerm' in node && node.isQuotedTerm) { | |
termValue = `"${termValue}"`; | |
} else if ('isRegexTerm' in node && node.isRegexTerm) { | |
termValue = `/${termValue}/`; | |
} | |
// Append boost and proximity if defined. | |
const boost = 'boost' in node && node.boost ? `^${node.boost}` : ''; | |
const proximity = 'proximity' in node && node.proximity ? `~${node.proximity}` : ''; | |
return `${negation}${prefix}${node.field}:${termValue}${boost}${proximity}`; | |
} | |
return ''; | |
}; | |
const traverse = (node: null | object): void => { | |
if (!node || typeof node !== 'object') { | |
return; | |
} | |
if ('hasParens' in node && node.hasParens) { | |
// Rebuild the raw query for a parens node. | |
const innerQuery = buildRawQuery(node); | |
termValues.push({ term: '', value: innerQuery }); | |
return; | |
} | |
if ('left' in node && 'right' in node) { | |
traverse(node.left as object); | |
traverse(node.right as object); | |
return; | |
} | |
if ('field' in node && 'term' in node) { | |
termValues.push({ term: node.field as string, value: node.term as string }); | |
} | |
}; | |
traverse(ast); | |
return termValues; | |
} | |
} | |
export function isValid(query: string): boolean { | |
if (!query) { | |
return true; | |
} | |
try { | |
parse(query); | |
} catch { | |
return false; | |
} | |
return true; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable @typescript-eslint/no-empty-object-type */ | |
/** | |
* Expected any character, with `.` | |
*/ | |
export interface AnyExpectation { | |
readonly type: 'any'; | |
} | |
/** | |
* Expected a class, such as `[^acd-gz]i` | |
*/ | |
export interface ClassExpectation { | |
readonly ignoreCase: boolean; | |
readonly inverted: boolean; | |
readonly parts: ClassParts; | |
readonly type: 'class'; | |
} | |
export interface ClassParts extends Array<ClassRange | string> {} | |
/** | |
* Range of characters, like `a-z` | |
*/ | |
export type ClassRange = [start: string, end: string]; | |
/** | |
* Expected the end of input. | |
*/ | |
export interface EndExpectation { | |
readonly type: 'end'; | |
} | |
export type Expectation = AnyExpectation | ClassExpectation | EndExpectation | LiteralExpectation | OtherExpectation; | |
/** | |
* Most often, you just use a string with the file name. | |
*/ | |
export type GrammarSource = GrammarSourceObject | string; | |
/** | |
* Anything that can successfully be converted to a string with `String()` | |
* so that it can be used in error messages. | |
* | |
* The GrammarLocation class in Peggy is a good example. | |
*/ | |
export interface GrammarSourceObject { | |
/** | |
* If specified, allows the grammar source to be embedded in a larger file | |
* at some offset. | |
*/ | |
readonly offset?: ((loc: Location) => Location) | undefined; | |
readonly toString: () => string; | |
} | |
/** | |
* Expected a literal string, like `"foo"i`. | |
*/ | |
export interface LiteralExpectation { | |
readonly ignoreCase: boolean; | |
readonly text: string; | |
readonly type: 'literal'; | |
} | |
/** Provides information pointing to a location within a source. */ | |
export interface Location { | |
/** Column in the parsed source (1-based). */ | |
readonly column: number; | |
/** Line in the parsed source (1-based). */ | |
readonly line: number; | |
/** Offset in the parsed source (0-based). */ | |
readonly offset: number; | |
} | |
/** The `start` and `end` position's of an object within the source. */ | |
export interface LocationRange { | |
/** Position after the end of the expression. */ | |
readonly end: Location; | |
/** | |
* A string or object that was supplied to the `parse()` call as the | |
* `grammarSource` option. | |
*/ | |
readonly source: GrammarSource; | |
/** Position at the beginning of the expression. */ | |
readonly start: Location; | |
} | |
/** | |
* Expected some other input. These are specified with a rule's | |
* "human-readable name", or with the `expected(message, location)` | |
* function. | |
*/ | |
export interface OtherExpectation { | |
readonly description: string; | |
readonly type: 'other'; | |
} | |
export interface ParseOptions<T extends StartRuleNames = 'start'> { | |
// Extra application-specific properties | |
[key: string]: unknown; | |
/** | |
* String or object that will be attached to the each `LocationRange` object | |
* created by the parser. For example, this can be path to the parsed file | |
* or even the File object. | |
*/ | |
readonly grammarSource?: GrammarSource; | |
// Internal use only: | |
peg$currPos?: number; | |
// Internal use only: | |
readonly peg$library?: boolean; | |
// Internal use only: | |
peg$maxFailExpected?: Expectation[]; | |
// Internal use only: | |
peg$silentFails?: number; | |
readonly startRule?: T; | |
readonly tracer?: ParserTracer; | |
} | |
/** | |
* Trace execution of the parser. | |
*/ | |
export interface ParserTracer { | |
trace: (event: ParserTracerEvent) => void; | |
} | |
export type ParserTracerEvent = | |
| { | |
readonly location: LocationRange; | |
/** Return value from the rule. */ | |
readonly result: unknown; | |
readonly rule: string; | |
readonly type: 'rule.match'; | |
} | |
| { | |
readonly location: LocationRange; | |
readonly rule: string; | |
readonly type: 'rule.enter'; | |
} | |
| { | |
readonly location: LocationRange; | |
readonly rule: string; | |
readonly type: 'rule.fail'; | |
}; | |
/** | |
* Pass an array of these into `SyntaxError.prototype.format()` | |
*/ | |
export interface SourceText { | |
/** | |
* Identifier of an input that was used as a grammarSource in parse(). | |
*/ | |
readonly source: GrammarSource; | |
/** Source text of the input. */ | |
readonly text: string; | |
} | |
export type StartRuleNames = 'start'; | |
export declare class SyntaxError extends Error { | |
readonly expected: Expectation[]; | |
readonly found: null | string | undefined; | |
readonly location: LocationRange; | |
readonly message: string; | |
readonly name: string; | |
constructor(message: string, expected: Expectation[], found: null | string, location: LocationRange); | |
/** | |
* Constructs the human-readable message from the machine representation. | |
* | |
* @param expected Array of expected items, generated by the parser | |
* @param found Any text that will appear as found in the input instead of | |
* expected | |
*/ | |
static buildMessage(expected: Expectation[], found?: null | string | undefined): string; | |
/** | |
* With good sources, generates a feature-rich error message pointing to the | |
* error in the input. | |
* @param sources List of {source, text} objects that map to the input. | |
*/ | |
format(sources: SourceText[]): string; | |
} | |
export declare const StartRules: StartRuleNames[]; | |
export declare const parse: typeof ParseFunction; | |
// Overload of ParseFunction for each allowedStartRule | |
declare function ParseFunction<Options extends ParseOptions<'start'>>(input: string, options?: Options): unknown; | |
declare function ParseFunction<Options extends ParseOptions<StartRuleNames>>(input: string, options?: Options): unknown; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable no-control-regex */ | |
/* eslint-disable no-useless-escape */ | |
/* eslint-disable no-empty */ | |
/* eslint-disable @typescript-eslint/no-unused-vars */ | |
// @generated by Peggy 4.2.0. | |
// | |
// https://peggyjs.org/ | |
function peg$subclass(child, parent) { | |
function C() { | |
this.constructor = child; | |
} | |
C.prototype = parent.prototype; | |
child.prototype = new C(); | |
} | |
function peg$SyntaxError(message, expected, found, location) { | |
var self = Error.call(this, message); | |
// istanbul ignore next Check is a necessary evil to support older environments | |
if (Object.setPrototypeOf) { | |
Object.setPrototypeOf(self, peg$SyntaxError.prototype); | |
} | |
self.expected = expected; | |
self.found = found; | |
self.location = location; | |
self.name = 'SyntaxError'; | |
return self; | |
} | |
peg$subclass(peg$SyntaxError, Error); | |
function peg$padEnd(str, targetLength, padString) { | |
padString = padString || ' '; | |
if (str.length > targetLength) { | |
return str; | |
} | |
targetLength -= str.length; | |
padString += padString.repeat(targetLength); | |
return str + padString.slice(0, targetLength); | |
} | |
peg$SyntaxError.prototype.format = function (sources) { | |
var str = 'Error: ' + this.message; | |
if (this.location) { | |
var src = null; | |
var k; | |
for (k = 0; k < sources.length; k++) { | |
if (sources[k].source === this.location.source) { | |
src = sources[k].text.split(/\r\n|\n|\r/g); | |
break; | |
} | |
} | |
var s = this.location.start; | |
var offset_s = this.location.source && typeof this.location.source.offset === 'function' ? this.location.source.offset(s) : s; | |
var loc = this.location.source + ':' + offset_s.line + ':' + offset_s.column; | |
if (src) { | |
var e = this.location.end; | |
var filler = peg$padEnd('', offset_s.line.toString().length, ' '); | |
var line = src[s.line - 1]; | |
var last = s.line === e.line ? e.column : line.length + 1; | |
var hatLen = last - s.column || 1; | |
str += | |
'\n --> ' + | |
loc + | |
'\n' + | |
filler + | |
' |\n' + | |
offset_s.line + | |
' | ' + | |
line + | |
'\n' + | |
filler + | |
' | ' + | |
peg$padEnd('', s.column - 1, ' ') + | |
peg$padEnd('', hatLen, '^'); | |
} else { | |
str += '\n at ' + loc; | |
} | |
} | |
return str; | |
}; | |
peg$SyntaxError.buildMessage = function (expected, found) { | |
var DESCRIBE_EXPECTATION_FNS = { | |
any: function () { | |
return 'any character'; | |
}, | |
class: function (expectation) { | |
var escapedParts = expectation.parts.map(function (part) { | |
return Array.isArray(part) ? classEscape(part[0]) + '-' + classEscape(part[1]) : classEscape(part); | |
}); | |
return '[' + (expectation.inverted ? '^' : '') + escapedParts.join('') + ']'; | |
}, | |
end: function () { | |
return 'end of input'; | |
}, | |
literal: function (expectation) { | |
return '"' + literalEscape(expectation.text) + '"'; | |
}, | |
other: function (expectation) { | |
return expectation.description; | |
} | |
}; | |
function hex(ch) { | |
return ch.charCodeAt(0).toString(16).toUpperCase(); | |
} | |
function literalEscape(s) { | |
return s | |
.replace(/\\/g, '\\\\') | |
.replace(/"/g, '\\"') | |
.replace(/\0/g, '\\0') | |
.replace(/\t/g, '\\t') | |
.replace(/\n/g, '\\n') | |
.replace(/\r/g, '\\r') | |
.replace(/[\x00-\x0F]/g, function (ch) { | |
return '\\x0' + hex(ch); | |
}) | |
.replace(/[\x10-\x1F\x7F-\x9F]/g, function (ch) { | |
return '\\x' + hex(ch); | |
}); | |
} | |
function classEscape(s) { | |
return s | |
.replace(/\\/g, '\\\\') | |
.replace(/\]/g, '\\]') | |
.replace(/\^/g, '\\^') | |
.replace(/-/g, '\\-') | |
.replace(/\0/g, '\\0') | |
.replace(/\t/g, '\\t') | |
.replace(/\n/g, '\\n') | |
.replace(/\r/g, '\\r') | |
.replace(/[\x00-\x0F]/g, function (ch) { | |
return '\\x0' + hex(ch); | |
}) | |
.replace(/[\x10-\x1F\x7F-\x9F]/g, function (ch) { | |
return '\\x' + hex(ch); | |
}); | |
} | |
function describeExpectation(expectation) { | |
return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation); | |
} | |
function describeExpected(expected) { | |
var descriptions = expected.map(describeExpectation); | |
var i, j; | |
descriptions.sort(); | |
if (descriptions.length > 0) { | |
for (i = 1, j = 1; i < descriptions.length; i++) { | |
if (descriptions[i - 1] !== descriptions[i]) { | |
descriptions[j] = descriptions[i]; | |
j++; | |
} | |
} | |
descriptions.length = j; | |
} | |
switch (descriptions.length) { | |
case 1: | |
return descriptions[0]; | |
case 2: | |
return descriptions[0] + ' or ' + descriptions[1]; | |
default: | |
return descriptions.slice(0, -1).join(', ') + ', or ' + descriptions[descriptions.length - 1]; | |
} | |
} | |
function describeFound(found) { | |
return found ? '"' + literalEscape(found) + '"' : 'end of input'; | |
} | |
return 'Expected ' + describeExpected(expected) + ' but ' + describeFound(found) + ' found.'; | |
}; | |
function peg$parse(input, options) { | |
options = options !== undefined ? options : {}; | |
var peg$FAILED = {}; | |
var peg$source = options.grammarSource; | |
var peg$startRuleFunctions = { start: peg$parsestart }; | |
var peg$startRuleFunction = peg$parsestart; | |
var peg$c0 = '('; | |
var peg$c1 = ')'; | |
var peg$c2 = '_exists_'; | |
var peg$c3 = ':'; | |
var peg$c4 = '_missing_'; | |
var peg$c5 = '\\'; | |
var peg$c6 = '*'; | |
var peg$c7 = '"'; | |
var peg$c8 = '\\"'; | |
var peg$c9 = '/'; | |
var peg$c10 = '^'; | |
var peg$c11 = '~'; | |
var peg$c12 = '>='; | |
var peg$c13 = '>'; | |
var peg$c14 = '<='; | |
var peg$c15 = '<'; | |
var peg$c16 = 'TO'; | |
var peg$c17 = '..'; | |
var peg$c18 = 'NOT'; | |
var peg$c19 = 'OR'; | |
var peg$c20 = 'AND'; | |
var peg$c21 = '||'; | |
var peg$c22 = '&&'; | |
var peg$r0 = /^[+\-!(){}[\]\^"~*?:\/]/; | |
var peg$r1 = /^[^: \t\r\n\f{}()"\^~[\]]/; | |
var peg$r2 = /^[^: .\t\r\n\f{}()"\^~[\]]/; | |
var peg$r3 = /^[.]/; | |
var peg$r4 = /^[^.]/; | |
var peg$r5 = /^[^"]/; | |
var peg$r6 = /^[^\/]/; | |
var peg$r7 = /^[[{]/; | |
var peg$r8 = /^[\]}]/; | |
var peg$r9 = /^[!+\-]/; | |
var peg$r10 = /^[ \t\r\n\f]/; | |
var peg$e0 = peg$literalExpectation('(', false); | |
var peg$e1 = peg$literalExpectation(')', false); | |
var peg$e2 = peg$literalExpectation('_exists_', false); | |
var peg$e3 = peg$literalExpectation(':', false); | |
var peg$e4 = peg$literalExpectation('_missing_', false); | |
var peg$e5 = peg$literalExpectation('\\', false); | |
var peg$e6 = peg$classExpectation(['+', '-', '!', '(', ')', '{', '}', '[', ']', '^', '"', '~', '*', '?', ':', '/'], false, false); | |
var peg$e7 = peg$classExpectation([':', ' ', '\t', '\r', '\n', '\f', '{', '}', '(', ')', '"', '^', '~', '[', ']'], true, false); | |
var peg$e8 = peg$classExpectation([':', ' ', '.', '\t', '\r', '\n', '\f', '{', '}', '(', ')', '"', '^', '~', '[', ']'], true, false); | |
var peg$e9 = peg$classExpectation(['.'], false, false); | |
var peg$e10 = peg$classExpectation(['.'], true, false); | |
var peg$e11 = peg$literalExpectation('*', false); | |
var peg$e12 = peg$literalExpectation('"', false); | |
var peg$e13 = peg$literalExpectation('\\"', false); | |
var peg$e14 = peg$classExpectation(['"'], true, false); | |
var peg$e15 = peg$literalExpectation('/', false); | |
var peg$e16 = peg$classExpectation(['/'], true, false); | |
var peg$e17 = peg$literalExpectation('^', false); | |
var peg$e18 = peg$literalExpectation('~', false); | |
var peg$e19 = peg$classExpectation(['[', '{'], false, false); | |
var peg$e20 = peg$classExpectation([']', '}'], false, false); | |
var peg$e21 = peg$literalExpectation('>=', false); | |
var peg$e22 = peg$literalExpectation('>', false); | |
var peg$e23 = peg$literalExpectation('<=', false); | |
var peg$e24 = peg$literalExpectation('<', false); | |
var peg$e25 = peg$literalExpectation('TO', false); | |
var peg$e26 = peg$literalExpectation('..', false); | |
var peg$e27 = peg$literalExpectation('NOT', false); | |
var peg$e28 = peg$literalExpectation('OR', false); | |
var peg$e29 = peg$literalExpectation('AND', false); | |
var peg$e30 = peg$literalExpectation('||', false); | |
var peg$e31 = peg$literalExpectation('&&', false); | |
var peg$e32 = peg$classExpectation(['!', '+', '-'], false, false); | |
var peg$e33 = peg$classExpectation([' ', '\t', '\r', '\n', '\f'], false, false); | |
var peg$e34 = peg$anyExpectation(); | |
var peg$f0 = function (node) { | |
return node !== undefined ? node : new GroupNode(); | |
}; | |
var peg$f1 = function (op) { | |
let gn = new GroupNode(); | |
gn.operator = op; | |
return gn; | |
}; | |
var peg$f2 = function (op, right) { | |
return right; | |
}; | |
var peg$f3 = function (left, op, right) { | |
let gn = new GroupNode(); | |
gn.left = left; | |
let rightExp = right.length === 0 ? null : right[0].right === null || right[0].right === undefined ? right[0].left : right[0]; | |
if (rightExp !== null) { | |
gn.operator = op !== null && op !== undefined ? op : null; | |
gn.right = rightExp; | |
} | |
return gn; | |
}; | |
var peg$f4 = function (f) { | |
return f; | |
}; | |
var peg$f5 = function (not, op, node, boost) { | |
node.hasParens = true; | |
node.prefix = op !== null && op !== undefined ? op : null; | |
if (boost !== null && boost !== undefined) { | |
node.boost = boost; | |
} | |
if (not !== null && not !== undefined) { | |
node.isNegated = true; | |
} | |
return node; | |
}; | |
var peg$f6 = function (not, op, fieldname) { | |
let en = new ExistsNode(); | |
en.isNegated = not != null; | |
en.prefix = op != null ? op : null; | |
en.field = fieldname; | |
return en; | |
}; | |
var peg$f7 = function (not, op, fieldname) { | |
let mn = new MissingNode(); | |
mn.isNegated = not != null; | |
mn.prefix = op != null ? op : null; | |
mn.field = fieldname; | |
return mn; | |
}; | |
var peg$f8 = function (not, name, range) { | |
if (name != null) { | |
range.isNegated = not != null; | |
range.field = name.field; | |
range.prefix = name.prefix; | |
} | |
return range; | |
}; | |
var peg$f9 = function (not, op, range) { | |
range.isNegated = not != null; | |
range.prefix = op != null ? op : null; | |
return range; | |
}; | |
var peg$f10 = function (not, name, node) { | |
node.isNegated = not != null; | |
node.field = name.field; | |
node.prefix = name.prefix; | |
return node; | |
}; | |
var peg$f11 = function (not, name, term) { | |
let tn = new TermNode(); | |
if (not != null) { | |
tn.isNegated = true; | |
} | |
tn.field = name.field; | |
tn.prefix = name.prefix; | |
term.copyTo(tn); | |
return tn; | |
}; | |
var peg$f12 = function (op, fieldname) { | |
let fi = new FieldInfo(fieldname, op != null ? op : null); | |
return fi; | |
}; | |
var peg$f13 = function (not, op, term, proximity, boost) { | |
let tn = new TermNode(); | |
tn.term = term.term; | |
tn.isQuotedTerm = term.isQuoted; | |
tn.isRegexTerm = term.isRegex; | |
if (proximity !== undefined) { | |
tn.proximity = proximity; | |
} | |
if (boost !== undefined) { | |
tn.boost = boost; | |
} | |
if (not !== undefined) { | |
tn.isNegated = true; | |
} | |
tn.prefix = op !== null && op !== undefined ? op : null; | |
return tn; | |
}; | |
var peg$f14 = function (not, prefix, op) { | |
throw new Error("Unexpected operator '" + op + "'."); | |
}; | |
var peg$f15 = function (term) { | |
return term.join(''); | |
}; | |
var peg$f16 = function (term) { | |
return new TermInfo(term.join('')); | |
}; | |
var peg$f17 = function (term) { | |
return new TermInfo(Array.isArray(term) ? term.join('') : term); | |
}; | |
var peg$f18 = function (term) { | |
return new TermInfo(term.join(''), true); | |
}; | |
var peg$f19 = function (term) { | |
throw new Error('Unterminated quoted string'); | |
}; | |
var peg$f20 = function (term) { | |
return new TermInfo(term.join(''), false, true); | |
}; | |
var peg$f21 = function (term) { | |
throw new Error('Unterminated regex'); | |
}; | |
var peg$f22 = function (boost) { | |
return boost.term; | |
}; | |
var peg$f23 = function (proximity) { | |
return proximity; | |
}; | |
var peg$f24 = function (left, term_min, delim, term_max, right, proximity, boost) { | |
let trn = new TermRangeNode(); | |
trn.min = term_min.term; | |
trn.isMinQuotedTerm = term_min.isQuoted; | |
trn.max = term_max.term; | |
trn.isMaxQuotedTerm = term_max.isQuoted; | |
trn.minInclusive = left === '['; | |
trn.maxInclusive = right === ']'; | |
trn.delimiter = delim; | |
if (proximity !== undefined) { | |
trn.proximity = proximity; | |
} | |
if (boost !== undefined) { | |
trn.boost = boost; | |
} | |
return trn; | |
}; | |
var peg$f25 = function (op, term, proximity, boost) { | |
let trn = new TermRangeNode(); | |
trn.min = op.startsWith('>') ? term.term : null; | |
trn.minInclusive = op === '>='; | |
trn.isMinQuotedTerm = op.startsWith('>') && term.isQuoted; | |
trn.max = op.startsWith('<') ? term.term : null; | |
trn.maxInclusive = op === '<='; | |
trn.isMaxQuotedTerm = op.startsWith('<') && term.isQuoted; | |
trn.operator = op; | |
if (proximity !== undefined) { | |
trn.proximity = proximity; | |
} | |
if (boost !== undefined) { | |
trn.boost = boost; | |
} | |
return trn; | |
}; | |
var peg$f26 = function (op) { | |
return op; | |
}; | |
var peg$f27 = function () { | |
return GroupOperator.Or; | |
}; | |
var peg$f28 = function () { | |
return GroupOperator.And; | |
}; | |
var peg$f29 = function () { | |
return GroupOperator.Or; | |
}; | |
var peg$f30 = function () { | |
return GroupOperator.And; | |
}; | |
var peg$f31 = function (op) { | |
return op; | |
}; | |
var peg$f32 = function () { | |
throw new Error("Missing closing paren ')' for group expression"); | |
}; | |
var peg$currPos = options.peg$currPos | 0; | |
var peg$savedPos = peg$currPos; | |
var peg$posDetailsCache = [{ column: 1, line: 1 }]; | |
var peg$maxFailPos = peg$currPos; | |
var peg$maxFailExpected = options.peg$maxFailExpected || []; | |
var peg$silentFails = options.peg$silentFails | 0; | |
var peg$resultsCache = {}; | |
var peg$result; | |
if (options.startRule) { | |
if (!(options.startRule in peg$startRuleFunctions)) { | |
throw new Error('Can\'t start parsing from rule "' + options.startRule + '".'); | |
} | |
peg$startRuleFunction = peg$startRuleFunctions[options.startRule]; | |
} | |
function text() { | |
return input.substring(peg$savedPos, peg$currPos); | |
} | |
function offset() { | |
return peg$savedPos; | |
} | |
function range() { | |
return { | |
end: peg$currPos, | |
source: peg$source, | |
start: peg$savedPos | |
}; | |
} | |
function location() { | |
return peg$computeLocation(peg$savedPos, peg$currPos); | |
} | |
function expected(description, location) { | |
location = location !== undefined ? location : peg$computeLocation(peg$savedPos, peg$currPos); | |
throw peg$buildStructuredError([peg$otherExpectation(description)], input.substring(peg$savedPos, peg$currPos), location); | |
} | |
function error(message, location) { | |
location = location !== undefined ? location : peg$computeLocation(peg$savedPos, peg$currPos); | |
throw peg$buildSimpleError(message, location); | |
} | |
function peg$literalExpectation(text, ignoreCase) { | |
return { ignoreCase: ignoreCase, text: text, type: 'literal' }; | |
} | |
function peg$classExpectation(parts, inverted, ignoreCase) { | |
return { ignoreCase: ignoreCase, inverted: inverted, parts: parts, type: 'class' }; | |
} | |
function peg$anyExpectation() { | |
return { type: 'any' }; | |
} | |
function peg$endExpectation() { | |
return { type: 'end' }; | |
} | |
function peg$otherExpectation(description) { | |
return { description: description, type: 'other' }; | |
} | |
function peg$computePosDetails(pos) { | |
var details = peg$posDetailsCache[pos]; | |
var p; | |
if (details) { | |
return details; | |
} else { | |
if (pos >= peg$posDetailsCache.length) { | |
p = peg$posDetailsCache.length - 1; | |
} else { | |
p = pos; | |
while (!peg$posDetailsCache[--p]) {} | |
} | |
details = peg$posDetailsCache[p]; | |
details = { | |
column: details.column, | |
line: details.line | |
}; | |
while (p < pos) { | |
if (input.charCodeAt(p) === 10) { | |
details.line++; | |
details.column = 1; | |
} else { | |
details.column++; | |
} | |
p++; | |
} | |
peg$posDetailsCache[pos] = details; | |
return details; | |
} | |
} | |
function peg$computeLocation(startPos, endPos, offset) { | |
var startPosDetails = peg$computePosDetails(startPos); | |
var endPosDetails = peg$computePosDetails(endPos); | |
var res = { | |
end: { | |
column: endPosDetails.column, | |
line: endPosDetails.line, | |
offset: endPos | |
}, | |
source: peg$source, | |
start: { | |
column: startPosDetails.column, | |
line: startPosDetails.line, | |
offset: startPos | |
} | |
}; | |
if (offset && peg$source && typeof peg$source.offset === 'function') { | |
res.start = peg$source.offset(res.start); | |
res.end = peg$source.offset(res.end); | |
} | |
return res; | |
} | |
function peg$fail(expected) { | |
if (peg$currPos < peg$maxFailPos) { | |
return; | |
} | |
if (peg$currPos > peg$maxFailPos) { | |
peg$maxFailPos = peg$currPos; | |
peg$maxFailExpected = []; | |
} | |
peg$maxFailExpected.push(expected); | |
} | |
function peg$buildSimpleError(message, location) { | |
return new peg$SyntaxError(message, null, null, location); | |
} | |
function peg$buildStructuredError(expected, found, location) { | |
return new peg$SyntaxError(peg$SyntaxError.buildMessage(expected, found), expected, found, location); | |
} | |
function peg$parsestart() { | |
var s0, s1, s2, s3, s4; | |
var key = peg$currPos * 25 + 0; | |
var cached = peg$resultsCache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
s1 = []; | |
s2 = peg$parse_(); | |
while (s2 !== peg$FAILED) { | |
s1.push(s2); | |
s2 = peg$parse_(); | |
} | |
s2 = peg$parsenode(); | |
if (s2 === peg$FAILED) { | |
s2 = null; | |
} | |
s3 = []; | |
s4 = peg$parse_(); | |
while (s4 !== peg$FAILED) { | |
s3.push(s4); | |
s4 = peg$parse_(); | |
} | |
s4 = peg$parseEOF(); | |
if (s4 !== peg$FAILED) { | |
peg$savedPos = s0; | |
s0 = peg$f0(s2); | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parsenode() { | |
var s0, s1, s2, s3, s4; | |
var key = peg$currPos * 25 + 1; | |
var cached = peg$resultsCache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
s1 = peg$parseoperator_exp(); | |
if (s1 !== peg$FAILED) { | |
s2 = peg$parseEOF(); | |
if (s2 !== peg$FAILED) { | |
peg$savedPos = s0; | |
s0 = peg$f1(s1); | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
if (s0 === peg$FAILED) { | |
s0 = peg$currPos; | |
s1 = peg$parseoperator_exp(); | |
if (s1 !== peg$FAILED) { | |
s2 = peg$parsenode(); | |
if (s2 !== peg$FAILED) { | |
peg$savedPos = s0; | |
s0 = peg$f2(s1, s2); | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
if (s0 === peg$FAILED) { | |
s0 = peg$currPos; | |
s1 = peg$parsegroup_exp(); | |
if (s1 !== peg$FAILED) { | |
s2 = peg$parseoperator_exp(); | |
if (s2 === peg$FAILED) { | |
s2 = null; | |
} | |
s3 = []; | |
s4 = peg$parsenode(); | |
while (s4 !== peg$FAILED) { | |
s3.push(s4); | |
s4 = peg$parsenode(); | |
} | |
peg$savedPos = s0; | |
s0 = peg$f3(s1, s2, s3); | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} | |
} | |
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parsegroup_exp() { | |
var s0, s1, s2, s3; | |
var key = peg$currPos * 25 + 2; | |
var cached = peg$resultsCache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
s1 = peg$parsefield_exp(); | |
if (s1 !== peg$FAILED) { | |
s2 = []; | |
s3 = peg$parse_(); | |
while (s3 !== peg$FAILED) { | |
s2.push(s3); | |
s3 = peg$parse_(); | |
} | |
peg$savedPos = s0; | |
s0 = peg$f4(s1); | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
if (s0 === peg$FAILED) { | |
s0 = peg$parseparen_exp(); | |
} | |
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parseparen_exp() { | |
var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10; | |
var key = peg$currPos * 25 + 3; | |
var cached = peg$resultsCache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
s1 = peg$parsenot_exp(); | |
if (s1 === peg$FAILED) { | |
s1 = null; | |
} | |
s2 = peg$parseprefix_operator_exp(); | |
if (s2 === peg$FAILED) { | |
s2 = null; | |
} | |
if (input.charCodeAt(peg$currPos) === 40) { | |
s3 = peg$c0; | |
peg$currPos++; | |
} else { | |
s3 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e0); | |
} | |
} | |
if (s3 !== peg$FAILED) { | |
s4 = []; | |
s5 = peg$parse_(); | |
while (s5 !== peg$FAILED) { | |
s4.push(s5); | |
s5 = peg$parse_(); | |
} | |
s5 = peg$parsenode(); | |
if (s5 !== peg$FAILED) { | |
s6 = []; | |
s7 = peg$parse_(); | |
while (s7 !== peg$FAILED) { | |
s6.push(s7); | |
s7 = peg$parse_(); | |
} | |
if (input.charCodeAt(peg$currPos) === 41) { | |
s7 = peg$c1; | |
peg$currPos++; | |
} else { | |
s7 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e1); | |
} | |
} | |
if (s7 === peg$FAILED) { | |
s7 = peg$parsemissing_paren(); | |
} | |
if (s7 !== peg$FAILED) { | |
s8 = peg$parseboost_modifier(); | |
if (s8 === peg$FAILED) { | |
s8 = null; | |
} | |
s9 = []; | |
s10 = peg$parse_(); | |
while (s10 !== peg$FAILED) { | |
s9.push(s10); | |
s10 = peg$parse_(); | |
} | |
peg$savedPos = s0; | |
s0 = peg$f5(s1, s2, s5, s8); | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parsefield_exp() { | |
var s0, s1, s2, s3, s4, s5, s6, s7; | |
var key = peg$currPos * 25 + 4; | |
var cached = peg$resultsCache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
s1 = peg$parsenot_exp(); | |
if (s1 === peg$FAILED) { | |
s1 = null; | |
} | |
s2 = peg$parseprefix_operator_exp(); | |
if (s2 === peg$FAILED) { | |
s2 = null; | |
} | |
if (input.substr(peg$currPos, 8) === peg$c2) { | |
s3 = peg$c2; | |
peg$currPos += 8; | |
} else { | |
s3 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e2); | |
} | |
} | |
if (s3 !== peg$FAILED) { | |
s4 = []; | |
s5 = peg$parse_(); | |
while (s5 !== peg$FAILED) { | |
s4.push(s5); | |
s5 = peg$parse_(); | |
} | |
if (input.charCodeAt(peg$currPos) === 58) { | |
s5 = peg$c3; | |
peg$currPos++; | |
} else { | |
s5 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e3); | |
} | |
} | |
if (s5 !== peg$FAILED) { | |
s6 = []; | |
s7 = peg$parse_(); | |
while (s7 !== peg$FAILED) { | |
s6.push(s7); | |
s7 = peg$parse_(); | |
} | |
s7 = peg$parsename_term(); | |
if (s7 !== peg$FAILED) { | |
peg$savedPos = s0; | |
s0 = peg$f6(s1, s2, s7); | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
if (s0 === peg$FAILED) { | |
s0 = peg$currPos; | |
s1 = peg$parsenot_exp(); | |
if (s1 === peg$FAILED) { | |
s1 = null; | |
} | |
s2 = peg$parseprefix_operator_exp(); | |
if (s2 === peg$FAILED) { | |
s2 = null; | |
} | |
if (input.substr(peg$currPos, 9) === peg$c4) { | |
s3 = peg$c4; | |
peg$currPos += 9; | |
} else { | |
s3 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e4); | |
} | |
} | |
if (s3 !== peg$FAILED) { | |
s4 = []; | |
s5 = peg$parse_(); | |
while (s5 !== peg$FAILED) { | |
s4.push(s5); | |
s5 = peg$parse_(); | |
} | |
if (input.charCodeAt(peg$currPos) === 58) { | |
s5 = peg$c3; | |
peg$currPos++; | |
} else { | |
s5 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e3); | |
} | |
} | |
if (s5 !== peg$FAILED) { | |
s6 = []; | |
s7 = peg$parse_(); | |
while (s7 !== peg$FAILED) { | |
s6.push(s7); | |
s7 = peg$parse_(); | |
} | |
s7 = peg$parsename_term(); | |
if (s7 !== peg$FAILED) { | |
peg$savedPos = s0; | |
s0 = peg$f7(s1, s2, s7); | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
if (s0 === peg$FAILED) { | |
s0 = peg$currPos; | |
s1 = peg$parsenot_exp(); | |
if (s1 === peg$FAILED) { | |
s1 = null; | |
} | |
s2 = peg$parsefieldname(); | |
if (s2 === peg$FAILED) { | |
s2 = null; | |
} | |
s3 = peg$parserange_operator_exp(); | |
if (s3 !== peg$FAILED) { | |
peg$savedPos = s0; | |
s0 = peg$f8(s1, s2, s3); | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
if (s0 === peg$FAILED) { | |
s0 = peg$currPos; | |
s1 = peg$parsenot_exp(); | |
if (s1 === peg$FAILED) { | |
s1 = null; | |
} | |
s2 = peg$parseprefix_operator_exp(); | |
if (s2 === peg$FAILED) { | |
s2 = null; | |
} | |
s3 = peg$parserange_operator_exp(); | |
if (s3 !== peg$FAILED) { | |
peg$savedPos = s0; | |
s0 = peg$f9(s1, s2, s3); | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
if (s0 === peg$FAILED) { | |
s0 = peg$currPos; | |
s1 = peg$parsenot_exp(); | |
if (s1 === peg$FAILED) { | |
s1 = null; | |
} | |
s2 = peg$parsefieldname(); | |
if (s2 !== peg$FAILED) { | |
s3 = peg$parseparen_exp(); | |
if (s3 !== peg$FAILED) { | |
peg$savedPos = s0; | |
s0 = peg$f10(s1, s2, s3); | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
if (s0 === peg$FAILED) { | |
s0 = peg$currPos; | |
s1 = peg$parsenot_exp(); | |
if (s1 === peg$FAILED) { | |
s1 = null; | |
} | |
s2 = peg$parsefieldname(); | |
if (s2 !== peg$FAILED) { | |
s3 = peg$parseterm(); | |
if (s3 !== peg$FAILED) { | |
peg$savedPos = s0; | |
s0 = peg$f11(s1, s2, s3); | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} | |
} | |
} | |
} | |
} | |
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parsefieldname() { | |
var s0, s1, s2, s3, s4, s5, s6; | |
var key = peg$currPos * 25 + 5; | |
var cached = peg$resultsCache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
s1 = peg$parseprefix_operator_exp(); | |
if (s1 === peg$FAILED) { | |
s1 = null; | |
} | |
s2 = peg$parsename_term(); | |
if (s2 !== peg$FAILED) { | |
s3 = []; | |
s4 = peg$parse_(); | |
while (s4 !== peg$FAILED) { | |
s3.push(s4); | |
s4 = peg$parse_(); | |
} | |
if (input.charCodeAt(peg$currPos) === 58) { | |
s4 = peg$c3; | |
peg$currPos++; | |
} else { | |
s4 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e3); | |
} | |
} | |
if (s4 !== peg$FAILED) { | |
s5 = []; | |
s6 = peg$parse_(); | |
while (s6 !== peg$FAILED) { | |
s5.push(s6); | |
s6 = peg$parse_(); | |
} | |
peg$savedPos = s0; | |
s0 = peg$f12(s1, s2); | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parseterm() { | |
var s0, s1, s2, s3, s4, s5, s6, s7, s8; | |
var key = peg$currPos * 25 + 6; | |
var cached = peg$resultsCache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
s1 = peg$parsenot_exp(); | |
if (s1 === peg$FAILED) { | |
s1 = null; | |
} | |
s2 = peg$parseprefix_operator_exp(); | |
if (s2 === peg$FAILED) { | |
s2 = null; | |
} | |
s3 = peg$currPos; | |
peg$silentFails++; | |
s4 = peg$parseoperator_exp(); | |
peg$silentFails--; | |
if (s4 === peg$FAILED) { | |
s3 = undefined; | |
} else { | |
peg$currPos = s3; | |
s3 = peg$FAILED; | |
} | |
if (s3 !== peg$FAILED) { | |
s4 = peg$parsequoted_term(); | |
if (s4 === peg$FAILED) { | |
s4 = peg$parseregex_term(); | |
if (s4 === peg$FAILED) { | |
s4 = peg$parseunquoted_term(); | |
} | |
} | |
if (s4 !== peg$FAILED) { | |
s5 = peg$parseproximity_modifier(); | |
if (s5 === peg$FAILED) { | |
s5 = null; | |
} | |
s6 = peg$parseboost_modifier(); | |
if (s6 === peg$FAILED) { | |
s6 = null; | |
} | |
s7 = []; | |
s8 = peg$parse_(); | |
while (s8 !== peg$FAILED) { | |
s7.push(s8); | |
s8 = peg$parse_(); | |
} | |
peg$savedPos = s0; | |
s0 = peg$f13(s1, s2, s4, s5, s6); | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
if (s0 === peg$FAILED) { | |
s0 = peg$currPos; | |
s1 = peg$parsenot_exp(); | |
if (s1 === peg$FAILED) { | |
s1 = null; | |
} | |
s2 = peg$parseprefix_operator_exp(); | |
if (s2 === peg$FAILED) { | |
s2 = null; | |
} | |
s3 = peg$parseoperator_exp(); | |
if (s3 !== peg$FAILED) { | |
peg$savedPos = s0; | |
s0 = peg$f14(s1, s2, s3); | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} | |
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parseescape_sequence() { | |
var s0, s1, s2; | |
var key = peg$currPos * 25 + 7; | |
var cached = peg$resultsCache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
if (input.charCodeAt(peg$currPos) === 92) { | |
s1 = peg$c5; | |
peg$currPos++; | |
} else { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e5); | |
} | |
} | |
if (s1 !== peg$FAILED) { | |
s2 = input.charAt(peg$currPos); | |
if (peg$r0.test(s2)) { | |
peg$currPos++; | |
} else { | |
s2 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e6); | |
} | |
} | |
if (s2 !== peg$FAILED) { | |
s1 = [s1, s2]; | |
s0 = s1; | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parsename_term() { | |
var s0, s1, s2; | |
var key = peg$currPos * 25 + 8; | |
var cached = peg$resultsCache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
s1 = []; | |
s2 = input.charAt(peg$currPos); | |
if (peg$r1.test(s2)) { | |
peg$currPos++; | |
} else { | |
s2 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e7); | |
} | |
} | |
if (s2 === peg$FAILED) { | |
s2 = peg$parseescape_sequence(); | |
} | |
if (s2 !== peg$FAILED) { | |
while (s2 !== peg$FAILED) { | |
s1.push(s2); | |
s2 = input.charAt(peg$currPos); | |
if (peg$r1.test(s2)) { | |
peg$currPos++; | |
} else { | |
s2 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e7); | |
} | |
} | |
if (s2 === peg$FAILED) { | |
s2 = peg$parseescape_sequence(); | |
} | |
} | |
} else { | |
s1 = peg$FAILED; | |
} | |
if (s1 !== peg$FAILED) { | |
peg$savedPos = s0; | |
s1 = peg$f15(s1); | |
} | |
s0 = s1; | |
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parseunquoted_term() { | |
var s0, s1, s2; | |
var key = peg$currPos * 25 + 9; | |
var cached = peg$resultsCache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
s1 = []; | |
s2 = input.charAt(peg$currPos); | |
if (peg$r1.test(s2)) { | |
peg$currPos++; | |
} else { | |
s2 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e7); | |
} | |
} | |
if (s2 === peg$FAILED) { | |
s2 = peg$parseescape_sequence(); | |
} | |
if (s2 !== peg$FAILED) { | |
while (s2 !== peg$FAILED) { | |
s1.push(s2); | |
s2 = input.charAt(peg$currPos); | |
if (peg$r1.test(s2)) { | |
peg$currPos++; | |
} else { | |
s2 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e7); | |
} | |
} | |
if (s2 === peg$FAILED) { | |
s2 = peg$parseescape_sequence(); | |
} | |
} | |
} else { | |
s1 = peg$FAILED; | |
} | |
if (s1 !== peg$FAILED) { | |
peg$savedPos = s0; | |
s1 = peg$f16(s1); | |
} | |
s0 = s1; | |
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parserange_unquoted_term() { | |
var s0, s1, s2, s3, s4; | |
var key = peg$currPos * 25 + 10; | |
var cached = peg$resultsCache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
s1 = []; | |
s2 = input.charAt(peg$currPos); | |
if (peg$r2.test(s2)) { | |
peg$currPos++; | |
} else { | |
s2 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e8); | |
} | |
} | |
if (s2 === peg$FAILED) { | |
s2 = peg$currPos; | |
s3 = input.charAt(peg$currPos); | |
if (peg$r3.test(s3)) { | |
peg$currPos++; | |
} else { | |
s3 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e9); | |
} | |
} | |
if (s3 !== peg$FAILED) { | |
s4 = input.charAt(peg$currPos); | |
if (peg$r4.test(s4)) { | |
peg$currPos++; | |
} else { | |
s4 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e10); | |
} | |
} | |
if (s4 !== peg$FAILED) { | |
s3 = [s3, s4]; | |
s2 = s3; | |
} else { | |
peg$currPos = s2; | |
s2 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s2; | |
s2 = peg$FAILED; | |
} | |
if (s2 === peg$FAILED) { | |
s2 = peg$parseescape_sequence(); | |
} | |
} | |
if (s2 !== peg$FAILED) { | |
while (s2 !== peg$FAILED) { | |
s1.push(s2); | |
s2 = input.charAt(peg$currPos); | |
if (peg$r2.test(s2)) { | |
peg$currPos++; | |
} else { | |
s2 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e8); | |
} | |
} | |
if (s2 === peg$FAILED) { | |
s2 = peg$currPos; | |
s3 = input.charAt(peg$currPos); | |
if (peg$r3.test(s3)) { | |
peg$currPos++; | |
} else { | |
s3 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e9); | |
} | |
} | |
if (s3 !== peg$FAILED) { | |
s4 = input.charAt(peg$currPos); | |
if (peg$r4.test(s4)) { | |
peg$currPos++; | |
} else { | |
s4 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e10); | |
} | |
} | |
if (s4 !== peg$FAILED) { | |
s3 = [s3, s4]; | |
s2 = s3; | |
} else { | |
peg$currPos = s2; | |
s2 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s2; | |
s2 = peg$FAILED; | |
} | |
if (s2 === peg$FAILED) { | |
s2 = peg$parseescape_sequence(); | |
} | |
} | |
} | |
} else { | |
s1 = peg$FAILED; | |
} | |
if (s1 === peg$FAILED) { | |
if (input.charCodeAt(peg$currPos) === 42) { | |
s1 = peg$c6; | |
peg$currPos++; | |
} else { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e11); | |
} | |
} | |
} | |
if (s1 !== peg$FAILED) { | |
peg$savedPos = s0; | |
s1 = peg$f17(s1); | |
} | |
s0 = s1; | |
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parsequoted_term() { | |
var s0, s1, s2, s3; | |
var key = peg$currPos * 25 + 11; | |
var cached = peg$resultsCache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
if (input.charCodeAt(peg$currPos) === 34) { | |
s1 = peg$c7; | |
peg$currPos++; | |
} else { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e12); | |
} | |
} | |
if (s1 !== peg$FAILED) { | |
s2 = []; | |
if (input.substr(peg$currPos, 2) === peg$c8) { | |
s3 = peg$c8; | |
peg$currPos += 2; | |
} else { | |
s3 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e13); | |
} | |
} | |
if (s3 === peg$FAILED) { | |
s3 = input.charAt(peg$currPos); | |
if (peg$r5.test(s3)) { | |
peg$currPos++; | |
} else { | |
s3 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e14); | |
} | |
} | |
} | |
while (s3 !== peg$FAILED) { | |
s2.push(s3); | |
if (input.substr(peg$currPos, 2) === peg$c8) { | |
s3 = peg$c8; | |
peg$currPos += 2; | |
} else { | |
s3 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e13); | |
} | |
} | |
if (s3 === peg$FAILED) { | |
s3 = input.charAt(peg$currPos); | |
if (peg$r5.test(s3)) { | |
peg$currPos++; | |
} else { | |
s3 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e14); | |
} | |
} | |
} | |
} | |
if (input.charCodeAt(peg$currPos) === 34) { | |
s3 = peg$c7; | |
peg$currPos++; | |
} else { | |
s3 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e12); | |
} | |
} | |
if (s3 !== peg$FAILED) { | |
peg$savedPos = s0; | |
s0 = peg$f18(s2); | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
if (s0 === peg$FAILED) { | |
s0 = peg$currPos; | |
if (input.charCodeAt(peg$currPos) === 34) { | |
s1 = peg$c7; | |
peg$currPos++; | |
} else { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e12); | |
} | |
} | |
if (s1 !== peg$FAILED) { | |
s2 = []; | |
if (input.substr(peg$currPos, 2) === peg$c8) { | |
s3 = peg$c8; | |
peg$currPos += 2; | |
} else { | |
s3 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e13); | |
} | |
} | |
if (s3 === peg$FAILED) { | |
s3 = input.charAt(peg$currPos); | |
if (peg$r5.test(s3)) { | |
peg$currPos++; | |
} else { | |
s3 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e14); | |
} | |
} | |
} | |
while (s3 !== peg$FAILED) { | |
s2.push(s3); | |
if (input.substr(peg$currPos, 2) === peg$c8) { | |
s3 = peg$c8; | |
peg$currPos += 2; | |
} else { | |
s3 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e13); | |
} | |
} | |
if (s3 === peg$FAILED) { | |
s3 = input.charAt(peg$currPos); | |
if (peg$r5.test(s3)) { | |
peg$currPos++; | |
} else { | |
s3 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e14); | |
} | |
} | |
} | |
} | |
peg$savedPos = s0; | |
s0 = peg$f19(s2); | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} | |
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parseregex_term() { | |
var s0, s1, s2, s3; | |
var key = peg$currPos * 25 + 12; | |
var cached = peg$resultsCache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
if (input.charCodeAt(peg$currPos) === 47) { | |
s1 = peg$c9; | |
peg$currPos++; | |
} else { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e15); | |
} | |
} | |
if (s1 !== peg$FAILED) { | |
s2 = []; | |
if (input.charCodeAt(peg$currPos) === 47) { | |
s3 = peg$c9; | |
peg$currPos++; | |
} else { | |
s3 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e15); | |
} | |
} | |
if (s3 === peg$FAILED) { | |
s3 = input.charAt(peg$currPos); | |
if (peg$r6.test(s3)) { | |
peg$currPos++; | |
} else { | |
s3 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e16); | |
} | |
} | |
} | |
if (s3 !== peg$FAILED) { | |
while (s3 !== peg$FAILED) { | |
s2.push(s3); | |
if (input.charCodeAt(peg$currPos) === 47) { | |
s3 = peg$c9; | |
peg$currPos++; | |
} else { | |
s3 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e15); | |
} | |
} | |
if (s3 === peg$FAILED) { | |
s3 = input.charAt(peg$currPos); | |
if (peg$r6.test(s3)) { | |
peg$currPos++; | |
} else { | |
s3 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e16); | |
} | |
} | |
} | |
} | |
} else { | |
s2 = peg$FAILED; | |
} | |
if (s2 !== peg$FAILED) { | |
if (input.charCodeAt(peg$currPos) === 47) { | |
s3 = peg$c9; | |
peg$currPos++; | |
} else { | |
s3 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e15); | |
} | |
} | |
if (s3 !== peg$FAILED) { | |
peg$savedPos = s0; | |
s0 = peg$f20(s2); | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
if (s0 === peg$FAILED) { | |
s0 = peg$currPos; | |
if (input.charCodeAt(peg$currPos) === 47) { | |
s1 = peg$c9; | |
peg$currPos++; | |
} else { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e15); | |
} | |
} | |
if (s1 !== peg$FAILED) { | |
s2 = []; | |
if (input.charCodeAt(peg$currPos) === 47) { | |
s3 = peg$c9; | |
peg$currPos++; | |
} else { | |
s3 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e15); | |
} | |
} | |
if (s3 === peg$FAILED) { | |
s3 = input.charAt(peg$currPos); | |
if (peg$r6.test(s3)) { | |
peg$currPos++; | |
} else { | |
s3 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e16); | |
} | |
} | |
} | |
if (s3 !== peg$FAILED) { | |
while (s3 !== peg$FAILED) { | |
s2.push(s3); | |
if (input.charCodeAt(peg$currPos) === 47) { | |
s3 = peg$c9; | |
peg$currPos++; | |
} else { | |
s3 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e15); | |
} | |
} | |
if (s3 === peg$FAILED) { | |
s3 = input.charAt(peg$currPos); | |
if (peg$r6.test(s3)) { | |
peg$currPos++; | |
} else { | |
s3 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e16); | |
} | |
} | |
} | |
} | |
} else { | |
s2 = peg$FAILED; | |
} | |
if (s2 !== peg$FAILED) { | |
peg$savedPos = s0; | |
s0 = peg$f21(s2); | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} | |
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parseboost_modifier() { | |
var s0, s1, s2; | |
var key = peg$currPos * 25 + 13; | |
var cached = peg$resultsCache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
if (input.charCodeAt(peg$currPos) === 94) { | |
s1 = peg$c10; | |
peg$currPos++; | |
} else { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e17); | |
} | |
} | |
if (s1 !== peg$FAILED) { | |
s2 = peg$parsequoted_term(); | |
if (s2 === peg$FAILED) { | |
s2 = peg$parseunquoted_term(); | |
} | |
if (s2 !== peg$FAILED) { | |
peg$savedPos = s0; | |
s0 = peg$f22(s2); | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parseproximity_modifier() { | |
var s0, s1, s2; | |
var key = peg$currPos * 25 + 14; | |
var cached = peg$resultsCache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
if (input.charCodeAt(peg$currPos) === 126) { | |
s1 = peg$c11; | |
peg$currPos++; | |
} else { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e18); | |
} | |
} | |
if (s1 !== peg$FAILED) { | |
s2 = peg$parseunquoted_term(); | |
if (s2 === peg$FAILED) { | |
s2 = null; | |
} | |
peg$savedPos = s0; | |
s0 = peg$f23(s2); | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parserange_operator_exp() { | |
var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9; | |
var key = peg$currPos * 25 + 15; | |
var cached = peg$resultsCache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
s1 = input.charAt(peg$currPos); | |
if (peg$r7.test(s1)) { | |
peg$currPos++; | |
} else { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e19); | |
} | |
} | |
if (s1 !== peg$FAILED) { | |
s2 = []; | |
s3 = peg$parse_(); | |
while (s3 !== peg$FAILED) { | |
s2.push(s3); | |
s3 = peg$parse_(); | |
} | |
s3 = peg$parserange_unquoted_term(); | |
if (s3 === peg$FAILED) { | |
s3 = peg$parsequoted_term(); | |
} | |
if (s3 !== peg$FAILED) { | |
s4 = peg$parserange_delimiter_exp(); | |
if (s4 !== peg$FAILED) { | |
s5 = peg$parserange_unquoted_term(); | |
if (s5 === peg$FAILED) { | |
s5 = peg$parsequoted_term(); | |
} | |
if (s5 !== peg$FAILED) { | |
s6 = []; | |
s7 = peg$parse_(); | |
while (s7 !== peg$FAILED) { | |
s6.push(s7); | |
s7 = peg$parse_(); | |
} | |
s7 = input.charAt(peg$currPos); | |
if (peg$r8.test(s7)) { | |
peg$currPos++; | |
} else { | |
s7 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e20); | |
} | |
} | |
if (s7 !== peg$FAILED) { | |
s8 = peg$parseproximity_modifier(); | |
if (s8 === peg$FAILED) { | |
s8 = null; | |
} | |
s9 = peg$parseboost_modifier(); | |
if (s9 === peg$FAILED) { | |
s9 = null; | |
} | |
peg$savedPos = s0; | |
s0 = peg$f24(s1, s3, s4, s5, s7, s8, s9); | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
if (s0 === peg$FAILED) { | |
s0 = peg$currPos; | |
if (input.substr(peg$currPos, 2) === peg$c12) { | |
s1 = peg$c12; | |
peg$currPos += 2; | |
} else { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e21); | |
} | |
} | |
if (s1 === peg$FAILED) { | |
if (input.charCodeAt(peg$currPos) === 62) { | |
s1 = peg$c13; | |
peg$currPos++; | |
} else { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e22); | |
} | |
} | |
if (s1 === peg$FAILED) { | |
if (input.substr(peg$currPos, 2) === peg$c14) { | |
s1 = peg$c14; | |
peg$currPos += 2; | |
} else { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e23); | |
} | |
} | |
if (s1 === peg$FAILED) { | |
if (input.charCodeAt(peg$currPos) === 60) { | |
s1 = peg$c15; | |
peg$currPos++; | |
} else { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e24); | |
} | |
} | |
} | |
} | |
} | |
if (s1 !== peg$FAILED) { | |
s2 = []; | |
s3 = peg$parse_(); | |
while (s3 !== peg$FAILED) { | |
s2.push(s3); | |
s3 = peg$parse_(); | |
} | |
s3 = peg$parserange_unquoted_term(); | |
if (s3 === peg$FAILED) { | |
s3 = peg$parsequoted_term(); | |
} | |
if (s3 !== peg$FAILED) { | |
s4 = peg$parseproximity_modifier(); | |
if (s4 === peg$FAILED) { | |
s4 = null; | |
} | |
s5 = peg$parseboost_modifier(); | |
if (s5 === peg$FAILED) { | |
s5 = null; | |
} | |
peg$savedPos = s0; | |
s0 = peg$f25(s1, s3, s4, s5); | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} | |
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parserange_delimiter_exp() { | |
var s0, s1, s2, s3, s4; | |
var key = peg$currPos * 25 + 16; | |
var cached = peg$resultsCache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
s1 = []; | |
s2 = peg$parse_(); | |
if (s2 !== peg$FAILED) { | |
while (s2 !== peg$FAILED) { | |
s1.push(s2); | |
s2 = peg$parse_(); | |
} | |
} else { | |
s1 = peg$FAILED; | |
} | |
if (s1 !== peg$FAILED) { | |
if (input.substr(peg$currPos, 2) === peg$c16) { | |
s2 = peg$c16; | |
peg$currPos += 2; | |
} else { | |
s2 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e25); | |
} | |
} | |
if (s2 !== peg$FAILED) { | |
s3 = []; | |
s4 = peg$parse_(); | |
if (s4 !== peg$FAILED) { | |
while (s4 !== peg$FAILED) { | |
s3.push(s4); | |
s4 = peg$parse_(); | |
} | |
} else { | |
s3 = peg$FAILED; | |
} | |
if (s3 !== peg$FAILED) { | |
s1 = [s1, s2, s3]; | |
s0 = s1; | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
if (s0 === peg$FAILED) { | |
s0 = peg$currPos; | |
s1 = []; | |
s2 = peg$parse_(); | |
while (s2 !== peg$FAILED) { | |
s1.push(s2); | |
s2 = peg$parse_(); | |
} | |
if (input.substr(peg$currPos, 2) === peg$c17) { | |
s2 = peg$c17; | |
peg$currPos += 2; | |
} else { | |
s2 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e26); | |
} | |
} | |
if (s2 !== peg$FAILED) { | |
s3 = []; | |
s4 = peg$parse_(); | |
while (s4 !== peg$FAILED) { | |
s3.push(s4); | |
s4 = peg$parse_(); | |
} | |
s1 = [s1, s2, s3]; | |
s0 = s1; | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} | |
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parsenot_exp() { | |
var s0, s1, s2, s3; | |
var key = peg$currPos * 25 + 17; | |
var cached = peg$resultsCache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
if (input.substr(peg$currPos, 3) === peg$c18) { | |
s1 = peg$c18; | |
peg$currPos += 3; | |
} else { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e27); | |
} | |
} | |
if (s1 !== peg$FAILED) { | |
s2 = []; | |
s3 = peg$parse_(); | |
if (s3 !== peg$FAILED) { | |
while (s3 !== peg$FAILED) { | |
s2.push(s3); | |
s3 = peg$parse_(); | |
} | |
} else { | |
s2 = peg$FAILED; | |
} | |
if (s2 !== peg$FAILED) { | |
s1 = [s1, s2]; | |
s0 = s1; | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parseoperator_exp() { | |
var s0, s1, s2, s3, s4; | |
var key = peg$currPos * 25 + 18; | |
var cached = peg$resultsCache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
s1 = []; | |
s2 = peg$parse_(); | |
while (s2 !== peg$FAILED) { | |
s1.push(s2); | |
s2 = peg$parse_(); | |
} | |
s2 = peg$parseoperator(); | |
if (s2 !== peg$FAILED) { | |
s3 = []; | |
s4 = peg$parse_(); | |
if (s4 !== peg$FAILED) { | |
while (s4 !== peg$FAILED) { | |
s3.push(s4); | |
s4 = peg$parse_(); | |
} | |
} else { | |
s3 = peg$FAILED; | |
} | |
if (s3 !== peg$FAILED) { | |
peg$savedPos = s0; | |
s0 = peg$f26(s2); | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parseoperator() { | |
var s0, s1; | |
var key = peg$currPos * 25 + 19; | |
var cached = peg$resultsCache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
if (input.substr(peg$currPos, 2) === peg$c19) { | |
s1 = peg$c19; | |
peg$currPos += 2; | |
} else { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e28); | |
} | |
} | |
if (s1 !== peg$FAILED) { | |
peg$savedPos = s0; | |
s1 = peg$f27(); | |
} | |
s0 = s1; | |
if (s0 === peg$FAILED) { | |
s0 = peg$currPos; | |
if (input.substr(peg$currPos, 3) === peg$c20) { | |
s1 = peg$c20; | |
peg$currPos += 3; | |
} else { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e29); | |
} | |
} | |
if (s1 !== peg$FAILED) { | |
peg$savedPos = s0; | |
s1 = peg$f28(); | |
} | |
s0 = s1; | |
if (s0 === peg$FAILED) { | |
s0 = peg$currPos; | |
if (input.substr(peg$currPos, 2) === peg$c21) { | |
s1 = peg$c21; | |
peg$currPos += 2; | |
} else { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e30); | |
} | |
} | |
if (s1 !== peg$FAILED) { | |
peg$savedPos = s0; | |
s1 = peg$f29(); | |
} | |
s0 = s1; | |
if (s0 === peg$FAILED) { | |
s0 = peg$currPos; | |
if (input.substr(peg$currPos, 2) === peg$c22) { | |
s1 = peg$c22; | |
peg$currPos += 2; | |
} else { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e31); | |
} | |
} | |
if (s1 !== peg$FAILED) { | |
peg$savedPos = s0; | |
s1 = peg$f30(); | |
} | |
s0 = s1; | |
} | |
} | |
} | |
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parseprefix_operator_exp() { | |
var s0, s1, s2, s3, s4; | |
var key = peg$currPos * 25 + 20; | |
var cached = peg$resultsCache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
s1 = []; | |
s2 = peg$parse_(); | |
while (s2 !== peg$FAILED) { | |
s1.push(s2); | |
s2 = peg$parse_(); | |
} | |
s2 = peg$parseprefix_operator(); | |
if (s2 !== peg$FAILED) { | |
s3 = peg$currPos; | |
peg$silentFails++; | |
s4 = peg$parse_(); | |
peg$silentFails--; | |
if (s4 === peg$FAILED) { | |
s3 = undefined; | |
} else { | |
peg$currPos = s3; | |
s3 = peg$FAILED; | |
} | |
if (s3 !== peg$FAILED) { | |
peg$savedPos = s0; | |
s0 = peg$f31(s2); | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parseprefix_operator() { | |
var s0; | |
var key = peg$currPos * 25 + 21; | |
var cached = peg$resultsCache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = input.charAt(peg$currPos); | |
if (peg$r9.test(s0)) { | |
peg$currPos++; | |
} else { | |
s0 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e32); | |
} | |
} | |
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parse_() { | |
var s0, s1; | |
var key = peg$currPos * 25 + 22; | |
var cached = peg$resultsCache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = []; | |
s1 = input.charAt(peg$currPos); | |
if (peg$r10.test(s1)) { | |
peg$currPos++; | |
} else { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e33); | |
} | |
} | |
if (s1 !== peg$FAILED) { | |
while (s1 !== peg$FAILED) { | |
s0.push(s1); | |
s1 = input.charAt(peg$currPos); | |
if (peg$r10.test(s1)) { | |
peg$currPos++; | |
} else { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e33); | |
} | |
} | |
} | |
} else { | |
s0 = peg$FAILED; | |
} | |
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parsemissing_paren() { | |
var s0, s1; | |
var key = peg$currPos * 25 + 23; | |
var cached = peg$resultsCache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
s1 = ''; | |
peg$savedPos = s0; | |
s1 = peg$f32(); | |
s0 = s1; | |
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parseEOF() { | |
var s0, s1; | |
var key = peg$currPos * 25 + 24; | |
var cached = peg$resultsCache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
peg$silentFails++; | |
if (input.length > peg$currPos) { | |
s1 = input.charAt(peg$currPos); | |
peg$currPos++; | |
} else { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { | |
peg$fail(peg$e34); | |
} | |
} | |
peg$silentFails--; | |
if (s1 === peg$FAILED) { | |
s0 = undefined; | |
} else { | |
peg$currPos = s0; | |
s0 = peg$FAILED; | |
} | |
peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
class FieldInfo { | |
constructor(field, prefix = null) { | |
this.field = field; | |
this.prefix = prefix; | |
} | |
} | |
class TermInfo { | |
constructor(term, isQuoted = false, isRegex = false) { | |
this.term = term; | |
this.isQuoted = isQuoted; | |
this.isRegex = isRegex; | |
} | |
} | |
class GroupNode { | |
constructor() { | |
this.operator = null; | |
this.left = null; | |
this.right = null; | |
this.hasParens = false; | |
this.prefix = null; | |
this.boost = null; | |
this.isNegated = false; | |
// Added for safety: | |
this.field = null; | |
} | |
} | |
class ExistsNode { | |
constructor() { | |
this.isNegated = false; | |
this.prefix = null; | |
this.field = null; | |
} | |
} | |
class MissingNode { | |
constructor() { | |
this.isNegated = false; | |
this.prefix = null; | |
this.field = null; | |
} | |
} | |
class TermNode { | |
constructor() { | |
this.term = null; | |
this.isQuotedTerm = false; | |
this.isRegexTerm = false; | |
this.proximity = null; | |
this.boost = null; | |
this.isNegated = false; | |
this.prefix = null; | |
this.field = null; | |
} | |
copyTo(target) { | |
target.term = this.term; | |
target.isQuotedTerm = this.isQuotedTerm; | |
target.isRegexTerm = this.isRegexTerm; | |
} | |
} | |
class TermRangeNode { | |
constructor() { | |
this.min = null; | |
this.isMinQuotedTerm = false; | |
this.max = null; | |
this.isMaxQuotedTerm = false; | |
this.minInclusive = false; | |
this.maxInclusive = false; | |
this.delimiter = null; | |
this.proximity = null; | |
this.boost = null; | |
this.operator = null; | |
} | |
} | |
const GroupOperator = { | |
And: 'AND', | |
Or: 'OR' | |
}; | |
peg$result = peg$startRuleFunction(); | |
if (options.peg$library) { | |
return /** @type {any} */ ({ | |
peg$currPos, | |
peg$FAILED, | |
peg$maxFailExpected, | |
peg$maxFailPos, | |
peg$result | |
}); | |
} | |
if (peg$result !== peg$FAILED && peg$currPos === input.length) { | |
return peg$result; | |
} else { | |
if (peg$result !== peg$FAILED && peg$currPos < input.length) { | |
peg$fail(peg$endExpectation()); | |
} | |
throw peg$buildStructuredError( | |
peg$maxFailExpected, | |
peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null, | |
peg$maxFailPos < input.length ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1) : peg$computeLocation(peg$maxFailPos, peg$maxFailPos) | |
); | |
} | |
} | |
const peg$allowedStartRules = ['start']; | |
export { peg$parse as parse, peg$allowedStartRules as StartRules, peg$SyntaxError as SyntaxError }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@namespace Foundatio.Parsers.LuceneQueries | |
@classname LuceneQueryParser | |
@trace true | |
@using System.Linq; | |
@using Foundatio.Parsers.LuceneQueries.Nodes; | |
@using Foundatio.Parsers.LuceneQueries.Extensions; | |
@members | |
{ | |
public class FieldInfo { | |
public string Field { get; set; } | |
public string Prefix { get; set; } | |
} | |
public class TermInfo { | |
public string Term { get; set; } | |
public bool IsQuoted { get; set; } | |
public bool IsRegex { get; set; } | |
} | |
} | |
start<GroupNode> | |
= _* node:node? _* EOF | |
{ | |
node.SingleOrDefault() ?? new GroupNode() | |
} | |
node<GroupNode> | |
= op:operator_exp EOF | |
{ | |
new GroupNode { | |
Operator = op | |
} | |
} | |
/ op:operator_exp right:node | |
{ | |
right | |
} | |
/ left:group_exp op:operator_exp? right:node* | |
{{ | |
var node= new GroupNode { | |
Left = left | |
}; | |
left.Parent = node; | |
var rightExp = | |
right.Count == 0 | |
? (TermNode)null | |
: right[0].Right == null | |
? right[0].Left | |
: right[0]; | |
if (rightExp != null) | |
{ | |
node.Operator = op.SingleOrDefault(); | |
node.Right = rightExp; | |
rightExp.Parent = node; | |
} | |
return node; | |
}} | |
group_exp<IQueryNode> | |
= field_exp:field_exp _* | |
{ | |
field_exp | |
} | |
/ paren_exp | |
paren_exp<GroupNode> | |
= not:not_exp? op:prefix_operator_exp? "(" _* node:node _* (")" / #error{ "Missing closing paren ')' for group expression" }) boost:boost_modifier? _* | |
{{ | |
node.HasParens = true; | |
node.Prefix = op.SingleOrDefault(); | |
if (boost.Count > 0) | |
node.Boost = boost.SingleOrDefault(); | |
if (not.Any()) | |
node.IsNegated = true; | |
return node; | |
}} | |
field_exp<IQueryNode> | |
= not:not_exp? op:prefix_operator_exp? '_exists_' _* ':' _* fieldname:name_term | |
{{ | |
return new ExistsNode { IsNegated = not.Any(), Prefix = op.SingleOrDefault(), Field = fieldname }; | |
}} | |
/ not:not_exp? op:prefix_operator_exp? '_missing_' _* ':' _* fieldname:name_term | |
{{ | |
return new MissingNode { IsNegated = not.Any(), Prefix = op.SingleOrDefault(), Field = fieldname }; | |
}} | |
/ not:not_exp? name:fieldname? range:range_operator_exp | |
{{ | |
if (name.Count == 1) { | |
range.IsNegated = not.Any(); | |
range.Field = name[0].Field; | |
range.Prefix = name[0].Prefix; | |
} | |
return range; | |
}} | |
/ not:not_exp? op:prefix_operator_exp? range:range_operator_exp | |
{{ | |
range.IsNegated = not.Any(); | |
range.Prefix = op.SingleOrDefault(); | |
return range; | |
}} | |
/ not:not_exp? name:fieldname node:paren_exp | |
{{ | |
node.IsNegated = not.Any(); | |
node.Field = name.Field; | |
node.Prefix = name.Prefix; | |
return node; | |
}} | |
/ not:not_exp? name:fieldname? term:term | |
{{ | |
var query = new TermNode(); | |
if (not.Any()) | |
query.IsNegated = true; | |
if (name.Count == 1) { | |
query.Field = name[0].Field; | |
query.Prefix = name[0].Prefix; | |
} | |
term.CopyTo(query); | |
return query; | |
}} | |
fieldname<FieldInfo> -lexical | |
= op:prefix_operator_exp? fieldname:name_term _* ':' _* | |
{{ | |
var result = new FieldInfo { Field = fieldname }; | |
result.Prefix = op.SingleOrDefault(); | |
return result; | |
}} | |
term<TermNode> | |
= not:not_exp? op:prefix_operator_exp? !operator_exp term:(quoted_term / regex_term / unquoted_term) proximity:proximity_modifier? boost:boost_modifier? _* | |
{{ | |
var result = new TermNode { Term = term.Term, IsQuotedTerm = term.IsQuoted, IsRegexTerm = term.IsRegex }; | |
if (proximity.Count > 0) | |
result.Proximity = proximity.SingleOrDefault(); | |
if (boost.Count > 0) | |
result.Boost = boost.SingleOrDefault(); | |
if (not.Any()) | |
result.IsNegated = true; | |
result.Prefix = op.SingleOrDefault(); | |
return result; | |
}} | |
/ not:not_exp? prefix:prefix_operator_exp? op:operator_exp #error{ "Unexpected operator '" + op + "'." } | |
// https://lucene.apache.org/core/2_9_4/queryparsersyntax.html#Escaping%20Special%20Characters | |
escape_sequence | |
= '\\' [ \+\-\!\(\)\{\}\[\]\^\"\~\*\?\:\\\/] | |
name_term | |
= term:(([^: \\\t\r\n\f\{\}\(\)"^~\[\]] / escape_sequence)+ "") | |
{ | |
term | |
} | |
unquoted_term<TermInfo> | |
= term:(([^: \\\t\r\n\f\{\}\(\)"^~\[\]] / escape_sequence)+ "") | |
{ | |
new TermInfo { Term = term } | |
} | |
range_unquoted_term<TermInfo> | |
= term:((([^: \\\.\t\r\n\f\{\}\(\)"^~\[\]] / [\.][^\.] / escape_sequence)+ "") / '*') | |
{ | |
new TermInfo { Term = term } | |
} | |
quoted_term<TermInfo> | |
= '"' term:(('\\"' / [^"])* "") ('"' / #error{ "Unterminated quoted string" }) | |
{ | |
new TermInfo { Term = term, IsQuoted = true } | |
} | |
regex_term<TermInfo> | |
= '/' term:(('\\/' / [^/])+ "") ('/' / #error{ "Unterminated regex" }) | |
{ | |
new TermInfo { Term = term, IsRegex = true } | |
} | |
boost_modifier<string> | |
= '^' boost:(quoted_term / unquoted_term) | |
{ | |
boost.Term | |
} | |
proximity_modifier<string> | |
= '~' proximity:(unquoted_term? "") | |
{ | |
proximity | |
} | |
range_operator_exp<TermRangeNode> | |
= left:('[' / '{') _* term_min:(range_unquoted_term / quoted_term) delim:range_delimiter_exp term_max:(range_unquoted_term / quoted_term) _* right:(']' / '}') proximity:proximity_modifier? boost:boost_modifier? | |
{{ | |
var result = new TermRangeNode { | |
Min = term_min.Term, | |
IsMinQuotedTerm = term_min.IsQuoted, | |
Max = term_max.Term, | |
IsMaxQuotedTerm = term_max.IsQuoted, | |
MinInclusive = left.SingleOrDefault() == '[' ? true : false, | |
MaxInclusive = right.SingleOrDefault() == ']' ? true : false, | |
Delimiter = delim | |
}; | |
if (proximity.Count > 0) | |
result.Proximity = proximity.SingleOrDefault(); | |
if (boost.Count > 0) | |
result.Boost = boost.SingleOrDefault(); | |
return result; | |
}} | |
/ op:(">=" / ">" / "<=" / "<") _* term:(range_unquoted_term / quoted_term) proximity:proximity_modifier? boost:boost_modifier? | |
{{ | |
var result = new TermRangeNode { | |
Min = op.StartsWith(">") ? term.Term : null, | |
MinInclusive = op == ">=", | |
IsMinQuotedTerm = op.StartsWith(">") && term.IsQuoted, | |
Max = op.StartsWith("<") ? term.Term : null, | |
MaxInclusive = op == "<=", | |
IsMaxQuotedTerm = op.StartsWith("<") && term.IsQuoted, | |
Operator = op | |
}; | |
if (proximity.Count > 0) | |
result.Proximity = proximity.SingleOrDefault(); | |
if (boost.Count > 0) | |
result.Boost = boost.SingleOrDefault(); | |
return result; | |
}} | |
range_delimiter_exp -lexical | |
= _+ 'TO' _+ | |
/ _* '..' _* | |
not_exp | |
= 'NOT' _+ | |
operator_exp<GroupOperator> | |
= _* op:operator _+ | |
{ | |
op | |
} | |
operator<GroupOperator> -lexical | |
= "OR" { GroupOperator.Or } | |
/ "AND"{ GroupOperator.And } | |
/ "||" { GroupOperator.Or } | |
/ "&&" { GroupOperator.And } | |
prefix_operator_exp | |
= _* op:prefix_operator !_ | |
{ | |
op | |
} | |
prefix_operator -lexical | |
= '+' | |
/ '-' | |
/ '!' | |
_ | |
= [ \t\r\n\f]+ | |
EOF | |
= !. | |
/ unexpected:. #error{ "Unexpected character '" + unexpected + "'." } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
class FieldInfo { | |
constructor(field, prefix = null) { | |
this.field = field; | |
this.prefix = prefix; | |
} | |
} | |
class TermInfo { | |
constructor(term, isQuoted = false, isRegex = false) { | |
this.term = term; | |
this.isQuoted = isQuoted; | |
this.isRegex = isRegex; | |
} | |
} | |
class GroupNode { | |
constructor() { | |
this.operator = null; | |
this.left = null; | |
this.right = null; | |
this.hasParens = false; | |
this.prefix = null; | |
this.boost = null; | |
this.isNegated = false; | |
// Added for safety: | |
this.field = null; | |
} | |
} | |
class ExistsNode { | |
constructor() { | |
this.isNegated = false; | |
this.prefix = null; | |
this.field = null; | |
} | |
} | |
class MissingNode { | |
constructor() { | |
this.isNegated = false; | |
this.prefix = null; | |
this.field = null; | |
} | |
} | |
class TermNode { | |
constructor() { | |
this.term = null; | |
this.isQuotedTerm = false; | |
this.isRegexTerm = false; | |
this.proximity = null; | |
this.boost = null; | |
this.isNegated = false; | |
this.prefix = null; | |
this.field = null; | |
} | |
copyTo(target) { | |
target.term = this.term; | |
target.isQuotedTerm = this.isQuotedTerm; | |
target.isRegexTerm = this.isRegexTerm; | |
} | |
} | |
class TermRangeNode { | |
constructor() { | |
this.min = null; | |
this.isMinQuotedTerm = false; | |
this.max = null; | |
this.isMaxQuotedTerm = false; | |
this.minInclusive = false; | |
this.maxInclusive = false; | |
this.delimiter = null; | |
this.proximity = null; | |
this.boost = null; | |
this.operator = null; | |
} | |
} | |
const GroupOperator = { | |
Or: 'OR', | |
And: 'AND' | |
}; | |
} | |
start | |
= _* node:node? _* EOF { | |
return (node !== undefined ? node : new GroupNode()); | |
} | |
node | |
= op:operator_exp EOF { | |
let gn = new GroupNode(); | |
gn.operator = op; | |
return gn; | |
} | |
/ op:operator_exp right:node { | |
return right; | |
} | |
/ left:group_exp op:operator_exp? right:node* { | |
let gn = new GroupNode(); | |
gn.left = left; | |
let rightExp = (right.length === 0) | |
? null | |
: (right[0].right === null || right[0].right === undefined) | |
? right[0].left : right[0]; | |
if (rightExp !== null) { | |
gn.operator = (op !== null && op !== undefined) ? op : null; | |
gn.right = rightExp; | |
} | |
return gn; | |
} | |
group_exp | |
= f:field_exp _* { return f; } | |
/ paren_exp | |
paren_exp | |
= not:not_exp? op:prefix_operator_exp? "(" _* node:node _* (")" / missing_paren) boost:boost_modifier? _* { | |
node.hasParens = true; | |
node.prefix = (op !== null && op !== undefined) ? op : null; | |
if (boost !== null && boost !== undefined) { node.boost = boost; } | |
if (not !== null && not !== undefined) { node.isNegated = true; } | |
return node; | |
} | |
field_exp | |
= not:not_exp? op:prefix_operator_exp? '_exists_' _* ':' _* fieldname:name_term { | |
let en = new ExistsNode(); | |
en.isNegated = (not != null); | |
en.prefix = (op != null) ? op : null; | |
en.field = fieldname; | |
return en; | |
} | |
/ not:not_exp? op:prefix_operator_exp? '_missing_' _* ':' _* fieldname:name_term { | |
let mn = new MissingNode(); | |
mn.isNegated = (not != null); | |
mn.prefix = (op != null) ? op : null; | |
mn.field = fieldname; | |
return mn; | |
} | |
/ not:not_exp? name:fieldname? range:range_operator_exp { | |
if (name != null) { | |
range.isNegated = (not != null); | |
range.field = name.field; | |
range.prefix = name.prefix; | |
} | |
return range; | |
} | |
/ not:not_exp? op:prefix_operator_exp? range:range_operator_exp { | |
range.isNegated = (not != null); | |
range.prefix = (op != null) ? op : null; | |
return range; | |
} | |
/ not:not_exp? name:fieldname node:paren_exp { | |
node.isNegated = (not != null); | |
node.field = name.field; | |
node.prefix = name.prefix; | |
return node; | |
} | |
/ not:not_exp? name:fieldname term:term { | |
let tn = new TermNode(); | |
if (not != null) { tn.isNegated = true; } | |
tn.field = name.field; | |
tn.prefix = name.prefix; | |
term.copyTo(tn); | |
return tn; | |
} | |
fieldname | |
= op:prefix_operator_exp? fieldname:name_term _* ':' _* { | |
let fi = new FieldInfo(fieldname, (op != null) ? op : null); | |
return fi; | |
} | |
term | |
= not:not_exp? op:prefix_operator_exp? !operator_exp term:(quoted_term / regex_term / unquoted_term) proximity:proximity_modifier? boost:boost_modifier? _* { | |
let tn = new TermNode(); | |
tn.term = term.term; | |
tn.isQuotedTerm = term.isQuoted; | |
tn.isRegexTerm = term.isRegex; | |
if (proximity !== undefined) { tn.proximity = proximity; } | |
if (boost !== undefined) { tn.boost = boost; } | |
if (not !== undefined) { tn.isNegated = true; } | |
tn.prefix = (op !== null && op !== undefined) ? op : null; | |
return tn; | |
} | |
/ not:not_exp? prefix:prefix_operator_exp? op:operator_exp { throw new Error("Unexpected operator '" + op + "'."); } | |
// https://lucene.apache.org/core/2_9_4/queryparsersyntax.html#Escaping%20Special%20Characters | |
escape_sequence | |
= '\\' [+\-!(){}[\]^"~*?:\/] | |
name_term | |
= term:(([^: \t\r\n\f{}()"^~\[\]] / escape_sequence)+) { | |
return term.join(''); | |
} | |
unquoted_term | |
= term:(([^: \t\r\n\f{}()"^~\[\]] / escape_sequence)+) { | |
return new TermInfo(term.join('')); | |
} | |
range_unquoted_term | |
= term:((( [^: \.\t\r\n\f{}()"^~\[\]] / ([.][^.]) / escape_sequence)+) / '*') { | |
return new TermInfo(Array.isArray(term) ? term.join('') : term); | |
} | |
quoted_term | |
= '"' term:(('\\"' / [^"])* ) '"' { | |
return new TermInfo(term.join(''), true); | |
} | |
/ '"' term:(('\\"' / [^"])* ) { | |
throw new Error("Unterminated quoted string"); | |
} | |
regex_term | |
= '/' term:(('\/' / [^/])+ ) '/' { | |
return new TermInfo(term.join(''), false, true); | |
} | |
/ '/' term:(('\/' / [^/])+ ) { | |
throw new Error("Unterminated regex"); | |
} | |
boost_modifier | |
= '^' boost:(quoted_term / unquoted_term) { return boost.term; } | |
proximity_modifier | |
= '~' proximity:(unquoted_term?) { return proximity; } | |
range_operator_exp | |
= left:('[' / '{') _* term_min:(range_unquoted_term / quoted_term) delim:range_delimiter_exp term_max:(range_unquoted_term / quoted_term) _* right:(']' / '}') proximity:proximity_modifier? boost:boost_modifier? { | |
let trn = new TermRangeNode(); | |
trn.min = term_min.term; | |
trn.isMinQuotedTerm = term_min.isQuoted; | |
trn.max = term_max.term; | |
trn.isMaxQuotedTerm = term_max.isQuoted; | |
trn.minInclusive = left === '['; | |
trn.maxInclusive = right === ']'; | |
trn.delimiter = delim; | |
if (proximity !== undefined) { trn.proximity = proximity; } | |
if (boost !== undefined) { trn.boost = boost; } | |
return trn; | |
} | |
/ op:(">=" / ">" / "<=" / "<") _* term:(range_unquoted_term / quoted_term) proximity:proximity_modifier? boost:boost_modifier? { | |
let trn = new TermRangeNode(); | |
trn.min = op.startsWith(">") ? term.term : null; | |
trn.minInclusive = op === ">="; | |
trn.isMinQuotedTerm = op.startsWith(">") && term.isQuoted; | |
trn.max = op.startsWith("<") ? term.term : null; | |
trn.maxInclusive = op === "<="; | |
trn.isMaxQuotedTerm = op.startsWith("<") && term.isQuoted; | |
trn.operator = op; | |
if (proximity !== undefined) { trn.proximity = proximity; } | |
if (boost !== undefined) { trn.boost = boost; } | |
return trn; | |
} | |
range_delimiter_exp | |
= _+ "TO" _+ | |
/ _* ".." _* | |
not_exp | |
= "NOT" _+ | |
operator_exp | |
= _* op:operator _+ { return op; } | |
operator | |
= "OR" { return GroupOperator.Or; } | |
/ "AND" { return GroupOperator.And; } | |
/ "||" { return GroupOperator.Or; } | |
/ "&&" { return GroupOperator.And; } | |
prefix_operator_exp | |
= _* op:prefix_operator !_ { return op; } | |
prefix_operator | |
= '+' / '-' / '!' | |
_ | |
= [ \t\r\n\f]+ | |
missing_paren | |
= "" { throw new Error("Missing closing paren ')' for group expression"); } | |
EOF | |
= !. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
peggyjs/peggy#582 (comment)