Skip to content

Commit

Permalink
feat(parser): updates
Browse files Browse the repository at this point in the history
  • Loading branch information
chenasraf committed Aug 16, 2022
1 parent 905d9a0 commit 29c64eb
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 10 deletions.
53 changes: 53 additions & 0 deletions __tests__/parser_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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' },
},
],
},
})
})
10 changes: 10 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
55 changes: 45 additions & 10 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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:
Expand All @@ -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:
Expand All @@ -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 }
}
}

0 comments on commit 29c64eb

Please sign in to comment.