273 range: Text.Range, |
273 range: Text.Range, |
274 elements: Option[Set[String]], |
274 elements: Option[Set[String]], |
275 result: Command.State => PartialFunction[Text.Markup, A]): Stream[Text.Info[A]] |
275 result: Command.State => PartialFunction[Text.Markup, A]): Stream[Text.Info[A]] |
276 } |
276 } |
277 |
277 |
278 type Assign = List[(Document_ID.Command, List[Document_ID.Exec])] // exec state assignment |
278 type Assign_Update = |
|
279 List[(Document_ID.Command, List[Document_ID.Exec])] // update of exec state assignment |
279 |
280 |
280 object State |
281 object State |
281 { |
282 { |
282 class Fail(state: State) extends Exception |
283 class Fail(state: State) extends Exception |
283 |
284 |
291 val is_finished: Boolean = false) |
292 val is_finished: Boolean = false) |
292 { |
293 { |
293 def check_finished: Assignment = { require(is_finished); this } |
294 def check_finished: Assignment = { require(is_finished); this } |
294 def unfinished: Assignment = new Assignment(command_execs, false) |
295 def unfinished: Assignment = new Assignment(command_execs, false) |
295 |
296 |
296 def assign( |
297 def assign(update: Assign_Update): Assignment = |
297 add_command_execs: List[(Document_ID.Command, List[Document_ID.Exec])]): Assignment = |
|
298 { |
298 { |
299 require(!is_finished) |
299 require(!is_finished) |
300 val command_execs1 = |
300 val command_execs1 = |
301 (command_execs /: add_command_execs) { |
301 (command_execs /: update) { |
302 case (res, (command_id, Nil)) => res - command_id |
302 case (res, (command_id, exec_ids)) => |
303 case (res, assign) => res + assign |
303 if (exec_ids.isEmpty) res - command_id |
|
304 else res + (command_id -> exec_ids) |
304 } |
305 } |
305 new Assignment(command_execs1, true) |
306 new Assignment(command_execs1, true) |
306 } |
307 } |
307 } |
308 } |
308 |
309 |
309 val init: State = |
310 val init: State = |
310 State().define_version(Version.init, Assignment.init).assign(Version.init.id)._2 |
311 State().define_version(Version.init, Assignment.init).assign(Version.init.id, Nil)._2 |
311 } |
312 } |
312 |
313 |
313 final case class State private( |
314 final case class State private( |
314 val versions: Map[Document_ID.Version, Version] = Map.empty, |
315 val versions: Map[Document_ID.Version, Version] = Map.empty, |
315 val commands: Map[Document_ID.Command, Command.State] = Map.empty, // static markup from define_command |
316 val commands: Map[Document_ID.Command, Command.State] = Map.empty, // static markup from define_command |
344 } |
345 } |
345 |
346 |
346 def the_version(id: Document_ID.Version): Version = versions.getOrElse(id, fail) |
347 def the_version(id: Document_ID.Version): Version = versions.getOrElse(id, fail) |
347 def the_read_state(id: Document_ID.Command): Command.State = commands.getOrElse(id, fail) |
348 def the_read_state(id: Document_ID.Command): Command.State = commands.getOrElse(id, fail) |
348 def the_exec_state(id: Document_ID.Exec): Command.State = execs.getOrElse(id, fail) |
349 def the_exec_state(id: Document_ID.Exec): Command.State = execs.getOrElse(id, fail) |
349 def the_assignment(version: Version): State.Assignment = |
350 def the_assignment(version: Version): State.Assignment = assignments.getOrElse(version.id, fail) |
350 assignments.getOrElse(version.id, fail) |
|
351 |
351 |
352 def accumulate(id: Document_ID.Generic, message: XML.Elem): (Command.State, State) = |
352 def accumulate(id: Document_ID.Generic, message: XML.Elem): (Command.State, State) = |
353 execs.get(id) match { |
353 execs.get(id) match { |
354 case Some(st) => |
354 case Some(st) => |
355 val new_st = st + (id, message) |
355 val new_st = st + (id, message) |
361 (new_st, copy(commands = commands + (id -> new_st))) |
361 (new_st, copy(commands = commands + (id -> new_st))) |
362 case None => fail |
362 case None => fail |
363 } |
363 } |
364 } |
364 } |
365 |
365 |
366 def assign(id: Document_ID.Version, command_execs: Assign = Nil): (List[Command], State) = |
366 def assign(id: Document_ID.Version, update: Assign_Update): (List[Command], State) = |
367 { |
367 { |
368 val version = the_version(id) |
368 val version = the_version(id) |
369 |
369 |
370 val (changed_commands, new_execs) = |
370 val (changed_commands, new_execs) = |
371 ((Nil: List[Command], execs) /: command_execs) { |
371 ((Nil: List[Command], execs) /: update) { |
372 case ((commands1, execs1), (cmd_id, exec)) => |
372 case ((commands1, execs1), (cmd_id, exec)) => |
373 val st1 = the_read_state(cmd_id) |
373 val st1 = the_read_state(cmd_id) |
374 val command = st1.command |
374 val command = st1.command |
375 val st0 = command.empty_state |
375 val st0 = command.empty_state |
376 |
376 |
382 execs1 + (eval_id -> execs.getOrElse(eval_id, st1)) ++ |
382 execs1 + (eval_id -> execs.getOrElse(eval_id, st1)) ++ |
383 print_ids.iterator.map(id => id -> execs.getOrElse(id, st0)) |
383 print_ids.iterator.map(id => id -> execs.getOrElse(id, st0)) |
384 } |
384 } |
385 (commands2, execs2) |
385 (commands2, execs2) |
386 } |
386 } |
387 val new_assignment = the_assignment(version).assign(command_execs) |
387 val new_assignment = the_assignment(version).assign(update) |
388 val new_state = copy(assignments = assignments + (id -> new_assignment), execs = new_execs) |
388 val new_state = copy(assignments = assignments + (id -> new_assignment), execs = new_execs) |
389 |
389 |
390 (changed_commands, new_state) |
390 (changed_commands, new_state) |
391 } |
391 } |
392 |
392 |