# HG changeset patch # User wenzelm # Date 1735833582 -3600 # Node ID c914db7419a3e6b47700301ce53a45b8a237d340 # Parent 0b088316b8a36c9dddb0aa2faa7123021a6a1270 misc tuning and clarification: more explicit types; proper normal form for repeated text entries; diff -r 0b088316b8a3 -r c914db7419a3 src/Pure/General/pretty.scala --- a/src/Pure/General/pretty.scala Thu Jan 02 12:49:39 2025 +0100 +++ b/src/Pure/General/pretty.scala Thu Jan 02 16:59:42 2025 +0100 @@ -64,12 +64,6 @@ val no_markup: Markup_Body = (Markup.Empty, None) val item_markup: Markup_Body = (Markup.Expression.item, None) - def markup_elem(markup: Markup_Body, body: XML.Body): XML.Elem = - markup match { - case (m, None) => XML.Elem(m, body) - case (m1, Some(m2)) => XML.Wrapped_Elem(m1, m2, body) - } - private sealed abstract class Tree { def length: Double } private case object End extends Tree { override def length: Double = 0.0 @@ -131,43 +125,75 @@ /* formatting */ - private type State = List[(Markup_Body, List[XML.Tree])] - private val init_state: State = List((no_markup, Nil)) + private sealed abstract class Tree_Buffer { def result: XML.Tree } + private case class Elem_Buffer(markup: Markup_Body, body: XML.Body) extends Tree_Buffer { + def result: XML.Elem = + markup match { + case (m, None) => XML.Elem(m, body) + case (m1, Some(m2)) => XML.Wrapped_Elem(m1, m2, body) + } + } + private case class Text_Buffer(buffer: List[String]) extends Tree_Buffer { + def result: XML.Text = XML.Text(buffer.reverse.mkString) + + def add(s: String): Text_Buffer = + if (s.isEmpty) this else copy(buffer = s :: buffer) + } + + private case class Result_Buffer( + markup: Markup_Body = no_markup, + buffer: List[Tree_Buffer] = Nil + ) { + def result_body: XML.Body = buffer.foldLeft[XML.Body](Nil)((res, t) => t.result :: res) + def result_elem: Elem_Buffer = Elem_Buffer(markup, result_body) + + def add(elem: Elem_Buffer): Result_Buffer = copy(buffer = elem :: buffer) + + def string(s: String): Result_Buffer = + if (s.isEmpty) this + else { + buffer match { + case (text: Text_Buffer) :: ts => copy(buffer = text.add(s) :: ts) + case _ => copy(buffer = Text_Buffer(List(s)) :: buffer) + } + } + } + + private type State = List[Result_Buffer] + private val init_state: State = List(Result_Buffer()) private sealed case class Text( state: State = init_state, pos: Double = 0.0, nl: Int = 0 ) { - def add(t: XML.Tree, len: Double = 0.0): Text = + def add(elem: Elem_Buffer): Text = (state: @unchecked) match { - case (m, ts) :: rest => copy(state = (m, t :: ts) :: rest, pos = pos + len) + case res :: rest => copy(state = res.add(elem) :: rest) } def push(m: Markup_Body): Text = - copy(state = (m, Nil) :: state) + copy(state = Result_Buffer(markup = m) :: state) def pop: Text = (state: @unchecked) match { - case (m1, ts1) :: (m2, ts2) :: rest => - copy(state = (m2, markup_elem(m1, ts1.reverse) :: ts2) :: rest) + case res1 :: res2 :: rest => copy(state = res2.add(res1.result_elem) :: rest) } def result: XML.Body = (state: @unchecked) match { - case List((m, ts)) if m == no_markup => ts.reverse + case List(res) if res.markup == no_markup => res.result_body } def reset: Text = copy(state = init_state) def restore(other: Text): Text = copy(state = other.state) - def newline: Text = add(fbrk).copy(pos = 0.0, nl = nl + 1) - def string(s: String, len: Double): Text = - if (s.isEmpty) copy(pos = pos + len) - else add(XML.Text(s), len = len) - + (state: @unchecked) match { + case res :: rest => copy(state = res.string(s) :: rest, pos = pos + len) + } def blanks(wd: Int): Text = string(Symbol.spaces(wd), wd.toDouble) + def newline: Text = string("\n", 0.0).copy(pos = 0.0, nl = nl + 1) } private def break_dist(trees: List[Tree], after: Double): Double = @@ -235,7 +261,7 @@ if (block.markup == no_markup) format(body1, before1, after1, text) else { val btext = format(body1, before1, after1, text.reset) - val elem = markup_elem(block.markup, btext.result) + val elem = Elem_Buffer(block.markup, btext.result) btext.restore(text.add(elem)) } val ts1 = if (text.nl < btext1.nl) force_next(ts) else ts