# lihaoyi/fastparse

Fetching contributors…
Cannot retrieve contributors at this time
153 lines (142 sloc) 3.34 KB
 package test.fastparse import utest._ import fastparse._ import fastparse.internal.Util /** * Same as MathTests, but demonstrating the use of whitespace */ object IndentationTests extends TestSuite{ import fastparse.NoWhitespace._ def eval(tree: (String, Seq[Int])) = tree match{ case ("+", nums) => nums.reduceLeft(_+_) case ("-", nums) => nums.reduceLeft(_-_) case ("*", nums) => nums.reduceLeft(_*_) case ("/", nums) => nums.reduceLeft(_/_) } /** * Parser for an indentation-based math syntax. Parens are no longer * necessary, and the whole parser is parametrized with the current * depth of indentation */ class Parser(indent: Int){ def number[_: P]: P[Int] = P( CharIn("0-9").rep(1).!.map(_.toInt) ) def deeper[_: P]: P[Int] = P( " ".rep(indent + 1).!.map(_.length) ) def blockBody[_: P]: P[Seq[Int]] = "\n" ~ deeper.flatMapX(i => new Parser(indent = i).factor.rep(1, sep = ("\n" + " " * i)./) ) def block[_: P]: P[Int] = P( CharIn("+\\-*/").! ~/ blockBody).map(eval) def factor[_: P]: P[Int] = P( number | block ) def expr[_: P]: P[Int] = P( block ~ End ) } def expr[_: P] = new Parser(indent = 0).expr val tests = Tests { 'pass - { def check(str: String, num: Int) = { val Parsed.Success(value, _) = parse(str, expr(_)) assert(value == num) } check( """+ | 1 | 1 """.stripMargin.trim, 2 ) check( """+ | 1 | * | 1 | 2 """.stripMargin.trim, 3 ) check( """+ | + | 1 | * | 1 | 2 | * | 3 | 4 | 5 | """.stripMargin.trim, 63 ) check( """/ | 15 | 3 """.stripMargin.trim, 5 ) check( """/ | 63 | 3 """.stripMargin.trim, 21 ) check( """+ | + | 1 | * | 1 | 2 | / | * | 3 | 4 | 5 | 20 """.stripMargin.trim, 6 ) check( """/ | + | + | 1 | * | 1 | 2 | * | 3 | 4 | 5 | 3 """.stripMargin.trim, 21 ) } 'fail - { def check(input: String, expectedTrace: String): Unit = { val failure = parse(input, expr(_)).asInstanceOf[Parsed.Failure] val actualTrace = failure.trace(enableLogging = true).longAggregateMsg assert(expectedTrace.trim == actualTrace.trim) } * - check( "+", """ Expected expr:1:1 / block:1:1 / "\n":1:2, found "" """ ) * - check( """+ | 1 |1 """.stripMargin.trim, """ Expected expr:1:1 / ([0-9] | "\n " | end-of-input):2:4, found "\n1" """ ) * - check( """+ | 1 | 1 """.stripMargin.trim, """ Expected expr:1:1 / block:1:1 / factor:3:3 / (number | block):3:3, found " 1" """ ) } } }