@@ -20,6 +20,9 @@ import scala.language.implicitConversions
20
20
21
21
// TODO: better error handling (labelling like parsec's <?>)
22
22
23
+ /** An enumeration of operator associativity values: `Left`, `Right`, and
24
+ * `Non`.
25
+ */
23
26
object Associativity extends Enumeration {
24
27
type Associativity = Value
25
28
@@ -1025,18 +1028,34 @@ trait Parsers {
1025
1028
1026
1029
import Associativity ._
1027
1030
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 ] {
1031
+ /** A parser that respects operator the precedence and associativity
1032
+ * conventions specified in its constructor.
1033
+ *
1034
+ *@param primary a parser that matches atomic expressions (the atomicity is
1035
+ * from the perspective of binary operators). May include
1036
+ * unary operators or parentheses.
1037
+ *@param binop a parser that matches binary operators.
1038
+ *@param precedence a function from operators to their precedence levels.
1039
+ * Operators with higher precedence values bind more
1040
+ * tightly than those with lower values.
1041
+ *@param associativity a function from operators to their associativity.
1042
+ *@param makeBinop a function that combines two operands and an operator
1043
+ * into a new expression. The result must have the same type
1044
+ * as the operands because intermediate results become
1045
+ * operands to other operators.
1046
+ */
1047
+ class PrecedenceParser [Exp ,Op ,E <: Exp ](primary :Parser [E ],
1048
+ binop :Parser [Op ],
1049
+ precedence :Op => Int ,
1050
+ associativity :Op => Associativity ,
1051
+ makeBinop : (Exp ,Op ,Exp )=> Exp )extends Parser [Exp ] {
1052
+ private class ExpandLeftParser (lhs :Exp ,minLevel :Int )extends Parser [Exp ] {
1034
1053
val opPrimary = binop~ primary;
1035
- def parse (input :Input ): ParseResult [Exp ]= {
1054
+ def apply (input :Input ): ParseResult [Exp ]= {
1036
1055
opPrimary(input)match {
1037
1056
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);
1057
+ new ExpandRightParser (rhs, precedence(op), minLevel)(next)match {
1058
+ case Success (r, nextInput)=> new ExpandLeftParser (makeBinop(lhs, op, r), minLevel)(nextInput);
1040
1059
case ns=> ns// dead code
1041
1060
}
1042
1061
}
@@ -1047,7 +1066,7 @@ trait Parsers {
1047
1066
}
1048
1067
}
1049
1068
1050
- class PrecedenceRhsSuffixParser (rhs :Exp ,currentLevel :Int ,minLevel :Int )extends Parser [Exp ] {
1069
+ private class ExpandRightParser (rhs :Exp ,currentLevel :Int ,minLevel :Int )extends Parser [Exp ] {
1051
1070
private def nextLevel (nextBinop :Op ): Option [Int ]= {
1052
1071
if (precedence(nextBinop)> currentLevel) {
1053
1072
Some (minLevel+ 1 )
@@ -1057,14 +1076,14 @@ trait Parsers {
1057
1076
None
1058
1077
}
1059
1078
}
1060
- def parse (input :Input ): ParseResult [Exp ]= {
1079
+ def apply (input :Input ): ParseResult [Exp ]= {
1061
1080
def done : ParseResult [Exp ]= Success (rhs, input)
1062
1081
binop(input)match {
1063
1082
case Success (nextBinop,_)=> {
1064
1083
nextLevel(nextBinop)match {
1065
1084
case Some (level)=> {
1066
- new PrecedenceSuffixParser (rhs, level)(input)match {
1067
- case Success (r, next)=> new PrecedenceRhsSuffixParser (r, currentLevel, minLevel)(next)
1085
+ new ExpandLeftParser (rhs, level)(input)match {
1086
+ case Success (r, next)=> new ExpandRightParser (r, currentLevel, minLevel)(next)
1068
1087
case ns=> ns// dead code
1069
1088
}
1070
1089
}
@@ -1076,10 +1095,12 @@ trait Parsers {
1076
1095
}
1077
1096
}
1078
1097
1079
- def parse (input :Input ): ParseResult [Exp ]= {
1098
+ /** Parse an expression.
1099
+ */
1100
+ def apply (input :Input ): ParseResult [Exp ]= {
1080
1101
primary(input)match {
1081
1102
case Success (lhs, next)=> {
1082
- new PrecedenceSuffixParser (lhs,0 )(next)
1103
+ new ExpandLeftParser (lhs,0 )(next)
1083
1104
}
1084
1105
case noSuccess=> noSuccess
1085
1106
}