Efficient scanning of literals.
authorwenzelm
Tue, 16 Jun 2009 15:25:32 +0200
changeset 31648 31b1f296515b
parent 31647 76d8c30a92c5
child 31649 a11ea667d676
Efficient scanning of literals.
src/Pure/General/scan.scala
src/Pure/IsaMakefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Pure/General/scan.scala	Tue Jun 16 15:25:32 2009 +0200
@@ -0,0 +1,82 @@
+/*  Title:      Pure/General/scan.scala
+    Author:     Makarius
+
+Efficient scanning of literals.
+*/
+
+package isabelle
+
+import scala.util.parsing.combinator.RegexParsers
+
+
+object Scan
+{
+
+  /* class Lexicon -- position tree */
+
+  case class Lexicon(val tab: Map[Char, (Boolean, Lexicon)])
+
+  val empty_lexicon = Lexicon(Map())
+
+  def is_literal(lx: Lexicon, str: CharSequence): Boolean =
+  {
+    val len = str.length
+    def is_lit(lexicon: Lexicon, i: Int): Boolean =
+      i < len && {
+        lexicon.tab.get(str.charAt(i)) match {
+          case Some((tip, lex)) => tip && i + 1 == len || is_lit(lex, i + 1)
+          case None => false
+        }
+      }
+    is_lit(lx, 0)
+  }
+
+  def extend_lexicon(lx: Lexicon, str: CharSequence): Lexicon =
+  {
+    val len = str.length
+    def ext(lexicon: Lexicon, i: Int): Lexicon =
+      if (i == len) lexicon
+      else {
+        val c = str.charAt(i)
+        val is_last = (i + 1 == len)
+        lexicon.tab.get(c) match {
+          case Some((tip, lex)) => Lexicon(lexicon.tab + (c -> (tip || is_last, ext(lex, i + 1))))
+          case None => Lexicon(lexicon.tab + (c -> (is_last, ext(empty_lexicon, i + 1))))
+        }
+      }
+    if (is_literal(lx, str)) lx else ext(lx, 0)
+  }
+
+}
+
+
+class Scan extends RegexParsers
+{
+  override val whiteSpace = "".r
+
+  def keyword(lx: Scan.Lexicon): Parser[String] = new Parser[String] {
+    def apply(in: Input) =
+    {
+      val source = in.source
+      val offset = in.offset
+      val len = source.length - offset
+
+      def scan(lexicon: Scan.Lexicon, i: Int, res: Int): Int =
+      {
+        if (i < len) {
+          lexicon.tab.get(source.charAt(offset + i)) match {
+            case Some((tip, lex)) => scan(lex, i + 1, if (tip) i + 1 else res)
+            case None => res
+          }
+        } else res
+      }
+      scan(lx, 0, 0) match {
+        case res if res > 0 =>
+          Success(source.subSequence(offset, res).toString, in.drop(res))
+        case _ => Failure("keyword expected", in)
+      }
+    }
+  }.named("keyword")
+
+}
+
--- a/src/Pure/IsaMakefile	Mon Jun 15 21:33:27 2009 +0200
+++ b/src/Pure/IsaMakefile	Tue Jun 16 15:25:32 2009 +0200
@@ -115,9 +115,9 @@
 ## Scala material
 
 SCALA_FILES = General/event_bus.scala General/markup.scala		\
-  General/position.scala General/swing.scala General/symbol.scala	\
-  General/xml.scala General/yxml.scala Isar/isar.scala			\
-  Isar/isar_document.scala Isar/outer_keyword.scala			\
+  General/position.scala General/scan.scala General/swing.scala		\
+  General/symbol.scala General/xml.scala General/yxml.scala		\
+  Isar/isar.scala Isar/isar_document.scala Isar/outer_keyword.scala	\
   System/cygwin.scala System/isabelle_process.scala			\
   System/isabelle_system.scala Thy/thy_header.scala			\
   Tools/isabelle_syntax.scala