OSDN Git Service

Update to current version of Go library.
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 24 Mar 2011 23:46:17 +0000 (23:46 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 24 Mar 2011 23:46:17 +0000 (23:46 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@171427 138bc75d-0d04-0410-961f-82ee72b054a4

168 files changed:
libgo/MERGE
libgo/Makefile.am
libgo/Makefile.in
libgo/go/archive/zip/reader.go
libgo/go/big/int.go
libgo/go/big/int_test.go
libgo/go/big/nat.go
libgo/go/bufio/bufio_test.go
libgo/go/compress/flate/deflate_test.go
libgo/go/compress/lzw/reader_test.go
libgo/go/compress/lzw/writer_test.go
libgo/go/crypto/ecdsa/ecdsa.go [new file with mode: 0644]
libgo/go/crypto/ecdsa/ecdsa_test.go [new file with mode: 0644]
libgo/go/crypto/elliptic/elliptic.go
libgo/go/crypto/openpgp/packet/packet.go
libgo/go/crypto/openpgp/packet/packet_test.go
libgo/go/crypto/openpgp/packet/private_key.go
libgo/go/crypto/openpgp/packet/public_key.go
libgo/go/crypto/openpgp/packet/public_key_test.go
libgo/go/crypto/openpgp/packet/signature.go
libgo/go/crypto/openpgp/read_test.go
libgo/go/crypto/openpgp/write.go
libgo/go/crypto/openpgp/write_test.go
libgo/go/crypto/tls/common.go
libgo/go/crypto/tls/conn.go
libgo/go/crypto/tls/generate_cert.go
libgo/go/debug/proc/proc_darwin.go
libgo/go/debug/proc/proc_freebsd.go
libgo/go/debug/proc/proc_linux.go
libgo/go/debug/proc/proc_windows.go
libgo/go/exec/exec.go
libgo/go/exec/exec_test.go
libgo/go/exp/eval/stmt.go
libgo/go/exp/eval/stmt_test.go
libgo/go/exp/ogle/cmd.go
libgo/go/expvar/expvar.go
libgo/go/flag/flag.go
libgo/go/flag/flag_test.go
libgo/go/fmt/format.go
libgo/go/fmt/scan.go
libgo/go/fmt/scan_test.go
libgo/go/go/ast/ast.go
libgo/go/go/ast/filter.go
libgo/go/go/ast/print.go
libgo/go/go/ast/scope.go
libgo/go/go/ast/walk.go
libgo/go/go/parser/interface.go
libgo/go/go/parser/parser.go
libgo/go/go/parser/parser_test.go
libgo/go/go/printer/nodes.go
libgo/go/go/printer/printer.go
libgo/go/go/printer/printer_test.go
libgo/go/go/printer/testdata/expressions.golden
libgo/go/go/printer/testdata/expressions.input
libgo/go/go/printer/testdata/expressions.raw
libgo/go/go/printer/testdata/slow.golden [new file with mode: 0644]
libgo/go/go/printer/testdata/slow.input [new file with mode: 0644]
libgo/go/go/scanner/scanner.go
libgo/go/go/scanner/scanner_test.go
libgo/go/go/typechecker/scope.go
libgo/go/go/typechecker/testdata/test0.src [moved from libgo/go/go/typechecker/testdata/test0.go with 100% similarity]
libgo/go/go/typechecker/testdata/test1.src [moved from libgo/go/go/typechecker/testdata/test1.go with 83% similarity]
libgo/go/go/typechecker/testdata/test3.src [moved from libgo/go/go/typechecker/testdata/test3.go with 80% similarity]
libgo/go/go/typechecker/testdata/test4.src [moved from libgo/go/go/typechecker/testdata/test4.go with 84% similarity]
libgo/go/go/typechecker/type.go [new file with mode: 0644]
libgo/go/go/typechecker/typechecker.go
libgo/go/go/typechecker/typechecker_test.go
libgo/go/go/typechecker/universe.go
libgo/go/gob/codec_test.go
libgo/go/gob/decode.go
libgo/go/gob/decoder.go
libgo/go/gob/encode.go
libgo/go/gob/encoder.go
libgo/go/gob/gobencdec_test.go [new file with mode: 0644]
libgo/go/gob/timing_test.go [new file with mode: 0644]
libgo/go/gob/type.go
libgo/go/gob/type_test.go
libgo/go/hash/fnv/fnv.go [new file with mode: 0644]
libgo/go/hash/fnv/fnv_test.go [new file with mode: 0644]
libgo/go/http/cgi/child.go [new file with mode: 0644]
libgo/go/http/cgi/child_test.go [new file with mode: 0644]
libgo/go/http/cgi/host.go [new file with mode: 0644]
libgo/go/http/cgi/host_test.go [new file with mode: 0644]
libgo/go/http/cgi/matryoshka_test.go [new file with mode: 0644]
libgo/go/http/client.go
libgo/go/http/client_test.go
libgo/go/http/cookie.go [new file with mode: 0644]
libgo/go/http/cookie_test.go [new file with mode: 0644]
libgo/go/http/dump.go
libgo/go/http/export_test.go [new file with mode: 0644]
libgo/go/http/fs.go
libgo/go/http/fs_test.go
libgo/go/http/httptest/recorder.go [new file with mode: 0644]
libgo/go/http/httptest/server.go [new file with mode: 0644]
libgo/go/http/persist.go
libgo/go/http/pprof/pprof.go
libgo/go/http/proxy_test.go
libgo/go/http/range_test.go [new file with mode: 0644]
libgo/go/http/readrequest_test.go
libgo/go/http/request.go
libgo/go/http/request_test.go
libgo/go/http/requestwrite_test.go
libgo/go/http/response.go
libgo/go/http/responsewrite_test.go
libgo/go/http/serve_test.go
libgo/go/http/server.go
libgo/go/http/transport.go
libgo/go/http/transport_test.go [new file with mode: 0644]
libgo/go/io/ioutil/ioutil.go
libgo/go/io/ioutil/tempfile.go
libgo/go/io/ioutil/tempfile_test.go
libgo/go/io/pipe.go
libgo/go/mime/multipart/multipart.go
libgo/go/mime/multipart/multipart_test.go
libgo/go/net/fd.go
libgo/go/net/fd_linux.go
libgo/go/net/ip.go
libgo/go/netchan/common.go
libgo/go/netchan/export.go
libgo/go/netchan/import.go
libgo/go/netchan/netchan_test.go
libgo/go/os/exec.go
libgo/go/os/inotify/inotify_linux_test.go
libgo/go/os/os_test.go
libgo/go/path/filepath/match.go [new file with mode: 0644]
libgo/go/path/filepath/match_test.go [new file with mode: 0644]
libgo/go/path/filepath/path.go [new file with mode: 0644]
libgo/go/path/filepath/path_test.go [new file with mode: 0644]
libgo/go/path/filepath/path_unix.go [new file with mode: 0644]
libgo/go/path/filepath/path_windows.go [new file with mode: 0644]
libgo/go/path/match.go
libgo/go/path/match_test.go
libgo/go/path/path.go
libgo/go/path/path_test.go
libgo/go/path/path_unix.go [deleted file]
libgo/go/path/path_windows.go [deleted file]
libgo/go/reflect/all_test.go
libgo/go/reflect/value.go
libgo/go/rpc/client.go
libgo/go/rpc/server.go
libgo/go/rpc/server_test.go
libgo/go/runtime/debug.go
libgo/go/runtime/mem.go [new file with mode: 0644]
libgo/go/runtime/pprof/pprof.go
libgo/go/runtime/pprof/pprof_test.go [new file with mode: 0644]
libgo/go/strings/strings.go
libgo/go/strings/strings_test.go
libgo/go/sync/waitgroup.go
libgo/go/template/template.go
libgo/go/testing/script/script.go
libgo/go/testing/testing.go
libgo/go/time/sleep.go
libgo/go/time/sleep_test.go
libgo/go/time/sys.go [new file with mode: 0644]
libgo/go/time/time.go
libgo/go/time/time_test.go
libgo/go/websocket/server.go
libgo/go/websocket/websocket_test.go
libgo/go/xml/xml.go
libgo/merge.sh
libgo/runtime/channel.h
libgo/runtime/go-rec-big.c
libgo/runtime/go-rec-nb-big.c
libgo/runtime/go-rec-nb-small.c
libgo/runtime/go-rec-small.c
libgo/runtime/go-reflect-chan.c
libgo/syscalls/exec.go
libgo/testsuite/gotest

index e572b23..729be06 100644 (file)
@@ -1,4 +1,4 @@
-94d654be2064
+31d7feb9281b
 
 The first line of this file holds the Mercurial revision number of the
 last merge done from the master library sources.
index 2db29fd..77bf27a 100644 (file)
@@ -182,6 +182,7 @@ toolexeclibgocrypto_DATA = \
        crypto/cast5.gox \
        crypto/cipher.gox \
        crypto/dsa.gox \
+       crypto/ecdsa.gox \
        crypto/elliptic.gox \
        crypto/hmac.gox \
        crypto/md4.gox \
@@ -254,11 +255,14 @@ toolexeclibgohashdir = $(toolexeclibgodir)/hash
 toolexeclibgohash_DATA = \
        hash/adler32.gox \
        hash/crc32.gox \
-       hash/crc64.gox
+       hash/crc64.gox \
+       hash/fnv.gox
 
 toolexeclibgohttpdir = $(toolexeclibgodir)/http
 
 toolexeclibgohttp_DATA = \
+       http/cgi.gox \
+       http/httptest.gox \
        http/pprof.gox
 
 toolexeclibgoimagedir = $(toolexeclibgodir)/image
@@ -301,6 +305,11 @@ toolexeclibgoos_DATA = \
        $(os_inotify_gox) \
        os/signal.gox
 
+toolexeclibgopathdir = $(toolexeclibgodir)/path
+
+toolexeclibgopath_DATA = \
+       path/filepath.gox
+
 toolexeclibgorpcdir = $(toolexeclibgodir)/rpc
 
 toolexeclibgorpc_DATA = \
@@ -543,6 +552,7 @@ go_html_files = \
 go_http_files = \
        go/http/chunked.go \
        go/http/client.go \
+       go/http/cookie.go \
        go/http/dump.go \
        go/http/fs.go \
        go/http/header.go \
@@ -726,8 +736,7 @@ go_patch_files = \
 
 go_path_files = \
        go/path/match.go \
-       go/path/path.go \
-       go/path/path_unix.go
+       go/path/path.go
 
 go_rand_files = \
        go/rand/exp.go \
@@ -753,6 +762,7 @@ go_runtime_files = \
        go/runtime/debug.go \
        go/runtime/error.go \
        go/runtime/extern.go \
+       go/runtime/mem.go \
        go/runtime/sig.go \
        go/runtime/softfloat64.go \
        go/runtime/type.go \
@@ -826,6 +836,7 @@ go_testing_files = \
 go_time_files = \
        go/time/format.go \
        go/time/sleep.go \
+       go/time/sys.go \
        go/time/tick.go \
        go/time/time.go \
        go/time/zoneinfo_unix.go
@@ -936,6 +947,8 @@ go_crypto_cipher_files = \
        go/crypto/cipher/ofb.go
 go_crypto_dsa_files = \
        go/crypto/dsa/dsa.go
+go_crypto_ecdsa_files = \
+       go/crypto/ecdsa/ecdsa.go
 go_crypto_elliptic_files = \
        go/crypto/elliptic/elliptic.go
 go_crypto_hmac_files = \
@@ -1101,6 +1114,7 @@ go_go_token_files = \
        go/go/token/token.go
 go_go_typechecker_files = \
        go/go/typechecker/scope.go \
+       go/go/typechecker/type.go \
        go/go/typechecker/typechecker.go \
        go/go/typechecker/universe.go
 
@@ -1110,7 +1124,15 @@ go_hash_crc32_files = \
        go/hash/crc32/crc32.go
 go_hash_crc64_files = \
        go/hash/crc64/crc64.go
-
+go_hash_fnv_files = \
+       go/hash/fnv/fnv.go
+
+go_http_cgi_files = \
+       go/http/cgi/child.go \
+       go/http/cgi/host.go
+go_http_httptest_files = \
+       go/http/httptest/recorder.go \
+       go/http/httptest/server.go
 go_http_pprof_files = \
        go/http/pprof/pprof.go
 
@@ -1151,6 +1173,11 @@ go_os_signal_files = \
        go/os/signal/signal.go \
        unix.go
 
+go_path_filepath_files = \
+       go/path/filepath/match.go \
+       go/path/filepath/path.go \
+       go/path/filepath/path_unix.go
+
 go_rpc_jsonrpc_files = \
        go/rpc/jsonrpc/client.go \
        go/rpc/jsonrpc/server.go
@@ -1377,6 +1404,7 @@ libgo_go_objs = \
        crypto/cast5.lo \
        crypto/cipher.lo \
        crypto/dsa.lo \
+       crypto/ecdsa.lo \
        crypto/elliptic.lo \
        crypto/hmac.lo \
        crypto/md4.lo \
@@ -1426,6 +1454,9 @@ libgo_go_objs = \
        hash/adler32.lo \
        hash/crc32.lo \
        hash/crc64.lo \
+       hash/fnv.lo \
+       http/cgi.lo \
+       http/httptest.lo \
        http/pprof.lo \
        image/jpeg.lo \
        image/png.lo \
@@ -1436,6 +1467,7 @@ libgo_go_objs = \
        net/textproto.lo \
        $(os_lib_inotify_lo) \
        os/signal.lo \
+       path/filepath.lo \
        rpc/jsonrpc.lo \
        runtime/debug.lo \
        runtime/pprof.lo \
@@ -1532,7 +1564,7 @@ asn1/check: $(CHECK_DEPS)
        $(CHECK)
 .PHONY: asn1/check
 
-big/big.lo: $(go_big_files) fmt.gox rand.gox strings.gox
+big/big.lo: $(go_big_files) fmt.gox rand.gox strings.gox os.gox
        $(BUILDPACKAGE)
 big/check: $(CHECK_DEPS)
        $(CHECK)
@@ -1597,9 +1629,9 @@ fmt/check: $(CHECK_DEPS)
        $(CHECK)
 .PHONY: fmt/check
 
-gob/gob.lo: $(go_gob_files) bytes.gox fmt.gox io.gox math.gox os.gox \
-               reflect.gox runtime.gox strings.gox sync.gox unicode.gox \
-               utf8.gox
+gob/gob.lo: $(go_gob_files) bufio.gox bytes.gox fmt.gox io.gox math.gox \
+               os.gox reflect.gox runtime.gox strings.gox sync.gox \
+               unicode.gox utf8.gox
        $(BUILDPACKAGE)
 gob/check: $(CHECK_DEPS)
        $(CHECK)
@@ -1621,8 +1653,8 @@ html/check: $(CHECK_DEPS)
 http/http.lo: $(go_http_files) bufio.gox bytes.gox container/vector.gox \
                crypto/rand.gox crypto/tls.gox encoding/base64.gox fmt.gox \
                io.gox io/ioutil.gox log.gox mime.gox mime/multipart.gox \
-               net.gox net/textproto.gox os.gox path.gox sort.gox \
-               strconv.gox strings.gox sync.gox time.gox utf8.gox
+               net.gox net/textproto.gox os.gox path.gox path/filepath.gox \
+               sort.gox strconv.gox strings.gox sync.gox time.gox utf8.gox
        $(BUILDPACKAGE)
 http/check: $(CHECK_DEPS)
        $(CHECK)
@@ -1634,7 +1666,7 @@ image/check: $(CHECK_DEPS)
        $(CHECK)
 .PHONY: image/check
 
-io/io.lo: $(go_io_files) os.gox runtime.gox sync.gox
+io/io.lo: $(go_io_files) os.gox sync.gox
        $(BUILDPACKAGE)
 io/check: $(CHECK_DEPS)
        $(CHECK)
@@ -1697,8 +1729,7 @@ patch/check: $(CHECK_DEPS)
        $(CHECK)
 .PHONY: patch/check
 
-path/path.lo: $(go_path_files) io/ioutil.gox os.gox sort.gox strings.gox \
-               utf8.gox
+path/path.lo: $(go_path_files) os.gox strings.gox utf8.gox
        $(BUILDPACKAGE)
 path/check: $(CHECK_DEPS)
        $(CHECK)
@@ -1799,7 +1830,7 @@ template/check: $(CHECK_DEPS)
 .PHONY: template/check
 
 testing/testing.lo: $(go_testing_files) flag.gox fmt.gox os.gox regexp.gox \
-               runtime.gox time.gox
+               runtime.gox runtime/pprof.gox time.gox
        $(BUILDPACKAGE)
 testing/check: $(CHECK_DEPS)
        $(CHECK)
@@ -1862,7 +1893,7 @@ archive/tar/check: $(CHECK_DEPS)
 
 archive/zip.lo: $(go_archive_zip_files) bufio.gox bytes.gox \
                compress/flate.gox hash.gox hash/crc32.gox \
-               encoding/binary.gox io.gox os.gox
+               encoding/binary.gox io.gox io/ioutil.gox os.gox
        $(BUILDPACKAGE)
 archive/zip/check: $(CHECK_DEPS)
        @$(MKDIR_P) archive/zip
@@ -1977,6 +2008,14 @@ crypto/dsa/check: $(CHECK_DEPS)
        $(CHECK)
 .PHONY: crypto/dsa/check
 
+crypto/ecdsa.lo: $(go_crypto_ecdsa_files) big.gox crypto/elliptic.gox io.gox \
+               os.gox
+       $(BUILDPACKAGE)
+crypto/ecdsa/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/ecdsa
+       $(CHECK)
+.PHONY: crypto/ecdsa/check
+
 crypto/elliptic.lo: $(go_crypto_elliptic_files) big.gox io.gox os.gox sync.gox
        $(BUILDPACKAGE)
 crypto/elliptic/check: $(CHECK_DEPS)
@@ -2014,8 +2053,8 @@ crypto/ocsp/check: $(CHECK_DEPS)
        $(CHECK)
 .PHONY: crypto/ocsp/check
 
-crypto/openpgp.lo: $(go_crypto_openpgp_files) crypto.gox \
-                crypto/openpgp/armor.gox crypto/openpgp/error.gox \
+crypto/openpgp.lo: $(go_crypto_openpgp_files) crypto.gox crypto/dsa.gox \
+               crypto/openpgp/armor.gox crypto/openpgp/error.gox \
                crypto/openpgp/packet.gox crypto/rsa.gox crypto/sha256.gox \
                hash.gox io.gox os.gox strconv.gox time.gox
        $(BUILDPACKAGE)
@@ -2137,10 +2176,10 @@ crypto/openpgp/error/check: $(CHECK_DEPS)
 crypto/openpgp/packet.lo: $(go_crypto_openpgp_packet_files) big.gox bytes.gox \
                compress/flate.gox compress/zlib.gox crypto.gox \
                crypto/aes.gox crypto/cast5.gox crypto/cipher.gox \
-               crypto/openpgp/error.gox crypto/openpgp/s2k.gox \
-               crypto/rand.gox crypto/rsa.gox crypto/sha1.gox \
-               crypto/subtle.gox encoding/binary.gox hash.gox io.gox \
-               io/ioutil.gox os.gox strconv.gox strings.gox
+               crypto/dsa.gox crypto/openpgp/error.gox \
+               crypto/openpgp/s2k.gox crypto/rand.gox crypto/rsa.gox \
+               crypto/sha1.gox crypto/subtle.gox encoding/binary.gox fmt.gox \
+               hash.gox io.gox io/ioutil.gox os.gox strconv.gox strings.gox
        $(BUILDPACKAGE)
 crypto/openpgp/packet/check: $(CHECK_DEPS)
        @$(MKDIR_P) crypto/openpgp/packet
@@ -2288,8 +2327,8 @@ exp/eval/check: $(CHECK_DEPS)
        $(CHECK)
 .PHONY: exp/eval/check
 
-go/ast.lo: $(go_go_ast_files) fmt.gox go/token.gox io.gox os.gox reflect.gox \
-               unicode.gox utf8.gox
+go/ast.lo: $(go_go_ast_files) bytes.gox fmt.gox go/token.gox io.gox os.gox \
+               reflect.gox unicode.gox utf8.gox
        $(BUILDPACKAGE)
 go/ast/check: $(CHECK_DEPS)
        @$(MKDIR_P) go/ast
@@ -2306,7 +2345,7 @@ go/doc/check: $(CHECK_DEPS)
 
 go/parser.lo: $(go_go_parser_files) bytes.gox fmt.gox go/ast.gox \
                go/scanner.gox go/token.gox io.gox io/ioutil.gox os.gox \
-               path.gox strings.gox
+               path/filepath.gox strings.gox
        $(BUILDPACKAGE)
 go/parser/check: $(CHECK_DEPS)
        @$(MKDIR_P) go/parser
@@ -2314,8 +2353,8 @@ go/parser/check: $(CHECK_DEPS)
 .PHONY: go/parser/check
 
 go/printer.lo: $(go_go_printer_files) bytes.gox fmt.gox go/ast.gox \
-               go/token.gox io.gox os.gox reflect.gox runtime.gox \
-               strings.gox tabwriter.gox
+               go/token.gox io.gox os.gox path/filepath.gox reflect.gox \
+               runtime.gox strings.gox tabwriter.gox
        $(BUILDPACKAGE)
 go/printer/check: $(CHECK_DEPS)
        @$(MKDIR_P) go/printer
@@ -2323,8 +2362,8 @@ go/printer/check: $(CHECK_DEPS)
 .PHONY: go/printer/check
 
 go/scanner.lo: $(go_go_scanner_files) bytes.gox container/vector.gox fmt.gox \
-               go/token.gox io.gox os.gox path.gox sort.gox strconv.gox \
-               unicode.gox utf8.gox
+               go/token.gox io.gox os.gox path/filepath.gox sort.gox \
+               strconv.gox unicode.gox utf8.gox
        $(BUILDPACKAGE)
 go/scanner/check: $(CHECK_DEPS)
        @$(MKDIR_P) go/scanner
@@ -2367,6 +2406,30 @@ hash/crc64/check: $(CHECK_DEPS)
        $(CHECK)
 .PHONY: hash/crc64/check
 
+hash/fnv.lo: $(go_hash_fnv_files) encoding/binary.gox hash.gox os.gox
+       $(BUILDPACKAGE)
+hash/fnv/check: $(CHECK_DEPS)
+       @$(MKDIR_P) hash/fnv
+       $(CHECK)
+.PHONY: hash/fnv/check
+
+http/cgi.lo: $(go_http_cgi_files) bufio.gox bytes.gox encoding/line.gox \
+               exec.gox fmt.gox http.gox io.gox io/ioutil.gox log.gox \
+               os.gox path/filepath.gox regexp.gox strconv.gox strings.gox
+       $(BUILDPACKAGE)
+http/cgi/check: $(CHECK_DEPS)
+       @$(MKDIR_P) http/cgi
+       $(CHECK)
+.PHONY: http/cgi/check
+
+http/httptest.lo: $(go_http_httptest_files) bytes.gox fmt.gox http.gox \
+               net.gox os.gox
+       $(BUILDPACKAGE)
+http/httptest/check: $(CHECK_DEPS)
+       @$(MKDIR_P) http/httptest
+       $(CHECK)
+.PHONY: http/httptest/check
+
 http/pprof.lo: $(go_http_pprof_files) bufio.gox fmt.gox http.gox os.gox \
                runtime.gox runtime/pprof.gox strconv.gox strings.gox
        $(BUILDPACKAGE)
@@ -2398,8 +2461,8 @@ index/suffixarray/check: $(CHECK_DEPS)
        $(CHECK)
 .PHONY: index/suffixarray/check
 
-io/ioutil.lo: $(go_io_ioutil_files) bytes.gox io.gox os.gox sort.gox \
-               strconv.gox
+io/ioutil.lo: $(go_io_ioutil_files) bytes.gox io.gox os.gox path/filepath.gox \
+               sort.gox strconv.gox
        $(BUILDPACKAGE)
 io/ioutil/check: $(CHECK_DEPS)
        @$(MKDIR_P) io/ioutil
@@ -2407,7 +2470,7 @@ io/ioutil/check: $(CHECK_DEPS)
 .PHONY: io/ioutil/check
 
 mime/multipart.lo: $(go_mime_multipart_files) bufio.gox bytes.gox io.gox \
-               mime.gox os.gox regexp.gox strings.gox
+               mime.gox net/textproto.gox os.gox regexp.gox strings.gox
        $(BUILDPACKAGE)
 mime/multipart/check: $(CHECK_DEPS)
        @$(MKDIR_P) mime/multipart
@@ -2445,6 +2508,14 @@ unix.go: $(srcdir)/go/os/signal/mkunix.sh sysinfo.go
        $(SHELL) $(srcdir)/go/os/signal/mkunix.sh sysinfo.go > $@.tmp
        mv -f $@.tmp $@
 
+path/filepath.lo: $(go_path_filepath_files) bytes.gox os.gox sort.gox \
+               strings.gox utf8.gox
+       $(BUILDPACKAGE)
+path/filepath/check: $(CHECK_DEPS)
+       @$(MKDIR_P) path/filepath
+       $(CHECK)
+.PHONY: path/filepath/check
+
 rpc/jsonrpc.lo: $(go_rpc_jsonrpc_files) fmt.gox io.gox json.gox net.gox \
                os.gox rpc.gox sync.gox
        $(BUILDPACKAGE)
@@ -2462,7 +2533,7 @@ runtime/debug/check: $(CHECK_DEPS)
 .PHONY: runtime/debug/check
 
 runtime/pprof.lo: $(go_runtime_pprof_files) bufio.gox fmt.gox io.gox os.gox \
-               runtime.gox
+               runtime.gox sync.gox
        $(BUILDPACKAGE)
 runtime/pprof/check: $(CHECK_DEPS)
        @$(MKDIR_P) runtime/pprof
@@ -2653,6 +2724,8 @@ crypto/cipher.gox: crypto/cipher.lo
        $(BUILDGOX)
 crypto/dsa.gox: crypto/dsa.lo
        $(BUILDGOX)
+crypto/ecdsa.gox: crypto/ecdsa.lo      
+       $(BUILDGOX)
 crypto/elliptic.gox: crypto/elliptic.lo
        $(BUILDGOX)
 crypto/hmac.gox: crypto/hmac.lo
@@ -2757,7 +2830,13 @@ hash/crc32.gox: hash/crc32.lo
        $(BUILDGOX)
 hash/crc64.gox: hash/crc64.lo
        $(BUILDGOX)
+hash/fnv.gox: hash/fnv.lo
+       $(BUILDGOX)
 
+http/cgi.gox: http/cgi.lo
+       $(BUILDGOX)
+http/httptest.gox: http/httptest.lo
+       $(BUILDGOX)
 http/pprof.gox: http/pprof.lo
        $(BUILDGOX)
 
@@ -2785,6 +2864,9 @@ os/inotify.gox: os/inotify.lo
 os/signal.gox: os/signal.lo
        $(BUILDGOX)
 
+path/filepath.gox: path/filepath.lo
+       $(BUILDGOX)
+
 rpc/jsonrpc.gox: rpc/jsonrpc.lo
        $(BUILDGOX)
 
@@ -2823,7 +2905,7 @@ TEST_PACKAGES = \
        fmt/check \
        gob/check \
        html/check \
-       $(if $(GCCGO_RUN_ALL_TESTS),http/check) \
+       http/check \
        io/check \
        json/check \
        log/check \
@@ -2872,6 +2954,7 @@ TEST_PACKAGES = \
        crypto/cast5/check \
        crypto/cipher/check \
        crypto/dsa/check \
+       crypto/ecdsa/check \
        crypto/elliptic/check \
        crypto/hmac/check \
        crypto/md4/check \
@@ -2916,6 +2999,8 @@ TEST_PACKAGES = \
        hash/adler32/check \
        hash/crc32/check \
        hash/crc64/check \
+       hash/fnv/check \
+       http/cgi/check \
        image/png/check \
        index/suffixarray/check \
        io/ioutil/check \
@@ -2923,6 +3008,7 @@ TEST_PACKAGES = \
        net/textproto/check \
        $(os_inotify_check) \
        os/signal/check \
+       path/filepath/check \
        rpc/jsonrpc/check \
        sync/atomic/check \
        testing/quick/check \
index 7bb302d..dd94225 100644 (file)
@@ -110,6 +110,7 @@ am__installdirs = "$(DESTDIR)$(toolexeclibdir)" \
        "$(DESTDIR)$(toolexeclibgomimedir)" \
        "$(DESTDIR)$(toolexeclibgonetdir)" \
        "$(DESTDIR)$(toolexeclibgoosdir)" \
+       "$(DESTDIR)$(toolexeclibgopathdir)" \
        "$(DESTDIR)$(toolexeclibgorpcdir)" \
        "$(DESTDIR)$(toolexeclibgoruntimedir)" \
        "$(DESTDIR)$(toolexeclibgosyncdir)" \
@@ -141,9 +142,10 @@ am__DEPENDENCIES_2 = asn1/asn1.lo big/big.lo bufio/bufio.lo \
        container/heap.lo container/list.lo container/ring.lo \
        container/vector.lo crypto/aes.lo crypto/block.lo \
        crypto/blowfish.lo crypto/cast5.lo crypto/cipher.lo \
-       crypto/dsa.lo crypto/elliptic.lo crypto/hmac.lo crypto/md4.lo \
-       crypto/md5.lo crypto/ocsp.lo crypto/openpgp.lo crypto/rand.lo \
-       crypto/rc4.lo crypto/ripemd160.lo crypto/rsa.lo crypto/sha1.lo \
+       crypto/dsa.lo crypto/ecdsa.lo crypto/elliptic.lo \
+       crypto/hmac.lo crypto/md4.lo crypto/md5.lo crypto/ocsp.lo \
+       crypto/openpgp.lo crypto/rand.lo crypto/rc4.lo \
+       crypto/ripemd160.lo crypto/rsa.lo crypto/sha1.lo \
        crypto/sha256.lo crypto/sha512.lo crypto/subtle.lo \
        crypto/tls.lo crypto/twofish.lo crypto/x509.lo crypto/xtea.lo \
        crypto/openpgp/armor.lo crypto/openpgp/error.lo \
@@ -155,13 +157,14 @@ am__DEPENDENCIES_2 = asn1/asn1.lo big/big.lo bufio/bufio.lo \
        exp/datafmt.lo exp/draw.lo exp/eval.lo go/ast.lo go/doc.lo \
        go/parser.lo go/printer.lo go/scanner.lo go/token.lo \
        go/typechecker.lo hash/adler32.lo hash/crc32.lo hash/crc64.lo \
-       http/pprof.lo image/jpeg.lo image/png.lo index/suffixarray.lo \
-       io/ioutil.lo mime/multipart.lo net/dict.lo net/textproto.lo \
-       $(am__DEPENDENCIES_1) os/signal.lo rpc/jsonrpc.lo \
-       runtime/debug.lo runtime/pprof.lo sync/atomic.lo \
-       sync/atomic_c.lo syscalls/syscall.lo syscalls/errno.lo \
-       testing/testing.lo testing/iotest.lo testing/quick.lo \
-       testing/script.lo
+       hash/fnv.lo http/cgi.lo http/httptest.lo http/pprof.lo \
+       image/jpeg.lo image/png.lo index/suffixarray.lo io/ioutil.lo \
+       mime/multipart.lo net/dict.lo net/textproto.lo \
+       $(am__DEPENDENCIES_1) os/signal.lo path/filepath.lo \
+       rpc/jsonrpc.lo runtime/debug.lo runtime/pprof.lo \
+       sync/atomic.lo sync/atomic_c.lo syscalls/syscall.lo \
+       syscalls/errno.lo testing/testing.lo testing/iotest.lo \
+       testing/quick.lo testing/script.lo
 libgo_la_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \
        $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
        $(am__DEPENDENCIES_1)
@@ -280,8 +283,9 @@ DATA = $(toolexeclibgo_DATA) $(toolexeclibgoarchive_DATA) \
        $(toolexeclibgoimage_DATA) $(toolexeclibgoindex_DATA) \
        $(toolexeclibgoio_DATA) $(toolexeclibgomime_DATA) \
        $(toolexeclibgonet_DATA) $(toolexeclibgoos_DATA) \
-       $(toolexeclibgorpc_DATA) $(toolexeclibgoruntime_DATA) \
-       $(toolexeclibgosync_DATA) $(toolexeclibgotesting_DATA)
+       $(toolexeclibgopath_DATA) $(toolexeclibgorpc_DATA) \
+       $(toolexeclibgoruntime_DATA) $(toolexeclibgosync_DATA) \
+       $(toolexeclibgotesting_DATA)
 RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive        \
   distclean-recursive maintainer-clean-recursive
 AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
@@ -620,6 +624,7 @@ toolexeclibgocrypto_DATA = \
        crypto/cast5.gox \
        crypto/cipher.gox \
        crypto/dsa.gox \
+       crypto/ecdsa.gox \
        crypto/elliptic.gox \
        crypto/hmac.gox \
        crypto/md4.gox \
@@ -686,10 +691,13 @@ toolexeclibgohashdir = $(toolexeclibgodir)/hash
 toolexeclibgohash_DATA = \
        hash/adler32.gox \
        hash/crc32.gox \
-       hash/crc64.gox
+       hash/crc64.gox \
+       hash/fnv.gox
 
 toolexeclibgohttpdir = $(toolexeclibgodir)/http
 toolexeclibgohttp_DATA = \
+       http/cgi.gox \
+       http/httptest.gox \
        http/pprof.gox
 
 toolexeclibgoimagedir = $(toolexeclibgodir)/image
@@ -723,6 +731,10 @@ toolexeclibgoos_DATA = \
        $(os_inotify_gox) \
        os/signal.gox
 
+toolexeclibgopathdir = $(toolexeclibgodir)/path
+toolexeclibgopath_DATA = \
+       path/filepath.gox
+
 toolexeclibgorpcdir = $(toolexeclibgodir)/rpc
 toolexeclibgorpc_DATA = \
        rpc/jsonrpc.gox
@@ -928,6 +940,7 @@ go_html_files = \
 go_http_files = \
        go/http/chunked.go \
        go/http/client.go \
+       go/http/cookie.go \
        go/http/dump.go \
        go/http/fs.go \
        go/http/header.go \
@@ -1084,8 +1097,7 @@ go_patch_files = \
 
 go_path_files = \
        go/path/match.go \
-       go/path/path.go \
-       go/path/path_unix.go
+       go/path/path.go
 
 go_rand_files = \
        go/rand/exp.go \
@@ -1111,6 +1123,7 @@ go_runtime_files = \
        go/runtime/debug.go \
        go/runtime/error.go \
        go/runtime/extern.go \
+       go/runtime/mem.go \
        go/runtime/sig.go \
        go/runtime/softfloat64.go \
        go/runtime/type.go \
@@ -1170,6 +1183,7 @@ go_testing_files = \
 go_time_files = \
        go/time/format.go \
        go/time/sleep.go \
+       go/time/sys.go \
        go/time/tick.go \
        go/time/time.go \
        go/time/zoneinfo_unix.go
@@ -1286,6 +1300,9 @@ go_crypto_cipher_files = \
 go_crypto_dsa_files = \
        go/crypto/dsa/dsa.go
 
+go_crypto_ecdsa_files = \
+       go/crypto/ecdsa/ecdsa.go
+
 go_crypto_elliptic_files = \
        go/crypto/elliptic/elliptic.go
 
@@ -1490,6 +1507,7 @@ go_go_token_files = \
 
 go_go_typechecker_files = \
        go/go/typechecker/scope.go \
+       go/go/typechecker/type.go \
        go/go/typechecker/typechecker.go \
        go/go/typechecker/universe.go
 
@@ -1502,6 +1520,17 @@ go_hash_crc32_files = \
 go_hash_crc64_files = \
        go/hash/crc64/crc64.go
 
+go_hash_fnv_files = \
+       go/hash/fnv/fnv.go
+
+go_http_cgi_files = \
+       go/http/cgi/child.go \
+       go/http/cgi/host.go
+
+go_http_httptest_files = \
+       go/http/httptest/recorder.go \
+       go/http/httptest/server.go
+
 go_http_pprof_files = \
        go/http/pprof/pprof.go
 
@@ -1542,6 +1571,11 @@ go_os_signal_files = \
        go/os/signal/signal.go \
        unix.go
 
+go_path_filepath_files = \
+       go/path/filepath/match.go \
+       go/path/filepath/path.go \
+       go/path/filepath/path_unix.go
+
 go_rpc_jsonrpc_files = \
        go/rpc/jsonrpc/client.go \
        go/rpc/jsonrpc/server.go
@@ -1718,6 +1752,7 @@ libgo_go_objs = \
        crypto/cast5.lo \
        crypto/cipher.lo \
        crypto/dsa.lo \
+       crypto/ecdsa.lo \
        crypto/elliptic.lo \
        crypto/hmac.lo \
        crypto/md4.lo \
@@ -1767,6 +1802,9 @@ libgo_go_objs = \
        hash/adler32.lo \
        hash/crc32.lo \
        hash/crc64.lo \
+       hash/fnv.lo \
+       http/cgi.lo \
+       http/httptest.lo \
        http/pprof.lo \
        image/jpeg.lo \
        image/png.lo \
@@ -1777,6 +1815,7 @@ libgo_go_objs = \
        net/textproto.lo \
        $(os_lib_inotify_lo) \
        os/signal.lo \
+       path/filepath.lo \
        rpc/jsonrpc.lo \
        runtime/debug.lo \
        runtime/pprof.lo \
@@ -1883,7 +1922,7 @@ TEST_PACKAGES = \
        fmt/check \
        gob/check \
        html/check \
-       $(if $(GCCGO_RUN_ALL_TESTS),http/check) \
+       http/check \
        io/check \
        json/check \
        log/check \
@@ -1932,6 +1971,7 @@ TEST_PACKAGES = \
        crypto/cast5/check \
        crypto/cipher/check \
        crypto/dsa/check \
+       crypto/ecdsa/check \
        crypto/elliptic/check \
        crypto/hmac/check \
        crypto/md4/check \
@@ -1976,6 +2016,8 @@ TEST_PACKAGES = \
        hash/adler32/check \
        hash/crc32/check \
        hash/crc64/check \
+       hash/fnv/check \
+       http/cgi/check \
        image/png/check \
        index/suffixarray/check \
        io/ioutil/check \
@@ -1983,6 +2025,7 @@ TEST_PACKAGES = \
        net/textproto/check \
        $(os_inotify_check) \
        os/signal/check \
+       path/filepath/check \
        rpc/jsonrpc/check \
        sync/atomic/check \
        testing/quick/check \
@@ -3271,6 +3314,26 @@ uninstall-toolexeclibgoosDATA:
        test -n "$$files" || exit 0; \
        echo " ( cd '$(DESTDIR)$(toolexeclibgoosdir)' && rm -f" $$files ")"; \
        cd "$(DESTDIR)$(toolexeclibgoosdir)" && rm -f $$files
+install-toolexeclibgopathDATA: $(toolexeclibgopath_DATA)
+       @$(NORMAL_INSTALL)
+       test -z "$(toolexeclibgopathdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgopathdir)"
+       @list='$(toolexeclibgopath_DATA)'; test -n "$(toolexeclibgopathdir)" || list=; \
+       for p in $$list; do \
+         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+         echo "$$d$$p"; \
+       done | $(am__base_list) | \
+       while read files; do \
+         echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(toolexeclibgopathdir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(toolexeclibgopathdir)" || exit $$?; \
+       done
+
+uninstall-toolexeclibgopathDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(toolexeclibgopath_DATA)'; test -n "$(toolexeclibgopathdir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       test -n "$$files" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(toolexeclibgopathdir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(toolexeclibgopathdir)" && rm -f $$files
 install-toolexeclibgorpcDATA: $(toolexeclibgorpc_DATA)
        @$(NORMAL_INSTALL)
        test -z "$(toolexeclibgorpcdir)" || $(MKDIR_P) "$(DESTDIR)$(toolexeclibgorpcdir)"
@@ -3668,7 +3731,7 @@ all-am: Makefile $(LIBRARIES) $(LTLIBRARIES) all-multi $(DATA) \
                config.h
 installdirs: installdirs-recursive
 installdirs-am:
-       for dir in "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibgodir)" "$(DESTDIR)$(toolexeclibgoarchivedir)" "$(DESTDIR)$(toolexeclibgocompressdir)" "$(DESTDIR)$(toolexeclibgocontainerdir)" "$(DESTDIR)$(toolexeclibgocryptodir)" "$(DESTDIR)$(toolexeclibgocryptoopenpgpdir)" "$(DESTDIR)$(toolexeclibgodebugdir)" "$(DESTDIR)$(toolexeclibgoencodingdir)" "$(DESTDIR)$(toolexeclibgoexpdir)" "$(DESTDIR)$(toolexeclibgogodir)" "$(DESTDIR)$(toolexeclibgohashdir)" "$(DESTDIR)$(toolexeclibgohttpdir)" "$(DESTDIR)$(toolexeclibgoimagedir)" "$(DESTDIR)$(toolexeclibgoindexdir)" "$(DESTDIR)$(toolexeclibgoiodir)" "$(DESTDIR)$(toolexeclibgomimedir)" "$(DESTDIR)$(toolexeclibgonetdir)" "$(DESTDIR)$(toolexeclibgoosdir)" "$(DESTDIR)$(toolexeclibgorpcdir)" "$(DESTDIR)$(toolexeclibgoruntimedir)" "$(DESTDIR)$(toolexeclibgosyncdir)" "$(DESTDIR)$(toolexeclibgotestingdir)"; do \
+       for dir in "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibgodir)" "$(DESTDIR)$(toolexeclibgoarchivedir)" "$(DESTDIR)$(toolexeclibgocompressdir)" "$(DESTDIR)$(toolexeclibgocontainerdir)" "$(DESTDIR)$(toolexeclibgocryptodir)" "$(DESTDIR)$(toolexeclibgocryptoopenpgpdir)" "$(DESTDIR)$(toolexeclibgodebugdir)" "$(DESTDIR)$(toolexeclibgoencodingdir)" "$(DESTDIR)$(toolexeclibgoexpdir)" "$(DESTDIR)$(toolexeclibgogodir)" "$(DESTDIR)$(toolexeclibgohashdir)" "$(DESTDIR)$(toolexeclibgohttpdir)" "$(DESTDIR)$(toolexeclibgoimagedir)" "$(DESTDIR)$(toolexeclibgoindexdir)" "$(DESTDIR)$(toolexeclibgoiodir)" "$(DESTDIR)$(toolexeclibgomimedir)" "$(DESTDIR)$(toolexeclibgonetdir)" "$(DESTDIR)$(toolexeclibgoosdir)" "$(DESTDIR)$(toolexeclibgopathdir)" "$(DESTDIR)$(toolexeclibgorpcdir)" "$(DESTDIR)$(toolexeclibgoruntimedir)" "$(DESTDIR)$(toolexeclibgosyncdir)" "$(DESTDIR)$(toolexeclibgotestingdir)"; do \
          test -z "$$dir" || $(MKDIR_P) "$$dir"; \
        done
 install: install-recursive
@@ -3741,9 +3804,9 @@ install-exec-am: install-multi install-toolexeclibLIBRARIES \
        install-toolexeclibgohttpDATA install-toolexeclibgoimageDATA \
        install-toolexeclibgoindexDATA install-toolexeclibgoioDATA \
        install-toolexeclibgomimeDATA install-toolexeclibgonetDATA \
-       install-toolexeclibgoosDATA install-toolexeclibgorpcDATA \
-       install-toolexeclibgoruntimeDATA install-toolexeclibgosyncDATA \
-       install-toolexeclibgotestingDATA
+       install-toolexeclibgoosDATA install-toolexeclibgopathDATA \
+       install-toolexeclibgorpcDATA install-toolexeclibgoruntimeDATA \
+       install-toolexeclibgosyncDATA install-toolexeclibgotestingDATA
 
 install-html: install-html-recursive
 
@@ -3800,7 +3863,8 @@ uninstall-am: uninstall-toolexeclibLIBRARIES \
        uninstall-toolexeclibgoimageDATA \
        uninstall-toolexeclibgoindexDATA uninstall-toolexeclibgoioDATA \
        uninstall-toolexeclibgomimeDATA uninstall-toolexeclibgonetDATA \
-       uninstall-toolexeclibgoosDATA uninstall-toolexeclibgorpcDATA \
+       uninstall-toolexeclibgoosDATA uninstall-toolexeclibgopathDATA \
+       uninstall-toolexeclibgorpcDATA \
        uninstall-toolexeclibgoruntimeDATA \
        uninstall-toolexeclibgosyncDATA \
        uninstall-toolexeclibgotestingDATA
@@ -3836,15 +3900,15 @@ uninstall-am: uninstall-toolexeclibLIBRARIES \
        install-toolexeclibgohttpDATA install-toolexeclibgoimageDATA \
        install-toolexeclibgoindexDATA install-toolexeclibgoioDATA \
        install-toolexeclibgomimeDATA install-toolexeclibgonetDATA \
-       install-toolexeclibgoosDATA install-toolexeclibgorpcDATA \
-       install-toolexeclibgoruntimeDATA install-toolexeclibgosyncDATA \
-       install-toolexeclibgotestingDATA installcheck installcheck-am \
-       installdirs installdirs-am maintainer-clean \
-       maintainer-clean-generic maintainer-clean-multi mostlyclean \
-       mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
-       mostlyclean-local mostlyclean-multi pdf pdf-am ps ps-am tags \
-       tags-recursive uninstall uninstall-am \
-       uninstall-toolexeclibLIBRARIES \
+       install-toolexeclibgoosDATA install-toolexeclibgopathDATA \
+       install-toolexeclibgorpcDATA install-toolexeclibgoruntimeDATA \
+       install-toolexeclibgosyncDATA install-toolexeclibgotestingDATA \
+       installcheck installcheck-am installdirs installdirs-am \
+       maintainer-clean maintainer-clean-generic \
+       maintainer-clean-multi mostlyclean mostlyclean-compile \
+       mostlyclean-generic mostlyclean-libtool mostlyclean-local \
+       mostlyclean-multi pdf pdf-am ps ps-am tags tags-recursive \
+       uninstall uninstall-am uninstall-toolexeclibLIBRARIES \
        uninstall-toolexeclibLTLIBRARIES uninstall-toolexeclibgoDATA \
        uninstall-toolexeclibgoarchiveDATA \
        uninstall-toolexeclibgocompressDATA \
@@ -3859,7 +3923,8 @@ uninstall-am: uninstall-toolexeclibLIBRARIES \
        uninstall-toolexeclibgoimageDATA \
        uninstall-toolexeclibgoindexDATA uninstall-toolexeclibgoioDATA \
        uninstall-toolexeclibgomimeDATA uninstall-toolexeclibgonetDATA \
-       uninstall-toolexeclibgoosDATA uninstall-toolexeclibgorpcDATA \
+       uninstall-toolexeclibgoosDATA uninstall-toolexeclibgopathDATA \
+       uninstall-toolexeclibgorpcDATA \
        uninstall-toolexeclibgoruntimeDATA \
        uninstall-toolexeclibgosyncDATA \
        uninstall-toolexeclibgotestingDATA
@@ -3918,7 +3983,7 @@ asn1/check: $(CHECK_DEPS)
        $(CHECK)
 .PHONY: asn1/check
 
-big/big.lo: $(go_big_files) fmt.gox rand.gox strings.gox
+big/big.lo: $(go_big_files) fmt.gox rand.gox strings.gox os.gox
        $(BUILDPACKAGE)
 big/check: $(CHECK_DEPS)
        $(CHECK)
@@ -3983,9 +4048,9 @@ fmt/check: $(CHECK_DEPS)
        $(CHECK)
 .PHONY: fmt/check
 
-gob/gob.lo: $(go_gob_files) bytes.gox fmt.gox io.gox math.gox os.gox \
-               reflect.gox runtime.gox strings.gox sync.gox unicode.gox \
-               utf8.gox
+gob/gob.lo: $(go_gob_files) bufio.gox bytes.gox fmt.gox io.gox math.gox \
+               os.gox reflect.gox runtime.gox strings.gox sync.gox \
+               unicode.gox utf8.gox
        $(BUILDPACKAGE)
 gob/check: $(CHECK_DEPS)
        $(CHECK)
@@ -4007,8 +4072,8 @@ html/check: $(CHECK_DEPS)
 http/http.lo: $(go_http_files) bufio.gox bytes.gox container/vector.gox \
                crypto/rand.gox crypto/tls.gox encoding/base64.gox fmt.gox \
                io.gox io/ioutil.gox log.gox mime.gox mime/multipart.gox \
-               net.gox net/textproto.gox os.gox path.gox sort.gox \
-               strconv.gox strings.gox sync.gox time.gox utf8.gox
+               net.gox net/textproto.gox os.gox path.gox path/filepath.gox \
+               sort.gox strconv.gox strings.gox sync.gox time.gox utf8.gox
        $(BUILDPACKAGE)
 http/check: $(CHECK_DEPS)
        $(CHECK)
@@ -4020,7 +4085,7 @@ image/check: $(CHECK_DEPS)
        $(CHECK)
 .PHONY: image/check
 
-io/io.lo: $(go_io_files) os.gox runtime.gox sync.gox
+io/io.lo: $(go_io_files) os.gox sync.gox
        $(BUILDPACKAGE)
 io/check: $(CHECK_DEPS)
        $(CHECK)
@@ -4083,8 +4148,7 @@ patch/check: $(CHECK_DEPS)
        $(CHECK)
 .PHONY: patch/check
 
-path/path.lo: $(go_path_files) io/ioutil.gox os.gox sort.gox strings.gox \
-               utf8.gox
+path/path.lo: $(go_path_files) os.gox strings.gox utf8.gox
        $(BUILDPACKAGE)
 path/check: $(CHECK_DEPS)
        $(CHECK)
@@ -4185,7 +4249,7 @@ template/check: $(CHECK_DEPS)
 .PHONY: template/check
 
 testing/testing.lo: $(go_testing_files) flag.gox fmt.gox os.gox regexp.gox \
-               runtime.gox time.gox
+               runtime.gox runtime/pprof.gox time.gox
        $(BUILDPACKAGE)
 testing/check: $(CHECK_DEPS)
        $(CHECK)
@@ -4248,7 +4312,7 @@ archive/tar/check: $(CHECK_DEPS)
 
 archive/zip.lo: $(go_archive_zip_files) bufio.gox bytes.gox \
                compress/flate.gox hash.gox hash/crc32.gox \
-               encoding/binary.gox io.gox os.gox
+               encoding/binary.gox io.gox io/ioutil.gox os.gox
        $(BUILDPACKAGE)
 archive/zip/check: $(CHECK_DEPS)
        @$(MKDIR_P) archive/zip
@@ -4363,6 +4427,14 @@ crypto/dsa/check: $(CHECK_DEPS)
        $(CHECK)
 .PHONY: crypto/dsa/check
 
+crypto/ecdsa.lo: $(go_crypto_ecdsa_files) big.gox crypto/elliptic.gox io.gox \
+               os.gox
+       $(BUILDPACKAGE)
+crypto/ecdsa/check: $(CHECK_DEPS)
+       @$(MKDIR_P) crypto/ecdsa
+       $(CHECK)
+.PHONY: crypto/ecdsa/check
+
 crypto/elliptic.lo: $(go_crypto_elliptic_files) big.gox io.gox os.gox sync.gox
        $(BUILDPACKAGE)
 crypto/elliptic/check: $(CHECK_DEPS)
@@ -4400,8 +4472,8 @@ crypto/ocsp/check: $(CHECK_DEPS)
        $(CHECK)
 .PHONY: crypto/ocsp/check
 
-crypto/openpgp.lo: $(go_crypto_openpgp_files) crypto.gox \
-                crypto/openpgp/armor.gox crypto/openpgp/error.gox \
+crypto/openpgp.lo: $(go_crypto_openpgp_files) crypto.gox crypto/dsa.gox \
+               crypto/openpgp/armor.gox crypto/openpgp/error.gox \
                crypto/openpgp/packet.gox crypto/rsa.gox crypto/sha256.gox \
                hash.gox io.gox os.gox strconv.gox time.gox
        $(BUILDPACKAGE)
@@ -4523,10 +4595,10 @@ crypto/openpgp/error/check: $(CHECK_DEPS)
 crypto/openpgp/packet.lo: $(go_crypto_openpgp_packet_files) big.gox bytes.gox \
                compress/flate.gox compress/zlib.gox crypto.gox \
                crypto/aes.gox crypto/cast5.gox crypto/cipher.gox \
-               crypto/openpgp/error.gox crypto/openpgp/s2k.gox \
-               crypto/rand.gox crypto/rsa.gox crypto/sha1.gox \
-               crypto/subtle.gox encoding/binary.gox hash.gox io.gox \
-               io/ioutil.gox os.gox strconv.gox strings.gox
+               crypto/dsa.gox crypto/openpgp/error.gox \
+               crypto/openpgp/s2k.gox crypto/rand.gox crypto/rsa.gox \
+               crypto/sha1.gox crypto/subtle.gox encoding/binary.gox fmt.gox \
+               hash.gox io.gox io/ioutil.gox os.gox strconv.gox strings.gox
        $(BUILDPACKAGE)
 crypto/openpgp/packet/check: $(CHECK_DEPS)
        @$(MKDIR_P) crypto/openpgp/packet
@@ -4674,8 +4746,8 @@ exp/eval/check: $(CHECK_DEPS)
        $(CHECK)
 .PHONY: exp/eval/check
 
-go/ast.lo: $(go_go_ast_files) fmt.gox go/token.gox io.gox os.gox reflect.gox \
-               unicode.gox utf8.gox
+go/ast.lo: $(go_go_ast_files) bytes.gox fmt.gox go/token.gox io.gox os.gox \
+               reflect.gox unicode.gox utf8.gox
        $(BUILDPACKAGE)
 go/ast/check: $(CHECK_DEPS)
        @$(MKDIR_P) go/ast
@@ -4692,7 +4764,7 @@ go/doc/check: $(CHECK_DEPS)
 
 go/parser.lo: $(go_go_parser_files) bytes.gox fmt.gox go/ast.gox \
                go/scanner.gox go/token.gox io.gox io/ioutil.gox os.gox \
-               path.gox strings.gox
+               path/filepath.gox strings.gox
        $(BUILDPACKAGE)
 go/parser/check: $(CHECK_DEPS)
        @$(MKDIR_P) go/parser
@@ -4700,8 +4772,8 @@ go/parser/check: $(CHECK_DEPS)
 .PHONY: go/parser/check
 
 go/printer.lo: $(go_go_printer_files) bytes.gox fmt.gox go/ast.gox \
-               go/token.gox io.gox os.gox reflect.gox runtime.gox \
-               strings.gox tabwriter.gox
+               go/token.gox io.gox os.gox path/filepath.gox reflect.gox \
+               runtime.gox strings.gox tabwriter.gox
        $(BUILDPACKAGE)
 go/printer/check: $(CHECK_DEPS)
        @$(MKDIR_P) go/printer
@@ -4709,8 +4781,8 @@ go/printer/check: $(CHECK_DEPS)
 .PHONY: go/printer/check
 
 go/scanner.lo: $(go_go_scanner_files) bytes.gox container/vector.gox fmt.gox \
-               go/token.gox io.gox os.gox path.gox sort.gox strconv.gox \
-               unicode.gox utf8.gox
+               go/token.gox io.gox os.gox path/filepath.gox sort.gox \
+               strconv.gox unicode.gox utf8.gox
        $(BUILDPACKAGE)
 go/scanner/check: $(CHECK_DEPS)
        @$(MKDIR_P) go/scanner
@@ -4753,6 +4825,30 @@ hash/crc64/check: $(CHECK_DEPS)
        $(CHECK)
 .PHONY: hash/crc64/check
 
+hash/fnv.lo: $(go_hash_fnv_files) encoding/binary.gox hash.gox os.gox
+       $(BUILDPACKAGE)
+hash/fnv/check: $(CHECK_DEPS)
+       @$(MKDIR_P) hash/fnv
+       $(CHECK)
+.PHONY: hash/fnv/check
+
+http/cgi.lo: $(go_http_cgi_files) bufio.gox bytes.gox encoding/line.gox \
+               exec.gox fmt.gox http.gox io.gox io/ioutil.gox log.gox \
+               os.gox path/filepath.gox regexp.gox strconv.gox strings.gox
+       $(BUILDPACKAGE)
+http/cgi/check: $(CHECK_DEPS)
+       @$(MKDIR_P) http/cgi
+       $(CHECK)
+.PHONY: http/cgi/check
+
+http/httptest.lo: $(go_http_httptest_files) bytes.gox fmt.gox http.gox \
+               net.gox os.gox
+       $(BUILDPACKAGE)
+http/httptest/check: $(CHECK_DEPS)
+       @$(MKDIR_P) http/httptest
+       $(CHECK)
+.PHONY: http/httptest/check
+
 http/pprof.lo: $(go_http_pprof_files) bufio.gox fmt.gox http.gox os.gox \
                runtime.gox runtime/pprof.gox strconv.gox strings.gox
        $(BUILDPACKAGE)
@@ -4784,8 +4880,8 @@ index/suffixarray/check: $(CHECK_DEPS)
        $(CHECK)
 .PHONY: index/suffixarray/check
 
-io/ioutil.lo: $(go_io_ioutil_files) bytes.gox io.gox os.gox sort.gox \
-               strconv.gox
+io/ioutil.lo: $(go_io_ioutil_files) bytes.gox io.gox os.gox path/filepath.gox \
+               sort.gox strconv.gox
        $(BUILDPACKAGE)
 io/ioutil/check: $(CHECK_DEPS)
        @$(MKDIR_P) io/ioutil
@@ -4793,7 +4889,7 @@ io/ioutil/check: $(CHECK_DEPS)
 .PHONY: io/ioutil/check
 
 mime/multipart.lo: $(go_mime_multipart_files) bufio.gox bytes.gox io.gox \
-               mime.gox os.gox regexp.gox strings.gox
+               mime.gox net/textproto.gox os.gox regexp.gox strings.gox
        $(BUILDPACKAGE)
 mime/multipart/check: $(CHECK_DEPS)
        @$(MKDIR_P) mime/multipart
@@ -4831,6 +4927,14 @@ unix.go: $(srcdir)/go/os/signal/mkunix.sh sysinfo.go
        $(SHELL) $(srcdir)/go/os/signal/mkunix.sh sysinfo.go > $@.tmp
        mv -f $@.tmp $@
 
+path/filepath.lo: $(go_path_filepath_files) bytes.gox os.gox sort.gox \
+               strings.gox utf8.gox
+       $(BUILDPACKAGE)
+path/filepath/check: $(CHECK_DEPS)
+       @$(MKDIR_P) path/filepath
+       $(CHECK)
+.PHONY: path/filepath/check
+
 rpc/jsonrpc.lo: $(go_rpc_jsonrpc_files) fmt.gox io.gox json.gox net.gox \
                os.gox rpc.gox sync.gox
        $(BUILDPACKAGE)
@@ -4848,7 +4952,7 @@ runtime/debug/check: $(CHECK_DEPS)
 .PHONY: runtime/debug/check
 
 runtime/pprof.lo: $(go_runtime_pprof_files) bufio.gox fmt.gox io.gox os.gox \
-               runtime.gox
+               runtime.gox sync.gox
        $(BUILDPACKAGE)
 runtime/pprof/check: $(CHECK_DEPS)
        @$(MKDIR_P) runtime/pprof
@@ -5034,6 +5138,8 @@ crypto/cipher.gox: crypto/cipher.lo
        $(BUILDGOX)
 crypto/dsa.gox: crypto/dsa.lo
        $(BUILDGOX)
+crypto/ecdsa.gox: crypto/ecdsa.lo      
+       $(BUILDGOX)
 crypto/elliptic.gox: crypto/elliptic.lo
        $(BUILDGOX)
 crypto/hmac.gox: crypto/hmac.lo
@@ -5138,7 +5244,13 @@ hash/crc32.gox: hash/crc32.lo
        $(BUILDGOX)
 hash/crc64.gox: hash/crc64.lo
        $(BUILDGOX)
+hash/fnv.gox: hash/fnv.lo
+       $(BUILDGOX)
 
+http/cgi.gox: http/cgi.lo
+       $(BUILDGOX)
+http/httptest.gox: http/httptest.lo
+       $(BUILDGOX)
 http/pprof.gox: http/pprof.lo
        $(BUILDGOX)
 
@@ -5166,6 +5278,9 @@ os/inotify.gox: os/inotify.lo
 os/signal.gox: os/signal.lo
        $(BUILDGOX)
 
+path/filepath.gox: path/filepath.lo
+       $(BUILDGOX)
+
 rpc/jsonrpc.gox: rpc/jsonrpc.lo
        $(BUILDGOX)
 
index d8d9bba..3b265c9 100644 (file)
@@ -19,6 +19,7 @@ import (
        "hash/crc32"
        "encoding/binary"
        "io"
+       "io/ioutil"
        "os"
 )
 
@@ -109,7 +110,7 @@ func (f *File) Open() (rc io.ReadCloser, err os.Error) {
        r := io.NewSectionReader(f.zipr, off+f.bodyOffset, size)
        switch f.Method {
        case 0: // store (no compression)
-               rc = nopCloser{r}
+               rc = ioutil.NopCloser(r)
        case 8: // DEFLATE
                rc = flate.NewReader(r)
        default:
@@ -147,12 +148,6 @@ func (r *checksumReader) Read(b []byte) (n int, err os.Error) {
 
 func (r *checksumReader) Close() os.Error { return r.rc.Close() }
 
-type nopCloser struct {
-       io.Reader
-}
-
-func (f nopCloser) Close() os.Error { return nil }
-
 func readFileHeader(f *File, r io.Reader) (err os.Error) {
        defer func() {
                if rerr, ok := recover().(os.Error); ok {
index 46e0087..ecd70e0 100644 (file)
@@ -8,6 +8,7 @@ package big
 
 import (
        "fmt"
+       "os"
        "rand"
 )
 
@@ -393,62 +394,19 @@ func (z *Int) SetString(s string, base int) (*Int, bool) {
 }
 
 
-// SetBytes interprets b as the bytes of a big-endian, unsigned integer and
-// sets z to that value.
-func (z *Int) SetBytes(b []byte) *Int {
-       const s = _S
-       z.abs = z.abs.make((len(b) + s - 1) / s)
-
-       j := 0
-       for len(b) >= s {
-               var w Word
-
-               for i := s; i > 0; i-- {
-                       w <<= 8
-                       w |= Word(b[len(b)-i])
-               }
-
-               z.abs[j] = w
-               j++
-               b = b[0 : len(b)-s]
-       }
-
-       if len(b) > 0 {
-               var w Word
-
-               for i := len(b); i > 0; i-- {
-                       w <<= 8
-                       w |= Word(b[len(b)-i])
-               }
-
-               z.abs[j] = w
-       }
-
-       z.abs = z.abs.norm()
+// SetBytes interprets buf as the bytes of a big-endian unsigned
+// integer, sets z to that value, and returns z.
+func (z *Int) SetBytes(buf []byte) *Int {
+       z.abs = z.abs.setBytes(buf)
        z.neg = false
        return z
 }
 
 
-// Bytes returns the absolute value of x as a big-endian byte array.
+// Bytes returns the absolute value of z as a big-endian byte slice.
 func (z *Int) Bytes() []byte {
-       const s = _S
-       b := make([]byte, len(z.abs)*s)
-
-       for i, w := range z.abs {
-               wordBytes := b[(len(z.abs)-i-1)*s : (len(z.abs)-i)*s]
-               for j := s - 1; j >= 0; j-- {
-                       wordBytes[j] = byte(w)
-                       w >>= 8
-               }
-       }
-
-       i := 0
-       for i < len(b) && b[i] == 0 {
-               i++
-       }
-
-       return b[i:]
+       buf := make([]byte, len(z.abs)*_S)
+       return buf[z.abs.bytes(buf):]
 }
 
 
@@ -739,3 +697,34 @@ func (z *Int) Not(x *Int) *Int {
        z.neg = true // z cannot be zero if x is positive
        return z
 }
+
+
+// Gob codec version. Permits backward-compatible changes to the encoding.
+const version byte = 1
+
+// GobEncode implements the gob.GobEncoder interface.
+func (z *Int) GobEncode() ([]byte, os.Error) {
+       buf := make([]byte, len(z.abs)*_S+1) // extra byte for version and sign bit
+       i := z.abs.bytes(buf) - 1            // i >= 0
+       b := version << 1                    // make space for sign bit
+       if z.neg {
+               b |= 1
+       }
+       buf[i] = b
+       return buf[i:], nil
+}
+
+
+// GobDecode implements the gob.GobDecoder interface.
+func (z *Int) GobDecode(buf []byte) os.Error {
+       if len(buf) == 0 {
+               return os.NewError("Int.GobDecode: no data")
+       }
+       b := buf[0]
+       if b>>1 != version {
+               return os.NewError(fmt.Sprintf("Int.GobDecode: encoding version %d not supported", b>>1))
+       }
+       z.neg = b&1 != 0
+       z.abs = z.abs.setBytes(buf[1:])
+       return nil
+}
index fc981e1..c0cc9ac 100644 (file)
@@ -8,6 +8,7 @@ import (
        "bytes"
        "encoding/hex"
        "fmt"
+       "gob"
        "testing"
        "testing/quick"
 )
@@ -1053,3 +1054,41 @@ func TestModInverse(t *testing.T) {
                }
        }
 }
+
+
+var gobEncodingTests = []string{
+       "0",
+       "1",
+       "2",
+       "10",
+       "42",
+       "1234567890",
+       "298472983472983471903246121093472394872319615612417471234712061",
+}
+
+func TestGobEncoding(t *testing.T) {
+       var medium bytes.Buffer
+       enc := gob.NewEncoder(&medium)
+       dec := gob.NewDecoder(&medium)
+       for i, test := range gobEncodingTests {
+               for j := 0; j < 2; j++ {
+                       medium.Reset() // empty buffer for each test case (in case of failures)
+                       stest := test
+                       if j == 0 {
+                               stest = "-" + test
+                       }
+                       var tx Int
+                       tx.SetString(stest, 10)
+                       if err := enc.Encode(&tx); err != nil {
+                               t.Errorf("#%d%c: encoding failed: %s", i, 'a'+j, err)
+                       }
+                       var rx Int
+                       if err := dec.Decode(&rx); err != nil {
+                               t.Errorf("#%d%c: decoding failed: %s", i, 'a'+j, err)
+                       }
+                       if rx.Cmp(&tx) != 0 {
+                               t.Errorf("#%d%c: transmission failed: got %s want %s", i, 'a'+j, &rx, &tx)
+                       }
+               }
+       }
+}
index a308f69..a04d3b1 100644 (file)
@@ -1065,3 +1065,50 @@ NextRandom:
 
        return true
 }
+
+
+// bytes writes the value of z into buf using big-endian encoding.
+// len(buf) must be >= len(z)*_S. The value of z is encoded in the
+// slice buf[i:]. The number i of unused bytes at the beginning of
+// buf is returned as result.
+func (z nat) bytes(buf []byte) (i int) {
+       i = len(buf)
+       for _, d := range z {
+               for j := 0; j < _S; j++ {
+                       i--
+                       buf[i] = byte(d)
+                       d >>= 8
+               }
+       }
+
+       for i < len(buf) && buf[i] == 0 {
+               i++
+       }
+
+       return
+}
+
+
+// setBytes interprets buf as the bytes of a big-endian unsigned
+// integer, sets z to that value, and returns z.
+func (z nat) setBytes(buf []byte) nat {
+       z = z.make((len(buf) + _S - 1) / _S)
+
+       k := 0
+       s := uint(0)
+       var d Word
+       for i := len(buf); i > 0; i-- {
+               d |= Word(buf[i-1]) << s
+               if s += 8; s == _S*8 {
+                       z[k] = d
+                       k++
+                       s = 0
+                       d = 0
+               }
+       }
+       if k < len(z) {
+               z[k] = d
+       }
+
+       return z.norm()
+}
index 059ca6d..8028e04 100644 (file)
@@ -2,9 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package bufio
+package bufio_test
 
 import (
+       . "bufio"
        "bytes"
        "fmt"
        "io"
@@ -502,9 +503,8 @@ func TestWriteString(t *testing.T) {
        b.WriteString("7890")                      // easy after flush
        b.WriteString("abcdefghijklmnopqrstuvwxy") // hard
        b.WriteString("z")
-       b.Flush()
-       if b.err != nil {
-               t.Error("WriteString", b.err)
+       if err := b.Flush(); err != nil {
+               t.Error("WriteString", err)
        }
        s := "01234567890abcdefghijklmnopqrstuvwxyz"
        if string(buf.Bytes()) != s {
index ff54164..ed5884a 100644 (file)
@@ -191,9 +191,16 @@ func testSync(t *testing.T, level int, input []byte, name string) {
                        t.Errorf("testSync/%d: read wrong bytes: %x vs %x", i, input[lo:hi], out[:hi-lo])
                        return
                }
-               if i == 0 && buf.buf.Len() != 0 {
-                       t.Errorf("testSync/%d (%d, %d, %s): extra data after %d", i, level, len(input), name, hi-lo)
-               }
+               // This test originally checked that after reading
+               // the first half of the input, there was nothing left
+               // in the read buffer (buf.buf.Len() != 0) but that is
+               // not necessarily the case: the write Flush may emit
+               // some extra framing bits that are not necessary
+               // to process to obtain the first half of the uncompressed
+               // data.  The test ran correctly most of the time, because
+               // the background goroutine had usually read even
+               // those extra bits by now, but it's not a useful thing to
+               // check.
                buf.WriteMode()
        }
        buf.ReadMode()
index 7795a4c..4b5dfaa 100644 (file)
@@ -9,6 +9,7 @@ import (
        "io"
        "io/ioutil"
        "os"
+       "runtime"
        "strconv"
        "strings"
        "testing"
@@ -117,16 +118,34 @@ func (devNull) Write(p []byte) (int, os.Error) {
        return len(p), nil
 }
 
-func BenchmarkDecoder(b *testing.B) {
+func benchmarkDecoder(b *testing.B, n int) {
        b.StopTimer()
+       b.SetBytes(int64(n))
        buf0, _ := ioutil.ReadFile("../testdata/e.txt")
+       buf0 = buf0[:10000]
        compressed := bytes.NewBuffer(nil)
        w := NewWriter(compressed, LSB, 8)
-       io.Copy(w, bytes.NewBuffer(buf0))
+       for i := 0; i < n; i += len(buf0) {
+               io.Copy(w, bytes.NewBuffer(buf0))
+       }
        w.Close()
        buf1 := compressed.Bytes()
+       buf0, compressed, w = nil, nil, nil
+       runtime.GC()
        b.StartTimer()
        for i := 0; i < b.N; i++ {
                io.Copy(devNull{}, NewReader(bytes.NewBuffer(buf1), LSB, 8))
        }
 }
+
+func BenchmarkDecoder1e4(b *testing.B) {
+       benchmarkDecoder(b, 1e4)
+}
+
+func BenchmarkDecoder1e5(b *testing.B) {
+       benchmarkDecoder(b, 1e5)
+}
+
+func BenchmarkDecoder1e6(b *testing.B) {
+       benchmarkDecoder(b, 1e6)
+}
index 715b974..2e0a8de 100644 (file)
@@ -8,6 +8,7 @@ import (
        "io"
        "io/ioutil"
        "os"
+       "runtime"
        "testing"
 )
 
@@ -99,13 +100,33 @@ func TestWriter(t *testing.T) {
        }
 }
 
-func BenchmarkEncoder(b *testing.B) {
+func benchmarkEncoder(b *testing.B, n int) {
        b.StopTimer()
-       buf, _ := ioutil.ReadFile("../testdata/e.txt")
+       b.SetBytes(int64(n))
+       buf0, _ := ioutil.ReadFile("../testdata/e.txt")
+       buf0 = buf0[:10000]
+       buf1 := make([]byte, n)
+       for i := 0; i < n; i += len(buf0) {
+               copy(buf1[i:], buf0)
+       }
+       buf0 = nil
+       runtime.GC()
        b.StartTimer()
        for i := 0; i < b.N; i++ {
                w := NewWriter(devNull{}, LSB, 8)
-               w.Write(buf)
+               w.Write(buf1)
                w.Close()
        }
 }
+
+func BenchmarkEncoder1e4(b *testing.B) {
+       benchmarkEncoder(b, 1e4)
+}
+
+func BenchmarkEncoder1e5(b *testing.B) {
+       benchmarkEncoder(b, 1e5)
+}
+
+func BenchmarkEncoder1e6(b *testing.B) {
+       benchmarkEncoder(b, 1e6)
+}
diff --git a/libgo/go/crypto/ecdsa/ecdsa.go b/libgo/go/crypto/ecdsa/ecdsa.go
new file mode 100644 (file)
index 0000000..1f37849
--- /dev/null
@@ -0,0 +1,149 @@
+// 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 ecdsa implements the Elliptic Curve Digital Signature Algorithm, as
+// defined in FIPS 186-3.
+package ecdsa
+
+// References:
+//   [NSA]: Suite B implementor's guide to FIPS 186-3,
+//     http://www.nsa.gov/ia/_files/ecdsa.pdf
+//   [SECG]: SECG, SEC1
+//     http://www.secg.org/download/aid-780/sec1-v2.pdf
+
+import (
+       "big"
+       "crypto/elliptic"
+       "io"
+       "os"
+)
+
+// PublicKey represents an ECDSA public key.
+type PublicKey struct {
+       *elliptic.Curve
+       X, Y *big.Int
+}
+
+// PrivateKey represents a ECDSA private key.
+type PrivateKey struct {
+       PublicKey
+       D *big.Int
+}
+
+var one = new(big.Int).SetInt64(1)
+
+// randFieldElement returns a random element of the field underlying the given
+// curve using the procedure given in [NSA] A.2.1.
+func randFieldElement(c *elliptic.Curve, rand io.Reader) (k *big.Int, err os.Error) {
+       b := make([]byte, c.BitSize/8+8)
+       _, err = rand.Read(b)
+       if err != nil {
+               return
+       }
+
+       k = new(big.Int).SetBytes(b)
+       n := new(big.Int).Sub(c.N, one)
+       k.Mod(k, n)
+       k.Add(k, one)
+       return
+}
+
+// GenerateKey generates a public&private key pair.
+func GenerateKey(c *elliptic.Curve, rand io.Reader) (priv *PrivateKey, err os.Error) {
+       k, err := randFieldElement(c, rand)
+       if err != nil {
+               return
+       }
+
+       priv = new(PrivateKey)
+       priv.PublicKey.Curve = c
+       priv.D = k
+       priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes())
+       return
+}
+
+// hashToInt converts a hash value to an integer. There is some disagreement
+// about how this is done. [NSA] suggests that this is done in the obvious
+// manner, but [SECG] truncates the hash to the bit-length of the curve order
+// first. We follow [SECG] because that's what OpenSSL does.
+func hashToInt(hash []byte, c *elliptic.Curve) *big.Int {
+       orderBits := c.N.BitLen()
+       orderBytes := (orderBits + 7) / 8
+       if len(hash) > orderBytes {
+               hash = hash[:orderBytes]
+       }
+
+       ret := new(big.Int).SetBytes(hash)
+       excess := orderBytes*8 - orderBits
+       if excess > 0 {
+               ret.Rsh(ret, uint(excess))
+       }
+       return ret
+}
+
+// Sign signs an arbitrary length hash (which should be the result of hashing a
+// larger message) using the private key, priv. It returns the signature as a
+// pair of integers. The security of the private key depends on the entropy of
+// rand.
+func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err os.Error) {
+       // See [NSA] 3.4.1
+       c := priv.PublicKey.Curve
+
+       var k, kInv *big.Int
+       for {
+               for {
+                       k, err = randFieldElement(c, rand)
+                       if err != nil {
+                               r = nil
+                               return
+                       }
+
+                       kInv = new(big.Int).ModInverse(k, c.N)
+                       r, _ = priv.Curve.ScalarBaseMult(k.Bytes())
+                       r.Mod(r, priv.Curve.N)
+                       if r.Sign() != 0 {
+                               break
+                       }
+               }
+
+               e := hashToInt(hash, c)
+               s = new(big.Int).Mul(priv.D, r)
+               s.Add(s, e)
+               s.Mul(s, kInv)
+               s.Mod(s, priv.PublicKey.Curve.N)
+               if s.Sign() != 0 {
+                       break
+               }
+       }
+
+       return
+}
+
+// Verify verifies the signature in r, s of hash using the public key, pub. It
+// returns true iff the signature is valid.
+func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
+       // See [NSA] 3.4.2
+       c := pub.Curve
+
+       if r.Sign() == 0 || s.Sign() == 0 {
+               return false
+       }
+       if r.Cmp(c.N) >= 0 || s.Cmp(c.N) >= 0 {
+               return false
+       }
+       e := hashToInt(hash, c)
+       w := new(big.Int).ModInverse(s, c.N)
+
+       u1 := e.Mul(e, w)
+       u2 := w.Mul(r, w)
+
+       x1, y1 := c.ScalarBaseMult(u1.Bytes())
+       x2, y2 := c.ScalarMult(pub.X, pub.Y, u2.Bytes())
+       if x1.Cmp(x2) == 0 {
+               return false
+       }
+       x, _ := c.Add(x1, y1, x2, y2)
+       x.Mod(x, c.N)
+       return x.Cmp(r) == 0
+}
diff --git a/libgo/go/crypto/ecdsa/ecdsa_test.go b/libgo/go/crypto/ecdsa/ecdsa_test.go
new file mode 100644 (file)
index 0000000..cc22b7a
--- /dev/null
@@ -0,0 +1,218 @@
+// 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 ecdsa
+
+import (
+       "big"
+       "crypto/elliptic"
+       "crypto/sha1"
+       "crypto/rand"
+       "encoding/hex"
+       "testing"
+)
+
+func testKeyGeneration(t *testing.T, c *elliptic.Curve, tag string) {
+       priv, err := GenerateKey(c, rand.Reader)
+       if err != nil {
+               t.Errorf("%s: error: %s", tag, err)
+               return
+       }
+       if !c.IsOnCurve(priv.PublicKey.X, priv.PublicKey.Y) {
+               t.Errorf("%s: public key invalid", tag, err)
+       }
+}
+
+func TestKeyGeneration(t *testing.T) {
+       testKeyGeneration(t, elliptic.P224(), "p224")
+       testKeyGeneration(t, elliptic.P256(), "p256")
+       testKeyGeneration(t, elliptic.P384(), "p384")
+       testKeyGeneration(t, elliptic.P521(), "p521")
+}
+
+func testSignAndVerify(t *testing.T, c *elliptic.Curve, tag string) {
+       priv, _ := GenerateKey(c, rand.Reader)
+
+       hashed := []byte("testing")
+       r, s, err := Sign(rand.Reader, priv, hashed)
+       if err != nil {
+               t.Errorf("%s: error signing: %s", tag, err)
+               return
+       }
+
+       if !Verify(&priv.PublicKey, hashed, r, s) {
+               t.Errorf("%s: Verify failed", tag)
+       }
+
+       hashed[0] ^= 0xff
+       if Verify(&priv.PublicKey, hashed, r, s) {
+               t.Errorf("%s: Verify always works!", tag)
+       }
+}
+
+func TestSignAndVerify(t *testing.T) {
+       testSignAndVerify(t, elliptic.P224(), "p224")
+       testSignAndVerify(t, elliptic.P256(), "p256")
+       testSignAndVerify(t, elliptic.P384(), "p384")
+       testSignAndVerify(t, elliptic.P521(), "p521")
+}
+
+func fromHex(s string) *big.Int {
+       r, ok := new(big.Int).SetString(s, 16)
+       if !ok {
+               panic("bad hex")
+       }
+       return r
+}
+
+// These test vectors were taken from
+//   http://csrc.nist.gov/groups/STM/cavp/documents/dss/ecdsatestvectors.zip
+var testVectors = []struct {
+       msg    string
+       Qx, Qy string
+       r, s   string
+       ok     bool
+}{
+       {
+               "09626b45493672e48f3d1226a3aff3201960e577d33a7f72c7eb055302db8fe8ed61685dd036b554942a5737cd1512cdf811ee0c00e6dd2f08c69f08643be396e85dafda664801e772cdb7396868ac47b172245b41986aa2648cb77fbbfa562581be06651355a0c4b090f9d17d8f0ab6cced4e0c9d386cf465a516630f0231bd",
+               "9504b5b82d97a264d8b3735e0568decabc4b6ca275bc53cbadfc1c40",
+               "03426f80e477603b10dee670939623e3da91a94267fc4e51726009ed",
+               "81d3ac609f9575d742028dd496450a58a60eea2dcf8b9842994916e1",
+               "96a8c5f382c992e8f30ccce9af120b067ec1d74678fa8445232f75a5",
+               false,
+       },
+       {
+               "96b2b6536f6df29be8567a72528aceeaccbaa66c66c534f3868ca9778b02faadb182e4ed34662e73b9d52ecbe9dc8e875fc05033c493108b380689ebf47e5b062e6a0cdb3dd34ce5fe347d92768d72f7b9b377c20aea927043b509c078ed2467d7113405d2ddd458811e6faf41c403a2a239240180f1430a6f4330df5d77de37",
+               "851e3100368a22478a0029353045ae40d1d8202ef4d6533cfdddafd8",
+               "205302ac69457dd345e86465afa72ee8c74ca97e2b0b999aec1f10c2",
+               "4450c2d38b697e990721aa2dbb56578d32b4f5aeb3b9072baa955ee0",
+               "e26d4b589166f7b4ba4b1c8fce823fa47aad22f8c9c396b8c6526e12",
+               false,
+       },
+       {
+               "86778dbb4a068a01047a8d245d632f636c11d2ad350740b36fad90428b454ad0f120cb558d12ea5c8a23db595d87543d06d1ef489263d01ee529871eb68737efdb8ff85bc7787b61514bed85b7e01d6be209e0a4eb0db5c8df58a5c5bf706d76cb2bdf7800208639e05b89517155d11688236e6a47ed37d8e5a2b1e0adea338e",
+               "ad5bda09d319a717c1721acd6688d17020b31b47eef1edea57ceeffc",
+               "c8ce98e181770a7c9418c73c63d01494b8b80a41098c5ea50692c984",
+               "de5558c257ab4134e52c19d8db3b224a1899cbd08cc508ce8721d5e9",
+               "745db7af5a477e5046705c0a5eff1f52cb94a79d481f0c5a5e108ecd",
+               true,
+       },
+       {
+               "4bc6ef1958556686dab1e39c3700054a304cbd8f5928603dcd97fafd1f29e69394679b638f71c9344ce6a535d104803d22119f57b5f9477e253817a52afa9bfbc9811d6cc8c8be6b6566c6ef48b439bbb532abe30627548c598867f3861ba0b154dc1c3deca06eb28df8efd28258554b5179883a36fbb1eecf4f93ee19d41e3d",
+               "cc5eea2edf964018bdc0504a3793e4d2145142caa09a72ac5fb8d3e8",
+               "a48d78ae5d08aa725342773975a00d4219cf7a8029bb8cf3c17c374a",
+               "67b861344b4e416d4094472faf4272f6d54a497177fbc5f9ef292836",
+               "1d54f3fcdad795bf3b23408ecbac3e1321d1d66f2e4e3d05f41f7020",
+               false,
+       },
+       {
+               "bb658732acbf3147729959eb7318a2058308b2739ec58907dd5b11cfa3ecf69a1752b7b7d806fe00ec402d18f96039f0b78dbb90a59c4414fb33f1f4e02e4089de4122cd93df5263a95be4d7084e2126493892816e6a5b4ed123cb705bf930c8f67af0fb4514d5769232a9b008a803af225160ce63f675bd4872c4c97b146e5e",
+               "6234c936e27bf141fc7534bfc0a7eedc657f91308203f1dcbd642855",
+               "27983d87ca785ef4892c3591ef4a944b1deb125dd58bd351034a6f84",
+               "e94e05b42d01d0b965ffdd6c3a97a36a771e8ea71003de76c4ecb13f",
+               "1dc6464ffeefbd7872a081a5926e9fc3e66d123f1784340ba17737e9",
+               false,
+       },
+       {
+               "7c00be9123bfa2c4290be1d8bc2942c7f897d9a5b7917e3aabd97ef1aab890f148400a89abd554d19bec9d8ed911ce57b22fbcf6d30ca2115f13ce0a3f569a23bad39ee645f624c49c60dcfc11e7d2be24de9c905596d8f23624d63dc46591d1f740e46f982bfae453f107e80db23545782be23ce43708245896fc54e1ee5c43",
+               "9f3f037282aaf14d4772edffff331bbdda845c3f65780498cde334f1",
+               "8308ee5a16e3bcb721b6bc30000a0419bc1aaedd761be7f658334066",
+               "6381d7804a8808e3c17901e4d283b89449096a8fba993388fa11dc54",
+               "8e858f6b5b253686a86b757bad23658cda53115ac565abca4e3d9f57",
+               false,
+       },
+       {
+               "cffc122a44840dc705bb37130069921be313d8bde0b66201aebc48add028ca131914ef2e705d6bedd19dc6cf9459bbb0f27cdfe3c50483808ffcdaffbeaa5f062e097180f07a40ef4ab6ed03fe07ed6bcfb8afeb42c97eafa2e8a8df469de07317c5e1494c41547478eff4d8c7d9f0f484ad90fedf6e1c35ee68fa73f1691601",
+               "a03b88a10d930002c7b17ca6af2fd3e88fa000edf787dc594f8d4fd4",
+               "e0cf7acd6ddc758e64847fe4df9915ebda2f67cdd5ec979aa57421f5",
+               "387b84dcf37dc343c7d2c5beb82f0bf8bd894b395a7b894565d296c1",
+               "4adc12ce7d20a89ce3925e10491c731b15ddb3f339610857a21b53b4",
+               false,
+       },
+       {
+               "26e0e0cafd85b43d16255908ccfd1f061c680df75aba3081246b337495783052ba06c60f4a486c1591a4048bae11b4d7fec4f161d80bdc9a7b79d23e44433ed625eab280521a37f23dd3e1bdc5c6a6cfaa026f3c45cf703e76dab57add93fe844dd4cda67dc3bddd01f9152579e49df60969b10f09ce9372fdd806b0c7301866",
+               "9a8983c42f2b5a87c37a00458b5970320d247f0c8a88536440173f7d",
+               "15e489ec6355351361900299088cfe8359f04fe0cab78dde952be80c",
+               "929a21baa173d438ec9f28d6a585a2f9abcfc0a4300898668e476dc0",
+               "59a853f046da8318de77ff43f26fe95a92ee296fa3f7e56ce086c872",
+               true,
+       },
+       {
+               "1078eac124f48ae4f807e946971d0de3db3748dd349b14cca5c942560fb25401b2252744f18ad5e455d2d97ed5ae745f55ff509c6c8e64606afe17809affa855c4c4cdcaf6b69ab4846aa5624ed0687541aee6f2224d929685736c6a23906d974d3c257abce1a3fb8db5951b89ecb0cda92b5207d93f6618fd0f893c32cf6a6e",
+               "d6e55820bb62c2be97650302d59d667a411956138306bd566e5c3c2b",
+               "631ab0d64eaf28a71b9cbd27a7a88682a2167cee6251c44e3810894f",
+               "65af72bc7721eb71c2298a0eb4eed3cec96a737cc49125706308b129",
+               "bd5a987c78e2d51598dbd9c34a9035b0069c580edefdacee17ad892a",
+               false,
+       },
+       {
+               "919deb1fdd831c23481dfdb2475dcbe325b04c34f82561ced3d2df0b3d749b36e255c4928973769d46de8b95f162b53cd666cad9ae145e7fcfba97919f703d864efc11eac5f260a5d920d780c52899e5d76f8fe66936ff82130761231f536e6a3d59792f784902c469aa897aabf9a0678f93446610d56d5e0981e4c8a563556b",
+               "269b455b1024eb92d860a420f143ac1286b8cce43031562ae7664574",
+               "baeb6ca274a77c44a0247e5eb12ca72bdd9a698b3f3ae69c9f1aaa57",
+               "cb4ec2160f04613eb0dfe4608486091a25eb12aa4dec1afe91cfb008",
+               "40b01d8cd06589481574f958b98ca08ade9d2a8fe31024375c01bb40",
+               false,
+       },
+       {
+               "6e012361250dacf6166d2dd1aa7be544c3206a9d43464b3fcd90f3f8cf48d08ec099b59ba6fe7d9bdcfaf244120aed1695d8be32d1b1cd6f143982ab945d635fb48a7c76831c0460851a3d62b7209c30cd9c2abdbe3d2a5282a9fcde1a6f418dd23c409bc351896b9b34d7d3a1a63bbaf3d677e612d4a80fa14829386a64b33f",
+               "6d2d695efc6b43b13c14111f2109608f1020e3e03b5e21cfdbc82fcd",
+               "26a4859296b7e360b69cf40be7bd97ceaffa3d07743c8489fc47ca1b",
+               "9a8cb5f2fdc288b7183c5b32d8e546fc2ed1ca4285eeae00c8b572ad",
+               "8c623f357b5d0057b10cdb1a1593dab57cda7bdec9cf868157a79b97",
+               true,
+       },
+       {
+               "bf6bd7356a52b234fe24d25557200971fc803836f6fec3cade9642b13a8e7af10ab48b749de76aada9d8927f9b12f75a2c383ca7358e2566c4bb4f156fce1fd4e87ef8c8d2b6b1bdd351460feb22cdca0437ac10ca5e0abbbce9834483af20e4835386f8b1c96daaa41554ceee56730aac04f23a5c765812efa746051f396566",
+               "14250131b2599939cf2d6bc491be80ddfe7ad9de644387ee67de2d40",
+               "b5dc473b5d014cd504022043c475d3f93c319a8bdcb7262d9e741803",
+               "4f21642f2201278a95339a80f75cc91f8321fcb3c9462562f6cbf145",
+               "452a5f816ea1f75dee4fd514fa91a0d6a43622981966c59a1b371ff8",
+               false,
+       },
+       {
+               "0eb7f4032f90f0bd3cf9473d6d9525d264d14c031a10acd31a053443ed5fe919d5ac35e0be77813071b4062f0b5fdf58ad5f637b76b0b305aec18f82441b6e607b44cdf6e0e3c7c57f24e6fd565e39430af4a6b1d979821ed0175fa03e3125506847654d7e1ae904ce1190ae38dc5919e257bdac2db142a6e7cd4da6c2e83770",
+               "d1f342b7790a1667370a1840255ac5bbbdc66f0bc00ae977d99260ac",
+               "76416cabae2de9a1000b4646338b774baabfa3db4673790771220cdb",
+               "bc85e3fc143d19a7271b2f9e1c04b86146073f3fab4dda1c3b1f35ca",
+               "9a5c70ede3c48d5f43307a0c2a4871934424a3303b815df4bb0f128e",
+               false,
+       },
+       {
+               "5cc25348a05d85e56d4b03cec450128727bc537c66ec3a9fb613c151033b5e86878632249cba83adcefc6c1e35dcd31702929c3b57871cda5c18d1cf8f9650a25b917efaed56032e43b6fc398509f0d2997306d8f26675f3a8683b79ce17128e006aa0903b39eeb2f1001be65de0520115e6f919de902b32c38d691a69c58c92",
+               "7e49a7abf16a792e4c7bbc4d251820a2abd22d9f2fc252a7bf59c9a6",
+               "44236a8fb4791c228c26637c28ae59503a2f450d4cfb0dc42aa843b9",
+               "084461b4050285a1a85b2113be76a17878d849e6bc489f4d84f15cd8",
+               "079b5bddcc4d45de8dbdfd39f69817c7e5afa454a894d03ee1eaaac3",
+               false,
+       },
+       {
+               "1951533ce33afb58935e39e363d8497a8dd0442018fd96dff167b3b23d7206a3ee182a3194765df4768a3284e23b8696c199b4686e670d60c9d782f08794a4bccc05cffffbd1a12acd9eb1cfa01f7ebe124da66ecff4599ea7720c3be4bb7285daa1a86ebf53b042bd23208d468c1b3aa87381f8e1ad63e2b4c2ba5efcf05845",
+               "31945d12ebaf4d81f02be2b1768ed80784bf35cf5e2ff53438c11493",
+               "a62bebffac987e3b9d3ec451eb64c462cdf7b4aa0b1bbb131ceaa0a4",
+               "bc3c32b19e42b710bca5c6aaa128564da3ddb2726b25f33603d2af3c",
+               "ed1a719cc0c507edc5239d76fe50e2306c145ad252bd481da04180c0",
+               false,
+       },
+}
+
+func TestVectors(t *testing.T) {
+       sha := sha1.New()
+
+       for i, test := range testVectors {
+               pub := PublicKey{
+                       Curve: elliptic.P224(),
+                       X:     fromHex(test.Qx),
+                       Y:     fromHex(test.Qy),
+               }
+               msg, _ := hex.DecodeString(test.msg)
+               sha.Reset()
+               sha.Write(msg)
+               hashed := sha.Sum()
+               r := fromHex(test.r)
+               s := fromHex(test.s)
+               if Verify(&pub, hashed, r, s) != test.ok {
+                       t.Errorf("%d: bad result", i)
+               }
+       }
+}
index beac45c..2296e96 100644 (file)
@@ -24,6 +24,7 @@ import (
 // See http://www.hyperelliptic.org/EFD/g1p/auto-shortw.html
 type Curve struct {
        P       *big.Int // the order of the underlying field
+       N       *big.Int // the order of the base point
        B       *big.Int // the constant of the curve equation
        Gx, Gy  *big.Int // (x,y) of the base point
        BitSize int      // the size of the underlying field
@@ -315,6 +316,7 @@ func initP224() {
        // See FIPS 186-3, section D.2.2
        p224 = new(Curve)
        p224.P, _ = new(big.Int).SetString("26959946667150639794667015087019630673557916260026308143510066298881", 10)
+       p224.N, _ = new(big.Int).SetString("26959946667150639794667015087019625940457807714424391721682722368061", 10)
        p224.B, _ = new(big.Int).SetString("b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4", 16)
        p224.Gx, _ = new(big.Int).SetString("b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21", 16)
        p224.Gy, _ = new(big.Int).SetString("bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34", 16)
@@ -325,6 +327,7 @@ func initP256() {
        // See FIPS 186-3, section D.2.3
        p256 = new(Curve)
        p256.P, _ = new(big.Int).SetString("115792089210356248762697446949407573530086143415290314195533631308867097853951", 10)
+       p256.N, _ = new(big.Int).SetString("115792089210356248762697446949407573529996955224135760342422259061068512044369", 10)
        p256.B, _ = new(big.Int).SetString("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16)
        p256.Gx, _ = new(big.Int).SetString("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 16)
        p256.Gy, _ = new(big.Int).SetString("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 16)
@@ -335,6 +338,7 @@ func initP384() {
        // See FIPS 186-3, section D.2.4
        p384 = new(Curve)
        p384.P, _ = new(big.Int).SetString("39402006196394479212279040100143613805079739270465446667948293404245721771496870329047266088258938001861606973112319", 10)
+       p384.N, _ = new(big.Int).SetString("39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942643", 10)
        p384.B, _ = new(big.Int).SetString("b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef", 16)
        p384.Gx, _ = new(big.Int).SetString("aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7", 16)
        p384.Gy, _ = new(big.Int).SetString("3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f", 16)
@@ -345,6 +349,7 @@ func initP521() {
        // See FIPS 186-3, section D.2.5
        p521 = new(Curve)
        p521.P, _ = new(big.Int).SetString("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", 10)
+       p521.N, _ = new(big.Int).SetString("6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449", 10)
        p521.B, _ = new(big.Int).SetString("051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", 16)
        p521.Gx, _ = new(big.Int).SetString("c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66", 16)
        p521.Gy, _ = new(big.Int).SetString("11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650", 16)
index 269603b..57ff3af 100644 (file)
@@ -7,6 +7,7 @@
 package packet
 
 import (
+       "big"
        "crypto/aes"
        "crypto/cast5"
        "crypto/cipher"
@@ -166,10 +167,10 @@ func readHeader(r io.Reader) (tag packetType, length int64, contents io.Reader,
        return
 }
 
-// serialiseHeader writes an OpenPGP packet header to w. See RFC 4880, section
+// serializeHeader writes an OpenPGP packet header to w. See RFC 4880, section
 // 4.2.
-func serialiseHeader(w io.Writer, ptype packetType, length int) (err os.Error) {
-       var buf [5]byte
+func serializeHeader(w io.Writer, ptype packetType, length int) (err os.Error) {
+       var buf [6]byte
        var n int
 
        buf[0] = 0x80 | 0x40 | byte(ptype)
@@ -178,16 +179,16 @@ func serialiseHeader(w io.Writer, ptype packetType, length int) (err os.Error) {
                n = 2
        } else if length < 8384 {
                length -= 192
-               buf[1] = byte(length >> 8)
+               buf[1] = 192 + byte(length>>8)
                buf[2] = byte(length)
                n = 3
        } else {
-               buf[0] = 255
-               buf[1] = byte(length >> 24)
-               buf[2] = byte(length >> 16)
-               buf[3] = byte(length >> 8)
-               buf[4] = byte(length)
-               n = 5
+               buf[1] = 255
+               buf[2] = byte(length >> 24)
+               buf[3] = byte(length >> 16)
+               buf[4] = byte(length >> 8)
+               buf[5] = byte(length)
+               n = 6
        }
 
        _, err = w.Write(buf[:n])
@@ -371,7 +372,7 @@ func (cipher CipherFunction) new(key []byte) (block cipher.Block) {
 
 // readMPI reads a big integer from r. The bit length returned is the bit
 // length that was specified in r. This is preserved so that the integer can be
-// reserialised exactly.
+// reserialized exactly.
 func readMPI(r io.Reader) (mpi []byte, bitLength uint16, err os.Error) {
        var buf [2]byte
        _, err = readFull(r, buf[0:])
@@ -385,7 +386,7 @@ func readMPI(r io.Reader) (mpi []byte, bitLength uint16, err os.Error) {
        return
 }
 
-// writeMPI serialises a big integer to r.
+// writeMPI serializes a big integer to w.
 func writeMPI(w io.Writer, bitLength uint16, mpiBytes []byte) (err os.Error) {
        _, err = w.Write([]byte{byte(bitLength >> 8), byte(bitLength)})
        if err == nil {
@@ -393,3 +394,8 @@ func writeMPI(w io.Writer, bitLength uint16, mpiBytes []byte) (err os.Error) {
        }
        return
 }
+
+// writeBig serializes a *big.Int to w.
+func writeBig(w io.Writer, i *big.Int) os.Error {
+       return writeMPI(w, uint16(i.BitLen()), i.Bytes())
+}
index 6789d2a..1a4692c 100644 (file)
@@ -190,3 +190,23 @@ func TestReadHeader(t *testing.T) {
                }
        }
 }
+
+func TestSerializeHeader(t *testing.T) {
+       tag := packetTypePublicKey
+       lengths := []int{0, 1, 2, 64, 192, 193, 8000, 8384, 8385, 10000}
+
+       for _, length := range lengths {
+               buf := bytes.NewBuffer(nil)
+               serializeHeader(buf, tag, length)
+               tag2, length2, _, err := readHeader(buf)
+               if err != nil {
+                       t.Errorf("length %d, err: %s", length, err)
+               }
+               if tag2 != tag {
+                       t.Errorf("length %d, tag incorrect (got %d, want %d)", length, tag2, tag)
+               }
+               if int(length2) != length {
+                       t.Errorf("length %d, length incorrect (got %d)", length, length2)
+               }
+       }
+}
index b228917..6944823 100644 (file)
@@ -8,6 +8,7 @@ import (
        "big"
        "bytes"
        "crypto/cipher"
+       "crypto/dsa"
        "crypto/openpgp/error"
        "crypto/openpgp/s2k"
        "crypto/rsa"
@@ -134,7 +135,16 @@ func (pk *PrivateKey) Decrypt(passphrase []byte) os.Error {
 }
 
 func (pk *PrivateKey) parsePrivateKey(data []byte) (err os.Error) {
-       // TODO(agl): support DSA and ECDSA private keys.
+       switch pk.PublicKey.PubKeyAlgo {
+       case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoRSAEncryptOnly:
+               return pk.parseRSAPrivateKey(data)
+       case PubKeyAlgoDSA:
+               return pk.parseDSAPrivateKey(data)
+       }
+       panic("impossible")
+}
+
+func (pk *PrivateKey) parseRSAPrivateKey(data []byte) (err os.Error) {
        rsaPub := pk.PublicKey.PublicKey.(*rsa.PublicKey)
        rsaPriv := new(rsa.PrivateKey)
        rsaPriv.PublicKey = *rsaPub
@@ -162,3 +172,22 @@ func (pk *PrivateKey) parsePrivateKey(data []byte) (err os.Error) {
 
        return nil
 }
+
+func (pk *PrivateKey) parseDSAPrivateKey(data []byte) (err os.Error) {
+       dsaPub := pk.PublicKey.PublicKey.(*dsa.PublicKey)
+       dsaPriv := new(dsa.PrivateKey)
+       dsaPriv.PublicKey = *dsaPub
+
+       buf := bytes.NewBuffer(data)
+       x, _, err := readMPI(buf)
+       if err != nil {
+               return
+       }
+
+       dsaPriv.X = new(big.Int).SetBytes(x)
+       pk.PrivateKey = dsaPriv
+       pk.Encrypted = false
+       pk.encryptedData = nil
+
+       return nil
+}
index 8866bda..ebef481 100644 (file)
@@ -11,6 +11,7 @@ import (
        "crypto/rsa"
        "crypto/sha1"
        "encoding/binary"
+       "fmt"
        "hash"
        "io"
        "os"
@@ -178,12 +179,6 @@ func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err os.E
                return error.InvalidArgumentError("public key cannot generate signatures")
        }
 
-       rsaPublicKey, ok := pk.PublicKey.(*rsa.PublicKey)
-       if !ok {
-               // TODO(agl): support DSA and ECDSA keys.
-               return error.UnsupportedError("non-RSA public key")
-       }
-
        signed.Write(sig.HashSuffix)
        hashBytes := signed.Sum()
 
@@ -191,11 +186,28 @@ func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err os.E
                return error.SignatureError("hash tag doesn't match")
        }
 
-       err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.Signature)
-       if err != nil {
-               return error.SignatureError("RSA verification failure")
+       if pk.PubKeyAlgo != sig.PubKeyAlgo {
+               return error.InvalidArgumentError("public key and signature use different algorithms")
        }
-       return nil
+
+       switch pk.PubKeyAlgo {
+       case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
+               rsaPublicKey, _ := pk.PublicKey.(*rsa.PublicKey)
+               err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature)
+               if err != nil {
+                       return error.SignatureError("RSA verification failure")
+               }
+               return nil
+       case PubKeyAlgoDSA:
+               dsaPublicKey, _ := pk.PublicKey.(*dsa.PublicKey)
+               if !dsa.Verify(dsaPublicKey, hashBytes, sig.DSASigR, sig.DSASigS) {
+                       return error.SignatureError("DSA verification failure")
+               }
+               return nil
+       default:
+               panic("shouldn't happen")
+       }
+       panic("unreachable")
 }
 
 // VerifyKeySignature returns nil iff sig is a valid signature, make by this
@@ -239,9 +251,21 @@ func (pk *PublicKey) VerifyUserIdSignature(id string, sig *Signature) (err os.Er
        return pk.VerifySignature(h, sig)
 }
 
+// KeyIdString returns the public key's fingerprint in capital hex
+// (e.g. "6C7EE1B8621CC013").
+func (pk *PublicKey) KeyIdString() string {
+       return fmt.Sprintf("%X", pk.Fingerprint[12:20])
+}
+
+// KeyIdShortString returns the short form of public key's fingerprint
+// in capital hex, as shown by gpg --list-keys (e.g. "621CC013").
+func (pk *PublicKey) KeyIdShortString() string {
+       return fmt.Sprintf("%X", pk.Fingerprint[16:20])
+}
+
 // A parsedMPI is used to store the contents of a big integer, along with the
 // bit length that was specified in the original input. This allows the MPI to
-// be reserialised exactly.
+// be reserialized exactly.
 type parsedMPI struct {
        bytes     []byte
        bitLength uint16
index c015f64..069388c 100644 (file)
@@ -16,9 +16,11 @@ var pubKeyTests = []struct {
        creationTime   uint32
        pubKeyAlgo     PublicKeyAlgorithm
        keyId          uint64
+       keyIdString    string
+       keyIdShort     string
 }{
-       {rsaPkDataHex, rsaFingerprintHex, 0x4d3c5c10, PubKeyAlgoRSA, 0xa34d7e18c20c31bb},
-       {dsaPkDataHex, dsaFingerprintHex, 0x4d432f89, PubKeyAlgoDSA, 0x8e8fbe54062f19ed},
+       {rsaPkDataHex, rsaFingerprintHex, 0x4d3c5c10, PubKeyAlgoRSA, 0xa34d7e18c20c31bb, "A34D7E18C20C31BB", "C20C31BB"},
+       {dsaPkDataHex, dsaFingerprintHex, 0x4d432f89, PubKeyAlgoDSA, 0x8e8fbe54062f19ed, "8E8FBE54062F19ED", "062F19ED"},
 }
 
 func TestPublicKeyRead(t *testing.T) {
@@ -46,6 +48,12 @@ func TestPublicKeyRead(t *testing.T) {
                if pk.KeyId != test.keyId {
                        t.Errorf("#%d: bad keyid got:%x want:%x", i, pk.KeyId, test.keyId)
                }
+               if g, e := pk.KeyIdString(), test.keyIdString; g != e {
+                       t.Errorf("#%d: bad KeyIdString got:%q want:%q", i, g, e)
+               }
+               if g, e := pk.KeyIdShortString(), test.keyIdShort; g != e {
+                       t.Errorf("#%d: bad KeyIdShortString got:%q want:%q", i, g, e)
+               }
        }
 }
 
index fd2518a..719657e 100644 (file)
@@ -5,7 +5,9 @@
 package packet
 
 import (
+       "big"
        "crypto"
+       "crypto/dsa"
        "crypto/openpgp/error"
        "crypto/openpgp/s2k"
        "crypto/rand"
@@ -29,7 +31,9 @@ type Signature struct {
        // of bad signed data.
        HashTag      [2]byte
        CreationTime uint32 // Unix epoch time
-       Signature    []byte
+
+       RSASignature     []byte
+       DSASigR, DSASigS *big.Int
 
        // The following are optional so are nil when not included in the
        // signature.
@@ -66,7 +70,7 @@ func (sig *Signature) parse(r io.Reader) (err os.Error) {
        sig.SigType = SignatureType(buf[0])
        sig.PubKeyAlgo = PublicKeyAlgorithm(buf[1])
        switch sig.PubKeyAlgo {
-       case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
+       case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA:
        default:
                err = error.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo)))
                return
@@ -122,8 +126,20 @@ func (sig *Signature) parse(r io.Reader) (err os.Error) {
                return
        }
 
-       // We have already checked that the public key algorithm is RSA.
-       sig.Signature, _, err = readMPI(r)
+       switch sig.PubKeyAlgo {
+       case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
+               sig.RSASignature, _, err = readMPI(r)
+       case PubKeyAlgoDSA:
+               var rBytes, sBytes []byte
+               rBytes, _, err = readMPI(r)
+               sig.DSASigR = new(big.Int).SetBytes(rBytes)
+               if err == nil {
+                       sBytes, _, err = readMPI(r)
+                       sig.DSASigS = new(big.Int).SetBytes(sBytes)
+               }
+       default:
+               panic("unreachable")
+       }
        return
 }
 
@@ -316,8 +332,8 @@ func subpacketLengthLength(length int) int {
        return 5
 }
 
-// serialiseSubpacketLength marshals the given length into to.
-func serialiseSubpacketLength(to []byte, length int) int {
+// serializeSubpacketLength marshals the given length into to.
+func serializeSubpacketLength(to []byte, length int) int {
        if length < 192 {
                to[0] = byte(length)
                return 1
@@ -336,7 +352,7 @@ func serialiseSubpacketLength(to []byte, length int) int {
        return 5
 }
 
-// subpacketsLength returns the serialised length, in bytes, of the given
+// subpacketsLength returns the serialized length, in bytes, of the given
 // subpackets.
 func subpacketsLength(subpackets []outputSubpacket, hashed bool) (length int) {
        for _, subpacket := range subpackets {
@@ -349,11 +365,11 @@ func subpacketsLength(subpackets []outputSubpacket, hashed bool) (length int) {
        return
 }
 
-// serialiseSubpackets marshals the given subpackets into to.
-func serialiseSubpackets(to []byte, subpackets []outputSubpacket, hashed bool) {
+// serializeSubpackets marshals the given subpackets into to.
+func serializeSubpackets(to []byte, subpackets []outputSubpacket, hashed bool) {
        for _, subpacket := range subpackets {
                if subpacket.hashed == hashed {
-                       n := serialiseSubpacketLength(to, len(subpacket.contents)+1)
+                       n := serializeSubpacketLength(to, len(subpacket.contents)+1)
                        to[n] = byte(subpacket.subpacketType)
                        to = to[1+n:]
                        n = copy(to, subpacket.contents)
@@ -381,7 +397,7 @@ func (sig *Signature) buildHashSuffix() (err os.Error) {
        }
        sig.HashSuffix[4] = byte(hashedSubpacketsLen >> 8)
        sig.HashSuffix[5] = byte(hashedSubpacketsLen)
-       serialiseSubpackets(sig.HashSuffix[6:l], sig.outSubpackets, true)
+       serializeSubpackets(sig.HashSuffix[6:l], sig.outSubpackets, true)
        trailer := sig.HashSuffix[l:]
        trailer[0] = 4
        trailer[1] = 0xff
@@ -392,32 +408,66 @@ func (sig *Signature) buildHashSuffix() (err os.Error) {
        return
 }
 
-// SignRSA signs a message with an RSA private key. The hash, h, must contain
-// the hash of message to be signed and will be mutated by this function.
-func (sig *Signature) SignRSA(h hash.Hash, priv *rsa.PrivateKey) (err os.Error) {
+func (sig *Signature) signPrepareHash(h hash.Hash) (digest []byte, err os.Error) {
        err = sig.buildHashSuffix()
        if err != nil {
                return
        }
 
        h.Write(sig.HashSuffix)
-       digest := h.Sum()
+       digest = h.Sum()
        copy(sig.HashTag[:], digest)
-       sig.Signature, err = rsa.SignPKCS1v15(rand.Reader, priv, sig.Hash, digest)
        return
 }
 
-// Serialize marshals sig to w. SignRSA must have been called first.
+// SignRSA signs a message with an RSA private key. The hash, h, must contain
+// the hash of the message to be signed and will be mutated by this function.
+// On success, the signature is stored in sig. Call Serialize to write it out.
+func (sig *Signature) SignRSA(h hash.Hash, priv *rsa.PrivateKey) (err os.Error) {
+       digest, err := sig.signPrepareHash(h)
+       if err != nil {
+               return
+       }
+       sig.RSASignature, err = rsa.SignPKCS1v15(rand.Reader, priv, sig.Hash, digest)
+       return
+}
+
+// SignDSA signs a message with a DSA private key. The hash, h, must contain
+// the hash of the message to be signed and will be mutated by this function.
+// On success, the signature is stored in sig. Call Serialize to write it out.
+func (sig *Signature) SignDSA(h hash.Hash, priv *dsa.PrivateKey) (err os.Error) {
+       digest, err := sig.signPrepareHash(h)
+       if err != nil {
+               return
+       }
+       sig.DSASigR, sig.DSASigS, err = dsa.Sign(rand.Reader, priv, digest)
+       return
+}
+
+// Serialize marshals sig to w. SignRSA or SignDSA must have been called first.
 func (sig *Signature) Serialize(w io.Writer) (err os.Error) {
-       if sig.Signature == nil {
-               return error.InvalidArgumentError("Signature: need to call SignRSA before Serialize")
+       if sig.RSASignature == nil && sig.DSASigR == nil {
+               return error.InvalidArgumentError("Signature: need to call SignRSA or SignDSA before Serialize")
+       }
+
+       sigLength := 0
+       switch sig.PubKeyAlgo {
+       case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
+               sigLength = len(sig.RSASignature)
+       case PubKeyAlgoDSA:
+               sigLength = 2 /* MPI length */
+               sigLength += (sig.DSASigR.BitLen() + 7) / 8
+               sigLength += 2 /* MPI length */
+               sigLength += (sig.DSASigS.BitLen() + 7) / 8
+       default:
+               panic("impossible")
        }
 
        unhashedSubpacketsLen := subpacketsLength(sig.outSubpackets, false)
        length := len(sig.HashSuffix) - 6 /* trailer not included */ +
                2 /* length of unhashed subpackets */ + unhashedSubpacketsLen +
-               2 /* hash tag */ + 2 /* length of signature MPI */ + len(sig.Signature)
-       err = serialiseHeader(w, packetTypeSignature, length)
+               2 /* hash tag */ + 2 /* length of signature MPI */ + sigLength
+       err = serializeHeader(w, packetTypeSignature, length)
        if err != nil {
                return
        }
@@ -430,7 +480,7 @@ func (sig *Signature) Serialize(w io.Writer) (err os.Error) {
        unhashedSubpackets := make([]byte, 2+unhashedSubpacketsLen)
        unhashedSubpackets[0] = byte(unhashedSubpacketsLen >> 8)
        unhashedSubpackets[1] = byte(unhashedSubpacketsLen)
-       serialiseSubpackets(unhashedSubpackets[2:], sig.outSubpackets, false)
+       serializeSubpackets(unhashedSubpackets[2:], sig.outSubpackets, false)
 
        _, err = w.Write(unhashedSubpackets)
        if err != nil {
@@ -440,7 +490,19 @@ func (sig *Signature) Serialize(w io.Writer) (err os.Error) {
        if err != nil {
                return
        }
-       return writeMPI(w, 8*uint16(len(sig.Signature)), sig.Signature)
+
+       switch sig.PubKeyAlgo {
+       case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
+               err = writeMPI(w, 8*uint16(len(sig.RSASignature)), sig.RSASignature)
+       case PubKeyAlgoDSA:
+               err = writeBig(w, sig.DSASigR)
+               if err == nil {
+                       err = writeBig(w, sig.DSASigS)
+               }
+       default:
+               panic("impossible")
+       }
+       return
 }
 
 // outputSubpacket represents a subpacket to be marshaled.
index 58199e1..6218d99 100644 (file)
@@ -44,6 +44,17 @@ func TestReadPrivateKeyRing(t *testing.T) {
        }
 }
 
+func TestReadDSAKey(t *testing.T) {
+       kring, err := ReadKeyRing(readerFromHex(dsaTestKeyHex))
+       if err != nil {
+               t.Error(err)
+               return
+       }
+       if len(kring) != 1 || uint32(kring[0].PrimaryKey.KeyId) != 0x0CCC0360 {
+               t.Errorf("bad parse: %#v", kring)
+       }
+}
+
 func TestGetKeyById(t *testing.T) {
        kring, _ := ReadKeyRing(readerFromHex(testKeys1And2Hex))
 
@@ -192,7 +203,7 @@ func TestSymmetricallyEncrypted(t *testing.T) {
        }
 }
 
-func testDetachedSignature(t *testing.T, kring KeyRing, signature io.Reader, sigInput, tag string) {
+func testDetachedSignature(t *testing.T, kring KeyRing, signature io.Reader, sigInput, tag string, expectedSignerKeyId uint64) {
        signed := bytes.NewBufferString(sigInput)
        signer, err := CheckDetachedSignature(kring, signed, signature)
        if err != nil {
@@ -203,7 +214,6 @@ func testDetachedSignature(t *testing.T, kring KeyRing, signature io.Reader, sig
                t.Errorf("%s: signer is nil", tag)
                return
        }
-       expectedSignerKeyId := uint64(0xa34d7e18c20c31bb)
        if signer.PrimaryKey.KeyId != expectedSignerKeyId {
                t.Errorf("%s: wrong signer got:%x want:%x", tag, signer.PrimaryKey.KeyId, expectedSignerKeyId)
        }
@@ -211,10 +221,18 @@ func testDetachedSignature(t *testing.T, kring KeyRing, signature io.Reader, sig
 
 func TestDetachedSignature(t *testing.T) {
        kring, _ := ReadKeyRing(readerFromHex(testKeys1And2Hex))
-       testDetachedSignature(t, kring, readerFromHex(detachedSignatureHex), signedInput, "binary")
-       testDetachedSignature(t, kring, readerFromHex(detachedSignatureTextHex), signedInput, "text")
+       testDetachedSignature(t, kring, readerFromHex(detachedSignatureHex), signedInput, "binary", testKey1KeyId)
+       testDetachedSignature(t, kring, readerFromHex(detachedSignatureTextHex), signedInput, "text", testKey1KeyId)
 }
 
+func TestDetachedSignatureDSA(t *testing.T) {
+       kring, _ := ReadKeyRing(readerFromHex(dsaTestKeyHex))
+       testDetachedSignature(t, kring, readerFromHex(detachedSignatureDSAHex), signedInput, "binary", testKey3KeyId)
+}
+
+const testKey1KeyId = 0xA34D7E18C20C31BB
+const testKey3KeyId = 0x338934250CCC0360
+
 const signedInput = "Signed message\nline 2\nline 3\n"
 const signedTextInput = "Signed message\r\nline 2\r\nline 3\r\n"
 
@@ -224,6 +242,8 @@ const detachedSignatureHex = "889c04000102000605024d449cd1000a0910a34d7e18c20c31
 
 const detachedSignatureTextHex = "889c04010102000605024d449d21000a0910a34d7e18c20c31bbc8c60400a24fbef7342603a41cb1165767bd18985d015fb72fe05db42db36cfb2f1d455967f1e491194fbf6cf88146222b23bf6ffbd50d17598d976a0417d3192ff9cc0034fd00f287b02e90418bbefe609484b09231e4e7a5f3562e199bf39909ab5276c4d37382fe088f6b5c3426fc1052865da8b3ab158672d58b6264b10823dc4b39"
 
+const detachedSignatureDSAHex = "884604001102000605024d6c4eac000a0910338934250ccc0360f18d00a087d743d6405ed7b87755476629600b8b694a39e900a0abff8126f46faf1547c1743c37b21b4ea15b8f83"
+
 const testKeys1And2Hex = "988d044d3c5c10010400b1d13382944bd5aba23a4312968b5095d14f947f600eb478e14a6fcb16b0e0cac764884909c020bc495cfcc39a935387c661507bdb236a0612fb582cac3af9b29cc2c8c70090616c41b662f4da4c1201e195472eb7f4ae1ccbcbf9940fe21d985e379a5563dde5b9a23d35f1cfaa5790da3b79db26f23695107bfaca8e7b5bcd0011010001b41054657374204b6579203120285253412988b804130102002205024d3c5c10021b03060b090807030206150802090a0b0416020301021e01021780000a0910a34d7e18c20c31bbb5b304009cc45fe610b641a2c146331be94dade0a396e73ca725e1b25c21708d9cab46ecca5ccebc23055879df8f99eea39b377962a400f2ebdc36a7c99c333d74aeba346315137c3ff9d0a09b0273299090343048afb8107cf94cbd1400e3026f0ccac7ecebbc4d78588eb3e478fe2754d3ca664bcf3eac96ca4a6b0c8d7df5102f60f6b0020003b88d044d3c5c10010400b201df61d67487301f11879d514f4248ade90c8f68c7af1284c161098de4c28c2850f1ec7b8e30f959793e571542ffc6532189409cb51c3d30dad78c4ad5165eda18b20d9826d8707d0f742e2ab492103a85bbd9ddf4f5720f6de7064feb0d39ee002219765bb07bcfb8b877f47abe270ddeda4f676108cecb6b9bb2ad484a4f0011010001889f04180102000905024d3c5c10021b0c000a0910a34d7e18c20c31bb1a03040085c8d62e16d05dc4e9dad64953c8a2eed8b6c12f92b1575eeaa6dcf7be9473dd5b24b37b6dffbb4e7c99ed1bd3cb11634be19b3e6e207bed7505c7ca111ccf47cb323bf1f8851eb6360e8034cbff8dd149993c959de89f8f77f38e7e98b8e3076323aa719328e2b408db5ec0d03936efd57422ba04f925cdc7b4c1af7590e40ab0020003988d044d3c5c33010400b488c3e5f83f4d561f317817538d9d0397981e9aef1321ca68ebfae1cf8b7d388e19f4b5a24a82e2fbbf1c6c26557a6c5845307a03d815756f564ac7325b02bc83e87d5480a8fae848f07cb891f2d51ce7df83dcafdc12324517c86d472cc0ee10d47a68fd1d9ae49a6c19bbd36d82af597a0d88cc9c49de9df4e696fc1f0b5d0011010001b42754657374204b6579203220285253412c20656e637279707465642070726976617465206b65792988b804130102002205024d3c5c33021b03060b090807030206150802090a0b0416020301021e01021780000a0910d4984f961e35246b98940400908a73b6a6169f700434f076c6c79015a49bee37130eaf23aaa3cfa9ce60bfe4acaa7bc95f1146ada5867e0079babb38804891f4f0b8ebca57a86b249dee786161a755b7a342e68ccf3f78ed6440a93a6626beb9a37aa66afcd4f888790cb4bb46d94a4ae3eb3d7d3e6b00f6bfec940303e89ec5b32a1eaaacce66497d539328b0020003b88d044d3c5c33010400a4e913f9442abcc7f1804ccab27d2f787ffa592077ca935a8bb23165bd8d57576acac647cc596b2c3f814518cc8c82953c7a4478f32e0cf645630a5ba38d9618ef2bc3add69d459ae3dece5cab778938d988239f8c5ae437807075e06c828019959c644ff05ef6a5a1dab72227c98e3a040b0cf219026640698d7a13d8538a570011010001889f04180102000905024d3c5c33021b0c000a0910d4984f961e35246b26c703ff7ee29ef53bc1ae1ead533c408fa136db508434e233d6e62be621e031e5940bbd4c08142aed0f82217e7c3e1ec8de574bc06ccf3c36633be41ad78a9eacd209f861cae7b064100758545cc9dd83db71806dc1cfd5fb9ae5c7474bba0c19c44034ae61bae5eca379383339dece94ff56ff7aa44a582f3e5c38f45763af577c0934b0020003"
 
 const testKeys1And2PrivateHex = "9501d8044d3c5c10010400b1d13382944bd5aba23a4312968b5095d14f947f600eb478e14a6fcb16b0e0cac764884909c020bc495cfcc39a935387c661507bdb236a0612fb582cac3af9b29cc2c8c70090616c41b662f4da4c1201e195472eb7f4ae1ccbcbf9940fe21d985e379a5563dde5b9a23d35f1cfaa5790da3b79db26f23695107bfaca8e7b5bcd00110100010003ff4d91393b9a8e3430b14d6209df42f98dc927425b881f1209f319220841273a802a97c7bdb8b3a7740b3ab5866c4d1d308ad0d3a79bd1e883aacf1ac92dfe720285d10d08752a7efe3c609b1d00f17f2805b217be53999a7da7e493bfc3e9618fd17018991b8128aea70a05dbce30e4fbe626aa45775fa255dd9177aabf4df7cf0200c1ded12566e4bc2bb590455e5becfb2e2c9796482270a943343a7835de41080582c2be3caf5981aa838140e97afa40ad652a0b544f83eb1833b0957dce26e47b0200eacd6046741e9ce2ec5beb6fb5e6335457844fb09477f83b050a96be7da043e17f3a9523567ed40e7a521f818813a8b8a72209f1442844843ccc7eb9805442570200bdafe0438d97ac36e773c7162028d65844c4d463e2420aa2228c6e50dc2743c3d6c72d0d782a5173fe7be2169c8a9f4ef8a7cf3e37165e8c61b89c346cdc6c1799d2b41054657374204b6579203120285253412988b804130102002205024d3c5c10021b03060b090807030206150802090a0b0416020301021e01021780000a0910a34d7e18c20c31bbb5b304009cc45fe610b641a2c146331be94dade0a396e73ca725e1b25c21708d9cab46ecca5ccebc23055879df8f99eea39b377962a400f2ebdc36a7c99c333d74aeba346315137c3ff9d0a09b0273299090343048afb8107cf94cbd1400e3026f0ccac7ecebbc4d78588eb3e478fe2754d3ca664bcf3eac96ca4a6b0c8d7df5102f60f6b00200009d01d8044d3c5c10010400b201df61d67487301f11879d514f4248ade90c8f68c7af1284c161098de4c28c2850f1ec7b8e30f959793e571542ffc6532189409cb51c3d30dad78c4ad5165eda18b20d9826d8707d0f742e2ab492103a85bbd9ddf4f5720f6de7064feb0d39ee002219765bb07bcfb8b877f47abe270ddeda4f676108cecb6b9bb2ad484a4f00110100010003fd17a7490c22a79c59281fb7b20f5e6553ec0c1637ae382e8adaea295f50241037f8997cf42c1ce26417e015091451b15424b2c59eb8d4161b0975630408e394d3b00f88d4b4e18e2cc85e8251d4753a27c639c83f5ad4a571c4f19d7cd460b9b73c25ade730c99df09637bd173d8e3e981ac64432078263bb6dc30d3e974150dd0200d0ee05be3d4604d2146fb0457f31ba17c057560785aa804e8ca5530a7cd81d3440d0f4ba6851efcfd3954b7e68908fc0ba47f7ac37bf559c6c168b70d3a7c8cd0200da1c677c4bce06a068070f2b3733b0a714e88d62aa3f9a26c6f5216d48d5c2b5624144f3807c0df30be66b3268eeeca4df1fbded58faf49fc95dc3c35f134f8b01fd1396b6c0fc1b6c4f0eb8f5e44b8eace1e6073e20d0b8bc5385f86f1cf3f050f66af789f3ef1fc107b7f4421e19e0349c730c68f0a226981f4e889054fdb4dc149e8e889f04180102000905024d3c5c10021b0c000a0910a34d7e18c20c31bb1a03040085c8d62e16d05dc4e9dad64953c8a2eed8b6c12f92b1575eeaa6dcf7be9473dd5b24b37b6dffbb4e7c99ed1bd3cb11634be19b3e6e207bed7505c7ca111ccf47cb323bf1f8851eb6360e8034cbff8dd149993c959de89f8f77f38e7e98b8e3076323aa719328e2b408db5ec0d03936efd57422ba04f925cdc7b4c1af7590e40ab00200009501fe044d3c5c33010400b488c3e5f83f4d561f317817538d9d0397981e9aef1321ca68ebfae1cf8b7d388e19f4b5a24a82e2fbbf1c6c26557a6c5845307a03d815756f564ac7325b02bc83e87d5480a8fae848f07cb891f2d51ce7df83dcafdc12324517c86d472cc0ee10d47a68fd1d9ae49a6c19bbd36d82af597a0d88cc9c49de9df4e696fc1f0b5d0011010001fe030302e9030f3c783e14856063f16938530e148bc57a7aa3f3e4f90df9dceccdc779bc0835e1ad3d006e4a8d7b36d08b8e0de5a0d947254ecfbd22037e6572b426bcfdc517796b224b0036ff90bc574b5509bede85512f2eefb520fb4b02aa523ba739bff424a6fe81c5041f253f8d757e69a503d3563a104d0d49e9e890b9d0c26f96b55b743883b472caa7050c4acfd4a21f875bdf1258d88bd61224d303dc9df77f743137d51e6d5246b88c406780528fd9a3e15bab5452e5b93970d9dcc79f48b38651b9f15bfbcf6da452837e9cc70683d1bdca94507870f743e4ad902005812488dd342f836e72869afd00ce1850eea4cfa53ce10e3608e13d3c149394ee3cbd0e23d018fcbcb6e2ec5a1a22972d1d462ca05355d0d290dd2751e550d5efb38c6c89686344df64852bf4ff86638708f644e8ec6bd4af9b50d8541cb91891a431326ab2e332faa7ae86cfb6e0540aa63160c1e5cdd5a4add518b303fff0a20117c6bc77f7cfbaf36b04c865c6c2b42754657374204b6579203220285253412c20656e637279707465642070726976617465206b65792988b804130102002205024d3c5c33021b03060b090807030206150802090a0b0416020301021e01021780000a0910d4984f961e35246b98940400908a73b6a6169f700434f076c6c79015a49bee37130eaf23aaa3cfa9ce60bfe4acaa7bc95f1146ada5867e0079babb38804891f4f0b8ebca57a86b249dee786161a755b7a342e68ccf3f78ed6440a93a6626beb9a37aa66afcd4f888790cb4bb46d94a4ae3eb3d7d3e6b00f6bfec940303e89ec5b32a1eaaacce66497d539328b00200009d01fe044d3c5c33010400a4e913f9442abcc7f1804ccab27d2f787ffa592077ca935a8bb23165bd8d57576acac647cc596b2c3f814518cc8c82953c7a4478f32e0cf645630a5ba38d9618ef2bc3add69d459ae3dece5cab778938d988239f8c5ae437807075e06c828019959c644ff05ef6a5a1dab72227c98e3a040b0cf219026640698d7a13d8538a570011010001fe030302e9030f3c783e148560f936097339ae381d63116efcf802ff8b1c9360767db5219cc987375702a4123fd8657d3e22700f23f95020d1b261eda5257e9a72f9a918e8ef22dd5b3323ae03bbc1923dd224db988cadc16acc04b120a9f8b7e84da9716c53e0334d7b66586ddb9014df604b41be1e960dcfcbc96f4ed150a1a0dd070b9eb14276b9b6be413a769a75b519a53d3ecc0c220e85cd91ca354d57e7344517e64b43b6e29823cbd87eae26e2b2e78e6dedfbb76e3e9f77bcb844f9a8932eb3db2c3f9e44316e6f5d60e9e2a56e46b72abe6b06dc9a31cc63f10023d1f5e12d2a3ee93b675c96f504af0001220991c88db759e231b3320dcedf814dcf723fd9857e3d72d66a0f2af26950b915abdf56c1596f46a325bf17ad4810d3535fb02a259b247ac3dbd4cc3ecf9c51b6c07cebb009c1506fba0a89321ec8683e3fd009a6e551d50243e2d5092fefb3321083a4bad91320dc624bd6b5dddf93553e3d53924c05bfebec1fb4bd47e89a1a889f04180102000905024d3c5c33021b0c000a0910d4984f961e35246b26c703ff7ee29ef53bc1ae1ead533c408fa136db508434e233d6e62be621e031e5940bbd4c08142aed0f82217e7c3e1ec8de574bc06ccf3c36633be41ad78a9eacd209f861cae7b064100758545cc9dd83db71806dc1cfd5fb9ae5c7474bba0c19c44034ae61bae5eca379383339dece94ff56ff7aa44a582f3e5c38f45763af577c0934b0020000"
@@ -235,3 +255,7 @@ const signedTextMessageHex = "a3019bc0cbccc8c4b8d8b74ee2108fe16ec6d36a250cbece0c
 const signedEncryptedMessageHex = "848c032a67d68660df41c70103ff5789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8d2c03b018bd210b1d3791e1aba74b0f1034e122ab72e760492c192383cf5e20b5628bd043272d63df9b923f147eb6091cd897553204832aba48fec54aa447547bb16305a1024713b90e77fd0065f1918271947549205af3c74891af22ee0b56cd29bfec6d6e351901cd4ab3ece7c486f1e32a792d4e474aed98ee84b3f591c7dff37b64e0ecd68fd036d517e412dcadf85840ce184ad7921ad446c4ee28db80447aea1ca8d4f574db4d4e37688158ddd19e14ee2eab4873d46947d65d14a23e788d912cf9a19624ca7352469b72a83866b7c23cb5ace3deab3c7018061b0ba0f39ed2befe27163e5083cf9b8271e3e3d52cc7ad6e2a3bd81d4c3d7022f8d"
 
 const symmetricallyEncryptedCompressedHex = "8c0d04030302eb4a03808145d0d260c92f714339e13de5a79881216431925bf67ee2898ea61815f07894cd0703c50d0a76ef64d482196f47a8bc729af9b80bb6"
+
+const dsaTestKeyHex = "9901a2044d6c49de110400cb5ce438cf9250907ac2ba5bf6547931270b89f7c4b53d9d09f4d0213a5ef2ec1f26806d3d259960f872a4a102ef1581ea3f6d6882d15134f21ef6a84de933cc34c47cc9106efe3bd84c6aec12e78523661e29bc1a61f0aab17fa58a627fd5fd33f5149153fbe8cd70edf3d963bc287ef875270ff14b5bfdd1bca4483793923b00a0fe46d76cb6e4cbdc568435cd5480af3266d610d303fe33ae8273f30a96d4d34f42fa28ce1112d425b2e3bf7ea553d526e2db6b9255e9dc7419045ce817214d1a0056dbc8d5289956a4b1b69f20f1105124096e6a438f41f2e2495923b0f34b70642607d45559595c7fe94d7fa85fc41bf7d68c1fd509ebeaa5f315f6059a446b9369c277597e4f474a9591535354c7e7f4fd98a08aa60400b130c24ff20bdfbf683313f5daebf1c9b34b3bdadfc77f2ddd72ee1fb17e56c473664bc21d66467655dd74b9005e3a2bacce446f1920cd7017231ae447b67036c9b431b8179deacd5120262d894c26bc015bffe3d827ba7087ad9b700d2ca1f6d16cc1786581e5dd065f293c31209300f9b0afcc3f7c08dd26d0a22d87580b4db41054657374204b65792033202844534129886204131102002205024d6c49de021b03060b090807030206150802090a0b0416020301021e01021780000a0910338934250ccc03607e0400a0bdb9193e8a6b96fc2dfc108ae848914b504481f100a09c4dc148cb693293a67af24dd40d2b13a9e36794"
+
+const dsaTestKeyPrivateHex = "9501bb044d6c49de110400cb5ce438cf9250907ac2ba5bf6547931270b89f7c4b53d9d09f4d0213a5ef2ec1f26806d3d259960f872a4a102ef1581ea3f6d6882d15134f21ef6a84de933cc34c47cc9106efe3bd84c6aec12e78523661e29bc1a61f0aab17fa58a627fd5fd33f5149153fbe8cd70edf3d963bc287ef875270ff14b5bfdd1bca4483793923b00a0fe46d76cb6e4cbdc568435cd5480af3266d610d303fe33ae8273f30a96d4d34f42fa28ce1112d425b2e3bf7ea553d526e2db6b9255e9dc7419045ce817214d1a0056dbc8d5289956a4b1b69f20f1105124096e6a438f41f2e2495923b0f34b70642607d45559595c7fe94d7fa85fc41bf7d68c1fd509ebeaa5f315f6059a446b9369c277597e4f474a9591535354c7e7f4fd98a08aa60400b130c24ff20bdfbf683313f5daebf1c9b34b3bdadfc77f2ddd72ee1fb17e56c473664bc21d66467655dd74b9005e3a2bacce446f1920cd7017231ae447b67036c9b431b8179deacd5120262d894c26bc015bffe3d827ba7087ad9b700d2ca1f6d16cc1786581e5dd065f293c31209300f9b0afcc3f7c08dd26d0a22d87580b4d00009f592e0619d823953577d4503061706843317e4fee083db41054657374204b65792033202844534129886204131102002205024d6c49de021b03060b090807030206150802090a0b0416020301021e01021780000a0910338934250ccc03607e0400a0bdb9193e8a6b96fc2dfc108ae848914b504481f100a09c4dc148cb693293a67af24dd40d2b13a9e36794"
index 1a2e2bf..ef7b112 100644 (file)
@@ -6,6 +6,7 @@ package openpgp
 
 import (
        "crypto"
+       "crypto/dsa"
        "crypto/openpgp/armor"
        "crypto/openpgp/error"
        "crypto/openpgp/packet"
@@ -39,7 +40,7 @@ func DetachSignText(w io.Writer, signer *Entity, message io.Reader) os.Error {
 // ArmoredDetachSignText signs message (after canonicalising the line endings)
 // with the private key from signer (which must already have been decrypted)
 // and writes an armored signature to w.
-func SignTextDetachedArmored(w io.Writer, signer *Entity, message io.Reader) os.Error {
+func ArmoredDetachSignText(w io.Writer, signer *Entity, message io.Reader) os.Error {
        return armoredDetachSign(w, signer, message, packet.SigTypeText)
 }
 
@@ -80,6 +81,9 @@ func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.S
        case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSASignOnly:
                priv := signer.PrivateKey.PrivateKey.(*rsa.PrivateKey)
                err = sig.SignRSA(h, priv)
+       case packet.PubKeyAlgoDSA:
+               priv := signer.PrivateKey.PrivateKey.(*dsa.PrivateKey)
+               err = sig.SignDSA(h, priv)
        default:
                err = error.UnsupportedError("public key algorithm: " + strconv.Itoa(int(sig.PubKeyAlgo)))
        }
index 33e8809..42cd0d2 100644 (file)
@@ -18,7 +18,7 @@ func TestSignDetached(t *testing.T) {
                t.Error(err)
        }
 
-       testDetachedSignature(t, kring, out, signedInput, "check")
+       testDetachedSignature(t, kring, out, signedInput, "check", testKey1KeyId)
 }
 
 func TestSignTextDetached(t *testing.T) {
@@ -30,5 +30,17 @@ func TestSignTextDetached(t *testing.T) {
                t.Error(err)
        }
 
-       testDetachedSignature(t, kring, out, signedInput, "check")
+       testDetachedSignature(t, kring, out, signedInput, "check", testKey1KeyId)
+}
+
+func TestSignDetachedDSA(t *testing.T) {
+       kring, _ := ReadKeyRing(readerFromHex(dsaTestKeyPrivateHex))
+       out := bytes.NewBuffer(nil)
+       message := bytes.NewBufferString(signedInput)
+       err := DetachSign(out, kring[0], message)
+       if err != nil {
+               t.Error(err)
+       }
+
+       testDetachedSignature(t, kring, out, signedInput, "check", testKey3KeyId)
 }
index 7135f3d..81b5a07 100644 (file)
@@ -7,6 +7,7 @@ package tls
 import (
        "crypto/rand"
        "crypto/rsa"
+       "crypto/x509"
        "io"
        "io/ioutil"
        "sync"
@@ -95,6 +96,9 @@ type ConnectionState struct {
        HandshakeComplete  bool
        CipherSuite        uint16
        NegotiatedProtocol string
+
+       // the certificate chain that was presented by the other side
+       PeerCertificates []*x509.Certificate
 }
 
 // A Config structure is used to configure a TLS client or server. After one
index d203e8d..1e6fe60 100644 (file)
@@ -762,6 +762,7 @@ func (c *Conn) ConnectionState() ConnectionState {
        if c.handshakeComplete {
                state.NegotiatedProtocol = c.clientProtocol
                state.CipherSuite = c.cipherSuite
+               state.PeerCertificates = c.peerCertificates
        }
 
        return state
@@ -776,15 +777,6 @@ func (c *Conn) OCSPResponse() []byte {
        return c.ocspResponse
 }
 
-// PeerCertificates returns the certificate chain that was presented by the
-// other side.
-func (c *Conn) PeerCertificates() []*x509.Certificate {
-       c.handshakeMutex.Lock()
-       defer c.handshakeMutex.Unlock()
-
-       return c.peerCertificates
-}
-
 // VerifyHostname checks that the peer certificate chain is valid for
 // connecting to host.  If so, it returns nil; if not, it returns an os.Error
 // describing the problem.
index 3e0c639..ee77f94 100644 (file)
@@ -25,7 +25,7 @@ func main() {
 
        priv, err := rsa.GenerateKey(rand.Reader, 1024)
        if err != nil {
-               log.Exitf("failed to generate private key: %s", err)
+               log.Fatalf("failed to generate private key: %s", err)
                return
        }
 
@@ -46,13 +46,13 @@ func main() {
 
        derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
        if err != nil {
-               log.Exitf("Failed to create certificate: %s", err)
+               log.Fatalf("Failed to create certificate: %s", err)
                return
        }
 
        certOut, err := os.Open("cert.pem", os.O_WRONLY|os.O_CREAT, 0644)
        if err != nil {
-               log.Exitf("failed to open cert.pem for writing: %s", err)
+               log.Fatalf("failed to open cert.pem for writing: %s", err)
                return
        }
        pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
index 7caf3a2..49f0a53 100644 (file)
@@ -12,6 +12,6 @@ func Attach(pid int) (Process, os.Error) {
        return nil, os.NewError("debug/proc not implemented on OS X")
 }
 
-func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []*os.File) (Process, os.Error) {
+func StartProcess(argv0 string, argv []string, attr *os.ProcAttr) (Process, os.Error) {
        return Attach(0)
 }
index f6474ce..4df07c3 100644 (file)
@@ -12,6 +12,6 @@ func Attach(pid int) (Process, os.Error) {
        return nil, os.NewError("debug/proc not implemented on FreeBSD")
 }
 
-func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []*os.File) (Process, os.Error) {
+func StartProcess(argv0 string, argv []string, attr *os.ProcAttr) (Process, os.Error) {
        return Attach(0)
 }
index f0cc43a..6890a22 100644 (file)
@@ -1279,25 +1279,31 @@ func Attach(pid int) (Process, os.Error) {
        return p, nil
 }
 
-// ForkExec forks the current process and execs argv0, stopping the
-// new process after the exec syscall.  See os.ForkExec for additional
+// StartProcess forks the current process and execs argv0, stopping the
+// new process after the exec syscall.  See os.StartProcess for additional
 // details.
-func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []*os.File) (Process, os.Error) {
+func StartProcess(argv0 string, argv []string, attr *os.ProcAttr) (Process, os.Error) {
+       sysattr := &syscall.ProcAttr{
+               Dir:    attr.Dir,
+               Env:    attr.Env,
+               Ptrace: true,
+       }
        p := newProcess(-1)
 
        // Create array of integer (system) fds.
-       intfd := make([]int, len(fd))
-       for i, f := range fd {
+       intfd := make([]int, len(attr.Files))
+       for i, f := range attr.Files {
                if f == nil {
                        intfd[i] = -1
                } else {
                        intfd[i] = f.Fd()
                }
        }
+       sysattr.Files = intfd
 
        // Fork from the monitor thread so we get the right tracer pid.
        err := p.do(func() os.Error {
-               pid, errno := syscall.PtraceForkExec(argv0, argv, envv, dir, intfd)
+               pid, _, errno := syscall.StartProcess(argv0, argv, sysattr)
                if errno != 0 {
                        return &os.PathError{"fork/exec", argv0, os.Errno(errno)}
                }
index dc22fae..661474b 100644 (file)
@@ -12,6 +12,6 @@ func Attach(pid int) (Process, os.Error) {
        return nil, os.NewError("debug/proc not implemented on windows")
 }
 
-func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []*os.File) (Process, os.Error) {
+func StartProcess(argv0 string, argv []string, attr *os.ProcAttr) (Process, os.Error) {
        return Attach(0)
 }
index 80f6f3c..44e3b65 100644 (file)
@@ -75,17 +75,19 @@ func modeToFiles(mode, fd int) (*os.File, *os.File, os.Error) {
 
 // Run starts the named binary running with
 // arguments argv and environment envv.
+// If the dir argument is not empty, the child changes
+// into the directory before executing the binary.
 // It returns a pointer to a new Cmd representing
 // the command or an error.
 //
-// The parameters stdin, stdout, and stderr
+// The arguments stdin, stdout, and stderr
 // specify how to handle standard input, output, and error.
 // The choices are DevNull (connect to /dev/null),
 // PassThrough (connect to the current process's standard stream),
 // Pipe (connect to an operating system pipe), and
 // MergeWithStdout (only for standard error; use the same
 // file descriptor as was used for standard output).
-// If a parameter is Pipe, then the corresponding field (Stdin, Stdout, Stderr)
+// If an argument is Pipe, then the corresponding field (Stdin, Stdout, Stderr)
 // of the returned Cmd is the other end of the pipe.
 // Otherwise the field in Cmd is nil.
 func Run(name string, argv, envv []string, dir string, stdin, stdout, stderr int) (c *Cmd, err os.Error) {
@@ -105,7 +107,7 @@ func Run(name string, argv, envv []string, dir string, stdin, stdout, stderr int
        }
 
        // Run command.
-       c.Process, err = os.StartProcess(name, argv, envv, dir, fd[0:])
+       c.Process, err = os.StartProcess(name, argv, &os.ProcAttr{Dir: dir, Files: fd[:], Env: envv})
        if err != nil {
                goto Error
        }
index 3a3d3b1..5e37b99 100644 (file)
@@ -118,3 +118,55 @@ func TestAddEnvVar(t *testing.T) {
                t.Fatal("close:", err)
        }
 }
+
+var tryargs = []string{
+       `2`,
+       `2 `,
+       "2 \t",
+       `2" "`,
+       `2 ab `,
+       `2 "ab" `,
+       `2 \ `,
+       `2 \\ `,
+       `2 \" `,
+       `2 \`,
+       `2\`,
+       `2"`,
+       `2\"`,
+       `2 "`,
+       `2 \"`,
+       ``,
+       `2 ^ `,
+       `2 \^`,
+}
+
+func TestArgs(t *testing.T) {
+       for _, a := range tryargs {
+               argv := []string{
+                       "awk",
+                       `BEGIN{printf("%s|%s|%s",ARGV[1],ARGV[2],ARGV[3])}`,
+                       "/dev/null",
+                       a,
+                       "EOF",
+               }
+               exe, err := LookPath(argv[0])
+               if err != nil {
+                       t.Fatal("run:", err)
+               }
+               cmd, err := Run(exe, argv, nil, "", DevNull, Pipe, DevNull)
+               if err != nil {
+                       t.Fatal("run:", err)
+               }
+               buf, err := ioutil.ReadAll(cmd.Stdout)
+               if err != nil {
+                       t.Fatal("read:", err)
+               }
+               expect := "/dev/null|" + a + "|EOF"
+               if string(buf) != expect {
+                       t.Errorf("read: got %q expect %q", buf, expect)
+               }
+               if err = cmd.Close(); err != nil {
+                       t.Fatal("close:", err)
+               }
+       }
+}
index 5c5d433..f6b7c1c 100644 (file)
@@ -287,9 +287,6 @@ func (a *stmtCompiler) compile(s ast.Stmt) {
        case *ast.SwitchStmt:
                a.compileSwitchStmt(s)
 
-       case *ast.TypeCaseClause:
-               notimpl = true
-
        case *ast.TypeSwitchStmt:
                notimpl = true
 
@@ -1012,13 +1009,13 @@ func (a *stmtCompiler) compileSwitchStmt(s *ast.SwitchStmt) {
                        a.diagAt(clause.Pos(), "switch statement must contain case clauses")
                        continue
                }
-               if clause.Values == nil {
+               if clause.List == nil {
                        if hasDefault {
                                a.diagAt(clause.Pos(), "switch statement contains more than one default case")
                        }
                        hasDefault = true
                } else {
-                       ncases += len(clause.Values)
+                       ncases += len(clause.List)
                }
        }
 
@@ -1030,7 +1027,7 @@ func (a *stmtCompiler) compileSwitchStmt(s *ast.SwitchStmt) {
                if !ok {
                        continue
                }
-               for _, v := range clause.Values {
+               for _, v := range clause.List {
                        e := condbc.compileExpr(condbc.block, false, v)
                        switch {
                        case e == nil:
@@ -1077,8 +1074,8 @@ func (a *stmtCompiler) compileSwitchStmt(s *ast.SwitchStmt) {
 
                // Save jump PC's
                pc := a.nextPC()
-               if clause.Values != nil {
-                       for _ = range clause.Values {
+               if clause.List != nil {
+                       for _ = range clause.List {
                                casePCs[i] = &pc
                                i++
                        }
index 4a883ef..a8a3e16 100644 (file)
@@ -27,7 +27,7 @@ var stmtTests = []test{
        CErr("i, u := 1, 2", atLeastOneDecl),
        Val2("i, x := 2, f", "i", 2, "x", 1.0),
        // Various errors
-       CErr("1 := 2", "left side of := must be a name"),
+       CErr("1 := 2", "expected identifier"),
        CErr("c, a := 1, 1", "cannot assign"),
        // Unpacking
        Val2("x, y := oneTwo()", "x", 1, "y", 2),
index 4f67032..9920ff6 100644 (file)
@@ -160,7 +160,7 @@ func cmdLoad(args []byte) os.Error {
                } else {
                        fname = parts[0]
                }
-               tproc, err = proc.ForkExec(fname, parts, os.Environ(), "", []*os.File{os.Stdin, os.Stdout, os.Stderr})
+               tproc, err = proc.StartProcess(fname, parts, &os.ProcAttr{Files: []*os.File{os.Stdin, os.Stdout, os.Stderr}})
                if err != nil {
                        return err
                }
index b1f0f6c..ed6cff7 100644 (file)
@@ -269,7 +269,7 @@ func Iter() <-chan KeyValue {
 }
 
 func expvarHandler(w http.ResponseWriter, r *http.Request) {
-       w.SetHeader("content-type", "application/json; charset=utf-8")
+       w.Header().Set("Content-Type", "application/json; charset=utf-8")
        fmt.Fprintf(w, "{\n")
        first := true
        for name, value := range vars {
index be97205..14f4d52 100644 (file)
@@ -56,7 +56,7 @@
 
                flag.Bool(...)  // global options
                flag.Parse()  // parse leading command
-               subcmd := flag.Args(0)
+               subcmd := flag.Arg[0]
                switch subcmd {
                        // add per-subcommand options
                }
@@ -68,6 +68,7 @@ package flag
 import (
        "fmt"
        "os"
+       "sort"
        "strconv"
 )
 
@@ -205,16 +206,34 @@ type allFlags struct {
 
 var flags *allFlags
 
-// VisitAll visits the flags, calling fn for each. It visits all flags, even those not set.
+// sortFlags returns the flags as a slice in lexicographical sorted order.
+func sortFlags(flags map[string]*Flag) []*Flag {
+       list := make(sort.StringArray, len(flags))
+       i := 0
+       for _, f := range flags {
+               list[i] = f.Name
+               i++
+       }
+       list.Sort()
+       result := make([]*Flag, len(list))
+       for i, name := range list {
+               result[i] = flags[name]
+       }
+       return result
+}
+
+// VisitAll visits the flags in lexicographical order, calling fn for each.
+// It visits all flags, even those not set.
 func VisitAll(fn func(*Flag)) {
-       for _, f := range flags.formal {
+       for _, f := range sortFlags(flags.formal) {
                fn(f)
        }
 }
 
-// Visit visits the flags, calling fn for each. It visits only those flags that have been set.
+// Visit visits the flags in lexicographical order, calling fn for each.
+// It visits only those flags that have been set.
 func Visit(fn func(*Flag)) {
-       for _, f := range flags.actual {
+       for _, f := range sortFlags(flags.actual) {
                fn(f)
        }
 }
@@ -260,7 +279,9 @@ var Usage = func() {
 
 var panicOnError = false
 
-func fail() {
+// failf prints to standard error a formatted error and Usage, and then exits the program.
+func failf(format string, a ...interface{}) {
+       fmt.Fprintf(os.Stderr, format, a...)
        Usage()
        if panicOnError {
                panic("flag parse error")
@@ -268,6 +289,7 @@ func fail() {
        os.Exit(2)
 }
 
+// NFlag returns the number of flags that have been set.
 func NFlag() int { return len(flags.actual) }
 
 // Arg returns the i'th command-line argument.  Arg(0) is the first remaining argument
@@ -415,8 +437,7 @@ func (f *allFlags) parseOne() (ok bool) {
        }
        name := s[num_minuses:]
        if len(name) == 0 || name[0] == '-' || name[0] == '=' {
-               fmt.Fprintln(os.Stderr, "bad flag syntax:", s)
-               fail()
+               failf("bad flag syntax: %s\n", s)
        }
 
        // it's a flag. does it have an argument?
@@ -434,14 +455,12 @@ func (f *allFlags) parseOne() (ok bool) {
        m := flags.formal
        flag, alreadythere := m[name] // BUG
        if !alreadythere {
-               fmt.Fprintf(os.Stderr, "flag provided but not defined: -%s\n", name)
-               fail()
+               failf("flag provided but not defined: -%s\n", name)
        }
        if fv, ok := flag.Value.(*boolValue); ok { // special case: doesn't need an arg
                if has_value {
                        if !fv.Set(value) {
-                               fmt.Fprintf(os.Stderr, "invalid boolean value %q for flag: -%s\n", value, name)
-                               fail()
+                               failf("invalid boolean value %q for flag: -%s\n", value, name)
                        }
                } else {
                        fv.Set("true")
@@ -454,13 +473,11 @@ func (f *allFlags) parseOne() (ok bool) {
                        value, f.args = f.args[0], f.args[1:]
                }
                if !has_value {
-                       fmt.Fprintf(os.Stderr, "flag needs an argument: -%s\n", name)
-                       fail()
+                       failf("flag needs an argument: -%s\n", name)
                }
                ok = flag.Value.Set(value)
                if !ok {
-                       fmt.Fprintf(os.Stderr, "invalid value %q for flag: -%s\n", value, name)
-                       fail()
+                       failf("invalid value %q for flag: -%s\n", value, name)
                }
        }
        flags.actual[name] = flag
index 30a21e6..1e47d12 100644 (file)
@@ -8,6 +8,7 @@ import (
        . "flag"
        "fmt"
        "os"
+       "sort"
        "testing"
 )
 
@@ -77,6 +78,12 @@ func TestEverything(t *testing.T) {
                        t.Log(k, *v)
                }
        }
+       // Now test they're visited in sort order.
+       var flagNames []string
+       Visit(func(f *Flag) { flagNames = append(flagNames, f.Name) })
+       if !sort.StringsAreSorted(flagNames) {
+               t.Errorf("flag names not sorted: %v", flagNames)
+       }
 }
 
 func TestUsage(t *testing.T) {
index 86057bf..caaa7ac 100644 (file)
@@ -107,7 +107,7 @@ func (f *fmt) writePadding(n int, padding []byte) {
 }
 
 // Append b to f.buf, padded on left (w > 0) or right (w < 0 or f.minus)
-// clear flags aftewards.
+// clear flags afterwards.
 func (f *fmt) pad(b []byte) {
        var padding []byte
        var left, right int
@@ -124,7 +124,7 @@ func (f *fmt) pad(b []byte) {
 }
 
 // append s to buf, padded on left (w > 0) or right (w < 0 or f.minus).
-// clear flags aftewards.
+// clear flags afterwards.
 func (f *fmt) padString(s string) {
        var padding []byte
        var left, right int
index c0f2bac..36271a8 100644 (file)
@@ -35,10 +35,15 @@ type ScanState interface {
        ReadRune() (rune int, size int, err os.Error)
        // UnreadRune causes the next call to ReadRune to return the same rune.
        UnreadRune() os.Error
-       // Token returns the next space-delimited token from the input. If
-       // a width has been specified, the returned token will be no longer
-       // than the width.
-       Token() (token string, err os.Error)
+       // Token skips space in the input if skipSpace is true, then returns the
+       // run of Unicode code points c satisfying f(c).  If f is nil,
+       // !unicode.IsSpace(c) is used; that is, the token will hold non-space
+       // characters.  Newlines are treated as space unless the scan operation
+       // is Scanln, Fscanln or Sscanln, in which case a newline is treated as
+       // EOF.  The returned slice points to shared data that may be overwritten
+       // by the next call to Token, a call to a Scan function using the ScanState
+       // as input, or when the calling Scan method returns.
+       Token(skipSpace bool, f func(int) bool) (token []byte, err os.Error)
        // Width returns the value of the width option and whether it has been set.
        // The unit is Unicode code points.
        Width() (wid int, ok bool)
@@ -134,7 +139,7 @@ type scanError struct {
        err os.Error
 }
 
-const EOF = -1
+const eof = -1
 
 // ss is the internal implementation of ScanState.
 type ss struct {
@@ -202,7 +207,7 @@ func (s *ss) getRune() (rune int) {
        rune, _, err := s.ReadRune()
        if err != nil {
                if err == os.EOF {
-                       return EOF
+                       return eof
                }
                s.error(err)
        }
@@ -214,7 +219,7 @@ func (s *ss) getRune() (rune int) {
 // syntax error.
 func (s *ss) mustReadRune() (rune int) {
        rune = s.getRune()
-       if rune == EOF {
+       if rune == eof {
                s.error(io.ErrUnexpectedEOF)
        }
        return
@@ -238,7 +243,7 @@ func (s *ss) errorString(err string) {
        panic(scanError{os.ErrorString(err)})
 }
 
-func (s *ss) Token() (tok string, err os.Error) {
+func (s *ss) Token(skipSpace bool, f func(int) bool) (tok []byte, err os.Error) {
        defer func() {
                if e := recover(); e != nil {
                        if se, ok := e.(scanError); ok {
@@ -248,10 +253,19 @@ func (s *ss) Token() (tok string, err os.Error) {
                        }
                }
        }()
-       tok = s.token()
+       if f == nil {
+               f = notSpace
+       }
+       s.buf.Reset()
+       tok = s.token(skipSpace, f)
        return
 }
 
+// notSpace is the default scanning function used in Token.
+func notSpace(r int) bool {
+       return !unicode.IsSpace(r)
+}
+
 // readRune is a structure to enable reading UTF-8 encoded code points
 // from an io.Reader.  It is used if the Reader given to the scanner does
 // not already implement io.RuneReader.
@@ -364,7 +378,7 @@ func (s *ss) free(old ssave) {
 func (s *ss) skipSpace(stopAtNewline bool) {
        for {
                rune := s.getRune()
-               if rune == EOF {
+               if rune == eof {
                        return
                }
                if rune == '\n' {
@@ -384,24 +398,27 @@ func (s *ss) skipSpace(stopAtNewline bool) {
        }
 }
 
+
 // token returns the next space-delimited string from the input.  It
 // skips white space.  For Scanln, it stops at newlines.  For Scan,
 // newlines are treated as spaces.
-func (s *ss) token() string {
-       s.skipSpace(false)
+func (s *ss) token(skipSpace bool, f func(int) bool) []byte {
+       if skipSpace {
+               s.skipSpace(false)
+       }
        // read until white space or newline
        for {
                rune := s.getRune()
-               if rune == EOF {
+               if rune == eof {
                        break
                }
-               if unicode.IsSpace(rune) {
+               if !f(rune) {
                        s.UnreadRune()
                        break
                }
                s.buf.WriteRune(rune)
        }
-       return s.buf.String()
+       return s.buf.Bytes()
 }
 
 // typeError indicates that the type of the operand did not match the format
@@ -416,7 +433,7 @@ var boolError = os.ErrorString("syntax error scanning boolean")
 // If accept is true, it puts the character into the input token.
 func (s *ss) consume(ok string, accept bool) bool {
        rune := s.getRune()
-       if rune == EOF {
+       if rune == eof {
                return false
        }
        if strings.IndexRune(ok, rune) >= 0 {
@@ -425,7 +442,7 @@ func (s *ss) consume(ok string, accept bool) bool {
                }
                return true
        }
-       if rune != EOF && accept {
+       if rune != eof && accept {
                s.UnreadRune()
        }
        return false
@@ -434,7 +451,7 @@ func (s *ss) consume(ok string, accept bool) bool {
 // peek reports whether the next character is in the ok string, without consuming it.
 func (s *ss) peek(ok string) bool {
        rune := s.getRune()
-       if rune != EOF {
+       if rune != eof {
                s.UnreadRune()
        }
        return strings.IndexRune(ok, rune) >= 0
@@ -729,7 +746,7 @@ func (s *ss) convertString(verb int) (str string) {
        case 'x':
                str = s.hexString()
        default:
-               str = s.token() // %s and %v just return the next word
+               str = string(s.token(true, notSpace)) // %s and %v just return the next word
        }
        // Empty strings other than with %q are not OK.
        if len(str) == 0 && verb != 'q' && s.maxWid > 0 {
@@ -797,7 +814,7 @@ func (s *ss) hexDigit(digit int) int {
 // There must be either two hexadecimal digits or a space character in the input.
 func (s *ss) hexByte() (b byte, ok bool) {
        rune1 := s.getRune()
-       if rune1 == EOF {
+       if rune1 == eof {
                return
        }
        if unicode.IsSpace(rune1) {
@@ -953,7 +970,7 @@ func (s *ss) doScan(a []interface{}) (numProcessed int, err os.Error) {
        if !s.nlIsSpace {
                for {
                        rune := s.getRune()
-                       if rune == '\n' || rune == EOF {
+                       if rune == '\n' || rune == eof {
                                break
                        }
                        if !unicode.IsSpace(rune) {
@@ -993,7 +1010,7 @@ func (s *ss) advance(format string) (i int) {
                        // There was space in the format, so there should be space (EOF)
                        // in the input.
                        inputc := s.getRune()
-                       if inputc == EOF {
+                       if inputc == eof {
                                return
                        }
                        if !unicode.IsSpace(inputc) {
index 65adb02..8d2e6f5 100644 (file)
@@ -88,14 +88,15 @@ type FloatTest struct {
 type Xs string
 
 func (x *Xs) Scan(state ScanState, verb int) os.Error {
-       tok, err := state.Token()
+       tok, err := state.Token(true, func(r int) bool { return r == verb })
        if err != nil {
                return err
        }
-       if !regexp.MustCompile("^" + string(verb) + "+$").MatchString(tok) {
+       s := string(tok)
+       if !regexp.MustCompile("^" + string(verb) + "+$").MatchString(s) {
                return os.ErrorString("syntax error for xs")
        }
-       *x = Xs(tok)
+       *x = Xs(s)
        return nil
 }
 
@@ -113,9 +114,11 @@ func (s *IntString) Scan(state ScanState, verb int) os.Error {
                return err
        }
 
-       if _, err := Fscan(state, &s.s); err != nil {
+       tok, err := state.Token(true, nil)
+       if err != nil {
                return err
        }
+       s.s = string(tok)
        return nil
 }
 
@@ -331,7 +334,7 @@ var multiTests = []ScanfMultiTest{
        {"%c%c%c", "2\u50c2X", args(&i, &j, &k), args('2', '\u50c2', 'X'), ""},
 
        // Custom scanners.
-       {"%2e%f", "eefffff", args(&x, &y), args(Xs("ee"), Xs("fffff")), ""},
+       {"%e%f", "eefffff", args(&x, &y), args(Xs("ee"), Xs("fffff")), ""},
        {"%4v%s", "12abcd", args(&z, &s), args(IntString{12, "ab"}, "cd"), ""},
 
        // Errors
@@ -476,22 +479,12 @@ func verifyInf(str string, t *testing.T) {
        }
 }
 
-
 func TestInf(t *testing.T) {
        for _, s := range []string{"inf", "+inf", "-inf", "INF", "-INF", "+INF", "Inf", "-Inf", "+Inf"} {
                verifyInf(s, t)
        }
 }
 
-// TODO: there's no conversion from []T to ...T, but we can fake it.  These
-// functions do the faking.  We index the table by the length of the param list.
-var fscanf = []func(io.Reader, string, []interface{}) (int, os.Error){
-       0: func(r io.Reader, f string, i []interface{}) (int, os.Error) { return Fscanf(r, f) },
-       1: func(r io.Reader, f string, i []interface{}) (int, os.Error) { return Fscanf(r, f, i[0]) },
-       2: func(r io.Reader, f string, i []interface{}) (int, os.Error) { return Fscanf(r, f, i[0], i[1]) },
-       3: func(r io.Reader, f string, i []interface{}) (int, os.Error) { return Fscanf(r, f, i[0], i[1], i[2]) },
-}
-
 func testScanfMulti(name string, t *testing.T) {
        sliceType := reflect.Typeof(make([]interface{}, 1)).(*reflect.SliceType)
        for _, test := range multiTests {
@@ -501,7 +494,7 @@ func testScanfMulti(name string, t *testing.T) {
                } else {
                        r = newReader(test.text)
                }
-               n, err := fscanf[len(test.in)](r, test.format, test.in)
+               n, err := Fscanf(r, test.format, test.in...)
                if err != nil {
                        if test.err == "" {
                                t.Errorf("got error scanning (%q, %q): %q", test.format, test.text, err)
@@ -830,12 +823,12 @@ func testScanInts(t *testing.T, scan func(*RecursiveInt, *bytes.Buffer) os.Error
        i := 1
        for ; r != nil; r = r.next {
                if r.i != i {
-                       t.Fatal("bad scan: expected %d got %d", i, r.i)
+                       t.Fatalf("bad scan: expected %d got %d", i, r.i)
                }
                i++
        }
        if i-1 != intCount {
-               t.Fatal("bad scan count: expected %d got %d", intCount, i-1)
+               t.Fatalf("bad scan count: expected %d got %d", intCount, i-1)
        }
 }
 
index abafb56..4a4c12b 100644 (file)
@@ -602,12 +602,12 @@ type (
                Else Stmt // else branch; or nil
        }
 
-       // A CaseClause represents a case of an expression switch statement.
+       // A CaseClause represents a case of an expression or type switch statement.
        CaseClause struct {
-               Case   token.Pos // position of "case" or "default" keyword
-               Values []Expr    // nil means default case
-               Colon  token.Pos // position of ":"
-               Body   []Stmt    // statement list; or nil
+               Case  token.Pos // position of "case" or "default" keyword
+               List  []Expr    // list of expressions or types; nil means default case
+               Colon token.Pos // position of ":"
+               Body  []Stmt    // statement list; or nil
        }
 
        // A SwitchStmt node represents an expression switch statement.
@@ -618,20 +618,12 @@ type (
                Body   *BlockStmt // CaseClauses only
        }
 
-       // A TypeCaseClause represents a case of a type switch statement.
-       TypeCaseClause struct {
-               Case  token.Pos // position of "case" or "default" keyword
-               Types []Expr    // nil means default case
-               Colon token.Pos // position of ":"
-               Body  []Stmt    // statement list; or nil
-       }
-
        // An TypeSwitchStmt node represents a type switch statement.
        TypeSwitchStmt struct {
                Switch token.Pos  // position of "switch" keyword
                Init   Stmt       // initalization statement; or nil
-               Assign Stmt       // x := y.(type)
-               Body   *BlockStmt // TypeCaseClauses only
+               Assign Stmt       // x := y.(type) or y.(type)
+               Body   *BlockStmt // CaseClauses only
        }
 
        // A CommClause node represents a case of a select statement.
@@ -687,7 +679,6 @@ func (s *BlockStmt) Pos() token.Pos      { return s.Lbrace }
 func (s *IfStmt) Pos() token.Pos         { return s.If }
 func (s *CaseClause) Pos() token.Pos     { return s.Case }
 func (s *SwitchStmt) Pos() token.Pos     { return s.Switch }
-func (s *TypeCaseClause) Pos() token.Pos { return s.Case }
 func (s *TypeSwitchStmt) Pos() token.Pos { return s.Switch }
 func (s *CommClause) Pos() token.Pos     { return s.Case }
 func (s *SelectStmt) Pos() token.Pos     { return s.Select }
@@ -734,13 +725,7 @@ func (s *CaseClause) End() token.Pos {
        }
        return s.Colon + 1
 }
-func (s *SwitchStmt) End() token.Pos { return s.Body.End() }
-func (s *TypeCaseClause) End() token.Pos {
-       if n := len(s.Body); n > 0 {
-               return s.Body[n-1].End()
-       }
-       return s.Colon + 1
-}
+func (s *SwitchStmt) End() token.Pos     { return s.Body.End() }
 func (s *TypeSwitchStmt) End() token.Pos { return s.Body.End() }
 func (s *CommClause) End() token.Pos {
        if n := len(s.Body); n > 0 {
@@ -772,7 +757,6 @@ func (s *BlockStmt) stmtNode()      {}
 func (s *IfStmt) stmtNode()         {}
 func (s *CaseClause) stmtNode()     {}
 func (s *SwitchStmt) stmtNode()     {}
-func (s *TypeCaseClause) stmtNode() {}
 func (s *TypeSwitchStmt) stmtNode() {}
 func (s *CommClause) stmtNode()     {}
 func (s *SelectStmt) stmtNode()     {}
@@ -937,11 +921,13 @@ func (d *FuncDecl) declNode() {}
 // via Doc and Comment fields.
 //
 type File struct {
-       Doc      *CommentGroup   // associated documentation; or nil
-       Package  token.Pos       // position of "package" keyword
-       Name     *Ident          // package name
-       Decls    []Decl          // top-level declarations; or nil
-       Comments []*CommentGroup // list of all comments in the source file
+       Doc        *CommentGroup   // associated documentation; or nil
+       Package    token.Pos       // position of "package" keyword
+       Name       *Ident          // package name
+       Decls      []Decl          // top-level declarations; or nil
+       Scope      *Scope          // package scope
+       Unresolved []*Ident        // unresolved global identifiers
+       Comments   []*CommentGroup // list of all comments in the source file
 }
 
 
@@ -959,7 +945,7 @@ func (f *File) End() token.Pos {
 //
 type Package struct {
        Name  string           // package name
-       Scope *Scope           // package scope; or nil
+       Scope *Scope           // package scope
        Files map[string]*File // Go source files by filename
 }
 
index 0c3cef4..4da487c 100644 (file)
@@ -425,5 +425,6 @@ func MergePackageFiles(pkg *Package, mode MergeMode) *File {
                }
        }
 
-       return &File{doc, pos, NewIdent(pkg.Name), decls, comments}
+       // TODO(gri) need to compute pkgScope and unresolved identifiers!
+       return &File{doc, pos, NewIdent(pkg.Name), decls, nil, nil, comments}
 }
index d71490d..82c334e 100644 (file)
@@ -30,15 +30,19 @@ func NotNilFilter(_ string, value reflect.Value) bool {
 
 
 // Fprint prints the (sub-)tree starting at AST node x to w.
+// If fset != nil, position information is interpreted relative
+// to that file set. Otherwise positions are printed as integer
+// values (file set specific offsets).
 //
 // A non-nil FieldFilter f may be provided to control the output:
 // struct fields for which f(fieldname, fieldvalue) is true are
 // are printed; all others are filtered from the output.
 //
-func Fprint(w io.Writer, x interface{}, f FieldFilter) (n int, err os.Error) {
+func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (n int, err os.Error) {
        // setup printer
        p := printer{
                output: w,
+               fset:   fset,
                filter: f,
                ptrmap: make(map[interface{}]int),
                last:   '\n', // force printing of line number on first line
@@ -65,14 +69,15 @@ func Fprint(w io.Writer, x interface{}, f FieldFilter) (n int, err os.Error) {
 
 
 // Print prints x to standard output, skipping nil fields.
-// Print(x) is the same as Fprint(os.Stdout, x, NotNilFilter).
-func Print(x interface{}) (int, os.Error) {
-       return Fprint(os.Stdout, x, NotNilFilter)
+// Print(fset, x) is the same as Fprint(os.Stdout, fset, x, NotNilFilter).
+func Print(fset *token.FileSet, x interface{}) (int, os.Error) {
+       return Fprint(os.Stdout, fset, x, NotNilFilter)
 }
 
 
 type printer struct {
        output  io.Writer
+       fset    *token.FileSet
        filter  FieldFilter
        ptrmap  map[interface{}]int // *reflect.PtrValue -> line number
        written int                 // number of bytes written to output
@@ -137,16 +142,6 @@ func (p *printer) printf(format string, args ...interface{}) {
 // probably be in a different package.
 
 func (p *printer) print(x reflect.Value) {
-       // Note: This test is only needed because AST nodes
-       //       embed a token.Position, and thus all of them
-       //       understand the String() method (but it only
-       //       applies to the Position field).
-       // TODO: Should reconsider this AST design decision.
-       if pos, ok := x.Interface().(token.Position); ok {
-               p.printf("%s", pos)
-               return
-       }
-
        if !NotNilFilter("", x) {
                p.printf("nil")
                return
@@ -163,6 +158,7 @@ func (p *printer) print(x reflect.Value) {
                        p.print(key)
                        p.printf(": ")
                        p.print(v.Elem(key))
+                       p.printf("\n")
                }
                p.indent--
                p.printf("}")
@@ -212,6 +208,11 @@ func (p *printer) print(x reflect.Value) {
                p.printf("}")
 
        default:
-               p.printf("%v", x.Interface())
+               value := x.Interface()
+               // position values can be printed nicely if we have a file set
+               if pos, ok := value.(token.Pos); ok && p.fset != nil {
+                       value = p.fset.Position(pos)
+               }
+               p.printf("%v", value)
        }
 }
index 956a208..91866dc 100644 (file)
@@ -2,31 +2,31 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// This file implements scopes, the objects they contain,
-// and object types.
+// This file implements scopes and the objects they contain.
 
 package ast
 
+import (
+       "bytes"
+       "fmt"
+       "go/token"
+)
+
+
 // A Scope maintains the set of named language entities declared
 // in the scope and a link to the immediately surrounding (outer)
 // scope.
 //
 type Scope struct {
        Outer   *Scope
-       Objects []*Object // in declaration order
-       // Implementation note: In some cases (struct fields,
-       // function parameters) we need the source order of
-       // variables. Thus for now, we store scope entries
-       // in a linear list. If scopes become very large
-       // (say, for packages), we may need to change this
-       // to avoid slow lookups.
+       Objects map[string]*Object
 }
 
 
 // NewScope creates a new scope nested in the outer scope.
 func NewScope(outer *Scope) *Scope {
-       const n = 4 // initial scope capacity, must be > 0
-       return &Scope{outer, make([]*Object, 0, n)}
+       const n = 4 // initial scope capacity
+       return &Scope{outer, make(map[string]*Object, n)}
 }
 
 
@@ -34,73 +34,108 @@ func NewScope(outer *Scope) *Scope {
 // found in scope s, otherwise it returns nil. Outer scopes
 // are ignored.
 //
-// Lookup always returns nil if name is "_", even if the scope
-// contains objects with that name.
-//
 func (s *Scope) Lookup(name string) *Object {
-       if name != "_" {
-               for _, obj := range s.Objects {
-                       if obj.Name == name {
-                               return obj
-                       }
-               }
-       }
-       return nil
+       return s.Objects[name]
 }
 
 
 // Insert attempts to insert a named object into the scope s.
-// If the scope does not contain an object with that name yet
-// or if the object is named "_", Insert inserts the object
-// and returns it. Otherwise, Insert leaves the scope unchanged
-// and returns the object found in the scope instead.
+// If the scope does not contain an object with that name yet,
+// Insert inserts the object and returns it. Otherwise, Insert
+// leaves the scope unchanged and returns the object found in
+// the scope instead.
 //
-func (s *Scope) Insert(obj *Object) *Object {
-       alt := s.Lookup(obj.Name)
-       if alt == nil {
-               s.append(obj)
+func (s *Scope) Insert(obj *Object) (alt *Object) {
+       if alt = s.Objects[obj.Name]; alt == nil {
+               s.Objects[obj.Name] = obj
                alt = obj
        }
-       return alt
+       return
 }
 
 
-func (s *Scope) append(obj *Object) {
-       s.Objects = append(s.Objects, obj)
+// Debugging support
+func (s *Scope) String() string {
+       var buf bytes.Buffer
+       fmt.Fprintf(&buf, "scope %p {", s)
+       if s != nil && len(s.Objects) > 0 {
+               fmt.Fprintln(&buf)
+               for _, obj := range s.Objects {
+                       fmt.Fprintf(&buf, "\t%s %s\n", obj.Kind, obj.Name)
+               }
+       }
+       fmt.Fprintf(&buf, "}\n")
+       return buf.String()
 }
 
+
 // ----------------------------------------------------------------------------
 // Objects
 
-// An Object describes a language entity such as a package,
-// constant, type, variable, or function (incl. methods).
+// An Object describes a named language entity such as a package,
+// constant, type, variable, function (incl. methods), or label.
 //
 type Object struct {
-       Kind Kind
-       Name string // declared name
-       Type *Type
-       Decl interface{} // corresponding Field, XxxSpec or FuncDecl
-       N    int         // value of iota for this declaration
+       Kind ObjKind
+       Name string      // declared name
+       Decl interface{} // corresponding Field, XxxSpec, FuncDecl, or LabeledStmt; or nil
+       Type interface{} // place holder for type information; may be nil
 }
 
 
 // NewObj creates a new object of a given kind and name.
-func NewObj(kind Kind, name string) *Object {
+func NewObj(kind ObjKind, name string) *Object {
        return &Object{Kind: kind, Name: name}
 }
 
 
-// Kind describes what an object represents.
-type Kind int
+// Pos computes the source position of the declaration of an object name.
+// The result may be an invalid position if it cannot be computed
+// (obj.Decl may be nil or not correct).
+func (obj *Object) Pos() token.Pos {
+       name := obj.Name
+       switch d := obj.Decl.(type) {
+       case *Field:
+               for _, n := range d.Names {
+                       if n.Name == name {
+                               return n.Pos()
+                       }
+               }
+       case *ValueSpec:
+               for _, n := range d.Names {
+                       if n.Name == name {
+                               return n.Pos()
+                       }
+               }
+       case *TypeSpec:
+               if d.Name.Name == name {
+                       return d.Name.Pos()
+               }
+       case *FuncDecl:
+               if d.Name.Name == name {
+                       return d.Name.Pos()
+               }
+       case *LabeledStmt:
+               if d.Label.Name == name {
+                       return d.Label.Pos()
+               }
+       }
+       return token.NoPos
+}
+
+
+// ObKind describes what an object represents.
+type ObjKind int
 
 // The list of possible Object kinds.
 const (
-       Bad Kind = iota // for error handling
-       Pkg             // package
-       Con             // constant
-       Typ             // type
-       Var             // variable
-       Fun             // function or method
+       Bad ObjKind = iota // for error handling
+       Pkg                // package
+       Con                // constant
+       Typ                // type
+       Var                // variable
+       Fun                // function or method
+       Lbl                // label
 )
 
 
@@ -111,132 +146,8 @@ var objKindStrings = [...]string{
        Typ: "type",
        Var: "var",
        Fun: "func",
+       Lbl: "label",
 }
 
 
-func (kind Kind) String() string { return objKindStrings[kind] }
-
-
-// IsExported returns whether obj is exported.
-func (obj *Object) IsExported() bool { return IsExported(obj.Name) }
-
-
-// ----------------------------------------------------------------------------
-// Types
-
-// A Type represents a Go type.
-type Type struct {
-       Form     Form
-       Obj      *Object // corresponding type name, or nil
-       Scope    *Scope  // fields and methods, always present
-       N        uint    // basic type id, array length, number of function results, or channel direction
-       Key, Elt *Type   // map key and array, pointer, slice, map or channel element
-       Params   *Scope  // function (receiver, input and result) parameters, tuple expressions (results of function calls), or nil
-       Expr     Expr    // corresponding AST expression
-}
-
-
-// NewType creates a new type of a given form.
-func NewType(form Form) *Type {
-       return &Type{Form: form, Scope: NewScope(nil)}
-}
-
-
-// Form describes the form of a type.
-type Form int
-
-// The list of possible type forms.
-const (
-       BadType    Form = iota // for error handling
-       Unresolved             // type not fully setup
-       Basic
-       Array
-       Struct
-       Pointer
-       Function
-       Method
-       Interface
-       Slice
-       Map
-       Channel
-       Tuple
-)
-
-
-var formStrings = [...]string{
-       BadType:    "badType",
-       Unresolved: "unresolved",
-       Basic:      "basic",
-       Array:      "array",
-       Struct:     "struct",
-       Pointer:    "pointer",
-       Function:   "function",
-       Method:     "method",
-       Interface:  "interface",
-       Slice:      "slice",
-       Map:        "map",
-       Channel:    "channel",
-       Tuple:      "tuple",
-}
-
-
-func (form Form) String() string { return formStrings[form] }
-
-
-// The list of basic type id's.
-const (
-       Bool = iota
-       Byte
-       Uint
-       Int
-       Float
-       Complex
-       Uintptr
-       String
-
-       Uint8
-       Uint16
-       Uint32
-       Uint64
-
-       Int8
-       Int16
-       Int32
-       Int64
-
-       Float32
-       Float64
-
-       Complex64
-       Complex128
-
-       // TODO(gri) ideal types are missing
-)
-
-
-var BasicTypes = map[uint]string{
-       Bool:    "bool",
-       Byte:    "byte",
-       Uint:    "uint",
-       Int:     "int",
-       Float:   "float",
-       Complex: "complex",
-       Uintptr: "uintptr",
-       String:  "string",
-
-       Uint8:  "uint8",
-       Uint16: "uint16",
-       Uint32: "uint32",
-       Uint64: "uint64",
-
-       Int8:  "int8",
-       Int16: "int16",
-       Int32: "int32",
-       Int64: "int64",
-
-       Float32: "float32",
-       Float64: "float64",
-
-       Complex64:  "complex64",
-       Complex128: "complex128",
-}
+func (kind ObjKind) String() string { return objKindStrings[kind] }
index 20c337c..95c4b3a 100644 (file)
@@ -234,7 +234,7 @@ func Walk(v Visitor, node Node) {
                }
 
        case *CaseClause:
-               walkExprList(v, n.Values)
+               walkExprList(v, n.List)
                walkStmtList(v, n.Body)
 
        case *SwitchStmt:
@@ -246,12 +246,6 @@ func Walk(v Visitor, node Node) {
                }
                Walk(v, n.Body)
 
-       case *TypeCaseClause:
-               for _, x := range n.Types {
-                       Walk(v, x)
-               }
-               walkStmtList(v, n.Body)
-
        case *TypeSwitchStmt:
                if n.Init != nil {
                        Walk(v, n.Init)
index 84d699a..6f35b49 100644 (file)
@@ -14,7 +14,7 @@ import (
        "io"
        "io/ioutil"
        "os"
-       pathutil "path"
+       "path/filepath"
 )
 
 
@@ -198,7 +198,7 @@ func ParseDir(fset *token.FileSet, path string, filter func(*os.FileInfo) bool,
        for i := 0; i < len(list); i++ {
                d := &list[i]
                if filter == nil || filter(d) {
-                       filenames[n] = pathutil.Join(path, d.Name)
+                       filenames[n] = filepath.Join(path, d.Name)
                        n++
                }
        }
index 7c5843f..b0e8c8a 100644 (file)
@@ -17,10 +17,6 @@ import (
 )
 
 
-// noPos is used when there is no corresponding source position for a token.
-var noPos token.Position
-
-
 // The mode parameter to the Parse* functions is a set of flags (or 0).
 // They control the amount of source code parsed and other optional
 // parser functionality.
@@ -30,6 +26,7 @@ const (
        ImportsOnly                        // parsing stops after import declarations
        ParseComments                      // parse comments and add them to AST
        Trace                              // print a trace of parsed productions
+       DeclarationErrors                  // report declaration errors
 )
 
 
@@ -46,16 +43,26 @@ type parser struct {
 
        // Comments
        comments    []*ast.CommentGroup
-       leadComment *ast.CommentGroup // the last lead comment
-       lineComment *ast.CommentGroup // the last line comment
+       leadComment *ast.CommentGroup // last lead comment
+       lineComment *ast.CommentGroup // last line comment
 
        // Next token
-       pos token.Pos   // token position
-       tok token.Token // one token look-ahead
-       lit []byte      // token literal
+       pos  token.Pos   // token position
+       tok  token.Token // one token look-ahead
+       lit_ []byte      // token literal (slice into original source, don't hold on to it)
 
        // Non-syntactic parser control
        exprLev int // < 0: in control clause, >= 0: in expression
+
+       // Ordinary identifer scopes
+       pkgScope   *ast.Scope   // pkgScope.Outer == nil
+       topScope   *ast.Scope   // top-most scope; may be pkgScope
+       unresolved []*ast.Ident // unresolved global identifiers
+
+       // Label scope
+       // (maintained by open/close LabelScope)
+       labelScope  *ast.Scope     // label scope for current function
+       targetStack [][]*ast.Ident // stack of unresolved labels
 }
 
 
@@ -72,9 +79,126 @@ func scannerMode(mode uint) uint {
 func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode uint) {
        p.file = fset.AddFile(filename, fset.Base(), len(src))
        p.scanner.Init(p.file, src, p, scannerMode(mode))
+
        p.mode = mode
        p.trace = mode&Trace != 0 // for convenience (p.trace is used frequently)
+
        p.next()
+
+       // set up the pkgScope here (as opposed to in parseFile) because
+       // there are other parser entry points (ParseExpr, etc.)
+       p.openScope()
+       p.pkgScope = p.topScope
+
+       // for the same reason, set up a label scope
+       p.openLabelScope()
+}
+
+
+func (p *parser) lit() []byte {
+       // make a copy of p.lit_ so that we don't hold on to
+       // a copy of the entire source indirectly in the AST
+       t := make([]byte, len(p.lit_))
+       copy(t, p.lit_)
+       return t
+}
+
+
+// ----------------------------------------------------------------------------
+// Scoping support
+
+func (p *parser) openScope() {
+       p.topScope = ast.NewScope(p.topScope)
+}
+
+
+func (p *parser) closeScope() {
+       p.topScope = p.topScope.Outer
+}
+
+
+func (p *parser) openLabelScope() {
+       p.labelScope = ast.NewScope(p.labelScope)
+       p.targetStack = append(p.targetStack, nil)
+}
+
+
+func (p *parser) closeLabelScope() {
+       // resolve labels
+       n := len(p.targetStack) - 1
+       scope := p.labelScope
+       for _, ident := range p.targetStack[n] {
+               ident.Obj = scope.Lookup(ident.Name)
+               if ident.Obj == nil && p.mode&DeclarationErrors != 0 {
+                       p.error(ident.Pos(), fmt.Sprintf("label %s undefined", ident.Name))
+               }
+       }
+       // pop label scope
+       p.targetStack = p.targetStack[0:n]
+       p.labelScope = p.labelScope.Outer
+}
+
+
+func (p *parser) declare(decl interface{}, scope *ast.Scope, kind ast.ObjKind, idents ...*ast.Ident) {
+       for _, ident := range idents {
+               if ident.Name != "_" {
+                       obj := ast.NewObj(kind, ident.Name)
+                       // remember the corresponding declaration for redeclaration
+                       // errors and global variable resolution/typechecking phase
+                       obj.Decl = decl
+                       alt := scope.Insert(obj)
+                       if alt != obj && p.mode&DeclarationErrors != 0 {
+                               prevDecl := ""
+                               if pos := alt.Pos(); pos.IsValid() {
+                                       prevDecl = fmt.Sprintf("\n\tprevious declaration at %s", p.file.Position(pos))
+                               }
+                               p.error(ident.Pos(), fmt.Sprintf("%s redeclared in this block%s", ident.Name, prevDecl))
+                       }
+                       ident.Obj = obj
+               }
+       }
+}
+
+
+func (p *parser) shortVarDecl(idents []*ast.Ident) {
+       // Go spec: A short variable declaration may redeclare variables
+       // provided they were originally declared in the same block with
+       // the same type, and at least one of the non-blank variables is new.
+       n := 0 // number of new variables
+       for _, ident := range idents {
+               if ident.Name != "_" {
+                       obj := ast.NewObj(ast.Var, ident.Name)
+                       // short var declarations cannot have redeclaration errors
+                       // and are not global => no need to remember the respective
+                       // declaration
+                       alt := p.topScope.Insert(obj)
+                       if alt == obj {
+                               n++ // new declaration
+                       }
+                       ident.Obj = alt
+               }
+       }
+       if n == 0 && p.mode&DeclarationErrors != 0 {
+               p.error(idents[0].Pos(), "no new variables on left side of :=")
+       }
+}
+
+
+func (p *parser) resolve(ident *ast.Ident) {
+       if ident.Name == "_" {
+               return
+       }
+       // try to resolve the identifier
+       for s := p.topScope; s != nil; s = s.Outer {
+               if obj := s.Lookup(ident.Name); obj != nil {
+                       ident.Obj = obj
+                       return
+               }
+       }
+       // collect unresolved global identifiers; ignore the others
+       if p.topScope == p.pkgScope {
+               p.unresolved = append(p.unresolved, ident)
+       }
 }
 
 
@@ -120,7 +244,7 @@ func (p *parser) next0() {
                s := p.tok.String()
                switch {
                case p.tok.IsLiteral():
-                       p.printTrace(s, string(p.lit))
+                       p.printTrace(s, string(p.lit_))
                case p.tok.IsOperator(), p.tok.IsKeyword():
                        p.printTrace("\"" + s + "\"")
                default:
@@ -128,7 +252,7 @@ func (p *parser) next0() {
                }
        }
 
-       p.pos, p.tok, p.lit = p.scanner.Scan()
+       p.pos, p.tok, p.lit_ = p.scanner.Scan()
 }
 
 // Consume a comment and return it and the line on which it ends.
@@ -136,15 +260,15 @@ func (p *parser) consumeComment() (comment *ast.Comment, endline int) {
        // /*-style comments may end on a different line than where they start.
        // Scan the comment for '\n' chars and adjust endline accordingly.
        endline = p.file.Line(p.pos)
-       if p.lit[1] == '*' {
-               for _, b := range p.lit {
+       if p.lit_[1] == '*' {
+               for _, b := range p.lit_ {
                        if b == '\n' {
                                endline++
                        }
                }
        }
 
-       comment = &ast.Comment{p.pos, p.lit}
+       comment = &ast.Comment{p.pos, p.lit()}
        p.next0()
 
        return
@@ -234,12 +358,12 @@ func (p *parser) errorExpected(pos token.Pos, msg string) {
        if pos == p.pos {
                // the error happened at the current position;
                // make the error message more specific
-               if p.tok == token.SEMICOLON && p.lit[0] == '\n' {
+               if p.tok == token.SEMICOLON && p.lit_[0] == '\n' {
                        msg += ", found newline"
                } else {
                        msg += ", found '" + p.tok.String() + "'"
                        if p.tok.IsLiteral() {
-                               msg += " " + string(p.lit)
+                               msg += " " + string(p.lit_)
                        }
                }
        }
@@ -271,7 +395,7 @@ func (p *parser) parseIdent() *ast.Ident {
        pos := p.pos
        name := "_"
        if p.tok == token.IDENT {
-               name = string(p.lit)
+               name = string(p.lit_)
                p.next()
        } else {
                p.expect(token.IDENT) // use expect() error handling
@@ -339,13 +463,16 @@ func (p *parser) parseQualifiedIdent() ast.Expr {
                defer un(trace(p, "QualifiedIdent"))
        }
 
-       var x ast.Expr = p.parseIdent()
+       ident := p.parseIdent()
+       p.resolve(ident)
+       var x ast.Expr = ident
        if p.tok == token.PERIOD {
                // first identifier is a package identifier
                p.next()
                sel := p.parseIdent()
                x = &ast.SelectorExpr{x, sel}
        }
+
        return x
 }
 
@@ -407,7 +534,7 @@ func (p *parser) parseFieldDecl() *ast.Field {
        // optional tag
        var tag *ast.BasicLit
        if p.tok == token.STRING {
-               tag = &ast.BasicLit{p.pos, p.tok, p.lit}
+               tag = &ast.BasicLit{p.pos, p.tok, p.lit()}
                p.next()
        }
 
@@ -426,7 +553,7 @@ func (p *parser) parseFieldDecl() *ast.Field {
                }
        }
 
-       p.expectSemi()
+       p.expectSemi() // call before accessing p.linecomment
 
        return &ast.Field{doc, idents, typ, tag, p.lineComment}
 }
@@ -519,7 +646,7 @@ func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) {
 }
 
 
-func (p *parser) parseParameterList(ellipsisOk bool) (params []*ast.Field) {
+func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params []*ast.Field) {
        if p.trace {
                defer un(trace(p, "ParameterList"))
        }
@@ -528,7 +655,11 @@ func (p *parser) parseParameterList(ellipsisOk bool) (params []*ast.Field) {
        if typ != nil {
                // IdentifierList Type
                idents := p.makeIdentList(list)
-               params = append(params, &ast.Field{nil, idents, typ, nil, nil})
+               field := &ast.Field{nil, idents, typ, nil, nil}
+               params = append(params, field)
+               // Go spec: The scope of an identifier denoting a function
+               // parameter or result variable is the function body.
+               p.declare(field, scope, ast.Var, idents...)
                if p.tok == token.COMMA {
                        p.next()
                }
@@ -536,7 +667,11 @@ func (p *parser) parseParameterList(ellipsisOk bool) (params []*ast.Field) {
                for p.tok != token.RPAREN && p.tok != token.EOF {
                        idents := p.parseIdentList()
                        typ := p.parseVarType(ellipsisOk)
-                       params = append(params, &ast.Field{nil, idents, typ, nil, nil})
+                       field := &ast.Field{nil, idents, typ, nil, nil}
+                       params = append(params, field)
+                       // Go spec: The scope of an identifier denoting a function
+                       // parameter or result variable is the function body.
+                       p.declare(field, scope, ast.Var, idents...)
                        if p.tok != token.COMMA {
                                break
                        }
@@ -555,7 +690,7 @@ func (p *parser) parseParameterList(ellipsisOk bool) (params []*ast.Field) {
 }
 
 
-func (p *parser) parseParameters(ellipsisOk bool) *ast.FieldList {
+func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldList {
        if p.trace {
                defer un(trace(p, "Parameters"))
        }
@@ -563,7 +698,7 @@ func (p *parser) parseParameters(ellipsisOk bool) *ast.FieldList {
        var params []*ast.Field
        lparen := p.expect(token.LPAREN)
        if p.tok != token.RPAREN {
-               params = p.parseParameterList(ellipsisOk)
+               params = p.parseParameterList(scope, ellipsisOk)
        }
        rparen := p.expect(token.RPAREN)
 
@@ -571,13 +706,13 @@ func (p *parser) parseParameters(ellipsisOk bool) *ast.FieldList {
 }
 
 
-func (p *parser) parseResult() *ast.FieldList {
+func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList {
        if p.trace {
                defer un(trace(p, "Result"))
        }
 
        if p.tok == token.LPAREN {
-               return p.parseParameters(false)
+               return p.parseParameters(scope, false)
        }
 
        typ := p.tryType()
@@ -591,27 +726,28 @@ func (p *parser) parseResult() *ast.FieldList {
 }
 
 
-func (p *parser) parseSignature() (params, results *ast.FieldList) {
+func (p *parser) parseSignature(scope *ast.Scope) (params, results *ast.FieldList) {
        if p.trace {
                defer un(trace(p, "Signature"))
        }
 
-       params = p.parseParameters(true)
-       results = p.parseResult()
+       params = p.parseParameters(scope, true)
+       results = p.parseResult(scope)
 
        return
 }
 
 
-func (p *parser) parseFuncType() *ast.FuncType {
+func (p *parser) parseFuncType() (*ast.FuncType, *ast.Scope) {
        if p.trace {
                defer un(trace(p, "FuncType"))
        }
 
        pos := p.expect(token.FUNC)
-       params, results := p.parseSignature()
+       scope := ast.NewScope(p.topScope) // function scope
+       params, results := p.parseSignature(scope)
 
-       return &ast.FuncType{pos, params, results}
+       return &ast.FuncType{pos, params, results}, scope
 }
 
 
@@ -627,13 +763,14 @@ func (p *parser) parseMethodSpec() *ast.Field {
        if ident, isIdent := x.(*ast.Ident); isIdent && p.tok == token.LPAREN {
                // method
                idents = []*ast.Ident{ident}
-               params, results := p.parseSignature()
+               scope := ast.NewScope(nil) // method scope
+               params, results := p.parseSignature(scope)
                typ = &ast.FuncType{token.NoPos, params, results}
        } else {
                // embedded interface
                typ = x
        }
-       p.expectSemi()
+       p.expectSemi() // call before accessing p.linecomment
 
        return &ast.Field{doc, idents, typ, nil, p.lineComment}
 }
@@ -706,7 +843,8 @@ func (p *parser) tryRawType(ellipsisOk bool) ast.Expr {
        case token.MUL:
                return p.parsePointerType()
        case token.FUNC:
-               return p.parseFuncType()
+               typ, _ := p.parseFuncType()
+               return typ
        case token.INTERFACE:
                return p.parseInterfaceType()
        case token.MAP:
@@ -745,13 +883,17 @@ func (p *parser) parseStmtList() (list []ast.Stmt) {
 }
 
 
-func (p *parser) parseBody() *ast.BlockStmt {
+func (p *parser) parseBody(scope *ast.Scope) *ast.BlockStmt {
        if p.trace {
                defer un(trace(p, "Body"))
        }
 
        lbrace := p.expect(token.LBRACE)
+       p.topScope = scope // open function scope
+       p.openLabelScope()
        list := p.parseStmtList()
+       p.closeLabelScope()
+       p.closeScope()
        rbrace := p.expect(token.RBRACE)
 
        return &ast.BlockStmt{lbrace, list, rbrace}
@@ -764,7 +906,9 @@ func (p *parser) parseBlockStmt() *ast.BlockStmt {
        }
 
        lbrace := p.expect(token.LBRACE)
+       p.openScope()
        list := p.parseStmtList()
+       p.closeScope()
        rbrace := p.expect(token.RBRACE)
 
        return &ast.BlockStmt{lbrace, list, rbrace}
@@ -779,14 +923,14 @@ func (p *parser) parseFuncTypeOrLit() ast.Expr {
                defer un(trace(p, "FuncTypeOrLit"))
        }
 
-       typ := p.parseFuncType()
+       typ, scope := p.parseFuncType()
        if p.tok != token.LBRACE {
                // function type only
                return typ
        }
 
        p.exprLev++
-       body := p.parseBody()
+       body := p.parseBody(scope)
        p.exprLev--
 
        return &ast.FuncLit{typ, body}
@@ -803,10 +947,12 @@ func (p *parser) parseOperand() ast.Expr {
 
        switch p.tok {
        case token.IDENT:
-               return p.parseIdent()
+               ident := p.parseIdent()
+               p.resolve(ident)
+               return ident
 
        case token.INT, token.FLOAT, token.IMAG, token.CHAR, token.STRING:
-               x := &ast.BasicLit{p.pos, p.tok, p.lit}
+               x := &ast.BasicLit{p.pos, p.tok, p.lit()}
                p.next()
                return x
 
@@ -1202,6 +1348,9 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
                pos, tok := p.pos, p.tok
                p.next()
                y := p.parseExprList()
+               if tok == token.DEFINE {
+                       p.shortVarDecl(p.makeIdentList(x))
+               }
                return &ast.AssignStmt{x, pos, tok, y}
        }
 
@@ -1216,7 +1365,12 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
                colon := p.pos
                p.next()
                if label, isIdent := x[0].(*ast.Ident); labelOk && isIdent {
-                       return &ast.LabeledStmt{label, colon, p.parseStmt()}
+                       // Go spec: The scope of a label is the body of the function
+                       // in which it is declared and excludes the body of any nested
+                       // function.
+                       stmt := &ast.LabeledStmt{label, colon, p.parseStmt()}
+                       p.declare(stmt, p.labelScope, ast.Lbl, label)
+                       return stmt
                }
                p.error(x[0].Pos(), "illegal label declaration")
                return &ast.BadStmt{x[0].Pos(), colon + 1}
@@ -1304,14 +1458,17 @@ func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
                defer un(trace(p, "BranchStmt"))
        }
 
-       s := &ast.BranchStmt{p.pos, tok, nil}
-       p.expect(tok)
+       pos := p.expect(tok)
+       var label *ast.Ident
        if tok != token.FALLTHROUGH && p.tok == token.IDENT {
-               s.Label = p.parseIdent()
+               label = p.parseIdent()
+               // add to list of unresolved targets
+               n := len(p.targetStack) - 1
+               p.targetStack[n] = append(p.targetStack[n], label)
        }
        p.expectSemi()
 
-       return s
+       return &ast.BranchStmt{pos, tok, label}
 }
 
 
@@ -1333,6 +1490,8 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
        }
 
        pos := p.expect(token.IF)
+       p.openScope()
+       defer p.closeScope()
 
        var s ast.Stmt
        var x ast.Expr
@@ -1368,28 +1527,6 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
 }
 
 
-func (p *parser) parseCaseClause() *ast.CaseClause {
-       if p.trace {
-               defer un(trace(p, "CaseClause"))
-       }
-
-       // SwitchCase
-       pos := p.pos
-       var x []ast.Expr
-       if p.tok == token.CASE {
-               p.next()
-               x = p.parseExprList()
-       } else {
-               p.expect(token.DEFAULT)
-       }
-
-       colon := p.expect(token.COLON)
-       body := p.parseStmtList()
-
-       return &ast.CaseClause{pos, x, colon, body}
-}
-
-
 func (p *parser) parseTypeList() (list []ast.Expr) {
        if p.trace {
                defer un(trace(p, "TypeList"))
@@ -1405,25 +1542,30 @@ func (p *parser) parseTypeList() (list []ast.Expr) {
 }
 
 
-func (p *parser) parseTypeCaseClause() *ast.TypeCaseClause {
+func (p *parser) parseCaseClause(exprSwitch bool) *ast.CaseClause {
        if p.trace {
-               defer un(trace(p, "TypeCaseClause"))
+               defer un(trace(p, "CaseClause"))
        }
 
-       // TypeSwitchCase
        pos := p.pos
-       var types []ast.Expr
+       var list []ast.Expr
        if p.tok == token.CASE {
                p.next()
-               types = p.parseTypeList()
+               if exprSwitch {
+                       list = p.parseExprList()
+               } else {
+                       list = p.parseTypeList()
+               }
        } else {
                p.expect(token.DEFAULT)
        }
 
        colon := p.expect(token.COLON)
+       p.openScope()
        body := p.parseStmtList()
+       p.closeScope()
 
-       return &ast.TypeCaseClause{pos, types, colon, body}
+       return &ast.CaseClause{pos, list, colon, body}
 }
 
 
@@ -1447,6 +1589,8 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
        }
 
        pos := p.expect(token.SWITCH)
+       p.openScope()
+       defer p.closeScope()
 
        var s1, s2 ast.Stmt
        if p.tok != token.LBRACE {
@@ -1466,28 +1610,21 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
                p.exprLev = prevLev
        }
 
-       if isExprSwitch(s2) {
-               lbrace := p.expect(token.LBRACE)
-               var list []ast.Stmt
-               for p.tok == token.CASE || p.tok == token.DEFAULT {
-                       list = append(list, p.parseCaseClause())
-               }
-               rbrace := p.expect(token.RBRACE)
-               body := &ast.BlockStmt{lbrace, list, rbrace}
-               p.expectSemi()
-               return &ast.SwitchStmt{pos, s1, p.makeExpr(s2), body}
-       }
-
-       // type switch
-       // TODO(gri): do all the checks!
+       exprSwitch := isExprSwitch(s2)
        lbrace := p.expect(token.LBRACE)
        var list []ast.Stmt
        for p.tok == token.CASE || p.tok == token.DEFAULT {
-               list = append(list, p.parseTypeCaseClause())
+               list = append(list, p.parseCaseClause(exprSwitch))
        }
        rbrace := p.expect(token.RBRACE)
        p.expectSemi()
        body := &ast.BlockStmt{lbrace, list, rbrace}
+
+       if exprSwitch {
+               return &ast.SwitchStmt{pos, s1, p.makeExpr(s2), body}
+       }
+       // type switch
+       // TODO(gri): do all the checks!
        return &ast.TypeSwitchStmt{pos, s1, s2, body}
 }
 
@@ -1497,7 +1634,7 @@ func (p *parser) parseCommClause() *ast.CommClause {
                defer un(trace(p, "CommClause"))
        }
 
-       // CommCase
+       p.openScope()
        pos := p.pos
        var comm ast.Stmt
        if p.tok == token.CASE {
@@ -1518,7 +1655,7 @@ func (p *parser) parseCommClause() *ast.CommClause {
                        pos := p.pos
                        tok := p.tok
                        var rhs ast.Expr
-                       if p.tok == token.ASSIGN || p.tok == token.DEFINE {
+                       if tok == token.ASSIGN || tok == token.DEFINE {
                                // RecvStmt with assignment
                                if len(lhs) > 2 {
                                        p.errorExpected(lhs[0].Pos(), "1 or 2 expressions")
@@ -1527,6 +1664,9 @@ func (p *parser) parseCommClause() *ast.CommClause {
                                }
                                p.next()
                                rhs = p.parseExpr()
+                               if tok == token.DEFINE {
+                                       p.shortVarDecl(p.makeIdentList(lhs))
+                               }
                        } else {
                                // rhs must be single receive operation
                                if len(lhs) > 1 {
@@ -1552,6 +1692,7 @@ func (p *parser) parseCommClause() *ast.CommClause {
 
        colon := p.expect(token.COLON)
        body := p.parseStmtList()
+       p.closeScope()
 
        return &ast.CommClause{pos, comm, colon, body}
 }
@@ -1582,6 +1723,8 @@ func (p *parser) parseForStmt() ast.Stmt {
        }
 
        pos := p.expect(token.FOR)
+       p.openScope()
+       defer p.closeScope()
 
        var s1, s2, s3 ast.Stmt
        if p.tok != token.LBRACE {
@@ -1631,18 +1774,16 @@ func (p *parser) parseForStmt() ast.Stmt {
                        return &ast.BadStmt{pos, body.End()}
                }
                if rhs, isUnary := as.Rhs[0].(*ast.UnaryExpr); isUnary && rhs.Op == token.RANGE {
-                       // rhs is range expression; check lhs
+                       // rhs is range expression
+                       // (any short variable declaration was handled by parseSimpleStat above)
                        return &ast.RangeStmt{pos, key, value, as.TokPos, as.Tok, rhs.X, body}
-               } else {
-                       p.errorExpected(s2.Pos(), "range clause")
-                       return &ast.BadStmt{pos, body.End()}
                }
-       } else {
-               // regular for statement
-               return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body}
+               p.errorExpected(s2.Pos(), "range clause")
+               return &ast.BadStmt{pos, body.End()}
        }
 
-       panic("unreachable")
+       // regular for statement
+       return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body}
 }
 
 
@@ -1706,36 +1847,37 @@ func (p *parser) parseStmt() (s ast.Stmt) {
 // ----------------------------------------------------------------------------
 // Declarations
 
-type parseSpecFunction func(p *parser, doc *ast.CommentGroup) ast.Spec
+type parseSpecFunction func(p *parser, doc *ast.CommentGroup, iota int) ast.Spec
 
 
-func parseImportSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
+func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
        if p.trace {
                defer un(trace(p, "ImportSpec"))
        }
 
        var ident *ast.Ident
-       if p.tok == token.PERIOD {
+       switch p.tok {
+       case token.PERIOD:
                ident = &ast.Ident{p.pos, ".", nil}
                p.next()
-       } else if p.tok == token.IDENT {
+       case token.IDENT:
                ident = p.parseIdent()
        }
 
        var path *ast.BasicLit
        if p.tok == token.STRING {
-               path = &ast.BasicLit{p.pos, p.tok, p.lit}
+               path = &ast.BasicLit{p.pos, p.tok, p.lit()}
                p.next()
        } else {
                p.expect(token.STRING) // use expect() error handling
        }
-       p.expectSemi()
+       p.expectSemi() // call before accessing p.linecomment
 
        return &ast.ImportSpec{doc, ident, path, p.lineComment}
 }
 
 
-func parseConstSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
+func parseConstSpec(p *parser, doc *ast.CommentGroup, iota int) ast.Spec {
        if p.trace {
                defer un(trace(p, "ConstSpec"))
        }
@@ -1743,30 +1885,44 @@ func parseConstSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
        idents := p.parseIdentList()
        typ := p.tryType()
        var values []ast.Expr
-       if typ != nil || p.tok == token.ASSIGN {
+       if typ != nil || p.tok == token.ASSIGN || iota == 0 {
                p.expect(token.ASSIGN)
                values = p.parseExprList()
        }
-       p.expectSemi()
+       p.expectSemi() // call before accessing p.linecomment
+
+       // Go spec: The scope of a constant or variable identifier declared inside
+       // a function begins at the end of the ConstSpec or VarSpec and ends at
+       // the end of the innermost containing block.
+       // (Global identifiers are resolved in a separate phase after parsing.)
+       spec := &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
+       p.declare(spec, p.topScope, ast.Con, idents...)
 
-       return &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
+       return spec
 }
 
 
-func parseTypeSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
+func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
        if p.trace {
                defer un(trace(p, "TypeSpec"))
        }
 
        ident := p.parseIdent()
        typ := p.parseType()
-       p.expectSemi()
+       p.expectSemi() // call before accessing p.linecomment
+
+       // Go spec: The scope of a type identifier declared inside a function begins
+       // at the identifier in the TypeSpec and ends at the end of the innermost
+       // containing block.
+       // (Global identifiers are resolved in a separate phase after parsing.)
+       spec := &ast.TypeSpec{doc, ident, typ, p.lineComment}
+       p.declare(spec, p.topScope, ast.Typ, ident)
 
-       return &ast.TypeSpec{doc, ident, typ, p.lineComment}
+       return spec
 }
 
 
-func parseVarSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
+func parseVarSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
        if p.trace {
                defer un(trace(p, "VarSpec"))
        }
@@ -1778,9 +1934,16 @@ func parseVarSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
                p.expect(token.ASSIGN)
                values = p.parseExprList()
        }
-       p.expectSemi()
+       p.expectSemi() // call before accessing p.linecomment
+
+       // Go spec: The scope of a constant or variable identifier declared inside
+       // a function begins at the end of the ConstSpec or VarSpec and ends at
+       // the end of the innermost containing block.
+       // (Global identifiers are resolved in a separate phase after parsing.)
+       spec := &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
+       p.declare(spec, p.topScope, ast.Var, idents...)
 
-       return &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
+       return spec
 }
 
 
@@ -1796,26 +1959,26 @@ func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.Gen
        if p.tok == token.LPAREN {
                lparen = p.pos
                p.next()
-               for p.tok != token.RPAREN && p.tok != token.EOF {
-                       list = append(list, f(p, p.leadComment))
+               for iota := 0; p.tok != token.RPAREN && p.tok != token.EOF; iota++ {
+                       list = append(list, f(p, p.leadComment, iota))
                }
                rparen = p.expect(token.RPAREN)
                p.expectSemi()
        } else {
-               list = append(list, f(p, nil))
+               list = append(list, f(p, nil, 0))
        }
 
        return &ast.GenDecl{doc, pos, keyword, lparen, list, rparen}
 }
 
 
-func (p *parser) parseReceiver() *ast.FieldList {
+func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
        if p.trace {
                defer un(trace(p, "Receiver"))
        }
 
        pos := p.pos
-       par := p.parseParameters(false)
+       par := p.parseParameters(scope, false)
 
        // must have exactly one receiver
        if par.NumFields() != 1 {
@@ -1844,22 +2007,37 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl {
 
        doc := p.leadComment
        pos := p.expect(token.FUNC)
+       scope := ast.NewScope(p.topScope) // function scope
 
        var recv *ast.FieldList
        if p.tok == token.LPAREN {
-               recv = p.parseReceiver()
+               recv = p.parseReceiver(scope)
        }
 
        ident := p.parseIdent()
-       params, results := p.parseSignature()
+
+       params, results := p.parseSignature(scope)
 
        var body *ast.BlockStmt
        if p.tok == token.LBRACE {
-               body = p.parseBody()
+               body = p.parseBody(scope)
        }
        p.expectSemi()
 
-       return &ast.FuncDecl{doc, recv, ident, &ast.FuncType{pos, params, results}, body}
+       decl := &ast.FuncDecl{doc, recv, ident, &ast.FuncType{pos, params, results}, body}
+       if recv == nil {
+               // Go spec: The scope of an identifier denoting a constant, type,
+               // variable, or function (but not method) declared at top level
+               // (outside any function) is the package block.
+               //
+               // init() functions cannot be referred to and there may
+               // be more than one - don't put them in the pkgScope
+               if ident.Name != "init" {
+                       p.declare(decl, p.pkgScope, ast.Fun, ident)
+               }
+       }
+
+       return decl
 }
 
 
@@ -1918,6 +2096,8 @@ func (p *parser) parseFile() *ast.File {
        // package clause
        doc := p.leadComment
        pos := p.expect(token.PACKAGE)
+       // Go spec: The package clause is not a declaration;
+       // the package name does not appear in any scope.
        ident := p.parseIdent()
        p.expectSemi()
 
@@ -1940,5 +2120,20 @@ func (p *parser) parseFile() *ast.File {
                }
        }
 
-       return &ast.File{doc, pos, ident, decls, p.comments}
+       if p.topScope != p.pkgScope {
+               panic("internal error: imbalanced scopes")
+       }
+
+       // resolve global identifiers within the same file
+       i := 0
+       for _, ident := range p.unresolved {
+               // i <= index for current ident
+               ident.Obj = p.pkgScope.Lookup(ident.Name)
+               if ident.Obj == nil {
+                       p.unresolved[i] = ident
+                       i++
+               }
+       }
+
+       return &ast.File{doc, pos, ident, decls, p.pkgScope, p.unresolved[0:i], p.comments}
 }
index 3853562..2f1ee6b 100644 (file)
@@ -21,6 +21,7 @@ var illegalInputs = []interface{}{
        `package p; func f() { if /* should have condition */ {} };`,
        `package p; func f() { if ; /* should have condition */ {} };`,
        `package p; func f() { if f(); /* should have condition */ {} };`,
+       `package p; const c; /* should have constant value */`,
 }
 
 
@@ -73,7 +74,7 @@ var validFiles = []string{
 
 func TestParse3(t *testing.T) {
        for _, filename := range validFiles {
-               _, err := ParseFile(fset, filename, nil, 0)
+               _, err := ParseFile(fset, filename, nil, DeclarationErrors)
                if err != nil {
                        t.Errorf("ParseFile(%s): %v", filename, err)
                }
index 7933c2f..2238b6b 100644 (file)
@@ -108,17 +108,6 @@ func (p *printer) identList(list []*ast.Ident, indent bool, multiLine *bool) {
 }
 
 
-// Compute the key size of a key:value expression.
-// Returns 0 if the expression doesn't fit onto a single line.
-func (p *printer) keySize(pair *ast.KeyValueExpr) int {
-       if p.nodeSize(pair, infinity) <= infinity {
-               // entire expression fits on one line - return key size
-               return p.nodeSize(pair.Key, infinity)
-       }
-       return 0
-}
-
-
 // Print a list of expressions. If the list spans multiple
 // source lines, the original line breaks are respected between
 // expressions. Sets multiLine to true if the list spans multiple
@@ -204,17 +193,21 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
                //           the key and the node size into the decision process
                useFF := true
 
-               // determine size
+               // determine element size: all bets are off if we don't have
+               // position information for the previous and next token (likely
+               // generated code - simply ignore the size in this case by setting
+               // it to 0)
                prevSize := size
                const infinity = 1e6 // larger than any source line
                size = p.nodeSize(x, infinity)
                pair, isPair := x.(*ast.KeyValueExpr)
-               if size <= infinity {
+               if size <= infinity && prev.IsValid() && next.IsValid() {
                        // x fits on a single line
                        if isPair {
                                size = p.nodeSize(pair.Key, infinity) // size <= infinity
                        }
                } else {
+                       // size too large or we don't have good layout information
                        size = 0
                }
 
@@ -244,7 +237,6 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
                                // lines are broken using newlines so comments remain aligned
                                // unless forceFF is set or there are multiple expressions on
                                // the same line in which case formfeed is used
-                               // broken with a formfeed
                                if p.linebreak(line, linebreakMin, ws, useFF || prevBreak+1 < i) {
                                        ws = ignore
                                        *multiLine = true
@@ -375,7 +367,7 @@ func (p *printer) setLineComment(text string) {
 }
 
 
-func (p *printer) fieldList(fields *ast.FieldList, isIncomplete bool, ctxt exprContext) {
+func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) {
        p.nesting++
        defer func() {
                p.nesting--
@@ -384,15 +376,15 @@ func (p *printer) fieldList(fields *ast.FieldList, isIncomplete bool, ctxt exprC
        lbrace := fields.Opening
        list := fields.List
        rbrace := fields.Closing
+       srcIsOneLine := lbrace.IsValid() && rbrace.IsValid() && p.fset.Position(lbrace).Line == p.fset.Position(rbrace).Line
 
-       if !isIncomplete && !p.commentBefore(p.fset.Position(rbrace)) {
+       if !isIncomplete && !p.commentBefore(p.fset.Position(rbrace)) && srcIsOneLine {
                // possibly a one-line struct/interface
                if len(list) == 0 {
                        // no blank between keyword and {} in this case
                        p.print(lbrace, token.LBRACE, rbrace, token.RBRACE)
                        return
-               } else if ctxt&(compositeLit|structType) == compositeLit|structType &&
-                       p.isOneLineFieldList(list) { // for now ignore interfaces
+               } else if isStruct && p.isOneLineFieldList(list) { // for now ignore interfaces
                        // small enough - print on one line
                        // (don't use identList and ignore source line breaks)
                        p.print(lbrace, token.LBRACE, blank)
@@ -414,7 +406,7 @@ func (p *printer) fieldList(fields *ast.FieldList, isIncomplete bool, ctxt exprC
 
        // at least one entry or incomplete
        p.print(blank, lbrace, token.LBRACE, indent, formfeed)
-       if ctxt&structType != 0 {
+       if isStruct {
 
                sep := vtab
                if len(list) == 1 {
@@ -497,15 +489,6 @@ func (p *printer) fieldList(fields *ast.FieldList, isIncomplete bool, ctxt exprC
 // ----------------------------------------------------------------------------
 // Expressions
 
-// exprContext describes the syntactic environment in which an expression node is printed.
-type exprContext uint
-
-const (
-       compositeLit exprContext = 1 << iota
-       structType
-)
-
-
 func walkBinary(e *ast.BinaryExpr) (has4, has5 bool, maxProblem int) {
        switch e.Op.Precedence() {
        case 4:
@@ -650,7 +633,7 @@ func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiL
        printBlank := prec < cutoff
 
        ws := indent
-       p.expr1(x.X, prec, depth+diffPrec(x.X, prec), 0, multiLine)
+       p.expr1(x.X, prec, depth+diffPrec(x.X, prec), multiLine)
        if printBlank {
                p.print(blank)
        }
@@ -669,7 +652,7 @@ func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiL
        if printBlank {
                p.print(blank)
        }
-       p.expr1(x.Y, prec+1, depth+1, 0, multiLine)
+       p.expr1(x.Y, prec+1, depth+1, multiLine)
        if ws == ignore {
                p.print(unindent)
        }
@@ -742,7 +725,7 @@ func selectorExprList(expr ast.Expr) (list []ast.Expr) {
 
 
 // Sets multiLine to true if the expression spans multiple lines.
-func (p *printer) expr1(expr ast.Expr, prec1, depth int, ctxt exprContext, multiLine *bool) {
+func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) {
        p.print(expr.Pos())
 
        switch x := expr.(type) {
@@ -792,7 +775,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, ctxt exprContext, multi
                                // TODO(gri) Remove this code if it cannot be reached.
                                p.print(blank)
                        }
-                       p.expr1(x.X, prec, depth, 0, multiLine)
+                       p.expr1(x.X, prec, depth, multiLine)
                }
 
        case *ast.BasicLit:
@@ -818,7 +801,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, ctxt exprContext, multi
                p.exprList(token.NoPos, parts, depth, periodSep, multiLine, token.NoPos)
 
        case *ast.TypeAssertExpr:
-               p.expr1(x.X, token.HighestPrec, depth, 0, multiLine)
+               p.expr1(x.X, token.HighestPrec, depth, multiLine)
                p.print(token.PERIOD, token.LPAREN)
                if x.Type != nil {
                        p.expr(x.Type, multiLine)
@@ -829,14 +812,14 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, ctxt exprContext, multi
 
        case *ast.IndexExpr:
                // TODO(gri): should treat[] like parentheses and undo one level of depth
-               p.expr1(x.X, token.HighestPrec, 1, 0, multiLine)
+               p.expr1(x.X, token.HighestPrec, 1, multiLine)
                p.print(x.Lbrack, token.LBRACK)
                p.expr0(x.Index, depth+1, multiLine)
                p.print(x.Rbrack, token.RBRACK)
 
        case *ast.SliceExpr:
                // TODO(gri): should treat[] like parentheses and undo one level of depth
-               p.expr1(x.X, token.HighestPrec, 1, 0, multiLine)
+               p.expr1(x.X, token.HighestPrec, 1, multiLine)
                p.print(x.Lbrack, token.LBRACK)
                if x.Low != nil {
                        p.expr0(x.Low, depth+1, multiLine)
@@ -856,7 +839,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, ctxt exprContext, multi
                if len(x.Args) > 1 {
                        depth++
                }
-               p.expr1(x.Fun, token.HighestPrec, depth, 0, multiLine)
+               p.expr1(x.Fun, token.HighestPrec, depth, multiLine)
                p.print(x.Lparen, token.LPAREN)
                p.exprList(x.Lparen, x.Args, depth, commaSep|commaTerm, multiLine, x.Rparen)
                if x.Ellipsis.IsValid() {
@@ -867,7 +850,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, ctxt exprContext, multi
        case *ast.CompositeLit:
                // composite literal elements that are composite literals themselves may have the type omitted
                if x.Type != nil {
-                       p.expr1(x.Type, token.HighestPrec, depth, compositeLit, multiLine)
+                       p.expr1(x.Type, token.HighestPrec, depth, multiLine)
                }
                p.print(x.Lbrace, token.LBRACE)
                p.exprList(x.Lbrace, x.Elts, 1, commaSep|commaTerm, multiLine, x.Rbrace)
@@ -892,7 +875,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, ctxt exprContext, multi
 
        case *ast.StructType:
                p.print(token.STRUCT)
-               p.fieldList(x.Fields, x.Incomplete, ctxt|structType)
+               p.fieldList(x.Fields, true, x.Incomplete)
 
        case *ast.FuncType:
                p.print(token.FUNC)
@@ -900,7 +883,7 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, ctxt exprContext, multi
 
        case *ast.InterfaceType:
                p.print(token.INTERFACE)
-               p.fieldList(x.Methods, x.Incomplete, ctxt)
+               p.fieldList(x.Methods, false, x.Incomplete)
 
        case *ast.MapType:
                p.print(token.MAP, token.LBRACK)
@@ -929,14 +912,14 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, ctxt exprContext, multi
 
 
 func (p *printer) expr0(x ast.Expr, depth int, multiLine *bool) {
-       p.expr1(x, token.LowestPrec, depth, 0, multiLine)
+       p.expr1(x, token.LowestPrec, depth, multiLine)
 }
 
 
 // Sets multiLine to true if the expression spans multiple lines.
 func (p *printer) expr(x ast.Expr, multiLine *bool) {
        const depth = 1
-       p.expr1(x, token.LowestPrec, depth, 0, multiLine)
+       p.expr1(x, token.LowestPrec, depth, multiLine)
 }
 
 
@@ -1145,9 +1128,9 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
                }
 
        case *ast.CaseClause:
-               if s.Values != nil {
+               if s.List != nil {
                        p.print(token.CASE)
-                       p.exprList(s.Pos(), s.Values, 1, blankStart|commaSep, multiLine, s.Colon)
+                       p.exprList(s.Pos(), s.List, 1, blankStart|commaSep, multiLine, s.Colon)
                } else {
                        p.print(token.DEFAULT)
                }
@@ -1160,16 +1143,6 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
                p.block(s.Body, 0)
                *multiLine = true
 
-       case *ast.TypeCaseClause:
-               if s.Types != nil {
-                       p.print(token.CASE)
-                       p.exprList(s.Pos(), s.Types, 1, blankStart|commaSep, multiLine, s.Colon)
-               } else {
-                       p.print(token.DEFAULT)
-               }
-               p.print(s.Colon, token.COLON)
-               p.stmtList(s.Body, 1, nextIsRBrace)
-
        case *ast.TypeSwitchStmt:
                p.print(token.SWITCH)
                if s.Init != nil {
@@ -1331,13 +1304,23 @@ func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) {
 // any control chars. Otherwise, the result is > maxSize.
 //
 func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) {
+       // nodeSize invokes the printer, which may invoke nodeSize
+       // recursively. For deep composite literal nests, this can
+       // lead to an exponential algorithm. Remember previous
+       // results to prune the recursion (was issue 1628).
+       if size, found := p.nodeSizes[n]; found {
+               return size
+       }
+
        size = maxSize + 1 // assume n doesn't fit
+       p.nodeSizes[n] = size
+
        // nodeSize computation must be indendent of particular
        // style so that we always get the same decision; print
        // in RawFormat
        cfg := Config{Mode: RawFormat}
        var buf bytes.Buffer
-       if _, err := cfg.Fprint(&buf, p.fset, n); err != nil {
+       if _, err := cfg.fprint(&buf, p.fset, n, p.nodeSizes); err != nil {
                return
        }
        if buf.Len() <= maxSize {
@@ -1347,6 +1330,7 @@ func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) {
                        }
                }
                size = buf.Len() // n fits
+               p.nodeSizes[n] = size
        }
        return
 }
index 48e2af1..a43e4a1 100644 (file)
@@ -12,7 +12,7 @@ import (
        "go/token"
        "io"
        "os"
-       "path"
+       "path/filepath"
        "runtime"
        "tabwriter"
 )
@@ -94,22 +94,23 @@ type printer struct {
        // written using writeItem.
        last token.Position
 
-       // HTML support
-       lastTaggedLine int // last line for which a line tag was written
-
        // The list of all source comments, in order of appearance.
        comments        []*ast.CommentGroup // may be nil
        cindex          int                 // current comment index
        useNodeComments bool                // if not set, ignore lead and line comments of nodes
+
+       // Cache of already computed node sizes.
+       nodeSizes map[ast.Node]int
 }
 
 
-func (p *printer) init(output io.Writer, cfg *Config, fset *token.FileSet) {
+func (p *printer) init(output io.Writer, cfg *Config, fset *token.FileSet, nodeSizes map[ast.Node]int) {
        p.output = output
        p.Config = *cfg
        p.fset = fset
        p.errors = make(chan os.Error)
        p.buffer = make([]whiteSpace, 0, 16) // whitespace sequences are short
+       p.nodeSizes = nodeSizes
 }
 
 
@@ -244,7 +245,7 @@ func (p *printer) writeItem(pos token.Position, data []byte) {
        }
        if debug {
                // do not update p.pos - use write0
-               _, filename := path.Split(pos.Filename)
+               _, filename := filepath.Split(pos.Filename)
                p.write0([]byte(fmt.Sprintf("[%s:%d:%d]", filename, pos.Line, pos.Column)))
        }
        p.write(data)
@@ -994,13 +995,8 @@ type Config struct {
 }
 
 
-// Fprint "pretty-prints" an AST node to output and returns the number
-// of bytes written and an error (if any) for a given configuration cfg.
-// Position information is interpreted relative to the file set fset.
-// The node type must be *ast.File, or assignment-compatible to ast.Expr,
-// ast.Decl, ast.Spec, or ast.Stmt.
-//
-func (cfg *Config) Fprint(output io.Writer, fset *token.FileSet, node interface{}) (int, os.Error) {
+// fprint implements Fprint and takes a nodesSizes map for setting up the printer state.
+func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{}, nodeSizes map[ast.Node]int) (int, os.Error) {
        // redirect output through a trimmer to eliminate trailing whitespace
        // (Input to a tabwriter must be untrimmed since trailing tabs provide
        // formatting information. The tabwriter could provide trimming
@@ -1029,7 +1025,7 @@ func (cfg *Config) Fprint(output io.Writer, fset *token.FileSet, node interface{
 
        // setup printer and print node
        var p printer
-       p.init(output, cfg, fset)
+       p.init(output, cfg, fset, nodeSizes)
        go func() {
                switch n := node.(type) {
                case ast.Expr:
@@ -1076,6 +1072,17 @@ func (cfg *Config) Fprint(output io.Writer, fset *token.FileSet, node interface{
 }
 
 
+// Fprint "pretty-prints" an AST node to output and returns the number
+// of bytes written and an error (if any) for a given configuration cfg.
+// Position information is interpreted relative to the file set fset.
+// The node type must be *ast.File, or assignment-compatible to ast.Expr,
+// ast.Decl, ast.Spec, or ast.Stmt.
+//
+func (cfg *Config) Fprint(output io.Writer, fset *token.FileSet, node interface{}) (int, os.Error) {
+       return cfg.fprint(output, fset, node, make(map[ast.Node]int))
+}
+
+
 // Fprint "pretty-prints" an AST node to output.
 // It calls Config.Fprint with default settings.
 //
index 565075a..3ff087e 100644 (file)
@@ -11,8 +11,9 @@ import (
        "go/ast"
        "go/parser"
        "go/token"
-       "path"
+       "path/filepath"
        "testing"
+       "time"
 )
 
 
@@ -45,7 +46,7 @@ const (
 )
 
 
-func check(t *testing.T, source, golden string, mode checkMode) {
+func runcheck(t *testing.T, source, golden string, mode checkMode) {
        // parse source
        prog, err := parser.ParseFile(fset, source, nil, parser.ParseComments)
        if err != nil {
@@ -109,6 +110,32 @@ func check(t *testing.T, source, golden string, mode checkMode) {
 }
 
 
+func check(t *testing.T, source, golden string, mode checkMode) {
+       // start a timer to produce a time-out signal
+       tc := make(chan int)
+       go func() {
+               time.Sleep(20e9) // plenty of a safety margin, even for very slow machines
+               tc <- 0
+       }()
+
+       // run the test
+       cc := make(chan int)
+       go func() {
+               runcheck(t, source, golden, mode)
+               cc <- 0
+       }()
+
+       // wait for the first finisher
+       select {
+       case <-tc:
+               // test running past time out
+               t.Errorf("%s: running too slowly", source)
+       case <-cc:
+               // test finished within alloted time margin
+       }
+}
+
+
 type entry struct {
        source, golden string
        mode           checkMode
@@ -124,13 +151,14 @@ var data = []entry{
        {"expressions.input", "expressions.raw", rawFormat},
        {"declarations.input", "declarations.golden", 0},
        {"statements.input", "statements.golden", 0},
+       {"slow.input", "slow.golden", 0},
 }
 
 
 func TestFiles(t *testing.T) {
        for _, e := range data {
-               source := path.Join(dataDir, e.source)
-               golden := path.Join(dataDir, e.golden)
+               source := filepath.Join(dataDir, e.source)
+               golden := filepath.Join(dataDir, e.golden)
                check(t, source, golden, e.mode)
                // TODO(gri) check that golden is idempotent
                //check(t, golden, golden, e.mode);
index 7f18f33..314d321 100644 (file)
@@ -224,11 +224,7 @@ func _() {
        _ = struct{ x int }{0}
        _ = struct{ x, y, z int }{0, 1, 2}
        _ = struct{ int }{0}
-       _ = struct {
-               s struct {
-                       int
-               }
-       }{struct{ int }{0}}     // compositeLit context not propagated => multiLine result
+       _ = struct{ s struct{ int } }{struct{ int }{0}}
 }
 
 
index 6bcd9b5..cac22af 100644 (file)
@@ -224,7 +224,7 @@ func _() {
        _ = struct{ x int }{0}
        _ = struct{ x, y, z int }{0, 1, 2}
        _ = struct{ int }{0}
-       _ = struct{ s struct { int } }{struct{ int}{0}}  // compositeLit context not propagated => multiLine result
+       _ = struct{ s struct { int } }{struct{ int}{0} }
 }
 
 
index f1944c9..f22ceeb 100644 (file)
@@ -224,11 +224,7 @@ func _() {
        _ = struct{ x int }{0}
        _ = struct{ x, y, z int }{0, 1, 2}
        _ = struct{ int }{0}
-       _ = struct {
-               s struct {
-                       int
-               }
-       }{struct{ int }{0}}     // compositeLit context not propagated => multiLine result
+       _ = struct{ s struct{ int } }{struct{ int }{0}}
 }
 
 
diff --git a/libgo/go/go/printer/testdata/slow.golden b/libgo/go/go/printer/testdata/slow.golden
new file mode 100644 (file)
index 0000000..43a15cb
--- /dev/null
@@ -0,0 +1,85 @@
+// 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 deepequal_test
+
+import (
+       "testing"
+       "google3/spam/archer/frontend/deepequal"
+)
+
+func TestTwoNilValues(t *testing.T) {
+       if err := deepequal.Check(nil, nil); err != nil {
+               t.Errorf("expected nil, saw %v", err)
+       }
+}
+
+type Foo struct {
+       bar     *Bar
+       bang    *Bar
+}
+
+type Bar struct {
+       baz     *Baz
+       foo     []*Foo
+}
+
+type Baz struct {
+       entries         map[int]interface{}
+       whatever        string
+}
+
+func newFoo() *Foo {
+       return &Foo{bar: &Bar{baz: &Baz{
+               entries: map[int]interface{}{
+                       42:     &Foo{},
+                       21:     &Bar{},
+                       11:     &Baz{whatever: "it's just a test"}}}},
+               bang: &Bar{foo: []*Foo{
+                       &Foo{bar: &Bar{baz: &Baz{
+                               entries: map[int]interface{}{
+                                       43:     &Foo{},
+                                       22:     &Bar{},
+                                       13:     &Baz{whatever: "this is nuts"}}}},
+                               bang: &Bar{foo: []*Foo{
+                                       &Foo{bar: &Bar{baz: &Baz{
+                                               entries: map[int]interface{}{
+                                                       61:     &Foo{},
+                                                       71:     &Bar{},
+                                                       11:     &Baz{whatever: "no, it's Go"}}}},
+                                               bang: &Bar{foo: []*Foo{
+                                                       &Foo{bar: &Bar{baz: &Baz{
+                                                               entries: map[int]interface{}{
+                                                                       0:      &Foo{},
+                                                                       -2:     &Bar{},
+                                                                       -11:    &Baz{whatever: "we need to go deeper"}}}},
+                                                               bang: &Bar{foo: []*Foo{
+                                                                       &Foo{bar: &Bar{baz: &Baz{
+                                                                               entries: map[int]interface{}{
+                                                                                       -2:     &Foo{},
+                                                                                       -5:     &Bar{},
+                                                                                       -7:     &Baz{whatever: "are you serious?"}}}},
+                                                                               bang:   &Bar{foo: []*Foo{}}},
+                                                                       &Foo{bar: &Bar{baz: &Baz{
+                                                                               entries: map[int]interface{}{
+                                                                                       -100:   &Foo{},
+                                                                                       50:     &Bar{},
+                                                                                       20:     &Baz{whatever: "na, not really ..."}}}},
+                                                                               bang:   &Bar{foo: []*Foo{}}}}}}}}},
+                                       &Foo{bar: &Bar{baz: &Baz{
+                                               entries: map[int]interface{}{
+                                                       2:      &Foo{},
+                                                       1:      &Bar{},
+                                                       -1:     &Baz{whatever: "... it's just a test."}}}},
+                                               bang:   &Bar{foo: []*Foo{}}}}}}}}}
+}
+
+func TestElaborate(t *testing.T) {
+       a := newFoo()
+       b := newFoo()
+
+       if err := deepequal.Check(a, b); err != nil {
+               t.Errorf("expected nil, saw %v", err)
+       }
+}
diff --git a/libgo/go/go/printer/testdata/slow.input b/libgo/go/go/printer/testdata/slow.input
new file mode 100644 (file)
index 0000000..0e5a23d
--- /dev/null
@@ -0,0 +1,85 @@
+// 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 deepequal_test
+
+import (
+        "testing"
+        "google3/spam/archer/frontend/deepequal"
+)
+
+func TestTwoNilValues(t *testing.T) {
+        if err := deepequal.Check(nil, nil); err != nil {
+                t.Errorf("expected nil, saw %v", err)
+        }
+}
+
+type Foo struct {
+        bar *Bar
+        bang *Bar
+}
+
+type Bar struct {
+        baz *Baz
+        foo []*Foo
+}
+
+type Baz struct {
+        entries  map[int]interface{}
+        whatever string
+}
+
+func newFoo() (*Foo) {
+return &Foo{bar: &Bar{ baz: &Baz{
+entries: map[int]interface{}{
+42: &Foo{},
+21: &Bar{},
+11: &Baz{ whatever: "it's just a test" }}}},
+        bang: &Bar{foo: []*Foo{
+&Foo{bar: &Bar{ baz: &Baz{
+entries: map[int]interface{}{
+43: &Foo{},
+22: &Bar{},
+13: &Baz{ whatever: "this is nuts" }}}},
+        bang: &Bar{foo: []*Foo{
+&Foo{bar: &Bar{ baz: &Baz{
+entries: map[int]interface{}{
+61: &Foo{},
+71: &Bar{},
+11: &Baz{ whatever: "no, it's Go" }}}},
+        bang: &Bar{foo: []*Foo{
+&Foo{bar: &Bar{ baz: &Baz{
+entries: map[int]interface{}{
+0: &Foo{},
+-2: &Bar{},
+-11: &Baz{ whatever: "we need to go deeper" }}}},
+        bang: &Bar{foo: []*Foo{
+&Foo{bar: &Bar{ baz: &Baz{
+entries: map[int]interface{}{
+-2: &Foo{},
+-5: &Bar{},
+-7: &Baz{ whatever: "are you serious?" }}}},
+        bang: &Bar{foo: []*Foo{}}},
+&Foo{bar: &Bar{ baz: &Baz{
+entries: map[int]interface{}{
+-100: &Foo{},
+50: &Bar{},
+20: &Baz{ whatever: "na, not really ..." }}}},
+        bang: &Bar{foo: []*Foo{}}}}}}}}},
+&Foo{bar: &Bar{ baz: &Baz{
+entries: map[int]interface{}{
+2: &Foo{},
+1: &Bar{},
+-1: &Baz{ whatever: "... it's just a test." }}}},
+        bang: &Bar{foo: []*Foo{}}}}}}}}}
+}
+
+func TestElaborate(t *testing.T) {
+        a := newFoo()
+        b := newFoo()
+
+        if err := deepequal.Check(a, b); err != nil {
+                t.Errorf("expected nil, saw %v", err)
+        }
+}
index 2ae296b..59fed9d 100644 (file)
@@ -23,7 +23,7 @@ package scanner
 import (
        "bytes"
        "go/token"
-       "path"
+       "path/filepath"
        "strconv"
        "unicode"
        "utf8"
@@ -118,7 +118,7 @@ func (S *Scanner) Init(file *token.File, src []byte, err ErrorHandler, mode uint
                panic("file size does not match src len")
        }
        S.file = file
-       S.dir, _ = path.Split(file.Name())
+       S.dir, _ = filepath.Split(file.Name())
        S.src = src
        S.err = err
        S.mode = mode
@@ -177,13 +177,13 @@ var prefix = []byte("//line ")
 func (S *Scanner) interpretLineComment(text []byte) {
        if bytes.HasPrefix(text, prefix) {
                // get filename and line number, if any
-               if i := bytes.Index(text, []byte{':'}); i > 0 {
+               if i := bytes.LastIndex(text, []byte{':'}); i > 0 {
                        if line, err := strconv.Atoi(string(text[i+1:])); err == nil && line > 0 {
                                // valid //line filename:line comment;
-                               filename := path.Clean(string(text[len(prefix):i]))
-                               if filename[0] != '/' {
+                               filename := filepath.Clean(string(text[len(prefix):i]))
+                               if !filepath.IsAbs(filename) {
                                        // make filename relative to current directory
-                                       filename = path.Join(S.dir, filename)
+                                       filename = filepath.Join(S.dir, filename)
                                }
                                // update scanner position
                                S.file.AddLineInfo(S.lineOffset, filename, line-1) // -1 since comment applies to next line
index c622ff4..93f3458 100644 (file)
@@ -7,6 +7,8 @@ package scanner
 import (
        "go/token"
        "os"
+       "path/filepath"
+       "runtime"
        "testing"
 )
 
@@ -443,32 +445,41 @@ func TestSemis(t *testing.T) {
        }
 }
 
-
-var segments = []struct {
+type segment struct {
        srcline  string // a line of source text
        filename string // filename for current token
        line     int    // line number for current token
-}{
+}
+
+var segments = []segment{
        // exactly one token per line since the test consumes one token per segment
-       {"  line1", "dir/TestLineComments", 1},
-       {"\nline2", "dir/TestLineComments", 2},
-       {"\nline3  //line File1.go:100", "dir/TestLineComments", 3}, // bad line comment, ignored
-       {"\nline4", "dir/TestLineComments", 4},
-       {"\n//line File1.go:100\n  line100", "dir/File1.go", 100},
-       {"\n//line File2.go:200\n  line200", "dir/File2.go", 200},
+       {"  line1", filepath.Join("dir", "TestLineComments"), 1},
+       {"\nline2", filepath.Join("dir", "TestLineComments"), 2},
+       {"\nline3  //line File1.go:100", filepath.Join("dir", "TestLineComments"), 3}, // bad line comment, ignored
+       {"\nline4", filepath.Join("dir", "TestLineComments"), 4},
+       {"\n//line File1.go:100\n  line100", filepath.Join("dir", "File1.go"), 100},
+       {"\n//line File2.go:200\n  line200", filepath.Join("dir", "File2.go"), 200},
        {"\n//line :1\n  line1", "dir", 1},
-       {"\n//line foo:42\n  line42", "dir/foo", 42},
-       {"\n //line foo:42\n  line44", "dir/foo", 44},           // bad line comment, ignored
-       {"\n//line foo 42\n  line46", "dir/foo", 46},            // bad line comment, ignored
-       {"\n//line foo:42 extra text\n  line48", "dir/foo", 48}, // bad line comment, ignored
-       {"\n//line /bar:42\n  line42", "/bar", 42},
-       {"\n//line ./foo:42\n  line42", "dir/foo", 42},
-       {"\n//line a/b/c/File1.go:100\n  line100", "dir/a/b/c/File1.go", 100},
+       {"\n//line foo:42\n  line42", filepath.Join("dir", "foo"), 42},
+       {"\n //line foo:42\n  line44", filepath.Join("dir", "foo"), 44},           // bad line comment, ignored
+       {"\n//line foo 42\n  line46", filepath.Join("dir", "foo"), 46},            // bad line comment, ignored
+       {"\n//line foo:42 extra text\n  line48", filepath.Join("dir", "foo"), 48}, // bad line comment, ignored
+       {"\n//line /bar:42\n  line42", string(filepath.Separator) + "bar", 42},
+       {"\n//line ./foo:42\n  line42", filepath.Join("dir", "foo"), 42},
+       {"\n//line a/b/c/File1.go:100\n  line100", filepath.Join("dir", "a", "b", "c", "File1.go"), 100},
+}
+
+var winsegments = []segment{
+       {"\n//line c:\\dir\\File1.go:100\n  line100", "c:\\dir\\File1.go", 100},
 }
 
 
 // Verify that comments of the form "//line filename:line" are interpreted correctly.
 func TestLineComments(t *testing.T) {
+       if runtime.GOOS == "windows" {
+               segments = append(segments, winsegments...)
+       }
+
        // make source
        var src string
        for _, e := range segments {
@@ -477,7 +488,7 @@ func TestLineComments(t *testing.T) {
 
        // verify scan
        var S Scanner
-       file := fset.AddFile("dir/TestLineComments", fset.Base(), len(src))
+       file := fset.AddFile(filepath.Join("dir", "TestLineComments"), fset.Base(), len(src))
        S.Init(file, []byte(src), nil, 0)
        for _, s := range segments {
                p, _, lit := S.Scan()
index 114c93e..bd24f4c 100644 (file)
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// This file implements scope support functions.
+// DEPRECATED FILE - WILL GO AWAY EVENTUALLY.
+//
+// Scope handling is now done in go/parser.
+// The functionality here is only present to
+// keep the typechecker running for now.
 
 package typechecker
 
-import (
-       "fmt"
-       "go/ast"
-       "go/token"
-)
+import "go/ast"
 
 
 func (tc *typechecker) openScope() *ast.Scope {
@@ -24,52 +24,25 @@ func (tc *typechecker) closeScope() {
 }
 
 
-// objPos computes the source position of the declaration of an object name.
-// Only required for error reporting, so doesn't have to be fast.
-func objPos(obj *ast.Object) (pos token.Pos) {
-       switch d := obj.Decl.(type) {
-       case *ast.Field:
-               for _, n := range d.Names {
-                       if n.Name == obj.Name {
-                               return n.Pos()
-                       }
-               }
-       case *ast.ValueSpec:
-               for _, n := range d.Names {
-                       if n.Name == obj.Name {
-                               return n.Pos()
-                       }
-               }
-       case *ast.TypeSpec:
-               return d.Name.Pos()
-       case *ast.FuncDecl:
-               return d.Name.Pos()
-       }
-       if debug {
-               fmt.Printf("decl = %T\n", obj.Decl)
-       }
-       panic("unreachable")
-}
-
-
 // declInScope declares an object of a given kind and name in scope and sets the object's Decl and N fields.
 // It returns the newly allocated object. If an object with the same name already exists in scope, an error
 // is reported and the object is not inserted.
-// (Objects with _ name are always inserted into a scope without errors, but they cannot be found.)
-func (tc *typechecker) declInScope(scope *ast.Scope, kind ast.Kind, name *ast.Ident, decl interface{}, n int) *ast.Object {
+func (tc *typechecker) declInScope(scope *ast.Scope, kind ast.ObjKind, name *ast.Ident, decl interface{}, n int) *ast.Object {
        obj := ast.NewObj(kind, name.Name)
        obj.Decl = decl
-       obj.N = n
+       //obj.N = n
        name.Obj = obj
-       if alt := scope.Insert(obj); alt != obj {
-               tc.Errorf(name.Pos(), "%s already declared at %s", name.Name, objPos(alt))
+       if name.Name != "_" {
+               if alt := scope.Insert(obj); alt != obj {
+                       tc.Errorf(name.Pos(), "%s already declared at %s", name.Name, tc.fset.Position(alt.Pos()).String())
+               }
        }
        return obj
 }
 
 
 // decl is the same as declInScope(tc.topScope, ...)
-func (tc *typechecker) decl(kind ast.Kind, name *ast.Ident, decl interface{}, n int) *ast.Object {
+func (tc *typechecker) decl(kind ast.ObjKind, name *ast.Ident, decl interface{}, n int) *ast.Object {
        return tc.declInScope(tc.topScope, kind, name, decl, n)
 }
 
@@ -91,7 +64,7 @@ func (tc *typechecker) find(name *ast.Ident) (obj *ast.Object) {
 
 // findField returns the object with the given name if visible in the type's scope.
 // If no such object is found, an error is reported and a bad object is returned instead.
-func (tc *typechecker) findField(typ *ast.Type, name *ast.Ident) (obj *ast.Object) {
+func (tc *typechecker) findField(typ *Type, name *ast.Ident) (obj *ast.Object) {
        // TODO(gri) This is simplistic at the moment and ignores anonymous fields.
        obj = typ.Scope.Lookup(name.Name)
        if obj == nil {
@@ -100,20 +73,3 @@ func (tc *typechecker) findField(typ *ast.Type, name *ast.Ident) (obj *ast.Objec
        }
        return
 }
-
-
-// printScope prints the objects in a scope.
-func printScope(scope *ast.Scope) {
-       fmt.Printf("scope %p {", scope)
-       if scope != nil && len(scope.Objects) > 0 {
-               fmt.Println()
-               for _, obj := range scope.Objects {
-                       form := "void"
-                       if obj.Type != nil {
-                               form = obj.Type.Form.String()
-                       }
-                       fmt.Printf("\t%s\t%s\n", obj.Name, form)
-               }
-       }
-       fmt.Printf("}\n")
-}
similarity index 83%
rename from libgo/go/go/typechecker/testdata/test1.go
rename to libgo/go/go/typechecker/testdata/test1.src
index b0808ee..b5531fb 100644 (file)
@@ -7,7 +7,7 @@
 package P1
 
 const (
-       c1         /* ERROR "missing initializer" */
+       c1 = 0
        c2     int = 0
        c3, c4 = 0
 )
similarity index 80%
rename from libgo/go/go/typechecker/testdata/test3.go
rename to libgo/go/go/typechecker/testdata/test3.src
index ea35808..2e1a9fa 100644 (file)
@@ -27,8 +27,11 @@ func (T) m1 /* ERROR "already declared" */ ()    {}
 
 func (x *T) m2(u, x /* ERROR "already declared" */ int)               {}
 func (x *T) m3(a, b, c int) (u, x /* ERROR "already declared" */ int) {}
-func (T) _(x, x /* ERROR "already declared" */ int)                   {}
-func (T) _() (x, x /* ERROR "already declared" */ int)                {}
+// The following are disabled for now because the typechecker
+// in in the process of being rewritten and cannot handle them
+// at the moment
+//func (T) _(x, x /* "already declared" */ int)                   {}
+//func (T) _() (x, x /* "already declared" */ int)                {}
 
 //func (PT) _() {}
 
similarity index 84%
rename from libgo/go/go/typechecker/testdata/test4.go
rename to libgo/go/go/typechecker/testdata/test4.src
index bb9aee3..94d3558 100644 (file)
@@ -7,5 +7,5 @@
 package P4
 
 const (
-       c0 /* ERROR "missing initializer" */
+       c0 = 0
 )
diff --git a/libgo/go/go/typechecker/type.go b/libgo/go/go/typechecker/type.go
new file mode 100644 (file)
index 0000000..62b4e9d
--- /dev/null
@@ -0,0 +1,125 @@
+// Copyright 2010 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 typechecker
+
+import "go/ast"
+
+
+// A Type represents a Go type.
+type Type struct {
+       Form     Form
+       Obj      *ast.Object // corresponding type name, or nil
+       Scope    *ast.Scope  // fields and methods, always present
+       N        uint        // basic type id, array length, number of function results, or channel direction
+       Key, Elt *Type       // map key and array, pointer, slice, map or channel element
+       Params   *ast.Scope  // function (receiver, input and result) parameters, tuple expressions (results of function calls), or nil
+       Expr     ast.Expr    // corresponding AST expression
+}
+
+
+// NewType creates a new type of a given form.
+func NewType(form Form) *Type {
+       return &Type{Form: form, Scope: ast.NewScope(nil)}
+}
+
+
+// Form describes the form of a type.
+type Form int
+
+// The list of possible type forms.
+const (
+       BadType    Form = iota // for error handling
+       Unresolved             // type not fully setup
+       Basic
+       Array
+       Struct
+       Pointer
+       Function
+       Method
+       Interface
+       Slice
+       Map
+       Channel
+       Tuple
+)
+
+
+var formStrings = [...]string{
+       BadType:    "badType",
+       Unresolved: "unresolved",
+       Basic:      "basic",
+       Array:      "array",
+       Struct:     "struct",
+       Pointer:    "pointer",
+       Function:   "function",
+       Method:     "method",
+       Interface:  "interface",
+       Slice:      "slice",
+       Map:        "map",
+       Channel:    "channel",
+       Tuple:      "tuple",
+}
+
+
+func (form Form) String() string { return formStrings[form] }
+
+
+// The list of basic type id's.
+const (
+       Bool = iota
+       Byte
+       Uint
+       Int
+       Float
+       Complex
+       Uintptr
+       String
+
+       Uint8
+       Uint16
+       Uint32
+       Uint64
+
+       Int8
+       Int16
+       Int32
+       Int64
+
+       Float32
+       Float64
+
+       Complex64
+       Complex128
+
+       // TODO(gri) ideal types are missing
+)
+
+
+var BasicTypes = map[uint]string{
+       Bool:    "bool",
+       Byte:    "byte",
+       Uint:    "uint",
+       Int:     "int",
+       Float:   "float",
+       Complex: "complex",
+       Uintptr: "uintptr",
+       String:  "string",
+
+       Uint8:  "uint8",
+       Uint16: "uint16",
+       Uint32: "uint32",
+       Uint64: "uint64",
+
+       Int8:  "int8",
+       Int16: "int16",
+       Int32: "int32",
+       Int64: "int64",
+
+       Float32: "float32",
+       Float64: "float64",
+
+       Complex64:  "complex64",
+       Complex128: "complex128",
+}
index e9aefa2..4fc5647 100644 (file)
@@ -65,6 +65,7 @@ type typechecker struct {
        fset *token.FileSet
        scanner.ErrorVector
        importer Importer
+       globals  []*ast.Object        // list of global objects
        topScope *ast.Scope           // current top-most scope
        cyclemap map[*ast.Object]bool // for cycle detection
        iota     int                  // current value of iota
@@ -94,7 +95,7 @@ phase 1: declare all global objects; also collect all function and method declar
        - report global double declarations
 
 phase 2: bind methods to their receiver base types
-       - received base types must be declared in the