object TOML { /* typed representation and access */
type Key = Str
sealedtrait T caseclass String(rep: Str) extends T caseclass Integer(rep: Long) extends T caseclass Float(rep: Double) extends T caseclass Boolean(rep: Bool) extends T caseclass Offset_Date_Time(rep: OffsetDateTime) extends T caseclass Local_Date_Time(rep: LocalDateTime) extends T caseclass Local_Date(rep: LocalDate) extends T caseclass Local_Time(rep: LocalTime) extends T
object Scalar { def unapply(t: T): Option[Str] =
t match { case s: String => Some(s.rep) case i: Integer => Some(i.rep.toString) case f: Float => Some(f.rep.toString) case b: Boolean => Some(b.rep.toString) case o: Offset_Date_Time => Some(o.rep.toString) case l: Local_Date_Time => Some(l.rep.toString) case l: Local_Date => Some(l.rep.toString) case l: Local_Time => Some(l.rep.toString) case _ => None
}
}
class Array private(privateval rep: List[T]) extends T { overridedef hashCode(): Int = rep.hashCode() overridedef equals(that: Any): Bool = that match { case other: Array => rep == other.rep case _ => false
} overridedef toString: Str = "Array(" + length.toString + ")"
class Values[A](pf: PartialFunction[T, A]) { def values: List[A] = rep.collect(pf).reverse } lazyval string = new Values({ case s: String => s }) lazyval integer = new Values({ case i: Integer => i }) lazyval float = new Values({ case f: Float => f }) lazyval boolean = new Values({ case b: Boolean => b }) lazyval offset_date_time = new Values({ case o: Offset_Date_Time => o }) lazyval local_date_time = new Values({ case l: Local_Date_Time => l }) lazyval local_date = new Values({ case l: Local_Date => l }) lazyval local_time = new Values({ case l: Local_Time => l }) lazyval array = new Values({ case a: Array => a }) lazyval table = new Values({ case t: Table => t }) lazyval any = new Values({ case t => t })
def +(elem: T): Array = new Array(elem :: rep) def ++(other: Array): Array = new Array(other.rep ::: rep) def length: Int = rep.length def is_empty: Bool = rep.isEmpty
}
class Table private(privateval rep: ListMap[Key, T]) extends T { overridedef hashCode(): Int = rep.hashCode() overridedef equals(that: Any): Bool =
that match { case other: Table => rep == other.rep case _ => false
} overridedef toString: Str =
rep.map { case (k, t: Table) => k + "(" + t.domain.size + ")" case (k, a: Array) => k + "(" + a.length + ")" case (k, _) => k
}.mkString("Table(", ", ", ")")
class Value[A: ClassTag](pf: PartialFunction[T, A]) { def values: List[(Key, A)] =
rep.toList.collect { case (k, v) if pf.isDefinedAt(v) => k -> pf(v) } def get(k: Key): Option[A] = rep.get(k).flatMap(v => PartialFunction.condOpt(v)(pf)) def apply(k: Key): A =
rep.get(k) match { case Some(v) => PartialFunction.condOpt(v)(pf) match { case Some(value) => value case None =>
error("Expected" + classTag[A].runtimeClass.getName + ", got " + v.getClass.getSimpleName + " for key " + quote(k))
} case None => error("Key " + quote(k) + " does not exist")
}
}
lazyval string = new Value({ case s: String => s }) lazyval integer = new Value({ case i: Integer => i }) lazyval float = new Value({ case f: Float => f }) lazyval boolean = new Value({ case b: Boolean => b }) lazyval offset_date_time = new Value({ case o: Offset_Date_Time => o }) lazyval local_date_time = new Value({ case l: Local_Date_Time => l }) lazyval local_date = new Value({ case l: Local_Date => l }) lazyval local_time = new Value({ case l: Local_Time => l }) lazyval array = new Value({ case a: Array => a }) lazyval table = new Value({ case t: Table => t }) lazyval any = new Value({ case t => t })
def +(elem: (Key, T)): Table = { val (k, v) = elem val v1 = rep.get(k) match { case None => v case Some(v0) =>
(v0, v) match { case (t0: Table, t: Table) => t0 ++ t case (a0: Array, a: Array) => a0 ++ a case _ => v
}
} new Table(rep + (k -> v1))
} def -(k: Key): Table = new Table(rep - k) def ++(other: Table): Table = other.rep.foldLeft(this)(_ + _) def domain: Set[Key] = rep.keySet def is_empty: Bool = rep.isEmpty
}
trait Parsers extends combinator.Parsers { type Elem = Token
/* parse structure */
sealedtrait V extends Positional caseclass Primitive(t: T) extends V caseclass Array(rep: List[V]) extends V caseclass Inline_Table(elems: List[(Keys, V)]) extends V
/* checking and translating parse structure into toml */
class Parse_Context private(var seen_tables: Map[Keys, Seen], file: Option[Path] = None) { privatedef recent_array(ks: Keys): (Keys, Seen, Keys) =
ks.splits.collectFirst { case (ks1, ks2) if seen_tables.contains(ks1) => (ks1, seen_tables(ks1), ks2)
}.get
privatedef check_add(start: Int, ks: Keys, elem: Parsers.Def | Parsers.V): Unit = { val (to, seen, rest, split) =
elem match { case _: Parsers.Array_Of_Tables => val (_, seen, rest) = recent_array(ks.parent)
(ks, seen, rest ++ ks.last, 0) case _ => val (to, seen, rest) = recent_array(ks)
(to, seen, rest, start - to.length)
} val (rest0, rest1) = rest.split(split) val implicitly_seen = rest1.parent.prefixes.map(rest0 ++ _)
def error[A](s: Str): A = this.error(s, elem.pos, Some(ks))
seen.inlines.find(rest.is_child_of).foreach(ks =>
error("Attempting to update an inline value"))
val (inlines, tables) =
elem match { case _: Parsers.Primitive =>
(seen.inlines, seen.tables ++ implicitly_seen) case _: Parsers.Array => if (seen_tables.contains(ks))
error("Attempting to append with an inline array")
(seen.inlines + rest, seen.tables ++ implicitly_seen) case _: Parsers.Inline_Table =>
seen.tables.find(_.is_child_of(rest)).foreach(ks =>
error("Attempting to add with an inline table"))
(seen.inlines + rest, seen.tables ++ implicitly_seen) case _: Parsers.Table => if (seen.tables.contains(rest))
error("Attempting to define a table twice")
(seen.inlines, seen.tables + rest) case _: Parsers.Array_Of_Tables => (Set.empty, Set.empty)
}
seen_tables += to -> Seen(inlines, tables)
}
def for_file(file: Path): Parse_Context = new Parse_Context(seen_tables, Some(file))
def error[A](s: Str, pos: input.Position, key: Option[Keys] = None): A = { val key_msg = if_proper(key, " in table " + key.get) val file_msg = if_proper(file, " in " + file.get)
isabelle.error(s + key_msg + " at line " + pos.line + file_msg)
}
def update_rec(hd: Keys, map: Table, ks: Keys): Table = { val updated = if (ks.length == 1) {
map.any.get(ks.first.the_key) match { case Some(a: Array) =>
value match { case a2: Array => a ++ a2 case _ => error("Table conflicts with previous array of tables")
} case Some(t: Table) => value match { case t2: Table => if (t.domain.intersect(t2.domain).nonEmpty)
error("Attempting to redefine existing value in super-table") else t ++ t2 case _ => error("Attempting to redefine a table")
} case Some(_) => error("Attempting to redefine a value") case None => value
}
} else { val hd1 = hd ++ ks.first
map.any.get(ks.first.the_key) match { case Some(t: Table) => update_rec(hd1, t, ks.next) case Some(a: Array) =>
Array(a.table.values.dropRight(1) :+ update_rec(hd1, a.table.values.last, ks.next)) case Some(_) => error("Attempting to redefine a value") case None => update_rec(hd1, Table(), ks.next)
}
}
(map - ks.first.the_key) + (ks.first.the_key -> updated)
}
privatedef inline(t: T, indent: Int = 0): Str =
Library.string_builder() { result =>
result ++= Symbol.spaces(indent * 2)
(t: @unchecked) match { case s: String => if (s.rep.contains("\n") && s.rep.length > 20) result ++= multiline_basic_string(s.rep) else result ++= basic_string(s.rep) case a: Array => if (a.is_empty) result ++= "[]" else {
result ++= "[\n"
a.any.values.foreach { elem =>
result ++= inline(elem, indent + 1)
result ++= ",\n"
}
result ++= Symbol.spaces(indent * 2)
result += ']'
} case table: Table => if (table.is_empty) result ++= "{}" else {
result ++= "{ "
Library.separate(None, table.any.values.map(Some(_))).foreach { case None => result ++= ", " case Some((k, v)) =>
result ++= key(k)
result ++= " = "
result ++= inline(v)
}
result ++= " }"
} case Scalar(s) => result ++= s
}
}
def apply(toml: Table): Str =
Library.string_builder() { result => def inline_values(path: List[Key], t: T): Unit =
t match { case t: Table => t.any.values.foreach { case (k, v1) => inline_values(k :: path, v1) } case _ =>
result ++= keys(path.reverse)
result ++= " = "
result ++= inline(t)
result += '\n'
}
def array(path: List[Key], a: Array): Unit = if (a.any.values.forall(is_inline) || !a.any.values.forall(is_table))
inline_values(path.take(1), a) else a.table.values.foreach { t =>
result ++= "\n[["
result ++= keys(path.reverse)
result ++= "]]\n"
table(path, t, is_table_entry = true)
}
def table(path: List[Key], t: Table, is_table_entry: Bool = false): Unit = { val (values, nodes) = t.any.values.partition(kv => is_inline(kv._2))
if (!is_table_entry && path.nonEmpty) {
result ++= "\n["
result ++= keys(path.reverse)
result ++= "]\n"
}
values.foreach { case (k, v) => inline_values(List(k), v) }
nodes.foreach { case (k, t: Table) => table(k :: path, t) case (k, arr: Array) => array(k :: path, arr) case _ =>
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.