summaryrefslogtreecommitdiff
path: root/src/lib/json/parse.go
diff options
context:
space:
mode:
authorRob Pike <r@golang.org>2009-06-09 09:53:44 -0700
committerRob Pike <r@golang.org>2009-06-09 09:53:44 -0700
commit7249ea4df2b4f12a4e7ed446f270cea87e4ffd34 (patch)
tree7032a11d0cac2ae4d3e90f7a189b575b5a50f848 /src/lib/json/parse.go
parentacf6ef7a82b3fe61516a1bac4563706552bdf078 (diff)
downloadgolang-7249ea4df2b4f12a4e7ed446f270cea87e4ffd34.tar.gz
mv src/lib to src/pkg
tests: all.bash passes, gobuild still works, godoc still works. R=rsc OCL=30096 CL=30102
Diffstat (limited to 'src/lib/json/parse.go')
-rw-r--r--src/lib/json/parse.go419
1 files changed, 0 insertions, 419 deletions
diff --git a/src/lib/json/parse.go b/src/lib/json/parse.go
deleted file mode 100644
index e33b9dbc1..000000000
--- a/src/lib/json/parse.go
+++ /dev/null
@@ -1,419 +0,0 @@
-// 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 (
- "fmt";
- "io";
- "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(io.ByteBuffer);
- 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
-}
-