| 
 | 1 | +package scala.util.parsing.combinator  | 
 | 2 | + | 
 | 3 | +// import scala.language.implicitConversions  | 
 | 4 | + | 
 | 5 | +import java.io.StringReader  | 
 | 6 | +import org.junit.Test  | 
 | 7 | +import org.junit.Assert.{ assertEquals, assertTrue, fail }  | 
 | 8 | +import scala.util.parsing.input.StreamReader  | 
 | 9 | + | 
 | 10 | +class PrecedenceParsersTest {  | 
 | 11 | + | 
 | 12 | +  abstract class Op  | 
 | 13 | +  object Plus extends Op {  | 
 | 14 | +    override def toString = "+"  | 
 | 15 | +  }  | 
 | 16 | +  object Minus extends Op {  | 
 | 17 | +    override def toString = "-"  | 
 | 18 | +  }  | 
 | 19 | +  object Mult extends Op {  | 
 | 20 | +    override def toString = "*"  | 
 | 21 | +  }  | 
 | 22 | +  object Divide extends Op {  | 
 | 23 | +    override def toString = "/"  | 
 | 24 | +  }  | 
 | 25 | +  object Equals extends Op {  | 
 | 26 | +    override def toString = "="  | 
 | 27 | +  }  | 
 | 28 | + | 
 | 29 | +  abstract class Node  | 
 | 30 | +  case class Leaf(v: Int) extends Node {  | 
 | 31 | +    override def toString = v.toString  | 
 | 32 | +  }  | 
 | 33 | +  case class Binop(lhs: Node, op: Op, rhs: Node) extends Node {  | 
 | 34 | +    override def toString = s"($lhs $op $rhs)"  | 
 | 35 | +  }  | 
 | 36 | + | 
 | 37 | +  object ArithmeticParser extends RegexParsers {  | 
 | 38 | +    val prec = List(  | 
 | 39 | +      (Associativity.Left, List(Mult, Divide)),  | 
 | 40 | +      (Associativity.Left, List(Plus, Minus)),  | 
 | 41 | +      (Associativity.Right, List(Equals)))  | 
 | 42 | +    def integer: Parser[Leaf] = "[0-9]+".r ^^ { s: String => Leaf(s.toInt) }  | 
 | 43 | +    def binop: Parser[Op] = "+" ^^^ Plus | "-" ^^^ Minus | "*" ^^^ Mult | "/" ^^^ Divide | "=" ^^^ Equals  | 
 | 44 | +    def expression = new PrecedenceParser(integer, binop, prec, Binop.apply)  | 
 | 45 | +  }  | 
 | 46 | + | 
 | 47 | +  def testExp(expected: Node, input: String): Unit = {  | 
 | 48 | +    ArithmeticParser.expression(StreamReader(new StringReader(input))) match {  | 
 | 49 | +      case ArithmeticParser.Success(r, next) => {  | 
 | 50 | +        assertEquals(expected, r);  | 
 | 51 | +        assertTrue(next.atEnd);  | 
 | 52 | +      }  | 
 | 53 | +      case e => {  | 
 | 54 | +        fail(s"Error parsing $input: $e");  | 
 | 55 | +      }  | 
 | 56 | +    }  | 
 | 57 | +  }  | 
 | 58 | + | 
 | 59 | +  @Test  | 
 | 60 | +  def basicExpTests: Unit = {  | 
 | 61 | +    testExp(Leaf(4), "4")  | 
 | 62 | +    testExp(Binop(Leaf(1), Plus, Leaf(2)), "1 + 2")  | 
 | 63 | +    testExp(Binop(Leaf(2), Mult, Leaf(1)), "2 * 1")  | 
 | 64 | +  }  | 
 | 65 | + | 
 | 66 | +  @Test  | 
 | 67 | +  def associativityTests: Unit = {  | 
 | 68 | +    testExp(Binop(Binop(Leaf(1), Minus, Leaf(2)), Plus, Leaf(3)), "1 - 2 + 3")  | 
 | 69 | +    testExp(Binop(Leaf(1), Equals, Binop(Leaf(2), Equals, Leaf(3))), "1 = 2 = 3")  | 
 | 70 | +  }  | 
 | 71 | + | 
 | 72 | +  @Test  | 
 | 73 | +  def precedenceTests: Unit = {  | 
 | 74 | +    testExp(Binop(Binop(Leaf(0), Mult, Leaf(5)), Minus, Leaf(2)), "0 * 5 - 2")  | 
 | 75 | +    testExp(Binop(Leaf(3), Plus, Binop(Leaf(9), Divide, Leaf(11))), "3 + 9 / 11")  | 
 | 76 | +    testExp(Binop(Binop(Leaf(6), Plus, Leaf(8)), Equals, Leaf(1)), "6 + 8 = 1")  | 
 | 77 | +    testExp(Binop(Leaf(4), Equals, Binop(Leaf(5), Minus, Leaf(3))), "4 = 5 - 3")  | 
 | 78 | +  }  | 
 | 79 | +}  | 
0 commit comments