src/Pure/General/toml.scala
author wenzelm
Fri, 24 Nov 2023 11:33:53 +0100
changeset 79046 926fc9ca7360
parent 79007 eed4ca224c9c
child 80058 68f6b29ae066
permissions -rw-r--r--
tuned;
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
     1
/*  Title:      Pure/General/toml.scala
78317
fcabbb45b272 tuned whitespace;
wenzelm
parents: 78316
diff changeset
     2
    Author:     Fabian Huch, TU Muenchen
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
     3
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
     4
Support for TOML: https://toml.io/en/v1.0.0
78317
fcabbb45b272 tuned whitespace;
wenzelm
parents: 78316
diff changeset
     5
*/
fcabbb45b272 tuned whitespace;
wenzelm
parents: 78316
diff changeset
     6
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
     7
package isabelle
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
     8
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
     9
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    10
import TOML.Parse_Context.Seen
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    11
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    12
import java.lang.Long.parseLong
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    13
import java.lang.{String => Str}
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    14
import java.time.{LocalDate, LocalDateTime, LocalTime, OffsetDateTime}
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    15
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    16
import scala.{Boolean => Bool}
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    17
import scala.collection.immutable.ListMap
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    18
import scala.reflect.{ClassTag, classTag}
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    19
import scala.util.Try
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    20
import scala.util.matching.Regex
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    21
import scala.util.parsing.combinator
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    22
import scala.util.parsing.combinator.lexical.Scanners
78981
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
    23
import scala.util.parsing.input
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
    24
import scala.util.parsing.input.Positional
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    25
import scala.util.parsing.input.CharArrayReader.EofCh
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    26
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    27
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    28
object TOML {
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    29
  /* typed representation and access */
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    30
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    31
  type Key = Str
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    32
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    33
  sealed trait T
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    34
  case class String(rep: Str) extends T
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    35
  case class Integer(rep: Long) extends T
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    36
  case class Float(rep: Double) extends T
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    37
  case class Boolean(rep: Bool) extends T
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    38
  case class Offset_Date_Time(rep: OffsetDateTime) extends T
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    39
  case class Local_Date_Time(rep: LocalDateTime) extends T
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    40
  case class Local_Date(rep: LocalDate) extends T
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    41
  case class Local_Time(rep: LocalTime) extends T
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    42
78941
bc7b7357f4bc clarified signature: more operations;
wenzelm
parents: 78939
diff changeset
    43
  object Scalar {
bc7b7357f4bc clarified signature: more operations;
wenzelm
parents: 78939
diff changeset
    44
    def unapply(t: T): Option[Str] =
bc7b7357f4bc clarified signature: more operations;
wenzelm
parents: 78939
diff changeset
    45
      t match {
bc7b7357f4bc clarified signature: more operations;
wenzelm
parents: 78939
diff changeset
    46
        case s: String => Some(s.rep)
bc7b7357f4bc clarified signature: more operations;
wenzelm
parents: 78939
diff changeset
    47
        case i: Integer => Some(i.rep.toString)
bc7b7357f4bc clarified signature: more operations;
wenzelm
parents: 78939
diff changeset
    48
        case f: Float => Some(f.rep.toString)
bc7b7357f4bc clarified signature: more operations;
wenzelm
parents: 78939
diff changeset
    49
        case b: Boolean => Some(b.rep.toString)
bc7b7357f4bc clarified signature: more operations;
wenzelm
parents: 78939
diff changeset
    50
        case o: Offset_Date_Time => Some(o.rep.toString)
bc7b7357f4bc clarified signature: more operations;
wenzelm
parents: 78939
diff changeset
    51
        case l: Local_Date_Time => Some(l.rep.toString)
bc7b7357f4bc clarified signature: more operations;
wenzelm
parents: 78939
diff changeset
    52
        case l: Local_Date => Some(l.rep.toString)
bc7b7357f4bc clarified signature: more operations;
wenzelm
parents: 78939
diff changeset
    53
        case l: Local_Time => Some(l.rep.toString)
bc7b7357f4bc clarified signature: more operations;
wenzelm
parents: 78939
diff changeset
    54
        case _ => None
bc7b7357f4bc clarified signature: more operations;
wenzelm
parents: 78939
diff changeset
    55
      }
bc7b7357f4bc clarified signature: more operations;
wenzelm
parents: 78939
diff changeset
    56
  }
bc7b7357f4bc clarified signature: more operations;
wenzelm
parents: 78939
diff changeset
    57
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    58
  class Array private(private val rep: List[T]) extends T {
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    59
    override def hashCode(): Int = rep.hashCode()
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    60
    override def equals(that: Any): Bool = that match {
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    61
      case other: Array => rep == other.rep
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    62
      case _ => false
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    63
    }
78978
80fda74a045d clarified toString for toml objects;
Fabian Huch <huch@in.tum.de>
parents: 78948
diff changeset
    64
    override def toString: Str = "Array(" + length.toString + ")"
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    65
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    66
    class Values[A](pf: PartialFunction[T, A]) { def values: List[A] = rep.collect(pf).reverse }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    67
    lazy val string = new Values({ case s: String => s })
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    68
    lazy val integer = new Values({ case i: Integer => i })
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    69
    lazy val float = new Values({ case f: Float => f })
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    70
    lazy val boolean = new Values({ case b: Boolean => b })
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    71
    lazy val offset_date_time = new Values({ case o: Offset_Date_Time => o })
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    72
    lazy val local_date_time = new Values({ case l: Local_Date_Time => l })
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    73
    lazy val local_date = new Values({ case l: Local_Date => l })
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    74
    lazy val local_time = new Values({ case l: Local_Time => l })
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    75
    lazy val array = new Values({ case a: Array => a })
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    76
    lazy val table = new Values({ case t: Table => t })
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    77
    lazy val any = new Values({ case t => t })
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    78
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    79
    def +(elem: T): Array = new Array(elem :: rep)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    80
    def ++(other: Array): Array = new Array(other.rep ::: rep)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    81
    def length: Int = rep.length
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    82
    def is_empty: Bool = rep.isEmpty
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    83
  }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    84
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    85
  object Array {
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    86
    def apply(elems: Iterable[T]): Array = new Array(elems.toList.reverse)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    87
    def apply(elems: T*): Array = Array(elems)
78919
7847cbfe3a62 more operations;
wenzelm
parents: 78917
diff changeset
    88
    val empty: Array = apply()
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    89
  }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    90
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    91
  class Table private(private val rep: Map[Key, T]) extends T {
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    92
    override def hashCode(): Int = rep.hashCode()
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    93
    override def equals(that: Any): Bool =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    94
      that match {
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    95
        case other: Table => rep == other.rep
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    96
        case _ => false
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
    97
      }
78978
80fda74a045d clarified toString for toml objects;
Fabian Huch <huch@in.tum.de>
parents: 78948
diff changeset
    98
    override def toString: Str =
80fda74a045d clarified toString for toml objects;
Fabian Huch <huch@in.tum.de>
parents: 78948
diff changeset
    99
      rep.map {
80fda74a045d clarified toString for toml objects;
Fabian Huch <huch@in.tum.de>
parents: 78948
diff changeset
   100
        case (k, t: Table) => k + "(" + t.domain.size + ")"
80fda74a045d clarified toString for toml objects;
Fabian Huch <huch@in.tum.de>
parents: 78948
diff changeset
   101
        case (k, a: Array) => k + "(" + a.length + ")"
80fda74a045d clarified toString for toml objects;
Fabian Huch <huch@in.tum.de>
parents: 78948
diff changeset
   102
        case (k, _) => k
80fda74a045d clarified toString for toml objects;
Fabian Huch <huch@in.tum.de>
parents: 78948
diff changeset
   103
      }.mkString("Table(", ", ", ")")
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   104
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   105
    class Value[A: ClassTag](pf: PartialFunction[T, A]) {
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   106
      def values: List[(Key, A)] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   107
        rep.toList.collect { case (k, v) if pf.isDefinedAt(v) => k -> pf(v) }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   108
      def get(k: Key): Option[A] = rep.get(k).flatMap(v => PartialFunction.condOpt(v)(pf))
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   109
      def apply(k: Key): A =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   110
        rep.get(k) match {
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   111
          case Some(v) => PartialFunction.condOpt(v)(pf) match {
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   112
            case Some(value) => value
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   113
            case None =>
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   114
              error("Expected" + classTag[A].runtimeClass.getName +
79003
9d1c4824a055 clarified toml keys formatting vs. toString;
Fabian Huch <huch@in.tum.de>
parents: 79002
diff changeset
   115
                ", got " + v.getClass.getSimpleName + " for key " + quote(k))
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   116
          }
79003
9d1c4824a055 clarified toml keys formatting vs. toString;
Fabian Huch <huch@in.tum.de>
parents: 79002
diff changeset
   117
          case None => error("Key " + quote(k) + " does not exist")
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   118
        }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   119
    }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   120
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   121
    lazy val string = new Value({ case s: String => s })
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   122
    lazy val integer = new Value({ case i: Integer => i })
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   123
    lazy val float = new Value({ case f: Float => f })
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   124
    lazy val boolean = new Value({ case b: Boolean => b })
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   125
    lazy val offset_date_time = new Value({ case o: Offset_Date_Time => o })
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   126
    lazy val local_date_time = new Value({ case l: Local_Date_Time => l })
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   127
    lazy val local_date = new Value({ case l: Local_Date => l })
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   128
    lazy val local_time = new Value({ case l: Local_Time => l })
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   129
    lazy val array = new Value({ case a: Array => a })
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   130
    lazy val table = new Value({ case t: Table => t })
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   131
    lazy val any = new Value({ case t => t })
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   132
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   133
    def +(elem: (Key, T)): Table = {
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   134
      val (k, v) = elem
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   135
      val v1 = rep.get(k) match {
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   136
        case None => v
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   137
        case Some(v0) =>
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   138
          (v0, v) match {
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   139
            case (t0: Table, t: Table) => t0 ++ t
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   140
            case (a0: Array, a: Array) => a0 ++ a
78979
d5ce982ae60f allow re-defining keys in toml object (already checked during parse time);
Fabian Huch <huch@in.tum.de>
parents: 78978
diff changeset
   141
            case _ => v
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   142
          }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   143
      }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   144
      new Table(rep + (k -> v1))
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   145
    }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   146
    def -(k: Key): Table = new Table(rep - k)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   147
    def ++(other: Table): Table =  other.rep.foldLeft(this)(_ + _)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   148
    def domain: Set[Key] = rep.keySet
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   149
    def is_empty: Bool = rep.isEmpty
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   150
  }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   151
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   152
  object Table {
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   153
    def apply(elems: Iterable[(Key, T)]): Table = elems.foldLeft(new Table(ListMap.empty))(_ + _)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   154
    def apply(elems: (Key, T)*): Table = Table(elems)
78919
7847cbfe3a62 more operations;
wenzelm
parents: 78917
diff changeset
   155
    val empty: Table = apply()
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   156
  }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   157
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   158
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   159
  /* lexer */
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   160
78609
67492b2a3a62 clarified signature: prefer enum types;
wenzelm
parents: 78332
diff changeset
   161
  enum Kind { case KEYWORD, VALUE, STRING, MULTILINE_STRING, LINE_SEP, ERROR }
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   162
78981
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   163
  sealed case class Token(kind: Kind, text: Str) extends Positional {
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   164
    def is_keyword(name: Str): Bool = kind == Kind.KEYWORD && text == name
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   165
    def is_value: Bool = kind == Kind.VALUE
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   166
    def is_string: Bool = kind == Kind.STRING
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   167
    def is_multiline_string: Bool = kind == Kind.MULTILINE_STRING
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   168
    def is_line_sep: Bool = kind == Kind.LINE_SEP
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   169
  }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   170
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   171
  object Lexer extends Scanners with Scan.Parsers {
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   172
    override type Elem = Char
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   173
    type Token = TOML.Token
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   174
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   175
    def errorToken(msg: Str): Token = Token(Kind.ERROR, msg)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   176
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   177
    val white_space: Str = " \t"
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   178
    override val whiteSpace: Regex = ("[" + white_space + "]+").r
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   179
    override def whitespace: Parser[Any] = rep(comment | many1(character(white_space.contains(_))))
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   180
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   181
    def line_sep: Parser[Str] = rep1("\n" | s"\r\n" | EofCh) ^^ (cs => cs.mkString)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   182
    def line_sep_token: Parser[Token] = line_sep ^^ (s => Token(Kind.LINE_SEP, s))
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   183
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   184
    def is_control(e: Elem): Bool =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   185
      e <= '\u0008' || ('\u000A' <= e && e <= '\u001F') || e == '\u007F'
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   186
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   187
    override def comment: Parser[Str] = '#' ~>! many(character(c => !is_control(c)))
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   188
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   189
    def keyword: Parser[Token] = one(character("{}[],=.".contains)) ^^ (s => Token(Kind.KEYWORD, s))
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   190
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   191
    def is_value(c: Elem): Bool =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   192
      Symbol.is_ascii_letter(c) || Symbol.is_ascii_digit(c) || "_-:+".contains(c)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   193
    def value: Parser[Token] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   194
      many1(character(is_value)) ~
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   195
        opt(' ' ~ many1(character(is_value)) ^^ { case ws ~ s => ws.toString + s }) ~
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   196
        opt('.' ~ many1(character(is_value)) ^^ { case dot ~ s => dot.toString + s}) ^^
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   197
        { case s ~ ss ~ sd => Token(Kind.VALUE, s + ss.getOrElse("") + sd.getOrElse("")) }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   198
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   199
    def string: Parser[Token] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   200
      multiline_basic_string | basic_string | multiline_literal_string | literal_string
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   201
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   202
    private def trim(s: Str): Str =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   203
      if (s.startsWith("\n")) s.stripPrefix("\n") else s.stripPrefix("\r\n")
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   204
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   205
    def basic_string: Parser[Token] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   206
      '"' ~> rep(basic_string_elem) <~ '"' ^^ (cs => Token(Kind.STRING, cs.mkString))
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   207
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   208
    def multiline_basic_string: Parser[Token] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   209
      "\"\"\"" ~>
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   210
        rep(multiline_basic_string_elem |
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   211
          ("\"\"" | "\"") ~ multiline_basic_string_elem ^^ { case s ~ t => s + t }) ~
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   212
        repeated(character(_ == '"'), 3, 5) ^^ { case cs ~ q =>
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   213
          Token(Kind.MULTILINE_STRING, trim(cs.mkString + q.drop(3))) }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   214
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   215
    private def multiline_basic_string_elem: Parser[Str] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   216
      ('\\' ~ line_sep ~ rep(many1(character(white_space.contains)) | line_sep)) ^^ (_ => "") |
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   217
        basic_string_elem ^^ (_.toString) | line_sep
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   218
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   219
    def literal_string: Parser[Token] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   220
      '\'' ~> rep(literal_string_elem) <~ '\'' ^^ (cs => Token(Kind.STRING, cs.mkString))
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   221
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   222
    def multiline_literal_string: Parser[Token] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   223
      "'''" ~>
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   224
        rep(multiline_literal_string_elem |
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   225
          ("''" | "'") ~ multiline_literal_string_elem ^^ { case s ~ t => s + t }) ~
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   226
        repeated(character(_ == '\''), 3, 5) ^^ { case cs ~ q =>
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   227
          Token(Kind.MULTILINE_STRING, trim(cs.mkString + q.drop(3))) }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   228
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   229
    private def multiline_literal_string_elem: Parser[Str] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   230
      line_sep | literal_string_elem ^^ (_.toString)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   231
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   232
    private def basic_string_elem: Parser[Elem] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   233
      elem("", c => !is_control(c) && !"\"\\".contains(c)) | '\\' ~> string_escape
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   234
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   235
    private def string_escape: Parser[Elem] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   236
      elem("", "\"\\".contains(_)) |
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   237
        elem("", "btnfr".contains(_)) ^^
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   238
          { case 'b' => '\b' case 't' => '\t' case 'n' => '\n' case 'f' => '\f' case 'r' => '\r' } |
78920
wenzelm
parents: 78919
diff changeset
   239
        ('u' ~> repeated(character(Symbol.is_ascii_hex), 4, 4) |
wenzelm
parents: 78919
diff changeset
   240
          'U' ~> repeated(character(Symbol.is_ascii_hex), 8, 8)) ^^
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   241
          (s => java.lang.Integer.parseInt(s, 16).toChar)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   242
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   243
    private def literal_string_elem: Parser[Elem] = elem("", c => !is_control(c) && c != '\'')
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   244
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   245
    def string_failure: Parser[Token] = ("\"" | "'") ~> failure("Unterminated string")
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   246
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   247
    def token: Parser[Token] =
78981
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   248
      positioned(
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   249
        line_sep_token | keyword | value | string | string_failure | failure("Unrecognized token"))
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   250
  }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   251
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   252
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   253
  /* parser */
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   254
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   255
  trait Parsers extends combinator.Parsers {
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   256
    type Elem = Token
78317
fcabbb45b272 tuned whitespace;
wenzelm
parents: 78316
diff changeset
   257
fcabbb45b272 tuned whitespace;
wenzelm
parents: 78316
diff changeset
   258
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   259
    /* parse structure */
78317
fcabbb45b272 tuned whitespace;
wenzelm
parents: 78316
diff changeset
   260
78981
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   261
    sealed trait V extends Positional
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   262
    case class Primitive(t: T) extends V
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   263
    case class Array(rep: List[V]) extends V
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   264
    case class Inline_Table(elems: List[(Keys, V)]) extends V
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   265
78981
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   266
    sealed trait Def extends Positional
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   267
    case class Table(key: Keys, elems: List[(Keys, V)]) extends Def
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   268
    case class Array_Of_Tables(key: Keys, elems: List[(Keys, V)]) extends Def
78317
fcabbb45b272 tuned whitespace;
wenzelm
parents: 78316
diff changeset
   269
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   270
    case class File(elems: List[(Keys, V)], defs: List[Def])
78317
fcabbb45b272 tuned whitespace;
wenzelm
parents: 78316
diff changeset
   271
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   272
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   273
    /* top-level syntax structure */
78317
fcabbb45b272 tuned whitespace;
wenzelm
parents: 78316
diff changeset
   274
79007
eed4ca224c9c clarified toml keys operations;
Fabian Huch <huch@in.tum.de>
parents: 79006
diff changeset
   275
    def key: Parser[Keys] = positioned(rep1sep(keys, $$$(".")) ^^ (_.reduce(_ ++ _)))
78317
fcabbb45b272 tuned whitespace;
wenzelm
parents: 78316
diff changeset
   276
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   277
    def string: Parser[String] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   278
      elem("string", e => e.is_string || e.is_multiline_string) ^^ (s => String(s.text))
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   279
    def integer: Parser[Integer] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   280
      (decimal_int | binary_int | octal_int | hexadecimal_int) ^^ Integer.apply
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   281
    def float: Parser[Float] = (symbol_float | number_float) ^^ Float.apply
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   282
    def boolean: Parser[Boolean] = token("boolean", _.is_value, s => Boolean(Value.Boolean.parse(s)))
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   283
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   284
    def offset_date_time: Parser[Offset_Date_Time] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   285
      token("offset date-time", _.is_value,
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   286
        s => Offset_Date_Time(OffsetDateTime.parse(s.replace(" ", "T"))))
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   287
    def local_date_time: Parser[Local_Date_Time] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   288
      token("local date-time", _.is_value,
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   289
        s => Local_Date_Time(LocalDateTime.parse(s.replace(" ", "T"))))
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   290
    def local_date: Parser[Local_Date] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   291
      token("local date", _.is_value, s => Local_Date(LocalDate.parse(s)))
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   292
    def local_time: Parser[Local_Time] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   293
      token("local time", _.is_value, s => Local_Time(LocalTime.parse(s)))
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   294
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   295
    def array: Parser[Array] =
78981
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   296
      positioned(
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   297
        $$$("[") ~>! repsep(opt(line_sep) ~> toml_value, opt(line_sep) ~ $$$(",")) <~!
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   298
          opt(line_sep) ~! opt($$$(",")) ~! opt(line_sep) <~! $$$("]") ^^ Array.apply)
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   299
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   300
    def inline_table: Parser[Inline_Table] =
78981
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   301
      positioned(
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   302
        $$$("{") ~>! repsep(pair, $$$(",")) <~! $$$("}") ^^ Inline_Table.apply)
78317
fcabbb45b272 tuned whitespace;
wenzelm
parents: 78316
diff changeset
   303
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   304
    def pair: Parser[(Keys, V)] = (key <~! $$$("=")) ~! toml_value ^^ { case ks ~ v => (ks, v) }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   305
78981
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   306
    def table: Parser[Table] =
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   307
      positioned(
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   308
        $$$("[") ~> (key <~! $$$("]") ~! line_sep) ~! content ^^
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   309
          { case key ~ content => Table(key, content) })
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   310
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   311
    def array_of_tables: Parser[Array_Of_Tables] =
78981
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   312
      positioned(
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   313
        $$$("[") ~ $$$("[") ~>! (key <~! $$$("]") ~! $$$("]") ~! line_sep) ~! content ^^
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   314
          { case key ~ content => Array_Of_Tables(key, content) })
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   315
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   316
    def toml: Parser[File] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   317
      (opt(line_sep) ~>! content ~! rep(table | array_of_tables)) ^^
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   318
        { case content ~ defs => File(content, defs) }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   319
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   320
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   321
    /* auxiliary */
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   322
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   323
    private def $$$(name: Str): Parser[Token] = elem(name, _.is_keyword(name))
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   324
    private def maybe[A, B](p: Parser[A], f: A => B): Parser[B] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   325
      p ^^ (a => Try(f(a))) ^? { case util.Success(v) => v }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   326
    private def token[A](name: Str, p: Token => Bool, parser: Str => A): Parser[A] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   327
      maybe(elem(name, p), s => parser(s.text))
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   328
    private def prefixed[A](
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   329
      prefix: Str, name: Str, p: Str => Bool, parser: Str => A
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   330
    ): Parser[A] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   331
      token(name, e => e.is_value && e.text.startsWith(prefix) && p(e.text.stripPrefix(prefix)),
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   332
        s => parser(s.stripPrefix(prefix)))
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   333
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   334
    private def is_key(e: Elem): Bool = e.is_value && !e.text.exists("+: ".contains(_))
79002
16fa55f8958d clarified keys module;
Fabian Huch <huch@in.tum.de>
parents: 79001
diff changeset
   335
    private def keys: Parser[Keys] =
16fa55f8958d clarified keys module;
Fabian Huch <huch@in.tum.de>
parents: 79001
diff changeset
   336
      token("string key", _.is_string, Keys.quoted) | token("key", is_key, Keys.dotted)
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   337
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   338
    private def sep_surrounded(s: Str): Bool =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   339
      !s.startsWith("_") && !s.endsWith("_") && s.split('_').forall(_.nonEmpty)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   340
    private def no_leading_zero(s: Str): Bool = {
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   341
      val t = s.replaceAll("_", "").takeWhile(_.isDigit)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   342
      t == "0" || !t.startsWith("0")
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   343
    }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   344
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   345
    private def is_int(s: Str): Bool =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   346
      no_leading_zero(s.replaceAll("[-+]", "")) && sep_surrounded(s.replaceAll("[-+]", ""))
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   347
    private def decimal_int: Parser[Long] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   348
      token("integer", e => e.is_value && is_int(e.text), _.replace("_", "").toLong)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   349
    private def binary_int: Parser[Long] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   350
      prefixed("0b", "integer", sep_surrounded, s => parseLong(s.replace("_", ""), 2))
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   351
    private def octal_int: Parser[Long] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   352
      prefixed("0o", "integer", sep_surrounded, s => parseLong(s.replace("_", ""), 8))
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   353
    private def hexadecimal_int: Parser[Long] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   354
      prefixed("0x", "integer", sep_surrounded, s => parseLong(s.replace("_", ""), 16))
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   355
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   356
    private def is_float(s: Str): Bool =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   357
      s.exists(".eE".contains) && s.count("eE".contains) <= 1 &&
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   358
        no_leading_zero(s.replaceAll("[-+]", "")) &&
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   359
        sep_surrounded(s.replaceAll("[-+]", "").replaceAll("[.eE][+\\-]?", "_"))
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   360
    private def number_float: Parser[Double] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   361
      token("float", e => e.is_value && is_float(e.text), _.replace("_", "").toDouble)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   362
    private def symbol_float: Parser[Double] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   363
      token("float", _.is_value, {
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   364
        case "inf" | "+inf" => Double.PositiveInfinity
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   365
        case "-inf" => Double.NegativeInfinity
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   366
        case "nan" | "+nan" | "-nan" => Double.NaN
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   367
      })
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   368
78981
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   369
    private def toml_value: Parser[V] =
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   370
      positioned(
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   371
        (string | float | integer | boolean | offset_date_time |
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   372
          local_date_time | local_date | local_time) ^^ Primitive.apply | array | inline_table)
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   373
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   374
    private def line_sep: Parser[Any] = rep1(elem("line sep", _.is_line_sep))
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   375
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   376
    private def content: Parser[List[(Keys, V)]] =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   377
      rep((key <~! $$$("=")) ~! toml_value <~! line_sep ^^ { case ks ~ v => ks -> v })
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   378
  }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   379
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   380
  object Parsers extends Parsers
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   381
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   382
79001
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   383
  /* Keys for nested tables */
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   384
79002
16fa55f8958d clarified keys module;
Fabian Huch <huch@in.tum.de>
parents: 79001
diff changeset
   385
  object Keys {
16fa55f8958d clarified keys module;
Fabian Huch <huch@in.tum.de>
parents: 79001
diff changeset
   386
    def empty: Keys = new Keys(Nil)
16fa55f8958d clarified keys module;
Fabian Huch <huch@in.tum.de>
parents: 79001
diff changeset
   387
    def quoted(s: Str): Keys = new Keys(List(s))
16fa55f8958d clarified keys module;
Fabian Huch <huch@in.tum.de>
parents: 79001
diff changeset
   388
    def dotted(s: Str): Keys = new Keys(s.split('.').toList)
16fa55f8958d clarified keys module;
Fabian Huch <huch@in.tum.de>
parents: 79001
diff changeset
   389
  }
16fa55f8958d clarified keys module;
Fabian Huch <huch@in.tum.de>
parents: 79001
diff changeset
   390
79004
39373f2151c4 use toml key operations properly;
Fabian Huch <huch@in.tum.de>
parents: 79003
diff changeset
   391
  class Keys private(private val rep: List[Key]) extends Positional {
79002
16fa55f8958d clarified keys module;
Fabian Huch <huch@in.tum.de>
parents: 79001
diff changeset
   392
    override def hashCode(): Int = rep.hashCode()
16fa55f8958d clarified keys module;
Fabian Huch <huch@in.tum.de>
parents: 79001
diff changeset
   393
    override def equals(obj: Any): Bool =
16fa55f8958d clarified keys module;
Fabian Huch <huch@in.tum.de>
parents: 79001
diff changeset
   394
      obj match {
16fa55f8958d clarified keys module;
Fabian Huch <huch@in.tum.de>
parents: 79001
diff changeset
   395
        case other: Keys => rep == other.rep
16fa55f8958d clarified keys module;
Fabian Huch <huch@in.tum.de>
parents: 79001
diff changeset
   396
        case _ => false
16fa55f8958d clarified keys module;
Fabian Huch <huch@in.tum.de>
parents: 79001
diff changeset
   397
      }
16fa55f8958d clarified keys module;
Fabian Huch <huch@in.tum.de>
parents: 79001
diff changeset
   398
    override def toString: Str = rep.mkString("Keys(", ".", ")")
16fa55f8958d clarified keys module;
Fabian Huch <huch@in.tum.de>
parents: 79001
diff changeset
   399
79007
eed4ca224c9c clarified toml keys operations;
Fabian Huch <huch@in.tum.de>
parents: 79006
diff changeset
   400
    def first: Keys = new Keys(rep.take(1))
79002
16fa55f8958d clarified keys module;
Fabian Huch <huch@in.tum.de>
parents: 79001
diff changeset
   401
    def last: Keys = new Keys(rep.takeRight(1))
79006
Fabian Huch <huch@in.tum.de>
parents: 79005
diff changeset
   402
    def next: Keys = new Keys(rep.drop(1))
Fabian Huch <huch@in.tum.de>
parents: 79005
diff changeset
   403
    def parent: Keys = new Keys(rep.dropRight(1))
79001
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   404
79005
6201057b98dd clarified toml keys: more operations;
Fabian Huch <huch@in.tum.de>
parents: 79004
diff changeset
   405
    def the_key: Key = Library.the_single(rep)
79001
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   406
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   407
    def length: Int = rep.length
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   408
79007
eed4ca224c9c clarified toml keys operations;
Fabian Huch <huch@in.tum.de>
parents: 79006
diff changeset
   409
    def ++(other: Keys): Keys = new Keys(rep ::: other.rep)
79001
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   410
79006
Fabian Huch <huch@in.tum.de>
parents: 79005
diff changeset
   411
    def prefixes: Set[Keys] = splits.map(_._1).toSet
Fabian Huch <huch@in.tum.de>
parents: 79005
diff changeset
   412
    def splits: List[(Keys, Keys)] = Range.inclusive(0, length).toList.map(split).reverse
79001
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   413
    def split(i: Int): (Keys, Keys) = {
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   414
      val (rep0, rep1) = rep.splitAt(i)
79002
16fa55f8958d clarified keys module;
Fabian Huch <huch@in.tum.de>
parents: 79001
diff changeset
   415
      (new Keys(rep0), new Keys(rep1))
79001
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   416
    }
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   417
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   418
    def is_child_of(parent: Keys): Bool = rep.startsWith(parent.rep)
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   419
  }
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   420
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   421
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   422
  /* checking and translating parse structure into toml */
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   423
79001
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   424
  class Parse_Context private(var seen_tables: Map[Keys, Seen], file: Option[Path] = None) {
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   425
    private def recent_array(ks: Keys): (Keys, Seen, Keys) =
78981
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   426
      ks.splits.collectFirst {
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   427
        case (ks1, ks2) if seen_tables.contains(ks1) => (ks1, seen_tables(ks1), ks2)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   428
      }.get
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   429
79001
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   430
    private def check_add(start: Int, ks: Keys, elem: Parsers.Def | Parsers.V): Unit = {
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   431
      val (to, seen, rest, split) =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   432
        elem match {
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   433
          case _: Parsers.Array_Of_Tables =>
78981
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   434
            val (_, seen, rest) = recent_array(ks.parent)
79007
eed4ca224c9c clarified toml keys operations;
Fabian Huch <huch@in.tum.de>
parents: 79006
diff changeset
   435
            (ks, seen, rest ++ ks.last, 0)
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   436
          case _ =>
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   437
            val (to, seen, rest) = recent_array(ks)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   438
            (to, seen, rest, start - to.length)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   439
        }
78981
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   440
      val (rest0, rest1) = rest.split(split)
79007
eed4ca224c9c clarified toml keys operations;
Fabian Huch <huch@in.tum.de>
parents: 79006
diff changeset
   441
      val implicitly_seen = rest1.parent.prefixes.map(rest0 ++ _)
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   442
78983
295aa95cbff9 unify error messages;
Fabian Huch <huch@in.tum.de>
parents: 78982
diff changeset
   443
      def error[A](s: Str): A = this.error(s, elem.pos, Some(ks))
79007
eed4ca224c9c clarified toml keys operations;
Fabian Huch <huch@in.tum.de>
parents: 79006
diff changeset
   444
78981
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   445
      seen.inlines.find(rest.is_child_of).foreach(ks =>
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   446
        error("Attempting to update an inline value"))
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   447
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   448
      val (inlines, tables) =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   449
        elem match {
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   450
          case _: Parsers.Primitive =>
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   451
            (seen.inlines, seen.tables ++ implicitly_seen)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   452
          case _: Parsers.Array =>
78327
a235fc426523 tuned error messages;
Fabian Huch <huch@in.tum.de>
parents: 78326
diff changeset
   453
            if (seen_tables.contains(ks))
78981
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   454
              error("Attempting to append with an inline array")
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   455
            (seen.inlines + rest, seen.tables ++ implicitly_seen)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   456
          case _: Parsers.Inline_Table =>
78981
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   457
            seen.tables.find(_.is_child_of(rest)).foreach(ks =>
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   458
              error("Attempting to add with an inline table"))
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   459
            (seen.inlines + rest, seen.tables ++ implicitly_seen)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   460
          case _: Parsers.Table =>
78327
a235fc426523 tuned error messages;
Fabian Huch <huch@in.tum.de>
parents: 78326
diff changeset
   461
            if (seen.tables.contains(rest))
78981
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   462
              error("Attempting to define a table twice")
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   463
            (seen.inlines, seen.tables + rest)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   464
          case _: Parsers.Array_Of_Tables => (Set.empty, Set.empty)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   465
        }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   466
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   467
      seen_tables += to -> Seen(inlines, tables)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   468
    }
78982
be5c078f5292 add file information to toml parse context and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78981
diff changeset
   469
be5c078f5292 add file information to toml parse context and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78981
diff changeset
   470
    def for_file(file: Path): Parse_Context = new Parse_Context(seen_tables, Some(file))
be5c078f5292 add file information to toml parse context and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78981
diff changeset
   471
79001
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   472
    def error[A](s: Str, pos: input.Position, key: Option[Keys] = None): A = {
79003
9d1c4824a055 clarified toml keys formatting vs. toString;
Fabian Huch <huch@in.tum.de>
parents: 79002
diff changeset
   473
      val key_msg = if_proper(key, " in table " + key.get)
78982
be5c078f5292 add file information to toml parse context and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78981
diff changeset
   474
      val file_msg = if_proper(file, " in " + file.get)
78983
295aa95cbff9 unify error messages;
Fabian Huch <huch@in.tum.de>
parents: 78982
diff changeset
   475
      isabelle.error(s + key_msg + " at line " + pos.line + file_msg)
78982
be5c078f5292 add file information to toml parse context and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78981
diff changeset
   476
    }
be5c078f5292 add file information to toml parse context and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78981
diff changeset
   477
79001
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   478
    def check_add_def(ks: Keys, defn: Parsers.Def): Unit = check_add(0, ks, defn)
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   479
    def check_add_value(ks0: Keys, ks1: Keys, v: Parsers.V): Unit =
79007
eed4ca224c9c clarified toml keys operations;
Fabian Huch <huch@in.tum.de>
parents: 79006
diff changeset
   480
      check_add(ks0.length - 1, ks0 ++ ks1, v)
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   481
  }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   482
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   483
  object Parse_Context {
79001
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   484
    case class Seen(inlines: Set[Keys], tables: Set[Keys])
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   485
78981
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   486
    def apply(): Parse_Context =
79002
16fa55f8958d clarified keys module;
Fabian Huch <huch@in.tum.de>
parents: 79001
diff changeset
   487
      new Parse_Context(Map(Keys.empty -> Seen(Set.empty, Set.empty)))
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   488
  }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   489
78927
64f47e86526b clarified signature: emphasize mutable instance;
wenzelm
parents: 78920
diff changeset
   490
  def parse(s: Str, context: Parse_Context = Parse_Context()): Table = {
78983
295aa95cbff9 unify error messages;
Fabian Huch <huch@in.tum.de>
parents: 78982
diff changeset
   491
    val file =
79000
8f5be65a176b clarified toml parser interface;
Fabian Huch <huch@in.tum.de>
parents: 78983
diff changeset
   492
      Parsers.phrase(Parsers.toml)(new Lexer.Scanner(Scan.char_reader(s + EofCh))) match {
78983
295aa95cbff9 unify error messages;
Fabian Huch <huch@in.tum.de>
parents: 78982
diff changeset
   493
        case Parsers.Success (toml, _) => toml
295aa95cbff9 unify error messages;
Fabian Huch <huch@in.tum.de>
parents: 78982
diff changeset
   494
        case Parsers.Error(msg, next) => context.error("Error parsing toml: " + msg, next.pos)
295aa95cbff9 unify error messages;
Fabian Huch <huch@in.tum.de>
parents: 78982
diff changeset
   495
        case Parsers.Failure (msg, next) =>
295aa95cbff9 unify error messages;
Fabian Huch <huch@in.tum.de>
parents: 78982
diff changeset
   496
          context.error("Malformed TOML input: " + msg, next.pos)
295aa95cbff9 unify error messages;
Fabian Huch <huch@in.tum.de>
parents: 78982
diff changeset
   497
      }
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   498
79001
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   499
    def convert(ks0: Keys, ks1: Keys, v: Parsers.V): T = {
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   500
      def to_table(ks: Keys, t: T): Table =
79007
eed4ca224c9c clarified toml keys operations;
Fabian Huch <huch@in.tum.de>
parents: 79006
diff changeset
   501
        if (ks.length == 1) Table(ks.first.the_key -> t)
eed4ca224c9c clarified toml keys operations;
Fabian Huch <huch@in.tum.de>
parents: 79006
diff changeset
   502
        else Table(ks.first.the_key -> to_table(ks.next, t))
79004
39373f2151c4 use toml key operations properly;
Fabian Huch <huch@in.tum.de>
parents: 79003
diff changeset
   503
79001
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   504
      def to_toml(v: Parsers.V): (T, Set[Keys]) = v match {
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   505
        case Parsers.Primitive(t) => (t, Set.empty)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   506
        case Parsers.Array(rep) => (Array(rep.map(to_toml(_)._1)), Set.empty)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   507
        case Parsers.Inline_Table(elems) =>
78327
a235fc426523 tuned error messages;
Fabian Huch <huch@in.tum.de>
parents: 78326
diff changeset
   508
          elems.find(e => elems.count(_._1 == e._1) > 1).foreach((ks, _) =>
78983
295aa95cbff9 unify error messages;
Fabian Huch <huch@in.tum.de>
parents: 78982
diff changeset
   509
            context.error(
79007
eed4ca224c9c clarified toml keys operations;
Fabian Huch <huch@in.tum.de>
parents: 79006
diff changeset
   510
              "Duplicate " + ks + " in inline table", v.pos, Some(ks0 ++ ks1)))
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   511
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   512
          val (tables, pfxs, key_spaces) =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   513
            elems.map { (ks, v) =>
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   514
              val (t, keys) = to_toml(v)
79007
eed4ca224c9c clarified toml keys operations;
Fabian Huch <huch@in.tum.de>
parents: 79006
diff changeset
   515
              (to_table(ks, t), ks.prefixes, keys.map(ks ++ _) + ks)
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   516
            }.unzip3
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   517
78981
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   518
          for {
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   519
            pfx <- pfxs
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   520
            if key_spaces.count(pfx.intersect(_).nonEmpty) > 1
79007
eed4ca224c9c clarified toml keys operations;
Fabian Huch <huch@in.tum.de>
parents: 79006
diff changeset
   521
          } context.error("Inline table not self-contained", v.pos, Some(ks0 ++ ks1))
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   522
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   523
          (tables.foldLeft(Table())(_ ++ _), pfxs.toSet.flatten ++ key_spaces.toSet.flatten)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   524
      }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   525
      context.check_add_value(ks0, ks1, v)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   526
      to_toml(v)._1
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   527
    }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   528
79001
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   529
    def update(map: Table, ks0: Keys, value: T): Table = {
78983
295aa95cbff9 unify error messages;
Fabian Huch <huch@in.tum.de>
parents: 78982
diff changeset
   530
      def error[A](s: Str): A = context.error(s, ks0.pos, Some(ks0))
78981
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   531
79001
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   532
      def update_rec(hd: Keys, map: Table, ks: Keys): Table = {
78327
a235fc426523 tuned error messages;
Fabian Huch <huch@in.tum.de>
parents: 78326
diff changeset
   533
        val updated =
a235fc426523 tuned error messages;
Fabian Huch <huch@in.tum.de>
parents: 78326
diff changeset
   534
          if (ks.length == 1) {
79007
eed4ca224c9c clarified toml keys operations;
Fabian Huch <huch@in.tum.de>
parents: 79006
diff changeset
   535
            map.any.get(ks.first.the_key) match {
78327
a235fc426523 tuned error messages;
Fabian Huch <huch@in.tum.de>
parents: 78326
diff changeset
   536
              case Some(a: Array) =>
a235fc426523 tuned error messages;
Fabian Huch <huch@in.tum.de>
parents: 78326
diff changeset
   537
                value match {
a235fc426523 tuned error messages;
Fabian Huch <huch@in.tum.de>
parents: 78326
diff changeset
   538
                  case a2: Array => a ++ a2
78981
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   539
                  case _ => error("Table conflicts with previous array of tables")
78327
a235fc426523 tuned error messages;
Fabian Huch <huch@in.tum.de>
parents: 78326
diff changeset
   540
                }
a235fc426523 tuned error messages;
Fabian Huch <huch@in.tum.de>
parents: 78326
diff changeset
   541
              case Some(t: Table) => value match {
a235fc426523 tuned error messages;
Fabian Huch <huch@in.tum.de>
parents: 78326
diff changeset
   542
                case t2: Table =>
a235fc426523 tuned error messages;
Fabian Huch <huch@in.tum.de>
parents: 78326
diff changeset
   543
                  if (t.domain.intersect(t2.domain).nonEmpty)
78981
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   544
                    error("Attempting to redefine existing value in super-table")
78327
a235fc426523 tuned error messages;
Fabian Huch <huch@in.tum.de>
parents: 78326
diff changeset
   545
                  else t ++ t2
78981
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   546
                case _ => error("Attempting to redefine a table")
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   547
              }
78981
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   548
              case Some(_) => error("Attempting to redefine a value")
78327
a235fc426523 tuned error messages;
Fabian Huch <huch@in.tum.de>
parents: 78326
diff changeset
   549
              case None => value
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   550
            }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   551
          }
78327
a235fc426523 tuned error messages;
Fabian Huch <huch@in.tum.de>
parents: 78326
diff changeset
   552
          else {
79007
eed4ca224c9c clarified toml keys operations;
Fabian Huch <huch@in.tum.de>
parents: 79006
diff changeset
   553
            val hd1 = hd ++ ks.first
eed4ca224c9c clarified toml keys operations;
Fabian Huch <huch@in.tum.de>
parents: 79006
diff changeset
   554
            map.any.get(ks.first.the_key) match {
79006
Fabian Huch <huch@in.tum.de>
parents: 79005
diff changeset
   555
              case Some(t: Table) => update_rec(hd1, t, ks.next)
78327
a235fc426523 tuned error messages;
Fabian Huch <huch@in.tum.de>
parents: 78326
diff changeset
   556
              case Some(a: Array) =>
79006
Fabian Huch <huch@in.tum.de>
parents: 79005
diff changeset
   557
                Array(a.table.values.dropRight(1) :+ update_rec(hd1, a.table.values.last, ks.next))
78981
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   558
              case Some(_) => error("Attempting to redefine a value")
79006
Fabian Huch <huch@in.tum.de>
parents: 79005
diff changeset
   559
              case None => update_rec(hd1, Table(), ks.next)
78327
a235fc426523 tuned error messages;
Fabian Huch <huch@in.tum.de>
parents: 78326
diff changeset
   560
            }
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   561
          }
79007
eed4ca224c9c clarified toml keys operations;
Fabian Huch <huch@in.tum.de>
parents: 79006
diff changeset
   562
        (map - ks.first.the_key) + (ks.first.the_key -> updated)
78327
a235fc426523 tuned error messages;
Fabian Huch <huch@in.tum.de>
parents: 78326
diff changeset
   563
      }
78981
47f8533c6887 add position information to toml parser and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78980
diff changeset
   564
79002
16fa55f8958d clarified keys module;
Fabian Huch <huch@in.tum.de>
parents: 79001
diff changeset
   565
      update_rec(Keys.empty, map, ks0)
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   566
    }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   567
79001
e715c1d1f1a2 pull out toml keys module;
Fabian Huch <huch@in.tum.de>
parents: 79000
diff changeset
   568
    def fold(elems: List[(Keys, T)]): Table =
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   569
      elems.foldLeft(Table()) { case (t0, (ks1, t1)) => update(t0, ks1, t1) }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   570
79002
16fa55f8958d clarified keys module;
Fabian Huch <huch@in.tum.de>
parents: 79001
diff changeset
   571
    val t = fold(file.elems.map((ks, v) => (ks, convert(Keys.empty, ks, v))))
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   572
    file.defs.foldLeft(t) {
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   573
      case (t0, defn@Parsers.Table(ks0, elems)) =>
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   574
        context.check_add_def(ks0, defn)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   575
        update(t0, ks0, fold(elems.map((ks, v) => (ks, convert(ks0, ks, v)))))
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   576
      case (t0, defn@Parsers.Array_Of_Tables(ks0, elems)) =>
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   577
        context.check_add_def(ks0, defn)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   578
        update(t0, ks0, Array(fold(elems.map((ks, v) => (ks, convert(ks0, ks, v))))))
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   579
    }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   580
  }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   581
78980
a80ee3c97aae properly concatenate toml files: regular toml rules still apply (e.g., inline values may not be changed), but values defined in one file may be updated in another;
Fabian Huch <huch@in.tum.de>
parents: 78979
diff changeset
   582
  def parse_files(files: Iterable[Path], context: Parse_Context = Parse_Context()): Table =
78982
be5c078f5292 add file information to toml parse context and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78981
diff changeset
   583
    files.foldLeft((Table(), context)) {
be5c078f5292 add file information to toml parse context and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78981
diff changeset
   584
      case ((t, context0), file) =>
be5c078f5292 add file information to toml parse context and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78981
diff changeset
   585
        val context = context0.for_file(file)
be5c078f5292 add file information to toml parse context and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78981
diff changeset
   586
        (t ++ parse(File.read(file), context), context)
be5c078f5292 add file information to toml parse context and error messages;
Fabian Huch <huch@in.tum.de>
parents: 78981
diff changeset
   587
    }._1
78939
218929597048 support for global registry;
wenzelm
parents: 78927
diff changeset
   588
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   589
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   590
  /* Format TOML */
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   591
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   592
  object Format {
78326
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   593
    private def basic_string(s: Str): Str =
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   594
      "\"" + s.iterator.map {
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   595
        case '\b' => "\\b" case '\t' => "\\t" case '\n' => "\\n" case '\f' => "\\f"
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   596
        case '\r' => "\\r" case '"' => "\\\"" case '\\' => "\\\\" case c =>
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   597
        if (c <= '\u001f' || c == '\u007f') "\\u%04x".format(c.toInt) else c
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   598
      }.mkString + "\""
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   599
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   600
    private def multiline_basic_string(s: Str): Str =
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   601
      "\"\"\"\n" + s.iterator.map {
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   602
        case '\b' => "\\b" case '\t' => "\t" case '\n' => "\n" case '\f' => "\\f"
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   603
        case '\r' => "\r" case '"' => "\\\"" case '\\' => "\\\\" case c =>
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   604
          if (c <= '\u001f' || c == '\u007f') "\\u%04x".format(c.toInt) else c
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   605
      }.mkString.replace("\"\"\"", "\"\"\\\"") + "\"\"\""
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   606
79003
9d1c4824a055 clarified toml keys formatting vs. toString;
Fabian Huch <huch@in.tum.de>
parents: 79002
diff changeset
   607
    private def key(k: Key): Str = {
78326
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   608
      val Bare_Key = """[A-Za-z0-9_-]+""".r
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   609
      k match {
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   610
        case Bare_Key() => k
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   611
        case _ => basic_string(k)
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   612
      }
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   613
    }
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   614
79003
9d1c4824a055 clarified toml keys formatting vs. toString;
Fabian Huch <huch@in.tum.de>
parents: 79002
diff changeset
   615
    private def keys(ks: List[Key]): Str = ks.map(key).mkString(".")
78326
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   616
79003
9d1c4824a055 clarified toml keys formatting vs. toString;
Fabian Huch <huch@in.tum.de>
parents: 79002
diff changeset
   617
    private def inline(t: T, indent: Int = 0): Str = {
78326
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   618
      val result = new StringBuilder
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   619
78917
30e0c15a71f7 more direct indentation, using Symbol.spaces;
wenzelm
parents: 78609
diff changeset
   620
      result ++= Symbol.spaces(indent * 2)
78941
bc7b7357f4bc clarified signature: more operations;
wenzelm
parents: 78939
diff changeset
   621
      (t: @unchecked) match {
78326
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   622
        case s: String =>
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   623
          if (s.rep.contains("\n") && s.rep.length > 20) result ++= multiline_basic_string(s.rep)
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   624
          else result ++= basic_string(s.rep)
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   625
        case a: Array =>
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   626
          if (a.is_empty) result ++= "[]"
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   627
          else {
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   628
            result ++= "[\n"
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   629
            a.any.values.foreach { elem =>
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   630
              result ++= inline(elem, indent + 1)
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   631
              result ++= ",\n"
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   632
            }
78917
30e0c15a71f7 more direct indentation, using Symbol.spaces;
wenzelm
parents: 78609
diff changeset
   633
            result ++= Symbol.spaces(indent * 2)
78326
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   634
            result += ']'
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   635
          }
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   636
        case table: Table =>
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   637
          if (table.is_empty) result ++= "{}"
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   638
          else {
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   639
            result ++= "{ "
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   640
            Library.separate(None, table.any.values.map(Some(_))).foreach {
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   641
              case None => result ++= ", "
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   642
              case Some((k, v)) =>
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   643
                result ++= key(k)
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   644
                result ++= " = "
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   645
                result ++= inline(v)
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   646
            }
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   647
            result ++= " }"
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   648
          }
78941
bc7b7357f4bc clarified signature: more operations;
wenzelm
parents: 78939
diff changeset
   649
        case Scalar(s) => result ++= s
78326
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   650
      }
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   651
      result.toString()
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   652
    }
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   653
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   654
    def apply(toml: Table): Str = {
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   655
      val result = new StringBuilder
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   656
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   657
      def inline_values(path: List[Key], t: T): Unit =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   658
        t match {
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   659
          case t: Table => t.any.values.foreach { case (k, v1) => inline_values(k :: path, v1) }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   660
          case _ =>
78326
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   661
            result ++= keys(path.reverse)
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   662
            result ++= " = "
78326
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   663
            result ++= inline(t)
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   664
            result += '\n'
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   665
        }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   666
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   667
      def is_inline(elem: T): Bool =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   668
        elem match {
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   669
          case _: String | _: Integer | _: Float | _: Boolean | _: Offset_Date_Time |
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   670
               _: Local_Date_Time | _: Local_Date | _: Local_Time => true
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   671
          case a: Array => a.any.values.forall(is_inline)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   672
          case _ => false
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   673
        }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   674
      def is_table(elem: T): Bool = elem match { case _: Table => true case _ => false }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   675
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   676
      def array(path: List[Key], a: Array): Unit =
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   677
        if (a.any.values.forall(is_inline) || !a.any.values.forall(is_table))
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   678
          inline_values(path.take(1), a)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   679
        else a.table.values.foreach { t =>
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   680
          result ++= "\n[["
78326
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   681
          result ++= keys(path.reverse)
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   682
          result ++= "]]\n"
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   683
          table(path, t, is_table_entry = true)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   684
        }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   685
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   686
      def table(path: List[Key], t: Table, is_table_entry: Bool = false): Unit = {
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   687
        val (values, nodes) = t.any.values.partition(kv => is_inline(kv._2))
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   688
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   689
        if (!is_table_entry && path.nonEmpty) {
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   690
          result ++= "\n["
78326
1cdc65476c2e more TOML formatting functions;
Fabian Huch <huch@in.tum.de>
parents: 78317
diff changeset
   691
          result ++= keys(path.reverse)
78316
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   692
          result ++= "]\n"
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   693
        }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   694
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   695
        values.foreach { case (k, v) => inline_values(List(k), v) }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   696
        nodes.foreach {
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   697
          case (k, t: Table) => table(k :: path, t)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   698
          case (k, arr: Array) => array(k :: path, arr)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   699
          case _ =>
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   700
        }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   701
      }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   702
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   703
      table(Nil, toml)
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   704
      result.toString
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   705
    }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   706
  }
be8aaaa4ac25 added TOML module from afp;
Fabian Huch <huch@in.tum.de>
parents:
diff changeset
   707
}