feat(parser): updates

This commit is contained in:
Chen Asraf
2022-08-16 18:59:30 +03:00
parent 905d9a0b8e
commit 29c64eb668
3 changed files with 108 additions and 10 deletions

View File

@@ -31,3 +31,56 @@ test('should parse OR operator', () => {
},
})
})
test('should parse AND operator', () => {
const reader = new StringReader('word AND "phrase"')
const lexer = new Lexer(reader)
const parser = new Parser(lexer)
const tokens = parser.parse()
expect(tokens[0]).toEqual({
type: 'operator',
value: 'and',
left: {
type: 'word',
value: 'word',
},
right: {
type: 'phrase',
value: 'phrase',
quote: '"',
},
})
})
test('should parse multiple groups and logical operators', () => {
const reader = new StringReader('(apple OR orange) AND (drink OR juice)')
const lexer = new Lexer(reader)
const parser = new Parser(lexer)
const tokens = parser.parse()
expect(tokens[0]).toEqual({
type: 'operator',
value: 'and',
left: {
type: 'group',
children: [
{
type: 'operator',
value: 'or',
left: { type: 'word', value: 'apple' },
right: { type: 'word', value: 'orange' },
},
],
},
right: {
type: 'group',
children: [
{
type: 'operator',
value: 'or',
left: { type: 'word', value: 'drink' },
right: { type: 'word', value: 'juice' },
},
],
},
})
})

View File

@@ -5,6 +5,16 @@
"main": "index.js",
"repository": "https://github.com/chenasraf/search-ast-parser-js",
"author": "Chen Asraf <contact@casraf.dev>",
"keywords": [
"search",
"query",
"ast",
"parser",
"javascript",
"typescript",
"tree",
"syntax"
],
"license": "MIT",
"private": false,
"devDependencies": {

View File

@@ -130,15 +130,24 @@ export class Parser extends IParser {
this.lexer.consume()
return this.readNextToken()
}
while (nextToken && nextToken.token === 'whitespace') {
nextToken = this.lexer.peek(1)
this.lexer.consume()
}
nextToken = this.peekSkipWhitespace(nextToken)
// lookahead
switch (nextToken?.token) {
case LexerToken.operator:
// this.index++
this.lexer.consume()
const parsed = this.parseNormalLexToken(token!)!
const nextParsed = this.readNextToken()!
this.index++
return this.consumeOperator(this.parseNormalLexToken(token!)!, nextToken)
this.lexer.consume()
return this.consumeOperator(parsed, nextToken, nextParsed)
case LexerToken.group:
if (nextToken.value === ')') {
return this.parseNormalLexToken(token)
}
this.index++
this.lexer.consume()
return this.consumeGroup(nextToken!)
}
// no special token coming up, proceed with this token
@@ -149,6 +158,14 @@ export class Parser extends IParser {
}
}
private peekSkipWhitespace(nextToken: LexerTokenValue | null) {
while (nextToken && nextToken.token === 'whitespace') {
this.lexer.consume()
nextToken = this.lexer.peek()
}
return nextToken
}
private parseNormalLexToken(token: LexerTokenValue | null): ParserToken | null {
switch (token?.token) {
case LexerToken.word:
@@ -158,6 +175,9 @@ export class Parser extends IParser {
const quoteContent = this.lexer.consume()!
this.lexer.consume()
return this.consumePhrase(token, quoteContent)
case LexerToken.group:
// this.lexer.consume()
return this.consumeGroup(token!)
// case LexerToken.operator:
// return this.consumeOperator(token, nextToken!)
default:
@@ -175,11 +195,26 @@ export class Parser extends IParser {
return { type: 'phrase', value: quoteContent.value, quote: token.value as '"' }
}
private consumeOperator(left: ParserToken, opToken: LexerTokenValue): ParserToken | null {
this.index++
this.lexer.consume()
const right = this.readNextToken()
this.lexer.consume()
private consumeOperator(
left: ParserToken,
opToken: LexerTokenValue,
right: ParserToken,
): ParserToken | null {
// this.lexer.consume()
return { type: 'operator', value: opToken.value, left, right }
}
private consumeGroup(token: LexerTokenValue): ParserToken | null {
const children: ParserToken[] = []
let nextToken = this.peekSkipWhitespace(this.lexer.peek())
while (nextToken && nextToken?.value !== ')') {
const child = this.readNextToken()
if (child) {
children.push(child)
}
nextToken = this.lexer.peek()
}
this.lexer.consume()
return { type: 'group', children }
}
}