| // 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"; |
| "strconv"; |
| "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 b.String(); |
| } |
| |
| |
| // _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; |
| |
| // Flush changes to parent Builder if necessary. |
| Flush(); |
| } |
| |
| 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; |
| } else |
| // Fall back to floating point. |
| 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() |
| } |
| build.Flush(); |
| 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; |
| } |