Skip to content

Commit df50d34

Browse files
committed
Migrate PackratParsers tests to JUnit.
Most of the migration is straightforward. One exception is packrat3 (migrated to `test3` method). I simplified returned result by getting rid of useless Unit by changing this rule: repMany1(a,b) ~ not(b) into this rule: repMany1(a,b) <~ not(b) Also, I made all rules to be type safe. When constructing expected results, I decided to use scala.Symbol that allows us to use a bit more concise syntax for construction of one character strings. See `threeLists` method for details.
1 parent 062f7f3 commit df50d34

File tree

8 files changed

+141
-176
lines changed

8 files changed

+141
-176
lines changed

build.sbt

+2
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ pomExtra := (
7676
</developers>
7777
)
7878

79+
libraryDependencies ++= Seq("junit" % "junit" % "4.11" % "test", "com.novocode" % "junit-interface" % "0.10" % "test")
80+
7981
// default value must be set here
8082
TestKeys.includeTestDependencies := true
8183

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
package scala.util.parsing.combinator
2+
3+
import org.junit.Test
4+
import org.junit.Assert.assertEquals
5+
6+
import scala.util.parsing.combinator.syntactical.StandardTokenParsers
7+
8+
class PackratParsersTest {
9+
10+
@Test
11+
def test1: Unit = {
12+
import grammars1._
13+
val head = phrase(term)
14+
15+
def extractResult(r : ParseResult[Int]): Int = r match {
16+
case Success(a,_) => a
17+
case NoSuccess(a,_) => sys.error(a)
18+
}
19+
20+
assertEquals(1,extractResult(head(new lexical.Scanner("1"))))
21+
assertEquals(3, extractResult(head(new lexical.Scanner("1+2"))))
22+
assertEquals(5, extractResult(head(new lexical.Scanner("9-4"))))
23+
assertEquals(81, extractResult(head(new lexical.Scanner("9*9"))))
24+
assertEquals(4, extractResult(head(new lexical.Scanner("8/2"))))
25+
assertEquals(37, extractResult(head(new lexical.Scanner("4*9-0/7+9-8*1"))))
26+
assertEquals(9, extractResult(head(new lexical.Scanner("(1+2)*3"))))
27+
}
28+
29+
@Test
30+
def test2: Unit = {
31+
import grammars2._
32+
val head = phrase(exp)
33+
34+
def extractResult(r : ParseResult[Int]): Int = r match {
35+
case Success(a,_) => a
36+
case NoSuccess(a,_) => sys.error(a)
37+
}
38+
39+
assertEquals(1, extractResult(head(new lexical.Scanner("1"))))
40+
assertEquals(3, extractResult(head(new lexical.Scanner("1+2"))))
41+
assertEquals(81, extractResult(head(new lexical.Scanner("9*9"))))
42+
assertEquals(43, extractResult(head(new lexical.Scanner("4*9+7"))))
43+
assertEquals(59, extractResult(head(new lexical.Scanner("4*9+7*2+3*3"))))
44+
assertEquals(188, extractResult(head(new lexical.Scanner("4*9+7*2+3*3+9*5+7*6*2"))))
45+
assertEquals(960, extractResult(head(new lexical.Scanner("4*(9+7)*(2+3)*3"))))
46+
}
47+
48+
@Test
49+
def test3: Unit = {
50+
import grammars3._
51+
val head = phrase(AnBnCn)
52+
def extractResult(r: ParseResult[AnBnCnResult]): AnBnCnResult = r match {
53+
case Success(a,_) => a
54+
case NoSuccess(a,_) => sys.error(a)
55+
}
56+
def threeLists(as: List[Symbol], bs: List[Symbol], cs: List[Symbol]): AnBnCnResult = {
57+
val as1 = as.map(_.name)
58+
val bs1 = bs.map(_.name)
59+
val cs1 = cs.map(_.name)
60+
new ~(new ~(as1, bs1), cs1)
61+
}
62+
63+
val expected1 = threeLists(List('a, 'b), List('a), List('b, 'c))
64+
assertEquals(expected1, extractResult(head(new lexical.Scanner("a b c"))))
65+
val expected2 = threeLists(List('a, 'a, 'b, 'b), List('a, 'a), List('b, 'b, 'c, 'c))
66+
assertEquals(expected2, extractResult(head(new lexical.Scanner("a a b b c c"))))
67+
val expected3 = threeLists(List('a, 'a, 'a, 'b, 'b, 'b), List('a, 'a, 'a), List('b, 'b, 'b, 'c, 'c, 'c))
68+
assertEquals(expected3, extractResult(head(new lexical.Scanner("a a a b b b c c c"))))
69+
val expected4 = threeLists(List('a, 'a, 'a, 'a, 'b, 'b, 'b, 'b), List('a, 'a, 'a, 'a), List('b, 'b, 'b, 'b, 'c, 'c, 'c, 'c))
70+
assertEquals(expected4, extractResult(head(new lexical.Scanner("a a a a b b b b c c c c"))))
71+
val failure1 = AnBnCn(new PackratReader(new lexical.Scanner("a a a b b b b c c c c"))).asInstanceOf[Failure]
72+
assertEquals("Expected failure", failure1.msg)
73+
val failure2 = AnBnCn(new PackratReader(new lexical.Scanner("a a a a b b b c c c c"))).asInstanceOf[Failure]
74+
assertEquals("``b'' expected but `c' found", failure2.msg)
75+
val failure3 = AnBnCn(new PackratReader(new lexical.Scanner("a a a a b b b b c c c"))).asInstanceOf[Failure]
76+
assertEquals("end of input", failure3.msg)
77+
}
78+
79+
}
80+
81+
private object grammars1 extends StandardTokenParsers with PackratParsers {
82+
83+
lexical.delimiters ++= List("+","-","*","/","(",")")
84+
lexical.reserved ++= List("Hello","World")
85+
86+
/****
87+
* term = term + fact | term - fact | fact
88+
* fact = fact * num | fact / num | num
89+
*/
90+
91+
92+
val term: PackratParser[Int] = (term~("+"~>fact) ^^ {case x~y => x+y}
93+
|term~("-"~>fact) ^^ {case x~y => x-y}
94+
|fact)
95+
96+
val fact: PackratParser[Int] = (fact~("*"~>numericLit) ^^ {case x~y => x*y.toInt}
97+
|fact~("/"~>numericLit) ^^ {case x~y => x/y.toInt}
98+
|"("~>term<~")"
99+
|numericLit ^^ {_.toInt})
100+
}
101+
102+
private object grammars2 extends StandardTokenParsers with PackratParsers {
103+
104+
lexical.delimiters ++= List("+","-","*","/","(",")")
105+
lexical.reserved ++= List("Hello","World")
106+
107+
/*
108+
* exp = sum | prod | num
109+
* sum = exp ~ "+" ~ num
110+
* prod = exp ~ "*" ~ num
111+
*/
112+
113+
val exp : PackratParser[Int] = sum | prod | numericLit ^^{_.toInt} | "("~>exp<~")"
114+
val sum : PackratParser[Int] = exp~("+"~>exp) ^^ {case x~y => x+y}
115+
val prod: PackratParser[Int] = exp~("*"~>(numericLit ^^{_.toInt} | exp)) ^^ {case x~y => x*y}
116+
117+
}
118+
119+
private object grammars3 extends StandardTokenParsers with PackratParsers {
120+
lexical.reserved ++= List("a","b", "c")
121+
val a: PackratParser[String] = memo("a")
122+
val b: PackratParser[String] = memo("b")
123+
val c: PackratParser[String] = memo("c")
124+
125+
type AnBnCnResult = List[String] ~ List[String] ~ List[String]
126+
127+
val AnBnCn: PackratParser[AnBnCnResult] =
128+
guard(repMany1(a,b) <~ not(b)) ~ rep1(a) ~ repMany1(b,c)// ^^{case x~y => x:::y}
129+
130+
131+
private def repMany[T](p: => Parser[T], q: => Parser[T]): Parser[List[T]] =
132+
( p~repMany(p,q)~q ^^ {case x~xs~y => x::xs:::(y::Nil)}
133+
| success(Nil)
134+
)
135+
136+
def repMany1[T](p: => Parser[T], q: => Parser[T]): Parser[List[T]] =
137+
p~opt(repMany(p,q))~q ^^ {case x~Some(xs)~y => x::xs:::(y::Nil)}
138+
139+
}

test/files/run/packrat1.check

-7
This file was deleted.

test/files/run/packrat1.scala

-47
This file was deleted.

test/files/run/packrat2.check

-7
This file was deleted.

test/files/run/packrat2.scala

-57
This file was deleted.

test/files/run/packrat3.check

-7
This file was deleted.

test/files/run/packrat3.scala

-51
This file was deleted.

0 commit comments

Comments
 (0)