54 } |
54 } |
55 override def toString: String = entries.mkString("Results(", ", ", ")") |
55 override def toString: String = entries.mkString("Results(", ", ", ")") |
56 } |
56 } |
57 |
57 |
58 |
58 |
|
59 /* markup */ |
|
60 |
|
61 object Markup_Index |
|
62 { |
|
63 val markup: Markup_Index = Markup_Index(false, "") |
|
64 } |
|
65 |
|
66 sealed case class Markup_Index(status: Boolean, file_name: String) |
|
67 |
|
68 object Markups |
|
69 { |
|
70 val empty: Markups = new Markups(Map.empty) |
|
71 |
|
72 def init(markup: Markup_Tree): Markups = |
|
73 new Markups(Map(Markup_Index.markup -> markup)) |
|
74 } |
|
75 |
|
76 final class Markups private(private val rep: Map[Markup_Index, Markup_Tree]) |
|
77 { |
|
78 def apply(index: Markup_Index): Markup_Tree = |
|
79 rep.getOrElse(index, Markup_Tree.empty) |
|
80 |
|
81 def add(index: Markup_Index, markup: Text.Markup): Markups = |
|
82 new Markups(rep + (index -> (this(index) + markup))) |
|
83 |
|
84 def ++ (other: Markups): Markups = |
|
85 new Markups( |
|
86 (rep.keySet ++ other.rep.keySet) |
|
87 .map(index => index -> (this(index) ++ other(index))).toMap) |
|
88 |
|
89 override def hashCode: Int = rep.hashCode |
|
90 override def equals(that: Any): Boolean = |
|
91 that match { |
|
92 case other: Markups => rep == other.rep |
|
93 case _ => false |
|
94 } |
|
95 override def toString: String = rep.iterator.mkString("Markups(", ", ", ")") |
|
96 } |
|
97 |
|
98 |
59 /* state */ |
99 /* state */ |
60 |
100 |
61 sealed case class State( |
101 sealed case class State( |
62 command: Command, |
102 command: Command, |
63 status: List[Markup] = Nil, |
103 status: List[Markup] = Nil, |
64 results: Results = Results.empty, |
104 results: Results = Results.empty, |
65 markups: Map[String, Markup_Tree] = Map.empty) |
105 markups: Markups = Markups.empty) |
66 { |
106 { |
67 def get_markup(file_name: String): Markup_Tree = |
107 /* markup */ |
68 markups.getOrElse(file_name, Markup_Tree.empty) |
108 |
69 |
109 def get_markup(index: Markup_Index): Markup_Tree = markups(index) |
70 def markup: Markup_Tree = get_markup("") |
110 |
|
111 def markup: Markup_Tree = get_markup(Markup_Index.markup) |
71 |
112 |
72 def markup_to_XML(filter: XML.Elem => Boolean): XML.Body = |
113 def markup_to_XML(filter: XML.Elem => Boolean): XML.Body = |
73 markup.to_XML(command.range, command.source, filter) |
114 markup.to_XML(command.range, command.source, filter) |
74 |
115 |
75 |
116 |
79 command.source == other.command.source && |
120 command.source == other.command.source && |
80 status == other.status && |
121 status == other.status && |
81 results == other.results && |
122 results == other.results && |
82 markups == other.markups |
123 markups == other.markups |
83 |
124 |
84 private def add_status(st: Markup): State = copy(status = st :: status) |
125 private def add_status(st: Markup): State = |
85 |
126 copy(status = st :: status) |
86 private def add_markup(file_name: String, m: Text.Markup): State = |
127 |
87 copy(markups = markups + (file_name -> (get_markup(file_name) + m))) |
128 private def add_markup(status: Boolean, file_name: String, m: Text.Markup): State = |
|
129 { |
|
130 val markups1 = |
|
131 if (status || Protocol.status_elements(m.info.name)) |
|
132 markups.add(Markup_Index(true, file_name), m) |
|
133 else markups |
|
134 copy(markups = markups1.add(Markup_Index(false, file_name), m)) |
|
135 } |
88 |
136 |
89 def + (alt_id: Document_ID.Generic, message: XML.Elem): State = |
137 def + (alt_id: Document_ID.Generic, message: XML.Elem): State = |
90 message match { |
138 message match { |
91 case XML.Elem(Markup(Markup.STATUS, _), msgs) => |
139 case XML.Elem(Markup(Markup.STATUS, _), msgs) => |
92 (this /: msgs)((state, msg) => |
140 (this /: msgs)((state, msg) => |
93 msg match { |
141 msg match { |
94 case elem @ XML.Elem(markup, Nil) => |
142 case elem @ XML.Elem(markup, Nil) => |
95 state.add_status(markup).add_markup("", Text.Info(command.proper_range, elem)) |
143 state. |
96 |
144 add_status(markup). |
|
145 add_markup(true, "", Text.Info(command.proper_range, elem)) |
97 case _ => |
146 case _ => |
98 System.err.println("Ignored status message: " + msg) |
147 System.err.println("Ignored status message: " + msg) |
99 state |
148 state |
100 }) |
149 }) |
101 |
150 |
111 case Some(chunk) => |
160 case Some(chunk) => |
112 chunk.decode(raw_range).try_restrict(chunk.range) match { |
161 chunk.decode(raw_range).try_restrict(chunk.range) match { |
113 case Some(range) => |
162 case Some(range) => |
114 if (!range.is_singularity) { |
163 if (!range.is_singularity) { |
115 val props = Position.purge(atts) |
164 val props = Position.purge(atts) |
116 state.add_markup(file_name, |
165 val info = Text.Info(range, XML.Elem(Markup(name, props), args)) |
117 Text.Info(range, XML.Elem(Markup(name, props), args))) |
166 state.add_markup(false, file_name, info) |
118 } |
167 } |
119 else state |
168 else state |
120 case None => bad(); state |
169 case None => bad(); state |
121 } |
170 } |
122 case None => bad(); state |
171 case None => bad(); state |
125 case XML.Elem(Markup(name, atts), args) |
174 case XML.Elem(Markup(name, atts), args) |
126 if !atts.exists({ case (a, _) => Markup.POSITION_PROPERTIES(a) }) => |
175 if !atts.exists({ case (a, _) => Markup.POSITION_PROPERTIES(a) }) => |
127 val range = command.proper_range |
176 val range = command.proper_range |
128 val props = Position.purge(atts) |
177 val props = Position.purge(atts) |
129 val info: Text.Markup = Text.Info(range, XML.Elem(Markup(name, props), args)) |
178 val info: Text.Markup = Text.Info(range, XML.Elem(Markup(name, props), args)) |
130 state.add_markup("", info) |
179 state.add_markup(false, "", info) |
131 |
180 |
132 case _ => /* FIXME bad(); */ state |
181 case _ => /* FIXME bad(); */ state |
133 } |
182 } |
134 }) |
183 }) |
135 case XML.Elem(Markup(name, props), body) => |
184 case XML.Elem(Markup(name, props), body) => |
141 var st = copy(results = results + (i -> message1)) |
190 var st = copy(results = results + (i -> message1)) |
142 if (Protocol.is_inlined(message)) { |
191 if (Protocol.is_inlined(message)) { |
143 for { |
192 for { |
144 (file_name, chunk) <- command.chunks |
193 (file_name, chunk) <- command.chunks |
145 range <- Protocol.message_positions(command.id, alt_id, chunk, message) |
194 range <- Protocol.message_positions(command.id, alt_id, chunk, message) |
146 } st = st.add_markup(file_name, Text.Info(range, message2)) |
195 } st = st.add_markup(false, file_name, Text.Info(range, message2)) |
147 } |
196 } |
148 st |
197 st |
149 |
198 |
150 case _ => |
199 case _ => |
151 System.err.println("Ignored message without serial number: " + message) |
200 System.err.println("Ignored message without serial number: " + message) |
155 |
204 |
156 def ++ (other: State): State = |
205 def ++ (other: State): State = |
157 copy( |
206 copy( |
158 status = other.status ::: status, |
207 status = other.status ::: status, |
159 results = results ++ other.results, |
208 results = results ++ other.results, |
160 markups = |
209 markups = markups ++ other.markups |
161 (markups.keySet ++ other.markups.keySet) |
|
162 .map(a => a -> (get_markup(a) ++ other.get_markup(a))).toMap |
|
163 ) |
210 ) |
164 } |
211 } |
165 |
212 |
166 |
213 |
167 |
214 |
322 |
369 |
323 |
370 |
324 /* accumulated results */ |
371 /* accumulated results */ |
325 |
372 |
326 val init_state: Command.State = |
373 val init_state: Command.State = |
327 Command.State(this, results = init_results, markups = Map("" -> init_markup)) |
374 Command.State(this, results = init_results, markups = Command.Markups.init(init_markup)) |
328 |
375 |
329 val empty_state: Command.State = Command.State(this) |
376 val empty_state: Command.State = Command.State(this) |
330 } |
377 } |