fix(parser): Fix compare ops parsing (#748)

* Fix order of compare ops parse

* Add tests
This commit is contained in:
InversionSpaces 2023-06-14 14:52:30 +02:00 committed by GitHub
parent 45c44b3046
commit 739854a20b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 40 additions and 13 deletions

View File

@ -153,8 +153,10 @@ object InfixToken {
case Lt extends Op("<")
case Lte extends Op("<=")
def p: P[Unit] = P.string(symbol)
private def opsParser(ops: List[Op]): P[(Span, Op)] =
P.oneOf(ops.map(op => P.string(op.symbol).lift.map(s => s.as(op))))
P.oneOf(ops.map(op => op.p.lift.map(s => s.as(op))))
// Parse left-associative operations `basic (OP basic)*`.
// We use this form to avoid left recursion.
@ -214,7 +216,10 @@ object InfixToken {
private val compare: P[ValueToken[Span.S]] =
infixParserNone(
add,
Op.Gt :: Op.Gte :: Op.Lt :: Op.Lte :: Nil
// Here order is important as
// `Op.Gt` is prefix of `Op.Gte`
// and `Op.Lt` is prefix of `Op.Lte`
Op.Gte :: Op.Lte :: Op.Gt :: Op.Lt :: Nil
)
/**

View File

@ -50,9 +50,19 @@ class InfixTokenSpec extends AnyFlatSpec with Matchers with AquaSpec {
private def gt(left: ValueToken[Id], right: ValueToken[Id]): ValueToken[Id] =
infixToken(left, right, Gt)
"primitive math expression" should "be parfvfsed" in {
private def gte(left: ValueToken[Id], right: ValueToken[Id]): ValueToken[Id] =
infixToken(left, right, Gte)
private def lt(left: ValueToken[Id], right: ValueToken[Id]): ValueToken[Id] =
infixToken(left, right, Lt)
private def lte(left: ValueToken[Id], right: ValueToken[Id]): ValueToken[Id] =
infixToken(left, right, Lte)
"primitive math expression" should "be parsed" in {
val vt = ValueToken.`value`.parseAll("3").right.get.mapK(spanToId)
val vt1 = ValueToken.`value`.parseAll("2 - 3").right.get.mapK(spanToId)
val vt2 = ValueToken.`value`.parseAll("3 * 2 * 5").right.get.mapK(spanToId)
val vt3 = ValueToken.`value`.parseAll("3 + 1 * 2 - 2").right.get.mapK(spanToId)
@ -82,6 +92,7 @@ class InfixTokenSpec extends AnyFlatSpec with Matchers with AquaSpec {
.mapK(spanToId)
vt shouldBe literal(3)
vt1 shouldBe sub(literal(2), literal(3))
vt2 shouldBe mul(mul(3, 2), 5)
vt3 shouldBe sub(add(3, mul(1, 2)), 2)
vt4 shouldBe add(add(add(add(add(add(5, 6), 10), 20), 1), 2), 4)
@ -93,15 +104,6 @@ class InfixTokenSpec extends AnyFlatSpec with Matchers with AquaSpec {
vt11 shouldBe rem(2, 4)
}
"primitive math expression" should "be parsed" in {
val vt = ValueToken.`value`.parseAll("3 - 2").right.get.mapK(spanToId)
vt shouldBe
InfixToken[Id](literal(3), literal(2), Sub)
}
"primitive math expression with multiplication" should "be parsed" in {
val res = ValueToken.`value`.parseAll("(3 - 2) * 4").right.get.mapK(spanToId)
@ -244,7 +246,27 @@ class InfixTokenSpec extends AnyFlatSpec with Matchers with AquaSpec {
"simple cmp math expression " should "be parsed" in {
val vt = ValueToken.`value`.parseAll("1 > 3").right.get.mapK(spanToId)
vt shouldBe InfixToken(literal(1), literal(3), Gt)
val vt1 = ValueToken.`value`.parseAll("1 < 3").right.get.mapK(spanToId)
val vt2 = ValueToken.`value`.parseAll("1 >= 3").right.get.mapK(spanToId)
val vt3 = ValueToken.`value`.parseAll("1 <= 3").right.get.mapK(spanToId)
vt shouldBe gt(literal(1), literal(3))
vt1 shouldBe lt(literal(1), literal(3))
vt2 shouldBe gte(literal(1), literal(3))
vt3 shouldBe lte(literal(1), literal(3))
}
"complex cmp math expression " should "be parsed" in {
val test = (op: Op) => {
val vt =
ValueToken.`value`.parseAll(s"(1 + 2) ** 3 ${op.symbol} 4 - 5 * 6").right.get.mapK(spanToId)
val left = pow(add(literal(1), literal(2)), literal(3))
val right = sub(literal(4), mul(literal(5), literal(6)))
val exp = infixToken(left, right, op)
vt shouldBe exp
}
List(Gt, Lt, Gte, Lte).foreach(test)
}
"simple cmp math expression in brackets " should "be parsed" in {