Я играю с игрушечным синтаксическим анализатором HTML, чтобы лучше ознакомиться с библиотекой комбинаторов синтаксического анализа Scala:
import scala.util.parsing.combinator._
sealed abstract class Node
case class TextNode(val contents : String) extends Node
case class Element(
val tag : String,
val attributes : Map[String,Option[String]],
val children : Seq[Node]
) extends Node
object HTML extends RegexParsers {
val node: Parser[Node] = text | element
val text: Parser[TextNode] = """[^<]+""".r ^^ TextNode
val label: Parser[String] = """(\w[:\w]*)""".r
val value : Parser[String] = """("[^"]*"|\w+)""".r
val attribute : Parser[(String,Option[String])] = label ~ (
"=" ~> value ^^ Some[String] | "" ^^ { case _ => None }
) ^^ { case (k ~ v) => k -> v }
val element: Parser[Element] = (
("<" ~> label ~ rep(whiteSpace ~> attribute) <~ ">" )
~ rep(node) ~
("" ~> label <~ ">")
) ^^ {
case (tag ~ attributes ~ children ~ close) => Element(tag, Map(attributes : _*), children)
}
}
Что я понимаю, что хочу это некоторый способ убедиться, что мои открывающие и закрывающие теги совпадают.
Думаю, для этого мне нужен какой-нибудь комбинатор flatMap
~ Parser[A] => (A => Parser[B]) => Parser[B]
,
поэтому я могу использовать открывающий тег для создания анализатора закрывающего тега. Но я не вижу ничего, соответствующего этой подписи в библиотеке.
Как это правильно сделать?