9 |
9 |
10 |
10 |
11 import java.io.{InputStream, OutputStream, BufferedOutputStream, IOException} |
11 import java.io.{InputStream, OutputStream, BufferedOutputStream, IOException} |
12 |
12 |
13 |
13 |
14 object Prover |
14 object Prover { |
15 { |
|
16 /* messages */ |
15 /* messages */ |
17 |
16 |
18 sealed abstract class Message |
17 sealed abstract class Message |
19 type Receiver = Message => Unit |
18 type Receiver = Message => Unit |
20 |
19 |
21 class Input(val name: String, val args: List[String]) extends Message |
20 class Input(val name: String, val args: List[String]) extends Message { |
22 { |
|
23 override def toString: String = |
21 override def toString: String = |
24 XML.Elem(Markup(Markup.PROVER_COMMAND, List((Markup.NAME, name))), |
22 XML.Elem(Markup(Markup.PROVER_COMMAND, List((Markup.NAME, name))), |
25 args.flatMap(s => |
23 args.flatMap(s => |
26 List(XML.newline, XML.elem(Markup.PROVER_ARG, YXML.parse_body(s))))).toString |
24 List(XML.newline, XML.elem(Markup.PROVER_ARG, YXML.parse_body(s))))).toString |
27 } |
25 } |
28 |
26 |
29 class Output(val message: XML.Elem) extends Message |
27 class Output(val message: XML.Elem) extends Message { |
30 { |
|
31 def kind: String = message.markup.name |
28 def kind: String = message.markup.name |
32 def properties: Properties.T = message.markup.properties |
29 def properties: Properties.T = message.markup.properties |
33 def body: XML.Body = message.body |
30 def body: XML.Body = message.body |
34 |
31 |
35 def is_init: Boolean = kind == Markup.INIT |
32 def is_init: Boolean = kind == Markup.INIT |
39 def is_system: Boolean = kind == Markup.SYSTEM |
36 def is_system: Boolean = kind == Markup.SYSTEM |
40 def is_status: Boolean = kind == Markup.STATUS |
37 def is_status: Boolean = kind == Markup.STATUS |
41 def is_report: Boolean = kind == Markup.REPORT |
38 def is_report: Boolean = kind == Markup.REPORT |
42 def is_syslog: Boolean = is_init || is_exit || is_system || is_stderr |
39 def is_syslog: Boolean = is_init || is_exit || is_system || is_stderr |
43 |
40 |
44 override def toString: String = |
41 override def toString: String = { |
45 { |
|
46 val res = |
42 val res = |
47 if (is_status || is_report) message.body.map(_.toString).mkString |
43 if (is_status || is_report) message.body.map(_.toString).mkString |
48 else Pretty.string_of(message.body, metric = Symbol.Metric) |
44 else Pretty.string_of(message.body, metric = Symbol.Metric) |
49 if (properties.isEmpty) |
45 if (properties.isEmpty) |
50 kind + " [[" + res + "]]" |
46 kind + " [[" + res + "]]" |
63 case List(chunk) => chunk |
59 case List(chunk) => chunk |
64 case _ => throw new Malformed("single chunk expected: " + print) |
60 case _ => throw new Malformed("single chunk expected: " + print) |
65 } |
61 } |
66 |
62 |
67 class Protocol_Output(props: Properties.T, val chunks: List[Bytes]) |
63 class Protocol_Output(props: Properties.T, val chunks: List[Bytes]) |
68 extends Output(XML.Elem(Markup(Markup.PROTOCOL, props), Nil)) |
64 extends Output(XML.Elem(Markup(Markup.PROTOCOL, props), Nil)) { |
69 { |
|
70 def chunk: Bytes = the_chunk(chunks, toString) |
65 def chunk: Bytes = the_chunk(chunks, toString) |
71 lazy val text: String = chunk.text |
66 lazy val text: String = chunk.text |
72 } |
67 } |
73 } |
68 } |
74 |
69 |
75 |
70 |
76 class Prover( |
71 class Prover( |
77 receiver: Prover.Receiver, |
72 receiver: Prover.Receiver, |
78 cache: XML.Cache, |
73 cache: XML.Cache, |
79 channel: System_Channel, |
74 channel: System_Channel, |
80 process: Bash.Process) extends Protocol |
75 process: Bash.Process |
81 { |
76 ) extends Protocol { |
82 /** receiver output **/ |
77 /** receiver output **/ |
83 |
78 |
84 private def system_output(text: String): Unit = |
79 private def system_output(text: String): Unit = { |
85 { |
|
86 receiver(new Prover.Output(XML.Elem(Markup(Markup.SYSTEM, Nil), List(XML.Text(text))))) |
80 receiver(new Prover.Output(XML.Elem(Markup(Markup.SYSTEM, Nil), List(XML.Text(text))))) |
87 } |
81 } |
88 |
82 |
89 private def protocol_output(props: Properties.T, chunks: List[Bytes]): Unit = |
83 private def protocol_output(props: Properties.T, chunks: List[Bytes]): Unit = { |
90 { |
|
91 receiver(new Prover.Protocol_Output(props, chunks)) |
84 receiver(new Prover.Protocol_Output(props, chunks)) |
92 } |
85 } |
93 |
86 |
94 private def output(kind: String, props: Properties.T, body: XML.Body): Unit = |
87 private def output(kind: String, props: Properties.T, body: XML.Body): Unit = { |
95 { |
|
96 val main = XML.Elem(Markup(kind, props), Protocol_Message.clean_reports(body)) |
88 val main = XML.Elem(Markup(kind, props), Protocol_Message.clean_reports(body)) |
97 val reports = Protocol_Message.reports(props, body) |
89 val reports = Protocol_Message.reports(props, body) |
98 for (msg <- main :: reports) receiver(new Prover.Output(cache.elem(msg))) |
90 for (msg <- main :: reports) receiver(new Prover.Output(cache.elem(msg))) |
99 } |
91 } |
100 |
92 |
101 private def exit_message(result: Process_Result): Unit = |
93 private def exit_message(result: Process_Result): Unit = { |
102 { |
|
103 output(Markup.EXIT, Markup.Process_Result(result), |
94 output(Markup.EXIT, Markup.Process_Result(result), |
104 List(XML.Text(result.print_return_code))) |
95 List(XML.Text(result.print_return_code))) |
105 } |
96 } |
106 |
97 |
107 |
98 |
113 val rc = process.join() |
104 val rc = process.join() |
114 val timing = process.get_timing |
105 val timing = process.get_timing |
115 Process_Result(rc, timing = timing) |
106 Process_Result(rc, timing = timing) |
116 } |
107 } |
117 |
108 |
118 private def terminate_process(): Unit = |
109 private def terminate_process(): Unit = { |
119 { |
|
120 try { process.terminate() } |
110 try { process.terminate() } |
121 catch { |
111 catch { |
122 case exn @ ERROR(_) => system_output("Failed to terminate prover process: " + exn.getMessage) |
112 case exn @ ERROR(_) => system_output("Failed to terminate prover process: " + exn.getMessage) |
123 } |
113 } |
124 } |
114 } |
125 |
115 |
126 private val process_manager = Isabelle_Thread.fork(name = "process_manager") |
116 private val process_manager = Isabelle_Thread.fork(name = "process_manager") { |
127 { |
|
128 val stdout = physical_output(false) |
117 val stdout = physical_output(false) |
129 |
118 |
130 val (startup_failed, startup_errors) = |
119 val (startup_failed, startup_errors) = { |
131 { |
|
132 var finished: Option[Boolean] = None |
120 var finished: Option[Boolean] = None |
133 val result = new StringBuilder(100) |
121 val result = new StringBuilder(100) |
134 while (finished.isEmpty && (process.stderr.ready || !process_result.is_finished)) { |
122 while (finished.isEmpty && (process.stderr.ready || !process_result.is_finished)) { |
135 while (finished.isEmpty && process.stderr.ready) { |
123 while (finished.isEmpty && process.stderr.ready) { |
136 try { |
124 try { |
195 |
182 |
196 private var command_input: Option[Consumer_Thread[List[Bytes]]] = None |
183 private var command_input: Option[Consumer_Thread[List[Bytes]]] = None |
197 |
184 |
198 private def command_input_close(): Unit = command_input.foreach(_.shutdown()) |
185 private def command_input_close(): Unit = command_input.foreach(_.shutdown()) |
199 |
186 |
200 private def command_input_init(raw_stream: OutputStream): Unit = |
187 private def command_input_init(raw_stream: OutputStream): Unit = { |
201 { |
|
202 val name = "command_input" |
188 val name = "command_input" |
203 val stream = new BufferedOutputStream(raw_stream) |
189 val stream = new BufferedOutputStream(raw_stream) |
204 command_input = |
190 command_input = |
205 Some( |
191 Some( |
206 Consumer_Thread.fork(name)( |
192 Consumer_Thread.fork(name)( |
221 } |
207 } |
222 |
208 |
223 |
209 |
224 /* physical output */ |
210 /* physical output */ |
225 |
211 |
226 private def physical_output(err: Boolean): Thread = |
212 private def physical_output(err: Boolean): Thread = { |
227 { |
|
228 val (name, reader, markup) = |
213 val (name, reader, markup) = |
229 if (err) ("standard_error", process.stderr, Markup.STDERR) |
214 if (err) ("standard_error", process.stderr, Markup.STDERR) |
230 else ("standard_output", process.stdout, Markup.STDOUT) |
215 else ("standard_output", process.stdout, Markup.STDOUT) |
231 |
216 |
232 Isabelle_Thread.fork(name = name) { |
217 Isabelle_Thread.fork(name = name) { |
310 } |
294 } |
311 thread.send(Bytes(name) :: args) |
295 thread.send(Bytes(name) :: args) |
312 case _ => error("Inactive prover input thread for command " + quote(name)) |
296 case _ => error("Inactive prover input thread for command " + quote(name)) |
313 } |
297 } |
314 |
298 |
315 def protocol_command_args(name: String, args: List[String]): Unit = |
299 def protocol_command_args(name: String, args: List[String]): Unit = { |
316 { |
|
317 receiver(new Prover.Input(name, args)) |
300 receiver(new Prover.Input(name, args)) |
318 protocol_command_raw(name, args.map(Bytes(_))) |
301 protocol_command_raw(name, args.map(Bytes(_))) |
319 } |
302 } |
320 |
303 |
321 def protocol_command(name: String, args: String*): Unit = |
304 def protocol_command(name: String, args: String*): Unit = |