src/Pure/Tools/bibtex.scala
author wenzelm
Thu, 02 Oct 2014 11:54:30 +0200
changeset 58523 937c479e62fe
child 58524 f805b366a497
permissions -rw-r--r--
some support for bibtex files;
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
58523
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
     1
/*  Title:      Pure/Tools/bibtex.scala
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
     2
    Author:     Makarius
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
     3
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
     4
Some support for bibtex files.
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
     5
*/
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
     6
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
     7
package isabelle
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
     8
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
     9
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    10
import scala.util.parsing.input.{Reader, CharSequenceReader}
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    11
import scala.util.parsing.combinator.RegexParsers
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    12
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    13
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    14
object Bibtex
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    15
{
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    16
  /** content **/
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    17
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    18
  val months = List(
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    19
    "jan",
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    20
    "feb",
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    21
    "mar",
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    22
    "apr",
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    23
    "may",
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    24
    "jun",
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    25
    "jul",
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    26
    "aug",
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    27
    "sep",
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    28
    "oct",
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    29
    "nov",
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    30
    "dec")
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    31
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    32
  val commands = List("preamble", "string")
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    33
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    34
  sealed case class Entry_Type(
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    35
    required: List[String],
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    36
    optional_crossref: List[String],
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    37
    optional: List[String])
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    38
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    39
  val entries =
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    40
    Map[String, Entry_Type](
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    41
      "Article" ->
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    42
        Entry_Type(
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    43
          List("author", "title"),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    44
          List("journal", "year"),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    45
          List("volume", "number", "pages", "month", "note")),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    46
      "InProceedings" ->
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    47
        Entry_Type(
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    48
          List("author", "title"),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    49
          List("booktitle", "year"),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    50
          List("editor", "volume", "number", "series", "pages", "month", "address",
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    51
            "organization", "publisher", "note")),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    52
      "InCollection" ->
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    53
        Entry_Type(
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    54
          List("author", "title", "booktitle"),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    55
          List("publisher", "year"),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    56
          List("editor", "volume", "number", "series", "type", "chapter", "pages",
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    57
            "edition", "month", "address", "note")),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    58
      "InBook" ->
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    59
        Entry_Type(
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    60
         List("author", "editor", "title", "chapter"),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    61
         List("publisher", "year"),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    62
         List("volume", "number", "series", "type", "address", "edition", "month", "pages", "note")),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    63
      "Proceedings" ->
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    64
        Entry_Type(
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    65
          List("title", "year"),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    66
          List(),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    67
          List("booktitle", "editor", "volume", "number", "series", "address", "month",
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    68
            "organization", "publisher", "note")),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    69
      "Book" ->
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    70
        Entry_Type(
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    71
          List("author", "editor", "title"),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    72
          List("publisher", "year"),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    73
          List("volume", "number", "series", "address", "edition", "month", "note")),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    74
      "Booklet" ->
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    75
        Entry_Type(
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    76
          List("title"),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    77
          List(),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    78
          List("author", "howpublished", "address", "month", "year", "note")),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    79
      "PhdThesis" ->
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    80
        Entry_Type(
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    81
          List("author", "title", "school", "year"),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    82
          List(),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    83
          List("type", "address", "month", "note")),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    84
      "MastersThesis" ->
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    85
        Entry_Type(
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    86
          List("author", "title", "school", "year"),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    87
          List(),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    88
          List("type", "address", "month", "note")),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    89
      "TechReport" ->
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    90
        Entry_Type(
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    91
          List("author", "title", "institution", "year"),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    92
          List(),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    93
          List("type", "number", "address", "month", "note")),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    94
      "Manual" ->
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    95
        Entry_Type(
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    96
          List("title"),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    97
          List(),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    98
          List("author", "organization", "address", "edition", "month", "year", "note")),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
    99
      "Unpublished" ->
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   100
        Entry_Type(
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   101
          List("author", "title", "note"),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   102
          List(),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   103
          List("month", "year")),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   104
      "Misc" ->
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   105
        Entry_Type(
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   106
          List(),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   107
          List(),
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   108
          List("author", "title", "howpublished", "month", "year", "note")))
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   109
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   110
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   111
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   112
  /** tokens and chunks **/
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   113
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   114
  object Token
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   115
  {
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   116
    object Kind extends Enumeration
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   117
    {
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   118
      val KEYWORD = Value("keyword")
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   119
      val NAT = Value("natural number")
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   120
      val IDENT = Value("identifier")
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   121
      val STRING = Value("string")
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   122
      val SPACE = Value("white space")
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   123
      val ERROR = Value("bad input")
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   124
    }
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   125
  }
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   126
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   127
  sealed case class Token(kind: Token.Kind.Value, val source: String)
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   128
  {
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   129
    def is_space: Boolean = kind == Token.Kind.SPACE
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   130
    def is_error: Boolean = kind == Token.Kind.ERROR
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   131
  }
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   132
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   133
  abstract class Chunk
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   134
  case class Ignored(source: String) extends Chunk
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   135
  case class Malformed(source: String) extends Chunk
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   136
  case class Item(tokens: List[Token]) extends Chunk
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   137
  {
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   138
    val name: String =
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   139
      tokens match {
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   140
        case Token(Token.Kind.KEYWORD, "@") :: body
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   141
        if !body.isEmpty && !body.exists(_.is_error) =>
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   142
          (body.filterNot(_.is_space), body.last) match {
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   143
            case (Token(Token.Kind.IDENT, id) :: Token(Token.Kind.KEYWORD, "{") :: _,
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   144
                  Token(Token.Kind.KEYWORD, "}")) => id
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   145
            case (Token(Token.Kind.IDENT, id) :: Token(Token.Kind.KEYWORD, "(") :: _,
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   146
                  Token(Token.Kind.KEYWORD, ")")) => id
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   147
            case _ => ""
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   148
          }
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   149
        case _ => ""
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   150
      }
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   151
    val entry_name: String = if (commands.contains(name.toLowerCase)) "" else name
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   152
    def is_wellformed: Boolean = name != ""
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   153
  }
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   154
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   155
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   156
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   157
  /** parsing **/
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   158
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   159
  // context of partial line-oriented scans
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   160
  abstract class Line_Context
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   161
  case class Delimited(quoted: Boolean, depth: Int) extends Line_Context
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   162
  val Finished = Delimited(false, 0)
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   163
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   164
  private def token(kind: Token.Kind.Value)(source: String): Token = Token(kind, source)
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   165
  private def keyword(source: String): Token = Token(Token.Kind.KEYWORD, source)
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   166
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   167
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   168
  // See also http://ctan.org/tex-archive/biblio/bibtex/base/bibtex.web
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   169
  // module @<Scan for and process a \.{.bib} command or database entry@>.
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   170
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   171
  object Parsers extends RegexParsers
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   172
  {
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   173
    /* white space and comments */
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   174
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   175
    override val whiteSpace = "".r
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   176
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   177
    private val space = """[ \t\n\r]+""".r ^^ token(Token.Kind.SPACE)
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   178
    private val spaces = rep(space)
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   179
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   180
    private val ignored =
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   181
      rep1("""(?mi)([^@]+|@[ \t\n\r]*comment)""".r) ^^ { case ss => Ignored(ss.mkString) }
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   182
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   183
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   184
    /* delimited string: outermost "..." or {...} and body with balanced {...} */
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   185
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   186
    private def delimited_depth(delim: Delimited): Parser[(String, Delimited)] =
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   187
      new Parser[(String, Delimited)]
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   188
      {
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   189
        require(if (delim.quoted) delim.depth > 0 else delim.depth >= 0)
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   190
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   191
        def apply(in: Input) =
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   192
        {
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   193
          val start = in.offset
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   194
          val end = in.source.length
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   195
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   196
          var i = start
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   197
          var q = delim.quoted
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   198
          var d = delim.depth
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   199
          var finished = false
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   200
          while (!finished && i < end) {
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   201
            val c = in.source.charAt(i)
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   202
            if (c == '"' && d == 0) { i += 1; d = 1; q = true }
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   203
            else if (c == '"' && d == 1) { i += 1; d = 0; q = false; finished = true }
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   204
            else if (c == '{') { i += 1; d += 1 }
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   205
            else if (c == '}' && d > 0) { i += 1; d -= 1; if (d == 0) finished = true }
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   206
            else if (d > 0) i += 1
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   207
            else finished = true
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   208
          }
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   209
          if (i == start) Failure("bad input", in)
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   210
          else
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   211
            Success((in.source.subSequence(start, i).toString,
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   212
              Delimited(q, d)), in.drop(i - start))
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   213
        }
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   214
      }.named("delimited_depth")
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   215
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   216
    private def delimited: Parser[String] =
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   217
      delimited_depth(Finished) ^? { case (x, delim) if delim == Finished => x }
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   218
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   219
    private def delimited_line(ctxt: Line_Context): Parser[(String, Line_Context)] =
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   220
    {
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   221
      ctxt match {
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   222
        case delim: Delimited => delimited_depth(delim)
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   223
        case _ => failure("")
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   224
      }
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   225
    }
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   226
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   227
    private val recover_delimited: Parser[String] =
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   228
      delimited_depth(Finished) ^^ (_._1)
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   229
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   230
    private val delimited_token =
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   231
      delimited ^^ token(Token.Kind.STRING) |
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   232
      recover_delimited ^^ token(Token.Kind.ERROR)
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   233
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   234
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   235
    /* other tokens */
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   236
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   237
    private val at = "@" ^^ keyword
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   238
    private val left_brace = "{" ^^ keyword
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   239
    private val right_brace = "}" ^^ keyword
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   240
    private val left_paren = "(" ^^ keyword
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   241
    private val right_paren = ")" ^^ keyword
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   242
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   243
    private val nat = "[0-9]+".r ^^ token(Token.Kind.NAT)
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   244
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   245
    private val ident =
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   246
      """[\x21-\x7f&&[^"#%'(),={}0-9]][\x21-\x7f&&[^"#%'(),={}]]*""".r ^^ token(Token.Kind.IDENT)
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   247
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   248
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   249
    /* chunks */
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   250
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   251
    private val item_start =
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   252
      at ~ spaces ~ ident ~ spaces ^^
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   253
        { case a ~ b ~ c ~ d => List(a) ::: b ::: List(c) ::: d }
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   254
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   255
    private val body_token = delimited_token | ("[=#,]".r ^^ keyword | (nat | (ident | space)))
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   256
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   257
    private val item =
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   258
      (item_start ~ left_brace ~ rep(body_token) ~ opt(right_brace) |
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   259
       item_start ~ left_paren ~ rep(body_token) ~ opt(right_paren)) ^^
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   260
        { case a ~ b ~ c ~ d => Item(a ::: List(b) ::: c ::: d.toList) }
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   261
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   262
    private val recover_item = "(?m)@[^@]+".r ^^ (s => Malformed(s))
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   263
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   264
    val chunks: Parser[List[Chunk]] = rep(ignored | (item | recover_item))
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   265
  }
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   266
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   267
  def parse(input: CharSequence): List[Chunk] =
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   268
  {
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   269
    val in: Reader[Char] = new CharSequenceReader(input)
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   270
    Parsers.parseAll(Parsers.chunks, in) match {
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   271
      case Parsers.Success(result, _) => result
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   272
      case _ => error("Unexpected failure of tokenizing input:\n" + input.toString)
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   273
    }
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   274
  }
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   275
}
937c479e62fe some support for bibtex files;
wenzelm
parents:
diff changeset
   276