back to liberal spaces of official syntax (in contrast to 4b190c763097), e.g. relevant for easychair.bib;
authorwenzelm
Mon, 06 Oct 2014 11:44:16 +0200
changeset 58590 472b9fbcc7f0
parent 58589 d9350ec0937e
child 58591 3c1a8c1c6b3b
back to liberal spaces of official syntax (in contrast to 4b190c763097), e.g. relevant for easychair.bib;
src/Pure/Tools/bibtex.scala
--- a/src/Pure/Tools/bibtex.scala	Mon Oct 06 10:24:51 2014 +0200
+++ b/src/Pure/Tools/bibtex.scala	Mon Oct 06 11:44:16 2014 +0200
@@ -187,7 +187,11 @@
   // context of partial line-oriented scans
   abstract class Line_Context
   case object Ignored extends Line_Context
-  case class Item(kind: String, delim: Delimited, right: String) extends Line_Context
+  case object At extends Line_Context
+  case class Item_Start(kind: String) extends Line_Context
+  case class Item_Open(kind: String, right: String) extends Line_Context
+  case class Item(kind: String, right: String, delim: Delimited) extends Line_Context
+
   case class Delimited(quoted: Boolean, depth: Int)
   val Closed = Delimited(false, 0)
 
@@ -205,7 +209,7 @@
     override val whiteSpace = "".r
 
     private val space = """[ \t\n\r]+""".r ^^ token(Token.Kind.SPACE)
-    private val strict_space = """[ \t]+""".r ^^ token(Token.Kind.SPACE)
+    private val spaces = rep(space)
 
 
     /* ignored text */
@@ -265,13 +269,10 @@
     private def recover_delimited: Parser[Token] =
       """(?m)["{][^@]*""".r ^^ token(Token.Kind.ERROR)
 
-    def delimited_line(item_ctxt: Item): Parser[(Chunk, Line_Context)] =
-      item_ctxt match {
-        case Item(kind, delim, _) =>
-          delimited_depth(delim) ^^ { case (s, delim1) =>
-            (Chunk(kind, List(Token(Token.Kind.STRING, s))), item_ctxt.copy(delim = delim1)) } |
-          recover_delimited ^^ { case a => (Chunk(kind, List(a)), Ignored) }
-        }
+    def delimited_line(ctxt: Item): Parser[(Chunk, Line_Context)] =
+      delimited_depth(ctxt.delim) ^^ { case (s, delim1) =>
+        (Chunk(ctxt.kind, List(Token(Token.Kind.STRING, s))), ctxt.copy(delim = delim1)) } |
+      recover_delimited ^^ { case a => (Chunk(ctxt.kind, List(a)), Ignored) }
 
 
     /* other tokens */
@@ -304,26 +305,33 @@
       }
 
     private val item_start =
-      at ~ rep(strict_space) ~ item_kind ~ rep(strict_space) ^^
+      at ~ spaces ~ item_kind ~ spaces ^^
         { case a ~ b ~ c ~ d => (c.source, List(a) ::: b ::: List(c) ::: d) }
 
-    private val item_name =
-      rep(strict_space) ~ identifier ^^
-        { case a ~ b => a ::: List(Token(Token.Kind.NAME, b)) }
+    private val item_name = identifier ^^ token(Token.Kind.NAME)
 
     private val item_body =
       delimited | (recover_delimited | other_token)
 
     private val item: Parser[Chunk] =
-      (item_start ~ left_brace ~ item_name ~ rep(item_body) ~ opt(right_brace) |
-       item_start ~ left_paren ~ item_name ~ rep(item_body) ~ opt(right_paren)) ^^
-        { case (kind, a) ~ b ~ c ~ d ~ e => Chunk(kind, a ::: List(b) ::: c ::: d ::: e.toList) }
+      (item_start ~ left_brace ~ spaces ~ item_name ~ rep(item_body) ~ opt(right_brace) |
+       item_start ~ left_paren ~ spaces ~ item_name ~ rep(item_body) ~ opt(right_paren)) ^^
+        { case (kind, a) ~ b ~ c ~ d ~ e ~ f =>
+            Chunk(kind, a ::: List(b) ::: c ::: List(d) ::: e ::: f.toList) }
+
+
+    /* chunks */
 
     private val recover_item: Parser[Chunk] =
       at ~ "(?m)[^@]*".r ^^ { case a ~ b => Chunk("", List(a, Token(Token.Kind.ERROR, b))) }
 
-
-    /* chunks */
+    private def item_body_line(ctxt: Item) =
+      if (ctxt.delim.depth > 0)
+        delimited_line(ctxt)
+      else
+        delimited_line(ctxt) |
+        other_token ^^ { case a => (Chunk(ctxt.kind, List(a)), ctxt) } |
+        ctxt.right ^^ { case a => (Chunk(ctxt.kind, List(keyword(a))), Ignored) }
 
     val chunk: Parser[Chunk] = ignored | (item | recover_item)
 
@@ -332,22 +340,30 @@
       ctxt match {
         case Ignored =>
           ignored_line |
-          item_start ~ (left_brace | left_paren) ~ opt(item_name) ^^
-            { case (kind, a) ~ b ~ c =>
-                val right = if (b.source == "{") "}" else ")"
-                val chunk = Chunk(kind, a ::: List(b) ::: (c getOrElse Nil))
-                (chunk, Item(kind, Closed, right)) } |
-          recover_item ^^ { case a => (a, Ignored) }
-        case item_ctxt @ Item(kind, delim, right) =>
-          if (delim.depth > 0)
-            delimited_line(item_ctxt) |
-            ignored_line
-          else {
-            delimited_line(item_ctxt) |
-            other_token ^^ { case a => (Chunk(kind, List(a)), ctxt) } |
-            right ^^ { case a => (Chunk(kind, List(keyword(a))), Ignored) } |
-            ignored_line
-          }
+          at ^^ { case a => (Chunk("", List(a)), At) }
+
+        case At =>
+          space ^^ { case a => (Chunk("", List(a)), ctxt) } |
+          item_kind ^^ { case a => (Chunk(a.source, List(a)), Item_Start(a.source)) } |
+          recover_item ^^ { case a => (a, Ignored) } |
+          ignored_line
+
+        case Item_Start(kind) =>
+          space ^^ { case a => (Chunk(kind, List(a)), ctxt) } |
+          left_brace ^^ { case a => (Chunk(kind, List(a)), Item_Open(kind, "}")) } |
+          left_paren ^^ { case a => (Chunk(kind, List(a)), Item_Open(kind, ")")) } |
+          ignored_line
+
+        case Item_Open(kind, right) =>
+          space ^^ { case a => (Chunk(kind, List(a)), ctxt) } |
+          item_name ^^ { case a => (Chunk(kind, List(a)), Item(kind, right, Closed)) } |
+          item_body_line(Item(kind, right, Closed)) |
+          ignored_line
+
+        case item_ctxt: Item =>
+          item_body_line(item_ctxt) |
+          ignored_line
+
         case _ => failure("")
       }
     }