wenzelm@36676: /* Title: Pure/PIDE/command.scala wenzelm@36676: Author: Fabian Immler, TU Munich wenzelm@36676: Author: Makarius wenzelm@36676: wenzelm@36676: Prover commands with semantic state. wenzelm@36676: */ wenzelm@34407: wenzelm@34871: package isabelle wenzelm@34318: wenzelm@34451: wenzelm@34699: import scala.actors.Actor, Actor._ wenzelm@34497: import scala.collection.mutable wenzelm@34486: wenzelm@34451: wenzelm@34637: object Command wenzelm@34637: { wenzelm@34637: object Status extends Enumeration wenzelm@34637: { wenzelm@34318: val UNPROCESSED = Value("UNPROCESSED") wenzelm@34318: val FINISHED = Value("FINISHED") wenzelm@34318: val FAILED = Value("FAILED") wenzelm@36990: val UNDEFINED = Value("UNDEFINED") wenzelm@34318: } wenzelm@34707: wenzelm@37197: case class HighlightInfo(kind: String, sub_kind: Option[String]) { wenzelm@37197: override def toString = kind wenzelm@37197: } wenzelm@34717: case class TypeInfo(ty: String) wenzelm@34707: case class RefInfo(file: Option[String], line: Option[Int], wenzelm@38363: command_id: Option[Document.Command_ID], offset: Option[Int]) // FIXME Command_ID vs. Exec_ID !? wenzelm@38361: wenzelm@38361: wenzelm@38362: wenzelm@38361: /** accumulated results from prover **/ wenzelm@38361: wenzelm@38362: case class State( wenzelm@38361: val command: Command, wenzelm@38361: val status: Command.Status.Value, wenzelm@38361: val forks: Int, wenzelm@38361: val reverse_results: List[XML.Tree], wenzelm@38362: val markup: Markup_Text) wenzelm@38361: { wenzelm@38361: /* content */ wenzelm@38361: wenzelm@38362: lazy val results = reverse_results.reverse wenzelm@38361: wenzelm@38362: def add_result(result: XML.Tree): State = copy(reverse_results = result :: reverse_results) wenzelm@38361: wenzelm@38362: def add_markup(node: Markup_Tree): State = copy(markup = markup + node) wenzelm@38361: wenzelm@38361: wenzelm@38361: /* markup */ wenzelm@38361: wenzelm@38361: lazy val highlight: Markup_Text = wenzelm@38361: { wenzelm@38362: markup.filter(_.info match { wenzelm@38361: case Command.HighlightInfo(_, _) => true wenzelm@38361: case _ => false wenzelm@38361: }) wenzelm@38361: } wenzelm@38361: wenzelm@38361: private lazy val types: List[Markup_Node] = wenzelm@38362: markup.filter(_.info match { wenzelm@38361: case Command.TypeInfo(_) => true wenzelm@38361: case _ => false }).flatten wenzelm@38361: wenzelm@38426: def type_at(pos: Text.Offset): Option[String] = wenzelm@38361: { wenzelm@38426: types.find(t => t.range.start <= pos && pos < t.range.stop) match { wenzelm@38361: case Some(t) => wenzelm@38361: t.info match { wenzelm@38426: case Command.TypeInfo(ty) => Some(command.source(t.range) + " : " + ty) wenzelm@38361: case _ => None wenzelm@38361: } wenzelm@38361: case None => None wenzelm@38361: } wenzelm@38361: } wenzelm@38361: wenzelm@38361: private lazy val refs: List[Markup_Node] = wenzelm@38362: markup.filter(_.info match { wenzelm@38361: case Command.RefInfo(_, _, _, _) => true wenzelm@38361: case _ => false }).flatten wenzelm@38361: wenzelm@38426: def ref_at(pos: Text.Offset): Option[Markup_Node] = wenzelm@38426: refs.find(t => t.range.start <= pos && pos < t.range.stop) wenzelm@38361: wenzelm@38361: wenzelm@38361: /* message dispatch */ wenzelm@38361: wenzelm@38361: def accumulate(message: XML.Tree): Command.State = wenzelm@38361: message match { wenzelm@38361: case XML.Elem(Markup(Markup.STATUS, _), elems) => wenzelm@38361: (this /: elems)((state, elem) => wenzelm@38361: elem match { wenzelm@38362: case XML.Elem(Markup(Markup.UNPROCESSED, _), _) => state.copy(status = Command.Status.UNPROCESSED) wenzelm@38362: case XML.Elem(Markup(Markup.FINISHED, _), _) => state.copy(status = Command.Status.FINISHED) wenzelm@38362: case XML.Elem(Markup(Markup.FAILED, _), _) => state.copy(status = Command.Status.FAILED) wenzelm@38362: case XML.Elem(Markup(Markup.FORKED, _), _) => state.copy(forks = state.forks + 1) wenzelm@38362: case XML.Elem(Markup(Markup.JOINED, _), _) => state.copy(forks = state.forks - 1) wenzelm@38361: case _ => System.err.println("Ignored status message: " + elem); state wenzelm@38361: }) wenzelm@38361: wenzelm@38361: case XML.Elem(Markup(Markup.REPORT, _), elems) => wenzelm@38361: (this /: elems)((state, elem) => wenzelm@38361: elem match { wenzelm@38361: case XML.Elem(Markup(kind, atts), body) if Position.get_id(atts) == Some(command.id) => wenzelm@38361: atts match { wenzelm@38361: case Position.Range(begin, end) => wenzelm@38361: if (kind == Markup.ML_TYPING) { wenzelm@38361: val info = Pretty.string_of(body, margin = 40) wenzelm@38361: state.add_markup( wenzelm@38361: command.markup_node(begin - 1, end - 1, Command.TypeInfo(info))) wenzelm@38361: } wenzelm@38361: else if (kind == Markup.ML_REF) { wenzelm@38361: body match { wenzelm@38361: case List(XML.Elem(Markup(Markup.ML_DEF, props), _)) => wenzelm@38362: state.add_markup( wenzelm@38362: command.markup_node( wenzelm@38362: begin - 1, end - 1, wenzelm@38362: Command.RefInfo( wenzelm@38362: Position.get_file(props), wenzelm@38362: Position.get_line(props), wenzelm@38362: Position.get_id(props), wenzelm@38362: Position.get_offset(props)))) wenzelm@38361: case _ => state wenzelm@38361: } wenzelm@38361: } wenzelm@38361: else { wenzelm@38361: state.add_markup( wenzelm@38361: command.markup_node(begin - 1, end - 1, wenzelm@38361: Command.HighlightInfo(kind, Markup.get_string(Markup.KIND, atts)))) wenzelm@38361: } wenzelm@38361: case _ => state wenzelm@38361: } wenzelm@38361: case _ => System.err.println("Ignored report message: " + elem); state wenzelm@38361: }) wenzelm@38361: case _ => add_result(message) wenzelm@38361: } wenzelm@38361: } wenzelm@38367: wenzelm@38367: wenzelm@38367: /* unparsed dummy commands */ wenzelm@38367: wenzelm@38367: def unparsed(source: String) = wenzelm@38367: new Command(Document.NO_ID, List(Token(Token.Kind.UNPARSED, source))) wenzelm@34318: } wenzelm@34318: wenzelm@38361: wenzelm@34697: class Command( wenzelm@38150: val id: Document.Command_ID, wenzelm@38373: val span: List[Token]) wenzelm@34451: { wenzelm@34859: /* classification */ wenzelm@34500: wenzelm@36012: def is_command: Boolean = !span.isEmpty && span.head.is_command wenzelm@34865: def is_ignored: Boolean = span.forall(_.is_ignored) wenzelm@34859: def is_malformed: Boolean = !is_command && !is_ignored wenzelm@34859: wenzelm@38367: def is_unparsed = id == Document.NO_ID wenzelm@38367: wenzelm@36012: def name: String = if (is_command) span.head.content else "" wenzelm@37129: override def toString = wenzelm@37373: id + "/" + (if (is_command) name else if (is_ignored) "IGNORED" else "MALFORMED") wenzelm@34495: wenzelm@34859: wenzelm@34859: /* source text */ wenzelm@34451: wenzelm@34859: val source: String = span.map(_.source).mkString wenzelm@38426: def source(range: Text.Range): String = source.substring(range.start, range.stop) wenzelm@34859: def length: Int = source.length wenzelm@34855: wenzelm@34859: lazy val symbol_index = new Symbol.Index(source) immler@34593: wenzelm@34815: immler@34676: /* markup */ wenzelm@34508: wenzelm@34717: def markup_node(begin: Int, end: Int, info: Any): Markup_Tree = wenzelm@34699: { wenzelm@34703: val start = symbol_index.decode(begin) wenzelm@34703: val stop = symbol_index.decode(end) wenzelm@38426: new Markup_Tree(new Markup_Node(Text.Range(start, stop), info), Nil) wenzelm@34500: } wenzelm@38370: wenzelm@38370: wenzelm@38370: /* accumulated results */ wenzelm@38370: wenzelm@38415: val empty_state: Command.State = wenzelm@38370: Command.State(this, Command.Status.UNPROCESSED, 0, Nil, new Markup_Text(Nil, source)) immler@34676: }