Skip to content

Commit 7f86709

Browse files
authored
Merge pull request #370 from ilya-klyuchnikov/phrase
2 parents 55a539d + 1e703fe commit 7f86709

File tree

2 files changed

+53
-1
lines changed

2 files changed

+53
-1
lines changed

shared/src/main/scala/scala/util/parsing/combinator/PackratParsers.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ trait PackratParsers extends Parsers {
101101
* Overridden to make sure any input passed to the argument parser
102102
* is wrapped in a `PackratReader`.
103103
*/
104-
override def phrase[T](p: Parser[T]) = {
104+
override def phrase[T](p: Parser[T]): PackratParser[T] = {
105105
val q = super.phrase(p)
106106
new PackratParser[T] {
107107
def apply(in: Input) = in match {

shared/src/test/scala/scala/util/parsing/combinator/PackratParsersTest.scala

+52
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,35 @@ class PackratParsersTest {
133133
assertFailure("end of input", "a a a a b b b b c c c")
134134
}
135135

136+
@Test
137+
def test4: Unit = {
138+
import grammars4._
139+
import grammars4.parser._
140+
141+
def extractResult(r: ParseResult[Res]): Res = r match {
142+
case Success(a,_) => a
143+
case NoSuccess(a,_) => sys.error(a)
144+
case Failure(a, _) => sys.error(a)
145+
case Error(a, _) => sys.error(a)
146+
}
147+
def check(expected: Term, input: String, ctx: Ctx): Unit = {
148+
val parseResult = phraseTerm(new lexical.Scanner(input))
149+
val result = extractResult(parseResult)
150+
val term = result(ctx)
151+
assertEquals(expected, term)
152+
}
153+
154+
check(Var(-1, 0), "x", Nil)
155+
check(Var(0, 3), "x", List("x", "y", "z"))
156+
check(Var(1, 3), "y", List("x", "y", "z"))
157+
check(Var(2, 3), "z", List("x", "y", "z"))
158+
159+
check(App(Var(0, 2), Var(1, 2)), "x y", List("x", "y"))
160+
check(App(App(Var(0, 2), Var(1, 2)), Var(0, 2)), "x y x", List("x", "y"))
161+
check(App(App(Var(0, 2), Var(1, 2)), Var(0, 2)), "(x y) x", List("x", "y"))
162+
check(Abs(App(App(Var(0, 1), Var(0, 1)), Var(0, 1))), """\x. x x x""", List())
163+
}
164+
136165
}
137166

138167
private object grammars1 extends StandardTokenParsers with PackratParsers {
@@ -195,3 +224,26 @@ private object grammars3 extends StandardTokenParsers with PackratParsers {
195224
p~opt(repMany(p,q))~q ^^ {case x~Some(xs)~y => x::xs:::(y::Nil)}
196225

197226
}
227+
228+
private object grammars4 {
229+
// untyped lambda calculus with named vars -> de brujin indices conversion on the fly
230+
// Adapted from https://github.com/ilya-klyuchnikov/tapl-scala/blob/master/src/main/scala/tapl/untyped/parser.scala
231+
sealed trait Term
232+
case class Var(i: Int, cl: Int) extends Term
233+
case class Abs(t: Term) extends Term
234+
case class App(t1: Term, t2: Term) extends Term
235+
236+
object parser extends StandardTokenParsers with PackratParsers {
237+
lexical.delimiters ++= List("(", ")", ".", "\\")
238+
239+
type Res = Ctx => Term
240+
type Ctx = List[String]
241+
242+
private val term: PackratParser[Res] = app | atom | abs
243+
private val atom: PackratParser[Res] = "(" ~> term <~ ")" | id
244+
private val id : PackratParser[Res] = ident ^^ { n => (c: Ctx) => Var(c.indexOf(n), c.length) }
245+
private val app : PackratParser[Res] = (app ~ atom) ^^ {case t1 ~ t2 => (c: Ctx) => App(t1(c), t2(c)) } | atom
246+
private val abs : PackratParser[Res] = "\\" ~> ident ~ ("." ~> term) ^^ {case v ~ t => (c: Ctx) => Abs(t(v::c))}
247+
val phraseTerm : PackratParser[Res] = phrase(term)
248+
}
249+
}

0 commit comments

Comments
 (0)