Skip to content

Instantly share code, notes, and snippets.

@bilal-fazlani
Last active August 25, 2022 19:41
Show Gist options
  • Save bilal-fazlani/948456b5c2cfa3d46ce2a9288d4759cb to your computer and use it in GitHub Desktop.
Save bilal-fazlani/948456b5c2cfa3d46ce2a9288d4759cb to your computer and use it in GitHub Desktop.
Eliminating left recursion using zio-parser
import zio.parser.Syntax._
import zio.Chunk
import zio.parser.Syntax
sealed trait IntegerExpression
case class IntegerValueExpression(value: Int) extends IntegerExpression {
override def toString: String = value.toString
}
sealed trait IntegerOperator
case object Plus extends IntegerOperator{
override def toString: String = " + "
}
case object Minus extends IntegerOperator{
override def toString: String = " - "
}
case class Pair(operator: IntegerOperator, expression: IntegerValueExpression) {
override def toString: String = s"${operator.toString}${expression.toString}"
}
case class Compound(
left: IntegerValueExpression,
right: Chunk[Pair]
) extends IntegerExpression{
override def toString: String = s"${left.toString}, [${right.mkString(",")}]"
}
trait IntegerSyntax {
private lazy val plus = string(" + ", Plus).widen[IntegerOperator]
private lazy val minus = string(" - ", Minus).widen[IntegerOperator]
private lazy val int = digit.repeat0.transform[IntegerValueExpression](
x => IntegerValueExpression(x.mkString.toInt),
x => Chunk.fromIterable(x.toString)
)
private lazy val operatorSyntax = plus | minus
private lazy val compound: Syntax[String, Char, Char, Compound] =
(int ~ (operatorSyntax ~ int).repeat)
.transform[Compound](
{ case (left, right) =>
Compound(left, right.map { case (a, b) => Pair(a, b) })
},
complex =>
(
complex.left,
complex.right.map(pair => (pair.operator, pair.expression))
)
)
lazy val syntax =
compound.widen[IntegerExpression] | int.widen[IntegerExpression]
}
sealed trait IntExpression
case class Value(value: Integer) extends IntExpression {
override def toString: String = value.toString
}
case class PlusExpression(left: IntExpression, right: IntExpression)
extends IntExpression
case class MinusExpression(left: IntExpression, right: IntExpression)
extends IntExpression
object Transformer {
def transformLeftToRight(integer: IntegerExpression): IntExpression =
integer match {
case IntegerValueExpression(value) => Value(value)
case Compound(left, right) =>
right.foldLeft[IntExpression](Value(left.value)) {
case (left, Pair(Plus, right)) =>
PlusExpression(left, Value(right.value))
case (left, Pair(Minus, right)) =>
MinusExpression(left, Value(right.value))
}
}
}
object RunApp extends App with IntegerSyntax {
val input = "1 + 2 - 3 + 4 - 5"
val parsed = syntax.parseString(input)
println(parsed)
//prints: Right(1, [ + 2, - 3, + 4, - 5])
println(parsed.map(Transformer.transformLeftToRight))
//prints: Right(MinusExpression(PlusExpression(MinusExpression(PlusExpression(1,2),3),4),5))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment