33 bs + (r -> entry) |
35 bs + (r -> entry) |
34 } |
36 } |
35 }) |
37 }) |
36 } |
38 } |
37 |
39 |
|
40 |
|
41 /* tree building blocks */ |
|
42 |
|
43 object Elements |
|
44 { |
|
45 val empty = new Elements(Set.empty) |
|
46 def merge(es: Iterable[Elements]): Elements = (empty /: es.iterator)(_ ++ _) |
|
47 } |
|
48 |
|
49 final class Elements private(private val rep: Set[String]) |
|
50 { |
|
51 def contains(name: String): Boolean = rep.contains(name) |
|
52 |
|
53 def + (name: String): Elements = |
|
54 if (contains(name)) this |
|
55 else new Elements(rep + name) |
|
56 |
|
57 def + (elem: XML.Elem): Elements = this + elem.markup.name |
|
58 def ++ (elems: Iterable[XML.Elem]): Elements = (this /: elems.iterator)(_ + _) |
|
59 |
|
60 def ++ (other: Elements): Elements = |
|
61 if (this eq other) this |
|
62 else if (rep.isEmpty) other |
|
63 else (this /: other.rep)(_ + _) |
|
64 } |
|
65 |
38 object Entry |
66 object Entry |
39 { |
67 { |
40 def apply(markup: Text.Markup, subtree: Markup_Tree): Entry = |
68 def apply(markup: Text.Markup, subtree: Markup_Tree): Entry = |
41 Entry(markup.range, List(markup.info), Set(markup.info.markup.name), subtree) |
69 Entry(markup.range, List(markup.info), Elements.empty + markup.info, subtree) |
42 |
70 |
43 def apply(range: Text.Range, rev_markups: List[XML.Elem], subtree: Markup_Tree): Entry = |
71 def apply(range: Text.Range, rev_markups: List[XML.Elem], subtree: Markup_Tree): Entry = |
44 Entry(range, rev_markups, Set.empty ++ rev_markups.iterator.map(_.markup.name), subtree) |
72 Entry(range, rev_markups, Elements.empty ++ rev_markups, subtree) |
45 } |
73 } |
46 |
74 |
47 sealed case class Entry( |
75 sealed case class Entry( |
48 range: Text.Range, |
76 range: Text.Range, |
49 rev_markup: List[XML.Elem], |
77 rev_markup: List[XML.Elem], |
50 elements: Set[String], |
78 elements: Elements, |
51 subtree: Markup_Tree) |
79 subtree: Markup_Tree) |
52 { |
80 { |
53 def + (info: XML.Elem): Entry = |
81 def + (info: XML.Elem): Entry = |
54 if (elements(info.markup.name)) copy(rev_markup = info :: rev_markup) |
82 copy(rev_markup = info :: rev_markup, elements = elements + info) |
55 else copy(rev_markup = info :: rev_markup, elements = elements + info.markup.name) |
|
56 |
83 |
57 def markup: List[XML.Elem] = rev_markup.reverse |
84 def markup: List[XML.Elem] = rev_markup.reverse |
58 } |
85 } |
59 |
86 |
60 object Branches |
87 object Branches |
182 to_XML(Text.Range(0, text.length), text, (_: XML.Elem) => true) |
209 to_XML(Text.Range(0, text.length), text, (_: XML.Elem) => true) |
183 |
210 |
184 def cumulate[A](root_range: Text.Range, root_info: A, result_elements: Option[Set[String]], |
211 def cumulate[A](root_range: Text.Range, root_info: A, result_elements: Option[Set[String]], |
185 result: PartialFunction[(A, Text.Markup), A]): Stream[Text.Info[A]] = |
212 result: PartialFunction[(A, Text.Markup), A]): Stream[Text.Info[A]] = |
186 { |
213 { |
|
214 val notable: Elements => Boolean = |
|
215 result_elements match { |
|
216 case Some(res) => (elements: Elements) => res.exists(elements.contains) |
|
217 case None => (elements: Elements) => true |
|
218 } |
|
219 |
187 def results(x: A, entry: Entry): Option[A] = |
220 def results(x: A, entry: Entry): Option[A] = |
188 if (result_elements match { case Some(es) => es.exists(entry.elements) case None => true }) { |
221 if (notable(entry.elements)) { |
189 val (y, changed) = |
222 val (y, changed) = |
190 ((x, false) /: entry.rev_markup)((res, info) => // FIXME proper order!? |
223 // FIXME proper cumulation order (including status markup) (!?) |
|
224 ((x, false) /: entry.rev_markup)((res, info) => |
191 { |
225 { |
192 val (y, changed) = res |
226 val (y, changed) = res |
193 val arg = (y, Text.Info(entry.range, info)) |
227 val arg = (y, Text.Info(entry.range, info)) |
194 if (result.isDefinedAt(arg)) (result(arg), true) |
228 if (result.isDefinedAt(arg)) (result(arg), true) |
195 else res |
229 else res |