입력을 제한된 언어로 제한하려는 경우 스칼라 코어 라이브러리 만 사용하여 해당 언어에 대한 파서를 쉽게 만들 수 있습니다.
object FilterParser extends JavaTokenParsers {
def intExtractor : Parser[Extractor[Int]] = wholeNumber ^^ {s => Function.const(s.toInt)_} |
"intReturningMethod1()" ^^^ {(e : ExampleObject) => e.intReturningMethod1()} |
"integerValue1" ^^^ {_.integerValue1}
def stringExtractor : Parser[Extractor[String]] = stringLiteral ^^ {s => Function.const(sdrop(1).dropRight(1))_} |
"stringValue1" ^^^ {_.stringValue1}
def weekDayExtrator : Parser[Extractor[WeekDay.WeekDay]] = stringLiteral ^? {
case s if WeekDay.values.exists(_.toString == s) => Function.const(WeekDay.withName(s))_
}
def extractor : Parser[Extractor[Any]] = intExtractor | stringExtractor | weekDayExtrator
def compareOp : Parser[FilterCriterion] = (extractor ~ ("<"| "==" | ">") ~ extractor) ^^ {
case v1 ~ c ~ v2 => (e : ExampleObject) => compareAny(v1(e),c,v2(e))
}
def simpleExpression : Parser[FilterCriterion] = "(" ~> expression <~ ")" | compareOp
def notExpression : Parser[FilterCriterion] = "!" ~> simpleExpression ^^ {(ex) => (e : ExampleObject) => !ex(e)} |
simpleExpression
def andExpression : Parser[FilterCriterion] = repsep(notExpression,"&&") ^^ {(exs) => (e : ExampleObject) => exs.foldLeft(true)((b,ex)=> b && ex(e))}
def orExpression : Parser[FilterCriterion] = repsep(andExpression,"||") ^^ {(exs) => (e : ExampleObject) => exs.foldLeft(false)((b,ex)=> b || ex(e))}
def expression : Parser[FilterCriterion] = orExpression
def parseExpressionString(s : String) = parseAll(expression, s)
}
: 그럼 난 파서를 만들
type FilterCriterion = ExampleObject => Boolean
type Extractor[T] = ExampleObject => T
def compare[T <% Ordered[T]](v1 : T, c : String, v2 : T) : Boolean = c match {
case "<" => v1 < v2
case ">" => v1 > v2
case "==" => v1 == v2
}
def compareAny(v1: Any, c : String, v2 : Any) : Boolean = (v1,v2) match {
case (s1: String, s2:String) => compare(s1,c,s2)
case (i1: Int, i2 : Int) => compare(i1,c,i2)
case (w1 : WeekDay.WeekDay, w2 : WeekDay.WeekDay) => compare(w1.id, c, w2.id)
case _ => throw new IllegalArgumentException(s"Cannot compare ${v1.getClass} with ${v2.getClass}")
}
:
나는 당신의 예를
object WeekDay extends Enumeration {
type WeekDay = Value; val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
}
case class ExampleObject(val integerValue1 : Integer, val stringValue1 : String, val weekDay: WeekDay.Value){
def intReturningMethod1()= {0}
}
최초의 버전을 박탈에 대한 이런 짓을했는지 좀 헬퍼를 가져 오기를 사용하여 작성
이 파서는 입력 문자열을 가져와 ExampleObject를 부울 값에 매핑하는 함수를 반환합니다 . 이 테스트 함수는 사전 정의 된 도우미 함수와 구문 분석기 규칙에 정의 된 익명 함수를 사용하여 입력 문자열을 구문 분석하는 동안 한 번 작성됩니다. 테스트 함수를 생성하는 동안 입력 문자열의 해석은 한 번만 수행됩니다. 테스트 함수를 실행하면 컴파일 된 스케일 코드가 실행됩니다. 그래서 꽤 빨리 돌아 가야합니다.
테스트 기능은 사용자가 임의의 스칼라 코드를 실행할 수 없기 때문에 안전합니다. 파서와 사전 정의 된 헬퍼에서 제공되는 부분 함수로 구성됩니다.
ExampleObject에서 더 많은 기능이나 더 많은 필드를 사용하려는 경우 쉽게 파서를 확장 할 수 있습니다.
예와 같이 임의의 스칼라 문이나 간단한 필터 기준을 전달 하시겠습니까? –
예제와 같이 단순한 필터 기준입니다. – WillamS
임의의 문장을 사용하면 chrisloy의 답변과 같은 일종의 eval 함수를 사용해야합니다. 이것은 당신에게 훌륭한 유연성을 제공합니다. 실행 중에 Scala 컴파일러가 필요하고 거대한 보안 구멍을 열 수 있습니다. 간단한 기준을 사용하여 자신 만의 작은 파서를 작성할 수 있습니다. 옵션 중 하나를 선택하면 솔루션에서 큰 차이가납니다. –