bulundu: Ben ((1+2) > (3+4))
ifadeyi değiştirirsenizScala Kombinatörleri JavaTokennParsers '||' Ben bu testi çalıştırdığınızda beklendiği ancak '>'
Left("`||' expected but `>' found") did not equal Right(BinaryOp(>,BinaryOp(+,Number(1.0),Number(2.0),Num),BinaryOp(+,Number(3.0),Number(4.0),Num),Bool))
çalıştığını ancak isteğe bağlı destek edebilmek gerekir:
import com.dvMENTALmadness.parsers.{BinaryOp, ExprType, Number, SimpleEquationParser}
import org.scalatest.FlatSpec
class SimpleEquationParserTest extends FlatSpec {
"(1+2) > (3+4)" should " == false" in {
val result = SimpleEquationParser("(1+2) > (3+4)")
println(result)
assert(result == Right(BinaryOp(">",BinaryOp("+",Number(1.0),Number(2.0),ExprType.Num),BinaryOp("+",Number(3.0),Number(4.0),ExprType.Num),ExprType.Bool)))
}
}
alıyorum parantez. Baska öneri?
package com.dvMENTALmadness.parsers
import com.dvMENTALmadness.parsers.ExprType.ExprType
import scala.util.parsing.combinator.{JavaTokenParsers, PackratParsers}
sealed trait Expr
sealed trait Var extends Expr {
def key: String
}
object ExprType extends Enumeration {
type ExprType = Value
val Var, Num, Text, Bool = Value
}
case class Text(value: String) extends Expr
case class Number(value: Double) extends Expr
case class Bool(value: Boolean) extends Expr
case class NumericVar(key: String) extends Var
case class TextVar(key: String) extends Var
case class BoolVar(key: String) extends Var
case class AnyVar(key: String) extends Var
case class UnaryOp(operator: String, arg: Expr, expType: ExprType) extends Expr
case class BinaryOp(operator: String, left : Expr, right: Expr, expType: ExprType) extends Expr
trait ExprParser extends JavaTokenParsers with PackratParsers {
def foldExpr(etype: ExprType)(pat: Expr ~ List[String ~ Expr]) : Expr = pat match {
case left ~ xs => xs.foldLeft(left)((left, acc) => acc match {
case op ~ right => BinaryOp(op, left, right, etype)
})
}
// see: http://jim-mcbeath.blogspot.com/2011/07/debugging-scala-parser-combinators.html
implicit def toLogged(name: String) = new {
def !!![T](p:Parser[T]) = log(p)(name) // for debugging
//def !!![T](p:Parser[T]) = p // for production
}
}
trait BoolParser extends ExprParser {
// Operator precedence: http://www.tutorialspoint.com/scala/scala_operators.htm
def expr = "expr" !!! bool_expr | num_expr | text_expr
def bool_expr = "bool_expr" !!! or | bool_term
def num_expr = "num_expr" !!! num_equality | num_term
def text_expr = "text_expr" !!! text_equality
// operations
def or = "or" !!! and ~ rep("||" ~ and) ^^ foldExpr(ExprType.Bool)
def and = "and" !!! equality ~ rep("&&" ~ equality) ^^ foldExpr(ExprType.Bool)
def equality = "equality" !!! bool_equality | num_equality | text_equality
def bool_equality = "bool_equality" !!! bool_term ~ rep("==" ~ bool_term | "!=" ~ bool_term) ^^ foldExpr(ExprType.Bool)
def num_equality = "num_equality" !!! relational ~ rep("==" ~ relational | "!=" ~ relational) ^^ foldExpr(ExprType.Num)
def text_equality = "text_equality" !!! concat ~ rep("==" ~ concat | "!=" ~ concat) ^^ foldExpr(ExprType.Text)
def relational = "relational" !!! additive ~ rep(">=" ~ additive | "<=" ~ additive | ">" ~ additive | "<" ~ additive) ^^ foldExpr(ExprType.Num)
def additive = "additive" !!! multiplicative ~ rep("+" ~ multiplicative | "-" ~ multiplicative) ^^ foldExpr(ExprType.Num)
def multiplicative = "multiplicative" !!! num_term ~ rep("*" ~ num_term | "/" ~ num_term | "%" ~ num_term) ^^ foldExpr(ExprType.Num)
def concat = "concat" !!! text ~ rep("+" ~ text) ^^ foldExpr(ExprType.Text)
def operators = "*" | "/" | "%" | "+" | "-" | "&&" | "||"
// terms
def term = "term" !!! bool_term | num_term
def bool_term = "bool_term" !!! bool | bool_parens | not
def num_term = "num_term" !!! num | num_parens | neg
def not:PackratParser[Expr] = "not" !!! "!" ~> bool_term ^^ (x => UnaryOp("!", x, ExprType.Bool))
def neg:PackratParser[Expr] = "neg" !!! "-" ~> num_term ^^ (x => UnaryOp("-", x, ExprType.Num))
def parens:PackratParser[Expr] = "parens" !!! "(" ~> expr <~ ")"
def bool_parens:PackratParser[Expr] = "bool_parens" !!! "(" ~> bool_expr <~ ")"
def num_parens:PackratParser[Expr] = "num_parens" !!! "(" ~> num_expr <~ ")"
def text_parens:PackratParser[Expr] = "text_parens" !!! "(" ~> text_expr <~ ")"
//values
def bool: PackratParser[Expr] = "bool" !!!
"true" ^^^ (Bool(true)) |
"false" ^^^ (Bool(false)) |
var_factor
def num: PackratParser[Expr] = "num" !!!
floatingPointNumber ^^ (x => Number(x.toDouble)) |
wholeNumber ^^ (x => Number(x.toDouble)) |
var_factor
def text: PackratParser[Expr] = "text" !!!
stringLiteral ^^ (x => Text(stripQuote(x))) |
var_factor
def var_factor: Parser[Expr] = "var_factor" !!!
id <~ ".asNumber" ^^ (x => NumericVar(x)) |
id <~ ".asText" ^^ (x => TextVar(x)) |
id <~ ".asBool" ^^ (x => BoolVar(x)) |
id ^^ (x => AnyVar(x))
def id: PackratParser[String] = "id" !!! opt("{") ~> ident <~ opt("}")
private def stripQuote(s: String) = {
s.substring(1, s.length - 1)
}
}
object SimpleEquationParser extends BoolParser {
def apply(input: String) : Either[String,Expr] = {
parseAll("root" !!! expr, input) match {
case Success(r, _) => Right(r)
case Failure(msg, _) => Left(msg)
case Error(msg, _) => Left(msg)
}
}
}
günlük izleme:
trying root at [email protected]004
trying expr at [email protected]004
trying bool_expr at [email protected]004
trying or at [email protected]004
trying and at [email protected]004
trying equality at [email protected]004
trying bool_equality at scala.util.parsing.combinator.Packra[email protected]
trying bool_term at [email protected]004
trying bool at [email protected]004
bool --> [1.1] failure: `true' expected but `(' found
(1+2) > (3+4)
^
trying var_factor at [email protected]004
trying id at [email protected]004
id --> [1.1] failure: string matching regex `\p{javaJavaIdentifierStart}\p{javaJavaIdentifierPart}*' expected but `(' found
(1+2) > (3+4)
^
var_factor --> [1.1] failure: string matching regex `\p{javaJavaIdentifierStart}\p{javaJavaIdentifierPart}*' expected but `(' found
(1+2) > (3+4)
^
trying id at [email protected]004
id --> [1.1] failure: string matching regex `\p{javaJavaIdentifierStart}\p{javaJavaIdentifierPart}*' expected but `(' found
(1+2) > (3+4)
^
trying id at [email protected]004
id --> [1.1] failure: string matching regex `\p{javaJavaIdentifierStart}\p{javaJavaIdentifierPart}*' expected but `(' found
(1+2) > (3+4)
^
trying id at [email protected]004
id --> [1.1] failure: string matching regex `\p{javaJavaIdentifierStart}\p{javaJavaIdentifierPart}*' expected but `(' found
(1+2) > (3+4)
^
bool_term --> [1.1] failure: string matching regex `\p{javaJavaIdentifierStart}\p{javaJavaIdentifierPart}*' expected but `(' found
(1+2) > (3+4)
^
trying bool_parens at [email protected]004
trying bool_expr at sca[email protected]59d016c9
trying or at sca[email protected]59d016c9
trying and at sca[email protected]59d016c9
trying equality at sca[email protected]59d016c9
trying bool_equality at sca[email protected]59d016c9
trying bool_term at sca[email protected]59d016c9
trying bool at sca[email protected]59d016c9
bool --> [1.2] failure: `true' expected but `1' found
(1+2) > (3+4)
^
trying var_factor at sca[email protected]59d016c9
trying id at sca[email protected]59d016c9
id --> [1.2] failure: string matching regex `\p{javaJavaIdentifierStart}\p{javaJavaIdentifierPart}*' expected but `1' found
(1+2) > (3+4)
^
var_factor --> [1.2] failure: string matching regex `\p{javaJavaIdentifierStart}\p{javaJavaIdentifierPart}*' expected but `1' found
(1+2) > (3+4)
^
trying id at sca[email protected]59d016c9
id --> [1.2] failure: string matching regex `\p{javaJavaIdentifierStart}\p{javaJavaIdentifierPart}*' expected but `1' found
(1+2) > (3+4)
^
trying id at sca[email protected]59d016c9
id --> [1.2] failure: string matching regex `\p{javaJavaIdentifierStart}\p{javaJavaIdentifierPart}*' expected but `1' found
(1+2) > (3+4)
^
trying id at sca[email protected]59d016c9
id --> [1.2] failure: string matching regex `\p{javaJavaIdentifierStart}\p{javaJavaIdentifierPart}*' expected but `1' found
(1+2) > (3+4)
^
bool_term --> [1.2] failure: string matching regex `\p{javaJavaIdentifierStart}\p{javaJavaIdentifierPart}*' expected but `1' found
(1+2) > (3+4)
^
trying bool_parens at sca[email protected]59d016c9
bool_parens --> [1.2] failure: `(' expected but `1' found
(1+2) > (3+4)
^
trying not at sca[email protected]59d016c9
not --> [1.2] failure: `!' expected but `1' found
(1+2) > (3+4)
^
bool_equality --> [1.2] failure: `!' expected but `1' found
(1+2) > (3+4)
^
equality --> [1.2] failure: `!' expected but `1' found
(1+2) > (3+4)
^
trying num_equality at sca[email protected]59d016c9
trying relational at sca[email protected]59d016c9
trying additive at sca[email protected]59d016c9
trying multiplicative at sca[email protected]59d016c9
trying num_term at sca[email protected]59d016c9
trying num at sca[email protected]59d016c9
num --> [1.3] parsed: 1
num_term --> [1.3] parsed: Number(1.0)
multiplicative --> [1.3] parsed: (Number(1.0)~List())
trying multiplicative at sca[email protected]36c88a32
trying num_term at sca[email protected]36c88a32
trying num at sca[email protected]36c88a32
num --> [1.5] parsed: 2
num_term --> [1.5] parsed: Number(2.0)
multiplicative --> [1.5] parsed: (Number(2.0)~List())
additive --> [1.5] parsed: (Number(1.0)~List((+~Number(2.0))))
relational --> [1.5] parsed: (BinaryOp(+,Number(1.0),Number(2.0),Num)~List())
num_equality --> [1.5] parsed: (BinaryOp(+,Number(1.0),Number(2.0),Num)~List())
and --> [1.5] parsed: (BinaryOp(+,Number(1.0),Number(2.0),Num)~List())
or --> [1.5] parsed: (BinaryOp(+,Number(1.0),Number(2.0),Num)~List())
bool_expr --> [1.5] parsed: BinaryOp(+,Number(1.0),Number(2.0),Num)
bool_parens --> [1.6] parsed: BinaryOp(+,Number(1.0),Number(2.0),Num)
bool_equality --> [1.6] parsed: (BinaryOp(+,Number(1.0),Number(2.0),Num)~List())
equality --> [1.6] parsed: BinaryOp(+,Number(1.0),Number(2.0),Num)
and --> [1.6] parsed: (BinaryOp(+,Number(1.0),Number(2.0),Num)~List())
or --> [1.6] parsed: (BinaryOp(+,Number(1.0),Number(2.0),Num)~List())
bool_expr --> [1.6] parsed: BinaryOp(+,Number(1.0),Number(2.0),Num)
expr --> [1.6] parsed: BinaryOp(+,Number(1.0),Number(2.0),Num)
root --> [1.6] parsed: BinaryOp(+,Number(1.0),Number(2.0),Num)
Left(`||' expected but `>' found)
'(1 + 2)' nin bool_expr ile ayrıştırıldığını unutmayın: bool_parens -> [1.6] ayrıştırılmış: BinaryOp (+, Sayı (1.0), Sayı (2.0), Num) '. Ancak dikkate alınması gereken 'ilişkisel' ayrıştırıcı için bir 'num_expr' ile ayrıştırılmalıdır. – Kolmar
Ayrıca, 'foldExpr''deki bazı türlerin yanlış olduğuna inanıyorum. Örneğin. "num_equality" ifadesinde sonuç, ExprType.Bool olmalıdır, ancak '^^ foldExpr (ExprType.Num)' olmalıdır. – Kolmar
@Kolmar Eşitlik ayrıştırıcılarının sırasını değiştirerek çalışmayı başarabildim, böylece "num_equality", "bool_equality" den önce gelir. Ancak, bunu yaptığımda "true" ve "false", ayrılmış boolean anahtar kelimeler yerine "ident" değerleri olarak ayrıştırıldı. Bu yüzden bunu düzeltmek için bir 'ayrılmış' çözümleyici ekledim. Bu tavsiyeye göre düştüğüne inanıyorum. –