| author | wenzelm | 
| Fri, 27 Oct 2017 17:04:41 +0200 | |
| changeset 66928 | 33f9133bed7c | 
| parent 66926 | 4cf560a6dd84 | 
| child 67111 | 42f290d8ccbd | 
| permissions | -rw-r--r-- | 
| 63992 | 1 | /* Title: Pure/General/json.scala | 
| 63644 | 2 | Author: Makarius | 
| 3 | ||
| 4 | Support for JSON parsing. | |
| 5 | */ | |
| 6 | ||
| 7 | package isabelle | |
| 8 | ||
| 9 | ||
| 66925 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 10 | import scala.util.parsing.combinator.Parsers | 
| 66922 | 11 | import scala.util.parsing.combinator.lexical.Scanners | 
| 12 | import scala.util.parsing.input.CharArrayReader.EofCh | |
| 64545 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 13 | |
| 66922 | 14 | |
| 63644 | 15 | object JSON | 
| 16 | {
 | |
| 64545 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 17 | type T = Any | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 18 | type S = String | 
| 63644 | 19 | |
| 66928 | 20 | type Object = Map[String, T] | 
| 21 | val empty: Object = Map.empty | |
| 22 | ||
| 63644 | 23 | |
| 66922 | 24 | /* lexer */ | 
| 25 | ||
| 26 | object Kind extends Enumeration | |
| 27 |   {
 | |
| 28 | val KEYWORD, STRING, NUMBER, ERROR = Value | |
| 29 | } | |
| 30 | ||
| 31 | sealed case class Token(kind: Kind.Value, text: String) | |
| 32 |   {
 | |
| 33 | def is_keyword: Boolean = kind == Kind.KEYWORD | |
| 66925 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 34 | def is_keyword(name: String): Boolean = kind == Kind.KEYWORD && text == name | 
| 66922 | 35 | def is_string: Boolean = kind == Kind.STRING | 
| 36 | def is_number: Boolean = kind == Kind.NUMBER | |
| 37 | def is_error: Boolean = kind == Kind.ERROR | |
| 38 | } | |
| 39 | ||
| 40 | object Lexer extends Scanners with Scan.Parsers | |
| 41 |   {
 | |
| 42 | override type Elem = Char | |
| 43 | type Token = JSON.Token | |
| 44 | ||
| 45 | def errorToken(msg: String): Token = Token(Kind.ERROR, msg) | |
| 46 | ||
| 47 | override val whiteSpace = """\s+""".r | |
| 48 | def whitespace: Parser[Any] = many(character(Symbol.is_ascii_blank(_))) | |
| 49 | ||
| 50 | val letter: Parser[String] = one(character(Symbol.is_ascii_letter(_))) | |
| 51 | val letters1: Parser[String] = many1(character(Symbol.is_ascii_letter(_))) | |
| 52 | ||
| 53 | def digits: Parser[String] = many(character(Symbol.is_ascii_digit(_))) | |
| 54 | def digits1: Parser[String] = many1(character(Symbol.is_ascii_digit(_))) | |
| 55 | ||
| 56 | ||
| 57 | /* keyword */ | |
| 58 | ||
| 59 | def keyword: Parser[Token] = | |
| 66924 | 60 |       (letters1 | one(character("{}[],:".contains(_)))) ^^ (s => Token(Kind.KEYWORD, s))
 | 
| 66922 | 61 | |
| 62 | ||
| 63 | /* string */ | |
| 64 | ||
| 65 | def string: Parser[Token] = | |
| 66 | '\"' ~> rep(string_body) <~ '\"' ^^ (cs => Token(Kind.STRING, cs.mkString)) | |
| 67 | ||
| 68 | def string_body: Parser[Char] = | |
| 69 |       elem("", c => c != '\"' && c != '\\' && c != EofCh) | '\\' ~> string_escape
 | |
| 70 | ||
| 71 | def string_escape: Parser[Char] = | |
| 72 |       elem("", "\"\\/".contains(_)) |
 | |
| 73 |       elem("", "bfnrt".contains(_)) ^^
 | |
| 74 |         { case 'b' => '\b' case 'f' => '\f' case 'n' => '\n' case 'r' => '\r' case 't' => '\t' } |
 | |
| 75 |       'u' ~> repeated(character("0123456789abcdefABCDEF".contains(_)), 4, 4) ^^
 | |
| 76 | (s => Integer.parseInt(s, 16).toChar) | |
| 77 | ||
| 78 |     def string_failure: Parser[Token] = '\"' ~> failure("Unterminated string")
 | |
| 79 | ||
| 80 | ||
| 81 | /* number */ | |
| 82 | ||
| 83 | def number: Parser[Token] = | |
| 84 |       opt("-" <~ whitespace) ~ number_body ~ opt(letter) ^^ {
 | |
| 85 |         case a ~ b ~ None => Token(Kind.NUMBER, a.getOrElse("") + b)
 | |
| 86 | case a ~ b ~ Some(c) => | |
| 87 |           errorToken("Invalid number format: " + quote(a.getOrElse("") + b + c))
 | |
| 88 | } | |
| 89 | ||
| 90 | def number_body: Parser[String] = | |
| 91 | (zero | positive) ~ opt(number_fract) ~ opt(number_exp) ^^ | |
| 92 |         { case a ~ b ~ c => a + b.getOrElse("") + c.getOrElse("") }
 | |
| 93 | ||
| 94 |     def number_fract: Parser[String] = "." ~ digits1 ^^ { case a ~ b => a + b }
 | |
| 95 | ||
| 96 | def number_exp: Parser[String] = | |
| 97 |       one(character("eE".contains(_))) ~ maybe(character("-+".contains(_))) ~ digits1 ^^
 | |
| 98 |         { case a ~ b ~ c => a + b + c }
 | |
| 99 | ||
| 100 | def zero = one(character(c => c == '0')) | |
| 101 | def nonzero = one(character(c => c != '0' && Symbol.is_ascii_digit(c))) | |
| 102 |     def positive: Parser[String] = nonzero ~ digits ^^ { case a ~ b => a + b }
 | |
| 103 | ||
| 104 | ||
| 105 | /* token */ | |
| 106 | ||
| 107 | def token: Parser[Token] = | |
| 108 |       keyword | (string | (string_failure | (number | failure("Illegal character"))))
 | |
| 109 | } | |
| 110 | ||
| 111 | ||
| 66925 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 112 | /* parser */ | 
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 113 | |
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 114 | trait Parser extends Parsers | 
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 115 |   {
 | 
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 116 | type Elem = Token | 
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 117 | |
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 118 | def $$$(name: String): Parser[Token] = elem(name, _.is_keyword(name)) | 
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 119 |     def string: Parser[String] = elem("string", _.is_string) ^^ (_.text)
 | 
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 120 |     def number: Parser[Double] = elem("number", _.is_number) ^^ (tok => tok.text.toDouble)
 | 
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 121 | |
| 66928 | 122 | def json_object: Parser[Object] = | 
| 66925 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 123 |       $$$("{") ~>
 | 
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 124 |         repsep(string ~ ($$$(":") ~> json_value) ^^ { case a ~ b => (a, b) }, $$$(",")) <~
 | 
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 125 |       $$$("}") ^^ (_.toMap)
 | 
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 126 | |
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 127 | def json_array: Parser[List[T]] = | 
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 128 |       $$$("[") ~> repsep(json_value, $$$(",")) <~ $$$("]")
 | 
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 129 | |
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 130 | def json_value: Parser[T] = | 
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 131 | json_object | (json_array | (number | (string | | 
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 132 |         ($$$("true") ^^^ true | ($$$("false") ^^^ false | ($$$("null") ^^^ null))))))
 | 
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 133 | |
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 134 | def parse(input: CharSequence, strict: Boolean): T = | 
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 135 |     {
 | 
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 136 | val scanner = new Lexer.Scanner(Scan.char_reader(input)) | 
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 137 |       phrase(if (strict) json_object | json_array else json_value)(scanner) match {
 | 
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 138 | case Success(json, _) => json | 
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 139 |         case NoSuccess(_, next) => error("Malformed JSON input at " + next.pos)
 | 
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 140 | } | 
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 141 | } | 
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 142 | } | 
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 143 | |
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 144 | object Parser extends Parser | 
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 145 | |
| 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 146 | |
| 64545 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 147 | /* standard format */ | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 148 | |
| 66925 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 149 | def parse(s: S, strict: Boolean = true): T = Parser.parse(s, strict) | 
| 64545 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 150 | |
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 151 | object Format | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 152 |   {
 | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 153 | def unapply(s: S): Option[T] = | 
| 66925 
8b117dc73278
separate JSON parser, which is slightly more general than (deprecated) scala.util.parsing.json.JSON;
 wenzelm parents: 
66924diff
changeset | 154 |       try { Some(parse(s, strict = false)) }
 | 
| 64545 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 155 |       catch { case ERROR(_) => None }
 | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 156 | |
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 157 | def apply(json: T): S = | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 158 |     {
 | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 159 | val result = new StringBuilder | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 160 | |
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 161 | def string(s: String) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 162 |       {
 | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 163 | result += '"' | 
| 64761 | 164 | result ++= | 
| 165 |           s.iterator.map {
 | |
| 166 | case '"' => "\\\"" | |
| 167 | case '\\' => "\\\\" | |
| 168 | case '\b' => "\\b" | |
| 169 | case '\f' => "\\f" | |
| 170 | case '\n' => "\\n" | |
| 171 | case '\r' => "\\r" | |
| 172 | case '\t' => "\\t" | |
| 173 | case c => | |
| 174 | if (c <= '\u001f' || c >= '\u007f' && c <= '\u009f') "\\u%04x".format(c.toInt) | |
| 175 | else c | |
| 176 | }.mkString | |
| 64545 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 177 | result += '"' | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 178 | } | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 179 | |
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 180 | def array(list: List[T]) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 181 |       {
 | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 182 | result += '[' | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 183 |         Library.separate(None, list.map(Some(_))).foreach({
 | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 184 | case None => result += ',' | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 185 | case Some(x) => json_format(x) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 186 | }) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 187 | result += ']' | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 188 | } | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 189 | |
| 66928 | 190 | def object_(obj: Object) | 
| 64545 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 191 |       {
 | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 192 |         result += '{'
 | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 193 |         Library.separate(None, obj.toList.map(Some(_))).foreach({
 | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 194 | case None => result += ',' | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 195 | case Some((x, y)) => | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 196 | string(x) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 197 | result += ':' | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 198 | json_format(y) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 199 | }) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 200 | result += '}' | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 201 | } | 
| 63644 | 202 | |
| 64545 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 203 | def json_format(x: T) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 204 |       {
 | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 205 |         x match {
 | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 206 | case null => result ++= "null" | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 207 | case _: Int | _: Long | _: Boolean => result ++= x.toString | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 208 | case n: Double => | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 209 | val i = n.toLong | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 210 | result ++= (if (i.toDouble == n) i.toString else n.toString) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 211 | case s: String => string(s) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 212 | case obj: Map[_, _] if obj.keySet.forall(_.isInstanceOf[String]) => | 
| 66928 | 213 | object_(obj.asInstanceOf[Object]) | 
| 64545 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 214 | case list: List[T] => array(list) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 215 |           case _ => error("Bad JSON value: " + x.toString)
 | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 216 | } | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 217 | } | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 218 | |
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 219 | json_format(json) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 220 | result.toString | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 221 | } | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 222 | } | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 223 | |
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 224 | |
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 225 | /* numbers */ | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 226 | |
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 227 | object Number | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 228 |   {
 | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 229 |     object Double {
 | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 230 | def unapply(json: T): Option[scala.Double] = | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 231 |         json match {
 | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 232 | case x: scala.Double => Some(x) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 233 | case x: scala.Long => Some(x.toDouble) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 234 | case x: scala.Int => Some(x.toDouble) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 235 | case _ => None | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 236 | } | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 237 | } | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 238 | |
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 239 |     object Long {
 | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 240 | def unapply(json: T): Option[scala.Long] = | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 241 |         json match {
 | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 242 | case x: scala.Double if x.toLong.toDouble == x => Some(x.toLong) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 243 | case x: scala.Long => Some(x) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 244 | case x: scala.Int => Some(x.toLong) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 245 | case _ => None | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 246 | } | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 247 | } | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 248 | |
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 249 |     object Int {
 | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 250 | def unapply(json: T): Option[scala.Int] = | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 251 |         json match {
 | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 252 | case x: scala.Double if x.toInt.toDouble == x => Some(x.toInt) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 253 | case x: scala.Long if x.toInt.toLong == x => Some(x.toInt) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 254 | case x: scala.Int => Some(x) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 255 | case _ => None | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 256 | } | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 257 | } | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 258 | } | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 259 | |
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 260 | |
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 261 | /* object values */ | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 262 | |
| 66928 | 263 | def optional(entry: (String, Option[T])): Object = | 
| 64878 | 264 |     entry match {
 | 
| 265 | case (name, Some(x)) => Map(name -> x) | |
| 66926 | 266 | case (_, None) => empty | 
| 64878 | 267 | } | 
| 268 | ||
| 64545 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 269 | def value(obj: T, name: String): Option[T] = | 
| 63644 | 270 |     obj match {
 | 
| 64545 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 271 | case m: Map[_, _] if m.keySet.forall(_.isInstanceOf[String]) => | 
| 66928 | 272 | m.asInstanceOf[Object].get(name) | 
| 63644 | 273 | case _ => None | 
| 274 | } | |
| 275 | ||
| 64545 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 276 | def value[A](obj: T, name: String, unapply: T => Option[A]): Option[A] = | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 277 |     for {
 | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 278 | json <- value(obj, name) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 279 | x <- unapply(json) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 280 | } yield x | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 281 | |
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 282 | def array(obj: T, name: String): Option[List[T]] = | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 283 |     value(obj, name) match {
 | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 284 | case Some(a: List[T]) => Some(a) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 285 | case _ => None | 
| 63644 | 286 | } | 
| 287 | ||
| 64545 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 288 | def array[A](obj: T, name: String, unapply: T => Option[A]): Option[List[A]] = | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 289 |     for {
 | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 290 | a0 <- array(obj, name) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 291 | a = a0.map(unapply(_)) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 292 | if a.forall(_.isDefined) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 293 | } yield a.map(_.get) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 294 | |
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 295 | def string(obj: T, name: String): Option[String] = | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 296 |     value(obj, name) match {
 | 
| 63644 | 297 | case Some(x: String) => Some(x) | 
| 298 | case _ => None | |
| 299 | } | |
| 300 | ||
| 64545 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 301 | def double(obj: T, name: String): Option[Double] = | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 302 | value(obj, name, Number.Double.unapply) | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 303 | |
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 304 | def long(obj: T, name: String): Option[Long] = | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 305 | value(obj, name, Number.Long.unapply) | 
| 63644 | 306 | |
| 64545 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 307 | def int(obj: T, name: String): Option[Int] = | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 308 | value(obj, name, Number.Int.unapply) | 
| 63644 | 309 | |
| 64545 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 310 | def bool(obj: T, name: String): Option[Boolean] = | 
| 
25045094d7bb
clarified JSON operations (see isabelle_vscode/a7931dc2a1ab);
 wenzelm parents: 
63992diff
changeset | 311 |     value(obj, name) match {
 | 
| 63644 | 312 | case Some(x: Boolean) => Some(x) | 
| 313 | case _ => None | |
| 314 | } | |
| 315 | } |