| // Copyright 2009 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| // JSON (JavaScript Object Notation) parser. | |
| // See http://www.json.org/ | |
| // The json package implements a simple parser and | |
| // representation for JSON (JavaScript Object Notation), | |
| // as defined at http://www.json.org/. | |
| package json | |
| import ( | |
| "bytes"; | |
| "fmt"; | |
| "math"; | |
| "strconv"; | |
| "strings"; | |
| "utf8"; | |
| ) | |
| // Strings | |
| // | |
| // Double quoted with escapes: \" \\ \/ \b \f \n \r \t \uXXXX. | |
| // No literal control characters, supposedly. | |
| // Have also seen \' and embedded newlines. | |
| func _UnHex(p string, r, l int) (v int, ok bool) { | |
| v = 0; | |
| for i := r; i < l; i++ { | |
| if i >= len(p) { | |
| return 0, false | |
| } | |
| v *= 16; | |
| switch { | |
| case '0' <= p[i] && p[i] <= '9': | |
| v += int(p[i] - '0'); | |
| case 'a' <= p[i] && p[i] <= 'f': | |
| v += int(p[i] - 'a' + 10); | |
| case 'A' <= p[i] && p[i] <= 'F': | |
| v += int(p[i] - 'A' + 10); | |
| default: | |
| return 0, false; | |
| } | |
| } | |
| return v, true; | |
| } | |
| // Unquote unquotes the JSON-quoted string s, | |
| // returning a raw string t. If s is not a valid | |
| // JSON-quoted string, Unquote returns with ok set to false. | |
| func Unquote(s string) (t string, ok bool) { | |
| if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { | |
| return | |
| } | |
| b := make([]byte, len(s)); | |
| w := 0; | |
| for r := 1; r < len(s)-1; { | |
| switch { | |
| case s[r] == '\\': | |
| r++; | |
| if r >= len(s)-1 { | |
| return | |
| } | |
| switch s[r] { | |
| default: | |
| return; | |
| case '"', '\\', '/', '\'': | |
| b[w] = s[r]; | |
| r++; | |
| w++; | |
| case 'b': | |
| b[w] = '\b'; | |
| r++; | |
| w++; | |
| case 'f': | |
| b[w] = '\f'; | |
| r++; | |
| w++; | |
| case 'n': | |
| b[w] = '\n'; | |
| r++; | |
| w++; | |
| case 'r': | |
| b[w] = '\r'; | |
| r++; | |
| w++; | |
| case 't': | |
| b[w] = '\t'; | |
| r++; | |
| w++; | |
| case 'u': | |
| r++; | |
| rune, ok := _UnHex(s, r, 4); | |
| if !ok { | |
| return | |
| } | |
| r += 4; | |
| w += utf8.EncodeRune(rune, b[w:len(b)]); | |
| } | |
| // Control characters are invalid, but we've seen raw \n. | |
| case s[r] < ' ' && s[r] != '\n': | |
| if s[r] == '\n' { | |
| b[w] = '\n'; | |
| r++; | |
| w++; | |
| break; | |
| } | |
| return; | |
| // ASCII | |
| case s[r] < utf8.RuneSelf: | |
| b[w] = s[r]; | |
| r++; | |
| w++; | |
| // Coerce to well-formed UTF-8. | |
| default: | |
| rune, size := utf8.DecodeRuneInString(s[r:len(s)]); | |
| r += size; | |
| w += utf8.EncodeRune(rune, b[w:len(b)]); | |
| } | |
| } | |
| return string(b[0:w]), true | |
| } | |
| // Quote quotes the raw string s using JSON syntax, | |
| // so that Unquote(Quote(s)) = s, true. | |
| func Quote(s string) string { | |
| chr := make([]byte, utf8.UTFMax); | |
| chr0 := chr[0:1]; | |
| b := new(bytes.Buffer); | |
| chr[0] = '"'; | |
| b.Write(chr0); | |
| for i := 0; i < len(s); i++ { | |
| switch { | |
| case s[i]=='"' || s[i]=='\\': | |
| chr[0] = '\\'; | |
| chr[1] = s[i]; | |
| b.Write(chr[0:2]); | |
| case s[i] == '\b': | |
| chr[0] = '\\'; | |
| chr[1] = 'b'; | |
| b.Write(chr[0:2]); | |
| case s[i] == '\f': | |
| chr[0] = '\\'; | |
| chr[1] = 'f'; | |
| b.Write(chr[0:2]); | |
| case s[i] == '\n': | |
| chr[0] = '\\'; | |
| chr[1] = 'n'; | |
| b.Write(chr[0:2]); | |
| case s[i] == '\r': | |
| chr[0] = '\\'; | |
| chr[1] = 'r'; | |
| b.Write(chr[0:2]); | |
| case s[i] == '\t': | |
| chr[0] = '\\'; | |
| chr[1] = 't'; | |
| b.Write(chr[0:2]); | |
| case 0x20 <= s[i] && s[i] < utf8.RuneSelf: | |
| chr[0] = s[i]; | |
| b.Write(chr0); | |
| } | |
| } | |
| chr[0] = '"'; | |
| b.Write(chr0); | |
| return string(b.Data()); | |
| } | |
| // _Lexer | |
| type _Lexer struct { | |
| s string; | |
| i int; | |
| kind int; | |
| token string; | |
| } | |
| func punct(c byte) bool { | |
| return c=='"' || c=='[' || c==']' || c==':' || c=='{' || c=='}' || c==',' | |
| } | |
| func white(c byte) bool { | |
| return c==' ' || c=='\t' || c=='\n' || c=='\v' | |
| } | |
| func skipwhite(p string, i int) int { | |
| for i < len(p) && white(p[i]) { | |
| i++ | |
| } | |
| return i | |
| } | |
| func skiptoken(p string, i int) int { | |
| for i < len(p) && !punct(p[i]) && !white(p[i]) { | |
| i++ | |
| } | |
| return i | |
| } | |
| func skipstring(p string, i int) int { | |
| for i++; i < len(p) && p[i] != '"'; i++ { | |
| if p[i] == '\\' { | |
| i++ | |
| } | |
| } | |
| if i >= len(p) { | |
| return i | |
| } | |
| return i+1 | |
| } | |
| func (t *_Lexer) Next() { | |
| i, s := t.i, t.s; | |
| i = skipwhite(s, i); | |
| if i >= len(s) { | |
| t.kind = 0; | |
| t.token = ""; | |
| t.i = len(s); | |
| return; | |
| } | |
| c := s[i]; | |
| switch { | |
| case c == '-' || '0' <= c && c <= '9': | |
| j := skiptoken(s, i); | |
| t.kind = '1'; | |
| t.token = s[i:j]; | |
| i = j; | |
| case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z': | |
| j := skiptoken(s, i); | |
| t.kind = 'a'; | |
| t.token = s[i:j]; | |
| i = j; | |
| case c == '"': | |
| j := skipstring(s, i); | |
| t.kind = '"'; | |
| t.token = s[i:j]; | |
| i = j; | |
| case c == '[', c == ']', c == ':', c == '{', c == '}', c == ',': | |
| t.kind = int(c); | |
| t.token = s[i:i+1]; | |
| i++; | |
| default: | |
| t.kind = '?'; | |
| t.token = s[i:i+1]; | |
| } | |
| t.i = i; | |
| } | |
| // Parser | |
| // | |
| // Implements parsing but not the actions. Those are | |
| // carried out by the implementation of the Builder interface. | |
| // A Builder represents the object being created. | |
| // Calling a method like Int64(i) sets that object to i. | |
| // Calling a method like Elem(i) or Key(s) creates a | |
| // new builder for a subpiece of the object (logically, | |
| // an array element or a map key). | |
| // | |
| // There are two Builders, in other files. | |
| // The JsonBuilder builds a generic Json structure | |
| // in which maps are maps. | |
| // The StructBuilder copies data into a possibly | |
| // nested data structure, using the "map keys" | |
| // as struct field names. | |
| type _Value interface {} | |
| // BUG(rsc): The json Builder interface needs to be | |
| // reconciled with the xml Builder interface. | |
| // A Builder is an interface implemented by clients and passed | |
| // to the JSON parser. It gives clients full control over the | |
| // eventual representation returned by the parser. | |
| type Builder interface { | |
| // Set value | |
| Int64(i int64); | |
| Uint64(i uint64); | |
| Float64(f float64); | |
| String(s string); | |
| Bool(b bool); | |
| Null(); | |
| Array(); | |
| Map(); | |
| // Create sub-Builders | |
| Elem(i int) Builder; | |
| Key(s string) Builder; | |
| } | |
| func parse(lex *_Lexer, build Builder) bool { | |
| ok := false; | |
| Switch: | |
| switch lex.kind { | |
| case 0: | |
| break; | |
| case '1': | |
| // If the number is exactly an integer, use that. | |
| if i, err := strconv.Atoi64(lex.token); err == nil { | |
| build.Int64(i); | |
| ok = true; | |
| } | |
| else if i, err := strconv.Atoui64(lex.token); err == nil { | |
| build.Uint64(i); | |
| ok = true; | |
| } | |
| // Fall back to floating point. | |
| else if f, err := strconv.Atof64(lex.token); err == nil { | |
| build.Float64(f); | |
| ok = true; | |
| } | |
| case 'a': | |
| switch lex.token { | |
| case "true": | |
| build.Bool(true); | |
| ok = true; | |
| case "false": | |
| build.Bool(false); | |
| ok = true; | |
| case "null": | |
| build.Null(); | |
| ok = true; | |
| } | |
| case '"': | |
| if str, ok1 := Unquote(lex.token); ok1 { | |
| build.String(str); | |
| ok = true; | |
| } | |
| case '[': | |
| // array | |
| build.Array(); | |
| lex.Next(); | |
| n := 0; | |
| for lex.kind != ']' { | |
| if n > 0 { | |
| if lex.kind != ',' { | |
| break Switch; | |
| } | |
| lex.Next(); | |
| } | |
| if !parse(lex, build.Elem(n)) { | |
| break Switch; | |
| } | |
| n++; | |
| } | |
| ok = true; | |
| case '{': | |
| // map | |
| lex.Next(); | |
| build.Map(); | |
| n := 0; | |
| for lex.kind != '}' { | |
| if n > 0 { | |
| if lex.kind != ',' { | |
| break Switch; | |
| } | |
| lex.Next(); | |
| } | |
| if lex.kind != '"' { | |
| break Switch; | |
| } | |
| key, ok := Unquote(lex.token); | |
| if !ok { | |
| break Switch; | |
| } | |
| lex.Next(); | |
| if lex.kind != ':' { | |
| break Switch; | |
| } | |
| lex.Next(); | |
| if !parse(lex, build.Key(key)) { | |
| break Switch; | |
| } | |
| n++; | |
| } | |
| ok = true; | |
| } | |
| if ok { | |
| lex.Next(); | |
| } | |
| return ok; | |
| } | |
| // Parse parses the JSON syntax string s and makes calls to | |
| // the builder to construct a parsed representation. | |
| // On success, it returns with ok set to true. | |
| // On error, it returns with ok set to false, errindx set | |
| // to the byte index in s where a syntax error occurred, | |
| // and errtok set to the offending token. | |
| func Parse(s string, builder Builder) (ok bool, errindx int, errtok string) { | |
| lex := new(_Lexer); | |
| lex.s = s; | |
| lex.Next(); | |
| if parse(lex, builder) { | |
| if lex.kind == 0 { // EOF | |
| return true, 0, "" | |
| } | |
| } | |
| return false, lex.i, lex.token | |
| } | |