Commit 9d49f4d0 by Ian Lance Taylor

Update Go library to release r60.1.

From-SVN: r179076
parent 270aae33
504f4e9b079c fd30c132d1bd
The first line of this file holds the Mercurial revision number of the The first line of this file holds the Mercurial revision number of the
last merge done from the master library sources. last merge done from the master library sources.
...@@ -636,7 +636,8 @@ go_json_files = \ ...@@ -636,7 +636,8 @@ go_json_files = \
go/json/encode.go \ go/json/encode.go \
go/json/indent.go \ go/json/indent.go \
go/json/scanner.go \ go/json/scanner.go \
go/json/stream.go go/json/stream.go \
go/json/tags.go
go_log_files = \ go_log_files = \
go/log/log.go go/log/log.go
......
...@@ -1037,7 +1037,8 @@ go_json_files = \ ...@@ -1037,7 +1037,8 @@ go_json_files = \
go/json/encode.go \ go/json/encode.go \
go/json/indent.go \ go/json/indent.go \
go/json/scanner.go \ go/json/scanner.go \
go/json/stream.go go/json/stream.go \
go/json/tags.go
go_log_files = \ go_log_files = \
go/log/log.go go/log/log.go
......
// Copyright 2011 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.
// type declarations
package test0
import "unsafe"
const pi = 3.1415
type (
N undeclared /* ERROR "undeclared" */
B bool
I int32
A [10]P
T struct {
x, y P
}
P *T
R (*R)
F func(A) I
Y interface {
f(A) I
}
S [](((P)))
M map[I]F
C chan<- I
)
type (
p1 pi /* ERROR "not a package" */ .foo
p2 unsafe.Pointer
)
type (
Pi pi /* ERROR "not a type" */
a /* DISABLED "illegal cycle" */ a
a /* ERROR "redeclared" */ int
// where the cycle error appears depends on the
// order in which declarations are processed
// (which depends on the order in which a map
// is iterated through)
b c
c /* DISABLED "illegal cycle" */ d
d e
e b
t *t
U V
V *W
W U
P1 *S2
P2 P1
S0 struct {
}
S1 struct {
a, b, c int
u, v, a /* ERROR "redeclared" */ float32
}
S2 struct {
U // anonymous field
// TODO(gri) recognize double-declaration below
// U /* ERROR "redeclared" */ int
}
S3 struct {
x S2
}
S4/* DISABLED "illegal cycle" */ struct {
S4
}
S5 struct {
S6
}
S6 /* DISABLED "illegal cycle" */ struct {
field S7
}
S7 struct {
S5
}
L1 []L1
L2 []int
A1 [10]int
A2 /* DISABLED "illegal cycle" */ [10]A2
A3 /* DISABLED "illegal cycle" */ [10]struct {
x A4
}
A4 [10]A3
F1 func()
F2 func(x, y, z float32)
F3 func(x, y, x /* ERROR "redeclared" */ float32)
F4 func() (x, y, x /* ERROR "redeclared" */ float32)
F5 func(x int) (x /* ERROR "redeclared" */ float32)
F6 func(x ...int)
I1 interface{}
I2 interface {
m1()
}
I3 interface {
m1()
m1 /* ERROR "redeclared" */ ()
}
I4 interface {
m1(x, y, x /* ERROR "redeclared" */ float32)
m2() (x, y, x /* ERROR "redeclared" */ float32)
m3(x int) (x /* ERROR "redeclared" */ float32)
}
I5 interface {
m1(I5)
}
I6 interface {
S0 /* ERROR "non-interface" */
}
I7 interface {
I1
I1
}
I8 /* DISABLED "illegal cycle" */ interface {
I8
}
I9 /* DISABLED "illegal cycle" */ interface {
I10
}
I10 interface {
I11
}
I11 interface {
I9
}
C1 chan int
C2 <-chan int
C3 chan<- C3
C4 chan C5
C5 chan C6
C6 chan C4
M1 map[Last]string
M2 map[string]M2
Last int
)
...@@ -221,6 +221,9 @@ In summary, a gob stream looks like ...@@ -221,6 +221,9 @@ In summary, a gob stream looks like
where * signifies zero or more repetitions and the type id of a value must where * signifies zero or more repetitions and the type id of a value must
be predefined or be defined before the value in the stream. be predefined or be defined before the value in the stream.
See "Gobs of data" for a design discussion of the gob wire format:
http://blog.golang.org/2011/03/gobs-of-data.html
*/ */
package gob package gob
......
...@@ -374,6 +374,8 @@ func TestCopyError(t *testing.T) { ...@@ -374,6 +374,8 @@ func TestCopyError(t *testing.T) {
} }
} }
/* This test doesn't work in gccgo's testing environment.
func TestDirUnix(t *testing.T) { func TestDirUnix(t *testing.T) {
if skipTest(t) || runtime.GOOS == "windows" { if skipTest(t) || runtime.GOOS == "windows" {
return return
...@@ -402,6 +404,8 @@ func TestDirUnix(t *testing.T) { ...@@ -402,6 +404,8 @@ func TestDirUnix(t *testing.T) {
runCgiTest(t, h, "GET /test.cgi HTTP/1.0\nHost: example.com\n\n", expectedMap) runCgiTest(t, h, "GET /test.cgi HTTP/1.0\nHost: example.com\n\n", expectedMap)
} }
*/
func TestDirWindows(t *testing.T) { func TestDirWindows(t *testing.T) {
if skipTest(t) || runtime.GOOS != "windows" { if skipTest(t) || runtime.GOOS != "windows" {
return return
......
#!/usr/bin/perl
# Copyright 2011 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.
#
# Test script run as a child process under cgi_test.go
use strict;
use Cwd;
my $q = MiniCGI->new;
my $params = $q->Vars;
if ($params->{"loc"}) {
print "Location: $params->{loc}\r\n\r\n";
exit(0);
}
my $NL = "\r\n";
$NL = "\n" if $params->{mode} eq "NL";
my $p = sub {
print "$_[0]$NL";
};
# With carriage returns
$p->("Content-Type: text/html");
$p->("X-CGI-Pid: $$");
$p->("X-Test-Header: X-Test-Value");
$p->("");
if ($params->{"bigresponse"}) {
for (1..1024) {
print "A" x 1024, "\n";
}
exit 0;
}
print "test=Hello CGI\n";
foreach my $k (sort keys %$params) {
print "param-$k=$params->{$k}\n";
}
foreach my $k (sort keys %ENV) {
my $clean_env = $ENV{$k};
$clean_env =~ s/[\n\r]//g;
print "env-$k=$clean_env\n";
}
# NOTE: don't call getcwd() for windows.
# msys return /c/go/src/... not C:\go\...
my $dir;
if ($^O eq 'MSWin32' || $^O eq 'msys') {
my $cmd = $ENV{'COMSPEC'} || 'c:\\windows\\system32\\cmd.exe';
$cmd =~ s!\\!/!g;
$dir = `$cmd /c cd`;
chomp $dir;
} else {
$dir = getcwd();
}
print "cwd=$dir\n";
# A minimal version of CGI.pm, for people without the perl-modules
# package installed. (CGI.pm used to be part of the Perl core, but
# some distros now bundle perl-base and perl-modules separately...)
package MiniCGI;
sub new {
my $class = shift;
return bless {}, $class;
}
sub Vars {
my $self = shift;
my $pairs;
if ($ENV{CONTENT_LENGTH}) {
$pairs = do { local $/; <STDIN> };
} else {
$pairs = $ENV{QUERY_STRING};
}
my $vars = {};
foreach my $kv (split(/&/, $pairs)) {
my ($k, $v) = split(/=/, $kv, 2);
$vars->{_urldecode($k)} = _urldecode($v);
}
return $vars;
}
sub _urldecode {
my $v = shift;
$v =~ tr/+/ /;
$v =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
return $v;
}
...@@ -140,6 +140,7 @@ type decodeState struct { ...@@ -140,6 +140,7 @@ type decodeState struct {
scan scanner scan scanner
nextscan scanner // for calls to nextValue nextscan scanner // for calls to nextValue
savedError os.Error savedError os.Error
tempstr string // scratch space to avoid some allocations
} }
// errPhase is used for errors that should not happen unless // errPhase is used for errors that should not happen unless
...@@ -470,6 +471,8 @@ func (d *decodeState) object(v reflect.Value) { ...@@ -470,6 +471,8 @@ func (d *decodeState) object(v reflect.Value) {
// Figure out field corresponding to key. // Figure out field corresponding to key.
var subv reflect.Value var subv reflect.Value
destring := false // whether the value is wrapped in a string to be decoded first
if mv.IsValid() { if mv.IsValid() {
elemType := mv.Type().Elem() elemType := mv.Type().Elem()
if !mapElem.IsValid() { if !mapElem.IsValid() {
...@@ -486,7 +489,8 @@ func (d *decodeState) object(v reflect.Value) { ...@@ -486,7 +489,8 @@ func (d *decodeState) object(v reflect.Value) {
if isValidTag(key) { if isValidTag(key) {
for i := 0; i < sv.NumField(); i++ { for i := 0; i < sv.NumField(); i++ {
f = st.Field(i) f = st.Field(i)
if f.Tag.Get("json") == key { tagName, _ := parseTag(f.Tag.Get("json"))
if tagName == key {
ok = true ok = true
break break
} }
...@@ -508,6 +512,8 @@ func (d *decodeState) object(v reflect.Value) { ...@@ -508,6 +512,8 @@ func (d *decodeState) object(v reflect.Value) {
} else { } else {
subv = sv.FieldByIndex(f.Index) subv = sv.FieldByIndex(f.Index)
} }
_, opts := parseTag(f.Tag.Get("json"))
destring = opts.Contains("string")
} }
} }
...@@ -520,8 +526,12 @@ func (d *decodeState) object(v reflect.Value) { ...@@ -520,8 +526,12 @@ func (d *decodeState) object(v reflect.Value) {
} }
// Read value. // Read value.
if destring {
d.value(reflect.ValueOf(&d.tempstr))
d.literalStore([]byte(d.tempstr), subv)
} else {
d.value(subv) d.value(subv)
}
// Write value back to map; // Write value back to map;
// if using struct, subv points into struct already. // if using struct, subv points into struct already.
if mv.IsValid() { if mv.IsValid() {
...@@ -550,8 +560,12 @@ func (d *decodeState) literal(v reflect.Value) { ...@@ -550,8 +560,12 @@ func (d *decodeState) literal(v reflect.Value) {
// Scan read one byte too far; back up. // Scan read one byte too far; back up.
d.off-- d.off--
d.scan.undo(op) d.scan.undo(op)
item := d.data[start:d.off]
d.literalStore(d.data[start:d.off], v)
}
// literalStore decodes a literal stored in item into v.
func (d *decodeState) literalStore(item []byte, v reflect.Value) {
// Check for unmarshaler. // Check for unmarshaler.
wantptr := item[0] == 'n' // null wantptr := item[0] == 'n' // null
unmarshaler, pv := d.indirect(v, wantptr) unmarshaler, pv := d.indirect(v, wantptr)
......
...@@ -263,6 +263,9 @@ type All struct { ...@@ -263,6 +263,9 @@ type All struct {
Float64 float64 Float64 float64
Foo string `json:"bar"` Foo string `json:"bar"`
Foo2 string `json:"bar2,dummyopt"`
IntStr int64 `json:",string"`
PBool *bool PBool *bool
PInt *int PInt *int
...@@ -331,6 +334,8 @@ var allValue = All{ ...@@ -331,6 +334,8 @@ var allValue = All{
Float32: 14.1, Float32: 14.1,
Float64: 15.1, Float64: 15.1,
Foo: "foo", Foo: "foo",
Foo2: "foo2",
IntStr: 42,
String: "16", String: "16",
Map: map[string]Small{ Map: map[string]Small{
"17": {Tag: "tag17"}, "17": {Tag: "tag17"},
...@@ -391,6 +396,8 @@ var allValueIndent = `{ ...@@ -391,6 +396,8 @@ var allValueIndent = `{
"Float32": 14.1, "Float32": 14.1,
"Float64": 15.1, "Float64": 15.1,
"bar": "foo", "bar": "foo",
"bar2": "foo2",
"IntStr": "42",
"PBool": null, "PBool": null,
"PInt": null, "PInt": null,
"PInt8": null, "PInt8": null,
...@@ -481,6 +488,8 @@ var pallValueIndent = `{ ...@@ -481,6 +488,8 @@ var pallValueIndent = `{
"Float32": 0, "Float32": 0,
"Float64": 0, "Float64": 0,
"bar": "", "bar": "",
"bar2": "",
"IntStr": "0",
"PBool": true, "PBool": true,
"PInt": 2, "PInt": 2,
"PInt8": 3, "PInt8": 3,
......
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
// Package json implements encoding and decoding of JSON objects as defined in // Package json implements encoding and decoding of JSON objects as defined in
// RFC 4627. // RFC 4627.
//
// See "JSON and Go" for an introduction to this package:
// http://blog.golang.org/2011/01/json-and-go.html
package json package json
import ( import (
...@@ -14,7 +17,6 @@ import ( ...@@ -14,7 +17,6 @@ import (
"runtime" "runtime"
"sort" "sort"
"strconv" "strconv"
"strings"
"unicode" "unicode"
"utf8" "utf8"
) )
...@@ -59,6 +61,12 @@ import ( ...@@ -59,6 +61,12 @@ import (
// // Note the leading comma. // // Note the leading comma.
// Field int `json:",omitempty"` // Field int `json:",omitempty"`
// //
// The "string" option signals that a field is stored as JSON inside a
// JSON-encoded string. This extra level of encoding is sometimes
// used when communicating with JavaScript programs:
//
// Int64String int64 `json:",string"`
//
// The key name will be used if it's a non-empty string consisting of // The key name will be used if it's a non-empty string consisting of
// only Unicode letters, digits, dollar signs, hyphens, and underscores. // only Unicode letters, digits, dollar signs, hyphens, and underscores.
// //
...@@ -221,6 +229,12 @@ func isEmptyValue(v reflect.Value) bool { ...@@ -221,6 +229,12 @@ func isEmptyValue(v reflect.Value) bool {
} }
func (e *encodeState) reflectValue(v reflect.Value) { func (e *encodeState) reflectValue(v reflect.Value) {
e.reflectValueQuoted(v, false)
}
// reflectValueQuoted writes the value in v to the output.
// If quoted is true, the serialization is wrapped in a JSON string.
func (e *encodeState) reflectValueQuoted(v reflect.Value, quoted bool) {
if !v.IsValid() { if !v.IsValid() {
e.WriteString("null") e.WriteString("null")
return return
...@@ -238,26 +252,39 @@ func (e *encodeState) reflectValue(v reflect.Value) { ...@@ -238,26 +252,39 @@ func (e *encodeState) reflectValue(v reflect.Value) {
return return
} }
writeString := (*encodeState).WriteString
if quoted {
writeString = (*encodeState).string
}
switch v.Kind() { switch v.Kind() {
case reflect.Bool: case reflect.Bool:
x := v.Bool() x := v.Bool()
if x { if x {
e.WriteString("true") writeString(e, "true")
} else { } else {
e.WriteString("false") writeString(e, "false")
} }
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
e.WriteString(strconv.Itoa64(v.Int())) writeString(e, strconv.Itoa64(v.Int()))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
e.WriteString(strconv.Uitoa64(v.Uint())) writeString(e, strconv.Uitoa64(v.Uint()))
case reflect.Float32, reflect.Float64: case reflect.Float32, reflect.Float64:
e.WriteString(strconv.FtoaN(v.Float(), 'g', -1, v.Type().Bits())) writeString(e, strconv.FtoaN(v.Float(), 'g', -1, v.Type().Bits()))
case reflect.String: case reflect.String:
if quoted {
sb, err := Marshal(v.String())
if err != nil {
e.error(err)
}
e.string(string(sb))
} else {
e.string(v.String()) e.string(v.String())
}
case reflect.Struct: case reflect.Struct:
e.WriteByte('{') e.WriteByte('{')
...@@ -269,17 +296,14 @@ func (e *encodeState) reflectValue(v reflect.Value) { ...@@ -269,17 +296,14 @@ func (e *encodeState) reflectValue(v reflect.Value) {
if f.PkgPath != "" { if f.PkgPath != "" {
continue continue
} }
tag, omitEmpty := f.Name, false tag, omitEmpty, quoted := f.Name, false, false
if tv := f.Tag.Get("json"); tv != "" { if tv := f.Tag.Get("json"); tv != "" {
ss := strings.SplitN(tv, ",", 2) name, opts := parseTag(tv)
if isValidTag(ss[0]) { if isValidTag(name) {
tag = ss[0] tag = name
}
if len(ss) > 1 {
// Currently the only option is omitempty,
// so parsing is trivial.
omitEmpty = ss[1] == "omitempty"
} }
omitEmpty = opts.Contains("omitempty")
quoted = opts.Contains("string")
} }
fieldValue := v.Field(i) fieldValue := v.Field(i)
if omitEmpty && isEmptyValue(fieldValue) { if omitEmpty && isEmptyValue(fieldValue) {
...@@ -292,7 +316,7 @@ func (e *encodeState) reflectValue(v reflect.Value) { ...@@ -292,7 +316,7 @@ func (e *encodeState) reflectValue(v reflect.Value) {
} }
e.string(tag) e.string(tag)
e.WriteByte(':') e.WriteByte(':')
e.reflectValue(fieldValue) e.reflectValueQuoted(fieldValue, quoted)
} }
e.WriteByte('}') e.WriteByte('}')
...@@ -380,7 +404,8 @@ func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] } ...@@ -380,7 +404,8 @@ func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] }
func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) } func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) }
func (sv stringValues) get(i int) string { return sv[i].String() } func (sv stringValues) get(i int) string { return sv[i].String() }
func (e *encodeState) string(s string) { func (e *encodeState) string(s string) (int, os.Error) {
len0 := e.Len()
e.WriteByte('"') e.WriteByte('"')
start := 0 start := 0
for i := 0; i < len(s); { for i := 0; i < len(s); {
...@@ -425,4 +450,5 @@ func (e *encodeState) string(s string) { ...@@ -425,4 +450,5 @@ func (e *encodeState) string(s string) {
e.WriteString(s[start:]) e.WriteString(s[start:])
} }
e.WriteByte('"') e.WriteByte('"')
return e.Len() - len0, nil
} }
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
package json package json
import ( import (
"bytes"
"reflect"
"testing" "testing"
) )
...@@ -42,3 +44,39 @@ func TestOmitEmpty(t *testing.T) { ...@@ -42,3 +44,39 @@ func TestOmitEmpty(t *testing.T) {
t.Errorf(" got: %s\nwant: %s\n", got, optionalsExpected) t.Errorf(" got: %s\nwant: %s\n", got, optionalsExpected)
} }
} }
type StringTag struct {
BoolStr bool `json:",string"`
IntStr int64 `json:",string"`
StrStr string `json:",string"`
}
var stringTagExpected = `{
"BoolStr": "true",
"IntStr": "42",
"StrStr": "\"xzbit\""
}`
func TestStringTag(t *testing.T) {
var s StringTag
s.BoolStr = true
s.IntStr = 42
s.StrStr = "xzbit"
got, err := MarshalIndent(&s, "", " ")
if err != nil {
t.Fatal(err)
}
if got := string(got); got != stringTagExpected {
t.Fatalf(" got: %s\nwant: %s\n", got, stringTagExpected)
}
// Verify that it round-trips.
var s2 StringTag
err = NewDecoder(bytes.NewBuffer(got)).Decode(&s2)
if err != nil {
t.Fatalf("Decode: %v", err)
}
if !reflect.DeepEqual(s, s2) {
t.Fatalf("decode didn't match.\nsource: %#v\nEncoded as:\n%s\ndecode: %#v", s, string(got), s2)
}
}
// Copyright 2011 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.
package json
import (
"strings"
)
// tagOptions is the string following a comma in a struct field's "json"
// tag, or the empty string. It does not include the leading comma.
type tagOptions string
// parseTag splits a struct field's json tag into its name and
// comma-separated options.
func parseTag(tag string) (string, tagOptions) {
if idx := strings.Index(tag, ","); idx != -1 {
return tag[:idx], tagOptions(tag[idx+1:])
}
return tag, tagOptions("")
}
// Contains returns whether checks that a comma-separated list of options
// contains a particular substr flag. substr must be surrounded by a
// string boundary or commas.
func (o tagOptions) Contains(optionName string) bool {
if len(o) == 0 {
return false
}
s := string(o)
for s != "" {
var next string
i := strings.Index(s, ",")
if i >= 0 {
s, next = s[:i], s[i+1:]
}
if s == optionName {
return true
}
s = next
}
return false
}
// Copyright 2011 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.
package json
import (
"testing"
)
func TestTagParsing(t *testing.T) {
name, opts := parseTag("field,foobar,foo")
if name != "field" {
t.Fatalf("name = %q, want field", name)
}
for _, tt := range []struct {
opt string
want bool
}{
{"foobar", true},
{"foo", true},
{"bar", false},
} {
if opts.Contains(tt.opt) != tt.want {
t.Errorf("Contains(%q) = %v", tt.opt, !tt.want)
}
}
}
...@@ -10,6 +10,9 @@ ...@@ -10,6 +10,9 @@
// A call to ValueOf returns a Value representing the run-time data. // A call to ValueOf returns a Value representing the run-time data.
// Zero takes a Type and returns a Value representing a zero value // Zero takes a Type and returns a Value representing a zero value
// for that type. // for that type.
//
// See "The Laws of Reflection" for an introduction to reflection in Go:
// http://blog.golang.org/2011/09/laws-of-reflection.html
package reflect package reflect
import ( import (
......
...@@ -40,7 +40,7 @@ hg clone -r ${old_rev} ${repository} ${OLDDIR} ...@@ -40,7 +40,7 @@ hg clone -r ${old_rev} ${repository} ${OLDDIR}
rm -rf ${NEWDIR} rm -rf ${NEWDIR}
hg clone -u release ${repository} ${NEWDIR} hg clone -u release ${repository} ${NEWDIR}
new_rev=`cd ${NEWDIR} && hg log | sed 1q | sed -e 's/.*://'` new_rev=`cd ${NEWDIR} && hg log -r release | sed 1q | sed -e 's/.*://'`
merge() { merge() {
name=$1 name=$1
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment