src/Pure/General/toml.scala
changeset 79001 e715c1d1f1a2
parent 79000 8f5be65a176b
child 79002 16fa55f8958d
equal deleted inserted replaced
79000:8f5be65a176b 79001:e715c1d1f1a2
   253   /* parser */
   253   /* parser */
   254 
   254 
   255   trait Parsers extends combinator.Parsers {
   255   trait Parsers extends combinator.Parsers {
   256     type Elem = Token
   256     type Elem = Token
   257 
   257 
   258     case class Keys(rep: List[Key]) extends Positional {
       
   259       def last: Keys = Keys(rep.takeRight(1))
       
   260       def the_last: Key = rep.last
       
   261       
       
   262       def head: Keys = Keys(rep.take(1))
       
   263       def the_head: Key = rep.head
       
   264 
       
   265       def length: Int = rep.length
       
   266 
       
   267       def +(other: Keys): Keys = Keys(rep ::: other.rep)
       
   268 
       
   269       def prefixes: Set[Keys] =
       
   270         if (rep.isEmpty) Set.empty
       
   271         else Range.inclusive(1, length).toSet.map(i => Keys(rep.take(i)))
       
   272 
       
   273       def splits: List[(Keys, Keys)] =
       
   274         Range.inclusive(0, length).toList.map(n =>
       
   275           (Keys(rep.dropRight(n)), Keys(rep.takeRight(n))))
       
   276       def split(i: Int): (Keys, Keys) = {
       
   277         val (rep0, rep1) = rep.splitAt(i)
       
   278         (Keys(rep0), Keys(rep1))
       
   279       }
       
   280 
       
   281       def parent: Keys = Keys(rep.dropRight(1))
       
   282       def is_child_of(parent: Keys): Bool = rep.startsWith(parent.rep)
       
   283     }
       
   284 
       
   285 
   258 
   286     /* parse structure */
   259     /* parse structure */
   287 
   260 
   288     sealed trait V extends Positional
   261     sealed trait V extends Positional
   289     case class Primitive(t: T) extends V
   262     case class Primitive(t: T) extends V
   405   }
   378   }
   406 
   379 
   407   object Parsers extends Parsers
   380   object Parsers extends Parsers
   408 
   381 
   409 
   382 
       
   383   /* Keys for nested tables */
       
   384 
       
   385   case class Keys(rep: List[Key]) extends Positional {
       
   386     def last: Keys = Keys(rep.takeRight(1))
       
   387     def the_last: Key = rep.last
       
   388 
       
   389     def head: Keys = Keys(rep.take(1))
       
   390     def the_head: Key = rep.head
       
   391 
       
   392     def length: Int = rep.length
       
   393 
       
   394     def +(other: Keys): Keys = Keys(rep ::: other.rep)
       
   395 
       
   396     def prefixes: Set[Keys] =
       
   397       if (rep.isEmpty) Set.empty
       
   398       else Range.inclusive(1, length).toSet.map(i => Keys(rep.take(i)))
       
   399 
       
   400     def splits: List[(Keys, Keys)] =
       
   401       Range.inclusive(0, length).toList.map(n =>
       
   402         (Keys(rep.dropRight(n)), Keys(rep.takeRight(n))))
       
   403     def split(i: Int): (Keys, Keys) = {
       
   404       val (rep0, rep1) = rep.splitAt(i)
       
   405       (Keys(rep0), Keys(rep1))
       
   406     }
       
   407 
       
   408     def parent: Keys = Keys(rep.dropRight(1))
       
   409     def is_child_of(parent: Keys): Bool = rep.startsWith(parent.rep)
       
   410   }
       
   411 
       
   412 
   410   /* checking and translating parse structure into toml */
   413   /* checking and translating parse structure into toml */
   411 
   414 
   412   class Parse_Context private(var seen_tables: Map[Parsers.Keys, Seen], file: Option[Path] = None) {
   415   class Parse_Context private(var seen_tables: Map[Keys, Seen], file: Option[Path] = None) {
   413     private def recent_array(ks: Parsers.Keys): (Parsers.Keys, Seen, Parsers.Keys) =
   416     private def recent_array(ks: Keys): (Keys, Seen, Keys) =
   414       ks.splits.collectFirst {
   417       ks.splits.collectFirst {
   415         case (ks1, ks2) if seen_tables.contains(ks1) => (ks1, seen_tables(ks1), ks2)
   418         case (ks1, ks2) if seen_tables.contains(ks1) => (ks1, seen_tables(ks1), ks2)
   416       }.get
   419       }.get
   417 
   420 
   418     private def check_add(start: Int, ks: Parsers.Keys, elem: Parsers.Def | Parsers.V): Unit = {
   421     private def check_add(start: Int, ks: Keys, elem: Parsers.Def | Parsers.V): Unit = {
   419       val (to, seen, rest, split) =
   422       val (to, seen, rest, split) =
   420         elem match {
   423         elem match {
   421           case _: Parsers.Array_Of_Tables =>
   424           case _: Parsers.Array_Of_Tables =>
   422             val (_, seen, rest) = recent_array(ks.parent)
   425             val (_, seen, rest) = recent_array(ks.parent)
   423             (ks, seen, rest + ks.last, 0)
   426             (ks, seen, rest + ks.last, 0)
   427         }
   430         }
   428       val (rest0, rest1) = rest.split(split)
   431       val (rest0, rest1) = rest.split(split)
   429       val implicitly_seen = rest1.parent.prefixes.map(rest0 + _)
   432       val implicitly_seen = rest1.parent.prefixes.map(rest0 + _)
   430 
   433 
   431       def error[A](s: Str): A = this.error(s, elem.pos, Some(ks))
   434       def error[A](s: Str): A = this.error(s, elem.pos, Some(ks))
   432 
   435   
   433       seen.inlines.find(rest.is_child_of).foreach(ks =>
   436       seen.inlines.find(rest.is_child_of).foreach(ks =>
   434         error("Attempting to update an inline value"))
   437         error("Attempting to update an inline value"))
   435 
   438 
   436       val (inlines, tables) =
   439       val (inlines, tables) =
   437         elem match {
   440         elem match {
   455       seen_tables += to -> Seen(inlines, tables)
   458       seen_tables += to -> Seen(inlines, tables)
   456     }
   459     }
   457 
   460 
   458     def for_file(file: Path): Parse_Context = new Parse_Context(seen_tables, Some(file))
   461     def for_file(file: Path): Parse_Context = new Parse_Context(seen_tables, Some(file))
   459 
   462 
   460     def error[A](s: Str, pos: input.Position, key: Option[Parsers.Keys] = None): A = {
   463     def error[A](s: Str, pos: input.Position, key: Option[Keys] = None): A = {
   461       val key_msg = if_proper(key, " in table " + Format.keys(key.get.rep))
   464       val key_msg = if_proper(key, " in table " + Format.keys(key.get.rep))
   462       val file_msg = if_proper(file, " in " + file.get)
   465       val file_msg = if_proper(file, " in " + file.get)
   463       isabelle.error(s + key_msg + " at line " + pos.line + file_msg)
   466       isabelle.error(s + key_msg + " at line " + pos.line + file_msg)
   464     }
   467     }
   465 
   468 
   466     def check_add_def(ks: Parsers.Keys, defn: Parsers.Def): Unit = check_add(0, ks, defn)
   469     def check_add_def(ks: Keys, defn: Parsers.Def): Unit = check_add(0, ks, defn)
   467     def check_add_value(ks0: Parsers.Keys, ks1: Parsers.Keys, v: Parsers.V): Unit =
   470     def check_add_value(ks0: Keys, ks1: Keys, v: Parsers.V): Unit =
   468       check_add(ks0.length - 1, ks0 + ks1, v)
   471       check_add(ks0.length - 1, ks0 + ks1, v)
   469   }
   472   }
   470 
   473 
   471   object Parse_Context {
   474   object Parse_Context {
   472     case class Seen(inlines: Set[Parsers.Keys], tables: Set[Parsers.Keys])
   475     case class Seen(inlines: Set[Keys], tables: Set[Keys])
   473 
   476 
   474     def apply(): Parse_Context =
   477     def apply(): Parse_Context =
   475       new Parse_Context(Map(Parsers.Keys(Nil) -> Seen(Set.empty, Set.empty)))
   478       new Parse_Context(Map(Keys(Nil) -> Seen(Set.empty, Set.empty)))
   476   }
   479   }
   477 
   480 
   478   def parse(s: Str, context: Parse_Context = Parse_Context()): Table = {
   481   def parse(s: Str, context: Parse_Context = Parse_Context()): Table = {
   479     val file =
   482     val file =
   480       Parsers.phrase(Parsers.toml)(new Lexer.Scanner(Scan.char_reader(s + EofCh))) match {
   483       Parsers.phrase(Parsers.toml)(new Lexer.Scanner(Scan.char_reader(s + EofCh))) match {
   482         case Parsers.Error(msg, next) => context.error("Error parsing toml: " + msg, next.pos)
   485         case Parsers.Error(msg, next) => context.error("Error parsing toml: " + msg, next.pos)
   483         case Parsers.Failure (msg, next) =>
   486         case Parsers.Failure (msg, next) =>
   484           context.error("Malformed TOML input: " + msg, next.pos)
   487           context.error("Malformed TOML input: " + msg, next.pos)
   485       }
   488       }
   486 
   489 
   487     def convert(ks0: Parsers.Keys, ks1: Parsers.Keys, v: Parsers.V): T = {
   490     def convert(ks0: Keys, ks1: Keys, v: Parsers.V): T = {
   488       def to_table(ks: Parsers.Keys, t: T): Table =
   491       def to_table(ks: Keys, t: T): Table =
   489         ks.parent.rep.foldRight(Table(ks.the_last -> t))((k, v) => Table(k -> v))
   492         ks.parent.rep.foldRight(Table(ks.the_last -> t))((k, v) => Table(k -> v))
   490       def to_toml(v: Parsers.V): (T, Set[Parsers.Keys]) = v match {
   493       def to_toml(v: Parsers.V): (T, Set[Keys]) = v match {
   491         case Parsers.Primitive(t) => (t, Set.empty)
   494         case Parsers.Primitive(t) => (t, Set.empty)
   492         case Parsers.Array(rep) => (Array(rep.map(to_toml(_)._1)), Set.empty)
   495         case Parsers.Array(rep) => (Array(rep.map(to_toml(_)._1)), Set.empty)
   493         case Parsers.Inline_Table(elems) =>
   496         case Parsers.Inline_Table(elems) =>
   494           elems.find(e => elems.count(_._1 == e._1) > 1).foreach((ks, _) =>
   497           elems.find(e => elems.count(_._1 == e._1) > 1).foreach((ks, _) =>
   495             context.error(
   498             context.error(
   510       }
   513       }
   511       context.check_add_value(ks0, ks1, v)
   514       context.check_add_value(ks0, ks1, v)
   512       to_toml(v)._1
   515       to_toml(v)._1
   513     }
   516     }
   514 
   517 
   515     def update(map: Table, ks0: Parsers.Keys, value: T): Table = {
   518     def update(map: Table, ks0: Keys, value: T): Table = {
   516       def error[A](s: Str): A = context.error(s, ks0.pos, Some(ks0))
   519       def error[A](s: Str): A = context.error(s, ks0.pos, Some(ks0))
   517 
   520 
   518       def update_rec(hd: Parsers.Keys, map: Table, ks: Parsers.Keys): Table = {
   521       def update_rec(hd: Keys, map: Table, ks: Keys): Table = {
   519         val updated =
   522         val updated =
   520           if (ks.length == 1) {
   523           if (ks.length == 1) {
   521             map.any.get(ks.the_head) match {
   524             map.any.get(ks.the_head) match {
   522               case Some(a: Array) =>
   525               case Some(a: Array) =>
   523                 value match {
   526                 value match {
   547             }
   550             }
   548           }
   551           }
   549         (map - ks.the_head) + (ks.the_head -> updated)
   552         (map - ks.the_head) + (ks.the_head -> updated)
   550       }
   553       }
   551 
   554 
   552       update_rec(Parsers.Keys(Nil), map, ks0)
   555       update_rec(Keys(Nil), map, ks0)
   553     }
   556     }
   554 
   557 
   555     def fold(elems: List[(Parsers.Keys, T)]): Table =
   558     def fold(elems: List[(Keys, T)]): Table =
   556       elems.foldLeft(Table()) { case (t0, (ks1, t1)) => update(t0, ks1, t1) }
   559       elems.foldLeft(Table()) { case (t0, (ks1, t1)) => update(t0, ks1, t1) }
   557 
   560 
   558     val t = fold(file.elems.map((ks, v) => (ks, convert(Parsers.Keys(Nil), ks, v))))
   561     val t = fold(file.elems.map((ks, v) => (ks, convert(Keys(Nil), ks, v))))
   559     file.defs.foldLeft(t) {
   562     file.defs.foldLeft(t) {
   560       case (t0, defn@Parsers.Table(ks0, elems)) =>
   563       case (t0, defn@Parsers.Table(ks0, elems)) =>
   561         context.check_add_def(ks0, defn)
   564         context.check_add_def(ks0, defn)
   562         update(t0, ks0, fold(elems.map((ks, v) => (ks, convert(ks0, ks, v)))))
   565         update(t0, ks0, fold(elems.map((ks, v) => (ks, convert(ks0, ks, v)))))
   563       case (t0, defn@Parsers.Array_Of_Tables(ks0, elems)) =>
   566       case (t0, defn@Parsers.Array_Of_Tables(ks0, elems)) =>