Skip to content

Commit 8dfb87b

Browse files
committed
added a pure functional implementation of operator precedence parsing
1 parent 5f6644d commit 8dfb87b

File tree

1 file changed

+69
-0
lines changed

1 file changed

+69
-0
lines changed

Diff for: shared/src/main/scala/scala/util/parsing/combinator/Parsers.scala

+69
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
@@ -1016,4 +1022,67 @@ trait Parsers {
10161022
override def <~ [U](p: => Parser[U]): Parser[T]
10171023
= OnceParser{ (for(a <- this; b <- commit(p)) yield a).named("<~") }
10181024
}
1025+
1026+
import Associativity._
1027+
1028+
class PrecedenceParser[Exp,Op](primary: Parser[Exp],
1029+
binop: Parser[Op],
1030+
precedence: Op => Int,
1031+
associativity: Op => Associativity,
1032+
makeBinop: (Exp, Op, Exp) => Exp) extends Parser[Exp] {
1033+
class PrecedenceSuffixParser(lhs: Exp, minLevel: Int) extends Parser[Exp] {
1034+
val opPrimary = binop ~ primary;
1035+
def parse(input: Input): ParseResult[Exp] = {
1036+
opPrimary(input) match {
1037+
case Success(op ~ rhs, next) if precedence(op) >= minLevel => {
1038+
new PrecedenceRhsSuffixParser(rhs, precedence(op), minLevel)(next) match {
1039+
case Success(r, nextInput) => new PrecedenceSuffixParser(makeBinop(lhs, op, r), minLevel)(nextInput);
1040+
case ns => ns // dead code
1041+
}
1042+
}
1043+
case _ => {
1044+
Success(lhs, input);
1045+
}
1046+
}
1047+
}
1048+
}
1049+
1050+
class PrecedenceRhsSuffixParser(rhs: Exp, currentLevel: Int, minLevel: Int) extends Parser[Exp] {
1051+
private def nextLevel(nextBinop: Op): Option[Int] = {
1052+
if (precedence(nextBinop) > currentLevel) {
1053+
Some(minLevel + 1)
1054+
} else if (precedence(nextBinop) == currentLevel && associativity(nextBinop) == Associativity.Right) {
1055+
Some(minLevel)
1056+
} else {
1057+
None
1058+
}
1059+
}
1060+
def parse(input: Input): ParseResult[Exp] = {
1061+
def done: ParseResult[Exp] = Success(rhs, input)
1062+
binop(input) match {
1063+
case Success(nextBinop,_) => {
1064+
nextLevel(nextBinop) match {
1065+
case Some(level) => {
1066+
new PrecedenceSuffixParser(rhs, level)(input) match {
1067+
case Success(r, next) => new PrecedenceRhsSuffixParser(r, currentLevel, minLevel)(next)
1068+
case ns => ns // dead code
1069+
}
1070+
}
1071+
case None => done
1072+
}
1073+
}
1074+
case _ => done
1075+
}
1076+
}
1077+
}
1078+
1079+
def parse(input: Input): ParseResult[Exp] = {
1080+
primary(input) match {
1081+
case Success(lhs, next) => {
1082+
new PrecedenceSuffixParser(lhs,0)(next)
1083+
}
1084+
case noSuccess => noSuccess
1085+
}
1086+
}
1087+
}
10191088
}

0 commit comments

Comments
 (0)