Как сопоставить шаблон с результатом комбинатора парсера Scala - PullRequest
5 голосов
/ 06 мая 2011

У нас есть многопоточный RPC-сервер, который анализирует входные строки.Мы столкнулись с проблемой, при которой библиотека комбинатора синтаксических анализаторов Scala не является многопоточной безопасностью: переменная lastNoSuccess в Parsers.scala используется для любого анализа.Мы получаем NullPointerException в этой строке

if (!(lastNoSuccess != null && next.pos < lastNoSuccess.next.pos))

Способ по умолчанию для реализации синтаксического анализатора путем создания объекта, который расширяет один из анализаторов, но я хочу создать анализатор по требованию, чтобы у каждого было свое внутреннее состояниеЯ использую класс вместо объекта.Тем не менее, я не могу заставить его скомпилировать, так как мне нужно сопоставить шаблон с результатом:

import scala.util.parsing.combinator.RegexParsers

class SqlParserImpl
  extends RegexParsers
{
  val term: Parser[String] = """(?i)term\b""".r
}

object Test
{
  def main(args: Array[String]): Unit =
  {
    val parser = new SqlParserImpl
    parser.parseAll(parser.term, "term") match {
      // How do I match?
      case SqlParserImpl#Success(result, _) => true
      case SqlParserImpl#NoSuccess => false
    }
  }
}

Сбой с

t.scala:16: error: '=>' expected but '#' found.
          case SqlParserImpl#Success(result, _) => true
                            ^
t.scala:17: error: '=>' expected but '#' found.
          case SqlParserImpl#NoSuccess => false
                            ^
two errors found

Ответы [ 3 ]

10 голосов
/ 06 мая 2011

Используйте это:

val parser = new SqlParserImpl
parser.parseAll(parser.term, "term") match {
  case parser.Success(result, _) => true
  case parser.NoSuccess(_, _) => false
}

Знак # используется для обозначения члена типа. В вашем случае он использует конструктор или шаблон экстрактора, который должен ссылаться на объект или что-то похожее на конструктор.

Хм. У меня нет 2,7 под рукой. Попробуйте это:

parser.parseAll(parser.term, "term") match {
  case parser.Success(result, _) => true
  case parser.Failure(_, _) => false
  case parser.Error(_, _) => false
}
4 голосов
/ 06 мая 2011

Объект NoSuccess (с экстрактором) был добавлен еще в 2009 году, когда код больше не был перенесен в версию 2.7. Однако его реализация довольно проста:

object NoSuccess {
  def unapply[T](x: ParseResult[T]) = x match {
    case Failure(msg, next)   => Some(msg, next)
    case Error(msg, next)     => Some(msg, next)
    case _                    => None
  }
}

Таким образом, вы можете заменить parser.NoSuccess(_, _) совпадение одним parser.Failure(_, _) и одним parser.Error(_, _) совпадением. Но если вас не интересует что возвращается , тогда проще сопоставить с типом:

case _: parser.Success[_] => true
case _: parser.NoSuccess  => false

Как предложено от Евгений .

4 голосов
/ 06 мая 2011

Мне удалось скомпилировать следующее:

object Test {  
  def main(args: Array[String]): Unit = {
    val parser = new SqlParserImpl

    println(parser.parseAll(parser.term, "term") match {
      case x: parser.Success[_] => true
      case x: parser.NoSuccess => false
    })
  }
}
...