src/Pure/General/yxml.scala
changeset 27943 f34ff5e7728f
parent 27930 2b44df907cc2
child 27944 2bf3f30558ed
equal deleted inserted replaced
27942:5ac9a0f9fad0 27943:f34ff5e7728f
    10 import java.util.regex.Pattern
    10 import java.util.regex.Pattern
    11 
    11 
    12 
    12 
    13 object YXML {
    13 object YXML {
    14 
    14 
    15   /* markers */
    15   /* chunk markers */
    16 
    16 
    17   private val X = '\5'
    17   private val X = '\5'
    18   private val Y = '\6'
    18   private val Y = '\6'
    19 
    19 
    20   def detect(source: CharSequence) = {
    20   def detect(source: CharSequence) = {
    21     source.length >= 2 &&
    21     source.length >= 2 &&
    22     source.charAt(0) == X &&
    22     source.charAt(0) == X &&
    23     source.charAt(1) == Y
    23     source.charAt(1) == Y
       
    24   }
       
    25 
       
    26 
       
    27   /* iterate over chunks (resembles space_explode in ML) */
       
    28 
       
    29   private def chunks(sep: Char, source: CharSequence) = new Iterator[CharSequence] {
       
    30     private val end = source.length
       
    31     private var state = if (end == 0) None else get_chunk(-1)
       
    32     private def get_chunk(i: Int) = {
       
    33       if (i < end) {
       
    34         var j = i; do j += 1 while (j < end && source.charAt(j) != sep)
       
    35         Some((source.subSequence(i + 1, j), j))
       
    36       }
       
    37       else None
       
    38     }
       
    39 
       
    40     def hasNext() = state.isDefined
       
    41     def next() = state match {
       
    42       case Some((s, i)) => { state = get_chunk(i); s }
       
    43       case None => throw new NoSuchElementException("next on empty iterator")
       
    44     }
    24   }
    45   }
    25 
    46 
    26 
    47 
    27   /* parsing */
    48   /* parsing */
    28 
    49 
    33   private def err_element() = err("bad element")
    54   private def err_element() = err("bad element")
    34   private def err_unbalanced(name: String) =
    55   private def err_unbalanced(name: String) =
    35     if (name == "") err("unbalanced element")
    56     if (name == "") err("unbalanced element")
    36     else err("unbalanced element \"" + name + "\"")
    57     else err("unbalanced element \"" + name + "\"")
    37 
    58 
    38   private val X_pattern = Pattern.compile(Pattern.quote(X.toString))
    59   private def parse_attrib(s: CharSequence) =
    39   private val Y_pattern = Pattern.compile(Pattern.quote(Y.toString))
    60     chunks('=', s).toList match {
    40   private val eq_pattern = Pattern.compile(Pattern.quote("="))
    61       case Nil => err_attribute()
    41 
    62       case "" :: _ => err_attribute()
    42   private def parse_attrib(s: String) =
    63       case a :: xs => (a.toString, xs.mkString("="))
    43     eq_pattern.split(s, 2).toList match {
       
    44       case List(x, y) => if (x != "") (x, y) else err_attribute()
       
    45       case _ => err_attribute()
       
    46     }
    64     }
    47 
    65 
    48 
    66 
    49   def parse_body(source: CharSequence) = {
    67   def parse_body(source: CharSequence) = {
    50 
    68 
    68 
    86 
    69 
    87 
    70     /* parse chunks */
    88     /* parse chunks */
    71 
    89 
    72     stack = List((("", Nil), Nil))
    90     stack = List((("", Nil), Nil))
    73     for (chunk <- X_pattern.split(source) if chunk != "") {
    91     for (chunk <- chunks(X, source) if chunk != "") {
    74       Y_pattern.split(chunk).toList match {
    92       chunks(Y, chunk).toList match {
    75         case Nil => pop()
    93         case List("", "") => pop()
    76         case "" :: name :: atts => push(name, atts.map(parse_attrib))
    94         case "" :: name :: atts => push(name.toString, atts.map(parse_attrib))
    77         case txts => for (txt <- txts) add(XML.Text(txt))
    95         case txts => for (txt <- txts) add(XML.Text(txt.toString))
    78       }
    96       }
    79     }
    97     }
    80     stack match {
    98     stack match {
    81       case List((("", _), result)) => result.reverse
    99       case List((("", _), result)) => result.reverse
    82       case ((name, _), _) :: _ => err_unbalanced(name)
   100       case ((name, _), _) :: _ => err_unbalanced(name)