Skip to content

Commit 668b3b7

Browse files
committed
added a pure functional implementation of operator precedence parsing
1 parent 4f020d5 commit 668b3b7

File tree

1 file changed

+69
-0
lines changed

1 file changed

+69
-0
lines changed

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

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ import scala.language.implicitConversions
2020

2121
// TODO: better error handling (labelling like parsec's <?>)
2222

23+
object Associativity extends Enumeration {
24+
type Associativity = Value
25+
26+
val Left, Right, Non = Value
27+
}
28+
2329
/** `Parsers` is a component that ''provides'' generic parser combinators.
2430
*
2531
* There are two abstract members that must be defined in order to
@@ -1037,4 +1043,67 @@ trait Parsers {
10371043
override def <~ [U](p: => Parser[U]): Parser[T]
10381044
= OnceParser{ (for(a <- this; _ <- commit(p)) yield a).named("<~") }
10391045
}
1046+
1047+
import Associativity._
1048+
1049+
class PrecedenceParser[Exp,Op](primary: Parser[Exp],
1050+
binop: Parser[Op],
1051+
precedence: Op => Int,
1052+
associativity: Op => Associativity,
1053+
makeBinop: (Exp, Op, Exp) => Exp) extends Parser[Exp] {
1054+
class PrecedenceSuffixParser(lhs: Exp, minLevel: Int) extends Parser[Exp] {
1055+
val opPrimary = binop ~ primary;
1056+
def parse(input: Input): ParseResult[Exp] = {
1057+
opPrimary(input) match {
1058+
case Success(op ~ rhs, next) if precedence(op) >= minLevel => {
1059+
new PrecedenceRhsSuffixParser(rhs, precedence(op), minLevel)(next) match {
1060+
case Success(r, nextInput) => new PrecedenceSuffixParser(makeBinop(lhs, op, r), minLevel)(nextInput);
1061+
case ns => ns // dead code
1062+
}
1063+
}
1064+
case _ => {
1065+
Success(lhs, input);
1066+
}
1067+
}
1068+
}
1069+
}
1070+
1071+
class PrecedenceRhsSuffixParser(rhs: Exp, currentLevel: Int, minLevel: Int) extends Parser[Exp] {
1072+
private def nextLevel(nextBinop: Op): Option[Int] = {
1073+
if (precedence(nextBinop) > currentLevel) {
1074+
Some(minLevel + 1)
1075+
} else if (precedence(nextBinop) == currentLevel && associativity(nextBinop) == Associativity.Right) {
1076+
Some(minLevel)
1077+
} else {
1078+
None
1079+
}
1080+
}
1081+
def parse(input: Input): ParseResult[Exp] = {
1082+
def done: ParseResult[Exp] = Success(rhs, input)
1083+
binop(input) match {
1084+
case Success(nextBinop,_) => {
1085+
nextLevel(nextBinop) match {
1086+
case Some(level) => {
1087+
new PrecedenceSuffixParser(rhs, level)(input) match {
1088+
case Success(r, next) => new PrecedenceRhsSuffixParser(r, currentLevel, minLevel)(next)
1089+
case ns => ns // dead code
1090+
}
1091+
}
1092+
case None => done
1093+
}
1094+
}
1095+
case _ => done
1096+
}
1097+
}
1098+
}
1099+
1100+
def parse(input: Input): ParseResult[Exp] = {
1101+
primary(input) match {
1102+
case Success(lhs, next) => {
1103+
new PrecedenceSuffixParser(lhs,0)(next)
1104+
}
1105+
case noSuccess => noSuccess
1106+
}
1107+
}
1108+
}
10401109
}

0 commit comments

Comments
 (0)