fix shunting yard

This commit is contained in:
Rowan 2024-11-27 22:51:24 -06:00
parent d9ebc1e875
commit 3a776ca1e1
3 changed files with 52 additions and 16 deletions

View file

@ -1,4 +1,4 @@
import { assocPath, curry, identity, is, last, mergeRightDeep, path } from '../fn.js'
import { curry, is, last, mergeRightDeep, path } from '../fn.js'
import { Stream } from '../stream.js'
class Value {
@ -97,11 +97,11 @@ export class Function {
#pop(stack) {
const result = []
const len = stack.length - 1
const n = Math.min(this.length, len)
let n = Math.min(this.length, stack.length)
for(let i = len; i >= len - n; i--) {
while(n > 0) {
result.push(stack.pop())
n--
}
result.reverse()
@ -122,14 +122,14 @@ const Associativity = Object.freeze({
export class Operator extends Function {
constructor(name, fn, priority, associativity = Associativity.Left, length = fn.length) {
super(name, fn, length)
this.priority = priority
this.precedence = priority
this.associativity = associativity
}
compare(other) {
if (other.priority > this.priority) {
if (other.precedence < this.precedence) {
return 1
} else if (other.priority === this.priority) {
} else if (other.precedence === this.precedence) {
if (this.associativity === Associativity.Left) {
return 1
} else {
@ -185,9 +185,10 @@ export class Filter {
const next = stream.next()
if (is(Function, next)) {
if (is(Operator, next)) {
const ops = this.#takeUntil(op => leftParen(op) && next.compare(op) <= 0, operators)
const ops = this.#takeWhile(op => !leftParen(op) && next.compare(op) > 0, operators)
output.push.apply(output, ops)
}
operators.push(next)
} else if (comma(next)) {
output.push.apply(output, this.#takeUntil(leftParen, operators))
@ -196,9 +197,11 @@ export class Filter {
} else if (rightParen(next)) {
const ops = this.#takeUntil(leftParen, operators)
output.push.apply(output, ops)
if (!leftParen(operators.pop())) {
throw new SyntaxError('mismatched parenthesis')
}
if (is(Function, last(operators))) {
output.push(operators.pop())
}
@ -226,13 +229,13 @@ export class Filter {
const next = stream.next()
if (is(Operator, next)) {
const result = next.apply(stack)
stack.unshift(result)
stack.push(result)
} else {
stack.push(next)
}
}
return stack.every(identity)
return stack[0]
})
}
}

View file

@ -49,10 +49,37 @@ export class Iterator {
return accumulator
}
takeWhile(fn) {
const accumulator = []
while (!this.done() || fn(this.peek())) {
accumulator.push(this.next())
}
return accumulator
}
takeUntil(fn) {
return this.takeWhile(x => !fn(x))
}
drop(n) {
this.take(n)
return this
}
dropWhile(fn) {
while(!this.done() || fn(this.peek())) {
this.next()
}
return this
}
dropUntil(fn) {
this.dropWhile(x => !fn(x))
return this
}
}
class ArrayIterator extends Iterator {

View file

@ -121,12 +121,18 @@ describe('query', () => {
)
assert.deepEqual(
query('MATCH (e, h:Health) WHERE h.max = 50 OR h.current < 50 RETURN e, h.max AS maxHealth', engine).unwrap(),
query('MATCH (e, h:Health) WHERE h.max = 50 OR h.current > 45 RETURN e, h.max AS maxHealth', engine).unwrap(),
[
{ e: 12, maxHealth: 50 },
{ e: 13, maxHealth: 50 }
]
)
assert.deepEqual(
query('MATCH (e, :Player, h:Health) WHERE (h.max = 50 OR h.current > 45) AND e = 12 RETURN e, h.max AS maxHealth', engine).unwrap(),
[
{ e: 12, maxHealth: 50 }
]
)
})
})