diff options
| author | Rob Pike <r@golang.org> | 2009-06-09 09:53:44 -0700 | 
|---|---|---|
| committer | Rob Pike <r@golang.org> | 2009-06-09 09:53:44 -0700 | 
| commit | 7249ea4df2b4f12a4e7ed446f270cea87e4ffd34 (patch) | |
| tree | 7032a11d0cac2ae4d3e90f7a189b575b5a50f848 /src/lib/json/parse.go | |
| parent | acf6ef7a82b3fe61516a1bac4563706552bdf078 (diff) | |
| download | golang-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.go | 419 | 
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 -} - | 
