diff --git a/parsing/src/main/scala/parsing/Parsing.scala b/parsing/src/main/scala/parsing/Parsing.scala index a0cafc79..150b7c9f 100644 --- a/parsing/src/main/scala/parsing/Parsing.scala +++ b/parsing/src/main/scala/parsing/Parsing.scala @@ -1,7 +1,5 @@ package parsing - - import scala.annotation.{switch, tailrec} import scala.collection.{BitSet, mutable} import acyclic.file @@ -9,9 +7,9 @@ import acyclic.file /** * Result of a parse, whether successful or failed */ -sealed trait Res[+T] -object Res{ - case class Success[T](t: T, index: Int, cut: Boolean = false) extends Res[T]{ +sealed trait Result[+T] +object Result{ + case class Success[T](t: T, index: Int, cut: Boolean = false) extends Result[T]{ override def toString = { s"Success($index, $cut)" } @@ -44,8 +42,8 @@ object Res{ sb.append('"') } - case class Failure(input: String, fullStack: List[(Int, Parser[_])], cut: Boolean) extends Res[Nothing]{ - def stack = fullStack.filter(_._2.isInstanceOf[Parser.Named[_]]) :+ fullStack.last + case class Failure(input: String, fullStack: List[(Int, Parser[_])], cut: Boolean) extends Result[Nothing]{ + def stack = fullStack.filter(_._2.isInstanceOf[Parser.Rule[_]]) :+ fullStack.last def verboseTrace = { val body = @@ -63,7 +61,7 @@ object Res{ override def toString = s"Failure($trace, $cut)" } } -import Res._ +import Result._ sealed trait Parser[+T]{ /** * Wraps this in a [[Parser.Logged]] @@ -73,7 +71,11 @@ sealed trait Parser[+T]{ /** * Parses the given `input` starting from the given `index` */ - def parse(input: String, index: Int): Res[T] + def parse(input: String, index: Int = 0): Result[T] = parseRecursive(input, index, 0) + /** + * Parses the given `input` starting from the given `index` and `logDepth` + */ + def parseRecursive(input: String, index: Int, logDepth: Int): Result[T] /** * Repeats this parser 0 or more times @@ -101,6 +103,14 @@ sealed trait Parser[+T]{ * Parses using this followed by the parser `p` */ def ~[V, R](p: Parser[V])(implicit ev: Implicits.Sequencer[T, V, R]): Parser[R] = Parser.Sequence(this, p, cut=false) + /** + * Parses using this followed by the parser `p`, performing a Cut if + * this parses successfully. That means that if `p` fails to parse, the + * parse will fail immediately and not backtrack past this success. + * + * This lets you greatly narrow the error position by avoiding unwanted + * backtracking. + */ def ~![V, R](p: Parser[V])(implicit ev: Implicits.Sequencer[T, V, R]): Parser[R] = Parser.Sequence(this, p, cut=true) /** @@ -113,8 +123,14 @@ sealed trait Parser[+T]{ */ def unary_! = Parser.Not(this) + /** + * Used to capture the text parsed by this as a `String` + */ def ! = Parser.Capturing(this) + /** + * Transforms the result of this Parser with the given function + */ def map[V](f: T => V): Parser[V] = Parser.Mapper(this, f) protected def fail(input: String, index: Int) = @@ -125,12 +141,9 @@ sealed trait Parser[+T]{ object Parser{ case class Mapper[T, V](p: Parser[T], f: T => V) extends Parser[V]{ - def parse(input: String, index: Int) = { - p.parse(input, index) match{ - case s: Success[T] => - println("!!! " + s.t) - println("??? " + f(s.t)) - Success(f(s.t), s.index, s.cut) + def parseRecursive(input: String, index: Int, logDepth: Int) = { + p.parseRecursive(input, index, logDepth) match{ + case s: Success[T] => Success(f(s.t), s.index, s.cut) case f: Failure => failMore(f, index) } } @@ -139,29 +152,30 @@ object Parser{ * A parser that always succeeds, consuming no input */ case object Pass extends Parser[Unit]{ - def parse(input: String, index: Int) = Res.Success((), index) + def parseRecursive(input: String, index: Int, logDepth: Int) = Result.Success((), index) } /** * A parser that always fails immediately */ case object Fail extends Parser[Nothing]{ - def parse(input: String, index: Int) = fail(input, index) + def parseRecursive(input: String, index: Int, logDepth: Int) = fail(input, index) } case class Capturing(p: Parser[_]) extends Parser[String]{ - def parse(input: String, index: Int) = { - p.parse(input, index) match { + def parseRecursive(input: String, index: Int, logDepth: Int) = { + p.parseRecursive(input, index, logDepth) match { case s: Success[_] => Success(input.substring(index, s.index), s.index, s.cut) case f: Failure => f } } + override def toString = p.toString + ".!" } /** * Succeeds, consuming a single character */ case object AnyChar extends Parser[Char]{ - def parse(input: String, index: Int) = { + def parseRecursive(input: String, index: Int, logDepth: Int) = { if (index >= input.length) fail(input, index) else Success(input(index), index+1) } @@ -171,7 +185,7 @@ object Parser{ * Succeeds if at the start of the input, consuming no input */ case object Start extends Parser[Unit]{ - def parse(input: String, index: Int) = { + def parseRecursive(input: String, index: Int, logDepth: Int) = { if (index == 0) Success((), index) else fail(input, index) } @@ -180,7 +194,7 @@ object Parser{ * Succeeds if at the end of the input, consuming no input */ case object End extends Parser[Unit]{ - def parse(input: String, index: Int) = { + def parseRecursive(input: String, index: Int, logDepth: Int) = { if (index == input.length) Success((), index) else fail(input, index) } @@ -190,8 +204,8 @@ object Parser{ * Parses a literal `String` */ case class Literal(s: String) extends Parser[Unit]{ - def parse(input: String, index: Int) = { - if (input.startsWith(s, index)) Res.Success(s, index + s.length) + def parseRecursive(input: String, index: Int, logDepth: Int) = { + if (input.startsWith(s, index)) Result.Success(s, index + s.length) else fail(input, index) } override def toString = literalize(s).toString @@ -201,9 +215,9 @@ object Parser{ * Parses a single character */ case class CharLiteral(c: Char) extends Parser[Unit]{ - def parse(input: String, index: Int) = { + def parseRecursive(input: String, index: Int, logDepth: Int) = { if (index >= input.length) fail(input, index) - else if (input(index) == c) Res.Success(c.toString, index + 1) + else if (input(index) == c) Result.Success(c.toString, index + 1) else fail(input, index) } override def toString = literalize(c.toString).toString @@ -217,11 +231,11 @@ object Parser{ * and ends, together with its result */ case class Logged[+T](p: Parser[T], msg: String) extends Parser[T]{ - def parse(input: String, index: Int) = { + def parseRecursive(input: String, index: Int, logDepth: Int) = { val indent = " " * logNesting println(indent + "+" + msg + ":" + index) logNesting += 1 - val res = p.parse(input, index) + val res = p.parseRecursive(input, index, logDepth + 1) logNesting -= 1 println(indent + "-" + msg + ":" + index + ":" + res) res @@ -232,10 +246,10 @@ object Parser{ /** * A top-level, named parser. */ - case class Named[+T](name: String, p: () => Parser[T]) extends Parser[T]{ + case class Rule[+T](name: String, p: () => Parser[T]) extends Parser[T]{ lazy val pCached = p() - def parse(input: String, index: Int) = { - pCached.parse(input, index) match{ + def parseRecursive(input: String, index: Int, logDepth: Int) = { + pCached.parseRecursive(input, index, logDepth) match{ case f: Failure => failMore(f, index) case s => s } @@ -248,9 +262,9 @@ object Parser{ * but consuming no input */ case class Lookahead(p: Parser[_]) extends Parser[Unit]{ - def parse(input: String, index: Int) = { - p.parse(input, index) match{ - case s: Success[_] => Res.Success((), index) + def parseRecursive(input: String, index: Int, logDepth: Int) = { + p.parseRecursive(input, index, logDepth) match{ + case s: Success[_] => Result.Success((), index) case f: Failure => failMore(f, index) } } @@ -261,11 +275,11 @@ object Parser{ * if it succeeds. Neither case consumes any input */ case class Not(p: Parser[_]) extends Parser[Unit]{ - def parse(input: String, index: Int) = { - val res0 = p.parse(input, index) + def parseRecursive(input: String, index: Int, logDepth: Int) = { + val res0 = p.parseRecursive(input, index, logDepth) val res = res0 match{ case s: Success[_] => fail(input, s.index) - case f: Failure => Res.Success((), index) + case f: Failure => Result.Success((), index) } res } @@ -280,8 +294,8 @@ object Parser{ case class Optional[+T, R](p: Parser[T]) (implicit ev: Implicits.Optioner[T, R]) extends Parser[R]{ - def parse(input: String, index: Int) = { - p.parse(input, index) match{ + def parseRecursive(input: String, index: Int, logDepth: Int) = { + p.parseRecursive(input, index, logDepth) match{ case Success(t, index, cut) => Success(ev(Some(t)), index, cut) case f: Failure if f.cut => failMore(f, index) case _ => Success(ev(None), index) @@ -296,11 +310,11 @@ object Parser{ */ case class Sequence[+T1, +T2, R](p1: Parser[T1], p2: Parser[T2], cut: Boolean) (implicit ev: Implicits.Sequencer[T1, T2, R]) extends Parser[R]{ - def parse(input: String, index: Int) = { - p1.parse(input, index) match{ + def parseRecursive(input: String, index: Int, logDepth: Int) = { + p1.parseRecursive(input, index, logDepth) match{ case f: Failure => failMore(f, index, cut = f.cut) case s1: Success[_] => - p2.parse(input, s1.index) match{ + p2.parseRecursive(input, s1.index, logDepth) match{ case f: Failure => failMore(f, index, cut = cut || f.cut || s1.cut) case s2: Success[_] => Success(ev(s1.t, s2.t), s2.index, s2.cut || s1.cut | cut) } @@ -325,16 +339,16 @@ object Parser{ */ case class Repeat[T, +R](p: Parser[T], min: Int, delimiter: Parser[_]) (implicit ev: Implicits.Repeater[T, R]) extends Parser[R]{ - def parse(input: String, index: Int) = { + def parseRecursive(input: String, index: Int, logDepth: Int) = { val res = mutable.Buffer.empty[T] var finalIndex = index var lastFailure: Failure = null @tailrec def rec(index: Int, del: Parser[_]): Unit = { - del.parse(input, index) match{ + del.parseRecursive(input, index, logDepth) match{ case f: Failure if f.cut => lastFailure = failMore(f, index) case f: Failure => lastFailure = f case Success(t, i, cut1) => - p.parse(input, i) match{ + p.parseRecursive(input, i, logDepth) match{ case f: Failure if f.cut | cut1 => lastFailure = failMore(f, index, f.cut | cut1) case f: Failure => lastFailure = f case Success(t, i, cut2) => @@ -361,11 +375,11 @@ object Parser{ * the first one that succeeds and fails if both fail */ case class Either[V](p1: Parser[V], p2: Parser[V]) extends Parser[V]{ - def parse(input: String, index: Int) = { - p1.parse(input, index) match{ + def parseRecursive(input: String, index: Int, logDepth: Int) = { + p1.parseRecursive(input, index, logDepth) match{ case s: Success[_] => s case f: Failure if f.cut => failMore(f, index) - case _ => p2.parse(input, index) match{ + case _ => p2.parseRecursive(input, index, logDepth) match{ case s: Success[_] => s case f: Failure if f.cut => failMore(f, index) case f: Failure => fail(input, index) @@ -385,20 +399,20 @@ object Parser{ * Parses a single character if it passes the predicate */ case class CharPred(predicate: Char => Boolean) extends Parser[Unit]{ - def parse(input: String, index: Int) = { + def parseRecursive(input: String, index: Int, logDepth: Int) = { if (index >= input.length) fail(input, index) - else if (predicate(input(index))) Res.Success(input(index), index + 1) + else if (predicate(input(index))) Result.Success(input(index), index + 1) else fail(input, index) } } /** * Parses a single character if it passes the predicate */ - case class CharSets(strings: Seq[Char]*) extends Parser[Unit]{ + case class CharIn(strings: Seq[Char]*) extends Parser[Unit]{ private[this] val uberSet = BitSet(strings.flatten.map(_.toInt):_*) - def parse(input: String, index: Int) = { + def parseRecursive(input: String, index: Int, logDepth: Int) = { if (index >= input.length) fail(input, index) - else if (uberSet(input(index))) Res.Success(input(index), index + 1) + else if (uberSet(input(index))) Result.Success(input(index), index + 1) else fail(input, index) } override def toString = { @@ -426,8 +440,8 @@ object Parser{ } current.word = string } - def parse(input: String, index: Int) = { - @tailrec def rec(offset: Int, currentNode: Node, currentRes: Res[Unit]): Res[Unit] = { + def parseRecursive(input: String, index: Int, logDepth: Int) = { + @tailrec def rec(offset: Int, currentNode: Node, currentRes: Result[Unit]): Result[Unit] = { if (index + offset >= input.length) currentRes else { val char = input(index + offset) @@ -445,9 +459,8 @@ object Parser{ rec(0, bitSet, fail(input, index)) } override def toString = { - s"CharTrie(${strings.map(literalize(_)).mkString(",")})" + s"CharTrie(${strings.map(literalize(_)).mkString(", ")})" } } - } diff --git a/parsing/src/main/scala/parsing/package.scala b/parsing/src/main/scala/parsing/package.scala index d1726aba..3fa52b5b 100644 --- a/parsing/src/main/scala/parsing/package.scala +++ b/parsing/src/main/scala/parsing/package.scala @@ -8,7 +8,7 @@ package object parsing { val Start = Parser.Start val End = Parser.End val CharPred = Parser.CharPred - val CharSets = Parser.CharSets + val CharSets = Parser.CharIn val Dispatcher = Parser.CharTrie val AnyChar = Parser.AnyChar @@ -16,7 +16,8 @@ package object parsing { implicit def wspStr(s: String) = if (s.length == 0) Parser.CharLiteral(s(0)) else Parser.Literal(s) - def R[T](p: => Parser[T])(implicit name: FuncName): Parser[T] = Parser.Named(name.name, () => p) - - type Parser0 = Parser[_] + def R[T](p: => Parser[T])(implicit name: FuncName): Parser[T] = Parser.Rule(name.name, () => p) + type R0 = Parser[Unit] + implicit def Unitize(f: Parser[Any]): Parser[Unit] = f.map(_ => ()) + type R[+T] = Parser[T] } diff --git a/parsing/src/test/scala/parsing/JsonTests.scala b/parsing/src/test/scala/parsing/JsonTests.scala index 2210c4f0..f2f0cd34 100644 --- a/parsing/src/test/scala/parsing/JsonTests.scala +++ b/parsing/src/test/scala/parsing/JsonTests.scala @@ -23,11 +23,11 @@ object JsonTests extends TestSuite{ val tests = TestSuite{ 'pass { - def test(p: Parser[_], s: String) = p.parse(s, 0) match{ - case Res.Success(v, i, cut) => + def test(p: R[_], s: String) = p.parse(s) match{ + case Result.Success(v, i, cut) => val expectedIndex = s.length assert(i == {s; expectedIndex}) - case f: Res.Failure => throw new Exception(f.fullStack.mkString("\n")) + case f: Result.Failure => throw new Exception(f.fullStack.mkString("\n")) } * - test(number, "12031.33123E-2") * - test(string, "\"i am a cow lol omfg\"" ) @@ -60,9 +60,9 @@ object JsonTests extends TestSuite{ } 'fail{ def check(s: String, expectedError: String) = { - jsonExpr.parse(s, 0) match{ - case s: Res.Success[_] => throw new Exception("Parsing should have failed:") - case f: Res.Failure => + jsonExpr.parse(s) match{ + case s: Result.Success[_] => throw new Exception("Parsing should have failed:") + case f: Result.Failure => val error = f.trace val expected = expectedError.trim assert(error == expected) diff --git a/parsing/src/test/scala/parsing/MathTests.scala b/parsing/src/test/scala/parsing/MathTests.scala index 8c59f9f6..86dd91cf 100644 --- a/parsing/src/test/scala/parsing/MathTests.scala +++ b/parsing/src/test/scala/parsing/MathTests.scala @@ -7,13 +7,13 @@ object MathTests extends TestSuite{ val parens = R( "(" ~ addSub ~ ")" ) val factor = R( number | parens ) - val divMul: Parser[Int] = R( factor ~ (CharSets("*/").! ~ factor).rep ).map{ + val divMul: R[Int] = R( factor ~ (CharSets("*/").! ~ factor).rep ).map{ case (a, s) => s.foldLeft(a){ case (left, ("*", right)) => left * right case (left, ("/", right)) => left / right } } - val addSub: Parser[Int] = R( divMul ~ (CharSets("+-").! ~ divMul).rep ).map{ + val addSub: R[Int] = R( divMul ~ (CharSets("+-").! ~ divMul).rep ).map{ case (a, s) => s.foldLeft(a){ case (left, ("+", right)) => left + right case (left, ("-", right)) => left - right @@ -23,8 +23,8 @@ object MathTests extends TestSuite{ val tests = TestSuite{ 'pass { def check(str: String, num: Int) = { - val res = expr.parse(str, 0) - assert(res == Res.Success(num, str.length)) + val res = expr.parse(str) + assert(res == Result.Success(num, str.length)) } check("1+1", 2) check("1+1*2", 3) diff --git a/parsing/src/test/scala/parsing/MiscTests.scala b/parsing/src/test/scala/parsing/MiscTests.scala new file mode 100644 index 00000000..e8bcfd9b --- /dev/null +++ b/parsing/src/test/scala/parsing/MiscTests.scala @@ -0,0 +1,61 @@ +package parsing + +import parsing.Parser.CharTrie +import utest._ + +object MiscTests extends TestSuite{ + + val tests = TestSuite{ + 'toString{ + def check(p: Parser[_], s: String) = { + assert(p.toString == s.trim) + } + 'Either { + check("A" | "B", """("A" | "B")""") + check("A" | "B" | "C", """("A" | "B" | "C")""") + check(("A" | "B") | "C", """("A" | "B" | "C")""") + check("A" | ("B" | "C"), """("A" | "B" | "C")""") + } + 'Sequence { + check("A" ~ "BBB", """("A" ~ "BBB")""") + check("A" ~ "B" ~ "C", """("A" ~ "B" ~ "C")""") + check(("A" ~ "B") ~ "C", """("A" ~ "B" ~ "C")""") + check("A" ~ ("B" ~ "C"), """("A" ~ "B" ~ "C")""") + } + 'Mixed{ + check(("A" ~ "B") | "C", """(("A" ~ "B") | "C")""") + check("A" ~ ("B" | "C"), """("A" ~ ("B" | "C"))""") + check(("A" | "B") ~ "C", """(("A" | "B") ~ "C")""") + check("A" | ("B" ~ "C"), """("A" | ("B" ~ "C"))""") + } + 'rep{ + check("A".rep, """ "A".rep """) + check(("A" | "B").rep, """ ("A" | "B").rep """) + check(("A".? | "B").rep, """ ("A".? | "B").rep """) + check(("A".? | "B").rep1, """ ("A".? | "B").rep1 """) + check(("A".? | "B").rep("C"), """ ("A".? | "B").rep("C") """) + check(("A".? | "B").rep1("C" ~ "D" | "E"), """ ("A".? | "B").rep1((("C" ~ "D") | "E")) """) + } + 'lookahead{ + check(&("A") ~ "ABC", """(&("A") ~ "ABC")""") + check(!"A" ~ "ABC", """(!("A") ~ "ABC")""") + check("A".! ~ "ABC".!, """("A".! ~ "ABC".!)""") + } + 'named{ + def Foo = R( "A" ) + check(Foo, """Foo""") + check(End, """End""") + check(Start, """Start""") + check(Pass, """Pass""") + check(Fail, """Fail""") + check(AnyChar, """AnyChar""") + check(CharSets("abc", "d", Seq('1', '2', '3')), """CharSets("abcd123")""") + check( + CharTrie("mango", "mandarin", "mangosteen"), + """CharTrie("mango", "mandarin", "mangosteen")""" + ) + check(CharPred(_.isUpper), """CharPred()""") + } + } + } +} diff --git a/parsing/src/test/scala/parsing/ParsingTests.scala b/parsing/src/test/scala/parsing/ParsingTests.scala index cfcf5f9e..71e019f7 100644 --- a/parsing/src/test/scala/parsing/ParsingTests.scala +++ b/parsing/src/test/scala/parsing/ParsingTests.scala @@ -5,14 +5,14 @@ import utest._ object ParsingTests extends TestSuite{ - import Res.{Success, Failure} + import Result.{Success, Failure} - def check[T](parser: Parser[T], input: (String, Int), rhs: Res[T]) = { + def check[T](parser: R[T], input: (String, Int), rhs: Result[T]) = { val (str, index) = input val parsed = parser.parse(str, index) assert({parser; str; parsed} == rhs) } - def checkFail[T](parser: Parser[T], input: (String, Int), expectedFailureIndex: Int) = { + def checkFail[T](parser: R[T], input: (String, Int), expectedFailureIndex: Int) = { val (str, index) = input val parsed = parser.parse(str, index) val failureIndex = parsed.asInstanceOf[Failure].fullStack.last._1 diff --git a/scalaParser/src/main/scala/scalaParser/Core.scala b/scalaParser/src/main/scala/scalaParser/Core.scala index 2316be1d..c1085dcd 100644 --- a/scalaParser/src/main/scala/scalaParser/Core.scala +++ b/scalaParser/src/main/scala/scalaParser/Core.scala @@ -8,7 +8,7 @@ import parsing._ trait Core extends syntax.Literals{ // Aliases for common things. These things are used in almost every parser // in the file, so it makes sense to keep them short. - type R0 = Parser0 + /** * Parses all whitespace, excluding newlines. This is only * really useful in e.g. {} blocks, where we want to avoid diff --git a/scalaParser/src/main/scala/scalaParser/Scala.scala b/scalaParser/src/main/scala/scalaParser/Scala.scala index 7c024f87..f36cbf95 100644 --- a/scalaParser/src/main/scala/scalaParser/Scala.scala +++ b/scalaParser/src/main/scala/scalaParser/Scala.scala @@ -73,7 +73,7 @@ object Scala extends Core with Types with Exprs/* with Xml*/{ R( TopStat.rep1(Semis) ) } val TopPkgSeq = R( (`package` ~ QualId ~ !(WS ~ "{")).rep1(Semis) ) - val CompilationUnit: Parser0 = { + val CompilationUnit: R0 = { val Body = R( TopPkgSeq ~ (Semis ~ TopStatSeq).? | TopStatSeq ) R( Semis.? ~ Body.? ~ Semis.? ~ WL ~ Parser.End) } diff --git a/scalaParser/src/main/scala/scalaParser/Xml.scala b/scalaParser/src/main/scala/scalaParser/Xml.scala index 9675de41..210344df 100644 --- a/scalaParser/src/main/scala/scalaParser/Xml.scala +++ b/scalaParser/src/main/scala/scalaParser/Xml.scala @@ -7,7 +7,7 @@ import scala.language.implicitConversions import scalaParser.syntax.Basic trait Xml extends Core { - def Patterns: Parser0 + def Patterns: R[_] val XmlExpr = R( WL ~ Xml.XmlContent ~ (WL ~ Xml.Element).rep ) val XmlPattern = R( WL ~ Xml.ElemPattern ) @@ -74,7 +74,7 @@ trait Xml extends Core { val ETag = R( "" ) val Content = R( (CharData | Content1).rep ) val Content1 = R( XmlContent | Reference | ScalaExpr ) - val XmlContent: Parser0 = R( Element | CDSect | PI | Comment ) + val XmlContent: R0 = R( Element | CDSect | PI | Comment ) val CDSect = R( CDStart ~ CData ~ CDEnd ) val CDStart = R( "" ) val STagP = R( "<" ~ Name ~ WL.? ~ ">") val ETagP = R( "" ) diff --git a/scalaParser/src/main/scala/scalaParser/syntax/Identifiers.scala b/scalaParser/src/main/scala/scalaParser/syntax/Identifiers.scala index f79d2b7d..8f108d63 100644 --- a/scalaParser/src/main/scala/scalaParser/syntax/Identifiers.scala +++ b/scalaParser/src/main/scala/scalaParser/syntax/Identifiers.scala @@ -12,7 +12,7 @@ object Identifiers{ def VarId0(dollar: Boolean) = R( !Keywords ~ Lower ~ IdRest(dollar) ) val PlainId = R( !Keywords ~ Upper ~ IdRest(true) | VarId | Operator ) val PlainIdNoDollar = R( !Keywords ~ Upper ~ IdRest(false) | VarId0(false) | Operator ) - val Id = R( !Keywords ~ PlainId | ("`" ~ (!"`" ~ Parser.AnyChar).rep1 ~ "`") ) + val Id: R0 = R( !Keywords ~ PlainId | ("`" ~ (!"`" ~ Parser.AnyChar).rep1 ~ "`") ) def IdRest(allowDollar: Boolean) = { val SkipChar: Parser[_] = if(allowDollar) "_" else CharSets("_$") diff --git a/scalaParser/src/main/scala/scalaParser/syntax/Literals.scala b/scalaParser/src/main/scala/scalaParser/syntax/Literals.scala index d8ba1393..ceaf1111 100644 --- a/scalaParser/src/main/scala/scalaParser/syntax/Literals.scala +++ b/scalaParser/src/main/scala/scalaParser/syntax/Literals.scala @@ -6,8 +6,8 @@ import Basic._ import Identifiers._ trait Literals { - def Block: Parser0 - def WL: Parser0 + def Block: R0 + def WL: R0 object Literals{ import Basic._ val Float = { @@ -20,8 +20,8 @@ trait Literals { val Bool = R( Key.W("true") | Key.W("false") ) - val MultilineComment: Parser0 = R( "/*" ~ (MultilineComment | !"*/" ~ Parser.AnyChar).rep ~ "*/" ) - val Comment: Parser0 = R( + val MultilineComment: R0 = R( "/*" ~ (MultilineComment | !"*/" ~ Parser.AnyChar).rep ~ "*/" ) + val Comment: R0 = R( MultilineComment | "//" ~ (!Basic.Newline ~ Parser.AnyChar).rep ~ &(Basic.Newline | Parser.End) ) val Null = Key.W("null") diff --git a/scalaParser/src/test/scala/scalaParser/Main.scala b/scalaParser/src/test/scala/scalaParser/Main.scala index 803f4c87..9c56288d 100644 --- a/scalaParser/src/test/scala/scalaParser/Main.scala +++ b/scalaParser/src/test/scala/scalaParser/Main.scala @@ -5,7 +5,7 @@ package scalaParser */ object Main { def main(args: Array[String]): Unit = { - println(syntax.Basic.Digit.parse("a", 0)) + println(syntax.Basic.Digit.parse("a")) } } diff --git a/scalaParser/src/test/scala/scalaParser/UnitTests.scala b/scalaParser/src/test/scala/scalaParser/UnitTests.scala index c157779e..0d6b9eae 100644 --- a/scalaParser/src/test/scala/scalaParser/UnitTests.scala +++ b/scalaParser/src/test/scala/scalaParser/UnitTests.scala @@ -9,22 +9,22 @@ import scala.util.{Failure, Success} object UnitTests extends TestSuite{ def checkNeg[T](input: String) = { println("Checking...\n" ) - Scala.CompilationUnit.parse(input, 0) match{ - case _: Res.Failure => () // yay - case Res.Success(parsed, index) => assert(index != input.length) + Scala.CompilationUnit.parse(input) match{ + case _: Result.Failure => () // yay + case Result.Success(parsed, index, cut) => assert(index != input.length) } } def check[T](input: String, tag: String = "") = { println("Checking...\n" ) import Scala._ - val res = Scala.CompilationUnit.parse(input, 0) + val res = Scala.CompilationUnit.parse(input) res match{ - case f: Res.Failure => + case f: Result.Failure => // println(f.formatExpectedAsString) // println(f.formatTraces) throw new Exception(s"Failure\n" + input + "\n" + f.fullStack.length + "\n" + f.fullStack.map(x => x._1 + ":\t" + x._2).mkString("\n")) - case s: Res.Success[_] => + case s: Result.Success[_] => // println(parsed) val inputLength = input.length assert(s.index == inputLength) @@ -42,7 +42,7 @@ object UnitTests extends TestSuite{ val start = System.currentTimeMillis() var count = 0 while(System.currentTimeMillis() - start < 30000){ - Scala.CompilationUnit.parse(input, 0) + Scala.CompilationUnit.parse(input) count += 1 } count