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)) => |