org.parboiled2.DynamicRuleDispatch.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of parboiled_2.12.0-RC2 Show documentation
Show all versions of parboiled_2.12.0-RC2 Show documentation
Fast and elegant PEG parsing in Scala - lightweight, easy-to-use, powerful
The newest version!
/*
* Copyright (C) 2009-2013 Mathias Doenitz, Alexander Myltsev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.parboiled2
import scala.collection.immutable
import scala.reflect.macros.whitebox.Context
import shapeless.HList
/**
* An application needs to implement this interface to receive the result
* of a dynamic parsing run.
* Often times this interface is directly implemented by the Parser class itself
* (even though this is not a requirement).
*/
trait DynamicRuleHandler[P <: Parser, L <: HList] extends Parser.DeliveryScheme[L] {
def parser: P
def ruleNotFound(ruleName: String): Result
}
/**
* Runs one of the rules of a parser instance of type `P` given the rules name.
* The rule must have type `RuleN[L]`.
*/
trait DynamicRuleDispatch[P <: Parser, L <: HList] {
def apply(handler: DynamicRuleHandler[P, L], ruleName: String): handler.Result
}
object DynamicRuleDispatch {
/**
* Implements efficient runtime dispatch to a predefined set of parser rules.
* Given a number of rule names this macro-supported method creates a `DynamicRuleDispatch` instance along with
* a sequence of the given rule names.
* Note that there is no reflection involved and compilation will fail, if one of the given rule names
* does not constitute a method of parser type `P` or has a type different from `RuleN[L]`.
*/
def apply[P <: Parser, L <: HList](ruleNames: String*): (DynamicRuleDispatch[P, L], immutable.Seq[String]) = macro __create[P, L]
///////////////////// INTERNAL ////////////////////////
def __create[P <: Parser, L <: HList](c: Context)(ruleNames: c.Expr[String]*)(implicit P: c.WeakTypeTag[P], L: c.WeakTypeTag[L]): c.Expr[(DynamicRuleDispatch[P, L], immutable.Seq[String])] = {
import c.universe._
val names: Array[String] = ruleNames.map {
_.tree match {
case Literal(Constant(s: String)) ⇒ s
case x ⇒ c.abort(x.pos, s"Invalid `String` argument `x`, only `String` literals are supported!")
}
}(collection.breakOut)
java.util.Arrays.sort(names.asInstanceOf[Array[Object]])
def rec(start: Int, end: Int): Tree =
if (start <= end) {
val mid = (start + end) >>> 1
val name = names(mid)
q"""val c = $name compare ruleName
if (c < 0) ${rec(mid + 1, end)}
else if (c > 0) ${rec(start, mid - 1)}
else {
val p = handler.parser
p.__run[$L](p.${TermName(name).encodedName.toTermName})(handler)
}"""
} else q"handler.ruleNotFound(ruleName)"
c.Expr[(DynamicRuleDispatch[P, L], immutable.Seq[String])] {
q"""val drd =
new org.parboiled2.DynamicRuleDispatch[$P, $L] {
def apply(handler: org.parboiled2.DynamicRuleHandler[$P, $L], ruleName: String): handler.Result =
${rec(0, names.length - 1)}
}
(drd, scala.collection.immutable.Seq(..$ruleNames))"""
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy