From adb0401dac41c81571722312d4586b2693f95aa6 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 16 Sep 2011 15:47:21 +0000 Subject: Update Go library to r60. From-SVN: r178910 --- libgo/go/archive/tar/reader.go | 2 +- libgo/go/archive/tar/reader_test.go | 1 - libgo/go/archive/zip/reader.go | 281 +- libgo/go/archive/zip/reader_test.go | 44 +- libgo/go/archive/zip/struct.go | 61 +- libgo/go/archive/zip/writer.go | 244 + libgo/go/archive/zip/writer_test.go | 73 + libgo/go/archive/zip/zip_test.go | 57 + libgo/go/asn1/asn1.go | 117 +- libgo/go/asn1/asn1_test.go | 78 +- libgo/go/asn1/common.go | 7 +- libgo/go/asn1/marshal.go | 54 +- libgo/go/asn1/marshal_test.go | 13 +- libgo/go/big/arith.go | 25 +- libgo/go/big/arith_decl.go | 4 +- libgo/go/big/arith_test.go | 33 +- libgo/go/big/calibrate_test.go | 4 - libgo/go/big/hilbert_test.go | 13 - libgo/go/big/int.go | 302 +- libgo/go/big/int_test.go | 402 +- libgo/go/big/nat.go | 388 +- libgo/go/big/nat_test.go | 403 +- libgo/go/big/rat.go | 107 +- libgo/go/big/rat_test.go | 74 +- libgo/go/bufio/bufio.go | 29 +- libgo/go/bufio/bufio_test.go | 11 +- libgo/go/builtin/builtin.go | 135 + libgo/go/bytes/buffer.go | 4 +- libgo/go/bytes/buffer_test.go | 17 - libgo/go/bytes/bytes.go | 27 +- libgo/go/bytes/bytes_test.go | 21 +- libgo/go/compress/bzip2/bzip2.go | 4 +- libgo/go/compress/bzip2/huffman.go | 2 +- libgo/go/compress/flate/deflate.go | 478 +- libgo/go/compress/flate/deflate_test.go | 16 +- libgo/go/compress/flate/huffman_bit_writer.go | 94 +- libgo/go/compress/flate/huffman_code.go | 7 +- libgo/go/compress/flate/inflate.go | 249 +- libgo/go/compress/gzip/gunzip.go | 4 +- libgo/go/compress/gzip/gzip_test.go | 2 +- libgo/go/compress/lzw/reader.go | 226 +- libgo/go/compress/lzw/reader_test.go | 2 +- libgo/go/compress/lzw/writer_test.go | 8 +- libgo/go/compress/zlib/reader.go | 6 +- libgo/go/compress/zlib/writer.go | 2 +- libgo/go/compress/zlib/writer_test.go | 95 +- libgo/go/container/heap/heap.go | 8 +- libgo/go/container/heap/heap_test.go | 9 - libgo/go/container/ring/ring.go | 9 - libgo/go/container/ring/ring_test.go | 10 - libgo/go/container/vector/defs.go | 8 - libgo/go/container/vector/intvector.go | 20 - libgo/go/container/vector/intvector_test.go | 13 - libgo/go/container/vector/nogen_test.go | 9 - libgo/go/container/vector/numbers_test.go | 8 - libgo/go/container/vector/stringvector.go | 20 - libgo/go/container/vector/stringvector_test.go | 13 - libgo/go/container/vector/vector.go | 20 - libgo/go/container/vector/vector_test.go | 13 - libgo/go/crypto/aes/cipher.go | 4 +- libgo/go/crypto/blowfish/cipher.go | 4 +- libgo/go/crypto/cast5/cast5.go | 2 +- libgo/go/crypto/cipher/ocfb.go | 8 +- libgo/go/crypto/dsa/dsa.go | 4 +- libgo/go/crypto/elliptic/elliptic.go | 2 +- libgo/go/crypto/elliptic/elliptic_test.go | 4 +- libgo/go/crypto/hmac/hmac_test.go | 2 +- libgo/go/crypto/ocsp/ocsp.go | 38 +- libgo/go/crypto/openpgp/armor/armor.go | 2 +- libgo/go/crypto/openpgp/canonical_text_test.go | 1 - libgo/go/crypto/openpgp/elgamal/elgamal.go | 122 + libgo/go/crypto/openpgp/elgamal/elgamal_test.go | 49 + libgo/go/crypto/openpgp/keys.go | 248 +- libgo/go/crypto/openpgp/packet/encrypted_key.go | 132 +- .../go/crypto/openpgp/packet/encrypted_key_test.go | 85 +- libgo/go/crypto/openpgp/packet/literal.go | 37 + .../go/crypto/openpgp/packet/one_pass_signature.go | 27 +- libgo/go/crypto/openpgp/packet/packet.go | 110 +- libgo/go/crypto/openpgp/packet/packet_test.go | 44 + libgo/go/crypto/openpgp/packet/private_key.go | 108 +- libgo/go/crypto/openpgp/packet/private_key_test.go | 64 +- libgo/go/crypto/openpgp/packet/public_key.go | 154 +- libgo/go/crypto/openpgp/packet/public_key_test.go | 36 +- libgo/go/crypto/openpgp/packet/signature.go | 110 +- libgo/go/crypto/openpgp/packet/signature_test.go | 22 +- .../openpgp/packet/symmetric_key_encrypted.go | 66 +- .../openpgp/packet/symmetric_key_encrypted_test.go | 39 + .../openpgp/packet/symmetrically_encrypted.go | 95 +- .../openpgp/packet/symmetrically_encrypted_test.go | 46 + libgo/go/crypto/openpgp/packet/userid.go | 56 + libgo/go/crypto/openpgp/packet/userid_test.go | 45 + libgo/go/crypto/openpgp/read.go | 24 +- libgo/go/crypto/openpgp/read_test.go | 125 +- libgo/go/crypto/openpgp/s2k/s2k.go | 22 +- libgo/go/crypto/openpgp/s2k/s2k_test.go | 25 +- libgo/go/crypto/openpgp/write.go | 236 +- libgo/go/crypto/openpgp/write_test.go | 187 + libgo/go/crypto/rand/rand_windows.go | 2 +- libgo/go/crypto/rand/util.go | 80 + libgo/go/crypto/rsa/pkcs1v15.go | 4 +- libgo/go/crypto/rsa/rsa.go | 100 +- libgo/go/crypto/subtle/constant_time_test.go | 4 +- libgo/go/crypto/tls/common.go | 2 +- libgo/go/crypto/tls/conn.go | 10 +- libgo/go/crypto/tls/generate_cert.go | 10 +- libgo/go/crypto/tls/handshake_client.go | 6 +- libgo/go/crypto/tls/handshake_server.go | 10 +- libgo/go/crypto/tls/handshake_server_test.go | 1 - libgo/go/crypto/tls/key_agreement.go | 42 +- libgo/go/crypto/tls/tls.go | 8 +- libgo/go/crypto/twofish/twofish.go | 4 +- libgo/go/crypto/x509/cert_pool.go | 3 +- libgo/go/crypto/x509/pkix/pkix.go | 167 + libgo/go/crypto/x509/verify.go | 11 +- libgo/go/crypto/x509/verify_test.go | 13 +- libgo/go/crypto/x509/x509.go | 552 +- libgo/go/crypto/x509/x509_test.go | 188 +- libgo/go/crypto/xtea/block.go | 2 +- libgo/go/crypto/xtea/cipher.go | 4 +- libgo/go/crypto/xtea/xtea_test.go | 10 +- libgo/go/csv/reader.go | 372 + libgo/go/csv/reader_test.go | 265 + libgo/go/csv/writer.go | 122 + libgo/go/csv/writer_test.go | 44 + libgo/go/debug/dwarf/type.go | 17 +- libgo/go/debug/dwarf/type_test.go | 1 - libgo/go/debug/elf/elf.go | 2 - libgo/go/debug/elf/file.go | 81 +- libgo/go/debug/elf/file_test.go | 70 +- .../testdata/go-relocation-test-gcc424-x86-64.o | Bin 3088 -> 0 bytes .../testdata/go-relocation-test-gcc424-x86-64.obj | Bin 0 -> 3088 bytes .../testdata/go-relocation-test-gcc441-x86-64.o | Bin 2936 -> 0 bytes .../testdata/go-relocation-test-gcc441-x86-64.obj | Bin 0 -> 2936 bytes .../elf/testdata/go-relocation-test-gcc441-x86.o | Bin 1884 -> 0 bytes .../elf/testdata/go-relocation-test-gcc441-x86.obj | Bin 0 -> 1884 bytes libgo/go/debug/macho/file.go | 2 +- libgo/go/debug/pe/file.go | 41 +- libgo/go/debug/proc/proc.go | 222 - libgo/go/debug/proc/proc_darwin.go | 17 - libgo/go/debug/proc/proc_freebsd.go | 17 - libgo/go/debug/proc/proc_linux.go | 1322 --- libgo/go/debug/proc/proc_windows.go | 17 - libgo/go/debug/proc/regs_darwin_386.go | 5 - libgo/go/debug/proc/regs_darwin_amd64.go | 5 - libgo/go/debug/proc/regs_freebsd_386.go | 5 - libgo/go/debug/proc/regs_freebsd_amd64.go | 5 - libgo/go/debug/proc/regs_linux_386.go | 143 - libgo/go/debug/proc/regs_linux_amd64.go | 191 - libgo/go/debug/proc/regs_linux_arm.go | 39 - libgo/go/debug/proc/regs_windows_386.go | 5 - libgo/go/debug/proc/regs_windows_amd64.go | 5 - libgo/go/ebnf/ebnf.go | 21 +- libgo/go/ebnf/ebnf_test.go | 35 +- libgo/go/ebnf/parser.go | 37 +- libgo/go/encoding/base32/base32_test.go | 1 - libgo/go/encoding/base64/base64.go | 14 + libgo/go/encoding/base64/base64_test.go | 9 +- libgo/go/encoding/binary/binary.go | 102 + libgo/go/encoding/binary/binary_test.go | 73 + libgo/go/encoding/git85/git.go | 2 +- libgo/go/encoding/hex/hex.go | 117 +- libgo/go/encoding/hex/hex_test.go | 43 + libgo/go/encoding/line/line.go | 115 - libgo/go/encoding/line/line_test.go | 133 - libgo/go/encoding/pem/pem.go | 17 +- libgo/go/exec/exec.go | 471 +- libgo/go/exec/exec_test.go | 283 +- libgo/go/exec/lp_plan9.go | 51 + libgo/go/exec/lp_test.go | 6 +- libgo/go/exec/lp_unix.go | 23 +- libgo/go/exec/lp_windows.go | 59 +- libgo/go/exp/datafmt/datafmt.go | 27 +- libgo/go/exp/datafmt/datafmt_test.go | 21 - libgo/go/exp/datafmt/parser.go | 58 +- libgo/go/exp/draw/draw.go | 476 - libgo/go/exp/draw/draw_test.go | 278 - libgo/go/exp/draw/event.go | 56 - libgo/go/exp/draw/x11/auth.go | 93 - libgo/go/exp/draw/x11/conn.go | 625 -- libgo/go/exp/eval/abort.go | 85 - libgo/go/exp/eval/bridge.go | 164 - libgo/go/exp/eval/compiler.go | 92 - libgo/go/exp/eval/eval_test.go | 263 - libgo/go/exp/eval/expr.go | 2015 ----- libgo/go/exp/eval/expr1.go | 1874 ---- libgo/go/exp/eval/expr_test.go | 355 - libgo/go/exp/eval/func.go | 70 - libgo/go/exp/eval/scope.go | 207 - libgo/go/exp/eval/stmt.go | 1299 --- libgo/go/exp/eval/stmt_test.go | 343 - libgo/go/exp/eval/type.go | 1252 --- libgo/go/exp/eval/typec.go | 409 - libgo/go/exp/eval/value.go | 586 -- libgo/go/exp/eval/world.go | 188 - libgo/go/exp/gui/gui.go | 58 + libgo/go/exp/gui/x11/auth.go | 93 + libgo/go/exp/gui/x11/conn.go | 627 ++ libgo/go/exp/norm/composition.go | 344 + libgo/go/exp/norm/composition_test.go | 138 + libgo/go/exp/norm/forminfo.go | 188 + libgo/go/exp/norm/maketables.go | 855 ++ libgo/go/exp/norm/maketesttables.go | 42 + libgo/go/exp/norm/norm_test.go | 14 + libgo/go/exp/norm/normalize.go | 99 + libgo/go/exp/norm/tables.go | 6580 ++++++++++++++ libgo/go/exp/norm/trie.go | 234 + libgo/go/exp/norm/trie_test.go | 107 + libgo/go/exp/norm/triedata_test.go | 63 + libgo/go/exp/norm/triegen.go | 211 + libgo/go/exp/ogle/abort.go | 35 - libgo/go/exp/ogle/arch.go | 125 - libgo/go/exp/ogle/cmd.go | 373 - libgo/go/exp/ogle/event.go | 280 - libgo/go/exp/ogle/frame.go | 212 - libgo/go/exp/ogle/goroutine.go | 117 - libgo/go/exp/ogle/main.go | 9 - libgo/go/exp/ogle/process.go | 521 -- libgo/go/exp/ogle/rruntime.go | 271 - libgo/go/exp/ogle/rtype.go | 288 - libgo/go/exp/ogle/rvalue.go | 515 -- libgo/go/exp/ogle/vars.go | 272 - libgo/go/exp/regexp/all_test.go | 429 + libgo/go/exp/regexp/exec.go | 295 + libgo/go/exp/regexp/find_test.go | 472 + libgo/go/exp/regexp/regexp.go | 795 ++ libgo/go/exp/regexp/syntax/compile.go | 269 + libgo/go/exp/regexp/syntax/parse.go | 1797 ++++ libgo/go/exp/regexp/syntax/parse_test.go | 350 + libgo/go/exp/regexp/syntax/perl_groups.go | 130 + libgo/go/exp/regexp/syntax/prog.go | 237 + libgo/go/exp/regexp/syntax/prog_test.go | 91 + libgo/go/exp/regexp/syntax/regexp.go | 284 + libgo/go/exp/regexp/syntax/simplify.go | 151 + libgo/go/exp/regexp/syntax/simplify_test.go | 151 + libgo/go/exp/template/html/context.go | 98 + libgo/go/exp/template/html/escape.go | 105 + libgo/go/exp/template/html/escape_test.go | 75 + libgo/go/exp/wingui/winapi.go | 23 +- libgo/go/exp/wingui/zwinapi.go | 70 +- libgo/go/expvar/expvar.go | 1 - libgo/go/expvar/expvar_test.go | 30 +- libgo/go/flag/export_test.go | 22 +- libgo/go/flag/flag.go | 416 +- libgo/go/flag/flag_test.go | 102 +- libgo/go/fmt/doc.go | 17 +- libgo/go/fmt/fmt_test.go | 95 +- libgo/go/fmt/format.go | 44 +- libgo/go/fmt/print.go | 103 +- libgo/go/fmt/scan.go | 70 +- libgo/go/fmt/scan_test.go | 68 +- libgo/go/go/ast/ast.go | 66 +- libgo/go/go/ast/filter.go | 130 +- libgo/go/go/ast/print.go | 9 - libgo/go/go/ast/print_test.go | 5 +- libgo/go/go/ast/resolve.go | 90 +- libgo/go/go/ast/scope.go | 22 +- libgo/go/go/ast/walk.go | 7 - libgo/go/go/build/build.go | 444 + libgo/go/go/build/build_test.go | 61 + libgo/go/go/build/cgotest/cgotest.go | 19 + libgo/go/go/build/cmdtest/main.go | 12 + libgo/go/go/build/dir.go | 172 + libgo/go/go/build/path.go | 182 + libgo/go/go/build/pkgtest/pkgtest.go | 9 + libgo/go/go/build/syslist_test.go | 62 + libgo/go/go/doc/comment.go | 16 +- libgo/go/go/doc/doc.go | 55 +- libgo/go/go/parser/interface.go | 37 +- libgo/go/go/parser/parser.go | 283 +- libgo/go/go/parser/parser_test.go | 28 +- libgo/go/go/printer/nodes.go | 240 +- libgo/go/go/printer/performance_test.go | 4 - libgo/go/go/printer/printer.go | 57 +- libgo/go/go/printer/printer_test.go | 10 - libgo/go/go/printer/testdata/comments.golden | 20 +- libgo/go/go/printer/testdata/comments.input | 2 +- libgo/go/go/printer/testdata/comments.x | 11 +- libgo/go/go/printer/testdata/declarations.golden | 61 +- libgo/go/go/printer/testdata/declarations.input | 29 +- libgo/go/go/printer/testdata/expressions.golden | 25 +- libgo/go/go/printer/testdata/expressions.raw | 25 +- libgo/go/go/printer/testdata/parser.go | 99 - libgo/go/go/printer/testdata/statements.golden | 31 +- libgo/go/go/printer/testdata/statements.input | 13 + libgo/go/go/scanner/errors.go | 34 +- libgo/go/go/scanner/scanner.go | 59 +- libgo/go/go/scanner/scanner_test.go | 44 +- libgo/go/go/token/position.go | 35 +- libgo/go/go/token/position_test.go | 9 - libgo/go/go/token/token.go | 8 - libgo/go/go/typechecker/scope.go | 6 - libgo/go/go/typechecker/type.go | 7 - libgo/go/go/typechecker/typechecker.go | 20 - libgo/go/go/typechecker/typechecker_test.go | 5 - libgo/go/go/typechecker/universe.go | 2 - libgo/go/go/types/check.go | 226 + libgo/go/go/types/check_test.go | 215 + libgo/go/go/types/const.go | 15 - libgo/go/go/types/exportdata.go | 11 +- libgo/go/go/types/gcimporter.go | 273 +- libgo/go/go/types/gcimporter_test.go | 28 +- libgo/go/go/types/testdata/exports.go | 23 +- libgo/go/go/types/types.go | 177 +- libgo/go/go/types/universe.go | 23 +- libgo/go/gob/codec_test.go | 53 +- libgo/go/gob/decode.go | 46 +- libgo/go/gob/decoder.go | 12 +- libgo/go/gob/doc.go | 39 +- libgo/go/gob/encode.go | 47 +- libgo/go/gob/encoder.go | 2 +- libgo/go/gob/encoder_test.go | 29 + libgo/go/gob/gobencdec_test.go | 32 +- libgo/go/gob/timing_test.go | 4 + libgo/go/gob/type.go | 33 +- libgo/go/hash/crc32/crc32.go | 37 +- libgo/go/hash/crc32/crc32_amd64.go | 25 + libgo/go/hash/crc32/crc32_generic.go | 12 + libgo/go/hash/crc32/crc32_test.go | 103 +- libgo/go/hash/fnv/fnv.go | 17 +- libgo/go/html/const.go | 90 + libgo/go/html/doc.go | 1 + libgo/go/html/entity.go | 3 + libgo/go/html/entity_test.go | 3 + libgo/go/html/escape.go | 28 +- libgo/go/html/node.go | 147 + libgo/go/html/parse.go | 312 +- libgo/go/html/parse_test.go | 6 +- libgo/go/html/testdata/webkit/comments01.dat | 17 +- libgo/go/html/testdata/webkit/doctype01.dat | 63 +- libgo/go/html/testdata/webkit/dom2string.js | 135 - libgo/go/html/testdata/webkit/entities01.dat | 9 - libgo/go/html/testdata/webkit/entities02.dat | 120 + libgo/go/html/testdata/webkit/tests1.dat | 59 +- libgo/go/html/testdata/webkit/tests10.dat | 369 + libgo/go/html/testdata/webkit/tests13.dat | 9 - libgo/go/html/testdata/webkit/tests14.dat | 2 +- libgo/go/html/testdata/webkit/tests15.dat | 2 +- libgo/go/html/testdata/webkit/tests2.dat | 27 +- libgo/go/html/testdata/webkit/tests3.dat | 12 + libgo/go/html/testdata/webkit/tests6.dat | 10 + libgo/go/html/testdata/webkit/tests9.dat | 27 + libgo/go/html/testdata/webkit/webkit01.dat | 460 +- libgo/go/html/token.go | 336 +- libgo/go/html/token_test.go | 87 +- libgo/go/http/cgi/child.go | 16 +- libgo/go/http/cgi/child_test.go | 8 +- libgo/go/http/cgi/host.go | 88 +- libgo/go/http/cgi/host_test.go | 173 +- libgo/go/http/chunked.go | 25 +- libgo/go/http/client.go | 172 +- libgo/go/http/client_test.go | 178 +- libgo/go/http/cookie.go | 161 +- libgo/go/http/cookie_test.go | 163 +- libgo/go/http/fs.go | 99 +- libgo/go/http/fs_test.go | 178 +- libgo/go/http/header.go | 5 +- libgo/go/http/header_test.go | 10 + libgo/go/http/httptest/server.go | 55 +- libgo/go/http/persist.go | 19 +- libgo/go/http/proxy_test.go | 4 +- libgo/go/http/readrequest_test.go | 85 +- libgo/go/http/request.go | 263 +- libgo/go/http/request_test.go | 40 +- libgo/go/http/requestwrite_test.go | 156 +- libgo/go/http/response.go | 45 +- libgo/go/http/response_test.go | 62 +- libgo/go/http/responsewrite_test.go | 14 +- libgo/go/http/reverseproxy.go | 63 +- libgo/go/http/reverseproxy_test.go | 20 +- libgo/go/http/serve_test.go | 332 +- libgo/go/http/server.go | 273 +- libgo/go/http/sniff.go | 214 + libgo/go/http/sniff_test.go | 80 + libgo/go/http/spdy/protocol.go | 367 - libgo/go/http/spdy/protocol_test.go | 259 - libgo/go/http/spdy/read.go | 313 + libgo/go/http/spdy/spdy_test.go | 497 ++ libgo/go/http/spdy/types.go | 370 + libgo/go/http/spdy/write.go | 286 + libgo/go/http/testdata/index.html | 1 + libgo/go/http/testdata/style.css | 1 + libgo/go/http/transfer.go | 64 +- libgo/go/http/transport.go | 247 +- libgo/go/http/transport_test.go | 149 +- libgo/go/http/url.go | 595 -- libgo/go/http/url_test.go | 675 -- libgo/go/image/bmp/reader.go | 151 + libgo/go/image/color.go | 24 +- libgo/go/image/decode_test.go | 68 +- libgo/go/image/draw/bench_test.go | 206 + libgo/go/image/draw/clip_test.go | 193 + libgo/go/image/draw/draw.go | 493 ++ libgo/go/image/draw/draw_test.go | 354 + libgo/go/image/geom.go | 19 +- libgo/go/image/gif/reader.go | 112 +- libgo/go/image/image.go | 554 +- libgo/go/image/image_test.go | 113 + libgo/go/image/jpeg/idct.go | 124 +- libgo/go/image/jpeg/reader.go | 237 +- libgo/go/image/jpeg/writer.go | 36 +- libgo/go/image/png/writer.go | 90 +- libgo/go/image/png/writer_test.go | 73 +- libgo/go/image/testdata/video-001.5bpp.gif | Bin 0 -> 6214 bytes libgo/go/image/testdata/video-001.interlaced.gif | Bin 0 -> 14142 bytes libgo/go/image/testdata/video-005.gray.jpeg | Bin 0 -> 5618 bytes libgo/go/image/testdata/video-005.gray.png | Bin 0 -> 14974 bytes libgo/go/image/tiff/consts.go | 1 + libgo/go/image/tiff/reader.go | 132 +- libgo/go/image/tiff/reader_test.go | 25 + libgo/go/image/tiff/testdata/no_rps.tiff | Bin 0 -> 1294 bytes libgo/go/image/ycbcr/ycbcr.go | 11 +- libgo/go/index/suffixarray/qsufsort.go | 4 - libgo/go/index/suffixarray/suffixarray.go | 11 +- libgo/go/index/suffixarray/suffixarray_test.go | 18 +- libgo/go/io/io.go | 117 +- libgo/go/io/ioutil/ioutil.go | 19 +- libgo/go/io/ioutil/ioutil_test.go | 1 - libgo/go/io/multi_test.go | 5 +- libgo/go/json/decode.go | 15 +- libgo/go/json/decode_test.go | 34 +- libgo/go/json/encode.go | 91 +- libgo/go/json/encode_test.go | 44 + libgo/go/json/scanner_test.go | 2 +- libgo/go/json/tagkey_test.go | 95 + libgo/go/log/log.go | 20 +- libgo/go/mail/message.go | 524 ++ libgo/go/mail/message_test.go | 278 + libgo/go/math/acosh.go | 1 - libgo/go/math/asin.go | 1 - libgo/go/math/asinh.go | 1 - libgo/go/math/atanh.go | 1 - libgo/go/math/erf.go | 1 - libgo/go/math/exp_port.go | 1 - libgo/go/math/expm1.go | 1 - libgo/go/math/floor.go | 1 - libgo/go/math/fmod.go | 1 - libgo/go/math/log.go | 2 +- libgo/go/math/log1p.go | 1 - libgo/go/math/sin.go | 1 - libgo/go/math/sinh.go | 1 - libgo/go/math/sqrt_port.go | 6 +- libgo/go/math/tan.go | 1 - libgo/go/math/tanh.go | 1 - libgo/go/mime/grammar.go | 4 +- libgo/go/mime/mediatype.go | 15 +- libgo/go/mime/mediatype_test.go | 3 +- libgo/go/mime/multipart/formdata.go | 2 +- libgo/go/mime/multipart/formdata_test.go | 4 +- libgo/go/mime/multipart/multipart.go | 90 +- libgo/go/mime/multipart/multipart_test.go | 97 +- libgo/go/mime/multipart/writer.go | 157 + libgo/go/mime/multipart/writer_test.go | 78 + libgo/go/mime/type.go | 2 +- libgo/go/net/dial.go | 93 +- libgo/go/net/dialgoogle_test.go | 8 +- libgo/go/net/dict/dict.go | 7 +- libgo/go/net/dnsclient.go | 398 +- libgo/go/net/dnsclient_unix.go | 261 + libgo/go/net/dnsconfig.go | 1 - libgo/go/net/dnsmsg.go | 56 +- libgo/go/net/dnsmsg_test.go | 7 - libgo/go/net/dnsname_test.go | 4 - libgo/go/net/fd.go | 14 +- libgo/go/net/fd_linux.go | 11 + libgo/go/net/fd_openbsd.go | 116 + libgo/go/net/fd_windows.go | 65 +- libgo/go/net/file_plan9.go | 33 + libgo/go/net/file_test.go | 10 +- libgo/go/net/hosts_test.go | 2 +- libgo/go/net/interface.go | 132 + libgo/go/net/interface_bsd.go | 171 + libgo/go/net/interface_darwin.go | 80 + libgo/go/net/interface_freebsd.go | 80 + libgo/go/net/interface_linux.go | 262 + libgo/go/net/interface_openbsd.go | 16 + libgo/go/net/interface_stub.go | 30 + libgo/go/net/interface_test.go | 73 + libgo/go/net/interface_windows.go | 158 + libgo/go/net/ip.go | 65 +- libgo/go/net/ip_test.go | 112 +- libgo/go/net/ipraw_test.go | 9 +- libgo/go/net/iprawsock.go | 317 +- libgo/go/net/iprawsock_plan9.go | 99 + libgo/go/net/iprawsock_posix.go | 305 + libgo/go/net/ipsock.go | 202 +- libgo/go/net/ipsock_plan9.go | 305 + libgo/go/net/ipsock_posix.go | 174 + libgo/go/net/lookup.go | 50 - libgo/go/net/lookup_plan9.go | 226 + libgo/go/net/lookup_test.go | 57 + libgo/go/net/lookup_unix.go | 111 + libgo/go/net/lookup_windows.go | 130 + libgo/go/net/net.go | 2 +- libgo/go/net/net_test.go | 4 - libgo/go/net/newpollserver.go | 14 +- libgo/go/net/parse_test.go | 4 +- libgo/go/net/resolv_windows.go | 141 - libgo/go/net/sendfile_linux.go | 84 + libgo/go/net/sendfile_stub.go | 14 + libgo/go/net/sendfile_windows.go | 68 + libgo/go/net/server_test.go | 48 +- libgo/go/net/sock.go | 42 +- libgo/go/net/sock_windows.go | 2 +- libgo/go/net/srv_test.go | 29 - libgo/go/net/tcpsock.go | 262 +- libgo/go/net/tcpsock_plan9.go | 63 + libgo/go/net/tcpsock_posix.go | 283 + libgo/go/net/textproto/reader.go | 64 +- libgo/go/net/udpsock.go | 290 +- libgo/go/net/udpsock_plan9.go | 187 + libgo/go/net/udpsock_posix.go | 294 + libgo/go/net/unixsock.go | 399 - libgo/go/net/unixsock_plan9.go | 105 + libgo/go/net/unixsock_posix.go | 418 + libgo/go/netchan/common.go | 4 +- libgo/go/netchan/export.go | 12 +- libgo/go/netchan/import.go | 51 +- libgo/go/netchan/netchan_test.go | 10 + libgo/go/old/template/doc.go | 91 + libgo/go/old/template/execute.go | 346 + libgo/go/old/template/format.go | 77 + libgo/go/old/template/parse.go | 743 ++ libgo/go/old/template/template_test.go | 804 ++ libgo/go/os/dir.go | 31 +- libgo/go/os/dir_plan9.go | 82 +- libgo/go/os/dir_unix.go | 45 +- libgo/go/os/env_plan9.go | 15 +- libgo/go/os/env_unix.go | 1 - libgo/go/os/env_windows.go | 2 +- libgo/go/os/error.go | 13 +- libgo/go/os/error_plan9.go | 1 + libgo/go/os/error_posix.go | 2 +- libgo/go/os/exec.go | 14 +- libgo/go/os/exec_plan9.go | 45 +- libgo/go/os/exec_posix.go | 44 +- libgo/go/os/exec_unix.go | 14 + libgo/go/os/exec_windows.go | 22 +- libgo/go/os/file.go | 30 +- libgo/go/os/file_plan9.go | 108 +- libgo/go/os/file_posix.go | 22 - libgo/go/os/file_unix.go | 69 +- libgo/go/os/inotify/inotify_linux.go | 7 - libgo/go/os/inotify/inotify_linux_test.go | 1 - libgo/go/os/mkunixsignals.sh | 24 + libgo/go/os/os_test.go | 147 +- libgo/go/os/path.go | 10 +- libgo/go/os/path_plan9.go | 15 + libgo/go/os/path_test.go | 26 +- libgo/go/os/path_unix.go | 15 + libgo/go/os/path_windows.go | 16 + libgo/go/os/proc.go | 1 - libgo/go/os/signal/mkunix.sh | 24 - libgo/go/os/signal/signal.go | 25 +- libgo/go/os/signal/signal_test.go | 5 +- libgo/go/os/stat_openbsd.go | 32 + libgo/go/os/stat_plan9.go | 18 +- libgo/go/os/str.go | 20 + libgo/go/os/sys_linux.go | 1 - libgo/go/os/sys_plan9.go | 1 - libgo/go/os/time.go | 1 - libgo/go/os/types.go | 2 +- libgo/go/os/user/lookup_unix.go | 4 + libgo/go/os/user/user.go | 2 + libgo/go/os/user/user_test.go | 8 +- libgo/go/patch/patch.go | 2 +- libgo/go/patch/textdiff.go | 10 +- libgo/go/path/filepath/match.go | 9 +- libgo/go/path/filepath/match_test.go | 9 +- libgo/go/path/filepath/path.go | 59 +- libgo/go/path/filepath/path_plan9.go | 19 +- libgo/go/path/filepath/path_test.go | 115 +- libgo/go/path/filepath/path_unix.go | 19 +- libgo/go/path/filepath/path_windows.go | 45 +- libgo/go/rand/rand_test.go | 8 +- libgo/go/reflect/all_test.go | 86 +- libgo/go/reflect/type.go | 148 +- libgo/go/reflect/value.go | 68 +- libgo/go/regexp/all_test.go | 2 +- libgo/go/regexp/regexp.go | 21 +- libgo/go/rpc/client.go | 11 +- libgo/go/rpc/debug.go | 20 +- libgo/go/rpc/jsonrpc/all_test.go | 8 +- libgo/go/rpc/jsonrpc/client.go | 12 +- libgo/go/rpc/jsonrpc/server.go | 12 +- libgo/go/rpc/server.go | 131 +- libgo/go/rpc/server_test.go | 91 +- libgo/go/runtime/append_test.go | 52 + libgo/go/runtime/chan_test.go | 322 + libgo/go/runtime/closure_test.go | 53 + libgo/go/runtime/debug/stack.go | 2 +- libgo/go/runtime/debug/stack_test.go | 6 +- libgo/go/runtime/error.go | 5 + libgo/go/runtime/export_test.go | 10 + libgo/go/runtime/mem.go | 9 +- libgo/go/runtime/pprof/pprof_test.go | 2 +- libgo/go/runtime/proc_test.go | 92 +- libgo/go/runtime/sema_test.go | 100 + libgo/go/runtime/softfloat64.go | 4 +- libgo/go/runtime/symtab_test.go | 55 + libgo/go/scanner/scanner.go | 35 +- libgo/go/scanner/scanner_test.go | 70 +- libgo/go/smtp/smtp.go | 9 +- libgo/go/smtp/smtp_test.go | 4 +- libgo/go/sort/search.go | 22 +- libgo/go/sort/search_test.go | 21 +- libgo/go/sort/sort.go | 74 +- libgo/go/sort/sort_test.go | 56 +- libgo/go/strconv/atob.go | 4 +- libgo/go/strconv/atob_test.go | 2 + libgo/go/strconv/atof.go | 10 +- libgo/go/strconv/atof_test.go | 3 + libgo/go/strconv/atoi.go | 8 +- libgo/go/strconv/decimal.go | 2 +- libgo/go/strconv/fp_test.go | 6 +- libgo/go/strconv/quote.go | 128 +- libgo/go/strconv/quote_test.go | 81 +- libgo/go/strings/reader.go | 74 +- libgo/go/strings/strings.go | 27 +- libgo/go/strings/strings_test.go | 89 +- libgo/go/sync/atomic/atomic.c | 28 + libgo/go/sync/atomic/atomic_test.go | 102 + libgo/go/sync/atomic/doc.go | 6 + libgo/go/sync/cond.go | 69 +- libgo/go/sync/cond_test.go | 27 + libgo/go/sync/mutex.go | 63 +- libgo/go/sync/mutex_test.go | 102 +- libgo/go/sync/once.go | 14 +- libgo/go/sync/once_test.go | 25 + libgo/go/sync/rwmutex.go | 67 +- libgo/go/sync/rwmutex_test.go | 83 + libgo/go/sync/waitgroup.go | 41 +- libgo/go/sync/waitgroup_test.go | 105 + libgo/go/syslog/syslog_unix.go | 2 +- libgo/go/tabwriter/tabwriter.go | 27 +- libgo/go/tabwriter/tabwriter_test.go | 10 - libgo/go/template/doc.go | 313 + libgo/go/template/exec.go | 674 ++ libgo/go/template/exec_test.go | 613 ++ libgo/go/template/format.go | 77 - libgo/go/template/funcs.go | 368 + libgo/go/template/helper.go | 238 + libgo/go/template/parse.go | 85 + libgo/go/template/parse/lex.go | 472 + libgo/go/template/parse/lex_test.go | 223 + libgo/go/template/parse/node.go | 470 + libgo/go/template/parse/parse.go | 436 + libgo/go/template/parse/parse_test.go | 259 + libgo/go/template/parse/set.go | 50 + libgo/go/template/set.go | 108 + libgo/go/template/set_test.go | 239 + libgo/go/template/template.go | 1044 --- libgo/go/template/template_test.go | 763 -- libgo/go/template/testdata/file1.tmpl | 2 + libgo/go/template/testdata/file2.tmpl | 2 + libgo/go/template/testdata/tmpl1.tmpl | 1 + libgo/go/template/testdata/tmpl2.tmpl | 1 + libgo/go/testing/benchmark.go | 67 +- libgo/go/testing/iotest/reader.go | 22 +- libgo/go/testing/testing.go | 67 +- libgo/go/time/format.go | 140 +- libgo/go/time/sleep.go | 2 +- libgo/go/time/sleep_test.go | 2 +- libgo/go/time/sys.go | 13 +- libgo/go/time/sys_plan9.go | 18 + libgo/go/time/sys_posix.go | 18 + libgo/go/time/tick.go | 4 +- libgo/go/time/time.go | 30 +- libgo/go/time/time_test.go | 255 +- libgo/go/time/zoneinfo_plan9.go | 59 + libgo/go/time/zoneinfo_posix.go | 62 + libgo/go/time/zoneinfo_unix.go | 58 - libgo/go/time/zoneinfo_windows.go | 12 +- libgo/go/unicode/casetables.go | 1 - libgo/go/unicode/digit.go | 2 +- libgo/go/unicode/digit_test.go | 2 +- libgo/go/unicode/graphic.go | 132 + libgo/go/unicode/graphic_test.go | 122 + libgo/go/unicode/letter.go | 186 +- libgo/go/unicode/letter_test.go | 52 +- libgo/go/unicode/script_test.go | 17 +- libgo/go/unicode/tables.go | 9275 ++++++++++++-------- libgo/go/url/url.go | 677 ++ libgo/go/url/url_test.go | 698 ++ libgo/go/utf8/utf8.go | 120 +- libgo/go/websocket/client.go | 44 +- libgo/go/websocket/server.go | 3 +- libgo/go/websocket/websocket.go | 2 +- libgo/go/websocket/websocket_test.go | 9 +- libgo/go/xml/atom_test.go | 50 + libgo/go/xml/embed_test.go | 10 +- libgo/go/xml/marshal.go | 228 + libgo/go/xml/marshal_test.go | 305 + libgo/go/xml/read.go | 128 +- libgo/go/xml/read_test.go | 78 +- libgo/go/xml/xml.go | 636 +- libgo/go/xml/xml_test.go | 29 +- 696 files changed, 60652 insertions(+), 33606 deletions(-) create mode 100644 libgo/go/archive/zip/writer.go create mode 100644 libgo/go/archive/zip/writer_test.go create mode 100644 libgo/go/archive/zip/zip_test.go create mode 100644 libgo/go/builtin/builtin.go create mode 100644 libgo/go/crypto/openpgp/elgamal/elgamal.go create mode 100644 libgo/go/crypto/openpgp/elgamal/elgamal_test.go create mode 100644 libgo/go/crypto/rand/util.go create mode 100644 libgo/go/crypto/x509/pkix/pkix.go create mode 100644 libgo/go/csv/reader.go create mode 100644 libgo/go/csv/reader_test.go create mode 100644 libgo/go/csv/writer.go create mode 100644 libgo/go/csv/writer_test.go delete mode 100644 libgo/go/debug/elf/testdata/go-relocation-test-gcc424-x86-64.o create mode 100644 libgo/go/debug/elf/testdata/go-relocation-test-gcc424-x86-64.obj delete mode 100644 libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86-64.o create mode 100644 libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86-64.obj delete mode 100644 libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86.o create mode 100644 libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86.obj delete mode 100644 libgo/go/debug/proc/proc.go delete mode 100644 libgo/go/debug/proc/proc_darwin.go delete mode 100644 libgo/go/debug/proc/proc_freebsd.go delete mode 100644 libgo/go/debug/proc/proc_linux.go delete mode 100644 libgo/go/debug/proc/proc_windows.go delete mode 100644 libgo/go/debug/proc/regs_darwin_386.go delete mode 100644 libgo/go/debug/proc/regs_darwin_amd64.go delete mode 100644 libgo/go/debug/proc/regs_freebsd_386.go delete mode 100644 libgo/go/debug/proc/regs_freebsd_amd64.go delete mode 100644 libgo/go/debug/proc/regs_linux_386.go delete mode 100644 libgo/go/debug/proc/regs_linux_amd64.go delete mode 100644 libgo/go/debug/proc/regs_linux_arm.go delete mode 100644 libgo/go/debug/proc/regs_windows_386.go delete mode 100644 libgo/go/debug/proc/regs_windows_amd64.go delete mode 100644 libgo/go/encoding/line/line.go delete mode 100644 libgo/go/encoding/line/line_test.go create mode 100644 libgo/go/exec/lp_plan9.go delete mode 100644 libgo/go/exp/draw/draw.go delete mode 100644 libgo/go/exp/draw/draw_test.go delete mode 100644 libgo/go/exp/draw/event.go delete mode 100644 libgo/go/exp/draw/x11/auth.go delete mode 100644 libgo/go/exp/draw/x11/conn.go delete mode 100644 libgo/go/exp/eval/abort.go delete mode 100644 libgo/go/exp/eval/bridge.go delete mode 100644 libgo/go/exp/eval/compiler.go delete mode 100644 libgo/go/exp/eval/eval_test.go delete mode 100644 libgo/go/exp/eval/expr.go delete mode 100644 libgo/go/exp/eval/expr1.go delete mode 100644 libgo/go/exp/eval/expr_test.go delete mode 100644 libgo/go/exp/eval/func.go delete mode 100644 libgo/go/exp/eval/scope.go delete mode 100644 libgo/go/exp/eval/stmt.go delete mode 100644 libgo/go/exp/eval/stmt_test.go delete mode 100644 libgo/go/exp/eval/type.go delete mode 100644 libgo/go/exp/eval/typec.go delete mode 100644 libgo/go/exp/eval/value.go delete mode 100644 libgo/go/exp/eval/world.go create mode 100644 libgo/go/exp/gui/gui.go create mode 100644 libgo/go/exp/gui/x11/auth.go create mode 100644 libgo/go/exp/gui/x11/conn.go create mode 100644 libgo/go/exp/norm/composition.go create mode 100644 libgo/go/exp/norm/composition_test.go create mode 100644 libgo/go/exp/norm/forminfo.go create mode 100644 libgo/go/exp/norm/maketables.go create mode 100644 libgo/go/exp/norm/maketesttables.go create mode 100644 libgo/go/exp/norm/norm_test.go create mode 100644 libgo/go/exp/norm/normalize.go create mode 100644 libgo/go/exp/norm/tables.go create mode 100644 libgo/go/exp/norm/trie.go create mode 100644 libgo/go/exp/norm/trie_test.go create mode 100644 libgo/go/exp/norm/triedata_test.go create mode 100644 libgo/go/exp/norm/triegen.go delete mode 100644 libgo/go/exp/ogle/abort.go delete mode 100644 libgo/go/exp/ogle/arch.go delete mode 100644 libgo/go/exp/ogle/cmd.go delete mode 100644 libgo/go/exp/ogle/event.go delete mode 100644 libgo/go/exp/ogle/frame.go delete mode 100644 libgo/go/exp/ogle/goroutine.go delete mode 100644 libgo/go/exp/ogle/main.go delete mode 100644 libgo/go/exp/ogle/process.go delete mode 100644 libgo/go/exp/ogle/rruntime.go delete mode 100644 libgo/go/exp/ogle/rtype.go delete mode 100644 libgo/go/exp/ogle/rvalue.go delete mode 100644 libgo/go/exp/ogle/vars.go create mode 100644 libgo/go/exp/regexp/all_test.go create mode 100644 libgo/go/exp/regexp/exec.go create mode 100644 libgo/go/exp/regexp/find_test.go create mode 100644 libgo/go/exp/regexp/regexp.go create mode 100644 libgo/go/exp/regexp/syntax/compile.go create mode 100644 libgo/go/exp/regexp/syntax/parse.go create mode 100644 libgo/go/exp/regexp/syntax/parse_test.go create mode 100644 libgo/go/exp/regexp/syntax/perl_groups.go create mode 100644 libgo/go/exp/regexp/syntax/prog.go create mode 100644 libgo/go/exp/regexp/syntax/prog_test.go create mode 100644 libgo/go/exp/regexp/syntax/regexp.go create mode 100644 libgo/go/exp/regexp/syntax/simplify.go create mode 100644 libgo/go/exp/regexp/syntax/simplify_test.go create mode 100644 libgo/go/exp/template/html/context.go create mode 100644 libgo/go/exp/template/html/escape.go create mode 100644 libgo/go/exp/template/html/escape_test.go create mode 100644 libgo/go/go/build/build.go create mode 100644 libgo/go/go/build/build_test.go create mode 100644 libgo/go/go/build/cgotest/cgotest.go create mode 100644 libgo/go/go/build/cmdtest/main.go create mode 100644 libgo/go/go/build/dir.go create mode 100644 libgo/go/go/build/path.go create mode 100644 libgo/go/go/build/pkgtest/pkgtest.go create mode 100644 libgo/go/go/build/syslist_test.go create mode 100644 libgo/go/go/types/check.go create mode 100644 libgo/go/go/types/check_test.go create mode 100644 libgo/go/hash/crc32/crc32_amd64.go create mode 100644 libgo/go/hash/crc32/crc32_generic.go create mode 100644 libgo/go/html/const.go create mode 100644 libgo/go/html/node.go delete mode 100644 libgo/go/html/testdata/webkit/dom2string.js delete mode 100644 libgo/go/html/testdata/webkit/tests13.dat create mode 100644 libgo/go/http/sniff.go create mode 100644 libgo/go/http/sniff_test.go delete mode 100644 libgo/go/http/spdy/protocol.go delete mode 100644 libgo/go/http/spdy/protocol_test.go create mode 100644 libgo/go/http/spdy/read.go create mode 100644 libgo/go/http/spdy/spdy_test.go create mode 100644 libgo/go/http/spdy/types.go create mode 100644 libgo/go/http/spdy/write.go create mode 100644 libgo/go/http/testdata/index.html create mode 100644 libgo/go/http/testdata/style.css delete mode 100644 libgo/go/http/url.go delete mode 100644 libgo/go/http/url_test.go create mode 100644 libgo/go/image/bmp/reader.go create mode 100644 libgo/go/image/draw/bench_test.go create mode 100644 libgo/go/image/draw/clip_test.go create mode 100644 libgo/go/image/draw/draw.go create mode 100644 libgo/go/image/draw/draw_test.go create mode 100644 libgo/go/image/image_test.go create mode 100644 libgo/go/image/testdata/video-001.5bpp.gif create mode 100644 libgo/go/image/testdata/video-001.interlaced.gif create mode 100644 libgo/go/image/testdata/video-005.gray.jpeg create mode 100644 libgo/go/image/testdata/video-005.gray.png create mode 100644 libgo/go/image/tiff/reader_test.go create mode 100644 libgo/go/image/tiff/testdata/no_rps.tiff create mode 100644 libgo/go/json/encode_test.go create mode 100644 libgo/go/json/tagkey_test.go create mode 100644 libgo/go/mail/message.go create mode 100644 libgo/go/mail/message_test.go create mode 100644 libgo/go/mime/multipart/writer.go create mode 100644 libgo/go/mime/multipart/writer_test.go create mode 100644 libgo/go/net/dnsclient_unix.go create mode 100644 libgo/go/net/fd_openbsd.go create mode 100644 libgo/go/net/file_plan9.go create mode 100644 libgo/go/net/interface.go create mode 100644 libgo/go/net/interface_bsd.go create mode 100644 libgo/go/net/interface_darwin.go create mode 100644 libgo/go/net/interface_freebsd.go create mode 100644 libgo/go/net/interface_linux.go create mode 100644 libgo/go/net/interface_openbsd.go create mode 100644 libgo/go/net/interface_stub.go create mode 100644 libgo/go/net/interface_test.go create mode 100644 libgo/go/net/interface_windows.go create mode 100644 libgo/go/net/iprawsock_plan9.go create mode 100644 libgo/go/net/iprawsock_posix.go create mode 100644 libgo/go/net/ipsock_plan9.go create mode 100644 libgo/go/net/ipsock_posix.go delete mode 100644 libgo/go/net/lookup.go create mode 100644 libgo/go/net/lookup_plan9.go create mode 100644 libgo/go/net/lookup_test.go create mode 100644 libgo/go/net/lookup_unix.go create mode 100644 libgo/go/net/lookup_windows.go delete mode 100644 libgo/go/net/resolv_windows.go create mode 100644 libgo/go/net/sendfile_linux.go create mode 100644 libgo/go/net/sendfile_stub.go create mode 100644 libgo/go/net/sendfile_windows.go delete mode 100644 libgo/go/net/srv_test.go create mode 100644 libgo/go/net/tcpsock_plan9.go create mode 100644 libgo/go/net/tcpsock_posix.go create mode 100644 libgo/go/net/udpsock_plan9.go create mode 100644 libgo/go/net/udpsock_posix.go create mode 100644 libgo/go/net/unixsock_plan9.go create mode 100644 libgo/go/net/unixsock_posix.go create mode 100644 libgo/go/old/template/doc.go create mode 100644 libgo/go/old/template/execute.go create mode 100644 libgo/go/old/template/format.go create mode 100644 libgo/go/old/template/parse.go create mode 100644 libgo/go/old/template/template_test.go create mode 100644 libgo/go/os/mkunixsignals.sh create mode 100644 libgo/go/os/path_plan9.go create mode 100644 libgo/go/os/path_unix.go create mode 100644 libgo/go/os/path_windows.go delete mode 100644 libgo/go/os/signal/mkunix.sh create mode 100644 libgo/go/os/stat_openbsd.go create mode 100644 libgo/go/os/str.go create mode 100644 libgo/go/runtime/append_test.go create mode 100644 libgo/go/runtime/chan_test.go create mode 100644 libgo/go/runtime/closure_test.go create mode 100644 libgo/go/runtime/sema_test.go create mode 100644 libgo/go/runtime/symtab_test.go create mode 100644 libgo/go/template/doc.go create mode 100644 libgo/go/template/exec.go create mode 100644 libgo/go/template/exec_test.go delete mode 100644 libgo/go/template/format.go create mode 100644 libgo/go/template/funcs.go create mode 100644 libgo/go/template/helper.go create mode 100644 libgo/go/template/parse.go create mode 100644 libgo/go/template/parse/lex.go create mode 100644 libgo/go/template/parse/lex_test.go create mode 100644 libgo/go/template/parse/node.go create mode 100644 libgo/go/template/parse/parse.go create mode 100644 libgo/go/template/parse/parse_test.go create mode 100644 libgo/go/template/parse/set.go create mode 100644 libgo/go/template/set.go create mode 100644 libgo/go/template/set_test.go delete mode 100644 libgo/go/template/template.go delete mode 100644 libgo/go/template/template_test.go create mode 100644 libgo/go/template/testdata/file1.tmpl create mode 100644 libgo/go/template/testdata/file2.tmpl create mode 100644 libgo/go/template/testdata/tmpl1.tmpl create mode 100644 libgo/go/template/testdata/tmpl2.tmpl create mode 100644 libgo/go/time/sys_plan9.go create mode 100644 libgo/go/time/sys_posix.go create mode 100644 libgo/go/time/zoneinfo_plan9.go create mode 100644 libgo/go/time/zoneinfo_posix.go create mode 100644 libgo/go/unicode/graphic.go create mode 100644 libgo/go/unicode/graphic_test.go create mode 100644 libgo/go/url/url.go create mode 100644 libgo/go/url/url_test.go create mode 100644 libgo/go/xml/atom_test.go create mode 100644 libgo/go/xml/marshal.go create mode 100644 libgo/go/xml/marshal_test.go (limited to 'libgo/go') diff --git a/libgo/go/archive/tar/reader.go b/libgo/go/archive/tar/reader.go index ad06b6d..45d95c3 100644 --- a/libgo/go/archive/tar/reader.go +++ b/libgo/go/archive/tar/reader.go @@ -16,7 +16,7 @@ import ( ) var ( - HeaderError os.Error = os.ErrorString("invalid tar header") + HeaderError = os.NewError("invalid tar header") ) // A Reader provides sequential access to the contents of a tar archive. diff --git a/libgo/go/archive/tar/reader_test.go b/libgo/go/archive/tar/reader_test.go index 32fc8f9..f473c90 100644 --- a/libgo/go/archive/tar/reader_test.go +++ b/libgo/go/archive/tar/reader_test.go @@ -178,7 +178,6 @@ func TestPartialRead(t *testing.T) { } } - func TestIncrementalRead(t *testing.T) { test := gnuTarTest f, err := os.Open(test.file) diff --git a/libgo/go/archive/zip/reader.go b/libgo/go/archive/zip/reader.go index 17464c5..f92f929 100644 --- a/libgo/go/archive/zip/reader.go +++ b/libgo/go/archive/zip/reader.go @@ -2,18 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -/* -Package zip provides support for reading ZIP archives. - -See: http://www.pkware.com/documents/casestudies/APPNOTE.TXT - -This package does not support ZIP64 or disk spanning. -*/ package zip import ( "bufio" - "bytes" "compress/flate" "hash" "hash/crc32" @@ -24,9 +16,9 @@ import ( ) var ( - FormatError = os.NewError("not a valid zip file") - UnsupportedMethod = os.NewError("unsupported compression algorithm") - ChecksumError = os.NewError("checksum error") + FormatError = os.NewError("zip: not a valid zip file") + UnsupportedMethod = os.NewError("zip: unsupported compression algorithm") + ChecksumError = os.NewError("zip: checksum error") ) type Reader struct { @@ -44,15 +36,14 @@ type File struct { FileHeader zipr io.ReaderAt zipsize int64 - headerOffset uint32 - bodyOffset int64 + headerOffset int64 } func (f *File) hasDataDescriptor() bool { return f.Flags&0x8 != 0 } -// OpenReader will open the Zip file specified by name and return a ReaderCloser. +// OpenReader will open the Zip file specified by name and return a ReadCloser. func OpenReader(name string) (*ReadCloser, os.Error) { f, err := os.Open(name) if err != nil { @@ -87,18 +78,33 @@ func (z *Reader) init(r io.ReaderAt, size int64) os.Error { return err } z.r = r - z.File = make([]*File, end.directoryRecords) + z.File = make([]*File, 0, end.directoryRecords) z.Comment = end.comment rs := io.NewSectionReader(r, 0, size) if _, err = rs.Seek(int64(end.directoryOffset), os.SEEK_SET); err != nil { return err } buf := bufio.NewReader(rs) - for i := range z.File { - z.File[i] = &File{zipr: r, zipsize: size} - if err := readDirectoryHeader(z.File[i], buf); err != nil { + + // The count of files inside a zip is truncated to fit in a uint16. + // Gloss over this by reading headers until we encounter + // a bad one, and then only report a FormatError or UnexpectedEOF if + // the file count modulo 65536 is incorrect. + for { + f := &File{zipr: r, zipsize: size} + err = readDirectoryHeader(f, buf) + if err == FormatError || err == io.ErrUnexpectedEOF { + break + } + if err != nil { return err } + z.File = append(z.File, f) + } + if uint16(len(z.File)) != end.directoryRecords { + // Return the readDirectoryHeader error if we read + // the wrong number of directory entries. + return err } return nil } @@ -109,31 +115,22 @@ func (rc *ReadCloser) Close() os.Error { } // Open returns a ReadCloser that provides access to the File's contents. +// It is safe to Open and Read from files concurrently. func (f *File) Open() (rc io.ReadCloser, err os.Error) { - off := int64(f.headerOffset) - if f.bodyOffset == 0 { - r := io.NewSectionReader(f.zipr, off, f.zipsize-off) - if err = readFileHeader(f, r); err != nil { - return - } - if f.bodyOffset, err = r.Seek(0, os.SEEK_CUR); err != nil { - return - } + bodyOffset, err := f.findBodyOffset() + if err != nil { + return } size := int64(f.CompressedSize) - if f.hasDataDescriptor() { - if size == 0 { - // permit SectionReader to see the rest of the file - size = f.zipsize - (off + f.bodyOffset) - } else { - size += dataDescriptorLen - } + if size == 0 && f.hasDataDescriptor() { + // permit SectionReader to see the rest of the file + size = f.zipsize - (f.headerOffset + bodyOffset) } - r := io.NewSectionReader(f.zipr, off+f.bodyOffset, size) + r := io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset, size) switch f.Method { - case 0: // store (no compression) + case Store: // (no compression) rc = ioutil.NopCloser(r) - case 8: // DEFLATE + case Deflate: rc = flate.NewReader(r) default: err = UnsupportedMethod @@ -170,90 +167,102 @@ func (r *checksumReader) Read(b []byte) (n int, err os.Error) { func (r *checksumReader) Close() os.Error { return r.rc.Close() } -func readFileHeader(f *File, r io.Reader) (err os.Error) { - defer func() { - if rerr, ok := recover().(os.Error); ok { - err = rerr - } - }() - var ( - signature uint32 - filenameLength uint16 - extraLength uint16 - ) - read(r, &signature) - if signature != fileHeaderSignature { +func readFileHeader(f *File, r io.Reader) os.Error { + var b [fileHeaderLen]byte + if _, err := io.ReadFull(r, b[:]); err != nil { + return err + } + c := binary.LittleEndian + if sig := c.Uint32(b[:4]); sig != fileHeaderSignature { return FormatError } - read(r, &f.ReaderVersion) - read(r, &f.Flags) - read(r, &f.Method) - read(r, &f.ModifiedTime) - read(r, &f.ModifiedDate) - read(r, &f.CRC32) - read(r, &f.CompressedSize) - read(r, &f.UncompressedSize) - read(r, &filenameLength) - read(r, &extraLength) - f.Name = string(readByteSlice(r, filenameLength)) - f.Extra = readByteSlice(r, extraLength) - return + f.ReaderVersion = c.Uint16(b[4:6]) + f.Flags = c.Uint16(b[6:8]) + f.Method = c.Uint16(b[8:10]) + f.ModifiedTime = c.Uint16(b[10:12]) + f.ModifiedDate = c.Uint16(b[12:14]) + f.CRC32 = c.Uint32(b[14:18]) + f.CompressedSize = c.Uint32(b[18:22]) + f.UncompressedSize = c.Uint32(b[22:26]) + filenameLen := int(c.Uint16(b[26:28])) + extraLen := int(c.Uint16(b[28:30])) + d := make([]byte, filenameLen+extraLen) + if _, err := io.ReadFull(r, d); err != nil { + return err + } + f.Name = string(d[:filenameLen]) + f.Extra = d[filenameLen:] + return nil } -func readDirectoryHeader(f *File, r io.Reader) (err os.Error) { - defer func() { - if rerr, ok := recover().(os.Error); ok { - err = rerr - } - }() - var ( - signature uint32 - filenameLength uint16 - extraLength uint16 - commentLength uint16 - startDiskNumber uint16 // unused - internalAttributes uint16 // unused - externalAttributes uint32 // unused - ) - read(r, &signature) - if signature != directoryHeaderSignature { +// findBodyOffset does the minimum work to verify the file has a header +// and returns the file body offset. +func (f *File) findBodyOffset() (int64, os.Error) { + r := io.NewSectionReader(f.zipr, f.headerOffset, f.zipsize-f.headerOffset) + var b [fileHeaderLen]byte + if _, err := io.ReadFull(r, b[:]); err != nil { + return 0, err + } + c := binary.LittleEndian + if sig := c.Uint32(b[:4]); sig != fileHeaderSignature { + return 0, FormatError + } + filenameLen := int(c.Uint16(b[26:28])) + extraLen := int(c.Uint16(b[28:30])) + return int64(fileHeaderLen + filenameLen + extraLen), nil +} + +// readDirectoryHeader attempts to read a directory header from r. +// It returns io.ErrUnexpectedEOF if it cannot read a complete header, +// and FormatError if it doesn't find a valid header signature. +func readDirectoryHeader(f *File, r io.Reader) os.Error { + var b [directoryHeaderLen]byte + if _, err := io.ReadFull(r, b[:]); err != nil { + return err + } + c := binary.LittleEndian + if sig := c.Uint32(b[:4]); sig != directoryHeaderSignature { return FormatError } - read(r, &f.CreatorVersion) - read(r, &f.ReaderVersion) - read(r, &f.Flags) - read(r, &f.Method) - read(r, &f.ModifiedTime) - read(r, &f.ModifiedDate) - read(r, &f.CRC32) - read(r, &f.CompressedSize) - read(r, &f.UncompressedSize) - read(r, &filenameLength) - read(r, &extraLength) - read(r, &commentLength) - read(r, &startDiskNumber) - read(r, &internalAttributes) - read(r, &externalAttributes) - read(r, &f.headerOffset) - f.Name = string(readByteSlice(r, filenameLength)) - f.Extra = readByteSlice(r, extraLength) - f.Comment = string(readByteSlice(r, commentLength)) - return + f.CreatorVersion = c.Uint16(b[4:6]) + f.ReaderVersion = c.Uint16(b[6:8]) + f.Flags = c.Uint16(b[8:10]) + f.Method = c.Uint16(b[10:12]) + f.ModifiedTime = c.Uint16(b[12:14]) + f.ModifiedDate = c.Uint16(b[14:16]) + f.CRC32 = c.Uint32(b[16:20]) + f.CompressedSize = c.Uint32(b[20:24]) + f.UncompressedSize = c.Uint32(b[24:28]) + filenameLen := int(c.Uint16(b[28:30])) + extraLen := int(c.Uint16(b[30:32])) + commentLen := int(c.Uint16(b[32:34])) + // startDiskNumber := c.Uint16(b[34:36]) // Unused + // internalAttributes := c.Uint16(b[36:38]) // Unused + // externalAttributes := c.Uint32(b[38:42]) // Unused + f.headerOffset = int64(c.Uint32(b[42:46])) + d := make([]byte, filenameLen+extraLen+commentLen) + if _, err := io.ReadFull(r, d); err != nil { + return err + } + f.Name = string(d[:filenameLen]) + f.Extra = d[filenameLen : filenameLen+extraLen] + f.Comment = string(d[filenameLen+extraLen:]) + return nil } -func readDataDescriptor(r io.Reader, f *File) (err os.Error) { - defer func() { - if rerr, ok := recover().(os.Error); ok { - err = rerr - } - }() - read(r, &f.CRC32) - read(r, &f.CompressedSize) - read(r, &f.UncompressedSize) - return +func readDataDescriptor(r io.Reader, f *File) os.Error { + var b [dataDescriptorLen]byte + if _, err := io.ReadFull(r, b[:]); err != nil { + return err + } + c := binary.LittleEndian + f.CRC32 = c.Uint32(b[:4]) + f.CompressedSize = c.Uint32(b[4:8]) + f.UncompressedSize = c.Uint32(b[8:12]) + return nil } -func readDirectoryEnd(r io.ReaderAt, size int64) (d *directoryEnd, err os.Error) { +func readDirectoryEnd(r io.ReaderAt, size int64) (dir *directoryEnd, err os.Error) { // look for directoryEndSignature in the last 1k, then in the last 65k var b []byte for i, bLen := range []int64{1024, 65 * 1024} { @@ -274,53 +283,29 @@ func readDirectoryEnd(r io.ReaderAt, size int64) (d *directoryEnd, err os.Error) } // read header into struct - defer func() { - if rerr, ok := recover().(os.Error); ok { - err = rerr - d = nil - } - }() - br := bytes.NewBuffer(b[4:]) // skip over signature - d = new(directoryEnd) - read(br, &d.diskNbr) - read(br, &d.dirDiskNbr) - read(br, &d.dirRecordsThisDisk) - read(br, &d.directoryRecords) - read(br, &d.directorySize) - read(br, &d.directoryOffset) - read(br, &d.commentLen) - d.comment = string(readByteSlice(br, d.commentLen)) + c := binary.LittleEndian + d := new(directoryEnd) + d.diskNbr = c.Uint16(b[4:6]) + d.dirDiskNbr = c.Uint16(b[6:8]) + d.dirRecordsThisDisk = c.Uint16(b[8:10]) + d.directoryRecords = c.Uint16(b[10:12]) + d.directorySize = c.Uint32(b[12:16]) + d.directoryOffset = c.Uint32(b[16:20]) + d.commentLen = c.Uint16(b[20:22]) + d.comment = string(b[22 : 22+int(d.commentLen)]) return d, nil } func findSignatureInBlock(b []byte) int { - const minSize = 4 + 2 + 2 + 2 + 2 + 4 + 4 + 2 // fixed part of header - for i := len(b) - minSize; i >= 0; i-- { + for i := len(b) - directoryEndLen; i >= 0; i-- { // defined from directoryEndSignature in struct.go if b[i] == 'P' && b[i+1] == 'K' && b[i+2] == 0x05 && b[i+3] == 0x06 { // n is length of comment - n := int(b[i+minSize-2]) | int(b[i+minSize-1])<<8 - if n+minSize+i == len(b) { + n := int(b[i+directoryEndLen-2]) | int(b[i+directoryEndLen-1])<<8 + if n+directoryEndLen+i == len(b) { return i } } } return -1 } - -func read(r io.Reader, data interface{}) { - if err := binary.Read(r, binary.LittleEndian, data); err != nil { - panic(err) - } -} - -func readByteSlice(r io.Reader, l uint16) []byte { - b := make([]byte, l) - if l == 0 { - return b - } - if _, err := io.ReadFull(r, b); err != nil { - panic(err) - } - return b -} diff --git a/libgo/go/archive/zip/reader_test.go b/libgo/go/archive/zip/reader_test.go index c72cd9a..fd5fed2 100644 --- a/libgo/go/archive/zip/reader_test.go +++ b/libgo/go/archive/zip/reader_test.go @@ -11,6 +11,7 @@ import ( "io/ioutil" "os" "testing" + "time" ) type ZipTest struct { @@ -24,8 +25,19 @@ type ZipTestFile struct { Name string Content []byte // if blank, will attempt to compare against File File string // name of file to compare to (relative to testdata/) + Mtime string // modified time in format "mm-dd-yy hh:mm:ss" } +// Caution: The Mtime values found for the test files should correspond to +// the values listed with unzip -l . However, the values +// listed by unzip appear to be off by some hours. When creating +// fresh test files and testing them, this issue is not present. +// The test files were created in Sydney, so there might be a time +// zone issue. The time zone information does have to be encoded +// somewhere, because otherwise unzip -l could not provide a different +// time from what the archive/zip package provides, but there appears +// to be no documentation about this. + var tests = []ZipTest{ { Name: "test.zip", @@ -34,10 +46,12 @@ var tests = []ZipTest{ { Name: "test.txt", Content: []byte("This is a test text file.\n"), + Mtime: "09-05-10 12:12:02", }, { - Name: "gophercolor16x16.png", - File: "gophercolor16x16.png", + Name: "gophercolor16x16.png", + File: "gophercolor16x16.png", + Mtime: "09-05-10 15:52:58", }, }, }, @@ -45,8 +59,9 @@ var tests = []ZipTest{ Name: "r.zip", File: []ZipTestFile{ { - Name: "r/r.zip", - File: "r.zip", + Name: "r/r.zip", + File: "r.zip", + Mtime: "03-04-10 00:24:16", }, }, }, @@ -58,6 +73,7 @@ var tests = []ZipTest{ { Name: "filename", Content: []byte("This is a test textfile.\n"), + Mtime: "02-02-11 13:06:20", }, }, }, @@ -136,18 +152,36 @@ func readTestFile(t *testing.T, ft ZipTestFile, f *File) { if f.Name != ft.Name { t.Errorf("name=%q, want %q", f.Name, ft.Name) } + + mtime, err := time.Parse("01-02-06 15:04:05", ft.Mtime) + if err != nil { + t.Error(err) + return + } + if got, want := f.Mtime_ns()/1e9, mtime.Seconds(); got != want { + t.Errorf("%s: mtime=%s (%d); want %s (%d)", f.Name, time.SecondsToUTC(got), got, mtime, want) + } + + size0 := f.UncompressedSize + var b bytes.Buffer r, err := f.Open() if err != nil { t.Error(err) return } + + if size1 := f.UncompressedSize; size0 != size1 { + t.Errorf("file %q changed f.UncompressedSize from %d to %d", f.Name, size0, size1) + } + _, err = io.Copy(&b, r) if err != nil { t.Error(err) return } r.Close() + var c []byte if len(ft.Content) != 0 { c = ft.Content @@ -155,10 +189,12 @@ func readTestFile(t *testing.T, ft ZipTestFile, f *File) { t.Error(err) return } + if b.Len() != len(c) { t.Errorf("%s: len=%d, want %d", f.Name, b.Len(), len(c)) return } + for i, b := range b.Bytes() { if b != c[i] { t.Errorf("%s: content[%d]=%q want %q", f.Name, i, b, c[i]) diff --git a/libgo/go/archive/zip/struct.go b/libgo/go/archive/zip/struct.go index bfe0aae..1d6e70f 100644 --- a/libgo/go/archive/zip/struct.go +++ b/libgo/go/archive/zip/struct.go @@ -1,9 +1,32 @@ +// 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 zip provides support for reading and writing ZIP archives. + +See: http://www.pkware.com/documents/casestudies/APPNOTE.TXT + +This package does not support ZIP64 or disk spanning. +*/ package zip +import "os" +import "time" + +// Compression methods. +const ( + Store uint16 = 0 + Deflate uint16 = 8 +) + const ( fileHeaderSignature = 0x04034b50 directoryHeaderSignature = 0x02014b50 directoryEndSignature = 0x06054b50 + fileHeaderLen = 30 // + filename + extra + directoryHeaderLen = 46 // + filename + extra + comment + directoryEndLen = 22 // + comment dataDescriptorLen = 12 ) @@ -13,8 +36,8 @@ type FileHeader struct { ReaderVersion uint16 Flags uint16 Method uint16 - ModifiedTime uint16 - ModifiedDate uint16 + ModifiedTime uint16 // MS-DOS time + ModifiedDate uint16 // MS-DOS date CRC32 uint32 CompressedSize uint32 UncompressedSize uint32 @@ -32,3 +55,37 @@ type directoryEnd struct { commentLen uint16 comment string } + +func recoverError(err *os.Error) { + if e := recover(); e != nil { + if osErr, ok := e.(os.Error); ok { + *err = osErr + return + } + panic(e) + } +} + +// msDosTimeToTime converts an MS-DOS date and time into a time.Time. +// The resolution is 2s. +// See: http://msdn.microsoft.com/en-us/library/ms724247(v=VS.85).aspx +func msDosTimeToTime(dosDate, dosTime uint16) time.Time { + return time.Time{ + // date bits 0-4: day of month; 5-8: month; 9-15: years since 1980 + Year: int64(dosDate>>9 + 1980), + Month: int(dosDate >> 5 & 0xf), + Day: int(dosDate & 0x1f), + + // time bits 0-4: second/2; 5-10: minute; 11-15: hour + Hour: int(dosTime >> 11), + Minute: int(dosTime >> 5 & 0x3f), + Second: int(dosTime & 0x1f * 2), + } +} + +// Mtime_ns returns the modified time in ns since epoch. +// The resolution is 2s. +func (h *FileHeader) Mtime_ns() int64 { + t := msDosTimeToTime(h.ModifiedDate, h.ModifiedTime) + return t.Seconds() * 1e9 +} diff --git a/libgo/go/archive/zip/writer.go b/libgo/go/archive/zip/writer.go new file mode 100644 index 0000000..2065b06 --- /dev/null +++ b/libgo/go/archive/zip/writer.go @@ -0,0 +1,244 @@ +// 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 zip + +import ( + "bufio" + "compress/flate" + "encoding/binary" + "hash" + "hash/crc32" + "io" + "os" +) + +// TODO(adg): support zip file comments +// TODO(adg): support specifying deflate level + +// Writer implements a zip file writer. +type Writer struct { + *countWriter + dir []*header + last *fileWriter + closed bool +} + +type header struct { + *FileHeader + offset uint32 +} + +// NewWriter returns a new Writer writing a zip file to w. +func NewWriter(w io.Writer) *Writer { + return &Writer{countWriter: &countWriter{w: bufio.NewWriter(w)}} +} + +// Close finishes writing the zip file by writing the central directory. +// It does not (and can not) close the underlying writer. +func (w *Writer) Close() (err os.Error) { + if w.last != nil && !w.last.closed { + if err = w.last.close(); err != nil { + return + } + w.last = nil + } + if w.closed { + return os.NewError("zip: writer closed twice") + } + w.closed = true + + defer recoverError(&err) + + // write central directory + start := w.count + for _, h := range w.dir { + write(w, uint32(directoryHeaderSignature)) + write(w, h.CreatorVersion) + write(w, h.ReaderVersion) + write(w, h.Flags) + write(w, h.Method) + write(w, h.ModifiedTime) + write(w, h.ModifiedDate) + write(w, h.CRC32) + write(w, h.CompressedSize) + write(w, h.UncompressedSize) + write(w, uint16(len(h.Name))) + write(w, uint16(len(h.Extra))) + write(w, uint16(len(h.Comment))) + write(w, uint16(0)) // disk number start + write(w, uint16(0)) // internal file attributes + write(w, uint32(0)) // external file attributes + write(w, h.offset) + writeBytes(w, []byte(h.Name)) + writeBytes(w, h.Extra) + writeBytes(w, []byte(h.Comment)) + } + end := w.count + + // write end record + write(w, uint32(directoryEndSignature)) + write(w, uint16(0)) // disk number + write(w, uint16(0)) // disk number where directory starts + write(w, uint16(len(w.dir))) // number of entries this disk + write(w, uint16(len(w.dir))) // number of entries total + write(w, uint32(end-start)) // size of directory + write(w, uint32(start)) // start of directory + write(w, uint16(0)) // size of comment + + return w.w.(*bufio.Writer).Flush() +} + +// Create adds a file to the zip file using the provided name. +// It returns a Writer to which the file contents should be written. +// The file's contents must be written to the io.Writer before the next +// call to Create, CreateHeader, or Close. +func (w *Writer) Create(name string) (io.Writer, os.Error) { + header := &FileHeader{ + Name: name, + Method: Deflate, + } + return w.CreateHeader(header) +} + +// CreateHeader adds a file to the zip file using the provided FileHeader +// for the file metadata. +// It returns a Writer to which the file contents should be written. +// The file's contents must be written to the io.Writer before the next +// call to Create, CreateHeader, or Close. +func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, os.Error) { + if w.last != nil && !w.last.closed { + if err := w.last.close(); err != nil { + return nil, err + } + } + + fh.Flags |= 0x8 // we will write a data descriptor + fh.CreatorVersion = 0x14 + fh.ReaderVersion = 0x14 + + fw := &fileWriter{ + zipw: w, + compCount: &countWriter{w: w}, + crc32: crc32.NewIEEE(), + } + switch fh.Method { + case Store: + fw.comp = nopCloser{fw.compCount} + case Deflate: + fw.comp = flate.NewWriter(fw.compCount, 5) + default: + return nil, UnsupportedMethod + } + fw.rawCount = &countWriter{w: fw.comp} + + h := &header{ + FileHeader: fh, + offset: uint32(w.count), + } + w.dir = append(w.dir, h) + fw.header = h + + if err := writeHeader(w, fh); err != nil { + return nil, err + } + + w.last = fw + return fw, nil +} + +func writeHeader(w io.Writer, h *FileHeader) (err os.Error) { + defer recoverError(&err) + write(w, uint32(fileHeaderSignature)) + write(w, h.ReaderVersion) + write(w, h.Flags) + write(w, h.Method) + write(w, h.ModifiedTime) + write(w, h.ModifiedDate) + write(w, h.CRC32) + write(w, h.CompressedSize) + write(w, h.UncompressedSize) + write(w, uint16(len(h.Name))) + write(w, uint16(len(h.Extra))) + writeBytes(w, []byte(h.Name)) + writeBytes(w, h.Extra) + return nil +} + +type fileWriter struct { + *header + zipw io.Writer + rawCount *countWriter + comp io.WriteCloser + compCount *countWriter + crc32 hash.Hash32 + closed bool +} + +func (w *fileWriter) Write(p []byte) (int, os.Error) { + if w.closed { + return 0, os.NewError("zip: write to closed file") + } + w.crc32.Write(p) + return w.rawCount.Write(p) +} + +func (w *fileWriter) close() (err os.Error) { + if w.closed { + return os.NewError("zip: file closed twice") + } + w.closed = true + if err = w.comp.Close(); err != nil { + return + } + + // update FileHeader + fh := w.header.FileHeader + fh.CRC32 = w.crc32.Sum32() + fh.CompressedSize = uint32(w.compCount.count) + fh.UncompressedSize = uint32(w.rawCount.count) + + // write data descriptor + defer recoverError(&err) + write(w.zipw, fh.CRC32) + write(w.zipw, fh.CompressedSize) + write(w.zipw, fh.UncompressedSize) + + return nil +} + +type countWriter struct { + w io.Writer + count int64 +} + +func (w *countWriter) Write(p []byte) (int, os.Error) { + n, err := w.w.Write(p) + w.count += int64(n) + return n, err +} + +type nopCloser struct { + io.Writer +} + +func (w nopCloser) Close() os.Error { + return nil +} + +func write(w io.Writer, data interface{}) { + if err := binary.Write(w, binary.LittleEndian, data); err != nil { + panic(err) + } +} + +func writeBytes(w io.Writer, b []byte) { + n, err := w.Write(b) + if err != nil { + panic(err) + } + if n != len(b) { + panic(io.ErrShortWrite) + } +} diff --git a/libgo/go/archive/zip/writer_test.go b/libgo/go/archive/zip/writer_test.go new file mode 100644 index 0000000..eb2a80c --- /dev/null +++ b/libgo/go/archive/zip/writer_test.go @@ -0,0 +1,73 @@ +// 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 zip + +import ( + "bytes" + "io/ioutil" + "rand" + "testing" +) + +// TODO(adg): a more sophisticated test suite + +const testString = "Rabbits, guinea pigs, gophers, marsupial rats, and quolls." + +func TestWriter(t *testing.T) { + largeData := make([]byte, 1<<17) + for i := range largeData { + largeData[i] = byte(rand.Int()) + } + + // write a zip file + buf := new(bytes.Buffer) + w := NewWriter(buf) + testCreate(t, w, "foo", []byte(testString), Store) + testCreate(t, w, "bar", largeData, Deflate) + if err := w.Close(); err != nil { + t.Fatal(err) + } + + // read it back + r, err := NewReader(sliceReaderAt(buf.Bytes()), int64(buf.Len())) + if err != nil { + t.Fatal(err) + } + testReadFile(t, r.File[0], []byte(testString)) + testReadFile(t, r.File[1], largeData) +} + +func testCreate(t *testing.T, w *Writer, name string, data []byte, method uint16) { + header := &FileHeader{ + Name: name, + Method: method, + } + f, err := w.CreateHeader(header) + if err != nil { + t.Fatal(err) + } + _, err = f.Write(data) + if err != nil { + t.Fatal(err) + } +} + +func testReadFile(t *testing.T, f *File, data []byte) { + rc, err := f.Open() + if err != nil { + t.Fatal("opening:", err) + } + b, err := ioutil.ReadAll(rc) + if err != nil { + t.Fatal("reading:", err) + } + err = rc.Close() + if err != nil { + t.Fatal("closing:", err) + } + if !bytes.Equal(b, data) { + t.Errorf("File contents %q, want %q", b, data) + } +} diff --git a/libgo/go/archive/zip/zip_test.go b/libgo/go/archive/zip/zip_test.go new file mode 100644 index 0000000..0f71fdf --- /dev/null +++ b/libgo/go/archive/zip/zip_test.go @@ -0,0 +1,57 @@ +// 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. + +// Tests that involve both reading and writing. + +package zip + +import ( + "bytes" + "fmt" + "os" + "testing" +) + +type stringReaderAt string + +func (s stringReaderAt) ReadAt(p []byte, off int64) (n int, err os.Error) { + if off >= int64(len(s)) { + return 0, os.EOF + } + n = copy(p, s[off:]) + return +} + +func TestOver65kFiles(t *testing.T) { + if testing.Short() { + t.Logf("slow test; skipping") + return + } + buf := new(bytes.Buffer) + w := NewWriter(buf) + const nFiles = (1 << 16) + 42 + for i := 0; i < nFiles; i++ { + _, err := w.Create(fmt.Sprintf("%d.dat", i)) + if err != nil { + t.Fatalf("creating file %d: %v", i, err) + } + } + if err := w.Close(); err != nil { + t.Fatalf("Writer.Close: %v", err) + } + rat := stringReaderAt(buf.String()) + zr, err := NewReader(rat, int64(len(rat))) + if err != nil { + t.Fatalf("NewReader: %v", err) + } + if got := len(zr.File); got != nFiles { + t.Fatalf("File contains %d files, want %d", got, nFiles) + } + for i := 0; i < nFiles; i++ { + want := fmt.Sprintf("%d.dat", i) + if zr.File[i].Name != want { + t.Fatalf("File(%d) = %q, want %q", i, zr.File[i].Name, want) + } + } +} diff --git a/libgo/go/asn1/asn1.go b/libgo/go/asn1/asn1.go index 5f470ae..39b676b 100644 --- a/libgo/go/asn1/asn1.go +++ b/libgo/go/asn1/asn1.go @@ -20,6 +20,7 @@ package asn1 // everything by any means. import ( + "big" "fmt" "os" "reflect" @@ -88,6 +89,27 @@ func parseInt(bytes []byte) (int, os.Error) { return int(ret64), nil } +var bigOne = big.NewInt(1) + +// parseBigInt treats the given bytes as a big-endian, signed integer and returns +// the result. +func parseBigInt(bytes []byte) *big.Int { + ret := new(big.Int) + if len(bytes) > 0 && bytes[0]&0x80 == 0x80 { + // This is a negative number. + notBytes := make([]byte, len(bytes)) + for i := range notBytes { + notBytes[i] = ^bytes[i] + } + ret.SetBytes(notBytes) + ret.Add(ret, bigOne) + ret.Neg(ret) + return ret + } + ret.SetBytes(bytes) + return ret +} + // BIT STRING // BitString is the structure to use when you want an ASN.1 BIT STRING type. A @@ -127,7 +149,7 @@ func (b BitString) RightAlign() []byte { return a } -// parseBitString parses an ASN.1 bit string from the given byte array and returns it. +// parseBitString parses an ASN.1 bit string from the given byte slice and returns it. func parseBitString(bytes []byte) (ret BitString, err os.Error) { if len(bytes) == 0 { err = SyntaxError{"zero length BIT STRING"} @@ -164,9 +186,9 @@ func (oi ObjectIdentifier) Equal(other ObjectIdentifier) bool { return true } -// parseObjectIdentifier parses an OBJECT IDENTIFER from the given bytes and -// returns it. An object identifer is a sequence of variable length integers -// that are assigned in a hierarachy. +// parseObjectIdentifier parses an OBJECT IDENTIFIER from the given bytes and +// returns it. An object identifier is a sequence of variable length integers +// that are assigned in a hierarchy. func parseObjectIdentifier(bytes []byte) (s []int, err os.Error) { if len(bytes) == 0 { err = SyntaxError{"zero length OBJECT IDENTIFIER"} @@ -198,14 +220,13 @@ func parseObjectIdentifier(bytes []byte) (s []int, err os.Error) { // An Enumerated is represented as a plain int. type Enumerated int - // FLAG // A Flag accepts any data and is set to true if present. type Flag bool // parseBase128Int parses a base-128 encoded int from the given offset in the -// given byte array. It returns the value and the new offset. +// given byte slice. It returns the value and the new offset. func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err os.Error) { offset = initOffset for shifted := 0; offset < len(bytes); shifted++ { @@ -237,7 +258,7 @@ func parseUTCTime(bytes []byte) (ret *time.Time, err os.Error) { return } -// parseGeneralizedTime parses the GeneralizedTime from the given byte array +// parseGeneralizedTime parses the GeneralizedTime from the given byte slice // and returns the resulting time. func parseGeneralizedTime(bytes []byte) (ret *time.Time, err os.Error) { return time.Parse("20060102150405Z0700", string(bytes)) @@ -269,7 +290,7 @@ func isPrintable(b byte) bool { b == ':' || b == '=' || b == '?' || - // This is techincally not allowed in a PrintableString. + // This is technically not allowed in a PrintableString. // However, x509 certificates with wildcard strings don't // always use the correct string type so we permit it. b == '*' @@ -278,7 +299,7 @@ func isPrintable(b byte) bool { // IA5String // parseIA5String parses a ASN.1 IA5String (ASCII string) from the given -// byte array and returns it. +// byte slice and returns it. func parseIA5String(bytes []byte) (ret string, err os.Error) { for _, b := range bytes { if b >= 0x80 { @@ -293,11 +314,19 @@ func parseIA5String(bytes []byte) (ret string, err os.Error) { // T61String // parseT61String parses a ASN.1 T61String (8-bit clean string) from the given -// byte array and returns it. +// byte slice and returns it. func parseT61String(bytes []byte) (ret string, err os.Error) { return string(bytes), nil } +// UTF8String + +// parseUTF8String parses a ASN.1 UTF8String (raw UTF-8) from the given byte +// array and returns it. +func parseUTF8String(bytes []byte) (ret string, err os.Error) { + return string(bytes), nil +} + // A RawValue represents an undecoded ASN.1 object. type RawValue struct { Class, Tag int @@ -314,7 +343,7 @@ type RawContent []byte // Tagging // parseTagAndLength parses an ASN.1 tag and length pair from the given offset -// into a byte array. It returns the parsed data and the new offset. SET and +// into a byte slice. It returns the parsed data and the new offset. SET and // SET OF (tag 17) are mapped to SEQUENCE and SEQUENCE OF (tag 16) since we // don't distinguish between ordered and unordered objects in this code. func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset int, err os.Error) { @@ -371,7 +400,7 @@ func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset i } // parseSequenceOf is used for SEQUENCE OF and SET OF values. It tries to parse -// a number of ASN.1 values from the given byte array and returns them as a +// a number of ASN.1 values from the given byte slice and returns them as a // slice of Go values of the given type. func parseSequenceOf(bytes []byte, sliceType reflect.Type, elemType reflect.Type) (ret reflect.Value, err os.Error) { expectedTag, compoundType, ok := getUniversalType(elemType) @@ -425,6 +454,7 @@ var ( timeType = reflect.TypeOf(&time.Time{}) rawValueType = reflect.TypeOf(RawValue{}) rawContentsType = reflect.TypeOf(RawContent(nil)) + bigIntType = reflect.TypeOf(new(big.Int)) ) // invalidLength returns true iff offset + length > sliceLength, or if the @@ -433,7 +463,7 @@ func invalidLength(offset, length, sliceLength int) bool { return offset+length < offset || offset+length > sliceLength } -// parseField is the main parsing function. Given a byte array and an offset +// parseField is the main parsing function. Given a byte slice and an offset // into the array, it will try to parse a suitable ASN.1 value out and store it // in the given Value. func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParameters) (offset int, err os.Error) { @@ -550,16 +580,15 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam } } - // Special case for strings: PrintableString and IA5String both map to - // the Go type string. getUniversalType returns the tag for - // PrintableString when it sees a string so, if we see an IA5String on - // the wire, we change the universal type to match. - if universalTag == tagPrintableString && t.tag == tagIA5String { - universalTag = tagIA5String - } - // Likewise for GeneralString - if universalTag == tagPrintableString && t.tag == tagGeneralString { - universalTag = tagGeneralString + // Special case for strings: all the ASN.1 string types map to the Go + // type string. getUniversalType returns the tag for PrintableString + // when it sees a string, so if we see a different string type on the + // wire, we change the universal type to match. + if universalTag == tagPrintableString { + switch t.tag { + case tagIA5String, tagGeneralString, tagT61String, tagUTF8String: + universalTag = t.tag + } } // Special case for time: UTCTime and GeneralizedTime both map to the @@ -639,6 +668,10 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam case flagType: v.SetBool(true) return + case bigIntType: + parsedInt := parseBigInt(innerBytes) + v.Set(reflect.ValueOf(parsedInt)) + return } switch val := v; val.Kind() { case reflect.Bool: @@ -648,23 +681,21 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam } err = err1 return - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - switch val.Type().Kind() { - case reflect.Int: - parsedInt, err1 := parseInt(innerBytes) - if err1 == nil { - val.SetInt(int64(parsedInt)) - } - err = err1 - return - case reflect.Int64: - parsedInt, err1 := parseInt64(innerBytes) - if err1 == nil { - val.SetInt(parsedInt) - } - err = err1 - return + case reflect.Int, reflect.Int32: + parsedInt, err1 := parseInt(innerBytes) + if err1 == nil { + val.SetInt(int64(parsedInt)) } + err = err1 + return + case reflect.Int64: + parsedInt, err1 := parseInt64(innerBytes) + if err1 == nil { + val.SetInt(parsedInt) + } + err = err1 + return + // TODO(dfc) Add support for the remaining integer types case reflect.Struct: structType := fieldType @@ -680,7 +711,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam if i == 0 && field.Type == rawContentsType { continue } - innerOffset, err = parseField(val.Field(i), innerBytes, innerOffset, parseFieldParameters(field.Tag)) + innerOffset, err = parseField(val.Field(i), innerBytes, innerOffset, parseFieldParameters(field.Tag.Get("asn1"))) if err != nil { return } @@ -711,6 +742,8 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam v, err = parseIA5String(innerBytes) case tagT61String: v, err = parseT61String(innerBytes) + case tagUTF8String: + v, err = parseUTF8String(innerBytes) case tagGeneralString: // GeneralString is specified in ISO-2022/ECMA-35, // A brief review suggests that it includes structures @@ -725,7 +758,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam } return } - err = StructuralError{"unknown Go type"} + err = StructuralError{"unsupported: " + v.Type().String()} return } @@ -752,7 +785,7 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) { // Because Unmarshal uses the reflect package, the structs // being written to must use upper case field names. // -// An ASN.1 INTEGER can be written to an int or int64. +// An ASN.1 INTEGER can be written to an int, int32 or int64. // If the encoded value does not fit in the Go type, // Unmarshal returns a parse error. // diff --git a/libgo/go/asn1/asn1_test.go b/libgo/go/asn1/asn1_test.go index 78f5628..9f48f7b 100644 --- a/libgo/go/asn1/asn1_test.go +++ b/libgo/go/asn1/asn1_test.go @@ -42,6 +42,64 @@ func TestParseInt64(t *testing.T) { } } +type int32Test struct { + in []byte + ok bool + out int32 +} + +var int32TestData = []int32Test{ + {[]byte{0x00}, true, 0}, + {[]byte{0x7f}, true, 127}, + {[]byte{0x00, 0x80}, true, 128}, + {[]byte{0x01, 0x00}, true, 256}, + {[]byte{0x80}, true, -128}, + {[]byte{0xff, 0x7f}, true, -129}, + {[]byte{0xff, 0xff, 0xff, 0xff}, true, -1}, + {[]byte{0xff}, true, -1}, + {[]byte{0x80, 0x00, 0x00, 0x00}, true, -2147483648}, + {[]byte{0x80, 0x00, 0x00, 0x00, 0x00}, false, 0}, +} + +func TestParseInt32(t *testing.T) { + for i, test := range int32TestData { + ret, err := parseInt(test.in) + if (err == nil) != test.ok { + t.Errorf("#%d: Incorrect error result (did fail? %v, expected: %v)", i, err == nil, test.ok) + } + if test.ok && int32(ret) != test.out { + t.Errorf("#%d: Bad result: %v (expected %v)", i, ret, test.out) + } + } +} + +var bigIntTests = []struct { + in []byte + base10 string +}{ + {[]byte{0xff}, "-1"}, + {[]byte{0x00}, "0"}, + {[]byte{0x01}, "1"}, + {[]byte{0x00, 0xff}, "255"}, + {[]byte{0xff, 0x00}, "-256"}, + {[]byte{0x01, 0x00}, "256"}, +} + +func TestParseBigInt(t *testing.T) { + for i, test := range bigIntTests { + ret := parseBigInt(test.in) + if ret.String() != test.base10 { + t.Errorf("#%d: bad result from %x, got %s want %s", i, test.in, ret.String(), test.base10) + } + fw := newForkableWriter() + marshalBigInt(fw, ret) + result := fw.Bytes() + if !bytes.Equal(result, test.in) { + t.Errorf("#%d: got %x from marshaling %s, want %x", i, result, ret, test.in) + } + } +} + type bitStringTest struct { in []byte ok bool @@ -148,10 +206,10 @@ type timeTest struct { } var utcTestData = []timeTest{ - {"910506164540-0700", true, &time.Time{1991, 05, 06, 16, 45, 40, 0, -7 * 60 * 60, ""}}, - {"910506164540+0730", true, &time.Time{1991, 05, 06, 16, 45, 40, 0, 7*60*60 + 30*60, ""}}, - {"910506234540Z", true, &time.Time{1991, 05, 06, 23, 45, 40, 0, 0, "UTC"}}, - {"9105062345Z", true, &time.Time{1991, 05, 06, 23, 45, 0, 0, 0, "UTC"}}, + {"910506164540-0700", true, &time.Time{1991, 05, 06, 16, 45, 40, 0, 0, -7 * 60 * 60, ""}}, + {"910506164540+0730", true, &time.Time{1991, 05, 06, 16, 45, 40, 0, 0, 7*60*60 + 30*60, ""}}, + {"910506234540Z", true, &time.Time{1991, 05, 06, 23, 45, 40, 0, 0, 0, "UTC"}}, + {"9105062345Z", true, &time.Time{1991, 05, 06, 23, 45, 0, 0, 0, 0, "UTC"}}, {"a10506234540Z", false, nil}, {"91a506234540Z", false, nil}, {"9105a6234540Z", false, nil}, @@ -177,10 +235,10 @@ func TestUTCTime(t *testing.T) { } var generalizedTimeTestData = []timeTest{ - {"20100102030405Z", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, 0, "UTC"}}, + {"20100102030405Z", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, 0, 0, "UTC"}}, {"20100102030405", false, nil}, - {"20100102030405+0607", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, 6*60*60 + 7*60, ""}}, - {"20100102030405-0607", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, -6*60*60 - 7*60, ""}}, + {"20100102030405+0607", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, 0, 6*60*60 + 7*60, ""}}, + {"20100102030405-0607", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, 0, -6*60*60 - 7*60, ""}}, } func TestGeneralizedTime(t *testing.T) { @@ -272,11 +330,11 @@ type TestObjectIdentifierStruct struct { } type TestContextSpecificTags struct { - A int "tag:1" + A int `asn1:"tag:1"` } type TestContextSpecificTags2 struct { - A int "explicit,tag:1" + A int `asn1:"explicit,tag:1"` B int } @@ -326,7 +384,7 @@ type Certificate struct { } type TBSCertificate struct { - Version int "optional,explicit,default:0,tag:0" + Version int `asn1:"optional,explicit,default:0,tag:0"` SerialNumber RawValue SignatureAlgorithm AlgorithmIdentifier Issuer RDNSequence diff --git a/libgo/go/asn1/common.go b/libgo/go/asn1/common.go index 1589877..01f4f7b 100644 --- a/libgo/go/asn1/common.go +++ b/libgo/go/asn1/common.go @@ -10,7 +10,7 @@ import ( "strings" ) -// ASN.1 objects have metadata preceeding them: +// ASN.1 objects have metadata preceding them: // the tag: the type of the object // a flag denoting if this object is compound or not // the class type: the namespace of the tag @@ -25,6 +25,7 @@ const ( tagOctetString = 4 tagOID = 6 tagEnum = 10 + tagUTF8String = 12 tagSequence = 16 tagSet = 17 tagPrintableString = 19 @@ -83,7 +84,7 @@ type fieldParameters struct { // parseFieldParameters will parse it into a fieldParameters structure, // ignoring unknown parts of the string. func parseFieldParameters(str string) (ret fieldParameters) { - for _, part := range strings.Split(str, ",", -1) { + for _, part := range strings.Split(str, ",") { switch { case part == "optional": ret.optional = true @@ -132,6 +133,8 @@ func getUniversalType(t reflect.Type) (tagNumber int, isCompound, ok bool) { return tagUTCTime, false, true case enumeratedType: return tagEnum, false, true + case bigIntType: + return tagInteger, false, true } switch t.Kind() { case reflect.Bool: diff --git a/libgo/go/asn1/marshal.go b/libgo/go/asn1/marshal.go index a3e1145..d7eb63b 100644 --- a/libgo/go/asn1/marshal.go +++ b/libgo/go/asn1/marshal.go @@ -5,6 +5,7 @@ package asn1 import ( + "big" "bytes" "fmt" "io" @@ -125,6 +126,43 @@ func int64Length(i int64) (numBytes int) { return } +func marshalBigInt(out *forkableWriter, n *big.Int) (err os.Error) { + if n.Sign() < 0 { + // A negative number has to be converted to two's-complement + // form. So we'll subtract 1 and invert. If the + // most-significant-bit isn't set then we'll need to pad the + // beginning with 0xff in order to keep the number negative. + nMinus1 := new(big.Int).Neg(n) + nMinus1.Sub(nMinus1, bigOne) + bytes := nMinus1.Bytes() + for i := range bytes { + bytes[i] ^= 0xff + } + if len(bytes) == 0 || bytes[0]&0x80 == 0 { + err = out.WriteByte(0xff) + if err != nil { + return + } + } + _, err = out.Write(bytes) + } else if n.Sign() == 0 { + // Zero is written as a single 0 zero rather than no bytes. + err = out.WriteByte(0x00) + } else { + bytes := n.Bytes() + if len(bytes) > 0 && bytes[0]&0x80 != 0 { + // We'll have to pad this with 0x00 in order to stop it + // looking like a negative number. + err = out.WriteByte(0) + if err != nil { + return + } + } + _, err = out.Write(bytes) + } + return +} + func marshalLength(out *forkableWriter, i int) (err os.Error) { n := lengthLength(i) @@ -334,6 +372,8 @@ func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameter return marshalBitString(out, value.Interface().(BitString)) case objectIdentifierType: return marshalObjectIdentifier(out, value.Interface().(ObjectIdentifier)) + case bigIntType: + return marshalBigInt(out, value.Interface().(*big.Int)) } switch v := value; v.Kind() { @@ -351,7 +391,7 @@ func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameter startingField := 0 // If the first element of the structure is a non-empty - // RawContents, then we don't bother serialising the rest. + // RawContents, then we don't bother serializing the rest. if t.NumField() > 0 && t.Field(0).Type == rawContentsType { s := v.Field(0) if s.Len() > 0 { @@ -361,7 +401,7 @@ func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameter } /* The RawContents will contain the tag and * length fields but we'll also be writing - * those outselves, so we strip them out of + * those ourselves, so we strip them out of * bytes */ _, err = out.Write(stripTagAndLength(bytes)) return @@ -373,7 +413,7 @@ func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameter for i := startingField; i < t.NumField(); i++ { var pre *forkableWriter pre, out = out.fork() - err = marshalField(pre, v.Field(i), parseFieldParameters(t.Field(i).Tag)) + err = marshalField(pre, v.Field(i), parseFieldParameters(t.Field(i).Tag.Get("asn1"))) if err != nil { return } @@ -418,6 +458,10 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters) return marshalField(out, v.Elem(), params) } + if params.optional && reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) { + return + } + if v.Type() == rawValueType { rv := v.Interface().(RawValue) err = marshalTagAndLength(out, tagAndLength{rv.Class, rv.Tag, len(rv.Bytes), rv.IsCompound}) @@ -428,10 +472,6 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters) return } - if params.optional && reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) { - return - } - tag, isCompound, ok := getUniversalType(v.Type()) if !ok { err = StructuralError{fmt.Sprintf("unknown Go type: %v", v.Type())} diff --git a/libgo/go/asn1/marshal_test.go b/libgo/go/asn1/marshal_test.go index cd165d2..03df5f1 100644 --- a/libgo/go/asn1/marshal_test.go +++ b/libgo/go/asn1/marshal_test.go @@ -30,19 +30,23 @@ type rawContentsStruct struct { } type implicitTagTest struct { - A int "implicit,tag:5" + A int `asn1:"implicit,tag:5"` } type explicitTagTest struct { - A int "explicit,tag:5" + A int `asn1:"explicit,tag:5"` } type ia5StringTest struct { - A string "ia5" + A string `asn1:"ia5"` } type printableStringTest struct { - A string "printable" + A string `asn1:"printable"` +} + +type optionalRawValueTest struct { + A RawValue `asn1:"optional"` } type testSET []int @@ -102,6 +106,7 @@ var marshalTests = []marshalTest{ "7878787878787878787878787878787878787878787878787878787878787878", }, {ia5StringTest{"test"}, "3006160474657374"}, + {optionalRawValueTest{}, "3000"}, {printableStringTest{"test"}, "3006130474657374"}, {printableStringTest{"test*"}, "30071305746573742a"}, {rawContentsStruct{nil, 64}, "3003020140"}, diff --git a/libgo/go/big/arith.go b/libgo/go/big/arith.go index a4048d6..242bd1e 100644 --- a/libgo/go/big/arith.go +++ b/libgo/go/big/arith.go @@ -27,7 +27,6 @@ const ( _M2 = _B2 - 1 // half digit mask ) - // ---------------------------------------------------------------------------- // Elementary operations on words // @@ -43,7 +42,6 @@ func addWW_g(x, y, c Word) (z1, z0 Word) { return } - // z1<<_W + z0 = x-y-c, with c == 0 or 1 func subWW_g(x, y, c Word) (z1, z0 Word) { yc := y + c @@ -54,7 +52,6 @@ func subWW_g(x, y, c Word) (z1, z0 Word) { return } - // z1<<_W + z0 = x*y func mulWW(x, y Word) (z1, z0 Word) { return mulWW_g(x, y) } // Adapted from Warren, Hacker's Delight, p. 132. @@ -73,7 +70,6 @@ func mulWW_g(x, y Word) (z1, z0 Word) { return } - // z1<<_W + z0 = x*y + c func mulAddWWW_g(x, y, c Word) (z1, z0 Word) { z1, zz0 := mulWW(x, y) @@ -83,7 +79,6 @@ func mulAddWWW_g(x, y, c Word) (z1, z0 Word) { return } - // Length of x in bits. func bitLen(x Word) (n int) { for ; x >= 0x100; x >>= 8 { @@ -95,7 +90,6 @@ func bitLen(x Word) (n int) { return } - // log2 computes the integer binary logarithm of x. // The result is the integer n for which 2^n <= x < 2^(n+1). // If x == 0, the result is -1. @@ -103,13 +97,11 @@ func log2(x Word) int { return bitLen(x) - 1 } - // Number of leading zeros in x. func leadingZeros(x Word) uint { return uint(_W - bitLen(x)) } - // q = (u1<<_W + u0 - r)/y func divWW(x1, x0, y Word) (q, r Word) { return divWW_g(x1, x0, y) } // Adapted from Warren, Hacker's Delight, p. 152. @@ -155,7 +147,6 @@ again2: return q1*_B2 + q0, (un21*_B2 + un0 - q0*v) >> s } - func addVV(z, x, y []Word) (c Word) { return addVV_g(z, x, y) } func addVV_g(z, x, y []Word) (c Word) { for i := range z { @@ -164,7 +155,6 @@ func addVV_g(z, x, y []Word) (c Word) { return } - func subVV(z, x, y []Word) (c Word) { return subVV_g(z, x, y) } func subVV_g(z, x, y []Word) (c Word) { for i := range z { @@ -173,7 +163,6 @@ func subVV_g(z, x, y []Word) (c Word) { return } - func addVW(z, x []Word, y Word) (c Word) { return addVW_g(z, x, y) } func addVW_g(z, x []Word, y Word) (c Word) { c = y @@ -183,7 +172,6 @@ func addVW_g(z, x []Word, y Word) (c Word) { return } - func subVW(z, x []Word, y Word) (c Word) { return subVW_g(z, x, y) } func subVW_g(z, x []Word, y Word) (c Word) { c = y @@ -193,9 +181,8 @@ func subVW_g(z, x []Word, y Word) (c Word) { return } - -func shlVW(z, x []Word, s Word) (c Word) { return shlVW_g(z, x, s) } -func shlVW_g(z, x []Word, s Word) (c Word) { +func shlVU(z, x []Word, s uint) (c Word) { return shlVU_g(z, x, s) } +func shlVU_g(z, x []Word, s uint) (c Word) { if n := len(z); n > 0 { ŝ := _W - s w1 := x[n-1] @@ -210,9 +197,8 @@ func shlVW_g(z, x []Word, s Word) (c Word) { return } - -func shrVW(z, x []Word, s Word) (c Word) { return shrVW_g(z, x, s) } -func shrVW_g(z, x []Word, s Word) (c Word) { +func shrVU(z, x []Word, s uint) (c Word) { return shrVU_g(z, x, s) } +func shrVU_g(z, x []Word, s uint) (c Word) { if n := len(z); n > 0 { ŝ := _W - s w1 := x[0] @@ -227,7 +213,6 @@ func shrVW_g(z, x []Word, s Word) (c Word) { return } - func mulAddVWW(z, x []Word, y, r Word) (c Word) { return mulAddVWW_g(z, x, y, r) } func mulAddVWW_g(z, x []Word, y, r Word) (c Word) { c = r @@ -237,7 +222,6 @@ func mulAddVWW_g(z, x []Word, y, r Word) (c Word) { return } - func addMulVVW(z, x []Word, y Word) (c Word) { return addMulVVW_g(z, x, y) } func addMulVVW_g(z, x []Word, y Word) (c Word) { for i := range z { @@ -248,7 +232,6 @@ func addMulVVW_g(z, x []Word, y Word) (c Word) { return } - func divWVW(z []Word, xn Word, x []Word, y Word) (r Word) { return divWVW_g(z, xn, x, y) } func divWVW_g(z []Word, xn Word, x []Word, y Word) (r Word) { r = xn diff --git a/libgo/go/big/arith_decl.go b/libgo/go/big/arith_decl.go index c456d5f..95fcd8b 100644 --- a/libgo/go/big/arith_decl.go +++ b/libgo/go/big/arith_decl.go @@ -11,8 +11,8 @@ func addVV(z, x, y []Word) (c Word) func subVV(z, x, y []Word) (c Word) func addVW(z, x []Word, y Word) (c Word) func subVW(z, x []Word, y Word) (c Word) -func shlVW(z, x []Word, s Word) (c Word) -func shrVW(z, x []Word, s Word) (c Word) +func shlVU(z, x []Word, s uint) (c Word) +func shrVU(z, x []Word, s uint) (c Word) func mulAddVWW(z, x []Word, y, r Word) (c Word) func addMulVVW(z, x []Word, y Word) (c Word) func divWVW(z []Word, xn Word, x []Word, y Word) (r Word) diff --git a/libgo/go/big/arith_test.go b/libgo/go/big/arith_test.go index 934b302d..b6c56c3 100644 --- a/libgo/go/big/arith_test.go +++ b/libgo/go/big/arith_test.go @@ -6,7 +6,6 @@ package big import "testing" - type funWW func(x, y, c Word) (z1, z0 Word) type argWW struct { x, y, c, z1, z0 Word @@ -26,7 +25,6 @@ var sumWW = []argWW{ {_M, _M, 1, 1, _M}, } - func testFunWW(t *testing.T, msg string, f funWW, a argWW) { z1, z0 := f(a.x, a.y, a.c) if z1 != a.z1 || z0 != a.z0 { @@ -34,7 +32,6 @@ func testFunWW(t *testing.T, msg string, f funWW, a argWW) { } } - func TestFunWW(t *testing.T) { for _, a := range sumWW { arg := a @@ -51,7 +48,6 @@ func TestFunWW(t *testing.T) { } } - type funVV func(z, x, y []Word) (c Word) type argVV struct { z, x, y nat @@ -70,7 +66,6 @@ var sumVV = []argVV{ {nat{0, 0, 0, 0}, nat{_M, 0, _M, 0}, nat{1, _M, 0, _M}, 1}, } - func testFunVV(t *testing.T, msg string, f funVV, a argVV) { z := make(nat, len(a.z)) c := f(z, a.x, a.y) @@ -85,7 +80,6 @@ func testFunVV(t *testing.T, msg string, f funVV, a argVV) { } } - func TestFunVV(t *testing.T) { for _, a := range sumVV { arg := a @@ -106,7 +100,6 @@ func TestFunVV(t *testing.T) { } } - type funVW func(z, x []Word, y Word) (c Word) type argVW struct { z, x nat @@ -169,7 +162,6 @@ var rshVW = []argVW{ {nat{_M, _M, _M >> 20}, nat{_M, _M, _M}, 20, _M << (_W - 20) & _M}, } - func testFunVW(t *testing.T, msg string, f funVW, a argVW) { z := make(nat, len(a.z)) c := f(z, a.x, a.y) @@ -184,6 +176,11 @@ func testFunVW(t *testing.T, msg string, f funVW, a argVW) { } } +func makeFunVW(f func(z, x []Word, s uint) (c Word)) funVW { + return func(z, x []Word, s Word) (c Word) { + return f(z, x, uint(s)) + } +} func TestFunVW(t *testing.T) { for _, a := range sumVW { @@ -196,20 +193,23 @@ func TestFunVW(t *testing.T) { testFunVW(t, "subVW", subVW, arg) } + shlVW_g := makeFunVW(shlVU_g) + shlVW := makeFunVW(shlVU) for _, a := range lshVW { arg := a - testFunVW(t, "shlVW_g", shlVW_g, arg) - testFunVW(t, "shlVW", shlVW, arg) + testFunVW(t, "shlVU_g", shlVW_g, arg) + testFunVW(t, "shlVU", shlVW, arg) } + shrVW_g := makeFunVW(shrVU_g) + shrVW := makeFunVW(shrVU) for _, a := range rshVW { arg := a - testFunVW(t, "shrVW_g", shrVW_g, arg) - testFunVW(t, "shrVW", shrVW, arg) + testFunVW(t, "shrVU_g", shrVW_g, arg) + testFunVW(t, "shrVU", shrVW, arg) } } - type funVWW func(z, x []Word, y, r Word) (c Word) type argVWW struct { z, x nat @@ -243,7 +243,6 @@ var prodVWW = []argVWW{ {nat{_M<<7&_M + 1<<6, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 1 << 6, _M >> (_W - 7)}, } - func testFunVWW(t *testing.T, msg string, f funVWW, a argVWW) { z := make(nat, len(a.z)) c := f(z, a.x, a.y, a.r) @@ -258,7 +257,6 @@ func testFunVWW(t *testing.T, msg string, f funVWW, a argVWW) { } } - // TODO(gri) mulAddVWW and divWVW are symmetric operations but // their signature is not symmetric. Try to unify. @@ -285,7 +283,6 @@ func testFunWVW(t *testing.T, msg string, f funWVW, a argWVW) { } } - func TestFunVWW(t *testing.T) { for _, a := range prodVWW { arg := a @@ -300,7 +297,6 @@ func TestFunVWW(t *testing.T) { } } - var mulWWTests = []struct { x, y Word q, r Word @@ -309,7 +305,6 @@ var mulWWTests = []struct { // 32 bit only: {0xc47dfa8c, 50911, 0x98a4, 0x998587f4}, } - func TestMulWW(t *testing.T) { for i, test := range mulWWTests { q, r := mulWW_g(test.x, test.y) @@ -319,7 +314,6 @@ func TestMulWW(t *testing.T) { } } - var mulAddWWWTests = []struct { x, y, c Word q, r Word @@ -331,7 +325,6 @@ var mulAddWWWTests = []struct { {_M, _M, _M, _M, 0}, } - func TestMulAddWWW(t *testing.T) { for i, test := range mulAddWWWTests { q, r := mulAddWWW_g(test.x, test.y, test.c) diff --git a/libgo/go/big/calibrate_test.go b/libgo/go/big/calibrate_test.go index c6cd2e6..1cd93b1 100644 --- a/libgo/go/big/calibrate_test.go +++ b/libgo/go/big/calibrate_test.go @@ -19,10 +19,8 @@ import ( "time" ) - var calibrate = flag.Bool("calibrate", false, "run calibration test") - // measure returns the time to run f func measure(f func()) int64 { const N = 100 @@ -34,7 +32,6 @@ func measure(f func()) int64 { return (stop - start) / N } - func computeThresholds() { fmt.Printf("Multiplication times for varying Karatsuba thresholds\n") fmt.Printf("(run repeatedly for good results)\n") @@ -84,7 +81,6 @@ func computeThresholds() { } } - func TestCalibrate(t *testing.T) { if *calibrate { computeThresholds() diff --git a/libgo/go/big/hilbert_test.go b/libgo/go/big/hilbert_test.go index 66a2121..1a84341 100644 --- a/libgo/go/big/hilbert_test.go +++ b/libgo/go/big/hilbert_test.go @@ -13,13 +13,11 @@ import ( "testing" ) - type matrix struct { n, m int a []*Rat } - func (a *matrix) at(i, j int) *Rat { if !(0 <= i && i < a.n && 0 <= j && j < a.m) { panic("index out of range") @@ -27,7 +25,6 @@ func (a *matrix) at(i, j int) *Rat { return a.a[i*a.m+j] } - func (a *matrix) set(i, j int, x *Rat) { if !(0 <= i && i < a.n && 0 <= j && j < a.m) { panic("index out of range") @@ -35,7 +32,6 @@ func (a *matrix) set(i, j int, x *Rat) { a.a[i*a.m+j] = x } - func newMatrix(n, m int) *matrix { if !(0 <= n && 0 <= m) { panic("illegal matrix") @@ -47,7 +43,6 @@ func newMatrix(n, m int) *matrix { return a } - func newUnit(n int) *matrix { a := newMatrix(n, n) for i := 0; i < n; i++ { @@ -62,7 +57,6 @@ func newUnit(n int) *matrix { return a } - func newHilbert(n int) *matrix { a := newMatrix(n, n) for i := 0; i < n; i++ { @@ -73,7 +67,6 @@ func newHilbert(n int) *matrix { return a } - func newInverseHilbert(n int) *matrix { a := newMatrix(n, n) for i := 0; i < n; i++ { @@ -98,7 +91,6 @@ func newInverseHilbert(n int) *matrix { return a } - func (a *matrix) mul(b *matrix) *matrix { if a.m != b.n { panic("illegal matrix multiply") @@ -116,7 +108,6 @@ func (a *matrix) mul(b *matrix) *matrix { return c } - func (a *matrix) eql(b *matrix) bool { if a.n != b.n || a.m != b.m { return false @@ -131,7 +122,6 @@ func (a *matrix) eql(b *matrix) bool { return true } - func (a *matrix) String() string { s := "" for i := 0; i < a.n; i++ { @@ -143,7 +133,6 @@ func (a *matrix) String() string { return s } - func doHilbert(t *testing.T, n int) { a := newHilbert(n) b := newInverseHilbert(n) @@ -160,12 +149,10 @@ func doHilbert(t *testing.T, n int) { } } - func TestHilbert(t *testing.T) { doHilbert(t, 10) } - func BenchmarkHilbert(b *testing.B) { for i := 0; i < b.N; i++ { doHilbert(nil, 10) diff --git a/libgo/go/big/int.go b/libgo/go/big/int.go index f1ea7b1..701b697 100644 --- a/libgo/go/big/int.go +++ b/libgo/go/big/int.go @@ -8,8 +8,10 @@ package big import ( "fmt" + "io" "os" "rand" + "strings" ) // An Int represents a signed multi-precision integer. @@ -19,10 +21,8 @@ type Int struct { abs nat // absolute value of the integer } - var intOne = &Int{false, natOne} - // Sign returns: // // -1 if x < 0 @@ -39,7 +39,6 @@ func (x *Int) Sign() int { return 1 } - // SetInt64 sets z to x and returns z. func (z *Int) SetInt64(x int64) *Int { neg := false @@ -52,13 +51,11 @@ func (z *Int) SetInt64(x int64) *Int { return z } - // NewInt allocates and returns a new Int set to x. func NewInt(x int64) *Int { return new(Int).SetInt64(x) } - // Set sets z to x and returns z. func (z *Int) Set(x *Int) *Int { z.abs = z.abs.set(x.abs) @@ -66,7 +63,6 @@ func (z *Int) Set(x *Int) *Int { return z } - // Abs sets z to |x| (the absolute value of x) and returns z. func (z *Int) Abs(x *Int) *Int { z.abs = z.abs.set(x.abs) @@ -74,7 +70,6 @@ func (z *Int) Abs(x *Int) *Int { return z } - // Neg sets z to -x and returns z. func (z *Int) Neg(x *Int) *Int { z.abs = z.abs.set(x.abs) @@ -82,7 +77,6 @@ func (z *Int) Neg(x *Int) *Int { return z } - // Add sets z to the sum x+y and returns z. func (z *Int) Add(x, y *Int) *Int { neg := x.neg @@ -104,7 +98,6 @@ func (z *Int) Add(x, y *Int) *Int { return z } - // Sub sets z to the difference x-y and returns z. func (z *Int) Sub(x, y *Int) *Int { neg := x.neg @@ -126,7 +119,6 @@ func (z *Int) Sub(x, y *Int) *Int { return z } - // Mul sets z to the product x*y and returns z. func (z *Int) Mul(x, y *Int) *Int { // x * y == x * y @@ -138,7 +130,6 @@ func (z *Int) Mul(x, y *Int) *Int { return z } - // MulRange sets z to the product of all integers // in the range [a, b] inclusively and returns z. // If a > b (empty range), the result is 1. @@ -162,7 +153,6 @@ func (z *Int) MulRange(a, b int64) *Int { return z } - // Binomial sets z to the binomial coefficient of (n, k) and returns z. func (z *Int) Binomial(n, k int64) *Int { var a, b Int @@ -171,7 +161,6 @@ func (z *Int) Binomial(n, k int64) *Int { return z.Quo(&a, &b) } - // Quo sets z to the quotient x/y for y != 0 and returns z. // If y == 0, a division-by-zero run-time panic occurs. // See QuoRem for more details. @@ -181,7 +170,6 @@ func (z *Int) Quo(x, y *Int) *Int { return z } - // Rem sets z to the remainder x%y for y != 0 and returns z. // If y == 0, a division-by-zero run-time panic occurs. // See QuoRem for more details. @@ -191,7 +179,6 @@ func (z *Int) Rem(x, y *Int) *Int { return z } - // QuoRem sets z to the quotient x/y and r to the remainder x%y // and returns the pair (z, r) for y != 0. // If y == 0, a division-by-zero run-time panic occurs. @@ -209,7 +196,6 @@ func (z *Int) QuoRem(x, y, r *Int) (*Int, *Int) { return z, r } - // Div sets z to the quotient x/y for y != 0 and returns z. // If y == 0, a division-by-zero run-time panic occurs. // See DivMod for more details. @@ -227,7 +213,6 @@ func (z *Int) Div(x, y *Int) *Int { return z } - // Mod sets z to the modulus x%y for y != 0 and returns z. // If y == 0, a division-by-zero run-time panic occurs. // See DivMod for more details. @@ -248,7 +233,6 @@ func (z *Int) Mod(x, y *Int) *Int { return z } - // DivMod sets z to the quotient x div y and m to the modulus x mod y // and returns the pair (z, m) for y != 0. // If y == 0, a division-by-zero run-time panic occurs. @@ -281,7 +265,6 @@ func (z *Int) DivMod(x, y, m *Int) (*Int, *Int) { return z, m } - // Cmp compares x and y and returns: // // -1 if x < y @@ -307,49 +290,197 @@ func (x *Int) Cmp(y *Int) (r int) { return } - func (x *Int) String() string { - s := "" - if x.neg { - s = "-" + switch { + case x == nil: + return "" + case x.neg: + return "-" + x.abs.decimalString() } - return s + x.abs.string(10) + return x.abs.decimalString() } - -func fmtbase(ch int) int { +func charset(ch int) string { switch ch { case 'b': - return 2 + return lowercaseDigits[0:2] case 'o': - return 8 - case 'd': - return 10 + return lowercaseDigits[0:8] + case 'd', 's', 'v': + return lowercaseDigits[0:10] case 'x': - return 16 + return lowercaseDigits[0:16] + case 'X': + return uppercaseDigits[0:16] } - return 10 + return "" // unknown format } +// write count copies of text to s +func writeMultiple(s fmt.State, text string, count int) { + if len(text) > 0 { + b := []byte(text) + for ; count > 0; count-- { + s.Write(b) + } + } +} // Format is a support routine for fmt.Formatter. It accepts -// the formats 'b' (binary), 'o' (octal), 'd' (decimal) and -// 'x' (hexadecimal). +// the formats 'b' (binary), 'o' (octal), 'd' (decimal), 'x' +// (lowercase hexadecimal), and 'X' (uppercase hexadecimal). +// Also supported are the full suite of package fmt's format +// verbs for integral types, including '+', '-', and ' ' +// for sign control, '#' for leading zero in octal and for +// hexadecimal, a leading "0x" or "0X" for "%#x" and "%#X" +// respectively, specification of minimum digits precision, +// output field width, space or zero padding, and left or +// right justification. // func (x *Int) Format(s fmt.State, ch int) { - if x == nil { + cs := charset(ch) + + // special cases + switch { + case cs == "": + // unknown format + fmt.Fprintf(s, "%%!%c(big.Int=%s)", ch, x.String()) + return + case x == nil: fmt.Fprint(s, "") return } - if x.neg { - fmt.Fprint(s, "-") + + // determine sign character + sign := "" + switch { + case x.neg: + sign = "-" + case s.Flag('+'): // supersedes ' ' when both specified + sign = "+" + case s.Flag(' '): + sign = " " + } + + // determine prefix characters for indicating output base + prefix := "" + if s.Flag('#') { + switch ch { + case 'o': // octal + prefix = "0" + case 'x': // hexadecimal + prefix = "0x" + case 'X': + prefix = "0X" + } + } + + // determine digits with base set by len(cs) and digit characters from cs + digits := x.abs.string(cs) + + // number of characters for the three classes of number padding + var left int // space characters to left of digits for right justification ("%8d") + var zeroes int // zero characters (actually cs[0]) as left-most digits ("%.8d") + var right int // space characters to right of digits for left justification ("%-8d") + + // determine number padding from precision: the least number of digits to output + precision, precisionSet := s.Precision() + if precisionSet { + switch { + case len(digits) < precision: + zeroes = precision - len(digits) // count of zero padding + case digits == "0" && precision == 0: + return // print nothing if zero value (x == 0) and zero precision ("." or ".0") + } + } + + // determine field pad from width: the least number of characters to output + length := len(sign) + len(prefix) + zeroes + len(digits) + if width, widthSet := s.Width(); widthSet && length < width { // pad as specified + switch d := width - length; { + case s.Flag('-'): + // pad on the right with spaces; supersedes '0' when both specified + right = d + case s.Flag('0') && !precisionSet: + // pad with zeroes unless precision also specified + zeroes = d + default: + // pad on the left with spaces + left = d + } } - fmt.Fprint(s, x.abs.string(fmtbase(ch))) + + // print number as [left pad][sign][prefix][zero pad][digits][right pad] + writeMultiple(s, " ", left) + writeMultiple(s, sign, 1) + writeMultiple(s, prefix, 1) + writeMultiple(s, "0", zeroes) + writeMultiple(s, digits, 1) + writeMultiple(s, " ", right) } +// scan sets z to the integer value corresponding to the longest possible prefix +// read from r representing a signed integer number in a given conversion base. +// It returns z, the actual conversion base used, and an error, if any. In the +// error case, the value of z is undefined. The syntax follows the syntax of +// integer literals in Go. +// +// The base argument must be 0 or a value from 2 through MaxBase. If the base +// is 0, the string prefix determines the actual conversion base. A prefix of +// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a +// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10. +// +func (z *Int) scan(r io.RuneScanner, base int) (*Int, int, os.Error) { + // determine sign + ch, _, err := r.ReadRune() + if err != nil { + return z, 0, err + } + neg := false + switch ch { + case '-': + neg = true + case '+': // nothing to do + default: + r.UnreadRune() + } -// Int64 returns the int64 representation of z. -// If z cannot be represented in an int64, the result is undefined. + // determine mantissa + z.abs, base, err = z.abs.scan(r, base) + if err != nil { + return z, base, err + } + z.neg = len(z.abs) > 0 && neg // 0 has no sign + + return z, base, nil +} + +// Scan is a support routine for fmt.Scanner; it sets z to the value of +// the scanned number. It accepts the formats 'b' (binary), 'o' (octal), +// 'd' (decimal), 'x' (lowercase hexadecimal), and 'X' (uppercase hexadecimal). +func (z *Int) Scan(s fmt.ScanState, ch int) os.Error { + s.SkipSpace() // skip leading space characters + base := 0 + switch ch { + case 'b': + base = 2 + case 'o': + base = 8 + case 'd': + base = 10 + case 'x', 'X': + base = 16 + case 's', 'v': + // let scan determine the base + default: + return os.NewError("Int.Scan: invalid verb") + } + _, _, err := z.scan(s, base) + return err +} + +// Int64 returns the int64 representation of x. +// If x cannot be represented in an int64, the result is undefined. func (x *Int) Int64() int64 { if len(x.abs) == 0 { return 0 @@ -364,40 +495,25 @@ func (x *Int) Int64() int64 { return v } - // SetString sets z to the value of s, interpreted in the given base, // and returns z and a boolean indicating success. If SetString fails, // the value of z is undefined. // -// If the base argument is 0, the string prefix determines the actual -// conversion base. A prefix of ``0x'' or ``0X'' selects base 16; the -// ``0'' prefix selects base 8, and a ``0b'' or ``0B'' prefix selects -// base 2. Otherwise the selected base is 10. +// The base argument must be 0 or a value from 2 through MaxBase. If the base +// is 0, the string prefix determines the actual conversion base. A prefix of +// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a +// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10. // func (z *Int) SetString(s string, base int) (*Int, bool) { - if len(s) == 0 || base < 0 || base == 1 || 16 < base { - return z, false - } - - neg := s[0] == '-' - if neg || s[0] == '+' { - s = s[1:] - if len(s) == 0 { - return z, false - } - } - - var scanned int - z.abs, _, scanned = z.abs.scan(s, base) - if scanned != len(s) { + r := strings.NewReader(s) + _, _, err := z.scan(r, base) + if err != nil { return z, false } - z.neg = len(z.abs) > 0 && neg // 0 has no sign - - return z, true + _, _, err = r.ReadRune() + return z, err == os.EOF // err == os.EOF => scan consumed all of s } - // 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 { @@ -406,21 +522,18 @@ func (z *Int) SetBytes(buf []byte) *Int { return z } - // Bytes returns the absolute value of z as a big-endian byte slice. func (z *Int) Bytes() []byte { buf := make([]byte, len(z.abs)*_S) return buf[z.abs.bytes(buf):] } - // BitLen returns the length of the absolute value of z in bits. // The bit length of 0 is 0. func (z *Int) BitLen() int { return z.abs.bitLen() } - // Exp sets z = x**y mod m. If m is nil, z = x**y. // See Knuth, volume 2, section 4.6.3. func (z *Int) Exp(x, y, m *Int) *Int { @@ -441,7 +554,6 @@ func (z *Int) Exp(x, y, m *Int) *Int { return z } - // GcdInt sets d to the greatest common divisor of a and b, which must be // positive numbers. // If x and y are not nil, GcdInt sets x and y such that d = a*x + b*y. @@ -500,7 +612,6 @@ func GcdInt(d, x, y, a, b *Int) { *d = *A } - // ProbablyPrime performs n Miller-Rabin tests to check whether z is prime. // If it returns true, z is prime with probability 1 - 1/4^n. // If it returns false, z is not prime. @@ -508,8 +619,7 @@ func ProbablyPrime(z *Int, n int) bool { return !z.neg && z.abs.probablyPrime(n) } - -// Rand sets z to a pseudo-random number in [0, n) and returns z. +// Rand sets z to a pseudo-random number in [0, n) and returns z. func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int { z.neg = false if n.neg == true || len(n.abs) == 0 { @@ -520,7 +630,6 @@ func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int { return z } - // ModInverse sets z to the multiplicative inverse of g in the group ℤ/pℤ (where // p is a prime) and returns z. func (z *Int) ModInverse(g, p *Int) *Int { @@ -534,7 +643,6 @@ func (z *Int) ModInverse(g, p *Int) *Int { return z } - // Lsh sets z = x << n and returns z. func (z *Int) Lsh(x *Int, n uint) *Int { z.abs = z.abs.shl(x.abs, n) @@ -542,7 +650,6 @@ func (z *Int) Lsh(x *Int, n uint) *Int { return z } - // Rsh sets z = x >> n and returns z. func (z *Int) Rsh(x *Int, n uint) *Int { if x.neg { @@ -559,6 +666,39 @@ func (z *Int) Rsh(x *Int, n uint) *Int { return z } +// Bit returns the value of the i'th bit of z. That is, it +// returns (z>>i)&1. The bit index i must be >= 0. +func (z *Int) Bit(i int) uint { + if i < 0 { + panic("negative bit index") + } + if z.neg { + t := nat{}.sub(z.abs, natOne) + return t.bit(uint(i)) ^ 1 + } + + return z.abs.bit(uint(i)) +} + +// SetBit sets the i'th bit of z to bit and returns z. +// That is, if bit is 1 SetBit sets z = x | (1 << i); +// if bit is 0 it sets z = x &^ (1 << i). If bit is not 0 or 1, +// SetBit will panic. +func (z *Int) SetBit(x *Int, i int, b uint) *Int { + if i < 0 { + panic("negative bit index") + } + if x.neg { + t := z.abs.sub(x.abs, natOne) + t = t.setBit(t, uint(i), b^1) + z.abs = t.add(t, natOne) + z.neg = len(z.abs) > 0 + return z + } + z.abs = z.abs.setBit(x.abs, uint(i), b) + z.neg = false + return z +} // And sets z = x & y and returns z. func (z *Int) And(x, y *Int) *Int { @@ -590,7 +730,6 @@ func (z *Int) And(x, y *Int) *Int { return z } - // AndNot sets z = x &^ y and returns z. func (z *Int) AndNot(x, y *Int) *Int { if x.neg == y.neg { @@ -624,7 +763,6 @@ func (z *Int) AndNot(x, y *Int) *Int { return z } - // Or sets z = x | y and returns z. func (z *Int) Or(x, y *Int) *Int { if x.neg == y.neg { @@ -655,7 +793,6 @@ func (z *Int) Or(x, y *Int) *Int { return z } - // Xor sets z = x ^ y and returns z. func (z *Int) Xor(x, y *Int) *Int { if x.neg == y.neg { @@ -686,7 +823,6 @@ func (z *Int) Xor(x, y *Int) *Int { return z } - // Not sets z = ^x and returns z. func (z *Int) Not(x *Int) *Int { if x.neg { @@ -702,15 +838,14 @@ func (z *Int) Not(x *Int) *Int { return z } - // Gob codec version. Permits backward-compatible changes to the encoding. -const version byte = 1 +const intGobVersion 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 + buf := make([]byte, 1+len(z.abs)*_S) // extra byte for version and sign bit i := z.abs.bytes(buf) - 1 // i >= 0 - b := version << 1 // make space for sign bit + b := intGobVersion << 1 // make space for sign bit if z.neg { b |= 1 } @@ -718,14 +853,13 @@ func (z *Int) GobEncode() ([]byte, os.Error) { 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 { + if b>>1 != intGobVersion { return os.NewError(fmt.Sprintf("Int.GobDecode: encoding version %d not supported", b>>1)) } z.neg = b&1 != 0 diff --git a/libgo/go/big/int_test.go b/libgo/go/big/int_test.go index 9c19dd5..03446d6 100644 --- a/libgo/go/big/int_test.go +++ b/libgo/go/big/int_test.go @@ -13,7 +13,6 @@ import ( "testing/quick" ) - func isNormalized(x *Int) bool { if len(x.abs) == 0 { return !x.neg @@ -22,13 +21,11 @@ func isNormalized(x *Int) bool { return x.abs[len(x.abs)-1] != 0 } - type funZZ func(z, x, y *Int) *Int type argZZ struct { z, x, y *Int } - var sumZZ = []argZZ{ {NewInt(0), NewInt(0), NewInt(0)}, {NewInt(1), NewInt(1), NewInt(0)}, @@ -38,7 +35,6 @@ var sumZZ = []argZZ{ {NewInt(-1111111110), NewInt(-123456789), NewInt(-987654321)}, } - var prodZZ = []argZZ{ {NewInt(0), NewInt(0), NewInt(0)}, {NewInt(0), NewInt(1), NewInt(0)}, @@ -47,7 +43,6 @@ var prodZZ = []argZZ{ // TODO(gri) add larger products } - func TestSignZ(t *testing.T) { var zero Int for _, a := range sumZZ { @@ -59,7 +54,6 @@ func TestSignZ(t *testing.T) { } } - func TestSetZ(t *testing.T) { for _, a := range sumZZ { var z Int @@ -73,7 +67,6 @@ func TestSetZ(t *testing.T) { } } - func TestAbsZ(t *testing.T) { var zero Int for _, a := range sumZZ { @@ -90,7 +83,6 @@ func TestAbsZ(t *testing.T) { } } - func testFunZZ(t *testing.T, msg string, f funZZ, a argZZ) { var z Int f(&z, a.x, a.y) @@ -102,7 +94,6 @@ func testFunZZ(t *testing.T, msg string, f funZZ, a argZZ) { } } - func TestSumZZ(t *testing.T) { AddZZ := func(z, x, y *Int) *Int { return z.Add(x, y) } SubZZ := func(z, x, y *Int) *Int { return z.Sub(x, y) } @@ -121,7 +112,6 @@ func TestSumZZ(t *testing.T) { } } - func TestProdZZ(t *testing.T) { MulZZ := func(z, x, y *Int) *Int { return z.Mul(x, y) } for _, a := range prodZZ { @@ -133,7 +123,6 @@ func TestProdZZ(t *testing.T) { } } - // mulBytes returns x*y via grade school multiplication. Both inputs // and the result are assumed to be in big-endian representation (to // match the semantics of Int.Bytes and Int.SetBytes). @@ -166,7 +155,6 @@ func mulBytes(x, y []byte) []byte { return z[i:] } - func checkMul(a, b []byte) bool { var x, y, z1 Int x.SetBytes(a) @@ -179,14 +167,12 @@ func checkMul(a, b []byte) bool { return z1.Cmp(&z2) == 0 } - func TestMul(t *testing.T) { if err := quick.Check(checkMul, nil); err != nil { t.Error(err) } } - var mulRangesZ = []struct { a, b int64 prod string @@ -212,7 +198,6 @@ var mulRangesZ = []struct { }, } - func TestMulRangeZ(t *testing.T) { var tmp Int // test entirely positive ranges @@ -231,7 +216,6 @@ func TestMulRangeZ(t *testing.T) { } } - var stringTests = []struct { in string out string @@ -280,7 +264,6 @@ var stringTests = []struct { {"1001010111", "1001010111", 2, 0x257, true}, } - func format(base int) string { switch base { case 2: @@ -293,7 +276,6 @@ func format(base int) string { return "%d" } - func TestGetString(t *testing.T) { z := new(Int) for i, test := range stringTests { @@ -316,7 +298,6 @@ func TestGetString(t *testing.T) { } } - func TestSetString(t *testing.T) { tmp := new(Int) for i, test := range stringTests { @@ -347,6 +328,212 @@ func TestSetString(t *testing.T) { } } +var formatTests = []struct { + input string + format string + output string +}{ + {"", "%x", ""}, + {"", "%#x", ""}, + {"", "%#y", "%!y(big.Int=)"}, + + {"10", "%b", "1010"}, + {"10", "%o", "12"}, + {"10", "%d", "10"}, + {"10", "%v", "10"}, + {"10", "%x", "a"}, + {"10", "%X", "A"}, + {"-10", "%X", "-A"}, + {"10", "%y", "%!y(big.Int=10)"}, + {"-10", "%y", "%!y(big.Int=-10)"}, + + {"10", "%#b", "1010"}, + {"10", "%#o", "012"}, + {"10", "%#d", "10"}, + {"10", "%#v", "10"}, + {"10", "%#x", "0xa"}, + {"10", "%#X", "0XA"}, + {"-10", "%#X", "-0XA"}, + {"10", "%#y", "%!y(big.Int=10)"}, + {"-10", "%#y", "%!y(big.Int=-10)"}, + + {"1234", "%d", "1234"}, + {"1234", "%3d", "1234"}, + {"1234", "%4d", "1234"}, + {"-1234", "%d", "-1234"}, + {"1234", "% 5d", " 1234"}, + {"1234", "%+5d", "+1234"}, + {"1234", "%-5d", "1234 "}, + {"1234", "%x", "4d2"}, + {"1234", "%X", "4D2"}, + {"-1234", "%3x", "-4d2"}, + {"-1234", "%4x", "-4d2"}, + {"-1234", "%5x", " -4d2"}, + {"-1234", "%-5x", "-4d2 "}, + {"1234", "%03d", "1234"}, + {"1234", "%04d", "1234"}, + {"1234", "%05d", "01234"}, + {"1234", "%06d", "001234"}, + {"-1234", "%06d", "-01234"}, + {"1234", "%+06d", "+01234"}, + {"1234", "% 06d", " 01234"}, + {"1234", "%-6d", "1234 "}, + {"1234", "%-06d", "1234 "}, + {"-1234", "%-06d", "-1234 "}, + + {"1234", "%.3d", "1234"}, + {"1234", "%.4d", "1234"}, + {"1234", "%.5d", "01234"}, + {"1234", "%.6d", "001234"}, + {"-1234", "%.3d", "-1234"}, + {"-1234", "%.4d", "-1234"}, + {"-1234", "%.5d", "-01234"}, + {"-1234", "%.6d", "-001234"}, + + {"1234", "%8.3d", " 1234"}, + {"1234", "%8.4d", " 1234"}, + {"1234", "%8.5d", " 01234"}, + {"1234", "%8.6d", " 001234"}, + {"-1234", "%8.3d", " -1234"}, + {"-1234", "%8.4d", " -1234"}, + {"-1234", "%8.5d", " -01234"}, + {"-1234", "%8.6d", " -001234"}, + + {"1234", "%+8.3d", " +1234"}, + {"1234", "%+8.4d", " +1234"}, + {"1234", "%+8.5d", " +01234"}, + {"1234", "%+8.6d", " +001234"}, + {"-1234", "%+8.3d", " -1234"}, + {"-1234", "%+8.4d", " -1234"}, + {"-1234", "%+8.5d", " -01234"}, + {"-1234", "%+8.6d", " -001234"}, + + {"1234", "% 8.3d", " 1234"}, + {"1234", "% 8.4d", " 1234"}, + {"1234", "% 8.5d", " 01234"}, + {"1234", "% 8.6d", " 001234"}, + {"-1234", "% 8.3d", " -1234"}, + {"-1234", "% 8.4d", " -1234"}, + {"-1234", "% 8.5d", " -01234"}, + {"-1234", "% 8.6d", " -001234"}, + + {"1234", "%.3x", "4d2"}, + {"1234", "%.4x", "04d2"}, + {"1234", "%.5x", "004d2"}, + {"1234", "%.6x", "0004d2"}, + {"-1234", "%.3x", "-4d2"}, + {"-1234", "%.4x", "-04d2"}, + {"-1234", "%.5x", "-004d2"}, + {"-1234", "%.6x", "-0004d2"}, + + {"1234", "%8.3x", " 4d2"}, + {"1234", "%8.4x", " 04d2"}, + {"1234", "%8.5x", " 004d2"}, + {"1234", "%8.6x", " 0004d2"}, + {"-1234", "%8.3x", " -4d2"}, + {"-1234", "%8.4x", " -04d2"}, + {"-1234", "%8.5x", " -004d2"}, + {"-1234", "%8.6x", " -0004d2"}, + + {"1234", "%+8.3x", " +4d2"}, + {"1234", "%+8.4x", " +04d2"}, + {"1234", "%+8.5x", " +004d2"}, + {"1234", "%+8.6x", " +0004d2"}, + {"-1234", "%+8.3x", " -4d2"}, + {"-1234", "%+8.4x", " -04d2"}, + {"-1234", "%+8.5x", " -004d2"}, + {"-1234", "%+8.6x", " -0004d2"}, + + {"1234", "% 8.3x", " 4d2"}, + {"1234", "% 8.4x", " 04d2"}, + {"1234", "% 8.5x", " 004d2"}, + {"1234", "% 8.6x", " 0004d2"}, + {"1234", "% 8.7x", " 00004d2"}, + {"1234", "% 8.8x", " 000004d2"}, + {"-1234", "% 8.3x", " -4d2"}, + {"-1234", "% 8.4x", " -04d2"}, + {"-1234", "% 8.5x", " -004d2"}, + {"-1234", "% 8.6x", " -0004d2"}, + {"-1234", "% 8.7x", "-00004d2"}, + {"-1234", "% 8.8x", "-000004d2"}, + + {"1234", "%-8.3d", "1234 "}, + {"1234", "%-8.4d", "1234 "}, + {"1234", "%-8.5d", "01234 "}, + {"1234", "%-8.6d", "001234 "}, + {"1234", "%-8.7d", "0001234 "}, + {"1234", "%-8.8d", "00001234"}, + {"-1234", "%-8.3d", "-1234 "}, + {"-1234", "%-8.4d", "-1234 "}, + {"-1234", "%-8.5d", "-01234 "}, + {"-1234", "%-8.6d", "-001234 "}, + {"-1234", "%-8.7d", "-0001234"}, + {"-1234", "%-8.8d", "-00001234"}, + + {"16777215", "%b", "111111111111111111111111"}, // 2**24 - 1 + + {"0", "%.d", ""}, + {"0", "%.0d", ""}, + {"0", "%3.d", ""}, +} + +func TestFormat(t *testing.T) { + for i, test := range formatTests { + var x *Int + if test.input != "" { + var ok bool + x, ok = new(Int).SetString(test.input, 0) + if !ok { + t.Errorf("#%d failed reading input %s", i, test.input) + } + } + output := fmt.Sprintf(test.format, x) + if output != test.output { + t.Errorf("#%d got %q; want %q, {%q, %q, %q}", i, output, test.output, test.input, test.format, test.output) + } + } +} + +var scanTests = []struct { + input string + format string + output string + remaining int +}{ + {"1010", "%b", "10", 0}, + {"0b1010", "%v", "10", 0}, + {"12", "%o", "10", 0}, + {"012", "%v", "10", 0}, + {"10", "%d", "10", 0}, + {"10", "%v", "10", 0}, + {"a", "%x", "10", 0}, + {"0xa", "%v", "10", 0}, + {"A", "%X", "10", 0}, + {"-A", "%X", "-10", 0}, + {"+0b1011001", "%v", "89", 0}, + {"0xA", "%v", "10", 0}, + {"0 ", "%v", "0", 1}, + {"2+3", "%v", "2", 2}, + {"0XABC 12", "%v", "2748", 3}, +} + +func TestScan(t *testing.T) { + var buf bytes.Buffer + for i, test := range scanTests { + x := new(Int) + buf.Reset() + buf.WriteString(test.input) + if _, err := fmt.Fscanf(&buf, test.format, x); err != nil { + t.Errorf("#%d error: %s", i, err.String()) + } + if x.String() != test.output { + t.Errorf("#%d got %s; want %s", i, x.String(), test.output) + } + if buf.Len() != test.remaining { + t.Errorf("#%d got %d bytes remaining; want %d", i, buf.Len(), test.remaining) + } + } +} // Examples from the Go Language Spec, section "Arithmetic operators" var divisionSignsTests = []struct { @@ -362,7 +549,6 @@ var divisionSignsTests = []struct { {8, 4, 2, 0, 2, 0}, } - func TestDivisionSigns(t *testing.T) { for i, test := range divisionSignsTests { x := NewInt(test.x) @@ -420,7 +606,6 @@ func TestDivisionSigns(t *testing.T) { } } - func checkSetBytes(b []byte) bool { hex1 := hex.EncodeToString(new(Int).SetBytes(b).Bytes()) hex2 := hex.EncodeToString(b) @@ -436,27 +621,23 @@ func checkSetBytes(b []byte) bool { return hex1 == hex2 } - func TestSetBytes(t *testing.T) { if err := quick.Check(checkSetBytes, nil); err != nil { t.Error(err) } } - func checkBytes(b []byte) bool { b2 := new(Int).SetBytes(b).Bytes() return bytes.Compare(b, b2) == 0 } - func TestBytes(t *testing.T) { if err := quick.Check(checkSetBytes, nil); err != nil { t.Error(err) } } - func checkQuo(x, y []byte) bool { u := new(Int).SetBytes(x) v := new(Int).SetBytes(y) @@ -479,7 +660,6 @@ func checkQuo(x, y []byte) bool { return uprime.Cmp(u) == 0 } - var quoTests = []struct { x, y string q, r string @@ -498,7 +678,6 @@ var quoTests = []struct { }, } - func TestQuo(t *testing.T) { if err := quick.Check(checkQuo, nil); err != nil { t.Error(err) @@ -519,7 +698,6 @@ func TestQuo(t *testing.T) { } } - func TestQuoStepD6(t *testing.T) { // See Knuth, Volume 2, section 4.3.1, exercise 21. This code exercises // a code path which only triggers 1 in 10^{-19} cases. @@ -539,7 +717,6 @@ func TestQuoStepD6(t *testing.T) { } } - var bitLenTests = []struct { in string out int @@ -558,7 +735,6 @@ var bitLenTests = []struct { {"-0x4000000000000000000000", 87}, } - func TestBitLen(t *testing.T) { for i, test := range bitLenTests { x, ok := new(Int).SetString(test.in, 0) @@ -573,7 +749,6 @@ func TestBitLen(t *testing.T) { } } - var expTests = []struct { x, y, m string out string @@ -598,7 +773,6 @@ var expTests = []struct { }, } - func TestExp(t *testing.T) { for i, test := range expTests { x, ok1 := new(Int).SetString(test.x, 0) @@ -629,7 +803,6 @@ func TestExp(t *testing.T) { } } - func checkGcd(aBytes, bBytes []byte) bool { a := new(Int).SetBytes(aBytes) b := new(Int).SetBytes(bBytes) @@ -646,7 +819,6 @@ func checkGcd(aBytes, bBytes []byte) bool { return x.Cmp(d) == 0 } - var gcdTests = []struct { a, b int64 d, x, y int64 @@ -654,7 +826,6 @@ var gcdTests = []struct { {120, 23, 1, -9, 47}, } - func TestGcd(t *testing.T) { for i, test := range gcdTests { a := NewInt(test.a) @@ -680,7 +851,6 @@ func TestGcd(t *testing.T) { quick.Check(checkGcd, nil) } - var primes = []string{ "2", "3", @@ -706,7 +876,6 @@ var primes = []string{ "203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123", } - var composites = []string{ "21284175091214687912771199898307297748211672914763848041968395774954376176754", "6084766654921918907427900243509372380954290099172559290432744450051395395951", @@ -714,7 +883,6 @@ var composites = []string{ "82793403787388584738507275144194252681", } - func TestProbablyPrime(t *testing.T) { nreps := 20 if testing.Short() { @@ -738,14 +906,12 @@ func TestProbablyPrime(t *testing.T) { } } - type intShiftTest struct { in string shift uint out string } - var rshTests = []intShiftTest{ {"0", 0, "0"}, {"-0", 0, "0"}, @@ -773,7 +939,6 @@ var rshTests = []intShiftTest{ {"340282366920938463463374607431768211456", 128, "1"}, } - func TestRsh(t *testing.T) { for i, test := range rshTests { in, _ := new(Int).SetString(test.in, 10) @@ -789,7 +954,6 @@ func TestRsh(t *testing.T) { } } - func TestRshSelf(t *testing.T) { for i, test := range rshTests { z, _ := new(Int).SetString(test.in, 10) @@ -805,7 +969,6 @@ func TestRshSelf(t *testing.T) { } } - var lshTests = []intShiftTest{ {"0", 0, "0"}, {"0", 1, "0"}, @@ -828,7 +991,6 @@ var lshTests = []intShiftTest{ {"1", 128, "340282366920938463463374607431768211456"}, } - func TestLsh(t *testing.T) { for i, test := range lshTests { in, _ := new(Int).SetString(test.in, 10) @@ -844,7 +1006,6 @@ func TestLsh(t *testing.T) { } } - func TestLshSelf(t *testing.T) { for i, test := range lshTests { z, _ := new(Int).SetString(test.in, 10) @@ -860,7 +1021,6 @@ func TestLshSelf(t *testing.T) { } } - func TestLshRsh(t *testing.T) { for i, test := range rshTests { in, _ := new(Int).SetString(test.in, 10) @@ -888,7 +1048,6 @@ func TestLshRsh(t *testing.T) { } } - var int64Tests = []int64{ 0, 1, @@ -902,7 +1061,6 @@ var int64Tests = []int64{ -9223372036854775808, } - func TestInt64(t *testing.T) { for i, testVal := range int64Tests { in := NewInt(testVal) @@ -914,7 +1072,6 @@ func TestInt64(t *testing.T) { } } - var bitwiseTests = []struct { x, y string and, or, xor, andNot string @@ -958,7 +1115,6 @@ var bitwiseTests = []struct { }, } - type bitFun func(z, x, y *Int) *Int func testBitFun(t *testing.T, msg string, f bitFun, x, y *Int, exp string) { @@ -971,7 +1127,6 @@ func testBitFun(t *testing.T, msg string, f bitFun, x, y *Int, exp string) { } } - func testBitFunSelf(t *testing.T, msg string, f bitFun, x, y *Int, exp string) { self := new(Int) self.Set(x) @@ -984,6 +1139,142 @@ func testBitFunSelf(t *testing.T, msg string, f bitFun, x, y *Int, exp string) { } } +func altBit(x *Int, i int) uint { + z := new(Int).Rsh(x, uint(i)) + z = z.And(z, NewInt(1)) + if z.Cmp(new(Int)) != 0 { + return 1 + } + return 0 +} + +func altSetBit(z *Int, x *Int, i int, b uint) *Int { + one := NewInt(1) + m := one.Lsh(one, uint(i)) + switch b { + case 1: + return z.Or(x, m) + case 0: + return z.AndNot(x, m) + } + panic("set bit is not 0 or 1") +} + +func testBitset(t *testing.T, x *Int) { + n := x.BitLen() + z := new(Int).Set(x) + z1 := new(Int).Set(x) + for i := 0; i < n+10; i++ { + old := z.Bit(i) + old1 := altBit(z1, i) + if old != old1 { + t.Errorf("bitset: inconsistent value for Bit(%s, %d), got %v want %v", z1, i, old, old1) + } + z := new(Int).SetBit(z, i, 1) + z1 := altSetBit(new(Int), z1, i, 1) + if z.Bit(i) == 0 { + t.Errorf("bitset: bit %d of %s got 0 want 1", i, x) + } + if z.Cmp(z1) != 0 { + t.Errorf("bitset: inconsistent value after SetBit 1, got %s want %s", z, z1) + } + z.SetBit(z, i, 0) + altSetBit(z1, z1, i, 0) + if z.Bit(i) != 0 { + t.Errorf("bitset: bit %d of %s got 1 want 0", i, x) + } + if z.Cmp(z1) != 0 { + t.Errorf("bitset: inconsistent value after SetBit 0, got %s want %s", z, z1) + } + altSetBit(z1, z1, i, old) + z.SetBit(z, i, old) + if z.Cmp(z1) != 0 { + t.Errorf("bitset: inconsistent value after SetBit old, got %s want %s", z, z1) + } + } + if z.Cmp(x) != 0 { + t.Errorf("bitset: got %s want %s", z, x) + } +} + +var bitsetTests = []struct { + x string + i int + b uint +}{ + {"0", 0, 0}, + {"0", 200, 0}, + {"1", 0, 1}, + {"1", 1, 0}, + {"-1", 0, 1}, + {"-1", 200, 1}, + {"0x2000000000000000000000000000", 108, 0}, + {"0x2000000000000000000000000000", 109, 1}, + {"0x2000000000000000000000000000", 110, 0}, + {"-0x2000000000000000000000000001", 108, 1}, + {"-0x2000000000000000000000000001", 109, 0}, + {"-0x2000000000000000000000000001", 110, 1}, +} + +func TestBitSet(t *testing.T) { + for _, test := range bitwiseTests { + x := new(Int) + x.SetString(test.x, 0) + testBitset(t, x) + x = new(Int) + x.SetString(test.y, 0) + testBitset(t, x) + } + for i, test := range bitsetTests { + x := new(Int) + x.SetString(test.x, 0) + b := x.Bit(test.i) + if b != test.b { + + t.Errorf("#%d want %v got %v", i, test.b, b) + } + } +} + +func BenchmarkBitset(b *testing.B) { + z := new(Int) + z.SetBit(z, 512, 1) + b.ResetTimer() + b.StartTimer() + for i := b.N - 1; i >= 0; i-- { + z.SetBit(z, i&512, 1) + } +} + +func BenchmarkBitsetNeg(b *testing.B) { + z := NewInt(-1) + z.SetBit(z, 512, 0) + b.ResetTimer() + b.StartTimer() + for i := b.N - 1; i >= 0; i-- { + z.SetBit(z, i&512, 0) + } +} + +func BenchmarkBitsetOrig(b *testing.B) { + z := new(Int) + altSetBit(z, z, 512, 1) + b.ResetTimer() + b.StartTimer() + for i := b.N - 1; i >= 0; i-- { + altSetBit(z, z, i&512, 1) + } +} + +func BenchmarkBitsetNegOrig(b *testing.B) { + z := NewInt(-1) + altSetBit(z, z, 512, 0) + b.ResetTimer() + b.StartTimer() + for i := b.N - 1; i >= 0; i-- { + altSetBit(z, z, i&512, 0) + } +} func TestBitwise(t *testing.T) { x := new(Int) @@ -1003,7 +1294,6 @@ func TestBitwise(t *testing.T) { } } - var notTests = []struct { in string out string @@ -1037,7 +1327,6 @@ func TestNot(t *testing.T) { } } - var modInverseTests = []struct { element string prime string @@ -1062,7 +1351,7 @@ func TestModInverse(t *testing.T) { } } - +// used by TestIntGobEncoding and TestRatGobEncoding var gobEncodingTests = []string{ "0", "1", @@ -1073,7 +1362,7 @@ var gobEncodingTests = []string{ "298472983472983471903246121093472394872319615612417471234712061", } -func TestGobEncoding(t *testing.T) { +func TestIntGobEncoding(t *testing.T) { var medium bytes.Buffer enc := gob.NewEncoder(&medium) dec := gob.NewDecoder(&medium) @@ -1081,7 +1370,8 @@ func TestGobEncoding(t *testing.T) { for j := 0; j < 2; j++ { medium.Reset() // empty buffer for each test case (in case of failures) stest := test - if j == 0 { + if j != 0 { + // negative numbers stest = "-" + test } var tx Int diff --git a/libgo/go/big/nat.go b/libgo/go/big/nat.go index 4848d42..be3aff2 100644 --- a/libgo/go/big/nat.go +++ b/libgo/go/big/nat.go @@ -18,7 +18,11 @@ package big // These are the building blocks for the operations on signed integers // and rationals. -import "rand" +import ( + "io" + "os" + "rand" +) // An unsigned integer x of the form // @@ -40,14 +44,12 @@ var ( natTen = nat{10} ) - func (z nat) clear() { for i := range z { z[i] = 0 } } - func (z nat) norm() nat { i := len(z) for i > 0 && z[i-1] == 0 { @@ -56,7 +58,6 @@ func (z nat) norm() nat { return z[0:i] } - func (z nat) make(n int) nat { if n <= cap(z) { return z[0:n] // reuse z @@ -67,7 +68,6 @@ func (z nat) make(n int) nat { return make(nat, n, n+e) } - func (z nat) setWord(x Word) nat { if x == 0 { return z.make(0) @@ -77,7 +77,6 @@ func (z nat) setWord(x Word) nat { return z } - func (z nat) setUint64(x uint64) nat { // single-digit values if w := Word(x); uint64(w) == x { @@ -100,14 +99,12 @@ func (z nat) setUint64(x uint64) nat { return z } - func (z nat) set(x nat) nat { z = z.make(len(x)) copy(z, x) return z } - func (z nat) add(x, y nat) nat { m := len(x) n := len(y) @@ -134,7 +131,6 @@ func (z nat) add(x, y nat) nat { return z.norm() } - func (z nat) sub(x, y nat) nat { m := len(x) n := len(y) @@ -163,7 +159,6 @@ func (z nat) sub(x, y nat) nat { return z.norm() } - func (x nat) cmp(y nat) (r int) { m := len(x) n := len(y) @@ -191,7 +186,6 @@ func (x nat) cmp(y nat) (r int) { return } - func (z nat) mulAddWW(x nat, y, r Word) nat { m := len(x) if m == 0 || y == 0 { @@ -205,7 +199,6 @@ func (z nat) mulAddWW(x nat, y, r Word) nat { return z.norm() } - // basicMul multiplies x and y and leaves the result in z. // The (non-normalized) result is placed in z[0 : len(x) + len(y)]. func basicMul(z, x, y nat) { @@ -217,7 +210,6 @@ func basicMul(z, x, y nat) { } } - // Fast version of z[0:n+n>>1].add(z[0:n+n>>1], x[0:n]) w/o bounds checks. // Factored out for readability - do not use outside karatsuba. func karatsubaAdd(z, x nat, n int) { @@ -226,7 +218,6 @@ func karatsubaAdd(z, x nat, n int) { } } - // Like karatsubaAdd, but does subtract. func karatsubaSub(z, x nat, n int) { if c := subVV(z[0:n], z, x); c != 0 { @@ -234,7 +225,6 @@ func karatsubaSub(z, x nat, n int) { } } - // Operands that are shorter than karatsubaThreshold are multiplied using // "grade school" multiplication; for longer operands the Karatsuba algorithm // is used. @@ -339,13 +329,11 @@ func karatsuba(z, x, y nat) { } } - // alias returns true if x and y share the same base array. func alias(x, y nat) bool { return cap(x) > 0 && cap(y) > 0 && &x[0:cap(x)][cap(x)-1] == &y[0:cap(y)][cap(y)-1] } - // addAt implements z += x*(1<<(_W*i)); z must be long enough. // (we don't use nat.add because we need z to stay the same // slice, and we don't need to normalize z after each addition) @@ -360,7 +348,6 @@ func addAt(z, x nat, i int) { } } - func max(x, y int) int { if x > y { return x @@ -368,7 +355,6 @@ func max(x, y int) int { return y } - // karatsubaLen computes an approximation to the maximum k <= n such that // k = p<= 0. Thus, the // result is the largest number that can be divided repeatedly by 2 before @@ -382,7 +368,6 @@ func karatsubaLen(n int) int { return n << i } - func (z nat) mul(x, y nat) nat { m := len(x) n := len(y) @@ -450,7 +435,6 @@ func (z nat) mul(x, y nat) nat { return z.norm() } - // mulRange computes the product of all the unsigned integers in the // range [a, b] inclusively. If a > b (empty range), the result is 1. func (z nat) mulRange(a, b uint64) nat { @@ -469,7 +453,6 @@ func (z nat) mulRange(a, b uint64) nat { return z.mul(nat(nil).mulRange(a, m), nat(nil).mulRange(m+1, b)) } - // q = (x-r)/y, with 0 <= r < y func (z nat) divW(x nat, y Word) (q nat, r Word) { m := len(x) @@ -490,7 +473,6 @@ func (z nat) divW(x nat, y Word) (q nat, r Word) { return } - func (z nat) div(z2, u, v nat) (q, r nat) { if len(v) == 0 { panic("division by zero") @@ -518,7 +500,6 @@ func (z nat) div(z2, u, v nat) (q, r nat) { return } - // q = (uIn-r)/v, with 0 <= r < y // Uses z as storage for q, and u as storage for r if possible. // See Knuth, Volume 2, section 4.3.1, Algorithm D. @@ -545,9 +526,14 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) { u.clear() // D1. - shift := Word(leadingZeros(v[n-1])) - shlVW(v, v, shift) - u[len(uIn)] = shlVW(u[0:len(uIn)], uIn, shift) + shift := leadingZeros(v[n-1]) + if shift > 0 { + // do not modify v, it may be used by another goroutine simultaneously + v1 := make(nat, n) + shlVU(v1, v, shift) + v = v1 + } + u[len(uIn)] = shlVU(u[0:len(uIn)], uIn, shift) // D2. for j := m; j >= 0; j-- { @@ -586,14 +572,12 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) { } q = q.norm() - shrVW(u, u, shift) - shrVW(v, v, shift) + shrVU(u, u, shift) r = u.norm() return q, r } - // Length of x in bits. x must be normalized. func (x nat) bitLen() int { if i := len(x) - 1; i >= 0 { @@ -602,103 +586,253 @@ func (x nat) bitLen() int { return 0 } +// MaxBase is the largest number base accepted for string conversions. +const MaxBase = 'z' - 'a' + 10 + 1 // = hexValue('z') + 1 -func hexValue(ch byte) int { - var d byte + +func hexValue(ch int) Word { + d := MaxBase + 1 // illegal base switch { case '0' <= ch && ch <= '9': d = ch - '0' - case 'a' <= ch && ch <= 'f': + case 'a' <= ch && ch <= 'z': d = ch - 'a' + 10 - case 'A' <= ch && ch <= 'F': + case 'A' <= ch && ch <= 'Z': d = ch - 'A' + 10 - default: - return -1 } - return int(d) + return Word(d) } - -// scan returns the natural number corresponding to the -// longest possible prefix of s representing a natural number in a -// given conversion base, the actual conversion base used, and the -// prefix length. The syntax of natural numbers follows the syntax -// of unsigned integer literals in Go. +// scan sets z to the natural number corresponding to the longest possible prefix +// read from r representing an unsigned integer in a given conversion base. +// It returns z, the actual conversion base used, and an error, if any. In the +// error case, the value of z is undefined. The syntax follows the syntax of +// unsigned integer literals in Go. // -// If the base argument is 0, the string prefix determines the actual -// conversion base. A prefix of ``0x'' or ``0X'' selects base 16; the -// ``0'' prefix selects base 8, and a ``0b'' or ``0B'' prefix selects -// base 2. Otherwise the selected base is 10. +// The base argument must be 0 or a value from 2 through MaxBase. If the base +// is 0, the string prefix determines the actual conversion base. A prefix of +// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a +// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10. // -func (z nat) scan(s string, base int) (nat, int, int) { +func (z nat) scan(r io.RuneScanner, base int) (nat, int, os.Error) { + // reject illegal bases + if base < 0 || base == 1 || MaxBase < base { + return z, 0, os.NewError("illegal number base") + } + + // one char look-ahead + ch, _, err := r.ReadRune() + if err != nil { + return z, 0, err + } + // determine base if necessary - i, n := 0, len(s) + b := Word(base) if base == 0 { - base = 10 - if n > 0 && s[0] == '0' { - base, i = 8, 1 - if n > 1 { - switch s[1] { + b = 10 + if ch == '0' { + switch ch, _, err = r.ReadRune(); err { + case nil: + b = 8 + switch ch { case 'x', 'X': - base, i = 16, 2 + b = 16 case 'b', 'B': - base, i = 2, 2 + b = 2 } + if b == 2 || b == 16 { + if ch, _, err = r.ReadRune(); err != nil { + return z, 0, err + } + } + case os.EOF: + return z, 10, nil + default: + return z, 10, err } } } - // reject illegal bases or strings consisting only of prefix - if base < 2 || 16 < base || (base != 8 && i >= n) { - return z, 0, 0 - } - // convert string + // - group as many digits d as possible together into a "super-digit" dd with "super-base" bb + // - only when bb does not fit into a word anymore, do a full number mulAddWW using bb and dd z = z.make(0) - for ; i < n; i++ { - d := hexValue(s[i]) - if 0 <= d && d < base { - z = z.mulAddWW(z, Word(base), Word(d)) + bb := Word(1) + dd := Word(0) + for max := _M / b; ; { + d := hexValue(ch) + if d >= b { + r.UnreadRune() // ch does not belong to number anymore + break + } + + if bb <= max { + bb *= b + dd = dd*b + d } else { + // bb * b would overflow + z = z.mulAddWW(z, bb, dd) + bb = b + dd = d + } + + if ch, _, err = r.ReadRune(); err != nil { + if err != os.EOF { + return z, int(b), err + } break } } - return z.norm(), base, i + switch { + case bb > 1: + // there was at least one mantissa digit + z = z.mulAddWW(z, bb, dd) + case base == 0 && b == 8: + // there was only the octal prefix 0 (possibly followed by digits > 7); + // return base 10, not 8 + return z, 10, nil + case base != 0 || b != 8: + // there was neither a mantissa digit nor the octal prefix 0 + return z, int(b), os.NewError("syntax error scanning number") + } + + return z.norm(), int(b), nil } +// Character sets for string conversion. +const ( + lowercaseDigits = "0123456789abcdefghijklmnopqrstuvwxyz" + uppercaseDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" +) -// string converts x to a string for a given base, with 2 <= base <= 16. -// TODO(gri) in the style of the other routines, perhaps this should take -// a []byte buffer and return it -func (x nat) string(base int) string { - if base < 2 || 16 < base { - panic("illegal base") - } +// decimalString returns a decimal representation of x. +// It calls x.string with the charset "0123456789". +func (x nat) decimalString() string { + return x.string(lowercaseDigits[0:10]) +} - if len(x) == 0 { - return "0" +// string converts x to a string using digits from a charset; a digit with +// value d is represented by charset[d]. The conversion base is determined +// by len(charset), which must be >= 2. +func (x nat) string(charset string) string { + b := Word(len(charset)) + + // special cases + switch { + case b < 2 || b > 256: + panic("illegal base") + case len(x) == 0: + return string(charset[0]) } // allocate buffer for conversion - i := x.bitLen()/log2(Word(base)) + 1 // +1: round up + i := x.bitLen()/log2(b) + 1 // +1: round up s := make([]byte, i) - // don't destroy x + // special case: power of two bases can avoid divisions completely + if b == b&-b { + // shift is base-b digit size in bits + shift := uint(trailingZeroBits(b)) // shift > 0 because b >= 2 + mask := Word(1)<= shift { + i-- + s[i] = charset[w&mask] + w >>= shift + nbits -= shift + } + + // convert any partial leading digit and advance to next word + if nbits == 0 { + // no partial digit remaining, just advance + w = x[k] + nbits = _W + } else { + // partial digit in current (k-1) and next (k) word + w |= x[k] << nbits + i-- + s[i] = charset[w&mask] + + // advance + w = x[k] >> (shift - nbits) + nbits = _W - (shift - nbits) + } + } + + // convert digits of most-significant word (omit leading zeros) + for nbits >= 0 && w != 0 { + i-- + s[i] = charset[w&mask] + w >>= shift + nbits -= shift + } + + return string(s[i:]) + } + + // general case: extract groups of digits by multiprecision division + + // maximize ndigits where b**ndigits < 2^_W; bb (big base) is b**ndigits + bb := Word(1) + ndigits := 0 + for max := Word(_M / b); bb <= max; bb *= b { + ndigits++ + } + + // preserve x, create local copy for use in repeated divisions q := nat(nil).set(x) + var r Word // convert - for len(q) > 0 { - i-- - var r Word - q, r = q.divW(q, Word(base)) - s[i] = "0123456789abcdef"[r] + if b == 10 { // hard-coding for 10 here speeds this up by 1.25x + for len(q) > 0 { + // extract least significant, base bb "digit" + q, r = q.divW(q, bb) // N.B. >82% of time is here. Optimize divW + if len(q) == 0 { + // skip leading zeros in most-significant group of digits + for j := 0; j < ndigits && r != 0; j++ { + i-- + s[i] = charset[r%10] + r /= 10 + } + } else { + for j := 0; j < ndigits; j++ { + i-- + s[i] = charset[r%10] + r /= 10 + } + } + } + } else { + for len(q) > 0 { + // extract least significant group of digits + q, r = q.divW(q, bb) // N.B. >82% of time is here. Optimize divW + if len(q) == 0 { + // skip leading zeros in most-significant group of digits + for j := 0; j < ndigits && r != 0; j++ { + i-- + s[i] = charset[r%b] + r /= b + } + } else { + for j := 0; j < ndigits; j++ { + i-- + s[i] = charset[r%b] + r /= b + } + } + } } return string(s[i:]) } - const deBruijn32 = 0x077CB531 var deBruijn32Lookup = []byte{ @@ -721,7 +855,7 @@ var deBruijn64Lookup = []byte{ func trailingZeroBits(x Word) int { // x & -x leaves only the right-most bit set in the word. Let k be the // index of that bit. Since only a single bit is set, the value is two - // to the power of k. Multipling by a power of two is equivalent to + // to the power of k. Multiplying by a power of two is equivalent to // left shifting, in this case by k bits. The de Bruijn constant is // such that all six bit, consecutive substrings are distinct. // Therefore, if we have a left shifted version of this constant we can @@ -739,7 +873,6 @@ func trailingZeroBits(x Word) int { return 0 } - // z = x << s func (z nat) shl(x nat, s uint) nat { m := len(x) @@ -750,13 +883,12 @@ func (z nat) shl(x nat, s uint) nat { n := m + int(s/_W) z = z.make(n + 1) - z[n] = shlVW(z[n-m:n], x, Word(s%_W)) + z[n] = shlVU(z[n-m:n], x, s%_W) z[0 : n-m].clear() return z.norm() } - // z = x >> s func (z nat) shr(x nat, s uint) nat { m := len(x) @@ -767,11 +899,45 @@ func (z nat) shr(x nat, s uint) nat { // n > 0 z = z.make(n) - shrVW(z, x[m-n:], Word(s%_W)) + shrVU(z, x[m-n:], s%_W) return z.norm() } +func (z nat) setBit(x nat, i uint, b uint) nat { + j := int(i / _W) + m := Word(1) << (i % _W) + n := len(x) + switch b { + case 0: + z = z.make(n) + copy(z, x) + if j >= n { + // no need to grow + return z + } + z[j] &^= m + return z.norm() + case 1: + if j >= n { + n = j + 1 + } + z = z.make(n) + copy(z, x) + z[j] |= m + // no need to normalize + return z + } + panic("set bit is not 0 or 1") +} + +func (z nat) bit(i uint) uint { + j := int(i / _W) + if j >= len(z) { + return 0 + } + return uint(z[j] >> (i % _W) & 1) +} func (z nat) and(x, y nat) nat { m := len(x) @@ -789,7 +955,6 @@ func (z nat) and(x, y nat) nat { return z.norm() } - func (z nat) andNot(x, y nat) nat { m := len(x) n := len(y) @@ -807,7 +972,6 @@ func (z nat) andNot(x, y nat) nat { return z.norm() } - func (z nat) or(x, y nat) nat { m := len(x) n := len(y) @@ -827,7 +991,6 @@ func (z nat) or(x, y nat) nat { return z.norm() } - func (z nat) xor(x, y nat) nat { m := len(x) n := len(y) @@ -847,10 +1010,10 @@ func (z nat) xor(x, y nat) nat { return z.norm() } - // greaterThan returns true iff (x1<<_W + x2) > (y1<<_W + y2) -func greaterThan(x1, x2, y1, y2 Word) bool { return x1 > y1 || x1 == y1 && x2 > y2 } - +func greaterThan(x1, x2, y1, y2 Word) bool { + return x1 > y1 || x1 == y1 && x2 > y2 +} // modW returns x % d. func (x nat) modW(d Word) (r Word) { @@ -860,30 +1023,29 @@ func (x nat) modW(d Word) (r Word) { return divWVW(q, 0, x, d) } - -// powersOfTwoDecompose finds q and k such that q * 1<= len(z)*_S. The value of z is encoded in the // slice buf[i:]. The number i of unused bytes at the beginning of @@ -1088,7 +1247,6 @@ func (z nat) bytes(buf []byte) (i int) { 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 { diff --git a/libgo/go/big/nat_test.go b/libgo/go/big/nat_test.go index 0bcb945..71d0860 100644 --- a/libgo/go/big/nat_test.go +++ b/libgo/go/big/nat_test.go @@ -4,7 +4,12 @@ package big -import "testing" +import ( + "fmt" + "os" + "strings" + "testing" +) var cmpTests = []struct { x, y nat @@ -26,7 +31,6 @@ var cmpTests = []struct { {nat{34986, 41, 105, 1957}, nat{56, 7458, 104, 1957}, 1}, } - func TestCmp(t *testing.T) { for i, a := range cmpTests { r := a.x.cmp(a.y) @@ -36,13 +40,11 @@ func TestCmp(t *testing.T) { } } - type funNN func(z, x, y nat) nat type argNN struct { z, x, y nat } - var sumNN = []argNN{ {}, {nat{1}, nil, nat{1}}, @@ -52,7 +54,6 @@ var sumNN = []argNN{ {nat{0, 0, 0, 1}, nat{0, 0, _M}, nat{0, 0, 1}}, } - var prodNN = []argNN{ {}, {nil, nil, nil}, @@ -64,7 +65,6 @@ var prodNN = []argNN{ {nat{4, 11, 20, 30, 20, 11, 4}, nat{1, 2, 3, 4}, nat{4, 3, 2, 1}}, } - func TestSet(t *testing.T) { for _, a := range sumNN { z := nat(nil).set(a.z) @@ -74,7 +74,6 @@ func TestSet(t *testing.T) { } } - func testFunNN(t *testing.T, msg string, f funNN, a argNN) { z := f(nil, a.x, a.y) if z.cmp(a.z) != 0 { @@ -82,7 +81,6 @@ func testFunNN(t *testing.T, msg string, f funNN, a argNN) { } } - func TestFunNN(t *testing.T) { for _, a := range sumNN { arg := a @@ -107,7 +105,6 @@ func TestFunNN(t *testing.T) { } } - var mulRangesN = []struct { a, b uint64 prod string @@ -130,17 +127,15 @@ var mulRangesN = []struct { }, } - func TestMulRangeN(t *testing.T) { for i, r := range mulRangesN { - prod := nat(nil).mulRange(r.a, r.b).string(10) + prod := nat(nil).mulRange(r.a, r.b).decimalString() if prod != r.prod { t.Errorf("#%d: got %s; want %s", i, prod, r.prod) } } } - var mulArg, mulTmp nat func init() { @@ -151,7 +146,6 @@ func init() { } } - func benchmarkMulLoad() { for j := 1; j <= 10; j++ { x := mulArg[0 : j*100] @@ -159,46 +153,376 @@ func benchmarkMulLoad() { } } - func BenchmarkMul(b *testing.B) { for i := 0; i < b.N; i++ { benchmarkMulLoad() } } +func toString(x nat, charset string) string { + base := len(charset) -var tab = []struct { - x nat - b int - s string -}{ - {nil, 10, "0"}, - {nat{1}, 10, "1"}, - {nat{10}, 10, "10"}, - {nat{1234567890}, 10, "1234567890"}, + // special cases + switch { + case base < 2: + panic("illegal base") + case len(x) == 0: + return string(charset[0]) + } + + // allocate buffer for conversion + i := x.bitLen()/log2(Word(base)) + 1 // +1: round up + s := make([]byte, i) + + // don't destroy x + q := nat(nil).set(x) + + // convert + for len(q) > 0 { + i-- + var r Word + q, r = q.divW(q, Word(base)) + s[i] = charset[r] + } + + return string(s[i:]) } +var strTests = []struct { + x nat // nat value to be converted + c string // conversion charset + s string // expected result +}{ + {nil, "01", "0"}, + {nat{1}, "01", "1"}, + {nat{0xc5}, "01", "11000101"}, + {nat{03271}, lowercaseDigits[0:8], "3271"}, + {nat{10}, lowercaseDigits[0:10], "10"}, + {nat{1234567890}, uppercaseDigits[0:10], "1234567890"}, + {nat{0xdeadbeef}, lowercaseDigits[0:16], "deadbeef"}, + {nat{0xdeadbeef}, uppercaseDigits[0:16], "DEADBEEF"}, + {nat{0x229be7}, lowercaseDigits[0:17], "1a2b3c"}, + {nat{0x309663e6}, uppercaseDigits[0:32], "O9COV6"}, +} func TestString(t *testing.T) { - for _, a := range tab { - s := a.x.string(a.b) + for _, a := range strTests { + s := a.x.string(a.c) if s != a.s { t.Errorf("string%+v\n\tgot s = %s; want %s", a, s, a.s) } - x, b, n := nat(nil).scan(a.s, a.b) + x, b, err := nat(nil).scan(strings.NewReader(a.s), len(a.c)) + if x.cmp(a.x) != 0 { + t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x) + } + if b != len(a.c) { + t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, len(a.c)) + } + if err != nil { + t.Errorf("scan%+v\n\tgot error = %s", a, err) + } + } +} + +var natScanTests = []struct { + s string // string to be scanned + base int // input base + x nat // expected nat + b int // expected base + ok bool // expected success + next int // next character (or 0, if at EOF) +}{ + // error: illegal base + {base: -1}, + {base: 1}, + {base: 37}, + + // error: no mantissa + {}, + {s: "?"}, + {base: 10}, + {base: 36}, + {s: "?", base: 10}, + {s: "0x"}, + {s: "345", base: 2}, + + // no errors + {"0", 0, nil, 10, true, 0}, + {"0", 10, nil, 10, true, 0}, + {"0", 36, nil, 36, true, 0}, + {"1", 0, nat{1}, 10, true, 0}, + {"1", 10, nat{1}, 10, true, 0}, + {"0 ", 0, nil, 10, true, ' '}, + {"08", 0, nil, 10, true, '8'}, + {"018", 0, nat{1}, 8, true, '8'}, + {"0b1", 0, nat{1}, 2, true, 0}, + {"0b11000101", 0, nat{0xc5}, 2, true, 0}, + {"03271", 0, nat{03271}, 8, true, 0}, + {"10ab", 0, nat{10}, 10, true, 'a'}, + {"1234567890", 0, nat{1234567890}, 10, true, 0}, + {"xyz", 36, nat{(33*36+34)*36 + 35}, 36, true, 0}, + {"xyz?", 36, nat{(33*36+34)*36 + 35}, 36, true, '?'}, + {"0x", 16, nil, 16, true, 'x'}, + {"0xdeadbeef", 0, nat{0xdeadbeef}, 16, true, 0}, + {"0XDEADBEEF", 0, nat{0xdeadbeef}, 16, true, 0}, +} + +func TestScanBase(t *testing.T) { + for _, a := range natScanTests { + r := strings.NewReader(a.s) + x, b, err := nat(nil).scan(r, a.base) + if err == nil && !a.ok { + t.Errorf("scan%+v\n\texpected error", a) + } + if err != nil { + if a.ok { + t.Errorf("scan%+v\n\tgot error = %s", a, err) + } + continue + } if x.cmp(a.x) != 0 { t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x) } if b != a.b { - t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, a.b) + t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, a.base) + } + next, _, err := r.ReadRune() + if err == os.EOF { + next = 0 + err = nil } - if n != len(a.s) { - t.Errorf("scan%+v\n\tgot n = %d; want %d", a, n, len(a.s)) + if err == nil && next != a.next { + t.Errorf("scan%+v\n\tgot next = %q; want %q", a, next, a.next) } } } +var pi = "3" + + "14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651" + + "32823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461" + + "28475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920" + + "96282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179" + + "31051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798" + + "60943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901" + + "22495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837" + + "29780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083" + + "81420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909" + + "21642019893809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151" + + "55748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035" + + "63707660104710181942955596198946767837449448255379774726847104047534646208046684259069491293313677028989152104" + + "75216205696602405803815019351125338243003558764024749647326391419927260426992279678235478163600934172164121992" + + "45863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818" + + "34797753566369807426542527862551818417574672890977772793800081647060016145249192173217214772350141441973568548" + + "16136115735255213347574184946843852332390739414333454776241686251898356948556209921922218427255025425688767179" + + "04946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886" + + "26945604241965285022210661186306744278622039194945047123713786960956364371917287467764657573962413890865832645" + + "99581339047802759009946576407895126946839835259570982582262052248940772671947826848260147699090264013639443745" + + "53050682034962524517493996514314298091906592509372216964615157098583874105978859597729754989301617539284681382" + + "68683868942774155991855925245953959431049972524680845987273644695848653836736222626099124608051243884390451244" + + "13654976278079771569143599770012961608944169486855584840635342207222582848864815845602850601684273945226746767" + + "88952521385225499546667278239864565961163548862305774564980355936345681743241125150760694794510965960940252288" + + "79710893145669136867228748940560101503308617928680920874760917824938589009714909675985261365549781893129784821" + + "68299894872265880485756401427047755513237964145152374623436454285844479526586782105114135473573952311342716610" + + "21359695362314429524849371871101457654035902799344037420073105785390621983874478084784896833214457138687519435" + + "06430218453191048481005370614680674919278191197939952061419663428754440643745123718192179998391015919561814675" + + "14269123974894090718649423196156794520809514655022523160388193014209376213785595663893778708303906979207734672" + + "21825625996615014215030680384477345492026054146659252014974428507325186660021324340881907104863317346496514539" + + "05796268561005508106658796998163574736384052571459102897064140110971206280439039759515677157700420337869936007" + + "23055876317635942187312514712053292819182618612586732157919841484882916447060957527069572209175671167229109816" + + "90915280173506712748583222871835209353965725121083579151369882091444210067510334671103141267111369908658516398" + + "31501970165151168517143765761835155650884909989859982387345528331635507647918535893226185489632132933089857064" + + "20467525907091548141654985946163718027098199430992448895757128289059232332609729971208443357326548938239119325" + + "97463667305836041428138830320382490375898524374417029132765618093773444030707469211201913020330380197621101100" + + "44929321516084244485963766983895228684783123552658213144957685726243344189303968642624341077322697802807318915" + + "44110104468232527162010526522721116603966655730925471105578537634668206531098965269186205647693125705863566201" + + "85581007293606598764861179104533488503461136576867532494416680396265797877185560845529654126654085306143444318" + + "58676975145661406800700237877659134401712749470420562230538994561314071127000407854733269939081454664645880797" + + "27082668306343285878569830523580893306575740679545716377525420211495576158140025012622859413021647155097925923" + + "09907965473761255176567513575178296664547791745011299614890304639947132962107340437518957359614589019389713111" + + "79042978285647503203198691514028708085990480109412147221317947647772622414254854540332157185306142288137585043" + + "06332175182979866223717215916077166925474873898665494945011465406284336639379003976926567214638530673609657120" + + "91807638327166416274888800786925602902284721040317211860820419000422966171196377921337575114959501566049631862" + + "94726547364252308177036751590673502350728354056704038674351362222477158915049530984448933309634087807693259939" + + "78054193414473774418426312986080998886874132604721569516239658645730216315981931951673538129741677294786724229" + + "24654366800980676928238280689964004824354037014163149658979409243237896907069779422362508221688957383798623001" + + "59377647165122893578601588161755782973523344604281512627203734314653197777416031990665541876397929334419521541" + + "34189948544473456738316249934191318148092777710386387734317720754565453220777092120190516609628049092636019759" + + "88281613323166636528619326686336062735676303544776280350450777235547105859548702790814356240145171806246436267" + + "94561275318134078330336254232783944975382437205835311477119926063813346776879695970309833913077109870408591337" + +// Test case for BenchmarkScanPi. +func TestScanPi(t *testing.T) { + var x nat + z, _, err := x.scan(strings.NewReader(pi), 10) + if err != nil { + t.Errorf("scanning pi: %s", err) + } + if s := z.decimalString(); s != pi { + t.Errorf("scanning pi: got %s", s) + } +} + +func BenchmarkScanPi(b *testing.B) { + for i := 0; i < b.N; i++ { + var x nat + x.scan(strings.NewReader(pi), 10) + } +} + +const ( + // 314**271 + // base 2: 2249 digits + // base 8: 751 digits + // base 10: 678 digits + // base 16: 563 digits + shortBase = 314 + shortExponent = 271 + + // 3141**2178 + // base 2: 31577 digits + // base 8: 10527 digits + // base 10: 9507 digits + // base 16: 7895 digits + mediumBase = 3141 + mediumExponent = 2718 + + // 3141**2178 + // base 2: 406078 digits + // base 8: 135360 digits + // base 10: 122243 digits + // base 16: 101521 digits + longBase = 31415 + longExponent = 27182 +) + +func BenchmarkScanShort2(b *testing.B) { + ScanHelper(b, 2, shortBase, shortExponent) +} + +func BenchmarkScanShort8(b *testing.B) { + ScanHelper(b, 8, shortBase, shortExponent) +} + +func BenchmarkScanSort10(b *testing.B) { + ScanHelper(b, 10, shortBase, shortExponent) +} + +func BenchmarkScanShort16(b *testing.B) { + ScanHelper(b, 16, shortBase, shortExponent) +} + +func BenchmarkScanMedium2(b *testing.B) { + ScanHelper(b, 2, mediumBase, mediumExponent) +} + +func BenchmarkScanMedium8(b *testing.B) { + ScanHelper(b, 8, mediumBase, mediumExponent) +} + +func BenchmarkScanMedium10(b *testing.B) { + ScanHelper(b, 10, mediumBase, mediumExponent) +} + +func BenchmarkScanMedium16(b *testing.B) { + ScanHelper(b, 16, mediumBase, mediumExponent) +} + +func BenchmarkScanLong2(b *testing.B) { + ScanHelper(b, 2, longBase, longExponent) +} + +func BenchmarkScanLong8(b *testing.B) { + ScanHelper(b, 8, longBase, longExponent) +} + +func BenchmarkScanLong10(b *testing.B) { + ScanHelper(b, 10, longBase, longExponent) +} + +func BenchmarkScanLong16(b *testing.B) { + ScanHelper(b, 16, longBase, longExponent) +} + +func ScanHelper(b *testing.B, base int, xv, yv Word) { + b.StopTimer() + var x, y, z nat + x = x.setWord(xv) + y = y.setWord(yv) + z = z.expNN(x, y, nil) + + var s string + s = z.string(lowercaseDigits[0:base]) + if t := toString(z, lowercaseDigits[0:base]); t != s { + panic(fmt.Sprintf("scanning: got %s; want %s", s, t)) + } + b.StartTimer() + + for i := 0; i < b.N; i++ { + x.scan(strings.NewReader(s), base) + } +} + +func BenchmarkStringShort2(b *testing.B) { + StringHelper(b, 2, shortBase, shortExponent) +} + +func BenchmarkStringShort8(b *testing.B) { + StringHelper(b, 8, shortBase, shortExponent) +} + +func BenchmarkStringShort10(b *testing.B) { + StringHelper(b, 10, shortBase, shortExponent) +} + +func BenchmarkStringShort16(b *testing.B) { + StringHelper(b, 16, shortBase, shortExponent) +} + +func BenchmarkStringMedium2(b *testing.B) { + StringHelper(b, 2, mediumBase, mediumExponent) +} + +func BenchmarkStringMedium8(b *testing.B) { + StringHelper(b, 8, mediumBase, mediumExponent) +} + +func BenchmarkStringMedium10(b *testing.B) { + StringHelper(b, 10, mediumBase, mediumExponent) +} + +func BenchmarkStringMedium16(b *testing.B) { + StringHelper(b, 16, mediumBase, mediumExponent) +} + +func BenchmarkStringLong2(b *testing.B) { + StringHelper(b, 2, longBase, longExponent) +} + +func BenchmarkStringLong8(b *testing.B) { + StringHelper(b, 8, longBase, longExponent) +} + +func BenchmarkStringLong10(b *testing.B) { + StringHelper(b, 10, longBase, longExponent) +} + +func BenchmarkStringLong16(b *testing.B) { + StringHelper(b, 16, longBase, longExponent) +} + +func StringHelper(b *testing.B, base int, xv, yv Word) { + b.StopTimer() + var x, y, z nat + x = x.setWord(xv) + y = y.setWord(yv) + z = z.expNN(x, y, nil) + b.StartTimer() + + for i := 0; i < b.N; i++ { + z.string(lowercaseDigits[0:base]) + } +} func TestLeadingZeros(t *testing.T) { var x Word = _B >> 1 @@ -210,14 +534,12 @@ func TestLeadingZeros(t *testing.T) { } } - type shiftTest struct { in nat shift uint out nat } - var leftShiftTests = []shiftTest{ {nil, 0, nil}, {nil, 1, nil}, @@ -227,7 +549,6 @@ var leftShiftTests = []shiftTest{ {nat{1 << (_W - 1), 0}, 1, nat{0, 1}}, } - func TestShiftLeft(t *testing.T) { for i, test := range leftShiftTests { var z nat @@ -241,7 +562,6 @@ func TestShiftLeft(t *testing.T) { } } - var rightShiftTests = []shiftTest{ {nil, 0, nil}, {nil, 1, nil}, @@ -252,7 +572,6 @@ var rightShiftTests = []shiftTest{ {nat{2, 1, 1}, 1, nat{1<<(_W-1) + 1, 1 << (_W - 1)}}, } - func TestShiftRight(t *testing.T) { for i, test := range rightShiftTests { var z nat @@ -266,24 +585,20 @@ func TestShiftRight(t *testing.T) { } } - type modWTest struct { in string dividend string out string } - var modWTests32 = []modWTest{ {"23492635982634928349238759823742", "252341", "220170"}, } - var modWTests64 = []modWTest{ {"6527895462947293856291561095690465243862946", "524326975699234", "375066989628668"}, } - func runModWTests(t *testing.T, tests []modWTest) { for i, test := range tests { in, _ := new(Int).SetString(test.in, 10) @@ -297,7 +612,6 @@ func runModWTests(t *testing.T, tests []modWTest) { } } - func TestModW(t *testing.T) { if _W >= 32 { runModWTests(t, modWTests32) @@ -307,7 +621,6 @@ func TestModW(t *testing.T) { } } - func TestTrailingZeroBits(t *testing.T) { var x Word x-- @@ -319,7 +632,6 @@ func TestTrailingZeroBits(t *testing.T) { } } - var expNNTests = []struct { x, y, m string out string @@ -337,17 +649,16 @@ var expNNTests = []struct { }, } - func TestExpNN(t *testing.T) { for i, test := range expNNTests { - x, _, _ := nat(nil).scan(test.x, 0) - y, _, _ := nat(nil).scan(test.y, 0) - out, _, _ := nat(nil).scan(test.out, 0) + x, _, _ := nat(nil).scan(strings.NewReader(test.x), 0) + y, _, _ := nat(nil).scan(strings.NewReader(test.y), 0) + out, _, _ := nat(nil).scan(strings.NewReader(test.out), 0) var m nat if len(test.m) > 0 { - m, _, _ = nat(nil).scan(test.m, 0) + m, _, _ = nat(nil).scan(strings.NewReader(test.m), 0) } z := nat(nil).expNN(x, y, m) diff --git a/libgo/go/big/rat.go b/libgo/go/big/rat.go index e70673a..327b9bd 100644 --- a/libgo/go/big/rat.go +++ b/libgo/go/big/rat.go @@ -6,7 +6,12 @@ package big -import "strings" +import ( + "encoding/binary" + "fmt" + "os" + "strings" +) // A Rat represents a quotient a/b of arbitrary precision. The zero value for // a Rat, 0/0, is not a legal Rat. @@ -15,13 +20,11 @@ type Rat struct { b nat } - // NewRat creates a new Rat with numerator a and denominator b. func NewRat(a, b int64) *Rat { return new(Rat).SetFrac64(a, b) } - // SetFrac sets z to a/b and returns z. func (z *Rat) SetFrac(a, b *Int) *Rat { z.a.Set(a) @@ -30,7 +33,6 @@ func (z *Rat) SetFrac(a, b *Int) *Rat { return z.norm() } - // SetFrac64 sets z to a/b and returns z. func (z *Rat) SetFrac64(a, b int64) *Rat { z.a.SetInt64(a) @@ -42,7 +44,6 @@ func (z *Rat) SetFrac64(a, b int64) *Rat { return z.norm() } - // SetInt sets z to x (by making a copy of x) and returns z. func (z *Rat) SetInt(x *Int) *Rat { z.a.Set(x) @@ -50,7 +51,6 @@ func (z *Rat) SetInt(x *Int) *Rat { return z } - // SetInt64 sets z to x and returns z. func (z *Rat) SetInt64(x int64) *Rat { z.a.SetInt64(x) @@ -58,7 +58,6 @@ func (z *Rat) SetInt64(x int64) *Rat { return z } - // Sign returns: // // -1 if x < 0 @@ -69,13 +68,11 @@ func (x *Rat) Sign() int { return x.a.Sign() } - // IsInt returns true if the denominator of x is 1. func (x *Rat) IsInt() bool { return len(x.b) == 1 && x.b[0] == 1 } - // Num returns the numerator of z; it may be <= 0. // The result is a reference to z's numerator; it // may change if a new value is assigned to z. @@ -83,15 +80,13 @@ func (z *Rat) Num() *Int { return &z.a } - -// Demom returns the denominator of z; it is always > 0. +// Denom returns the denominator of z; it is always > 0. // The result is a reference to z's denominator; it // may change if a new value is assigned to z. func (z *Rat) Denom() *Int { return &Int{false, z.b} } - func gcd(x, y nat) nat { // Euclidean algorithm. var a, b nat @@ -106,7 +101,6 @@ func gcd(x, y nat) nat { return a } - func (z *Rat) norm() *Rat { f := gcd(z.a.abs, z.b) if len(z.a.abs) == 0 { @@ -122,7 +116,6 @@ func (z *Rat) norm() *Rat { return z } - func mulNat(x *Int, y nat) *Int { var z Int z.abs = z.abs.mul(x.abs, y) @@ -130,7 +123,6 @@ func mulNat(x *Int, y nat) *Int { return &z } - // Cmp compares x and y and returns: // // -1 if x < y @@ -141,7 +133,6 @@ func (x *Rat) Cmp(y *Rat) (r int) { return mulNat(&x.a, y.b).Cmp(mulNat(&y.a, x.b)) } - // Abs sets z to |x| (the absolute value of x) and returns z. func (z *Rat) Abs(x *Rat) *Rat { z.a.Abs(&x.a) @@ -149,7 +140,6 @@ func (z *Rat) Abs(x *Rat) *Rat { return z } - // Add sets z to the sum x+y and returns z. func (z *Rat) Add(x, y *Rat) *Rat { a1 := mulNat(&x.a, y.b) @@ -159,7 +149,6 @@ func (z *Rat) Add(x, y *Rat) *Rat { return z.norm() } - // Sub sets z to the difference x-y and returns z. func (z *Rat) Sub(x, y *Rat) *Rat { a1 := mulNat(&x.a, y.b) @@ -169,7 +158,6 @@ func (z *Rat) Sub(x, y *Rat) *Rat { return z.norm() } - // Mul sets z to the product x*y and returns z. func (z *Rat) Mul(x, y *Rat) *Rat { z.a.Mul(&x.a, &y.a) @@ -177,7 +165,6 @@ func (z *Rat) Mul(x, y *Rat) *Rat { return z.norm() } - // Quo sets z to the quotient x/y and returns z. // If y == 0, a division-by-zero run-time panic occurs. func (z *Rat) Quo(x, y *Rat) *Rat { @@ -192,7 +179,6 @@ func (z *Rat) Quo(x, y *Rat) *Rat { return z.norm() } - // Neg sets z to -x (by making a copy of x if necessary) and returns z. func (z *Rat) Neg(x *Rat) *Rat { z.a.Neg(&x.a) @@ -200,7 +186,6 @@ func (z *Rat) Neg(x *Rat) *Rat { return z } - // Set sets z to x (by making a copy of x if necessary) and returns z. func (z *Rat) Set(x *Rat) *Rat { z.a.Set(&x.a) @@ -208,6 +193,25 @@ func (z *Rat) Set(x *Rat) *Rat { return z } +func ratTok(ch int) bool { + return strings.IndexRune("+-/0123456789.eE", ch) >= 0 +} + +// Scan is a support routine for fmt.Scanner. It accepts the formats +// 'e', 'E', 'f', 'F', 'g', 'G', and 'v'. All formats are equivalent. +func (z *Rat) Scan(s fmt.ScanState, ch int) os.Error { + tok, err := s.Token(true, ratTok) + if err != nil { + return err + } + if strings.IndexRune("efgEFGv", ch) < 0 { + return os.NewError("Rat.Scan: invalid verb") + } + if _, ok := z.SetString(string(tok)); !ok { + return os.NewError("Rat.Scan: invalid syntax") + } + return nil +} // SetString sets z to the value of s and returns z and a boolean indicating // success. s can be given as a fraction "a/b" or as a floating-point number @@ -225,8 +229,8 @@ func (z *Rat) SetString(s string) (*Rat, bool) { return z, false } s = s[sep+1:] - var n int - if z.b, _, n = z.b.scan(s, 10); n != len(s) { + var err os.Error + if z.b, _, err = z.b.scan(strings.NewReader(s), 10); err != nil { return z, false } return z.norm(), true @@ -267,13 +271,11 @@ func (z *Rat) SetString(s string) (*Rat, bool) { return z, true } - // String returns a string representation of z in the form "a/b" (even if b == 1). func (z *Rat) String() string { - return z.a.String() + "/" + z.b.string(10) + return z.a.String() + "/" + z.b.decimalString() } - // RatString returns a string representation of z in the form "a/b" if b != 1, // and in the form "a" if b == 1. func (z *Rat) RatString() string { @@ -283,12 +285,15 @@ func (z *Rat) RatString() string { return z.String() } - // FloatString returns a string representation of z in decimal form with prec // digits of precision after the decimal point and the last digit rounded. func (z *Rat) FloatString(prec int) string { if z.IsInt() { - return z.a.String() + s := z.a.String() + if prec > 0 { + s += "." + strings.Repeat("0", prec) + } + return s } q, r := nat{}.div(nat{}, z.a.abs, z.b) @@ -311,16 +316,56 @@ func (z *Rat) FloatString(prec int) string { } } - s := q.string(10) + s := q.decimalString() if z.a.neg { s = "-" + s } if prec > 0 { - rs := r.string(10) + rs := r.decimalString() leadingZeros := prec - len(rs) s += "." + strings.Repeat("0", leadingZeros) + rs } return s } + +// Gob codec version. Permits backward-compatible changes to the encoding. +const ratGobVersion byte = 1 + +// GobEncode implements the gob.GobEncoder interface. +func (z *Rat) GobEncode() ([]byte, os.Error) { + buf := make([]byte, 1+4+(len(z.a.abs)+len(z.b))*_S) // extra bytes for version and sign bit (1), and numerator length (4) + i := z.b.bytes(buf) + j := z.a.abs.bytes(buf[0:i]) + n := i - j + if int(uint32(n)) != n { + // this should never happen + return nil, os.NewError("Rat.GobEncode: numerator too large") + } + binary.BigEndian.PutUint32(buf[j-4:j], uint32(n)) + j -= 1 + 4 + b := ratGobVersion << 1 // make space for sign bit + if z.a.neg { + b |= 1 + } + buf[j] = b + return buf[j:], nil +} + +// GobDecode implements the gob.GobDecoder interface. +func (z *Rat) GobDecode(buf []byte) os.Error { + if len(buf) == 0 { + return os.NewError("Rat.GobDecode: no data") + } + b := buf[0] + if b>>1 != ratGobVersion { + return os.NewError(fmt.Sprintf("Rat.GobDecode: encoding version %d not supported", b>>1)) + } + const j = 1 + 4 + i := j + binary.BigEndian.Uint32(buf[j-4:j]) + z.a.neg = b&1 != 0 + z.a.abs = z.a.abs.setBytes(buf[j:i]) + z.b = z.b.setBytes(buf[i:]) + return nil +} diff --git a/libgo/go/big/rat_test.go b/libgo/go/big/rat_test.go index 8f42949..dbc5bb6 100644 --- a/libgo/go/big/rat_test.go +++ b/libgo/go/big/rat_test.go @@ -4,8 +4,12 @@ package big -import "testing" - +import ( + "bytes" + "fmt" + "gob" + "testing" +) var setStringTests = []struct { in, out string @@ -52,6 +56,27 @@ func TestRatSetString(t *testing.T) { } } +func TestRatScan(t *testing.T) { + var buf bytes.Buffer + for i, test := range setStringTests { + x := new(Rat) + buf.Reset() + buf.WriteString(test.in) + + _, err := fmt.Fscanf(&buf, "%v", x) + if err == nil != test.ok { + if test.ok { + t.Errorf("#%d error: %s", i, err.String()) + } else { + t.Errorf("#%d expected error", i) + } + continue + } + if err == nil && x.RatString() != test.out { + t.Errorf("#%d got %s want %s", i, x.RatString(), test.out) + } + } +} var floatStringTests = []struct { in string @@ -59,12 +84,13 @@ var floatStringTests = []struct { out string }{ {"0", 0, "0"}, - {"0", 4, "0"}, + {"0", 4, "0.0000"}, {"1", 0, "1"}, - {"1", 2, "1"}, + {"1", 2, "1.00"}, {"-1", 0, "-1"}, {".25", 2, "0.25"}, {".25", 1, "0.3"}, + {".25", 3, "0.250"}, {"-1/3", 3, "-0.333"}, {"-2/3", 4, "-0.6667"}, {"0.96", 1, "1.0"}, @@ -84,7 +110,6 @@ func TestFloatString(t *testing.T) { } } - func TestRatSign(t *testing.T) { zero := NewRat(0, 1) for _, a := range setStringTests { @@ -98,7 +123,6 @@ func TestRatSign(t *testing.T) { } } - var ratCmpTests = []struct { rat1, rat2 string out int @@ -126,7 +150,6 @@ func TestRatCmp(t *testing.T) { } } - func TestIsInt(t *testing.T) { one := NewInt(1) for _, a := range setStringTests { @@ -140,7 +163,6 @@ func TestIsInt(t *testing.T) { } } - func TestRatAbs(t *testing.T) { zero := NewRat(0, 1) for _, a := range setStringTests { @@ -158,7 +180,6 @@ func TestRatAbs(t *testing.T) { } } - type ratBinFun func(z, x, y *Rat) *Rat type ratBinArg struct { x, y, z string @@ -175,7 +196,6 @@ func testRatBin(t *testing.T, i int, name string, f ratBinFun, a ratBinArg) { } } - var ratBinTests = []struct { x, y string sum, prod string @@ -232,7 +252,6 @@ func TestRatBin(t *testing.T) { } } - func TestIssue820(t *testing.T) { x := NewRat(3, 1) y := NewRat(2, 1) @@ -258,7 +277,6 @@ func TestIssue820(t *testing.T) { } } - var setFrac64Tests = []struct { a, b int64 out string @@ -280,3 +298,35 @@ func TestRatSetFrac64Rat(t *testing.T) { } } } + +func TestRatGobEncoding(t *testing.T) { + var medium bytes.Buffer + enc := gob.NewEncoder(&medium) + dec := gob.NewDecoder(&medium) + for i, test := range gobEncodingTests { + for j := 0; j < 4; j++ { + medium.Reset() // empty buffer for each test case (in case of failures) + stest := test + if j&1 != 0 { + // negative numbers + stest = "-" + test + } + if j%2 != 0 { + // fractions + stest = stest + "." + test + } + var tx Rat + tx.SetString(stest) + if err := enc.Encode(&tx); err != nil { + t.Errorf("#%d%c: encoding failed: %s", i, 'a'+j, err) + } + var rx Rat + 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) + } + } + } +} diff --git a/libgo/go/bufio/bufio.go b/libgo/go/bufio/bufio.go index eaae8bb..727ebfdb 100644 --- a/libgo/go/bufio/bufio.go +++ b/libgo/go/bufio/bufio.go @@ -15,16 +15,17 @@ import ( "utf8" ) - const ( defaultBufSize = 4096 ) // Errors introduced by this package. type Error struct { - os.ErrorString + ErrorString string } +func (err *Error) String() string { return err.ErrorString } + var ( ErrInvalidUnreadByte os.Error = &Error{"bufio: invalid use of UnreadByte"} ErrInvalidUnreadRune os.Error = &Error{"bufio: invalid use of UnreadRune"} @@ -40,7 +41,6 @@ func (b BufSizeError) String() string { return "bufio: bad buffer size " + strconv.Itoa(int(b)) } - // Buffered input. // Reader implements buffering for an io.Reader object. @@ -101,6 +101,12 @@ func (b *Reader) fill() { } } +func (b *Reader) readErr() os.Error { + err := b.err + b.err = nil + return err +} + // Peek returns the next n bytes without advancing the reader. The bytes stop // being valid at the next read call. If Peek returns fewer than n bytes, it // also returns an error explaining why the read is short. The error is @@ -119,7 +125,7 @@ func (b *Reader) Peek(n int) ([]byte, os.Error) { if m > n { m = n } - err := b.err + err := b.readErr() if m < n && err == nil { err = ErrBufferFull } @@ -134,11 +140,11 @@ func (b *Reader) Peek(n int) ([]byte, os.Error) { func (b *Reader) Read(p []byte) (n int, err os.Error) { n = len(p) if n == 0 { - return 0, b.err + return 0, b.readErr() } if b.w == b.r { if b.err != nil { - return 0, b.err + return 0, b.readErr() } if len(p) >= len(b.buf) { // Large read, empty buffer. @@ -148,11 +154,11 @@ func (b *Reader) Read(p []byte) (n int, err os.Error) { b.lastByte = int(p[n-1]) b.lastRuneSize = -1 } - return n, b.err + return n, b.readErr() } b.fill() if b.w == b.r { - return 0, b.err + return 0, b.readErr() } } @@ -172,7 +178,7 @@ func (b *Reader) ReadByte() (c byte, err os.Error) { b.lastRuneSize = -1 for b.w == b.r { if b.err != nil { - return 0, b.err + return 0, b.readErr() } b.fill() } @@ -208,7 +214,7 @@ func (b *Reader) ReadRune() (rune int, size int, err os.Error) { } b.lastRuneSize = -1 if b.r == b.w { - return 0, 0, b.err + return 0, 0, b.readErr() } rune, size = int(b.buf[b.r]), 1 if rune >= 0x80 { @@ -260,7 +266,7 @@ func (b *Reader) ReadSlice(delim byte) (line []byte, err os.Error) { if b.err != nil { line := b.buf[b.r:b.w] b.r = b.w - return line, b.err + return line, b.readErr() } n := b.Buffered() @@ -367,7 +373,6 @@ func (b *Reader) ReadString(delim byte) (line string, err os.Error) { return string(bytes), e } - // buffered output // Writer implements buffering for an io.Writer object. diff --git a/libgo/go/bufio/bufio_test.go b/libgo/go/bufio/bufio_test.go index 123adac..82c73d3 100644 --- a/libgo/go/bufio/bufio_test.go +++ b/libgo/go/bufio/bufio_test.go @@ -53,11 +53,12 @@ func readBytes(buf *Reader) string { if e == os.EOF { break } - if e != nil { + if e == nil { + b[nb] = c + nb++ + } else if e != iotest.ErrTimeout { panic("Data: " + e.String()) } - b[nb] = c - nb++ } return string(b[0:nb]) } @@ -75,7 +76,6 @@ func TestReaderSimple(t *testing.T) { } } - type readMaker struct { name string fn func(io.Reader) io.Reader @@ -86,6 +86,7 @@ var readMakers = []readMaker{ {"byte", iotest.OneByteReader}, {"half", iotest.HalfReader}, {"data+err", iotest.DataErrReader}, + {"timeout", iotest.TimeoutReader}, } // Call ReadString (which ends up calling everything else) @@ -97,7 +98,7 @@ func readLines(b *Reader) string { if e == os.EOF { break } - if e != nil { + if e != nil && e != iotest.ErrTimeout { panic("GetLines: " + e.String()) } s += s1 diff --git a/libgo/go/builtin/builtin.go b/libgo/go/builtin/builtin.go new file mode 100644 index 0000000..07acce4 --- /dev/null +++ b/libgo/go/builtin/builtin.go @@ -0,0 +1,135 @@ +// 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 builtin provides documentation for Go's built-in functions. + The functions documented here are not actually in package builtin + but their descriptions here allow godoc to present documentation + for the language's special functions. +*/ +package builtin + +// Type is here for the purposes of documentation only. It is a stand-in +// for any Go type, but represents the same type for any given function +// invocation. +type Type int + +// IntegerType is here for the purposes of documentation only. It is a stand-in +// for any integer type: int, uint, int8 etc. +type IntegerType int + +// FloatType is here for the purposes of documentation only. It is a stand-in +// for either float type: float32 or float64. +type FloatType int + +// ComplexType is here for the purposes of documentation only. It is a +// stand-in for either complex type: complex64 or complex128. +type ComplexType int + +// The append built-in function appends elements to the end of a slice. If +// it has sufficient capacity, the destination is resliced to accommodate the +// new elements. If it does not, a new underlying array will be allocated. +// Append returns the updated slice. It is therefore necessary to store the +// result of append, often in the variable holding the slice itself: +// slice = append(slice, elem1, elem2) +// slice = append(slice, anotherSlice...) +func append(slice []Type, elems ...Type) []Type + +// The copy built-in function copies elements from a source slice into a +// destination slice. (As a special case, it also will copy bytes from a +// string to a slice of bytes.) The source and destination may overlap. Copy +// returns the number of elements copied, which will be the minimum of +// len(src) and len(dst). +func copy(dst, src []Type) int + +// The len built-in function returns the length of v, according to its type: +// Array: the number of elements in v. +// Pointer to array: the number of elements in *v (even if v is nil). +// Slice, or map: the number of elements in v; if v is nil, len(v) is zero. +// String: the number of bytes in v. +// Channel: the number of elements queued (unread) in the channel buffer; +// if v is nil, len(v) is zero. +func len(v Type) int + +// The cap built-in function returns the capacity of v, according to its type: +// Array: the number of elements in v (same as len(v)). +// Pointer to array: the number of elements in *v (same as len(v)). +// Slice: the maximum length the slice can reach when resliced; +// if v is nil, cap(v) is zero. +// Channel: the channel buffer capacity, in units of elements; +// if v is nil, cap(v) is zero. +func cap(v Type) int + +// The make built-in function allocates and initializes an object of type +// slice, map, or chan (only). Like new, the first argument is a type, not a +// value. Unlike new, make's return type is the same as the type of its +// argument, not a pointer to it. The specification of the result depends on +// the type: +// Slice: The size specifies the length. The capacity of the slice is +// equal to its length. A second integer argument may be provided to +// specify a different capacity; it must be no smaller than the +// length, so make([]int, 0, 10) allocates a slice of length 0 and +// capacity 10. +// Map: An initial allocation is made according to the size but the +// resulting map has length 0. The size may be omitted, in which case +// a small starting size is allocated. +// Channel: The channel's buffer is initialized with the specified +// buffer capacity. If zero, or the size is omitted, the channel is +// unbuffered. +func make(Type, size IntegerType) Type + +// The new built-in function allocates memory. The first argument is a type, +// not a value, and the value returned is a pointer to a newly +// allocated zero value of that type. +func new(Type) *Type + +// The complex built-in function constructs a complex value from two +// floating-point values. The real and imaginary parts must be of the same +// size, either float32 or float64 (or assignable to them), and the return +// value will be the corresponding complex type (complex64 for float32, +// complex128 for float64). +func complex(r, i FloatType) ComplexType + +// The real built-in function returns the real part of the complex number c. +// The return value will be floating point type corresponding to the type of c. +func real(c ComplexType) FloatType + +// The imaginary built-in function returns the imaginary part of the complex +// number c. The return value will be floating point type corresponding to +// the type of c. +func imag(c ComplexType) FloatType + +// The close built-in function closes a channel, which must be either +// bidirectional or send-only. It should be executed only by the sender, +// never the receiver, and has the effect of shutting down the channel after +// the last sent value is received. After the last value has been received +// from a closed channel c, any receive from c will succeed without +// blocking, returning the zero value for the channel element. The form +// x, ok := <-c +// will also set ok to false for a closed channel. +func close(c chan<- Type) + +// The panic built-in function stops normal execution of the current +// goroutine. When a function F calls panic, normal execution of F stops +// immediately. Any functions whose execution was deferred by F are run in +// the usual way, and then F returns to its caller. To the caller G, the +// invocation of F then behaves like a call to panic, terminating G's +// execution and running any deferred functions. This continues until all +// functions in the executing goroutine have stopped, in reverse order. At +// that point, the program is terminated and the error condition is reported, +// including the value of the argument to panic. This termination sequence +// is called panicking and can be controlled by the built-in function +// recover. +func panic(v interface{}) + +// The recover built-in function allows a program to manage behavior of a +// panicking goroutine. Executing a call to recover inside a deferred +// function (but not any function called by it) stops the panicking sequence +// by restoring normal execution and retrieves the error value passed to the +// call of panic. If recover is called outside the deferred function it will +// not stop a panicking sequence. In this case, or when the goroutine is not +// panicking, or if the argument supplied to panic was nil, recover returns +// nil. Thus the return value from recover reports whether the goroutine is +// panicking. +func recover() interface{} diff --git a/libgo/go/bytes/buffer.go b/libgo/go/bytes/buffer.go index 1acd4e0..5de8610 100644 --- a/libgo/go/bytes/buffer.go +++ b/libgo/go/bytes/buffer.go @@ -280,7 +280,7 @@ func (b *Buffer) ReadRune() (r int, size int, err os.Error) { // from any read operation.) func (b *Buffer) UnreadRune() os.Error { if b.lastRead != opReadRune { - return os.ErrorString("bytes.Buffer: UnreadRune: previous operation was not ReadRune") + return os.NewError("bytes.Buffer: UnreadRune: previous operation was not ReadRune") } b.lastRead = opInvalid if b.off > 0 { @@ -295,7 +295,7 @@ func (b *Buffer) UnreadRune() os.Error { // returns an error. func (b *Buffer) UnreadByte() os.Error { if b.lastRead != opReadRune && b.lastRead != opRead { - return os.ErrorString("bytes.Buffer: UnreadByte: previous operation was not a read") + return os.NewError("bytes.Buffer: UnreadByte: previous operation was not a read") } b.lastRead = opInvalid if b.off > 0 { diff --git a/libgo/go/bytes/buffer_test.go b/libgo/go/bytes/buffer_test.go index 14f9501..06d2a65 100644 --- a/libgo/go/bytes/buffer_test.go +++ b/libgo/go/bytes/buffer_test.go @@ -12,7 +12,6 @@ import ( "utf8" ) - const N = 10000 // make this bigger for a larger (and slower) test var data string // test data for write tests var bytes []byte // test data; same as data but as a slice. @@ -47,7 +46,6 @@ func check(t *testing.T, testname string, buf *Buffer, s string) { } } - // Fill buf through n writes of string fus. // The initial contents of buf corresponds to the string s; // the result is the final contents of buf returned as a string. @@ -67,7 +65,6 @@ func fillString(t *testing.T, testname string, buf *Buffer, s string, n int, fus return s } - // Fill buf through n writes of byte slice fub. // The initial contents of buf corresponds to the string s; // the result is the final contents of buf returned as a string. @@ -87,19 +84,16 @@ func fillBytes(t *testing.T, testname string, buf *Buffer, s string, n int, fub return s } - func TestNewBuffer(t *testing.T) { buf := NewBuffer(bytes) check(t, "NewBuffer", buf, data) } - func TestNewBufferString(t *testing.T) { buf := NewBufferString(data) check(t, "NewBufferString", buf, data) } - // Empty buf through repeated reads into fub. // The initial contents of buf corresponds to the string s. func empty(t *testing.T, testname string, buf *Buffer, s string, fub []byte) { @@ -120,7 +114,6 @@ func empty(t *testing.T, testname string, buf *Buffer, s string, fub []byte) { check(t, testname+" (empty 4)", buf, "") } - func TestBasicOperations(t *testing.T) { var buf Buffer @@ -175,7 +168,6 @@ func TestBasicOperations(t *testing.T) { } } - func TestLargeStringWrites(t *testing.T) { var buf Buffer limit := 30 @@ -189,7 +181,6 @@ func TestLargeStringWrites(t *testing.T) { check(t, "TestLargeStringWrites (3)", &buf, "") } - func TestLargeByteWrites(t *testing.T) { var buf Buffer limit := 30 @@ -203,7 +194,6 @@ func TestLargeByteWrites(t *testing.T) { check(t, "TestLargeByteWrites (3)", &buf, "") } - func TestLargeStringReads(t *testing.T) { var buf Buffer for i := 3; i < 30; i += 3 { @@ -213,7 +203,6 @@ func TestLargeStringReads(t *testing.T) { check(t, "TestLargeStringReads (3)", &buf, "") } - func TestLargeByteReads(t *testing.T) { var buf Buffer for i := 3; i < 30; i += 3 { @@ -223,7 +212,6 @@ func TestLargeByteReads(t *testing.T) { check(t, "TestLargeByteReads (3)", &buf, "") } - func TestMixedReadsAndWrites(t *testing.T) { var buf Buffer s := "" @@ -243,7 +231,6 @@ func TestMixedReadsAndWrites(t *testing.T) { empty(t, "TestMixedReadsAndWrites (2)", &buf, s, make([]byte, buf.Len())) } - func TestNil(t *testing.T) { var b *Buffer if b.String() != "" { @@ -251,7 +238,6 @@ func TestNil(t *testing.T) { } } - func TestReadFrom(t *testing.T) { var buf Buffer for i := 3; i < 30; i += 3 { @@ -262,7 +248,6 @@ func TestReadFrom(t *testing.T) { } } - func TestWriteTo(t *testing.T) { var buf Buffer for i := 3; i < 30; i += 3 { @@ -273,7 +258,6 @@ func TestWriteTo(t *testing.T) { } } - func TestRuneIO(t *testing.T) { const NRune = 1000 // Built a test array while we write the data @@ -323,7 +307,6 @@ func TestRuneIO(t *testing.T) { } } - func TestNext(t *testing.T) { b := []byte{0, 1, 2, 3, 4} tmp := make([]byte, 5) diff --git a/libgo/go/bytes/bytes.go b/libgo/go/bytes/bytes.go index 0f9ac98..5119fce 100644 --- a/libgo/go/bytes/bytes.go +++ b/libgo/go/bytes/bytes.go @@ -212,26 +212,40 @@ func genSplit(s, sep []byte, sepSave, n int) [][]byte { return a[0 : na+1] } -// Split slices s into subslices separated by sep and returns a slice of +// SplitN slices s into subslices separated by sep and returns a slice of // the subslices between those separators. -// If sep is empty, Split splits after each UTF-8 sequence. +// If sep is empty, SplitN splits after each UTF-8 sequence. // The count determines the number of subslices to return: // n > 0: at most n subslices; the last subslice will be the unsplit remainder. // n == 0: the result is nil (zero subslices) // n < 0: all subslices -func Split(s, sep []byte, n int) [][]byte { return genSplit(s, sep, 0, n) } +func SplitN(s, sep []byte, n int) [][]byte { return genSplit(s, sep, 0, n) } -// SplitAfter slices s into subslices after each instance of sep and +// SplitAfterN slices s into subslices after each instance of sep and // returns a slice of those subslices. -// If sep is empty, Split splits after each UTF-8 sequence. +// If sep is empty, SplitAfterN splits after each UTF-8 sequence. // The count determines the number of subslices to return: // n > 0: at most n subslices; the last subslice will be the unsplit remainder. // n == 0: the result is nil (zero subslices) // n < 0: all subslices -func SplitAfter(s, sep []byte, n int) [][]byte { +func SplitAfterN(s, sep []byte, n int) [][]byte { return genSplit(s, sep, len(sep), n) } +// Split slices s into all subslices separated by sep and returns a slice of +// the subslices between those separators. +// If sep is empty, Split splits after each UTF-8 sequence. +// It is equivalent to SplitN with a count of -1. +func Split(s, sep []byte) [][]byte { return genSplit(s, sep, 0, -1) } + +// SplitAfter slices s into all subslices after each instance of sep and +// returns a slice of those subslices. +// If sep is empty, SplitAfter splits after each UTF-8 sequence. +// It is equivalent to SplitAfterN with a count of -1. +func SplitAfter(s, sep []byte) [][]byte { + return genSplit(s, sep, len(sep), -1) +} + // Fields splits the array s around each instance of one or more consecutive white space // characters, returning a slice of subarrays of s or an empty list if s contains only white space. func Fields(s []byte) [][]byte { @@ -384,7 +398,6 @@ func ToTitleSpecial(_case unicode.SpecialCase, s []byte) []byte { return Map(func(r int) int { return _case.ToTitle(r) }, s) } - // isSeparator reports whether the rune could mark a word boundary. // TODO: update when package unicode captures more of the properties. func isSeparator(rune int) bool { diff --git a/libgo/go/bytes/bytes_test.go b/libgo/go/bytes/bytes_test.go index 4ce291a..9444358 100644 --- a/libgo/go/bytes/bytes_test.go +++ b/libgo/go/bytes/bytes_test.go @@ -6,6 +6,7 @@ package bytes_test import ( . "bytes" + "reflect" "testing" "unicode" "utf8" @@ -315,7 +316,7 @@ var explodetests = []ExplodeTest{ func TestExplode(t *testing.T) { for _, tt := range explodetests { - a := Split([]byte(tt.s), nil, tt.n) + a := SplitN([]byte(tt.s), nil, tt.n) result := arrayOfString(a) if !eq(result, tt.a) { t.Errorf(`Explode("%s", %d) = %v; want %v`, tt.s, tt.n, result, tt.a) @@ -328,7 +329,6 @@ func TestExplode(t *testing.T) { } } - type SplitTest struct { s string sep string @@ -354,7 +354,7 @@ var splittests = []SplitTest{ func TestSplit(t *testing.T) { for _, tt := range splittests { - a := Split([]byte(tt.s), []byte(tt.sep), tt.n) + a := SplitN([]byte(tt.s), []byte(tt.sep), tt.n) result := arrayOfString(a) if !eq(result, tt.a) { t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a) @@ -367,6 +367,12 @@ func TestSplit(t *testing.T) { if string(s) != tt.s { t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s) } + if tt.n < 0 { + b := Split([]byte(tt.s), []byte(tt.sep)) + if !reflect.DeepEqual(a, b) { + t.Errorf("Split disagrees withSplitN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a) + } + } } } @@ -388,7 +394,7 @@ var splitaftertests = []SplitTest{ func TestSplitAfter(t *testing.T) { for _, tt := range splitaftertests { - a := SplitAfter([]byte(tt.s), []byte(tt.sep), tt.n) + a := SplitAfterN([]byte(tt.s), []byte(tt.sep), tt.n) result := arrayOfString(a) if !eq(result, tt.a) { t.Errorf(`Split(%q, %q, %d) = %v; want %v`, tt.s, tt.sep, tt.n, result, tt.a) @@ -398,6 +404,12 @@ func TestSplitAfter(t *testing.T) { if string(s) != tt.s { t.Errorf(`Join(Split(%q, %q, %d), %q) = %q`, tt.s, tt.sep, tt.n, tt.sep, s) } + if tt.n < 0 { + b := SplitAfter([]byte(tt.s), []byte(tt.sep)) + if !reflect.DeepEqual(a, b) { + t.Errorf("SplitAfter disagrees withSplitAfterN(%q, %q, %d) = %v; want %v", tt.s, tt.sep, tt.n, b, a) + } + } } } @@ -649,7 +661,6 @@ func TestRunes(t *testing.T) { } } - type TrimTest struct { f func([]byte, string) []byte in, cutset, out string diff --git a/libgo/go/compress/bzip2/bzip2.go b/libgo/go/compress/bzip2/bzip2.go index 9e97ede..8b45723 100644 --- a/libgo/go/compress/bzip2/bzip2.go +++ b/libgo/go/compress/bzip2/bzip2.go @@ -284,7 +284,7 @@ func (bz2 *reader) readBlock() (err os.Error) { repeat := 0 repeat_power := 0 - // The `C' array (used by the inverse BWT) needs to be zero initialised. + // The `C' array (used by the inverse BWT) needs to be zero initialized. for i := range bz2.c { bz2.c[i] = 0 } @@ -330,7 +330,7 @@ func (bz2 *reader) readBlock() (err os.Error) { if int(v) == numSymbols-1 { // This is the EOF symbol. Because it's always at the - // end of the move-to-front list, and nevers gets moved + // end of the move-to-front list, and never gets moved // to the front, it has this unique value. break } diff --git a/libgo/go/compress/bzip2/huffman.go b/libgo/go/compress/bzip2/huffman.go index 732bc4a..dc05739 100644 --- a/libgo/go/compress/bzip2/huffman.go +++ b/libgo/go/compress/bzip2/huffman.go @@ -68,7 +68,7 @@ func newHuffmanTree(lengths []uint8) (huffmanTree, os.Error) { // each symbol (consider reflecting a tree down the middle, for // example). Since the code length assignments determine the // efficiency of the tree, each of these trees is equally good. In - // order to minimise the amount of information needed to build a tree + // order to minimize the amount of information needed to build a tree // bzip2 uses a canonical tree so that it can be reconstructed given // only the code length assignments. diff --git a/libgo/go/compress/flate/deflate.go b/libgo/go/compress/flate/deflate.go index a02a5e8..b1cee0b 100644 --- a/libgo/go/compress/flate/deflate.go +++ b/libgo/go/compress/flate/deflate.go @@ -11,16 +11,18 @@ import ( ) const ( - NoCompression = 0 - BestSpeed = 1 - fastCompression = 3 - BestCompression = 9 - DefaultCompression = -1 - logMaxOffsetSize = 15 // Standard DEFLATE - wideLogMaxOffsetSize = 22 // Wide DEFLATE - minMatchLength = 3 // The smallest match that the compressor looks for - maxMatchLength = 258 // The longest match for the compressor - minOffsetSize = 1 // The shortest offset that makes any sence + NoCompression = 0 + BestSpeed = 1 + fastCompression = 3 + BestCompression = 9 + DefaultCompression = -1 + logWindowSize = 15 + windowSize = 1 << logWindowSize + windowMask = windowSize - 1 + logMaxOffsetSize = 15 // Standard DEFLATE + minMatchLength = 3 // The smallest match that the compressor looks for + maxMatchLength = 258 // The longest match for the compressor + minOffsetSize = 1 // The shortest offset that makes any sence // The maximum number of tokens we put into a single flat block, just too // stop things from getting too large. @@ -32,22 +34,6 @@ const ( hashShift = (hashBits + minMatchLength - 1) / minMatchLength ) -type syncPipeReader struct { - *io.PipeReader - closeChan chan bool -} - -func (sr *syncPipeReader) CloseWithError(err os.Error) os.Error { - retErr := sr.PipeReader.CloseWithError(err) - sr.closeChan <- true // finish writer close - return retErr -} - -type syncPipeWriter struct { - *io.PipeWriter - closeChan chan bool -} - type compressionLevel struct { good, lazy, nice, chain, fastSkipHashing int } @@ -68,105 +54,73 @@ var levels = []compressionLevel{ {32, 258, 258, 4096, math.MaxInt32}, } -func (sw *syncPipeWriter) Close() os.Error { - err := sw.PipeWriter.Close() - <-sw.closeChan // wait for reader close - return err -} - -func syncPipe() (*syncPipeReader, *syncPipeWriter) { - r, w := io.Pipe() - sr := &syncPipeReader{r, make(chan bool, 1)} - sw := &syncPipeWriter{w, sr.closeChan} - return sr, sw -} - type compressor struct { - level int - logWindowSize uint - w *huffmanBitWriter - r io.Reader - // (1 << logWindowSize) - 1. - windowMask int + compressionLevel - eof bool // has eof been reached on input? - sync bool // writer wants to flush - syncChan chan os.Error + w *huffmanBitWriter - // hashHead[hashValue] contains the largest inputIndex with the specified hash value - hashHead []int + // compression algorithm + fill func(*compressor, []byte) int // copy data to window + step func(*compressor) // process window + sync bool // requesting flush + // Input hash chains + // hashHead[hashValue] contains the largest inputIndex with the specified hash value // If hashHead[hashValue] is within the current window, then // hashPrev[hashHead[hashValue] & windowMask] contains the previous index // with the same hash value. - hashPrev []int - - // If we find a match of length >= niceMatch, then we don't bother searching - // any further. - niceMatch int - - // If we find a match of length >= goodMatch, we only do a half-hearted - // effort at doing lazy matching starting at the next character - goodMatch int - - // The maximum number of chains we look at when finding a match - maxChainLength int - - // The sliding window we use for matching - window []byte - - // The index just past the last valid character - windowEnd int - - // index in "window" at which current block starts - blockStart int -} - -func (d *compressor) flush() os.Error { - d.w.flush() - return d.w.err + chainHead int + hashHead []int + hashPrev []int + + // input window: unprocessed data is window[index:windowEnd] + index int + window []byte + windowEnd int + blockStart int // window index where current tokens start + byteAvailable bool // if true, still need to process window[index-1]. + + // queued output tokens: tokens[:ti] + tokens []token + ti int + + // deflate state + length int + offset int + hash int + maxInsertIndex int + err os.Error } -func (d *compressor) fillWindow(index int) (int, os.Error) { - if d.sync { - return index, nil - } - wSize := d.windowMask + 1 - if index >= wSize+wSize-(minMatchLength+maxMatchLength) { - // shift the window by wSize - copy(d.window, d.window[wSize:2*wSize]) - index -= wSize - d.windowEnd -= wSize - if d.blockStart >= wSize { - d.blockStart -= wSize +func (d *compressor) fillDeflate(b []byte) int { + if d.index >= 2*windowSize-(minMatchLength+maxMatchLength) { + // shift the window by windowSize + copy(d.window, d.window[windowSize:2*windowSize]) + d.index -= windowSize + d.windowEnd -= windowSize + if d.blockStart >= windowSize { + d.blockStart -= windowSize } else { d.blockStart = math.MaxInt32 } for i, h := range d.hashHead { - v := h - wSize + v := h - windowSize if v < -1 { v = -1 } d.hashHead[i] = v } for i, h := range d.hashPrev { - v := -h - wSize + v := -h - windowSize if v < -1 { v = -1 } d.hashPrev[i] = v } } - count, err := d.r.Read(d.window[d.windowEnd:]) - d.windowEnd += count - if count == 0 && err == nil { - d.sync = true - } - if err == os.EOF { - d.eof = true - err = nil - } - return index, err + n := copy(d.window[d.windowEnd:], b) + d.windowEnd += n + return n } func (d *compressor) writeBlock(tokens []token, index int, eof bool) os.Error { @@ -194,21 +148,21 @@ func (d *compressor) findMatch(pos int, prevHead int, prevLength int, lookahead // We quit when we get a match that's at least nice long nice := len(win) - pos - if d.niceMatch < nice { - nice = d.niceMatch + if d.nice < nice { + nice = d.nice } // If we've got a match that's good enough, only look in 1/4 the chain. - tries := d.maxChainLength + tries := d.chain length = prevLength - if length >= d.goodMatch { + if length >= d.good { tries >>= 2 } w0 := win[pos] w1 := win[pos+1] wEnd := win[pos+length] - minIndex := pos - (d.windowMask + 1) + minIndex := pos - windowSize for i := prevHead; tries > 0; tries-- { if w0 == win[i] && w1 == win[i+1] && wEnd == win[i+length] { @@ -233,7 +187,7 @@ func (d *compressor) findMatch(pos int, prevHead int, prevLength int, lookahead // hashPrev[i & windowMask] has already been overwritten, so stop now. break } - if i = d.hashPrev[i&d.windowMask]; i < minIndex || i < 0 { + if i = d.hashPrev[i&windowMask]; i < minIndex || i < 0 { break } } @@ -248,234 +202,224 @@ func (d *compressor) writeStoredBlock(buf []byte) os.Error { return d.w.err } -func (d *compressor) storedDeflate() os.Error { - buf := make([]byte, maxStoreBlockSize) - for { - n, err := d.r.Read(buf) - if n == 0 && err == nil { - d.sync = true - } - if n > 0 || d.sync { - if err := d.writeStoredBlock(buf[0:n]); err != nil { - return err - } - if d.sync { - d.syncChan <- nil - d.sync = false - } - } - if err != nil { - if err == os.EOF { - break - } - return err - } - } - return nil -} - -func (d *compressor) doDeflate() (err os.Error) { - // init - d.windowMask = 1< windowEnd { + if d.index > d.windowEnd { panic("index > windowEnd") } - lookahead := windowEnd - index + lookahead := d.windowEnd - d.index if lookahead < minMatchLength+maxMatchLength { - if index, err = d.fillWindow(index); err != nil { - return + if !d.sync { + break Loop } - windowEnd = d.windowEnd - if index > windowEnd { + if d.index > d.windowEnd { panic("index > windowEnd") } - maxInsertIndex = windowEnd - (minMatchLength - 1) - lookahead = windowEnd - index if lookahead == 0 { // Flush current output block if any. - if byteAvailable { + if d.byteAvailable { // There is still one pending token that needs to be flushed - tokens[ti] = literalToken(uint32(d.window[index-1]) & 0xFF) - ti++ - byteAvailable = false + d.tokens[d.ti] = literalToken(uint32(d.window[d.index-1])) + d.ti++ + d.byteAvailable = false } - if ti > 0 { - if err = d.writeBlock(tokens[0:ti], index, false); err != nil { + if d.ti > 0 { + if d.err = d.writeBlock(d.tokens[0:d.ti], d.index, false); d.err != nil { return } - ti = 0 - } - if d.sync { - d.w.writeStoredHeader(0, false) - d.w.flush() - d.syncChan <- d.w.err - d.sync = false - } - - // If this was only a sync (not at EOF) keep going. - if !d.eof { - continue + d.ti = 0 } break Loop } } - if index < maxInsertIndex { + if d.index < d.maxInsertIndex { // Update the hash - hash = (hash<= minIndex && - (isFastDeflate && lookahead > minMatchLength-1 || - !isFastDeflate && lookahead > prevLength && prevLength < lazyMatch) { - if newLength, newOffset, ok := d.findMatch(index, chainHead, minMatchLength-1, lookahead); ok { - length = newLength - offset = newOffset + if d.chainHead >= minIndex && + (d.fastSkipHashing != 0 && lookahead > minMatchLength-1 || + d.fastSkipHashing == 0 && lookahead > prevLength && prevLength < d.lazy) { + if newLength, newOffset, ok := d.findMatch(d.index, d.chainHead, minMatchLength-1, lookahead); ok { + d.length = newLength + d.offset = newOffset } } - if isFastDeflate && length >= minMatchLength || - !isFastDeflate && prevLength >= minMatchLength && length <= prevLength { + if d.fastSkipHashing != 0 && d.length >= minMatchLength || + d.fastSkipHashing == 0 && prevLength >= minMatchLength && d.length <= prevLength { // There was a match at the previous step, and the current match is // not better. Output the previous match. - if isFastDeflate { - tokens[ti] = matchToken(uint32(length-minMatchLength), uint32(offset-minOffsetSize)) + if d.fastSkipHashing != 0 { + d.tokens[d.ti] = matchToken(uint32(d.length-minMatchLength), uint32(d.offset-minOffsetSize)) } else { - tokens[ti] = matchToken(uint32(prevLength-minMatchLength), uint32(prevOffset-minOffsetSize)) + d.tokens[d.ti] = matchToken(uint32(prevLength-minMatchLength), uint32(prevOffset-minOffsetSize)) } - ti++ + d.ti++ // Insert in the hash table all strings up to the end of the match. // index and index-1 are already inserted. If there is not enough // lookahead, the last two strings are not inserted into the hash // table. - if length <= l.fastSkipHashing { + if d.length <= d.fastSkipHashing { var newIndex int - if isFastDeflate { - newIndex = index + length + if d.fastSkipHashing != 0 { + newIndex = d.index + d.length } else { newIndex = prevLength - 1 } - for index++; index < newIndex; index++ { - if index < maxInsertIndex { - hash = (hash< 0 { + d.err = d.writeStoredBlock(d.window[:d.windowEnd]) + } + d.windowEnd = 0 +} + +func (d *compressor) write(b []byte) (n int, err os.Error) { + n = len(b) + b = b[d.fill(d, b):] + for len(b) > 0 { + d.step(d) + b = b[d.fill(d, b):] + } + return n, d.err +} + +func (d *compressor) syncFlush() os.Error { + d.sync = true + d.step(d) + if d.err == nil { + d.w.writeStoredHeader(0, false) + d.w.flush() + d.err = d.w.err + } + d.sync = false + return d.err +} + +func (d *compressor) init(w io.Writer, level int) (err os.Error) { d.w = newHuffmanBitWriter(w) - d.level = level - d.logWindowSize = logWindowSize switch { case level == NoCompression: - err = d.storedDeflate() + d.window = make([]byte, maxStoreBlockSize) + d.fill = (*compressor).fillStore + d.step = (*compressor).store case level == DefaultCompression: - d.level = 6 + level = 6 fallthrough case 1 <= level && level <= 9: - err = d.doDeflate() + d.compressionLevel = levels[level] + d.initDeflate() + d.fill = (*compressor).fillDeflate + d.step = (*compressor).deflate default: return WrongValueError{"level", 0, 9, int32(level)} } + return nil +} - if d.sync { - d.syncChan <- err - d.sync = false - } - if err != nil { - return err +func (d *compressor) close() os.Error { + d.sync = true + d.step(d) + if d.err != nil { + return d.err } if d.w.writeStoredHeader(0, true); d.w.err != nil { return d.w.err } - return d.flush() + d.w.flush() + return d.w.err } // NewWriter returns a new Writer compressing @@ -486,14 +430,9 @@ func (d *compressor) compress(r io.Reader, w io.Writer, level int, logWindowSize // compression; it only adds the necessary DEFLATE framing. func NewWriter(w io.Writer, level int) *Writer { const logWindowSize = logMaxOffsetSize - var d compressor - d.syncChan = make(chan os.Error, 1) - pr, pw := syncPipe() - go func() { - err := d.compress(pr, w, level, logWindowSize) - pr.CloseWithError(err) - }() - return &Writer{pw, &d} + var dw Writer + dw.d.init(w, level) + return &dw } // NewWriterDict is like NewWriter but initializes the new @@ -526,18 +465,13 @@ func (w *dictWriter) Write(b []byte) (n int, err os.Error) { // A Writer takes data written to it and writes the compressed // form of that data to an underlying writer (see NewWriter). type Writer struct { - w *syncPipeWriter - d *compressor + d compressor } // Write writes data to w, which will eventually write the // compressed form of data to its underlying writer. func (w *Writer) Write(data []byte) (n int, err os.Error) { - if len(data) == 0 { - // no point, and nil interferes with sync - return - } - return w.w.Write(data) + return w.d.write(data) } // Flush flushes any pending compressed data to the underlying writer. @@ -550,18 +484,10 @@ func (w *Writer) Write(data []byte) (n int, err os.Error) { func (w *Writer) Flush() os.Error { // For more about flushing: // http://www.bolet.org/~pornin/deflate-flush.html - if w.d.sync { - panic("compress/flate: double Flush") - } - _, err := w.w.Write(nil) - err1 := <-w.d.syncChan - if err == nil { - err = err1 - } - return err + return w.d.syncFlush() } // Close flushes and closes the writer. func (w *Writer) Close() os.Error { - return w.w.Close() + return w.d.close() } diff --git a/libgo/go/compress/flate/deflate_test.go b/libgo/go/compress/flate/deflate_test.go index 650a805..9308236 100644 --- a/libgo/go/compress/flate/deflate_test.go +++ b/libgo/go/compress/flate/deflate_test.go @@ -57,7 +57,7 @@ var deflateInflateTests = []*deflateInflateTest{ &deflateInflateTest{[]byte{0x11, 0x12}}, &deflateInflateTest{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}}, &deflateInflateTest{[]byte{0x11, 0x10, 0x13, 0x41, 0x21, 0x21, 0x41, 0x13, 0x87, 0x78, 0x13}}, - &deflateInflateTest{getLargeDataChunk()}, + &deflateInflateTest{largeDataChunk()}, } var reverseBitsTests = []*reverseBitsTest{ @@ -71,23 +71,22 @@ var reverseBitsTests = []*reverseBitsTest{ &reverseBitsTest{29, 5, 23}, } -func getLargeDataChunk() []byte { +func largeDataChunk() []byte { result := make([]byte, 100000) for i := range result { - result[i] = byte(int64(i) * int64(i) & 0xFF) + result[i] = byte(i * i & 0xFF) } return result } func TestDeflate(t *testing.T) { for _, h := range deflateTests { - buffer := bytes.NewBuffer(nil) - w := NewWriter(buffer, h.level) + var buf bytes.Buffer + w := NewWriter(&buf, h.level) w.Write(h.in) w.Close() - if bytes.Compare(buffer.Bytes(), h.out) != 0 { - t.Errorf("buffer is wrong; level = %v, buffer.Bytes() = %v, expected output = %v", - h.level, buffer.Bytes(), h.out) + if !bytes.Equal(buf.Bytes(), h.out) { + t.Errorf("Deflate(%d, %x) = %x, want %x", h.level, h.in, buf.Bytes(), h.out) } } } @@ -226,7 +225,6 @@ func testSync(t *testing.T, level int, input []byte, name string) { } } - func testToFromWithLevel(t *testing.T, level int, input []byte, name string) os.Error { buffer := bytes.NewBuffer(nil) w := NewWriter(buffer, level) diff --git a/libgo/go/compress/flate/huffman_bit_writer.go b/libgo/go/compress/flate/huffman_bit_writer.go index abff82d..3981df5 100644 --- a/libgo/go/compress/flate/huffman_bit_writer.go +++ b/libgo/go/compress/flate/huffman_bit_writer.go @@ -15,9 +15,6 @@ const ( // The largest offset code. offsetCodeCount = 30 - // The largest offset code in the extensions. - extendedOffsetCodeCount = 42 - // The special code used to mark the end of a block. endBlockMarker = 256 @@ -100,11 +97,11 @@ func newHuffmanBitWriter(w io.Writer) *huffmanBitWriter { return &huffmanBitWriter{ w: w, literalFreq: make([]int32, maxLit), - offsetFreq: make([]int32, extendedOffsetCodeCount), - codegen: make([]uint8, maxLit+extendedOffsetCodeCount+1), + offsetFreq: make([]int32, offsetCodeCount), + codegen: make([]uint8, maxLit+offsetCodeCount+1), codegenFreq: make([]int32, codegenCodeCount), literalEncoding: newHuffmanEncoder(maxLit), - offsetEncoding: newHuffmanEncoder(extendedOffsetCodeCount), + offsetEncoding: newHuffmanEncoder(offsetCodeCount), codegenEncoding: newHuffmanEncoder(codegenCodeCount), } } @@ -185,7 +182,7 @@ func (w *huffmanBitWriter) writeBytes(bytes []byte) { _, w.err = w.w.Write(bytes) } -// RFC 1951 3.2.7 specifies a special run-length encoding for specifiying +// RFC 1951 3.2.7 specifies a special run-length encoding for specifying // the literal and offset lengths arrays (which are concatenated into a single // array). This method generates that run-length encoding. // @@ -279,7 +276,7 @@ func (w *huffmanBitWriter) writeCode(code *huffmanEncoder, literal uint32) { // // numLiterals The number of literals specified in codegen // numOffsets The number of offsets specified in codegen -// numCodegens Tne number of codegens used in codegen +// numCodegens The number of codegens used in codegen func (w *huffmanBitWriter) writeDynamicHeader(numLiterals int, numOffsets int, numCodegens int, isEof bool) { if w.err != nil { return @@ -290,13 +287,7 @@ func (w *huffmanBitWriter) writeDynamicHeader(numLiterals int, numOffsets int, n } w.writeBits(firstBits, 3) w.writeBits(int32(numLiterals-257), 5) - if numOffsets > offsetCodeCount { - // Extended version of decompressor - w.writeBits(int32(offsetCodeCount+((numOffsets-(1+offsetCodeCount))>>3)), 5) - w.writeBits(int32((numOffsets-(1+offsetCodeCount))&0x7), 3) - } else { - w.writeBits(int32(numOffsets-1), 5) - } + w.writeBits(int32(numOffsets-1), 5) w.writeBits(int32(numCodegens-4), 4) for i := 0; i < numCodegens; i++ { @@ -368,24 +359,17 @@ func (w *huffmanBitWriter) writeBlock(tokens []token, eof bool, input []byte) { tokens = tokens[0 : n+1] tokens[n] = endBlockMarker - totalLength := -1 // Subtract 1 for endBlock. for _, t := range tokens { switch t.typ() { case literalType: w.literalFreq[t.literal()]++ - totalLength++ - break case matchType: length := t.length() offset := t.offset() - totalLength += int(length + 3) w.literalFreq[lengthCodesStart+lengthCode(length)]++ w.offsetFreq[offsetCode(offset)]++ - break } } - w.literalEncoding.generate(w.literalFreq, 15) - w.offsetEncoding.generate(w.offsetFreq, 15) // get the number of literals numLiterals := len(w.literalFreq) @@ -394,15 +378,25 @@ func (w *huffmanBitWriter) writeBlock(tokens []token, eof bool, input []byte) { } // get the number of offsets numOffsets := len(w.offsetFreq) - for numOffsets > 1 && w.offsetFreq[numOffsets-1] == 0 { + for numOffsets > 0 && w.offsetFreq[numOffsets-1] == 0 { numOffsets-- } + if numOffsets == 0 { + // We haven't found a single match. If we want to go with the dynamic encoding, + // we should count at least one offset to be sure that the offset huffman tree could be encoded. + w.offsetFreq[0] = 1 + numOffsets = 1 + } + + w.literalEncoding.generate(w.literalFreq, 15) + w.offsetEncoding.generate(w.offsetFreq, 15) + storedBytes := 0 if input != nil { storedBytes = len(input) } var extraBits int64 - var storedSize int64 + var storedSize int64 = math.MaxInt64 if storedBytes <= maxStoreBlockSize && input != nil { storedSize = int64((storedBytes + 5) * 8) // We only bother calculating the costs of the extra bits required by @@ -417,34 +411,29 @@ func (w *huffmanBitWriter) writeBlock(tokens []token, eof bool, input []byte) { // First four offset codes have extra size = 0. extraBits += int64(w.offsetFreq[offsetCode]) * int64(offsetExtraBits[offsetCode]) } - } else { - storedSize = math.MaxInt32 } - // Figure out which generates smaller code, fixed Huffman, dynamic - // Huffman, or just storing the data. - var fixedSize int64 = math.MaxInt64 - if numOffsets <= offsetCodeCount { - fixedSize = int64(3) + - fixedLiteralEncoding.bitLength(w.literalFreq) + - fixedOffsetEncoding.bitLength(w.offsetFreq) + - extraBits - } + // Figure out smallest code. + // Fixed Huffman baseline. + var size = int64(3) + + fixedLiteralEncoding.bitLength(w.literalFreq) + + fixedOffsetEncoding.bitLength(w.offsetFreq) + + extraBits + var literalEncoding = fixedLiteralEncoding + var offsetEncoding = fixedOffsetEncoding + + // Dynamic Huffman? + var numCodegens int + // Generate codegen and codegenFrequencies, which indicates how to encode // the literalEncoding and the offsetEncoding. w.generateCodegen(numLiterals, numOffsets) w.codegenEncoding.generate(w.codegenFreq, 7) - numCodegens := len(w.codegenFreq) + numCodegens = len(w.codegenFreq) for numCodegens > 4 && w.codegenFreq[codegenOrder[numCodegens-1]] == 0 { numCodegens-- } - extensionSummand := 0 - if numOffsets > offsetCodeCount { - extensionSummand = 3 - } dynamicHeader := int64(3+5+5+4+(3*numCodegens)) + - // Following line is an extension. - int64(extensionSummand) + w.codegenEncoding.bitLength(w.codegenFreq) + int64(extraBits) + int64(w.codegenFreq[16]*2) + @@ -454,26 +443,25 @@ func (w *huffmanBitWriter) writeBlock(tokens []token, eof bool, input []byte) { w.literalEncoding.bitLength(w.literalFreq) + w.offsetEncoding.bitLength(w.offsetFreq) - if storedSize < fixedSize && storedSize < dynamicSize { + if dynamicSize < size { + size = dynamicSize + literalEncoding = w.literalEncoding + offsetEncoding = w.offsetEncoding + } + + // Stored bytes? + if storedSize < size { w.writeStoredHeader(storedBytes, eof) w.writeBytes(input[0:storedBytes]) return } - var literalEncoding *huffmanEncoder - var offsetEncoding *huffmanEncoder - if fixedSize <= dynamicSize { + // Huffman. + if literalEncoding == fixedLiteralEncoding { w.writeFixedHeader(eof) - literalEncoding = fixedLiteralEncoding - offsetEncoding = fixedOffsetEncoding } else { - // Write the header. w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof) - literalEncoding = w.literalEncoding - offsetEncoding = w.offsetEncoding } - - // Write the tokens. for _, t := range tokens { switch t.typ() { case literalType: diff --git a/libgo/go/compress/flate/huffman_code.go b/libgo/go/compress/flate/huffman_code.go index 6be605f..7ed603a 100644 --- a/libgo/go/compress/flate/huffman_code.go +++ b/libgo/go/compress/flate/huffman_code.go @@ -363,7 +363,12 @@ func (s literalNodeSorter) Less(i, j int) bool { func (s literalNodeSorter) Swap(i, j int) { s.a[i], s.a[j] = s.a[j], s.a[i] } func sortByFreq(a []literalNode) { - s := &literalNodeSorter{a, func(i, j int) bool { return a[i].freq < a[j].freq }} + s := &literalNodeSorter{a, func(i, j int) bool { + if a[i].freq == a[j].freq { + return a[i].literal < a[j].literal + } + return a[i].freq < a[j].freq + }} sort.Sort(s) } diff --git a/libgo/go/compress/flate/inflate.go b/libgo/go/compress/flate/inflate.go index 320b80d..3845f12 100644 --- a/libgo/go/compress/flate/inflate.go +++ b/libgo/go/compress/flate/inflate.go @@ -77,8 +77,6 @@ type huffmanDecoder struct { // Initialize Huffman decoding tables from array of code lengths. func (h *huffmanDecoder) init(bits []int) bool { - // TODO(rsc): Return false sometimes. - // Count number of codes of each length, // compute min and max length. var count [maxCodeLen + 1]int @@ -197,9 +195,8 @@ type Reader interface { // Decompress state. type decompressor struct { - // Input/output sources. + // Input source. r Reader - w io.Writer roffset int64 woffset int64 @@ -222,38 +219,79 @@ type decompressor struct { // Temporary buffer (avoids repeated allocation). buf [4]byte + + // Next step in the decompression, + // and decompression state. + step func(*decompressor) + final bool + err os.Error + toRead []byte + hl, hd *huffmanDecoder + copyLen int + copyDist int } -func (f *decompressor) inflate() (err os.Error) { - final := false - for err == nil && !final { - for f.nb < 1+2 { - if err = f.moreBits(); err != nil { - return - } +func (f *decompressor) nextBlock() { + if f.final { + if f.hw != f.hp { + f.flush((*decompressor).nextBlock) + return } - final = f.b&1 == 1 - f.b >>= 1 - typ := f.b & 3 - f.b >>= 2 - f.nb -= 1 + 2 - switch typ { - case 0: - err = f.dataBlock() - case 1: - // compressed, fixed Huffman tables - err = f.decodeBlock(&fixedHuffmanDecoder, nil) - case 2: - // compressed, dynamic Huffman tables - if err = f.readHuffman(); err == nil { - err = f.decodeBlock(&f.h1, &f.h2) - } - default: - // 3 is reserved. - err = CorruptInputError(f.roffset) + f.err = os.EOF + return + } + for f.nb < 1+2 { + if f.err = f.moreBits(); f.err != nil { + return + } + } + f.final = f.b&1 == 1 + f.b >>= 1 + typ := f.b & 3 + f.b >>= 2 + f.nb -= 1 + 2 + switch typ { + case 0: + f.dataBlock() + case 1: + // compressed, fixed Huffman tables + f.hl = &fixedHuffmanDecoder + f.hd = nil + f.huffmanBlock() + case 2: + // compressed, dynamic Huffman tables + if f.err = f.readHuffman(); f.err != nil { + break + } + f.hl = &f.h1 + f.hd = &f.h2 + f.huffmanBlock() + default: + // 3 is reserved. + f.err = CorruptInputError(f.roffset) + } +} + +func (f *decompressor) Read(b []byte) (int, os.Error) { + for { + if len(f.toRead) > 0 { + n := copy(b, f.toRead) + f.toRead = f.toRead[n:] + return n, nil + } + if f.err != nil { + return 0, f.err } + f.step(f) } - return + panic("unreachable") +} + +func (f *decompressor) Close() os.Error { + if f.err == os.EOF { + return nil + } + return f.err } // RFC 1951 section 3.2.7. @@ -358,11 +396,12 @@ func (f *decompressor) readHuffman() os.Error { // hl and hd are the Huffman states for the lit/length values // and the distance values, respectively. If hd == nil, using the // fixed distance encoding associated with fixed Huffman blocks. -func (f *decompressor) decodeBlock(hl, hd *huffmanDecoder) os.Error { +func (f *decompressor) huffmanBlock() { for { - v, err := f.huffSym(hl) + v, err := f.huffSym(f.hl) if err != nil { - return err + f.err = err + return } var n uint // number of bits extra var length int @@ -371,13 +410,15 @@ func (f *decompressor) decodeBlock(hl, hd *huffmanDecoder) os.Error { f.hist[f.hp] = byte(v) f.hp++ if f.hp == len(f.hist) { - if err = f.flush(); err != nil { - return err - } + // After the flush, continue this loop. + f.flush((*decompressor).huffmanBlock) + return } continue case v == 256: - return nil + // Done with huffman block; read next block. + f.step = (*decompressor).nextBlock + return // otherwise, reference to older data case v < 265: length = v - (257 - 3) @@ -404,7 +445,8 @@ func (f *decompressor) decodeBlock(hl, hd *huffmanDecoder) os.Error { if n > 0 { for f.nb < n { if err = f.moreBits(); err != nil { - return err + f.err = err + return } } length += int(f.b & uint32(1<>= 5 f.nb -= 5 } else { - if dist, err = f.huffSym(hd); err != nil { - return err + if dist, err = f.huffSym(f.hd); err != nil { + f.err = err + return } } @@ -432,14 +476,16 @@ func (f *decompressor) decodeBlock(hl, hd *huffmanDecoder) os.Error { case dist < 4: dist++ case dist >= 30: - return CorruptInputError(f.roffset) + f.err = CorruptInputError(f.roffset) + return default: nb := uint(dist-2) >> 1 // have 1 bit in bottom of dist, need nb more. extra := (dist & 1) << nb for f.nb < nb { if err = f.moreBits(); err != nil { - return err + f.err = err + return } } extra |= int(f.b & uint32(1< len(f.hist) { - return InternalError("bad history distance") + f.err = InternalError("bad history distance") + return } // No check on length; encoding can be prescient. if !f.hfull && dist > f.hp { - return CorruptInputError(f.roffset) + f.err = CorruptInputError(f.roffset) + return } p := f.hp - dist @@ -467,9 +515,11 @@ func (f *decompressor) decodeBlock(hl, hd *huffmanDecoder) os.Error { f.hp++ p++ if f.hp == len(f.hist) { - if err = f.flush(); err != nil { - return err - } + // After flush continue copying out of history. + f.copyLen = length - (i + 1) + f.copyDist = dist + f.flush((*decompressor).copyHuff) + return } if p == len(f.hist) { p = 0 @@ -479,8 +529,33 @@ func (f *decompressor) decodeBlock(hl, hd *huffmanDecoder) os.Error { panic("unreached") } +func (f *decompressor) copyHuff() { + length := f.copyLen + dist := f.copyDist + p := f.hp - dist + if p < 0 { + p += len(f.hist) + } + for i := 0; i < length; i++ { + f.hist[f.hp] = f.hist[p] + f.hp++ + p++ + if f.hp == len(f.hist) { + f.copyLen = length - (i + 1) + f.flush((*decompressor).copyHuff) + return + } + if p == len(f.hist) { + p = 0 + } + } + + // Continue processing Huffman block. + f.huffmanBlock() +} + // Copy a single uncompressed data block from input to output. -func (f *decompressor) dataBlock() os.Error { +func (f *decompressor) dataBlock() { // Uncompressed. // Discard current half-byte. f.nb = 0 @@ -490,21 +565,30 @@ func (f *decompressor) dataBlock() os.Error { nr, err := io.ReadFull(f.r, f.buf[0:4]) f.roffset += int64(nr) if err != nil { - return &ReadError{f.roffset, err} + f.err = &ReadError{f.roffset, err} + return } n := int(f.buf[0]) | int(f.buf[1])<<8 nn := int(f.buf[2]) | int(f.buf[3])<<8 if uint16(nn) != uint16(^n) { - return CorruptInputError(f.roffset) + f.err = CorruptInputError(f.roffset) + return } if n == 0 { // 0-length block means sync - return f.flush() + f.flush((*decompressor).nextBlock) + return } - // Read len bytes into history, - // writing as history fills. + f.copyLen = n + f.copyData() +} + +func (f *decompressor) copyData() { + // Read f.dataLen bytes into history, + // pausing for reads as history fills. + n := f.copyLen for n > 0 { m := len(f.hist) - f.hp if m > n { @@ -513,17 +597,18 @@ func (f *decompressor) dataBlock() os.Error { m, err := io.ReadFull(f.r, f.hist[f.hp:f.hp+m]) f.roffset += int64(m) if err != nil { - return &ReadError{f.roffset, err} + f.err = &ReadError{f.roffset, err} + return } n -= m f.hp += m if f.hp == len(f.hist) { - if err = f.flush(); err != nil { - return err - } + f.copyLen = n + f.flush((*decompressor).copyData) + return } } - return nil + f.step = (*decompressor).nextBlock } func (f *decompressor) setDict(dict []byte) { @@ -579,17 +664,8 @@ func (f *decompressor) huffSym(h *huffmanDecoder) (int, os.Error) { } // Flush any buffered output to the underlying writer. -func (f *decompressor) flush() os.Error { - if f.hw == f.hp { - return nil - } - n, err := f.w.Write(f.hist[f.hw:f.hp]) - if n != f.hp-f.hw && err == nil { - err = io.ErrShortWrite - } - if err != nil { - return &WriteError{f.woffset, err} - } +func (f *decompressor) flush(step func(*decompressor)) { + f.toRead = f.hist[f.hw:f.hp] f.woffset += int64(f.hp - f.hw) f.hw = f.hp if f.hp == len(f.hist) { @@ -597,7 +673,7 @@ func (f *decompressor) flush() os.Error { f.hw = 0 f.hfull = true } - return nil + f.step = step } func makeReader(r io.Reader) Reader { @@ -607,30 +683,15 @@ func makeReader(r io.Reader) Reader { return bufio.NewReader(r) } -// decompress reads DEFLATE-compressed data from r and writes -// the uncompressed data to w. -func (f *decompressor) decompress(r io.Reader, w io.Writer) os.Error { - f.r = makeReader(r) - f.w = w - f.woffset = 0 - if err := f.inflate(); err != nil { - return err - } - if err := f.flush(); err != nil { - return err - } - return nil -} - // NewReader returns a new ReadCloser that can be used // to read the uncompressed version of r. It is the caller's // responsibility to call Close on the ReadCloser when // finished reading. func NewReader(r io.Reader) io.ReadCloser { var f decompressor - pr, pw := io.Pipe() - go func() { pw.CloseWithError(f.decompress(r, pw)) }() - return pr + f.r = makeReader(r) + f.step = (*decompressor).nextBlock + return &f } // NewReaderDict is like NewReader but initializes the reader @@ -641,7 +702,7 @@ func NewReader(r io.Reader) io.ReadCloser { func NewReaderDict(r io.Reader, dict []byte) io.ReadCloser { var f decompressor f.setDict(dict) - pr, pw := io.Pipe() - go func() { pw.CloseWithError(f.decompress(r, pw)) }() - return pr + f.r = makeReader(r) + f.step = (*decompressor).nextBlock + return &f } diff --git a/libgo/go/compress/gzip/gunzip.go b/libgo/go/compress/gzip/gunzip.go index b0ddc81..6ac9293 100644 --- a/libgo/go/compress/gzip/gunzip.go +++ b/libgo/go/compress/gzip/gunzip.go @@ -36,8 +36,8 @@ func makeReader(r io.Reader) flate.Reader { return bufio.NewReader(r) } -var HeaderError os.Error = os.ErrorString("invalid gzip header") -var ChecksumError os.Error = os.ErrorString("gzip checksum error") +var HeaderError = os.NewError("invalid gzip header") +var ChecksumError = os.NewError("gzip checksum error") // The gzip file stores a header giving metadata about the compressed file. // That header is exposed as the fields of the Compressor and Decompressor structs. diff --git a/libgo/go/compress/gzip/gzip_test.go b/libgo/go/compress/gzip/gzip_test.go index 23f3514..121e627 100644 --- a/libgo/go/compress/gzip/gzip_test.go +++ b/libgo/go/compress/gzip/gzip_test.go @@ -11,7 +11,7 @@ import ( ) // pipe creates two ends of a pipe that gzip and gunzip, and runs dfunc at the -// writer end and ifunc at the reader end. +// writer end and cfunc at the reader end. func pipe(t *testing.T, dfunc func(*Compressor), cfunc func(*Decompressor)) { piper, pipew := io.Pipe() defer piper.Close() diff --git a/libgo/go/compress/lzw/reader.go b/libgo/go/compress/lzw/reader.go index a1cd2ab..21231c8 100644 --- a/libgo/go/compress/lzw/reader.go +++ b/libgo/go/compress/lzw/reader.go @@ -32,13 +32,49 @@ const ( MSB ) +const ( + maxWidth = 12 + decoderInvalidCode = 0xffff + flushBuffer = 1 << maxWidth +) + // decoder is the state from which the readXxx method converts a byte // stream into a code stream. type decoder struct { - r io.ByteReader - bits uint32 - nBits uint - width uint + r io.ByteReader + bits uint32 + nBits uint + width uint + read func(*decoder) (uint16, os.Error) // readLSB or readMSB + litWidth int // width in bits of literal codes + err os.Error + + // The first 1<= 1< 0 { + n := copy(b, d.toRead) + d.toRead = d.toRead[n:] + return n, nil + } + if d.err != nil { + return 0, d.err + } + d.decode() } - pw.CloseWithError(decode1(pw, br, read, uint(litWidth))) + panic("unreachable") } -func decode1(pw *io.PipeWriter, r io.ByteReader, read func(*decoder) (uint16, os.Error), litWidth uint) os.Error { - const ( - maxWidth = 12 - invalidCode = 0xffff - ) - d := decoder{r, 0, 0, 1 + litWidth} - w := bufio.NewWriter(pw) - // The first 1<= clear { - c = prefix[c] + c = d.last + for c >= d.clear { + c = d.prefix[c] } - buf[i] = uint8(c) + d.output[i] = uint8(c) i-- - c = last + c = d.last } - // Copy the suffix chain into buf and then write that to w. - for c >= clear { - buf[i] = suffix[c] + // Copy the suffix chain into output and then write that to w. + for c >= d.clear { + d.output[i] = d.suffix[c] i-- - c = prefix[c] + c = d.prefix[c] } - buf[i] = uint8(c) - if _, err := w.Write(buf[i:]); err != nil { - return err - } - if last != invalidCode { + d.output[i] = uint8(c) + d.o += copy(d.output[d.o:], d.output[i:]) + if d.last != decoderInvalidCode { // Save what the hi code expands to. - suffix[hi] = uint8(c) - prefix[hi] = last + d.suffix[d.hi] = uint8(c) + d.prefix[d.hi] = d.last } default: - return os.NewError("lzw: invalid code") + d.err = os.NewError("lzw: invalid code") + return } - last, hi = code, hi+1 - if hi >= overflow { + d.last, d.hi = code, d.hi+1 + if d.hi >= d.overflow { if d.width == maxWidth { - last = invalidCode - continue + d.last = decoderInvalidCode + } else { + d.width++ + d.overflow <<= 1 } - d.width++ - overflow <<= 1 + } + if d.o >= flushBuffer { + d.flush() + return } } panic("unreachable") } +func (d *decoder) flush() { + d.toRead = d.output[:d.o] + d.o = 0 +} + +func (d *decoder) Close() os.Error { + d.err = os.EINVAL // in case any Reads come along + return nil +} + // NewReader creates a new io.ReadCloser that satisfies reads by decompressing // the data read from r. // It is the caller's responsibility to call Close on the ReadCloser when @@ -193,21 +223,31 @@ func decode1(pw *io.PipeWriter, r io.ByteReader, read func(*decoder) (uint16, os // The number of bits to use for literal codes, litWidth, must be in the // range [2,8] and is typically 8. func NewReader(r io.Reader, order Order, litWidth int) io.ReadCloser { - pr, pw := io.Pipe() - var read func(*decoder) (uint16, os.Error) + d := new(decoder) switch order { case LSB: - read = (*decoder).readLSB + d.read = (*decoder).readLSB case MSB: - read = (*decoder).readMSB + d.read = (*decoder).readMSB default: - pw.CloseWithError(os.NewError("lzw: unknown order")) - return pr + d.err = os.NewError("lzw: unknown order") + return d } if litWidth < 2 || 8 < litWidth { - pw.CloseWithError(fmt.Errorf("lzw: litWidth %d out of range", litWidth)) - return pr + d.err = fmt.Errorf("lzw: litWidth %d out of range", litWidth) + return d } - go decode(r, read, litWidth, pw) - return pr + if br, ok := r.(io.ByteReader); ok { + d.r = br + } else { + d.r = bufio.NewReader(r) + } + d.litWidth = litWidth + d.width = 1 + uint(litWidth) + d.clear = uint16(1) << uint(litWidth) + d.eof, d.hi = d.clear+1, d.clear+1 + d.overflow = uint16(1) << d.width + d.last = decoderInvalidCode + + return d } diff --git a/libgo/go/compress/lzw/reader_test.go b/libgo/go/compress/lzw/reader_test.go index 72121a6..f8042b0 100644 --- a/libgo/go/compress/lzw/reader_test.go +++ b/libgo/go/compress/lzw/reader_test.go @@ -84,7 +84,7 @@ var lzwTests = []lzwTest{ func TestReader(t *testing.T) { b := bytes.NewBuffer(nil) for _, tt := range lzwTests { - d := strings.Split(tt.desc, ";", -1) + d := strings.Split(tt.desc, ";") var order Order switch d[1] { case "LSB": diff --git a/libgo/go/compress/lzw/writer_test.go b/libgo/go/compress/lzw/writer_test.go index 82464ec..4c5e522 100644 --- a/libgo/go/compress/lzw/writer_test.go +++ b/libgo/go/compress/lzw/writer_test.go @@ -77,13 +77,13 @@ func testFile(t *testing.T, fn string, order Order, litWidth int) { t.Errorf("%s (order=%d litWidth=%d): %v", fn, order, litWidth, err1) return } - if len(b0) != len(b1) { - t.Errorf("%s (order=%d litWidth=%d): length mismatch %d versus %d", fn, order, litWidth, len(b0), len(b1)) + if len(b1) != len(b0) { + t.Errorf("%s (order=%d litWidth=%d): length mismatch %d != %d", fn, order, litWidth, len(b1), len(b0)) return } for i := 0; i < len(b0); i++ { - if b0[i] != b1[i] { - t.Errorf("%s (order=%d litWidth=%d): mismatch at %d, 0x%02x versus 0x%02x\n", fn, order, litWidth, i, b0[i], b1[i]) + if b1[i] != b0[i] { + t.Errorf("%s (order=%d litWidth=%d): mismatch at %d, 0x%02x != 0x%02x\n", fn, order, litWidth, i, b1[i], b0[i]) return } } diff --git a/libgo/go/compress/zlib/reader.go b/libgo/go/compress/zlib/reader.go index 8a3ef15..78dabdf 100644 --- a/libgo/go/compress/zlib/reader.go +++ b/libgo/go/compress/zlib/reader.go @@ -34,9 +34,9 @@ import ( const zlibDeflate = 8 -var ChecksumError os.Error = os.ErrorString("zlib checksum error") -var HeaderError os.Error = os.ErrorString("invalid zlib header") -var DictionaryError os.Error = os.ErrorString("invalid zlib dictionary") +var ChecksumError = os.NewError("zlib checksum error") +var HeaderError = os.NewError("invalid zlib header") +var DictionaryError = os.NewError("invalid zlib dictionary") type reader struct { r flate.Reader diff --git a/libgo/go/compress/zlib/writer.go b/libgo/go/compress/zlib/writer.go index f1f9b28..8f86e9c 100644 --- a/libgo/go/compress/zlib/writer.go +++ b/libgo/go/compress/zlib/writer.go @@ -89,7 +89,7 @@ func NewWriterDict(w io.Writer, level int, dict []byte) (*Writer, os.Error) { } } z.w = w - z.compressor = flate.NewWriter(w, level) + z.compressor = flate.NewWriterDict(w, level, dict) z.digest = adler32.New() return z, nil } diff --git a/libgo/go/compress/zlib/writer_test.go b/libgo/go/compress/zlib/writer_test.go index f94f284..32f05ab 100644 --- a/libgo/go/compress/zlib/writer_test.go +++ b/libgo/go/compress/zlib/writer_test.go @@ -5,6 +5,8 @@ package zlib import ( + "bytes" + "fmt" "io" "io/ioutil" "os" @@ -16,15 +18,13 @@ var filenames = []string{ "../testdata/pi.txt", } +var data = []string{ + "test a reasonable sized string that can be compressed", +} + // Tests that compressing and then decompressing the given file at the given compression level and dictionary // yields equivalent bytes to the original file. func testFileLevelDict(t *testing.T, fn string, level int, d string) { - // Read dictionary, if given. - var dict []byte - if d != "" { - dict = []byte(d) - } - // Read the file, as golden output. golden, err := os.Open(fn) if err != nil { @@ -32,17 +32,25 @@ func testFileLevelDict(t *testing.T, fn string, level int, d string) { return } defer golden.Close() - - // Read the file again, and push it through a pipe that compresses at the write end, and decompresses at the read end. - raw, err := os.Open(fn) - if err != nil { - t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err) + b0, err0 := ioutil.ReadAll(golden) + if err0 != nil { + t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err0) return } + testLevelDict(t, fn, b0, level, d) +} + +func testLevelDict(t *testing.T, fn string, b0 []byte, level int, d string) { + // Make dictionary, if given. + var dict []byte + if d != "" { + dict = []byte(d) + } + + // Push data through a pipe that compresses at the write end, and decompresses at the read end. piper, pipew := io.Pipe() defer piper.Close() go func() { - defer raw.Close() defer pipew.Close() zlibw, err := NewWriterDict(pipew, level, dict) if err != nil { @@ -50,25 +58,14 @@ func testFileLevelDict(t *testing.T, fn string, level int, d string) { return } defer zlibw.Close() - var b [1024]byte - for { - n, err0 := raw.Read(b[0:]) - if err0 != nil && err0 != os.EOF { - t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err0) - return - } - _, err1 := zlibw.Write(b[0:n]) - if err1 == os.EPIPE { - // Fail, but do not report the error, as some other (presumably reportable) error broke the pipe. - return - } - if err1 != nil { - t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err1) - return - } - if err0 == os.EOF { - break - } + _, err = zlibw.Write(b0) + if err == os.EPIPE { + // Fail, but do not report the error, as some other (presumably reported) error broke the pipe. + return + } + if err != nil { + t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err) + return } }() zlibr, err := NewReaderDict(piper, dict) @@ -78,13 +75,8 @@ func testFileLevelDict(t *testing.T, fn string, level int, d string) { } defer zlibr.Close() - // Compare the two. - b0, err0 := ioutil.ReadAll(golden) + // Compare the decompressed data. b1, err1 := ioutil.ReadAll(zlibr) - if err0 != nil { - t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err0) - return - } if err1 != nil { t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err1) return @@ -102,6 +94,18 @@ func testFileLevelDict(t *testing.T, fn string, level int, d string) { } func TestWriter(t *testing.T) { + for i, s := range data { + b := []byte(s) + tag := fmt.Sprintf("#%d", i) + testLevelDict(t, tag, b, DefaultCompression, "") + testLevelDict(t, tag, b, NoCompression, "") + for level := BestSpeed; level <= BestCompression; level++ { + testLevelDict(t, tag, b, level, "") + } + } +} + +func TestWriterBig(t *testing.T) { for _, fn := range filenames { testFileLevelDict(t, fn, DefaultCompression, "") testFileLevelDict(t, fn, NoCompression, "") @@ -121,3 +125,20 @@ func TestWriterDict(t *testing.T) { } } } + +func TestWriterDictIsUsed(t *testing.T) { + var input = []byte("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.") + buf := bytes.NewBuffer(nil) + compressor, err := NewWriterDict(buf, BestCompression, input) + if err != nil { + t.Errorf("error in NewWriterDict: %s", err) + return + } + compressor.Write(input) + compressor.Close() + const expectedMaxSize = 25 + output := buf.Bytes() + if len(output) > expectedMaxSize { + t.Errorf("result too large (got %d, want <= %d bytes). Is the dictionary being used?", len(output), expectedMaxSize) + } +} diff --git a/libgo/go/container/heap/heap.go b/libgo/go/container/heap/heap.go index f2b8a75..2dfe5b4 100644 --- a/libgo/go/container/heap/heap.go +++ b/libgo/go/container/heap/heap.go @@ -21,8 +21,7 @@ type Interface interface { Pop() interface{} } - -// A heaper must be initialized before any of the heap operations +// A heap must be initialized before any of the heap operations // can be used. Init is idempotent with respect to the heap invariants // and may be called whenever the heap invariants may have been invalidated. // Its complexity is O(n) where n = h.Len(). @@ -35,7 +34,6 @@ func Init(h Interface) { } } - // Push pushes the element x onto the heap. The complexity is // O(log(n)) where n = h.Len(). // @@ -44,7 +42,6 @@ func Push(h Interface, x interface{}) { up(h, h.Len()-1) } - // Pop removes the minimum element (according to Less) from the heap // and returns it. The complexity is O(log(n)) where n = h.Len(). // Same as Remove(h, 0). @@ -56,7 +53,6 @@ func Pop(h Interface) interface{} { return h.Pop() } - // Remove removes the element at index i from the heap. // The complexity is O(log(n)) where n = h.Len(). // @@ -70,7 +66,6 @@ func Remove(h Interface, i int) interface{} { return h.Pop() } - func up(h Interface, j int) { for { i := (j - 1) / 2 // parent @@ -82,7 +77,6 @@ func up(h Interface, j int) { } } - func down(h Interface, i, n int) { for { j1 := 2*i + 1 diff --git a/libgo/go/container/heap/heap_test.go b/libgo/go/container/heap/heap_test.go index 5eb5437..c5c1f76 100644 --- a/libgo/go/container/heap/heap_test.go +++ b/libgo/go/container/heap/heap_test.go @@ -10,17 +10,14 @@ import ( . "container/heap" ) - type myHeap struct { // A vector.Vector implements sort.Interface except for Less, // and it implements Push and Pop as required for heap.Interface. vector.Vector } - func (h *myHeap) Less(i, j int) bool { return h.At(i).(int) < h.At(j).(int) } - func (h *myHeap) verify(t *testing.T, i int) { n := h.Len() j1 := 2*i + 1 @@ -41,7 +38,6 @@ func (h *myHeap) verify(t *testing.T, i int) { } } - func TestInit0(t *testing.T) { h := new(myHeap) for i := 20; i > 0; i-- { @@ -59,7 +55,6 @@ func TestInit0(t *testing.T) { } } - func TestInit1(t *testing.T) { h := new(myHeap) for i := 20; i > 0; i-- { @@ -77,7 +72,6 @@ func TestInit1(t *testing.T) { } } - func Test(t *testing.T) { h := new(myHeap) h.verify(t, 0) @@ -105,7 +99,6 @@ func Test(t *testing.T) { } } - func TestRemove0(t *testing.T) { h := new(myHeap) for i := 0; i < 10; i++ { @@ -123,7 +116,6 @@ func TestRemove0(t *testing.T) { } } - func TestRemove1(t *testing.T) { h := new(myHeap) for i := 0; i < 10; i++ { @@ -140,7 +132,6 @@ func TestRemove1(t *testing.T) { } } - func TestRemove2(t *testing.T) { N := 10 diff --git a/libgo/go/container/ring/ring.go b/libgo/go/container/ring/ring.go index cc870ce..1d96918 100644 --- a/libgo/go/container/ring/ring.go +++ b/libgo/go/container/ring/ring.go @@ -16,14 +16,12 @@ type Ring struct { Value interface{} // for use by client; untouched by this library } - func (r *Ring) init() *Ring { r.next = r r.prev = r return r } - // Next returns the next ring element. r must not be empty. func (r *Ring) Next() *Ring { if r.next == nil { @@ -32,7 +30,6 @@ func (r *Ring) Next() *Ring { return r.next } - // Prev returns the previous ring element. r must not be empty. func (r *Ring) Prev() *Ring { if r.next == nil { @@ -41,7 +38,6 @@ func (r *Ring) Prev() *Ring { return r.prev } - // Move moves n % r.Len() elements backward (n < 0) or forward (n >= 0) // in the ring and returns that ring element. r must not be empty. // @@ -62,7 +58,6 @@ func (r *Ring) Move(n int) *Ring { return r } - // New creates a ring of n elements. func New(n int) *Ring { if n <= 0 { @@ -79,7 +74,6 @@ func New(n int) *Ring { return r } - // Link connects ring r with with ring s such that r.Next() // becomes s and returns the original value for r.Next(). // r must not be empty. @@ -110,7 +104,6 @@ func (r *Ring) Link(s *Ring) *Ring { return n } - // Unlink removes n % r.Len() elements from the ring r, starting // at r.Next(). If n % r.Len() == 0, r remains unchanged. // The result is the removed subring. r must not be empty. @@ -122,7 +115,6 @@ func (r *Ring) Unlink(n int) *Ring { return r.Link(r.Move(n + 1)) } - // Len computes the number of elements in ring r. // It executes in time proportional to the number of elements. // @@ -137,7 +129,6 @@ func (r *Ring) Len() int { return n } - // Do calls function f on each element of the ring, in forward order. // The behavior of Do is undefined if f changes *r. func (r *Ring) Do(f func(interface{})) { diff --git a/libgo/go/container/ring/ring_test.go b/libgo/go/container/ring/ring_test.go index 778c083..099d92b 100644 --- a/libgo/go/container/ring/ring_test.go +++ b/libgo/go/container/ring/ring_test.go @@ -9,7 +9,6 @@ import ( "testing" ) - // For debugging - keep around. func dump(r *Ring) { if r == nil { @@ -24,7 +23,6 @@ func dump(r *Ring) { fmt.Println() } - func verify(t *testing.T, r *Ring, N int, sum int) { // Len n := r.Len() @@ -96,7 +94,6 @@ func verify(t *testing.T, r *Ring, N int, sum int) { } } - func TestCornerCases(t *testing.T) { var ( r0 *Ring @@ -118,7 +115,6 @@ func TestCornerCases(t *testing.T) { verify(t, &r1, 1, 0) } - func makeN(n int) *Ring { r := New(n) for i := 1; i <= n; i++ { @@ -130,7 +126,6 @@ func makeN(n int) *Ring { func sumN(n int) int { return (n*n + n) / 2 } - func TestNew(t *testing.T) { for i := 0; i < 10; i++ { r := New(i) @@ -142,7 +137,6 @@ func TestNew(t *testing.T) { } } - func TestLink1(t *testing.T) { r1a := makeN(1) var r1b Ring @@ -163,7 +157,6 @@ func TestLink1(t *testing.T) { verify(t, r2b, 1, 0) } - func TestLink2(t *testing.T) { var r0 *Ring r1a := &Ring{Value: 42} @@ -183,7 +176,6 @@ func TestLink2(t *testing.T) { verify(t, r10, 12, sumN(10)+42+77) } - func TestLink3(t *testing.T) { var r Ring n := 1 @@ -193,7 +185,6 @@ func TestLink3(t *testing.T) { } } - func TestUnlink(t *testing.T) { r10 := makeN(10) s10 := r10.Move(6) @@ -215,7 +206,6 @@ func TestUnlink(t *testing.T) { verify(t, r10, 9, sum10-2) } - func TestLinkUnlink(t *testing.T) { for i := 1; i < 4; i++ { ri := New(i) diff --git a/libgo/go/container/vector/defs.go b/libgo/go/container/vector/defs.go index bfb5481..6d6b2ac 100644 --- a/libgo/go/container/vector/defs.go +++ b/libgo/go/container/vector/defs.go @@ -6,29 +6,24 @@ // Vectors grow and shrink dynamically as necessary. package vector - // Vector is a container for numbered sequences of elements of type interface{}. // A vector's length and capacity adjusts automatically as necessary. // The zero value for Vector is an empty vector ready to use. type Vector []interface{} - // IntVector is a container for numbered sequences of elements of type int. // A vector's length and capacity adjusts automatically as necessary. // The zero value for IntVector is an empty vector ready to use. type IntVector []int - // StringVector is a container for numbered sequences of elements of type string. // A vector's length and capacity adjusts automatically as necessary. // The zero value for StringVector is an empty vector ready to use. type StringVector []string - // Initial underlying array size const initialSize = 8 - // Partial sort.Interface support // LessInterface provides partial support of the sort.Interface. @@ -36,16 +31,13 @@ type LessInterface interface { Less(y interface{}) bool } - // Less returns a boolean denoting whether the i'th element is less than the j'th element. func (p *Vector) Less(i, j int) bool { return (*p)[i].(LessInterface).Less((*p)[j]) } - // sort.Interface support // Less returns a boolean denoting whether the i'th element is less than the j'th element. func (p *IntVector) Less(i, j int) bool { return (*p)[i] < (*p)[j] } - // Less returns a boolean denoting whether the i'th element is less than the j'th element. func (p *StringVector) Less(i, j int) bool { return (*p)[i] < (*p)[j] } diff --git a/libgo/go/container/vector/intvector.go b/libgo/go/container/vector/intvector.go index 5ad9e29..aa88cfe 100644 --- a/libgo/go/container/vector/intvector.go +++ b/libgo/go/container/vector/intvector.go @@ -7,7 +7,6 @@ package vector - func (p *IntVector) realloc(length, capacity int) (b []int) { if capacity < initialSize { capacity = initialSize @@ -21,7 +20,6 @@ func (p *IntVector) realloc(length, capacity int) (b []int) { return } - // Insert n elements at position i. func (p *IntVector) Expand(i, n int) { a := *p @@ -51,11 +49,9 @@ func (p *IntVector) Expand(i, n int) { *p = a } - // Insert n elements at the end of a vector. func (p *IntVector) Extend(n int) { p.Expand(len(*p), n) } - // Resize changes the length and capacity of a vector. // If the new length is shorter than the current length, Resize discards // trailing elements. If the new length is longer than the current length, @@ -80,30 +76,24 @@ func (p *IntVector) Resize(length, capacity int) *IntVector { return p } - // Len returns the number of elements in the vector. // Same as len(*p). func (p *IntVector) Len() int { return len(*p) } - // Cap returns the capacity of the vector; that is, the // maximum length the vector can grow without resizing. // Same as cap(*p). func (p *IntVector) Cap() int { return cap(*p) } - // At returns the i'th element of the vector. func (p *IntVector) At(i int) int { return (*p)[i] } - // Set sets the i'th element of the vector to value x. func (p *IntVector) Set(i int, x int) { (*p)[i] = x } - // Last returns the element in the vector of highest index. func (p *IntVector) Last() int { return (*p)[len(*p)-1] } - // Copy makes a copy of the vector and returns it. func (p *IntVector) Copy() IntVector { arr := make(IntVector, len(*p)) @@ -111,7 +101,6 @@ func (p *IntVector) Copy() IntVector { return arr } - // Insert inserts into the vector an element of value x before // the current element at index i. func (p *IntVector) Insert(i int, x int) { @@ -119,7 +108,6 @@ func (p *IntVector) Insert(i int, x int) { (*p)[i] = x } - // Delete deletes the i'th element of the vector. The gap is closed so the old // element at index i+1 has index i afterwards. func (p *IntVector) Delete(i int) { @@ -132,7 +120,6 @@ func (p *IntVector) Delete(i int) { *p = a[0 : n-1] } - // InsertVector inserts into the vector the contents of the vector // x such that the 0th element of x appears at index i after insertion. func (p *IntVector) InsertVector(i int, x *IntVector) { @@ -142,7 +129,6 @@ func (p *IntVector) InsertVector(i int, x *IntVector) { copy((*p)[i:i+len(b)], b) } - // Cut deletes elements i through j-1, inclusive. func (p *IntVector) Cut(i, j int) { a := *p @@ -158,7 +144,6 @@ func (p *IntVector) Cut(i, j int) { *p = a[0:m] } - // Slice returns a new sub-vector by slicing the old one to extract slice [i:j]. // The elements are copied. The original vector is unchanged. func (p *IntVector) Slice(i, j int) *IntVector { @@ -168,13 +153,11 @@ func (p *IntVector) Slice(i, j int) *IntVector { return &s } - // Convenience wrappers // Push appends x to the end of the vector. func (p *IntVector) Push(x int) { p.Insert(len(*p), x) } - // Pop deletes the last element of the vector. func (p *IntVector) Pop() int { a := *p @@ -187,18 +170,15 @@ func (p *IntVector) Pop() int { return x } - // AppendVector appends the entire vector x to the end of this vector. func (p *IntVector) AppendVector(x *IntVector) { p.InsertVector(len(*p), x) } - // Swap exchanges the elements at indexes i and j. func (p *IntVector) Swap(i, j int) { a := *p a[i], a[j] = a[j], a[i] } - // Do calls function f for each element of the vector, in order. // The behavior of Do is undefined if f changes *p. func (p *IntVector) Do(f func(elem int)) { diff --git a/libgo/go/container/vector/intvector_test.go b/libgo/go/container/vector/intvector_test.go index 1e38a19..b825af9 100644 --- a/libgo/go/container/vector/intvector_test.go +++ b/libgo/go/container/vector/intvector_test.go @@ -9,7 +9,6 @@ package vector import "testing" - func TestIntZeroLen(t *testing.T) { a := new(IntVector) if a.Len() != 0 { @@ -27,7 +26,6 @@ func TestIntZeroLen(t *testing.T) { } } - func TestIntResize(t *testing.T) { var a IntVector checkSize(t, &a, 0, 0) @@ -40,7 +38,6 @@ func TestIntResize(t *testing.T) { checkSize(t, a.Resize(11, 100), 11, 100) } - func TestIntResize2(t *testing.T) { var a IntVector checkSize(t, &a, 0, 0) @@ -62,7 +59,6 @@ func TestIntResize2(t *testing.T) { } } - func checkIntZero(t *testing.T, a *IntVector, i int) { for j := 0; j < i; j++ { if a.At(j) == intzero { @@ -82,7 +78,6 @@ func checkIntZero(t *testing.T, a *IntVector, i int) { } } - func TestIntTrailingElements(t *testing.T) { var a IntVector for i := 0; i < 10; i++ { @@ -95,7 +90,6 @@ func TestIntTrailingElements(t *testing.T) { checkIntZero(t, &a, 5) } - func TestIntAccess(t *testing.T) { const n = 100 var a IntVector @@ -120,7 +114,6 @@ func TestIntAccess(t *testing.T) { } } - func TestIntInsertDeleteClear(t *testing.T) { const n = 100 var a IntVector @@ -207,7 +200,6 @@ func TestIntInsertDeleteClear(t *testing.T) { } } - func verify_sliceInt(t *testing.T, x *IntVector, elt, i, j int) { for k := i; k < j; k++ { if elem2IntValue(x.At(k)) != int2IntValue(elt) { @@ -223,7 +215,6 @@ func verify_sliceInt(t *testing.T, x *IntVector, elt, i, j int) { } } - func verify_patternInt(t *testing.T, x *IntVector, a, b, c int) { n := a + b + c if x.Len() != n { @@ -237,7 +228,6 @@ func verify_patternInt(t *testing.T, x *IntVector, a, b, c int) { verify_sliceInt(t, x, 0, a+b, n) } - func make_vectorInt(elt, len int) *IntVector { x := new(IntVector).Resize(len, 0) for i := 0; i < len; i++ { @@ -246,7 +236,6 @@ func make_vectorInt(elt, len int) *IntVector { return x } - func TestIntInsertVector(t *testing.T) { // 1 a := make_vectorInt(0, 0) @@ -270,7 +259,6 @@ func TestIntInsertVector(t *testing.T) { verify_patternInt(t, a, 8, 1000, 2) } - func TestIntDo(t *testing.T) { const n = 25 const salt = 17 @@ -325,7 +313,6 @@ func TestIntDo(t *testing.T) { } - func TestIntVectorCopy(t *testing.T) { // verify Copy() returns a copy, not simply a slice of the original vector const Len = 10 diff --git a/libgo/go/container/vector/nogen_test.go b/libgo/go/container/vector/nogen_test.go index 790d374..7b6a259 100644 --- a/libgo/go/container/vector/nogen_test.go +++ b/libgo/go/container/vector/nogen_test.go @@ -4,7 +4,6 @@ package vector - import ( "fmt" "sort" @@ -17,28 +16,23 @@ var ( strzero string ) - func int2Value(x int) int { return x } func int2IntValue(x int) int { return x } func int2StrValue(x int) string { return string(x) } - func elem2Value(x interface{}) int { return x.(int) } func elem2IntValue(x int) int { return x } func elem2StrValue(x string) string { return x } - func intf2Value(x interface{}) int { return x.(int) } func intf2IntValue(x interface{}) int { return x.(int) } func intf2StrValue(x interface{}) string { return x.(string) } - type VectorInterface interface { Len() int Cap() int } - func checkSize(t *testing.T, v VectorInterface, len, cap int) { if v.Len() != len { t.Errorf("%T expected len = %d; found %d", v, len, v.Len()) @@ -48,10 +42,8 @@ func checkSize(t *testing.T, v VectorInterface, len, cap int) { } } - func val(i int) int { return i*991 - 1234 } - func TestSorting(t *testing.T) { const n = 100 @@ -72,5 +64,4 @@ func TestSorting(t *testing.T) { } } - func tname(x interface{}) string { return fmt.Sprintf("%T: ", x) } diff --git a/libgo/go/container/vector/numbers_test.go b/libgo/go/container/vector/numbers_test.go index b83b0bf..abe01a8 100644 --- a/libgo/go/container/vector/numbers_test.go +++ b/libgo/go/container/vector/numbers_test.go @@ -11,10 +11,8 @@ import ( "testing" ) - const memTestN = 1000000 - func s(n uint64) string { str := fmt.Sprintf("%d", n) lens := len(str) @@ -31,7 +29,6 @@ func s(n uint64) string { return strings.Join(a, " ") } - func TestVectorNums(t *testing.T) { if testing.Short() { return @@ -52,7 +49,6 @@ func TestVectorNums(t *testing.T) { t.Logf("%T.Push(%#v), n = %s: Alloc/n = %.2f\n", v, c, s(memTestN), float64(n)/memTestN) } - func TestIntVectorNums(t *testing.T) { if testing.Short() { return @@ -73,7 +69,6 @@ func TestIntVectorNums(t *testing.T) { t.Logf("%T.Push(%#v), n = %s: Alloc/n = %.2f\n", v, c, s(memTestN), float64(n)/memTestN) } - func TestStringVectorNums(t *testing.T) { if testing.Short() { return @@ -94,7 +89,6 @@ func TestStringVectorNums(t *testing.T) { t.Logf("%T.Push(%#v), n = %s: Alloc/n = %.2f\n", v, c, s(memTestN), float64(n)/memTestN) } - func BenchmarkVectorNums(b *testing.B) { c := int(0) var v Vector @@ -106,7 +100,6 @@ func BenchmarkVectorNums(b *testing.B) { } } - func BenchmarkIntVectorNums(b *testing.B) { c := int(0) var v IntVector @@ -118,7 +111,6 @@ func BenchmarkIntVectorNums(b *testing.B) { } } - func BenchmarkStringVectorNums(b *testing.B) { c := "" var v StringVector diff --git a/libgo/go/container/vector/stringvector.go b/libgo/go/container/vector/stringvector.go index 852685f..dc81f06 100644 --- a/libgo/go/container/vector/stringvector.go +++ b/libgo/go/container/vector/stringvector.go @@ -7,7 +7,6 @@ package vector - func (p *StringVector) realloc(length, capacity int) (b []string) { if capacity < initialSize { capacity = initialSize @@ -21,7 +20,6 @@ func (p *StringVector) realloc(length, capacity int) (b []string) { return } - // Insert n elements at position i. func (p *StringVector) Expand(i, n int) { a := *p @@ -51,11 +49,9 @@ func (p *StringVector) Expand(i, n int) { *p = a } - // Insert n elements at the end of a vector. func (p *StringVector) Extend(n int) { p.Expand(len(*p), n) } - // Resize changes the length and capacity of a vector. // If the new length is shorter than the current length, Resize discards // trailing elements. If the new length is longer than the current length, @@ -80,30 +76,24 @@ func (p *StringVector) Resize(length, capacity int) *StringVector { return p } - // Len returns the number of elements in the vector. // Same as len(*p). func (p *StringVector) Len() int { return len(*p) } - // Cap returns the capacity of the vector; that is, the // maximum length the vector can grow without resizing. // Same as cap(*p). func (p *StringVector) Cap() int { return cap(*p) } - // At returns the i'th element of the vector. func (p *StringVector) At(i int) string { return (*p)[i] } - // Set sets the i'th element of the vector to value x. func (p *StringVector) Set(i int, x string) { (*p)[i] = x } - // Last returns the element in the vector of highest index. func (p *StringVector) Last() string { return (*p)[len(*p)-1] } - // Copy makes a copy of the vector and returns it. func (p *StringVector) Copy() StringVector { arr := make(StringVector, len(*p)) @@ -111,7 +101,6 @@ func (p *StringVector) Copy() StringVector { return arr } - // Insert inserts into the vector an element of value x before // the current element at index i. func (p *StringVector) Insert(i int, x string) { @@ -119,7 +108,6 @@ func (p *StringVector) Insert(i int, x string) { (*p)[i] = x } - // Delete deletes the i'th element of the vector. The gap is closed so the old // element at index i+1 has index i afterwards. func (p *StringVector) Delete(i int) { @@ -132,7 +120,6 @@ func (p *StringVector) Delete(i int) { *p = a[0 : n-1] } - // InsertVector inserts into the vector the contents of the vector // x such that the 0th element of x appears at index i after insertion. func (p *StringVector) InsertVector(i int, x *StringVector) { @@ -142,7 +129,6 @@ func (p *StringVector) InsertVector(i int, x *StringVector) { copy((*p)[i:i+len(b)], b) } - // Cut deletes elements i through j-1, inclusive. func (p *StringVector) Cut(i, j int) { a := *p @@ -158,7 +144,6 @@ func (p *StringVector) Cut(i, j int) { *p = a[0:m] } - // Slice returns a new sub-vector by slicing the old one to extract slice [i:j]. // The elements are copied. The original vector is unchanged. func (p *StringVector) Slice(i, j int) *StringVector { @@ -168,13 +153,11 @@ func (p *StringVector) Slice(i, j int) *StringVector { return &s } - // Convenience wrappers // Push appends x to the end of the vector. func (p *StringVector) Push(x string) { p.Insert(len(*p), x) } - // Pop deletes the last element of the vector. func (p *StringVector) Pop() string { a := *p @@ -187,18 +170,15 @@ func (p *StringVector) Pop() string { return x } - // AppendVector appends the entire vector x to the end of this vector. func (p *StringVector) AppendVector(x *StringVector) { p.InsertVector(len(*p), x) } - // Swap exchanges the elements at indexes i and j. func (p *StringVector) Swap(i, j int) { a := *p a[i], a[j] = a[j], a[i] } - // Do calls function f for each element of the vector, in order. // The behavior of Do is undefined if f changes *p. func (p *StringVector) Do(f func(elem string)) { diff --git a/libgo/go/container/vector/stringvector_test.go b/libgo/go/container/vector/stringvector_test.go index 776ae26..c75676f 100644 --- a/libgo/go/container/vector/stringvector_test.go +++ b/libgo/go/container/vector/stringvector_test.go @@ -9,7 +9,6 @@ package vector import "testing" - func TestStrZeroLen(t *testing.T) { a := new(StringVector) if a.Len() != 0 { @@ -27,7 +26,6 @@ func TestStrZeroLen(t *testing.T) { } } - func TestStrResize(t *testing.T) { var a StringVector checkSize(t, &a, 0, 0) @@ -40,7 +38,6 @@ func TestStrResize(t *testing.T) { checkSize(t, a.Resize(11, 100), 11, 100) } - func TestStrResize2(t *testing.T) { var a StringVector checkSize(t, &a, 0, 0) @@ -62,7 +59,6 @@ func TestStrResize2(t *testing.T) { } } - func checkStrZero(t *testing.T, a *StringVector, i int) { for j := 0; j < i; j++ { if a.At(j) == strzero { @@ -82,7 +78,6 @@ func checkStrZero(t *testing.T, a *StringVector, i int) { } } - func TestStrTrailingElements(t *testing.T) { var a StringVector for i := 0; i < 10; i++ { @@ -95,7 +90,6 @@ func TestStrTrailingElements(t *testing.T) { checkStrZero(t, &a, 5) } - func TestStrAccess(t *testing.T) { const n = 100 var a StringVector @@ -120,7 +114,6 @@ func TestStrAccess(t *testing.T) { } } - func TestStrInsertDeleteClear(t *testing.T) { const n = 100 var a StringVector @@ -207,7 +200,6 @@ func TestStrInsertDeleteClear(t *testing.T) { } } - func verify_sliceStr(t *testing.T, x *StringVector, elt, i, j int) { for k := i; k < j; k++ { if elem2StrValue(x.At(k)) != int2StrValue(elt) { @@ -223,7 +215,6 @@ func verify_sliceStr(t *testing.T, x *StringVector, elt, i, j int) { } } - func verify_patternStr(t *testing.T, x *StringVector, a, b, c int) { n := a + b + c if x.Len() != n { @@ -237,7 +228,6 @@ func verify_patternStr(t *testing.T, x *StringVector, a, b, c int) { verify_sliceStr(t, x, 0, a+b, n) } - func make_vectorStr(elt, len int) *StringVector { x := new(StringVector).Resize(len, 0) for i := 0; i < len; i++ { @@ -246,7 +236,6 @@ func make_vectorStr(elt, len int) *StringVector { return x } - func TestStrInsertVector(t *testing.T) { // 1 a := make_vectorStr(0, 0) @@ -270,7 +259,6 @@ func TestStrInsertVector(t *testing.T) { verify_patternStr(t, a, 8, 1000, 2) } - func TestStrDo(t *testing.T) { const n = 25 const salt = 17 @@ -325,7 +313,6 @@ func TestStrDo(t *testing.T) { } - func TestStrVectorCopy(t *testing.T) { // verify Copy() returns a copy, not simply a slice of the original vector const Len = 10 diff --git a/libgo/go/container/vector/vector.go b/libgo/go/container/vector/vector.go index f43e4d2..8470ec0 100644 --- a/libgo/go/container/vector/vector.go +++ b/libgo/go/container/vector/vector.go @@ -7,7 +7,6 @@ package vector - func (p *Vector) realloc(length, capacity int) (b []interface{}) { if capacity < initialSize { capacity = initialSize @@ -21,7 +20,6 @@ func (p *Vector) realloc(length, capacity int) (b []interface{}) { return } - // Insert n elements at position i. func (p *Vector) Expand(i, n int) { a := *p @@ -51,11 +49,9 @@ func (p *Vector) Expand(i, n int) { *p = a } - // Insert n elements at the end of a vector. func (p *Vector) Extend(n int) { p.Expand(len(*p), n) } - // Resize changes the length and capacity of a vector. // If the new length is shorter than the current length, Resize discards // trailing elements. If the new length is longer than the current length, @@ -80,30 +76,24 @@ func (p *Vector) Resize(length, capacity int) *Vector { return p } - // Len returns the number of elements in the vector. // Same as len(*p). func (p *Vector) Len() int { return len(*p) } - // Cap returns the capacity of the vector; that is, the // maximum length the vector can grow without resizing. // Same as cap(*p). func (p *Vector) Cap() int { return cap(*p) } - // At returns the i'th element of the vector. func (p *Vector) At(i int) interface{} { return (*p)[i] } - // Set sets the i'th element of the vector to value x. func (p *Vector) Set(i int, x interface{}) { (*p)[i] = x } - // Last returns the element in the vector of highest index. func (p *Vector) Last() interface{} { return (*p)[len(*p)-1] } - // Copy makes a copy of the vector and returns it. func (p *Vector) Copy() Vector { arr := make(Vector, len(*p)) @@ -111,7 +101,6 @@ func (p *Vector) Copy() Vector { return arr } - // Insert inserts into the vector an element of value x before // the current element at index i. func (p *Vector) Insert(i int, x interface{}) { @@ -119,7 +108,6 @@ func (p *Vector) Insert(i int, x interface{}) { (*p)[i] = x } - // Delete deletes the i'th element of the vector. The gap is closed so the old // element at index i+1 has index i afterwards. func (p *Vector) Delete(i int) { @@ -132,7 +120,6 @@ func (p *Vector) Delete(i int) { *p = a[0 : n-1] } - // InsertVector inserts into the vector the contents of the vector // x such that the 0th element of x appears at index i after insertion. func (p *Vector) InsertVector(i int, x *Vector) { @@ -142,7 +129,6 @@ func (p *Vector) InsertVector(i int, x *Vector) { copy((*p)[i:i+len(b)], b) } - // Cut deletes elements i through j-1, inclusive. func (p *Vector) Cut(i, j int) { a := *p @@ -158,7 +144,6 @@ func (p *Vector) Cut(i, j int) { *p = a[0:m] } - // Slice returns a new sub-vector by slicing the old one to extract slice [i:j]. // The elements are copied. The original vector is unchanged. func (p *Vector) Slice(i, j int) *Vector { @@ -168,13 +153,11 @@ func (p *Vector) Slice(i, j int) *Vector { return &s } - // Convenience wrappers // Push appends x to the end of the vector. func (p *Vector) Push(x interface{}) { p.Insert(len(*p), x) } - // Pop deletes the last element of the vector. func (p *Vector) Pop() interface{} { a := *p @@ -187,18 +170,15 @@ func (p *Vector) Pop() interface{} { return x } - // AppendVector appends the entire vector x to the end of this vector. func (p *Vector) AppendVector(x *Vector) { p.InsertVector(len(*p), x) } - // Swap exchanges the elements at indexes i and j. func (p *Vector) Swap(i, j int) { a := *p a[i], a[j] = a[j], a[i] } - // Do calls function f for each element of the vector, in order. // The behavior of Do is undefined if f changes *p. func (p *Vector) Do(f func(elem interface{})) { diff --git a/libgo/go/container/vector/vector_test.go b/libgo/go/container/vector/vector_test.go index a9c4ceb..a7f47b8 100644 --- a/libgo/go/container/vector/vector_test.go +++ b/libgo/go/container/vector/vector_test.go @@ -9,7 +9,6 @@ package vector import "testing" - func TestZeroLen(t *testing.T) { a := new(Vector) if a.Len() != 0 { @@ -27,7 +26,6 @@ func TestZeroLen(t *testing.T) { } } - func TestResize(t *testing.T) { var a Vector checkSize(t, &a, 0, 0) @@ -40,7 +38,6 @@ func TestResize(t *testing.T) { checkSize(t, a.Resize(11, 100), 11, 100) } - func TestResize2(t *testing.T) { var a Vector checkSize(t, &a, 0, 0) @@ -62,7 +59,6 @@ func TestResize2(t *testing.T) { } } - func checkZero(t *testing.T, a *Vector, i int) { for j := 0; j < i; j++ { if a.At(j) == zero { @@ -82,7 +78,6 @@ func checkZero(t *testing.T, a *Vector, i int) { } } - func TestTrailingElements(t *testing.T) { var a Vector for i := 0; i < 10; i++ { @@ -95,7 +90,6 @@ func TestTrailingElements(t *testing.T) { checkZero(t, &a, 5) } - func TestAccess(t *testing.T) { const n = 100 var a Vector @@ -120,7 +114,6 @@ func TestAccess(t *testing.T) { } } - func TestInsertDeleteClear(t *testing.T) { const n = 100 var a Vector @@ -207,7 +200,6 @@ func TestInsertDeleteClear(t *testing.T) { } } - func verify_slice(t *testing.T, x *Vector, elt, i, j int) { for k := i; k < j; k++ { if elem2Value(x.At(k)) != int2Value(elt) { @@ -223,7 +215,6 @@ func verify_slice(t *testing.T, x *Vector, elt, i, j int) { } } - func verify_pattern(t *testing.T, x *Vector, a, b, c int) { n := a + b + c if x.Len() != n { @@ -237,7 +228,6 @@ func verify_pattern(t *testing.T, x *Vector, a, b, c int) { verify_slice(t, x, 0, a+b, n) } - func make_vector(elt, len int) *Vector { x := new(Vector).Resize(len, 0) for i := 0; i < len; i++ { @@ -246,7 +236,6 @@ func make_vector(elt, len int) *Vector { return x } - func TestInsertVector(t *testing.T) { // 1 a := make_vector(0, 0) @@ -270,7 +259,6 @@ func TestInsertVector(t *testing.T) { verify_pattern(t, a, 8, 1000, 2) } - func TestDo(t *testing.T) { const n = 25 const salt = 17 @@ -325,7 +313,6 @@ func TestDo(t *testing.T) { } - func TestVectorCopy(t *testing.T) { // verify Copy() returns a copy, not simply a slice of the original vector const Len = 10 diff --git a/libgo/go/crypto/aes/cipher.go b/libgo/go/crypto/aes/cipher.go index 3a9d023..7322353 100644 --- a/libgo/go/crypto/aes/cipher.go +++ b/libgo/go/crypto/aes/cipher.go @@ -45,14 +45,14 @@ func NewCipher(key []byte) (*Cipher, os.Error) { // BlockSize returns the AES block size, 16 bytes. // It is necessary to satisfy the Cipher interface in the -// package "crypto/block". +// package "crypto/cipher". func (c *Cipher) BlockSize() int { return BlockSize } // Encrypt encrypts the 16-byte buffer src using the key k // and stores the result in dst. // Note that for amounts of data larger than a block, // it is not safe to just call Encrypt on successive blocks; -// instead, use an encryption mode like CBC (see crypto/block/cbc.go). +// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go). func (c *Cipher) Encrypt(dst, src []byte) { encryptBlock(c.enc, dst, src) } // Decrypt decrypts the 16-byte buffer src using the key k diff --git a/libgo/go/crypto/blowfish/cipher.go b/libgo/go/crypto/blowfish/cipher.go index f3c5175..6c37dfe 100644 --- a/libgo/go/crypto/blowfish/cipher.go +++ b/libgo/go/crypto/blowfish/cipher.go @@ -42,14 +42,14 @@ func NewCipher(key []byte) (*Cipher, os.Error) { // BlockSize returns the Blowfish block size, 8 bytes. // It is necessary to satisfy the Cipher interface in the -// package "crypto/block". +// package "crypto/cipher". func (c *Cipher) BlockSize() int { return BlockSize } // Encrypt encrypts the 8-byte buffer src using the key k // and stores the result in dst. // Note that for amounts of data larger than a block, // it is not safe to just call Encrypt on successive blocks; -// instead, use an encryption mode like CBC (see crypto/block/cbc.go). +// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go). func (c *Cipher) Encrypt(dst, src []byte) { l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3]) r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7]) diff --git a/libgo/go/crypto/cast5/cast5.go b/libgo/go/crypto/cast5/cast5.go index cb62e31..e9d4a24 100644 --- a/libgo/go/crypto/cast5/cast5.go +++ b/libgo/go/crypto/cast5/cast5.go @@ -20,7 +20,7 @@ type Cipher struct { func NewCipher(key []byte) (c *Cipher, err os.Error) { if len(key) != KeySize { - return nil, os.ErrorString("CAST5: keys must be 16 bytes") + return nil, os.NewError("CAST5: keys must be 16 bytes") } c = new(Cipher) diff --git a/libgo/go/crypto/cipher/ocfb.go b/libgo/go/crypto/cipher/ocfb.go index b2d8775..031e74a 100644 --- a/libgo/go/crypto/cipher/ocfb.go +++ b/libgo/go/crypto/cipher/ocfb.go @@ -80,9 +80,10 @@ type ocfbDecrypter struct { // NewOCFBDecrypter returns a Stream which decrypts data with OpenPGP's cipher // feedback mode using the given Block. Prefix must be the first blockSize + 2 // bytes of the ciphertext, where blockSize is the Block's block size. If an -// incorrect key is detected then nil is returned. Resync determines if the -// "resynchronization step" from RFC 4880, 13.9 step 7 is performed. Different -// parts of OpenPGP vary on this point. +// incorrect key is detected then nil is returned. On successful exit, +// blockSize+2 bytes of decrypted data are written into prefix. Resync +// determines if the "resynchronization step" from RFC 4880, 13.9 step 7 is +// performed. Different parts of OpenPGP vary on this point. func NewOCFBDecrypter(block Block, prefix []byte, resync OCFBResyncOption) Stream { blockSize := block.BlockSize() if len(prefix) != blockSize+2 { @@ -118,6 +119,7 @@ func NewOCFBDecrypter(block Block, prefix []byte, resync OCFBResyncOption) Strea x.fre[1] = prefix[blockSize+1] x.outUsed = 2 } + copy(prefix, prefixCopy) return x } diff --git a/libgo/go/crypto/dsa/dsa.go b/libgo/go/crypto/dsa/dsa.go index f0af8bb..a5f96fe 100644 --- a/libgo/go/crypto/dsa/dsa.go +++ b/libgo/go/crypto/dsa/dsa.go @@ -79,7 +79,7 @@ func GenerateParameters(params *Parameters, rand io.Reader, sizes ParameterSizes L = 3072 N = 256 default: - return os.ErrorString("crypto/dsa: invalid ParameterSizes") + return os.NewError("crypto/dsa: invalid ParameterSizes") } qBytes := make([]byte, N/8) @@ -158,7 +158,7 @@ GeneratePrimes: // PrivateKey must already be valid (see GenerateParameters). func GenerateKey(priv *PrivateKey, rand io.Reader) os.Error { if priv.P == nil || priv.Q == nil || priv.G == nil { - return os.ErrorString("crypto/dsa: parameters not set up before generating key") + return os.NewError("crypto/dsa: parameters not set up before generating key") } x := new(big.Int) diff --git a/libgo/go/crypto/elliptic/elliptic.go b/libgo/go/crypto/elliptic/elliptic.go index 335c964..41835f1 100644 --- a/libgo/go/crypto/elliptic/elliptic.go +++ b/libgo/go/crypto/elliptic/elliptic.go @@ -284,7 +284,7 @@ func (curve *Curve) Marshal(x, y *big.Int) []byte { return ret } -// Unmarshal converts a point, serialised by Marshal, into an x, y pair. On +// Unmarshal converts a point, serialized by Marshal, into an x, y pair. On // error, x = nil. func (curve *Curve) Unmarshal(data []byte) (x, y *big.Int) { byteLen := (curve.BitSize + 7) >> 3 diff --git a/libgo/go/crypto/elliptic/elliptic_test.go b/libgo/go/crypto/elliptic/elliptic_test.go index 02083a9..b7e7f03 100644 --- a/libgo/go/crypto/elliptic/elliptic_test.go +++ b/libgo/go/crypto/elliptic/elliptic_test.go @@ -321,8 +321,8 @@ func TestMarshal(t *testing.T) { t.Error(err) return } - serialised := p224.Marshal(x, y) - xx, yy := p224.Unmarshal(serialised) + serialized := p224.Marshal(x, y) + xx, yy := p224.Unmarshal(serialized) if xx == nil { t.Error("failed to unmarshal") return diff --git a/libgo/go/crypto/hmac/hmac_test.go b/libgo/go/crypto/hmac/hmac_test.go index 40adbad..bcae63b 100644 --- a/libgo/go/crypto/hmac/hmac_test.go +++ b/libgo/go/crypto/hmac/hmac_test.go @@ -190,7 +190,7 @@ func TestHMAC(t *testing.T) { continue } - // Repetive Sum() calls should return the same value + // Repetitive Sum() calls should return the same value for k := 0; k < 2; k++ { sum := fmt.Sprintf("%x", h.Sum()) if sum != tt.out { diff --git a/libgo/go/crypto/ocsp/ocsp.go b/libgo/go/crypto/ocsp/ocsp.go index acd75b8..7ea7a1e 100644 --- a/libgo/go/crypto/ocsp/ocsp.go +++ b/libgo/go/crypto/ocsp/ocsp.go @@ -13,6 +13,7 @@ import ( "crypto/rsa" _ "crypto/sha1" "crypto/x509" + "crypto/x509/pkix" "os" "time" ) @@ -32,21 +33,8 @@ const ( ocspUnauthorized = 5 ) -type rdnSequence []relativeDistinguishedNameSET - -type relativeDistinguishedNameSET []attributeTypeAndValue - -type attributeTypeAndValue struct { - Type asn1.ObjectIdentifier - Value interface{} -} - -type algorithmIdentifier struct { - Algorithm asn1.ObjectIdentifier -} - type certID struct { - HashAlgorithm algorithmIdentifier + HashAlgorithm pkix.AlgorithmIdentifier NameHash []byte IssuerKeyHash []byte SerialNumber asn1.RawValue @@ -54,7 +42,7 @@ type certID struct { type responseASN1 struct { Status asn1.Enumerated - Response responseBytes "explicit,tag:0" + Response responseBytes `asn1:"explicit,tag:0"` } type responseBytes struct { @@ -64,32 +52,32 @@ type responseBytes struct { type basicResponse struct { TBSResponseData responseData - SignatureAlgorithm algorithmIdentifier + SignatureAlgorithm pkix.AlgorithmIdentifier Signature asn1.BitString - Certificates []asn1.RawValue "explicit,tag:0,optional" + Certificates []asn1.RawValue `asn1:"explicit,tag:0,optional"` } type responseData struct { Raw asn1.RawContent - Version int "optional,default:1,explicit,tag:0" - RequestorName rdnSequence "optional,explicit,tag:1" - KeyHash []byte "optional,explicit,tag:2" + Version int `asn1:"optional,default:1,explicit,tag:0"` + RequestorName pkix.RDNSequence `asn1:"optional,explicit,tag:1"` + KeyHash []byte `asn1:"optional,explicit,tag:2"` ProducedAt *time.Time Responses []singleResponse } type singleResponse struct { CertID certID - Good asn1.Flag "explicit,tag:0,optional" - Revoked revokedInfo "explicit,tag:1,optional" - Unknown asn1.Flag "explicit,tag:2,optional" + Good asn1.Flag `asn1:"explicit,tag:0,optional"` + Revoked revokedInfo `asn1:"explicit,tag:1,optional"` + Unknown asn1.Flag `asn1:"explicit,tag:2,optional"` ThisUpdate *time.Time - NextUpdate *time.Time "explicit,tag:0,optional" + NextUpdate *time.Time `asn1:"explicit,tag:0,optional"` } type revokedInfo struct { RevocationTime *time.Time - Reason int "explicit,tag:0,optional" + Reason int `asn1:"explicit,tag:0,optional"` } // This is the exposed reflection of the internal OCSP structures. diff --git a/libgo/go/crypto/openpgp/armor/armor.go b/libgo/go/crypto/openpgp/armor/armor.go index 8da612c..9c4180d 100644 --- a/libgo/go/crypto/openpgp/armor/armor.go +++ b/libgo/go/crypto/openpgp/armor/armor.go @@ -153,7 +153,7 @@ func (r *openpgpReader) Read(p []byte) (n int, err os.Error) { // Decode reads a PGP armored block from the given Reader. It will ignore // leading garbage. If it doesn't find a block, it will return nil, os.EOF. The -// given Reader is not usable after calling this function: an arbitary amount +// given Reader is not usable after calling this function: an arbitrary amount // of data may have been read past the end of the block. func Decode(in io.Reader) (p *Block, err os.Error) { r, _ := bufio.NewReaderSize(in, 100) diff --git a/libgo/go/crypto/openpgp/canonical_text_test.go b/libgo/go/crypto/openpgp/canonical_text_test.go index 69ecf91..ccf2910 100644 --- a/libgo/go/crypto/openpgp/canonical_text_test.go +++ b/libgo/go/crypto/openpgp/canonical_text_test.go @@ -30,7 +30,6 @@ func (r recordingHash) Size() int { panic("shouldn't be called") } - func testCanonicalText(t *testing.T, input, expected string) { r := recordingHash{bytes.NewBuffer(nil)} c := NewCanonicalTextHash(r) diff --git a/libgo/go/crypto/openpgp/elgamal/elgamal.go b/libgo/go/crypto/openpgp/elgamal/elgamal.go new file mode 100644 index 0000000..99a6e3e --- /dev/null +++ b/libgo/go/crypto/openpgp/elgamal/elgamal.go @@ -0,0 +1,122 @@ +// 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 elgamal implements ElGamal encryption, suitable for OpenPGP, +// as specified in "A Public-Key Cryptosystem and a Signature Scheme Based on +// Discrete Logarithms," IEEE Transactions on Information Theory, v. IT-31, +// n. 4, 1985, pp. 469-472. +// +// This form of ElGamal embeds PKCS#1 v1.5 padding, which may make it +// unsuitable for other protocols. RSA should be used in preference in any +// case. +package elgamal + +import ( + "big" + "crypto/rand" + "crypto/subtle" + "io" + "os" +) + +// PublicKey represents an ElGamal public key. +type PublicKey struct { + G, P, Y *big.Int +} + +// PrivateKey represents an ElGamal private key. +type PrivateKey struct { + PublicKey + X *big.Int +} + +// Encrypt encrypts the given message to the given public key. The result is a +// pair of integers. Errors can result from reading random, or because msg is +// too large to be encrypted to the public key. +func Encrypt(random io.Reader, pub *PublicKey, msg []byte) (c1, c2 *big.Int, err os.Error) { + pLen := (pub.P.BitLen() + 7) / 8 + if len(msg) > pLen-11 { + err = os.NewError("elgamal: message too long") + return + } + + // EM = 0x02 || PS || 0x00 || M + em := make([]byte, pLen-1) + em[0] = 2 + ps, mm := em[1:len(em)-len(msg)-1], em[len(em)-len(msg):] + err = nonZeroRandomBytes(ps, random) + if err != nil { + return + } + em[len(em)-len(msg)-1] = 0 + copy(mm, msg) + + m := new(big.Int).SetBytes(em) + + k, err := rand.Int(random, pub.P) + if err != nil { + return + } + + c1 = new(big.Int).Exp(pub.G, k, pub.P) + s := new(big.Int).Exp(pub.Y, k, pub.P) + c2 = s.Mul(s, m) + c2.Mod(c2, pub.P) + + return +} + +// Decrypt takes two integers, resulting from an ElGamal encryption, and +// returns the plaintext of the message. An error can result only if the +// ciphertext is invalid. Users should keep in mind that this is a padding +// oracle and thus, if exposed to an adaptive chosen ciphertext attack, can +// be used to break the cryptosystem. See ``Chosen Ciphertext Attacks +// Against Protocols Based on the RSA Encryption Standard PKCS #1'', Daniel +// Bleichenbacher, Advances in Cryptology (Crypto '98), +func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err os.Error) { + s := new(big.Int).Exp(c1, priv.X, priv.P) + s.ModInverse(s, priv.P) + s.Mul(s, c2) + s.Mod(s, priv.P) + em := s.Bytes() + + firstByteIsTwo := subtle.ConstantTimeByteEq(em[0], 2) + + // The remainder of the plaintext must be a string of non-zero random + // octets, followed by a 0, followed by the message. + // lookingForIndex: 1 iff we are still looking for the zero. + // index: the offset of the first zero byte. + var lookingForIndex, index int + lookingForIndex = 1 + + for i := 1; i < len(em); i++ { + equals0 := subtle.ConstantTimeByteEq(em[i], 0) + index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index) + lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex) + } + + if firstByteIsTwo != 1 || lookingForIndex != 0 || index < 9 { + return nil, os.NewError("elgamal: decryption error") + } + return em[index+1:], nil +} + +// nonZeroRandomBytes fills the given slice with non-zero random octets. +func nonZeroRandomBytes(s []byte, rand io.Reader) (err os.Error) { + _, err = io.ReadFull(rand, s) + if err != nil { + return + } + + for i := 0; i < len(s); i++ { + for s[i] == 0 { + _, err = io.ReadFull(rand, s[i:i+1]) + if err != nil { + return + } + } + } + + return +} diff --git a/libgo/go/crypto/openpgp/elgamal/elgamal_test.go b/libgo/go/crypto/openpgp/elgamal/elgamal_test.go new file mode 100644 index 0000000..101121a --- /dev/null +++ b/libgo/go/crypto/openpgp/elgamal/elgamal_test.go @@ -0,0 +1,49 @@ +// 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 elgamal + +import ( + "big" + "bytes" + "crypto/rand" + "testing" +) + +// This is the 1024-bit MODP group from RFC 5114, section 2.1: +const primeHex = "B10B8F96A080E01DDE92DE5EAE5D54EC52C99FBCFB06A3C69A6A9DCA52D23B616073E28675A23D189838EF1E2EE652C013ECB4AEA906112324975C3CD49B83BFACCBDD7D90C4BD7098488E9C219A73724EFFD6FAE5644738FAA31A4FF55BCCC0A151AF5F0DC8B4BD45BF37DF365C1A65E68CFDA76D4DA708DF1FB2BC2E4A4371" + +const generatorHex = "A4D1CBD5C3FD34126765A442EFB99905F8104DD258AC507FD6406CFF14266D31266FEA1E5C41564B777E690F5504F213160217B4B01B886A5E91547F9E2749F4D7FBD7D3B9A92EE1909D0D2263F80A76A6A24C087A091F531DBF0A0169B6A28AD662A4D18E73AFA32D779D5918D08BC8858F4DCEF97C2A24855E6EEB22B3B2E5" + +func fromHex(hex string) *big.Int { + n, ok := new(big.Int).SetString(hex, 16) + if !ok { + panic("failed to parse hex number") + } + return n +} + +func TestEncryptDecrypt(t *testing.T) { + priv := &PrivateKey{ + PublicKey: PublicKey{ + G: fromHex(generatorHex), + P: fromHex(primeHex), + }, + X: fromHex("42"), + } + priv.Y = new(big.Int).Exp(priv.G, priv.X, priv.P) + + message := []byte("hello world") + c1, c2, err := Encrypt(rand.Reader, &priv.PublicKey, message) + if err != nil { + t.Errorf("error encrypting: %s", err) + } + message2, err := Decrypt(priv, c1, c2) + if err != nil { + t.Errorf("error decrypting: %s", err) + } + if !bytes.Equal(message2, message) { + t.Errorf("decryption failed, got: %x, want: %x", message2, message) + } +} diff --git a/libgo/go/crypto/openpgp/keys.go b/libgo/go/crypto/openpgp/keys.go index 6c03f88..c70fb79 100644 --- a/libgo/go/crypto/openpgp/keys.go +++ b/libgo/go/crypto/openpgp/keys.go @@ -5,11 +5,14 @@ package openpgp import ( + "crypto" "crypto/openpgp/armor" "crypto/openpgp/error" "crypto/openpgp/packet" + "crypto/rsa" "io" "os" + "time" ) // PublicKeyType is the armor type for a PGP public key. @@ -62,6 +65,78 @@ type KeyRing interface { DecryptionKeys() []Key } +// primaryIdentity returns the Identity marked as primary or the first identity +// if none are so marked. +func (e *Entity) primaryIdentity() *Identity { + var firstIdentity *Identity + for _, ident := range e.Identities { + if firstIdentity == nil { + firstIdentity = ident + } + if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId { + return ident + } + } + return firstIdentity +} + +// encryptionKey returns the best candidate Key for encrypting a message to the +// given Entity. +func (e *Entity) encryptionKey() Key { + candidateSubkey := -1 + + for i, subkey := range e.Subkeys { + if subkey.Sig.FlagsValid && subkey.Sig.FlagEncryptCommunications && subkey.PublicKey.PubKeyAlgo.CanEncrypt() { + candidateSubkey = i + break + } + } + + i := e.primaryIdentity() + + if e.PrimaryKey.PubKeyAlgo.CanEncrypt() { + // If we don't have any candidate subkeys for encryption and + // the primary key doesn't have any usage metadata then we + // assume that the primary key is ok. Or, if the primary key is + // marked as ok to encrypt to, then we can obviously use it. + if candidateSubkey == -1 && !i.SelfSignature.FlagsValid || i.SelfSignature.FlagEncryptCommunications && i.SelfSignature.FlagsValid { + return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature} + } + } + + if candidateSubkey != -1 { + subkey := e.Subkeys[candidateSubkey] + return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig} + } + + // This Entity appears to be signing only. + return Key{} +} + +// signingKey return the best candidate Key for signing a message with this +// Entity. +func (e *Entity) signingKey() Key { + candidateSubkey := -1 + + for i, subkey := range e.Subkeys { + if subkey.Sig.FlagsValid && subkey.Sig.FlagSign && subkey.PublicKey.PubKeyAlgo.CanSign() { + candidateSubkey = i + break + } + } + + i := e.primaryIdentity() + + // If we have no candidate subkey then we assume that it's ok to sign + // with the primary key. + if candidateSubkey == -1 || i.SelfSignature.FlagsValid && i.SelfSignature.FlagSign { + return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature} + } + + subkey := e.Subkeys[candidateSubkey] + return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig} +} + // An EntityList contains one or more Entities. type EntityList []*Entity @@ -197,6 +272,10 @@ func readEntity(packets *packet.Reader) (*Entity, os.Error) { } } + if !e.PrimaryKey.PubKeyAlgo.CanSign() { + return nil, error.StructuralError("primary key cannot be used for signatures") + } + var current *Identity EachPacket: for { @@ -227,7 +306,7 @@ EachPacket: return nil, error.StructuralError("user ID packet not followed by self-signature") } - if sig.SigType == packet.SigTypePositiveCert && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId { + if (sig.SigType == packet.SigTypePositiveCert || sig.SigType == packet.SigTypeGenericCert) && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId { if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, sig); err != nil { return nil, error.StructuralError("user ID self-signature invalid: " + err.String()) } @@ -297,3 +376,170 @@ func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *p e.Subkeys = append(e.Subkeys, subKey) return nil } + +const defaultRSAKeyBits = 2048 + +// NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a +// single identity composed of the given full name, comment and email, any of +// which may be empty but must not contain any of "()<>\x00". +func NewEntity(rand io.Reader, currentTimeSecs int64, name, comment, email string) (*Entity, os.Error) { + uid := packet.NewUserId(name, comment, email) + if uid == nil { + return nil, error.InvalidArgumentError("user id field contained invalid characters") + } + signingPriv, err := rsa.GenerateKey(rand, defaultRSAKeyBits) + if err != nil { + return nil, err + } + encryptingPriv, err := rsa.GenerateKey(rand, defaultRSAKeyBits) + if err != nil { + return nil, err + } + + t := uint32(currentTimeSecs) + + e := &Entity{ + PrimaryKey: packet.NewRSAPublicKey(t, &signingPriv.PublicKey, false /* not a subkey */ ), + PrivateKey: packet.NewRSAPrivateKey(t, signingPriv, false /* not a subkey */ ), + Identities: make(map[string]*Identity), + } + isPrimaryId := true + e.Identities[uid.Id] = &Identity{ + Name: uid.Name, + UserId: uid, + SelfSignature: &packet.Signature{ + CreationTime: t, + SigType: packet.SigTypePositiveCert, + PubKeyAlgo: packet.PubKeyAlgoRSA, + Hash: crypto.SHA256, + IsPrimaryId: &isPrimaryId, + FlagsValid: true, + FlagSign: true, + FlagCertify: true, + IssuerKeyId: &e.PrimaryKey.KeyId, + }, + } + + e.Subkeys = make([]Subkey, 1) + e.Subkeys[0] = Subkey{ + PublicKey: packet.NewRSAPublicKey(t, &encryptingPriv.PublicKey, true /* is a subkey */ ), + PrivateKey: packet.NewRSAPrivateKey(t, encryptingPriv, true /* is a subkey */ ), + Sig: &packet.Signature{ + CreationTime: t, + SigType: packet.SigTypeSubkeyBinding, + PubKeyAlgo: packet.PubKeyAlgoRSA, + Hash: crypto.SHA256, + FlagsValid: true, + FlagEncryptStorage: true, + FlagEncryptCommunications: true, + IssuerKeyId: &e.PrimaryKey.KeyId, + }, + } + + return e, nil +} + +// SerializePrivate serializes an Entity, including private key material, to +// the given Writer. For now, it must only be used on an Entity returned from +// NewEntity. +func (e *Entity) SerializePrivate(w io.Writer) (err os.Error) { + err = e.PrivateKey.Serialize(w) + if err != nil { + return + } + for _, ident := range e.Identities { + err = ident.UserId.Serialize(w) + if err != nil { + return + } + err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey) + if err != nil { + return + } + err = ident.SelfSignature.Serialize(w) + if err != nil { + return + } + } + for _, subkey := range e.Subkeys { + err = subkey.PrivateKey.Serialize(w) + if err != nil { + return + } + err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey) + if err != nil { + return + } + err = subkey.Sig.Serialize(w) + if err != nil { + return + } + } + return nil +} + +// Serialize writes the public part of the given Entity to w. (No private +// key material will be output). +func (e *Entity) Serialize(w io.Writer) os.Error { + err := e.PrimaryKey.Serialize(w) + if err != nil { + return err + } + for _, ident := range e.Identities { + err = ident.UserId.Serialize(w) + if err != nil { + return err + } + err = ident.SelfSignature.Serialize(w) + if err != nil { + return err + } + for _, sig := range ident.Signatures { + err = sig.Serialize(w) + if err != nil { + return err + } + } + } + for _, subkey := range e.Subkeys { + err = subkey.PublicKey.Serialize(w) + if err != nil { + return err + } + err = subkey.Sig.Serialize(w) + if err != nil { + return err + } + } + return nil +} + +// SignIdentity adds a signature to e, from signer, attesting that identity is +// associated with e. The provided identity must already be an element of +// e.Identities and the private key of signer must have been decrypted if +// necessary. +func (e *Entity) SignIdentity(identity string, signer *Entity) os.Error { + if signer.PrivateKey == nil { + return error.InvalidArgumentError("signing Entity must have a private key") + } + if signer.PrivateKey.Encrypted { + return error.InvalidArgumentError("signing Entity's private key must be decrypted") + } + ident, ok := e.Identities[identity] + if !ok { + return error.InvalidArgumentError("given identity string not found in Entity") + } + + sig := &packet.Signature{ + SigType: packet.SigTypeGenericCert, + PubKeyAlgo: signer.PrivateKey.PubKeyAlgo, + Hash: crypto.SHA256, + CreationTime: uint32(time.Seconds()), + IssuerKeyId: &signer.PrivateKey.KeyId, + } + if err := sig.SignKey(e.PrimaryKey, signer.PrivateKey); err != nil { + return err + } + ident.Signatures = append(ident.Signatures, sig) + return nil +} diff --git a/libgo/go/crypto/openpgp/packet/encrypted_key.go b/libgo/go/crypto/openpgp/packet/encrypted_key.go index b11a9b8..b4730cb 100644 --- a/libgo/go/crypto/openpgp/packet/encrypted_key.go +++ b/libgo/go/crypto/openpgp/packet/encrypted_key.go @@ -5,6 +5,8 @@ package packet import ( + "big" + "crypto/openpgp/elgamal" "crypto/openpgp/error" "crypto/rand" "crypto/rsa" @@ -14,14 +16,17 @@ import ( "strconv" ) +const encryptedKeyVersion = 3 + // EncryptedKey represents a public-key encrypted session key. See RFC 4880, // section 5.1. type EncryptedKey struct { KeyId uint64 Algo PublicKeyAlgorithm - Encrypted []byte CipherFunc CipherFunction // only valid after a successful Decrypt Key []byte // only valid after a successful Decrypt + + encryptedMPI1, encryptedMPI2 []byte } func (e *EncryptedKey) parse(r io.Reader) (err os.Error) { @@ -30,37 +35,134 @@ func (e *EncryptedKey) parse(r io.Reader) (err os.Error) { if err != nil { return } - if buf[0] != 3 { + if buf[0] != encryptedKeyVersion { return error.UnsupportedError("unknown EncryptedKey version " + strconv.Itoa(int(buf[0]))) } e.KeyId = binary.BigEndian.Uint64(buf[1:9]) e.Algo = PublicKeyAlgorithm(buf[9]) - if e.Algo == PubKeyAlgoRSA || e.Algo == PubKeyAlgoRSAEncryptOnly { - e.Encrypted, _, err = readMPI(r) + switch e.Algo { + case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: + e.encryptedMPI1, _, err = readMPI(r) + case PubKeyAlgoElGamal: + e.encryptedMPI1, _, err = readMPI(r) + if err != nil { + return + } + e.encryptedMPI2, _, err = readMPI(r) } _, err = consumeAll(r) return } -// DecryptRSA decrypts an RSA encrypted session key with the given private key. -func (e *EncryptedKey) DecryptRSA(priv *rsa.PrivateKey) (err os.Error) { - if e.Algo != PubKeyAlgoRSA && e.Algo != PubKeyAlgoRSAEncryptOnly { - return error.InvalidArgumentError("EncryptedKey not RSA encrypted") +func checksumKeyMaterial(key []byte) uint16 { + var checksum uint16 + for _, v := range key { + checksum += uint16(v) } - b, err := rsa.DecryptPKCS1v15(rand.Reader, priv, e.Encrypted) + return checksum +} + +// Decrypt decrypts an encrypted session key with the given private key. The +// private key must have been decrypted first. +func (e *EncryptedKey) Decrypt(priv *PrivateKey) os.Error { + var err os.Error + var b []byte + + // TODO(agl): use session key decryption routines here to avoid + // padding oracle attacks. + switch priv.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: + b, err = rsa.DecryptPKCS1v15(rand.Reader, priv.PrivateKey.(*rsa.PrivateKey), e.encryptedMPI1) + case PubKeyAlgoElGamal: + c1 := new(big.Int).SetBytes(e.encryptedMPI1) + c2 := new(big.Int).SetBytes(e.encryptedMPI2) + b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2) + default: + err = error.InvalidArgumentError("cannot decrypted encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo))) + } + if err != nil { - return + return err } + e.CipherFunc = CipherFunction(b[0]) e.Key = b[1 : len(b)-2] expectedChecksum := uint16(b[len(b)-2])<<8 | uint16(b[len(b)-1]) - var checksum uint16 - for _, v := range e.Key { - checksum += uint16(v) - } + checksum := checksumKeyMaterial(e.Key) if checksum != expectedChecksum { return error.StructuralError("EncryptedKey checksum incorrect") } - return + return nil +} + +// SerializeEncryptedKey serializes an encrypted key packet to w that contains +// key, encrypted to pub. +func SerializeEncryptedKey(w io.Writer, rand io.Reader, pub *PublicKey, cipherFunc CipherFunction, key []byte) os.Error { + var buf [10]byte + buf[0] = encryptedKeyVersion + binary.BigEndian.PutUint64(buf[1:9], pub.KeyId) + buf[9] = byte(pub.PubKeyAlgo) + + keyBlock := make([]byte, 1 /* cipher type */ +len(key)+2 /* checksum */ ) + keyBlock[0] = byte(cipherFunc) + copy(keyBlock[1:], key) + checksum := checksumKeyMaterial(key) + keyBlock[1+len(key)] = byte(checksum >> 8) + keyBlock[1+len(key)+1] = byte(checksum) + + switch pub.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: + return serializeEncryptedKeyRSA(w, rand, buf, pub.PublicKey.(*rsa.PublicKey), keyBlock) + case PubKeyAlgoElGamal: + return serializeEncryptedKeyElGamal(w, rand, buf, pub.PublicKey.(*elgamal.PublicKey), keyBlock) + case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly: + return error.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo))) + } + + return error.UnsupportedError("encrypting a key to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo))) +} + +func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header [10]byte, pub *rsa.PublicKey, keyBlock []byte) os.Error { + cipherText, err := rsa.EncryptPKCS1v15(rand, pub, keyBlock) + if err != nil { + return error.InvalidArgumentError("RSA encryption failed: " + err.String()) + } + + packetLen := 10 /* header length */ + 2 /* mpi size */ + len(cipherText) + + err = serializeHeader(w, packetTypeEncryptedKey, packetLen) + if err != nil { + return err + } + _, err = w.Write(header[:]) + if err != nil { + return err + } + return writeMPI(w, 8*uint16(len(cipherText)), cipherText) +} + +func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header [10]byte, pub *elgamal.PublicKey, keyBlock []byte) os.Error { + c1, c2, err := elgamal.Encrypt(rand, pub, keyBlock) + if err != nil { + return error.InvalidArgumentError("ElGamal encryption failed: " + err.String()) + } + + packetLen := 10 /* header length */ + packetLen += 2 /* mpi size */ + (c1.BitLen()+7)/8 + packetLen += 2 /* mpi size */ + (c2.BitLen()+7)/8 + + err = serializeHeader(w, packetTypeEncryptedKey, packetLen) + if err != nil { + return err + } + _, err = w.Write(header[:]) + if err != nil { + return err + } + err = writeBig(w, c1) + if err != nil { + return err + } + return writeBig(w, c2) } diff --git a/libgo/go/crypto/openpgp/packet/encrypted_key_test.go b/libgo/go/crypto/openpgp/packet/encrypted_key_test.go index 755ae7a..b402245 100644 --- a/libgo/go/crypto/openpgp/packet/encrypted_key_test.go +++ b/libgo/go/crypto/openpgp/packet/encrypted_key_test.go @@ -6,6 +6,8 @@ package packet import ( "big" + "bytes" + "crypto/rand" "crypto/rsa" "fmt" "testing" @@ -19,7 +21,27 @@ func bigFromBase10(s string) *big.Int { return b } -func TestEncryptedKey(t *testing.T) { +var encryptedKeyPub = rsa.PublicKey{ + E: 65537, + N: bigFromBase10("115804063926007623305902631768113868327816898845124614648849934718568541074358183759250136204762053879858102352159854352727097033322663029387610959884180306668628526686121021235757016368038585212410610742029286439607686208110250133174279811431933746643015923132833417396844716207301518956640020862630546868823"), +} + +var encryptedKeyRSAPriv = &rsa.PrivateKey{ + PublicKey: encryptedKeyPub, + D: bigFromBase10("32355588668219869544751561565313228297765464314098552250409557267371233892496951383426602439009993875125222579159850054973310859166139474359774543943714622292329487391199285040721944491839695981199720170366763547754915493640685849961780092241140181198779299712578774460837139360803883139311171713302987058393"), +} + +var encryptedKeyPriv = &PrivateKey{ + PublicKey: PublicKey{ + PubKeyAlgo: PubKeyAlgoRSA, + }, + PrivateKey: encryptedKeyRSAPriv, +} + +func TestDecryptingEncryptedKey(t *testing.T) { + const encryptedKeyHex = "c18c032a67d68660df41c70104005789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8" + const expectedKeyHex = "d930363f7e0308c333b9618617ea728963d8df993665ae7be1092d4926fd864b" + p, err := Read(readerFromHex(encryptedKeyHex)) if err != nil { t.Errorf("error from Read: %s", err) @@ -36,23 +58,63 @@ func TestEncryptedKey(t *testing.T) { return } - pub := rsa.PublicKey{ - E: 65537, - N: bigFromBase10("115804063926007623305902631768113868327816898845124614648849934718568541074358183759250136204762053879858102352159854352727097033322663029387610959884180306668628526686121021235757016368038585212410610742029286439607686208110250133174279811431933746643015923132833417396844716207301518956640020862630546868823"), + err = ek.Decrypt(encryptedKeyPriv) + if err != nil { + t.Errorf("error from Decrypt: %s", err) + return + } + + if ek.CipherFunc != CipherAES256 { + t.Errorf("unexpected EncryptedKey contents: %#v", ek) + return + } + + keyHex := fmt.Sprintf("%x", ek.Key) + if keyHex != expectedKeyHex { + t.Errorf("bad key, got %s want %x", keyHex, expectedKeyHex) + } +} + +func TestEncryptingEncryptedKey(t *testing.T) { + key := []byte{1, 2, 3, 4} + const expectedKeyHex = "01020304" + const keyId = 42 + + pub := &PublicKey{ + PublicKey: &encryptedKeyPub, + KeyId: keyId, + PubKeyAlgo: PubKeyAlgoRSAEncryptOnly, + } + + buf := new(bytes.Buffer) + err := SerializeEncryptedKey(buf, rand.Reader, pub, CipherAES128, key) + if err != nil { + t.Errorf("error writing encrypted key packet: %s", err) + } + + p, err := Read(buf) + if err != nil { + t.Errorf("error from Read: %s", err) + return + } + ek, ok := p.(*EncryptedKey) + if !ok { + t.Errorf("didn't parse an EncryptedKey, got %#v", p) + return } - priv := &rsa.PrivateKey{ - PublicKey: pub, - D: bigFromBase10("32355588668219869544751561565313228297765464314098552250409557267371233892496951383426602439009993875125222579159850054973310859166139474359774543943714622292329487391199285040721944491839695981199720170366763547754915493640685849961780092241140181198779299712578774460837139360803883139311171713302987058393"), + if ek.KeyId != keyId || ek.Algo != PubKeyAlgoRSAEncryptOnly { + t.Errorf("unexpected EncryptedKey contents: %#v", ek) + return } - err = ek.DecryptRSA(priv) + err = ek.Decrypt(encryptedKeyPriv) if err != nil { - t.Errorf("error from DecryptRSA: %s", err) + t.Errorf("error from Decrypt: %s", err) return } - if ek.CipherFunc != CipherAES256 { + if ek.CipherFunc != CipherAES128 { t.Errorf("unexpected EncryptedKey contents: %#v", ek) return } @@ -62,6 +124,3 @@ func TestEncryptedKey(t *testing.T) { t.Errorf("bad key, got %s want %x", keyHex, expectedKeyHex) } } - -const encryptedKeyHex = "c18c032a67d68660df41c70104005789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8" -const expectedKeyHex = "d930363f7e0308c333b9618617ea728963d8df993665ae7be1092d4926fd864b" diff --git a/libgo/go/crypto/openpgp/packet/literal.go b/libgo/go/crypto/openpgp/packet/literal.go index 04f50e5..9411572 100644 --- a/libgo/go/crypto/openpgp/packet/literal.go +++ b/libgo/go/crypto/openpgp/packet/literal.go @@ -51,3 +51,40 @@ func (l *LiteralData) parse(r io.Reader) (err os.Error) { l.Body = r return } + +// SerializeLiteral serializes a literal data packet to w and returns a +// WriteCloser to which the data itself can be written and which MUST be closed +// on completion. The fileName is truncated to 255 bytes. +func SerializeLiteral(w io.WriteCloser, isBinary bool, fileName string, time uint32) (plaintext io.WriteCloser, err os.Error) { + var buf [4]byte + buf[0] = 't' + if isBinary { + buf[0] = 'b' + } + if len(fileName) > 255 { + fileName = fileName[:255] + } + buf[1] = byte(len(fileName)) + + inner, err := serializeStreamHeader(w, packetTypeLiteralData) + if err != nil { + return + } + + _, err = inner.Write(buf[:2]) + if err != nil { + return + } + _, err = inner.Write([]byte(fileName)) + if err != nil { + return + } + binary.BigEndian.PutUint32(buf[:], time) + _, err = inner.Write(buf[:]) + if err != nil { + return + } + + plaintext = inner + return +} diff --git a/libgo/go/crypto/openpgp/packet/one_pass_signature.go b/libgo/go/crypto/openpgp/packet/one_pass_signature.go index acbf58b..ca826e4 100644 --- a/libgo/go/crypto/openpgp/packet/one_pass_signature.go +++ b/libgo/go/crypto/openpgp/packet/one_pass_signature.go @@ -24,6 +24,8 @@ type OnePassSignature struct { IsLast bool } +const onePassSignatureVersion = 3 + func (ops *OnePassSignature) parse(r io.Reader) (err os.Error) { var buf [13]byte @@ -31,7 +33,7 @@ func (ops *OnePassSignature) parse(r io.Reader) (err os.Error) { if err != nil { return } - if buf[0] != 3 { + if buf[0] != onePassSignatureVersion { err = error.UnsupportedError("one-pass-signature packet version " + strconv.Itoa(int(buf[0]))) } @@ -47,3 +49,26 @@ func (ops *OnePassSignature) parse(r io.Reader) (err os.Error) { ops.IsLast = buf[12] != 0 return } + +// Serialize marshals the given OnePassSignature to w. +func (ops *OnePassSignature) Serialize(w io.Writer) os.Error { + var buf [13]byte + buf[0] = onePassSignatureVersion + buf[1] = uint8(ops.SigType) + var ok bool + buf[2], ok = s2k.HashToHashId(ops.Hash) + if !ok { + return error.UnsupportedError("hash type: " + strconv.Itoa(int(ops.Hash))) + } + buf[3] = uint8(ops.PubKeyAlgo) + binary.BigEndian.PutUint64(buf[4:12], ops.KeyId) + if ops.IsLast { + buf[12] = 1 + } + + if err := serializeHeader(w, packetTypeOnePassSignature, len(buf)); err != nil { + return err + } + _, err := w.Write(buf[:]) + return err +} diff --git a/libgo/go/crypto/openpgp/packet/packet.go b/libgo/go/crypto/openpgp/packet/packet.go index c0ec44d..1d7297e 100644 --- a/libgo/go/crypto/openpgp/packet/packet.go +++ b/libgo/go/crypto/openpgp/packet/packet.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package packet implements parsing and serialisation of OpenPGP packets, as +// Package packet implements parsing and serialization of OpenPGP packets, as // specified in RFC 4880. package packet @@ -92,6 +92,46 @@ func (r *partialLengthReader) Read(p []byte) (n int, err os.Error) { return } +// partialLengthWriter writes a stream of data using OpenPGP partial lengths. +// See RFC 4880, section 4.2.2.4. +type partialLengthWriter struct { + w io.WriteCloser + lengthByte [1]byte +} + +func (w *partialLengthWriter) Write(p []byte) (n int, err os.Error) { + for len(p) > 0 { + for power := uint(14); power < 32; power-- { + l := 1 << power + if len(p) >= l { + w.lengthByte[0] = 224 + uint8(power) + _, err = w.w.Write(w.lengthByte[:]) + if err != nil { + return + } + var m int + m, err = w.w.Write(p[:l]) + n += m + if err != nil { + return + } + p = p[l:] + break + } + } + } + return +} + +func (w *partialLengthWriter) Close() os.Error { + w.lengthByte[0] = 0 + _, err := w.w.Write(w.lengthByte[:]) + if err != nil { + return err + } + return w.w.Close() +} + // A spanReader is an io.LimitReader, but it returns ErrUnexpectedEOF if the // underlying Reader returns EOF before the limit has been reached. type spanReader struct { @@ -195,6 +235,20 @@ func serializeHeader(w io.Writer, ptype packetType, length int) (err os.Error) { return } +// serializeStreamHeader writes an OpenPGP packet header to w where the +// length of the packet is unknown. It returns a io.WriteCloser which can be +// used to write the contents of the packet. See RFC 4880, section 4.2. +func serializeStreamHeader(w io.WriteCloser, ptype packetType) (out io.WriteCloser, err os.Error) { + var buf [1]byte + buf[0] = 0x80 | 0x40 | byte(ptype) + _, err = w.Write(buf[:]) + if err != nil { + return + } + out = &partialLengthWriter{w: w} + return +} + // Packet represents an OpenPGP packet. Users are expected to try casting // instances of this interface to specific packet types. type Packet interface { @@ -301,12 +355,12 @@ type SignatureType uint8 const ( SigTypeBinary SignatureType = 0 - SigTypeText = 1 - SigTypeGenericCert = 0x10 - SigTypePersonaCert = 0x11 - SigTypeCasualCert = 0x12 - SigTypePositiveCert = 0x13 - SigTypeSubkeyBinding = 0x18 + SigTypeText = 1 + SigTypeGenericCert = 0x10 + SigTypePersonaCert = 0x11 + SigTypeCasualCert = 0x12 + SigTypePositiveCert = 0x13 + SigTypeSubkeyBinding = 0x18 ) // PublicKeyAlgorithm represents the different public key system specified for @@ -318,23 +372,43 @@ const ( PubKeyAlgoRSA PublicKeyAlgorithm = 1 PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2 PubKeyAlgoRSASignOnly PublicKeyAlgorithm = 3 - PubKeyAlgoElgamal PublicKeyAlgorithm = 16 + PubKeyAlgoElGamal PublicKeyAlgorithm = 16 PubKeyAlgoDSA PublicKeyAlgorithm = 17 ) +// CanEncrypt returns true if it's possible to encrypt a message to a public +// key of the given type. +func (pka PublicKeyAlgorithm) CanEncrypt() bool { + switch pka { + case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal: + return true + } + return false +} + +// CanSign returns true if it's possible for a public key of the given type to +// sign a message. +func (pka PublicKeyAlgorithm) CanSign() bool { + switch pka { + case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA: + return true + } + return false +} + // CipherFunction represents the different block ciphers specified for OpenPGP. See // http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-13 type CipherFunction uint8 const ( - CipherCAST5 = 3 - CipherAES128 = 7 - CipherAES192 = 8 - CipherAES256 = 9 + CipherCAST5 CipherFunction = 3 + CipherAES128 CipherFunction = 7 + CipherAES192 CipherFunction = 8 + CipherAES256 CipherFunction = 9 ) -// keySize returns the key size, in bytes, of cipher. -func (cipher CipherFunction) keySize() int { +// KeySize returns the key size, in bytes, of cipher. +func (cipher CipherFunction) KeySize() int { switch cipher { case CipherCAST5: return cast5.KeySize @@ -386,6 +460,14 @@ func readMPI(r io.Reader) (mpi []byte, bitLength uint16, err os.Error) { return } +// mpiLength returns the length of the given *big.Int when serialized as an +// MPI. +func mpiLength(n *big.Int) (mpiLengthInBytes int) { + mpiLengthInBytes = 2 /* MPI length */ + mpiLengthInBytes += (n.BitLen() + 7) / 8 + return +} + // 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)}) diff --git a/libgo/go/crypto/openpgp/packet/packet_test.go b/libgo/go/crypto/openpgp/packet/packet_test.go index 1a4692c..23d9978 100644 --- a/libgo/go/crypto/openpgp/packet/packet_test.go +++ b/libgo/go/crypto/openpgp/packet/packet_test.go @@ -210,3 +210,47 @@ func TestSerializeHeader(t *testing.T) { } } } + +func TestPartialLengths(t *testing.T) { + buf := bytes.NewBuffer(nil) + w := new(partialLengthWriter) + w.w = noOpCloser{buf} + + const maxChunkSize = 64 + + var b [maxChunkSize]byte + var n uint8 + for l := 1; l <= maxChunkSize; l++ { + for i := 0; i < l; i++ { + b[i] = n + n++ + } + m, err := w.Write(b[:l]) + if m != l { + t.Errorf("short write got: %d want: %d", m, l) + } + if err != nil { + t.Errorf("error from write: %s", err) + } + } + w.Close() + + want := (maxChunkSize * (maxChunkSize + 1)) / 2 + copyBuf := bytes.NewBuffer(nil) + r := &partialLengthReader{buf, 0, true} + m, err := io.Copy(copyBuf, r) + if m != int64(want) { + t.Errorf("short copy got: %d want: %d", m, want) + } + if err != nil { + t.Errorf("error from copy: %s", err) + } + + copyBytes := copyBuf.Bytes() + for i := 0; i < want; i++ { + if copyBytes[i] != uint8(i) { + t.Errorf("bad pattern in copy at %d", i) + break + } + } +} diff --git a/libgo/go/crypto/openpgp/packet/private_key.go b/libgo/go/crypto/openpgp/packet/private_key.go index fde2a99..6f8133d 100644 --- a/libgo/go/crypto/openpgp/packet/private_key.go +++ b/libgo/go/crypto/openpgp/packet/private_key.go @@ -9,6 +9,7 @@ import ( "bytes" "crypto/cipher" "crypto/dsa" + "crypto/openpgp/elgamal" "crypto/openpgp/error" "crypto/openpgp/s2k" "crypto/rsa" @@ -32,6 +33,13 @@ type PrivateKey struct { iv []byte } +func NewRSAPrivateKey(currentTimeSecs uint32, priv *rsa.PrivateKey, isSubkey bool) *PrivateKey { + pk := new(PrivateKey) + pk.PublicKey = *NewRSAPublicKey(currentTimeSecs, &priv.PublicKey, isSubkey) + pk.PrivateKey = priv + return pk +} + func (pk *PrivateKey) parse(r io.Reader) (err os.Error) { err = (&pk.PublicKey).parse(r) if err != nil { @@ -91,13 +99,90 @@ func (pk *PrivateKey) parse(r io.Reader) (err os.Error) { return } +func mod64kHash(d []byte) uint16 { + h := uint16(0) + for i := 0; i < len(d); i += 2 { + v := uint16(d[i]) << 8 + if i+1 < len(d) { + v += uint16(d[i+1]) + } + h += v + } + return h +} + +func (pk *PrivateKey) Serialize(w io.Writer) (err os.Error) { + // TODO(agl): support encrypted private keys + buf := bytes.NewBuffer(nil) + err = pk.PublicKey.serializeWithoutHeaders(buf) + if err != nil { + return + } + buf.WriteByte(0 /* no encryption */ ) + + privateKeyBuf := bytes.NewBuffer(nil) + + switch priv := pk.PrivateKey.(type) { + case *rsa.PrivateKey: + err = serializeRSAPrivateKey(privateKeyBuf, priv) + default: + err = error.InvalidArgumentError("non-RSA private key") + } + if err != nil { + return + } + + ptype := packetTypePrivateKey + contents := buf.Bytes() + privateKeyBytes := privateKeyBuf.Bytes() + if pk.IsSubkey { + ptype = packetTypePrivateSubkey + } + err = serializeHeader(w, ptype, len(contents)+len(privateKeyBytes)+2) + if err != nil { + return + } + _, err = w.Write(contents) + if err != nil { + return + } + _, err = w.Write(privateKeyBytes) + if err != nil { + return + } + + checksum := mod64kHash(privateKeyBytes) + var checksumBytes [2]byte + checksumBytes[0] = byte(checksum >> 8) + checksumBytes[1] = byte(checksum) + _, err = w.Write(checksumBytes[:]) + + return +} + +func serializeRSAPrivateKey(w io.Writer, priv *rsa.PrivateKey) os.Error { + err := writeBig(w, priv.D) + if err != nil { + return err + } + err = writeBig(w, priv.Primes[1]) + if err != nil { + return err + } + err = writeBig(w, priv.Primes[0]) + if err != nil { + return err + } + return writeBig(w, priv.Precomputed.Qinv) +} + // Decrypt decrypts an encrypted private key using a passphrase. func (pk *PrivateKey) Decrypt(passphrase []byte) os.Error { if !pk.Encrypted { return nil } - key := make([]byte, pk.cipher.keySize()) + key := make([]byte, pk.cipher.KeySize()) pk.s2k(key, passphrase) block := pk.cipher.new(key) cfb := cipher.NewCFBDecrypter(block, pk.iv) @@ -140,6 +225,8 @@ func (pk *PrivateKey) parsePrivateKey(data []byte) (err os.Error) { return pk.parseRSAPrivateKey(data) case PubKeyAlgoDSA: return pk.parseDSAPrivateKey(data) + case PubKeyAlgoElGamal: + return pk.parseElGamalPrivateKey(data) } panic("impossible") } @@ -193,3 +280,22 @@ func (pk *PrivateKey) parseDSAPrivateKey(data []byte) (err os.Error) { return nil } + +func (pk *PrivateKey) parseElGamalPrivateKey(data []byte) (err os.Error) { + pub := pk.PublicKey.PublicKey.(*elgamal.PublicKey) + priv := new(elgamal.PrivateKey) + priv.PublicKey = *pub + + buf := bytes.NewBuffer(data) + x, _, err := readMPI(buf) + if err != nil { + return + } + + priv.X = new(big.Int).SetBytes(x) + pk.PrivateKey = priv + pk.Encrypted = false + pk.encryptedData = nil + + return nil +} diff --git a/libgo/go/crypto/openpgp/packet/private_key_test.go b/libgo/go/crypto/openpgp/packet/private_key_test.go index e941cc7..60eebaa 100644 --- a/libgo/go/crypto/openpgp/packet/private_key_test.go +++ b/libgo/go/crypto/openpgp/packet/private_key_test.go @@ -8,30 +8,50 @@ import ( "testing" ) -func TestPrivateKeyRead(t *testing.T) { - packet, err := Read(readerFromHex(privKeyHex)) - if err != nil { - t.Error(err) - return - } - - privKey := packet.(*PrivateKey) - - if !privKey.Encrypted { - t.Error("private key isn't encrypted") - return - } - - err = privKey.Decrypt([]byte("testing")) - if err != nil { - t.Error(err) - return - } +var privateKeyTests = []struct { + privateKeyHex string + creationTime uint32 +}{ + { + privKeyRSAHex, + 0x4cc349a8, + }, + { + privKeyElGamalHex, + 0x4df9ee1a, + }, +} - if privKey.CreationTime != 0x4cc349a8 || privKey.Encrypted { - t.Errorf("failed to parse, got: %#v", privKey) +func TestPrivateKeyRead(t *testing.T) { + for i, test := range privateKeyTests { + packet, err := Read(readerFromHex(test.privateKeyHex)) + if err != nil { + t.Errorf("#%d: failed to parse: %s", i, err) + continue + } + + privKey := packet.(*PrivateKey) + + if !privKey.Encrypted { + t.Errorf("#%d: private key isn't encrypted", i) + continue + } + + err = privKey.Decrypt([]byte("testing")) + if err != nil { + t.Errorf("#%d: failed to decrypt: %s", i, err) + continue + } + + if privKey.CreationTime != test.creationTime || privKey.Encrypted { + t.Errorf("#%d: bad result, got: %#v", i, privKey) + } } } // Generated with `gpg --export-secret-keys "Test Key 2"` -const privKeyHex = "9501fe044cc349a8010400b70ca0010e98c090008d45d1ee8f9113bd5861fd57b88bacb7c68658747663f1e1a3b5a98f32fda6472373c024b97359cd2efc88ff60f77751adfbf6af5e615e6a1408cfad8bf0cea30b0d5f53aa27ad59089ba9b15b7ebc2777a25d7b436144027e3bcd203909f147d0e332b240cf63d3395f5dfe0df0a6c04e8655af7eacdf0011010001fe0303024a252e7d475fd445607de39a265472aa74a9320ba2dac395faa687e9e0336aeb7e9a7397e511b5afd9dc84557c80ac0f3d4d7bfec5ae16f20d41c8c84a04552a33870b930420e230e179564f6d19bb153145e76c33ae993886c388832b0fa042ddda7f133924f3854481533e0ede31d51278c0519b29abc3bf53da673e13e3e1214b52413d179d7f66deee35cac8eacb060f78379d70ef4af8607e68131ff529439668fc39c9ce6dfef8a5ac234d234802cbfb749a26107db26406213ae5c06d4673253a3cbee1fcbae58d6ab77e38d6e2c0e7c6317c48e054edadb5a40d0d48acb44643d998139a8a66bb820be1f3f80185bc777d14b5954b60effe2448a036d565c6bc0b915fcea518acdd20ab07bc1529f561c58cd044f723109b93f6fd99f876ff891d64306b5d08f48bab59f38695e9109c4dec34013ba3153488ce070268381ba923ee1eb77125b36afcb4347ec3478c8f2735b06ef17351d872e577fa95d0c397c88c71b59629a36aec" +const privKeyRSAHex = "9501fe044cc349a8010400b70ca0010e98c090008d45d1ee8f9113bd5861fd57b88bacb7c68658747663f1e1a3b5a98f32fda6472373c024b97359cd2efc88ff60f77751adfbf6af5e615e6a1408cfad8bf0cea30b0d5f53aa27ad59089ba9b15b7ebc2777a25d7b436144027e3bcd203909f147d0e332b240cf63d3395f5dfe0df0a6c04e8655af7eacdf0011010001fe0303024a252e7d475fd445607de39a265472aa74a9320ba2dac395faa687e9e0336aeb7e9a7397e511b5afd9dc84557c80ac0f3d4d7bfec5ae16f20d41c8c84a04552a33870b930420e230e179564f6d19bb153145e76c33ae993886c388832b0fa042ddda7f133924f3854481533e0ede31d51278c0519b29abc3bf53da673e13e3e1214b52413d179d7f66deee35cac8eacb060f78379d70ef4af8607e68131ff529439668fc39c9ce6dfef8a5ac234d234802cbfb749a26107db26406213ae5c06d4673253a3cbee1fcbae58d6ab77e38d6e2c0e7c6317c48e054edadb5a40d0d48acb44643d998139a8a66bb820be1f3f80185bc777d14b5954b60effe2448a036d565c6bc0b915fcea518acdd20ab07bc1529f561c58cd044f723109b93f6fd99f876ff891d64306b5d08f48bab59f38695e9109c4dec34013ba3153488ce070268381ba923ee1eb77125b36afcb4347ec3478c8f2735b06ef17351d872e577fa95d0c397c88c71b59629a36aec" + +// Generated by `gpg --export-secret-keys` followed by a manual extraction of +// the ElGamal subkey from the packets. +const privKeyElGamalHex = "9d0157044df9ee1a100400eb8e136a58ec39b582629cdadf830bc64e0a94ed8103ca8bb247b27b11b46d1d25297ef4bcc3071785ba0c0bedfe89eabc5287fcc0edf81ab5896c1c8e4b20d27d79813c7aede75320b33eaeeaa586edc00fd1036c10133e6ba0ff277245d0d59d04b2b3421b7244aca5f4a8d870c6f1c1fbff9e1c26699a860b9504f35ca1d700030503fd1ededd3b840795be6d9ccbe3c51ee42e2f39233c432b831ddd9c4e72b7025a819317e47bf94f9ee316d7273b05d5fcf2999c3a681f519b1234bbfa6d359b4752bd9c3f77d6b6456cde152464763414ca130f4e91d91041432f90620fec0e6d6b5116076c2985d5aeaae13be492b9b329efcaf7ee25120159a0a30cd976b42d7afe030302dae7eb80db744d4960c4df930d57e87fe81412eaace9f900e6c839817a614ddb75ba6603b9417c33ea7b6c93967dfa2bcff3fa3c74a5ce2c962db65b03aece14c96cbd0038fc" diff --git a/libgo/go/crypto/openpgp/packet/public_key.go b/libgo/go/crypto/openpgp/packet/public_key.go index cd4a9ae..e6b0ae5 100644 --- a/libgo/go/crypto/openpgp/packet/public_key.go +++ b/libgo/go/crypto/openpgp/packet/public_key.go @@ -7,6 +7,7 @@ package packet import ( "big" "crypto/dsa" + "crypto/openpgp/elgamal" "crypto/openpgp/error" "crypto/rsa" "crypto/sha1" @@ -30,6 +31,28 @@ type PublicKey struct { n, e, p, q, g, y parsedMPI } +func fromBig(n *big.Int) parsedMPI { + return parsedMPI{ + bytes: n.Bytes(), + bitLength: uint16(n.BitLen()), + } +} + +// NewRSAPublicKey returns a PublicKey that wraps the given rsa.PublicKey. +func NewRSAPublicKey(creationTimeSecs uint32, pub *rsa.PublicKey, isSubkey bool) *PublicKey { + pk := &PublicKey{ + CreationTime: creationTimeSecs, + PubKeyAlgo: PubKeyAlgoRSA, + PublicKey: pub, + IsSubkey: isSubkey, + n: fromBig(pub.N), + e: fromBig(big.NewInt(int64(pub.E))), + } + + pk.setFingerPrintAndKeyId() + return pk +} + func (pk *PublicKey) parse(r io.Reader) (err os.Error) { // RFC 4880, section 5.5.2 var buf [6]byte @@ -47,6 +70,8 @@ func (pk *PublicKey) parse(r io.Reader) (err os.Error) { err = pk.parseRSA(r) case PubKeyAlgoDSA: err = pk.parseDSA(r) + case PubKeyAlgoElGamal: + err = pk.parseElGamal(r) default: err = error.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo))) } @@ -54,14 +79,17 @@ func (pk *PublicKey) parse(r io.Reader) (err os.Error) { return } + pk.setFingerPrintAndKeyId() + return +} + +func (pk *PublicKey) setFingerPrintAndKeyId() { // RFC 4880, section 12.2 fingerPrint := sha1.New() pk.SerializeSignaturePrefix(fingerPrint) - pk.Serialize(fingerPrint) + pk.serializeWithoutHeaders(fingerPrint) copy(pk.Fingerprint[:], fingerPrint.Sum()) pk.KeyId = binary.BigEndian.Uint64(pk.Fingerprint[12:20]) - - return } // parseRSA parses RSA public key material from the given Reader. See RFC 4880, @@ -92,7 +120,7 @@ func (pk *PublicKey) parseRSA(r io.Reader) (err os.Error) { return } -// parseRSA parses DSA public key material from the given Reader. See RFC 4880, +// parseDSA parses DSA public key material from the given Reader. See RFC 4880, // section 5.5.2. func (pk *PublicKey) parseDSA(r io.Reader) (err os.Error) { pk.p.bytes, pk.p.bitLength, err = readMPI(r) @@ -121,6 +149,30 @@ func (pk *PublicKey) parseDSA(r io.Reader) (err os.Error) { return } +// parseElGamal parses ElGamal public key material from the given Reader. See +// RFC 4880, section 5.5.2. +func (pk *PublicKey) parseElGamal(r io.Reader) (err os.Error) { + pk.p.bytes, pk.p.bitLength, err = readMPI(r) + if err != nil { + return + } + pk.g.bytes, pk.g.bitLength, err = readMPI(r) + if err != nil { + return + } + pk.y.bytes, pk.y.bitLength, err = readMPI(r) + if err != nil { + return + } + + elgamal := new(elgamal.PublicKey) + elgamal.P = new(big.Int).SetBytes(pk.p.bytes) + elgamal.G = new(big.Int).SetBytes(pk.g.bytes) + elgamal.Y = new(big.Int).SetBytes(pk.y.bytes) + pk.PublicKey = elgamal + return +} + // SerializeSignaturePrefix writes the prefix for this public key to the given Writer. // The prefix is used when calculating a signature over this public key. See // RFC 4880, section 5.2.4. @@ -135,6 +187,10 @@ func (pk *PublicKey) SerializeSignaturePrefix(h hash.Hash) { pLength += 2 + uint16(len(pk.q.bytes)) pLength += 2 + uint16(len(pk.g.bytes)) pLength += 2 + uint16(len(pk.y.bytes)) + case PubKeyAlgoElGamal: + pLength += 2 + uint16(len(pk.p.bytes)) + pLength += 2 + uint16(len(pk.g.bytes)) + pLength += 2 + uint16(len(pk.y.bytes)) default: panic("unknown public key algorithm") } @@ -143,9 +199,40 @@ func (pk *PublicKey) SerializeSignaturePrefix(h hash.Hash) { return } -// Serialize marshals the PublicKey to w in the form of an OpenPGP public key -// packet, not including the packet header. func (pk *PublicKey) Serialize(w io.Writer) (err os.Error) { + length := 6 // 6 byte header + + switch pk.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly: + length += 2 + len(pk.n.bytes) + length += 2 + len(pk.e.bytes) + case PubKeyAlgoDSA: + length += 2 + len(pk.p.bytes) + length += 2 + len(pk.q.bytes) + length += 2 + len(pk.g.bytes) + length += 2 + len(pk.y.bytes) + case PubKeyAlgoElGamal: + length += 2 + len(pk.p.bytes) + length += 2 + len(pk.g.bytes) + length += 2 + len(pk.y.bytes) + default: + panic("unknown public key algorithm") + } + + packetType := packetTypePublicKey + if pk.IsSubkey { + packetType = packetTypePublicSubkey + } + err = serializeHeader(w, packetType, length) + if err != nil { + return + } + return pk.serializeWithoutHeaders(w) +} + +// serializeWithoutHeaders marshals the PublicKey to w in the form of an +// OpenPGP public key packet, not including the packet header. +func (pk *PublicKey) serializeWithoutHeaders(w io.Writer) (err os.Error) { var buf [6]byte buf[0] = 4 buf[1] = byte(pk.CreationTime >> 24) @@ -164,13 +251,15 @@ func (pk *PublicKey) Serialize(w io.Writer) (err os.Error) { return writeMPIs(w, pk.n, pk.e) case PubKeyAlgoDSA: return writeMPIs(w, pk.p, pk.q, pk.g, pk.y) + case PubKeyAlgoElGamal: + return writeMPIs(w, pk.p, pk.g, pk.y) } return error.InvalidArgumentError("bad public-key algorithm") } // CanSign returns true iff this public key can generate signatures func (pk *PublicKey) CanSign() bool { - return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly && pk.PubKeyAlgo != PubKeyAlgoElgamal + return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly && pk.PubKeyAlgo != PubKeyAlgoElGamal } // VerifySignature returns nil iff sig is a valid signature, made by this @@ -194,14 +283,14 @@ func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err os.E switch pk.PubKeyAlgo { case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: rsaPublicKey, _ := pk.PublicKey.(*rsa.PublicKey) - err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature) + err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes) 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) { + if !dsa.Verify(dsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.DSASigR.bytes), new(big.Int).SetBytes(sig.DSASigS.bytes)) { return error.SignatureError("DSA verification failure") } return nil @@ -211,34 +300,43 @@ func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err os.E panic("unreachable") } -// VerifyKeySignature returns nil iff sig is a valid signature, make by this -// public key, of the public key in signed. -func (pk *PublicKey) VerifyKeySignature(signed *PublicKey, sig *Signature) (err os.Error) { - h := sig.Hash.New() +// keySignatureHash returns a Hash of the message that needs to be signed for +// pk to assert a subkey relationship to signed. +func keySignatureHash(pk, signed *PublicKey, sig *Signature) (h hash.Hash, err os.Error) { + h = sig.Hash.New() if h == nil { - return error.UnsupportedError("hash function") + return nil, error.UnsupportedError("hash function") } // RFC 4880, section 5.2.4 pk.SerializeSignaturePrefix(h) - pk.Serialize(h) + pk.serializeWithoutHeaders(h) signed.SerializeSignaturePrefix(h) - signed.Serialize(h) + signed.serializeWithoutHeaders(h) + return +} +// VerifyKeySignature returns nil iff sig is a valid signature, made by this +// public key, of signed. +func (pk *PublicKey) VerifyKeySignature(signed *PublicKey, sig *Signature) (err os.Error) { + h, err := keySignatureHash(pk, signed, sig) + if err != nil { + return err + } return pk.VerifySignature(h, sig) } -// VerifyUserIdSignature returns nil iff sig is a valid signature, make by this -// public key, of the given user id. -func (pk *PublicKey) VerifyUserIdSignature(id string, sig *Signature) (err os.Error) { - h := sig.Hash.New() +// userIdSignatureHash returns a Hash of the message that needs to be signed +// to assert that pk is a valid key for id. +func userIdSignatureHash(id string, pk *PublicKey, sig *Signature) (h hash.Hash, err os.Error) { + h = sig.Hash.New() if h == nil { - return error.UnsupportedError("hash function") + return nil, error.UnsupportedError("hash function") } // RFC 4880, section 5.2.4 pk.SerializeSignaturePrefix(h) - pk.Serialize(h) + pk.serializeWithoutHeaders(h) var buf [5]byte buf[0] = 0xb4 @@ -249,6 +347,16 @@ func (pk *PublicKey) VerifyUserIdSignature(id string, sig *Signature) (err os.Er h.Write(buf[:]) h.Write([]byte(id)) + return +} + +// VerifyUserIdSignature returns nil iff sig is a valid signature, made by this +// public key, of id. +func (pk *PublicKey) VerifyUserIdSignature(id string, sig *Signature) (err os.Error) { + h, err := userIdSignatureHash(id, pk, sig) + if err != nil { + return err + } return pk.VerifySignature(h, sig) } @@ -272,7 +380,7 @@ type parsedMPI struct { bitLength uint16 } -// writeMPIs is a utility function for serialising several big integers to the +// writeMPIs is a utility function for serializing several big integers to the // given Writer. func writeMPIs(w io.Writer, mpis ...parsedMPI) (err os.Error) { for _, mpi := range mpis { diff --git a/libgo/go/crypto/openpgp/packet/public_key_test.go b/libgo/go/crypto/openpgp/packet/public_key_test.go index 069388c..6e8bfbc 100644 --- a/libgo/go/crypto/openpgp/packet/public_key_test.go +++ b/libgo/go/crypto/openpgp/packet/public_key_test.go @@ -28,12 +28,12 @@ func TestPublicKeyRead(t *testing.T) { packet, err := Read(readerFromHex(test.hexData)) if err != nil { t.Errorf("#%d: Read error: %s", i, err) - return + continue } pk, ok := packet.(*PublicKey) if !ok { t.Errorf("#%d: failed to parse, got: %#v", i, packet) - return + continue } if pk.PubKeyAlgo != test.pubKeyAlgo { t.Errorf("#%d: bad public key algorithm got:%x want:%x", i, pk.PubKeyAlgo, test.pubKeyAlgo) @@ -57,6 +57,38 @@ func TestPublicKeyRead(t *testing.T) { } } +func TestPublicKeySerialize(t *testing.T) { + for i, test := range pubKeyTests { + packet, err := Read(readerFromHex(test.hexData)) + if err != nil { + t.Errorf("#%d: Read error: %s", i, err) + continue + } + pk, ok := packet.(*PublicKey) + if !ok { + t.Errorf("#%d: failed to parse, got: %#v", i, packet) + continue + } + serializeBuf := bytes.NewBuffer(nil) + err = pk.Serialize(serializeBuf) + if err != nil { + t.Errorf("#%d: failed to serialize: %s", i, err) + continue + } + + packet, err = Read(serializeBuf) + if err != nil { + t.Errorf("#%d: Read error (from serialized data): %s", i, err) + continue + } + pk, ok = packet.(*PublicKey) + if !ok { + t.Errorf("#%d: failed to parse serialized data, got: %#v", i, packet) + continue + } + } +} + const rsaFingerprintHex = "5fb74b1d03b1e3cb31bc2f8aa34d7e18c20c31bb" const rsaPkDataHex = "988d044d3c5c10010400b1d13382944bd5aba23a4312968b5095d14f947f600eb478e14a6fcb16b0e0cac764884909c020bc495cfcc39a935387c661507bdb236a0612fb582cac3af9b29cc2c8c70090616c41b662f4da4c1201e195472eb7f4ae1ccbcbf9940fe21d985e379a5563dde5b9a23d35f1cfaa5790da3b79db26f23695107bfaca8e7b5bcd0011010001" diff --git a/libgo/go/crypto/openpgp/packet/signature.go b/libgo/go/crypto/openpgp/packet/signature.go index 719657e..7577e28 100644 --- a/libgo/go/crypto/openpgp/packet/signature.go +++ b/libgo/go/crypto/openpgp/packet/signature.go @@ -5,7 +5,6 @@ package packet import ( - "big" "crypto" "crypto/dsa" "crypto/openpgp/error" @@ -32,8 +31,11 @@ type Signature struct { HashTag [2]byte CreationTime uint32 // Unix epoch time - RSASignature []byte - DSASigR, DSASigS *big.Int + RSASignature parsedMPI + DSASigR, DSASigS parsedMPI + + // rawSubpackets contains the unparsed subpackets, in order. + rawSubpackets []outputSubpacket // The following are optional so are nil when not included in the // signature. @@ -128,14 +130,11 @@ func (sig *Signature) parse(r io.Reader) (err os.Error) { switch sig.PubKeyAlgo { case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: - sig.RSASignature, _, err = readMPI(r) + sig.RSASignature.bytes, sig.RSASignature.bitLength, err = readMPI(r) case PubKeyAlgoDSA: - var rBytes, sBytes []byte - rBytes, _, err = readMPI(r) - sig.DSASigR = new(big.Int).SetBytes(rBytes) + sig.DSASigR.bytes, sig.DSASigR.bitLength, err = readMPI(r) if err == nil { - sBytes, _, err = readMPI(r) - sig.DSASigS = new(big.Int).SetBytes(sBytes) + sig.DSASigS.bytes, sig.DSASigS.bitLength, err = readMPI(r) } default: panic("unreachable") @@ -177,7 +176,11 @@ const ( // parseSignatureSubpacket parses a single subpacket. len(subpacket) is >= 1. func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (rest []byte, err os.Error) { // RFC 4880, section 5.2.3.1 - var length uint32 + var ( + length uint32 + packetType signatureSubpacketType + isCritical bool + ) switch { case subpacket[0] < 192: length = uint32(subpacket[0]) @@ -207,10 +210,11 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r err = error.StructuralError("zero length signature subpacket") return } - packetType := subpacket[0] & 0x7f - isCritial := subpacket[0]&0x80 == 0x80 + packetType = signatureSubpacketType(subpacket[0] & 0x7f) + isCritical = subpacket[0]&0x80 == 0x80 subpacket = subpacket[1:] - switch signatureSubpacketType(packetType) { + sig.rawSubpackets = append(sig.rawSubpackets, outputSubpacket{isHashed, packetType, isCritical, subpacket}) + switch packetType { case creationTimeSubpacket: if !isHashed { err = error.StructuralError("signature creation time in non-hashed area") @@ -309,7 +313,7 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r } default: - if isCritial { + if isCritical { err = error.UnsupportedError("unknown critical signature subpacket type " + strconv.Itoa(int(packetType))) return } @@ -381,7 +385,6 @@ func serializeSubpackets(to []byte, subpackets []outputSubpacket, hashed bool) { // buildHashSuffix constructs the HashSuffix member of sig in preparation for signing. func (sig *Signature) buildHashSuffix() (err os.Error) { - sig.outSubpackets = sig.buildSubpackets() hashedSubpacketsLen := subpacketsLength(sig.outSubpackets, true) var ok bool @@ -393,7 +396,7 @@ func (sig *Signature) buildHashSuffix() (err os.Error) { sig.HashSuffix[3], ok = s2k.HashToHashId(sig.Hash) if !ok { sig.HashSuffix = nil - return error.InvalidArgumentError("hash cannot be repesented in OpenPGP: " + strconv.Itoa(int(sig.Hash))) + return error.InvalidArgumentError("hash cannot be represented in OpenPGP: " + strconv.Itoa(int(sig.Hash))) } sig.HashSuffix[4] = byte(hashedSubpacketsLen >> 8) sig.HashSuffix[5] = byte(hashedSubpacketsLen) @@ -420,45 +423,72 @@ func (sig *Signature) signPrepareHash(h hash.Hash) (digest []byte, err os.Error) return } -// SignRSA signs a message with an RSA private key. The hash, h, must contain +// Sign signs a message with a 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) { +func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey) (err os.Error) { + sig.outSubpackets = sig.buildSubpackets() digest, err := sig.signPrepareHash(h) if err != nil { return } - sig.RSASignature, err = rsa.SignPKCS1v15(rand.Reader, priv, sig.Hash, digest) + + switch priv.PubKeyAlgo { + case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: + sig.RSASignature.bytes, err = rsa.SignPKCS1v15(rand.Reader, priv.PrivateKey.(*rsa.PrivateKey), sig.Hash, digest) + sig.RSASignature.bitLength = uint16(8 * len(sig.RSASignature.bytes)) + case PubKeyAlgoDSA: + r, s, err := dsa.Sign(rand.Reader, priv.PrivateKey.(*dsa.PrivateKey), digest) + if err == nil { + sig.DSASigR.bytes = r.Bytes() + sig.DSASigR.bitLength = uint16(8 * len(sig.DSASigR.bytes)) + sig.DSASigS.bytes = s.Bytes() + sig.DSASigS.bitLength = uint16(8 * len(sig.DSASigS.bytes)) + } + default: + err = error.UnsupportedError("public key algorithm: " + strconv.Itoa(int(sig.PubKeyAlgo))) + } + 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) +// SignUserId computes a signature from priv, asserting that pub is a valid +// key for the identity id. On success, the signature is stored in sig. Call +// Serialize to write it out. +func (sig *Signature) SignUserId(id string, pub *PublicKey, priv *PrivateKey) os.Error { + h, err := userIdSignatureHash(id, pub, sig) if err != nil { - return + return nil } - sig.DSASigR, sig.DSASigS, err = dsa.Sign(rand.Reader, priv, digest) - return + return sig.Sign(h, priv) +} + +// SignKey computes a signature from priv, asserting that pub is a subkey. On +// success, the signature is stored in sig. Call Serialize to write it out. +func (sig *Signature) SignKey(pub *PublicKey, priv *PrivateKey) os.Error { + h, err := keySignatureHash(&priv.PublicKey, pub, sig) + if err != nil { + return err + } + return sig.Sign(h, priv) } // 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.RSASignature == nil && sig.DSASigR == nil { + if len(sig.outSubpackets) == 0 { + sig.outSubpackets = sig.rawSubpackets + } + if sig.RSASignature.bytes == nil && sig.DSASigR.bytes == 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) + sigLength = 2 + len(sig.RSASignature.bytes) case PubKeyAlgoDSA: - sigLength = 2 /* MPI length */ - sigLength += (sig.DSASigR.BitLen() + 7) / 8 - sigLength += 2 /* MPI length */ - sigLength += (sig.DSASigS.BitLen() + 7) / 8 + sigLength = 2 + len(sig.DSASigR.bytes) + sigLength += 2 + len(sig.DSASigS.bytes) default: panic("impossible") } @@ -466,7 +496,7 @@ func (sig *Signature) Serialize(w io.Writer) (err os.Error) { 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 */ + sigLength + 2 /* hash tag */ + sigLength err = serializeHeader(w, packetTypeSignature, length) if err != nil { return @@ -493,12 +523,9 @@ func (sig *Signature) Serialize(w io.Writer) (err os.Error) { switch sig.PubKeyAlgo { case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: - err = writeMPI(w, 8*uint16(len(sig.RSASignature)), sig.RSASignature) + err = writeMPIs(w, sig.RSASignature) case PubKeyAlgoDSA: - err = writeBig(w, sig.DSASigR) - if err == nil { - err = writeBig(w, sig.DSASigS) - } + err = writeMPIs(w, sig.DSASigR, sig.DSASigS) default: panic("impossible") } @@ -509,6 +536,7 @@ func (sig *Signature) Serialize(w io.Writer) (err os.Error) { type outputSubpacket struct { hashed bool // true if this subpacket is in the hashed area. subpacketType signatureSubpacketType + isCritical bool contents []byte } @@ -518,12 +546,12 @@ func (sig *Signature) buildSubpackets() (subpackets []outputSubpacket) { creationTime[1] = byte(sig.CreationTime >> 16) creationTime[2] = byte(sig.CreationTime >> 8) creationTime[3] = byte(sig.CreationTime) - subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, creationTime}) + subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, false, creationTime}) if sig.IssuerKeyId != nil { keyId := make([]byte, 8) binary.BigEndian.PutUint64(keyId, *sig.IssuerKeyId) - subpackets = append(subpackets, outputSubpacket{true, issuerSubpacket, keyId}) + subpackets = append(subpackets, outputSubpacket{true, issuerSubpacket, false, keyId}) } return diff --git a/libgo/go/crypto/openpgp/packet/signature_test.go b/libgo/go/crypto/openpgp/packet/signature_test.go index 1305548..c1bbde8 100644 --- a/libgo/go/crypto/openpgp/packet/signature_test.go +++ b/libgo/go/crypto/openpgp/packet/signature_test.go @@ -12,9 +12,7 @@ import ( ) func TestSignatureRead(t *testing.T) { - signatureData, _ := hex.DecodeString(signatureDataHex) - buf := bytes.NewBuffer(signatureData) - packet, err := Read(buf) + packet, err := Read(readerFromHex(signatureDataHex)) if err != nil { t.Error(err) return @@ -25,4 +23,20 @@ func TestSignatureRead(t *testing.T) { } } -const signatureDataHex = "89011c04000102000605024cb45112000a0910ab105c91af38fb158f8d07ff5596ea368c5efe015bed6e78348c0f033c931d5f2ce5db54ce7f2a7e4b4ad64db758d65a7a71773edeab7ba2a9e0908e6a94a1175edd86c1d843279f045b021a6971a72702fcbd650efc393c5474d5b59a15f96d2eaad4c4c426797e0dcca2803ef41c6ff234d403eec38f31d610c344c06f2401c262f0993b2e66cad8a81ebc4322c723e0d4ba09fe917e8777658307ad8329adacba821420741009dfe87f007759f0982275d028a392c6ed983a0d846f890b36148c7358bdb8a516007fac760261ecd06076813831a36d0459075d1befa245ae7f7fb103d92ca759e9498fe60ef8078a39a3beda510deea251ea9f0a7f0df6ef42060f20780360686f3e400e" +func TestSignatureReserialize(t *testing.T) { + packet, _ := Read(readerFromHex(signatureDataHex)) + sig := packet.(*Signature) + out := new(bytes.Buffer) + err := sig.Serialize(out) + if err != nil { + t.Errorf("error reserializing: %s", err) + return + } + + expected, _ := hex.DecodeString(signatureDataHex) + if !bytes.Equal(expected, out.Bytes()) { + t.Errorf("output doesn't match input (got vs expected):\n%s\n%s", hex.Dump(out.Bytes()), hex.Dump(expected)) + } +} + +const signatureDataHex = "c2c05c04000102000605024cb45112000a0910ab105c91af38fb158f8d07ff5596ea368c5efe015bed6e78348c0f033c931d5f2ce5db54ce7f2a7e4b4ad64db758d65a7a71773edeab7ba2a9e0908e6a94a1175edd86c1d843279f045b021a6971a72702fcbd650efc393c5474d5b59a15f96d2eaad4c4c426797e0dcca2803ef41c6ff234d403eec38f31d610c344c06f2401c262f0993b2e66cad8a81ebc4322c723e0d4ba09fe917e8777658307ad8329adacba821420741009dfe87f007759f0982275d028a392c6ed983a0d846f890b36148c7358bdb8a516007fac760261ecd06076813831a36d0459075d1befa245ae7f7fb103d92ca759e9498fe60ef8078a39a3beda510deea251ea9f0a7f0df6ef42060f20780360686f3e400e" diff --git a/libgo/go/crypto/openpgp/packet/symmetric_key_encrypted.go b/libgo/go/crypto/openpgp/packet/symmetric_key_encrypted.go index d9010f8..ad4f1d6 100644 --- a/libgo/go/crypto/openpgp/packet/symmetric_key_encrypted.go +++ b/libgo/go/crypto/openpgp/packet/symmetric_key_encrypted.go @@ -5,6 +5,7 @@ package packet import ( + "bytes" "crypto/cipher" "crypto/openpgp/error" "crypto/openpgp/s2k" @@ -27,6 +28,8 @@ type SymmetricKeyEncrypted struct { encryptedKey []byte } +const symmetricKeyEncryptedVersion = 4 + func (ske *SymmetricKeyEncrypted) parse(r io.Reader) (err os.Error) { // RFC 4880, section 5.3. var buf [2]byte @@ -34,12 +37,12 @@ func (ske *SymmetricKeyEncrypted) parse(r io.Reader) (err os.Error) { if err != nil { return } - if buf[0] != 4 { + if buf[0] != symmetricKeyEncryptedVersion { return error.UnsupportedError("SymmetricKeyEncrypted version") } ske.CipherFunc = CipherFunction(buf[1]) - if ske.CipherFunc.keySize() == 0 { + if ske.CipherFunc.KeySize() == 0 { return error.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[1]))) } @@ -75,7 +78,7 @@ func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) os.Error { return nil } - key := make([]byte, ske.CipherFunc.keySize()) + key := make([]byte, ske.CipherFunc.KeySize()) ske.s2k(key, passphrase) if len(ske.encryptedKey) == 0 { @@ -100,3 +103,60 @@ func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) os.Error { ske.Encrypted = false return nil } + +// SerializeSymmetricKeyEncrypted serializes a symmetric key packet to w. The +// packet contains a random session key, encrypted by a key derived from the +// given passphrase. The session key is returned and must be passed to +// SerializeSymmetricallyEncrypted. +func SerializeSymmetricKeyEncrypted(w io.Writer, rand io.Reader, passphrase []byte, cipherFunc CipherFunction) (key []byte, err os.Error) { + keySize := cipherFunc.KeySize() + if keySize == 0 { + return nil, error.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc))) + } + + s2kBuf := new(bytes.Buffer) + keyEncryptingKey := make([]byte, keySize) + // s2k.Serialize salts and stretches the passphrase, and writes the + // resulting key to keyEncryptingKey and the s2k descriptor to s2kBuf. + err = s2k.Serialize(s2kBuf, keyEncryptingKey, rand, passphrase) + if err != nil { + return + } + s2kBytes := s2kBuf.Bytes() + + packetLength := 2 /* header */ + len(s2kBytes) + 1 /* cipher type */ + keySize + err = serializeHeader(w, packetTypeSymmetricKeyEncrypted, packetLength) + if err != nil { + return + } + + var buf [2]byte + buf[0] = symmetricKeyEncryptedVersion + buf[1] = byte(cipherFunc) + _, err = w.Write(buf[:]) + if err != nil { + return + } + _, err = w.Write(s2kBytes) + if err != nil { + return + } + + sessionKey := make([]byte, keySize) + _, err = io.ReadFull(rand, sessionKey) + if err != nil { + return + } + iv := make([]byte, cipherFunc.blockSize()) + c := cipher.NewCFBEncrypter(cipherFunc.new(keyEncryptingKey), iv) + encryptedCipherAndKey := make([]byte, keySize+1) + c.XORKeyStream(encryptedCipherAndKey, buf[1:]) + c.XORKeyStream(encryptedCipherAndKey[1:], sessionKey) + _, err = w.Write(encryptedCipherAndKey) + if err != nil { + return + } + + key = sessionKey + return +} diff --git a/libgo/go/crypto/openpgp/packet/symmetric_key_encrypted_test.go b/libgo/go/crypto/openpgp/packet/symmetric_key_encrypted_test.go index 717c8ff..823ec40 100644 --- a/libgo/go/crypto/openpgp/packet/symmetric_key_encrypted_test.go +++ b/libgo/go/crypto/openpgp/packet/symmetric_key_encrypted_test.go @@ -6,6 +6,7 @@ package packet import ( "bytes" + "crypto/rand" "encoding/hex" "io/ioutil" "os" @@ -60,3 +61,41 @@ func TestSymmetricKeyEncrypted(t *testing.T) { const symmetricallyEncryptedHex = "8c0d04030302371a0b38d884f02060c91cf97c9973b8e58e028e9501708ccfe618fb92afef7fa2d80ddadd93cf" const symmetricallyEncryptedContentsHex = "cb1062004d14c4df636f6e74656e74732e0a" + +func TestSerializeSymmetricKeyEncrypted(t *testing.T) { + buf := bytes.NewBuffer(nil) + passphrase := []byte("testing") + cipherFunc := CipherAES128 + + key, err := SerializeSymmetricKeyEncrypted(buf, rand.Reader, passphrase, cipherFunc) + if err != nil { + t.Errorf("failed to serialize: %s", err) + return + } + + p, err := Read(buf) + if err != nil { + t.Errorf("failed to reparse: %s", err) + return + } + ske, ok := p.(*SymmetricKeyEncrypted) + if !ok { + t.Errorf("parsed a different packet type: %#v", p) + return + } + + if !ske.Encrypted { + t.Errorf("SKE not encrypted but should be") + } + if ske.CipherFunc != cipherFunc { + t.Errorf("SKE cipher function is %d (expected %d)", ske.CipherFunc, cipherFunc) + } + err = ske.Decrypt(passphrase) + if err != nil { + t.Errorf("failed to decrypt reparsed SKE: %s", err) + return + } + if !bytes.Equal(key, ske.Key) { + t.Errorf("keys don't match after Decrpyt: %x (original) vs %x (parsed)", key, ske.Key) + } +} diff --git a/libgo/go/crypto/openpgp/packet/symmetrically_encrypted.go b/libgo/go/crypto/openpgp/packet/symmetrically_encrypted.go index fc19ffe..e33c9f3 100644 --- a/libgo/go/crypto/openpgp/packet/symmetrically_encrypted.go +++ b/libgo/go/crypto/openpgp/packet/symmetrically_encrypted.go @@ -7,6 +7,7 @@ package packet import ( "crypto/cipher" "crypto/openpgp/error" + "crypto/rand" "crypto/sha1" "crypto/subtle" "hash" @@ -24,6 +25,8 @@ type SymmetricallyEncrypted struct { prefix []byte } +const symmetricallyEncryptedVersion = 1 + func (se *SymmetricallyEncrypted) parse(r io.Reader) os.Error { if se.MDC { // See RFC 4880, section 5.13. @@ -32,7 +35,7 @@ func (se *SymmetricallyEncrypted) parse(r io.Reader) os.Error { if err != nil { return err } - if buf[0] != 1 { + if buf[0] != symmetricallyEncryptedVersion { return error.UnsupportedError("unknown SymmetricallyEncrypted version") } } @@ -44,7 +47,7 @@ func (se *SymmetricallyEncrypted) parse(r io.Reader) os.Error { // packet can be read. An incorrect key can, with high probability, be detected // immediately and this will result in a KeyIncorrect error being returned. func (se *SymmetricallyEncrypted) Decrypt(c CipherFunction, key []byte) (io.ReadCloser, os.Error) { - keySize := c.keySize() + keySize := c.KeySize() if keySize == 0 { return nil, error.UnsupportedError("unknown cipher: " + strconv.Itoa(int(c))) } @@ -174,6 +177,9 @@ func (ser *seMDCReader) Read(buf []byte) (n int, err os.Error) { return } +// This is a new-format packet tag byte for a type 19 (MDC) packet. +const mdcPacketTagByte = byte(0x80) | 0x40 | 19 + func (ser *seMDCReader) Close() os.Error { if ser.error { return error.SignatureError("error during reading") @@ -191,16 +197,95 @@ func (ser *seMDCReader) Close() os.Error { } } - // This is a new-format packet tag byte for a type 19 (MDC) packet. - const mdcPacketTagByte = byte(0x80) | 0x40 | 19 if ser.trailer[0] != mdcPacketTagByte || ser.trailer[1] != sha1.Size { return error.SignatureError("MDC packet not found") } ser.h.Write(ser.trailer[:2]) final := ser.h.Sum() - if subtle.ConstantTimeCompare(final, ser.trailer[2:]) == 1 { + if subtle.ConstantTimeCompare(final, ser.trailer[2:]) != 1 { return error.SignatureError("hash mismatch") } return nil } + +// An seMDCWriter writes through to an io.WriteCloser while maintains a running +// hash of the data written. On close, it emits an MDC packet containing the +// running hash. +type seMDCWriter struct { + w io.WriteCloser + h hash.Hash +} + +func (w *seMDCWriter) Write(buf []byte) (n int, err os.Error) { + w.h.Write(buf) + return w.w.Write(buf) +} + +func (w *seMDCWriter) Close() (err os.Error) { + var buf [mdcTrailerSize]byte + + buf[0] = mdcPacketTagByte + buf[1] = sha1.Size + w.h.Write(buf[:2]) + digest := w.h.Sum() + copy(buf[2:], digest) + + _, err = w.w.Write(buf[:]) + if err != nil { + return + } + return w.w.Close() +} + +// noOpCloser is like an ioutil.NopCloser, but for an io.Writer. +type noOpCloser struct { + w io.Writer +} + +func (c noOpCloser) Write(data []byte) (n int, err os.Error) { + return c.w.Write(data) +} + +func (c noOpCloser) Close() os.Error { + return nil +} + +// SerializeSymmetricallyEncrypted serializes a symmetrically encrypted packet +// to w and returns a WriteCloser to which the to-be-encrypted packets can be +// written. +func SerializeSymmetricallyEncrypted(w io.Writer, c CipherFunction, key []byte) (contents io.WriteCloser, err os.Error) { + if c.KeySize() != len(key) { + return nil, error.InvalidArgumentError("SymmetricallyEncrypted.Serialize: bad key length") + } + writeCloser := noOpCloser{w} + ciphertext, err := serializeStreamHeader(writeCloser, packetTypeSymmetricallyEncryptedMDC) + if err != nil { + return + } + + _, err = ciphertext.Write([]byte{symmetricallyEncryptedVersion}) + if err != nil { + return + } + + block := c.new(key) + blockSize := block.BlockSize() + iv := make([]byte, blockSize) + _, err = rand.Reader.Read(iv) + if err != nil { + return + } + s, prefix := cipher.NewOCFBEncrypter(block, iv, cipher.OCFBNoResync) + _, err = ciphertext.Write(prefix) + if err != nil { + return + } + plaintext := cipher.StreamWriter{S: s, W: ciphertext} + + h := sha1.New() + h.Write(iv) + h.Write(iv[blockSize-2:]) + contents = &seMDCWriter{w: plaintext, h: h} + return +} diff --git a/libgo/go/crypto/openpgp/packet/symmetrically_encrypted_test.go b/libgo/go/crypto/openpgp/packet/symmetrically_encrypted_test.go index 5543b20..1054fc2 100644 --- a/libgo/go/crypto/openpgp/packet/symmetrically_encrypted_test.go +++ b/libgo/go/crypto/openpgp/packet/symmetrically_encrypted_test.go @@ -9,6 +9,7 @@ import ( "crypto/openpgp/error" "crypto/sha1" "encoding/hex" + "io" "io/ioutil" "os" "testing" @@ -76,3 +77,48 @@ func testMDCReader(t *testing.T) { } const mdcPlaintextHex = "a302789c3b2d93c4e0eb9aba22283539b3203335af44a134afb800c849cb4c4de10200aff40b45d31432c80cb384299a0655966d6939dfdeed1dddf980" + +func TestSerialize(t *testing.T) { + buf := bytes.NewBuffer(nil) + c := CipherAES128 + key := make([]byte, c.KeySize()) + + w, err := SerializeSymmetricallyEncrypted(buf, c, key) + if err != nil { + t.Errorf("error from SerializeSymmetricallyEncrypted: %s", err) + return + } + + contents := []byte("hello world\n") + + w.Write(contents) + w.Close() + + p, err := Read(buf) + if err != nil { + t.Errorf("error from Read: %s", err) + return + } + + se, ok := p.(*SymmetricallyEncrypted) + if !ok { + t.Errorf("didn't read a *SymmetricallyEncrypted") + return + } + + r, err := se.Decrypt(c, key) + if err != nil { + t.Errorf("error from Decrypt: %s", err) + return + } + + contentsCopy := bytes.NewBuffer(nil) + _, err = io.Copy(contentsCopy, r) + if err != nil { + t.Errorf("error from io.Copy: %s", err) + return + } + if !bytes.Equal(contentsCopy.Bytes(), contents) { + t.Errorf("contents not equal got: %x want: %x", contentsCopy.Bytes(), contents) + } +} diff --git a/libgo/go/crypto/openpgp/packet/userid.go b/libgo/go/crypto/openpgp/packet/userid.go index ed2ad77..0580ba3 100644 --- a/libgo/go/crypto/openpgp/packet/userid.go +++ b/libgo/go/crypto/openpgp/packet/userid.go @@ -20,6 +20,51 @@ type UserId struct { Name, Comment, Email string } +func hasInvalidCharacters(s string) bool { + for _, c := range s { + switch c { + case '(', ')', '<', '>', 0: + return true + } + } + return false +} + +// NewUserId returns a UserId or nil if any of the arguments contain invalid +// characters. The invalid characters are '\x00', '(', ')', '<' and '>' +func NewUserId(name, comment, email string) *UserId { + // RFC 4880 doesn't deal with the structure of userid strings; the + // name, comment and email form is just a convention. However, there's + // no convention about escaping the metacharacters and GPG just refuses + // to create user ids where, say, the name contains a '('. We mirror + // this behaviour. + + if hasInvalidCharacters(name) || hasInvalidCharacters(comment) || hasInvalidCharacters(email) { + return nil + } + + uid := new(UserId) + uid.Name, uid.Comment, uid.Email = name, comment, email + uid.Id = name + if len(comment) > 0 { + if len(uid.Id) > 0 { + uid.Id += " " + } + uid.Id += "(" + uid.Id += comment + uid.Id += ")" + } + if len(email) > 0 { + if len(uid.Id) > 0 { + uid.Id += " " + } + uid.Id += "<" + uid.Id += email + uid.Id += ">" + } + return uid +} + func (uid *UserId) parse(r io.Reader) (err os.Error) { // RFC 4880, section 5.11 b, err := ioutil.ReadAll(r) @@ -31,6 +76,17 @@ func (uid *UserId) parse(r io.Reader) (err os.Error) { return } +// Serialize marshals uid to w in the form of an OpenPGP packet, including +// header. +func (uid *UserId) Serialize(w io.Writer) os.Error { + err := serializeHeader(w, packetTypeUserId, len(uid.Id)) + if err != nil { + return err + } + _, err = w.Write([]byte(uid.Id)) + return err +} + // parseUserId extracts the name, comment and email from a user id string that // is formatted as "Full Name (Comment) ". func parseUserId(id string) (name, comment, email string) { diff --git a/libgo/go/crypto/openpgp/packet/userid_test.go b/libgo/go/crypto/openpgp/packet/userid_test.go index 394873d..2968193 100644 --- a/libgo/go/crypto/openpgp/packet/userid_test.go +++ b/libgo/go/crypto/openpgp/packet/userid_test.go @@ -40,3 +40,48 @@ func TestParseUserId(t *testing.T) { } } } + +var newUserIdTests = []struct { + name, comment, email, id string +}{ + {"foo", "", "", "foo"}, + {"", "bar", "", "(bar)"}, + {"", "", "baz", ""}, + {"foo", "bar", "", "foo (bar)"}, + {"foo", "", "baz", "foo "}, + {"", "bar", "baz", "(bar) "}, + {"foo", "bar", "baz", "foo (bar) "}, +} + +func TestNewUserId(t *testing.T) { + for i, test := range newUserIdTests { + uid := NewUserId(test.name, test.comment, test.email) + if uid == nil { + t.Errorf("#%d: returned nil", i) + continue + } + if uid.Id != test.id { + t.Errorf("#%d: got '%s', want '%s'", i, uid.Id, test.id) + } + } +} + +var invalidNewUserIdTests = []struct { + name, comment, email string +}{ + {"foo(", "", ""}, + {"foo<", "", ""}, + {"", "bar)", ""}, + {"", "bar<", ""}, + {"", "", "baz>"}, + {"", "", "baz)"}, + {"", "", "baz\x00"}, +} + +func TestNewUserIdWithInvalidInput(t *testing.T) { + for i, test := range invalidNewUserIdTests { + if uid := NewUserId(test.name, test.comment, test.email); uid != nil { + t.Errorf("#%d: returned non-nil value: %#v", i, uid) + } + } +} diff --git a/libgo/go/crypto/openpgp/read.go b/libgo/go/crypto/openpgp/read.go index 4f84dff..d95f613 100644 --- a/libgo/go/crypto/openpgp/read.go +++ b/libgo/go/crypto/openpgp/read.go @@ -10,7 +10,6 @@ import ( "crypto/openpgp/armor" "crypto/openpgp/error" "crypto/openpgp/packet" - "crypto/rsa" _ "crypto/sha256" "hash" "io" @@ -44,7 +43,7 @@ type MessageDetails struct { DecryptedWith Key // the private key used to decrypt the message, if any. IsSigned bool // true if the message is signed. SignedByKeyId uint64 // the key id of the signer, if any. - SignedBy *Key // the key of the signer, if availible. + SignedBy *Key // the key of the signer, if available. LiteralData *packet.LiteralData // the metadata of the contents UnverifiedBody io.Reader // the contents of the message. @@ -57,7 +56,6 @@ type MessageDetails struct { // been consumed. Once EOF has been seen, the following fields are // valid. (An authentication code failure is reported as a // SignatureError error when reading from UnverifiedBody.) - SignatureError os.Error // nil if the signature is good. Signature *packet.Signature // the signature packet itself. @@ -112,7 +110,10 @@ ParsePackets: case *packet.EncryptedKey: // This packet contains the decryption key encrypted to a public key. md.EncryptedToKeyIds = append(md.EncryptedToKeyIds, p.KeyId) - if p.Algo != packet.PubKeyAlgoRSA && p.Algo != packet.PubKeyAlgoRSAEncryptOnly { + switch p.Algo { + case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal: + break + default: continue } var keys []Key @@ -145,7 +146,7 @@ ParsePackets: // function so that it can decrypt a key or give us a passphrase. FindKey: for { - // See if any of the keys already have a private key availible + // See if any of the keys already have a private key available candidates = candidates[:0] candidateFingerprints := make(map[string]bool) @@ -155,7 +156,7 @@ FindKey: } if !pk.key.PrivateKey.Encrypted { if len(pk.encryptedKey.Key) == 0 { - pk.encryptedKey.DecryptRSA(pk.key.PrivateKey.PrivateKey.(*rsa.PrivateKey)) + pk.encryptedKey.Decrypt(pk.key.PrivateKey) } if len(pk.encryptedKey.Key) == 0 { continue @@ -214,7 +215,7 @@ FindKey: return readSignedMessage(packets, md, keyring) } -// readSignedMessage reads a possibily signed message if mdin is non-zero then +// readSignedMessage reads a possibly signed message if mdin is non-zero then // that structure is updated and returned. Otherwise a fresh MessageDetails is // used. func readSignedMessage(packets *packet.Reader, mdin *MessageDetails, keyring KeyRing) (md *MessageDetails, err os.Error) { @@ -249,11 +250,12 @@ FindLiteralData: md.IsSigned = true md.SignedByKeyId = p.KeyId keys := keyring.KeysById(p.KeyId) - for _, key := range keys { + for i, key := range keys { if key.SelfSignature.FlagsValid && !key.SelfSignature.FlagSign { continue } - md.SignedBy = &key + md.SignedBy = &keys[i] + break } case *packet.LiteralData: md.LiteralData = p @@ -274,13 +276,13 @@ FindLiteralData: // hashForSignature returns a pair of hashes that can be used to verify a // signature. The signature may specify that the contents of the signed message -// should be preprocessed (i.e. to normalise line endings). Thus this function +// should be preprocessed (i.e. to normalize line endings). Thus this function // returns two hashes. The second should be used to hash the message itself and // performs any needed preprocessing. func hashForSignature(hashId crypto.Hash, sigType packet.SignatureType) (hash.Hash, hash.Hash, os.Error) { h := hashId.New() if h == nil { - return nil, nil, error.UnsupportedError("hash not availible: " + strconv.Itoa(int(hashId))) + return nil, nil, error.UnsupportedError("hash not available: " + strconv.Itoa(int(hashId))) } switch sigType { diff --git a/libgo/go/crypto/openpgp/read_test.go b/libgo/go/crypto/openpgp/read_test.go index 423c85b..4dc290e 100644 --- a/libgo/go/crypto/openpgp/read_test.go +++ b/libgo/go/crypto/openpgp/read_test.go @@ -33,6 +33,29 @@ func TestReadKeyRing(t *testing.T) { } } +func TestRereadKeyRing(t *testing.T) { + kring, err := ReadKeyRing(readerFromHex(testKeys1And2Hex)) + if err != nil { + t.Errorf("error in initial parse: %s", err) + return + } + out := new(bytes.Buffer) + err = kring[0].Serialize(out) + if err != nil { + t.Errorf("error in serialization: %s", err) + return + } + kring, err = ReadKeyRing(out) + if err != nil { + t.Errorf("error in second parse: %s", err) + return + } + + if len(kring) != 1 || uint32(kring[0].PrimaryKey.KeyId) != 0xC20C31BB { + t.Errorf("bad keyring: %#v", kring) + } +} + func TestReadPrivateKeyRing(t *testing.T) { kring, err := ReadKeyRing(readerFromHex(testKeys1And2PrivateHex)) if err != nil { @@ -102,49 +125,71 @@ func TestTextSignedMessage(t *testing.T) { checkSignedMessage(t, signedTextMessageHex, signedTextInput) } -func TestSignedEncryptedMessage(t *testing.T) { - expected := "Signed and encrypted message\n" - kring, _ := ReadKeyRing(readerFromHex(testKeys1And2PrivateHex)) - prompt := func(keys []Key, symmetric bool) ([]byte, os.Error) { - if symmetric { - t.Errorf("prompt: message was marked as symmetrically encrypted") - return nil, error.KeyIncorrectError - } +var signedEncryptedMessageTests = []struct { + keyRingHex string + messageHex string + signedByKeyId uint64 + encryptedToKeyId uint64 +}{ + { + testKeys1And2PrivateHex, + signedEncryptedMessageHex, + 0xa34d7e18c20c31bb, + 0x2a67d68660df41c7, + }, + { + dsaElGamalTestKeysHex, + signedEncryptedMessage2Hex, + 0x33af447ccd759b09, + 0xcf6a7abcd43e3673, + }, +} - if len(keys) == 0 { - t.Error("prompt: no keys requested") - return nil, error.KeyIncorrectError +func TestSignedEncryptedMessage(t *testing.T) { + for i, test := range signedEncryptedMessageTests { + expected := "Signed and encrypted message\n" + kring, _ := ReadKeyRing(readerFromHex(test.keyRingHex)) + prompt := func(keys []Key, symmetric bool) ([]byte, os.Error) { + if symmetric { + t.Errorf("prompt: message was marked as symmetrically encrypted") + return nil, error.KeyIncorrectError + } + + if len(keys) == 0 { + t.Error("prompt: no keys requested") + return nil, error.KeyIncorrectError + } + + err := keys[0].PrivateKey.Decrypt([]byte("passphrase")) + if err != nil { + t.Errorf("prompt: error decrypting key: %s", err) + return nil, error.KeyIncorrectError + } + + return nil, nil } - err := keys[0].PrivateKey.Decrypt([]byte("passphrase")) + md, err := ReadMessage(readerFromHex(test.messageHex), kring, prompt) if err != nil { - t.Errorf("prompt: error decrypting key: %s", err) - return nil, error.KeyIncorrectError + t.Errorf("#%d: error reading message: %s", i, err) + return } - return nil, nil - } - - md, err := ReadMessage(readerFromHex(signedEncryptedMessageHex), kring, prompt) - if err != nil { - t.Errorf("error reading message: %s", err) - return - } - - if !md.IsSigned || md.SignedByKeyId != 0xa34d7e18c20c31bb || md.SignedBy == nil || !md.IsEncrypted || md.IsSymmetricallyEncrypted || len(md.EncryptedToKeyIds) == 0 || md.EncryptedToKeyIds[0] != 0x2a67d68660df41c7 { - t.Errorf("bad MessageDetails: %#v", md) - } + if !md.IsSigned || md.SignedByKeyId != test.signedByKeyId || md.SignedBy == nil || !md.IsEncrypted || md.IsSymmetricallyEncrypted || len(md.EncryptedToKeyIds) == 0 || md.EncryptedToKeyIds[0] != test.encryptedToKeyId { + t.Errorf("#%d: bad MessageDetails: %#v", i, md) + } - contents, err := ioutil.ReadAll(md.UnverifiedBody) - if err != nil { - t.Errorf("error reading UnverifiedBody: %s", err) - } - if string(contents) != expected { - t.Errorf("bad UnverifiedBody got:%s want:%s", string(contents), expected) - } + contents, err := ioutil.ReadAll(md.UnverifiedBody) + if err != nil { + t.Errorf("#%d: error reading UnverifiedBody: %s", i, err) + } + if string(contents) != expected { + t.Errorf("#%d: bad UnverifiedBody got:%s want:%s", i, string(contents), expected) + } - if md.SignatureError != nil || md.Signature == nil { - t.Errorf("failed to validate: %s", md.SignatureError) + if md.SignatureError != nil || md.Signature == nil { + t.Errorf("#%d: failed to validate: %s", i, md.SignatureError) + } } } @@ -193,9 +238,9 @@ func TestSymmetricallyEncrypted(t *testing.T) { t.Errorf("ReadAll: %s", err) } - expectedCreatationTime := uint32(1295992998) - if md.LiteralData.Time != expectedCreatationTime { - t.Errorf("LiteralData.Time is %d, want %d", md.LiteralData.Time, expectedCreatationTime) + expectedCreationTime := uint32(1295992998) + if md.LiteralData.Time != expectedCreationTime { + t.Errorf("LiteralData.Time is %d, want %d", md.LiteralData.Time, expectedCreationTime) } if string(contents) != expected { @@ -265,12 +310,16 @@ const testKeys1And2Hex = "988d044d3c5c10010400b1d13382944bd5aba23a4312968b5095d1 const testKeys1And2PrivateHex = "9501d8044d3c5c10010400b1d13382944bd5aba23a4312968b5095d14f947f600eb478e14a6fcb16b0e0cac764884909c020bc495cfcc39a935387c661507bdb236a0612fb582cac3af9b29cc2c8c70090616c41b662f4da4c1201e195472eb7f4ae1ccbcbf9940fe21d985e379a5563dde5b9a23d35f1cfaa5790da3b79db26f23695107bfaca8e7b5bcd00110100010003ff4d91393b9a8e3430b14d6209df42f98dc927425b881f1209f319220841273a802a97c7bdb8b3a7740b3ab5866c4d1d308ad0d3a79bd1e883aacf1ac92dfe720285d10d08752a7efe3c609b1d00f17f2805b217be53999a7da7e493bfc3e9618fd17018991b8128aea70a05dbce30e4fbe626aa45775fa255dd9177aabf4df7cf0200c1ded12566e4bc2bb590455e5becfb2e2c9796482270a943343a7835de41080582c2be3caf5981aa838140e97afa40ad652a0b544f83eb1833b0957dce26e47b0200eacd6046741e9ce2ec5beb6fb5e6335457844fb09477f83b050a96be7da043e17f3a9523567ed40e7a521f818813a8b8a72209f1442844843ccc7eb9805442570200bdafe0438d97ac36e773c7162028d65844c4d463e2420aa2228c6e50dc2743c3d6c72d0d782a5173fe7be2169c8a9f4ef8a7cf3e37165e8c61b89c346cdc6c1799d2b41054657374204b6579203120285253412988b804130102002205024d3c5c10021b03060b090807030206150802090a0b0416020301021e01021780000a0910a34d7e18c20c31bbb5b304009cc45fe610b641a2c146331be94dade0a396e73ca725e1b25c21708d9cab46ecca5ccebc23055879df8f99eea39b377962a400f2ebdc36a7c99c333d74aeba346315137c3ff9d0a09b0273299090343048afb8107cf94cbd1400e3026f0ccac7ecebbc4d78588eb3e478fe2754d3ca664bcf3eac96ca4a6b0c8d7df5102f60f6b00200009d01d8044d3c5c10010400b201df61d67487301f11879d514f4248ade90c8f68c7af1284c161098de4c28c2850f1ec7b8e30f959793e571542ffc6532189409cb51c3d30dad78c4ad5165eda18b20d9826d8707d0f742e2ab492103a85bbd9ddf4f5720f6de7064feb0d39ee002219765bb07bcfb8b877f47abe270ddeda4f676108cecb6b9bb2ad484a4f00110100010003fd17a7490c22a79c59281fb7b20f5e6553ec0c1637ae382e8adaea295f50241037f8997cf42c1ce26417e015091451b15424b2c59eb8d4161b0975630408e394d3b00f88d4b4e18e2cc85e8251d4753a27c639c83f5ad4a571c4f19d7cd460b9b73c25ade730c99df09637bd173d8e3e981ac64432078263bb6dc30d3e974150dd0200d0ee05be3d4604d2146fb0457f31ba17c057560785aa804e8ca5530a7cd81d3440d0f4ba6851efcfd3954b7e68908fc0ba47f7ac37bf559c6c168b70d3a7c8cd0200da1c677c4bce06a068070f2b3733b0a714e88d62aa3f9a26c6f5216d48d5c2b5624144f3807c0df30be66b3268eeeca4df1fbded58faf49fc95dc3c35f134f8b01fd1396b6c0fc1b6c4f0eb8f5e44b8eace1e6073e20d0b8bc5385f86f1cf3f050f66af789f3ef1fc107b7f4421e19e0349c730c68f0a226981f4e889054fdb4dc149e8e889f04180102000905024d3c5c10021b0c000a0910a34d7e18c20c31bb1a03040085c8d62e16d05dc4e9dad64953c8a2eed8b6c12f92b1575eeaa6dcf7be9473dd5b24b37b6dffbb4e7c99ed1bd3cb11634be19b3e6e207bed7505c7ca111ccf47cb323bf1f8851eb6360e8034cbff8dd149993c959de89f8f77f38e7e98b8e3076323aa719328e2b408db5ec0d03936efd57422ba04f925cdc7b4c1af7590e40ab00200009501fe044d3c5c33010400b488c3e5f83f4d561f317817538d9d0397981e9aef1321ca68ebfae1cf8b7d388e19f4b5a24a82e2fbbf1c6c26557a6c5845307a03d815756f564ac7325b02bc83e87d5480a8fae848f07cb891f2d51ce7df83dcafdc12324517c86d472cc0ee10d47a68fd1d9ae49a6c19bbd36d82af597a0d88cc9c49de9df4e696fc1f0b5d0011010001fe030302e9030f3c783e14856063f16938530e148bc57a7aa3f3e4f90df9dceccdc779bc0835e1ad3d006e4a8d7b36d08b8e0de5a0d947254ecfbd22037e6572b426bcfdc517796b224b0036ff90bc574b5509bede85512f2eefb520fb4b02aa523ba739bff424a6fe81c5041f253f8d757e69a503d3563a104d0d49e9e890b9d0c26f96b55b743883b472caa7050c4acfd4a21f875bdf1258d88bd61224d303dc9df77f743137d51e6d5246b88c406780528fd9a3e15bab5452e5b93970d9dcc79f48b38651b9f15bfbcf6da452837e9cc70683d1bdca94507870f743e4ad902005812488dd342f836e72869afd00ce1850eea4cfa53ce10e3608e13d3c149394ee3cbd0e23d018fcbcb6e2ec5a1a22972d1d462ca05355d0d290dd2751e550d5efb38c6c89686344df64852bf4ff86638708f644e8ec6bd4af9b50d8541cb91891a431326ab2e332faa7ae86cfb6e0540aa63160c1e5cdd5a4add518b303fff0a20117c6bc77f7cfbaf36b04c865c6c2b42754657374204b6579203220285253412c20656e637279707465642070726976617465206b65792988b804130102002205024d3c5c33021b03060b090807030206150802090a0b0416020301021e01021780000a0910d4984f961e35246b98940400908a73b6a6169f700434f076c6c79015a49bee37130eaf23aaa3cfa9ce60bfe4acaa7bc95f1146ada5867e0079babb38804891f4f0b8ebca57a86b249dee786161a755b7a342e68ccf3f78ed6440a93a6626beb9a37aa66afcd4f888790cb4bb46d94a4ae3eb3d7d3e6b00f6bfec940303e89ec5b32a1eaaacce66497d539328b00200009d01fe044d3c5c33010400a4e913f9442abcc7f1804ccab27d2f787ffa592077ca935a8bb23165bd8d57576acac647cc596b2c3f814518cc8c82953c7a4478f32e0cf645630a5ba38d9618ef2bc3add69d459ae3dece5cab778938d988239f8c5ae437807075e06c828019959c644ff05ef6a5a1dab72227c98e3a040b0cf219026640698d7a13d8538a570011010001fe030302e9030f3c783e148560f936097339ae381d63116efcf802ff8b1c9360767db5219cc987375702a4123fd8657d3e22700f23f95020d1b261eda5257e9a72f9a918e8ef22dd5b3323ae03bbc1923dd224db988cadc16acc04b120a9f8b7e84da9716c53e0334d7b66586ddb9014df604b41be1e960dcfcbc96f4ed150a1a0dd070b9eb14276b9b6be413a769a75b519a53d3ecc0c220e85cd91ca354d57e7344517e64b43b6e29823cbd87eae26e2b2e78e6dedfbb76e3e9f77bcb844f9a8932eb3db2c3f9e44316e6f5d60e9e2a56e46b72abe6b06dc9a31cc63f10023d1f5e12d2a3ee93b675c96f504af0001220991c88db759e231b3320dcedf814dcf723fd9857e3d72d66a0f2af26950b915abdf56c1596f46a325bf17ad4810d3535fb02a259b247ac3dbd4cc3ecf9c51b6c07cebb009c1506fba0a89321ec8683e3fd009a6e551d50243e2d5092fefb3321083a4bad91320dc624bd6b5dddf93553e3d53924c05bfebec1fb4bd47e89a1a889f04180102000905024d3c5c33021b0c000a0910d4984f961e35246b26c703ff7ee29ef53bc1ae1ead533c408fa136db508434e233d6e62be621e031e5940bbd4c08142aed0f82217e7c3e1ec8de574bc06ccf3c36633be41ad78a9eacd209f861cae7b064100758545cc9dd83db71806dc1cfd5fb9ae5c7474bba0c19c44034ae61bae5eca379383339dece94ff56ff7aa44a582f3e5c38f45763af577c0934b0020000" +const dsaElGamalTestKeysHex = "9501e1044dfcb16a110400aa3e5c1a1f43dd28c2ffae8abf5cfce555ee874134d8ba0a0f7b868ce2214beddc74e5e1e21ded354a95d18acdaf69e5e342371a71fbb9093162e0c5f3427de413a7f2c157d83f5cd2f9d791256dc4f6f0e13f13c3302af27f2384075ab3021dff7a050e14854bbde0a1094174855fc02f0bae8e00a340d94a1f22b32e48485700a0cec672ac21258fb95f61de2ce1af74b2c4fa3e6703ff698edc9be22c02ae4d916e4fa223f819d46582c0516235848a77b577ea49018dcd5e9e15cff9dbb4663a1ae6dd7580fa40946d40c05f72814b0f88481207e6c0832c3bded4853ebba0a7e3bd8e8c66df33d5a537cd4acf946d1080e7a3dcea679cb2b11a72a33a2b6a9dc85f466ad2ddf4c3db6283fa645343286971e3dd700703fc0c4e290d45767f370831a90187e74e9972aae5bff488eeff7d620af0362bfb95c1a6c3413ab5d15a2e4139e5d07a54d72583914661ed6a87cce810be28a0aa8879a2dd39e52fb6fe800f4f181ac7e328f740cde3d09a05cecf9483e4cca4253e60d4429ffd679d9996a520012aad119878c941e3cf151459873bdfc2a9563472fe0303027a728f9feb3b864260a1babe83925ce794710cfd642ee4ae0e5b9d74cee49e9c67b6cd0ea5dfbb582132195a121356a1513e1bca73e5b80c58c7ccb4164453412f456c47616d616c2054657374204b65792031886204131102002205024dfcb16a021b03060b090807030206150802090a0b0416020301021e01021780000a091033af447ccd759b09fadd00a0b8fd6f5a790bad7e9f2dbb7632046dc4493588db009c087c6a9ba9f7f49fab221587a74788c00db4889ab00200009d0157044dfcb16a1004008dec3f9291205255ccff8c532318133a6840739dd68b03ba942676f9038612071447bf07d00d559c5c0875724ea16a4c774f80d8338b55fca691a0522e530e604215b467bbc9ccfd483a1da99d7bc2648b4318fdbd27766fc8bfad3fddb37c62b8ae7ccfe9577e9b8d1e77c1d417ed2c2ef02d52f4da11600d85d3229607943700030503ff506c94c87c8cab778e963b76cf63770f0a79bf48fb49d3b4e52234620fc9f7657f9f8d56c96a2b7c7826ae6b57ebb2221a3fe154b03b6637cea7e6d98e3e45d87cf8dc432f723d3d71f89c5192ac8d7290684d2c25ce55846a80c9a7823f6acd9bb29fa6cd71f20bc90eccfca20451d0c976e460e672b000df49466408d527affe0303027a728f9feb3b864260abd761730327bca2aaa4ea0525c175e92bf240682a0e83b226f97ecb2e935b62c9a133858ce31b271fa8eb41f6a1b3cd72a63025ce1a75ee4180dcc284884904181102000905024dfcb16a021b0c000a091033af447ccd759b09dd0b009e3c3e7296092c81bee5a19929462caaf2fff3ae26009e218c437a2340e7ea628149af1ec98ec091a43992b00200009501e1044dfcb1be1104009f61faa61aa43df75d128cbe53de528c4aec49ce9360c992e70c77072ad5623de0a3a6212771b66b39a30dad6781799e92608316900518ec01184a85d872365b7d2ba4bacfb5882ea3c2473d3750dc6178cc1cf82147fb58caa28b28e9f12f6d1efcb0534abed644156c91cca4ab78834268495160b2400bc422beb37d237c2300a0cac94911b6d493bda1e1fbc6feeca7cb7421d34b03fe22cec6ccb39675bb7b94a335c2b7be888fd3906a1125f33301d8aa6ec6ee6878f46f73961c8d57a3e9544d8ef2a2cbfd4d52da665b1266928cfe4cb347a58c412815f3b2d2369dec04b41ac9a71cc9547426d5ab941cccf3b18575637ccfb42df1a802df3cfe0a999f9e7109331170e3a221991bf868543960f8c816c28097e503fe319db10fb98049f3a57d7c80c420da66d56f3644371631fad3f0ff4040a19a4fedc2d07727a1b27576f75a4d28c47d8246f27071e12d7a8de62aad216ddbae6aa02efd6b8a3e2818cda48526549791ab277e447b3a36c57cefe9b592f5eab73959743fcc8e83cbefec03a329b55018b53eec196765ae40ef9e20521a603c551efe0303020950d53a146bf9c66034d00c23130cce95576a2ff78016ca471276e8227fb30b1ffbd92e61804fb0c3eff9e30b1a826ee8f3e4730b4d86273ca977b4164453412f456c47616d616c2054657374204b65792032886204131102002205024dfcb1be021b03060b090807030206150802090a0b0416020301021e01021780000a0910a86bf526325b21b22bd9009e34511620415c974750a20df5cb56b182f3b48e6600a0a9466cb1a1305a84953445f77d461593f1d42bc1b00200009d0157044dfcb1be1004009565a951da1ee87119d600c077198f1c1bceb0f7aa54552489298e41ff788fa8f0d43a69871f0f6f77ebdfb14a4260cf9fbeb65d5844b4272a1904dd95136d06c3da745dc46327dd44a0f16f60135914368c8039a34033862261806bb2c5ce1152e2840254697872c85441ccb7321431d75a747a4bfb1d2c66362b51ce76311700030503fc0ea76601c196768070b7365a200e6ddb09307f262d5f39eec467b5f5784e22abdf1aa49226f59ab37cb49969d8f5230ea65caf56015abda62604544ed526c5c522bf92bed178a078789f6c807b6d34885688024a5bed9e9f8c58d11d4b82487b44c5f470c5606806a0443b79cadb45e0f897a561a53f724e5349b9267c75ca17fe0303020950d53a146bf9c660bc5f4ce8f072465e2d2466434320c1e712272fafc20e342fe7608101580fa1a1a367e60486a7cd1246b7ef5586cf5e10b32762b710a30144f12dd17dd4884904181102000905024dfcb1be021b0c000a0910a86bf526325b21b2904c00a0b2b66b4b39ccffda1d10f3ea8d58f827e30a8b8e009f4255b2d8112a184e40cde43a34e8655ca7809370b0020000" + const signedMessageHex = "a3019bc0cbccc0c4b8d8b74ee2108fe16ec6d3ca490cbe362d3f8333d3f352531472538b8b13d353b97232f352158c20943157c71c16064626063656269052062e4e01987e9b6fccff4b7df3a34c534b23e679cbec3bc0f8f6e64dfb4b55fe3f8efa9ce110ddb5cd79faf1d753c51aecfa669f7e7aa043436596cccc3359cb7dd6bbe9ecaa69e5989d9e57209571edc0b2fa7f57b9b79a64ee6e99ce1371395fee92fec2796f7b15a77c386ff668ee27f6d38f0baa6c438b561657377bf6acff3c5947befd7bf4c196252f1d6e5c524d0300" const signedTextMessageHex = "a3019bc0cbccc8c4b8d8b74ee2108fe16ec6d36a250cbece0c178233d3f352531472538b8b13d35379b97232f352158ca0b4312f57c71c1646462606365626906a062e4e019811591798ff99bf8afee860b0d8a8c2a85c3387e3bcf0bb3b17987f2bbcfab2aa526d930cbfd3d98757184df3995c9f3e7790e36e3e9779f06089d4c64e9e47dd6202cb6e9bc73c5d11bb59fbaf89d22d8dc7cf199ddf17af96e77c5f65f9bbed56f427bd8db7af37f6c9984bf9385efaf5f184f986fb3e6adb0ecfe35bbf92d16a7aa2a344fb0bc52fb7624f0200" const signedEncryptedMessageHex = "848c032a67d68660df41c70103ff5789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8d2c03b018bd210b1d3791e1aba74b0f1034e122ab72e760492c192383cf5e20b5628bd043272d63df9b923f147eb6091cd897553204832aba48fec54aa447547bb16305a1024713b90e77fd0065f1918271947549205af3c74891af22ee0b56cd29bfec6d6e351901cd4ab3ece7c486f1e32a792d4e474aed98ee84b3f591c7dff37b64e0ecd68fd036d517e412dcadf85840ce184ad7921ad446c4ee28db80447aea1ca8d4f574db4d4e37688158ddd19e14ee2eab4873d46947d65d14a23e788d912cf9a19624ca7352469b72a83866b7c23cb5ace3deab3c7018061b0ba0f39ed2befe27163e5083cf9b8271e3e3d52cc7ad6e2a3bd81d4c3d7022f8d" +const signedEncryptedMessage2Hex = "85010e03cf6a7abcd43e36731003fb057f5495b79db367e277cdbe4ab90d924ddee0c0381494112ff8c1238fb0184af35d1731573b01bc4c55ecacd2aafbe2003d36310487d1ecc9ac994f3fada7f9f7f5c3a64248ab7782906c82c6ff1303b69a84d9a9529c31ecafbcdb9ba87e05439897d87e8a2a3dec55e14df19bba7f7bd316291c002ae2efd24f83f9e3441203fc081c0c23dc3092a454ca8a082b27f631abf73aca341686982e8fbda7e0e7d863941d68f3de4a755c2964407f4b5e0477b3196b8c93d551dd23c8beef7d0f03fbb1b6066f78907faf4bf1677d8fcec72651124080e0b7feae6b476e72ab207d38d90b958759fdedfc3c6c35717c9dbfc979b3cfbbff0a76d24a5e57056bb88acbd2a901ef64bc6e4db02adc05b6250ff378de81dca18c1910ab257dff1b9771b85bb9bbe0a69f5989e6d1710a35e6dfcceb7d8fb5ccea8db3932b3d9ff3fe0d327597c68b3622aec8e3716c83a6c93f497543b459b58ba504ed6bcaa747d37d2ca746fe49ae0a6ce4a8b694234e941b5159ff8bd34b9023da2814076163b86f40eed7c9472f81b551452d5ab87004a373c0172ec87ea6ce42ccfa7dbdad66b745496c4873d8019e8c28d6b3" + const symmetricallyEncryptedCompressedHex = "8c0d04030302eb4a03808145d0d260c92f714339e13de5a79881216431925bf67ee2898ea61815f07894cd0703c50d0a76ef64d482196f47a8bc729af9b80bb6" const dsaTestKeyHex = "9901a2044d6c49de110400cb5ce438cf9250907ac2ba5bf6547931270b89f7c4b53d9d09f4d0213a5ef2ec1f26806d3d259960f872a4a102ef1581ea3f6d6882d15134f21ef6a84de933cc34c47cc9106efe3bd84c6aec12e78523661e29bc1a61f0aab17fa58a627fd5fd33f5149153fbe8cd70edf3d963bc287ef875270ff14b5bfdd1bca4483793923b00a0fe46d76cb6e4cbdc568435cd5480af3266d610d303fe33ae8273f30a96d4d34f42fa28ce1112d425b2e3bf7ea553d526e2db6b9255e9dc7419045ce817214d1a0056dbc8d5289956a4b1b69f20f1105124096e6a438f41f2e2495923b0f34b70642607d45559595c7fe94d7fa85fc41bf7d68c1fd509ebeaa5f315f6059a446b9369c277597e4f474a9591535354c7e7f4fd98a08aa60400b130c24ff20bdfbf683313f5daebf1c9b34b3bdadfc77f2ddd72ee1fb17e56c473664bc21d66467655dd74b9005e3a2bacce446f1920cd7017231ae447b67036c9b431b8179deacd5120262d894c26bc015bffe3d827ba7087ad9b700d2ca1f6d16cc1786581e5dd065f293c31209300f9b0afcc3f7c08dd26d0a22d87580b4db41054657374204b65792033202844534129886204131102002205024d6c49de021b03060b090807030206150802090a0b0416020301021e01021780000a0910338934250ccc03607e0400a0bdb9193e8a6b96fc2dfc108ae848914b504481f100a09c4dc148cb693293a67af24dd40d2b13a9e36794" diff --git a/libgo/go/crypto/openpgp/s2k/s2k.go b/libgo/go/crypto/openpgp/s2k/s2k.go index 93b7582..da926a7 100644 --- a/libgo/go/crypto/openpgp/s2k/s2k.go +++ b/libgo/go/crypto/openpgp/s2k/s2k.go @@ -90,7 +90,7 @@ func Parse(r io.Reader) (f func(out, in []byte), err os.Error) { } h := hash.New() if h == nil { - return nil, error.UnsupportedError("hash not availible: " + strconv.Itoa(int(hash))) + return nil, error.UnsupportedError("hash not available: " + strconv.Itoa(int(hash))) } switch buf[0] { @@ -123,6 +123,26 @@ func Parse(r io.Reader) (f func(out, in []byte), err os.Error) { return nil, error.UnsupportedError("S2K function") } +// Serialize salts and stretches the given passphrase and writes the resulting +// key into key. It also serializes an S2K descriptor to w. +func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte) os.Error { + var buf [11]byte + buf[0] = 3 /* iterated and salted */ + buf[1], _ = HashToHashId(crypto.SHA1) + salt := buf[2:10] + if _, err := io.ReadFull(rand, salt); err != nil { + return err + } + const count = 65536 // this is the default in gpg + buf[10] = 96 // 65536 iterations + if _, err := w.Write(buf[:]); err != nil { + return err + } + + Iterated(key, crypto.SHA1.New(), passphrase, salt, count) + return nil +} + // hashToHashIdMapping contains pairs relating OpenPGP's hash identifier with // Go's crypto.Hash type. See RFC 4880, section 9.4. var hashToHashIdMapping = []struct { diff --git a/libgo/go/crypto/openpgp/s2k/s2k_test.go b/libgo/go/crypto/openpgp/s2k/s2k_test.go index 75bc47e..ec4012c 100644 --- a/libgo/go/crypto/openpgp/s2k/s2k_test.go +++ b/libgo/go/crypto/openpgp/s2k/s2k_test.go @@ -7,6 +7,7 @@ package s2k import ( "bytes" "crypto/sha1" + "crypto/rand" "encoding/hex" "testing" ) @@ -36,7 +37,6 @@ func TestSalted(t *testing.T) { } } - var iteratedTests = []struct { in, out string }{ @@ -62,7 +62,6 @@ func TestIterated(t *testing.T) { } } - var parseTests = []struct { spec, in, out string }{ @@ -95,3 +94,25 @@ func TestParse(t *testing.T) { } } } + +func TestSerialize(t *testing.T) { + buf := bytes.NewBuffer(nil) + key := make([]byte, 16) + passphrase := []byte("testing") + err := Serialize(buf, key, rand.Reader, passphrase) + if err != nil { + t.Errorf("failed to serialize: %s", err) + return + } + + f, err := Parse(buf) + if err != nil { + t.Errorf("failed to reparse: %s", err) + return + } + key2 := make([]byte, len(key)) + f(key2, passphrase) + if !bytes.Equal(key2, key) { + t.Errorf("keys don't match: %x (serialied) vs %x (parsed)", key, key2) + } +} diff --git a/libgo/go/crypto/openpgp/write.go b/libgo/go/crypto/openpgp/write.go index ef7b112..9884472c 100644 --- a/libgo/go/crypto/openpgp/write.go +++ b/libgo/go/crypto/openpgp/write.go @@ -6,12 +6,13 @@ package openpgp import ( "crypto" - "crypto/dsa" "crypto/openpgp/armor" "crypto/openpgp/error" "crypto/openpgp/packet" - "crypto/rsa" + "crypto/openpgp/s2k" + "crypto/rand" _ "crypto/sha256" + "hash" "io" "os" "strconv" @@ -77,20 +78,231 @@ func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.S } io.Copy(wrappedHash, message) - switch signer.PrivateKey.PubKeyAlgo { - 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))) + err = sig.Sign(h, signer.PrivateKey) + if err != nil { + return + } + + return sig.Serialize(w) +} + +// FileHints contains metadata about encrypted files. This metadata is, itself, +// encrypted. +type FileHints struct { + // IsBinary can be set to hint that the contents are binary data. + IsBinary bool + // FileName hints at the name of the file that should be written. It's + // truncated to 255 bytes if longer. It may be empty to suggest that the + // file should not be written to disk. It may be equal to "_CONSOLE" to + // suggest the data should not be written to disk. + FileName string + // EpochSeconds contains the modification time of the file, or 0 if not applicable. + EpochSeconds uint32 +} + +// SymmetricallyEncrypt acts like gpg -c: it encrypts a file with a passphrase. +// The resulting WriteCloser must be closed after the contents of the file have +// been written. +func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHints) (plaintext io.WriteCloser, err os.Error) { + if hints == nil { + hints = &FileHints{} } + key, err := packet.SerializeSymmetricKeyEncrypted(ciphertext, rand.Reader, passphrase, packet.CipherAES128) if err != nil { return } + w, err := packet.SerializeSymmetricallyEncrypted(ciphertext, packet.CipherAES128, key) + if err != nil { + return + } + return packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, hints.EpochSeconds) +} - return sig.Serialize(w) +// intersectPreferences mutates and returns a prefix of a that contains only +// the values in the intersection of a and b. The order of a is preserved. +func intersectPreferences(a []uint8, b []uint8) (intersection []uint8) { + var j int + for _, v := range a { + for _, v2 := range b { + if v == v2 { + a[j] = v + j++ + break + } + } + } + + return a[:j] +} + +func hashToHashId(h crypto.Hash) uint8 { + v, ok := s2k.HashToHashId(h) + if !ok { + panic("tried to convert unknown hash") + } + return v +} + +// Encrypt encrypts a message to a number of recipients and, optionally, signs +// it. hints contains optional information, that is also encrypted, that aids +// the recipients in processing the message. The resulting WriteCloser must +// be closed after the contents of the file have been written. +func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints) (plaintext io.WriteCloser, err os.Error) { + var signer *packet.PrivateKey + if signed != nil { + signer = signed.signingKey().PrivateKey + if signer == nil || signer.Encrypted { + return nil, error.InvalidArgumentError("signing key must be decrypted") + } + } + + // These are the possible ciphers that we'll use for the message. + candidateCiphers := []uint8{ + uint8(packet.CipherAES128), + uint8(packet.CipherAES256), + uint8(packet.CipherCAST5), + } + // These are the possible hash functions that we'll use for the signature. + candidateHashes := []uint8{ + hashToHashId(crypto.SHA256), + hashToHashId(crypto.SHA512), + hashToHashId(crypto.SHA1), + hashToHashId(crypto.RIPEMD160), + } + // In the event that a recipient doesn't specify any supported ciphers + // or hash functions, these are the ones that we assume that every + // implementation supports. + defaultCiphers := candidateCiphers[len(candidateCiphers)-1:] + defaultHashes := candidateHashes[len(candidateHashes)-1:] + + encryptKeys := make([]Key, len(to)) + for i := range to { + encryptKeys[i] = to[i].encryptionKey() + if encryptKeys[i].PublicKey == nil { + return nil, error.InvalidArgumentError("cannot encrypt a message to key id " + strconv.Uitob64(to[i].PrimaryKey.KeyId, 16) + " because it has no encryption keys") + } + + sig := to[i].primaryIdentity().SelfSignature + + preferredSymmetric := sig.PreferredSymmetric + if len(preferredSymmetric) == 0 { + preferredSymmetric = defaultCiphers + } + preferredHashes := sig.PreferredHash + if len(preferredHashes) == 0 { + preferredHashes = defaultHashes + } + candidateCiphers = intersectPreferences(candidateCiphers, preferredSymmetric) + candidateHashes = intersectPreferences(candidateHashes, preferredHashes) + } + + if len(candidateCiphers) == 0 || len(candidateHashes) == 0 { + return nil, error.InvalidArgumentError("cannot encrypt because recipient set shares no common algorithms") + } + + cipher := packet.CipherFunction(candidateCiphers[0]) + hash, _ := s2k.HashIdToHash(candidateHashes[0]) + symKey := make([]byte, cipher.KeySize()) + if _, err := io.ReadFull(rand.Reader, symKey); err != nil { + return nil, err + } + + for _, key := range encryptKeys { + if err := packet.SerializeEncryptedKey(ciphertext, rand.Reader, key.PublicKey, cipher, symKey); err != nil { + return nil, err + } + } + + encryptedData, err := packet.SerializeSymmetricallyEncrypted(ciphertext, cipher, symKey) + if err != nil { + return + } + + if signer != nil { + ops := &packet.OnePassSignature{ + SigType: packet.SigTypeBinary, + Hash: hash, + PubKeyAlgo: signer.PubKeyAlgo, + KeyId: signer.KeyId, + IsLast: true, + } + if err := ops.Serialize(encryptedData); err != nil { + return nil, err + } + } + + if hints == nil { + hints = &FileHints{} + } + + w := encryptedData + if signer != nil { + // If we need to write a signature packet after the literal + // data then we need to stop literalData from closing + // encryptedData. + w = noOpCloser{encryptedData} + + } + literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, hints.EpochSeconds) + if err != nil { + return nil, err + } + + if signer != nil { + return signatureWriter{encryptedData, literalData, hash, hash.New(), signer}, nil + } + return literalData, nil +} + +// signatureWriter hashes the contents of a message while passing it along to +// literalData. When closed, it closes literalData, writes a signature packet +// to encryptedData and then also closes encryptedData. +type signatureWriter struct { + encryptedData io.WriteCloser + literalData io.WriteCloser + hashType crypto.Hash + h hash.Hash + signer *packet.PrivateKey +} + +func (s signatureWriter) Write(data []byte) (int, os.Error) { + s.h.Write(data) + return s.literalData.Write(data) +} + +func (s signatureWriter) Close() os.Error { + sig := &packet.Signature{ + SigType: packet.SigTypeBinary, + PubKeyAlgo: s.signer.PubKeyAlgo, + Hash: s.hashType, + CreationTime: uint32(time.Seconds()), + IssuerKeyId: &s.signer.KeyId, + } + + if err := sig.Sign(s.h, s.signer); err != nil { + return err + } + if err := s.literalData.Close(); err != nil { + return err + } + if err := sig.Serialize(s.encryptedData); err != nil { + return err + } + return s.encryptedData.Close() +} + +// noOpCloser is like an ioutil.NopCloser, but for an io.Writer. +// TODO: we have two of these in OpenPGP packages alone. This probably needs +// to be promoted somewhere more common. +type noOpCloser struct { + w io.Writer +} + +func (c noOpCloser) Write(data []byte) (n int, err os.Error) { + return c.w.Write(data) +} + +func (c noOpCloser) Close() os.Error { + return nil } diff --git a/libgo/go/crypto/openpgp/write_test.go b/libgo/go/crypto/openpgp/write_test.go index 42cd0d2..c542dfa 100644 --- a/libgo/go/crypto/openpgp/write_test.go +++ b/libgo/go/crypto/openpgp/write_test.go @@ -6,7 +6,12 @@ package openpgp import ( "bytes" + "crypto/rand" + "os" + "io" + "io/ioutil" "testing" + "time" ) func TestSignDetached(t *testing.T) { @@ -44,3 +49,185 @@ func TestSignDetachedDSA(t *testing.T) { testDetachedSignature(t, kring, out, signedInput, "check", testKey3KeyId) } + +func TestNewEntity(t *testing.T) { + if testing.Short() { + return + } + + e, err := NewEntity(rand.Reader, time.Seconds(), "Test User", "test", "test@example.com") + if err != nil { + t.Errorf("failed to create entity: %s", err) + return + } + + w := bytes.NewBuffer(nil) + if err := e.SerializePrivate(w); err != nil { + t.Errorf("failed to serialize entity: %s", err) + return + } + serialized := w.Bytes() + + el, err := ReadKeyRing(w) + if err != nil { + t.Errorf("failed to reparse entity: %s", err) + return + } + + if len(el) != 1 { + t.Errorf("wrong number of entities found, got %d, want 1", len(el)) + } + + w = bytes.NewBuffer(nil) + if err := e.SerializePrivate(w); err != nil { + t.Errorf("failed to serialize entity second time: %s", err) + return + } + + if !bytes.Equal(w.Bytes(), serialized) { + t.Errorf("results differed") + } +} + +func TestSymmetricEncryption(t *testing.T) { + buf := new(bytes.Buffer) + plaintext, err := SymmetricallyEncrypt(buf, []byte("testing"), nil) + if err != nil { + t.Errorf("error writing headers: %s", err) + return + } + message := []byte("hello world\n") + _, err = plaintext.Write(message) + if err != nil { + t.Errorf("error writing to plaintext writer: %s", err) + } + err = plaintext.Close() + if err != nil { + t.Errorf("error closing plaintext writer: %s", err) + } + + md, err := ReadMessage(buf, nil, func(keys []Key, symmetric bool) ([]byte, os.Error) { + return []byte("testing"), nil + }) + if err != nil { + t.Errorf("error rereading message: %s", err) + } + messageBuf := bytes.NewBuffer(nil) + _, err = io.Copy(messageBuf, md.UnverifiedBody) + if err != nil { + t.Errorf("error rereading message: %s", err) + } + if !bytes.Equal(message, messageBuf.Bytes()) { + t.Errorf("recovered message incorrect got '%s', want '%s'", messageBuf.Bytes(), message) + } +} + +var testEncryptionTests = []struct { + keyRingHex string + isSigned bool +}{ + { + testKeys1And2PrivateHex, + false, + }, + { + testKeys1And2PrivateHex, + true, + }, + { + dsaElGamalTestKeysHex, + false, + }, + { + dsaElGamalTestKeysHex, + true, + }, +} + +func TestEncryption(t *testing.T) { + for i, test := range testEncryptionTests { + kring, _ := ReadKeyRing(readerFromHex(test.keyRingHex)) + + passphrase := []byte("passphrase") + for _, entity := range kring { + if entity.PrivateKey != nil && entity.PrivateKey.Encrypted { + err := entity.PrivateKey.Decrypt(passphrase) + if err != nil { + t.Errorf("#%d: failed to decrypt key", i) + } + } + for _, subkey := range entity.Subkeys { + if subkey.PrivateKey != nil && subkey.PrivateKey.Encrypted { + err := subkey.PrivateKey.Decrypt(passphrase) + if err != nil { + t.Errorf("#%d: failed to decrypt subkey", i) + } + } + } + } + + var signed *Entity + if test.isSigned { + signed = kring[0] + } + + buf := new(bytes.Buffer) + w, err := Encrypt(buf, kring[:1], signed, nil /* no hints */ ) + if err != nil { + t.Errorf("#%d: error in Encrypt: %s", i, err) + continue + } + + const message = "testing" + _, err = w.Write([]byte(message)) + if err != nil { + t.Errorf("#%d: error writing plaintext: %s", i, err) + continue + } + err = w.Close() + if err != nil { + t.Errorf("#%d: error closing WriteCloser: %s", i, err) + continue + } + + md, err := ReadMessage(buf, kring, nil /* no prompt */ ) + if err != nil { + t.Errorf("#%d: error reading message: %s", i, err) + continue + } + + if test.isSigned { + expectedKeyId := kring[0].signingKey().PublicKey.KeyId + if md.SignedByKeyId != expectedKeyId { + t.Errorf("#%d: message signed by wrong key id, got: %d, want: %d", i, *md.SignedBy, expectedKeyId) + } + if md.SignedBy == nil { + t.Errorf("#%d: failed to find the signing Entity", i) + } + } + + plaintext, err := ioutil.ReadAll(md.UnverifiedBody) + if err != nil { + t.Errorf("#%d: error reading encrypted contents: %s", i, err) + continue + } + + expectedKeyId := kring[0].encryptionKey().PublicKey.KeyId + if len(md.EncryptedToKeyIds) != 1 || md.EncryptedToKeyIds[0] != expectedKeyId { + t.Errorf("#%d: expected message to be encrypted to %v, but got %#v", i, expectedKeyId, md.EncryptedToKeyIds) + } + + if string(plaintext) != message { + t.Errorf("#%d: got: %s, want: %s", i, string(plaintext), message) + } + + if test.isSigned { + if md.SignatureError != nil { + t.Errorf("#%d: signature error: %s", i, err) + } + if md.Signature == nil { + t.Error("signature missing") + } + } + } +} diff --git a/libgo/go/crypto/rand/rand_windows.go b/libgo/go/crypto/rand/rand_windows.go index 281d6dc..0eab6b2 100644 --- a/libgo/go/crypto/rand/rand_windows.go +++ b/libgo/go/crypto/rand/rand_windows.go @@ -19,7 +19,7 @@ func init() { Reader = &rngReader{} } // A rngReader satisfies reads by reading from the Windows CryptGenRandom API. type rngReader struct { - prov uint32 + prov syscall.Handle mu sync.Mutex } diff --git a/libgo/go/crypto/rand/util.go b/libgo/go/crypto/rand/util.go new file mode 100644 index 0000000..7702847 --- /dev/null +++ b/libgo/go/crypto/rand/util.go @@ -0,0 +1,80 @@ +// 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 rand + +import ( + "big" + "io" + "os" +) + +// Prime returns a number, p, of the given size, such that p is prime +// with high probability. +func Prime(rand io.Reader, bits int) (p *big.Int, err os.Error) { + if bits < 1 { + err = os.EINVAL + } + + b := uint(bits % 8) + if b == 0 { + b = 8 + } + + bytes := make([]byte, (bits+7)/8) + p = new(big.Int) + + for { + _, err = io.ReadFull(rand, bytes) + if err != nil { + return nil, err + } + + // Clear bits in the first byte to make sure the candidate has a size <= bits. + bytes[0] &= uint8(int(1<= 2 elements. // Precomputed contains precomputed values that speed up private - // operations, if availible. + // operations, if available. Precomputed PrecomputedValues } @@ -126,7 +64,7 @@ func (priv *PrivateKey) Validate() os.Error { // easy for an attack to generate composites that pass this test. for _, prime := range priv.Primes { if !big.ProbablyPrime(prime, 20) { - return os.ErrorString("Prime factor is composite") + return os.NewError("prime factor is composite") } } @@ -136,7 +74,7 @@ func (priv *PrivateKey) Validate() os.Error { modulus.Mul(modulus, prime) } if modulus.Cmp(priv.N) != 0 { - return os.ErrorString("invalid modulus") + return os.NewError("invalid modulus") } // Check that e and totient(Πprimes) are coprime. totient := new(big.Int).Set(bigOne) @@ -150,20 +88,20 @@ func (priv *PrivateKey) Validate() os.Error { y := new(big.Int) big.GcdInt(gcd, x, y, totient, e) if gcd.Cmp(bigOne) != 0 { - return os.ErrorString("invalid public exponent E") + return os.NewError("invalid public exponent E") } // Check that de ≡ 1 (mod totient(Πprimes)) de := new(big.Int).Mul(priv.D, e) de.Mod(de, totient) if de.Cmp(bigOne) != 0 { - return os.ErrorString("invalid private exponent D") + return os.NewError("invalid private exponent D") } return nil } // GenerateKey generates an RSA keypair of the given bit size. -func GenerateKey(rand io.Reader, bits int) (priv *PrivateKey, err os.Error) { - return GenerateMultiPrimeKey(rand, 2, bits) +func GenerateKey(random io.Reader, bits int) (priv *PrivateKey, err os.Error) { + return GenerateMultiPrimeKey(random, 2, bits) } // GenerateMultiPrimeKey generates a multi-prime RSA keypair of the given bit @@ -176,7 +114,7 @@ func GenerateKey(rand io.Reader, bits int) (priv *PrivateKey, err os.Error) { // // [1] US patent 4405829 (1972, expired) // [2] http://www.cacr.math.uwaterloo.ca/techreports/2006/cacr2006-16.pdf -func GenerateMultiPrimeKey(rand io.Reader, nprimes int, bits int) (priv *PrivateKey, err os.Error) { +func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (priv *PrivateKey, err os.Error) { priv = new(PrivateKey) // Smaller public exponents lead to faster public key // operations. Since the exponent must be coprime to @@ -189,7 +127,7 @@ func GenerateMultiPrimeKey(rand io.Reader, nprimes int, bits int) (priv *Private priv.E = 3 if nprimes < 2 { - return nil, os.ErrorString("rsa.GenerateMultiPrimeKey: nprimes must be >= 2") + return nil, os.NewError("rsa.GenerateMultiPrimeKey: nprimes must be >= 2") } primes := make([]*big.Int, nprimes) @@ -198,7 +136,7 @@ NextSetOfPrimes: for { todo := bits for i := 0; i < nprimes; i++ { - primes[i], err = randomPrime(rand, todo/(nprimes-i)) + primes[i], err = rand.Prime(random, todo/(nprimes-i)) if err != nil { return nil, err } @@ -293,7 +231,7 @@ func encrypt(c *big.Int, pub *PublicKey, m *big.Int) *big.Int { // EncryptOAEP encrypts the given message with RSA-OAEP. // The message must be no longer than the length of the public modulus less // twice the hash length plus 2. -func EncryptOAEP(hash hash.Hash, rand io.Reader, pub *PublicKey, msg []byte, label []byte) (out []byte, err os.Error) { +func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) (out []byte, err os.Error) { hash.Reset() k := (pub.N.BitLen() + 7) / 8 if len(msg) > k-2*hash.Size()-2 { @@ -313,7 +251,7 @@ func EncryptOAEP(hash hash.Hash, rand io.Reader, pub *PublicKey, msg []byte, lab db[len(db)-len(msg)-1] = 1 copy(db[len(db)-len(msg):], msg) - _, err = io.ReadFull(rand, seed) + _, err = io.ReadFull(random, seed) if err != nil { return } @@ -405,7 +343,7 @@ func (priv *PrivateKey) Precompute() { // decrypt performs an RSA decryption, resulting in a plaintext integer. If a // random source is given, RSA blinding is used. -func decrypt(rand io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err os.Error) { +func decrypt(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err os.Error) { // TODO(agl): can we get away with reusing blinds? if c.Cmp(priv.N) > 0 { err = DecryptionError{} @@ -413,16 +351,16 @@ func decrypt(rand io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err os.E } var ir *big.Int - if rand != nil { + if random != nil { // Blinding enabled. Blinding involves multiplying c by r^e. // Then the decryption operation performs (m^e * r^e)^d mod n // which equals mr mod n. The factor of r can then be removed - // by multipling by the multiplicative inverse of r. + // by multiplying by the multiplicative inverse of r. var r *big.Int for { - r, err = randomNumber(rand, priv.N) + r, err = rand.Int(random, priv.N) if err != nil { return } @@ -483,7 +421,7 @@ func decrypt(rand io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err os.E // DecryptOAEP decrypts ciphertext using RSA-OAEP. // If rand != nil, DecryptOAEP uses RSA blinding to avoid timing side-channel attacks. -func DecryptOAEP(hash hash.Hash, rand io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) (msg []byte, err os.Error) { +func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) (msg []byte, err os.Error) { k := (priv.N.BitLen() + 7) / 8 if len(ciphertext) > k || k < hash.Size()*2+2 { @@ -493,7 +431,7 @@ func DecryptOAEP(hash hash.Hash, rand io.Reader, priv *PrivateKey, ciphertext [] c := new(big.Int).SetBytes(ciphertext) - m, err := decrypt(rand, priv, c) + m, err := decrypt(random, priv, c) if err != nil { return } diff --git a/libgo/go/crypto/subtle/constant_time_test.go b/libgo/go/crypto/subtle/constant_time_test.go index b28b735..adab8e2 100644 --- a/libgo/go/crypto/subtle/constant_time_test.go +++ b/libgo/go/crypto/subtle/constant_time_test.go @@ -14,14 +14,14 @@ type TestConstantTimeCompareStruct struct { out int } -var testConstandTimeCompareData = []TestConstantTimeCompareStruct{ +var testConstantTimeCompareData = []TestConstantTimeCompareStruct{ {[]byte{}, []byte{}, 1}, {[]byte{0x11}, []byte{0x11}, 1}, {[]byte{0x12}, []byte{0x11}, 0}, } func TestConstantTimeCompare(t *testing.T) { - for i, test := range testConstandTimeCompareData { + for i, test := range testConstantTimeCompareData { if r := ConstantTimeCompare(test.a, test.b); r != test.out { t.Errorf("#%d bad result (got %x, want %x)", i, r, test.out) } diff --git a/libgo/go/crypto/tls/common.go b/libgo/go/crypto/tls/common.go index 0b26aae..3efac9c 100644 --- a/libgo/go/crypto/tls/common.go +++ b/libgo/go/crypto/tls/common.go @@ -87,7 +87,7 @@ const ( certTypeRSASign = 1 // A certificate containing an RSA key certTypeDSSSign = 2 // A certificate containing a DSA key certTypeRSAFixedDH = 3 // A certificate containing a static DH key - certTypeDSSFixedDH = 4 // A certficiate containing a static DH key + certTypeDSSFixedDH = 4 // A certificate containing a static DH key // Rest of these are reserved by the TLS spec ) diff --git a/libgo/go/crypto/tls/conn.go b/libgo/go/crypto/tls/conn.go index 48d3f72..fac65af 100644 --- a/libgo/go/crypto/tls/conn.go +++ b/libgo/go/crypto/tls/conn.go @@ -34,7 +34,7 @@ type Conn struct { cipherSuite uint16 ocspResponse []byte // stapled OCSP response peerCertificates []*x509.Certificate - // verifedChains contains the certificate chains that we built, as + // verifiedChains contains the certificate chains that we built, as // opposed to the ones presented by the server. verifiedChains [][]*x509.Certificate @@ -237,7 +237,7 @@ func (hc *halfConn) decrypt(b *block) (bool, alert) { // "Password Interception in a SSL/TLS Channel", Brice // Canvel et al. // - // However, our behaviour matches OpenSSL, so we leak + // However, our behavior matches OpenSSL, so we leak // only as much as they do. default: panic("unknown cipher type") @@ -410,7 +410,7 @@ func (hc *halfConn) freeBlock(b *block) { // splitBlock splits a block after the first n bytes, // returning a block with those n bytes and a -// block with the remaindec. the latter may be nil. +// block with the remainder. the latter may be nil. func (hc *halfConn) splitBlock(b *block, n int) (*block, *block) { if len(b.data) <= n { return b, nil @@ -790,10 +790,10 @@ func (c *Conn) VerifyHostname(host string) os.Error { c.handshakeMutex.Lock() defer c.handshakeMutex.Unlock() if !c.isClient { - return os.ErrorString("VerifyHostname called on TLS server connection") + return os.NewError("VerifyHostname called on TLS server connection") } if !c.handshakeComplete { - return os.ErrorString("TLS handshake has not yet been performed") + return os.NewError("TLS handshake has not yet been performed") } return c.peerCertificates[0].VerifyHostname(host) } diff --git a/libgo/go/crypto/tls/generate_cert.go b/libgo/go/crypto/tls/generate_cert.go index 5b8c700..41206e2 100644 --- a/libgo/go/crypto/tls/generate_cert.go +++ b/libgo/go/crypto/tls/generate_cert.go @@ -8,8 +8,10 @@ package main import ( - "crypto/rsa" + "big" + "crypto/x509/pkix" "crypto/rand" + "crypto/rsa" "crypto/x509" "encoding/pem" "flag" @@ -32,8 +34,8 @@ func main() { now := time.Seconds() template := x509.Certificate{ - SerialNumber: []byte{0}, - Subject: x509.Name{ + SerialNumber: new(big.Int).SetInt64(0), + Subject: pkix.Name{ CommonName: *hostName, Organization: []string{"Acme Co"}, }, @@ -59,7 +61,7 @@ func main() { certOut.Close() log.Print("written cert.pem\n") - keyOut, err := os.OpenFile("key.pem", os.O_WRONLY|os.O_CREAT|os.O_TRUNC, 0600) + keyOut, err := os.OpenFile("key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) if err != nil { log.Print("failed to open key.pem for writing:", err) return diff --git a/libgo/go/crypto/tls/handshake_client.go b/libgo/go/crypto/tls/handshake_client.go index c758c96..15604ce 100644 --- a/libgo/go/crypto/tls/handshake_client.go +++ b/libgo/go/crypto/tls/handshake_client.go @@ -40,7 +40,7 @@ func (c *Conn) clientHandshake() os.Error { _, err := io.ReadFull(c.config.rand(), hello.random[4:]) if err != nil { c.sendAlert(alertInternalError) - return os.ErrorString("short read from Rand") + return os.NewError("short read from Rand") } finishedHash.Write(hello.marshal()) @@ -69,7 +69,7 @@ func (c *Conn) clientHandshake() os.Error { if !hello.nextProtoNeg && serverHello.nextProtoNeg { c.sendAlert(alertHandshakeFailure) - return os.ErrorString("server advertised unrequested NPN") + return os.NewError("server advertised unrequested NPN") } suite, suiteId := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite) @@ -92,7 +92,7 @@ func (c *Conn) clientHandshake() os.Error { cert, err := x509.ParseCertificate(asn1Data) if err != nil { c.sendAlert(alertBadCertificate) - return os.ErrorString("failed to parse certificate from server: " + err.String()) + return os.NewError("failed to parse certificate from server: " + err.String()) } certs[i] = cert } diff --git a/libgo/go/crypto/tls/handshake_server.go b/libgo/go/crypto/tls/handshake_server.go index 37c8d15..44a3240 100644 --- a/libgo/go/crypto/tls/handshake_server.go +++ b/libgo/go/crypto/tls/handshake_server.go @@ -173,7 +173,7 @@ FindCipherSuite: cert, err := x509.ParseCertificate(asn1Data) if err != nil { c.sendAlert(alertBadCertificate) - return os.ErrorString("could not parse client's certificate: " + err.String()) + return os.NewError("could not parse client's certificate: " + err.String()) } certs[i] = cert } @@ -182,7 +182,7 @@ FindCipherSuite: for i := 1; i < len(certs); i++ { if err := certs[i-1].CheckSignatureFrom(certs[i]); err != nil { c.sendAlert(alertBadCertificate) - return os.ErrorString("could not validate certificate signature: " + err.String()) + return os.NewError("could not validate certificate signature: " + err.String()) } } @@ -209,10 +209,10 @@ FindCipherSuite: // If we received a client cert in response to our certificate request message, // the client will send us a certificateVerifyMsg immediately after the - // clientKeyExchangeMsg. This message is a MD5SHA1 digest of all preceeding + // clientKeyExchangeMsg. This message is a MD5SHA1 digest of all preceding // handshake-layer messages that is signed using the private key corresponding // to the client's certificate. This allows us to verify that the client is in - // posession of the private key of the certificate. + // possession of the private key of the certificate. if len(c.peerCertificates) > 0 { msg, err = c.readHandshake() if err != nil { @@ -229,7 +229,7 @@ FindCipherSuite: err = rsa.VerifyPKCS1v15(pub, crypto.MD5SHA1, digest, certVerify.signature) if err != nil { c.sendAlert(alertBadCertificate) - return os.ErrorString("could not validate signature of connection nonces: " + err.String()) + return os.NewError("could not validate signature of connection nonces: " + err.String()) } finishedHash.Write(certVerify.marshal()) diff --git a/libgo/go/crypto/tls/handshake_server_test.go b/libgo/go/crypto/tls/handshake_server_test.go index 5a1e754..b77646e 100644 --- a/libgo/go/crypto/tls/handshake_server_test.go +++ b/libgo/go/crypto/tls/handshake_server_test.go @@ -106,7 +106,6 @@ func TestClose(t *testing.T) { } } - func testServerScript(t *testing.T, name string, serverScript [][]byte, config *Config) { c, s := net.Pipe() srv := Server(s, config) diff --git a/libgo/go/crypto/tls/key_agreement.go b/libgo/go/crypto/tls/key_agreement.go index 8edbb11..a40d18f 100644 --- a/libgo/go/crypto/tls/key_agreement.go +++ b/libgo/go/crypto/tls/key_agreement.go @@ -32,11 +32,11 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKe } if len(ckx.ciphertext) < 2 { - return nil, os.ErrorString("bad ClientKeyExchange") + return nil, os.NewError("bad ClientKeyExchange") } ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1]) if ciphertextLen != len(ckx.ciphertext)-2 { - return nil, os.ErrorString("bad ClientKeyExchange") + return nil, os.NewError("bad ClientKeyExchange") } ciphertext := ckx.ciphertext[2:] @@ -54,7 +54,7 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKe } func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) os.Error { - return os.ErrorString("unexpected ServerKeyExchange") + return os.NewError("unexpected ServerKeyExchange") } func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, os.Error) { @@ -78,7 +78,6 @@ func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello return preMasterSecret, ckx, nil } - // md5SHA1Hash implements TLS 1.0's hybrid hash function which consists of the // concatenation of an MD5 and SHA1 hash. func md5SHA1Hash(slices ...[]byte) []byte { @@ -146,7 +145,7 @@ Curve: md5sha1 := md5SHA1Hash(clientHello.random, hello.random, serverECDHParams) sig, err := rsa.SignPKCS1v15(config.rand(), config.Certificates[0].PrivateKey, crypto.MD5SHA1, md5sha1) if err != nil { - return nil, os.ErrorString("failed to sign ECDHE parameters: " + err.String()) + return nil, os.NewError("failed to sign ECDHE parameters: " + err.String()) } skx := new(serverKeyExchangeMsg) @@ -162,11 +161,11 @@ Curve: func (ka *ecdheRSAKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKeyExchangeMsg) ([]byte, os.Error) { if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 { - return nil, os.ErrorString("bad ClientKeyExchange") + return nil, os.NewError("bad ClientKeyExchange") } x, y := ka.curve.Unmarshal(ckx.ciphertext[1:]) if x == nil { - return nil, os.ErrorString("bad ClientKeyExchange") + return nil, os.NewError("bad ClientKeyExchange") } x, _ = ka.curve.ScalarMult(x, y, ka.privateKey) preMasterSecret := make([]byte, (ka.curve.BitSize+7)>>3) @@ -176,12 +175,14 @@ func (ka *ecdheRSAKeyAgreement) processClientKeyExchange(config *Config, ckx *cl return preMasterSecret, nil } +var errServerKeyExchange = os.NewError("invalid ServerKeyExchange") + func (ka *ecdheRSAKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) os.Error { if len(skx.key) < 4 { - goto Error + return errServerKeyExchange } if skx.key[0] != 3 { // named curve - return os.ErrorString("server selected unsupported curve") + return os.NewError("server selected unsupported curve") } curveid := uint16(skx.key[1])<<8 | uint16(skx.key[2]) @@ -193,39 +194,36 @@ func (ka *ecdheRSAKeyAgreement) processServerKeyExchange(config *Config, clientH case curveP521: ka.curve = elliptic.P521() default: - return os.ErrorString("server selected unsupported curve") + return os.NewError("server selected unsupported curve") } publicLen := int(skx.key[3]) if publicLen+4 > len(skx.key) { - goto Error + return errServerKeyExchange } ka.x, ka.y = ka.curve.Unmarshal(skx.key[4 : 4+publicLen]) if ka.x == nil { - goto Error + return errServerKeyExchange } serverECDHParams := skx.key[:4+publicLen] sig := skx.key[4+publicLen:] if len(sig) < 2 { - goto Error + return errServerKeyExchange } sigLen := int(sig[0])<<8 | int(sig[1]) if sigLen+2 != len(sig) { - goto Error + return errServerKeyExchange } sig = sig[2:] md5sha1 := md5SHA1Hash(clientHello.random, serverHello.random, serverECDHParams) return rsa.VerifyPKCS1v15(cert.PublicKey.(*rsa.PublicKey), crypto.MD5SHA1, md5sha1, sig) - -Error: - return os.ErrorString("invalid ServerKeyExchange") } func (ka *ecdheRSAKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, os.Error) { if ka.curve == nil { - return nil, nil, os.ErrorString("missing ServerKeyExchange message") + return nil, nil, os.NewError("missing ServerKeyExchange message") } priv, mx, my, err := ka.curve.GenerateKey(config.rand()) if err != nil { @@ -236,12 +234,12 @@ func (ka *ecdheRSAKeyAgreement) generateClientKeyExchange(config *Config, client xBytes := x.Bytes() copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes) - serialised := ka.curve.Marshal(mx, my) + serialized := ka.curve.Marshal(mx, my) ckx := new(clientKeyExchangeMsg) - ckx.ciphertext = make([]byte, 1+len(serialised)) - ckx.ciphertext[0] = byte(len(serialised)) - copy(ckx.ciphertext[1:], serialised) + ckx.ciphertext = make([]byte, 1+len(serialized)) + ckx.ciphertext[0] = byte(len(serialized)) + copy(ckx.ciphertext[1:], serialized) return preMasterSecret, ckx, nil } diff --git a/libgo/go/crypto/tls/tls.go b/libgo/go/crypto/tls/tls.go index 7d0bb9f..4f0859f 100644 --- a/libgo/go/crypto/tls/tls.go +++ b/libgo/go/crypto/tls/tls.go @@ -147,19 +147,19 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err os.Err } if len(cert.Certificate) == 0 { - err = os.ErrorString("crypto/tls: failed to parse certificate PEM data") + err = os.NewError("crypto/tls: failed to parse certificate PEM data") return } keyDERBlock, _ := pem.Decode(keyPEMBlock) if keyDERBlock == nil { - err = os.ErrorString("crypto/tls: failed to parse key PEM data") + err = os.NewError("crypto/tls: failed to parse key PEM data") return } key, err := x509.ParsePKCS1PrivateKey(keyDERBlock.Bytes) if err != nil { - err = os.ErrorString("crypto/tls: failed to parse key") + err = os.NewError("crypto/tls: failed to parse key: " + err.String()) return } @@ -173,7 +173,7 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err os.Err } if x509Cert.PublicKeyAlgorithm != x509.RSA || x509Cert.PublicKey.(*rsa.PublicKey).N.Cmp(key.PublicKey.N) != 0 { - err = os.ErrorString("crypto/tls: private key does not match public key") + err = os.NewError("crypto/tls: private key does not match public key") return } diff --git a/libgo/go/crypto/twofish/twofish.go b/libgo/go/crypto/twofish/twofish.go index 9303f03..2e537c6 100644 --- a/libgo/go/crypto/twofish/twofish.go +++ b/libgo/go/crypto/twofish/twofish.go @@ -116,7 +116,7 @@ func (c *Cipher) Reset() { c.k[i] = 0 } for i := range c.s { - for j := 0; j < 265; j++ { + for j := 0; j < 256; j++ { c.s[i][j] = 0 } } @@ -269,7 +269,7 @@ func h(in, key []byte, offset int) uint32 { // Encrypt encrypts a 16-byte block from src to dst, which may overlap. // Note that for amounts of data larger than a block, // it is not safe to just call Encrypt on successive blocks; -// instead, use an encryption mode like CBC (see crypto/block/cbc.go). +// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go). func (c *Cipher) Encrypt(dst, src []byte) { S1 := c.s[0] S2 := c.s[1] diff --git a/libgo/go/crypto/x509/cert_pool.go b/libgo/go/crypto/x509/cert_pool.go index c295fd9..16cd92e 100644 --- a/libgo/go/crypto/x509/cert_pool.go +++ b/libgo/go/crypto/x509/cert_pool.go @@ -5,6 +5,7 @@ package x509 import ( + "crypto/x509/pkix" "encoding/pem" "strings" ) @@ -25,7 +26,7 @@ func NewCertPool() *CertPool { } } -func nameToKey(name *Name) string { +func nameToKey(name *pkix.Name) string { return strings.Join(name.Country, ",") + "/" + strings.Join(name.Organization, ",") + "/" + strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName } diff --git a/libgo/go/crypto/x509/pkix/pkix.go b/libgo/go/crypto/x509/pkix/pkix.go new file mode 100644 index 0000000..266fd55 --- /dev/null +++ b/libgo/go/crypto/x509/pkix/pkix.go @@ -0,0 +1,167 @@ +// 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 pkix contains shared, low level structures used for ASN.1 parsing +// and serialization of X.509 certificates, CRL and OCSP. +package pkix + +import ( + "asn1" + "big" + "time" +) + +// AlgorithmIdentifier represents the ASN.1 structure of the same name. See RFC +// 5280, section 4.1.1.2. +type AlgorithmIdentifier struct { + Algorithm asn1.ObjectIdentifier + Parameters asn1.RawValue `asn1:"optional"` +} + +type RDNSequence []RelativeDistinguishedNameSET + +type RelativeDistinguishedNameSET []AttributeTypeAndValue + +type AttributeTypeAndValue struct { + Type asn1.ObjectIdentifier + Value interface{} +} + +// Extension represents the ASN.1 structure of the same name. See RFC +// 5280, section 4.2. +type Extension struct { + Id asn1.ObjectIdentifier + Critical bool `asn1:"optional"` + Value []byte +} + +// Name represents an X.509 distinguished name. This only includes the common +// elements of a DN. Additional elements in the name are ignored. +type Name struct { + Country, Organization, OrganizationalUnit []string + Locality, Province []string + StreetAddress, PostalCode []string + SerialNumber, CommonName string +} + +func (n *Name) FillFromRDNSequence(rdns *RDNSequence) { + for _, rdn := range *rdns { + if len(rdn) == 0 { + continue + } + atv := rdn[0] + value, ok := atv.Value.(string) + if !ok { + continue + } + + t := atv.Type + if len(t) == 4 && t[0] == 2 && t[1] == 5 && t[2] == 4 { + switch t[3] { + case 3: + n.CommonName = value + case 5: + n.SerialNumber = value + case 6: + n.Country = append(n.Country, value) + case 7: + n.Locality = append(n.Locality, value) + case 8: + n.Province = append(n.Province, value) + case 9: + n.StreetAddress = append(n.StreetAddress, value) + case 10: + n.Organization = append(n.Organization, value) + case 11: + n.OrganizationalUnit = append(n.OrganizationalUnit, value) + case 17: + n.PostalCode = append(n.PostalCode, value) + } + } + } +} + +var ( + oidCountry = []int{2, 5, 4, 6} + oidOrganization = []int{2, 5, 4, 10} + oidOrganizationalUnit = []int{2, 5, 4, 11} + oidCommonName = []int{2, 5, 4, 3} + oidSerialNumber = []int{2, 5, 4, 5} + oidLocality = []int{2, 5, 4, 7} + oidProvince = []int{2, 5, 4, 8} + oidStreetAddress = []int{2, 5, 4, 9} + oidPostalCode = []int{2, 5, 4, 17} +) + +// appendRDNs appends a relativeDistinguishedNameSET to the given RDNSequence +// and returns the new value. The relativeDistinguishedNameSET contains an +// attributeTypeAndValue for each of the given values. See RFC 5280, A.1, and +// search for AttributeTypeAndValue. +func appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNSequence { + if len(values) == 0 { + return in + } + + s := make([]AttributeTypeAndValue, len(values)) + for i, value := range values { + s[i].Type = oid + s[i].Value = value + } + + return append(in, s) +} + +func (n Name) ToRDNSequence() (ret RDNSequence) { + ret = appendRDNs(ret, n.Country, oidCountry) + ret = appendRDNs(ret, n.Organization, oidOrganization) + ret = appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit) + ret = appendRDNs(ret, n.Locality, oidLocality) + ret = appendRDNs(ret, n.Province, oidProvince) + ret = appendRDNs(ret, n.StreetAddress, oidStreetAddress) + ret = appendRDNs(ret, n.PostalCode, oidPostalCode) + if len(n.CommonName) > 0 { + ret = appendRDNs(ret, []string{n.CommonName}, oidCommonName) + } + if len(n.SerialNumber) > 0 { + ret = appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber) + } + + return ret +} + +// CertificateList represents the ASN.1 structure of the same name. See RFC +// 5280, section 5.1. Use Certificate.CheckCRLSignature to verify the +// signature. +type CertificateList struct { + TBSCertList TBSCertificateList + SignatureAlgorithm AlgorithmIdentifier + SignatureValue asn1.BitString +} + +// HasExpired returns true iff currentTimeSeconds is past the expiry time of +// certList. +func (certList *CertificateList) HasExpired(currentTimeSeconds int64) bool { + return certList.TBSCertList.NextUpdate.Seconds() <= currentTimeSeconds +} + +// TBSCertificateList represents the ASN.1 structure of the same name. See RFC +// 5280, section 5.1. +type TBSCertificateList struct { + Raw asn1.RawContent + Version int `asn1:"optional,default:2"` + Signature AlgorithmIdentifier + Issuer RDNSequence + ThisUpdate *time.Time + NextUpdate *time.Time + RevokedCertificates []RevokedCertificate `asn1:"optional"` + Extensions []Extension `asn1:"tag:0,optional,explicit"` +} + +// RevokedCertificate represents the ASN.1 structure of the same name. See RFC +// 5280, section 5.1. +type RevokedCertificate struct { + SerialNumber *big.Int + RevocationTime *time.Time + Extensions []Extension `asn1:"optional"` +} diff --git a/libgo/go/crypto/x509/verify.go b/libgo/go/crypto/x509/verify.go index 9145880..4c0fecc 100644 --- a/libgo/go/crypto/x509/verify.go +++ b/libgo/go/crypto/x509/verify.go @@ -62,7 +62,6 @@ func (h HostnameError) String() string { return "certificate is valid for " + valid + ", not " + h.Host } - // UnknownAuthorityError results when the certificate issuer is unknown type UnknownAuthorityError struct { cert *Certificate @@ -171,8 +170,14 @@ func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain [ chains = append(chains, appendToFreshChain(currentChain, root)) } +nextIntermediate: for _, intermediateNum := range opts.Intermediates.findVerifiedParents(c) { intermediate := opts.Intermediates.certs[intermediateNum] + for _, cert := range currentChain { + if cert == intermediate { + continue nextIntermediate + } + } err = intermediate.isValid(intermediateCertificate, opts) if err != nil { continue @@ -202,8 +207,8 @@ func matchHostnames(pattern, host string) bool { return false } - patternParts := strings.Split(pattern, ".", -1) - hostParts := strings.Split(host, ".", -1) + patternParts := strings.Split(pattern, ".") + hostParts := strings.Split(host, ".") if len(patternParts) != len(hostParts) { return false diff --git a/libgo/go/crypto/x509/verify_test.go b/libgo/go/crypto/x509/verify_test.go index 6a103dc..111f60e 100644 --- a/libgo/go/crypto/x509/verify_test.go +++ b/libgo/go/crypto/x509/verify_test.go @@ -72,23 +72,24 @@ var verifyTests = []verifyTest{ }, }, { - leaf: googleLeaf, - intermediates: []string{verisignRoot, thawteIntermediate}, - roots: []string{verisignRoot}, + leaf: dnssecExpLeaf, + intermediates: []string{startComIntermediate}, + roots: []string{startComRoot}, currentTime: 1302726541, expectedChains: [][]string{ - []string{"Google", "Thawte", "VeriSign"}, + []string{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"}, }, }, { leaf: dnssecExpLeaf, - intermediates: []string{startComIntermediate}, + intermediates: []string{startComIntermediate, startComRoot}, roots: []string{startComRoot}, currentTime: 1302726541, expectedChains: [][]string{ []string{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"}, + []string{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority", "StartCom Certification Authority"}, }, }, } @@ -120,7 +121,7 @@ func expectAuthorityUnknown(t *testing.T, i int, err os.Error) (ok bool) { func certificateFromPEM(pemBytes string) (*Certificate, os.Error) { block, _ := pem.Decode([]byte(pemBytes)) if block == nil { - return nil, os.ErrorString("failed to decode PEM") + return nil, os.NewError("failed to decode PEM") } return ParseCertificate(block.Bytes) } diff --git a/libgo/go/crypto/x509/x509.go b/libgo/go/crypto/x509/x509.go index d0c5a26..8fda471 100644 --- a/libgo/go/crypto/x509/x509.go +++ b/libgo/go/crypto/x509/x509.go @@ -9,11 +9,12 @@ import ( "asn1" "big" "bytes" - "container/vector" "crypto" + "crypto/dsa" "crypto/rsa" "crypto/sha1" - "hash" + "crypto/x509/pkix" + "encoding/pem" "io" "os" "time" @@ -22,30 +23,25 @@ import ( // pkcs1PrivateKey is a structure which mirrors the PKCS#1 ASN.1 for an RSA private key. type pkcs1PrivateKey struct { Version int - N asn1.RawValue + N *big.Int E int - D asn1.RawValue - P asn1.RawValue - Q asn1.RawValue + D *big.Int + P *big.Int + Q *big.Int // We ignore these values, if present, because rsa will calculate them. - Dp asn1.RawValue "optional" - Dq asn1.RawValue "optional" - Qinv asn1.RawValue "optional" + Dp *big.Int `asn1:"optional"` + Dq *big.Int `asn1:"optional"` + Qinv *big.Int `asn1:"optional"` - AdditionalPrimes []pkcs1AddtionalRSAPrime "optional" + AdditionalPrimes []pkcs1AdditionalRSAPrime `asn1:"optional"` } -type pkcs1AddtionalRSAPrime struct { - Prime asn1.RawValue +type pkcs1AdditionalRSAPrime struct { + Prime *big.Int // We ignore these values because rsa will calculate them. - Exp asn1.RawValue - Coeff asn1.RawValue -} - -// rawValueIsInteger returns true iff the given ASN.1 RawValue is an INTEGER type. -func rawValueIsInteger(raw *asn1.RawValue) bool { - return raw.Class == 0 && raw.Tag == 2 && raw.IsCompound == false + Exp *big.Int + Coeff *big.Int } // ParsePKCS1PrivateKey returns an RSA private key from its ASN.1 PKCS#1 DER encoded form. @@ -61,32 +57,28 @@ func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err os.Error) { } if priv.Version > 1 { - return nil, os.ErrorString("x509: unsupported private key version") + return nil, os.NewError("x509: unsupported private key version") } - if !rawValueIsInteger(&priv.N) || - !rawValueIsInteger(&priv.D) || - !rawValueIsInteger(&priv.P) || - !rawValueIsInteger(&priv.Q) { - err = asn1.StructuralError{"tags don't match"} - return + if priv.N.Sign() <= 0 || priv.D.Sign() <= 0 || priv.P.Sign() <= 0 || priv.Q.Sign() <= 0 { + return nil, os.NewError("private key contains zero or negative value") } key = new(rsa.PrivateKey) key.PublicKey = rsa.PublicKey{ E: priv.E, - N: new(big.Int).SetBytes(priv.N.Bytes), + N: priv.N, } - key.D = new(big.Int).SetBytes(priv.D.Bytes) + key.D = priv.D key.Primes = make([]*big.Int, 2+len(priv.AdditionalPrimes)) - key.Primes[0] = new(big.Int).SetBytes(priv.P.Bytes) - key.Primes[1] = new(big.Int).SetBytes(priv.Q.Bytes) + key.Primes[0] = priv.P + key.Primes[1] = priv.Q for i, a := range priv.AdditionalPrimes { - if !rawValueIsInteger(&a.Prime) { - return nil, asn1.StructuralError{"tags don't match"} + if a.Prime.Sign() <= 0 { + return nil, os.NewError("private key contains zero or negative prime") } - key.Primes[i+2] = new(big.Int).SetBytes(a.Prime.Bytes) + key.Primes[i+2] = a.Prime // We ignore the other two values because rsa will calculate // them as needed. } @@ -100,19 +92,6 @@ func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err os.Error) { return } -// rawValueForBig returns an asn1.RawValue which represents the given integer. -func rawValueForBig(n *big.Int) asn1.RawValue { - b := n.Bytes() - if n.Sign() >= 0 && len(b) > 0 && b[0]&0x80 != 0 { - // This positive number would be interpreted as a negative - // number in ASN.1 because the MSB is set. - padded := make([]byte, len(b)+1) - copy(padded[1:], b) - b = padded - } - return asn1.RawValue{Tag: 2, Bytes: b} -} - // MarshalPKCS1PrivateKey converts a private key to ASN.1 DER encoded form. func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte { key.Precompute() @@ -124,21 +103,21 @@ func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte { priv := pkcs1PrivateKey{ Version: version, - N: rawValueForBig(key.N), + N: key.N, E: key.PublicKey.E, - D: rawValueForBig(key.D), - P: rawValueForBig(key.Primes[0]), - Q: rawValueForBig(key.Primes[1]), - Dp: rawValueForBig(key.Precomputed.Dp), - Dq: rawValueForBig(key.Precomputed.Dq), - Qinv: rawValueForBig(key.Precomputed.Qinv), + D: key.D, + P: key.Primes[0], + Q: key.Primes[1], + Dp: key.Precomputed.Dp, + Dq: key.Precomputed.Dq, + Qinv: key.Precomputed.Qinv, } - priv.AdditionalPrimes = make([]pkcs1AddtionalRSAPrime, len(key.Precomputed.CRTValues)) + priv.AdditionalPrimes = make([]pkcs1AdditionalRSAPrime, len(key.Precomputed.CRTValues)) for i, values := range key.Precomputed.CRTValues { - priv.AdditionalPrimes[i].Prime = rawValueForBig(key.Primes[2+i]) - priv.AdditionalPrimes[i].Exp = rawValueForBig(values.Exp) - priv.AdditionalPrimes[i].Coeff = rawValueForBig(values.Coeff) + priv.AdditionalPrimes[i].Prime = key.Primes[2+i] + priv.AdditionalPrimes[i].Exp = values.Exp + priv.AdditionalPrimes[i].Coeff = values.Coeff } b, _ := asn1.Marshal(priv) @@ -150,35 +129,30 @@ func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte { type certificate struct { Raw asn1.RawContent TBSCertificate tbsCertificate - SignatureAlgorithm algorithmIdentifier + SignatureAlgorithm pkix.AlgorithmIdentifier SignatureValue asn1.BitString } type tbsCertificate struct { Raw asn1.RawContent - Version int "optional,explicit,default:1,tag:0" - SerialNumber asn1.RawValue - SignatureAlgorithm algorithmIdentifier - Issuer rdnSequence + Version int `asn1:"optional,explicit,default:1,tag:0"` + SerialNumber *big.Int + SignatureAlgorithm pkix.AlgorithmIdentifier + Issuer pkix.RDNSequence Validity validity - Subject rdnSequence + Subject pkix.RDNSequence PublicKey publicKeyInfo - UniqueId asn1.BitString "optional,tag:1" - SubjectUniqueId asn1.BitString "optional,tag:2" - Extensions []extension "optional,explicit,tag:3" + UniqueId asn1.BitString `asn1:"optional,tag:1"` + SubjectUniqueId asn1.BitString `asn1:"optional,tag:2"` + Extensions []pkix.Extension `asn1:"optional,explicit,tag:3"` } -type algorithmIdentifier struct { - Algorithm asn1.ObjectIdentifier +type dsaAlgorithmParameters struct { + P, Q, G *big.Int } -type rdnSequence []relativeDistinguishedNameSET - -type relativeDistinguishedNameSET []attributeTypeAndValue - -type attributeTypeAndValue struct { - Type asn1.ObjectIdentifier - Value interface{} +type dsaSignature struct { + R, S *big.Int } type validity struct { @@ -187,19 +161,13 @@ type validity struct { type publicKeyInfo struct { Raw asn1.RawContent - Algorithm algorithmIdentifier + Algorithm pkix.AlgorithmIdentifier PublicKey asn1.BitString } -type extension struct { - Id asn1.ObjectIdentifier - Critical bool "optional" - Value []byte -} - // RFC 5280, 4.2.1.1 type authKeyId struct { - Id []byte "optional,tag:0" + Id []byte `asn1:"optional,tag:0"` } type SignatureAlgorithm int @@ -212,6 +180,8 @@ const ( SHA256WithRSA SHA384WithRSA SHA512WithRSA + DSAWithSHA1 + DSAWithSHA256 ) type PublicKeyAlgorithm int @@ -219,133 +189,96 @@ type PublicKeyAlgorithm int const ( UnknownPublicKeyAlgorithm PublicKeyAlgorithm = iota RSA + DSA ) -// Name represents an X.509 distinguished name. This only includes the common -// elements of a DN. Additional elements in the name are ignored. -type Name struct { - Country, Organization, OrganizationalUnit []string - Locality, Province []string - StreetAddress, PostalCode []string - SerialNumber, CommonName string -} - -func (n *Name) fillFromRDNSequence(rdns *rdnSequence) { - for _, rdn := range *rdns { - if len(rdn) == 0 { - continue - } - atv := rdn[0] - value, ok := atv.Value.(string) - if !ok { - continue - } - - t := atv.Type - if len(t) == 4 && t[0] == 2 && t[1] == 5 && t[2] == 4 { - switch t[3] { - case 3: - n.CommonName = value - case 5: - n.SerialNumber = value - case 6: - n.Country = append(n.Country, value) - case 7: - n.Locality = append(n.Locality, value) - case 8: - n.Province = append(n.Province, value) - case 9: - n.StreetAddress = append(n.StreetAddress, value) - case 10: - n.Organization = append(n.Organization, value) - case 11: - n.OrganizationalUnit = append(n.OrganizationalUnit, value) - case 17: - n.PostalCode = append(n.PostalCode, value) - } - } - } -} - +// OIDs for signature algorithms +// +// pkcs-1 OBJECT IDENTIFIER ::= { +// iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 } +// +// +// RFC 3279 2.2.1 RSA Signature Algorithms +// +// md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 } +// +// md5WithRSAEncryption OBJECT IDENTIFER ::= { pkcs-1 4 } +// +// sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 } +// +// dsaWithSha1 OBJECT IDENTIFIER ::= { +// iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 3 } +// +// +// RFC 4055 5 PKCS #1 Version 1.5 +// +// sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 } +// +// sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 } +// +// sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 } +// +// +// RFC 5758 3.1 DSA Signature Algorithms +// +// dsaWithSha356 OBJECT IDENTIFER ::= { +// joint-iso-ccitt(2) country(16) us(840) organization(1) gov(101) +// algorithms(4) id-dsa-with-sha2(3) 2} +// var ( - oidCountry = []int{2, 5, 4, 6} - oidOrganization = []int{2, 5, 4, 10} - oidOrganizationalUnit = []int{2, 5, 4, 11} - oidCommonName = []int{2, 5, 4, 3} - oidSerialNumber = []int{2, 5, 4, 5} - oidLocatity = []int{2, 5, 4, 7} - oidProvince = []int{2, 5, 4, 8} - oidStreetAddress = []int{2, 5, 4, 9} - oidPostalCode = []int{2, 5, 4, 17} + oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2} + oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4} + oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5} + oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11} + oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12} + oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13} + oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3} + oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 4, 3, 2} ) -// appendRDNs appends a relativeDistinguishedNameSET to the given rdnSequence -// and returns the new value. The relativeDistinguishedNameSET contains an -// attributeTypeAndValue for each of the given values. See RFC 5280, A.1, and -// search for AttributeTypeAndValue. -func appendRDNs(in rdnSequence, values []string, oid asn1.ObjectIdentifier) rdnSequence { - if len(values) == 0 { - return in - } - - s := make([]attributeTypeAndValue, len(values)) - for i, value := range values { - s[i].Type = oid - s[i].Value = value - } - - return append(in, s) -} - -func (n Name) toRDNSequence() (ret rdnSequence) { - ret = appendRDNs(ret, n.Country, oidCountry) - ret = appendRDNs(ret, n.Organization, oidOrganization) - ret = appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit) - ret = appendRDNs(ret, n.Locality, oidLocatity) - ret = appendRDNs(ret, n.Province, oidProvince) - ret = appendRDNs(ret, n.StreetAddress, oidStreetAddress) - ret = appendRDNs(ret, n.PostalCode, oidPostalCode) - if len(n.CommonName) > 0 { - ret = appendRDNs(ret, []string{n.CommonName}, oidCommonName) - } - if len(n.SerialNumber) > 0 { - ret = appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber) - } - - return ret -} - -func getSignatureAlgorithmFromOID(oid []int) SignatureAlgorithm { - if len(oid) == 7 && oid[0] == 1 && oid[1] == 2 && oid[2] == 840 && - oid[3] == 113549 && oid[4] == 1 && oid[5] == 1 { - switch oid[6] { - case 2: - return MD2WithRSA - case 4: - return MD5WithRSA - case 5: - return SHA1WithRSA - case 11: - return SHA256WithRSA - case 12: - return SHA384WithRSA - case 13: - return SHA512WithRSA - } +func getSignatureAlgorithmFromOID(oid asn1.ObjectIdentifier) SignatureAlgorithm { + switch { + case oid.Equal(oidSignatureMD2WithRSA): + return MD2WithRSA + case oid.Equal(oidSignatureMD5WithRSA): + return MD5WithRSA + case oid.Equal(oidSignatureSHA1WithRSA): + return SHA1WithRSA + case oid.Equal(oidSignatureSHA256WithRSA): + return SHA256WithRSA + case oid.Equal(oidSignatureSHA384WithRSA): + return SHA384WithRSA + case oid.Equal(oidSignatureSHA512WithRSA): + return SHA512WithRSA + case oid.Equal(oidSignatureDSAWithSHA1): + return DSAWithSHA1 + case oid.Equal(oidSignatureDSAWithSHA256): + return DSAWithSHA256 } - return UnknownSignatureAlgorithm } -func getPublicKeyAlgorithmFromOID(oid []int) PublicKeyAlgorithm { - if len(oid) == 7 && oid[0] == 1 && oid[1] == 2 && oid[2] == 840 && - oid[3] == 113549 && oid[4] == 1 && oid[5] == 1 { - switch oid[6] { - case 1: - return RSA - } - } +// RFC 3279, 2.3 Public Key Algorithms +// +// pkcs-1 OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840) +// rsadsi(113549) pkcs(1) 1 } +// +// rsaEncryption OBJECT IDENTIFIER ::== { pkcs1-1 1 } +// +// id-dsa OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840) +// x9-57(10040) x9cm(4) 1 } +var ( + oidPublicKeyRsa = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1} + oidPublicKeyDsa = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1} +) +func getPublicKeyAlgorithmFromOID(oid asn1.ObjectIdentifier) PublicKeyAlgorithm { + switch { + case oid.Equal(oidPublicKeyRsa): + return RSA + case oid.Equal(oidPublicKeyDsa): + return DSA + } return UnknownPublicKeyAlgorithm } @@ -414,9 +347,9 @@ type Certificate struct { PublicKey interface{} Version int - SerialNumber []byte - Issuer Name - Subject Name + SerialNumber *big.Int + Issuer pkix.Name + Subject pkix.Name NotBefore, NotAfter *time.Time // Validity bounds. KeyUsage KeyUsage @@ -485,26 +418,58 @@ func (c *Certificate) CheckSignatureFrom(parent *Certificate) (err os.Error) { // TODO(agl): don't ignore the path length constraint. - var h hash.Hash + return parent.CheckSignature(c.SignatureAlgorithm, c.RawTBSCertificate, c.Signature) +} + +// CheckSignature verifies that signature is a valid signature over signed from +// c's public key. +func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature []byte) (err os.Error) { var hashType crypto.Hash - switch c.SignatureAlgorithm { - case SHA1WithRSA: - h = sha1.New() + switch algo { + case SHA1WithRSA, DSAWithSHA1: hashType = crypto.SHA1 + case SHA256WithRSA, DSAWithSHA256: + hashType = crypto.SHA256 + case SHA384WithRSA: + hashType = crypto.SHA384 + case SHA512WithRSA: + hashType = crypto.SHA512 default: return UnsupportedAlgorithmError{} } - pub, ok := parent.PublicKey.(*rsa.PublicKey) - if !ok { + h := hashType.New() + if h == nil { return UnsupportedAlgorithmError{} } - h.Write(c.RawTBSCertificate) + h.Write(signed) digest := h.Sum() - return rsa.VerifyPKCS1v15(pub, hashType, digest, c.Signature) + switch pub := c.PublicKey.(type) { + case *rsa.PublicKey: + return rsa.VerifyPKCS1v15(pub, hashType, digest, signature) + case *dsa.PublicKey: + dsaSig := new(dsaSignature) + if _, err := asn1.Unmarshal(signature, dsaSig); err != nil { + return err + } + if dsaSig.R.Sign() <= 0 || dsaSig.S.Sign() <= 0 { + return os.NewError("DSA signature contained zero or negative values") + } + if !dsa.Verify(pub, digest, dsaSig.R, dsaSig.S) { + return os.NewError("DSA verification failure") + } + return + } + return UnsupportedAlgorithmError{} +} + +// CheckCRLSignature checks that the signature in crl is from c. +func (c *Certificate) CheckCRLSignature(crl *pkix.CertificateList) (err os.Error) { + algo := getSignatureAlgorithmFromOID(crl.SignatureAlgorithm.Algorithm) + return c.CheckSignature(algo, crl.TBSCertList.Raw, crl.SignatureValue.RightAlign()) } type UnhandledCriticalExtension struct{} @@ -514,12 +479,12 @@ func (h UnhandledCriticalExtension) String() string { } type basicConstraints struct { - IsCA bool "optional" - MaxPathLen int "optional" + IsCA bool `asn1:"optional"` + MaxPathLen int `asn1:"optional"` } type rsaPublicKey struct { - N asn1.RawValue + N *big.Int E int } @@ -531,17 +496,18 @@ type policyInformation struct { // RFC 5280, 4.2.1.10 type nameConstraints struct { - Permitted []generalSubtree "optional,tag:0" - Excluded []generalSubtree "optional,tag:1" + Permitted []generalSubtree `asn1:"optional,tag:0"` + Excluded []generalSubtree `asn1:"optional,tag:1"` } type generalSubtree struct { - Name string "tag:2,optional,ia5" - Min int "optional,tag:0" - Max int "optional,tag:1" + Name string `asn1:"tag:2,optional,ia5"` + Min int `asn1:"optional,tag:0"` + Max int `asn1:"optional,tag:1"` } -func parsePublicKey(algo PublicKeyAlgorithm, asn1Data []byte) (interface{}, os.Error) { +func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{}, os.Error) { + asn1Data := keyData.PublicKey.RightAlign() switch algo { case RSA: p := new(rsaPublicKey) @@ -550,19 +516,38 @@ func parsePublicKey(algo PublicKeyAlgorithm, asn1Data []byte) (interface{}, os.E return nil, err } - if !rawValueIsInteger(&p.N) { - return nil, asn1.StructuralError{"tags don't match"} - } - pub := &rsa.PublicKey{ E: p.E, - N: new(big.Int).SetBytes(p.N.Bytes), + N: p.N, + } + return pub, nil + case DSA: + var p *big.Int + _, err := asn1.Unmarshal(asn1Data, &p) + if err != nil { + return nil, err + } + paramsData := keyData.Algorithm.Parameters.FullBytes + params := new(dsaAlgorithmParameters) + _, err = asn1.Unmarshal(paramsData, params) + if err != nil { + return nil, err + } + if p.Sign() <= 0 || params.P.Sign() <= 0 || params.Q.Sign() <= 0 || params.G.Sign() <= 0 { + return nil, os.NewError("zero or negative DSA parameter") + } + pub := &dsa.PublicKey{ + Parameters: dsa.Parameters{ + P: params.P, + Q: params.Q, + G: params.G, + }, + Y: p, } return pub, nil default: return nil, nil } - panic("unreachable") } @@ -579,15 +564,19 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) { out.PublicKeyAlgorithm = getPublicKeyAlgorithmFromOID(in.TBSCertificate.PublicKey.Algorithm.Algorithm) var err os.Error - out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, in.TBSCertificate.PublicKey.PublicKey.RightAlign()) + out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, &in.TBSCertificate.PublicKey) if err != nil { return nil, err } + if in.TBSCertificate.SerialNumber.Sign() < 0 { + return nil, os.NewError("negative serial number") + } + out.Version = in.TBSCertificate.Version + 1 - out.SerialNumber = in.TBSCertificate.SerialNumber.Bytes - out.Issuer.fillFromRDNSequence(&in.TBSCertificate.Issuer) - out.Subject.fillFromRDNSequence(&in.TBSCertificate.Subject) + out.SerialNumber = in.TBSCertificate.SerialNumber + out.Issuer.FillFromRDNSequence(&in.TBSCertificate.Issuer) + out.Subject.FillFromRDNSequence(&in.TBSCertificate.Subject) out.NotBefore = in.TBSCertificate.Validity.NotBefore out.NotAfter = in.TBSCertificate.Validity.NotAfter @@ -611,13 +600,13 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) { } case 19: // RFC 5280, 4.2.1.9 - var constriants basicConstraints - _, err := asn1.Unmarshal(e.Value, &constriants) + var constraints basicConstraints + _, err := asn1.Unmarshal(e.Value, &constraints) if err == nil { out.BasicConstraintsValid = true - out.IsCA = constriants.IsCA - out.MaxPathLen = constriants.MaxPathLen + out.IsCA = constraints.IsCA + out.MaxPathLen = constraints.MaxPathLen continue } case 17: @@ -804,7 +793,7 @@ func ParseCertificate(asn1Data []byte) (*Certificate, os.Error) { // ParseCertificates parses one or more certificates from the given ASN.1 DER // data. The certificates must be concatenated with no intermediate padding. func ParseCertificates(asn1Data []byte) ([]*Certificate, os.Error) { - v := new(vector.Vector) + var v []*certificate for len(asn1Data) > 0 { cert := new(certificate) @@ -813,12 +802,12 @@ func ParseCertificates(asn1Data []byte) ([]*Certificate, os.Error) { if err != nil { return nil, err } - v.Push(cert) + v = append(v, cert) } - ret := make([]*Certificate, v.Len()) - for i := 0; i < v.Len(); i++ { - cert, err := parseCertificate(v.At(i).(*certificate)) + ret := make([]*Certificate, len(v)) + for i, ci := range v { + cert, err := parseCertificate(ci) if err != nil { return nil, err } @@ -845,8 +834,8 @@ var ( oidExtensionNameConstraints = []int{2, 5, 29, 30} ) -func buildExtensions(template *Certificate) (ret []extension, err os.Error) { - ret = make([]extension, 7 /* maximum number of elements. */ ) +func buildExtensions(template *Certificate) (ret []pkix.Extension, err os.Error) { + ret = make([]pkix.Extension, 7 /* maximum number of elements. */ ) n := 0 if template.KeyUsage != 0 { @@ -963,7 +952,7 @@ var ( // The returned slice is the certificate in DER encoding. func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.PublicKey, priv *rsa.PrivateKey) (cert []byte, err os.Error) { asn1PublicKey, err := asn1.Marshal(rsaPublicKey{ - N: asn1.RawValue{Tag: 2, Bytes: pub.N.Bytes()}, + N: pub.N, E: pub.E, }) if err != nil { @@ -982,12 +971,12 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P encodedPublicKey := asn1.BitString{BitLength: len(asn1PublicKey) * 8, Bytes: asn1PublicKey} c := tbsCertificate{ Version: 2, - SerialNumber: asn1.RawValue{Bytes: template.SerialNumber, Tag: 2}, - SignatureAlgorithm: algorithmIdentifier{oidSHA1WithRSA}, - Issuer: parent.Subject.toRDNSequence(), + SerialNumber: template.SerialNumber, + SignatureAlgorithm: pkix.AlgorithmIdentifier{Algorithm: oidSHA1WithRSA}, + Issuer: parent.Subject.ToRDNSequence(), Validity: validity{template.NotBefore, template.NotAfter}, - Subject: template.Subject.toRDNSequence(), - PublicKey: publicKeyInfo{nil, algorithmIdentifier{oidRSA}, encodedPublicKey}, + Subject: template.Subject.ToRDNSequence(), + PublicKey: publicKeyInfo{nil, pkix.AlgorithmIdentifier{Algorithm: oidRSA}, encodedPublicKey}, Extensions: extensions, } @@ -1010,8 +999,75 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P cert, err = asn1.Marshal(certificate{ nil, c, - algorithmIdentifier{oidSHA1WithRSA}, + pkix.AlgorithmIdentifier{Algorithm: oidSHA1WithRSA}, asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, }) return } + +// pemCRLPrefix is the magic string that indicates that we have a PEM encoded +// CRL. +var pemCRLPrefix = []byte("-----BEGIN X509 CRL") +// pemType is the type of a PEM encoded CRL. +var pemType = "X509 CRL" + +// ParseCRL parses a CRL from the given bytes. It's often the case that PEM +// encoded CRLs will appear where they should be DER encoded, so this function +// will transparently handle PEM encoding as long as there isn't any leading +// garbage. +func ParseCRL(crlBytes []byte) (certList *pkix.CertificateList, err os.Error) { + if bytes.HasPrefix(crlBytes, pemCRLPrefix) { + block, _ := pem.Decode(crlBytes) + if block != nil && block.Type == pemType { + crlBytes = block.Bytes + } + } + return ParseDERCRL(crlBytes) +} + +// ParseDERCRL parses a DER encoded CRL from the given bytes. +func ParseDERCRL(derBytes []byte) (certList *pkix.CertificateList, err os.Error) { + certList = new(pkix.CertificateList) + _, err = asn1.Unmarshal(derBytes, certList) + if err != nil { + certList = nil + } + return +} + +// CreateCRL returns a DER encoded CRL, signed by this Certificate, that +// contains the given list of revoked certificates. +func (c *Certificate) CreateCRL(rand io.Reader, priv *rsa.PrivateKey, revokedCerts []pkix.RevokedCertificate, now, expiry *time.Time) (crlBytes []byte, err os.Error) { + tbsCertList := pkix.TBSCertificateList{ + Version: 2, + Signature: pkix.AlgorithmIdentifier{ + Algorithm: oidSignatureSHA1WithRSA, + }, + Issuer: c.Subject.ToRDNSequence(), + ThisUpdate: now, + NextUpdate: expiry, + RevokedCertificates: revokedCerts, + } + + tbsCertListContents, err := asn1.Marshal(tbsCertList) + if err != nil { + return + } + + h := sha1.New() + h.Write(tbsCertListContents) + digest := h.Sum() + + signature, err := rsa.SignPKCS1v15(rand, priv, crypto.SHA1, digest) + if err != nil { + return + } + + return asn1.Marshal(pkix.CertificateList{ + TBSCertList: tbsCertList, + SignatureAlgorithm: pkix.AlgorithmIdentifier{ + Algorithm: oidSignatureSHA1WithRSA, + }, + SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, + }) +} diff --git a/libgo/go/crypto/x509/x509_test.go b/libgo/go/crypto/x509/x509_test.go index a42113a..dc21650 100644 --- a/libgo/go/crypto/x509/x509_test.go +++ b/libgo/go/crypto/x509/x509_test.go @@ -7,8 +7,11 @@ package x509 import ( "asn1" "big" + "crypto/dsa" "crypto/rand" "crypto/rsa" + "crypto/x509/pkix" + "encoding/base64" "encoding/hex" "encoding/pem" "testing" @@ -54,6 +57,12 @@ func fromBase10(base10 string) *big.Int { return i } +func bigFromHexString(s string) *big.Int { + ret := new(big.Int) + ret.SetString(s, 16) + return ret +} + var rsaPrivateKey = &rsa.PrivateKey{ PublicKey: rsa.PublicKey{ N: bigFromString("9353930466774385905609975137998169297361893554149986716853295022578535724979677252958524466350471210367835187480748268864277464700638583474144061408845077"), @@ -200,8 +209,8 @@ func TestCreateSelfSignedCertificate(t *testing.T) { } template := Certificate{ - SerialNumber: []byte{1}, - Subject: Name{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ CommonName: "test.example.com", Organization: []string{"Acme Co"}, }, @@ -245,3 +254,178 @@ func TestCreateSelfSignedCertificate(t *testing.T) { return } } + +// Self-signed certificate using DSA with SHA1 +var dsaCertPem = `-----BEGIN CERTIFICATE----- +MIIEDTCCA82gAwIBAgIJALHPghaoxeDhMAkGByqGSM44BAMweTELMAkGA1UEBhMC +VVMxCzAJBgNVBAgTAk5DMQ8wDQYDVQQHEwZOZXd0b24xFDASBgNVBAoTC0dvb2ds +ZSwgSW5jMRIwEAYDVQQDEwlKb24gQWxsaWUxIjAgBgkqhkiG9w0BCQEWE2pvbmFs +bGllQGdvb2dsZS5jb20wHhcNMTEwNTE0MDMwMTQ1WhcNMTEwNjEzMDMwMTQ1WjB5 +MQswCQYDVQQGEwJVUzELMAkGA1UECBMCTkMxDzANBgNVBAcTBk5ld3RvbjEUMBIG +A1UEChMLR29vZ2xlLCBJbmMxEjAQBgNVBAMTCUpvbiBBbGxpZTEiMCAGCSqGSIb3 +DQEJARYTam9uYWxsaWVAZ29vZ2xlLmNvbTCCAbcwggEsBgcqhkjOOAQBMIIBHwKB +gQC8hLUnQ7FpFYu4WXTj6DKvXvz8QrJkNJCVMTpKAT7uBpobk32S5RrPKXocd4gN +8lyGB9ggS03EVlEwXvSmO0DH2MQtke2jl9j1HLydClMf4sbx5V6TV9IFw505U1iW +jL7awRMgxge+FsudtJK254FjMFo03ZnOQ8ZJJ9E6AEDrlwIVAJpnBn9moyP11Ox5 +Asc/5dnjb6dPAoGBAJFHd4KVv1iTVCvEG6gGiYop5DJh28hUQcN9kul+2A0yPUSC +X93oN00P8Vh3eYgSaCWZsha7zDG53MrVJ0Zf6v/X/CoZNhLldeNOepivTRAzn+Rz +kKUYy5l1sxYLHQKF0UGNCXfFKZT0PCmgU+PWhYNBBMn6/cIh44vp85ideo5CA4GE +AAKBgFmifCafzeRaohYKXJgMGSEaggCVCRq5xdyDCat+wbOkjC4mfG01/um3G8u5 +LxasjlWRKTR/tcAL7t0QuokVyQaYdVypZXNaMtx1db7YBuHjj3aP+8JOQRI9xz8c +bp5NDJ5pISiFOv4p3GZfqZPcqckDt78AtkQrmnal2txhhjF6o4HeMIHbMB0GA1Ud +DgQWBBQVyyr7hO11ZFFpWX50298Sa3V+rzCBqwYDVR0jBIGjMIGggBQVyyr7hO11 +ZFFpWX50298Sa3V+r6F9pHsweTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk5DMQ8w +DQYDVQQHEwZOZXd0b24xFDASBgNVBAoTC0dvb2dsZSwgSW5jMRIwEAYDVQQDEwlK +b24gQWxsaWUxIjAgBgkqhkiG9w0BCQEWE2pvbmFsbGllQGdvb2dsZS5jb22CCQCx +z4IWqMXg4TAMBgNVHRMEBTADAQH/MAkGByqGSM44BAMDLwAwLAIUPtn/5j8Q1jJI +7ggOIsgrhgUdjGQCFCsmDq1H11q9+9Wp9IMeGrTSKHIM +-----END CERTIFICATE----- +` + +func TestParseCertificateWithDsaPublicKey(t *testing.T) { + expectedKey := &dsa.PublicKey{ + Parameters: dsa.Parameters{ + P: bigFromHexString("00BC84B52743B169158BB85974E3E832AF5EFCFC42B264349095313A4A013EEE069A1B937D92E51ACF297A1C77880DF25C8607D8204B4DC45651305EF4A63B40C7D8C42D91EDA397D8F51CBC9D0A531FE2C6F1E55E9357D205C39D395358968CBEDAC11320C607BE16CB9DB492B6E78163305A34DD99CE43C64927D13A0040EB97"), + Q: bigFromHexString("009A67067F66A323F5D4EC7902C73FE5D9E36FA74F"), + G: bigFromHexString("009147778295BF5893542BC41BA806898A29E43261DBC85441C37D92E97ED80D323D44825FDDE8374D0FF15877798812682599B216BBCC31B9DCCAD527465FEAFFD7FC2A193612E575E34E7A98AF4D10339FE47390A518CB9975B3160B1D0285D1418D0977C52994F43C29A053E3D685834104C9FAFDC221E38BE9F3989D7A8E42"), + }, + Y: bigFromHexString("59A27C269FCDE45AA2160A5C980C19211A820095091AB9C5DC8309AB7EC1B3A48C2E267C6D35FEE9B71BCBB92F16AC8E559129347FB5C00BEEDD10BA8915C90698755CA965735A32DC7575BED806E1E38F768FFBC24E41123DC73F1C6E9E4D0C9E692128853AFE29DC665FA993DCA9C903B7BF00B6442B9A76A5DADC6186317A"), + } + pemBlock, _ := pem.Decode([]byte(dsaCertPem)) + cert, err := ParseCertificate(pemBlock.Bytes) + if err != nil { + t.Fatalf("Failed to parse certificate: %s", err) + } + if cert.PublicKeyAlgorithm != DSA { + t.Errorf("Parsed key algorithm was not DSA") + } + parsedKey, ok := cert.PublicKey.(*dsa.PublicKey) + if !ok { + t.Fatalf("Parsed key was not a DSA key: %s", err) + } + if expectedKey.Y.Cmp(parsedKey.Y) != 0 || + expectedKey.P.Cmp(parsedKey.P) != 0 || + expectedKey.Q.Cmp(parsedKey.Q) != 0 || + expectedKey.G.Cmp(parsedKey.G) != 0 { + t.Fatal("Parsed key differs from expected key") + } +} + +func TestParseCertificateWithDSASignatureAlgorithm(t *testing.T) { + pemBlock, _ := pem.Decode([]byte(dsaCertPem)) + cert, err := ParseCertificate(pemBlock.Bytes) + if err != nil { + t.Fatalf("Failed to parse certificate: %s", err) + } + if cert.SignatureAlgorithm != DSAWithSHA1 { + t.Errorf("Parsed signature algorithm was not DSAWithSHA1") + } +} + +func TestVerifyCertificateWithDSASignature(t *testing.T) { + pemBlock, _ := pem.Decode([]byte(dsaCertPem)) + cert, err := ParseCertificate(pemBlock.Bytes) + if err != nil { + t.Fatalf("Failed to parse certificate: %s", err) + } + // test cert is self-signed + if err = cert.CheckSignatureFrom(cert); err != nil { + t.Fatalf("DSA Certificate verfication failed: %s", err) + } +} + +const pemCertificate = `-----BEGIN CERTIFICATE----- +MIIB5DCCAZCgAwIBAgIBATALBgkqhkiG9w0BAQUwLTEQMA4GA1UEChMHQWNtZSBDbzEZMBcGA1UE +AxMQdGVzdC5leGFtcGxlLmNvbTAeFw03MDAxMDEwMDE2NDBaFw03MDAxMDIwMzQ2NDBaMC0xEDAO +BgNVBAoTB0FjbWUgQ28xGTAXBgNVBAMTEHRlc3QuZXhhbXBsZS5jb20wWjALBgkqhkiG9w0BAQED +SwAwSAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0fd7Ai2KW5ToIwzFo +fvJcS/STa6HA5gQenRUCAwEAAaOBnjCBmzAOBgNVHQ8BAf8EBAMCAAQwDwYDVR0TAQH/BAUwAwEB +/zANBgNVHQ4EBgQEAQIDBDAPBgNVHSMECDAGgAQBAgMEMBsGA1UdEQQUMBKCEHRlc3QuZXhhbXBs +ZS5jb20wDwYDVR0gBAgwBjAEBgIqAzAqBgNVHR4EIzAhoB8wDoIMLmV4YW1wbGUuY29tMA2CC2V4 +YW1wbGUuY29tMAsGCSqGSIb3DQEBBQNBAHKZKoS1wEQOGhgklx4+/yFYQlnqwKXvar/ZecQvJwui +0seMQnwBhwdBkHfVIU2Fu5VUMRyxlf0ZNaDXcpU581k= +-----END CERTIFICATE-----` + +func TestCRLCreation(t *testing.T) { + block, _ := pem.Decode([]byte(pemPrivateKey)) + priv, _ := ParsePKCS1PrivateKey(block.Bytes) + block, _ = pem.Decode([]byte(pemCertificate)) + cert, _ := ParseCertificate(block.Bytes) + + now := time.SecondsToUTC(1000) + expiry := time.SecondsToUTC(10000) + + revokedCerts := []pkix.RevokedCertificate{ + { + SerialNumber: big.NewInt(1), + RevocationTime: now, + }, + { + SerialNumber: big.NewInt(42), + RevocationTime: now, + }, + } + + crlBytes, err := cert.CreateCRL(rand.Reader, priv, revokedCerts, now, expiry) + if err != nil { + t.Errorf("error creating CRL: %s", err) + } + + _, err = ParseDERCRL(crlBytes) + if err != nil { + t.Errorf("error reparsing CRL: %s", err) + } +} + +func fromBase64(in string) []byte { + out := make([]byte, base64.StdEncoding.DecodedLen(len(in))) + _, err := base64.StdEncoding.Decode(out, []byte(in)) + if err != nil { + panic("failed to base64 decode") + } + return out +} + +func TestParseDERCRL(t *testing.T) { + derBytes := fromBase64(derCRLBase64) + certList, err := ParseDERCRL(derBytes) + if err != nil { + t.Errorf("error parsing: %s", err) + return + } + numCerts := len(certList.TBSCertList.RevokedCertificates) + expected := 88 + if numCerts != expected { + t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected) + } + + if certList.HasExpired(1302517272) { + t.Errorf("CRL has expired (but shouldn't have)") + } + + // Can't check the signature here without a package cycle. +} + +func TestParsePEMCRL(t *testing.T) { + pemBytes := fromBase64(pemCRLBase64) + certList, err := ParseCRL(pemBytes) + if err != nil { + t.Errorf("error parsing: %s", err) + return + } + numCerts := len(certList.TBSCertList.RevokedCertificates) + expected := 2 + if numCerts != expected { + t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected) + } + + if certList.HasExpired(1302517272) { + t.Errorf("CRL has expired (but shouldn't have)") + } + + // Can't check the signature here without a package cycle. +} + +const derCRLBase64 = "MIINqzCCDJMCAQEwDQYJKoZIhvcNAQEFBQAwVjEZMBcGA1UEAxMQUEtJIEZJTk1FQ0NBTklDQTEVMBMGA1UEChMMRklOTUVDQ0FOSUNBMRUwEwYDVQQLEwxGSU5NRUNDQU5JQ0ExCzAJBgNVBAYTAklUFw0xMTA1MDQxNjU3NDJaFw0xMTA1MDQyMDU3NDJaMIIMBzAhAg4Ze1od49Lt1qIXBydAzhcNMDkwNzE2MDg0MzIyWjAAMCECDl0HSL9bcZ1Ci/UHJ0DPFw0wOTA3MTYwODQzMTNaMAAwIQIOESB9tVAmX3cY7QcnQNAXDTA5MDcxNjA4NDUyMlowADAhAg4S1tGAQ3mHt8uVBydA1RcNMDkwODA0MTUyNTIyWjAAMCECDlQ249Y7vtC25ScHJ0DWFw0wOTA4MDQxNTI1MzdaMAAwIQIOISMop3NkA4PfYwcnQNkXDTA5MDgwNDExMDAzNFowADAhAg56/BMoS29KEShTBydA2hcNMDkwODA0MTEwMTAzWjAAMCECDnBp/22HPH5CSWoHJ0DbFw0wOTA4MDQxMDU0NDlaMAAwIQIOV9IP+8CD8bK+XAcnQNwXDTA5MDgwNDEwNTcxN1owADAhAg4v5aRz0IxWqYiXBydA3RcNMDkwODA0MTA1NzQ1WjAAMCECDlOU34VzvZAybQwHJ0DeFw0wOTA4MDQxMDU4MjFaMAAwIAINO4CD9lluIxcwBydBAxcNMDkwNzIyMTUzMTU5WjAAMCECDgOllfO8Y1QA7/wHJ0ExFw0wOTA3MjQxMTQxNDNaMAAwIQIOJBX7jbiCdRdyjgcnQUQXDTA5MDkxNjA5MzAwOFowADAhAg5iYSAgmDrlH/RZBydBRRcNMDkwOTE2MDkzMDE3WjAAMCECDmu6k6srP3jcMaQHJ0FRFw0wOTA4MDQxMDU2NDBaMAAwIQIOX8aHlO0V+WVH4QcnQVMXDTA5MDgwNDEwNTcyOVowADAhAg5flK2rg3NnsRgDBydBzhcNMTEwMjAxMTUzMzQ2WjAAMCECDg35yJDL1jOPTgoHJ0HPFw0xMTAyMDExNTM0MjZaMAAwIQIOMyFJ6+e9iiGVBQcnQdAXDTA5MDkxODEzMjAwNVowADAhAg5Emb/Oykucmn8fBydB1xcNMDkwOTIxMTAxMDQ3WjAAMCECDjQKCncV+MnUavMHJ0HaFw0wOTA5MjIwODE1MjZaMAAwIQIOaxiFUt3dpd+tPwcnQfQXDTEwMDYxODA4NDI1MVowADAhAg5G7P8nO0tkrMt7BydB9RcNMTAwNjE4MDg0MjMwWjAAMCECDmTCC3SXhmDRst4HJ0H2Fw0wOTA5MjgxMjA3MjBaMAAwIQIOHoGhUr/pRwzTKgcnQfcXDTA5MDkyODEyMDcyNFowADAhAg50wrcrCiw8mQmPBydCBBcNMTAwMjE2MTMwMTA2WjAAMCECDifWmkvwyhEqwEcHJ0IFFw0xMDAyMTYxMzAxMjBaMAAwIQIOfgPmlW9fg+osNgcnQhwXDTEwMDQxMzA5NTIwMFowADAhAg4YHAGuA6LgCk7tBydCHRcNMTAwNDEzMDk1MTM4WjAAMCECDi1zH1bxkNJhokAHJ0IsFw0xMDA0MTMwOTU5MzBaMAAwIQIOMipNccsb/wo2fwcnQi0XDTEwMDQxMzA5NTkwMFowADAhAg46lCmvPl4GpP6ABydCShcNMTAwMTE5MDk1MjE3WjAAMCECDjaTcaj+wBpcGAsHJ0JLFw0xMDAxMTkwOTUyMzRaMAAwIQIOOMC13EOrBuxIOQcnQloXDTEwMDIwMTA5NDcwNVowADAhAg5KmZl+krz4RsmrBydCWxcNMTAwMjAxMDk0NjQwWjAAMCECDmLG3zQJ/fzdSsUHJ0JiFw0xMDAzMDEwOTUxNDBaMAAwIQIOP39ksgHdojf4owcnQmMXDTEwMDMwMTA5NTExN1owADAhAg4LDQzvWNRlD6v9BydCZBcNMTAwMzAxMDk0NjIyWjAAMCECDkmNfeclaFhIaaUHJ0JlFw0xMDAzMDEwOTQ2MDVaMAAwIQIOT/qWWfpH/m8NTwcnQpQXDTEwMDUxMTA5MTgyMVowADAhAg5m/ksYxvCEgJSvBydClRcNMTAwNTExMDkxODAxWjAAMCECDgvf3Ohq6JOPU9AHJ0KWFw0xMDA1MTEwOTIxMjNaMAAwIQIOKSPas10z4jNVIQcnQpcXDTEwMDUxMTA5MjEwMlowADAhAg4mCWmhoZ3lyKCDBydCohcNMTEwNDI4MTEwMjI1WjAAMCECDkeiyRsBMK0Gvr4HJ0KjFw0xMTA0MjgxMTAyMDdaMAAwIQIOa09b/nH2+55SSwcnQq4XDTExMDQwMTA4Mjk0NlowADAhAg5O7M7iq7gGplr1BydCrxcNMTEwNDAxMDgzMDE3WjAAMCECDjlT6mJxUjTvyogHJ0K1Fw0xMTAxMjcxNTQ4NTJaMAAwIQIODS/l4UUFLe21NAcnQrYXDTExMDEyNzE1NDgyOFowADAhAg5lPRA0XdOUF6lSBydDHhcNMTEwMTI4MTQzNTA1WjAAMCECDixKX4fFGGpENwgHJ0MfFw0xMTAxMjgxNDM1MzBaMAAwIQIORNBkqsPnpKTtbAcnQ08XDTEwMDkwOTA4NDg0MlowADAhAg5QL+EMM3lohedEBydDUBcNMTAwOTA5MDg0ODE5WjAAMCECDlhDnHK+HiTRAXcHJ0NUFw0xMDEwMTkxNjIxNDBaMAAwIQIOdBFqAzq/INz53gcnQ1UXDTEwMTAxOTE2MjA0NFowADAhAg4OjR7s8MgKles1BydDWhcNMTEwMTI3MTY1MzM2WjAAMCECDmfR/elHee+d0SoHJ0NbFw0xMTAxMjcxNjUzNTZaMAAwIQIOBTKv2ui+KFMI+wcnQ5YXDTEwMDkxNTEwMjE1N1owADAhAg49F3c/GSah+oRUBydDmxcNMTEwMTI3MTczMjMzWjAAMCECDggv4I61WwpKFMMHJ0OcFw0xMTAxMjcxNzMyNTVaMAAwIQIOXx/Y8sEvwS10LAcnQ6UXDTExMDEyODExMjkzN1owADAhAg5LSLbnVrSKaw/9BydDphcNMTEwMTI4MTEyOTIwWjAAMCECDmFFoCuhKUeACQQHJ0PfFw0xMTAxMTExMDE3MzdaMAAwIQIOQTDdFh2fSPF6AAcnQ+AXDTExMDExMTEwMTcxMFowADAhAg5B8AOXX61FpvbbBydD5RcNMTAxMDA2MTAxNDM2WjAAMCECDh41P2Gmi7PkwI4HJ0PmFw0xMDEwMDYxMDE2MjVaMAAwIQIOWUHGLQCd+Ale9gcnQ/0XDTExMDUwMjA3NTYxMFowADAhAg5Z2c9AYkikmgWOBydD/hcNMTEwNTAyMDc1NjM0WjAAMCECDmf/UD+/h8nf+74HJ0QVFw0xMTA0MTUwNzI4MzNaMAAwIQIOICvj4epy3MrqfwcnRBYXDTExMDQxNTA3Mjg1NlowADAhAg4bouRMfOYqgv4xBydEHxcNMTEwMzA4MTYyNDI1WjAAMCECDhebWHGoKiTp7pEHJ0QgFw0xMTAzMDgxNjI0NDhaMAAwIQIOX+qnxxAqJ8LtawcnRDcXDTExMDEzMTE1MTIyOFowADAhAg4j0fICqZ+wkOdqBydEOBcNMTEwMTMxMTUxMTQxWjAAMCECDhmXjsV4SUpWtAMHJ0RLFw0xMTAxMjgxMTI0MTJaMAAwIQIODno/w+zG43kkTwcnREwXDTExMDEyODExMjM1MlowADAhAg4b1gc88767Fr+LBydETxcNMTEwMTI4MTEwMjA4WjAAMCECDn+M3Pa1w2nyFeUHJ0RQFw0xMTAxMjgxMDU4NDVaMAAwIQIOaduoyIH61tqybAcnRJUXDTEwMTIxNTA5NDMyMlowADAhAg4nLqQPkyi3ESAKBydElhcNMTAxMjE1MDk0MzM2WjAAMCECDi504NIMH8578gQHJ0SbFw0xMTAyMTQxNDA1NDFaMAAwIQIOGuaM8PDaC5u1egcnRJwXDTExMDIxNDE0MDYwNFowADAhAg4ehYq/BXGnB5PWBydEnxcNMTEwMjA0MDgwOTUxWjAAMCECDkSD4eS4FxW5H20HJ0SgFw0xMTAyMDQwODA5MjVaMAAwIQIOOCcb6ilYObt1egcnRKEXDTExMDEyNjEwNDEyOVowADAhAg58tISWCCwFnKGnBydEohcNMTEwMjA0MDgxMzQyWjAAMCECDn5rjtabY/L/WL0HJ0TJFw0xMTAyMDQxMTAzNDFaMAAwDQYJKoZIhvcNAQEFBQADggEBAGnF2Gs0+LNiYCW1Ipm83OXQYP/bd5tFFRzyz3iepFqNfYs4D68/QihjFoRHQoXEB0OEe1tvaVnnPGnEOpi6krwekquMxo4H88B5SlyiFIqemCOIss0SxlCFs69LmfRYvPPvPEhoXtQ3ZThe0UvKG83GOklhvGl6OaiRf4Mt+m8zOT4Wox/j6aOBK6cw6qKCdmD+Yj1rrNqFGg1CnSWMoD6S6mwNgkzwdBUJZ22BwrzAAo4RHa2Uy3ef1FjwD0XtU5N3uDSxGGBEDvOe5z82rps3E22FpAA8eYl8kaXtmWqyvYU0epp4brGuTxCuBMCAsxt/OjIjeNNQbBGkwxgfYA0=" + +const pemCRLBase64 = "LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tDQpNSUlCOWpDQ0FWOENBUUV3RFFZSktvWklodmNOQVFFRkJRQXdiREVhTUJnR0ExVUVDaE1SVWxOQklGTmxZM1Z5DQphWFI1SUVsdVl5NHhIakFjQmdOVkJBTVRGVkpUUVNCUWRXSnNhV01nVW05dmRDQkRRU0IyTVRFdU1Dd0dDU3FHDQpTSWIzRFFFSkFSWWZjbk5oYTJWdmJuSnZiM1J6YVdkdVFISnpZWE5sWTNWeWFYUjVMbU52YlJjTk1URXdNakl6DQpNVGt5T0RNd1doY05NVEV3T0RJeU1Ua3lPRE13V2pDQmpEQktBaEVBckRxb2g5RkhKSFhUN09QZ3V1bjQrQmNODQpNRGt4TVRBeU1UUXlOekE1V2pBbU1Bb0dBMVVkRlFRRENnRUpNQmdHQTFVZEdBUVJHQTh5TURBNU1URXdNakUwDQpNalExTlZvd1BnSVJBTEd6blowOTVQQjVhQU9MUGc1N2ZNTVhEVEF5TVRBeU16RTBOVEF4TkZvd0dqQVlCZ05WDQpIUmdFRVJnUE1qQXdNakV3TWpNeE5EVXdNVFJhb0RBd0xqQWZCZ05WSFNNRUdEQVdnQlQxVERGNlVRTS9MTmVMDQpsNWx2cUhHUXEzZzltekFMQmdOVkhSUUVCQUlDQUlRd0RRWUpLb1pJaHZjTkFRRUZCUUFEZ1lFQUZVNUFzNk16DQpxNVBSc2lmYW9iUVBHaDFhSkx5QytNczVBZ2MwYld5QTNHQWR4dXI1U3BQWmVSV0NCamlQL01FSEJXSkNsQkhQDQpHUmNxNXlJZDNFakRrYUV5eFJhK2k2N0x6dmhJNmMyOUVlNks5cFNZd2ppLzdSVWhtbW5Qclh0VHhsTDBsckxyDQptUVFKNnhoRFJhNUczUUE0Q21VZHNITnZicnpnbUNZcHZWRT0NCi0tLS0tRU5EIFg1MDkgQ1JMLS0tLS0NCg0K" diff --git a/libgo/go/crypto/xtea/block.go b/libgo/go/crypto/xtea/block.go index 3ac36d0..bf5d245 100644 --- a/libgo/go/crypto/xtea/block.go +++ b/libgo/go/crypto/xtea/block.go @@ -22,7 +22,7 @@ func blockToUint32(src []byte) (uint32, uint32) { return r0, r1 } -// uint32ToBlock writes two unint32s into an 8 byte data block. +// uint32ToBlock writes two uint32s into an 8 byte data block. // Values are written as big endian. func uint32ToBlock(v0, v1 uint32, dst []byte) { dst[0] = byte(v0 >> 24) diff --git a/libgo/go/crypto/xtea/cipher.go b/libgo/go/crypto/xtea/cipher.go index f2a5da0..b3fba3c8 100644 --- a/libgo/go/crypto/xtea/cipher.go +++ b/libgo/go/crypto/xtea/cipher.go @@ -48,13 +48,13 @@ func NewCipher(key []byte) (*Cipher, os.Error) { // BlockSize returns the XTEA block size, 8 bytes. // It is necessary to satisfy the Cipher interface in the -// package "crypto/block". +// package "crypto/cipher". func (c *Cipher) BlockSize() int { return BlockSize } // Encrypt encrypts the 8 byte buffer src using the key and stores the result in dst. // Note that for amounts of data larger than a block, // it is not safe to just call Encrypt on successive blocks; -// instead, use an encryption mode like CBC (see crypto/block/cbc.go). +// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go). func (c *Cipher) Encrypt(dst, src []byte) { encryptBlock(c, dst, src) } // Decrypt decrypts the 8 byte buffer src using the key k and stores the result in dst. diff --git a/libgo/go/crypto/xtea/xtea_test.go b/libgo/go/crypto/xtea/xtea_test.go index 03934f1..217d96a 100644 --- a/libgo/go/crypto/xtea/xtea_test.go +++ b/libgo/go/crypto/xtea/xtea_test.go @@ -8,7 +8,7 @@ import ( "testing" ) -// A sample test key for when we just want to initialise a cipher +// A sample test key for when we just want to initialize a cipher var testKey = []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF} // Test that the block size for XTEA is correct @@ -26,12 +26,12 @@ func TestBlocksize(t *testing.T) { result := c.BlockSize() if result != 8 { - t.Errorf("BlockSize function - expected 8, gotr %d", result) + t.Errorf("BlockSize function - expected 8, got %d", result) return } } -// A series of test values to confirm that the Cipher.table array was initialised correctly +// A series of test values to confirm that the Cipher.table array was initialized correctly var testTable = []uint32{ 0x00112233, 0x6B1568B8, 0xE28CE030, 0xC5089E2D, 0xC5089E2D, 0x1EFBD3A2, 0xA7845C2A, 0x78EF0917, 0x78EF0917, 0x172682D0, 0x5B6AC714, 0x822AC955, 0x3DE68511, 0xDC1DFECA, 0x2062430E, 0x3611343F, @@ -43,7 +43,7 @@ var testTable = []uint32{ 0x4E22726F, 0x309E306C, 0x309E306C, 0x8A9165E1, 0x1319EE69, 0xF595AC66, 0xF595AC66, 0x4F88E1DB, } -// Test that the cipher context is initialised correctly +// Test that the cipher context is initialized correctly func TestCipherInit(t *testing.T) { c, err := NewCipher(testKey) if err != nil { @@ -53,7 +53,7 @@ func TestCipherInit(t *testing.T) { for i := 0; i < len(c.table); i++ { if c.table[i] != testTable[i] { - t.Errorf("NewCipher() failed to initialise Cipher.table[%d] correctly. Expected %08X, got %08X", i, testTable[i], c.table[i]) + t.Errorf("NewCipher() failed to initialize Cipher.table[%d] correctly. Expected %08X, got %08X", i, testTable[i], c.table[i]) break } } diff --git a/libgo/go/csv/reader.go b/libgo/go/csv/reader.go new file mode 100644 index 0000000..ea2c266 --- /dev/null +++ b/libgo/go/csv/reader.go @@ -0,0 +1,372 @@ +// 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 csv reads and writes comma-separated values (CSV) files. +// +// A csv file contains zero or more records of one or more fields per record. +// Each record is separated by the newline character. The final record may +// optionally be followed by a newline character. +// +// field1,field2,field3 +// +// White space is considered part of a field. +// +// Carriage returns before newline characters are silently removed. +// +// Blank lines are ignored. A line with only whitespace characters (excluding +// the ending newline character) is not considered a blank line. +// +// Fields which start and stop with the quote character " are called +// quoted-fields. The beginning and ending quote are not part of the +// field. +// +// The source: +// +// normal string,"quoted-field" +// +// results in the fields +// +// {`normal string`, `quoted-field`} +// +// Within a quoted-field a quote character followed by a second quote +// character is considered a single quote. +// +// "the ""word"" is true","a ""quoted-field""" +// +// results in +// +// {`the "word" is true`, `a "quoted-field"`} +// +// Newlines and commas may be included in a quoted-field +// +// "Multi-line +// field","comma is ," +// +// results in +// +// {`Multi-line +// field`, `comma is ,`} +package csv + +import ( + "bufio" + "bytes" + "fmt" + "io" + "os" + "unicode" +) + +// A ParseError is returned for parsing errors. +// The first line is 1. The first column is 0. +type ParseError struct { + Line int // Line where the error occurred + Column int // Column (rune index) where the error occurred + Error os.Error // The actual error +} + +func (e *ParseError) String() string { + return fmt.Sprintf("line %d, column %d: %s", e.Line, e.Column, e.Error) +} + +// These are the errors that can be returned in ParseError.Error +var ( + ErrTrailingComma = os.NewError("extra delimiter at end of line") + ErrBareQuote = os.NewError("bare \" in non-quoted-field") + ErrQuote = os.NewError("extraneous \" in field") + ErrFieldCount = os.NewError("wrong number of fields in line") +) + +// A Reader reads records from a CSV-encoded file. +// +// As returned by NewReader, a Reader expects input conforming to RFC 4180. +// The exported fields can be changed to customize the details before the +// first call to Read or ReadAll. +// +// Comma is the field delimiter. It defaults to ','. +// +// Comment, if not 0, is the comment character. Lines beginning with the +// Comment character are ignored. +// +// If FieldsPerRecord is positive, Read requires each record to +// have the given number of fields. If FieldsPerRecord is 0, Read sets it to +// the number of fields in the first record, so that future records must +// have the same field count. +// +// If LazyQuotes is true, a quote may appear in an unquoted field and a +// non-doubled quote may appear in a quoted field. +// +// If TrailingComma is true, the last field may be an unquoted empty field. +// +// If TrimLeadingSpace is true, leading white space in a field is ignored. +type Reader struct { + Comma int // Field delimiter (set to ',' by NewReader) + Comment int // Comment character for start of line + FieldsPerRecord int // Number of expected fields per record + LazyQuotes bool // Allow lazy quotes + TrailingComma bool // Allow trailing comma + TrimLeadingSpace bool // Trim leading space + line int + column int + r *bufio.Reader + field bytes.Buffer +} + +// NewReader returns a new Reader that reads from r. +func NewReader(r io.Reader) *Reader { + return &Reader{ + Comma: ',', + r: bufio.NewReader(r), + } +} + +// error creates a new ParseError based on err. +func (r *Reader) error(err os.Error) os.Error { + return &ParseError{ + Line: r.line, + Column: r.column, + Error: err, + } +} + +// Read reads one record from r. The record is a slice of strings with each +// string representing one field. +func (r *Reader) Read() (record []string, err os.Error) { + for { + record, err = r.parseRecord() + if record != nil { + break + } + if err != nil { + return nil, err + } + } + + if r.FieldsPerRecord > 0 { + if len(record) != r.FieldsPerRecord { + r.column = 0 // report at start of record + return record, r.error(ErrFieldCount) + } + } else if r.FieldsPerRecord == 0 { + r.FieldsPerRecord = len(record) + } + return record, nil +} + +// ReadAll reads all the remaining records from r. +// Each record is a slice of fields. +func (r *Reader) ReadAll() (records [][]string, err os.Error) { + for { + record, err := r.Read() + if err == os.EOF { + return records, nil + } + if err != nil { + return nil, err + } + records = append(records, record) + } + panic("unreachable") +} + +// readRune reads one rune from r, folding \r\n to \n and keeping track +// of how far into the line we have read. r.column will point to the start +// of this rune, not the end of this rune. +func (r *Reader) readRune() (int, os.Error) { + rune, _, err := r.r.ReadRune() + + // Handle \r\n here. We make the simplifying assumption that + // anytime \r is followed by \n that it can be folded to \n. + // We will not detect files which contain both \r\n and bare \n. + if rune == '\r' { + rune, _, err = r.r.ReadRune() + if err == nil { + if rune != '\n' { + r.r.UnreadRune() + rune = '\r' + } + } + } + r.column++ + return rune, err +} + +// unreadRune puts the last rune read from r back. +func (r *Reader) unreadRune() { + r.r.UnreadRune() + r.column-- +} + +// skip reads runes up to and including the rune delim or until error. +func (r *Reader) skip(delim int) os.Error { + for { + rune, err := r.readRune() + if err != nil { + return err + } + if rune == delim { + return nil + } + } + panic("unreachable") +} + +// parseRecord reads and parses a single csv record from r. +func (r *Reader) parseRecord() (fields []string, err os.Error) { + // Each record starts on a new line. We increment our line + // number (lines start at 1, not 0) and set column to -1 + // so as we increment in readRune it points to the character we read. + r.line++ + r.column = -1 + + // Peek at the first rune. If it is an error we are done. + // If we are support comments and it is the comment character + // then skip to the end of line. + + rune, _, err := r.r.ReadRune() + if err != nil { + return nil, err + } + + if r.Comment != 0 && rune == r.Comment { + return nil, r.skip('\n') + } + r.r.UnreadRune() + + // At this point we have at least one field. + for { + haveField, delim, err := r.parseField() + if haveField { + fields = append(fields, r.field.String()) + } + if delim == '\n' || err == os.EOF { + return fields, err + } else if err != nil { + return nil, err + } + } + panic("unreachable") +} + +// parseField parses the next field in the record. The read field is +// located in r.field. Delim is the first character not part of the field +// (r.Comma or '\n'). +func (r *Reader) parseField() (haveField bool, delim int, err os.Error) { + r.field.Reset() + + rune, err := r.readRune() + if err != nil { + // If we have EOF and are not at the start of a line + // then we return the empty field. We have already + // checked for trailing commas if needed. + if err == os.EOF && r.column != 0 { + return true, 0, err + } + return false, 0, err + } + + if r.TrimLeadingSpace { + for unicode.IsSpace(rune) { + rune, err = r.readRune() + if err != nil { + return false, 0, err + } + } + } + + switch rune { + case r.Comma: + // will check below + + case '\n': + // We are a trailing empty field or a blank line + if r.column == 0 { + return false, rune, nil + } + return true, rune, nil + + case '"': + // quoted field + Quoted: + for { + rune, err = r.readRune() + if err != nil { + if err == os.EOF { + if r.LazyQuotes { + return true, 0, err + } + return false, 0, r.error(ErrQuote) + } + return false, 0, err + } + switch rune { + case '"': + rune, err = r.readRune() + if err != nil || rune == r.Comma { + break Quoted + } + if rune == '\n' { + return true, rune, nil + } + if rune != '"' { + if !r.LazyQuotes { + r.column-- + return false, 0, r.error(ErrQuote) + } + // accept the bare quote + r.field.WriteRune('"') + } + case '\n': + r.line++ + r.column = -1 + } + r.field.WriteRune(rune) + } + + default: + // unquoted field + for { + r.field.WriteRune(rune) + rune, err = r.readRune() + if err != nil || rune == r.Comma { + break + } + if rune == '\n' { + return true, rune, nil + } + if !r.LazyQuotes && rune == '"' { + return false, 0, r.error(ErrBareQuote) + } + } + } + + if err != nil { + if err == os.EOF { + return true, 0, err + } + return false, 0, err + } + + if !r.TrailingComma { + // We don't allow trailing commas. See if we + // are at the end of the line (being mindful + // of trimming spaces). + c := r.column + rune, err = r.readRune() + if r.TrimLeadingSpace { + for unicode.IsSpace(rune) { + rune, err = r.readRune() + if err != nil { + break + } + } + } + if err == os.EOF || rune == '\n' { + r.column = c // report the comma + return false, 0, r.error(ErrTrailingComma) + } + r.unreadRune() + } + return true, rune, nil +} diff --git a/libgo/go/csv/reader_test.go b/libgo/go/csv/reader_test.go new file mode 100644 index 0000000..0068bad --- /dev/null +++ b/libgo/go/csv/reader_test.go @@ -0,0 +1,265 @@ +// 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 csv + +import ( + "reflect" + "strings" + "testing" +) + +var readTests = []struct { + Name string + Input string + Output [][]string + UseFieldsPerRecord bool // false (default) means FieldsPerRecord is -1 + + // These fields are copied into the Reader + Comma int + Comment int + FieldsPerRecord int + LazyQuotes bool + TrailingComma bool + TrimLeadingSpace bool + + Error string + Line int // Expected error line if != 0 + Column int // Expected error column if line != 0 +}{ + { + Name: "Simple", + Input: "a,b,c\n", + Output: [][]string{{"a", "b", "c"}}, + }, + { + Name: "CRLF", + Input: "a,b\r\nc,d\r\n", + Output: [][]string{{"a", "b"}, {"c", "d"}}, + }, + { + Name: "BareCR", + Input: "a,b\rc,d\r\n", + Output: [][]string{{"a", "b\rc", "d"}}, + }, + { + Name: "RFC4180test", + UseFieldsPerRecord: true, + Input: `#field1,field2,field3 +"aaa","bb +b","ccc" +"a,a","b""bb","ccc" +zzz,yyy,xxx +`, + Output: [][]string{ + {"#field1", "field2", "field3"}, + {"aaa", "bb\nb", "ccc"}, + {"a,a", `b"bb`, "ccc"}, + {"zzz", "yyy", "xxx"}, + }, + }, + { + Name: "NoEOLTest", + Input: "a,b,c", + Output: [][]string{{"a", "b", "c"}}, + }, + { + Name: "Semicolon", + Comma: ';', + Input: "a;b;c\n", + Output: [][]string{{"a", "b", "c"}}, + }, + { + Name: "MultiLine", + Input: `"two +line","one line","three +line +field"`, + Output: [][]string{{"two\nline", "one line", "three\nline\nfield"}}, + }, + { + Name: "BlankLine", + Input: "a,b,c\n\nd,e,f\n\n", + Output: [][]string{ + {"a", "b", "c"}, + {"d", "e", "f"}, + }, + }, + { + Name: "TrimSpace", + Input: " a, b, c\n", + TrimLeadingSpace: true, + Output: [][]string{{"a", "b", "c"}}, + }, + { + Name: "LeadingSpace", + Input: " a, b, c\n", + Output: [][]string{{" a", " b", " c"}}, + }, + { + Name: "Comment", + Comment: '#', + Input: "#1,2,3\na,b,c\n#comment", + Output: [][]string{{"a", "b", "c"}}, + }, + { + Name: "NoComment", + Input: "#1,2,3\na,b,c", + Output: [][]string{{"#1", "2", "3"}, {"a", "b", "c"}}, + }, + { + Name: "LazyQuotes", + LazyQuotes: true, + Input: `a "word","1"2",a","b`, + Output: [][]string{{`a "word"`, `1"2`, `a"`, `b`}}, + }, + { + Name: "BareQuotes", + LazyQuotes: true, + Input: `a "word","1"2",a"`, + Output: [][]string{{`a "word"`, `1"2`, `a"`}}, + }, + { + Name: "BareDoubleQuotes", + LazyQuotes: true, + Input: `a""b,c`, + Output: [][]string{{`a""b`, `c`}}, + }, + { + Name: "BadDoubleQuotes", + Input: `a""b,c`, + Output: [][]string{{`a""b`, `c`}}, + Error: `bare " in non-quoted-field`, Line: 1, Column: 1, + }, + { + Name: "TrimQuote", + Input: ` "a"," b",c`, + TrimLeadingSpace: true, + Output: [][]string{{"a", " b", "c"}}, + }, + { + Name: "BadBareQuote", + Input: `a "word","b"`, + Error: `bare " in non-quoted-field`, Line: 1, Column: 2, + }, + { + Name: "BadTrailingQuote", + Input: `"a word",b"`, + Error: `bare " in non-quoted-field`, Line: 1, Column: 10, + }, + { + Name: "ExtraneousQuote", + Input: `"a "word","b"`, + Error: `extraneous " in field`, Line: 1, Column: 3, + }, + { + Name: "BadFieldCount", + UseFieldsPerRecord: true, + Input: "a,b,c\nd,e", + Error: "wrong number of fields", Line: 2, + }, + { + Name: "BadFieldCount1", + UseFieldsPerRecord: true, + FieldsPerRecord: 2, + Input: `a,b,c`, + Error: "wrong number of fields", Line: 1, + }, + { + Name: "FieldCount", + Input: "a,b,c\nd,e", + Output: [][]string{{"a", "b", "c"}, {"d", "e"}}, + }, + { + Name: "BadTrailingCommaEOF", + Input: "a,b,c,", + Error: "extra delimiter at end of line", Line: 1, Column: 5, + }, + { + Name: "BadTrailingCommaEOL", + Input: "a,b,c,\n", + Error: "extra delimiter at end of line", Line: 1, Column: 5, + }, + { + Name: "BadTrailingCommaSpaceEOF", + TrimLeadingSpace: true, + Input: "a,b,c, ", + Error: "extra delimiter at end of line", Line: 1, Column: 5, + }, + { + Name: "BadTrailingCommaSpaceEOL", + TrimLeadingSpace: true, + Input: "a,b,c, \n", + Error: "extra delimiter at end of line", Line: 1, Column: 5, + }, + { + Name: "BadTrailingCommaLine3", + TrimLeadingSpace: true, + Input: "a,b,c\nd,e,f\ng,hi,", + Error: "extra delimiter at end of line", Line: 3, Column: 4, + }, + { + Name: "NotTrailingComma3", + Input: "a,b,c, \n", + Output: [][]string{{"a", "b", "c", " "}}, + }, + { + Name: "CommaFieldTest", + TrailingComma: true, + Input: `x,y,z,w +x,y,z, +x,y,, +x,,, +,,, +"x","y","z","w" +"x","y","z","" +"x","y","","" +"x","","","" +"","","","" +`, + Output: [][]string{ + {"x", "y", "z", "w"}, + {"x", "y", "z", ""}, + {"x", "y", "", ""}, + {"x", "", "", ""}, + {"", "", "", ""}, + {"x", "y", "z", "w"}, + {"x", "y", "z", ""}, + {"x", "y", "", ""}, + {"x", "", "", ""}, + {"", "", "", ""}, + }, + }, +} + +func TestRead(t *testing.T) { + for _, tt := range readTests { + r := NewReader(strings.NewReader(tt.Input)) + r.Comment = tt.Comment + if tt.UseFieldsPerRecord { + r.FieldsPerRecord = tt.FieldsPerRecord + } else { + r.FieldsPerRecord = -1 + } + r.LazyQuotes = tt.LazyQuotes + r.TrailingComma = tt.TrailingComma + r.TrimLeadingSpace = tt.TrimLeadingSpace + if tt.Comma != 0 { + r.Comma = tt.Comma + } + out, err := r.ReadAll() + perr, _ := err.(*ParseError) + if tt.Error != "" { + if err == nil || !strings.Contains(err.String(), tt.Error) { + t.Errorf("%s: error %v, want error %q", tt.Name, err, tt.Error) + } else if tt.Line != 0 && (tt.Line != perr.Line || tt.Column != perr.Column) { + t.Errorf("%s: error at %d:%d expected %d:%d", tt.Name, perr.Line, perr.Column, tt.Line, tt.Column) + } + } else if err != nil { + t.Errorf("%s: unexpected error %v", tt.Name, err) + } else if !reflect.DeepEqual(out, tt.Output) { + t.Errorf("%s: out=%q want %q", tt.Name, out, tt.Output) + } + } +} diff --git a/libgo/go/csv/writer.go b/libgo/go/csv/writer.go new file mode 100644 index 0000000..ccf703f --- /dev/null +++ b/libgo/go/csv/writer.go @@ -0,0 +1,122 @@ +// 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 csv + +import ( + "bufio" + "io" + "os" + "strings" + "unicode" + "utf8" +) + +// A Writer writes records to a CSV encoded file. +// +// As returned by NewWriter, a Writer writes records terminated by a +// newline and uses ',' as the field delimiter. The exported fields can be +// changed to customize the details before the first call to Write or WriteAll. +// +// Comma is the field delimiter. +// +// If UseCRLF is true, the Writer ends each record with \r\n instead of \n. +type Writer struct { + Comma int // Field delimiter (set to to ',' by NewWriter) + UseCRLF bool // True to use \r\n as the line terminator + w *bufio.Writer +} + +// NewWriter returns a new Writer that writes to w. +func NewWriter(w io.Writer) *Writer { + return &Writer{ + Comma: ',', + w: bufio.NewWriter(w), + } +} + +// Writer writes a single CSV record to w along with any necessary quoting. +// A record is a slice of strings with each string being one field. +func (w *Writer) Write(record []string) (err os.Error) { + for n, field := range record { + if n > 0 { + if _, err = w.w.WriteRune(w.Comma); err != nil { + return + } + } + + // If we don't have to have a quoted field then just + // write out the field and continue to the next field. + if !w.fieldNeedsQuotes(field) { + if _, err = w.w.WriteString(field); err != nil { + return + } + continue + } + if err = w.w.WriteByte('"'); err != nil { + return + } + + for _, rune := range field { + switch rune { + case '"': + _, err = w.w.WriteString(`""`) + case '\r': + if !w.UseCRLF { + err = w.w.WriteByte('\r') + } + case '\n': + if w.UseCRLF { + _, err = w.w.WriteString("\r\n") + } else { + err = w.w.WriteByte('\n') + } + default: + _, err = w.w.WriteRune(rune) + } + if err != nil { + return + } + } + + if err = w.w.WriteByte('"'); err != nil { + return + } + } + if w.UseCRLF { + _, err = w.w.WriteString("\r\n") + } else { + err = w.w.WriteByte('\n') + } + return +} + +// Flush writes any buffered data to the underlying io.Writer. +func (w *Writer) Flush() { + w.w.Flush() +} + +// WriteAll writes multiple CSV records to w using Write and then calls Flush. +func (w *Writer) WriteAll(records [][]string) (err os.Error) { + for _, record := range records { + err = w.Write(record) + if err != nil { + break + } + } + w.Flush() + return nil +} + +// fieldNeedsQuotes returns true if our field must be enclosed in quotes. +// Empty fields, files with a Comma, fields with a quote or newline, and +// fields which start with a space must be enclosed in quotes. +func (w *Writer) fieldNeedsQuotes(field string) bool { + if len(field) == 0 || strings.IndexRune(field, w.Comma) >= 0 || strings.IndexAny(field, "\"\r\n") >= 0 { + return true + } + + rune, _ := utf8.DecodeRuneInString(field) + return unicode.IsSpace(rune) +} diff --git a/libgo/go/csv/writer_test.go b/libgo/go/csv/writer_test.go new file mode 100644 index 0000000..5789590 --- /dev/null +++ b/libgo/go/csv/writer_test.go @@ -0,0 +1,44 @@ +// 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 csv + +import ( + "bytes" + "testing" +) + +var writeTests = []struct { + Input [][]string + Output string + UseCRLF bool +}{ + {Input: [][]string{{"abc"}}, Output: "abc\n"}, + {Input: [][]string{{"abc"}}, Output: "abc\r\n", UseCRLF: true}, + {Input: [][]string{{`"abc"`}}, Output: `"""abc"""` + "\n"}, + {Input: [][]string{{`a"b`}}, Output: `"a""b"` + "\n"}, + {Input: [][]string{{`"a"b"`}}, Output: `"""a""b"""` + "\n"}, + {Input: [][]string{{" abc"}}, Output: `" abc"` + "\n"}, + {Input: [][]string{{"abc,def"}}, Output: `"abc,def"` + "\n"}, + {Input: [][]string{{"abc", "def"}}, Output: "abc,def\n"}, + {Input: [][]string{{"abc"}, {"def"}}, Output: "abc\ndef\n"}, + {Input: [][]string{{"abc\ndef"}}, Output: "\"abc\ndef\"\n"}, + {Input: [][]string{{"abc\ndef"}}, Output: "\"abc\r\ndef\"\r\n", UseCRLF: true}, +} + +func TestWrite(t *testing.T) { + for n, tt := range writeTests { + b := &bytes.Buffer{} + f := NewWriter(b) + f.UseCRLF = tt.UseCRLF + err := f.WriteAll(tt.Input) + if err != nil { + t.Errorf("Unexpected error: %s\n", err) + } + out := b.String() + if out != tt.Output { + t.Errorf("#%d: out=%q want %q", n, out, tt.Output) + } + } +} diff --git a/libgo/go/debug/dwarf/type.go b/libgo/go/debug/dwarf/type.go index 902a545..f35365e 100644 --- a/libgo/go/debug/dwarf/type.go +++ b/libgo/go/debug/dwarf/type.go @@ -352,8 +352,8 @@ func (d *Data) Type(off Offset) (Type, os.Error) { } } if ndim == 0 { - err = DecodeError{"info", e.Offset, "missing dimension for array"} - goto Error + // LLVM generates this for x[]. + t.Count = -1 } case TagBaseType: @@ -523,7 +523,7 @@ func (d *Data) Type(off Offset) (Type, os.Error) { // Attributes: // AttrType: type of return value if any // AttrName: possible name of type [ignored] - // AttrPrototyped: whether used ANSI C prototye [ignored] + // AttrPrototyped: whether used ANSI C prototype [ignored] // Children: // TagFormalParameter: typed parameter // AttrType: type of parameter @@ -566,12 +566,13 @@ func (d *Data) Type(off Offset) (Type, os.Error) { goto Error } - b, ok := e.Val(AttrByteSize).(int64) - if !ok { - b = -1 + { + b, ok := e.Val(AttrByteSize).(int64) + if !ok { + b = -1 + } + typ.Common().ByteSize = b } - typ.Common().ByteSize = b - return typ, nil Error: diff --git a/libgo/go/debug/dwarf/type_test.go b/libgo/go/debug/dwarf/type_test.go index e01f735..b9470a4 100644 --- a/libgo/go/debug/dwarf/type_test.go +++ b/libgo/go/debug/dwarf/type_test.go @@ -58,7 +58,6 @@ func machoData(t *testing.T, name string) *Data { return d } - func TestTypedefsELF(t *testing.T) { testTypedefs(t, elfData(t, "testdata/typedef.elf")) } func TestTypedefsMachO(t *testing.T) { diff --git a/libgo/go/debug/elf/elf.go b/libgo/go/debug/elf/elf.go index 5d45b24..c71b230 100644 --- a/libgo/go/debug/elf/elf.go +++ b/libgo/go/debug/elf/elf.go @@ -1289,7 +1289,6 @@ func (i R_SPARC) GoString() string { return stringName(uint32(i), rsparcStrings, // Magic number for the elf trampoline, chosen wisely to be an immediate value. const ARM_MAGIC_TRAMP_NUMBER = 0x5c000003 - // ELF32 File header. type Header32 struct { Ident [EI_NIDENT]byte /* File identification. */ @@ -1455,7 +1454,6 @@ func R_SYM64(info uint64) uint32 { return uint32(info >> 32) } func R_TYPE64(info uint64) uint32 { return uint32(info) } func R_INFO(sym, typ uint32) uint64 { return uint64(sym)<<32 | uint64(typ) } - // ELF64 symbol table entries. type Sym64 struct { Name uint32 /* String table index of name. */ diff --git a/libgo/go/debug/elf/file.go b/libgo/go/debug/elf/file.go index 9ae8b41..a0ddb1f 100644 --- a/libgo/go/debug/elf/file.go +++ b/libgo/go/debug/elf/file.go @@ -81,7 +81,7 @@ func (s *Section) Data() ([]byte, os.Error) { // specified link value. func (f *File) stringTable(link uint32) ([]byte, os.Error) { if link <= 0 || link >= uint32(len(f.Sections)) { - return nil, os.ErrorString("section has invalid string table link") + return nil, os.NewError("section has invalid string table link") } return f.Sections[link].Data() } @@ -93,6 +93,7 @@ func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<< type ProgHeader struct { Type ProgType Flags ProgFlag + Off uint64 Vaddr uint64 Paddr uint64 Filesz uint64 @@ -224,6 +225,8 @@ func NewFile(r io.ReaderAt) (*File, os.Error) { f.ABIVersion = ident[EI_ABIVERSION] // Read ELF file header + var phoff int64 + var phentsize, phnum int var shoff int64 var shentsize, shnum, shstrndx int shstrndx = -1 @@ -239,6 +242,9 @@ func NewFile(r io.ReaderAt) (*File, os.Error) { if v := Version(hdr.Version); v != f.Version { return nil, &FormatError{0, "mismatched ELF version", v} } + phoff = int64(hdr.Phoff) + phentsize = int(hdr.Phentsize) + phnum = int(hdr.Phnum) shoff = int64(hdr.Shoff) shentsize = int(hdr.Shentsize) shnum = int(hdr.Shnum) @@ -254,6 +260,9 @@ func NewFile(r io.ReaderAt) (*File, os.Error) { if v := Version(hdr.Version); v != f.Version { return nil, &FormatError{0, "mismatched ELF version", v} } + phoff = int64(hdr.Phoff) + phentsize = int(hdr.Phentsize) + phnum = int(hdr.Phnum) shoff = int64(hdr.Shoff) shentsize = int(hdr.Shentsize) shnum = int(hdr.Shnum) @@ -264,7 +273,47 @@ func NewFile(r io.ReaderAt) (*File, os.Error) { } // Read program headers - // TODO + f.Progs = make([]*Prog, phnum) + for i := 0; i < phnum; i++ { + off := phoff + int64(i)*int64(phentsize) + sr.Seek(off, os.SEEK_SET) + p := new(Prog) + switch f.Class { + case ELFCLASS32: + ph := new(Prog32) + if err := binary.Read(sr, f.ByteOrder, ph); err != nil { + return nil, err + } + p.ProgHeader = ProgHeader{ + Type: ProgType(ph.Type), + Flags: ProgFlag(ph.Flags), + Off: uint64(ph.Off), + Vaddr: uint64(ph.Vaddr), + Paddr: uint64(ph.Paddr), + Filesz: uint64(ph.Filesz), + Memsz: uint64(ph.Memsz), + Align: uint64(ph.Align), + } + case ELFCLASS64: + ph := new(Prog64) + if err := binary.Read(sr, f.ByteOrder, ph); err != nil { + return nil, err + } + p.ProgHeader = ProgHeader{ + Type: ProgType(ph.Type), + Flags: ProgFlag(ph.Flags), + Off: uint64(ph.Off), + Vaddr: uint64(ph.Vaddr), + Paddr: uint64(ph.Paddr), + Filesz: uint64(ph.Filesz), + Memsz: uint64(ph.Memsz), + Align: uint64(ph.Align), + } + } + p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz)) + p.ReaderAt = p.sr + f.Progs[i] = p + } // Read section headers f.Sections = make([]*Section, shnum) @@ -341,27 +390,27 @@ func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, os.Error) { return f.getSymbols32(typ) } - return nil, nil, os.ErrorString("not implemented") + return nil, nil, os.NewError("not implemented") } func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, os.Error) { symtabSection := f.SectionByType(typ) if symtabSection == nil { - return nil, nil, os.ErrorString("no symbol section") + return nil, nil, os.NewError("no symbol section") } data, err := symtabSection.Data() if err != nil { - return nil, nil, os.ErrorString("cannot load symbol section") + return nil, nil, os.NewError("cannot load symbol section") } symtab := bytes.NewBuffer(data) if symtab.Len()%Sym32Size != 0 { - return nil, nil, os.ErrorString("length of symbol section is not a multiple of SymSize") + return nil, nil, os.NewError("length of symbol section is not a multiple of SymSize") } strdata, err := f.stringTable(symtabSection.Link) if err != nil { - return nil, nil, os.ErrorString("cannot load string table section") + return nil, nil, os.NewError("cannot load string table section") } // The first entry is all zeros. @@ -390,21 +439,21 @@ func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, os.Error) { func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, os.Error) { symtabSection := f.SectionByType(typ) if symtabSection == nil { - return nil, nil, os.ErrorString("no symbol section") + return nil, nil, os.NewError("no symbol section") } data, err := symtabSection.Data() if err != nil { - return nil, nil, os.ErrorString("cannot load symbol section") + return nil, nil, os.NewError("cannot load symbol section") } symtab := bytes.NewBuffer(data) if symtab.Len()%Sym64Size != 0 { - return nil, nil, os.ErrorString("length of symbol section is not a multiple of Sym64Size") + return nil, nil, os.NewError("length of symbol section is not a multiple of Sym64Size") } strdata, err := f.stringTable(symtabSection.Link) if err != nil { - return nil, nil, os.ErrorString("cannot load string table section") + return nil, nil, os.NewError("cannot load string table section") } // The first entry is all zeros. @@ -462,12 +511,12 @@ func (f *File) applyRelocations(dst []byte, rels []byte) os.Error { return f.applyRelocationsAMD64(dst, rels) } - return os.ErrorString("not implemented") + return os.NewError("not implemented") } func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) os.Error { if len(rels)%Sym64Size != 0 { - return os.ErrorString("length of relocation section is not a multiple of Sym64Size") + return os.NewError("length of relocation section is not a multiple of Sym64Size") } symbols, _, err := f.getSymbols(SHT_SYMTAB) @@ -546,6 +595,12 @@ func (f *File) DWARF() (*dwarf.Data, os.Error) { return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str) } +// Symbols returns the symbol table for f. +func (f *File) Symbols() ([]Symbol, os.Error) { + sym, _, err := f.getSymbols(SHT_SYMTAB) + return sym, err +} + type ImportedSymbol struct { Name string Version string diff --git a/libgo/go/debug/elf/file_test.go b/libgo/go/debug/elf/file_test.go index 84068ea..98f2723c 100644 --- a/libgo/go/debug/elf/file_test.go +++ b/libgo/go/debug/elf/file_test.go @@ -7,7 +7,10 @@ package elf import ( "debug/dwarf" "encoding/binary" + "net" + "os" "reflect" + "runtime" "testing" ) @@ -15,6 +18,7 @@ type fileTest struct { file string hdr FileHeader sections []SectionHeader + progs []ProgHeader } var fileTests = []fileTest{ @@ -53,6 +57,13 @@ var fileTests = []fileTest{ {".symtab", SHT_SYMTAB, 0x0, 0x0, 0xfb8, 0x4b0, 0x1d, 0x38, 0x4, 0x10}, {".strtab", SHT_STRTAB, 0x0, 0x0, 0x1468, 0x206, 0x0, 0x0, 0x1, 0x0}, }, + []ProgHeader{ + {PT_PHDR, PF_R + PF_X, 0x34, 0x8048034, 0x8048034, 0xa0, 0xa0, 0x4}, + {PT_INTERP, PF_R, 0xd4, 0x80480d4, 0x80480d4, 0x15, 0x15, 0x1}, + {PT_LOAD, PF_R + PF_X, 0x0, 0x8048000, 0x8048000, 0x5fb, 0x5fb, 0x1000}, + {PT_LOAD, PF_R + PF_W, 0x5fc, 0x80495fc, 0x80495fc, 0xd8, 0xf8, 0x1000}, + {PT_DYNAMIC, PF_R + PF_W, 0x60c, 0x804960c, 0x804960c, 0x98, 0x98, 0x4}, + }, }, { "testdata/gcc-amd64-linux-exec", @@ -96,6 +107,16 @@ var fileTests = []fileTest{ {".symtab", SHT_SYMTAB, 0x0, 0x0, 0x19a0, 0x6f0, 0x24, 0x39, 0x8, 0x18}, {".strtab", SHT_STRTAB, 0x0, 0x0, 0x2090, 0x1fc, 0x0, 0x0, 0x1, 0x0}, }, + []ProgHeader{ + {PT_PHDR, PF_R + PF_X, 0x40, 0x400040, 0x400040, 0x1c0, 0x1c0, 0x8}, + {PT_INTERP, PF_R, 0x200, 0x400200, 0x400200, 0x1c, 0x1c, 1}, + {PT_LOAD, PF_R + PF_X, 0x0, 0x400000, 0x400000, 0x684, 0x684, 0x200000}, + {PT_LOAD, PF_R + PF_W, 0x688, 0x600688, 0x600688, 0x210, 0x218, 0x200000}, + {PT_DYNAMIC, PF_R + PF_W, 0x6b0, 0x6006b0, 0x6006b0, 0x1a0, 0x1a0, 0x8}, + {PT_NOTE, PF_R, 0x21c, 0x40021c, 0x40021c, 0x20, 0x20, 0x4}, + {PT_LOOS + 0x474E550, PF_R, 0x5b8, 0x4005b8, 0x4005b8, 0x24, 0x24, 0x4}, + {PT_LOOS + 0x474E551, PF_R + PF_W, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8}, + }, }, } @@ -121,11 +142,25 @@ func TestOpen(t *testing.T) { t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, &s.SectionHeader, sh) } } + for i, p := range f.Progs { + if i >= len(tt.progs) { + break + } + ph := &tt.progs[i] + if !reflect.DeepEqual(&p.ProgHeader, ph) { + t.Errorf("open %s, program %d:\n\thave %#v\n\twant %#v\n", tt.file, i, &p.ProgHeader, ph) + } + } tn := len(tt.sections) fn := len(f.Sections) if tn != fn { t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn) } + tn = len(tt.progs) + fn = len(f.Progs) + if tn != fn { + t.Errorf("open %s: len(Progs) = %d, want %d", tt.file, fn, tn) + } } } @@ -136,15 +171,15 @@ type relocationTest struct { var relocationTests = []relocationTest{ { - "testdata/go-relocation-test-gcc441-x86-64.o", + "testdata/go-relocation-test-gcc441-x86-64.obj", &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}, }, { - "testdata/go-relocation-test-gcc441-x86.o", + "testdata/go-relocation-test-gcc441-x86.obj", &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "t.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x5)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}, }, { - "testdata/go-relocation-test-gcc424-x86-64.o", + "testdata/go-relocation-test-gcc424-x86-64.obj", &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}, }, } @@ -178,3 +213,32 @@ func TestDWARFRelocations(t *testing.T) { } } } + +func TestNoSectionOverlaps(t *testing.T) { + // Ensure 6l outputs sections without overlaps. + if runtime.GOOS != "linux" && runtime.GOOS != "freebsd" { + return // not ELF + } + _ = net.ResolveIPAddr // force dynamic linkage + f, err := Open(os.Args[0]) + if err != nil { + t.Error(err) + return + } + for i, si := range f.Sections { + sih := si.SectionHeader + if sih.Type == SHT_NOBITS { + continue + } + for j, sj := range f.Sections { + sjh := sj.SectionHeader + if i == j || sjh.Type == SHT_NOBITS || sih.Offset == sjh.Offset && sih.Size == 0 { + continue + } + if sih.Offset >= sjh.Offset && sih.Offset < sjh.Offset+sjh.Size { + t.Errorf("ld produced ELF with section %s within %s: 0x%x <= 0x%x..0x%x < 0x%x", + sih.Name, sjh.Name, sjh.Offset, sih.Offset, sih.Offset+sih.Size, sjh.Offset+sjh.Size) + } + } + } +} diff --git a/libgo/go/debug/elf/testdata/go-relocation-test-gcc424-x86-64.o b/libgo/go/debug/elf/testdata/go-relocation-test-gcc424-x86-64.o deleted file mode 100644 index a7c6d6e..0000000 Binary files a/libgo/go/debug/elf/testdata/go-relocation-test-gcc424-x86-64.o and /dev/null differ diff --git a/libgo/go/debug/elf/testdata/go-relocation-test-gcc424-x86-64.obj b/libgo/go/debug/elf/testdata/go-relocation-test-gcc424-x86-64.obj new file mode 100644 index 0000000..a7c6d6e Binary files /dev/null and b/libgo/go/debug/elf/testdata/go-relocation-test-gcc424-x86-64.obj differ diff --git a/libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86-64.o b/libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86-64.o deleted file mode 100644 index 2d37ab6..0000000 Binary files a/libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86-64.o and /dev/null differ diff --git a/libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86-64.obj b/libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86-64.obj new file mode 100644 index 0000000..2d37ab6 Binary files /dev/null and b/libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86-64.obj differ diff --git a/libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86.o b/libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86.o deleted file mode 100644 index 0d59fe3..0000000 Binary files a/libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86.o and /dev/null differ diff --git a/libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86.obj b/libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86.obj new file mode 100644 index 0000000..0d59fe3 Binary files /dev/null and b/libgo/go/debug/elf/testdata/go-relocation-test-gcc441-x86.obj differ diff --git a/libgo/go/debug/macho/file.go b/libgo/go/debug/macho/file.go index a777d87..721a4c4 100644 --- a/libgo/go/debug/macho/file.go +++ b/libgo/go/debug/macho/file.go @@ -184,7 +184,7 @@ func (f *File) Close() os.Error { return err } -// NewFile creates a new File for acecssing a Mach-O binary in an underlying reader. +// NewFile creates a new File for accessing a Mach-O binary in an underlying reader. // The Mach-O binary is expected to start at position 0 in the ReaderAt. func NewFile(r io.ReaderAt) (*File, os.Error) { f := new(File) diff --git a/libgo/go/debug/pe/file.go b/libgo/go/debug/pe/file.go index 6a14e50..d86d916 100644 --- a/libgo/go/debug/pe/file.go +++ b/libgo/go/debug/pe/file.go @@ -35,7 +35,6 @@ type SectionHeader struct { Characteristics uint32 } - type Section struct { SectionHeader @@ -69,7 +68,6 @@ func (s *Section) Data() ([]byte, os.Error) { // Open returns a new ReadSeeker reading the PE section. func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) } - type FormatError struct { off int64 msg string @@ -112,7 +110,7 @@ func (f *File) Close() os.Error { return err } -// NewFile creates a new File for acecssing a PE binary in an underlying reader. +// NewFile creates a new File for accessing a PE binary in an underlying reader. func NewFile(r io.ReaderAt) (*File, os.Error) { f := new(File) sr := io.NewSectionReader(r, 0, 1<<63-1) @@ -245,6 +243,7 @@ func (f *File) DWARF() (*dwarf.Data, os.Error) { // satisfied by other libraries at dynamic load time. // It does not return weak symbols. func (f *File) ImportedSymbols() ([]string, os.Error) { + pe64 := f.Machine == IMAGE_FILE_MACHINE_AMD64 ds := f.Section(".idata") if ds == nil { // not dynamic, so no libraries @@ -274,17 +273,31 @@ func (f *File) ImportedSymbols() ([]string, os.Error) { // seek to OriginalFirstThunk d = d[dt.OriginalFirstThunk-ds.VirtualAddress:] for len(d) > 0 { - va := binary.LittleEndian.Uint32(d[0:4]) - d = d[4:] - if va == 0 { - break - } - if va&0x80000000 > 0 { // is Ordinal - // TODO add dynimport ordinal support. - //ord := va&0x0000FFFF - } else { - fn, _ := getString(names, int(va-ds.VirtualAddress+2)) - all = append(all, fn+":"+dt.dll) + if pe64 { // 64bit + va := binary.LittleEndian.Uint64(d[0:8]) + d = d[8:] + if va == 0 { + break + } + if va&0x8000000000000000 > 0 { // is Ordinal + // TODO add dynimport ordinal support. + } else { + fn, _ := getString(names, int(uint32(va)-ds.VirtualAddress+2)) + all = append(all, fn+":"+dt.dll) + } + } else { // 32bit + va := binary.LittleEndian.Uint32(d[0:4]) + d = d[4:] + if va == 0 { + break + } + if va&0x80000000 > 0 { // is Ordinal + // TODO add dynimport ordinal support. + //ord := va&0x0000FFFF + } else { + fn, _ := getString(names, int(va-ds.VirtualAddress+2)) + all = append(all, fn+":"+dt.dll) + } } } } diff --git a/libgo/go/debug/proc/proc.go b/libgo/go/debug/proc/proc.go deleted file mode 100644 index d89649c..0000000 --- a/libgo/go/debug/proc/proc.go +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package proc provides a platform-independent interface for -// tracing and controlling running processes. It supports -// multi-threaded processes and provides typical low-level debugging -// controls such as breakpoints, single stepping, and manipulating -// memory and registers. -package proc - -// TODO(rsc): Have to import everything that proc_linux.go -// and proc_darwin.go do, because deps.bash only looks at -// this file. -import ( - _ "container/vector" - _ "fmt" - _ "io" - "os" - _ "runtime" - "strconv" - _ "strings" - _ "sync" - _ "syscall" -) - -type Word uint64 - -// A Cause explains why a thread is stopped. -type Cause interface { - String() string -} - -// Regs is a set of named machine registers, including a program -// counter, link register, and stack pointer. -// -// TODO(austin) There's quite a proliferation of methods here. We -// could make a Reg interface with Get and Set and make this just PC, -// Link, SP, Names, and Reg. We could also put Index in Reg and that -// makes it easy to get the index of things like the PC (currently -// there's just no way to know that). This would also let us include -// other per-register information like how to print it. -type Regs interface { - // PC returns the value of the program counter. - PC() Word - - // SetPC sets the program counter to val. - SetPC(val Word) os.Error - - // Link returns the link register, if any. - Link() Word - - // SetLink sets the link register to val. - SetLink(val Word) os.Error - - // SP returns the value of the stack pointer. - SP() Word - - // SetSP sets the stack pointer register to val. - SetSP(val Word) os.Error - - // Names returns the names of all of the registers. - Names() []string - - // Get returns the value of a register, where i corresponds to - // the index of the register's name in the array returned by - // Names. - Get(i int) Word - - // Set sets the value of a register. - Set(i int, val Word) os.Error -} - -// Thread is a thread in the process being traced. -type Thread interface { - // Step steps this thread by a single instruction. The thread - // must be stopped. If the thread is currently stopped on a - // breakpoint, this will step over the breakpoint. - // - // XXX What if it's stopped because of a signal? - Step() os.Error - - // Stopped returns the reason that this thread is stopped. It - // is an error is the thread not stopped. - Stopped() (Cause, os.Error) - - // Regs retrieves the current register values from this - // thread. The thread must be stopped. - Regs() (Regs, os.Error) - - // Peek reads len(out) bytes from the address addr in this - // thread into out. The thread must be stopped. It returns - // the number of bytes successfully read. If an error occurs, - // such as attempting to read unmapped memory, this count - // could be short and an error will be returned. If this does - // encounter unmapped memory, it will read up to the byte - // preceding the unmapped area. - Peek(addr Word, out []byte) (int, os.Error) - - // Poke writes b to the address addr in this thread. The - // thread must be stopped. It returns the number of bytes - // successfully written. If an error occurs, such as - // attempting to write to unmapped memory, this count could be - // short and an error will be returned. If this does - // encounter unmapped memory, it will write up to the byte - // preceding the unmapped area. - Poke(addr Word, b []byte) (int, os.Error) -} - -// Process is a process being traced. It consists of a set of -// threads. A process can be running, stopped, or terminated. The -// process's state extends to all of its threads. -type Process interface { - // Threads returns an array of all threads in this process. - Threads() []Thread - - // AddBreakpoint creates a new breakpoint at program counter - // pc. Breakpoints can only be created when the process is - // stopped. It is an error if a breakpoint already exists at - // pc. - AddBreakpoint(pc Word) os.Error - - // RemoveBreakpoint removes the breakpoint at the program - // counter pc. It is an error if no breakpoint exists at pc. - RemoveBreakpoint(pc Word) os.Error - - // Stop stops all running threads in this process before - // returning. - Stop() os.Error - - // Continue resumes execution of all threads in this process. - // Any thread that is stopped on a breakpoint will be stepped - // over that breakpoint. Any thread that is stopped because - // of a signal (other than SIGSTOP or SIGTRAP) will receive - // the pending signal. - Continue() os.Error - - // WaitStop waits until all threads in process p are stopped - // as a result of some thread hitting a breakpoint, receiving - // a signal, creating a new thread, or exiting. - WaitStop() os.Error - - // Detach detaches from this process. All stopped threads - // will be resumed. - Detach() os.Error -} - -// Stopped is a stop cause used for threads that are stopped either by -// user request (e.g., from the Stop method or after single stepping), -// or that are stopped because some other thread caused the program to -// stop. -type Stopped struct{} - -func (c Stopped) String() string { return "stopped" } - -// Breakpoint is a stop cause resulting from a thread reaching a set -// breakpoint. -type Breakpoint Word - -// PC returns the program counter that the program is stopped at. -func (c Breakpoint) PC() Word { return Word(c) } - -func (c Breakpoint) String() string { - return "breakpoint at 0x" + strconv.Uitob64(uint64(c.PC()), 16) -} - -// Signal is a stop cause resulting from a thread receiving a signal. -// When the process is continued, the signal will be delivered. -type Signal string - -// Signal returns the signal being delivered to the thread. -func (c Signal) Name() string { return string(c) } - -func (c Signal) String() string { return c.Name() } - -// ThreadCreate is a stop cause returned from an existing thread when -// it creates a new thread. The new thread exists in a primordial -// form at this point and will begin executing in earnest when the -// process is continued. -type ThreadCreate struct { - thread Thread -} - -func (c *ThreadCreate) NewThread() Thread { return c.thread } - -func (c *ThreadCreate) String() string { return "thread create" } - -// ThreadExit is a stop cause resulting from a thread exiting. When -// this cause first arises, the thread will still be in the list of -// process threads and its registers and memory will still be -// accessible. -type ThreadExit struct { - exitStatus int - signal string -} - -// Exited returns true if the thread exited normally. -func (c *ThreadExit) Exited() bool { return c.exitStatus != -1 } - -// ExitStatus returns the exit status of the thread if it exited -// normally or -1 otherwise. -func (c *ThreadExit) ExitStatus() int { return c.exitStatus } - -// Signaled returns true if the thread was terminated by a signal. -func (c *ThreadExit) Signaled() bool { return c.exitStatus == -1 } - -// StopSignal returns the signal that terminated the thread, or "" if -// it was not terminated by a signal. -func (c *ThreadExit) StopSignal() string { return c.signal } - -func (c *ThreadExit) String() string { - res := "thread exited " - switch { - case c.Exited(): - res += "with status " + strconv.Itoa(c.ExitStatus()) - case c.Signaled(): - res += "from signal " + c.StopSignal() - default: - res += "from unknown cause" - } - return res -} diff --git a/libgo/go/debug/proc/proc_darwin.go b/libgo/go/debug/proc/proc_darwin.go deleted file mode 100644 index 49f0a53..0000000 --- a/libgo/go/debug/proc/proc_darwin.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proc - -import "os" - -// Process tracing is not supported on OS X yet. - -func Attach(pid int) (Process, os.Error) { - return nil, os.NewError("debug/proc not implemented on OS X") -} - -func StartProcess(argv0 string, argv []string, attr *os.ProcAttr) (Process, os.Error) { - return Attach(0) -} diff --git a/libgo/go/debug/proc/proc_freebsd.go b/libgo/go/debug/proc/proc_freebsd.go deleted file mode 100644 index 4df07c3..0000000 --- a/libgo/go/debug/proc/proc_freebsd.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proc - -import "os" - -// Process tracing is not supported on FreeBSD yet. - -func Attach(pid int) (Process, os.Error) { - return nil, os.NewError("debug/proc not implemented on FreeBSD") -} - -func StartProcess(argv0 string, argv []string, attr *os.ProcAttr) (Process, os.Error) { - return Attach(0) -} diff --git a/libgo/go/debug/proc/proc_linux.go b/libgo/go/debug/proc/proc_linux.go deleted file mode 100644 index 17c8fa5..0000000 --- a/libgo/go/debug/proc/proc_linux.go +++ /dev/null @@ -1,1322 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proc - -// TODO(rsc): Imports here after to be in proc.go too in order -// for deps.bash to get the right answer. -import ( - "container/vector" - "fmt" - "io/ioutil" - "os" - "runtime" - "strconv" - "strings" - "sync" - "syscall" -) - -// This is an implementation of the process tracing interface using -// Linux's ptrace(2) interface. The implementation is multi-threaded. -// Each attached process has an associated monitor thread, and each -// running attached thread has an associated "wait" thread. The wait -// thread calls wait4 on the thread's TID and reports any wait events -// or errors via "debug events". The monitor thread consumes these -// wait events and updates the internally maintained state of each -// thread. All ptrace calls must run in the monitor thread, so the -// monitor executes closures received on the debugReq channel. -// -// As ptrace's documentation is somewhat light, this is heavily based -// on information gleaned from the implementation of ptrace found at -// http://lxr.linux.no/linux+v2.6.30/kernel/ptrace.c -// http://lxr.linux.no/linux+v2.6.30/arch/x86/kernel/ptrace.c#L854 -// as well as experimentation and examination of gdb's behavior. - -const ( - trace = false - traceIP = false - traceMem = false -) - -/* - * Thread state - */ - -// Each thread can be in one of the following set of states. -// Each state satisfies -// isRunning() || isStopped() || isZombie() || isTerminal(). -// -// Running threads can be sent signals and must be waited on, but they -// cannot be inspected using ptrace. -// -// Stopped threads can be inspected and continued, but cannot be -// meaningfully waited on. They can be sent signals, but the signals -// will be queued until they are running again. -// -// Zombie threads cannot be inspected, continued, or sent signals (and -// therefore they cannot be stopped), but they must be waited on. -// -// Terminal threads no longer exist in the OS and thus you can't do -// anything with them. -type threadState string - -const ( - running threadState = "Running" - singleStepping threadState = "SingleStepping" // Transient - stopping threadState = "Stopping" // Transient - stopped threadState = "Stopped" - stoppedBreakpoint threadState = "StoppedBreakpoint" - stoppedSignal threadState = "StoppedSignal" - stoppedThreadCreate threadState = "StoppedThreadCreate" - stoppedExiting threadState = "StoppedExiting" - exiting threadState = "Exiting" // Transient (except main thread) - exited threadState = "Exited" - detached threadState = "Detached" -) - -func (ts threadState) isRunning() bool { - return ts == running || ts == singleStepping || ts == stopping -} - -func (ts threadState) isStopped() bool { - return ts == stopped || ts == stoppedBreakpoint || ts == stoppedSignal || ts == stoppedThreadCreate || ts == stoppedExiting -} - -func (ts threadState) isZombie() bool { return ts == exiting } - -func (ts threadState) isTerminal() bool { return ts == exited || ts == detached } - -func (ts threadState) String() string { return string(ts) } - -/* - * Basic types - */ - -// A breakpoint stores information about a single breakpoint, -// including its program counter, the overwritten text if the -// breakpoint is installed. -type breakpoint struct { - pc uintptr - olddata []byte -} - -func (bp *breakpoint) String() string { - if bp == nil { - return "" - } - return fmt.Sprintf("%#x", bp.pc) -} - -// bpinst386 is the breakpoint instruction used on 386 and amd64. -var bpinst386 = []byte{0xcc} - -// A debugEvent represents a reason a thread stopped or a wait error. -type debugEvent struct { - *os.Waitmsg - t *thread - err os.Error -} - -// A debugReq is a request to execute a closure in the monitor thread. -type debugReq struct { - f func() os.Error - res chan os.Error -} - -// A transitionHandler specifies a function to be called when a thread -// changes state and a function to be called when an error occurs in -// the monitor. Both run in the monitor thread. Before the monitor -// invokes a handler, it removes the handler from the handler queue. -// The handler should re-add itself if needed. -type transitionHandler struct { - handle func(*thread, threadState, threadState) - onErr func(os.Error) -} - -// A process is a Linux process, which consists of a set of threads. -// Each running process has one monitor thread, which processes -// messages from the debugEvents, debugReqs, and stopReq channels and -// calls transition handlers. -// -// To send a message to the monitor thread, first receive from the -// ready channel. If the ready channel returns true, the monitor is -// still running and will accept a message. If the ready channel -// returns false, the monitor is not running (the ready channel has -// been closed), and the reason it is not running will be stored in err. -type process struct { - pid int - threads map[int]*thread - breakpoints map[uintptr]*breakpoint - ready chan bool - debugEvents chan *debugEvent - debugReqs chan *debugReq - stopReq chan os.Error - transitionHandlers vector.Vector - err os.Error -} - -// A thread represents a Linux thread in another process that is being -// debugged. Each running thread has an associated goroutine that -// waits for thread updates and sends them to the process monitor. -type thread struct { - tid int - proc *process - // Whether to ignore the next SIGSTOP received by wait. - ignoreNextSigstop bool - - // Thread state. Only modified via setState. - state threadState - // If state == StoppedBreakpoint - breakpoint *breakpoint - // If state == StoppedSignal or state == Exited - signal int - // If state == StoppedThreadCreate - newThread *thread - // If state == Exited - exitStatus int -} - -/* - * Errors - */ - -type badState struct { - thread *thread - message string - state threadState -} - -func (e *badState) String() string { - return fmt.Sprintf("Thread %d %s from state %v", e.thread.tid, e.message, e.state) -} - -type breakpointExistsError Word - -func (e breakpointExistsError) String() string { - return fmt.Sprintf("breakpoint already exists at PC %#x", e) -} - -type noBreakpointError Word - -func (e noBreakpointError) String() string { return fmt.Sprintf("no breakpoint at PC %#x", e) } - -type newThreadError struct { - *os.Waitmsg - wantPid int - wantSig int -} - -func (e *newThreadError) String() string { - return fmt.Sprintf("newThread wait wanted pid %v and signal %v, got %v and %v", e.Pid, e.StopSignal(), e.wantPid, e.wantSig) -} - -type ProcessExited struct{} - -func (p ProcessExited) String() string { return "process exited" } - -/* - * Ptrace wrappers - */ - -func (t *thread) ptracePeekText(addr uintptr, out []byte) (int, os.Error) { - c, err := syscall.PtracePeekText(t.tid, addr, out) - if traceMem { - fmt.Printf("peek(%#x) => %v, %v\n", addr, out, err) - } - return c, os.NewSyscallError("ptrace(PEEKTEXT)", err) -} - -func (t *thread) ptracePokeText(addr uintptr, out []byte) (int, os.Error) { - c, err := syscall.PtracePokeText(t.tid, addr, out) - if traceMem { - fmt.Printf("poke(%#x, %v) => %v\n", addr, out, err) - } - return c, os.NewSyscallError("ptrace(POKETEXT)", err) -} - -func (t *thread) ptraceGetRegs(regs *syscall.PtraceRegs) os.Error { - err := syscall.PtraceGetRegs(t.tid, regs) - return os.NewSyscallError("ptrace(GETREGS)", err) -} - -func (t *thread) ptraceSetRegs(regs *syscall.PtraceRegs) os.Error { - err := syscall.PtraceSetRegs(t.tid, regs) - return os.NewSyscallError("ptrace(SETREGS)", err) -} - -func (t *thread) ptraceSetOptions(options int) os.Error { - err := syscall.PtraceSetOptions(t.tid, options) - return os.NewSyscallError("ptrace(SETOPTIONS)", err) -} - -func (t *thread) ptraceGetEventMsg() (uint, os.Error) { - msg, err := syscall.PtraceGetEventMsg(t.tid) - return msg, os.NewSyscallError("ptrace(GETEVENTMSG)", err) -} - -func (t *thread) ptraceCont() os.Error { - err := syscall.PtraceCont(t.tid, 0) - return os.NewSyscallError("ptrace(CONT)", err) -} - -func (t *thread) ptraceContWithSignal(sig int) os.Error { - err := syscall.PtraceCont(t.tid, sig) - return os.NewSyscallError("ptrace(CONT)", err) -} - -func (t *thread) ptraceStep() os.Error { - err := syscall.PtraceSingleStep(t.tid) - return os.NewSyscallError("ptrace(SINGLESTEP)", err) -} - -func (t *thread) ptraceDetach() os.Error { - err := syscall.PtraceDetach(t.tid) - return os.NewSyscallError("ptrace(DETACH)", err) -} - -/* - * Logging utilties - */ - -var logLock sync.Mutex - -func (t *thread) logTrace(format string, args ...interface{}) { - if !trace { - return - } - logLock.Lock() - defer logLock.Unlock() - fmt.Fprintf(os.Stderr, "Thread %d", t.tid) - if traceIP { - var regs syscall.PtraceRegs - err := t.ptraceGetRegs(®s) - if err == nil { - fmt.Fprintf(os.Stderr, "@%x", regs.PC()) - } - } - fmt.Fprint(os.Stderr, ": ") - fmt.Fprintf(os.Stderr, format, args...) - fmt.Fprint(os.Stderr, "\n") -} - -func (t *thread) warn(format string, args ...interface{}) { - logLock.Lock() - defer logLock.Unlock() - fmt.Fprintf(os.Stderr, "Thread %d: WARNING ", t.tid) - fmt.Fprintf(os.Stderr, format, args...) - fmt.Fprint(os.Stderr, "\n") -} - -func (p *process) logTrace(format string, args ...interface{}) { - if !trace { - return - } - logLock.Lock() - defer logLock.Unlock() - fmt.Fprintf(os.Stderr, "Process %d: ", p.pid) - fmt.Fprintf(os.Stderr, format, args...) - fmt.Fprint(os.Stderr, "\n") -} - -/* - * State utilities - */ - -// someStoppedThread returns a stopped thread from the process. -// Returns nil if no threads are stopped. -// -// Must be called from the monitor thread. -func (p *process) someStoppedThread() *thread { - for _, t := range p.threads { - if t.state.isStopped() { - return t - } - } - return nil -} - -// someRunningThread returns a running thread from the process. -// Returns nil if no threads are running. -// -// Must be called from the monitor thread. -func (p *process) someRunningThread() *thread { - for _, t := range p.threads { - if t.state.isRunning() { - return t - } - } - return nil -} - -/* - * Breakpoint utilities - */ - -// installBreakpoints adds breakpoints to the attached process. -// -// Must be called from the monitor thread. -func (p *process) installBreakpoints() os.Error { - n := 0 - main := p.someStoppedThread() - for _, b := range p.breakpoints { - if b.olddata != nil { - continue - } - - b.olddata = make([]byte, len(bpinst386)) - _, err := main.ptracePeekText(uintptr(b.pc), b.olddata) - if err != nil { - b.olddata = nil - return err - } - - _, err = main.ptracePokeText(uintptr(b.pc), bpinst386) - if err != nil { - b.olddata = nil - return err - } - n++ - } - if n > 0 { - p.logTrace("installed %d/%d breakpoints", n, len(p.breakpoints)) - } - - return nil -} - -// uninstallBreakpoints removes the installed breakpoints from p. -// -// Must be called from the monitor thread. -func (p *process) uninstallBreakpoints() os.Error { - if len(p.threads) == 0 { - return nil - } - n := 0 - main := p.someStoppedThread() - for _, b := range p.breakpoints { - if b.olddata == nil { - continue - } - - _, err := main.ptracePokeText(uintptr(b.pc), b.olddata) - if err != nil { - return err - } - b.olddata = nil - n++ - } - if n > 0 { - p.logTrace("uninstalled %d/%d breakpoints", n, len(p.breakpoints)) - } - - return nil -} - -/* - * Debug event handling - */ - -// wait waits for a wait event from this thread and sends it on the -// debug events channel for this thread's process. This should be -// started in its own goroutine when the attached thread enters a -// running state. The goroutine will exit as soon as it sends a debug -// event. -func (t *thread) wait() { - for { - var ev debugEvent - ev.t = t - t.logTrace("beginning wait") - ev.Waitmsg, ev.err = os.Wait(t.tid, syscall.WALL) - if ev.err == nil && ev.Pid != t.tid { - panic(fmt.Sprint("Wait returned pid ", ev.Pid, " wanted ", t.tid)) - } - if ev.StopSignal() == syscall.SIGSTOP && t.ignoreNextSigstop { - // Spurious SIGSTOP. See Thread.Stop(). - t.ignoreNextSigstop = false - err := t.ptraceCont() - if err == nil { - continue - } - // If we failed to continue, just let - // the stop go through so we can - // update the thread's state. - } - if !<-t.proc.ready { - // The monitor exited - break - } - t.proc.debugEvents <- &ev - break - } -} - -// setState sets this thread's state, starts a wait thread if -// necessary, and invokes state transition handlers. -// -// Must be called from the monitor thread. -func (t *thread) setState(newState threadState) { - oldState := t.state - t.state = newState - t.logTrace("state %v -> %v", oldState, newState) - - if !oldState.isRunning() && (newState.isRunning() || newState.isZombie()) { - // Start waiting on this thread - go t.wait() - } - - // Invoke state change handlers - handlers := t.proc.transitionHandlers - if handlers.Len() == 0 { - return - } - - t.proc.transitionHandlers = nil - for _, h := range handlers { - h := h.(*transitionHandler) - h.handle(t, oldState, newState) - } -} - -// sendSigstop sends a SIGSTOP to this thread. -func (t *thread) sendSigstop() os.Error { - t.logTrace("sending SIGSTOP") - err := syscall.Tgkill(t.proc.pid, t.tid, syscall.SIGSTOP) - return os.NewSyscallError("tgkill", err) -} - -// stopAsync sends SIGSTOP to all threads in state 'running'. -// -// Must be called from the monitor thread. -func (p *process) stopAsync() os.Error { - for _, t := range p.threads { - if t.state == running { - err := t.sendSigstop() - if err != nil { - return err - } - t.setState(stopping) - } - } - return nil -} - -// doTrap handles SIGTRAP debug events with a cause of 0. These can -// be caused either by an installed breakpoint, a breakpoint in the -// program text, or by single stepping. -// -// TODO(austin) I think we also get this on an execve syscall. -func (ev *debugEvent) doTrap() (threadState, os.Error) { - t := ev.t - - if t.state == singleStepping { - return stopped, nil - } - - // Hit a breakpoint. Linux leaves the program counter after - // the breakpoint. If this is an installed breakpoint, we - // need to back the PC up to the breakpoint PC. - var regs syscall.PtraceRegs - err := t.ptraceGetRegs(®s) - if err != nil { - return stopped, err - } - - b, ok := t.proc.breakpoints[uintptr(regs.PC())-uintptr(len(bpinst386))] - if !ok { - // We must have hit a breakpoint that was actually in - // the program. Leave the IP where it is so we don't - // re-execute the breakpoint instruction. Expose the - // fact that we stopped with a SIGTRAP. - return stoppedSignal, nil - } - - t.breakpoint = b - t.logTrace("at breakpoint %v, backing up PC from %#x", b, regs.PC()) - - regs.SetPC(uint64(b.pc)) - err = t.ptraceSetRegs(®s) - if err != nil { - return stopped, err - } - return stoppedBreakpoint, nil -} - -// doPtraceClone handles SIGTRAP debug events with a PTRACE_EVENT_CLONE -// cause. It initializes the new thread, adds it to the process, and -// returns the appropriate thread state for the existing thread. -func (ev *debugEvent) doPtraceClone() (threadState, os.Error) { - t := ev.t - - // Get the TID of the new thread - tid, err := t.ptraceGetEventMsg() - if err != nil { - return stopped, err - } - - nt, err := t.proc.newThread(int(tid), syscall.SIGSTOP, true) - if err != nil { - return stopped, err - } - - // Remember the thread - t.newThread = nt - - return stoppedThreadCreate, nil -} - -// doPtraceExit handles SIGTRAP debug events with a PTRACE_EVENT_EXIT -// cause. It sets up the thread's state, but does not remove it from -// the process. A later WIFEXITED debug event will remove it from the -// process. -func (ev *debugEvent) doPtraceExit() (threadState, os.Error) { - t := ev.t - - // Get exit status - exitStatus, err := t.ptraceGetEventMsg() - if err != nil { - return stopped, err - } - ws := syscall.WaitStatus(exitStatus) - t.logTrace("exited with %v", ws) - switch { - case ws.Exited(): - t.exitStatus = ws.ExitStatus() - case ws.Signaled(): - t.signal = ws.Signal() - } - - // We still need to continue this thread and wait on this - // thread's WIFEXITED event. We'll delete it then. - return stoppedExiting, nil -} - -// process handles a debug event. It modifies any thread or process -// state as necessary, uninstalls breakpoints if necessary, and stops -// any running threads. -func (ev *debugEvent) process() os.Error { - if ev.err != nil { - return ev.err - } - - t := ev.t - t.exitStatus = -1 - t.signal = -1 - - // Decode wait status. - var state threadState - switch { - case ev.Stopped(): - state = stoppedSignal - t.signal = ev.StopSignal() - t.logTrace("stopped with %v", ev) - if ev.StopSignal() == syscall.SIGTRAP { - // What caused the debug trap? - var err os.Error - switch cause := ev.TrapCause(); cause { - case 0: - // Breakpoint or single stepping - state, err = ev.doTrap() - - case syscall.PTRACE_EVENT_CLONE: - state, err = ev.doPtraceClone() - - case syscall.PTRACE_EVENT_EXIT: - state, err = ev.doPtraceExit() - - default: - t.warn("Unknown trap cause %d", cause) - } - - if err != nil { - t.setState(stopped) - t.warn("failed to handle trap %v: %v", ev, err) - } - } - - case ev.Exited(): - state = exited - t.proc.threads[t.tid] = nil, false - t.logTrace("exited %v", ev) - // We should have gotten the exit status in - // PTRACE_EVENT_EXIT, but just in case. - t.exitStatus = ev.ExitStatus() - - case ev.Signaled(): - state = exited - t.proc.threads[t.tid] = nil, false - t.logTrace("signaled %v", ev) - // Again, this should be redundant. - t.signal = ev.Signal() - - default: - panic(fmt.Sprintf("Unexpected wait status %v", ev.Waitmsg)) - } - - // If we sent a SIGSTOP to the thread (indicated by state - // Stopping), we might have raced with a different type of - // stop. If we didn't get the stop we expected, then the - // SIGSTOP we sent is now queued up, so we should ignore the - // next one we get. - if t.state == stopping && ev.StopSignal() != syscall.SIGSTOP { - t.ignoreNextSigstop = true - } - - // TODO(austin) If we're in state stopping and get a SIGSTOP, - // set state stopped instead of stoppedSignal. - - t.setState(state) - - if t.proc.someRunningThread() == nil { - // Nothing is running, uninstall breakpoints - return t.proc.uninstallBreakpoints() - } - // Stop any other running threads - return t.proc.stopAsync() -} - -// onStop adds a handler for state transitions from running to -// non-running states. The handler will be called from the monitor -// thread. -// -// Must be called from the monitor thread. -func (t *thread) onStop(handle func(), onErr func(os.Error)) { - // TODO(austin) This is rather inefficient for things like - // stepping all threads during a continue. Maybe move - // transitionHandlers to the thread, or have both per-thread - // and per-process transition handlers. - h := &transitionHandler{nil, onErr} - h.handle = func(st *thread, old, new threadState) { - if t == st && old.isRunning() && !new.isRunning() { - handle() - } else { - t.proc.transitionHandlers.Push(h) - } - } - t.proc.transitionHandlers.Push(h) -} - -/* - * Event monitor - */ - -// monitor handles debug events and debug requests for p, exiting when -// there are no threads left in p. -func (p *process) monitor() { - var err os.Error - - // Linux requires that all ptrace calls come from the thread - // that originally attached. Prevent the Go scheduler from - // migrating us to other OS threads. - runtime.LockOSThread() - defer runtime.UnlockOSThread() - - hadThreads := false - for err == nil { - p.ready <- true - select { - case event := <-p.debugEvents: - err = event.process() - - case req := <-p.debugReqs: - req.res <- req.f() - - case err = <-p.stopReq: - break - } - - if len(p.threads) == 0 { - if err == nil && hadThreads { - p.logTrace("no more threads; monitor exiting") - err = ProcessExited{} - } - } else { - hadThreads = true - } - } - - // Abort waiting handlers - // TODO(austin) How do I stop the wait threads? - for _, h := range p.transitionHandlers { - h := h.(*transitionHandler) - h.onErr(err) - } - - // Indicate that the monitor cannot receive any more messages - p.err = err - close(p.ready) -} - -// do executes f in the monitor thread (and, thus, atomically with -// respect to thread state changes). f must not block. -// -// Must NOT be called from the monitor thread. -func (p *process) do(f func() os.Error) os.Error { - if !<-p.ready { - return p.err - } - req := &debugReq{f, make(chan os.Error)} - p.debugReqs <- req - return <-req.res -} - -// stopMonitor stops the monitor with the given error. If the monitor -// is already stopped, does nothing. -func (p *process) stopMonitor(err os.Error) { - if err == nil { - panic("cannot stop the monitor with no error") - } - if <-p.ready { - p.stopReq <- err - } -} - -/* - * Public thread interface - */ - -func (t *thread) Regs() (Regs, os.Error) { - var regs syscall.PtraceRegs - - err := t.proc.do(func() os.Error { - if !t.state.isStopped() { - return &badState{t, "cannot get registers", t.state} - } - return t.ptraceGetRegs(®s) - }) - if err != nil { - return nil, err - } - - setter := func(r *syscall.PtraceRegs) os.Error { - return t.proc.do(func() os.Error { - if !t.state.isStopped() { - return &badState{t, "cannot get registers", t.state} - } - return t.ptraceSetRegs(r) - }) - } - return newRegs(®s, setter), nil -} - -func (t *thread) Peek(addr Word, out []byte) (int, os.Error) { - var c int - - err := t.proc.do(func() os.Error { - if !t.state.isStopped() { - return &badState{t, "cannot peek text", t.state} - } - - var err os.Error - c, err = t.ptracePeekText(uintptr(addr), out) - return err - }) - - return c, err -} - -func (t *thread) Poke(addr Word, out []byte) (int, os.Error) { - var c int - - err := t.proc.do(func() os.Error { - if !t.state.isStopped() { - return &badState{t, "cannot poke text", t.state} - } - - var err os.Error - c, err = t.ptracePokeText(uintptr(addr), out) - return err - }) - - return c, err -} - -// stepAsync starts this thread single stepping. When the single step -// is complete, it will send nil on the given channel. If an error -// occurs while setting up the single step, it returns that error. If -// an error occurs while waiting for the single step to complete, it -// sends that error on the channel. -func (t *thread) stepAsync(ready chan os.Error) os.Error { - if err := t.ptraceStep(); err != nil { - return err - } - t.setState(singleStepping) - t.onStop(func() { ready <- nil }, - func(err os.Error) { ready <- err }) - return nil -} - -func (t *thread) Step() os.Error { - t.logTrace("Step {") - defer t.logTrace("}") - - ready := make(chan os.Error) - - err := t.proc.do(func() os.Error { - if !t.state.isStopped() { - return &badState{t, "cannot single step", t.state} - } - return t.stepAsync(ready) - }) - if err != nil { - return err - } - - err = <-ready - return err -} - -// TODO(austin) We should probably get this via C's strsignal. -var sigNames = [...]string{ - "SIGEXIT", "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", - "SIGTRAP", "SIGABRT", "SIGBUS", "SIGFPE", "SIGKILL", - "SIGUSR1", "SIGSEGV", "SIGUSR2", "SIGPIPE", "SIGALRM", - "SIGTERM", "SIGSTKFLT", "SIGCHLD", "SIGCONT", "SIGSTOP", - "SIGTSTP", "SIGTTIN", "SIGTTOU", "SIGURG", "SIGXCPU", - "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", "SIGPOLL", - "SIGPWR", "SIGSYS", -} - -// sigName returns the symbolic name for the given signal number. If -// the signal number is invalid, returns "". -func sigName(signal int) string { - if signal < 0 || signal >= len(sigNames) { - return "" - } - return sigNames[signal] -} - -func (t *thread) Stopped() (Cause, os.Error) { - var c Cause - err := t.proc.do(func() os.Error { - switch t.state { - case stopped: - c = Stopped{} - - case stoppedBreakpoint: - c = Breakpoint(t.breakpoint.pc) - - case stoppedSignal: - c = Signal(sigName(t.signal)) - - case stoppedThreadCreate: - c = &ThreadCreate{t.newThread} - - case stoppedExiting, exiting, exited: - if t.signal == -1 { - c = &ThreadExit{t.exitStatus, ""} - } else { - c = &ThreadExit{t.exitStatus, sigName(t.signal)} - } - - default: - return &badState{t, "cannot get stop cause", t.state} - } - return nil - }) - if err != nil { - return nil, err - } - - return c, nil -} - -func (p *process) Threads() []Thread { - var res []Thread - - p.do(func() os.Error { - res = make([]Thread, len(p.threads)) - i := 0 - for _, t := range p.threads { - // Exclude zombie threads. - st := t.state - if st == exiting || st == exited || st == detached { - continue - } - - res[i] = t - i++ - } - res = res[0:i] - return nil - }) - return res -} - -func (p *process) AddBreakpoint(pc Word) os.Error { - return p.do(func() os.Error { - if t := p.someRunningThread(); t != nil { - return &badState{t, "cannot add breakpoint", t.state} - } - if _, ok := p.breakpoints[uintptr(pc)]; ok { - return breakpointExistsError(pc) - } - p.breakpoints[uintptr(pc)] = &breakpoint{pc: uintptr(pc)} - return nil - }) -} - -func (p *process) RemoveBreakpoint(pc Word) os.Error { - return p.do(func() os.Error { - if t := p.someRunningThread(); t != nil { - return &badState{t, "cannot remove breakpoint", t.state} - } - if _, ok := p.breakpoints[uintptr(pc)]; !ok { - return noBreakpointError(pc) - } - p.breakpoints[uintptr(pc)] = nil, false - return nil - }) -} - -func (p *process) Continue() os.Error { - // Single step any threads that are stopped at breakpoints so - // we can reinstall breakpoints. - var ready chan os.Error - count := 0 - - err := p.do(func() os.Error { - // We make the ready channel big enough to hold all - // ready message so we don't jam up the monitor if we - // stop listening (e.g., if there's an error). - ready = make(chan os.Error, len(p.threads)) - - for _, t := range p.threads { - if !t.state.isStopped() { - continue - } - - // We use the breakpoint map directly here - // instead of checking the stop cause because - // it could have been stopped at a breakpoint - // for some other reason, or the breakpoint - // could have been added since it was stopped. - var regs syscall.PtraceRegs - err := t.ptraceGetRegs(®s) - if err != nil { - return err - } - if b, ok := p.breakpoints[uintptr(regs.PC())]; ok { - t.logTrace("stepping over breakpoint %v", b) - if err := t.stepAsync(ready); err != nil { - return err - } - count++ - } - } - return nil - }) - if err != nil { - p.stopMonitor(err) - return err - } - - // Wait for single stepping threads - for count > 0 { - err = <-ready - if err != nil { - p.stopMonitor(err) - return err - } - count-- - } - - // Continue all threads - err = p.do(func() os.Error { - if err := p.installBreakpoints(); err != nil { - return err - } - - for _, t := range p.threads { - var err os.Error - switch { - case !t.state.isStopped(): - continue - - case t.state == stoppedSignal && t.signal != syscall.SIGSTOP && t.signal != syscall.SIGTRAP: - t.logTrace("continuing with signal %d", t.signal) - err = t.ptraceContWithSignal(t.signal) - - default: - t.logTrace("continuing") - err = t.ptraceCont() - } - if err != nil { - return err - } - if t.state == stoppedExiting { - t.setState(exiting) - } else { - t.setState(running) - } - } - return nil - }) - if err != nil { - // TODO(austin) Do we need to stop the monitor with - // this error atomically with the do-routine above? - p.stopMonitor(err) - return err - } - - return nil -} - -func (p *process) WaitStop() os.Error { - // We need a non-blocking ready channel for the case where all - // threads are already stopped. - ready := make(chan os.Error, 1) - - err := p.do(func() os.Error { - // Are all of the threads already stopped? - if p.someRunningThread() == nil { - ready <- nil - return nil - } - - // Monitor state transitions - h := &transitionHandler{} - h.handle = func(st *thread, old, new threadState) { - if !new.isRunning() { - if p.someRunningThread() == nil { - ready <- nil - return - } - } - p.transitionHandlers.Push(h) - } - h.onErr = func(err os.Error) { ready <- err } - p.transitionHandlers.Push(h) - return nil - }) - if err != nil { - return err - } - - return <-ready -} - -func (p *process) Stop() os.Error { - err := p.do(func() os.Error { return p.stopAsync() }) - if err != nil { - return err - } - - return p.WaitStop() -} - -func (p *process) Detach() os.Error { - if err := p.Stop(); err != nil { - return err - } - - err := p.do(func() os.Error { - if err := p.uninstallBreakpoints(); err != nil { - return err - } - - for pid, t := range p.threads { - if t.state.isStopped() { - // We can't detach from zombies. - if err := t.ptraceDetach(); err != nil { - return err - } - } - t.setState(detached) - p.threads[pid] = nil, false - } - return nil - }) - // TODO(austin) Wait for monitor thread to exit? - return err -} - -// newThread creates a new thread object and waits for its initial -// signal. If cloned is true, this thread was cloned from a thread we -// are already attached to. -// -// Must be run from the monitor thread. -func (p *process) newThread(tid int, signal int, cloned bool) (*thread, os.Error) { - t := &thread{tid: tid, proc: p, state: stopped} - - // Get the signal from the thread - // TODO(austin) Thread might already be stopped if we're attaching. - w, err := os.Wait(tid, syscall.WALL) - if err != nil { - return nil, err - } - if w.Pid != tid || w.StopSignal() != signal { - return nil, &newThreadError{w, tid, signal} - } - - if !cloned { - err = t.ptraceSetOptions(syscall.PTRACE_O_TRACECLONE | syscall.PTRACE_O_TRACEEXIT) - if err != nil { - return nil, err - } - } - - p.threads[tid] = t - - return t, nil -} - -// attachThread attaches a running thread to the process. -// -// Must NOT be run from the monitor thread. -func (p *process) attachThread(tid int) (*thread, os.Error) { - p.logTrace("attaching to thread %d", tid) - var thr *thread - err := p.do(func() os.Error { - errno := syscall.PtraceAttach(tid) - if errno != 0 { - return os.NewSyscallError("ptrace(ATTACH)", errno) - } - - var err os.Error - thr, err = p.newThread(tid, syscall.SIGSTOP, false) - return err - }) - return thr, err -} - -// attachAllThreads attaches to all threads in a process. -func (p *process) attachAllThreads() os.Error { - taskPath := "/proc/" + strconv.Itoa(p.pid) + "/task" - taskDir, err := os.Open(taskPath) - if err != nil { - return err - } - defer taskDir.Close() - - // We stop threads as we attach to them; however, because new - // threads can appear while we're looping over all of them, we - // have to repeatly scan until we know we're attached to all - // of them. - for again := true; again; { - again = false - - tids, err := taskDir.Readdirnames(-1) - if err != nil { - return err - } - - for _, tidStr := range tids { - tid, err := strconv.Atoi(tidStr) - if err != nil { - return err - } - if _, ok := p.threads[tid]; ok { - continue - } - - _, err = p.attachThread(tid) - if err != nil { - // There could have been a race, or - // this process could be a zobmie. - statFile, err2 := ioutil.ReadFile(taskPath + "/" + tidStr + "/stat") - if err2 != nil { - switch err2 := err2.(type) { - case *os.PathError: - if err2.Error == os.ENOENT { - // Raced with thread exit - p.logTrace("raced with thread %d exit", tid) - continue - } - } - // Return the original error - return err - } - - statParts := strings.Split(string(statFile), " ", 4) - if len(statParts) > 2 && statParts[2] == "Z" { - // tid is a zombie - p.logTrace("thread %d is a zombie", tid) - continue - } - - // Return the original error - return err - } - again = true - } - } - - return nil -} - -// newProcess creates a new process object and starts its monitor thread. -func newProcess(pid int) *process { - p := &process{ - pid: pid, - threads: make(map[int]*thread), - breakpoints: make(map[uintptr]*breakpoint), - ready: make(chan bool, 1), - debugEvents: make(chan *debugEvent), - debugReqs: make(chan *debugReq), - stopReq: make(chan os.Error), - } - - go p.monitor() - - return p -} - -// Attach attaches to process pid and stops all of its threads. -func Attach(pid int) (Process, os.Error) { - p := newProcess(pid) - - // Attach to all threads - err := p.attachAllThreads() - if err != nil { - p.Detach() - // TODO(austin) Detach stopped the monitor already - //p.stopMonitor(err); - return nil, err - } - - return p, nil -} - -// StartProcess forks the current process and execs argv0, stopping the -// new process after the exec syscall. See os.StartProcess for additional -// details. -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(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.StartProcess(argv0, argv, sysattr) - if errno != 0 { - return &os.PathError{"fork/exec", argv0, os.Errno(errno)} - } - p.pid = pid - - // The process will raise SIGTRAP when it reaches execve. - _, err := p.newThread(pid, syscall.SIGTRAP, false) - return err - }) - if err != nil { - p.stopMonitor(err) - return nil, err - } - - return p, nil -} diff --git a/libgo/go/debug/proc/proc_windows.go b/libgo/go/debug/proc/proc_windows.go deleted file mode 100644 index 661474b..0000000 --- a/libgo/go/debug/proc/proc_windows.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proc - -import "os" - -// Process tracing is not supported on windows yet. - -func Attach(pid int) (Process, os.Error) { - return nil, os.NewError("debug/proc not implemented on windows") -} - -func StartProcess(argv0 string, argv []string, attr *os.ProcAttr) (Process, os.Error) { - return Attach(0) -} diff --git a/libgo/go/debug/proc/regs_darwin_386.go b/libgo/go/debug/proc/regs_darwin_386.go deleted file mode 100644 index 60c9ac7..0000000 --- a/libgo/go/debug/proc/regs_darwin_386.go +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proc diff --git a/libgo/go/debug/proc/regs_darwin_amd64.go b/libgo/go/debug/proc/regs_darwin_amd64.go deleted file mode 100644 index 60c9ac7..0000000 --- a/libgo/go/debug/proc/regs_darwin_amd64.go +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proc diff --git a/libgo/go/debug/proc/regs_freebsd_386.go b/libgo/go/debug/proc/regs_freebsd_386.go deleted file mode 100644 index 60c9ac7..0000000 --- a/libgo/go/debug/proc/regs_freebsd_386.go +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proc diff --git a/libgo/go/debug/proc/regs_freebsd_amd64.go b/libgo/go/debug/proc/regs_freebsd_amd64.go deleted file mode 100644 index 60c9ac7..0000000 --- a/libgo/go/debug/proc/regs_freebsd_amd64.go +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proc diff --git a/libgo/go/debug/proc/regs_linux_386.go b/libgo/go/debug/proc/regs_linux_386.go deleted file mode 100644 index b4a9769..0000000 --- a/libgo/go/debug/proc/regs_linux_386.go +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proc - -import ( - "os" - "strconv" - "syscall" -) - -type _386Regs struct { - syscall.PtraceRegs - setter func(*syscall.PtraceRegs) os.Error -} - -var names = []string{ - "eax", - "ebx", - "ecx", - "edx", - "esi", - "edi", - "ebp", - "esp", - "eip", - "eflags", - "cs", - "ss", - "ds", - "es", - "fs", - "gs", -} - -func (r *_386Regs) PC() Word { return Word(r.Eip) } - -func (r *_386Regs) SetPC(val Word) os.Error { - r.Eip = int32(val) - return r.setter(&r.PtraceRegs) -} - -func (r *_386Regs) Link() Word { - // TODO(austin) - panic("No link register") -} - -func (r *_386Regs) SetLink(val Word) os.Error { panic("No link register") } - -func (r *_386Regs) SP() Word { return Word(r.Esp) } - -func (r *_386Regs) SetSP(val Word) os.Error { - r.Esp = int32(val) - return r.setter(&r.PtraceRegs) -} - -func (r *_386Regs) Names() []string { return names } - -func (r *_386Regs) Get(i int) Word { - switch i { - case 0: - return Word(uint32(r.Eax)) - case 1: - return Word(uint32(r.Ebx)) - case 2: - return Word(uint32(r.Ecx)) - case 3: - return Word(uint32(r.Edx)) - case 4: - return Word(uint32(r.Esi)) - case 5: - return Word(uint32(r.Edi)) - case 6: - return Word(uint32(r.Ebp)) - case 7: - return Word(uint32(r.Esp)) - case 8: - return Word(uint32(r.Eip)) - case 9: - return Word(uint32(r.Eflags)) - case 10: - return Word(r.Xcs) - case 11: - return Word(r.Xss) - case 12: - return Word(r.Xds) - case 13: - return Word(r.Xes) - case 14: - return Word(r.Xfs) - case 15: - return Word(r.Xgs) - } - panic("invalid register index " + strconv.Itoa(i)) -} - -func (r *_386Regs) Set(i int, val Word) os.Error { - switch i { - case 0: - r.Eax = int32(val) - case 1: - r.Ebx = int32(val) - case 2: - r.Ecx = int32(val) - case 3: - r.Edx = int32(val) - case 4: - r.Esi = int32(val) - case 5: - r.Edi = int32(val) - case 6: - r.Ebp = int32(val) - case 7: - r.Esp = int32(val) - case 8: - r.Eip = int32(val) - case 9: - r.Eflags = int32(val) - case 10: - r.Xcs = int32(val) - case 11: - r.Xss = int32(val) - case 12: - r.Xds = int32(val) - case 13: - r.Xes = int32(val) - case 14: - r.Xfs = int32(val) - case 15: - r.Xgs = int32(val) - default: - panic("invalid register index " + strconv.Itoa(i)) - } - return r.setter(&r.PtraceRegs) -} - -func newRegs(regs *syscall.PtraceRegs, setter func(*syscall.PtraceRegs) os.Error) Regs { - res := _386Regs{} - res.PtraceRegs = *regs - res.setter = setter - return &res -} diff --git a/libgo/go/debug/proc/regs_linux_amd64.go b/libgo/go/debug/proc/regs_linux_amd64.go deleted file mode 100644 index 381be29..0000000 --- a/libgo/go/debug/proc/regs_linux_amd64.go +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proc - -import ( - "os" - "strconv" - "syscall" -) - -type amd64Regs struct { - syscall.PtraceRegs - setter func(*syscall.PtraceRegs) os.Error -} - -var names = [...]string{ - "rax", - "rbx", - "rcx", - "rdx", - "rsi", - "rdi", - "rbp", - "rsp", - "r8", - "r9", - "r10", - "r11", - "r12", - "r13", - "r14", - "r15", - "rip", - "eflags", - "cs", - "ss", - "ds", - "es", - "fs", - "gs", - - // PtraceRegs contains these registers, but I don't think - // they're actually meaningful. - //"orig_rax", - //"fs_base", - //"gs_base", -} - -func (r *amd64Regs) PC() Word { return Word(r.Rip) } - -func (r *amd64Regs) SetPC(val Word) os.Error { - r.Rip = uint64(val) - return r.setter(&r.PtraceRegs) -} - -func (r *amd64Regs) Link() Word { - // TODO(austin) - panic("No link register") -} - -func (r *amd64Regs) SetLink(val Word) os.Error { - panic("No link register") -} - -func (r *amd64Regs) SP() Word { return Word(r.Rsp) } - -func (r *amd64Regs) SetSP(val Word) os.Error { - r.Rsp = uint64(val) - return r.setter(&r.PtraceRegs) -} - -func (r *amd64Regs) Names() []string { return names[0:] } - -func (r *amd64Regs) Get(i int) Word { - switch i { - case 0: - return Word(r.Rax) - case 1: - return Word(r.Rbx) - case 2: - return Word(r.Rcx) - case 3: - return Word(r.Rdx) - case 4: - return Word(r.Rsi) - case 5: - return Word(r.Rdi) - case 6: - return Word(r.Rbp) - case 7: - return Word(r.Rsp) - case 8: - return Word(r.R8) - case 9: - return Word(r.R9) - case 10: - return Word(r.R10) - case 11: - return Word(r.R11) - case 12: - return Word(r.R12) - case 13: - return Word(r.R13) - case 14: - return Word(r.R14) - case 15: - return Word(r.R15) - case 16: - return Word(r.Rip) - case 17: - return Word(r.Eflags) - case 18: - return Word(r.Cs) - case 19: - return Word(r.Ss) - case 20: - return Word(r.Ds) - case 21: - return Word(r.Es) - case 22: - return Word(r.Fs) - case 23: - return Word(r.Gs) - } - panic("invalid register index " + strconv.Itoa(i)) -} - -func (r *amd64Regs) Set(i int, val Word) os.Error { - switch i { - case 0: - r.Rax = uint64(val) - case 1: - r.Rbx = uint64(val) - case 2: - r.Rcx = uint64(val) - case 3: - r.Rdx = uint64(val) - case 4: - r.Rsi = uint64(val) - case 5: - r.Rdi = uint64(val) - case 6: - r.Rbp = uint64(val) - case 7: - r.Rsp = uint64(val) - case 8: - r.R8 = uint64(val) - case 9: - r.R9 = uint64(val) - case 10: - r.R10 = uint64(val) - case 11: - r.R11 = uint64(val) - case 12: - r.R12 = uint64(val) - case 13: - r.R13 = uint64(val) - case 14: - r.R14 = uint64(val) - case 15: - r.R15 = uint64(val) - case 16: - r.Rip = uint64(val) - case 17: - r.Eflags = uint64(val) - case 18: - r.Cs = uint64(val) - case 19: - r.Ss = uint64(val) - case 20: - r.Ds = uint64(val) - case 21: - r.Es = uint64(val) - case 22: - r.Fs = uint64(val) - case 23: - r.Gs = uint64(val) - default: - panic("invalid register index " + strconv.Itoa(i)) - } - return r.setter(&r.PtraceRegs) -} - -func newRegs(regs *syscall.PtraceRegs, setter func(*syscall.PtraceRegs) os.Error) Regs { - res := amd64Regs{} - res.PtraceRegs = *regs - res.setter = setter - return &res -} diff --git a/libgo/go/debug/proc/regs_linux_arm.go b/libgo/go/debug/proc/regs_linux_arm.go deleted file mode 100644 index ec78cbc..0000000 --- a/libgo/go/debug/proc/regs_linux_arm.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proc - -import ( - "os" - "syscall" -) - -// TODO(kaib): add support - -type armRegs struct{} - -func (r *armRegs) PC() Word { return Word(0) } - -func (r *armRegs) SetPC(val Word) os.Error { return nil } - -func (r *armRegs) Link() Word { return Word(0) } - -func (r *armRegs) SetLink(val Word) os.Error { return nil } - -func (r *armRegs) SP() Word { return Word(0) } - -func (r *armRegs) SetSP(val Word) os.Error { return nil } - -func (r *armRegs) Names() []string { return nil } - -func (r *armRegs) Get(i int) Word { return Word(0) } - -func (r *armRegs) Set(i int, val Word) os.Error { - return nil -} - -func newRegs(regs *syscall.PtraceRegs, setter func(*syscall.PtraceRegs) os.Error) Regs { - res := armRegs{} - return &res -} diff --git a/libgo/go/debug/proc/regs_windows_386.go b/libgo/go/debug/proc/regs_windows_386.go deleted file mode 100644 index 60c9ac7..0000000 --- a/libgo/go/debug/proc/regs_windows_386.go +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proc diff --git a/libgo/go/debug/proc/regs_windows_amd64.go b/libgo/go/debug/proc/regs_windows_amd64.go deleted file mode 100644 index 60c9ac7..0000000 --- a/libgo/go/debug/proc/regs_windows_amd64.go +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package proc diff --git a/libgo/go/ebnf/ebnf.go b/libgo/go/ebnf/ebnf.go index 7918c45..69da117 100644 --- a/libgo/go/ebnf/ebnf.go +++ b/libgo/go/ebnf/ebnf.go @@ -5,10 +5,10 @@ // Package ebnf is a library for EBNF grammars. The input is text ([]byte) // satisfying the following grammar (represented itself in EBNF): // -// Production = name "=" Expression "." . +// Production = name "=" [ Expression ] "." . // Expression = Alternative { "|" Alternative } . // Alternative = Term { Term } . -// Term = name | token [ "..." token ] | Group | Option | Repetition . +// Term = name | token [ "…" token ] | Group | Option | Repetition . // Group = "(" Expression ")" . // Option = "[" Expression "]" . // Repetition = "{" Expression "}" . @@ -30,7 +30,6 @@ import ( "utf8" ) - // ---------------------------------------------------------------------------- // Internal representation @@ -82,6 +81,12 @@ type ( Body Expression // {body} } + // A Bad node stands for pieces of source code that lead to a parse error. + Bad struct { + TokPos token.Pos + Error string // parser error message + } + // A Production node represents an EBNF production. Production struct { Name *Name @@ -94,7 +99,6 @@ type ( Grammar map[string]*Production ) - func (x Alternative) Pos() token.Pos { return x[0].Pos() } // the parser always generates non-empty Alternative func (x Sequence) Pos() token.Pos { return x[0].Pos() } // the parser always generates non-empty Sequences func (x *Name) Pos() token.Pos { return x.StringPos } @@ -103,9 +107,9 @@ func (x *Range) Pos() token.Pos { return x.Begin.Pos() } func (x *Group) Pos() token.Pos { return x.Lparen } func (x *Option) Pos() token.Pos { return x.Lbrack } func (x *Repetition) Pos() token.Pos { return x.Lbrace } +func (x *Bad) Pos() token.Pos { return x.TokPos } func (x *Production) Pos() token.Pos { return x.Name.Pos() } - // ---------------------------------------------------------------------------- // Grammar verification @@ -114,7 +118,6 @@ func isLexical(name string) bool { return !unicode.IsUpper(ch) } - type verifier struct { fset *token.FileSet scanner.ErrorVector @@ -123,12 +126,10 @@ type verifier struct { grammar Grammar } - func (v *verifier) error(pos token.Pos, msg string) { v.Error(v.fset.Position(pos), msg) } - func (v *verifier) push(prod *Production) { name := prod.Name.String if _, found := v.reached[name]; !found { @@ -137,7 +138,6 @@ func (v *verifier) push(prod *Production) { } } - func (v *verifier) verifyChar(x *Token) int { s := x.String if utf8.RuneCountInString(s) != 1 { @@ -148,7 +148,6 @@ func (v *verifier) verifyChar(x *Token) int { return ch } - func (v *verifier) verifyExpr(expr Expression, lexical bool) { switch x := expr.(type) { case nil: @@ -193,7 +192,6 @@ func (v *verifier) verifyExpr(expr Expression, lexical bool) { } } - func (v *verifier) verify(fset *token.FileSet, grammar Grammar, start string) { // find root production root, found := grammar[start] @@ -233,7 +231,6 @@ func (v *verifier) verify(fset *token.FileSet, grammar Grammar, start string) { } } - // Verify checks that: // - all productions used are defined // - all productions defined are used when beginning at start diff --git a/libgo/go/ebnf/ebnf_test.go b/libgo/go/ebnf/ebnf_test.go index e77cf64..b086fac 100644 --- a/libgo/go/ebnf/ebnf_test.go +++ b/libgo/go/ebnf/ebnf_test.go @@ -10,11 +10,9 @@ import ( "testing" ) - var fset = token.NewFileSet() - -var grammars = []string{ +var goodGrammars = []string{ `Program = .`, `Program = foo . @@ -22,7 +20,7 @@ var grammars = []string{ `Program = "a" | "b" "c" .`, - `Program = "a" ... "z" .`, + `Program = "a" … "z" .`, `Program = Song . Song = { Note } . @@ -37,8 +35,18 @@ var grammars = []string{ ti = "b" .`, } +var badGrammars = []string{ + `Program = | .`, + `Program = | b .`, + `Program = a … b .`, + `Program = "a" … .`, + `Program = … "b" .`, + `Program = () .`, + `Program = [] .`, + `Program = {} .`, +} -func check(t *testing.T, filename string, src []byte) { +func checkGood(t *testing.T, filename string, src []byte) { grammar, err := Parse(fset, filename, src) if err != nil { t.Errorf("Parse(%s) failed: %v", src, err) @@ -48,25 +56,32 @@ func check(t *testing.T, filename string, src []byte) { } } +func checkBad(t *testing.T, filename string, src []byte) { + _, err := Parse(fset, filename, src) + if err == nil { + t.Errorf("Parse(%s) should have failed", src) + } +} func TestGrammars(t *testing.T) { - for _, src := range grammars { - check(t, "", []byte(src)) + for _, src := range goodGrammars { + checkGood(t, "", []byte(src)) + } + for _, src := range badGrammars { + checkBad(t, "", []byte(src)) } } - var files = []string{ // TODO(gri) add some test files } - func TestFiles(t *testing.T) { for _, filename := range files { src, err := ioutil.ReadFile(filename) if err != nil { t.Fatal(err) } - check(t, filename, src) + checkGood(t, filename, src) } } diff --git a/libgo/go/ebnf/parser.go b/libgo/go/ebnf/parser.go index 818168e..ef2fac0 100644 --- a/libgo/go/ebnf/parser.go +++ b/libgo/go/ebnf/parser.go @@ -11,7 +11,6 @@ import ( "strconv" ) - type parser struct { fset *token.FileSet scanner.ErrorVector @@ -21,7 +20,6 @@ type parser struct { lit string // token literal } - func (p *parser) next() { p.pos, p.tok, p.lit = p.scanner.Scan() if p.tok.IsKeyword() { @@ -31,12 +29,10 @@ func (p *parser) next() { } } - func (p *parser) error(pos token.Pos, msg string) { p.Error(p.fset.Position(pos), msg) } - func (p *parser) errorExpected(pos token.Pos, msg string) { msg = "expected " + msg if pos == p.pos { @@ -50,7 +46,6 @@ func (p *parser) errorExpected(pos token.Pos, msg string) { p.error(pos, msg) } - func (p *parser) expect(tok token.Token) token.Pos { pos := p.pos if p.tok != tok { @@ -60,7 +55,6 @@ func (p *parser) expect(tok token.Token) token.Pos { return pos } - func (p *parser) parseIdentifier() *Name { pos := p.pos name := p.lit @@ -68,7 +62,6 @@ func (p *parser) parseIdentifier() *Name { return &Name{pos, name} } - func (p *parser) parseToken() *Token { pos := p.pos value := "" @@ -84,7 +77,7 @@ func (p *parser) parseToken() *Token { return &Token{pos, value} } - +// ParseTerm returns nil if no term was found. func (p *parser) parseTerm() (x Expression) { pos := p.pos @@ -95,7 +88,8 @@ func (p *parser) parseTerm() (x Expression) { case token.STRING: tok := p.parseToken() x = tok - if p.tok == token.ELLIPSIS { + const ellipsis = "…" // U+2026, the horizontal ellipsis character + if p.tok == token.ILLEGAL && p.lit == ellipsis { p.next() x = &Range{tok, p.parseToken()} } @@ -119,7 +113,6 @@ func (p *parser) parseTerm() (x Expression) { return x } - func (p *parser) parseSequence() Expression { var list Sequence @@ -130,7 +123,8 @@ func (p *parser) parseSequence() Expression { // no need for a sequence if list.Len() < 2 switch len(list) { case 0: - return nil + p.errorExpected(p.pos, "term") + return &Bad{p.pos, "term expected"} case 1: return list[0] } @@ -138,46 +132,42 @@ func (p *parser) parseSequence() Expression { return list } - func (p *parser) parseExpression() Expression { var list Alternative for { - if x := p.parseSequence(); x != nil { - list = append(list, x) - } + list = append(list, p.parseSequence()) if p.tok != token.OR { break } p.next() } + // len(list) > 0 // no need for an Alternative node if list.Len() < 2 - switch len(list) { - case 0: - return nil - case 1: + if len(list) == 1 { return list[0] } return list } - func (p *parser) parseProduction() *Production { name := p.parseIdentifier() p.expect(token.ASSIGN) - expr := p.parseExpression() + var expr Expression + if p.tok != token.PERIOD { + expr = p.parseExpression() + } p.expect(token.PERIOD) return &Production{name, expr} } - func (p *parser) parse(fset *token.FileSet, filename string, src []byte) Grammar { // initialize parser p.fset = fset p.ErrorVector.Reset() - p.scanner.Init(fset.AddFile(filename, fset.Base(), len(src)), src, p, 0) + p.scanner.Init(fset.AddFile(filename, fset.Base(), len(src)), src, p, scanner.AllowIllegalChars) p.next() // initializes pos, tok, lit grammar := make(Grammar) @@ -194,7 +184,6 @@ func (p *parser) parse(fset *token.FileSet, filename string, src []byte) Grammar return grammar } - // Parse parses a set of EBNF productions from source src. // It returns a set of productions. Errors are reported // for incorrect syntax and if a production is declared diff --git a/libgo/go/encoding/base32/base32_test.go b/libgo/go/encoding/base32/base32_test.go index 792e4dc..3fa1c2b 100644 --- a/libgo/go/encoding/base32/base32_test.go +++ b/libgo/go/encoding/base32/base32_test.go @@ -25,7 +25,6 @@ var pairs = []testpair{ {"fooba", "MZXW6YTB"}, {"foobar", "MZXW6YTBOI======"}, - // Wikipedia examples, converted to base32 {"sure.", "ON2XEZJO"}, {"sure", "ON2XEZI="}, diff --git a/libgo/go/encoding/base64/base64.go b/libgo/go/encoding/base64/base64.go index 4961297..c6b2a13e 100644 --- a/libgo/go/encoding/base64/base64.go +++ b/libgo/go/encoding/base64/base64.go @@ -106,6 +106,13 @@ func (enc *Encoding) Encode(dst, src []byte) { } } +// EncodeToString returns the base64 encoding of src. +func (enc *Encoding) EncodeToString(src []byte) string { + buf := make([]byte, enc.EncodedLen(len(src))) + enc.Encode(buf, src) + return string(buf) +} + type encoder struct { err os.Error enc *Encoding @@ -260,6 +267,13 @@ func (enc *Encoding) Decode(dst, src []byte) (n int, err os.Error) { return } +// DecodeString returns the bytes represented by the base64 string s. +func (enc *Encoding) DecodeString(s string) ([]byte, os.Error) { + dbuf := make([]byte, enc.DecodedLen(len(s))) + n, err := enc.Decode(dbuf, []byte(s)) + return dbuf[:n], err +} + type decoder struct { err os.Error enc *Encoding diff --git a/libgo/go/encoding/base64/base64_test.go b/libgo/go/encoding/base64/base64_test.go index de41e70..c163dae 100644 --- a/libgo/go/encoding/base64/base64_test.go +++ b/libgo/go/encoding/base64/base64_test.go @@ -56,9 +56,8 @@ func testEqual(t *testing.T, msg string, args ...interface{}) bool { func TestEncode(t *testing.T) { for _, p := range pairs { - buf := make([]byte, StdEncoding.EncodedLen(len(p.decoded))) - StdEncoding.Encode(buf, []byte(p.decoded)) - testEqual(t, "Encode(%q) = %q, want %q", p.decoded, string(buf), p.encoded) + got := StdEncoding.EncodeToString([]byte(p.decoded)) + testEqual(t, "Encode(%q) = %q, want %q", p.decoded, got, p.encoded) } } @@ -102,6 +101,10 @@ func TestDecode(t *testing.T) { testEqual(t, "Decode(%q) = end %v, want %v", p.encoded, end, (p.encoded[len(p.encoded)-1] == '=')) } testEqual(t, "Decode(%q) = %q, want %q", p.encoded, string(dbuf[0:count]), p.decoded) + + dbuf, err = StdEncoding.DecodeString(p.encoded) + testEqual(t, "DecodeString(%q) = error %v, want %v", p.encoded, err, os.Error(nil)) + testEqual(t, "DecodeString(%q) = %q, want %q", string(dbuf), p.decoded) } } diff --git a/libgo/go/encoding/binary/binary.go b/libgo/go/encoding/binary/binary.go index a01d0e0..8e55cb2 100644 --- a/libgo/go/encoding/binary/binary.go +++ b/libgo/go/encoding/binary/binary.go @@ -125,6 +125,35 @@ func (bigEndian) GoString() string { return "binary.BigEndian" } // Bytes read from r are decoded using the specified byte order // and written to successive fields of the data. func Read(r io.Reader, order ByteOrder, data interface{}) os.Error { + // Fast path for basic types. + if n := intDestSize(data); n != 0 { + var b [8]byte + bs := b[:n] + if _, err := io.ReadFull(r, bs); err != nil { + return err + } + switch v := data.(type) { + case *int8: + *v = int8(b[0]) + case *uint8: + *v = b[0] + case *int16: + *v = int16(order.Uint16(bs)) + case *uint16: + *v = order.Uint16(bs) + case *int32: + *v = int32(order.Uint32(bs)) + case *uint32: + *v = order.Uint32(bs) + case *int64: + *v = int64(order.Uint64(bs)) + case *uint64: + *v = order.Uint64(bs) + } + return nil + } + + // Fallback to reflect-based. var v reflect.Value switch d := reflect.ValueOf(data); d.Kind() { case reflect.Ptr: @@ -155,6 +184,63 @@ func Read(r io.Reader, order ByteOrder, data interface{}) os.Error { // Bytes written to w are encoded using the specified byte order // and read from successive fields of the data. func Write(w io.Writer, order ByteOrder, data interface{}) os.Error { + // Fast path for basic types. + var b [8]byte + var bs []byte + switch v := data.(type) { + case *int8: + bs = b[:1] + b[0] = byte(*v) + case int8: + bs = b[:1] + b[0] = byte(v) + case *uint8: + bs = b[:1] + b[0] = *v + case uint8: + bs = b[:1] + b[0] = byte(v) + case *int16: + bs = b[:2] + order.PutUint16(bs, uint16(*v)) + case int16: + bs = b[:2] + order.PutUint16(bs, uint16(v)) + case *uint16: + bs = b[:2] + order.PutUint16(bs, *v) + case uint16: + bs = b[:2] + order.PutUint16(bs, v) + case *int32: + bs = b[:4] + order.PutUint32(bs, uint32(*v)) + case int32: + bs = b[:4] + order.PutUint32(bs, uint32(v)) + case *uint32: + bs = b[:4] + order.PutUint32(bs, *v) + case uint32: + bs = b[:4] + order.PutUint32(bs, v) + case *int64: + bs = b[:8] + order.PutUint64(bs, uint64(*v)) + case int64: + bs = b[:8] + order.PutUint64(bs, uint64(v)) + case *uint64: + bs = b[:8] + order.PutUint64(bs, *v) + case uint64: + bs = b[:8] + order.PutUint64(bs, v) + } + if bs != nil { + _, err := w.Write(bs) + return err + } v := reflect.Indirect(reflect.ValueOf(data)) size := TotalSize(v) if size < 0 { @@ -394,3 +480,19 @@ func (e *encoder) value(v reflect.Value) { } } } + +// intDestSize returns the size of the integer that ptrType points to, +// or 0 if the type is not supported. +func intDestSize(ptrType interface{}) int { + switch ptrType.(type) { + case *int8, *uint8: + return 1 + case *int16, *uint16: + return 2 + case *int32, *uint32: + return 4 + case *int64, *uint64: + return 8 + } + return 0 +} diff --git a/libgo/go/encoding/binary/binary_test.go b/libgo/go/encoding/binary/binary_test.go index 7857c68..b266996 100644 --- a/libgo/go/encoding/binary/binary_test.go +++ b/libgo/go/encoding/binary/binary_test.go @@ -5,6 +5,7 @@ package binary import ( + "io" "os" "bytes" "math" @@ -160,3 +161,75 @@ func TestWriteT(t *testing.T) { } } } + +type byteSliceReader struct { + remain []byte +} + +func (br *byteSliceReader) Read(p []byte) (int, os.Error) { + n := copy(p, br.remain) + br.remain = br.remain[n:] + return n, nil +} + +func BenchmarkRead(b *testing.B) { + var ls Struct + bsr := &byteSliceReader{} + var r io.Reader = bsr + + for i := 0; i < b.N; i++ { + bsr.remain = big + Read(r, BigEndian, &ls.Int8) + Read(r, BigEndian, &ls.Int16) + Read(r, BigEndian, &ls.Int32) + Read(r, BigEndian, &ls.Int64) + Read(r, BigEndian, &ls.Uint8) + Read(r, BigEndian, &ls.Uint16) + Read(r, BigEndian, &ls.Uint32) + Read(r, BigEndian, &ls.Uint64) + } + + want := s + want.Float32 = 0 + want.Float64 = 0 + want.Complex64 = 0 + want.Complex128 = 0 + for i := range want.Array { + want.Array[i] = 0 + } + if !reflect.DeepEqual(ls, want) { + panic("no match") + } +} + +func BenchmarkWrite(b *testing.B) { + buf := new(bytes.Buffer) + var w io.Writer = buf + + for i := 0; i < b.N; i++ { + buf.Reset() + Write(w, BigEndian, &s.Int8) + Write(w, BigEndian, &s.Int16) + Write(w, BigEndian, &s.Int32) + Write(w, BigEndian, &s.Int64) + Write(w, BigEndian, &s.Uint8) + Write(w, BigEndian, &s.Uint16) + Write(w, BigEndian, &s.Uint32) + Write(w, BigEndian, &s.Uint64) + Write(w, BigEndian, s.Int8) + Write(w, BigEndian, s.Int16) + Write(w, BigEndian, s.Int32) + Write(w, BigEndian, s.Int64) + Write(w, BigEndian, s.Uint8) + Write(w, BigEndian, s.Uint16) + Write(w, BigEndian, s.Uint32) + Write(w, BigEndian, s.Uint64) + } + + if !bytes.Equal(buf.Bytes()[:30], big[:30]) { + panic("first half doesn't match") + } + if !bytes.Equal(buf.Bytes()[30:], big[:30]) { + panic("second half doesn't match") + } +} diff --git a/libgo/go/encoding/git85/git.go b/libgo/go/encoding/git85/git.go index 09a45cd..6bb74f4 100644 --- a/libgo/go/encoding/git85/git.go +++ b/libgo/go/encoding/git85/git.go @@ -273,5 +273,5 @@ func (d *decoder) Read(p []byte) (n int, err os.Error) { d.nbuf = copy(d.buf[0:], d.buf[nl+1:d.nbuf]) d.off += int64(nl + 1) } - panic("unreacahable") + panic("unreachable") } diff --git a/libgo/go/encoding/hex/hex.go b/libgo/go/encoding/hex/hex.go index 891de18..e7ea8b0 100644 --- a/libgo/go/encoding/hex/hex.go +++ b/libgo/go/encoding/hex/hex.go @@ -6,6 +6,8 @@ package hex import ( + "bytes" + "io" "os" "strconv" ) @@ -40,7 +42,6 @@ func (e InvalidHexCharError) String() string { return "invalid hex char: " + strconv.Itoa(int(e)) } - func DecodedLen(x int) int { return x / 2 } // Decode decodes src into DecodedLen(len(src)) bytes, returning the actual @@ -99,3 +100,117 @@ func DecodeString(s string) ([]byte, os.Error) { } return dst, nil } + +// Dump returns a string that contains a hex dump of the given data. The format +// of the hex dump matches the output of `hexdump -C` on the command line. +func Dump(data []byte) string { + buf := bytes.NewBuffer(nil) + dumper := Dumper(buf) + dumper.Write(data) + dumper.Close() + return string(buf.Bytes()) +} + +// Dumper returns a WriteCloser that writes a hex dump of all written data to +// w. The format of the dump matches the output of `hexdump -C` on the command +// line. +func Dumper(w io.Writer) io.WriteCloser { + return &dumper{w: w} +} + +type dumper struct { + w io.Writer + rightChars [18]byte + buf [14]byte + used int // number of bytes in the current line + n uint // number of bytes, total +} + +func toChar(b byte) byte { + if b < 32 || b > 126 { + return '.' + } + return b +} + +func (h *dumper) Write(data []byte) (n int, err os.Error) { + // Output lines look like: + // 00000010 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d |./0123456789:;<=| + // ^ offset ^ extra space ^ ASCII of line. + for i := range data { + if h.used == 0 { + // At the beginning of a line we print the current + // offset in hex. + h.buf[0] = byte(h.n >> 24) + h.buf[1] = byte(h.n >> 16) + h.buf[2] = byte(h.n >> 8) + h.buf[3] = byte(h.n) + Encode(h.buf[4:], h.buf[:4]) + h.buf[12] = ' ' + h.buf[13] = ' ' + _, err = h.w.Write(h.buf[4:]) + } + Encode(h.buf[:], data[i:i+1]) + h.buf[2] = ' ' + l := 3 + if h.used == 7 { + // There's an additional space after the 8th byte. + h.buf[3] = ' ' + l = 4 + } else if h.used == 15 { + // At the end of the line there's an extra space and + // the bar for the right column. + h.buf[3] = ' ' + h.buf[4] = '|' + l = 5 + } + _, err = h.w.Write(h.buf[:l]) + if err != nil { + return + } + n++ + h.rightChars[h.used] = toChar(data[i]) + h.used++ + h.n++ + if h.used == 16 { + h.rightChars[16] = '|' + h.rightChars[17] = '\n' + _, err = h.w.Write(h.rightChars[:]) + if err != nil { + return + } + h.used = 0 + } + } + return +} + +func (h *dumper) Close() (err os.Error) { + // See the comments in Write() for the details of this format. + if h.used == 0 { + return + } + h.buf[0] = ' ' + h.buf[1] = ' ' + h.buf[2] = ' ' + h.buf[3] = ' ' + h.buf[4] = '|' + nBytes := h.used + for h.used < 16 { + l := 3 + if h.used == 7 { + l = 4 + } else if h.used == 15 { + l = 5 + } + _, err = h.w.Write(h.buf[:l]) + if err != nil { + return + } + h.used++ + } + h.rightChars[nBytes] = '|' + h.rightChars[nBytes+1] = '\n' + _, err = h.w.Write(h.rightChars[:nBytes+2]) + return +} diff --git a/libgo/go/encoding/hex/hex_test.go b/libgo/go/encoding/hex/hex_test.go index a14c9d4..8e1838e 100644 --- a/libgo/go/encoding/hex/hex_test.go +++ b/libgo/go/encoding/hex/hex_test.go @@ -147,3 +147,46 @@ func TestDecodeString(t *testing.T) { } } } + +func TestDumper(t *testing.T) { + var in [40]byte + for i := range in { + in[i] = byte(i + 30) + } + + for stride := 1; stride < len(in); stride++ { + out := bytes.NewBuffer(nil) + dumper := Dumper(out) + done := 0 + for done < len(in) { + todo := done + stride + if todo > len(in) { + todo = len(in) + } + dumper.Write(in[done:todo]) + done = todo + } + + dumper.Close() + if !bytes.Equal(out.Bytes(), expectedHexDump) { + t.Errorf("stride: %d failed. got:\n%s\nwant:\n%s", stride, out.Bytes(), expectedHexDump) + } + } +} + +func TestDump(t *testing.T) { + var in [40]byte + for i := range in { + in[i] = byte(i + 30) + } + + out := []byte(Dump(in[:])) + if !bytes.Equal(out, expectedHexDump) { + t.Errorf("got:\n%s\nwant:\n%s", out, expectedHexDump) + } +} + +var expectedHexDump = []byte(`00000000 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d |.. !"#$%&'()*+,-| +00000010 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d |./0123456789:;<=| +00000020 3e 3f 40 41 42 43 44 45 |>?@ABCDE| +`) diff --git a/libgo/go/encoding/line/line.go b/libgo/go/encoding/line/line.go deleted file mode 100644 index 123962b..0000000 --- a/libgo/go/encoding/line/line.go +++ /dev/null @@ -1,115 +0,0 @@ -// 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 line implements a Reader that reads lines delimited by '\n' or -// ' \r\n'. -package line - -import ( - "io" - "os" -) - -// Reader reads lines, delimited by '\n' or \r\n', from an io.Reader. -type Reader struct { - buf []byte - consumed int - in io.Reader - err os.Error -} - -// NewReader returns a new Reader that will read successive -// lines from the input Reader. -func NewReader(input io.Reader, maxLineLength int) *Reader { - return &Reader{ - buf: make([]byte, 0, maxLineLength), - consumed: 0, - in: input, - } -} - -// Read reads from any buffered data past the last line read, or from the underlying -// io.Reader if the buffer is empty. -func (l *Reader) Read(p []byte) (n int, err os.Error) { - l.removeConsumedFromBuffer() - if len(l.buf) > 0 { - n = copy(p, l.buf) - l.consumed += n - return - } - return l.in.Read(p) -} - -func (l *Reader) removeConsumedFromBuffer() { - if l.consumed > 0 { - n := copy(l.buf, l.buf[l.consumed:]) - l.buf = l.buf[:n] - l.consumed = 0 - } -} - -// ReadLine tries to return a single line, not including the end-of-line bytes. -// If the line was found to be longer than the maximum length then isPrefix is -// set and the beginning of the line is returned. The rest of the line will be -// returned from future calls. isPrefix will be false when returning the last -// fragment of the line. The returned buffer points into the internal state of -// the Reader and is only valid until the next call to ReadLine. ReadLine -// either returns a non-nil line or it returns an error, never both. -func (l *Reader) ReadLine() (line []byte, isPrefix bool, err os.Error) { - l.removeConsumedFromBuffer() - - if len(l.buf) == 0 && l.err != nil { - err = l.err - return - } - - scannedTo := 0 - - for { - i := scannedTo - for ; i < len(l.buf); i++ { - if l.buf[i] == '\r' && len(l.buf) > i+1 && l.buf[i+1] == '\n' { - line = l.buf[:i] - l.consumed = i + 2 - return - } else if l.buf[i] == '\n' { - line = l.buf[:i] - l.consumed = i + 1 - return - } - } - - if i == cap(l.buf) { - line = l.buf[:i] - l.consumed = i - isPrefix = true - return - } - - if l.err != nil { - line = l.buf - l.consumed = i - return - } - - // We don't want to rescan the input that we just scanned. - // However, we need to back up one byte because the last byte - // could have been a '\r' and we do need to rescan that. - scannedTo = i - if scannedTo > 0 { - scannedTo-- - } - oldLen := len(l.buf) - l.buf = l.buf[:cap(l.buf)] - n, readErr := l.in.Read(l.buf[oldLen:]) - l.buf = l.buf[:oldLen+n] - if readErr != nil { - l.err = readErr - if len(l.buf) == 0 { - return nil, false, readErr - } - } - } - panic("unreachable") -} diff --git a/libgo/go/encoding/line/line_test.go b/libgo/go/encoding/line/line_test.go deleted file mode 100644 index ff3d516..0000000 --- a/libgo/go/encoding/line/line_test.go +++ /dev/null @@ -1,133 +0,0 @@ -// 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 line - -import ( - "bytes" - "io" - "io/ioutil" - "os" - "testing" -) - -var testOutput = []byte("0123456789abcdefghijklmnopqrstuvwxy") -var testInput = []byte("012\n345\n678\n9ab\ncde\nfgh\nijk\nlmn\nopq\nrst\nuvw\nxy") -var testInputrn = []byte("012\r\n345\r\n678\r\n9ab\r\ncde\r\nfgh\r\nijk\r\nlmn\r\nopq\r\nrst\r\nuvw\r\nxy\r\n\n\r\n") - -// TestReader wraps a []byte and returns reads of a specific length. -type testReader struct { - data []byte - stride int -} - -func (t *testReader) Read(buf []byte) (n int, err os.Error) { - n = t.stride - if n > len(t.data) { - n = len(t.data) - } - if n > len(buf) { - n = len(buf) - } - copy(buf, t.data) - t.data = t.data[n:] - if len(t.data) == 0 { - err = os.EOF - } - return -} - -func testLineReader(t *testing.T, input []byte) { - for stride := 1; stride < len(input); stride++ { - done := 0 - reader := testReader{input, stride} - l := NewReader(&reader, len(input)+1) - for { - line, isPrefix, err := l.ReadLine() - if len(line) > 0 && err != nil { - t.Errorf("ReadLine returned both data and error: %s", err) - } - if isPrefix { - t.Errorf("ReadLine returned prefix") - } - if err != nil { - if err != os.EOF { - t.Fatalf("Got unknown error: %s", err) - } - break - } - if want := testOutput[done : done+len(line)]; !bytes.Equal(want, line) { - t.Errorf("Bad line at stride %d: want: %x got: %x", stride, want, line) - } - done += len(line) - } - if done != len(testOutput) { - t.Error("ReadLine didn't return everything") - } - } -} - -func TestReader(t *testing.T) { - testLineReader(t, testInput) - testLineReader(t, testInputrn) -} - -func TestLineTooLong(t *testing.T) { - buf := bytes.NewBuffer([]byte("aaabbbcc\n")) - l := NewReader(buf, 3) - line, isPrefix, err := l.ReadLine() - if !isPrefix || !bytes.Equal(line, []byte("aaa")) || err != nil { - t.Errorf("bad result for first line: %x %s", line, err) - } - line, isPrefix, err = l.ReadLine() - if !isPrefix || !bytes.Equal(line, []byte("bbb")) || err != nil { - t.Errorf("bad result for second line: %x", line) - } - line, isPrefix, err = l.ReadLine() - if isPrefix || !bytes.Equal(line, []byte("cc")) || err != nil { - t.Errorf("bad result for third line: %x", line) - } -} - -func TestReadAfterLines(t *testing.T) { - line1 := "line1" - restData := "line2\nline 3\n" - inbuf := bytes.NewBuffer([]byte(line1 + "\n" + restData)) - outbuf := new(bytes.Buffer) - maxLineLength := len(line1) + len(restData)/2 - l := NewReader(inbuf, maxLineLength) - line, isPrefix, err := l.ReadLine() - if isPrefix || err != nil || string(line) != line1 { - t.Errorf("bad result for first line: isPrefix=%v err=%v line=%q", isPrefix, err, string(line)) - } - n, err := io.Copy(outbuf, l) - if int(n) != len(restData) || err != nil { - t.Errorf("bad result for Read: n=%d err=%v", n, err) - } - if outbuf.String() != restData { - t.Errorf("bad result for Read: got %q; expected %q", outbuf.String(), restData) - } -} - -func TestReadEmptyBuffer(t *testing.T) { - l := NewReader(bytes.NewBuffer(nil), 10) - line, isPrefix, err := l.ReadLine() - if err != os.EOF { - t.Errorf("expected EOF from ReadLine, got '%s' %t %s", line, isPrefix, err) - } -} - -func TestLinesAfterRead(t *testing.T) { - l := NewReader(bytes.NewBuffer([]byte("foo")), 10) - _, err := ioutil.ReadAll(l) - if err != nil { - t.Error(err) - return - } - - line, isPrefix, err := l.ReadLine() - if err != os.EOF { - t.Errorf("expected EOF from ReadLine, got '%s' %t %s", line, isPrefix, err) - } -} diff --git a/libgo/go/encoding/pem/pem.go b/libgo/go/encoding/pem/pem.go index 44e3d0a..12689b5 100644 --- a/libgo/go/encoding/pem/pem.go +++ b/libgo/go/encoding/pem/pem.go @@ -86,7 +86,7 @@ func Decode(data []byte) (p *Block, rest []byte) { typeLine, rest := getLine(rest) if !bytes.HasSuffix(typeLine, pemEndOfLine) { - goto Error + return decodeError(data, rest) } typeLine = typeLine[0 : len(typeLine)-len(pemEndOfLine)] @@ -97,7 +97,7 @@ func Decode(data []byte) (p *Block, rest []byte) { for { // This loop terminates because getLine's second result is - // always smaller than it's argument. + // always smaller than its argument. if len(rest) == 0 { return nil, data } @@ -118,29 +118,30 @@ func Decode(data []byte) (p *Block, rest []byte) { i := bytes.Index(rest, pemEnd) if i < 0 { - goto Error + return decodeError(data, rest) } base64Data := removeWhitespace(rest[0:i]) p.Bytes = make([]byte, base64.StdEncoding.DecodedLen(len(base64Data))) n, err := base64.StdEncoding.Decode(p.Bytes, base64Data) if err != nil { - goto Error + return decodeError(data, rest) } p.Bytes = p.Bytes[0:n] _, rest = getLine(rest[i+len(pemEnd):]) return +} -Error: +func decodeError(data, rest []byte) (*Block, []byte) { // If we get here then we have rejected a likely looking, but // ultimately invalid PEM block. We need to start over from a new // position. We have consumed the preamble line and will have consumed // any lines which could be header lines. However, a valid preamble // line is not a valid header line, therefore we cannot have consumed // the preamble line for the any subsequent block. Thus, we will always - // find any valid block, no matter what bytes preceed it. + // find any valid block, no matter what bytes precede it. // // For example, if the input is // @@ -154,11 +155,11 @@ Error: // // we've failed to parse using the first BEGIN line // and now will try again, using the second BEGIN line. - p, rest = Decode(rest) + p, rest := Decode(rest) if p == nil { rest = data } - return + return p, rest } const pemLineLength = 64 diff --git a/libgo/go/exec/exec.go b/libgo/go/exec/exec.go index 043f847..3b20f20 100644 --- a/libgo/go/exec/exec.go +++ b/libgo/go/exec/exec.go @@ -7,198 +7,371 @@ // adjustments. package exec -// BUG(r): This package should be made even easier to use or merged into os. - import ( + "bytes" + "io" "os" "strconv" + "syscall" ) -// Arguments to Run. -const ( - DevNull = iota - PassThrough - Pipe - MergeWithStdout -) +// Error records the name of a binary that failed to be be executed +// and the reason it failed. +type Error struct { + Name string + Error os.Error +} -// A Cmd represents a running command. -// Stdin, Stdout, and Stderr are Files representing pipes -// connected to the running command's standard input, output, and error, -// or else nil, depending on the arguments to Run. -// Process represents the underlying operating system process. +func (e *Error) String() string { + return "exec: " + strconv.Quote(e.Name) + ": " + e.Error.String() +} + +// Cmd represents an external command being prepared or run. type Cmd struct { - Stdin *os.File - Stdout *os.File - Stderr *os.File + // Path is the path of the command to run. + // + // This is the only field that must be set to a non-zero + // value. + Path string + + // Args holds command line arguments, including the command as Args[0]. + // If the Args field is empty or nil, Run uses {Path}. + // + // In typical use, both Path and Args are set by calling Command. + Args []string + + // Env specifies the environment of the process. + // If Env is nil, Run uses the current process's environment. + Env []string + + // Dir specifies the working directory of the command. + // If Dir is the empty string, Run runs the command in the + // calling process's current directory. + Dir string + + // Stdin specifies the process's standard input. + // If Stdin is nil, the process reads from DevNull. + Stdin io.Reader + + // Stdout and Stderr specify the process's standard output and error. + // + // If either is nil, Run connects the + // corresponding file descriptor to /dev/null. + // + // If Stdout and Stderr are are the same writer, at most one + // goroutine at a time will call Write. + Stdout io.Writer + Stderr io.Writer + + // SysProcAttr holds optional, operating system-specific attributes. + // Run passes it to os.StartProcess as the os.ProcAttr's Sys field. + SysProcAttr *syscall.SysProcAttr + + // Process is the underlying process, once started. Process *os.Process + + err os.Error // last error (from LookPath, stdin, stdout, stderr) + finished bool // when Wait was called + childFiles []*os.File + closeAfterStart []io.Closer + closeAfterWait []io.Closer + goroutine []func() os.Error + errch chan os.Error // one send per goroutine } -// PathError records the name of a binary that was not -// found on the current $PATH. -type PathError struct { - Name string +// Command returns the Cmd struct to execute the named program with +// the given arguments. +// +// It sets Path and Args in the returned structure and zeroes the +// other fields. +// +// If name contains no path separators, Command uses LookPath to +// resolve the path to a complete name if possible. Otherwise it uses +// name directly. +// +// The returned Cmd's Args field is constructed from the command name +// followed by the elements of arg, so arg should not include the +// command name itself. For example, Command("echo", "hello") +func Command(name string, arg ...string) *Cmd { + aname, err := LookPath(name) + if err != nil { + aname = name + } + return &Cmd{ + Path: aname, + Args: append([]string{name}, arg...), + err: err, + } } -func (e *PathError) String() string { - return "command " + strconv.Quote(e.Name) + " not found in $PATH" +// interfaceEqual protects against panics from doing equality tests on +// two interfaces with non-comparable underlying types +func interfaceEqual(a, b interface{}) bool { + defer func() { + recover() + }() + return a == b } -// Given mode (DevNull, etc), return file for child -// and file to record in Cmd structure. -func modeToFiles(mode, fd int) (*os.File, *os.File, os.Error) { - switch mode { - case DevNull: - rw := os.O_WRONLY - if fd == 0 { - rw = os.O_RDONLY - } - f, err := os.OpenFile(os.DevNull, rw, 0) - return f, nil, err - case PassThrough: - switch fd { - case 0: - return os.Stdin, nil, nil - case 1: - return os.Stdout, nil, nil - case 2: - return os.Stderr, nil, nil - } - case Pipe: - r, w, err := os.Pipe() - if err != nil { - return nil, nil, err - } - if fd == 0 { - return r, w, nil +func (c *Cmd) envv() []string { + if c.Env != nil { + return c.Env + } + return os.Environ() +} + +func (c *Cmd) argv() []string { + if len(c.Args) > 0 { + return c.Args + } + return []string{c.Path} +} + +func (c *Cmd) stdin() (f *os.File, err os.Error) { + if c.Stdin == nil { + f, err = os.Open(os.DevNull) + c.closeAfterStart = append(c.closeAfterStart, f) + return + } + + if f, ok := c.Stdin.(*os.File); ok { + return f, nil + } + + pr, pw, err := os.Pipe() + if err != nil { + return + } + + c.closeAfterStart = append(c.closeAfterStart, pr) + c.closeAfterWait = append(c.closeAfterWait, pw) + c.goroutine = append(c.goroutine, func() os.Error { + _, err := io.Copy(pw, c.Stdin) + if err1 := pw.Close(); err == nil { + err = err1 } - return w, r, nil + return err + }) + return pr, nil +} + +func (c *Cmd) stdout() (f *os.File, err os.Error) { + return c.writerDescriptor(c.Stdout) +} + +func (c *Cmd) stderr() (f *os.File, err os.Error) { + if c.Stderr != nil && interfaceEqual(c.Stderr, c.Stdout) { + return c.childFiles[1], nil } - return nil, nil, os.EINVAL + return c.writerDescriptor(c.Stderr) } -// 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. +func (c *Cmd) writerDescriptor(w io.Writer) (f *os.File, err os.Error) { + if w == nil { + f, err = os.OpenFile(os.DevNull, os.O_WRONLY, 0) + c.closeAfterStart = append(c.closeAfterStart, f) + return + } + + if f, ok := w.(*os.File); ok { + return f, nil + } + + pr, pw, err := os.Pipe() + if err != nil { + return + } + + c.closeAfterStart = append(c.closeAfterStart, pw) + c.closeAfterWait = append(c.closeAfterWait, pr) + c.goroutine = append(c.goroutine, func() os.Error { + _, err := io.Copy(w, pr) + return err + }) + return pw, nil +} + +// Run starts the specified command and waits for it to complete. // -// 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 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) { - c = new(Cmd) - var fd [3]*os.File - - if fd[0], c.Stdin, err = modeToFiles(stdin, 0); err != nil { - goto Error - } - if fd[1], c.Stdout, err = modeToFiles(stdout, 1); err != nil { - goto Error - } - if stderr == MergeWithStdout { - fd[2] = fd[1] - } else if fd[2], c.Stderr, err = modeToFiles(stderr, 2); err != nil { - goto Error - } - - // Run command. - c.Process, err = os.StartProcess(name, argv, &os.ProcAttr{Dir: dir, Files: fd[:], Env: envv}) +// The returned error is nil if the command runs, has no problems +// copying stdin, stdout, and stderr, and exits with a zero exit +// status. +// +// If the command fails to run or doesn't complete successfully, the +// error is of type *os.Waitmsg. Other error types may be +// returned for I/O problems. +func (c *Cmd) Run() os.Error { + if err := c.Start(); err != nil { + return err + } + return c.Wait() +} + +// Start starts the specified command but does not wait for it to complete. +func (c *Cmd) Start() os.Error { + if c.err != nil { + return c.err + } + if c.Process != nil { + return os.NewError("exec: already started") + } + + type F func(*Cmd) (*os.File, os.Error) + for _, setupFd := range []F{(*Cmd).stdin, (*Cmd).stdout, (*Cmd).stderr} { + fd, err := setupFd(c) + if err != nil { + return err + } + c.childFiles = append(c.childFiles, fd) + } + + var err os.Error + c.Process, err = os.StartProcess(c.Path, c.argv(), &os.ProcAttr{ + Dir: c.Dir, + Files: c.childFiles, + Env: c.envv(), + Sys: c.SysProcAttr, + }) if err != nil { - goto Error + return err } - if fd[0] != os.Stdin { - fd[0].Close() + + for _, fd := range c.closeAfterStart { + fd.Close() } - if fd[1] != os.Stdout { - fd[1].Close() + + c.errch = make(chan os.Error, len(c.goroutine)) + for _, fn := range c.goroutine { + go func(fn func() os.Error) { + c.errch <- fn() + }(fn) } - if fd[2] != os.Stderr && fd[2] != fd[1] { - fd[2].Close() + + return nil +} + +// Wait waits for the command to exit. +// It must have been started by Start. +// +// The returned error is nil if the command runs, has no problems +// copying stdin, stdout, and stderr, and exits with a zero exit +// status. +// +// If the command fails to run or doesn't complete successfully, the +// error is of type *os.Waitmsg. Other error types may be +// returned for I/O problems. +func (c *Cmd) Wait() os.Error { + if c.Process == nil { + return os.NewError("exec: not started") } - return c, nil + if c.finished { + return os.NewError("exec: Wait was already called") + } + c.finished = true + msg, err := c.Process.Wait(0) -Error: - if fd[0] != os.Stdin && fd[0] != nil { - fd[0].Close() + var copyError os.Error + for _ = range c.goroutine { + if err := <-c.errch; err != nil && copyError == nil { + copyError = err + } } - if fd[1] != os.Stdout && fd[1] != nil { - fd[1].Close() + + for _, fd := range c.closeAfterWait { + fd.Close() } - if fd[2] != os.Stderr && fd[2] != nil && fd[2] != fd[1] { - fd[2].Close() + + if err != nil { + return err + } else if !msg.Exited() || msg.ExitStatus() != 0 { + return msg } - if c.Stdin != nil { - c.Stdin.Close() + + return copyError +} + +// Output runs the command and returns its standard output. +func (c *Cmd) Output() ([]byte, os.Error) { + if c.Stdout != nil { + return nil, os.NewError("exec: Stdout already set") } + var b bytes.Buffer + c.Stdout = &b + err := c.Run() + return b.Bytes(), err +} + +// CombinedOutput runs the command and returns its combined standard +// output and standard error. +func (c *Cmd) CombinedOutput() ([]byte, os.Error) { if c.Stdout != nil { - c.Stdout.Close() + return nil, os.NewError("exec: Stdout already set") } if c.Stderr != nil { - c.Stderr.Close() + return nil, os.NewError("exec: Stderr already set") } - if c.Process != nil { - c.Process.Release() - } - return nil, err + var b bytes.Buffer + c.Stdout = &b + c.Stderr = &b + err := c.Run() + return b.Bytes(), err } -// Wait waits for the running command c, -// returning the Waitmsg returned when the process exits. -// The options are passed to the process's Wait method. -// Setting options to 0 waits for c to exit; -// other options cause Wait to return for other -// process events; see package os for details. -func (c *Cmd) Wait(options int) (*os.Waitmsg, os.Error) { - if c.Process == nil { - return nil, os.ErrorString("exec: invalid use of Cmd.Wait") +// StdinPipe returns a pipe that will be connected to the command's +// standard input when the command starts. +func (c *Cmd) StdinPipe() (io.WriteCloser, os.Error) { + if c.Stdin != nil { + return nil, os.NewError("exec: Stdin already set") } - w, err := c.Process.Wait(options) - if w != nil && (w.Exited() || w.Signaled()) { - c.Process.Release() - c.Process = nil + if c.Process != nil { + return nil, os.NewError("exec: StdinPipe after process started") + } + pr, pw, err := os.Pipe() + if err != nil { + return nil, err } - return w, err + c.Stdin = pr + c.closeAfterStart = append(c.closeAfterStart, pr) + c.closeAfterWait = append(c.closeAfterWait, pw) + return pw, nil } -// Close waits for the running command c to exit, -// if it hasn't already, and then closes the non-nil file descriptors -// c.Stdin, c.Stdout, and c.Stderr. -func (c *Cmd) Close() os.Error { +// StdoutPipe returns a pipe that will be connected to the command's +// standard output when the command starts. +// The pipe will be closed automatically after Wait sees the command exit. +func (c *Cmd) StdoutPipe() (io.ReadCloser, os.Error) { + if c.Stdout != nil { + return nil, os.NewError("exec: Stdout already set") + } if c.Process != nil { - // Loop on interrupt, but - // ignore other errors -- maybe - // caller has already waited for pid. - _, err := c.Wait(0) - for err == os.EINTR { - _, err = c.Wait(0) - } + return nil, os.NewError("exec: StdoutPipe after process started") } + pr, pw, err := os.Pipe() + if err != nil { + return nil, err + } + c.Stdout = pw + c.closeAfterStart = append(c.closeAfterStart, pw) + c.closeAfterWait = append(c.closeAfterWait, pr) + return pr, nil +} - // Close the FDs that are still open. - var err os.Error - if c.Stdin != nil && c.Stdin.Fd() >= 0 { - if err1 := c.Stdin.Close(); err1 != nil { - err = err1 - } +// StderrPipe returns a pipe that will be connected to the command's +// standard error when the command starts. +// The pipe will be closed automatically after Wait sees the command exit. +func (c *Cmd) StderrPipe() (io.ReadCloser, os.Error) { + if c.Stderr != nil { + return nil, os.NewError("exec: Stderr already set") } - if c.Stdout != nil && c.Stdout.Fd() >= 0 { - if err1 := c.Stdout.Close(); err1 != nil && err != nil { - err = err1 - } + if c.Process != nil { + return nil, os.NewError("exec: StderrPipe after process started") } - if c.Stderr != nil && c.Stderr != c.Stdout && c.Stderr.Fd() >= 0 { - if err1 := c.Stderr.Close(); err1 != nil && err != nil { - err = err1 - } + pr, pw, err := os.Pipe() + if err != nil { + return nil, err } - return err + c.Stderr = pw + c.closeAfterStart = append(c.closeAfterStart, pw) + c.closeAfterWait = append(c.closeAfterWait, pr) + return pr, nil } diff --git a/libgo/go/exec/exec_test.go b/libgo/go/exec/exec_test.go index eb8cd5f..242120f 100644 --- a/libgo/go/exec/exec_test.go +++ b/libgo/go/exec/exec_test.go @@ -5,163 +5,210 @@ package exec import ( + "bufio" + "bytes" + "fmt" "io" - "io/ioutil" "testing" "os" + "strconv" + "strings" ) -func run(argv []string, stdin, stdout, stderr int) (p *Cmd, err os.Error) { - exe, err := LookPath(argv[0]) - if err != nil { - return nil, err - } - return Run(exe, argv, nil, "", stdin, stdout, stderr) +func helperCommand(s ...string) *Cmd { + cs := []string{"-test.run=exec.TestHelperProcess", "--"} + cs = append(cs, s...) + cmd := Command(os.Args[0], cs...) + cmd.Env = append([]string{"GO_WANT_HELPER_PROCESS=1"}, os.Environ()...) + return cmd } -func TestRunCat(t *testing.T) { - cmd, err := run([]string{"cat"}, Pipe, Pipe, DevNull) +func TestEcho(t *testing.T) { + bs, err := helperCommand("echo", "foo bar", "baz").Output() if err != nil { - t.Fatal("run:", err) - } - io.WriteString(cmd.Stdin, "hello, world\n") - cmd.Stdin.Close() - buf, err := ioutil.ReadAll(cmd.Stdout) - if err != nil { - t.Fatal("read:", err) - } - if string(buf) != "hello, world\n" { - t.Fatalf("read: got %q", buf) + t.Errorf("echo: %v", err) } - if err = cmd.Close(); err != nil { - t.Fatal("close:", err) + if g, e := string(bs), "foo bar baz\n"; g != e { + t.Errorf("echo: want %q, got %q", e, g) } } -func TestRunEcho(t *testing.T) { - cmd, err := run([]string{"sh", "-c", "echo hello world"}, - DevNull, Pipe, DevNull) +func TestCatStdin(t *testing.T) { + // Cat, testing stdin and stdout. + input := "Input string\nLine 2" + p := helperCommand("cat") + p.Stdin = strings.NewReader(input) + bs, err := p.Output() if err != nil { - t.Fatal("run:", err) + t.Errorf("cat: %v", err) } - buf, err := ioutil.ReadAll(cmd.Stdout) - if err != nil { - t.Fatal("read:", err) - } - if string(buf) != "hello world\n" { - t.Fatalf("read: got %q", buf) - } - if err = cmd.Close(); err != nil { - t.Fatal("close:", err) + s := string(bs) + if s != input { + t.Errorf("cat: want %q, got %q", input, s) } } -func TestStderr(t *testing.T) { - cmd, err := run([]string{"sh", "-c", "echo hello world 1>&2"}, - DevNull, DevNull, Pipe) - if err != nil { - t.Fatal("run:", err) +func TestCatGoodAndBadFile(t *testing.T) { + // Testing combined output and error values. + bs, err := helperCommand("cat", "/bogus/file.foo", "exec_test.go").CombinedOutput() + if _, ok := err.(*os.Waitmsg); !ok { + t.Errorf("expected Waitmsg from cat combined; got %T: %v", err, err) } - buf, err := ioutil.ReadAll(cmd.Stderr) - if err != nil { - t.Fatal("read:", err) + s := string(bs) + sp := strings.SplitN(s, "\n", 2) + if len(sp) != 2 { + t.Fatalf("expected two lines from cat; got %q", s) } - if string(buf) != "hello world\n" { - t.Fatalf("read: got %q", buf) + errLine, body := sp[0], sp[1] + if !strings.HasPrefix(errLine, "Error: open /bogus/file.foo") { + t.Errorf("expected stderr to complain about file; got %q", errLine) } - if err = cmd.Close(); err != nil { - t.Fatal("close:", err) + if !strings.Contains(body, "func TestHelperProcess(t *testing.T)") { + t.Errorf("expected test code; got %q (len %d)", body, len(body)) } } -func TestMergeWithStdout(t *testing.T) { - cmd, err := run([]string{"sh", "-c", "echo hello world 1>&2"}, - DevNull, Pipe, MergeWithStdout) - if err != nil { - t.Fatal("run:", err) - } - buf, err := ioutil.ReadAll(cmd.Stdout) - if err != nil { - t.Fatal("read:", err) +func TestNoExistBinary(t *testing.T) { + // Can't run a non-existent binary + err := Command("/no-exist-binary").Run() + if err == nil { + t.Error("expected error from /no-exist-binary") } - if string(buf) != "hello world\n" { - t.Fatalf("read: got %q", buf) - } - if err = cmd.Close(); err != nil { - t.Fatal("close:", err) +} + +func TestExitStatus(t *testing.T) { + // Test that exit values are returned correctly + err := helperCommand("exit", "42").Run() + if werr, ok := err.(*os.Waitmsg); ok { + if s, e := werr.String(), "exit status 42"; s != e { + t.Errorf("from exit 42 got exit %q, want %q", s, e) + } + } else { + t.Fatalf("expected Waitmsg from exit 42; got %T: %v", err, err) } } -func TestAddEnvVar(t *testing.T) { - err := os.Setenv("NEWVAR", "hello world") - if err != nil { - t.Fatal("setenv:", err) +func TestPipes(t *testing.T) { + check := func(what string, err os.Error) { + if err != nil { + t.Fatalf("%s: %v", what, err) + } } - cmd, err := run([]string{"sh", "-c", "echo $NEWVAR"}, - DevNull, Pipe, DevNull) - if err != nil { - t.Fatal("run:", err) + // Cat, testing stdin and stdout. + c := helperCommand("pipetest") + stdin, err := c.StdinPipe() + check("StdinPipe", err) + stdout, err := c.StdoutPipe() + check("StdoutPipe", err) + stderr, err := c.StderrPipe() + check("StderrPipe", err) + + outbr := bufio.NewReader(stdout) + errbr := bufio.NewReader(stderr) + line := func(what string, br *bufio.Reader) string { + line, _, err := br.ReadLine() + if err != nil { + t.Fatalf("%s: %v", what, err) + } + return string(line) } - buf, err := ioutil.ReadAll(cmd.Stdout) - if err != nil { - t.Fatal("read:", err) + + err = c.Start() + check("Start", err) + + _, err = stdin.Write([]byte("O:I am output\n")) + check("first stdin Write", err) + if g, e := line("first output line", outbr), "O:I am output"; g != e { + t.Errorf("got %q, want %q", g, e) } - if string(buf) != "hello world\n" { - t.Fatalf("read: got %q", buf) + + _, err = stdin.Write([]byte("E:I am error\n")) + check("second stdin Write", err) + if g, e := line("first error line", errbr), "E:I am error"; g != e { + t.Errorf("got %q, want %q", g, e) } - if err = cmd.Close(); err != nil { - t.Fatal("close:", err) + + _, err = stdin.Write([]byte("O:I am output2\n")) + check("third stdin Write 3", err) + if g, e := line("second output line", outbr), "O:I am output2"; g != e { + t.Errorf("got %q, want %q", g, e) } -} -var tryargs = []string{ - `2`, - `2 `, - "2 \t", - `2" "`, - `2 ab `, - `2 "ab" `, - `2 \ `, - `2 \\ `, - `2 \" `, - `2 \`, - `2\`, - `2"`, - `2\"`, - `2 "`, - `2 \"`, - ``, - `2 ^ `, - `2 \^`, + stdin.Close() + err = c.Wait() + check("Wait", err) } -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) +// TestHelperProcess isn't a real test. It's used as a helper process +// for TestParameterRun. +func TestHelperProcess(*testing.T) { + if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" { + return + } + defer os.Exit(0) + + args := os.Args + for len(args) > 0 { + if args[0] == "--" { + args = args[1:] + break } - cmd, err := Run(exe, argv, nil, "", DevNull, Pipe, DevNull) - if err != nil { - t.Fatal("run:", err) + args = args[1:] + } + if len(args) == 0 { + fmt.Fprintf(os.Stderr, "No command\n") + os.Exit(2) + } + + cmd, args := args[0], args[1:] + switch cmd { + case "echo": + iargs := []interface{}{} + for _, s := range args { + iargs = append(iargs, s) } - buf, err := ioutil.ReadAll(cmd.Stdout) - if err != nil { - t.Fatal("read:", err) + fmt.Println(iargs...) + case "cat": + if len(args) == 0 { + io.Copy(os.Stdout, os.Stdin) + return } - expect := "/dev/null|" + a + "|EOF" - if string(buf) != expect { - t.Errorf("read: got %q expect %q", buf, expect) + exit := 0 + for _, fn := range args { + f, err := os.Open(fn) + if err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + exit = 2 + } else { + defer f.Close() + io.Copy(os.Stdout, f) + } } - if err = cmd.Close(); err != nil { - t.Fatal("close:", err) + os.Exit(exit) + case "pipetest": + bufr := bufio.NewReader(os.Stdin) + for { + line, _, err := bufr.ReadLine() + if err == os.EOF { + break + } else if err != nil { + os.Exit(1) + } + if bytes.HasPrefix(line, []byte("O:")) { + os.Stdout.Write(line) + os.Stdout.Write([]byte{'\n'}) + } else if bytes.HasPrefix(line, []byte("E:")) { + os.Stderr.Write(line) + os.Stderr.Write([]byte{'\n'}) + } else { + os.Exit(1) + } } + case "exit": + n, _ := strconv.Atoi(args[0]) + os.Exit(n) + default: + fmt.Fprintf(os.Stderr, "Unknown command %q\n", cmd) + os.Exit(2) } } diff --git a/libgo/go/exec/lp_plan9.go b/libgo/go/exec/lp_plan9.go new file mode 100644 index 0000000..e4751a4 --- /dev/null +++ b/libgo/go/exec/lp_plan9.go @@ -0,0 +1,51 @@ +// 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 exec + +import ( + "os" + "strings" +) + +// ErrNotFound is the error resulting if a path search failed to find an executable file. +var ErrNotFound = os.NewError("executable file not found in $path") + +func findExecutable(file string) os.Error { + d, err := os.Stat(file) + if err != nil { + return err + } + if d.IsRegular() && d.Permission()&0111 != 0 { + return nil + } + return os.EPERM +} + +// LookPath searches for an executable binary named file +// in the directories named by the path environment variable. +// If file begins with "/", "#", "./", or "../", it is tried +// directly and the path is not consulted. +func LookPath(file string) (string, os.Error) { + // skip the path lookup for these prefixes + skip := []string{"/", "#", "./", "../"} + + for _, p := range skip { + if strings.HasPrefix(file, p) { + err := findExecutable(file) + if err == nil { + return file, nil + } + return "", &Error{file, err} + } + } + + path := os.Getenv("path") + for _, dir := range strings.Split(path, "\000") { + if err := findExecutable(dir + "/" + file); err == nil { + return dir + "/" + file, nil + } + } + return "", &Error{file, ErrNotFound} +} diff --git a/libgo/go/exec/lp_test.go b/libgo/go/exec/lp_test.go index 5408177..77d8e84 100644 --- a/libgo/go/exec/lp_test.go +++ b/libgo/go/exec/lp_test.go @@ -22,12 +22,12 @@ func TestLookPathNotFound(t *testing.T) { if path != "" { t.Fatalf("LookPath path == %q when err != nil", path) } - perr, ok := err.(*PathError) + perr, ok := err.(*Error) if !ok { - t.Fatal("LookPath error is not a PathError") + t.Fatal("LookPath error is not an exec.Error") } if perr.Name != name { - t.Fatalf("want PathError name %q, got %q", name, perr.Name) + t.Fatalf("want Error name %q, got %q", name, perr.Name) } } } diff --git a/libgo/go/exec/lp_unix.go b/libgo/go/exec/lp_unix.go index 44f8434..008fb11 100644 --- a/libgo/go/exec/lp_unix.go +++ b/libgo/go/exec/lp_unix.go @@ -9,12 +9,18 @@ import ( "strings" ) -func canExec(file string) bool { +// ErrNotFound is the error resulting if a path search failed to find an executable file. +var ErrNotFound = os.NewError("executable file not found in $PATH") + +func findExecutable(file string) os.Error { d, err := os.Stat(file) if err != nil { - return false + return err + } + if d.IsRegular() && d.Permission()&0111 != 0 { + return nil } - return d.IsRegular() && d.Permission()&0111 != 0 + return os.EPERM } // LookPath searches for an executable binary named file @@ -26,20 +32,21 @@ func LookPath(file string) (string, os.Error) { // but that would not match all the Unix shells. if strings.Contains(file, "/") { - if canExec(file) { + err := findExecutable(file) + if err == nil { return file, nil } - return "", &PathError{file} + return "", &Error{file, err} } pathenv := os.Getenv("PATH") - for _, dir := range strings.Split(pathenv, ":", -1) { + for _, dir := range strings.Split(pathenv, ":") { if dir == "" { // Unix shell semantics: path element "" means "." dir = "." } - if canExec(dir + "/" + file) { + if err := findExecutable(dir + "/" + file); err == nil { return dir + "/" + file, nil } } - return "", &PathError{file} + return "", &Error{file, ErrNotFound} } diff --git a/libgo/go/exec/lp_windows.go b/libgo/go/exec/lp_windows.go index d357575..7581088e 100644 --- a/libgo/go/exec/lp_windows.go +++ b/libgo/go/exec/lp_windows.go @@ -9,15 +9,21 @@ import ( "strings" ) -func chkStat(file string) bool { +// ErrNotFound is the error resulting if a path search failed to find an executable file. +var ErrNotFound = os.NewError("executable file not found in %PATH%") + +func chkStat(file string) os.Error { d, err := os.Stat(file) if err != nil { - return false + return err + } + if d.IsRegular() { + return nil } - return d.IsRegular() + return os.EPERM } -func canExec(file string, exts []string) (string, bool) { +func findExecutable(file string, exts []string) (string, os.Error) { if len(exts) == 0 { return file, chkStat(file) } @@ -28,39 +34,44 @@ func canExec(file string, exts []string) (string, bool) { } } for _, e := range exts { - if f := file + e; chkStat(f) { - return f, true + if f := file + e; chkStat(f) == nil { + return f, nil } } - return ``, false + return ``, os.ENOENT } -func LookPath(file string) (string, os.Error) { +func LookPath(file string) (f string, err os.Error) { + x := os.Getenv(`PATHEXT`) + if x == `` { + x = `.COM;.EXE;.BAT;.CMD` + } exts := []string{} - if x := os.Getenv(`PATHEXT`); x != `` { - exts = strings.Split(strings.ToLower(x), `;`, -1) - for i, e := range exts { - if e == `` || e[0] != '.' { - exts[i] = `.` + e - } + for _, e := range strings.Split(strings.ToLower(x), `;`) { + if e == "" { + continue + } + if e[0] != '.' { + e = "." + e } + exts = append(exts, e) } - if strings.Contains(file, `\`) || strings.Contains(file, `/`) { - if f, ok := canExec(file, exts); ok { - return f, nil + if strings.IndexAny(file, `:\/`) != -1 { + if f, err = findExecutable(file, exts); err == nil { + return } - return ``, &PathError{file} + return ``, &Error{file, err} } if pathenv := os.Getenv(`PATH`); pathenv == `` { - if f, ok := canExec(`.\`+file, exts); ok { - return f, nil + if f, err = findExecutable(`.\`+file, exts); err == nil { + return } } else { - for _, dir := range strings.Split(pathenv, `;`, -1) { - if f, ok := canExec(dir+`\`+file, exts); ok { - return f, nil + for _, dir := range strings.Split(pathenv, `;`) { + if f, err = findExecutable(dir+`\`+file, exts); err == nil { + return } } } - return ``, &PathError{file} + return ``, &Error{file, ErrNotFound} } diff --git a/libgo/go/exp/datafmt/datafmt.go b/libgo/go/exp/datafmt/datafmt.go index a8efdc5..6d7e764 100644 --- a/libgo/go/exp/datafmt/datafmt.go +++ b/libgo/go/exp/datafmt/datafmt.go @@ -211,7 +211,6 @@ import ( "runtime" ) - // ---------------------------------------------------------------------------- // Format representation @@ -228,13 +227,11 @@ import ( // type Formatter func(state *State, value interface{}, ruleName string) bool - // A FormatterMap is a set of custom formatters. // It maps a rule name to a formatter function. // type FormatterMap map[string]Formatter - // A parsed format expression is built from the following nodes. // type ( @@ -269,13 +266,11 @@ type ( } ) - // A Format is the result of parsing a format specification. // The format may be applied repeatedly to format values. // type Format map[string]expr - // ---------------------------------------------------------------------------- // Formatting @@ -293,7 +288,6 @@ type Environment interface { Copy() Environment } - // State represents the current formatting state. // It is provided as argument to custom formatters. // @@ -309,7 +303,6 @@ type State struct { separator expr // possibly nil } - func newState(fmt Format, env Environment, errors chan os.Error) *State { s := new(State) s.fmt = fmt @@ -317,12 +310,12 @@ func newState(fmt Format, env Environment, errors chan os.Error) *State { s.errors = errors s.linePos = token.Position{Line: 1} - // if we have a default rule, cache it's expression for fast access + // if we have a default rule, cache its expression for fast access if x, found := fmt["default"]; found { s.default_ = x } - // if we have a global separator rule, cache it's expression for fast access + // if we have a global separator rule, cache its expression for fast access if x, found := fmt["/"]; found { s.separator = x } @@ -330,17 +323,14 @@ func newState(fmt Format, env Environment, errors chan os.Error) *State { return s } - // Env returns the environment passed to Format.Apply. func (s *State) Env() interface{} { return s.env } - // LinePos returns the position of the current line beginning // in the state's output buffer. Line numbers start at 1. // func (s *State) LinePos() token.Position { return s.linePos } - // Pos returns the position of the next byte to be written to the // output buffer. Line numbers start at 1. // @@ -349,7 +339,6 @@ func (s *State) Pos() token.Position { return token.Position{Line: s.linePos.Line, Column: offs - s.linePos.Offset, Offset: offs} } - // Write writes data to the output buffer, inserting the indentation // string after each newline or form feed character. It cannot return an error. // @@ -371,7 +360,6 @@ func (s *State) Write(data []byte) (int, os.Error) { return n + n3, nil } - type checkpoint struct { env Environment hasOutput bool @@ -379,7 +367,6 @@ type checkpoint struct { linePos token.Position } - func (s *State) save() checkpoint { saved := checkpoint{nil, s.hasOutput, s.output.Len(), s.linePos} if s.env != nil { @@ -388,19 +375,16 @@ func (s *State) save() checkpoint { return saved } - func (s *State) restore(m checkpoint) { s.env = m.env s.output.Truncate(m.outputLen) } - func (s *State) error(msg string) { s.errors <- os.NewError(msg) runtime.Goexit() } - // TODO At the moment, unnamed types are simply mapped to the default // names below. For instance, all unnamed arrays are mapped to // 'array' which is not really sufficient. Eventually one may want @@ -440,7 +424,6 @@ func (s *State) getFormat(name string) expr { return nil } - // eval applies a format expression fexpr to a value. If the expression // evaluates internally to a non-nil []byte, that slice is appended to // the state's output buffer and eval returns true. Otherwise, eval @@ -594,7 +577,7 @@ func (s *State) eval(fexpr expr, value reflect.Value, index int) bool { s.eval(t.indent, value, index) // if the indentation evaluates to nil, the state's output buffer // didn't change - either way it's ok to append the difference to - // the current identation + // the current indentation s.indent.Write(s.output.Bytes()[mark.outputLen:s.output.Len()]) s.restore(mark) @@ -653,7 +636,6 @@ func (s *State) eval(fexpr expr, value reflect.Value, index int) bool { return false } - // Eval formats each argument according to the format // f and returns the resulting []byte and os.Error. If // an error occurred, the []byte contains the partially @@ -688,7 +670,6 @@ func (f Format) Eval(env Environment, args ...interface{}) ([]byte, os.Error) { return s.output.Bytes(), err } - // ---------------------------------------------------------------------------- // Convenience functions @@ -705,7 +686,6 @@ func (f Format) Fprint(w io.Writer, env Environment, args ...interface{}) (int, return w.Write(data) } - // Print formats each argument according to the format f // and writes to standard output. The result is the total // number of bytes written and an os.Error, if any. @@ -714,7 +694,6 @@ func (f Format) Print(args ...interface{}) (int, os.Error) { return f.Fprint(os.Stdout, nil, args...) } - // Sprint formats each argument according to the format f // and returns the resulting string. If an error occurs // during formatting, the result string contains the diff --git a/libgo/go/exp/datafmt/datafmt_test.go b/libgo/go/exp/datafmt/datafmt_test.go index d7c70b2..87d0716 100644 --- a/libgo/go/exp/datafmt/datafmt_test.go +++ b/libgo/go/exp/datafmt/datafmt_test.go @@ -10,10 +10,8 @@ import ( "go/token" ) - var fset = token.NewFileSet() - func parse(t *testing.T, form string, fmap FormatterMap) Format { f, err := Parse(fset, "", []byte(form), fmap) if err != nil { @@ -23,7 +21,6 @@ func parse(t *testing.T, form string, fmap FormatterMap) Format { return f } - func verify(t *testing.T, f Format, expected string, args ...interface{}) { if f == nil { return // allow other tests to run @@ -36,7 +33,6 @@ func verify(t *testing.T, f Format, expected string, args ...interface{}) { } } - func formatter(s *State, value interface{}, rule_name string) bool { switch rule_name { case "/": @@ -62,7 +58,6 @@ func formatter(s *State, value interface{}, rule_name string) bool { return false } - func TestCustomFormatters(t *testing.T) { fmap0 := FormatterMap{"/": formatter} fmap1 := FormatterMap{"int": formatter, "blank": formatter, "nil": formatter} @@ -92,7 +87,6 @@ func TestCustomFormatters(t *testing.T) { // TODO needs more tests } - // ---------------------------------------------------------------------------- // Formatting of basic and simple composite types @@ -109,7 +103,6 @@ func check(t *testing.T, form, expected string, args ...interface{}) { } } - func TestBasicTypes(t *testing.T) { check(t, ``, ``) check(t, `bool=":%v"`, `:true:false`, true, false) @@ -144,7 +137,6 @@ func TestBasicTypes(t *testing.T) { check(t, `float64="%g"`, fs, float64(f)) } - func TestArrayTypes(t *testing.T) { var a0 [10]int check(t, `array="array";`, `array`, a0) @@ -159,7 +151,6 @@ func TestArrayTypes(t *testing.T) { check(t, `array={* / ", "}; interface=*; string="bar"; default="%v";`, `42, bar, 3.14`, a2) } - func TestChanTypes(t *testing.T) { var c0 chan int check(t, `chan="chan"`, `chan`, c0) @@ -170,7 +161,6 @@ func TestChanTypes(t *testing.T) { // check(t, `chan=*`, `42`, c1); // reflection support for chans incomplete } - func TestFuncTypes(t *testing.T) { var f0 func() int check(t, `func="func"`, `func`, f0) @@ -180,7 +170,6 @@ func TestFuncTypes(t *testing.T) { // check(t, `func=*`, `42`, f1); // reflection support for funcs incomplete } - func TestMapTypes(t *testing.T) { var m0 map[string]int check(t, `map="map"`, `map`, m0) @@ -190,7 +179,6 @@ func TestMapTypes(t *testing.T) { // check(t, `map=*`, ``, m1); // reflection support for maps incomplete } - func TestPointerTypes(t *testing.T) { var p0 *int check(t, `ptr="ptr"`, `ptr`, p0) @@ -203,7 +191,6 @@ func TestPointerTypes(t *testing.T) { check(t, `ptr=*; int="%d"`, `99991`, p1) } - func TestDefaultRule(t *testing.T) { check(t, `default="%v"`, `42foo3.14`, 42, "foo", 3.14) check(t, `default="%v"; int="%x"`, `abcdef`, 10, 11, 12, 13, 14, 15) @@ -211,13 +198,11 @@ func TestDefaultRule(t *testing.T) { check(t, `default="%x"; int=@:default`, `abcdef`, 10, 11, 12, 13, 14, 15) } - func TestGlobalSeparatorRule(t *testing.T) { check(t, `int="%d"; / ="-"`, `1-2-3-4`, 1, 2, 3, 4) check(t, `int="%x%x"; / ="*"`, `aa*aa`, 10, 10) } - // ---------------------------------------------------------------------------- // Formatting of a struct @@ -231,7 +216,6 @@ const F1 = `datafmt "datafmt";` + func TestStruct1(t *testing.T) { check(t, F1, "<42>", T1{42}) } - // ---------------------------------------------------------------------------- // Formatting of a struct with an optional field (ptr) @@ -256,7 +240,6 @@ func TestStruct2(t *testing.T) { check(t, F2b, "fooempty", T2{"foo", nil}) } - // ---------------------------------------------------------------------------- // Formatting of a struct with a repetitive field (slice) @@ -285,7 +268,6 @@ func TestStruct3(t *testing.T) { check(t, F3b, "bal: 2-3-5", T3{"bal", []int{2, 3, 5}}) } - // ---------------------------------------------------------------------------- // Formatting of a struct with alternative field @@ -318,7 +300,6 @@ func TestStruct4(t *testing.T) { check(t, F4b, "<2, 3, 7>", T4{nil, []int{2, 3, 7}}) } - // ---------------------------------------------------------------------------- // Formatting a struct (documentation example) @@ -338,7 +319,6 @@ func TestStructPoint(t *testing.T) { check(t, FPoint, "---foo---{3, 0xf}", p) } - // ---------------------------------------------------------------------------- // Formatting a slice (documentation example) @@ -347,5 +327,4 @@ const FSlice = `int = "%b";` + func TestSlice(t *testing.T) { check(t, FSlice, "10, 11, 101, 111", []int{2, 3, 5, 7}) } - // TODO add more tests diff --git a/libgo/go/exp/datafmt/parser.go b/libgo/go/exp/datafmt/parser.go index 7dedb53..a2ddd38 100644 --- a/libgo/go/exp/datafmt/parser.go +++ b/libgo/go/exp/datafmt/parser.go @@ -5,7 +5,6 @@ package datafmt import ( - "container/vector" "go/scanner" "go/token" "os" @@ -28,7 +27,6 @@ type parser struct { rules map[string]expr // RuleName -> Expression } - func (p *parser) next() { p.pos, p.tok, p.lit = p.scanner.Scan() switch p.tok { @@ -39,7 +37,6 @@ func (p *parser) next() { } } - func (p *parser) init(fset *token.FileSet, filename string, src []byte) { p.ErrorVector.Reset() p.file = fset.AddFile(filename, fset.Base(), len(src)) @@ -49,12 +46,10 @@ func (p *parser) init(fset *token.FileSet, filename string, src []byte) { p.rules = make(map[string]expr) } - func (p *parser) error(pos token.Pos, msg string) { p.Error(p.file.Position(pos), msg) } - func (p *parser) errorExpected(pos token.Pos, msg string) { msg = "expected " + msg if pos == p.pos { @@ -68,7 +63,6 @@ func (p *parser) errorExpected(pos token.Pos, msg string) { p.error(pos, msg) } - func (p *parser) expect(tok token.Token) token.Pos { pos := p.pos if p.tok != tok { @@ -78,14 +72,12 @@ func (p *parser) expect(tok token.Token) token.Pos { return pos } - func (p *parser) parseIdentifier() string { name := p.lit p.expect(token.IDENT) return name } - func (p *parser) parseTypeName() (string, bool) { pos := p.pos name, isIdent := p.parseIdentifier(), true @@ -102,7 +94,6 @@ func (p *parser) parseTypeName() (string, bool) { return name, isIdent } - // Parses a rule name and returns it. If the rule name is // a package-qualified type name, the package name is resolved. // The 2nd result value is true iff the rule name consists of a @@ -126,7 +117,6 @@ func (p *parser) parseRuleName() (string, bool) { return name, isIdent } - func (p *parser) parseString() string { s := "" if p.tok == token.STRING { @@ -142,7 +132,6 @@ func (p *parser) parseString() string { return s } - func (p *parser) parseLiteral() literal { s := []byte(p.parseString()) @@ -150,14 +139,14 @@ func (p *parser) parseLiteral() literal { // and speed up printing of the literal, split it into segments // that start with "%" possibly followed by a last segment that // starts with some other character. - var list vector.Vector + var list []interface{} i0 := 0 for i := 0; i < len(s); i++ { if s[i] == '%' && i+1 < len(s) { // the next segment starts with a % format if i0 < i { // the current segment is not empty, split it off - list.Push(s[i0:i]) + list = append(list, s[i0:i]) i0 = i } i++ // skip %; let loop skip over char after % @@ -165,18 +154,17 @@ func (p *parser) parseLiteral() literal { } // the final segment may start with any character // (it is empty iff the string is empty) - list.Push(s[i0:]) + list = append(list, s[i0:]) // convert list into a literal - lit := make(literal, list.Len()) - for i := 0; i < list.Len(); i++ { - lit[i] = list.At(i).([]byte) + lit := make(literal, len(list)) + for i := 0; i < len(list); i++ { + lit[i] = list[i].([]byte) } return lit } - func (p *parser) parseField() expr { var fname string switch p.tok { @@ -204,7 +192,6 @@ func (p *parser) parseField() expr { return &field{fname, ruleName} } - func (p *parser) parseOperand() (x expr) { switch p.tok { case token.STRING: @@ -242,38 +229,36 @@ func (p *parser) parseOperand() (x expr) { return x } - func (p *parser) parseSequence() expr { - var list vector.Vector + var list []interface{} for x := p.parseOperand(); x != nil; x = p.parseOperand() { - list.Push(x) + list = append(list, x) } // no need for a sequence if list.Len() < 2 - switch list.Len() { + switch len(list) { case 0: return nil case 1: - return list.At(0).(expr) + return list[0].(expr) } // convert list into a sequence - seq := make(sequence, list.Len()) - for i := 0; i < list.Len(); i++ { - seq[i] = list.At(i).(expr) + seq := make(sequence, len(list)) + for i := 0; i < len(list); i++ { + seq[i] = list[i].(expr) } return seq } - func (p *parser) parseExpression() expr { - var list vector.Vector + var list []interface{} for { x := p.parseSequence() if x != nil { - list.Push(x) + list = append(list, x) } if p.tok != token.OR { break @@ -282,22 +267,21 @@ func (p *parser) parseExpression() expr { } // no need for an alternatives if list.Len() < 2 - switch list.Len() { + switch len(list) { case 0: return nil case 1: - return list.At(0).(expr) + return list[0].(expr) } // convert list into a alternatives - alt := make(alternatives, list.Len()) - for i := 0; i < list.Len(); i++ { - alt[i] = list.At(i).(expr) + alt := make(alternatives, len(list)) + for i := 0; i < len(list); i++ { + alt[i] = list[i].(expr) } return alt } - func (p *parser) parseFormat() { for p.tok != token.EOF { pos := p.pos @@ -343,7 +327,6 @@ func (p *parser) parseFormat() { p.expect(token.EOF) } - func remap(p *parser, name string) string { i := strings.Index(name, ".") if i >= 0 { @@ -359,7 +342,6 @@ func remap(p *parser, name string) string { return name } - // Parse parses a set of format productions from source src. Custom // formatters may be provided via a map of formatter functions. If // there are no errors, the result is a Format and the error is nil. diff --git a/libgo/go/exp/draw/draw.go b/libgo/go/exp/draw/draw.go deleted file mode 100644 index f98e246..0000000 --- a/libgo/go/exp/draw/draw.go +++ /dev/null @@ -1,476 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package draw provides basic graphics and drawing primitives, -// in the style of the Plan 9 graphics library -// (see http://plan9.bell-labs.com/magic/man2html/2/draw) -// and the X Render extension. -package draw - -import ( - "image" - "image/ycbcr" -) - -// m is the maximum color value returned by image.Color.RGBA. -const m = 1<<16 - 1 - -// A Porter-Duff compositing operator. -type Op int - -const ( - // Over specifies ``(src in mask) over dst''. - Over Op = iota - // Src specifies ``src in mask''. - Src -) - -var zeroColor image.Color = image.AlphaColor{0} - -// A draw.Image is an image.Image with a Set method to change a single pixel. -type Image interface { - image.Image - Set(x, y int, c image.Color) -} - -// Draw calls DrawMask with a nil mask and an Over op. -func Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point) { - DrawMask(dst, r, src, sp, nil, image.ZP, Over) -} - -// DrawMask aligns r.Min in dst with sp in src and mp in mask and then replaces the rectangle r -// in dst with the result of a Porter-Duff composition. A nil mask is treated as opaque. -func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) { - sb := src.Bounds() - dx, dy := sb.Max.X-sp.X, sb.Max.Y-sp.Y - if mask != nil { - mb := mask.Bounds() - if dx > mb.Max.X-mp.X { - dx = mb.Max.X - mp.X - } - if dy > mb.Max.Y-mp.Y { - dy = mb.Max.Y - mp.Y - } - } - if r.Dx() > dx { - r.Max.X = r.Min.X + dx - } - if r.Dy() > dy { - r.Max.Y = r.Min.Y + dy - } - r = r.Intersect(dst.Bounds()) - if r.Empty() { - return - } - - // Fast paths for special cases. If none of them apply, then we fall back to a general but slow implementation. - if dst0, ok := dst.(*image.RGBA); ok { - if op == Over { - if mask == nil { - switch src0 := src.(type) { - case *image.ColorImage: - drawFillOver(dst0, r, src0) - return - case *image.RGBA: - drawCopyOver(dst0, r, src0, sp) - return - case *image.NRGBA: - drawNRGBAOver(dst0, r, src0, sp) - return - case *ycbcr.YCbCr: - drawYCbCr(dst0, r, src0, sp) - return - } - } else if mask0, ok := mask.(*image.Alpha); ok { - switch src0 := src.(type) { - case *image.ColorImage: - drawGlyphOver(dst0, r, src0, mask0, mp) - return - } - } - } else { - if mask == nil { - switch src0 := src.(type) { - case *image.ColorImage: - drawFillSrc(dst0, r, src0) - return - case *image.RGBA: - drawCopySrc(dst0, r, src0, sp) - return - case *image.NRGBA: - drawNRGBASrc(dst0, r, src0, sp) - return - case *ycbcr.YCbCr: - drawYCbCr(dst0, r, src0, sp) - return - } - } - } - drawRGBA(dst0, r, src, sp, mask, mp, op) - return - } - - x0, x1, dx := r.Min.X, r.Max.X, 1 - y0, y1, dy := r.Min.Y, r.Max.Y, 1 - if image.Image(dst) == src && r.Overlaps(r.Add(sp.Sub(r.Min))) { - // Rectangles overlap: process backward? - if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X { - x0, x1, dx = x1-1, x0-1, -1 - y0, y1, dy = y1-1, y0-1, -1 - } - } - - var out *image.RGBA64Color - sy := sp.Y + y0 - r.Min.Y - my := mp.Y + y0 - r.Min.Y - for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy { - sx := sp.X + x0 - r.Min.X - mx := mp.X + x0 - r.Min.X - for x := x0; x != x1; x, sx, mx = x+dx, sx+dx, mx+dx { - ma := uint32(m) - if mask != nil { - _, _, _, ma = mask.At(mx, my).RGBA() - } - switch { - case ma == 0: - if op == Over { - // No-op. - } else { - dst.Set(x, y, zeroColor) - } - case ma == m && op == Src: - dst.Set(x, y, src.At(sx, sy)) - default: - sr, sg, sb, sa := src.At(sx, sy).RGBA() - if out == nil { - out = new(image.RGBA64Color) - } - if op == Over { - dr, dg, db, da := dst.At(x, y).RGBA() - a := m - (sa * ma / m) - out.R = uint16((dr*a + sr*ma) / m) - out.G = uint16((dg*a + sg*ma) / m) - out.B = uint16((db*a + sb*ma) / m) - out.A = uint16((da*a + sa*ma) / m) - } else { - out.R = uint16(sr * ma / m) - out.G = uint16(sg * ma / m) - out.B = uint16(sb * ma / m) - out.A = uint16(sa * ma / m) - } - dst.Set(x, y, out) - } - } - } -} - -func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) { - cr, cg, cb, ca := src.RGBA() - // The 0x101 is here for the same reason as in drawRGBA. - a := (m - ca) * 0x101 - x0, x1 := r.Min.X, r.Max.X - y0, y1 := r.Min.Y, r.Max.Y - for y := y0; y != y1; y++ { - dbase := y * dst.Stride - dpix := dst.Pix[dbase+x0 : dbase+x1] - for i, rgba := range dpix { - dr := (uint32(rgba.R)*a)/m + cr - dg := (uint32(rgba.G)*a)/m + cg - db := (uint32(rgba.B)*a)/m + cb - da := (uint32(rgba.A)*a)/m + ca - dpix[i] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)} - } - } -} - -func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) { - dx0, dx1 := r.Min.X, r.Max.X - dy0, dy1 := r.Min.Y, r.Max.Y - nrows := dy1 - dy0 - sx0, sx1 := sp.X, sp.X+dx1-dx0 - d0 := dy0*dst.Stride + dx0 - d1 := dy0*dst.Stride + dx1 - s0 := sp.Y*src.Stride + sx0 - s1 := sp.Y*src.Stride + sx1 - var ( - ddelta, sdelta int - i0, i1, idelta int - ) - if r.Min.Y < sp.Y || r.Min.Y == sp.Y && r.Min.X <= sp.X { - ddelta = dst.Stride - sdelta = src.Stride - i0, i1, idelta = 0, d1-d0, +1 - } else { - // If the source start point is higher than the destination start point, or equal height but to the left, - // then we compose the rows in right-to-left, bottom-up order instead of left-to-right, top-down. - d0 += (nrows - 1) * dst.Stride - d1 += (nrows - 1) * dst.Stride - s0 += (nrows - 1) * src.Stride - s1 += (nrows - 1) * src.Stride - ddelta = -dst.Stride - sdelta = -src.Stride - i0, i1, idelta = d1-d0-1, -1, -1 - } - for ; nrows > 0; nrows-- { - dpix := dst.Pix[d0:d1] - spix := src.Pix[s0:s1] - for i := i0; i != i1; i += idelta { - // For unknown reasons, even though both dpix[i] and spix[i] are - // image.RGBAColors, on an x86 CPU it seems fastest to call RGBA - // for the source but to do it manually for the destination. - sr, sg, sb, sa := spix[i].RGBA() - rgba := dpix[i] - dr := uint32(rgba.R) - dg := uint32(rgba.G) - db := uint32(rgba.B) - da := uint32(rgba.A) - // The 0x101 is here for the same reason as in drawRGBA. - a := (m - sa) * 0x101 - dr = (dr*a)/m + sr - dg = (dg*a)/m + sg - db = (db*a)/m + sb - da = (da*a)/m + sa - dpix[i] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)} - } - d0 += ddelta - d1 += ddelta - s0 += sdelta - s1 += sdelta - } -} - -func drawNRGBAOver(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image.Point) { - for y, sy := r.Min.Y, sp.Y; y != r.Max.Y; y, sy = y+1, sy+1 { - dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride] - spix := src.Pix[sy*src.Stride : (sy+1)*src.Stride] - for x, sx := r.Min.X, sp.X; x != r.Max.X; x, sx = x+1, sx+1 { - // Convert from non-premultiplied color to pre-multiplied color. - // The order of operations here is to match the NRGBAColor.RGBA - // method in image/color.go. - snrgba := spix[sx] - sa := uint32(snrgba.A) - sr := uint32(snrgba.R) * 0x101 * sa / 0xff - sg := uint32(snrgba.G) * 0x101 * sa / 0xff - sb := uint32(snrgba.B) * 0x101 * sa / 0xff - sa *= 0x101 - - rgba := dpix[x] - dr := uint32(rgba.R) - dg := uint32(rgba.G) - db := uint32(rgba.B) - da := uint32(rgba.A) - a := (m - sa) * 0x101 - dr = (dr*a + sr*m) / m - dg = (dg*a + sg*m) / m - db = (db*a + sb*m) / m - da = (da*a + sa*m) / m - dpix[x] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)} - } - } -} - -func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage, mask *image.Alpha, mp image.Point) { - x0, x1 := r.Min.X, r.Max.X - y0, y1 := r.Min.Y, r.Max.Y - cr, cg, cb, ca := src.RGBA() - for y, my := y0, mp.Y; y != y1; y, my = y+1, my+1 { - dbase := y * dst.Stride - dpix := dst.Pix[dbase+x0 : dbase+x1] - mbase := my * mask.Stride - mpix := mask.Pix[mbase+mp.X:] - for i, rgba := range dpix { - ma := uint32(mpix[i].A) - if ma == 0 { - continue - } - ma |= ma << 8 - dr := uint32(rgba.R) - dg := uint32(rgba.G) - db := uint32(rgba.B) - da := uint32(rgba.A) - // The 0x101 is here for the same reason as in drawRGBA. - a := (m - (ca * ma / m)) * 0x101 - dr = (dr*a + cr*ma) / m - dg = (dg*a + cg*ma) / m - db = (db*a + cb*ma) / m - da = (da*a + ca*ma) / m - dpix[i] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)} - } - } -} - -func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) { - if r.Dy() < 1 { - return - } - cr, cg, cb, ca := src.RGBA() - color := image.RGBAColor{uint8(cr >> 8), uint8(cg >> 8), uint8(cb >> 8), uint8(ca >> 8)} - // The built-in copy function is faster than a straightforward for loop to fill the destination with - // the color, but copy requires a slice source. We therefore use a for loop to fill the first row, and - // then use the first row as the slice source for the remaining rows. - dx0, dx1 := r.Min.X, r.Max.X - dy0, dy1 := r.Min.Y, r.Max.Y - dbase := dy0 * dst.Stride - i0, i1 := dbase+dx0, dbase+dx1 - firstRow := dst.Pix[i0:i1] - for i := range firstRow { - firstRow[i] = color - } - for y := dy0 + 1; y < dy1; y++ { - i0 += dst.Stride - i1 += dst.Stride - copy(dst.Pix[i0:i1], firstRow) - } -} - -func drawCopySrc(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) { - dx0, dx1 := r.Min.X, r.Max.X - dy0, dy1 := r.Min.Y, r.Max.Y - nrows := dy1 - dy0 - sx0, sx1 := sp.X, sp.X+dx1-dx0 - d0 := dy0*dst.Stride + dx0 - d1 := dy0*dst.Stride + dx1 - s0 := sp.Y*src.Stride + sx0 - s1 := sp.Y*src.Stride + sx1 - var ddelta, sdelta int - if r.Min.Y <= sp.Y { - ddelta = dst.Stride - sdelta = src.Stride - } else { - // If the source start point is higher than the destination start point, then we compose the rows - // in bottom-up order instead of top-down. Unlike the drawCopyOver function, we don't have to - // check the x co-ordinates because the built-in copy function can handle overlapping slices. - d0 += (nrows - 1) * dst.Stride - d1 += (nrows - 1) * dst.Stride - s0 += (nrows - 1) * src.Stride - s1 += (nrows - 1) * src.Stride - ddelta = -dst.Stride - sdelta = -src.Stride - } - for ; nrows > 0; nrows-- { - copy(dst.Pix[d0:d1], src.Pix[s0:s1]) - d0 += ddelta - d1 += ddelta - s0 += sdelta - s1 += sdelta - } -} - -func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image.Point) { - for y, sy := r.Min.Y, sp.Y; y != r.Max.Y; y, sy = y+1, sy+1 { - dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride] - spix := src.Pix[sy*src.Stride : (sy+1)*src.Stride] - for x, sx := r.Min.X, sp.X; x != r.Max.X; x, sx = x+1, sx+1 { - // Convert from non-premultiplied color to pre-multiplied color. - // The order of operations here is to match the NRGBAColor.RGBA - // method in image/color.go. - snrgba := spix[sx] - sa := uint32(snrgba.A) - sr := uint32(snrgba.R) * 0x101 * sa / 0xff - sg := uint32(snrgba.G) * 0x101 * sa / 0xff - sb := uint32(snrgba.B) * 0x101 * sa / 0xff - sa *= 0x101 - - dpix[x] = image.RGBAColor{uint8(sr >> 8), uint8(sg >> 8), uint8(sb >> 8), uint8(sa >> 8)} - } - } -} - -func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *ycbcr.YCbCr, sp image.Point) { - // A YCbCr image is always fully opaque, and so if the mask is implicitly nil - // (i.e. fully opaque) then the op is effectively always Src. - var ( - yy, cb, cr uint8 - rr, gg, bb uint8 - ) - switch src.SubsampleRatio { - case ycbcr.SubsampleRatio422: - for y, sy := r.Min.Y, sp.Y; y != r.Max.Y; y, sy = y+1, sy+1 { - dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride] - for x, sx := r.Min.X, sp.X; x != r.Max.X; x, sx = x+1, sx+1 { - i := sx / 2 - yy = src.Y[sy*src.YStride+sx] - cb = src.Cb[sy*src.CStride+i] - cr = src.Cr[sy*src.CStride+i] - rr, gg, bb = ycbcr.YCbCrToRGB(yy, cb, cr) - dpix[x] = image.RGBAColor{rr, gg, bb, 255} - } - } - case ycbcr.SubsampleRatio420: - for y, sy := r.Min.Y, sp.Y; y != r.Max.Y; y, sy = y+1, sy+1 { - dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride] - for x, sx := r.Min.X, sp.X; x != r.Max.X; x, sx = x+1, sx+1 { - i, j := sx/2, sy/2 - yy = src.Y[sy*src.YStride+sx] - cb = src.Cb[j*src.CStride+i] - cr = src.Cr[j*src.CStride+i] - rr, gg, bb = ycbcr.YCbCrToRGB(yy, cb, cr) - dpix[x] = image.RGBAColor{rr, gg, bb, 255} - } - } - default: - // Default to 4:4:4 subsampling. - for y, sy := r.Min.Y, sp.Y; y != r.Max.Y; y, sy = y+1, sy+1 { - dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride] - for x, sx := r.Min.X, sp.X; x != r.Max.X; x, sx = x+1, sx+1 { - yy = src.Y[sy*src.YStride+sx] - cb = src.Cb[sy*src.CStride+sx] - cr = src.Cr[sy*src.CStride+sx] - rr, gg, bb = ycbcr.YCbCrToRGB(yy, cb, cr) - dpix[x] = image.RGBAColor{rr, gg, bb, 255} - } - } - } -} - -func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) { - x0, x1, dx := r.Min.X, r.Max.X, 1 - y0, y1, dy := r.Min.Y, r.Max.Y, 1 - if image.Image(dst) == src && r.Overlaps(r.Add(sp.Sub(r.Min))) { - if sp.Y < r.Min.Y || sp.Y == r.Min.Y && sp.X < r.Min.X { - x0, x1, dx = x1-1, x0-1, -1 - y0, y1, dy = y1-1, y0-1, -1 - } - } - - sy := sp.Y + y0 - r.Min.Y - my := mp.Y + y0 - r.Min.Y - for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy { - sx := sp.X + x0 - r.Min.X - mx := mp.X + x0 - r.Min.X - dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride] - for x := x0; x != x1; x, sx, mx = x+dx, sx+dx, mx+dx { - ma := uint32(m) - if mask != nil { - _, _, _, ma = mask.At(mx, my).RGBA() - } - sr, sg, sb, sa := src.At(sx, sy).RGBA() - var dr, dg, db, da uint32 - if op == Over { - rgba := dpix[x] - dr = uint32(rgba.R) - dg = uint32(rgba.G) - db = uint32(rgba.B) - da = uint32(rgba.A) - // dr, dg, db and da are all 8-bit color at the moment, ranging in [0,255]. - // We work in 16-bit color, and so would normally do: - // dr |= dr << 8 - // and similarly for dg, db and da, but instead we multiply a - // (which is a 16-bit color, ranging in [0,65535]) by 0x101. - // This yields the same result, but is fewer arithmetic operations. - a := (m - (sa * ma / m)) * 0x101 - dr = (dr*a + sr*ma) / m - dg = (dg*a + sg*ma) / m - db = (db*a + sb*ma) / m - da = (da*a + sa*ma) / m - } else { - dr = sr * ma / m - dg = sg * ma / m - db = sb * ma / m - da = sa * ma / m - } - dpix[x] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)} - } - } -} diff --git a/libgo/go/exp/draw/draw_test.go b/libgo/go/exp/draw/draw_test.go deleted file mode 100644 index 873a2f2..0000000 --- a/libgo/go/exp/draw/draw_test.go +++ /dev/null @@ -1,278 +0,0 @@ -// 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 draw - -import ( - "image" - "image/ycbcr" - "testing" -) - -func eq(c0, c1 image.Color) bool { - r0, g0, b0, a0 := c0.RGBA() - r1, g1, b1, a1 := c1.RGBA() - return r0 == r1 && g0 == g1 && b0 == b1 && a0 == a1 -} - -func fillBlue(alpha int) image.Image { - return image.NewColorImage(image.RGBAColor{0, 0, uint8(alpha), uint8(alpha)}) -} - -func fillAlpha(alpha int) image.Image { - return image.NewColorImage(image.AlphaColor{uint8(alpha)}) -} - -func vgradGreen(alpha int) image.Image { - m := image.NewRGBA(16, 16) - for y := 0; y < 16; y++ { - for x := 0; x < 16; x++ { - m.Set(x, y, image.RGBAColor{0, uint8(y * alpha / 15), 0, uint8(alpha)}) - } - } - return m -} - -func vgradAlpha(alpha int) image.Image { - m := image.NewAlpha(16, 16) - for y := 0; y < 16; y++ { - for x := 0; x < 16; x++ { - m.Set(x, y, image.AlphaColor{uint8(y * alpha / 15)}) - } - } - return m -} - -func vgradGreenNRGBA(alpha int) image.Image { - m := image.NewNRGBA(16, 16) - for y := 0; y < 16; y++ { - for x := 0; x < 16; x++ { - m.Set(x, y, image.RGBAColor{0, uint8(y * 0x11), 0, uint8(alpha)}) - } - } - return m -} - -func vgradCr() image.Image { - m := &ycbcr.YCbCr{ - Y: make([]byte, 16*16), - Cb: make([]byte, 16*16), - Cr: make([]byte, 16*16), - YStride: 16, - CStride: 16, - SubsampleRatio: ycbcr.SubsampleRatio444, - Rect: image.Rect(0, 0, 16, 16), - } - for y := 0; y < 16; y++ { - for x := 0; x < 16; x++ { - m.Cr[y*m.CStride+x] = uint8(y * 0x11) - } - } - return m -} - -func hgradRed(alpha int) Image { - m := image.NewRGBA(16, 16) - for y := 0; y < 16; y++ { - for x := 0; x < 16; x++ { - m.Set(x, y, image.RGBAColor{uint8(x * alpha / 15), 0, 0, uint8(alpha)}) - } - } - return m -} - -func gradYellow(alpha int) Image { - m := image.NewRGBA(16, 16) - for y := 0; y < 16; y++ { - for x := 0; x < 16; x++ { - m.Set(x, y, image.RGBAColor{uint8(x * alpha / 15), uint8(y * alpha / 15), 0, uint8(alpha)}) - } - } - return m -} - -type drawTest struct { - desc string - src image.Image - mask image.Image - op Op - expected image.Color -} - -var drawTests = []drawTest{ - // Uniform mask (0% opaque). - {"nop", vgradGreen(255), fillAlpha(0), Over, image.RGBAColor{136, 0, 0, 255}}, - {"clear", vgradGreen(255), fillAlpha(0), Src, image.RGBAColor{0, 0, 0, 0}}, - // Uniform mask (100%, 75%, nil) and uniform source. - // At (x, y) == (8, 8): - // The destination pixel is {136, 0, 0, 255}. - // The source pixel is {0, 0, 90, 90}. - {"fill", fillBlue(90), fillAlpha(255), Over, image.RGBAColor{88, 0, 90, 255}}, - {"fillSrc", fillBlue(90), fillAlpha(255), Src, image.RGBAColor{0, 0, 90, 90}}, - {"fillAlpha", fillBlue(90), fillAlpha(192), Over, image.RGBAColor{100, 0, 68, 255}}, - {"fillAlphaSrc", fillBlue(90), fillAlpha(192), Src, image.RGBAColor{0, 0, 68, 68}}, - {"fillNil", fillBlue(90), nil, Over, image.RGBAColor{88, 0, 90, 255}}, - {"fillNilSrc", fillBlue(90), nil, Src, image.RGBAColor{0, 0, 90, 90}}, - // Uniform mask (100%, 75%, nil) and variable source. - // At (x, y) == (8, 8): - // The destination pixel is {136, 0, 0, 255}. - // The source pixel is {0, 48, 0, 90}. - {"copy", vgradGreen(90), fillAlpha(255), Over, image.RGBAColor{88, 48, 0, 255}}, - {"copySrc", vgradGreen(90), fillAlpha(255), Src, image.RGBAColor{0, 48, 0, 90}}, - {"copyAlpha", vgradGreen(90), fillAlpha(192), Over, image.RGBAColor{100, 36, 0, 255}}, - {"copyAlphaSrc", vgradGreen(90), fillAlpha(192), Src, image.RGBAColor{0, 36, 0, 68}}, - {"copyNil", vgradGreen(90), nil, Over, image.RGBAColor{88, 48, 0, 255}}, - {"copyNilSrc", vgradGreen(90), nil, Src, image.RGBAColor{0, 48, 0, 90}}, - // Uniform mask (100%, 75%, nil) and variable NRGBA source. - // At (x, y) == (8, 8): - // The destination pixel is {136, 0, 0, 255}. - // The source pixel is {0, 136, 0, 90} in NRGBA-space, which is {0, 48, 0, 90} in RGBA-space. - // The result pixel is different than in the "copy*" test cases because of rounding errors. - {"nrgba", vgradGreenNRGBA(90), fillAlpha(255), Over, image.RGBAColor{88, 46, 0, 255}}, - {"nrgbaSrc", vgradGreenNRGBA(90), fillAlpha(255), Src, image.RGBAColor{0, 46, 0, 90}}, - {"nrgbaAlpha", vgradGreenNRGBA(90), fillAlpha(192), Over, image.RGBAColor{100, 34, 0, 255}}, - {"nrgbaAlphaSrc", vgradGreenNRGBA(90), fillAlpha(192), Src, image.RGBAColor{0, 34, 0, 68}}, - {"nrgbaNil", vgradGreenNRGBA(90), nil, Over, image.RGBAColor{88, 46, 0, 255}}, - {"nrgbaNilSrc", vgradGreenNRGBA(90), nil, Src, image.RGBAColor{0, 46, 0, 90}}, - // Uniform mask (100%, 75%, nil) and variable YCbCr source. - // At (x, y) == (8, 8): - // The destination pixel is {136, 0, 0, 255}. - // The source pixel is {0, 0, 136} in YCbCr-space, which is {11, 38, 0, 255} in RGB-space. - {"ycbcr", vgradCr(), fillAlpha(255), Over, image.RGBAColor{11, 38, 0, 255}}, - {"ycbcrSrc", vgradCr(), fillAlpha(255), Src, image.RGBAColor{11, 38, 0, 255}}, - {"ycbcrAlpha", vgradCr(), fillAlpha(192), Over, image.RGBAColor{42, 28, 0, 255}}, - {"ycbcrAlphaSrc", vgradCr(), fillAlpha(192), Src, image.RGBAColor{8, 28, 0, 192}}, - {"ycbcrNil", vgradCr(), nil, Over, image.RGBAColor{11, 38, 0, 255}}, - {"ycbcrNilSrc", vgradCr(), nil, Src, image.RGBAColor{11, 38, 0, 255}}, - // Variable mask and variable source. - // At (x, y) == (8, 8): - // The destination pixel is {136, 0, 0, 255}. - // The source pixel is {0, 0, 255, 255}. - // The mask pixel's alpha is 102, or 40%. - {"generic", fillBlue(255), vgradAlpha(192), Over, image.RGBAColor{81, 0, 102, 255}}, - {"genericSrc", fillBlue(255), vgradAlpha(192), Src, image.RGBAColor{0, 0, 102, 102}}, -} - -func makeGolden(dst, src, mask image.Image, op Op) image.Image { - // Since golden is a newly allocated image, we don't have to check if the - // input source and mask images and the output golden image overlap. - b := dst.Bounds() - sx0 := src.Bounds().Min.X - b.Min.X - sy0 := src.Bounds().Min.Y - b.Min.Y - var mx0, my0 int - if mask != nil { - mx0 = mask.Bounds().Min.X - b.Min.X - my0 = mask.Bounds().Min.Y - b.Min.Y - } - golden := image.NewRGBA(b.Max.X, b.Max.Y) - for y := b.Min.Y; y < b.Max.Y; y++ { - my, sy := my0+y, sy0+y - for x := b.Min.X; x < b.Max.X; x++ { - mx, sx := mx0+x, sx0+x - const M = 1<<16 - 1 - var dr, dg, db, da uint32 - if op == Over { - dr, dg, db, da = dst.At(x, y).RGBA() - } - sr, sg, sb, sa := src.At(sx, sy).RGBA() - ma := uint32(M) - if mask != nil { - _, _, _, ma = mask.At(mx, my).RGBA() - } - a := M - (sa * ma / M) - golden.Set(x, y, image.RGBA64Color{ - uint16((dr*a + sr*ma) / M), - uint16((dg*a + sg*ma) / M), - uint16((db*a + sb*ma) / M), - uint16((da*a + sa*ma) / M), - }) - } - } - golden.Rect = b - return golden -} - -func TestDraw(t *testing.T) { -loop: - for _, test := range drawTests { - dst := hgradRed(255) - // Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation. - golden := makeGolden(dst, test.src, test.mask, test.op) - b := dst.Bounds() - if !b.Eq(golden.Bounds()) { - t.Errorf("draw %s: bounds %v versus %v", test.desc, dst.Bounds(), golden.Bounds()) - continue - } - // Draw the same combination onto the actual dst using the optimized DrawMask implementation. - DrawMask(dst, b, test.src, image.ZP, test.mask, image.ZP, test.op) - // Check that the resultant pixel at (8, 8) matches what we expect - // (the expected value can be verified by hand). - if !eq(dst.At(8, 8), test.expected) { - t.Errorf("draw %s: at (8, 8) %v versus %v", test.desc, dst.At(8, 8), test.expected) - continue - } - // Check that the resultant dst image matches the golden output. - for y := b.Min.Y; y < b.Max.Y; y++ { - for x := b.Min.X; x < b.Max.X; x++ { - if !eq(dst.At(x, y), golden.At(x, y)) { - t.Errorf("draw %s: at (%d, %d), %v versus golden %v", test.desc, x, y, dst.At(x, y), golden.At(x, y)) - continue loop - } - } - } - } -} - -func TestDrawOverlap(t *testing.T) { - for _, op := range []Op{Over, Src} { - for yoff := -2; yoff <= 2; yoff++ { - loop: - for xoff := -2; xoff <= 2; xoff++ { - m := gradYellow(127).(*image.RGBA) - dst := &image.RGBA{ - Pix: m.Pix, - Stride: m.Stride, - Rect: image.Rect(5, 5, 10, 10), - } - src := &image.RGBA{ - Pix: m.Pix, - Stride: m.Stride, - Rect: image.Rect(5+xoff, 5+yoff, 10+xoff, 10+yoff), - } - // Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation. - golden := makeGolden(dst, src, nil, op) - b := dst.Bounds() - if !b.Eq(golden.Bounds()) { - t.Errorf("drawOverlap xoff=%d,yoff=%d: bounds %v versus %v", xoff, yoff, dst.Bounds(), golden.Bounds()) - continue - } - // Draw the same combination onto the actual dst using the optimized DrawMask implementation. - DrawMask(dst, b, src, src.Bounds().Min, nil, image.ZP, op) - // Check that the resultant dst image matches the golden output. - for y := b.Min.Y; y < b.Max.Y; y++ { - for x := b.Min.X; x < b.Max.X; x++ { - if !eq(dst.At(x, y), golden.At(x, y)) { - t.Errorf("drawOverlap xoff=%d,yoff=%d: at (%d, %d), %v versus golden %v", xoff, yoff, x, y, dst.At(x, y), golden.At(x, y)) - continue loop - } - } - } - } - } - } -} - -// TestIssue836 verifies http://code.google.com/p/go/issues/detail?id=836. -func TestIssue836(t *testing.T) { - a := image.NewRGBA(1, 1) - b := image.NewRGBA(2, 2) - b.Set(0, 0, image.RGBAColor{0, 0, 0, 5}) - b.Set(1, 0, image.RGBAColor{0, 0, 5, 5}) - b.Set(0, 1, image.RGBAColor{0, 5, 0, 5}) - b.Set(1, 1, image.RGBAColor{5, 0, 0, 5}) - Draw(a, image.Rect(0, 0, 1, 1), b, image.Pt(1, 1)) - if !eq(image.RGBAColor{5, 0, 0, 5}, a.At(0, 0)) { - t.Errorf("Issue 836: want %v got %v", image.RGBAColor{5, 0, 0, 5}, a.At(0, 0)) - } -} diff --git a/libgo/go/exp/draw/event.go b/libgo/go/exp/draw/event.go deleted file mode 100644 index b777d91..0000000 --- a/libgo/go/exp/draw/event.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package draw - -import ( - "image" - "os" -) - -// A Window represents a single graphics window. -type Window interface { - // Screen returns an editable Image for the window. - Screen() Image - // FlushImage flushes changes made to Screen() back to screen. - FlushImage() - // EventChan returns a channel carrying UI events such as key presses, - // mouse movements and window resizes. - EventChan() <-chan interface{} - // Close closes the window. - Close() os.Error -} - -// A KeyEvent is sent for a key press or release. -type KeyEvent struct { - // The value k represents key k being pressed. - // The value -k represents key k being released. - // The specific set of key values is not specified, - // but ordinary characters represent themselves. - Key int -} - -// A MouseEvent is sent for a button press or release or for a mouse movement. -type MouseEvent struct { - // Buttons is a bit mask of buttons: 1<<0 is left, 1<<1 middle, 1<<2 right. - // It represents button state and not necessarily the state delta: bit 0 - // being on means that the left mouse button is down, but does not imply - // that the same button was up in the previous MouseEvent. - Buttons int - // Loc is the location of the cursor. - Loc image.Point - // Nsec is the event's timestamp. - Nsec int64 -} - -// A ConfigEvent is sent each time the window's color model or size changes. -// The client should respond by calling Window.Screen to obtain a new image. -type ConfigEvent struct { - Config image.Config -} - -// An ErrEvent is sent when an error occurs. -type ErrEvent struct { - Err os.Error -} diff --git a/libgo/go/exp/draw/x11/auth.go b/libgo/go/exp/draw/x11/auth.go deleted file mode 100644 index d48936a..0000000 --- a/libgo/go/exp/draw/x11/auth.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package x11 - -import ( - "bufio" - "io" - "os" -) - -// readU16BE reads a big-endian uint16 from r, using b as a scratch buffer. -func readU16BE(r io.Reader, b []byte) (uint16, os.Error) { - _, err := io.ReadFull(r, b[0:2]) - if err != nil { - return 0, err - } - return uint16(b[0])<<8 + uint16(b[1]), nil -} - -// readStr reads a length-prefixed string from r, using b as a scratch buffer. -func readStr(r io.Reader, b []byte) (string, os.Error) { - n, err := readU16BE(r, b) - if err != nil { - return "", err - } - if int(n) > len(b) { - return "", os.NewError("Xauthority entry too long for buffer") - } - _, err = io.ReadFull(r, b[0:n]) - if err != nil { - return "", err - } - return string(b[0:n]), nil -} - -// readAuth reads the X authority file and returns the name/data pair for the display. -// displayStr is the "12" out of a $DISPLAY like ":12.0". -func readAuth(displayStr string) (name, data string, err os.Error) { - // b is a scratch buffer to use and should be at least 256 bytes long - // (i.e. it should be able to hold a hostname). - var b [256]byte - // As per /usr/include/X11/Xauth.h. - const familyLocal = 256 - - fn := os.Getenv("XAUTHORITY") - if fn == "" { - home := os.Getenv("HOME") - if home == "" { - err = os.NewError("Xauthority not found: $XAUTHORITY, $HOME not set") - return - } - fn = home + "/.Xauthority" - } - r, err := os.Open(fn) - if err != nil { - return - } - defer r.Close() - br := bufio.NewReader(r) - - hostname, err := os.Hostname() - if err != nil { - return - } - for { - family, err := readU16BE(br, b[0:2]) - if err != nil { - return - } - addr, err := readStr(br, b[0:]) - if err != nil { - return - } - disp, err := readStr(br, b[0:]) - if err != nil { - return - } - name0, err := readStr(br, b[0:]) - if err != nil { - return - } - data0, err := readStr(br, b[0:]) - if err != nil { - return - } - if family == familyLocal && addr == hostname && disp == displayStr { - return name0, data0, nil - } - } - panic("unreachable") -} diff --git a/libgo/go/exp/draw/x11/conn.go b/libgo/go/exp/draw/x11/conn.go deleted file mode 100644 index 81c6726..0000000 --- a/libgo/go/exp/draw/x11/conn.go +++ /dev/null @@ -1,625 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package x11 implements an X11 backend for the exp/draw package. -// -// The X protocol specification is at ftp://ftp.x.org/pub/X11R7.0/doc/PDF/proto.pdf. -// A summary of the wire format can be found in XCB's xproto.xml. -package x11 - -import ( - "bufio" - "exp/draw" - "image" - "io" - "log" - "net" - "os" - "strconv" - "strings" - "time" -) - -type resID uint32 // X resource IDs. - -// TODO(nigeltao): Handle window resizes. -const ( - windowHeight = 600 - windowWidth = 800 -) - -const ( - keymapLo = 8 - keymapHi = 255 -) - -type conn struct { - c io.Closer - r *bufio.Reader - w *bufio.Writer - - gc, window, root, visual resID - - img *image.RGBA - eventc chan interface{} - mouseState draw.MouseEvent - - buf [256]byte // General purpose scratch buffer. - - flush chan bool - flushBuf0 [24]byte - flushBuf1 [4 * 1024]byte -} - -// writeSocket runs in its own goroutine, serving both FlushImage calls -// directly from the exp/draw client and indirectly from X expose events. -// It paints c.img to the X server via PutImage requests. -func (c *conn) writeSocket() { - defer c.c.Close() - for _ = range c.flush { - b := c.img.Bounds() - if b.Empty() { - continue - } - // Each X request has a 16-bit length (in terms of 4-byte units). To avoid going over - // this limit, we send PutImage for each row of the image, rather than trying to paint - // the entire image in one X request. This approach could easily be optimized (or the - // X protocol may have an escape sequence to delimit very large requests). - // TODO(nigeltao): See what XCB's xcb_put_image does in this situation. - units := 6 + b.Dx() - if units > 0xffff || b.Dy() > 0xffff { - log.Print("x11: window is too large for PutImage") - return - } - - c.flushBuf0[0] = 0x48 // PutImage opcode. - c.flushBuf0[1] = 0x02 // XCB_IMAGE_FORMAT_Z_PIXMAP. - c.flushBuf0[2] = uint8(units) - c.flushBuf0[3] = uint8(units >> 8) - setU32LE(c.flushBuf0[4:8], uint32(c.window)) - setU32LE(c.flushBuf0[8:12], uint32(c.gc)) - setU32LE(c.flushBuf0[12:16], 1<<16|uint32(b.Dx())) - c.flushBuf0[21] = 0x18 // depth = 24 bits. - - for y := b.Min.Y; y < b.Max.Y; y++ { - setU32LE(c.flushBuf0[16:20], uint32(y<<16)) - if _, err := c.w.Write(c.flushBuf0[0:24]); err != nil { - if err != os.EOF { - log.Println("x11:", err.String()) - } - return - } - p := c.img.Pix[y*c.img.Stride : (y+1)*c.img.Stride] - for x := b.Min.X; x < b.Max.X; { - nx := b.Max.X - x - if nx > len(c.flushBuf1)/4 { - nx = len(c.flushBuf1) / 4 - } - for i, rgba := range p[x : x+nx] { - c.flushBuf1[4*i+0] = rgba.B - c.flushBuf1[4*i+1] = rgba.G - c.flushBuf1[4*i+2] = rgba.R - } - x += nx - if _, err := c.w.Write(c.flushBuf1[0 : 4*nx]); err != nil { - if err != os.EOF { - log.Println("x11:", err.String()) - } - return - } - } - } - if err := c.w.Flush(); err != nil { - if err != os.EOF { - log.Println("x11:", err.String()) - } - return - } - } -} - -func (c *conn) Screen() draw.Image { return c.img } - -func (c *conn) FlushImage() { - select { - case c.flush <- false: - // Flush notification sent. - default: - // Could not send. - // Flush notification must be pending already. - } -} - -func (c *conn) Close() os.Error { - // Shut down the writeSocket goroutine. This will close the socket to the - // X11 server, which will cause c.eventc to close. - close(c.flush) - for _ = range c.eventc { - // Drain the channel to allow the readSocket goroutine to shut down. - } - return nil -} - -func (c *conn) EventChan() <-chan interface{} { return c.eventc } - -// readSocket runs in its own goroutine, reading X events and sending draw -// events on c's EventChan. -func (c *conn) readSocket() { - var ( - keymap [256][]int - keysymsPerKeycode int - ) - defer close(c.eventc) - for { - // X events are always 32 bytes long. - if _, err := io.ReadFull(c.r, c.buf[0:32]); err != nil { - if err != os.EOF { - c.eventc <- draw.ErrEvent{err} - } - return - } - switch c.buf[0] { - case 0x01: // Reply from a request (e.g. GetKeyboardMapping). - cookie := int(c.buf[3])<<8 | int(c.buf[2]) - if cookie != 1 { - // We issued only one request (GetKeyboardMapping) with a cookie of 1, - // so we shouldn't get any other reply from the X server. - c.eventc <- draw.ErrEvent{os.NewError("x11: unexpected cookie")} - return - } - keysymsPerKeycode = int(c.buf[1]) - b := make([]int, 256*keysymsPerKeycode) - for i := range keymap { - keymap[i] = b[i*keysymsPerKeycode : (i+1)*keysymsPerKeycode] - } - for i := keymapLo; i <= keymapHi; i++ { - m := keymap[i] - for j := range m { - u, err := readU32LE(c.r, c.buf[0:4]) - if err != nil { - if err != os.EOF { - c.eventc <- draw.ErrEvent{err} - } - return - } - m[j] = int(u) - } - } - case 0x02, 0x03: // Key press, key release. - // X Keyboard Encoding is documented at http://tronche.com/gui/x/xlib/input/keyboard-encoding.html - // TODO(nigeltao): Do we need to implement the "MODE SWITCH / group modifier" feature - // or is that some no-longer-used X construct? - if keysymsPerKeycode < 2 { - // Either we haven't yet received the GetKeyboardMapping reply or - // the X server has sent one that's too short. - continue - } - keycode := int(c.buf[1]) - shift := int(c.buf[28]) & 0x01 - keysym := keymap[keycode][shift] - if keysym == 0 { - keysym = keymap[keycode][0] - } - // TODO(nigeltao): Should we send KeyEvents for Shift/Ctrl/Alt? Should Shift-A send - // the same int down the channel as the sent on just the A key? - // TODO(nigeltao): How should IME events (e.g. key presses that should generate CJK text) work? Or - // is that outside the scope of the draw.Window interface? - if c.buf[0] == 0x03 { - keysym = -keysym - } - c.eventc <- draw.KeyEvent{keysym} - case 0x04, 0x05: // Button press, button release. - mask := 1 << (c.buf[1] - 1) - if c.buf[0] == 0x04 { - c.mouseState.Buttons |= mask - } else { - c.mouseState.Buttons &^= mask - } - c.mouseState.Nsec = time.Nanoseconds() - c.eventc <- c.mouseState - case 0x06: // Motion notify. - c.mouseState.Loc.X = int(int16(c.buf[25])<<8 | int16(c.buf[24])) - c.mouseState.Loc.Y = int(int16(c.buf[27])<<8 | int16(c.buf[26])) - c.mouseState.Nsec = time.Nanoseconds() - c.eventc <- c.mouseState - case 0x0c: // Expose. - // A single user action could trigger multiple expose events (e.g. if moving another - // window with XShape'd rounded corners over our window). In that case, the X server will - // send a uint16 count (in bytes 16-17) of the number of additional expose events coming. - // We could parse each event for the (x, y, width, height) and maintain a minimal dirty - // rectangle, but for now, the simplest approach is to paint the entire window, when - // receiving the final event in the series. - if c.buf[17] == 0 && c.buf[16] == 0 { - // TODO(nigeltao): Should we ignore the very first expose event? A freshly mapped window - // will trigger expose, but until the first c.FlushImage call, there's probably nothing to - // paint but black. For an 800x600 window, at 4 bytes per pixel, each repaint writes about - // 2MB over the socket. - c.FlushImage() - } - // TODO(nigeltao): Should we listen to DestroyNotify (0x11) and ResizeRequest (0x19) events? - // What about EnterNotify (0x07) and LeaveNotify (0x08)? - } - } -} - -// connect connects to the X server given by the full X11 display name (e.g. -// ":12.0") and returns the connection as well as the portion of the full name -// that is the display number (e.g. "12"). -// Examples: -// connect(":1") // calls net.Dial("unix", "", "/tmp/.X11-unix/X1"), displayStr="1" -// connect("/tmp/launch-123/:0") // calls net.Dial("unix", "", "/tmp/launch-123/:0"), displayStr="0" -// connect("hostname:2.1") // calls net.Dial("tcp", "", "hostname:6002"), displayStr="2" -// connect("tcp/hostname:1.0") // calls net.Dial("tcp", "", "hostname:6001"), displayStr="1" -func connect(display string) (conn net.Conn, displayStr string, err os.Error) { - colonIdx := strings.LastIndex(display, ":") - if colonIdx < 0 { - return nil, "", os.NewError("bad display: " + display) - } - // Parse the section before the colon. - var protocol, host, socket string - if display[0] == '/' { - socket = display[0:colonIdx] - } else { - if i := strings.LastIndex(display, "/"); i < 0 { - // The default protocol is TCP. - protocol = "tcp" - host = display[0:colonIdx] - } else { - protocol = display[0:i] - host = display[i+1 : colonIdx] - } - } - // Parse the section after the colon. - after := display[colonIdx+1:] - if after == "" { - return nil, "", os.NewError("bad display: " + display) - } - if i := strings.LastIndex(after, "."); i < 0 { - displayStr = after - } else { - displayStr = after[0:i] - } - displayInt, err := strconv.Atoi(displayStr) - if err != nil || displayInt < 0 { - return nil, "", os.NewError("bad display: " + display) - } - // Make the connection. - if socket != "" { - conn, err = net.Dial("unix", socket+":"+displayStr) - } else if host != "" { - conn, err = net.Dial(protocol, host+":"+strconv.Itoa(6000+displayInt)) - } else { - conn, err = net.Dial("unix", "/tmp/.X11-unix/X"+displayStr) - } - if err != nil { - return nil, "", os.NewError("cannot connect to " + display + ": " + err.String()) - } - return -} - -// authenticate authenticates ourselves with the X server. -// displayStr is the "12" out of ":12.0". -func authenticate(w *bufio.Writer, displayStr string) os.Error { - key, value, err := readAuth(displayStr) - if err != nil { - return err - } - // Assume that the authentication protocol is "MIT-MAGIC-COOKIE-1". - if len(key) != 18 || len(value) != 16 { - return os.NewError("unsupported Xauth") - } - // 0x006c means little-endian. 0x000b, 0x0000 means X major version 11, minor version 0. - // 0x0012 and 0x0010 means the auth key and value have lenths 18 and 16. - // The final 0x0000 is padding, so that the string length is a multiple of 4. - _, err = io.WriteString(w, "\x6c\x00\x0b\x00\x00\x00\x12\x00\x10\x00\x00\x00") - if err != nil { - return err - } - _, err = io.WriteString(w, key) - if err != nil { - return err - } - // Again, the 0x0000 is padding. - _, err = io.WriteString(w, "\x00\x00") - if err != nil { - return err - } - _, err = io.WriteString(w, value) - if err != nil { - return err - } - err = w.Flush() - if err != nil { - return err - } - return nil -} - -// readU8 reads a uint8 from r, using b as a scratch buffer. -func readU8(r io.Reader, b []byte) (uint8, os.Error) { - _, err := io.ReadFull(r, b[0:1]) - if err != nil { - return 0, err - } - return uint8(b[0]), nil -} - -// readU16LE reads a little-endian uint16 from r, using b as a scratch buffer. -func readU16LE(r io.Reader, b []byte) (uint16, os.Error) { - _, err := io.ReadFull(r, b[0:2]) - if err != nil { - return 0, err - } - return uint16(b[0]) | uint16(b[1])<<8, nil -} - -// readU32LE reads a little-endian uint32 from r, using b as a scratch buffer. -func readU32LE(r io.Reader, b []byte) (uint32, os.Error) { - _, err := io.ReadFull(r, b[0:4]) - if err != nil { - return 0, err - } - return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, nil -} - -// setU32LE sets b[0:4] to be the little-endian representation of u. -func setU32LE(b []byte, u uint32) { - b[0] = byte((u >> 0) & 0xff) - b[1] = byte((u >> 8) & 0xff) - b[2] = byte((u >> 16) & 0xff) - b[3] = byte((u >> 24) & 0xff) -} - -// checkPixmapFormats checks that we have an agreeable X pixmap Format. -func checkPixmapFormats(r io.Reader, b []byte, n int) (agree bool, err os.Error) { - for i := 0; i < n; i++ { - _, err = io.ReadFull(r, b[0:8]) - if err != nil { - return - } - // Byte 0 is depth, byte 1 is bits-per-pixel, byte 2 is scanline-pad, the rest (5) is padding. - if b[0] == 24 && b[1] == 32 { - agree = true - } - } - return -} - -// checkDepths checks that we have an agreeable X Depth (i.e. one that has an agreeable X VisualType). -func checkDepths(r io.Reader, b []byte, n int, visual uint32) (agree bool, err os.Error) { - for i := 0; i < n; i++ { - depth, err := readU16LE(r, b) - if err != nil { - return - } - depth &= 0xff - visualsLen, err := readU16LE(r, b) - if err != nil { - return - } - // Ignore 4 bytes of padding. - _, err = io.ReadFull(r, b[0:4]) - if err != nil { - return - } - for j := 0; j < int(visualsLen); j++ { - // Read 24 bytes: visual(4), class(1), bits per rgb value(1), colormap entries(2), - // red mask(4), green mask(4), blue mask(4), padding(4). - v, err := readU32LE(r, b) - _, err = readU32LE(r, b) - rm, err := readU32LE(r, b) - gm, err := readU32LE(r, b) - bm, err := readU32LE(r, b) - _, err = readU32LE(r, b) - if err != nil { - return - } - if v == visual && rm == 0xff0000 && gm == 0xff00 && bm == 0xff && depth == 24 { - agree = true - } - } - } - return -} - -// checkScreens checks that we have an agreeable X Screen. -func checkScreens(r io.Reader, b []byte, n int) (root, visual uint32, err os.Error) { - for i := 0; i < n; i++ { - root0, err := readU32LE(r, b) - if err != nil { - return - } - // Ignore the next 7x4 bytes, which is: colormap, whitepixel, blackpixel, current input masks, - // width and height (pixels), width and height (mm), min and max installed maps. - _, err = io.ReadFull(r, b[0:28]) - if err != nil { - return - } - visual0, err := readU32LE(r, b) - if err != nil { - return - } - // Next 4 bytes: backing stores, save unders, root depth, allowed depths length. - x, err := readU32LE(r, b) - if err != nil { - return - } - nDepths := int(x >> 24) - agree, err := checkDepths(r, b, nDepths, visual0) - if err != nil { - return - } - if agree && root == 0 { - root = root0 - visual = visual0 - } - } - return -} - -// handshake performs the protocol handshake with the X server, and ensures -// that the server provides a compatible Screen, Depth, etc. -func (c *conn) handshake() os.Error { - _, err := io.ReadFull(c.r, c.buf[0:8]) - if err != nil { - return err - } - // Byte 0:1 should be 1 (success), bytes 2:6 should be 0xb0000000 (major/minor version 11.0). - if c.buf[0] != 1 || c.buf[2] != 11 || c.buf[3] != 0 || c.buf[4] != 0 || c.buf[5] != 0 { - return os.NewError("unsupported X version") - } - // Ignore the release number. - _, err = io.ReadFull(c.r, c.buf[0:4]) - if err != nil { - return err - } - // Read the resource ID base. - resourceIdBase, err := readU32LE(c.r, c.buf[0:4]) - if err != nil { - return err - } - // Read the resource ID mask. - resourceIdMask, err := readU32LE(c.r, c.buf[0:4]) - if err != nil { - return err - } - if resourceIdMask < 256 { - return os.NewError("X resource ID mask is too small") - } - // Ignore the motion buffer size. - _, err = io.ReadFull(c.r, c.buf[0:4]) - if err != nil { - return err - } - // Read the vendor length and round it up to a multiple of 4, - // for X11 protocol alignment reasons. - vendorLen, err := readU16LE(c.r, c.buf[0:2]) - if err != nil { - return err - } - vendorLen = (vendorLen + 3) &^ 3 - // Read the maximum request length. - maxReqLen, err := readU16LE(c.r, c.buf[0:2]) - if err != nil { - return err - } - if maxReqLen != 0xffff { - return os.NewError("unsupported X maximum request length") - } - // Read the roots length. - rootsLen, err := readU8(c.r, c.buf[0:1]) - if err != nil { - return err - } - // Read the pixmap formats length. - pixmapFormatsLen, err := readU8(c.r, c.buf[0:1]) - if err != nil { - return err - } - // Ignore some things that we don't care about (totalling 10 + vendorLen bytes): - // imageByteOrder(1), bitmapFormatBitOrder(1), bitmapFormatScanlineUnit(1) bitmapFormatScanlinePad(1), - // minKeycode(1), maxKeycode(1), padding(4), vendor (vendorLen). - if 10+int(vendorLen) > cap(c.buf) { - return os.NewError("unsupported X vendor") - } - _, err = io.ReadFull(c.r, c.buf[0:10+int(vendorLen)]) - if err != nil { - return err - } - // Check that we have an agreeable pixmap format. - agree, err := checkPixmapFormats(c.r, c.buf[0:8], int(pixmapFormatsLen)) - if err != nil { - return err - } - if !agree { - return os.NewError("unsupported X pixmap formats") - } - // Check that we have an agreeable screen. - root, visual, err := checkScreens(c.r, c.buf[0:24], int(rootsLen)) - if err != nil { - return err - } - if root == 0 || visual == 0 { - return os.NewError("unsupported X screen") - } - c.gc = resID(resourceIdBase) - c.window = resID(resourceIdBase + 1) - c.root = resID(root) - c.visual = resID(visual) - return nil -} - -// NewWindow calls NewWindowDisplay with $DISPLAY. -func NewWindow() (draw.Window, os.Error) { - display := os.Getenv("DISPLAY") - if len(display) == 0 { - return nil, os.NewError("$DISPLAY not set") - } - return NewWindowDisplay(display) -} - -// NewWindowDisplay returns a new draw.Window, backed by a newly created and -// mapped X11 window. The X server to connect to is specified by the display -// string, such as ":1". -func NewWindowDisplay(display string) (draw.Window, os.Error) { - socket, displayStr, err := connect(display) - if err != nil { - return nil, err - } - c := new(conn) - c.c = socket - c.r = bufio.NewReader(socket) - c.w = bufio.NewWriter(socket) - err = authenticate(c.w, displayStr) - if err != nil { - return nil, err - } - err = c.handshake() - if err != nil { - return nil, err - } - - // Now that we're connected, show a window, via three X protocol messages. - // First, issue a GetKeyboardMapping request. This is the first request, and - // will be associated with a cookie of 1. - setU32LE(c.buf[0:4], 0x00020065) // 0x65 is the GetKeyboardMapping opcode, and the message is 2 x 4 bytes long. - setU32LE(c.buf[4:8], uint32((keymapHi-keymapLo+1)<<8|keymapLo)) - // Second, create a graphics context (GC). - setU32LE(c.buf[8:12], 0x00060037) // 0x37 is the CreateGC opcode, and the message is 6 x 4 bytes long. - setU32LE(c.buf[12:16], uint32(c.gc)) - setU32LE(c.buf[16:20], uint32(c.root)) - setU32LE(c.buf[20:24], 0x00010004) // Bit 2 is XCB_GC_FOREGROUND, bit 16 is XCB_GC_GRAPHICS_EXPOSURES. - setU32LE(c.buf[24:28], 0x00000000) // The Foreground is black. - setU32LE(c.buf[28:32], 0x00000000) // GraphicsExposures' value is unused. - // Third, create the window. - setU32LE(c.buf[32:36], 0x000a0001) // 0x01 is the CreateWindow opcode, and the message is 10 x 4 bytes long. - setU32LE(c.buf[36:40], uint32(c.window)) - setU32LE(c.buf[40:44], uint32(c.root)) - setU32LE(c.buf[44:48], 0x00000000) // Initial (x, y) is (0, 0). - setU32LE(c.buf[48:52], windowHeight<<16|windowWidth) - setU32LE(c.buf[52:56], 0x00010000) // Border width is 0, XCB_WINDOW_CLASS_INPUT_OUTPUT is 1. - setU32LE(c.buf[56:60], uint32(c.visual)) - setU32LE(c.buf[60:64], 0x00000802) // Bit 1 is XCB_CW_BACK_PIXEL, bit 11 is XCB_CW_EVENT_MASK. - setU32LE(c.buf[64:68], 0x00000000) // The Back-Pixel is black. - setU32LE(c.buf[68:72], 0x0000804f) // Key/button press and release, pointer motion, and expose event masks. - // Fourth, map the window. - setU32LE(c.buf[72:76], 0x00020008) // 0x08 is the MapWindow opcode, and the message is 2 x 4 bytes long. - setU32LE(c.buf[76:80], uint32(c.window)) - // Write the bytes. - _, err = c.w.Write(c.buf[0:80]) - if err != nil { - return nil, err - } - err = c.w.Flush() - if err != nil { - return nil, err - } - - c.img = image.NewRGBA(windowWidth, windowHeight) - c.eventc = make(chan interface{}, 16) - c.flush = make(chan bool, 1) - go c.readSocket() - go c.writeSocket() - return c, nil -} diff --git a/libgo/go/exp/eval/abort.go b/libgo/go/exp/eval/abort.go deleted file mode 100644 index 22e17ce..0000000 --- a/libgo/go/exp/eval/abort.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package eval - -import ( - "fmt" - "os" - "runtime" -) - -// Abort aborts the thread's current computation, -// causing the innermost Try to return err. -func (t *Thread) Abort(err os.Error) { - if t.abort == nil { - panic("abort: " + err.String()) - } - t.abort <- err - runtime.Goexit() -} - -// Try executes a computation; if the computation -// Aborts, Try returns the error passed to abort. -func (t *Thread) Try(f func(t *Thread)) os.Error { - oc := t.abort - c := make(chan os.Error) - t.abort = c - go func() { - f(t) - c <- nil - }() - err := <-c - t.abort = oc - return err -} - -type DivByZeroError struct{} - -func (DivByZeroError) String() string { return "divide by zero" } - -type NilPointerError struct{} - -func (NilPointerError) String() string { return "nil pointer dereference" } - -type IndexError struct { - Idx, Len int64 -} - -func (e IndexError) String() string { - if e.Idx < 0 { - return fmt.Sprintf("negative index: %d", e.Idx) - } - return fmt.Sprintf("index %d exceeds length %d", e.Idx, e.Len) -} - -type SliceError struct { - Lo, Hi, Cap int64 -} - -func (e SliceError) String() string { - return fmt.Sprintf("slice [%d:%d]; cap %d", e.Lo, e.Hi, e.Cap) -} - -type KeyError struct { - Key interface{} -} - -func (e KeyError) String() string { return fmt.Sprintf("key '%v' not found in map", e.Key) } - -type NegativeLengthError struct { - Len int64 -} - -func (e NegativeLengthError) String() string { - return fmt.Sprintf("negative length: %d", e.Len) -} - -type NegativeCapacityError struct { - Len int64 -} - -func (e NegativeCapacityError) String() string { - return fmt.Sprintf("negative capacity: %d", e.Len) -} diff --git a/libgo/go/exp/eval/bridge.go b/libgo/go/exp/eval/bridge.go deleted file mode 100644 index f31d9ab..0000000 --- a/libgo/go/exp/eval/bridge.go +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package eval - -import ( - "log" - "go/token" - "reflect" -) - -/* - * Type bridging - */ - -var ( - evalTypes = make(map[reflect.Type]Type) - nativeTypes = make(map[Type]reflect.Type) -) - -// TypeFromNative converts a regular Go type into a the corresponding -// interpreter Type. -func TypeFromNative(t reflect.Type) Type { - if et, ok := evalTypes[t]; ok { - return et - } - - var nt *NamedType - if t.Name() != "" { - name := t.PkgPath() + "·" + t.Name() - nt = &NamedType{token.NoPos, name, nil, true, make(map[string]Method)} - evalTypes[t] = nt - } - - var et Type - switch t.Kind() { - case reflect.Bool: - et = BoolType - - case reflect.Float32: - et = Float32Type - case reflect.Float64: - et = Float64Type - - case reflect.Int16: - et = Int16Type - case reflect.Int32: - et = Int32Type - case reflect.Int64: - et = Int64Type - case reflect.Int8: - et = Int8Type - case reflect.Int: - et = IntType - - case reflect.Uint16: - et = Uint16Type - case reflect.Uint32: - et = Uint32Type - case reflect.Uint64: - et = Uint64Type - case reflect.Uint8: - et = Uint8Type - case reflect.Uint: - et = UintType - case reflect.Uintptr: - et = UintptrType - - case reflect.String: - et = StringType - case reflect.Array: - et = NewArrayType(int64(t.Len()), TypeFromNative(t.Elem())) - case reflect.Chan: - log.Panicf("%T not implemented", t) - case reflect.Func: - nin := t.NumIn() - // Variadic functions have DotDotDotType at the end - variadic := t.IsVariadic() - if variadic { - nin-- - } - in := make([]Type, nin) - for i := range in { - in[i] = TypeFromNative(t.In(i)) - } - out := make([]Type, t.NumOut()) - for i := range out { - out[i] = TypeFromNative(t.Out(i)) - } - et = NewFuncType(in, variadic, out) - case reflect.Interface: - log.Panicf("%T not implemented", t) - case reflect.Map: - log.Panicf("%T not implemented", t) - case reflect.Ptr: - et = NewPtrType(TypeFromNative(t.Elem())) - case reflect.Slice: - et = NewSliceType(TypeFromNative(t.Elem())) - case reflect.Struct: - n := t.NumField() - fields := make([]StructField, n) - for i := 0; i < n; i++ { - sf := t.Field(i) - // TODO(austin) What to do about private fields? - fields[i].Name = sf.Name - fields[i].Type = TypeFromNative(sf.Type) - fields[i].Anonymous = sf.Anonymous - } - et = NewStructType(fields) - case reflect.UnsafePointer: - log.Panicf("%T not implemented", t) - default: - log.Panicf("unexpected reflect.Type: %T", t) - } - - if nt != nil { - if _, ok := et.(*NamedType); !ok { - nt.Complete(et) - et = nt - } - } - - nativeTypes[et] = t - evalTypes[t] = et - - return et -} - -// TypeOfNative returns the interpreter Type of a regular Go value. -func TypeOfNative(v interface{}) Type { return TypeFromNative(reflect.TypeOf(v)) } - -/* - * Function bridging - */ - -type nativeFunc struct { - fn func(*Thread, []Value, []Value) - in, out int -} - -func (f *nativeFunc) NewFrame() *Frame { - vars := make([]Value, f.in+f.out) - return &Frame{nil, vars} -} - -func (f *nativeFunc) Call(t *Thread) { f.fn(t, t.f.Vars[0:f.in], t.f.Vars[f.in:f.in+f.out]) } - -// FuncFromNative creates an interpreter function from a native -// function that takes its in and out arguments as slices of -// interpreter Value's. While somewhat inconvenient, this avoids -// value marshalling. -func FuncFromNative(fn func(*Thread, []Value, []Value), t *FuncType) FuncValue { - return &funcV{&nativeFunc{fn, len(t.In), len(t.Out)}} -} - -// FuncFromNativeTyped is like FuncFromNative, but constructs the -// function type from a function pointer using reflection. Typically, -// the type will be given as a nil pointer to a function with the -// desired signature. -func FuncFromNativeTyped(fn func(*Thread, []Value, []Value), t interface{}) (*FuncType, FuncValue) { - ft := TypeOfNative(t).(*FuncType) - return ft, FuncFromNative(fn, ft) -} diff --git a/libgo/go/exp/eval/compiler.go b/libgo/go/exp/eval/compiler.go deleted file mode 100644 index 9d2923b..0000000 --- a/libgo/go/exp/eval/compiler.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package eval - -import ( - "fmt" - "go/scanner" - "go/token" -) - - -// A compiler captures information used throughout an entire -// compilation. Currently it includes only the error handler. -// -// TODO(austin) This might actually represent package level, in which -// case it should be package compiler. -type compiler struct { - fset *token.FileSet - errors scanner.ErrorHandler - numErrors int - silentErrors int -} - -func (a *compiler) diagAt(pos token.Pos, format string, args ...interface{}) { - a.errors.Error(a.fset.Position(pos), fmt.Sprintf(format, args...)) - a.numErrors++ -} - -func (a *compiler) numError() int { return a.numErrors + a.silentErrors } - -// The universal scope -func newUniverse() *Scope { - sc := &Scope{nil, 0} - sc.block = &block{ - offset: 0, - scope: sc, - global: true, - defs: make(map[string]Def), - } - return sc -} - -var universe *Scope = newUniverse() - - -// TODO(austin) These can all go in stmt.go now -type label struct { - name string - desc string - // The PC goto statements should jump to, or nil if this label - // cannot be goto'd (such as an anonymous for loop label). - gotoPC *uint - // The PC break statements should jump to, or nil if a break - // statement is invalid. - breakPC *uint - // The PC continue statements should jump to, or nil if a - // continue statement is invalid. - continuePC *uint - // The position where this label was resolved. If it has not - // been resolved yet, an invalid position. - resolved token.Pos - // The position where this label was first jumped to. - used token.Pos -} - -// A funcCompiler captures information used throughout the compilation -// of a single function body. -type funcCompiler struct { - *compiler - fnType *FuncType - // Whether the out variables are named. This affects what - // kinds of return statements are legal. - outVarsNamed bool - *codeBuf - flow *flowBuf - labels map[string]*label -} - -// A blockCompiler captures information used throughout the compilation -// of a single block within a function. -type blockCompiler struct { - *funcCompiler - block *block - // The label of this block, used for finding break and - // continue labels. - label *label - // The blockCompiler for the block enclosing this one, or nil - // for a function-level block. - parent *blockCompiler -} diff --git a/libgo/go/exp/eval/eval_test.go b/libgo/go/exp/eval/eval_test.go deleted file mode 100644 index 541d3fe..0000000 --- a/libgo/go/exp/eval/eval_test.go +++ /dev/null @@ -1,263 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package eval - -import ( - "big" - "flag" - "fmt" - "go/token" - "log" - "os" - "reflect" - "regexp" - "testing" -) - -// All tests are done using the same file set. -var fset = token.NewFileSet() - -// Print each statement or expression before parsing it -var noisy = false - -func init() { flag.BoolVar(&noisy, "noisy", false, "chatter during eval tests") } - -/* - * Generic statement/expression test framework - */ - -type test []job - -type job struct { - code string - cerr string - rterr string - val Value - noval bool -} - -func runTests(t *testing.T, baseName string, tests []test) { - delta := 1 - if testing.Short() { - delta = 16 - } - for i := 0; i < len(tests); i += delta { - name := fmt.Sprintf("%s[%d]", baseName, i) - tests[i].run(t, name) - } -} - -func (a test) run(t *testing.T, name string) { - w := newTestWorld() - for _, j := range a { - src := j.code + ";" // trailing semicolon to finish statement - if noisy { - println("code:", src) - } - - code, err := w.Compile(fset, src) - if err != nil { - if j.cerr == "" { - t.Errorf("%s: Compile %s: %v", name, src, err) - break - } - if !match(t, err, j.cerr) { - t.Errorf("%s: Compile %s = error %s; want %v", name, src, err, j.cerr) - break - } - continue - } - if j.cerr != "" { - t.Errorf("%s: Compile %s succeeded; want %s", name, src, j.cerr) - break - } - - val, err := code.Run() - if err != nil { - if j.rterr == "" { - t.Errorf("%s: Run %s: %v", name, src, err) - break - } - if !match(t, err, j.rterr) { - t.Errorf("%s: Run %s = error %s; want %v", name, src, err, j.rterr) - break - } - continue - } - if j.rterr != "" { - t.Errorf("%s: Run %s succeeded; want %s", name, src, j.rterr) - break - } - - if !j.noval && !reflect.DeepEqual(val, j.val) { - t.Errorf("%s: Run %s = %T(%v) want %T(%v)", name, src, val, val, j.val, j.val) - } - } -} - -func match(t *testing.T, err os.Error, pat string) bool { - ok, err1 := regexp.MatchString(pat, err.String()) - if err1 != nil { - t.Fatalf("compile regexp %s: %v", pat, err1) - } - return ok -} - - -/* - * Test constructors - */ - -// Expression compile error -func CErr(expr string, cerr string) test { return test([]job{{code: expr, cerr: cerr}}) } - -// Expression runtime error -func RErr(expr string, rterr string) test { return test([]job{{code: expr, rterr: rterr}}) } - -// Expression value -func Val(expr string, val interface{}) test { - return test([]job{{code: expr, val: toValue(val)}}) -} - -// Statement runs without error -func Run(stmts string) test { return test([]job{{code: stmts, noval: true}}) } - -// Two statements without error. -// TODO(rsc): Should be possible with Run but the parser -// won't let us do both top-level and non-top-level statements. -func Run2(stmt1, stmt2 string) test { - return test([]job{{code: stmt1, noval: true}, {code: stmt2, noval: true}}) -} - -// Statement runs and test one expression's value -func Val1(stmts string, expr1 string, val1 interface{}) test { - return test([]job{ - {code: stmts, noval: true}, - {code: expr1, val: toValue(val1)}, - }) -} - -// Statement runs and test two expressions' values -func Val2(stmts string, expr1 string, val1 interface{}, expr2 string, val2 interface{}) test { - return test([]job{ - {code: stmts, noval: true}, - {code: expr1, val: toValue(val1)}, - {code: expr2, val: toValue(val2)}, - }) -} - -/* - * Value constructors - */ - -type vstruct []interface{} - -type varray []interface{} - -type vslice struct { - arr varray - len, cap int -} - -func toValue(val interface{}) Value { - switch val := val.(type) { - case bool: - r := boolV(val) - return &r - case uint8: - r := uint8V(val) - return &r - case uint: - r := uintV(val) - return &r - case int: - r := intV(val) - return &r - case *big.Int: - return &idealIntV{val} - case float64: - r := float64V(val) - return &r - case *big.Rat: - return &idealFloatV{val} - case string: - r := stringV(val) - return &r - case vstruct: - elems := make([]Value, len(val)) - for i, e := range val { - elems[i] = toValue(e) - } - r := structV(elems) - return &r - case varray: - elems := make([]Value, len(val)) - for i, e := range val { - elems[i] = toValue(e) - } - r := arrayV(elems) - return &r - case vslice: - return &sliceV{Slice{toValue(val.arr).(ArrayValue), int64(val.len), int64(val.cap)}} - case Func: - return &funcV{val} - } - log.Panicf("toValue(%T) not implemented", val) - panic("unreachable") -} - -/* - * Default test scope - */ - -type testFunc struct{} - -func (*testFunc) NewFrame() *Frame { return &Frame{nil, make([]Value, 2)} } - -func (*testFunc) Call(t *Thread) { - n := t.f.Vars[0].(IntValue).Get(t) - - res := n + 1 - - t.f.Vars[1].(IntValue).Set(t, res) -} - -type oneTwoFunc struct{} - -func (*oneTwoFunc) NewFrame() *Frame { return &Frame{nil, make([]Value, 2)} } - -func (*oneTwoFunc) Call(t *Thread) { - t.f.Vars[0].(IntValue).Set(t, 1) - t.f.Vars[1].(IntValue).Set(t, 2) -} - -type voidFunc struct{} - -func (*voidFunc) NewFrame() *Frame { return &Frame{nil, []Value{}} } - -func (*voidFunc) Call(t *Thread) {} - -func newTestWorld() *World { - w := NewWorld() - - def := func(name string, t Type, val interface{}) { w.DefineVar(name, t, toValue(val)) } - - w.DefineConst("c", IdealIntType, toValue(big.NewInt(1))) - def("i", IntType, 1) - def("i2", IntType, 2) - def("u", UintType, uint(1)) - def("f", Float64Type, 1.0) - def("s", StringType, "abc") - def("t", NewStructType([]StructField{{"a", IntType, false}}), vstruct{1}) - def("ai", NewArrayType(2, IntType), varray{1, 2}) - def("aai", NewArrayType(2, NewArrayType(2, IntType)), varray{varray{1, 2}, varray{3, 4}}) - def("aai2", NewArrayType(2, NewArrayType(2, IntType)), varray{varray{5, 6}, varray{7, 8}}) - def("fn", NewFuncType([]Type{IntType}, false, []Type{IntType}), &testFunc{}) - def("oneTwo", NewFuncType([]Type{}, false, []Type{IntType, IntType}), &oneTwoFunc{}) - def("void", NewFuncType([]Type{}, false, []Type{}), &voidFunc{}) - def("sli", NewSliceType(IntType), vslice{varray{1, 2, 3}, 2, 3}) - - return w -} diff --git a/libgo/go/exp/eval/expr.go b/libgo/go/exp/eval/expr.go deleted file mode 100644 index e65f476..0000000 --- a/libgo/go/exp/eval/expr.go +++ /dev/null @@ -1,2015 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package eval - -import ( - "big" - "fmt" - "go/ast" - "go/token" - "log" - "strconv" - "strings" - "os" -) - -var ( - idealZero = big.NewInt(0) - idealOne = big.NewInt(1) -) - -// An expr is the result of compiling an expression. It stores the -// type of the expression and its evaluator function. -type expr struct { - *exprInfo - t Type - - // Evaluate this node as the given type. - eval interface{} - - // Map index expressions permit special forms of assignment, - // for which we need to know the Map and key. - evalMapValue func(t *Thread) (Map, interface{}) - - // Evaluate to the "address of" this value; that is, the - // settable Value object. nil for expressions whose address - // cannot be taken. - evalAddr func(t *Thread) Value - - // Execute this expression as a statement. Only expressions - // that are valid expression statements should set this. - exec func(t *Thread) - - // If this expression is a type, this is its compiled type. - // This is only permitted in the function position of a call - // expression. In this case, t should be nil. - valType Type - - // A short string describing this expression for error - // messages. - desc string -} - -// exprInfo stores information needed to compile any expression node. -// Each expr also stores its exprInfo so further expressions can be -// compiled from it. -type exprInfo struct { - *compiler - pos token.Pos -} - -func (a *exprInfo) newExpr(t Type, desc string) *expr { - return &expr{exprInfo: a, t: t, desc: desc} -} - -func (a *exprInfo) diag(format string, args ...interface{}) { - a.diagAt(a.pos, format, args...) -} - -func (a *exprInfo) diagOpType(op token.Token, vt Type) { - a.diag("illegal operand type for '%v' operator\n\t%v", op, vt) -} - -func (a *exprInfo) diagOpTypes(op token.Token, lt Type, rt Type) { - a.diag("illegal operand types for '%v' operator\n\t%v\n\t%v", op, lt, rt) -} - -/* - * Common expression manipulations - */ - -// a.convertTo(t) converts the value of the analyzed expression a, -// which must be a constant, ideal number, to a new analyzed -// expression with a constant value of type t. -// -// TODO(austin) Rename to resolveIdeal or something? -func (a *expr) convertTo(t Type) *expr { - if !a.t.isIdeal() { - log.Panicf("attempted to convert from %v, expected ideal", a.t) - } - - var rat *big.Rat - - // XXX(Spec) The spec says "It is erroneous". - // - // It is an error to assign a value with a non-zero fractional - // part to an integer, or if the assignment would overflow or - // underflow, or in general if the value cannot be represented - // by the type of the variable. - switch a.t { - case IdealFloatType: - rat = a.asIdealFloat()() - if t.isInteger() && !rat.IsInt() { - a.diag("constant %v truncated to integer", rat.FloatString(6)) - return nil - } - case IdealIntType: - i := a.asIdealInt()() - rat = new(big.Rat).SetInt(i) - default: - log.Panicf("unexpected ideal type %v", a.t) - } - - // Check bounds - if t, ok := t.lit().(BoundedType); ok { - if rat.Cmp(t.minVal()) < 0 { - a.diag("constant %v underflows %v", rat.FloatString(6), t) - return nil - } - if rat.Cmp(t.maxVal()) > 0 { - a.diag("constant %v overflows %v", rat.FloatString(6), t) - return nil - } - } - - // Convert rat to type t. - res := a.newExpr(t, a.desc) - switch t := t.lit().(type) { - case *uintType: - n, d := rat.Num(), rat.Denom() - f := new(big.Int).Quo(n, d) - f = f.Abs(f) - v := uint64(f.Int64()) - res.eval = func(*Thread) uint64 { return v } - case *intType: - n, d := rat.Num(), rat.Denom() - f := new(big.Int).Quo(n, d) - v := f.Int64() - res.eval = func(*Thread) int64 { return v } - case *idealIntType: - n, d := rat.Num(), rat.Denom() - f := new(big.Int).Quo(n, d) - res.eval = func() *big.Int { return f } - case *floatType: - n, d := rat.Num(), rat.Denom() - v := float64(n.Int64()) / float64(d.Int64()) - res.eval = func(*Thread) float64 { return v } - case *idealFloatType: - res.eval = func() *big.Rat { return rat } - default: - log.Panicf("cannot convert to type %T", t) - } - - return res -} - -// convertToInt converts this expression to an integer, if possible, -// or produces an error if not. This accepts ideal ints, uints, and -// ints. If max is not -1, produces an error if possible if the value -// exceeds max. If negErr is not "", produces an error if possible if -// the value is negative. -func (a *expr) convertToInt(max int64, negErr string, errOp string) *expr { - switch a.t.lit().(type) { - case *idealIntType: - val := a.asIdealInt()() - if negErr != "" && val.Sign() < 0 { - a.diag("negative %s: %s", negErr, val) - return nil - } - bound := max - if negErr == "slice" { - bound++ - } - if max != -1 && val.Cmp(big.NewInt(bound)) >= 0 { - a.diag("index %s exceeds length %d", val, max) - return nil - } - return a.convertTo(IntType) - - case *uintType: - // Convert to int - na := a.newExpr(IntType, a.desc) - af := a.asUint() - na.eval = func(t *Thread) int64 { return int64(af(t)) } - return na - - case *intType: - // Good as is - return a - } - - a.diag("illegal operand type for %s\n\t%v", errOp, a.t) - return nil -} - -// derefArray returns an expression of array type if the given -// expression is a *array type. Otherwise, returns the given -// expression. -func (a *expr) derefArray() *expr { - if pt, ok := a.t.lit().(*PtrType); ok { - if _, ok := pt.Elem.lit().(*ArrayType); ok { - deref := a.compileStarExpr(a) - if deref == nil { - log.Panicf("failed to dereference *array") - } - return deref - } - } - return a -} - -/* - * Assignments - */ - -// An assignCompiler compiles assignment operations. Anything other -// than short declarations should use the compileAssign wrapper. -// -// There are three valid types of assignment: -// 1) T = T -// Assigning a single expression with single-valued type to a -// single-valued type. -// 2) MT = T, T, ... -// Assigning multiple expressions with single-valued types to a -// multi-valued type. -// 3) MT = MT -// Assigning a single expression with multi-valued type to a -// multi-valued type. -type assignCompiler struct { - *compiler - pos token.Pos - // The RHS expressions. This may include nil's for - // expressions that failed to compile. - rs []*expr - // The (possibly unary) MultiType of the RHS. - rmt *MultiType - // Whether this is an unpack assignment (case 3). - isUnpack bool - // Whether map special assignment forms are allowed. - allowMap bool - // Whether this is a "r, ok = a[x]" assignment. - isMapUnpack bool - // The operation name to use in error messages, such as - // "assignment" or "function call". - errOp string - // The name to use for positions in error messages, such as - // "argument". - errPosName string -} - -// Type check the RHS of an assignment, returning a new assignCompiler -// and indicating if the type check succeeded. This always returns an -// assignCompiler with rmt set, but if type checking fails, slots in -// the MultiType may be nil. If rs contains nil's, type checking will -// fail and these expressions given a nil type. -func (a *compiler) checkAssign(pos token.Pos, rs []*expr, errOp, errPosName string) (*assignCompiler, bool) { - c := &assignCompiler{ - compiler: a, - pos: pos, - rs: rs, - errOp: errOp, - errPosName: errPosName, - } - - // Is this an unpack? - if len(rs) == 1 && rs[0] != nil { - if rmt, isUnpack := rs[0].t.(*MultiType); isUnpack { - c.rmt = rmt - c.isUnpack = true - return c, true - } - } - - // Create MultiType for RHS and check that all RHS expressions - // are single-valued. - rts := make([]Type, len(rs)) - ok := true - for i, r := range rs { - if r == nil { - ok = false - continue - } - - if _, isMT := r.t.(*MultiType); isMT { - r.diag("multi-valued expression not allowed in %s", errOp) - ok = false - continue - } - - rts[i] = r.t - } - - c.rmt = NewMultiType(rts) - return c, ok -} - -func (a *assignCompiler) allowMapForms(nls int) { - a.allowMap = true - - // Update unpacking info if this is r, ok = a[x] - if nls == 2 && len(a.rs) == 1 && a.rs[0] != nil && a.rs[0].evalMapValue != nil { - a.isUnpack = true - a.rmt = NewMultiType([]Type{a.rs[0].t, BoolType}) - a.isMapUnpack = true - } -} - -// compile type checks and compiles an assignment operation, returning -// a function that expects an l-value and the frame in which to -// evaluate the RHS expressions. The l-value must have exactly the -// type given by lt. Returns nil if type checking fails. -func (a *assignCompiler) compile(b *block, lt Type) func(Value, *Thread) { - lmt, isMT := lt.(*MultiType) - rmt, isUnpack := a.rmt, a.isUnpack - - // Create unary MultiType for single LHS - if !isMT { - lmt = NewMultiType([]Type{lt}) - } - - // Check that the assignment count matches - lcount := len(lmt.Elems) - rcount := len(rmt.Elems) - if lcount != rcount { - msg := "not enough" - pos := a.pos - if rcount > lcount { - msg = "too many" - if lcount > 0 { - pos = a.rs[lcount-1].pos - } - } - a.diagAt(pos, "%s %ss for %s\n\t%s\n\t%s", msg, a.errPosName, a.errOp, lt, rmt) - return nil - } - - bad := false - - // If this is an unpack, create a temporary to store the - // multi-value and replace the RHS with expressions to pull - // out values from the temporary. Technically, this is only - // necessary when we need to perform assignment conversions. - var effect func(*Thread) - if isUnpack { - // This leaks a slot, but is definitely safe. - temp := b.DefineTemp(a.rmt) - tempIdx := temp.Index - if tempIdx < 0 { - panic(fmt.Sprintln("tempidx", tempIdx)) - } - if a.isMapUnpack { - rf := a.rs[0].evalMapValue - vt := a.rmt.Elems[0] - effect = func(t *Thread) { - m, k := rf(t) - v := m.Elem(t, k) - found := boolV(true) - if v == nil { - found = boolV(false) - v = vt.Zero() - } - t.f.Vars[tempIdx] = multiV([]Value{v, &found}) - } - } else { - rf := a.rs[0].asMulti() - effect = func(t *Thread) { t.f.Vars[tempIdx] = multiV(rf(t)) } - } - orig := a.rs[0] - a.rs = make([]*expr, len(a.rmt.Elems)) - for i, t := range a.rmt.Elems { - if t.isIdeal() { - log.Panicf("Right side of unpack contains ideal: %s", rmt) - } - a.rs[i] = orig.newExpr(t, orig.desc) - index := i - a.rs[i].genValue(func(t *Thread) Value { return t.f.Vars[tempIdx].(multiV)[index] }) - } - } - // Now len(a.rs) == len(a.rmt) and we've reduced any unpacking - // to multi-assignment. - - // TODO(austin) Deal with assignment special cases. - - // Values of any type may always be assigned to variables of - // compatible static type. - for i, lt := range lmt.Elems { - rt := rmt.Elems[i] - - // When [an ideal is] (used in an expression) assigned - // to a variable or typed constant, the destination - // must be able to represent the assigned value. - if rt.isIdeal() { - a.rs[i] = a.rs[i].convertTo(lmt.Elems[i]) - if a.rs[i] == nil { - bad = true - continue - } - rt = a.rs[i].t - } - - // A pointer p to an array can be assigned to a slice - // variable v with compatible element type if the type - // of p or v is unnamed. - if rpt, ok := rt.lit().(*PtrType); ok { - if at, ok := rpt.Elem.lit().(*ArrayType); ok { - if lst, ok := lt.lit().(*SliceType); ok { - if lst.Elem.compat(at.Elem, false) && (rt.lit() == Type(rt) || lt.lit() == Type(lt)) { - rf := a.rs[i].asPtr() - a.rs[i] = a.rs[i].newExpr(lt, a.rs[i].desc) - len := at.Len - a.rs[i].eval = func(t *Thread) Slice { return Slice{rf(t).(ArrayValue), len, len} } - rt = a.rs[i].t - } - } - } - } - - if !lt.compat(rt, false) { - if len(a.rs) == 1 { - a.rs[0].diag("illegal operand types for %s\n\t%v\n\t%v", a.errOp, lt, rt) - } else { - a.rs[i].diag("illegal operand types in %s %d of %s\n\t%v\n\t%v", a.errPosName, i+1, a.errOp, lt, rt) - } - bad = true - } - } - if bad { - return nil - } - - // Compile - if !isMT { - // Case 1 - return genAssign(lt, a.rs[0]) - } - // Case 2 or 3 - as := make([]func(lv Value, t *Thread), len(a.rs)) - for i, r := range a.rs { - as[i] = genAssign(lmt.Elems[i], r) - } - return func(lv Value, t *Thread) { - if effect != nil { - effect(t) - } - lmv := lv.(multiV) - for i, a := range as { - a(lmv[i], t) - } - } -} - -// compileAssign compiles an assignment operation without the full -// generality of an assignCompiler. See assignCompiler for a -// description of the arguments. -func (a *compiler) compileAssign(pos token.Pos, b *block, lt Type, rs []*expr, errOp, errPosName string) func(Value, *Thread) { - ac, ok := a.checkAssign(pos, rs, errOp, errPosName) - if !ok { - return nil - } - return ac.compile(b, lt) -} - -/* - * Expression compiler - */ - -// An exprCompiler stores information used throughout the compilation -// of a single expression. It does not embed funcCompiler because -// expressions can appear at top level. -type exprCompiler struct { - *compiler - // The block this expression is being compiled in. - block *block - // Whether this expression is used in a constant context. - constant bool -} - -// compile compiles an expression AST. callCtx should be true if this -// AST is in the function position of a function call node; it allows -// the returned expression to be a type or a built-in function (which -// otherwise result in errors). -func (a *exprCompiler) compile(x ast.Expr, callCtx bool) *expr { - ei := &exprInfo{a.compiler, x.Pos()} - - switch x := x.(type) { - // Literals - case *ast.BasicLit: - switch x.Kind { - case token.INT: - return ei.compileIntLit(string(x.Value)) - case token.FLOAT: - return ei.compileFloatLit(string(x.Value)) - case token.CHAR: - return ei.compileCharLit(string(x.Value)) - case token.STRING: - return ei.compileStringLit(string(x.Value)) - default: - log.Panicf("unexpected basic literal type %v", x.Kind) - } - - case *ast.CompositeLit: - goto notimpl - - case *ast.FuncLit: - decl := ei.compileFuncType(a.block, x.Type) - if decl == nil { - // TODO(austin) Try compiling the body, - // perhaps with dummy argument definitions - return nil - } - fn := ei.compileFunc(a.block, decl, x.Body) - if fn == nil { - return nil - } - if a.constant { - a.diagAt(x.Pos(), "function literal used in constant expression") - return nil - } - return ei.compileFuncLit(decl, fn) - - // Types - case *ast.ArrayType: - // TODO(austin) Use a multi-type case - goto typeexpr - - case *ast.ChanType: - goto typeexpr - - case *ast.Ellipsis: - goto typeexpr - - case *ast.FuncType: - goto typeexpr - - case *ast.InterfaceType: - goto typeexpr - - case *ast.MapType: - goto typeexpr - - // Remaining expressions - case *ast.BadExpr: - // Error already reported by parser - a.silentErrors++ - return nil - - case *ast.BinaryExpr: - l, r := a.compile(x.X, false), a.compile(x.Y, false) - if l == nil || r == nil { - return nil - } - return ei.compileBinaryExpr(x.Op, l, r) - - case *ast.CallExpr: - l := a.compile(x.Fun, true) - args := make([]*expr, len(x.Args)) - bad := false - for i, arg := range x.Args { - if i == 0 && l != nil && (l.t == Type(makeType) || l.t == Type(newType)) { - argei := &exprInfo{a.compiler, arg.Pos()} - args[i] = argei.exprFromType(a.compileType(a.block, arg)) - } else { - args[i] = a.compile(arg, false) - } - if args[i] == nil { - bad = true - } - } - if bad || l == nil { - return nil - } - if a.constant { - a.diagAt(x.Pos(), "function call in constant context") - return nil - } - - if l.valType != nil { - a.diagAt(x.Pos(), "type conversions not implemented") - return nil - } else if ft, ok := l.t.(*FuncType); ok && ft.builtin != "" { - return ei.compileBuiltinCallExpr(a.block, ft, args) - } else { - return ei.compileCallExpr(a.block, l, args) - } - - case *ast.Ident: - return ei.compileIdent(a.block, a.constant, callCtx, x.Name) - - case *ast.IndexExpr: - l, r := a.compile(x.X, false), a.compile(x.Index, false) - if l == nil || r == nil { - return nil - } - return ei.compileIndexExpr(l, r) - - case *ast.SliceExpr: - var lo, hi *expr - arr := a.compile(x.X, false) - if x.Low == nil { - // beginning was omitted, so we need to provide it - ei := &exprInfo{a.compiler, x.Pos()} - lo = ei.compileIntLit("0") - } else { - lo = a.compile(x.Low, false) - } - if x.High == nil { - // End was omitted, so we need to compute len(x.X) - ei := &exprInfo{a.compiler, x.Pos()} - hi = ei.compileBuiltinCallExpr(a.block, lenType, []*expr{arr}) - } else { - hi = a.compile(x.High, false) - } - if arr == nil || lo == nil || hi == nil { - return nil - } - return ei.compileSliceExpr(arr, lo, hi) - - case *ast.KeyValueExpr: - goto notimpl - - case *ast.ParenExpr: - return a.compile(x.X, callCtx) - - case *ast.SelectorExpr: - v := a.compile(x.X, false) - if v == nil { - return nil - } - return ei.compileSelectorExpr(v, x.Sel.Name) - - case *ast.StarExpr: - // We pass down our call context because this could be - // a pointer type (and thus a type conversion) - v := a.compile(x.X, callCtx) - if v == nil { - return nil - } - if v.valType != nil { - // Turns out this was a pointer type, not a dereference - return ei.exprFromType(NewPtrType(v.valType)) - } - return ei.compileStarExpr(v) - - case *ast.StructType: - goto notimpl - - case *ast.TypeAssertExpr: - goto notimpl - - case *ast.UnaryExpr: - v := a.compile(x.X, false) - if v == nil { - return nil - } - return ei.compileUnaryExpr(x.Op, v) - } - log.Panicf("unexpected ast node type %T", x) - panic("unreachable") - -typeexpr: - if !callCtx { - a.diagAt(x.Pos(), "type used as expression") - return nil - } - return ei.exprFromType(a.compileType(a.block, x)) - -notimpl: - a.diagAt(x.Pos(), "%T expression node not implemented", x) - return nil -} - -func (a *exprInfo) exprFromType(t Type) *expr { - if t == nil { - return nil - } - expr := a.newExpr(nil, "type") - expr.valType = t - return expr -} - -func (a *exprInfo) compileIdent(b *block, constant bool, callCtx bool, name string) *expr { - bl, level, def := b.Lookup(name) - if def == nil { - a.diag("%s: undefined", name) - return nil - } - switch def := def.(type) { - case *Constant: - expr := a.newExpr(def.Type, "constant") - if ft, ok := def.Type.(*FuncType); ok && ft.builtin != "" { - // XXX(Spec) I don't think anything says that - // built-in functions can't be used as values. - if !callCtx { - a.diag("built-in function %s cannot be used as a value", ft.builtin) - return nil - } - // Otherwise, we leave the evaluators empty - // because this is handled specially - } else { - expr.genConstant(def.Value) - } - return expr - case *Variable: - if constant { - a.diag("variable %s used in constant expression", name) - return nil - } - if bl.global { - return a.compileGlobalVariable(def) - } - return a.compileVariable(level, def) - case Type: - if callCtx { - return a.exprFromType(def) - } - a.diag("type %v used as expression", name) - return nil - } - log.Panicf("name %s has unknown type %T", name, def) - panic("unreachable") -} - -func (a *exprInfo) compileVariable(level int, v *Variable) *expr { - if v.Type == nil { - // Placeholder definition from an earlier error - a.silentErrors++ - return nil - } - expr := a.newExpr(v.Type, "variable") - expr.genIdentOp(level, v.Index) - return expr -} - -func (a *exprInfo) compileGlobalVariable(v *Variable) *expr { - if v.Type == nil { - // Placeholder definition from an earlier error - a.silentErrors++ - return nil - } - if v.Init == nil { - v.Init = v.Type.Zero() - } - expr := a.newExpr(v.Type, "variable") - val := v.Init - expr.genValue(func(t *Thread) Value { return val }) - return expr -} - -func (a *exprInfo) compileIdealInt(i *big.Int, desc string) *expr { - expr := a.newExpr(IdealIntType, desc) - expr.eval = func() *big.Int { return i } - return expr -} - -func (a *exprInfo) compileIntLit(lit string) *expr { - i, _ := new(big.Int).SetString(lit, 0) - return a.compileIdealInt(i, "integer literal") -} - -func (a *exprInfo) compileCharLit(lit string) *expr { - if lit[0] != '\'' { - // Caught by parser - a.silentErrors++ - return nil - } - v, _, tail, err := strconv.UnquoteChar(lit[1:], '\'') - if err != nil || tail != "'" { - // Caught by parser - a.silentErrors++ - return nil - } - return a.compileIdealInt(big.NewInt(int64(v)), "character literal") -} - -func (a *exprInfo) compileFloatLit(lit string) *expr { - f, ok := new(big.Rat).SetString(lit) - if !ok { - log.Panicf("malformed float literal %s at %v passed parser", lit, a.pos) - } - expr := a.newExpr(IdealFloatType, "float literal") - expr.eval = func() *big.Rat { return f } - return expr -} - -func (a *exprInfo) compileString(s string) *expr { - // Ideal strings don't have a named type but they are - // compatible with type string. - - // TODO(austin) Use unnamed string type. - expr := a.newExpr(StringType, "string literal") - expr.eval = func(*Thread) string { return s } - return expr -} - -func (a *exprInfo) compileStringLit(lit string) *expr { - s, err := strconv.Unquote(lit) - if err != nil { - a.diag("illegal string literal, %v", err) - return nil - } - return a.compileString(s) -} - -func (a *exprInfo) compileStringList(list []*expr) *expr { - ss := make([]string, len(list)) - for i, s := range list { - ss[i] = s.asString()(nil) - } - return a.compileString(strings.Join(ss, "")) -} - -func (a *exprInfo) compileFuncLit(decl *FuncDecl, fn func(*Thread) Func) *expr { - expr := a.newExpr(decl.Type, "function literal") - expr.eval = fn - return expr -} - -func (a *exprInfo) compileSelectorExpr(v *expr, name string) *expr { - // mark marks a field that matches the selector name. It - // tracks the best depth found so far and whether more than - // one field has been found at that depth. - bestDepth := -1 - ambig := false - amberr := "" - mark := func(depth int, pathName string) { - switch { - case bestDepth == -1 || depth < bestDepth: - bestDepth = depth - ambig = false - amberr = "" - - case depth == bestDepth: - ambig = true - - default: - log.Panicf("Marked field at depth %d, but already found one at depth %d", depth, bestDepth) - } - amberr += "\n\t" + pathName[1:] - } - - visited := make(map[Type]bool) - - // find recursively searches for the named field, starting at - // type t. If it finds the named field, it returns a function - // which takes an expr that represents a value of type 't' and - // returns an expr that retrieves the named field. We delay - // expr construction to avoid producing lots of useless expr's - // as we search. - // - // TODO(austin) Now that the expression compiler works on - // semantic values instead of AST's, there should be a much - // better way of doing this. - var find func(Type, int, string) func(*expr) *expr - find = func(t Type, depth int, pathName string) func(*expr) *expr { - // Don't bother looking if we've found something shallower - if bestDepth != -1 && bestDepth < depth { - return nil - } - - // Don't check the same type twice and avoid loops - if visited[t] { - return nil - } - visited[t] = true - - // Implicit dereference - deref := false - if ti, ok := t.(*PtrType); ok { - deref = true - t = ti.Elem - } - - // If it's a named type, look for methods - if ti, ok := t.(*NamedType); ok { - _, ok := ti.methods[name] - if ok { - mark(depth, pathName+"."+name) - log.Panic("Methods not implemented") - } - t = ti.Def - } - - // If it's a struct type, check fields and embedded types - var builder func(*expr) *expr - if t, ok := t.(*StructType); ok { - for i, f := range t.Elems { - var sub func(*expr) *expr - switch { - case f.Name == name: - mark(depth, pathName+"."+name) - sub = func(e *expr) *expr { return e } - - case f.Anonymous: - sub = find(f.Type, depth+1, pathName+"."+f.Name) - if sub == nil { - continue - } - - default: - continue - } - - // We found something. Create a - // builder for accessing this field. - ft := f.Type - index := i - builder = func(parent *expr) *expr { - if deref { - parent = a.compileStarExpr(parent) - } - expr := a.newExpr(ft, "selector expression") - pf := parent.asStruct() - evalAddr := func(t *Thread) Value { return pf(t).Field(t, index) } - expr.genValue(evalAddr) - return sub(expr) - } - } - } - - return builder - } - - builder := find(v.t, 0, "") - if builder == nil { - a.diag("type %v has no field or method %s", v.t, name) - return nil - } - if ambig { - a.diag("field %s is ambiguous in type %v%s", name, v.t, amberr) - return nil - } - - return builder(v) -} - -func (a *exprInfo) compileSliceExpr(arr, lo, hi *expr) *expr { - // Type check object - arr = arr.derefArray() - - var at Type - var maxIndex int64 = -1 - - switch lt := arr.t.lit().(type) { - case *ArrayType: - at = NewSliceType(lt.Elem) - maxIndex = lt.Len - - case *SliceType: - at = lt - - case *stringType: - at = lt - - default: - a.diag("cannot slice %v", arr.t) - return nil - } - - // Type check index and convert to int - // XXX(Spec) It's unclear if ideal floats with no - // fractional part are allowed here. 6g allows it. I - // believe that's wrong. - lo = lo.convertToInt(maxIndex, "slice", "slice") - hi = hi.convertToInt(maxIndex, "slice", "slice") - if lo == nil || hi == nil { - return nil - } - - expr := a.newExpr(at, "slice expression") - - // Compile - lof := lo.asInt() - hif := hi.asInt() - switch lt := arr.t.lit().(type) { - case *ArrayType: - arrf := arr.asArray() - bound := lt.Len - expr.eval = func(t *Thread) Slice { - arr, lo, hi := arrf(t), lof(t), hif(t) - if lo > hi || hi > bound || lo < 0 { - t.Abort(SliceError{lo, hi, bound}) - } - return Slice{arr.Sub(lo, bound-lo), hi - lo, bound - lo} - } - - case *SliceType: - arrf := arr.asSlice() - expr.eval = func(t *Thread) Slice { - arr, lo, hi := arrf(t), lof(t), hif(t) - if lo > hi || hi > arr.Cap || lo < 0 { - t.Abort(SliceError{lo, hi, arr.Cap}) - } - return Slice{arr.Base.Sub(lo, arr.Cap-lo), hi - lo, arr.Cap - lo} - } - - case *stringType: - arrf := arr.asString() - // TODO(austin) This pulls over the whole string in a - // remote setting, instead of creating a substring backed - // by remote memory. - expr.eval = func(t *Thread) string { - arr, lo, hi := arrf(t), lof(t), hif(t) - if lo > hi || hi > int64(len(arr)) || lo < 0 { - t.Abort(SliceError{lo, hi, int64(len(arr))}) - } - return arr[lo:hi] - } - - default: - log.Panicf("unexpected left operand type %T", arr.t.lit()) - } - - return expr -} - -func (a *exprInfo) compileIndexExpr(l, r *expr) *expr { - // Type check object - l = l.derefArray() - - var at Type - intIndex := false - var maxIndex int64 = -1 - - switch lt := l.t.lit().(type) { - case *ArrayType: - at = lt.Elem - intIndex = true - maxIndex = lt.Len - - case *SliceType: - at = lt.Elem - intIndex = true - - case *stringType: - at = Uint8Type - intIndex = true - - case *MapType: - at = lt.Elem - if r.t.isIdeal() { - r = r.convertTo(lt.Key) - if r == nil { - return nil - } - } - if !lt.Key.compat(r.t, false) { - a.diag("cannot use %s as index into %s", r.t, lt) - return nil - } - - default: - a.diag("cannot index into %v", l.t) - return nil - } - - // Type check index and convert to int if necessary - if intIndex { - // XXX(Spec) It's unclear if ideal floats with no - // fractional part are allowed here. 6g allows it. I - // believe that's wrong. - r = r.convertToInt(maxIndex, "index", "index") - if r == nil { - return nil - } - } - - expr := a.newExpr(at, "index expression") - - // Compile - switch lt := l.t.lit().(type) { - case *ArrayType: - lf := l.asArray() - rf := r.asInt() - bound := lt.Len - expr.genValue(func(t *Thread) Value { - l, r := lf(t), rf(t) - if r < 0 || r >= bound { - t.Abort(IndexError{r, bound}) - } - return l.Elem(t, r) - }) - - case *SliceType: - lf := l.asSlice() - rf := r.asInt() - expr.genValue(func(t *Thread) Value { - l, r := lf(t), rf(t) - if l.Base == nil { - t.Abort(NilPointerError{}) - } - if r < 0 || r >= l.Len { - t.Abort(IndexError{r, l.Len}) - } - return l.Base.Elem(t, r) - }) - - case *stringType: - lf := l.asString() - rf := r.asInt() - // TODO(austin) This pulls over the whole string in a - // remote setting, instead of just the one character. - expr.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - if r < 0 || r >= int64(len(l)) { - t.Abort(IndexError{r, int64(len(l))}) - } - return uint64(l[r]) - } - - case *MapType: - lf := l.asMap() - rf := r.asInterface() - expr.genValue(func(t *Thread) Value { - m := lf(t) - k := rf(t) - if m == nil { - t.Abort(NilPointerError{}) - } - e := m.Elem(t, k) - if e == nil { - t.Abort(KeyError{k}) - } - return e - }) - // genValue makes things addressable, but map values - // aren't addressable. - expr.evalAddr = nil - expr.evalMapValue = func(t *Thread) (Map, interface{}) { - // TODO(austin) Key check? nil check? - return lf(t), rf(t) - } - - default: - log.Panicf("unexpected left operand type %T", l.t.lit()) - } - - return expr -} - -func (a *exprInfo) compileCallExpr(b *block, l *expr, as []*expr) *expr { - // TODO(austin) Variadic functions. - - // Type check - - // XXX(Spec) Calling a named function type is okay. I really - // think there needs to be a general discussion of named - // types. A named type creates a new, distinct type, but the - // type of that type is still whatever it's defined to. Thus, - // in "type Foo int", Foo is still an integer type and in - // "type Foo func()", Foo is a function type. - lt, ok := l.t.lit().(*FuncType) - if !ok { - a.diag("cannot call non-function type %v", l.t) - return nil - } - - // The arguments must be single-valued expressions assignment - // compatible with the parameters of F. - // - // XXX(Spec) The spec is wrong. It can also be a single - // multi-valued expression. - nin := len(lt.In) - assign := a.compileAssign(a.pos, b, NewMultiType(lt.In), as, "function call", "argument") - if assign == nil { - return nil - } - - var t Type - nout := len(lt.Out) - switch nout { - case 0: - t = EmptyType - case 1: - t = lt.Out[0] - default: - t = NewMultiType(lt.Out) - } - expr := a.newExpr(t, "function call") - - // Gather argument and out types to initialize frame variables - vts := make([]Type, nin+nout) - copy(vts, lt.In) - copy(vts[nin:], lt.Out) - - // Compile - lf := l.asFunc() - call := func(t *Thread) []Value { - fun := lf(t) - fr := fun.NewFrame() - for i, t := range vts { - fr.Vars[i] = t.Zero() - } - assign(multiV(fr.Vars[0:nin]), t) - oldf := t.f - t.f = fr - fun.Call(t) - t.f = oldf - return fr.Vars[nin : nin+nout] - } - expr.genFuncCall(call) - - return expr -} - -func (a *exprInfo) compileBuiltinCallExpr(b *block, ft *FuncType, as []*expr) *expr { - checkCount := func(min, max int) bool { - if len(as) < min { - a.diag("not enough arguments to %s", ft.builtin) - return false - } else if len(as) > max { - a.diag("too many arguments to %s", ft.builtin) - return false - } - return true - } - - switch ft { - case capType: - if !checkCount(1, 1) { - return nil - } - arg := as[0].derefArray() - expr := a.newExpr(IntType, "function call") - switch t := arg.t.lit().(type) { - case *ArrayType: - // TODO(austin) It would be nice if this could - // be a constant int. - v := t.Len - expr.eval = func(t *Thread) int64 { return v } - - case *SliceType: - vf := arg.asSlice() - expr.eval = func(t *Thread) int64 { return vf(t).Cap } - - //case *ChanType: - - default: - a.diag("illegal argument type for cap function\n\t%v", arg.t) - return nil - } - return expr - - case copyType: - if !checkCount(2, 2) { - return nil - } - src := as[1] - dst := as[0] - if src.t != dst.t { - a.diag("arguments to built-in function 'copy' must have same type\nsrc: %s\ndst: %s\n", src.t, dst.t) - return nil - } - if _, ok := src.t.lit().(*SliceType); !ok { - a.diag("src argument to 'copy' must be a slice (got: %s)", src.t) - return nil - } - if _, ok := dst.t.lit().(*SliceType); !ok { - a.diag("dst argument to 'copy' must be a slice (got: %s)", dst.t) - return nil - } - expr := a.newExpr(IntType, "function call") - srcf := src.asSlice() - dstf := dst.asSlice() - expr.eval = func(t *Thread) int64 { - src, dst := srcf(t), dstf(t) - nelems := src.Len - if nelems > dst.Len { - nelems = dst.Len - } - dst.Base.Sub(0, nelems).Assign(t, src.Base.Sub(0, nelems)) - return nelems - } - return expr - - case lenType: - if !checkCount(1, 1) { - return nil - } - arg := as[0].derefArray() - expr := a.newExpr(IntType, "function call") - switch t := arg.t.lit().(type) { - case *stringType: - vf := arg.asString() - expr.eval = func(t *Thread) int64 { return int64(len(vf(t))) } - - case *ArrayType: - // TODO(austin) It would be nice if this could - // be a constant int. - v := t.Len - expr.eval = func(t *Thread) int64 { return v } - - case *SliceType: - vf := arg.asSlice() - expr.eval = func(t *Thread) int64 { return vf(t).Len } - - case *MapType: - vf := arg.asMap() - expr.eval = func(t *Thread) int64 { - // XXX(Spec) What's the len of an - // uninitialized map? - m := vf(t) - if m == nil { - return 0 - } - return m.Len(t) - } - - //case *ChanType: - - default: - a.diag("illegal argument type for len function\n\t%v", arg.t) - return nil - } - return expr - - case makeType: - if !checkCount(1, 3) { - return nil - } - // XXX(Spec) What are the types of the - // arguments? Do they have to be ints? 6g - // accepts any integral type. - var lenexpr, capexpr *expr - var lenf, capf func(*Thread) int64 - if len(as) > 1 { - lenexpr = as[1].convertToInt(-1, "length", "make function") - if lenexpr == nil { - return nil - } - lenf = lenexpr.asInt() - } - if len(as) > 2 { - capexpr = as[2].convertToInt(-1, "capacity", "make function") - if capexpr == nil { - return nil - } - capf = capexpr.asInt() - } - - switch t := as[0].valType.lit().(type) { - case *SliceType: - // A new, initialized slice value for a given - // element type T is made using the built-in - // function make, which takes a slice type and - // parameters specifying the length and - // optionally the capacity. - if !checkCount(2, 3) { - return nil - } - et := t.Elem - expr := a.newExpr(t, "function call") - expr.eval = func(t *Thread) Slice { - l := lenf(t) - // XXX(Spec) What if len or cap is - // negative? The runtime panics. - if l < 0 { - t.Abort(NegativeLengthError{l}) - } - c := l - if capf != nil { - c = capf(t) - if c < 0 { - t.Abort(NegativeCapacityError{c}) - } - // XXX(Spec) What happens if - // len > cap? The runtime - // sets cap to len. - if l > c { - c = l - } - } - base := arrayV(make([]Value, c)) - for i := int64(0); i < c; i++ { - base[i] = et.Zero() - } - return Slice{&base, l, c} - } - return expr - - case *MapType: - // A new, empty map value is made using the - // built-in function make, which takes the map - // type and an optional capacity hint as - // arguments. - if !checkCount(1, 2) { - return nil - } - expr := a.newExpr(t, "function call") - expr.eval = func(t *Thread) Map { - if lenf == nil { - return make(evalMap) - } - l := lenf(t) - return make(evalMap, l) - } - return expr - - //case *ChanType: - - default: - a.diag("illegal argument type for make function\n\t%v", as[0].valType) - return nil - } - - case closeType, closedType: - a.diag("built-in function %s not implemented", ft.builtin) - return nil - - case newType: - if !checkCount(1, 1) { - return nil - } - - t := as[0].valType - expr := a.newExpr(NewPtrType(t), "new") - expr.eval = func(*Thread) Value { return t.Zero() } - return expr - - case panicType, printType, printlnType: - evals := make([]func(*Thread) interface{}, len(as)) - for i, x := range as { - evals[i] = x.asInterface() - } - spaces := ft == printlnType - newline := ft != printType - printer := func(t *Thread) { - for i, eval := range evals { - if i > 0 && spaces { - print(" ") - } - v := eval(t) - type stringer interface { - String() string - } - switch v1 := v.(type) { - case bool: - print(v1) - case uint64: - print(v1) - case int64: - print(v1) - case float64: - print(v1) - case string: - print(v1) - case stringer: - print(v1.String()) - default: - print("???") - } - } - if newline { - print("\n") - } - } - expr := a.newExpr(EmptyType, "print") - expr.exec = printer - if ft == panicType { - expr.exec = func(t *Thread) { - printer(t) - t.Abort(os.NewError("panic")) - } - } - return expr - } - - log.Panicf("unexpected built-in function '%s'", ft.builtin) - panic("unreachable") -} - -func (a *exprInfo) compileStarExpr(v *expr) *expr { - switch vt := v.t.lit().(type) { - case *PtrType: - expr := a.newExpr(vt.Elem, "indirect expression") - vf := v.asPtr() - expr.genValue(func(t *Thread) Value { - v := vf(t) - if v == nil { - t.Abort(NilPointerError{}) - } - return v - }) - return expr - } - - a.diagOpType(token.MUL, v.t) - return nil -} - -var unaryOpDescs = make(map[token.Token]string) - -func (a *exprInfo) compileUnaryExpr(op token.Token, v *expr) *expr { - // Type check - var t Type - switch op { - case token.ADD, token.SUB: - if !v.t.isInteger() && !v.t.isFloat() { - a.diagOpType(op, v.t) - return nil - } - t = v.t - - case token.NOT: - if !v.t.isBoolean() { - a.diagOpType(op, v.t) - return nil - } - t = BoolType - - case token.XOR: - if !v.t.isInteger() { - a.diagOpType(op, v.t) - return nil - } - t = v.t - - case token.AND: - // The unary prefix address-of operator & generates - // the address of its operand, which must be a - // variable, pointer indirection, field selector, or - // array or slice indexing operation. - if v.evalAddr == nil { - a.diag("cannot take the address of %s", v.desc) - return nil - } - - // TODO(austin) Implement "It is illegal to take the - // address of a function result variable" once I have - // function result variables. - - t = NewPtrType(v.t) - - case token.ARROW: - log.Panicf("Unary op %v not implemented", op) - - default: - log.Panicf("unknown unary operator %v", op) - } - - desc, ok := unaryOpDescs[op] - if !ok { - desc = "unary " + op.String() + " expression" - unaryOpDescs[op] = desc - } - - // Compile - expr := a.newExpr(t, desc) - switch op { - case token.ADD: - // Just compile it out - expr = v - expr.desc = desc - - case token.SUB: - expr.genUnaryOpNeg(v) - - case token.NOT: - expr.genUnaryOpNot(v) - - case token.XOR: - expr.genUnaryOpXor(v) - - case token.AND: - vf := v.evalAddr - expr.eval = func(t *Thread) Value { return vf(t) } - - default: - log.Panicf("Compilation of unary op %v not implemented", op) - } - - return expr -} - -var binOpDescs = make(map[token.Token]string) - -func (a *exprInfo) compileBinaryExpr(op token.Token, l, r *expr) *expr { - // Save the original types of l.t and r.t for error messages. - origlt := l.t - origrt := r.t - - // XXX(Spec) What is the exact definition of a "named type"? - - // XXX(Spec) Arithmetic operators: "Integer types" apparently - // means all types compatible with basic integer types, though - // this is never explained. Likewise for float types, etc. - // This relates to the missing explanation of named types. - - // XXX(Spec) Operators: "If both operands are ideal numbers, - // the conversion is to ideal floats if one of the operands is - // an ideal float (relevant for / and %)." How is that - // relevant only for / and %? If I add an ideal int and an - // ideal float, I get an ideal float. - - if op != token.SHL && op != token.SHR { - // Except in shift expressions, if one operand has - // numeric type and the other operand is an ideal - // number, the ideal number is converted to match the - // type of the other operand. - if (l.t.isInteger() || l.t.isFloat()) && !l.t.isIdeal() && r.t.isIdeal() { - r = r.convertTo(l.t) - } else if (r.t.isInteger() || r.t.isFloat()) && !r.t.isIdeal() && l.t.isIdeal() { - l = l.convertTo(r.t) - } - if l == nil || r == nil { - return nil - } - - // Except in shift expressions, if both operands are - // ideal numbers and one is an ideal float, the other - // is converted to ideal float. - if l.t.isIdeal() && r.t.isIdeal() { - if l.t.isInteger() && r.t.isFloat() { - l = l.convertTo(r.t) - } else if l.t.isFloat() && r.t.isInteger() { - r = r.convertTo(l.t) - } - if l == nil || r == nil { - return nil - } - } - } - - // Useful type predicates - // TODO(austin) CL 33668 mandates identical types except for comparisons. - compat := func() bool { return l.t.compat(r.t, false) } - integers := func() bool { return l.t.isInteger() && r.t.isInteger() } - floats := func() bool { return l.t.isFloat() && r.t.isFloat() } - strings := func() bool { - // TODO(austin) Deal with named types - return l.t == StringType && r.t == StringType - } - booleans := func() bool { return l.t.isBoolean() && r.t.isBoolean() } - - // Type check - var t Type - switch op { - case token.ADD: - if !compat() || (!integers() && !floats() && !strings()) { - a.diagOpTypes(op, origlt, origrt) - return nil - } - t = l.t - - case token.SUB, token.MUL, token.QUO: - if !compat() || (!integers() && !floats()) { - a.diagOpTypes(op, origlt, origrt) - return nil - } - t = l.t - - case token.REM, token.AND, token.OR, token.XOR, token.AND_NOT: - if !compat() || !integers() { - a.diagOpTypes(op, origlt, origrt) - return nil - } - t = l.t - - case token.SHL, token.SHR: - // XXX(Spec) Is it okay for the right operand to be an - // ideal float with no fractional part? "The right - // operand in a shift operation must be always be of - // unsigned integer type or an ideal number that can - // be safely converted into an unsigned integer type - // (§Arithmetic operators)" suggests so and 6g agrees. - - if !l.t.isInteger() || !(r.t.isInteger() || r.t.isIdeal()) { - a.diagOpTypes(op, origlt, origrt) - return nil - } - - // The right operand in a shift operation must be - // always be of unsigned integer type or an ideal - // number that can be safely converted into an - // unsigned integer type. - if r.t.isIdeal() { - r2 := r.convertTo(UintType) - if r2 == nil { - return nil - } - - // If the left operand is not ideal, convert - // the right to not ideal. - if !l.t.isIdeal() { - r = r2 - } - - // If both are ideal, but the right side isn't - // an ideal int, convert it to simplify things. - if l.t.isIdeal() && !r.t.isInteger() { - r = r.convertTo(IdealIntType) - if r == nil { - log.Panicf("conversion to uintType succeeded, but conversion to idealIntType failed") - } - } - } else if _, ok := r.t.lit().(*uintType); !ok { - a.diag("right operand of shift must be unsigned") - return nil - } - - if l.t.isIdeal() && !r.t.isIdeal() { - // XXX(Spec) What is the meaning of "ideal >> - // non-ideal"? Russ says the ideal should be - // converted to an int. 6g propagates the - // type down from assignments as a hint. - - l = l.convertTo(IntType) - if l == nil { - return nil - } - } - - // At this point, we should have one of three cases: - // 1) uint SHIFT uint - // 2) int SHIFT uint - // 3) ideal int SHIFT ideal int - - t = l.t - - case token.LOR, token.LAND: - if !booleans() { - return nil - } - // XXX(Spec) There's no mention of *which* boolean - // type the logical operators return. From poking at - // 6g, it appears to be the named boolean type, NOT - // the type of the left operand, and NOT an unnamed - // boolean type. - - t = BoolType - - case token.ARROW: - // The operands in channel sends differ in type: one - // is always a channel and the other is a variable or - // value of the channel's element type. - log.Panic("Binary op <- not implemented") - t = BoolType - - case token.LSS, token.GTR, token.LEQ, token.GEQ: - // XXX(Spec) It's really unclear what types which - // comparison operators apply to. I feel like the - // text is trying to paint a Venn diagram for me, - // which it's really pretty simple: <, <=, >, >= apply - // only to numeric types and strings. == and != apply - // to everything except arrays and structs, and there - // are some restrictions on when it applies to slices. - - if !compat() || (!integers() && !floats() && !strings()) { - a.diagOpTypes(op, origlt, origrt) - return nil - } - t = BoolType - - case token.EQL, token.NEQ: - // XXX(Spec) The rules for type checking comparison - // operators are spread across three places that all - // partially overlap with each other: the Comparison - // Compatibility section, the Operators section, and - // the Comparison Operators section. The Operators - // section should just say that operators require - // identical types (as it does currently) except that - // there a few special cases for comparison, which are - // described in section X. Currently it includes just - // one of the four special cases. The Comparison - // Compatibility section and the Comparison Operators - // section should either be merged, or at least the - // Comparison Compatibility section should be - // exclusively about type checking and the Comparison - // Operators section should be exclusively about - // semantics. - - // XXX(Spec) Comparison operators: "All comparison - // operators apply to basic types except bools." This - // is very difficult to parse. It's explained much - // better in the Comparison Compatibility section. - - // XXX(Spec) Comparison compatibility: "Function - // values are equal if they refer to the same - // function." is rather vague. It should probably be - // similar to the way the rule for map values is - // written: Function values are equal if they were - // created by the same execution of a function literal - // or refer to the same function declaration. This is - // *almost* but not quite waht 6g implements. If a - // function literals does not capture any variables, - // then multiple executions of it will result in the - // same closure. Russ says he'll change that. - - // TODO(austin) Deal with remaining special cases - - if !compat() { - a.diagOpTypes(op, origlt, origrt) - return nil - } - // Arrays and structs may not be compared to anything. - switch l.t.(type) { - case *ArrayType, *StructType: - a.diagOpTypes(op, origlt, origrt) - return nil - } - t = BoolType - - default: - log.Panicf("unknown binary operator %v", op) - } - - desc, ok := binOpDescs[op] - if !ok { - desc = op.String() + " expression" - binOpDescs[op] = desc - } - - // Check for ideal divide by zero - switch op { - case token.QUO, token.REM: - if r.t.isIdeal() { - if (r.t.isInteger() && r.asIdealInt()().Sign() == 0) || - (r.t.isFloat() && r.asIdealFloat()().Sign() == 0) { - a.diag("divide by zero") - return nil - } - } - } - - // Compile - expr := a.newExpr(t, desc) - switch op { - case token.ADD: - expr.genBinOpAdd(l, r) - - case token.SUB: - expr.genBinOpSub(l, r) - - case token.MUL: - expr.genBinOpMul(l, r) - - case token.QUO: - expr.genBinOpQuo(l, r) - - case token.REM: - expr.genBinOpRem(l, r) - - case token.AND: - expr.genBinOpAnd(l, r) - - case token.OR: - expr.genBinOpOr(l, r) - - case token.XOR: - expr.genBinOpXor(l, r) - - case token.AND_NOT: - expr.genBinOpAndNot(l, r) - - case token.SHL: - if l.t.isIdeal() { - lv := l.asIdealInt()() - rv := r.asIdealInt()() - const maxShift = 99999 - if rv.Cmp(big.NewInt(maxShift)) > 0 { - a.diag("left shift by %v; exceeds implementation limit of %v", rv, maxShift) - expr.t = nil - return nil - } - val := new(big.Int).Lsh(lv, uint(rv.Int64())) - expr.eval = func() *big.Int { return val } - } else { - expr.genBinOpShl(l, r) - } - - case token.SHR: - if l.t.isIdeal() { - lv := l.asIdealInt()() - rv := r.asIdealInt()() - val := new(big.Int).Rsh(lv, uint(rv.Int64())) - expr.eval = func() *big.Int { return val } - } else { - expr.genBinOpShr(l, r) - } - - case token.LSS: - expr.genBinOpLss(l, r) - - case token.GTR: - expr.genBinOpGtr(l, r) - - case token.LEQ: - expr.genBinOpLeq(l, r) - - case token.GEQ: - expr.genBinOpGeq(l, r) - - case token.EQL: - expr.genBinOpEql(l, r) - - case token.NEQ: - expr.genBinOpNeq(l, r) - - case token.LAND: - expr.genBinOpLogAnd(l, r) - - case token.LOR: - expr.genBinOpLogOr(l, r) - - default: - log.Panicf("Compilation of binary op %v not implemented", op) - } - - return expr -} - -// TODO(austin) This is a hack to eliminate a circular dependency -// between type.go and expr.go -func (a *compiler) compileArrayLen(b *block, expr ast.Expr) (int64, bool) { - lenExpr := a.compileExpr(b, true, expr) - if lenExpr == nil { - return 0, false - } - - // XXX(Spec) Are ideal floats with no fractional part okay? - if lenExpr.t.isIdeal() { - lenExpr = lenExpr.convertTo(IntType) - if lenExpr == nil { - return 0, false - } - } - - if !lenExpr.t.isInteger() { - a.diagAt(expr.Pos(), "array size must be an integer") - return 0, false - } - - switch lenExpr.t.lit().(type) { - case *intType: - return lenExpr.asInt()(nil), true - case *uintType: - return int64(lenExpr.asUint()(nil)), true - } - log.Panicf("unexpected integer type %T", lenExpr.t) - return 0, false -} - -func (a *compiler) compileExpr(b *block, constant bool, expr ast.Expr) *expr { - ec := &exprCompiler{a, b, constant} - nerr := a.numError() - e := ec.compile(expr, false) - if e == nil && nerr == a.numError() { - log.Panicf("expression compilation failed without reporting errors") - } - return e -} - -// extractEffect separates out any effects that the expression may -// have, returning a function that will perform those effects and a -// new exprCompiler that is guaranteed to be side-effect free. These -// are the moral equivalents of "temp := expr" and "temp" (or "temp := -// &expr" and "*temp" for addressable exprs). Because this creates a -// temporary variable, the caller should create a temporary block for -// the compilation of this expression and the evaluation of the -// results. -func (a *expr) extractEffect(b *block, errOp string) (func(*Thread), *expr) { - // Create "&a" if a is addressable - rhs := a - if a.evalAddr != nil { - rhs = a.compileUnaryExpr(token.AND, rhs) - } - - // Create temp - ac, ok := a.checkAssign(a.pos, []*expr{rhs}, errOp, "") - if !ok { - return nil, nil - } - if len(ac.rmt.Elems) != 1 { - a.diag("multi-valued expression not allowed in %s", errOp) - return nil, nil - } - tempType := ac.rmt.Elems[0] - if tempType.isIdeal() { - // It's too bad we have to duplicate this rule. - switch { - case tempType.isInteger(): - tempType = IntType - case tempType.isFloat(): - tempType = Float64Type - default: - log.Panicf("unexpected ideal type %v", tempType) - } - } - temp := b.DefineTemp(tempType) - tempIdx := temp.Index - - // Create "temp := rhs" - assign := ac.compile(b, tempType) - if assign == nil { - log.Panicf("compileAssign type check failed") - } - - effect := func(t *Thread) { - tempVal := tempType.Zero() - t.f.Vars[tempIdx] = tempVal - assign(tempVal, t) - } - - // Generate "temp" or "*temp" - getTemp := a.compileVariable(0, temp) - if a.evalAddr == nil { - return effect, getTemp - } - - deref := a.compileStarExpr(getTemp) - if deref == nil { - return nil, nil - } - return effect, deref -} diff --git a/libgo/go/exp/eval/expr1.go b/libgo/go/exp/eval/expr1.go deleted file mode 100644 index 5d0e500..0000000 --- a/libgo/go/exp/eval/expr1.go +++ /dev/null @@ -1,1874 +0,0 @@ -// This file is machine generated by gen.go. -// 6g gen.go && 6l gen.6 && ./6.out >expr1.go - -package eval - -import ( - "big" - "log" -) - -/* - * "As" functions. These retrieve evaluator functions from an - * expr, panicking if the requested evaluator has the wrong type. - */ -func (a *expr) asBool() func(*Thread) bool { - return a.eval.(func(*Thread) bool) -} -func (a *expr) asUint() func(*Thread) uint64 { - return a.eval.(func(*Thread) uint64) -} -func (a *expr) asInt() func(*Thread) int64 { - return a.eval.(func(*Thread) int64) -} -func (a *expr) asIdealInt() func() *big.Int { - return a.eval.(func() *big.Int) -} -func (a *expr) asFloat() func(*Thread) float64 { - return a.eval.(func(*Thread) float64) -} -func (a *expr) asIdealFloat() func() *big.Rat { - return a.eval.(func() *big.Rat) -} -func (a *expr) asString() func(*Thread) string { - return a.eval.(func(*Thread) string) -} -func (a *expr) asArray() func(*Thread) ArrayValue { - return a.eval.(func(*Thread) ArrayValue) -} -func (a *expr) asStruct() func(*Thread) StructValue { - return a.eval.(func(*Thread) StructValue) -} -func (a *expr) asPtr() func(*Thread) Value { - return a.eval.(func(*Thread) Value) -} -func (a *expr) asFunc() func(*Thread) Func { - return a.eval.(func(*Thread) Func) -} -func (a *expr) asSlice() func(*Thread) Slice { - return a.eval.(func(*Thread) Slice) -} -func (a *expr) asMap() func(*Thread) Map { - return a.eval.(func(*Thread) Map) -} -func (a *expr) asMulti() func(*Thread) []Value { - return a.eval.(func(*Thread) []Value) -} - -func (a *expr) asInterface() func(*Thread) interface{} { - switch sf := a.eval.(type) { - case func(t *Thread) bool: - return func(t *Thread) interface{} { return sf(t) } - case func(t *Thread) uint64: - return func(t *Thread) interface{} { return sf(t) } - case func(t *Thread) int64: - return func(t *Thread) interface{} { return sf(t) } - case func() *big.Int: - return func(*Thread) interface{} { return sf() } - case func(t *Thread) float64: - return func(t *Thread) interface{} { return sf(t) } - case func() *big.Rat: - return func(*Thread) interface{} { return sf() } - case func(t *Thread) string: - return func(t *Thread) interface{} { return sf(t) } - case func(t *Thread) ArrayValue: - return func(t *Thread) interface{} { return sf(t) } - case func(t *Thread) StructValue: - return func(t *Thread) interface{} { return sf(t) } - case func(t *Thread) Value: - return func(t *Thread) interface{} { return sf(t) } - case func(t *Thread) Func: - return func(t *Thread) interface{} { return sf(t) } - case func(t *Thread) Slice: - return func(t *Thread) interface{} { return sf(t) } - case func(t *Thread) Map: - return func(t *Thread) interface{} { return sf(t) } - default: - log.Panicf("unexpected expression node type %T at %v", a.eval, a.pos) - } - panic("fail") -} - -/* - * Operator generators. - */ - -func (a *expr) genConstant(v Value) { - switch a.t.lit().(type) { - case *boolType: - a.eval = func(t *Thread) bool { return v.(BoolValue).Get(t) } - case *uintType: - a.eval = func(t *Thread) uint64 { return v.(UintValue).Get(t) } - case *intType: - a.eval = func(t *Thread) int64 { return v.(IntValue).Get(t) } - case *idealIntType: - val := v.(IdealIntValue).Get() - a.eval = func() *big.Int { return val } - case *floatType: - a.eval = func(t *Thread) float64 { return v.(FloatValue).Get(t) } - case *idealFloatType: - val := v.(IdealFloatValue).Get() - a.eval = func() *big.Rat { return val } - case *stringType: - a.eval = func(t *Thread) string { return v.(StringValue).Get(t) } - case *ArrayType: - a.eval = func(t *Thread) ArrayValue { return v.(ArrayValue).Get(t) } - case *StructType: - a.eval = func(t *Thread) StructValue { return v.(StructValue).Get(t) } - case *PtrType: - a.eval = func(t *Thread) Value { return v.(PtrValue).Get(t) } - case *FuncType: - a.eval = func(t *Thread) Func { return v.(FuncValue).Get(t) } - case *SliceType: - a.eval = func(t *Thread) Slice { return v.(SliceValue).Get(t) } - case *MapType: - a.eval = func(t *Thread) Map { return v.(MapValue).Get(t) } - default: - log.Panicf("unexpected constant type %v at %v", a.t, a.pos) - } -} - -func (a *expr) genIdentOp(level, index int) { - a.evalAddr = func(t *Thread) Value { return t.f.Get(level, index) } - switch a.t.lit().(type) { - case *boolType: - a.eval = func(t *Thread) bool { return t.f.Get(level, index).(BoolValue).Get(t) } - case *uintType: - a.eval = func(t *Thread) uint64 { return t.f.Get(level, index).(UintValue).Get(t) } - case *intType: - a.eval = func(t *Thread) int64 { return t.f.Get(level, index).(IntValue).Get(t) } - case *floatType: - a.eval = func(t *Thread) float64 { return t.f.Get(level, index).(FloatValue).Get(t) } - case *stringType: - a.eval = func(t *Thread) string { return t.f.Get(level, index).(StringValue).Get(t) } - case *ArrayType: - a.eval = func(t *Thread) ArrayValue { return t.f.Get(level, index).(ArrayValue).Get(t) } - case *StructType: - a.eval = func(t *Thread) StructValue { return t.f.Get(level, index).(StructValue).Get(t) } - case *PtrType: - a.eval = func(t *Thread) Value { return t.f.Get(level, index).(PtrValue).Get(t) } - case *FuncType: - a.eval = func(t *Thread) Func { return t.f.Get(level, index).(FuncValue).Get(t) } - case *SliceType: - a.eval = func(t *Thread) Slice { return t.f.Get(level, index).(SliceValue).Get(t) } - case *MapType: - a.eval = func(t *Thread) Map { return t.f.Get(level, index).(MapValue).Get(t) } - default: - log.Panicf("unexpected identifier type %v at %v", a.t, a.pos) - } -} - -func (a *expr) genFuncCall(call func(t *Thread) []Value) { - a.exec = func(t *Thread) { call(t) } - switch a.t.lit().(type) { - case *boolType: - a.eval = func(t *Thread) bool { return call(t)[0].(BoolValue).Get(t) } - case *uintType: - a.eval = func(t *Thread) uint64 { return call(t)[0].(UintValue).Get(t) } - case *intType: - a.eval = func(t *Thread) int64 { return call(t)[0].(IntValue).Get(t) } - case *floatType: - a.eval = func(t *Thread) float64 { return call(t)[0].(FloatValue).Get(t) } - case *stringType: - a.eval = func(t *Thread) string { return call(t)[0].(StringValue).Get(t) } - case *ArrayType: - a.eval = func(t *Thread) ArrayValue { return call(t)[0].(ArrayValue).Get(t) } - case *StructType: - a.eval = func(t *Thread) StructValue { return call(t)[0].(StructValue).Get(t) } - case *PtrType: - a.eval = func(t *Thread) Value { return call(t)[0].(PtrValue).Get(t) } - case *FuncType: - a.eval = func(t *Thread) Func { return call(t)[0].(FuncValue).Get(t) } - case *SliceType: - a.eval = func(t *Thread) Slice { return call(t)[0].(SliceValue).Get(t) } - case *MapType: - a.eval = func(t *Thread) Map { return call(t)[0].(MapValue).Get(t) } - case *MultiType: - a.eval = func(t *Thread) []Value { return call(t) } - default: - log.Panicf("unexpected result type %v at %v", a.t, a.pos) - } -} - -func (a *expr) genValue(vf func(*Thread) Value) { - a.evalAddr = vf - switch a.t.lit().(type) { - case *boolType: - a.eval = func(t *Thread) bool { return vf(t).(BoolValue).Get(t) } - case *uintType: - a.eval = func(t *Thread) uint64 { return vf(t).(UintValue).Get(t) } - case *intType: - a.eval = func(t *Thread) int64 { return vf(t).(IntValue).Get(t) } - case *floatType: - a.eval = func(t *Thread) float64 { return vf(t).(FloatValue).Get(t) } - case *stringType: - a.eval = func(t *Thread) string { return vf(t).(StringValue).Get(t) } - case *ArrayType: - a.eval = func(t *Thread) ArrayValue { return vf(t).(ArrayValue).Get(t) } - case *StructType: - a.eval = func(t *Thread) StructValue { return vf(t).(StructValue).Get(t) } - case *PtrType: - a.eval = func(t *Thread) Value { return vf(t).(PtrValue).Get(t) } - case *FuncType: - a.eval = func(t *Thread) Func { return vf(t).(FuncValue).Get(t) } - case *SliceType: - a.eval = func(t *Thread) Slice { return vf(t).(SliceValue).Get(t) } - case *MapType: - a.eval = func(t *Thread) Map { return vf(t).(MapValue).Get(t) } - default: - log.Panicf("unexpected result type %v at %v", a.t, a.pos) - } -} - -func (a *expr) genUnaryOpNeg(v *expr) { - switch a.t.lit().(type) { - case *uintType: - vf := v.asUint() - a.eval = func(t *Thread) uint64 { v := vf(t); return -v } - case *intType: - vf := v.asInt() - a.eval = func(t *Thread) int64 { v := vf(t); return -v } - case *idealIntType: - val := v.asIdealInt()() - val.Neg(val) - a.eval = func() *big.Int { return val } - case *floatType: - vf := v.asFloat() - a.eval = func(t *Thread) float64 { v := vf(t); return -v } - case *idealFloatType: - val := v.asIdealFloat()() - val.Neg(val) - a.eval = func() *big.Rat { return val } - default: - log.Panicf("unexpected type %v at %v", a.t, a.pos) - } -} - -func (a *expr) genUnaryOpNot(v *expr) { - switch a.t.lit().(type) { - case *boolType: - vf := v.asBool() - a.eval = func(t *Thread) bool { v := vf(t); return !v } - default: - log.Panicf("unexpected type %v at %v", a.t, a.pos) - } -} - -func (a *expr) genUnaryOpXor(v *expr) { - switch a.t.lit().(type) { - case *uintType: - vf := v.asUint() - a.eval = func(t *Thread) uint64 { v := vf(t); return ^v } - case *intType: - vf := v.asInt() - a.eval = func(t *Thread) int64 { v := vf(t); return ^v } - case *idealIntType: - val := v.asIdealInt()() - val.Not(val) - a.eval = func() *big.Int { return val } - default: - log.Panicf("unexpected type %v at %v", a.t, a.pos) - } -} - -func (a *expr) genBinOpLogAnd(l, r *expr) { - lf := l.asBool() - rf := r.asBool() - a.eval = func(t *Thread) bool { return lf(t) && rf(t) } -} - -func (a *expr) genBinOpLogOr(l, r *expr) { - lf := l.asBool() - rf := r.asBool() - a.eval = func(t *Thread) bool { return lf(t) || rf(t) } -} - -func (a *expr) genBinOpAdd(l, r *expr) { - switch t := l.t.lit().(type) { - case *uintType: - lf := l.asUint() - rf := r.asUint() - switch t.Bits { - case 8: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l + r - return uint64(uint8(ret)) - } - case 16: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l + r - return uint64(uint16(ret)) - } - case 32: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l + r - return uint64(uint32(ret)) - } - case 64: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l + r - return uint64(uint64(ret)) - } - case 0: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l + r - return uint64(uint(ret)) - } - default: - log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) - } - case *intType: - lf := l.asInt() - rf := r.asInt() - switch t.Bits { - case 8: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l + r - return int64(int8(ret)) - } - case 16: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l + r - return int64(int16(ret)) - } - case 32: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l + r - return int64(int32(ret)) - } - case 64: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l + r - return int64(int64(ret)) - } - case 0: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l + r - return int64(int(ret)) - } - default: - log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) - } - case *idealIntType: - l := l.asIdealInt()() - r := r.asIdealInt()() - val := l.Add(l, r) - a.eval = func() *big.Int { return val } - case *floatType: - lf := l.asFloat() - rf := r.asFloat() - switch t.Bits { - case 32: - a.eval = func(t *Thread) float64 { - l, r := lf(t), rf(t) - var ret float64 - ret = l + r - return float64(float32(ret)) - } - case 64: - a.eval = func(t *Thread) float64 { - l, r := lf(t), rf(t) - var ret float64 - ret = l + r - return float64(float64(ret)) - } - default: - log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) - } - case *idealFloatType: - l := l.asIdealFloat()() - r := r.asIdealFloat()() - val := l.Add(l, r) - a.eval = func() *big.Rat { return val } - case *stringType: - lf := l.asString() - rf := r.asString() - a.eval = func(t *Thread) string { - l, r := lf(t), rf(t) - return l + r - } - default: - log.Panicf("unexpected type %v at %v", l.t, a.pos) - } -} - -func (a *expr) genBinOpSub(l, r *expr) { - switch t := l.t.lit().(type) { - case *uintType: - lf := l.asUint() - rf := r.asUint() - switch t.Bits { - case 8: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l - r - return uint64(uint8(ret)) - } - case 16: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l - r - return uint64(uint16(ret)) - } - case 32: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l - r - return uint64(uint32(ret)) - } - case 64: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l - r - return uint64(uint64(ret)) - } - case 0: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l - r - return uint64(uint(ret)) - } - default: - log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) - } - case *intType: - lf := l.asInt() - rf := r.asInt() - switch t.Bits { - case 8: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l - r - return int64(int8(ret)) - } - case 16: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l - r - return int64(int16(ret)) - } - case 32: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l - r - return int64(int32(ret)) - } - case 64: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l - r - return int64(int64(ret)) - } - case 0: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l - r - return int64(int(ret)) - } - default: - log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) - } - case *idealIntType: - l := l.asIdealInt()() - r := r.asIdealInt()() - val := l.Sub(l, r) - a.eval = func() *big.Int { return val } - case *floatType: - lf := l.asFloat() - rf := r.asFloat() - switch t.Bits { - case 32: - a.eval = func(t *Thread) float64 { - l, r := lf(t), rf(t) - var ret float64 - ret = l - r - return float64(float32(ret)) - } - case 64: - a.eval = func(t *Thread) float64 { - l, r := lf(t), rf(t) - var ret float64 - ret = l - r - return float64(float64(ret)) - } - default: - log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) - } - case *idealFloatType: - l := l.asIdealFloat()() - r := r.asIdealFloat()() - val := l.Sub(l, r) - a.eval = func() *big.Rat { return val } - default: - log.Panicf("unexpected type %v at %v", l.t, a.pos) - } -} - -func (a *expr) genBinOpMul(l, r *expr) { - switch t := l.t.lit().(type) { - case *uintType: - lf := l.asUint() - rf := r.asUint() - switch t.Bits { - case 8: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l * r - return uint64(uint8(ret)) - } - case 16: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l * r - return uint64(uint16(ret)) - } - case 32: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l * r - return uint64(uint32(ret)) - } - case 64: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l * r - return uint64(uint64(ret)) - } - case 0: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l * r - return uint64(uint(ret)) - } - default: - log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) - } - case *intType: - lf := l.asInt() - rf := r.asInt() - switch t.Bits { - case 8: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l * r - return int64(int8(ret)) - } - case 16: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l * r - return int64(int16(ret)) - } - case 32: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l * r - return int64(int32(ret)) - } - case 64: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l * r - return int64(int64(ret)) - } - case 0: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l * r - return int64(int(ret)) - } - default: - log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) - } - case *idealIntType: - l := l.asIdealInt()() - r := r.asIdealInt()() - val := l.Mul(l, r) - a.eval = func() *big.Int { return val } - case *floatType: - lf := l.asFloat() - rf := r.asFloat() - switch t.Bits { - case 32: - a.eval = func(t *Thread) float64 { - l, r := lf(t), rf(t) - var ret float64 - ret = l * r - return float64(float32(ret)) - } - case 64: - a.eval = func(t *Thread) float64 { - l, r := lf(t), rf(t) - var ret float64 - ret = l * r - return float64(float64(ret)) - } - default: - log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) - } - case *idealFloatType: - l := l.asIdealFloat()() - r := r.asIdealFloat()() - val := l.Mul(l, r) - a.eval = func() *big.Rat { return val } - default: - log.Panicf("unexpected type %v at %v", l.t, a.pos) - } -} - -func (a *expr) genBinOpQuo(l, r *expr) { - switch t := l.t.lit().(type) { - case *uintType: - lf := l.asUint() - rf := r.asUint() - switch t.Bits { - case 8: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - if r == 0 { - t.Abort(DivByZeroError{}) - } - ret = l / r - return uint64(uint8(ret)) - } - case 16: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - if r == 0 { - t.Abort(DivByZeroError{}) - } - ret = l / r - return uint64(uint16(ret)) - } - case 32: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - if r == 0 { - t.Abort(DivByZeroError{}) - } - ret = l / r - return uint64(uint32(ret)) - } - case 64: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - if r == 0 { - t.Abort(DivByZeroError{}) - } - ret = l / r - return uint64(uint64(ret)) - } - case 0: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - if r == 0 { - t.Abort(DivByZeroError{}) - } - ret = l / r - return uint64(uint(ret)) - } - default: - log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) - } - case *intType: - lf := l.asInt() - rf := r.asInt() - switch t.Bits { - case 8: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - if r == 0 { - t.Abort(DivByZeroError{}) - } - ret = l / r - return int64(int8(ret)) - } - case 16: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - if r == 0 { - t.Abort(DivByZeroError{}) - } - ret = l / r - return int64(int16(ret)) - } - case 32: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - if r == 0 { - t.Abort(DivByZeroError{}) - } - ret = l / r - return int64(int32(ret)) - } - case 64: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - if r == 0 { - t.Abort(DivByZeroError{}) - } - ret = l / r - return int64(int64(ret)) - } - case 0: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - if r == 0 { - t.Abort(DivByZeroError{}) - } - ret = l / r - return int64(int(ret)) - } - default: - log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) - } - case *idealIntType: - l := l.asIdealInt()() - r := r.asIdealInt()() - val := l.Quo(l, r) - a.eval = func() *big.Int { return val } - case *floatType: - lf := l.asFloat() - rf := r.asFloat() - switch t.Bits { - case 32: - a.eval = func(t *Thread) float64 { - l, r := lf(t), rf(t) - var ret float64 - if r == 0 { - t.Abort(DivByZeroError{}) - } - ret = l / r - return float64(float32(ret)) - } - case 64: - a.eval = func(t *Thread) float64 { - l, r := lf(t), rf(t) - var ret float64 - if r == 0 { - t.Abort(DivByZeroError{}) - } - ret = l / r - return float64(float64(ret)) - } - default: - log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) - } - case *idealFloatType: - l := l.asIdealFloat()() - r := r.asIdealFloat()() - val := l.Quo(l, r) - a.eval = func() *big.Rat { return val } - default: - log.Panicf("unexpected type %v at %v", l.t, a.pos) - } -} - -func (a *expr) genBinOpRem(l, r *expr) { - switch t := l.t.lit().(type) { - case *uintType: - lf := l.asUint() - rf := r.asUint() - switch t.Bits { - case 8: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - if r == 0 { - t.Abort(DivByZeroError{}) - } - ret = l % r - return uint64(uint8(ret)) - } - case 16: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - if r == 0 { - t.Abort(DivByZeroError{}) - } - ret = l % r - return uint64(uint16(ret)) - } - case 32: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - if r == 0 { - t.Abort(DivByZeroError{}) - } - ret = l % r - return uint64(uint32(ret)) - } - case 64: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - if r == 0 { - t.Abort(DivByZeroError{}) - } - ret = l % r - return uint64(uint64(ret)) - } - case 0: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - if r == 0 { - t.Abort(DivByZeroError{}) - } - ret = l % r - return uint64(uint(ret)) - } - default: - log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) - } - case *intType: - lf := l.asInt() - rf := r.asInt() - switch t.Bits { - case 8: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - if r == 0 { - t.Abort(DivByZeroError{}) - } - ret = l % r - return int64(int8(ret)) - } - case 16: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - if r == 0 { - t.Abort(DivByZeroError{}) - } - ret = l % r - return int64(int16(ret)) - } - case 32: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - if r == 0 { - t.Abort(DivByZeroError{}) - } - ret = l % r - return int64(int32(ret)) - } - case 64: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - if r == 0 { - t.Abort(DivByZeroError{}) - } - ret = l % r - return int64(int64(ret)) - } - case 0: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - if r == 0 { - t.Abort(DivByZeroError{}) - } - ret = l % r - return int64(int(ret)) - } - default: - log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) - } - case *idealIntType: - l := l.asIdealInt()() - r := r.asIdealInt()() - val := l.Rem(l, r) - a.eval = func() *big.Int { return val } - default: - log.Panicf("unexpected type %v at %v", l.t, a.pos) - } -} - -func (a *expr) genBinOpAnd(l, r *expr) { - switch t := l.t.lit().(type) { - case *uintType: - lf := l.asUint() - rf := r.asUint() - switch t.Bits { - case 8: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l & r - return uint64(uint8(ret)) - } - case 16: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l & r - return uint64(uint16(ret)) - } - case 32: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l & r - return uint64(uint32(ret)) - } - case 64: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l & r - return uint64(uint64(ret)) - } - case 0: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l & r - return uint64(uint(ret)) - } - default: - log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) - } - case *intType: - lf := l.asInt() - rf := r.asInt() - switch t.Bits { - case 8: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l & r - return int64(int8(ret)) - } - case 16: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l & r - return int64(int16(ret)) - } - case 32: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l & r - return int64(int32(ret)) - } - case 64: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l & r - return int64(int64(ret)) - } - case 0: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l & r - return int64(int(ret)) - } - default: - log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) - } - case *idealIntType: - l := l.asIdealInt()() - r := r.asIdealInt()() - val := l.And(l, r) - a.eval = func() *big.Int { return val } - default: - log.Panicf("unexpected type %v at %v", l.t, a.pos) - } -} - -func (a *expr) genBinOpOr(l, r *expr) { - switch t := l.t.lit().(type) { - case *uintType: - lf := l.asUint() - rf := r.asUint() - switch t.Bits { - case 8: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l | r - return uint64(uint8(ret)) - } - case 16: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l | r - return uint64(uint16(ret)) - } - case 32: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l | r - return uint64(uint32(ret)) - } - case 64: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l | r - return uint64(uint64(ret)) - } - case 0: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l | r - return uint64(uint(ret)) - } - default: - log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) - } - case *intType: - lf := l.asInt() - rf := r.asInt() - switch t.Bits { - case 8: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l | r - return int64(int8(ret)) - } - case 16: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l | r - return int64(int16(ret)) - } - case 32: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l | r - return int64(int32(ret)) - } - case 64: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l | r - return int64(int64(ret)) - } - case 0: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l | r - return int64(int(ret)) - } - default: - log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) - } - case *idealIntType: - l := l.asIdealInt()() - r := r.asIdealInt()() - val := l.Or(l, r) - a.eval = func() *big.Int { return val } - default: - log.Panicf("unexpected type %v at %v", l.t, a.pos) - } -} - -func (a *expr) genBinOpXor(l, r *expr) { - switch t := l.t.lit().(type) { - case *uintType: - lf := l.asUint() - rf := r.asUint() - switch t.Bits { - case 8: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l ^ r - return uint64(uint8(ret)) - } - case 16: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l ^ r - return uint64(uint16(ret)) - } - case 32: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l ^ r - return uint64(uint32(ret)) - } - case 64: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l ^ r - return uint64(uint64(ret)) - } - case 0: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l ^ r - return uint64(uint(ret)) - } - default: - log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) - } - case *intType: - lf := l.asInt() - rf := r.asInt() - switch t.Bits { - case 8: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l ^ r - return int64(int8(ret)) - } - case 16: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l ^ r - return int64(int16(ret)) - } - case 32: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l ^ r - return int64(int32(ret)) - } - case 64: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l ^ r - return int64(int64(ret)) - } - case 0: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l ^ r - return int64(int(ret)) - } - default: - log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) - } - case *idealIntType: - l := l.asIdealInt()() - r := r.asIdealInt()() - val := l.Xor(l, r) - a.eval = func() *big.Int { return val } - default: - log.Panicf("unexpected type %v at %v", l.t, a.pos) - } -} - -func (a *expr) genBinOpAndNot(l, r *expr) { - switch t := l.t.lit().(type) { - case *uintType: - lf := l.asUint() - rf := r.asUint() - switch t.Bits { - case 8: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l &^ r - return uint64(uint8(ret)) - } - case 16: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l &^ r - return uint64(uint16(ret)) - } - case 32: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l &^ r - return uint64(uint32(ret)) - } - case 64: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l &^ r - return uint64(uint64(ret)) - } - case 0: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l &^ r - return uint64(uint(ret)) - } - default: - log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) - } - case *intType: - lf := l.asInt() - rf := r.asInt() - switch t.Bits { - case 8: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l &^ r - return int64(int8(ret)) - } - case 16: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l &^ r - return int64(int16(ret)) - } - case 32: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l &^ r - return int64(int32(ret)) - } - case 64: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l &^ r - return int64(int64(ret)) - } - case 0: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l &^ r - return int64(int(ret)) - } - default: - log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) - } - case *idealIntType: - l := l.asIdealInt()() - r := r.asIdealInt()() - val := l.AndNot(l, r) - a.eval = func() *big.Int { return val } - default: - log.Panicf("unexpected type %v at %v", l.t, a.pos) - } -} - -func (a *expr) genBinOpShl(l, r *expr) { - switch t := l.t.lit().(type) { - case *uintType: - lf := l.asUint() - rf := r.asUint() - switch t.Bits { - case 8: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l << r - return uint64(uint8(ret)) - } - case 16: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l << r - return uint64(uint16(ret)) - } - case 32: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l << r - return uint64(uint32(ret)) - } - case 64: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l << r - return uint64(uint64(ret)) - } - case 0: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l << r - return uint64(uint(ret)) - } - default: - log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) - } - case *intType: - lf := l.asInt() - rf := r.asUint() - switch t.Bits { - case 8: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l << r - return int64(int8(ret)) - } - case 16: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l << r - return int64(int16(ret)) - } - case 32: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l << r - return int64(int32(ret)) - } - case 64: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l << r - return int64(int64(ret)) - } - case 0: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l << r - return int64(int(ret)) - } - default: - log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) - } - default: - log.Panicf("unexpected type %v at %v", l.t, a.pos) - } -} - -func (a *expr) genBinOpShr(l, r *expr) { - switch t := l.t.lit().(type) { - case *uintType: - lf := l.asUint() - rf := r.asUint() - switch t.Bits { - case 8: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l >> r - return uint64(uint8(ret)) - } - case 16: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l >> r - return uint64(uint16(ret)) - } - case 32: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l >> r - return uint64(uint32(ret)) - } - case 64: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l >> r - return uint64(uint64(ret)) - } - case 0: - a.eval = func(t *Thread) uint64 { - l, r := lf(t), rf(t) - var ret uint64 - ret = l >> r - return uint64(uint(ret)) - } - default: - log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) - } - case *intType: - lf := l.asInt() - rf := r.asUint() - switch t.Bits { - case 8: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l >> r - return int64(int8(ret)) - } - case 16: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l >> r - return int64(int16(ret)) - } - case 32: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l >> r - return int64(int32(ret)) - } - case 64: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l >> r - return int64(int64(ret)) - } - case 0: - a.eval = func(t *Thread) int64 { - l, r := lf(t), rf(t) - var ret int64 - ret = l >> r - return int64(int(ret)) - } - default: - log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos) - } - default: - log.Panicf("unexpected type %v at %v", l.t, a.pos) - } -} - -func (a *expr) genBinOpLss(l, r *expr) { - switch t := l.t.lit().(type) { - case *uintType: - lf := l.asUint() - rf := r.asUint() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l < r - } - case *intType: - lf := l.asInt() - rf := r.asInt() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l < r - } - case *idealIntType: - l := l.asIdealInt()() - r := r.asIdealInt()() - val := l.Cmp(r) < 0 - a.eval = func(t *Thread) bool { return val } - case *floatType: - lf := l.asFloat() - rf := r.asFloat() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l < r - } - case *idealFloatType: - l := l.asIdealFloat()() - r := r.asIdealFloat()() - val := l.Cmp(r) < 0 - a.eval = func(t *Thread) bool { return val } - case *stringType: - lf := l.asString() - rf := r.asString() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l < r - } - default: - log.Panicf("unexpected type %v at %v", l.t, a.pos) - } -} - -func (a *expr) genBinOpGtr(l, r *expr) { - switch t := l.t.lit().(type) { - case *uintType: - lf := l.asUint() - rf := r.asUint() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l > r - } - case *intType: - lf := l.asInt() - rf := r.asInt() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l > r - } - case *idealIntType: - l := l.asIdealInt()() - r := r.asIdealInt()() - val := l.Cmp(r) > 0 - a.eval = func(t *Thread) bool { return val } - case *floatType: - lf := l.asFloat() - rf := r.asFloat() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l > r - } - case *idealFloatType: - l := l.asIdealFloat()() - r := r.asIdealFloat()() - val := l.Cmp(r) > 0 - a.eval = func(t *Thread) bool { return val } - case *stringType: - lf := l.asString() - rf := r.asString() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l > r - } - default: - log.Panicf("unexpected type %v at %v", l.t, a.pos) - } -} - -func (a *expr) genBinOpLeq(l, r *expr) { - switch t := l.t.lit().(type) { - case *uintType: - lf := l.asUint() - rf := r.asUint() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l <= r - } - case *intType: - lf := l.asInt() - rf := r.asInt() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l <= r - } - case *idealIntType: - l := l.asIdealInt()() - r := r.asIdealInt()() - val := l.Cmp(r) <= 0 - a.eval = func(t *Thread) bool { return val } - case *floatType: - lf := l.asFloat() - rf := r.asFloat() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l <= r - } - case *idealFloatType: - l := l.asIdealFloat()() - r := r.asIdealFloat()() - val := l.Cmp(r) <= 0 - a.eval = func(t *Thread) bool { return val } - case *stringType: - lf := l.asString() - rf := r.asString() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l <= r - } - default: - log.Panicf("unexpected type %v at %v", l.t, a.pos) - } -} - -func (a *expr) genBinOpGeq(l, r *expr) { - switch t := l.t.lit().(type) { - case *uintType: - lf := l.asUint() - rf := r.asUint() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l >= r - } - case *intType: - lf := l.asInt() - rf := r.asInt() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l >= r - } - case *idealIntType: - l := l.asIdealInt()() - r := r.asIdealInt()() - val := l.Cmp(r) >= 0 - a.eval = func(t *Thread) bool { return val } - case *floatType: - lf := l.asFloat() - rf := r.asFloat() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l >= r - } - case *idealFloatType: - l := l.asIdealFloat()() - r := r.asIdealFloat()() - val := l.Cmp(r) >= 0 - a.eval = func(t *Thread) bool { return val } - case *stringType: - lf := l.asString() - rf := r.asString() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l >= r - } - default: - log.Panicf("unexpected type %v at %v", l.t, a.pos) - } -} - -func (a *expr) genBinOpEql(l, r *expr) { - switch t := l.t.lit().(type) { - case *boolType: - lf := l.asBool() - rf := r.asBool() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l == r - } - case *uintType: - lf := l.asUint() - rf := r.asUint() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l == r - } - case *intType: - lf := l.asInt() - rf := r.asInt() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l == r - } - case *idealIntType: - l := l.asIdealInt()() - r := r.asIdealInt()() - val := l.Cmp(r) == 0 - a.eval = func(t *Thread) bool { return val } - case *floatType: - lf := l.asFloat() - rf := r.asFloat() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l == r - } - case *idealFloatType: - l := l.asIdealFloat()() - r := r.asIdealFloat()() - val := l.Cmp(r) == 0 - a.eval = func(t *Thread) bool { return val } - case *stringType: - lf := l.asString() - rf := r.asString() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l == r - } - case *PtrType: - lf := l.asPtr() - rf := r.asPtr() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l == r - } - case *FuncType: - lf := l.asFunc() - rf := r.asFunc() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l == r - } - case *MapType: - lf := l.asMap() - rf := r.asMap() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l == r - } - default: - log.Panicf("unexpected type %v at %v", l.t, a.pos) - } -} - -func (a *expr) genBinOpNeq(l, r *expr) { - switch t := l.t.lit().(type) { - case *boolType: - lf := l.asBool() - rf := r.asBool() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l != r - } - case *uintType: - lf := l.asUint() - rf := r.asUint() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l != r - } - case *intType: - lf := l.asInt() - rf := r.asInt() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l != r - } - case *idealIntType: - l := l.asIdealInt()() - r := r.asIdealInt()() - val := l.Cmp(r) != 0 - a.eval = func(t *Thread) bool { return val } - case *floatType: - lf := l.asFloat() - rf := r.asFloat() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l != r - } - case *idealFloatType: - l := l.asIdealFloat()() - r := r.asIdealFloat()() - val := l.Cmp(r) != 0 - a.eval = func(t *Thread) bool { return val } - case *stringType: - lf := l.asString() - rf := r.asString() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l != r - } - case *PtrType: - lf := l.asPtr() - rf := r.asPtr() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l != r - } - case *FuncType: - lf := l.asFunc() - rf := r.asFunc() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l != r - } - case *MapType: - lf := l.asMap() - rf := r.asMap() - a.eval = func(t *Thread) bool { - l, r := lf(t), rf(t) - return l != r - } - default: - log.Panicf("unexpected type %v at %v", l.t, a.pos) - } -} - -func genAssign(lt Type, r *expr) func(lv Value, t *Thread) { - switch lt.lit().(type) { - case *boolType: - rf := r.asBool() - return func(lv Value, t *Thread) { lv.(BoolValue).Set(t, rf(t)) } - case *uintType: - rf := r.asUint() - return func(lv Value, t *Thread) { lv.(UintValue).Set(t, rf(t)) } - case *intType: - rf := r.asInt() - return func(lv Value, t *Thread) { lv.(IntValue).Set(t, rf(t)) } - case *floatType: - rf := r.asFloat() - return func(lv Value, t *Thread) { lv.(FloatValue).Set(t, rf(t)) } - case *stringType: - rf := r.asString() - return func(lv Value, t *Thread) { lv.(StringValue).Set(t, rf(t)) } - case *ArrayType: - rf := r.asArray() - return func(lv Value, t *Thread) { lv.Assign(t, rf(t)) } - case *StructType: - rf := r.asStruct() - return func(lv Value, t *Thread) { lv.Assign(t, rf(t)) } - case *PtrType: - rf := r.asPtr() - return func(lv Value, t *Thread) { lv.(PtrValue).Set(t, rf(t)) } - case *FuncType: - rf := r.asFunc() - return func(lv Value, t *Thread) { lv.(FuncValue).Set(t, rf(t)) } - case *SliceType: - rf := r.asSlice() - return func(lv Value, t *Thread) { lv.(SliceValue).Set(t, rf(t)) } - case *MapType: - rf := r.asMap() - return func(lv Value, t *Thread) { lv.(MapValue).Set(t, rf(t)) } - default: - log.Panicf("unexpected left operand type %v at %v", lt, r.pos) - } - panic("fail") -} diff --git a/libgo/go/exp/eval/expr_test.go b/libgo/go/exp/eval/expr_test.go deleted file mode 100644 index 0dbce43..0000000 --- a/libgo/go/exp/eval/expr_test.go +++ /dev/null @@ -1,355 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package eval - -import ( - "big" - "testing" -) - -var undefined = "undefined" -var typeAsExpr = "type .* used as expression" -var badCharLit = "character literal" -var unknownEscape = "unknown escape sequence" -var opTypes = "illegal (operand|argument) type|cannot index into" -var badAddrOf = "cannot take the address" -var constantTruncated = "constant [^ ]* truncated" -var constantUnderflows = "constant [^ ]* underflows" -var constantOverflows = "constant [^ ]* overflows" -var implLimit = "implementation limit" -var mustBeUnsigned = "must be unsigned" -var divByZero = "divide by zero" - -var hugeInteger = new(big.Int).Lsh(idealOne, 64) - -var exprTests = []test{ - Val("i", 1), - CErr("zzz", undefined), - // TODO(austin) Test variable in constant context - //CErr("t", typeAsExpr), - - Val("'a'", big.NewInt('a')), - Val("'\\uffff'", big.NewInt('\uffff')), - Val("'\\n'", big.NewInt('\n')), - CErr("''+x", badCharLit), - // Produces two parse errors - //CErr("'''", ""), - CErr("'\n'", badCharLit), - CErr("'\\z'", unknownEscape), - CErr("'ab'", badCharLit), - - Val("1.0", big.NewRat(1, 1)), - Val("1.", big.NewRat(1, 1)), - Val(".1", big.NewRat(1, 10)), - Val("1e2", big.NewRat(100, 1)), - - Val("\"abc\"", "abc"), - Val("\"\"", ""), - Val("\"\\n\\\"\"", "\n\""), - CErr("\"\\z\"", unknownEscape), - CErr("\"abc", "string not terminated"), - - Val("(i)", 1), - - Val("ai[0]", 1), - Val("(&ai)[0]", 1), - Val("ai[1]", 2), - Val("ai[i]", 2), - Val("ai[u]", 2), - CErr("ai[f]", opTypes), - CErr("ai[0][0]", opTypes), - CErr("ai[2]", "index 2 exceeds"), - CErr("ai[1+1]", "index 2 exceeds"), - CErr("ai[-1]", "negative index"), - RErr("ai[i+i]", "index 2 exceeds"), - RErr("ai[-i]", "negative index"), - CErr("i[0]", opTypes), - CErr("f[0]", opTypes), - - Val("aai[0][0]", 1), - Val("aai[1][1]", 4), - CErr("aai[2][0]", "index 2 exceeds"), - CErr("aai[0][2]", "index 2 exceeds"), - - Val("sli[0]", 1), - Val("sli[1]", 2), - CErr("sli[-1]", "negative index"), - RErr("sli[-i]", "negative index"), - RErr("sli[2]", "index 2 exceeds"), - - Val("s[0]", uint8('a')), - Val("s[1]", uint8('b')), - CErr("s[-1]", "negative index"), - RErr("s[-i]", "negative index"), - RErr("s[3]", "index 3 exceeds"), - - Val("ai[0:2]", vslice{varray{1, 2}, 2, 2}), - Val("ai[0:1]", vslice{varray{1, 2}, 1, 2}), - Val("ai[0:]", vslice{varray{1, 2}, 2, 2}), - Val("ai[i:]", vslice{varray{2}, 1, 1}), - - Val("sli[0:2]", vslice{varray{1, 2, 3}, 2, 3}), - Val("sli[0:i]", vslice{varray{1, 2, 3}, 1, 3}), - Val("sli[1:]", vslice{varray{2, 3}, 1, 2}), - - CErr("1(2)", "cannot call"), - CErr("fn(1,2)", "too many"), - CErr("fn()", "not enough"), - CErr("fn(true)", opTypes), - CErr("fn(true)", "function call"), - // Single argument functions don't say which argument. - //CErr("fn(true)", "argument 1"), - Val("fn(1)", 2), - Val("fn(1.0)", 2), - CErr("fn(1.5)", constantTruncated), - Val("fn(i)", 2), - CErr("fn(u)", opTypes), - - CErr("void()+2", opTypes), - CErr("oneTwo()+2", opTypes), - - Val("cap(ai)", 2), - Val("cap(&ai)", 2), - Val("cap(aai)", 2), - Val("cap(sli)", 3), - CErr("cap(0)", opTypes), - CErr("cap(i)", opTypes), - CErr("cap(s)", opTypes), - - Val("len(s)", 3), - Val("len(ai)", 2), - Val("len(&ai)", 2), - Val("len(ai[0:])", 2), - Val("len(ai[1:])", 1), - Val("len(ai[2:])", 0), - Val("len(aai)", 2), - Val("len(sli)", 2), - Val("len(sli[0:])", 2), - Val("len(sli[1:])", 1), - Val("len(sli[2:])", 0), - // TODO(austin) Test len of map - CErr("len(0)", opTypes), - CErr("len(i)", opTypes), - - CErr("*i", opTypes), - Val("*&i", 1), - Val("*&(i)", 1), - CErr("&1", badAddrOf), - CErr("&c", badAddrOf), - Val("*(&ai[0])", 1), - - Val("+1", big.NewInt(+1)), - Val("+1.0", big.NewRat(1, 1)), - Val("01.5", big.NewRat(15, 10)), - CErr("+\"x\"", opTypes), - - Val("-42", big.NewInt(-42)), - Val("-i", -1), - Val("-f", -1.0), - // 6g bug? - //Val("-(f-1)", -0.0), - CErr("-\"x\"", opTypes), - - // TODO(austin) Test unary ! - - Val("^2", big.NewInt(^2)), - Val("^(-2)", big.NewInt(^(-2))), - CErr("^2.0", opTypes), - CErr("^2.5", opTypes), - Val("^i", ^1), - Val("^u", ^uint(1)), - CErr("^f", opTypes), - - Val("1+i", 2), - Val("1+u", uint(2)), - Val("3.0+i", 4), - Val("1+1", big.NewInt(2)), - Val("f+f", 2.0), - Val("1+f", 2.0), - Val("1.0+1", big.NewRat(2, 1)), - Val("\"abc\" + \"def\"", "abcdef"), - CErr("i+u", opTypes), - CErr("-1+u", constantUnderflows), - // TODO(austin) Test named types - - Val("2-1", big.NewInt(1)), - Val("2.0-1", big.NewRat(1, 1)), - Val("f-2", -1.0), - Val("-0.0", big.NewRat(0, 1)), - Val("2*2", big.NewInt(4)), - Val("2*i", 2), - Val("3/2", big.NewInt(1)), - Val("3/i", 3), - CErr("1/0", divByZero), - CErr("1.0/0", divByZero), - RErr("i/0", divByZero), - Val("3%2", big.NewInt(1)), - Val("i%2", 1), - CErr("3%0", divByZero), - CErr("3.0%0", opTypes), - RErr("i%0", divByZero), - - // Examples from "Arithmetic operators" - Val("5/3", big.NewInt(1)), - Val("(i+4)/(i+2)", 1), - Val("5%3", big.NewInt(2)), - Val("(i+4)%(i+2)", 2), - Val("-5/3", big.NewInt(-1)), - Val("(i-6)/(i+2)", -1), - Val("-5%3", big.NewInt(-2)), - Val("(i-6)%(i+2)", -2), - Val("5/-3", big.NewInt(-1)), - Val("(i+4)/(i-4)", -1), - Val("5%-3", big.NewInt(2)), - Val("(i+4)%(i-4)", 2), - Val("-5/-3", big.NewInt(1)), - Val("(i-6)/(i-4)", 1), - Val("-5%-3", big.NewInt(-2)), - Val("(i-6)%(i-4)", -2), - - // Examples from "Arithmetic operators" - Val("11/4", big.NewInt(2)), - Val("(i+10)/4", 2), - Val("11%4", big.NewInt(3)), - Val("(i+10)%4", 3), - Val("11>>2", big.NewInt(2)), - Val("(i+10)>>2", 2), - Val("11&3", big.NewInt(3)), - Val("(i+10)&3", 3), - Val("-11/4", big.NewInt(-2)), - Val("(i-12)/4", -2), - Val("-11%4", big.NewInt(-3)), - Val("(i-12)%4", -3), - Val("-11>>2", big.NewInt(-3)), - Val("(i-12)>>2", -3), - Val("-11&3", big.NewInt(1)), - Val("(i-12)&3", 1), - - // TODO(austin) Test bit ops - - // For shift, we try nearly every combination of positive - // ideal int, negative ideal int, big ideal int, ideal - // fractional float, ideal non-fractional float, int, uint, - // and float. - Val("2<<2", big.NewInt(2<<2)), - CErr("2<<(-1)", constantUnderflows), - CErr("2<<0x10000000000000000", constantOverflows), - CErr("2<<2.5", constantTruncated), - Val("2<<2.0", big.NewInt(2<<2.0)), - CErr("2<, >= - Val("1<2", 1 < 2), - Val("1<=2", 1 <= 2), - Val("2<=2", 2 <= 2), - Val("1>2", 1 > 2), - Val("1>=2", 1 >= 2), - Val("2>=2", 2 >= 2), - - Val("i<2", 1 < 2), - Val("i<=2", 1 <= 2), - Val("i+1<=2", 2 <= 2), - Val("i>2", 1 > 2), - Val("i>=2", 1 >= 2), - Val("i+1>=2", 2 >= 2), - - Val("u<2", 1 < 2), - Val("f<2", 1 < 2), - - Val("s<\"b\"", true), - Val("s<\"a\"", false), - Val("s<=\"abc\"", true), - Val("s>\"aa\"", true), - Val("s>\"ac\"", false), - Val("s>=\"abc\"", true), - - CErr("i= b.scope.maxVars { - b.scope.maxVars = index + 1 - } - } - v := &Variable{token.NoPos, index, t, nil} - return v -} - -func (b *block) DefineConst(name string, pos token.Pos, t Type, v Value) (*Constant, Def) { - if prev, ok := b.defs[name]; ok { - return nil, prev - } - c := &Constant{pos, t, v} - b.defs[name] = c - return c, nil -} - -func (b *block) DefineType(name string, pos token.Pos, t Type) Type { - if _, ok := b.defs[name]; ok { - return nil - } - nt := &NamedType{pos, name, nil, true, make(map[string]Method)} - if t != nil { - nt.Complete(t) - } - b.defs[name] = nt - return nt -} - -func (b *block) Lookup(name string) (bl *block, level int, def Def) { - for b != nil { - if d, ok := b.defs[name]; ok { - return b, level, d - } - if b.outer != nil && b.scope != b.outer.scope { - level++ - } - b = b.outer - } - return nil, 0, nil -} - -func (s *Scope) NewFrame(outer *Frame) *Frame { return outer.child(s.maxVars) } - -/* - * Frames - */ - -type Frame struct { - Outer *Frame - Vars []Value -} - -func (f *Frame) Get(level int, index int) Value { - for ; level > 0; level-- { - f = f.Outer - } - return f.Vars[index] -} - -func (f *Frame) child(numVars int) *Frame { - // TODO(austin) This is probably rather expensive. All values - // require heap allocation and zeroing them when we execute a - // definition typically requires some computation. - return &Frame{f, make([]Value, numVars)} -} diff --git a/libgo/go/exp/eval/stmt.go b/libgo/go/exp/eval/stmt.go deleted file mode 100644 index f6b7c1c..0000000 --- a/libgo/go/exp/eval/stmt.go +++ /dev/null @@ -1,1299 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package eval - -import ( - "big" - "log" - "go/ast" - "go/token" -) - -const ( - returnPC = ^uint(0) - badPC = ^uint(1) -) - -/* - * Statement compiler - */ - -type stmtCompiler struct { - *blockCompiler - pos token.Pos - // This statement's label, or nil if it is not labeled. - stmtLabel *label -} - -func (a *stmtCompiler) diag(format string, args ...interface{}) { - a.diagAt(a.pos, format, args...) -} - -/* - * Flow checker - */ - -type flowEnt struct { - // Whether this flow entry is conditional. If true, flow can - // continue to the next PC. - cond bool - // True if this will terminate flow (e.g., a return statement). - // cond must be false and jumps must be nil if this is true. - term bool - // PC's that can be reached from this flow entry. - jumps []*uint - // Whether this flow entry has been visited by reachesEnd. - visited bool -} - -type flowBlock struct { - // If this is a goto, the target label. - target string - // The inner-most block containing definitions. - block *block - // The numVars from each block leading to the root of the - // scope, starting at block. - numVars []int -} - -type flowBuf struct { - cb *codeBuf - // ents is a map from PC's to flow entries. Any PC missing - // from this map is assumed to reach only PC+1. - ents map[uint]*flowEnt - // gotos is a map from goto positions to information on the - // block at the point of the goto. - gotos map[token.Pos]*flowBlock - // labels is a map from label name to information on the block - // at the point of the label. labels are tracked by name, - // since mutliple labels at the same PC can have different - // blocks. - labels map[string]*flowBlock -} - -func newFlowBuf(cb *codeBuf) *flowBuf { - return &flowBuf{cb, make(map[uint]*flowEnt), make(map[token.Pos]*flowBlock), make(map[string]*flowBlock)} -} - -// put creates a flow control point for the next PC in the code buffer. -// This should be done before pushing the instruction into the code buffer. -func (f *flowBuf) put(cond bool, term bool, jumps []*uint) { - pc := f.cb.nextPC() - if ent, ok := f.ents[pc]; ok { - log.Panicf("Flow entry already exists at PC %d: %+v", pc, ent) - } - f.ents[pc] = &flowEnt{cond, term, jumps, false} -} - -// putTerm creates a flow control point at the next PC that -// unconditionally terminates execution. -func (f *flowBuf) putTerm() { f.put(false, true, nil) } - -// put1 creates a flow control point at the next PC that jumps to one -// PC and, if cond is true, can also continue to the PC following the -// next PC. -func (f *flowBuf) put1(cond bool, jumpPC *uint) { - f.put(cond, false, []*uint{jumpPC}) -} - -func newFlowBlock(target string, b *block) *flowBlock { - // Find the inner-most block containing definitions - for b.numVars == 0 && b.outer != nil && b.outer.scope == b.scope { - b = b.outer - } - - // Count parents leading to the root of the scope - n := 0 - for bp := b; bp.scope == b.scope; bp = bp.outer { - n++ - } - - // Capture numVars from each block to the root of the scope - numVars := make([]int, n) - i := 0 - for bp := b; i < n; bp = bp.outer { - numVars[i] = bp.numVars - i++ - } - - return &flowBlock{target, b, numVars} -} - -// putGoto captures the block at a goto statement. This should be -// called in addition to putting a flow control point. -func (f *flowBuf) putGoto(pos token.Pos, target string, b *block) { - f.gotos[pos] = newFlowBlock(target, b) -} - -// putLabel captures the block at a label. -func (f *flowBuf) putLabel(name string, b *block) { - f.labels[name] = newFlowBlock("", b) -} - -// reachesEnd returns true if the end of f's code buffer can be -// reached from the given program counter. Error reporting is the -// caller's responsibility. -func (f *flowBuf) reachesEnd(pc uint) bool { - endPC := f.cb.nextPC() - if pc > endPC { - log.Panicf("Reached bad PC %d past end PC %d", pc, endPC) - } - - for ; pc < endPC; pc++ { - ent, ok := f.ents[pc] - if !ok { - continue - } - - if ent.visited { - return false - } - ent.visited = true - - if ent.term { - return false - } - - // If anything can reach the end, we can reach the end - // from pc. - for _, j := range ent.jumps { - if f.reachesEnd(*j) { - return true - } - } - // If the jump was conditional, we can reach the next - // PC, so try reaching the end from it. - if ent.cond { - continue - } - return false - } - return true -} - -// gotosObeyScopes returns true if no goto statement causes any -// variables to come into scope that were not in scope at the point of -// the goto. Reports any errors using the given compiler. -func (f *flowBuf) gotosObeyScopes(a *compiler) { - for pos, src := range f.gotos { - tgt := f.labels[src.target] - - // The target block must be a parent of this block - numVars := src.numVars - b := src.block - for len(numVars) > 0 && b != tgt.block { - b = b.outer - numVars = numVars[1:] - } - if b != tgt.block { - // We jumped into a deeper block - a.diagAt(pos, "goto causes variables to come into scope") - return - } - - // There must be no variables in the target block that - // did not exist at the jump - tgtNumVars := tgt.numVars - for i := range numVars { - if tgtNumVars[i] > numVars[i] { - a.diagAt(pos, "goto causes variables to come into scope") - return - } - } - } -} - -/* - * Statement generation helpers - */ - -func (a *stmtCompiler) defineVar(ident *ast.Ident, t Type) *Variable { - v, prev := a.block.DefineVar(ident.Name, ident.Pos(), t) - if prev != nil { - if prev.Pos().IsValid() { - a.diagAt(ident.Pos(), "variable %s redeclared in this block\n\tprevious declaration at %s", ident.Name, a.fset.Position(prev.Pos())) - } else { - a.diagAt(ident.Pos(), "variable %s redeclared in this block", ident.Name) - } - return nil - } - - // Initialize the variable - index := v.Index - if v.Index >= 0 { - a.push(func(v *Thread) { v.f.Vars[index] = t.Zero() }) - } - return v -} - -// TODO(austin) Move doAssign to here - -/* - * Statement compiler - */ - -func (a *stmtCompiler) compile(s ast.Stmt) { - if a.block.inner != nil { - log.Panic("Child scope still entered") - } - - notimpl := false - switch s := s.(type) { - case *ast.BadStmt: - // Error already reported by parser. - a.silentErrors++ - - case *ast.DeclStmt: - a.compileDeclStmt(s) - - case *ast.EmptyStmt: - // Do nothing. - - case *ast.LabeledStmt: - a.compileLabeledStmt(s) - - case *ast.ExprStmt: - a.compileExprStmt(s) - - case *ast.IncDecStmt: - a.compileIncDecStmt(s) - - case *ast.AssignStmt: - a.compileAssignStmt(s) - - case *ast.GoStmt: - notimpl = true - - case *ast.DeferStmt: - notimpl = true - - case *ast.ReturnStmt: - a.compileReturnStmt(s) - - case *ast.BranchStmt: - a.compileBranchStmt(s) - - case *ast.BlockStmt: - a.compileBlockStmt(s) - - case *ast.IfStmt: - a.compileIfStmt(s) - - case *ast.CaseClause: - a.diag("case clause outside switch") - - case *ast.SwitchStmt: - a.compileSwitchStmt(s) - - case *ast.TypeSwitchStmt: - notimpl = true - - case *ast.CommClause: - notimpl = true - - case *ast.SelectStmt: - notimpl = true - - case *ast.ForStmt: - a.compileForStmt(s) - - case *ast.RangeStmt: - notimpl = true - - default: - log.Panicf("unexpected ast node type %T", s) - } - - if notimpl { - a.diag("%T statment node not implemented", s) - } - - if a.block.inner != nil { - log.Panic("Forgot to exit child scope") - } -} - -func (a *stmtCompiler) compileDeclStmt(s *ast.DeclStmt) { - switch decl := s.Decl.(type) { - case *ast.BadDecl: - // Do nothing. Already reported by parser. - a.silentErrors++ - - case *ast.FuncDecl: - if !a.block.global { - log.Panic("FuncDecl at statement level") - } - - case *ast.GenDecl: - if decl.Tok == token.IMPORT && !a.block.global { - log.Panic("import at statement level") - } - - default: - log.Panicf("Unexpected Decl type %T", s.Decl) - } - a.compileDecl(s.Decl) -} - -func (a *stmtCompiler) compileVarDecl(decl *ast.GenDecl) { - for _, spec := range decl.Specs { - spec := spec.(*ast.ValueSpec) - if spec.Values == nil { - // Declaration without assignment - if spec.Type == nil { - // Parser should have caught - log.Panic("Type and Values nil") - } - t := a.compileType(a.block, spec.Type) - // Define placeholders even if type compile failed - for _, n := range spec.Names { - a.defineVar(n, t) - } - } else { - // Declaration with assignment - lhs := make([]ast.Expr, len(spec.Names)) - for i, n := range spec.Names { - lhs[i] = n - } - a.doAssign(lhs, spec.Values, decl.Tok, spec.Type) - } - } -} - -func (a *stmtCompiler) compileDecl(decl ast.Decl) { - switch d := decl.(type) { - case *ast.BadDecl: - // Do nothing. Already reported by parser. - a.silentErrors++ - - case *ast.FuncDecl: - decl := a.compileFuncType(a.block, d.Type) - if decl == nil { - return - } - // Declare and initialize v before compiling func - // so that body can refer to itself. - c, prev := a.block.DefineConst(d.Name.Name, a.pos, decl.Type, decl.Type.Zero()) - if prev != nil { - pos := prev.Pos() - if pos.IsValid() { - a.diagAt(d.Name.Pos(), "identifier %s redeclared in this block\n\tprevious declaration at %s", d.Name.Name, a.fset.Position(pos)) - } else { - a.diagAt(d.Name.Pos(), "identifier %s redeclared in this block", d.Name.Name) - } - } - fn := a.compileFunc(a.block, decl, d.Body) - if c == nil || fn == nil { - return - } - var zeroThread Thread - c.Value.(FuncValue).Set(nil, fn(&zeroThread)) - - case *ast.GenDecl: - switch d.Tok { - case token.IMPORT: - log.Panicf("%v not implemented", d.Tok) - case token.CONST: - log.Panicf("%v not implemented", d.Tok) - case token.TYPE: - a.compileTypeDecl(a.block, d) - case token.VAR: - a.compileVarDecl(d) - } - - default: - log.Panicf("Unexpected Decl type %T", decl) - } -} - -func (a *stmtCompiler) compileLabeledStmt(s *ast.LabeledStmt) { - // Define label - l, ok := a.labels[s.Label.Name] - if ok { - if l.resolved.IsValid() { - a.diag("label %s redeclared in this block\n\tprevious declaration at %s", s.Label.Name, a.fset.Position(l.resolved)) - } - } else { - pc := badPC - l = &label{name: s.Label.Name, gotoPC: &pc} - a.labels[l.name] = l - } - l.desc = "regular label" - l.resolved = s.Pos() - - // Set goto PC - *l.gotoPC = a.nextPC() - - // Define flow entry so we can check for jumps over declarations. - a.flow.putLabel(l.name, a.block) - - // Compile the statement. Reuse our stmtCompiler for simplicity. - sc := &stmtCompiler{a.blockCompiler, s.Stmt.Pos(), l} - sc.compile(s.Stmt) -} - -func (a *stmtCompiler) compileExprStmt(s *ast.ExprStmt) { - bc := a.enterChild() - defer bc.exit() - - e := a.compileExpr(bc.block, false, s.X) - if e == nil { - return - } - - if e.exec == nil { - a.diag("%s cannot be used as expression statement", e.desc) - return - } - - a.push(e.exec) -} - -func (a *stmtCompiler) compileIncDecStmt(s *ast.IncDecStmt) { - // Create temporary block for extractEffect - bc := a.enterChild() - defer bc.exit() - - l := a.compileExpr(bc.block, false, s.X) - if l == nil { - return - } - - if l.evalAddr == nil { - l.diag("cannot assign to %s", l.desc) - return - } - if !(l.t.isInteger() || l.t.isFloat()) { - l.diagOpType(s.Tok, l.t) - return - } - - var op token.Token - var desc string - switch s.Tok { - case token.INC: - op = token.ADD - desc = "increment statement" - case token.DEC: - op = token.SUB - desc = "decrement statement" - default: - log.Panicf("Unexpected IncDec token %v", s.Tok) - } - - effect, l := l.extractEffect(bc.block, desc) - - one := l.newExpr(IdealIntType, "constant") - one.pos = s.Pos() - one.eval = func() *big.Int { return big.NewInt(1) } - - binop := l.compileBinaryExpr(op, l, one) - if binop == nil { - return - } - - assign := a.compileAssign(s.Pos(), bc.block, l.t, []*expr{binop}, "", "") - if assign == nil { - log.Panicf("compileAssign type check failed") - } - - lf := l.evalAddr - a.push(func(v *Thread) { - effect(v) - assign(lf(v), v) - }) -} - -func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token, declTypeExpr ast.Expr) { - nerr := a.numError() - - // Compile right side first so we have the types when - // compiling the left side and so we don't see definitions - // made on the left side. - rs := make([]*expr, len(rhs)) - for i, re := range rhs { - rs[i] = a.compileExpr(a.block, false, re) - } - - errOp := "assignment" - if tok == token.DEFINE || tok == token.VAR { - errOp = "declaration" - } - ac, ok := a.checkAssign(a.pos, rs, errOp, "value") - ac.allowMapForms(len(lhs)) - - // If this is a definition and the LHS is too big, we won't be - // able to produce the usual error message because we can't - // begin to infer the types of the LHS. - if (tok == token.DEFINE || tok == token.VAR) && len(lhs) > len(ac.rmt.Elems) { - a.diag("not enough values for definition") - } - - // Compile left type if there is one - var declType Type - if declTypeExpr != nil { - declType = a.compileType(a.block, declTypeExpr) - } - - // Compile left side - ls := make([]*expr, len(lhs)) - nDefs := 0 - for i, le := range lhs { - // If this is a definition, get the identifier and its type - var ident *ast.Ident - var lt Type - switch tok { - case token.DEFINE: - // Check that it's an identifier - ident, ok = le.(*ast.Ident) - if !ok { - a.diagAt(le.Pos(), "left side of := must be a name") - // Suppress new defitions errors - nDefs++ - continue - } - - // Is this simply an assignment? - if _, ok := a.block.defs[ident.Name]; ok { - ident = nil - break - } - nDefs++ - - case token.VAR: - ident = le.(*ast.Ident) - } - - // If it's a definition, get or infer its type. - if ident != nil { - // Compute the identifier's type from the RHS - // type. We use the computed MultiType so we - // don't have to worry about unpacking. - switch { - case declTypeExpr != nil: - // We have a declaration type, use it. - // If declType is nil, we gave an - // error when we compiled it. - lt = declType - - case i >= len(ac.rmt.Elems): - // Define a placeholder. We already - // gave the "not enough" error above. - lt = nil - - case ac.rmt.Elems[i] == nil: - // We gave the error when we compiled - // the RHS. - lt = nil - - case ac.rmt.Elems[i].isIdeal(): - // If the type is absent and the - // corresponding expression is a - // constant expression of ideal - // integer or ideal float type, the - // type of the declared variable is - // int or float respectively. - switch { - case ac.rmt.Elems[i].isInteger(): - lt = IntType - case ac.rmt.Elems[i].isFloat(): - lt = Float64Type - default: - log.Panicf("unexpected ideal type %v", rs[i].t) - } - - default: - lt = ac.rmt.Elems[i] - } - } - - // If it's a definition, define the identifier - if ident != nil { - if a.defineVar(ident, lt) == nil { - continue - } - } - - // Compile LHS - ls[i] = a.compileExpr(a.block, false, le) - if ls[i] == nil { - continue - } - - if ls[i].evalMapValue != nil { - // Map indexes are not generally addressable, - // but they are assignable. - // - // TODO(austin) Now that the expression - // compiler uses semantic values, this might - // be easier to implement as a function call. - sub := ls[i] - ls[i] = ls[i].newExpr(sub.t, sub.desc) - ls[i].evalMapValue = sub.evalMapValue - mvf := sub.evalMapValue - et := sub.t - ls[i].evalAddr = func(t *Thread) Value { - m, k := mvf(t) - e := m.Elem(t, k) - if e == nil { - e = et.Zero() - m.SetElem(t, k, e) - } - return e - } - } else if ls[i].evalAddr == nil { - ls[i].diag("cannot assign to %s", ls[i].desc) - continue - } - } - - // 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 variables is - // new. - if tok == token.DEFINE && nDefs == 0 { - a.diag("at least one new variable must be declared") - return - } - - // If there have been errors, our arrays are full of nil's so - // get out of here now. - if nerr != a.numError() { - return - } - - // Check for 'a[x] = r, ok' - if len(ls) == 1 && len(rs) == 2 && ls[0].evalMapValue != nil { - a.diag("a[x] = r, ok form not implemented") - return - } - - // Create assigner - var lt Type - n := len(lhs) - if n == 1 { - lt = ls[0].t - } else { - lts := make([]Type, len(ls)) - for i, l := range ls { - if l != nil { - lts[i] = l.t - } - } - lt = NewMultiType(lts) - } - bc := a.enterChild() - defer bc.exit() - assign := ac.compile(bc.block, lt) - if assign == nil { - return - } - - // Compile - if n == 1 { - // Don't need temporaries and can avoid []Value. - lf := ls[0].evalAddr - a.push(func(t *Thread) { assign(lf(t), t) }) - } else if tok == token.VAR || (tok == token.DEFINE && nDefs == n) { - // Don't need temporaries - lfs := make([]func(*Thread) Value, n) - for i, l := range ls { - lfs[i] = l.evalAddr - } - a.push(func(t *Thread) { - dest := make([]Value, n) - for i, lf := range lfs { - dest[i] = lf(t) - } - assign(multiV(dest), t) - }) - } else { - // Need temporaries - lmt := lt.(*MultiType) - lfs := make([]func(*Thread) Value, n) - for i, l := range ls { - lfs[i] = l.evalAddr - } - a.push(func(t *Thread) { - temp := lmt.Zero().(multiV) - assign(temp, t) - // Copy to destination - for i := 0; i < n; i++ { - // TODO(austin) Need to evaluate LHS - // before RHS - lfs[i](t).Assign(t, temp[i]) - } - }) - } -} - -var assignOpToOp = map[token.Token]token.Token{ - token.ADD_ASSIGN: token.ADD, - token.SUB_ASSIGN: token.SUB, - token.MUL_ASSIGN: token.MUL, - token.QUO_ASSIGN: token.QUO, - token.REM_ASSIGN: token.REM, - - token.AND_ASSIGN: token.AND, - token.OR_ASSIGN: token.OR, - token.XOR_ASSIGN: token.XOR, - token.SHL_ASSIGN: token.SHL, - token.SHR_ASSIGN: token.SHR, - token.AND_NOT_ASSIGN: token.AND_NOT, -} - -func (a *stmtCompiler) doAssignOp(s *ast.AssignStmt) { - if len(s.Lhs) != 1 || len(s.Rhs) != 1 { - a.diag("tuple assignment cannot be combined with an arithmetic operation") - return - } - - // Create temporary block for extractEffect - bc := a.enterChild() - defer bc.exit() - - l := a.compileExpr(bc.block, false, s.Lhs[0]) - r := a.compileExpr(bc.block, false, s.Rhs[0]) - if l == nil || r == nil { - return - } - - if l.evalAddr == nil { - l.diag("cannot assign to %s", l.desc) - return - } - - effect, l := l.extractEffect(bc.block, "operator-assignment") - - binop := r.compileBinaryExpr(assignOpToOp[s.Tok], l, r) - if binop == nil { - return - } - - assign := a.compileAssign(s.Pos(), bc.block, l.t, []*expr{binop}, "assignment", "value") - if assign == nil { - log.Panicf("compileAssign type check failed") - } - - lf := l.evalAddr - a.push(func(t *Thread) { - effect(t) - assign(lf(t), t) - }) -} - -func (a *stmtCompiler) compileAssignStmt(s *ast.AssignStmt) { - switch s.Tok { - case token.ASSIGN, token.DEFINE: - a.doAssign(s.Lhs, s.Rhs, s.Tok, nil) - - default: - a.doAssignOp(s) - } -} - -func (a *stmtCompiler) compileReturnStmt(s *ast.ReturnStmt) { - if a.fnType == nil { - a.diag("cannot return at the top level") - return - } - - if len(s.Results) == 0 && (len(a.fnType.Out) == 0 || a.outVarsNamed) { - // Simple case. Simply exit from the function. - a.flow.putTerm() - a.push(func(v *Thread) { v.pc = returnPC }) - return - } - - bc := a.enterChild() - defer bc.exit() - - // Compile expressions - bad := false - rs := make([]*expr, len(s.Results)) - for i, re := range s.Results { - rs[i] = a.compileExpr(bc.block, false, re) - if rs[i] == nil { - bad = true - } - } - if bad { - return - } - - // Create assigner - - // However, if the expression list in the "return" statement - // is a single call to a multi-valued function, the values - // returned from the called function will be returned from - // this one. - assign := a.compileAssign(s.Pos(), bc.block, NewMultiType(a.fnType.Out), rs, "return", "value") - - // XXX(Spec) "The result types of the current function and the - // called function must match." Match is fuzzy. It should - // say that they must be assignment compatible. - - // Compile - start := len(a.fnType.In) - nout := len(a.fnType.Out) - a.flow.putTerm() - a.push(func(t *Thread) { - assign(multiV(t.f.Vars[start:start+nout]), t) - t.pc = returnPC - }) -} - -func (a *stmtCompiler) findLexicalLabel(name *ast.Ident, pred func(*label) bool, errOp, errCtx string) *label { - bc := a.blockCompiler - for ; bc != nil; bc = bc.parent { - if bc.label == nil { - continue - } - l := bc.label - if name == nil && pred(l) { - return l - } - if name != nil && l.name == name.Name { - if !pred(l) { - a.diag("cannot %s to %s %s", errOp, l.desc, l.name) - return nil - } - return l - } - } - if name == nil { - a.diag("%s outside %s", errOp, errCtx) - } else { - a.diag("%s label %s not defined", errOp, name.Name) - } - return nil -} - -func (a *stmtCompiler) compileBranchStmt(s *ast.BranchStmt) { - var pc *uint - - switch s.Tok { - case token.BREAK: - l := a.findLexicalLabel(s.Label, func(l *label) bool { return l.breakPC != nil }, "break", "for loop, switch, or select") - if l == nil { - return - } - pc = l.breakPC - - case token.CONTINUE: - l := a.findLexicalLabel(s.Label, func(l *label) bool { return l.continuePC != nil }, "continue", "for loop") - if l == nil { - return - } - pc = l.continuePC - - case token.GOTO: - l, ok := a.labels[s.Label.Name] - if !ok { - pc := badPC - l = &label{name: s.Label.Name, desc: "unresolved label", gotoPC: &pc, used: s.Pos()} - a.labels[l.name] = l - } - - pc = l.gotoPC - a.flow.putGoto(s.Pos(), l.name, a.block) - - case token.FALLTHROUGH: - a.diag("fallthrough outside switch") - return - - default: - log.Panicf("Unexpected branch token %v", s.Tok) - } - - a.flow.put1(false, pc) - a.push(func(v *Thread) { v.pc = *pc }) -} - -func (a *stmtCompiler) compileBlockStmt(s *ast.BlockStmt) { - bc := a.enterChild() - bc.compileStmts(s) - bc.exit() -} - -func (a *stmtCompiler) compileIfStmt(s *ast.IfStmt) { - // The scope of any variables declared by [the init] statement - // extends to the end of the "if" statement and the variables - // are initialized once before the statement is entered. - // - // XXX(Spec) What this really wants to say is that there's an - // implicit scope wrapping every if, for, and switch - // statement. This is subtly different from what it actually - // says when there's a non-block else clause, because that - // else claus has to execute in a scope that is *not* the - // surrounding scope. - bc := a.enterChild() - defer bc.exit() - - // Compile init statement, if any - if s.Init != nil { - bc.compileStmt(s.Init) - } - - elsePC := badPC - endPC := badPC - - // Compile condition, if any. If there is no condition, we - // fall through to the body. - if s.Cond != nil { - e := bc.compileExpr(bc.block, false, s.Cond) - switch { - case e == nil: - // Error reported by compileExpr - case !e.t.isBoolean(): - e.diag("'if' condition must be boolean\n\t%v", e.t) - default: - eval := e.asBool() - a.flow.put1(true, &elsePC) - a.push(func(t *Thread) { - if !eval(t) { - t.pc = elsePC - } - }) - } - } - - // Compile body - body := bc.enterChild() - body.compileStmts(s.Body) - body.exit() - - // Compile else - if s.Else != nil { - // Skip over else if we executed the body - a.flow.put1(false, &endPC) - a.push(func(v *Thread) { v.pc = endPC }) - elsePC = a.nextPC() - bc.compileStmt(s.Else) - } else { - elsePC = a.nextPC() - } - endPC = a.nextPC() -} - -func (a *stmtCompiler) compileSwitchStmt(s *ast.SwitchStmt) { - // Create implicit scope around switch - bc := a.enterChild() - defer bc.exit() - - // Compile init statement, if any - if s.Init != nil { - bc.compileStmt(s.Init) - } - - // Compile condition, if any, and extract its effects - var cond *expr - condbc := bc.enterChild() - if s.Tag != nil { - e := condbc.compileExpr(condbc.block, false, s.Tag) - if e != nil { - var effect func(*Thread) - effect, cond = e.extractEffect(condbc.block, "switch") - a.push(effect) - } - } - - // Count cases - ncases := 0 - hasDefault := false - for _, c := range s.Body.List { - clause, ok := c.(*ast.CaseClause) - if !ok { - a.diagAt(clause.Pos(), "switch statement must contain case clauses") - continue - } - if clause.List == nil { - if hasDefault { - a.diagAt(clause.Pos(), "switch statement contains more than one default case") - } - hasDefault = true - } else { - ncases += len(clause.List) - } - } - - // Compile case expressions - cases := make([]func(*Thread) bool, ncases) - i := 0 - for _, c := range s.Body.List { - clause, ok := c.(*ast.CaseClause) - if !ok { - continue - } - for _, v := range clause.List { - e := condbc.compileExpr(condbc.block, false, v) - switch { - case e == nil: - // Error reported by compileExpr - case cond == nil && !e.t.isBoolean(): - a.diagAt(v.Pos(), "'case' condition must be boolean") - case cond == nil: - cases[i] = e.asBool() - case cond != nil: - // Create comparison - // TOOD(austin) This produces bad error messages - compare := e.compileBinaryExpr(token.EQL, cond, e) - if compare != nil { - cases[i] = compare.asBool() - } - } - i++ - } - } - - // Emit condition - casePCs := make([]*uint, ncases+1) - endPC := badPC - - a.flow.put(false, false, casePCs) - a.push(func(t *Thread) { - for i, c := range cases { - if c(t) { - t.pc = *casePCs[i] - return - } - } - t.pc = *casePCs[ncases] - }) - condbc.exit() - - // Compile cases - i = 0 - for _, c := range s.Body.List { - clause, ok := c.(*ast.CaseClause) - if !ok { - continue - } - - // Save jump PC's - pc := a.nextPC() - if clause.List != nil { - for _ = range clause.List { - casePCs[i] = &pc - i++ - } - } else { - // Default clause - casePCs[ncases] = &pc - } - - // Compile body - fall := false - for j, s := range clause.Body { - if br, ok := s.(*ast.BranchStmt); ok && br.Tok == token.FALLTHROUGH { - // println("Found fallthrough"); - // It may be used only as the final - // non-empty statement in a case or - // default clause in an expression - // "switch" statement. - for _, s2 := range clause.Body[j+1:] { - // XXX(Spec) 6g also considers - // empty blocks to be empty - // statements. - if _, ok := s2.(*ast.EmptyStmt); !ok { - a.diagAt(s.Pos(), "fallthrough statement must be final statement in case") - break - } - } - fall = true - } else { - bc.compileStmt(s) - } - } - // Jump out of switch, unless there was a fallthrough - if !fall { - a.flow.put1(false, &endPC) - a.push(func(v *Thread) { v.pc = endPC }) - } - } - - // Get end PC - endPC = a.nextPC() - if !hasDefault { - casePCs[ncases] = &endPC - } -} - -func (a *stmtCompiler) compileForStmt(s *ast.ForStmt) { - // Wrap the entire for in a block. - bc := a.enterChild() - defer bc.exit() - - // Compile init statement, if any - if s.Init != nil { - bc.compileStmt(s.Init) - } - - bodyPC := badPC - postPC := badPC - checkPC := badPC - endPC := badPC - - // Jump to condition check. We generate slightly less code by - // placing the condition check after the body. - a.flow.put1(false, &checkPC) - a.push(func(v *Thread) { v.pc = checkPC }) - - // Compile body - bodyPC = a.nextPC() - body := bc.enterChild() - if a.stmtLabel != nil { - body.label = a.stmtLabel - } else { - body.label = &label{resolved: s.Pos()} - } - body.label.desc = "for loop" - body.label.breakPC = &endPC - body.label.continuePC = &postPC - body.compileStmts(s.Body) - body.exit() - - // Compile post, if any - postPC = a.nextPC() - if s.Post != nil { - // TODO(austin) Does the parser disallow short - // declarations in s.Post? - bc.compileStmt(s.Post) - } - - // Compile condition check, if any - checkPC = a.nextPC() - if s.Cond == nil { - // If the condition is absent, it is equivalent to true. - a.flow.put1(false, &bodyPC) - a.push(func(v *Thread) { v.pc = bodyPC }) - } else { - e := bc.compileExpr(bc.block, false, s.Cond) - switch { - case e == nil: - // Error reported by compileExpr - case !e.t.isBoolean(): - a.diag("'for' condition must be boolean\n\t%v", e.t) - default: - eval := e.asBool() - a.flow.put1(true, &bodyPC) - a.push(func(t *Thread) { - if eval(t) { - t.pc = bodyPC - } - }) - } - } - - endPC = a.nextPC() -} - -/* - * Block compiler - */ - -func (a *blockCompiler) compileStmt(s ast.Stmt) { - sc := &stmtCompiler{a, s.Pos(), nil} - sc.compile(s) -} - -func (a *blockCompiler) compileStmts(block *ast.BlockStmt) { - for _, sub := range block.List { - a.compileStmt(sub) - } -} - -func (a *blockCompiler) enterChild() *blockCompiler { - block := a.block.enterChild() - return &blockCompiler{ - funcCompiler: a.funcCompiler, - block: block, - parent: a, - } -} - -func (a *blockCompiler) exit() { a.block.exit() } - -/* - * Function compiler - */ - -func (a *compiler) compileFunc(b *block, decl *FuncDecl, body *ast.BlockStmt) func(*Thread) Func { - // Create body scope - // - // The scope of a parameter or result is the body of the - // corresponding function. - bodyScope := b.ChildScope() - defer bodyScope.exit() - for i, t := range decl.Type.In { - if decl.InNames[i] != nil { - bodyScope.DefineVar(decl.InNames[i].Name, decl.InNames[i].Pos(), t) - } else { - bodyScope.DefineTemp(t) - } - } - for i, t := range decl.Type.Out { - if decl.OutNames[i] != nil { - bodyScope.DefineVar(decl.OutNames[i].Name, decl.OutNames[i].Pos(), t) - } else { - bodyScope.DefineTemp(t) - } - } - - // Create block context - cb := newCodeBuf() - fc := &funcCompiler{ - compiler: a, - fnType: decl.Type, - outVarsNamed: len(decl.OutNames) > 0 && decl.OutNames[0] != nil, - codeBuf: cb, - flow: newFlowBuf(cb), - labels: make(map[string]*label), - } - bc := &blockCompiler{ - funcCompiler: fc, - block: bodyScope.block, - } - - // Compile body - nerr := a.numError() - bc.compileStmts(body) - fc.checkLabels() - if nerr != a.numError() { - return nil - } - - // Check that the body returned if necessary. We only check - // this if there were no errors compiling the body. - if len(decl.Type.Out) > 0 && fc.flow.reachesEnd(0) { - // XXX(Spec) Not specified. - a.diagAt(body.Rbrace, "function ends without a return statement") - return nil - } - - code := fc.get() - maxVars := bodyScope.maxVars - return func(t *Thread) Func { return &evalFunc{t.f, maxVars, code} } -} - -// Checks that labels were resolved and that all jumps obey scoping -// rules. Reports an error and set fc.err if any check fails. -func (a *funcCompiler) checkLabels() { - nerr := a.numError() - for _, l := range a.labels { - if !l.resolved.IsValid() { - a.diagAt(l.used, "label %s not defined", l.name) - } - } - if nerr != a.numError() { - // Don't check scopes if we have unresolved labels - return - } - - // Executing the "goto" statement must not cause any variables - // to come into scope that were not already in scope at the - // point of the goto. - a.flow.gotosObeyScopes(a.compiler) -} diff --git a/libgo/go/exp/eval/stmt_test.go b/libgo/go/exp/eval/stmt_test.go deleted file mode 100644 index a8a3e16..0000000 --- a/libgo/go/exp/eval/stmt_test.go +++ /dev/null @@ -1,343 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package eval - -import "testing" - -var atLeastOneDecl = "at least one new variable must be declared" - -var stmtTests = []test{ - // Short declarations - Val1("x := i", "x", 1), - Val1("x := f", "x", 1.0), - // Type defaulting - Val1("a := 42", "a", 42), - Val1("a := 1.0", "a", 1.0), - // Parallel assignment - Val2("a, b := 1, 2", "a", 1, "b", 2), - Val2("a, i := 1, 2", "a", 1, "i", 2), - CErr("a, i := 1, f", opTypes), - CErr("a, b := 1, 2, 3", "too many"), - CErr("a := 1, 2", "too many"), - CErr("a, b := 1", "not enough"), - // Mixed declarations - CErr("i := 1", atLeastOneDecl), - CErr("i, u := 1, 2", atLeastOneDecl), - Val2("i, x := 2, f", "i", 2, "x", 1.0), - // Various errors - CErr("1 := 2", "expected identifier"), - CErr("c, a := 1, 1", "cannot assign"), - // Unpacking - Val2("x, y := oneTwo()", "x", 1, "y", 2), - CErr("x := oneTwo()", "too many"), - CErr("x, y, z := oneTwo()", "not enough"), - CErr("x, y := oneTwo(), 2", "multi-valued"), - CErr("x := oneTwo()+2", opTypes), - // TOOD(austin) This error message is weird - CErr("x := void()", "not enough"), - // Placeholders - CErr("x := 1+\"x\"; i=x+1", opTypes), - - // Assignment - Val1("i = 2", "i", 2), - Val1("(i) = 2", "i", 2), - CErr("1 = 2", "cannot assign"), - CErr("1-1 = 2", "- expression"), - Val1("i = 2.0", "i", 2), - CErr("i = 2.2", constantTruncated), - CErr("u = -2", constantUnderflows), - CErr("i = f", opTypes), - CErr("i, u = 0, f", opTypes), - CErr("i, u = 0, f", "value 2"), - Val2("i, i2 = i2, i", "i", 2, "i2", 1), - CErr("c = 1", "cannot assign"), - - Val1("x := &i; *x = 2", "i", 2), - - Val1("ai[0] = 42", "ai", varray{42, 2}), - Val1("aai[1] = ai; ai[0] = 42", "aai", varray{varray{1, 2}, varray{1, 2}}), - Val1("aai = aai2", "aai", varray{varray{5, 6}, varray{7, 8}}), - - // Assignment conversions - Run("var sl []int; sl = &ai"), - CErr("type ST []int; type AT *[2]int; var x AT = &ai; var y ST = x", opTypes), - Run("type ST []int; var y ST = &ai"), - Run("type AT *[2]int; var x AT = &ai; var y []int = x"), - - // Op-assignment - Val1("i += 2", "i", 3), - Val("i", 1), - Val1("f += 2", "f", 3.0), - CErr("2 += 2", "cannot assign"), - CErr("i, j += 2", "cannot be combined"), - CErr("i += 2, 3", "cannot be combined"), - Val2("s2 := s; s += \"def\"", "s2", "abc", "s", "abcdef"), - CErr("s += 1", opTypes), - // Single evaluation - Val2("ai[func()int{i+=1;return 0}()] *= 3; i2 = ai[0]", "i", 2, "i2", 3), - - // Type declarations - // Identifiers - Run("type T int"), - CErr("type T x", "undefined"), - CErr("type T c", "constant"), - CErr("type T i", "variable"), - CErr("type T T", "recursive"), - CErr("type T x; type U T; var v U; v = 1", "undefined"), - // Pointer types - Run("type T *int"), - Run("type T *T"), - // Array types - Run("type T [5]int"), - Run("type T [c+42/2]int"), - Run("type T [2.0]int"), - CErr("type T [i]int", "constant expression"), - CErr("type T [2.5]int", constantTruncated), - CErr("type T [-1]int", "negative"), - CErr("type T [2]T", "recursive"), - // Struct types - Run("type T struct { a int; b int }"), - Run("type T struct { a int; int }"), - Run("type T struct { x *T }"), - Run("type T int; type U struct { T }"), - CErr("type T *int; type U struct { T }", "embedded.*pointer"), - CErr("type T *struct { T }", "embedded.*pointer"), - CErr("type T struct { a int; a int }", " a .*redeclared.*:1:17"), - CErr("type T struct { int; int }", "int .*redeclared.*:1:17"), - CErr("type T struct { int int; int }", "int .*redeclared.*:1:17"), - Run("type T struct { x *struct { T } }"), - CErr("type T struct { x struct { T } }", "recursive"), - CErr("type T struct { x }; type U struct { T }", "undefined"), - // Function types - Run("type T func()"), - Run("type T func(a, b int) int"), - Run("type T func(a, b int) (x int, y int)"), - Run("type T func(a, a int) (a int, a int)"), - Run("type T func(a, b int) (x, y int)"), - Run("type T func(int, int) (int, int)"), - CErr("type T func(x); type U T", "undefined"), - CErr("type T func(a T)", "recursive"), - // Interface types - Run("type T interface {x(a, b int) int}"), - Run("type T interface {x(a, b int) int}; type U interface {T; y(c int)}"), - CErr("type T interface {x(a int); x()}", "method x redeclared"), - CErr("type T interface {x()}; type U interface {T; x()}", "method x redeclared"), - CErr("type T int; type U interface {T}", "embedded type"), - // Parens - Run("type T (int)"), - - // Variable declarations - Val2("var x int", "i", 1, "x", 0), - Val1("var x = 1", "x", 1), - Val1("var x = 1.0", "x", 1.0), - Val1("var x int = 1.0", "x", 1), - // Placeholders - CErr("var x foo; x = 1", "undefined"), - CErr("var x foo = 1; x = 1", "undefined"), - // Redeclaration - CErr("var i, x int", " i .*redeclared"), - CErr("var x int; var x int", " x .*redeclared.*:1:5"), - - // Expression statements - CErr("x := func(){ 1-1 }", "expression statement"), - CErr("x := func(){ 1-1 }", "- expression"), - Val1("fn(2)", "i", 1), - - // IncDec statements - Val1("i++", "i", 2), - Val1("i--", "i", 0), - Val1("u++", "u", uint(2)), - Val1("u--", "u", uint(0)), - Val1("f++", "f", 2.0), - Val1("f--", "f", 0.0), - // Single evaluation - Val2("ai[func()int{i+=1;return 0}()]++; i2 = ai[0]", "i", 2, "i2", 2), - // Operand types - CErr("s++", opTypes), - CErr("s++", "'\\+\\+'"), - CErr("2++", "cannot assign"), - CErr("c++", "cannot assign"), - - // Function scoping - Val1("fn1 := func() { i=2 }; fn1()", "i", 2), - Val1("fn1 := func() { i:=2 }; fn1()", "i", 1), - Val2("fn1 := func() int { i=2; i:=3; i=4; return i }; x := fn1()", "i", 2, "x", 4), - - // Basic returns - CErr("fn1 := func() int {}", "return"), - Run("fn1 := func() {}"), - CErr("fn1 := func() (r int) {}", "return"), - Val1("fn1 := func() (r int) {return}; i = fn1()", "i", 0), - Val1("fn1 := func() (r int) {r = 2; return}; i = fn1()", "i", 2), - Val1("fn1 := func() (r int) {return 2}; i = fn1()", "i", 2), - Val1("fn1 := func(int) int {return 2}; i = fn1(1)", "i", 2), - - // Multi-valued returns - Val2("fn1 := func() (bool, int) {return true, 2}; x, y := fn1()", "x", true, "y", 2), - CErr("fn1 := func() int {return}", "not enough values"), - CErr("fn1 := func() int {return 1,2}", "too many values"), - CErr("fn1 := func() {return 1}", "too many values"), - CErr("fn1 := func() (int,int,int) {return 1,2}", "not enough values"), - Val2("fn1 := func() (int, int) {return oneTwo()}; x, y := fn1()", "x", 1, "y", 2), - CErr("fn1 := func() int {return oneTwo()}", "too many values"), - CErr("fn1 := func() (int,int,int) {return oneTwo()}", "not enough values"), - Val1("fn1 := func(x,y int) int {return x+y}; x := fn1(oneTwo())", "x", 3), - - // Return control flow - Val2("fn1 := func(x *int) bool { *x = 2; return true; *x = 3; }; x := fn1(&i)", "i", 2, "x", true), - - // Break/continue/goto/fallthrough - CErr("break", "outside"), - CErr("break foo", "break.*foo.*not defined"), - CErr("continue", "outside"), - CErr("continue foo", "continue.*foo.*not defined"), - CErr("fallthrough", "outside"), - CErr("goto foo", "foo.*not defined"), - CErr(" foo: foo:;", "foo.*redeclared.*:1:2"), - Val1("i+=2; goto L; i+=4; L: i+=8", "i", 1+2+8), - // Return checking - CErr("fn1 := func() int { goto L; return 1; L: }", "return"), - Run("fn1 := func() int { L: goto L; i = 2 }"), - Run("fn1 := func() int { return 1; L: goto L }"), - // Scope checking - Run("fn1 := func() { { L: x:=1 }; goto L }"), - CErr("fn1 := func() { { x:=1; L: }; goto L }", "into scope"), - CErr("fn1 := func() { goto L; x:=1; L: }", "into scope"), - Run("fn1 := func() { goto L; { L: x:=1 } }"), - CErr("fn1 := func() { goto L; { x:=1; L: } }", "into scope"), - - // Blocks - CErr("fn1 := func() int {{}}", "return"), - Val1("fn1 := func() bool { { return true } }; b := fn1()", "b", true), - - // If - Val2("if true { i = 2 } else { i = 3 }; i2 = 4", "i", 2, "i2", 4), - Val2("if false { i = 2 } else { i = 3 }; i2 = 4", "i", 3, "i2", 4), - Val2("if i == i2 { i = 2 } else { i = 3 }; i2 = 4", "i", 3, "i2", 4), - // Omit optional parts - Val2("if true { i = 2 } else { i = 3 }; i2 = 4", "i", 2, "i2", 4), - Val2("if true { i = 2 }; i2 = 4", "i", 2, "i2", 4), - Val2("if false { i = 2 }; i2 = 4", "i", 1, "i2", 4), - // Init - Val2("if x := true; x { i = 2 } else { i = 3 }; i2 = 4", "i", 2, "i2", 4), - Val2("if x := false; x { i = 2 } else { i = 3 }; i2 = 4", "i", 3, "i2", 4), - // Statement else - Val2("if true { i = 2 } else i = 3; i2 = 4", "i", 2, "i2", 4), - Val2("if false { i = 2 } else i = 3; i2 = 4", "i", 3, "i2", 4), - // Scoping - Val2("if true { i := 2 } else { i := 3 }; i2 = i", "i", 1, "i2", 1), - Val2("if false { i := 2 } else { i := 3 }; i2 = i", "i", 1, "i2", 1), - Val2("if false { i := 2 } else i := 3; i2 = i", "i", 1, "i2", 1), - CErr("if true { x := 2 }; x = 4", undefined), - Val2("if i := 2; true { i2 = i; i := 3 }", "i", 1, "i2", 2), - Val2("if i := 2; false {} else { i2 = i; i := 3 }", "i", 1, "i2", 2), - // Return checking - Run("fn1 := func() int { if true { return 1 } else { return 2 } }"), - Run("fn1 := func() int { if true { return 1 } else return 2 }"), - CErr("fn1 := func() int { if true { return 1 } else { } }", "return"), - CErr("fn1 := func() int { if true { } else { return 1 } }", "return"), - CErr("fn1 := func() int { if true { } else return 1 }", "return"), - CErr("fn1 := func() int { if true { } else { } }", "return"), - CErr("fn1 := func() int { if true { return 1 } }", "return"), - CErr("fn1 := func() int { if true { } }", "return"), - Run("fn1 := func() int { if true { }; return 1 }"), - CErr("fn1 := func() int { if true { } }", "return"), - CErr("fn1 := func() int { if true { } else { return 2 } }", "return"), - Run("fn1 := func() int { if true { return 1 }; return 0 }"), - Run("fn1 := func() int { if true { return 1 } else { }; return 0 }"), - Run("fn1 := func() int { if true { return 1 } else { }; return 0 }"), - - // Switch - Val1("switch { case false: i += 2; case true: i += 4; default: i += 8 }", "i", 1+4), - Val1("switch { default: i += 2; case false: i += 4; case true: i += 8 }", "i", 1+8), - CErr("switch { default: i += 2; default: i += 4 }", "more than one"), - Val1("switch false { case false: i += 2; case true: i += 4; default: i += 8 }", "i", 1+2), - CErr("switch s { case 1: }", opTypes), - CErr("switch ai { case ai: i += 2 }", opTypes), - Val1("switch 1.0 { case 1: i += 2; case 2: i += 4 }", "i", 1+2), - Val1("switch 1.5 { case 1: i += 2; case 2: i += 4 }", "i", 1), - CErr("switch oneTwo() {}", "multi-valued expression"), - Val1("switch 2 { case 1: i += 2; fallthrough; case 2: i += 4; fallthrough; case 3: i += 8; fallthrough }", "i", 1+4+8), - Val1("switch 5 { case 1: i += 2; fallthrough; default: i += 4; fallthrough; case 2: i += 8; fallthrough; case 3: i += 16; fallthrough }", "i", 1+4+8+16), - CErr("switch { case true: fallthrough; i += 2 }", "final statement"), - Val1("switch { case true: i += 2; fallthrough; ; ; case false: i += 4 }", "i", 1+2+4), - Val1("switch 2 { case 0, 1: i += 2; case 2, 3: i += 4 }", "i", 1+4), - Val2("switch func()int{i2++;return 5}() { case 1, 2: i += 2; case 4, 5: i += 4 }", "i", 1+4, "i2", 3), - Run("switch i { case i: }"), - // TODO(austin) Why doesn't this fail? - //CErr("case 1:", "XXX"), - - // For - Val2("for x := 1; x < 5; x++ { i+=x }; i2 = 4", "i", 11, "i2", 4), - Val2("for x := 1; x < 5; x++ { i+=x; break; i++ }; i2 = 4", "i", 2, "i2", 4), - Val2("for x := 1; x < 5; x++ { i+=x; continue; i++ }; i2 = 4", "i", 11, "i2", 4), - Val2("for i = 2; false; i = 3 { i = 4 }; i2 = 4", "i", 2, "i2", 4), - Val2("for i < 5 { i++ }; i2 = 4", "i", 5, "i2", 4), - Val2("for i < 0 { i++ }; i2 = 4", "i", 1, "i2", 4), - // Scoping - Val2("for i := 2; true; { i2 = i; i := 3; break }", "i", 1, "i2", 2), - // Labeled break/continue - Val1("L1: for { L2: for { i+=2; break L1; i+=4 }; i+=8 }", "i", 1+2), - Val1("L1: for { L2: for { i+=2; break L2; i+=4 }; i+=8; break; i+=16 }", "i", 1+2+8), - CErr("L1: { for { break L1 } }", "break.*not defined"), - CErr("L1: for {}; for { break L1 }", "break.*not defined"), - CErr("L1:; for { break L1 }", "break.*not defined"), - Val2("L1: for i = 0; i < 2; i++ { L2: for { i2++; continue L1; i2++ } }", "i", 2, "i2", 4), - CErr("L1: { for { continue L1 } }", "continue.*not defined"), - CErr("L1:; for { continue L1 }", "continue.*not defined"), - // Return checking - Run("fn1 := func() int{ for {} }"), - CErr("fn1 := func() int{ for true {} }", "return"), - CErr("fn1 := func() int{ for true {return 1} }", "return"), - CErr("fn1 := func() int{ for {break} }", "return"), - Run("fn1 := func() int{ for { for {break} } }"), - CErr("fn1 := func() int{ L1: for { for {break L1} } }", "return"), - Run("fn1 := func() int{ for true {}; return 1 }"), - - // Selectors - Val1("var x struct { a int; b int }; x.a = 42; i = x.a", "i", 42), - Val1("type T struct { x int }; var y struct { T }; y.x = 42; i = y.x", "i", 42), - Val2("type T struct { x int }; var y struct { T; x int }; y.x = 42; i = y.x; i2 = y.T.x", "i", 42, "i2", 0), - Run("type T struct { x int }; var y struct { *T }; a := func(){i=y.x}"), - CErr("type T struct { x int }; var x T; x.y = 42", "no field"), - CErr("type T struct { x int }; type U struct { x int }; var y struct { T; U }; y.x = 42", "ambiguous.*\tT\\.x\n\tU\\.x"), - CErr("type T struct { *T }; var x T; x.foo", "no field"), - - Val1("fib := func(int) int{return 0;}; fib = func(v int) int { if v < 2 { return 1 }; return fib(v-1)+fib(v-2) }; i = fib(20)", "i", 10946), - - // Make slice - Val2("x := make([]int, 2); x[0] = 42; i, i2 = x[0], x[1]", "i", 42, "i2", 0), - Val2("x := make([]int, 2); x[1] = 42; i, i2 = x[0], x[1]", "i", 0, "i2", 42), - RErr("x := make([]int, 2); x[-i] = 42", "negative index"), - RErr("x := make([]int, 2); x[2] = 42", "index 2 exceeds"), - Val2("x := make([]int, 2, 3); i, i2 = len(x), cap(x)", "i", 2, "i2", 3), - Val2("x := make([]int, 3, 2); i, i2 = len(x), cap(x)", "i", 3, "i2", 3), - RErr("x := make([]int, -i)", "negative length"), - RErr("x := make([]int, 2, -i)", "negative capacity"), - RErr("x := make([]int, 2, 3); x[2] = 42", "index 2 exceeds"), - CErr("x := make([]int, 2, 3, 4)", "too many"), - CErr("x := make([]int)", "not enough"), - - // TODO(austin) Test make map - - // Maps - Val1("x := make(map[int] int); x[1] = 42; i = x[1]", "i", 42), - Val2("x := make(map[int] int); x[1] = 42; i, y := x[1]", "i", 42, "y", true), - Val2("x := make(map[int] int); x[1] = 42; i, y := x[2]", "i", 0, "y", false), - // Not implemented - //Val1("x := make(map[int] int); x[1] = 42, true; i = x[1]", "i", 42), - //Val2("x := make(map[int] int); x[1] = 42; x[1] = 42, false; i, y := x[1]", "i", 0, "y", false), - Run("var x int; a := make(map[int] int); a[0], x = 1, 2"), - CErr("x := make(map[int] int); (func(a,b int){})(x[0])", "not enough"), - CErr("x := make(map[int] int); x[1] = oneTwo()", "too many"), - RErr("x := make(map[int] int); i = x[1]", "key '1' not found"), - - // Functions - Val2("func fib(n int) int { if n <= 2 { return n }; return fib(n-1) + fib(n-2) }", "fib(4)", 5, "fib(10)", 89), - Run("func f1(){}"), - Run2("func f1(){}", "f1()"), -} - -func TestStmt(t *testing.T) { runTests(t, "stmtTests", stmtTests) } diff --git a/libgo/go/exp/eval/type.go b/libgo/go/exp/eval/type.go deleted file mode 100644 index 8a93d8a..0000000 --- a/libgo/go/exp/eval/type.go +++ /dev/null @@ -1,1252 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package eval - -import ( - "big" - "go/ast" - "go/token" - "log" - "reflect" - "sort" - "unsafe" // For Sizeof -) - - -// XXX(Spec) The type compatibility section is very confusing because -// it makes it seem like there are three distinct types of -// compatibility: plain compatibility, assignment compatibility, and -// comparison compatibility. As I understand it, there's really only -// assignment compatibility and comparison and conversion have some -// restrictions and have special meaning in some cases where the types -// are not otherwise assignment compatible. The comparison -// compatibility section is almost all about the semantics of -// comparison, not the type checking of it, so it would make much more -// sense in the comparison operators section. The compatibility and -// assignment compatibility sections should be rolled into one. - -type Type interface { - // compat returns whether this type is compatible with another - // type. If conv is false, this is normal compatibility, - // where two named types are compatible only if they are the - // same named type. If conv if true, this is conversion - // compatibility, where two named types are conversion - // compatible if their definitions are conversion compatible. - // - // TODO(austin) Deal with recursive types - compat(o Type, conv bool) bool - // lit returns this type's literal. If this is a named type, - // this is the unnamed underlying type. Otherwise, this is an - // identity operation. - lit() Type - // isBoolean returns true if this is a boolean type. - isBoolean() bool - // isInteger returns true if this is an integer type. - isInteger() bool - // isFloat returns true if this is a floating type. - isFloat() bool - // isIdeal returns true if this is an ideal int or float. - isIdeal() bool - // Zero returns a new zero value of this type. - Zero() Value - // String returns the string representation of this type. - String() string - // The position where this type was defined, if any. - Pos() token.Pos -} - -type BoundedType interface { - Type - // minVal returns the smallest value of this type. - minVal() *big.Rat - // maxVal returns the largest value of this type. - maxVal() *big.Rat -} - -var universePos = token.NoPos - -/* - * Type array maps. These are used to memoize composite types. - */ - -type typeArrayMapEntry struct { - key []Type - v interface{} - next *typeArrayMapEntry -} - -type typeArrayMap map[uintptr]*typeArrayMapEntry - -func hashTypeArray(key []Type) uintptr { - hash := uintptr(0) - for _, t := range key { - hash = hash * 33 - if t == nil { - continue - } - addr := reflect.ValueOf(t).Pointer() - hash ^= addr - } - return hash -} - -func newTypeArrayMap() typeArrayMap { return make(map[uintptr]*typeArrayMapEntry) } - -func (m typeArrayMap) Get(key []Type) interface{} { - ent, ok := m[hashTypeArray(key)] - if !ok { - return nil - } - -nextEnt: - for ; ent != nil; ent = ent.next { - if len(key) != len(ent.key) { - continue - } - for i := 0; i < len(key); i++ { - if key[i] != ent.key[i] { - continue nextEnt - } - } - // Found it - return ent.v - } - - return nil -} - -func (m typeArrayMap) Put(key []Type, v interface{}) interface{} { - hash := hashTypeArray(key) - ent := m[hash] - - new := &typeArrayMapEntry{key, v, ent} - m[hash] = new - return v -} - -/* - * Common type - */ - -type commonType struct{} - -func (commonType) isBoolean() bool { return false } - -func (commonType) isInteger() bool { return false } - -func (commonType) isFloat() bool { return false } - -func (commonType) isIdeal() bool { return false } - -func (commonType) Pos() token.Pos { return token.NoPos } - -/* - * Bool - */ - -type boolType struct { - commonType -} - -var BoolType = universe.DefineType("bool", universePos, &boolType{}) - -func (t *boolType) compat(o Type, conv bool) bool { - _, ok := o.lit().(*boolType) - return ok -} - -func (t *boolType) lit() Type { return t } - -func (t *boolType) isBoolean() bool { return true } - -func (boolType) String() string { - // Use angle brackets as a convention for printing the - // underlying, unnamed type. This should only show up in - // debug output. - return "" -} - -func (t *boolType) Zero() Value { - res := boolV(false) - return &res -} - -/* - * Uint - */ - -type uintType struct { - commonType - - // 0 for architecture-dependent types - Bits uint - // true for uintptr, false for all others - Ptr bool - name string -} - -var ( - Uint8Type = universe.DefineType("uint8", universePos, &uintType{commonType{}, 8, false, "uint8"}) - Uint16Type = universe.DefineType("uint16", universePos, &uintType{commonType{}, 16, false, "uint16"}) - Uint32Type = universe.DefineType("uint32", universePos, &uintType{commonType{}, 32, false, "uint32"}) - Uint64Type = universe.DefineType("uint64", universePos, &uintType{commonType{}, 64, false, "uint64"}) - - UintType = universe.DefineType("uint", universePos, &uintType{commonType{}, 0, false, "uint"}) - UintptrType = universe.DefineType("uintptr", universePos, &uintType{commonType{}, 0, true, "uintptr"}) -) - -func (t *uintType) compat(o Type, conv bool) bool { - t2, ok := o.lit().(*uintType) - return ok && t == t2 -} - -func (t *uintType) lit() Type { return t } - -func (t *uintType) isInteger() bool { return true } - -func (t *uintType) String() string { return "<" + t.name + ">" } - -func (t *uintType) Zero() Value { - switch t.Bits { - case 0: - if t.Ptr { - res := uintptrV(0) - return &res - } else { - res := uintV(0) - return &res - } - case 8: - res := uint8V(0) - return &res - case 16: - res := uint16V(0) - return &res - case 32: - res := uint32V(0) - return &res - case 64: - res := uint64V(0) - return &res - } - panic("unexpected uint bit count") -} - -func (t *uintType) minVal() *big.Rat { return big.NewRat(0, 1) } - -func (t *uintType) maxVal() *big.Rat { - bits := t.Bits - if bits == 0 { - if t.Ptr { - bits = uint(8 * unsafe.Sizeof(uintptr(0))) - } else { - bits = uint(8 * unsafe.Sizeof(uint(0))) - } - } - numer := big.NewInt(1) - numer.Lsh(numer, bits) - numer.Sub(numer, idealOne) - return new(big.Rat).SetInt(numer) -} - -/* - * Int - */ - -type intType struct { - commonType - - // XXX(Spec) Numeric types: "There is also a set of - // architecture-independent basic numeric types whose size - // depends on the architecture." Should that be - // architecture-dependent? - - // 0 for architecture-dependent types - Bits uint - name string -} - -var ( - Int8Type = universe.DefineType("int8", universePos, &intType{commonType{}, 8, "int8"}) - Int16Type = universe.DefineType("int16", universePos, &intType{commonType{}, 16, "int16"}) - Int32Type = universe.DefineType("int32", universePos, &intType{commonType{}, 32, "int32"}) - Int64Type = universe.DefineType("int64", universePos, &intType{commonType{}, 64, "int64"}) - - IntType = universe.DefineType("int", universePos, &intType{commonType{}, 0, "int"}) -) - -func (t *intType) compat(o Type, conv bool) bool { - t2, ok := o.lit().(*intType) - return ok && t == t2 -} - -func (t *intType) lit() Type { return t } - -func (t *intType) isInteger() bool { return true } - -func (t *intType) String() string { return "<" + t.name + ">" } - -func (t *intType) Zero() Value { - switch t.Bits { - case 8: - res := int8V(0) - return &res - case 16: - res := int16V(0) - return &res - case 32: - res := int32V(0) - return &res - case 64: - res := int64V(0) - return &res - - case 0: - res := intV(0) - return &res - } - panic("unexpected int bit count") -} - -func (t *intType) minVal() *big.Rat { - bits := t.Bits - if bits == 0 { - bits = uint(8 * unsafe.Sizeof(int(0))) - } - numer := big.NewInt(-1) - numer.Lsh(numer, bits-1) - return new(big.Rat).SetInt(numer) -} - -func (t *intType) maxVal() *big.Rat { - bits := t.Bits - if bits == 0 { - bits = uint(8 * unsafe.Sizeof(int(0))) - } - numer := big.NewInt(1) - numer.Lsh(numer, bits-1) - numer.Sub(numer, idealOne) - return new(big.Rat).SetInt(numer) -} - -/* - * Ideal int - */ - -type idealIntType struct { - commonType -} - -var IdealIntType Type = &idealIntType{} - -func (t *idealIntType) compat(o Type, conv bool) bool { - _, ok := o.lit().(*idealIntType) - return ok -} - -func (t *idealIntType) lit() Type { return t } - -func (t *idealIntType) isInteger() bool { return true } - -func (t *idealIntType) isIdeal() bool { return true } - -func (t *idealIntType) String() string { return "ideal integer" } - -func (t *idealIntType) Zero() Value { return &idealIntV{idealZero} } - -/* - * Float - */ - -type floatType struct { - commonType - - // 0 for architecture-dependent type - Bits uint - - name string -} - -var ( - Float32Type = universe.DefineType("float32", universePos, &floatType{commonType{}, 32, "float32"}) - Float64Type = universe.DefineType("float64", universePos, &floatType{commonType{}, 64, "float64"}) -) - -func (t *floatType) compat(o Type, conv bool) bool { - t2, ok := o.lit().(*floatType) - return ok && t == t2 -} - -func (t *floatType) lit() Type { return t } - -func (t *floatType) isFloat() bool { return true } - -func (t *floatType) String() string { return "<" + t.name + ">" } - -func (t *floatType) Zero() Value { - switch t.Bits { - case 32: - res := float32V(0) - return &res - case 64: - res := float64V(0) - return &res - } - panic("unexpected float bit count") -} - -var maxFloat32Val *big.Rat -var maxFloat64Val *big.Rat -var minFloat32Val *big.Rat -var minFloat64Val *big.Rat - -func (t *floatType) minVal() *big.Rat { - bits := t.Bits - switch bits { - case 32: - return minFloat32Val - case 64: - return minFloat64Val - } - log.Panicf("unexpected floating point bit count: %d", bits) - panic("unreachable") -} - -func (t *floatType) maxVal() *big.Rat { - bits := t.Bits - switch bits { - case 32: - return maxFloat32Val - case 64: - return maxFloat64Val - } - log.Panicf("unexpected floating point bit count: %d", bits) - panic("unreachable") -} - -/* - * Ideal float - */ - -type idealFloatType struct { - commonType -} - -var IdealFloatType Type = &idealFloatType{} - -func (t *idealFloatType) compat(o Type, conv bool) bool { - _, ok := o.lit().(*idealFloatType) - return ok -} - -func (t *idealFloatType) lit() Type { return t } - -func (t *idealFloatType) isFloat() bool { return true } - -func (t *idealFloatType) isIdeal() bool { return true } - -func (t *idealFloatType) String() string { return "ideal float" } - -func (t *idealFloatType) Zero() Value { return &idealFloatV{big.NewRat(0, 1)} } - -/* - * String - */ - -type stringType struct { - commonType -} - -var StringType = universe.DefineType("string", universePos, &stringType{}) - -func (t *stringType) compat(o Type, conv bool) bool { - _, ok := o.lit().(*stringType) - return ok -} - -func (t *stringType) lit() Type { return t } - -func (t *stringType) String() string { return "" } - -func (t *stringType) Zero() Value { - res := stringV("") - return &res -} - -/* - * Array - */ - -type ArrayType struct { - commonType - Len int64 - Elem Type -} - -var arrayTypes = make(map[int64]map[Type]*ArrayType) - -// Two array types are identical if they have identical element types -// and the same array length. - -func NewArrayType(len int64, elem Type) *ArrayType { - ts, ok := arrayTypes[len] - if !ok { - ts = make(map[Type]*ArrayType) - arrayTypes[len] = ts - } - t, ok := ts[elem] - if !ok { - t = &ArrayType{commonType{}, len, elem} - ts[elem] = t - } - return t -} - -func (t *ArrayType) compat(o Type, conv bool) bool { - t2, ok := o.lit().(*ArrayType) - if !ok { - return false - } - return t.Len == t2.Len && t.Elem.compat(t2.Elem, conv) -} - -func (t *ArrayType) lit() Type { return t } - -func (t *ArrayType) String() string { return "[]" + t.Elem.String() } - -func (t *ArrayType) Zero() Value { - res := arrayV(make([]Value, t.Len)) - // TODO(austin) It's unfortunate that each element is - // separately heap allocated. We could add ZeroArray to - // everything, though that doesn't help with multidimensional - // arrays. Or we could do something unsafe. We'll have this - // same problem with structs. - for i := int64(0); i < t.Len; i++ { - res[i] = t.Elem.Zero() - } - return &res -} - -/* - * Struct - */ - -type StructField struct { - Name string - Type Type - Anonymous bool -} - -type StructType struct { - commonType - Elems []StructField -} - -var structTypes = newTypeArrayMap() - -// Two struct types are identical if they have the same sequence of -// fields, and if corresponding fields have the same names and -// identical types. Two anonymous fields are considered to have the -// same name. - -func NewStructType(fields []StructField) *StructType { - // Start by looking up just the types - fts := make([]Type, len(fields)) - for i, f := range fields { - fts[i] = f.Type - } - tMapI := structTypes.Get(fts) - if tMapI == nil { - tMapI = structTypes.Put(fts, make(map[string]*StructType)) - } - tMap := tMapI.(map[string]*StructType) - - // Construct key for field names - key := "" - for _, f := range fields { - // XXX(Spec) It's not clear if struct { T } and struct - // { T T } are either identical or compatible. The - // "Struct Types" section says that the name of that - // field is "T", which suggests that they are - // identical, but it really means that it's the name - // for the purpose of selector expressions and nothing - // else. We decided that they should be neither - // identical or compatible. - if f.Anonymous { - key += "!" - } - key += f.Name + " " - } - - // XXX(Spec) Do the tags also have to be identical for the - // types to be identical? I certainly hope so, because - // otherwise, this is the only case where two distinct type - // objects can represent identical types. - - t, ok := tMap[key] - if !ok { - // Create new struct type - t = &StructType{commonType{}, fields} - tMap[key] = t - } - return t -} - -func (t *StructType) compat(o Type, conv bool) bool { - t2, ok := o.lit().(*StructType) - if !ok { - return false - } - if len(t.Elems) != len(t2.Elems) { - return false - } - for i, e := range t.Elems { - e2 := t2.Elems[i] - // XXX(Spec) An anonymous and a non-anonymous field - // are neither identical nor compatible. - if e.Anonymous != e2.Anonymous || - (!e.Anonymous && e.Name != e2.Name) || - !e.Type.compat(e2.Type, conv) { - return false - } - } - return true -} - -func (t *StructType) lit() Type { return t } - -func (t *StructType) String() string { - s := "struct {" - for i, f := range t.Elems { - if i > 0 { - s += "; " - } - if !f.Anonymous { - s += f.Name + " " - } - s += f.Type.String() - } - return s + "}" -} - -func (t *StructType) Zero() Value { - res := structV(make([]Value, len(t.Elems))) - for i, f := range t.Elems { - res[i] = f.Type.Zero() - } - return &res -} - -/* - * Pointer - */ - -type PtrType struct { - commonType - Elem Type -} - -var ptrTypes = make(map[Type]*PtrType) - -// Two pointer types are identical if they have identical base types. - -func NewPtrType(elem Type) *PtrType { - t, ok := ptrTypes[elem] - if !ok { - t = &PtrType{commonType{}, elem} - ptrTypes[elem] = t - } - return t -} - -func (t *PtrType) compat(o Type, conv bool) bool { - t2, ok := o.lit().(*PtrType) - if !ok { - return false - } - return t.Elem.compat(t2.Elem, conv) -} - -func (t *PtrType) lit() Type { return t } - -func (t *PtrType) String() string { return "*" + t.Elem.String() } - -func (t *PtrType) Zero() Value { return &ptrV{nil} } - -/* - * Function - */ - -type FuncType struct { - commonType - // TODO(austin) Separate receiver Type for methods? - In []Type - Variadic bool - Out []Type - builtin string -} - -var funcTypes = newTypeArrayMap() -var variadicFuncTypes = newTypeArrayMap() - -// Create singleton function types for magic built-in functions -var ( - capType = &FuncType{builtin: "cap"} - closeType = &FuncType{builtin: "close"} - closedType = &FuncType{builtin: "closed"} - lenType = &FuncType{builtin: "len"} - makeType = &FuncType{builtin: "make"} - newType = &FuncType{builtin: "new"} - panicType = &FuncType{builtin: "panic"} - printType = &FuncType{builtin: "print"} - printlnType = &FuncType{builtin: "println"} - copyType = &FuncType{builtin: "copy"} -) - -// Two function types are identical if they have the same number of -// parameters and result values and if corresponding parameter and -// result types are identical. All "..." parameters have identical -// type. Parameter and result names are not required to match. - -func NewFuncType(in []Type, variadic bool, out []Type) *FuncType { - inMap := funcTypes - if variadic { - inMap = variadicFuncTypes - } - - outMapI := inMap.Get(in) - if outMapI == nil { - outMapI = inMap.Put(in, newTypeArrayMap()) - } - outMap := outMapI.(typeArrayMap) - - tI := outMap.Get(out) - if tI != nil { - return tI.(*FuncType) - } - - t := &FuncType{commonType{}, in, variadic, out, ""} - outMap.Put(out, t) - return t -} - -func (t *FuncType) compat(o Type, conv bool) bool { - t2, ok := o.lit().(*FuncType) - if !ok { - return false - } - if len(t.In) != len(t2.In) || t.Variadic != t2.Variadic || len(t.Out) != len(t2.Out) { - return false - } - for i := range t.In { - if !t.In[i].compat(t2.In[i], conv) { - return false - } - } - for i := range t.Out { - if !t.Out[i].compat(t2.Out[i], conv) { - return false - } - } - return true -} - -func (t *FuncType) lit() Type { return t } - -func typeListString(ts []Type, ns []*ast.Ident) string { - s := "" - for i, t := range ts { - if i > 0 { - s += ", " - } - if ns != nil && ns[i] != nil { - s += ns[i].Name + " " - } - if t == nil { - // Some places use nil types to represent errors - s += "" - } else { - s += t.String() - } - } - return s -} - -func (t *FuncType) String() string { - if t.builtin != "" { - return "built-in function " + t.builtin - } - args := typeListString(t.In, nil) - if t.Variadic { - if len(args) > 0 { - args += ", " - } - args += "..." - } - s := "func(" + args + ")" - if len(t.Out) > 0 { - s += " (" + typeListString(t.Out, nil) + ")" - } - return s -} - -func (t *FuncType) Zero() Value { return &funcV{nil} } - -type FuncDecl struct { - Type *FuncType - Name *ast.Ident // nil for function literals - // InNames will be one longer than Type.In if this function is - // variadic. - InNames []*ast.Ident - OutNames []*ast.Ident -} - -func (t *FuncDecl) String() string { - s := "func" - if t.Name != nil { - s += " " + t.Name.Name - } - s += funcTypeString(t.Type, t.InNames, t.OutNames) - return s -} - -func funcTypeString(ft *FuncType, ins []*ast.Ident, outs []*ast.Ident) string { - s := "(" - s += typeListString(ft.In, ins) - if ft.Variadic { - if len(ft.In) > 0 { - s += ", " - } - s += "..." - } - s += ")" - if len(ft.Out) > 0 { - s += " (" + typeListString(ft.Out, outs) + ")" - } - return s -} - -/* - * Interface - */ - -// TODO(austin) Interface values, types, and type compilation are -// implemented, but none of the type checking or semantics of -// interfaces are. - -type InterfaceType struct { - commonType - // TODO(austin) This should be a map from names to - // *FuncType's. We only need the sorted list for generating - // the type map key. It's detrimental for everything else. - methods []IMethod -} - -type IMethod struct { - Name string - Type *FuncType -} - -var interfaceTypes = newTypeArrayMap() - -func NewInterfaceType(methods []IMethod, embeds []*InterfaceType) *InterfaceType { - // Count methods of embedded interfaces - nMethods := len(methods) - for _, e := range embeds { - nMethods += len(e.methods) - } - - // Combine methods - allMethods := make([]IMethod, nMethods) - copy(allMethods, methods) - n := len(methods) - for _, e := range embeds { - for _, m := range e.methods { - allMethods[n] = m - n++ - } - } - - // Sort methods - sort.Sort(iMethodSorter(allMethods)) - - mts := make([]Type, len(allMethods)) - for i, m := range methods { - mts[i] = m.Type - } - tMapI := interfaceTypes.Get(mts) - if tMapI == nil { - tMapI = interfaceTypes.Put(mts, make(map[string]*InterfaceType)) - } - tMap := tMapI.(map[string]*InterfaceType) - - key := "" - for _, m := range allMethods { - key += m.Name + " " - } - - t, ok := tMap[key] - if !ok { - t = &InterfaceType{commonType{}, allMethods} - tMap[key] = t - } - return t -} - -type iMethodSorter []IMethod - -func (s iMethodSorter) Less(a, b int) bool { return s[a].Name < s[b].Name } - -func (s iMethodSorter) Swap(a, b int) { s[a], s[b] = s[b], s[a] } - -func (s iMethodSorter) Len() int { return len(s) } - -func (t *InterfaceType) compat(o Type, conv bool) bool { - t2, ok := o.lit().(*InterfaceType) - if !ok { - return false - } - if len(t.methods) != len(t2.methods) { - return false - } - for i, e := range t.methods { - e2 := t2.methods[i] - if e.Name != e2.Name || !e.Type.compat(e2.Type, conv) { - return false - } - } - return true -} - -func (t *InterfaceType) lit() Type { return t } - -func (t *InterfaceType) String() string { - // TODO(austin) Instead of showing embedded interfaces, this - // shows their methods. - s := "interface {" - for i, m := range t.methods { - if i > 0 { - s += "; " - } - s += m.Name + funcTypeString(m.Type, nil, nil) - } - return s + "}" -} - -// implementedBy tests if o implements t, returning nil, true if it does. -// Otherwise, it returns a method of t that o is missing and false. -func (t *InterfaceType) implementedBy(o Type) (*IMethod, bool) { - if len(t.methods) == 0 { - return nil, true - } - - // The methods of a named interface types are those of the - // underlying type. - if it, ok := o.lit().(*InterfaceType); ok { - o = it - } - - // XXX(Spec) Interface types: "A type implements any interface - // comprising any subset of its methods" It's unclear if - // methods must have identical or compatible types. 6g - // requires identical types. - - switch o := o.(type) { - case *NamedType: - for _, tm := range t.methods { - sm, ok := o.methods[tm.Name] - if !ok || sm.decl.Type != tm.Type { - return &tm, false - } - } - return nil, true - - case *InterfaceType: - var ti, oi int - for ti < len(t.methods) && oi < len(o.methods) { - tm, om := &t.methods[ti], &o.methods[oi] - switch { - case tm.Name == om.Name: - if tm.Type != om.Type { - return tm, false - } - ti++ - oi++ - case tm.Name > om.Name: - oi++ - default: - return tm, false - } - } - if ti < len(t.methods) { - return &t.methods[ti], false - } - return nil, true - } - - return &t.methods[0], false -} - -func (t *InterfaceType) Zero() Value { return &interfaceV{} } - -/* - * Slice - */ - -type SliceType struct { - commonType - Elem Type -} - -var sliceTypes = make(map[Type]*SliceType) - -// Two slice types are identical if they have identical element types. - -func NewSliceType(elem Type) *SliceType { - t, ok := sliceTypes[elem] - if !ok { - t = &SliceType{commonType{}, elem} - sliceTypes[elem] = t - } - return t -} - -func (t *SliceType) compat(o Type, conv bool) bool { - t2, ok := o.lit().(*SliceType) - if !ok { - return false - } - return t.Elem.compat(t2.Elem, conv) -} - -func (t *SliceType) lit() Type { return t } - -func (t *SliceType) String() string { return "[]" + t.Elem.String() } - -func (t *SliceType) Zero() Value { - // The value of an uninitialized slice is nil. The length and - // capacity of a nil slice are 0. - return &sliceV{Slice{nil, 0, 0}} -} - -/* - * Map type - */ - -type MapType struct { - commonType - Key Type - Elem Type -} - -var mapTypes = make(map[Type]map[Type]*MapType) - -func NewMapType(key Type, elem Type) *MapType { - ts, ok := mapTypes[key] - if !ok { - ts = make(map[Type]*MapType) - mapTypes[key] = ts - } - t, ok := ts[elem] - if !ok { - t = &MapType{commonType{}, key, elem} - ts[elem] = t - } - return t -} - -func (t *MapType) compat(o Type, conv bool) bool { - t2, ok := o.lit().(*MapType) - if !ok { - return false - } - return t.Elem.compat(t2.Elem, conv) && t.Key.compat(t2.Key, conv) -} - -func (t *MapType) lit() Type { return t } - -func (t *MapType) String() string { return "map[" + t.Key.String() + "] " + t.Elem.String() } - -func (t *MapType) Zero() Value { - // The value of an uninitialized map is nil. - return &mapV{nil} -} - -/* -type ChanType struct { - // TODO(austin) -} -*/ - -/* - * Named types - */ - -type Method struct { - decl *FuncDecl - fn Func -} - -type NamedType struct { - NamePos token.Pos - Name string - // Underlying type. If incomplete is true, this will be nil. - // If incomplete is false and this is still nil, then this is - // a placeholder type representing an error. - Def Type - // True while this type is being defined. - incomplete bool - methods map[string]Method -} - -// TODO(austin) This is temporarily needed by the debugger's remote -// type parser. This should only be possible with block.DefineType. -func NewNamedType(name string) *NamedType { - return &NamedType{token.NoPos, name, nil, true, make(map[string]Method)} -} - -func (t *NamedType) Pos() token.Pos { - return t.NamePos -} - -func (t *NamedType) Complete(def Type) { - if !t.incomplete { - log.Panicf("cannot complete already completed NamedType %+v", *t) - } - // We strip the name from def because multiple levels of - // naming are useless. - if ndef, ok := def.(*NamedType); ok { - def = ndef.Def - } - t.Def = def - t.incomplete = false -} - -func (t *NamedType) compat(o Type, conv bool) bool { - t2, ok := o.(*NamedType) - if ok { - if conv { - // Two named types are conversion compatible - // if their literals are conversion - // compatible. - return t.Def.compat(t2.Def, conv) - } else { - // Two named types are compatible if their - // type names originate in the same type - // declaration. - return t == t2 - } - } - // A named and an unnamed type are compatible if the - // respective type literals are compatible. - return o.compat(t.Def, conv) -} - -func (t *NamedType) lit() Type { return t.Def.lit() } - -func (t *NamedType) isBoolean() bool { return t.Def.isBoolean() } - -func (t *NamedType) isInteger() bool { return t.Def.isInteger() } - -func (t *NamedType) isFloat() bool { return t.Def.isFloat() } - -func (t *NamedType) isIdeal() bool { return false } - -func (t *NamedType) String() string { return t.Name } - -func (t *NamedType) Zero() Value { return t.Def.Zero() } - -/* - * Multi-valued type - */ - -// MultiType is a special type used for multi-valued expressions, akin -// to a tuple type. It's not generally accessible within the -// language. -type MultiType struct { - commonType - Elems []Type -} - -var multiTypes = newTypeArrayMap() - -func NewMultiType(elems []Type) *MultiType { - if t := multiTypes.Get(elems); t != nil { - return t.(*MultiType) - } - - t := &MultiType{commonType{}, elems} - multiTypes.Put(elems, t) - return t -} - -func (t *MultiType) compat(o Type, conv bool) bool { - t2, ok := o.lit().(*MultiType) - if !ok { - return false - } - if len(t.Elems) != len(t2.Elems) { - return false - } - for i := range t.Elems { - if !t.Elems[i].compat(t2.Elems[i], conv) { - return false - } - } - return true -} - -var EmptyType Type = NewMultiType([]Type{}) - -func (t *MultiType) lit() Type { return t } - -func (t *MultiType) String() string { - if len(t.Elems) == 0 { - return "" - } - return typeListString(t.Elems, nil) -} - -func (t *MultiType) Zero() Value { - res := make([]Value, len(t.Elems)) - for i, t := range t.Elems { - res[i] = t.Zero() - } - return multiV(res) -} - -/* - * Initialize the universe - */ - -func init() { - numer := big.NewInt(0xffffff) - numer.Lsh(numer, 127-23) - maxFloat32Val = new(big.Rat).SetInt(numer) - numer.SetInt64(0x1fffffffffffff) - numer.Lsh(numer, 1023-52) - maxFloat64Val = new(big.Rat).SetInt(numer) - minFloat32Val = new(big.Rat).Neg(maxFloat32Val) - minFloat64Val = new(big.Rat).Neg(maxFloat64Val) - - // To avoid portability issues all numeric types are distinct - // except byte, which is an alias for uint8. - - // Make byte an alias for the named type uint8. Type aliases - // are otherwise impossible in Go, so just hack it here. - universe.defs["byte"] = universe.defs["uint8"] - - // Built-in functions - universe.DefineConst("cap", universePos, capType, nil) - universe.DefineConst("close", universePos, closeType, nil) - universe.DefineConst("closed", universePos, closedType, nil) - universe.DefineConst("copy", universePos, copyType, nil) - universe.DefineConst("len", universePos, lenType, nil) - universe.DefineConst("make", universePos, makeType, nil) - universe.DefineConst("new", universePos, newType, nil) - universe.DefineConst("panic", universePos, panicType, nil) - universe.DefineConst("print", universePos, printType, nil) - universe.DefineConst("println", universePos, printlnType, nil) -} diff --git a/libgo/go/exp/eval/typec.go b/libgo/go/exp/eval/typec.go deleted file mode 100644 index de90cf6..0000000 --- a/libgo/go/exp/eval/typec.go +++ /dev/null @@ -1,409 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package eval - -import ( - "go/ast" - "go/token" - "log" -) - - -/* - * Type compiler - */ - -type typeCompiler struct { - *compiler - block *block - // Check to be performed after a type declaration is compiled. - // - // TODO(austin) This will probably have to change after we - // eliminate forward declarations. - lateCheck func() bool -} - -func (a *typeCompiler) compileIdent(x *ast.Ident, allowRec bool) Type { - _, _, def := a.block.Lookup(x.Name) - if def == nil { - a.diagAt(x.Pos(), "%s: undefined", x.Name) - return nil - } - switch def := def.(type) { - case *Constant: - a.diagAt(x.Pos(), "constant %v used as type", x.Name) - return nil - case *Variable: - a.diagAt(x.Pos(), "variable %v used as type", x.Name) - return nil - case *NamedType: - if !allowRec && def.incomplete { - a.diagAt(x.Pos(), "illegal recursive type") - return nil - } - if !def.incomplete && def.Def == nil { - // Placeholder type from an earlier error - return nil - } - return def - case Type: - return def - } - log.Panicf("name %s has unknown type %T", x.Name, def) - return nil -} - -func (a *typeCompiler) compileArrayType(x *ast.ArrayType, allowRec bool) Type { - // Compile element type - elem := a.compileType(x.Elt, allowRec) - - // Compile length expression - if x.Len == nil { - if elem == nil { - return nil - } - return NewSliceType(elem) - } - - if _, ok := x.Len.(*ast.Ellipsis); ok { - a.diagAt(x.Len.Pos(), "... array initailizers not implemented") - return nil - } - l, ok := a.compileArrayLen(a.block, x.Len) - if !ok { - return nil - } - if l < 0 { - a.diagAt(x.Len.Pos(), "array length must be non-negative") - return nil - } - if elem == nil { - return nil - } - - return NewArrayType(l, elem) -} - -func (a *typeCompiler) compileFields(fields *ast.FieldList, allowRec bool) ([]Type, []*ast.Ident, []token.Pos, bool) { - n := fields.NumFields() - ts := make([]Type, n) - ns := make([]*ast.Ident, n) - ps := make([]token.Pos, n) - bad := false - - if fields != nil { - i := 0 - for _, f := range fields.List { - t := a.compileType(f.Type, allowRec) - if t == nil { - bad = true - } - if f.Names == nil { - ns[i] = nil - ts[i] = t - ps[i] = f.Type.Pos() - i++ - continue - } - for _, n := range f.Names { - ns[i] = n - ts[i] = t - ps[i] = n.Pos() - i++ - } - } - } - - return ts, ns, ps, bad -} - -func (a *typeCompiler) compileStructType(x *ast.StructType, allowRec bool) Type { - ts, names, poss, bad := a.compileFields(x.Fields, allowRec) - - // XXX(Spec) The spec claims that field identifiers must be - // unique, but 6g only checks this when they are accessed. I - // think the spec is better in this regard: if I write two - // fields with the same name in the same struct type, clearly - // that's a mistake. This definition does *not* descend into - // anonymous fields, so it doesn't matter if those change. - // There's separate language in the spec about checking - // uniqueness of field names inherited from anonymous fields - // at use time. - fields := make([]StructField, len(ts)) - nameSet := make(map[string]token.Pos, len(ts)) - for i := range fields { - // Compute field name and check anonymous fields - var name string - if names[i] != nil { - name = names[i].Name - } else { - if ts[i] == nil { - continue - } - - var nt *NamedType - // [For anonymous fields,] the unqualified - // type name acts as the field identifier. - switch t := ts[i].(type) { - case *NamedType: - name = t.Name - nt = t - case *PtrType: - switch t := t.Elem.(type) { - case *NamedType: - name = t.Name - nt = t - } - } - // [An anonymous field] must be specified as a - // type name T or as a pointer to a type name - // *T, and T itself, may not be a pointer or - // interface type. - if nt == nil { - a.diagAt(poss[i], "embedded type must T or *T, where T is a named type") - bad = true - continue - } - // The check for embedded pointer types must - // be deferred because of things like - // type T *struct { T } - lateCheck := a.lateCheck - a.lateCheck = func() bool { - if _, ok := nt.lit().(*PtrType); ok { - a.diagAt(poss[i], "embedded type %v is a pointer type", nt) - return false - } - return lateCheck() - } - } - - // Check name uniqueness - if prev, ok := nameSet[name]; ok { - a.diagAt(poss[i], "field %s redeclared\n\tprevious declaration at %s", name, a.fset.Position(prev)) - bad = true - continue - } - nameSet[name] = poss[i] - - // Create field - fields[i].Name = name - fields[i].Type = ts[i] - fields[i].Anonymous = (names[i] == nil) - } - - if bad { - return nil - } - - return NewStructType(fields) -} - -func (a *typeCompiler) compilePtrType(x *ast.StarExpr) Type { - elem := a.compileType(x.X, true) - if elem == nil { - return nil - } - return NewPtrType(elem) -} - -func (a *typeCompiler) compileFuncType(x *ast.FuncType, allowRec bool) *FuncDecl { - // TODO(austin) Variadic function types - - // The types of parameters and results must be complete. - // - // TODO(austin) It's not clear they actually have to be complete. - in, inNames, _, inBad := a.compileFields(x.Params, allowRec) - out, outNames, _, outBad := a.compileFields(x.Results, allowRec) - - if inBad || outBad { - return nil - } - return &FuncDecl{NewFuncType(in, false, out), nil, inNames, outNames} -} - -func (a *typeCompiler) compileInterfaceType(x *ast.InterfaceType, allowRec bool) *InterfaceType { - ts, names, poss, bad := a.compileFields(x.Methods, allowRec) - - methods := make([]IMethod, len(ts)) - nameSet := make(map[string]token.Pos, len(ts)) - embeds := make([]*InterfaceType, len(ts)) - - var nm, ne int - for i := range ts { - if ts[i] == nil { - continue - } - - if names[i] != nil { - name := names[i].Name - methods[nm].Name = name - methods[nm].Type = ts[i].(*FuncType) - nm++ - if prev, ok := nameSet[name]; ok { - a.diagAt(poss[i], "method %s redeclared\n\tprevious declaration at %s", name, a.fset.Position(prev)) - bad = true - continue - } - nameSet[name] = poss[i] - } else { - // Embedded interface - it, ok := ts[i].lit().(*InterfaceType) - if !ok { - a.diagAt(poss[i], "embedded type must be an interface") - bad = true - continue - } - embeds[ne] = it - ne++ - for _, m := range it.methods { - if prev, ok := nameSet[m.Name]; ok { - a.diagAt(poss[i], "method %s redeclared\n\tprevious declaration at %s", m.Name, a.fset.Position(prev)) - bad = true - continue - } - nameSet[m.Name] = poss[i] - } - } - } - - if bad { - return nil - } - - methods = methods[0:nm] - embeds = embeds[0:ne] - - return NewInterfaceType(methods, embeds) -} - -func (a *typeCompiler) compileMapType(x *ast.MapType) Type { - key := a.compileType(x.Key, true) - val := a.compileType(x.Value, true) - if key == nil || val == nil { - return nil - } - // XXX(Spec) The Map types section explicitly lists all types - // that can be map keys except for function types. - switch key.lit().(type) { - case *StructType: - a.diagAt(x.Pos(), "map key cannot be a struct type") - return nil - case *ArrayType: - a.diagAt(x.Pos(), "map key cannot be an array type") - return nil - case *SliceType: - a.diagAt(x.Pos(), "map key cannot be a slice type") - return nil - } - return NewMapType(key, val) -} - -func (a *typeCompiler) compileType(x ast.Expr, allowRec bool) Type { - switch x := x.(type) { - case *ast.BadExpr: - // Error already reported by parser - a.silentErrors++ - return nil - - case *ast.Ident: - return a.compileIdent(x, allowRec) - - case *ast.ArrayType: - return a.compileArrayType(x, allowRec) - - case *ast.StructType: - return a.compileStructType(x, allowRec) - - case *ast.StarExpr: - return a.compilePtrType(x) - - case *ast.FuncType: - fd := a.compileFuncType(x, allowRec) - if fd == nil { - return nil - } - return fd.Type - - case *ast.InterfaceType: - return a.compileInterfaceType(x, allowRec) - - case *ast.MapType: - return a.compileMapType(x) - - case *ast.ChanType: - goto notimpl - - case *ast.ParenExpr: - return a.compileType(x.X, allowRec) - - case *ast.Ellipsis: - a.diagAt(x.Pos(), "illegal use of ellipsis") - return nil - } - a.diagAt(x.Pos(), "expression used as type") - return nil - -notimpl: - a.diagAt(x.Pos(), "compileType: %T not implemented", x) - return nil -} - -/* - * Type compiler interface - */ - -func noLateCheck() bool { return true } - -func (a *compiler) compileType(b *block, typ ast.Expr) Type { - tc := &typeCompiler{a, b, noLateCheck} - t := tc.compileType(typ, false) - if !tc.lateCheck() { - t = nil - } - return t -} - -func (a *compiler) compileTypeDecl(b *block, decl *ast.GenDecl) bool { - ok := true - for _, spec := range decl.Specs { - spec := spec.(*ast.TypeSpec) - // Create incomplete type for this type - nt := b.DefineType(spec.Name.Name, spec.Name.Pos(), nil) - if nt != nil { - nt.(*NamedType).incomplete = true - } - // Compile type - tc := &typeCompiler{a, b, noLateCheck} - t := tc.compileType(spec.Type, false) - if t == nil { - // Create a placeholder type - ok = false - } - // Fill incomplete type - if nt != nil { - nt.(*NamedType).Complete(t) - } - // Perform late type checking with complete type - if !tc.lateCheck() { - ok = false - if nt != nil { - // Make the type a placeholder - nt.(*NamedType).Def = nil - } - } - } - return ok -} - -func (a *compiler) compileFuncType(b *block, typ *ast.FuncType) *FuncDecl { - tc := &typeCompiler{a, b, noLateCheck} - res := tc.compileFuncType(typ, false) - if res != nil { - if !tc.lateCheck() { - res = nil - } - } - return res -} diff --git a/libgo/go/exp/eval/value.go b/libgo/go/exp/eval/value.go deleted file mode 100644 index daa6918..0000000 --- a/libgo/go/exp/eval/value.go +++ /dev/null @@ -1,586 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package eval - -import ( - "big" - "fmt" -) - -type Value interface { - String() string - // Assign copies another value into this one. It should - // assume that the other value satisfies the same specific - // value interface (BoolValue, etc.), but must not assume - // anything about its specific type. - Assign(t *Thread, o Value) -} - -type BoolValue interface { - Value - Get(*Thread) bool - Set(*Thread, bool) -} - -type UintValue interface { - Value - Get(*Thread) uint64 - Set(*Thread, uint64) -} - -type IntValue interface { - Value - Get(*Thread) int64 - Set(*Thread, int64) -} - -// TODO(austin) IdealIntValue and IdealFloatValue should not exist -// because ideals are not l-values. -type IdealIntValue interface { - Value - Get() *big.Int -} - -type FloatValue interface { - Value - Get(*Thread) float64 - Set(*Thread, float64) -} - -type IdealFloatValue interface { - Value - Get() *big.Rat -} - -type StringValue interface { - Value - Get(*Thread) string - Set(*Thread, string) -} - -type ArrayValue interface { - Value - // TODO(austin) Get() is here for uniformity, but is - // completely useless. If a lot of other types have similarly - // useless Get methods, just special-case these uses. - Get(*Thread) ArrayValue - Elem(*Thread, int64) Value - // Sub returns an ArrayValue backed by the same array that - // starts from element i and has length len. - Sub(i int64, len int64) ArrayValue -} - -type StructValue interface { - Value - // TODO(austin) This is another useless Get() - Get(*Thread) StructValue - Field(*Thread, int) Value -} - -type PtrValue interface { - Value - Get(*Thread) Value - Set(*Thread, Value) -} - -type Func interface { - NewFrame() *Frame - Call(*Thread) -} - -type FuncValue interface { - Value - Get(*Thread) Func - Set(*Thread, Func) -} - -type Interface struct { - Type Type - Value Value -} - -type InterfaceValue interface { - Value - Get(*Thread) Interface - Set(*Thread, Interface) -} - -type Slice struct { - Base ArrayValue - Len, Cap int64 -} - -type SliceValue interface { - Value - Get(*Thread) Slice - Set(*Thread, Slice) -} - -type Map interface { - Len(*Thread) int64 - // Retrieve an element from the map, returning nil if it does - // not exist. - Elem(t *Thread, key interface{}) Value - // Set an entry in the map. If val is nil, delete the entry. - SetElem(t *Thread, key interface{}, val Value) - // TODO(austin) Perhaps there should be an iterator interface instead. - Iter(func(key interface{}, val Value) bool) -} - -type MapValue interface { - Value - Get(*Thread) Map - Set(*Thread, Map) -} - -/* - * Bool - */ - -type boolV bool - -func (v *boolV) String() string { return fmt.Sprint(*v) } - -func (v *boolV) Assign(t *Thread, o Value) { *v = boolV(o.(BoolValue).Get(t)) } - -func (v *boolV) Get(*Thread) bool { return bool(*v) } - -func (v *boolV) Set(t *Thread, x bool) { *v = boolV(x) } - -/* - * Uint - */ - -type uint8V uint8 - -func (v *uint8V) String() string { return fmt.Sprint(*v) } - -func (v *uint8V) Assign(t *Thread, o Value) { *v = uint8V(o.(UintValue).Get(t)) } - -func (v *uint8V) Get(*Thread) uint64 { return uint64(*v) } - -func (v *uint8V) Set(t *Thread, x uint64) { *v = uint8V(x) } - -type uint16V uint16 - -func (v *uint16V) String() string { return fmt.Sprint(*v) } - -func (v *uint16V) Assign(t *Thread, o Value) { *v = uint16V(o.(UintValue).Get(t)) } - -func (v *uint16V) Get(*Thread) uint64 { return uint64(*v) } - -func (v *uint16V) Set(t *Thread, x uint64) { *v = uint16V(x) } - -type uint32V uint32 - -func (v *uint32V) String() string { return fmt.Sprint(*v) } - -func (v *uint32V) Assign(t *Thread, o Value) { *v = uint32V(o.(UintValue).Get(t)) } - -func (v *uint32V) Get(*Thread) uint64 { return uint64(*v) } - -func (v *uint32V) Set(t *Thread, x uint64) { *v = uint32V(x) } - -type uint64V uint64 - -func (v *uint64V) String() string { return fmt.Sprint(*v) } - -func (v *uint64V) Assign(t *Thread, o Value) { *v = uint64V(o.(UintValue).Get(t)) } - -func (v *uint64V) Get(*Thread) uint64 { return uint64(*v) } - -func (v *uint64V) Set(t *Thread, x uint64) { *v = uint64V(x) } - -type uintV uint - -func (v *uintV) String() string { return fmt.Sprint(*v) } - -func (v *uintV) Assign(t *Thread, o Value) { *v = uintV(o.(UintValue).Get(t)) } - -func (v *uintV) Get(*Thread) uint64 { return uint64(*v) } - -func (v *uintV) Set(t *Thread, x uint64) { *v = uintV(x) } - -type uintptrV uintptr - -func (v *uintptrV) String() string { return fmt.Sprint(*v) } - -func (v *uintptrV) Assign(t *Thread, o Value) { *v = uintptrV(o.(UintValue).Get(t)) } - -func (v *uintptrV) Get(*Thread) uint64 { return uint64(*v) } - -func (v *uintptrV) Set(t *Thread, x uint64) { *v = uintptrV(x) } - -/* - * Int - */ - -type int8V int8 - -func (v *int8V) String() string { return fmt.Sprint(*v) } - -func (v *int8V) Assign(t *Thread, o Value) { *v = int8V(o.(IntValue).Get(t)) } - -func (v *int8V) Get(*Thread) int64 { return int64(*v) } - -func (v *int8V) Set(t *Thread, x int64) { *v = int8V(x) } - -type int16V int16 - -func (v *int16V) String() string { return fmt.Sprint(*v) } - -func (v *int16V) Assign(t *Thread, o Value) { *v = int16V(o.(IntValue).Get(t)) } - -func (v *int16V) Get(*Thread) int64 { return int64(*v) } - -func (v *int16V) Set(t *Thread, x int64) { *v = int16V(x) } - -type int32V int32 - -func (v *int32V) String() string { return fmt.Sprint(*v) } - -func (v *int32V) Assign(t *Thread, o Value) { *v = int32V(o.(IntValue).Get(t)) } - -func (v *int32V) Get(*Thread) int64 { return int64(*v) } - -func (v *int32V) Set(t *Thread, x int64) { *v = int32V(x) } - -type int64V int64 - -func (v *int64V) String() string { return fmt.Sprint(*v) } - -func (v *int64V) Assign(t *Thread, o Value) { *v = int64V(o.(IntValue).Get(t)) } - -func (v *int64V) Get(*Thread) int64 { return int64(*v) } - -func (v *int64V) Set(t *Thread, x int64) { *v = int64V(x) } - -type intV int - -func (v *intV) String() string { return fmt.Sprint(*v) } - -func (v *intV) Assign(t *Thread, o Value) { *v = intV(o.(IntValue).Get(t)) } - -func (v *intV) Get(*Thread) int64 { return int64(*v) } - -func (v *intV) Set(t *Thread, x int64) { *v = intV(x) } - -/* - * Ideal int - */ - -type idealIntV struct { - V *big.Int -} - -func (v *idealIntV) String() string { return v.V.String() } - -func (v *idealIntV) Assign(t *Thread, o Value) { - v.V = o.(IdealIntValue).Get() -} - -func (v *idealIntV) Get() *big.Int { return v.V } - -/* - * Float - */ - -type float32V float32 - -func (v *float32V) String() string { return fmt.Sprint(*v) } - -func (v *float32V) Assign(t *Thread, o Value) { *v = float32V(o.(FloatValue).Get(t)) } - -func (v *float32V) Get(*Thread) float64 { return float64(*v) } - -func (v *float32V) Set(t *Thread, x float64) { *v = float32V(x) } - -type float64V float64 - -func (v *float64V) String() string { return fmt.Sprint(*v) } - -func (v *float64V) Assign(t *Thread, o Value) { *v = float64V(o.(FloatValue).Get(t)) } - -func (v *float64V) Get(*Thread) float64 { return float64(*v) } - -func (v *float64V) Set(t *Thread, x float64) { *v = float64V(x) } - -/* - * Ideal float - */ - -type idealFloatV struct { - V *big.Rat -} - -func (v *idealFloatV) String() string { return v.V.FloatString(6) } - -func (v *idealFloatV) Assign(t *Thread, o Value) { - v.V = o.(IdealFloatValue).Get() -} - -func (v *idealFloatV) Get() *big.Rat { return v.V } - -/* - * String - */ - -type stringV string - -func (v *stringV) String() string { return fmt.Sprint(*v) } - -func (v *stringV) Assign(t *Thread, o Value) { *v = stringV(o.(StringValue).Get(t)) } - -func (v *stringV) Get(*Thread) string { return string(*v) } - -func (v *stringV) Set(t *Thread, x string) { *v = stringV(x) } - -/* - * Array - */ - -type arrayV []Value - -func (v *arrayV) String() string { - res := "{" - for i, e := range *v { - if i > 0 { - res += ", " - } - res += e.String() - } - return res + "}" -} - -func (v *arrayV) Assign(t *Thread, o Value) { - oa := o.(ArrayValue) - l := int64(len(*v)) - for i := int64(0); i < l; i++ { - (*v)[i].Assign(t, oa.Elem(t, i)) - } -} - -func (v *arrayV) Get(*Thread) ArrayValue { return v } - -func (v *arrayV) Elem(t *Thread, i int64) Value { - return (*v)[i] -} - -func (v *arrayV) Sub(i int64, len int64) ArrayValue { - res := (*v)[i : i+len] - return &res -} - -/* - * Struct - */ - -type structV []Value - -// TODO(austin) Should these methods (and arrayV's) be on structV -// instead of *structV? -func (v *structV) String() string { - res := "{" - for i, v := range *v { - if i > 0 { - res += ", " - } - res += v.String() - } - return res + "}" -} - -func (v *structV) Assign(t *Thread, o Value) { - oa := o.(StructValue) - l := len(*v) - for i := 0; i < l; i++ { - (*v)[i].Assign(t, oa.Field(t, i)) - } -} - -func (v *structV) Get(*Thread) StructValue { return v } - -func (v *structV) Field(t *Thread, i int) Value { - return (*v)[i] -} - -/* - * Pointer - */ - -type ptrV struct { - // nil if the pointer is nil - target Value -} - -func (v *ptrV) String() string { - if v.target == nil { - return "" - } - return "&" + v.target.String() -} - -func (v *ptrV) Assign(t *Thread, o Value) { v.target = o.(PtrValue).Get(t) } - -func (v *ptrV) Get(*Thread) Value { return v.target } - -func (v *ptrV) Set(t *Thread, x Value) { v.target = x } - -/* - * Functions - */ - -type funcV struct { - target Func -} - -func (v *funcV) String() string { - // TODO(austin) Rob wants to see the definition - return "func {...}" -} - -func (v *funcV) Assign(t *Thread, o Value) { v.target = o.(FuncValue).Get(t) } - -func (v *funcV) Get(*Thread) Func { return v.target } - -func (v *funcV) Set(t *Thread, x Func) { v.target = x } - -/* - * Interfaces - */ - -type interfaceV struct { - Interface -} - -func (v *interfaceV) String() string { - if v.Type == nil || v.Value == nil { - return "" - } - return v.Value.String() -} - -func (v *interfaceV) Assign(t *Thread, o Value) { - v.Interface = o.(InterfaceValue).Get(t) -} - -func (v *interfaceV) Get(*Thread) Interface { return v.Interface } - -func (v *interfaceV) Set(t *Thread, x Interface) { - v.Interface = x -} - -/* - * Slices - */ - -type sliceV struct { - Slice -} - -func (v *sliceV) String() string { - if v.Base == nil { - return "" - } - return v.Base.Sub(0, v.Len).String() -} - -func (v *sliceV) Assign(t *Thread, o Value) { v.Slice = o.(SliceValue).Get(t) } - -func (v *sliceV) Get(*Thread) Slice { return v.Slice } - -func (v *sliceV) Set(t *Thread, x Slice) { v.Slice = x } - -/* - * Maps - */ - -type mapV struct { - target Map -} - -func (v *mapV) String() string { - if v.target == nil { - return "" - } - res := "map[" - i := 0 - v.target.Iter(func(key interface{}, val Value) bool { - if i > 0 { - res += ", " - } - i++ - res += fmt.Sprint(key) + ":" + val.String() - return true - }) - return res + "]" -} - -func (v *mapV) Assign(t *Thread, o Value) { v.target = o.(MapValue).Get(t) } - -func (v *mapV) Get(*Thread) Map { return v.target } - -func (v *mapV) Set(t *Thread, x Map) { v.target = x } - -type evalMap map[interface{}]Value - -func (m evalMap) Len(t *Thread) int64 { return int64(len(m)) } - -func (m evalMap) Elem(t *Thread, key interface{}) Value { - return m[key] -} - -func (m evalMap) SetElem(t *Thread, key interface{}, val Value) { - if val == nil { - m[key] = nil, false - } else { - m[key] = val - } -} - -func (m evalMap) Iter(cb func(key interface{}, val Value) bool) { - for k, v := range m { - if !cb(k, v) { - break - } - } -} - -/* - * Multi-values - */ - -type multiV []Value - -func (v multiV) String() string { - res := "(" - for i, v := range v { - if i > 0 { - res += ", " - } - res += v.String() - } - return res + ")" -} - -func (v multiV) Assign(t *Thread, o Value) { - omv := o.(multiV) - for i := range v { - v[i].Assign(t, omv[i]) - } -} - -/* - * Universal constants - */ - -func init() { - s := universe - - true := boolV(true) - s.DefineConst("true", universePos, BoolType, &true) - false := boolV(false) - s.DefineConst("false", universePos, BoolType, &false) -} diff --git a/libgo/go/exp/eval/world.go b/libgo/go/exp/eval/world.go deleted file mode 100644 index a5f6ac7e..0000000 --- a/libgo/go/exp/eval/world.go +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package eval is the beginning of an interpreter for Go. -// It can run simple Go programs but does not implement -// interface values or packages. -package eval - -import ( - "go/ast" - "go/parser" - "go/scanner" - "go/token" - "os" -) - -type World struct { - scope *Scope - frame *Frame -} - -func NewWorld() *World { - w := new(World) - w.scope = universe.ChildScope() - w.scope.global = true // this block's vars allocate directly - return w -} - -type Code interface { - // The type of the value Run returns, or nil if Run returns nil. - Type() Type - - // Run runs the code; if the code is a single expression - // with a value, it returns the value; otherwise it returns nil. - Run() (Value, os.Error) -} - -type stmtCode struct { - w *World - code code -} - -func (w *World) CompileStmtList(fset *token.FileSet, stmts []ast.Stmt) (Code, os.Error) { - if len(stmts) == 1 { - if s, ok := stmts[0].(*ast.ExprStmt); ok { - return w.CompileExpr(fset, s.X) - } - } - errors := new(scanner.ErrorVector) - cc := &compiler{fset, errors, 0, 0} - cb := newCodeBuf() - fc := &funcCompiler{ - compiler: cc, - fnType: nil, - outVarsNamed: false, - codeBuf: cb, - flow: newFlowBuf(cb), - labels: make(map[string]*label), - } - bc := &blockCompiler{ - funcCompiler: fc, - block: w.scope.block, - } - nerr := cc.numError() - for _, stmt := range stmts { - bc.compileStmt(stmt) - } - fc.checkLabels() - if nerr != cc.numError() { - return nil, errors.GetError(scanner.Sorted) - } - return &stmtCode{w, fc.get()}, nil -} - -func (w *World) CompileDeclList(fset *token.FileSet, decls []ast.Decl) (Code, os.Error) { - stmts := make([]ast.Stmt, len(decls)) - for i, d := range decls { - stmts[i] = &ast.DeclStmt{d} - } - return w.CompileStmtList(fset, stmts) -} - -func (s *stmtCode) Type() Type { return nil } - -func (s *stmtCode) Run() (Value, os.Error) { - t := new(Thread) - t.f = s.w.scope.NewFrame(nil) - return nil, t.Try(func(t *Thread) { s.code.exec(t) }) -} - -type exprCode struct { - w *World - e *expr - eval func(Value, *Thread) -} - -func (w *World) CompileExpr(fset *token.FileSet, e ast.Expr) (Code, os.Error) { - errors := new(scanner.ErrorVector) - cc := &compiler{fset, errors, 0, 0} - - ec := cc.compileExpr(w.scope.block, false, e) - if ec == nil { - return nil, errors.GetError(scanner.Sorted) - } - var eval func(Value, *Thread) - switch t := ec.t.(type) { - case *idealIntType: - // nothing - case *idealFloatType: - // nothing - default: - if tm, ok := t.(*MultiType); ok && len(tm.Elems) == 0 { - return &stmtCode{w, code{ec.exec}}, nil - } - eval = genAssign(ec.t, ec) - } - return &exprCode{w, ec, eval}, nil -} - -func (e *exprCode) Type() Type { return e.e.t } - -func (e *exprCode) Run() (Value, os.Error) { - t := new(Thread) - t.f = e.w.scope.NewFrame(nil) - switch e.e.t.(type) { - case *idealIntType: - return &idealIntV{e.e.asIdealInt()()}, nil - case *idealFloatType: - return &idealFloatV{e.e.asIdealFloat()()}, nil - } - v := e.e.t.Zero() - eval := e.eval - err := t.Try(func(t *Thread) { eval(v, t) }) - return v, err -} - -func (w *World) Compile(fset *token.FileSet, text string) (Code, os.Error) { - stmts, err := parser.ParseStmtList(fset, "input", text) - if err == nil { - return w.CompileStmtList(fset, stmts) - } - - // Otherwise try as DeclList. - decls, err1 := parser.ParseDeclList(fset, "input", text) - if err1 == nil { - return w.CompileDeclList(fset, decls) - } - - // Have to pick an error. - // Parsing as statement list admits more forms, - // its error is more likely to be useful. - return nil, err -} - -type RedefinitionError struct { - Name string - Prev Def -} - -func (e *RedefinitionError) String() string { - res := "identifier " + e.Name + " redeclared" - pos := e.Prev.Pos() - if pos.IsValid() { - // TODO: fix this - currently this code is not reached by the tests - // need to get a file set (fset) from somewhere - //res += "; previous declaration at " + fset.Position(pos).String() - panic(0) - } - return res -} - -func (w *World) DefineConst(name string, t Type, val Value) os.Error { - _, prev := w.scope.DefineConst(name, token.NoPos, t, val) - if prev != nil { - return &RedefinitionError{name, prev} - } - return nil -} - -func (w *World) DefineVar(name string, t Type, val Value) os.Error { - v, prev := w.scope.DefineVar(name, token.NoPos, t) - if prev != nil { - return &RedefinitionError{name, prev} - } - v.Init = val - return nil -} diff --git a/libgo/go/exp/gui/gui.go b/libgo/go/exp/gui/gui.go new file mode 100644 index 0000000..1714991 --- /dev/null +++ b/libgo/go/exp/gui/gui.go @@ -0,0 +1,58 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package gui defines a basic graphical user interface programming model. +package gui + +import ( + "image" + "image/draw" + "os" +) + +// A Window represents a single graphics window. +type Window interface { + // Screen returns an editable Image for the window. + Screen() draw.Image + // FlushImage flushes changes made to Screen() back to screen. + FlushImage() + // EventChan returns a channel carrying UI events such as key presses, + // mouse movements and window resizes. + EventChan() <-chan interface{} + // Close closes the window. + Close() os.Error +} + +// A KeyEvent is sent for a key press or release. +type KeyEvent struct { + // The value k represents key k being pressed. + // The value -k represents key k being released. + // The specific set of key values is not specified, + // but ordinary characters represent themselves. + Key int +} + +// A MouseEvent is sent for a button press or release or for a mouse movement. +type MouseEvent struct { + // Buttons is a bit mask of buttons: 1<<0 is left, 1<<1 middle, 1<<2 right. + // It represents button state and not necessarily the state delta: bit 0 + // being on means that the left mouse button is down, but does not imply + // that the same button was up in the previous MouseEvent. + Buttons int + // Loc is the location of the cursor. + Loc image.Point + // Nsec is the event's timestamp. + Nsec int64 +} + +// A ConfigEvent is sent each time the window's color model or size changes. +// The client should respond by calling Window.Screen to obtain a new image. +type ConfigEvent struct { + Config image.Config +} + +// An ErrEvent is sent when an error occurs. +type ErrEvent struct { + Err os.Error +} diff --git a/libgo/go/exp/gui/x11/auth.go b/libgo/go/exp/gui/x11/auth.go new file mode 100644 index 0000000..d48936a --- /dev/null +++ b/libgo/go/exp/gui/x11/auth.go @@ -0,0 +1,93 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package x11 + +import ( + "bufio" + "io" + "os" +) + +// readU16BE reads a big-endian uint16 from r, using b as a scratch buffer. +func readU16BE(r io.Reader, b []byte) (uint16, os.Error) { + _, err := io.ReadFull(r, b[0:2]) + if err != nil { + return 0, err + } + return uint16(b[0])<<8 + uint16(b[1]), nil +} + +// readStr reads a length-prefixed string from r, using b as a scratch buffer. +func readStr(r io.Reader, b []byte) (string, os.Error) { + n, err := readU16BE(r, b) + if err != nil { + return "", err + } + if int(n) > len(b) { + return "", os.NewError("Xauthority entry too long for buffer") + } + _, err = io.ReadFull(r, b[0:n]) + if err != nil { + return "", err + } + return string(b[0:n]), nil +} + +// readAuth reads the X authority file and returns the name/data pair for the display. +// displayStr is the "12" out of a $DISPLAY like ":12.0". +func readAuth(displayStr string) (name, data string, err os.Error) { + // b is a scratch buffer to use and should be at least 256 bytes long + // (i.e. it should be able to hold a hostname). + var b [256]byte + // As per /usr/include/X11/Xauth.h. + const familyLocal = 256 + + fn := os.Getenv("XAUTHORITY") + if fn == "" { + home := os.Getenv("HOME") + if home == "" { + err = os.NewError("Xauthority not found: $XAUTHORITY, $HOME not set") + return + } + fn = home + "/.Xauthority" + } + r, err := os.Open(fn) + if err != nil { + return + } + defer r.Close() + br := bufio.NewReader(r) + + hostname, err := os.Hostname() + if err != nil { + return + } + for { + family, err := readU16BE(br, b[0:2]) + if err != nil { + return + } + addr, err := readStr(br, b[0:]) + if err != nil { + return + } + disp, err := readStr(br, b[0:]) + if err != nil { + return + } + name0, err := readStr(br, b[0:]) + if err != nil { + return + } + data0, err := readStr(br, b[0:]) + if err != nil { + return + } + if family == familyLocal && addr == hostname && disp == displayStr { + return name0, data0, nil + } + } + panic("unreachable") +} diff --git a/libgo/go/exp/gui/x11/conn.go b/libgo/go/exp/gui/x11/conn.go new file mode 100644 index 0000000..1d23781 --- /dev/null +++ b/libgo/go/exp/gui/x11/conn.go @@ -0,0 +1,627 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package x11 implements an X11 backend for the exp/gui package. +// +// The X protocol specification is at ftp://ftp.x.org/pub/X11R7.0/doc/PDF/proto.pdf. +// A summary of the wire format can be found in XCB's xproto.xml. +package x11 + +import ( + "bufio" + "exp/gui" + "image" + "image/draw" + "io" + "log" + "net" + "os" + "strconv" + "strings" + "time" +) + +type resID uint32 // X resource IDs. + +// TODO(nigeltao): Handle window resizes. +const ( + windowHeight = 600 + windowWidth = 800 +) + +const ( + keymapLo = 8 + keymapHi = 255 +) + +type conn struct { + c io.Closer + r *bufio.Reader + w *bufio.Writer + + gc, window, root, visual resID + + img *image.RGBA + eventc chan interface{} + mouseState gui.MouseEvent + + buf [256]byte // General purpose scratch buffer. + + flush chan bool + flushBuf0 [24]byte + flushBuf1 [4 * 1024]byte +} + +// writeSocket runs in its own goroutine, serving both FlushImage calls +// directly from the exp/gui client and indirectly from X expose events. +// It paints c.img to the X server via PutImage requests. +func (c *conn) writeSocket() { + defer c.c.Close() + for _ = range c.flush { + b := c.img.Bounds() + if b.Empty() { + continue + } + // Each X request has a 16-bit length (in terms of 4-byte units). To avoid going over + // this limit, we send PutImage for each row of the image, rather than trying to paint + // the entire image in one X request. This approach could easily be optimized (or the + // X protocol may have an escape sequence to delimit very large requests). + // TODO(nigeltao): See what XCB's xcb_put_image does in this situation. + units := 6 + b.Dx() + if units > 0xffff || b.Dy() > 0xffff { + log.Print("x11: window is too large for PutImage") + return + } + + c.flushBuf0[0] = 0x48 // PutImage opcode. + c.flushBuf0[1] = 0x02 // XCB_IMAGE_FORMAT_Z_PIXMAP. + c.flushBuf0[2] = uint8(units) + c.flushBuf0[3] = uint8(units >> 8) + setU32LE(c.flushBuf0[4:8], uint32(c.window)) + setU32LE(c.flushBuf0[8:12], uint32(c.gc)) + setU32LE(c.flushBuf0[12:16], 1<<16|uint32(b.Dx())) + c.flushBuf0[21] = 0x18 // depth = 24 bits. + + for y := b.Min.Y; y < b.Max.Y; y++ { + setU32LE(c.flushBuf0[16:20], uint32(y<<16)) + if _, err := c.w.Write(c.flushBuf0[:24]); err != nil { + if err != os.EOF { + log.Println("x11:", err.String()) + } + return + } + p := c.img.Pix[(y-b.Min.Y)*c.img.Stride:] + for x, dx := 0, 4*b.Dx(); x < dx; { + nx := dx - x + if nx > len(c.flushBuf1) { + nx = len(c.flushBuf1) &^ 3 + } + for i := 0; i < nx; i += 4 { + // X11's order is BGRX, not RGBA. + c.flushBuf1[i+0] = p[x+i+2] + c.flushBuf1[i+1] = p[x+i+1] + c.flushBuf1[i+2] = p[x+i+0] + } + x += nx + if _, err := c.w.Write(c.flushBuf1[:nx]); err != nil { + if err != os.EOF { + log.Println("x11:", err.String()) + } + return + } + } + } + if err := c.w.Flush(); err != nil { + if err != os.EOF { + log.Println("x11:", err.String()) + } + return + } + } +} + +func (c *conn) Screen() draw.Image { return c.img } + +func (c *conn) FlushImage() { + select { + case c.flush <- false: + // Flush notification sent. + default: + // Could not send. + // Flush notification must be pending already. + } +} + +func (c *conn) Close() os.Error { + // Shut down the writeSocket goroutine. This will close the socket to the + // X11 server, which will cause c.eventc to close. + close(c.flush) + for _ = range c.eventc { + // Drain the channel to allow the readSocket goroutine to shut down. + } + return nil +} + +func (c *conn) EventChan() <-chan interface{} { return c.eventc } + +// readSocket runs in its own goroutine, reading X events and sending gui +// events on c's EventChan. +func (c *conn) readSocket() { + var ( + keymap [256][]int + keysymsPerKeycode int + ) + defer close(c.eventc) + for { + // X events are always 32 bytes long. + if _, err := io.ReadFull(c.r, c.buf[:32]); err != nil { + if err != os.EOF { + c.eventc <- gui.ErrEvent{err} + } + return + } + switch c.buf[0] { + case 0x01: // Reply from a request (e.g. GetKeyboardMapping). + cookie := int(c.buf[3])<<8 | int(c.buf[2]) + if cookie != 1 { + // We issued only one request (GetKeyboardMapping) with a cookie of 1, + // so we shouldn't get any other reply from the X server. + c.eventc <- gui.ErrEvent{os.NewError("x11: unexpected cookie")} + return + } + keysymsPerKeycode = int(c.buf[1]) + b := make([]int, 256*keysymsPerKeycode) + for i := range keymap { + keymap[i] = b[i*keysymsPerKeycode : (i+1)*keysymsPerKeycode] + } + for i := keymapLo; i <= keymapHi; i++ { + m := keymap[i] + for j := range m { + u, err := readU32LE(c.r, c.buf[:4]) + if err != nil { + if err != os.EOF { + c.eventc <- gui.ErrEvent{err} + } + return + } + m[j] = int(u) + } + } + case 0x02, 0x03: // Key press, key release. + // X Keyboard Encoding is documented at http://tronche.com/gui/x/xlib/input/keyboard-encoding.html + // TODO(nigeltao): Do we need to implement the "MODE SWITCH / group modifier" feature + // or is that some no-longer-used X construct? + if keysymsPerKeycode < 2 { + // Either we haven't yet received the GetKeyboardMapping reply or + // the X server has sent one that's too short. + continue + } + keycode := int(c.buf[1]) + shift := int(c.buf[28]) & 0x01 + keysym := keymap[keycode][shift] + if keysym == 0 { + keysym = keymap[keycode][0] + } + // TODO(nigeltao): Should we send KeyEvents for Shift/Ctrl/Alt? Should Shift-A send + // the same int down the channel as the sent on just the A key? + // TODO(nigeltao): How should IME events (e.g. key presses that should generate CJK text) work? Or + // is that outside the scope of the gui.Window interface? + if c.buf[0] == 0x03 { + keysym = -keysym + } + c.eventc <- gui.KeyEvent{keysym} + case 0x04, 0x05: // Button press, button release. + mask := 1 << (c.buf[1] - 1) + if c.buf[0] == 0x04 { + c.mouseState.Buttons |= mask + } else { + c.mouseState.Buttons &^= mask + } + c.mouseState.Nsec = time.Nanoseconds() + c.eventc <- c.mouseState + case 0x06: // Motion notify. + c.mouseState.Loc.X = int(int16(c.buf[25])<<8 | int16(c.buf[24])) + c.mouseState.Loc.Y = int(int16(c.buf[27])<<8 | int16(c.buf[26])) + c.mouseState.Nsec = time.Nanoseconds() + c.eventc <- c.mouseState + case 0x0c: // Expose. + // A single user action could trigger multiple expose events (e.g. if moving another + // window with XShape'd rounded corners over our window). In that case, the X server will + // send a uint16 count (in bytes 16-17) of the number of additional expose events coming. + // We could parse each event for the (x, y, width, height) and maintain a minimal dirty + // rectangle, but for now, the simplest approach is to paint the entire window, when + // receiving the final event in the series. + if c.buf[17] == 0 && c.buf[16] == 0 { + // TODO(nigeltao): Should we ignore the very first expose event? A freshly mapped window + // will trigger expose, but until the first c.FlushImage call, there's probably nothing to + // paint but black. For an 800x600 window, at 4 bytes per pixel, each repaint writes about + // 2MB over the socket. + c.FlushImage() + } + // TODO(nigeltao): Should we listen to DestroyNotify (0x11) and ResizeRequest (0x19) events? + // What about EnterNotify (0x07) and LeaveNotify (0x08)? + } + } +} + +// connect connects to the X server given by the full X11 display name (e.g. +// ":12.0") and returns the connection as well as the portion of the full name +// that is the display number (e.g. "12"). +// Examples: +// connect(":1") // calls net.Dial("unix", "", "/tmp/.X11-unix/X1"), displayStr="1" +// connect("/tmp/launch-123/:0") // calls net.Dial("unix", "", "/tmp/launch-123/:0"), displayStr="0" +// connect("hostname:2.1") // calls net.Dial("tcp", "", "hostname:6002"), displayStr="2" +// connect("tcp/hostname:1.0") // calls net.Dial("tcp", "", "hostname:6001"), displayStr="1" +func connect(display string) (conn net.Conn, displayStr string, err os.Error) { + colonIdx := strings.LastIndex(display, ":") + if colonIdx < 0 { + return nil, "", os.NewError("bad display: " + display) + } + // Parse the section before the colon. + var protocol, host, socket string + if display[0] == '/' { + socket = display[:colonIdx] + } else { + if i := strings.LastIndex(display, "/"); i < 0 { + // The default protocol is TCP. + protocol = "tcp" + host = display[:colonIdx] + } else { + protocol = display[:i] + host = display[i+1 : colonIdx] + } + } + // Parse the section after the colon. + after := display[colonIdx+1:] + if after == "" { + return nil, "", os.NewError("bad display: " + display) + } + if i := strings.LastIndex(after, "."); i < 0 { + displayStr = after + } else { + displayStr = after[:i] + } + displayInt, err := strconv.Atoi(displayStr) + if err != nil || displayInt < 0 { + return nil, "", os.NewError("bad display: " + display) + } + // Make the connection. + if socket != "" { + conn, err = net.Dial("unix", socket+":"+displayStr) + } else if host != "" { + conn, err = net.Dial(protocol, host+":"+strconv.Itoa(6000+displayInt)) + } else { + conn, err = net.Dial("unix", "/tmp/.X11-unix/X"+displayStr) + } + if err != nil { + return nil, "", os.NewError("cannot connect to " + display + ": " + err.String()) + } + return +} + +// authenticate authenticates ourselves with the X server. +// displayStr is the "12" out of ":12.0". +func authenticate(w *bufio.Writer, displayStr string) os.Error { + key, value, err := readAuth(displayStr) + if err != nil { + return err + } + // Assume that the authentication protocol is "MIT-MAGIC-COOKIE-1". + if len(key) != 18 || len(value) != 16 { + return os.NewError("unsupported Xauth") + } + // 0x006c means little-endian. 0x000b, 0x0000 means X major version 11, minor version 0. + // 0x0012 and 0x0010 means the auth key and value have lengths 18 and 16. + // The final 0x0000 is padding, so that the string length is a multiple of 4. + _, err = io.WriteString(w, "\x6c\x00\x0b\x00\x00\x00\x12\x00\x10\x00\x00\x00") + if err != nil { + return err + } + _, err = io.WriteString(w, key) + if err != nil { + return err + } + // Again, the 0x0000 is padding. + _, err = io.WriteString(w, "\x00\x00") + if err != nil { + return err + } + _, err = io.WriteString(w, value) + if err != nil { + return err + } + err = w.Flush() + if err != nil { + return err + } + return nil +} + +// readU8 reads a uint8 from r, using b as a scratch buffer. +func readU8(r io.Reader, b []byte) (uint8, os.Error) { + _, err := io.ReadFull(r, b[:1]) + if err != nil { + return 0, err + } + return uint8(b[0]), nil +} + +// readU16LE reads a little-endian uint16 from r, using b as a scratch buffer. +func readU16LE(r io.Reader, b []byte) (uint16, os.Error) { + _, err := io.ReadFull(r, b[:2]) + if err != nil { + return 0, err + } + return uint16(b[0]) | uint16(b[1])<<8, nil +} + +// readU32LE reads a little-endian uint32 from r, using b as a scratch buffer. +func readU32LE(r io.Reader, b []byte) (uint32, os.Error) { + _, err := io.ReadFull(r, b[:4]) + if err != nil { + return 0, err + } + return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, nil +} + +// setU32LE sets b[:4] to be the little-endian representation of u. +func setU32LE(b []byte, u uint32) { + b[0] = byte((u >> 0) & 0xff) + b[1] = byte((u >> 8) & 0xff) + b[2] = byte((u >> 16) & 0xff) + b[3] = byte((u >> 24) & 0xff) +} + +// checkPixmapFormats checks that we have an agreeable X pixmap Format. +func checkPixmapFormats(r io.Reader, b []byte, n int) (agree bool, err os.Error) { + for i := 0; i < n; i++ { + _, err = io.ReadFull(r, b[:8]) + if err != nil { + return + } + // Byte 0 is depth, byte 1 is bits-per-pixel, byte 2 is scanline-pad, the rest (5) is padding. + if b[0] == 24 && b[1] == 32 { + agree = true + } + } + return +} + +// checkDepths checks that we have an agreeable X Depth (i.e. one that has an agreeable X VisualType). +func checkDepths(r io.Reader, b []byte, n int, visual uint32) (agree bool, err os.Error) { + for i := 0; i < n; i++ { + depth, err := readU16LE(r, b) + if err != nil { + return + } + depth &= 0xff + visualsLen, err := readU16LE(r, b) + if err != nil { + return + } + // Ignore 4 bytes of padding. + _, err = io.ReadFull(r, b[:4]) + if err != nil { + return + } + for j := 0; j < int(visualsLen); j++ { + // Read 24 bytes: visual(4), class(1), bits per rgb value(1), colormap entries(2), + // red mask(4), green mask(4), blue mask(4), padding(4). + v, err := readU32LE(r, b) + _, err = readU32LE(r, b) + rm, err := readU32LE(r, b) + gm, err := readU32LE(r, b) + bm, err := readU32LE(r, b) + _, err = readU32LE(r, b) + if err != nil { + return + } + if v == visual && rm == 0xff0000 && gm == 0xff00 && bm == 0xff && depth == 24 { + agree = true + } + } + } + return +} + +// checkScreens checks that we have an agreeable X Screen. +func checkScreens(r io.Reader, b []byte, n int) (root, visual uint32, err os.Error) { + for i := 0; i < n; i++ { + root0, err := readU32LE(r, b) + if err != nil { + return + } + // Ignore the next 7x4 bytes, which is: colormap, whitepixel, blackpixel, current input masks, + // width and height (pixels), width and height (mm), min and max installed maps. + _, err = io.ReadFull(r, b[:28]) + if err != nil { + return + } + visual0, err := readU32LE(r, b) + if err != nil { + return + } + // Next 4 bytes: backing stores, save unders, root depth, allowed depths length. + x, err := readU32LE(r, b) + if err != nil { + return + } + nDepths := int(x >> 24) + agree, err := checkDepths(r, b, nDepths, visual0) + if err != nil { + return + } + if agree && root == 0 { + root = root0 + visual = visual0 + } + } + return +} + +// handshake performs the protocol handshake with the X server, and ensures +// that the server provides a compatible Screen, Depth, etc. +func (c *conn) handshake() os.Error { + _, err := io.ReadFull(c.r, c.buf[:8]) + if err != nil { + return err + } + // Byte 0 should be 1 (success), bytes 2:6 should be 0xb0000000 (major/minor version 11.0). + if c.buf[0] != 1 || c.buf[2] != 11 || c.buf[3] != 0 || c.buf[4] != 0 || c.buf[5] != 0 { + return os.NewError("unsupported X version") + } + // Ignore the release number. + _, err = io.ReadFull(c.r, c.buf[:4]) + if err != nil { + return err + } + // Read the resource ID base. + resourceIdBase, err := readU32LE(c.r, c.buf[:4]) + if err != nil { + return err + } + // Read the resource ID mask. + resourceIdMask, err := readU32LE(c.r, c.buf[:4]) + if err != nil { + return err + } + if resourceIdMask < 256 { + return os.NewError("X resource ID mask is too small") + } + // Ignore the motion buffer size. + _, err = io.ReadFull(c.r, c.buf[:4]) + if err != nil { + return err + } + // Read the vendor length and round it up to a multiple of 4, + // for X11 protocol alignment reasons. + vendorLen, err := readU16LE(c.r, c.buf[:2]) + if err != nil { + return err + } + vendorLen = (vendorLen + 3) &^ 3 + // Read the maximum request length. + maxReqLen, err := readU16LE(c.r, c.buf[:2]) + if err != nil { + return err + } + if maxReqLen != 0xffff { + return os.NewError("unsupported X maximum request length") + } + // Read the roots length. + rootsLen, err := readU8(c.r, c.buf[:1]) + if err != nil { + return err + } + // Read the pixmap formats length. + pixmapFormatsLen, err := readU8(c.r, c.buf[:1]) + if err != nil { + return err + } + // Ignore some things that we don't care about (totaling 10 + vendorLen bytes): + // imageByteOrder(1), bitmapFormatBitOrder(1), bitmapFormatScanlineUnit(1) bitmapFormatScanlinePad(1), + // minKeycode(1), maxKeycode(1), padding(4), vendor (vendorLen). + if 10+int(vendorLen) > cap(c.buf) { + return os.NewError("unsupported X vendor") + } + _, err = io.ReadFull(c.r, c.buf[:10+int(vendorLen)]) + if err != nil { + return err + } + // Check that we have an agreeable pixmap format. + agree, err := checkPixmapFormats(c.r, c.buf[:8], int(pixmapFormatsLen)) + if err != nil { + return err + } + if !agree { + return os.NewError("unsupported X pixmap formats") + } + // Check that we have an agreeable screen. + root, visual, err := checkScreens(c.r, c.buf[:24], int(rootsLen)) + if err != nil { + return err + } + if root == 0 || visual == 0 { + return os.NewError("unsupported X screen") + } + c.gc = resID(resourceIdBase) + c.window = resID(resourceIdBase + 1) + c.root = resID(root) + c.visual = resID(visual) + return nil +} + +// NewWindow calls NewWindowDisplay with $DISPLAY. +func NewWindow() (gui.Window, os.Error) { + display := os.Getenv("DISPLAY") + if len(display) == 0 { + return nil, os.NewError("$DISPLAY not set") + } + return NewWindowDisplay(display) +} + +// NewWindowDisplay returns a new gui.Window, backed by a newly created and +// mapped X11 window. The X server to connect to is specified by the display +// string, such as ":1". +func NewWindowDisplay(display string) (gui.Window, os.Error) { + socket, displayStr, err := connect(display) + if err != nil { + return nil, err + } + c := new(conn) + c.c = socket + c.r = bufio.NewReader(socket) + c.w = bufio.NewWriter(socket) + err = authenticate(c.w, displayStr) + if err != nil { + return nil, err + } + err = c.handshake() + if err != nil { + return nil, err + } + + // Now that we're connected, show a window, via three X protocol messages. + // First, issue a GetKeyboardMapping request. This is the first request, and + // will be associated with a cookie of 1. + setU32LE(c.buf[0:4], 0x00020065) // 0x65 is the GetKeyboardMapping opcode, and the message is 2 x 4 bytes long. + setU32LE(c.buf[4:8], uint32((keymapHi-keymapLo+1)<<8|keymapLo)) + // Second, create a graphics context (GC). + setU32LE(c.buf[8:12], 0x00060037) // 0x37 is the CreateGC opcode, and the message is 6 x 4 bytes long. + setU32LE(c.buf[12:16], uint32(c.gc)) + setU32LE(c.buf[16:20], uint32(c.root)) + setU32LE(c.buf[20:24], 0x00010004) // Bit 2 is XCB_GC_FOREGROUND, bit 16 is XCB_GC_GRAPHICS_EXPOSURES. + setU32LE(c.buf[24:28], 0x00000000) // The Foreground is black. + setU32LE(c.buf[28:32], 0x00000000) // GraphicsExposures' value is unused. + // Third, create the window. + setU32LE(c.buf[32:36], 0x000a0001) // 0x01 is the CreateWindow opcode, and the message is 10 x 4 bytes long. + setU32LE(c.buf[36:40], uint32(c.window)) + setU32LE(c.buf[40:44], uint32(c.root)) + setU32LE(c.buf[44:48], 0x00000000) // Initial (x, y) is (0, 0). + setU32LE(c.buf[48:52], windowHeight<<16|windowWidth) + setU32LE(c.buf[52:56], 0x00010000) // Border width is 0, XCB_WINDOW_CLASS_INPUT_OUTPUT is 1. + setU32LE(c.buf[56:60], uint32(c.visual)) + setU32LE(c.buf[60:64], 0x00000802) // Bit 1 is XCB_CW_BACK_PIXEL, bit 11 is XCB_CW_EVENT_MASK. + setU32LE(c.buf[64:68], 0x00000000) // The Back-Pixel is black. + setU32LE(c.buf[68:72], 0x0000804f) // Key/button press and release, pointer motion, and expose event masks. + // Fourth, map the window. + setU32LE(c.buf[72:76], 0x00020008) // 0x08 is the MapWindow opcode, and the message is 2 x 4 bytes long. + setU32LE(c.buf[76:80], uint32(c.window)) + // Write the bytes. + _, err = c.w.Write(c.buf[:80]) + if err != nil { + return nil, err + } + err = c.w.Flush() + if err != nil { + return nil, err + } + + c.img = image.NewRGBA(windowWidth, windowHeight) + c.eventc = make(chan interface{}, 16) + c.flush = make(chan bool, 1) + go c.readSocket() + go c.writeSocket() + return c, nil +} diff --git a/libgo/go/exp/norm/composition.go b/libgo/go/exp/norm/composition.go new file mode 100644 index 0000000..b2d2aba --- /dev/null +++ b/libgo/go/exp/norm/composition.go @@ -0,0 +1,344 @@ +// 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 norm + +import "utf8" + +const ( + maxCombiningChars = 30 + 2 // +2 to hold CGJ and Hangul overflow. + maxBackRunes = maxCombiningChars - 1 + maxNFCExpansion = 3 // NFC(0x1D160) + maxNFKCExpansion = 18 // NFKC(0xFDFA) + + maxRuneSizeInDecomp = 4 + // Need to multiply by 2 as we don't reuse byte buffer space for recombining. + maxByteBufferSize = 2 * maxRuneSizeInDecomp * maxCombiningChars // 256 +) + +// reorderBuffer is used to normalize a single segment. Characters inserted with +// insert() are decomposed and reordered based on CCC. The compose() method can +// be used to recombine characters. Note that the byte buffer does not hold +// the UTF-8 characters in order. Only the rune array is maintained in sorted +// order. flush() writes the resulting segment to a byte array. +type reorderBuffer struct { + rune [maxCombiningChars]runeInfo // Per character info. + byte [maxByteBufferSize]byte // UTF-8 buffer. Referenced by runeInfo.pos. + nrune int // Number of runeInfos. + nbyte uint8 // Number or bytes. + f formInfo +} + +// reset discards all characters from the buffer. +func (rb *reorderBuffer) reset() { + rb.nrune = 0 + rb.nbyte = 0 +} + +// flush appends the normalized segment to out and resets rb. +func (rb *reorderBuffer) flush(out []byte) []byte { + for i := 0; i < rb.nrune; i++ { + start := rb.rune[i].pos + end := start + rb.rune[i].size + out = append(out, rb.byte[start:end]...) + } + rb.reset() + return out +} + +// insertOrdered inserts a rune in the buffer, ordered by Canonical Combining Class. +// It returns false if the buffer is not large enough to hold the rune. +// It is used internally by insert. +func (rb *reorderBuffer) insertOrdered(info runeInfo) bool { + n := rb.nrune + if n >= maxCombiningChars { + return false + } + b := rb.rune[:] + cc := info.ccc + if cc > 0 { + // Find insertion position + move elements to make room. + for ; n > 0; n-- { + if b[n-1].ccc <= cc { + break + } + b[n] = b[n-1] + } + } + rb.nrune += 1 + pos := uint8(rb.nbyte) + rb.nbyte += info.size + info.pos = pos + b[n] = info + return true +} + +// insert inserts the given rune in the buffer ordered by CCC. +// It returns true if the buffer was large enough to hold the decomposed rune. +func (rb *reorderBuffer) insert(src []byte, info runeInfo) bool { + if info.size == 3 && isHangul(src) { + rune, _ := utf8.DecodeRune(src) + return rb.decomposeHangul(uint32(rune)) + } + pos := rb.nbyte + if info.flags.hasDecomposition() { + dcomp := rb.f.decompose(src) + for i := 0; i < len(dcomp); i += int(info.size) { + info = rb.f.info(dcomp[i:]) + if !rb.insertOrdered(info) { + return false + } + } + copy(rb.byte[pos:], dcomp) + } else { + if !rb.insertOrdered(info) { + return false + } + copy(rb.byte[pos:], src[:info.size]) + } + return true +} + +// insertString inserts the given rune in the buffer ordered by CCC. +// It returns true if the buffer was large enough to hold the decomposed rune. +func (rb *reorderBuffer) insertString(src string, info runeInfo) bool { + if info.size == 3 && isHangulString(src) { + rune, _ := utf8.DecodeRuneInString(src) + return rb.decomposeHangul(uint32(rune)) + } + pos := rb.nbyte + dcomp := rb.f.decomposeString(src) + dn := len(dcomp) + if dn != 0 { + for i := 0; i < dn; i += int(info.size) { + info = rb.f.info(dcomp[i:]) + if !rb.insertOrdered(info) { + return false + } + } + copy(rb.byte[pos:], dcomp) + } else { + if !rb.insertOrdered(info) { + return false + } + copy(rb.byte[pos:], src[:info.size]) + } + return true +} + +// appendRune inserts a rune at the end of the buffer. It is used for Hangul. +func (rb *reorderBuffer) appendRune(rune uint32) { + bn := rb.nbyte + sz := utf8.EncodeRune(rb.byte[bn:], int(rune)) + rb.nbyte += uint8(sz) + rb.rune[rb.nrune] = runeInfo{bn, uint8(sz), 0, 0} + rb.nrune++ +} + +// assignRune sets a rune at position pos. It is used for Hangul and recomposition. +func (rb *reorderBuffer) assignRune(pos int, rune uint32) { + bn := rb.nbyte + sz := utf8.EncodeRune(rb.byte[bn:], int(rune)) + rb.rune[pos] = runeInfo{bn, uint8(sz), 0, 0} + rb.nbyte += uint8(sz) +} + +// runeAt returns the rune at position n. It is used for Hangul and recomposition. +func (rb *reorderBuffer) runeAt(n int) uint32 { + inf := rb.rune[n] + rune, _ := utf8.DecodeRune(rb.byte[inf.pos : inf.pos+inf.size]) + return uint32(rune) +} + +// bytesAt returns the UTF-8 encoding of the rune at position n. +// It is used for Hangul and recomposition. +func (rb *reorderBuffer) bytesAt(n int) []byte { + inf := rb.rune[n] + return rb.byte[inf.pos : int(inf.pos)+int(inf.size)] +} + +// For Hangul we combine algorithmically, instead of using tables. +const ( + hangulBase = 0xAC00 // UTF-8(hangulBase) -> EA B0 80 + hangulBase0 = 0xEA + hangulBase1 = 0xB0 + hangulBase2 = 0x80 + + hangulEnd = hangulBase + jamoLVTCount // UTF-8(0xD7A4) -> ED 9E A4 + hangulEnd0 = 0xED + hangulEnd1 = 0x9E + hangulEnd2 = 0xA4 + + jamoLBase = 0x1100 // UTF-8(jamoLBase) -> E1 84 00 + jamoLBase0 = 0xE1 + jamoLBase1 = 0x84 + jamoLEnd = 0x1113 + jamoVBase = 0x1161 + jamoVEnd = 0x1176 + jamoTBase = 0x11A7 + jamoTEnd = 0x11C3 + + jamoTCount = 28 + jamoVCount = 21 + jamoVTCount = 21 * 28 + jamoLVTCount = 19 * 21 * 28 +) + +// Caller must verify that len(b) >= 3. +func isHangul(b []byte) bool { + b0 := b[0] + if b0 < hangulBase0 { + return false + } + b1 := b[1] + switch { + case b0 == hangulBase0: + return b1 >= hangulBase1 + case b0 < hangulEnd0: + return true + case b0 > hangulEnd0: + return false + case b1 < hangulEnd1: + return true + } + return b1 == hangulEnd1 && b[2] < hangulEnd2 +} + +// Caller must verify that len(b) >= 3. +func isHangulString(b string) bool { + b0 := b[0] + if b0 < hangulBase0 { + return false + } + b1 := b[1] + switch { + case b0 == hangulBase0: + return b1 >= hangulBase1 + case b0 < hangulEnd0: + return true + case b0 > hangulEnd0: + return false + case b1 < hangulEnd1: + return true + } + return b1 == hangulEnd1 && b[2] < hangulEnd2 +} + +// Caller must ensure len(b) >= 2. +func isJamoVT(b []byte) bool { + // True if (rune & 0xff00) == jamoLBase + return b[0] == jamoLBase0 && (b[1]&0xFC) == jamoLBase1 +} + +func isHangulWithoutJamoT(b []byte) bool { + c, _ := utf8.DecodeRune(b) + c -= hangulBase + return c < jamoLVTCount && c%jamoTCount == 0 +} + +// decomposeHangul algorithmically decomposes a Hangul rune into +// its Jamo components. +// See http://unicode.org/reports/tr15/#Hangul for details on decomposing Hangul. +func (rb *reorderBuffer) decomposeHangul(rune uint32) bool { + b := rb.rune[:] + n := rb.nrune + if n+3 > len(b) { + return false + } + rune -= hangulBase + x := rune % jamoTCount + rune /= jamoTCount + rb.appendRune(jamoLBase + rune/jamoVCount) + rb.appendRune(jamoVBase + rune%jamoVCount) + if x != 0 { + rb.appendRune(jamoTBase + x) + } + return true +} + +// combineHangul algorithmically combines Jamo character components into Hangul. +// See http://unicode.org/reports/tr15/#Hangul for details on combining Hangul. +func (rb *reorderBuffer) combineHangul() { + k := 1 + b := rb.rune[:] + bn := rb.nrune + for s, i := 0, 1; i < bn; i++ { + cccB := b[k-1].ccc + cccC := b[i].ccc + if cccB == 0 { + s = k - 1 + } + if s != k-1 && cccB >= cccC { + // b[i] is blocked by greater-equal cccX below it + b[k] = b[i] + k++ + } else { + l := rb.runeAt(s) // also used to compare to hangulBase + v := rb.runeAt(i) // also used to compare to jamoT + switch { + case jamoLBase <= l && l < jamoLEnd && + jamoVBase <= v && v < jamoVEnd: + // 11xx plus 116x to LV + rb.assignRune(s, hangulBase+ + (l-jamoLBase)*jamoVTCount+(v-jamoVBase)*jamoTCount) + case hangulBase <= l && l < hangulEnd && + jamoTBase < v && v < jamoTEnd && + ((l-hangulBase)%jamoTCount) == 0: + // ACxx plus 11Ax to LVT + rb.assignRune(s, l+v-jamoTBase) + default: + b[k] = b[i] + k++ + } + } + } + rb.nrune = k +} + +// compose recombines the runes in the buffer. +// It should only be used to recompose a single segment, as it will not +// handle alternations between Hangul and non-Hangul characters correctly. +func (rb *reorderBuffer) compose() { + // UAX #15, section X5 , including Corrigendum #5 + // "In any character sequence beginning with starter S, a character C is + // blocked from S if and only if there is some character B between S + // and C, and either B is a starter or it has the same or higher + // combining class as C." + k := 1 + b := rb.rune[:] + bn := rb.nrune + for s, i := 0, 1; i < bn; i++ { + if isJamoVT(rb.bytesAt(i)) { + // Redo from start in Hangul mode. Necessary to support + // U+320E..U+321E in NFKC mode. + rb.combineHangul() + return + } + ii := b[i] + // We can only use combineForward as a filter if we later + // get the info for the combined character. This is more + // expensive than using the filter. Using combinesBackward() + // is safe. + if ii.flags.combinesBackward() { + cccB := b[k-1].ccc + cccC := ii.ccc + blocked := false // b[i] blocked by starter or greater or equal CCC? + if cccB == 0 { + s = k - 1 + } else { + blocked = s != k-1 && cccB >= cccC + } + if !blocked { + combined := combine(rb.runeAt(s), rb.runeAt(i)) + if combined != 0 { + rb.assignRune(s, combined) + continue + } + } + } + b[k] = b[i] + k++ + } + rb.nrune = k +} diff --git a/libgo/go/exp/norm/composition_test.go b/libgo/go/exp/norm/composition_test.go new file mode 100644 index 0000000..195a0c1 --- /dev/null +++ b/libgo/go/exp/norm/composition_test.go @@ -0,0 +1,138 @@ +// 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 norm + +import "testing" + +// TestCase is used for most tests. +type TestCase struct { + in []int + out []int +} + +type insertFunc func(rb *reorderBuffer, rune int) bool + +func insert(rb *reorderBuffer, rune int) bool { + b := []byte(string(rune)) + return rb.insert(b, rb.f.info(b)) +} + +func insertString(rb *reorderBuffer, rune int) bool { + s := string(rune) + return rb.insertString(s, rb.f.infoString(s)) +} + +func runTests(t *testing.T, name string, rb *reorderBuffer, f insertFunc, tests []TestCase) { + for i, test := range tests { + rb.reset() + for j, rune := range test.in { + b := []byte(string(rune)) + if !rb.insert(b, rb.f.info(b)) { + t.Errorf("%s:%d: insert failed for rune %d", name, i, j) + } + } + if rb.f.composing { + rb.compose() + } + if rb.nrune != len(test.out) { + t.Errorf("%s:%d: length = %d; want %d", name, i, rb.nrune, len(test.out)) + continue + } + for j, want := range test.out { + found := int(rb.runeAt(j)) + if found != want { + t.Errorf("%s:%d: runeAt(%d) = %U; want %U", name, i, j, found, want) + } + } + } +} + +func TestFlush(t *testing.T) { + rb := &reorderBuffer{f: *formTable[NFC]} + out := make([]byte, 0) + + out = rb.flush(out) + if len(out) != 0 { + t.Errorf("wrote bytes on flush of empty buffer. (len(out) = %d)", len(out)) + } + + for _, r := range []int("world!") { + insert(rb, r) + } + + out = []byte("Hello ") + out = rb.flush(out) + want := "Hello world!" + if string(out) != want { + t.Errorf(`output after flush was "%s"; want "%s"`, string(out), want) + } + if rb.nrune != 0 { + t.Errorf("flush: non-null size of info buffer (rb.nrune == %d)", rb.nrune) + } + if rb.nbyte != 0 { + t.Errorf("flush: non-null size of byte buffer (rb.nbyte == %d)", rb.nbyte) + } +} + +var insertTests = []TestCase{ + {[]int{'a'}, []int{'a'}}, + {[]int{0x300}, []int{0x300}}, + {[]int{0x300, 0x316}, []int{0x316, 0x300}}, // CCC(0x300)==230; CCC(0x316)==220 + {[]int{0x316, 0x300}, []int{0x316, 0x300}}, + {[]int{0x41, 0x316, 0x300}, []int{0x41, 0x316, 0x300}}, + {[]int{0x41, 0x300, 0x316}, []int{0x41, 0x316, 0x300}}, + {[]int{0x300, 0x316, 0x41}, []int{0x316, 0x300, 0x41}}, + {[]int{0x41, 0x300, 0x40, 0x316}, []int{0x41, 0x300, 0x40, 0x316}}, +} + +func TestInsert(t *testing.T) { + rb := &reorderBuffer{f: *formTable[NFD]} + runTests(t, "TestInsert", rb, insert, insertTests) +} + +func TestInsertString(t *testing.T) { + rb := &reorderBuffer{f: *formTable[NFD]} + runTests(t, "TestInsertString", rb, insertString, insertTests) +} + +var decompositionNFDTest = []TestCase{ + {[]int{0xC0}, []int{0x41, 0x300}}, + {[]int{0xAC00}, []int{0x1100, 0x1161}}, + {[]int{0x01C4}, []int{0x01C4}}, + {[]int{0x320E}, []int{0x320E}}, + {[]int("음ẻ과"), []int{0x110B, 0x1173, 0x11B7, 0x65, 0x309, 0x1100, 0x116A}}, +} + +var decompositionNFKDTest = []TestCase{ + {[]int{0xC0}, []int{0x41, 0x300}}, + {[]int{0xAC00}, []int{0x1100, 0x1161}}, + {[]int{0x01C4}, []int{0x44, 0x5A, 0x030C}}, + {[]int{0x320E}, []int{0x28, 0x1100, 0x1161, 0x29}}, +} + +func TestDecomposition(t *testing.T) { + rb := &reorderBuffer{} + rb.f = *formTable[NFD] + runTests(t, "TestDecompositionNFD", rb, insert, decompositionNFDTest) + rb.f = *formTable[NFKD] + runTests(t, "TestDecompositionNFKD", rb, insert, decompositionNFKDTest) +} + +var compositionTest = []TestCase{ + {[]int{0x41, 0x300}, []int{0xC0}}, + {[]int{0x41, 0x316}, []int{0x41, 0x316}}, + {[]int{0x41, 0x300, 0x35D}, []int{0xC0, 0x35D}}, + {[]int{0x41, 0x316, 0x300}, []int{0xC0, 0x316}}, + // blocking starter + {[]int{0x41, 0x316, 0x40, 0x300}, []int{0x41, 0x316, 0x40, 0x300}}, + {[]int{0x1100, 0x1161}, []int{0xAC00}}, + // parenthesized Hangul, alternate between ASCII and Hangul. + {[]int{0x28, 0x1100, 0x1161, 0x29}, []int{0x28, 0xAC00, 0x29}}, +} + +func TestComposition(t *testing.T) { + rb := &reorderBuffer{f: *formTable[NFC]} + runTests(t, "TestComposition", rb, insert, compositionTest) +} diff --git a/libgo/go/exp/norm/forminfo.go b/libgo/go/exp/norm/forminfo.go new file mode 100644 index 0000000..ee3edb8 --- /dev/null +++ b/libgo/go/exp/norm/forminfo.go @@ -0,0 +1,188 @@ +// 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 norm + +// This file contains Form-specific logic and wrappers for data in tables.go. + +type runeInfo struct { + pos uint8 // start position in reorderBuffer; used in composition.go + size uint8 // length of UTF-8 encoding of this rune + ccc uint8 // canonical combining class + flags qcInfo // quick check flags +} + +// functions dispatchable per form +type boundaryFunc func(f *formInfo, info runeInfo) bool +type lookupFunc func(b []byte) runeInfo +type lookupFuncString func(s string) runeInfo +type decompFunc func(b []byte) []byte +type decompFuncString func(s string) []byte + +// formInfo holds Form-specific functions and tables. +type formInfo struct { + form Form + + composing, compatibility bool // form type + + decompose decompFunc + decomposeString decompFuncString + info lookupFunc + infoString lookupFuncString + boundaryBefore boundaryFunc + boundaryAfter boundaryFunc +} + +var formTable []*formInfo + +func init() { + formTable = make([]*formInfo, 4) + + for i := range formTable { + f := &formInfo{} + formTable[i] = f + f.form = Form(i) + if Form(i) == NFKD || Form(i) == NFKC { + f.compatibility = true + f.decompose = decomposeNFKC + f.decomposeString = decomposeStringNFKC + f.info = lookupInfoNFKC + f.infoString = lookupInfoStringNFKC + } else { + f.decompose = decomposeNFC + f.decomposeString = decomposeStringNFC + f.info = lookupInfoNFC + f.infoString = lookupInfoStringNFC + } + if Form(i) == NFC || Form(i) == NFKC { + f.composing = true + f.boundaryBefore = compBoundaryBefore + f.boundaryAfter = compBoundaryAfter + } else { + f.boundaryBefore = decompBoundary + f.boundaryAfter = decompBoundary + } + } +} + +func decompBoundary(f *formInfo, info runeInfo) bool { + if info.ccc == 0 && info.flags.isYesD() { // Implies isHangul(b) == true + return true + } + // We assume that the CCC of the first character in a decomposition + // is always non-zero if different from info.ccc and that we can return + // false at this point. This is verified by maketables. + return false +} + +func compBoundaryBefore(f *formInfo, info runeInfo) bool { + if info.ccc == 0 && info.flags.isYesC() { + return true + } + // We assume that the CCC of the first character in a decomposition + // is always non-zero if different from info.ccc and that we can return + // false at this point. This is verified by maketables. + return false +} + +func compBoundaryAfter(f *formInfo, info runeInfo) bool { + // This misses values where the last char in a decomposition is a + // boundary such as Hangul with JamoT. + // TODO(mpvl): verify this does not lead to segments that do + // not fit in the reorderBuffer. + return info.flags.isInert() +} + +// We pack quick check data in 4 bits: +// 0: NFD_QC Yes (0) or No (1). No also means there is a decomposition. +// 1..2: NFC_QC Yes(00), No (01), or Maybe (11) +// 3: Combines forward (0 == false, 1 == true) +// +// When all 4 bits are zero, the character is inert, meaning it is never +// influenced by normalization. +// +// We pack the bits for both NFC/D and NFKC/D in one byte. +type qcInfo uint8 + +func (i qcInfo) isYesC() bool { return i&0x2 == 0 } +func (i qcInfo) isNoC() bool { return i&0x6 == 0x2 } +func (i qcInfo) isMaybe() bool { return i&0x4 != 0 } +func (i qcInfo) isYesD() bool { return i&0x1 == 0 } +func (i qcInfo) isNoD() bool { return i&0x1 != 0 } +func (i qcInfo) isInert() bool { return i&0xf == 0 } + +func (i qcInfo) combinesForward() bool { return i&0x8 != 0 } +func (i qcInfo) combinesBackward() bool { return i&0x4 != 0 } // == isMaybe +func (i qcInfo) hasDecomposition() bool { return i&0x1 != 0 } // == isNoD + +// Wrappers for tables.go + +// The 16-bit value of the decompostion tries is an index into a byte +// array of UTF-8 decomposition sequences. The first byte is the number +// of bytes in the decomposition (excluding this length byte). The actual +// sequence starts at the offset+1. +func decomposeNFC(b []byte) []byte { + p := nfcDecompTrie.lookupUnsafe(b) + n := decomps[p] + p++ + return decomps[p : p+uint16(n)] +} + +func decomposeNFKC(b []byte) []byte { + p := nfkcDecompTrie.lookupUnsafe(b) + n := decomps[p] + p++ + return decomps[p : p+uint16(n)] +} + +func decomposeStringNFC(s string) []byte { + p := nfcDecompTrie.lookupStringUnsafe(s) + n := decomps[p] + p++ + return decomps[p : p+uint16(n)] +} + +func decomposeStringNFKC(s string) []byte { + p := nfkcDecompTrie.lookupStringUnsafe(s) + n := decomps[p] + p++ + return decomps[p : p+uint16(n)] +} + +// Recomposition +// We use 32-bit keys instead of 64-bit for the two codepoint keys. +// This clips off the bits of three entries, but we know this will not +// result in a collision. In the unlikely event that changes to +// UnicodeData.txt introduce collisions, the compiler will catch it. +// Note that the recomposition map for NFC and NFKC are identical. + +// combine returns the combined rune or 0 if it doesn't exist. +func combine(a, b uint32) uint32 { + key := uint32(uint16(a))<<16 + uint32(uint16(b)) + return recompMap[key] +} + +// The 16-bit character info has the following bit layout: +// 0..7 CCC value. +// 8..11 qcInfo for NFC/NFD +// 12..15 qcInfo for NFKC/NFKD +func lookupInfoNFC(b []byte) runeInfo { + v, sz := charInfoTrie.lookup(b) + return runeInfo{0, uint8(sz), uint8(v), qcInfo(v >> 8)} +} + +func lookupInfoStringNFC(s string) runeInfo { + v, sz := charInfoTrie.lookupString(s) + return runeInfo{0, uint8(sz), uint8(v), qcInfo(v >> 8)} +} + +func lookupInfoNFKC(b []byte) runeInfo { + v, sz := charInfoTrie.lookup(b) + return runeInfo{0, uint8(sz), uint8(v), qcInfo(v >> 12)} +} + +func lookupInfoStringNFKC(s string) runeInfo { + v, sz := charInfoTrie.lookupString(s) + return runeInfo{0, uint8(sz), uint8(v), qcInfo(v >> 12)} +} diff --git a/libgo/go/exp/norm/maketables.go b/libgo/go/exp/norm/maketables.go new file mode 100644 index 0000000..e3e5700a --- /dev/null +++ b/libgo/go/exp/norm/maketables.go @@ -0,0 +1,855 @@ +// 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. + +// Normalization table generator. +// Data read from the web. + +package main + +import ( + "bufio" + "bytes" + "flag" + "fmt" + "http" + "io" + "log" + "os" + "regexp" + "strconv" + "strings" +) + +func main() { + flag.Parse() + loadUnicodeData() + loadCompositionExclusions() + completeCharFields(FCanonical) + completeCharFields(FCompatibility) + verifyComputed() + printChars() + makeTables() + testDerived() +} + +var url = flag.String("url", + "http://www.unicode.org/Public/6.0.0/ucd/", + "URL of Unicode database directory") +var tablelist = flag.String("tables", + "all", + "comma-separated list of which tables to generate; "+ + "can be 'decomp', 'recomp', 'info' and 'all'") +var test = flag.Bool("test", + false, + "test existing tables; can be used to compare web data with package data") +var verbose = flag.Bool("verbose", + false, + "write data to stdout as it is parsed") +var localFiles = flag.Bool("local", + false, + "data files have been copied to the current directory; for debugging only") + +var logger = log.New(os.Stderr, "", log.Lshortfile) + +// UnicodeData.txt has form: +// 0037;DIGIT SEVEN;Nd;0;EN;;7;7;7;N;;;;; +// 007A;LATIN SMALL LETTER Z;Ll;0;L;;;;;N;;;005A;;005A +// See http://unicode.org/reports/tr44/ for full explanation +// The fields: +const ( + FCodePoint = iota + FName + FGeneralCategory + FCanonicalCombiningClass + FBidiClass + FDecompMapping + FDecimalValue + FDigitValue + FNumericValue + FBidiMirrored + FUnicode1Name + FISOComment + FSimpleUppercaseMapping + FSimpleLowercaseMapping + FSimpleTitlecaseMapping + NumField + + MaxChar = 0x10FFFF // anything above this shouldn't exist +) + +// Quick Check properties of runes allow us to quickly +// determine whether a rune may occur in a normal form. +// For a given normal form, a rune may be guaranteed to occur +// verbatim (QC=Yes), may or may not combine with another +// rune (QC=Maybe), or may not occur (QC=No). +type QCResult int + +const ( + QCUnknown QCResult = iota + QCYes + QCNo + QCMaybe +) + +func (r QCResult) String() string { + switch r { + case QCYes: + return "Yes" + case QCNo: + return "No" + case QCMaybe: + return "Maybe" + } + return "***UNKNOWN***" +} + +const ( + FCanonical = iota // NFC or NFD + FCompatibility // NFKC or NFKD + FNumberOfFormTypes +) + +const ( + MComposed = iota // NFC or NFKC + MDecomposed // NFD or NFKD + MNumberOfModes +) + +// This contains only the properties we're interested in. +type Char struct { + name string + codePoint int // if zero, this index is not a valid code point. + ccc uint8 // canonical combining class + excludeInComp bool // from CompositionExclusions.txt + compatDecomp bool // it has a compatibility expansion + + forms [FNumberOfFormTypes]FormInfo // For FCanonical and FCompatibility + + state State +} + +var chars = make([]Char, MaxChar+1) + +func (c Char) String() string { + buf := new(bytes.Buffer) + + fmt.Fprintf(buf, "%U [%s]:\n", c.codePoint, c.name) + fmt.Fprintf(buf, " ccc: %v\n", c.ccc) + fmt.Fprintf(buf, " excludeInComp: %v\n", c.excludeInComp) + fmt.Fprintf(buf, " compatDecomp: %v\n", c.compatDecomp) + fmt.Fprintf(buf, " state: %v\n", c.state) + fmt.Fprintf(buf, " NFC:\n") + fmt.Fprint(buf, c.forms[FCanonical]) + fmt.Fprintf(buf, " NFKC:\n") + fmt.Fprint(buf, c.forms[FCompatibility]) + + return buf.String() +} + +// In UnicodeData.txt, some ranges are marked like this: +// 3400;;Lo;0;L;;;;;N;;;;; +// 4DB5;;Lo;0;L;;;;;N;;;;; +// parseCharacter keeps a state variable indicating the weirdness. +type State int + +const ( + SNormal State = iota // known to be zero for the type + SFirst + SLast + SMissing +) + +var lastChar int = 0 + +func (c Char) isValid() bool { + return c.codePoint != 0 && c.state != SMissing +} + +type FormInfo struct { + quickCheck [MNumberOfModes]QCResult // index: MComposed or MDecomposed + verified [MNumberOfModes]bool // index: MComposed or MDecomposed + + combinesForward bool // May combine with rune on the right + combinesBackward bool // May combine with rune on the left + isOneWay bool // Never appears in result + inDecomp bool // Some decompositions result in this char. + decomp Decomposition + expandedDecomp Decomposition +} + +func (f FormInfo) String() string { + buf := bytes.NewBuffer(make([]byte, 0)) + + fmt.Fprintf(buf, " quickCheck[C]: %v\n", f.quickCheck[MComposed]) + fmt.Fprintf(buf, " quickCheck[D]: %v\n", f.quickCheck[MDecomposed]) + fmt.Fprintf(buf, " cmbForward: %v\n", f.combinesForward) + fmt.Fprintf(buf, " cmbBackward: %v\n", f.combinesBackward) + fmt.Fprintf(buf, " isOneWay: %v\n", f.isOneWay) + fmt.Fprintf(buf, " inDecomp: %v\n", f.inDecomp) + fmt.Fprintf(buf, " decomposition: %v\n", f.decomp) + fmt.Fprintf(buf, " expandedDecomp: %v\n", f.expandedDecomp) + + return buf.String() +} + +type Decomposition []int + +func (d Decomposition) String() string { + return fmt.Sprintf("%.4X", d) +} + +func openReader(file string) (input io.ReadCloser) { + if *localFiles { + f, err := os.Open(file) + if err != nil { + logger.Fatal(err) + } + input = f + } else { + path := *url + file + resp, err := http.Get(path) + if err != nil { + logger.Fatal(err) + } + if resp.StatusCode != 200 { + logger.Fatal("bad GET status for "+file, resp.Status) + } + input = resp.Body + } + return +} + +func parseDecomposition(s string, skipfirst bool) (a []int, e os.Error) { + decomp := strings.Split(s, " ") + if len(decomp) > 0 && skipfirst { + decomp = decomp[1:] + } + for _, d := range decomp { + point, err := strconv.Btoui64(d, 16) + if err != nil { + return a, err + } + a = append(a, int(point)) + } + return a, nil +} + +func parseCharacter(line string) { + field := strings.Split(line, ";") + if len(field) != NumField { + logger.Fatalf("%5s: %d fields (expected %d)\n", line, len(field), NumField) + } + x, err := strconv.Btoui64(field[FCodePoint], 16) + point := int(x) + if err != nil { + logger.Fatalf("%.5s...: %s", line, err) + } + if point == 0 { + return // not interesting and we use 0 as unset + } + if point > MaxChar { + logger.Fatalf("%5s: Rune %X > MaxChar (%X)", line, point, MaxChar) + return + } + state := SNormal + switch { + case strings.Index(field[FName], ", First>") > 0: + state = SFirst + case strings.Index(field[FName], ", Last>") > 0: + state = SLast + } + firstChar := lastChar + 1 + lastChar = int(point) + if state != SLast { + firstChar = lastChar + } + x, err = strconv.Atoui64(field[FCanonicalCombiningClass]) + if err != nil { + logger.Fatalf("%U: bad ccc field: %s", int(x), err) + } + ccc := uint8(x) + decmap := field[FDecompMapping] + exp, e := parseDecomposition(decmap, false) + isCompat := false + if e != nil { + if len(decmap) > 0 { + exp, e = parseDecomposition(decmap, true) + if e != nil { + logger.Fatalf(`%U: bad decomp |%v|: "%s"`, int(x), decmap, e) + } + isCompat = true + } + } + for i := firstChar; i <= lastChar; i++ { + char := &chars[i] + char.name = field[FName] + char.codePoint = i + char.forms[FCompatibility].decomp = exp + if !isCompat { + char.forms[FCanonical].decomp = exp + } else { + char.compatDecomp = true + } + if len(decmap) > 0 { + char.forms[FCompatibility].decomp = exp + } + char.ccc = ccc + char.state = SMissing + if i == lastChar { + char.state = state + } + } + return +} + +func loadUnicodeData() { + f := openReader("UnicodeData.txt") + defer f.Close() + input := bufio.NewReader(f) + for { + line, err := input.ReadString('\n') + if err != nil { + if err == os.EOF { + break + } + logger.Fatal(err) + } + parseCharacter(line[0 : len(line)-1]) + } +} + +var singlePointRe = regexp.MustCompile(`^([0-9A-F]+) *$`) + +// CompositionExclusions.txt has form: +// 0958 # ... +// See http://unicode.org/reports/tr44/ for full explanation +func parseExclusion(line string) int { + comment := strings.Index(line, "#") + if comment >= 0 { + line = line[0:comment] + } + if len(line) == 0 { + return 0 + } + matches := singlePointRe.FindStringSubmatch(line) + if len(matches) != 2 { + logger.Fatalf("%s: %d matches (expected 1)\n", line, len(matches)) + } + point, err := strconv.Btoui64(matches[1], 16) + if err != nil { + logger.Fatalf("%.5s...: %s", line, err) + } + return int(point) +} + +func loadCompositionExclusions() { + f := openReader("CompositionExclusions.txt") + defer f.Close() + input := bufio.NewReader(f) + for { + line, err := input.ReadString('\n') + if err != nil { + if err == os.EOF { + break + } + logger.Fatal(err) + } + point := parseExclusion(line[0 : len(line)-1]) + if point == 0 { + continue + } + c := &chars[point] + if c.excludeInComp { + logger.Fatalf("%U: Duplicate entry in exclusions.", c.codePoint) + } + c.excludeInComp = true + } +} + +// hasCompatDecomp returns true if any of the recursive +// decompositions contains a compatibility expansion. +// In this case, the character may not occur in NFK*. +func hasCompatDecomp(rune int) bool { + c := &chars[rune] + if c.compatDecomp { + return true + } + for _, d := range c.forms[FCompatibility].decomp { + if hasCompatDecomp(d) { + return true + } + } + return false +} + +// Hangul related constants. +const ( + HangulBase = 0xAC00 + HangulEnd = 0xD7A4 // hangulBase + Jamo combinations (19 * 21 * 28) + + JamoLBase = 0x1100 + JamoLEnd = 0x1113 + JamoVBase = 0x1161 + JamoVEnd = 0x1176 + JamoTBase = 0x11A8 + JamoTEnd = 0x11C3 +) + +func isHangul(rune int) bool { + return HangulBase <= rune && rune < HangulEnd +} + +func ccc(rune int) uint8 { + return chars[rune].ccc +} + +// Insert a rune in a buffer, ordered by Canonical Combining Class. +func insertOrdered(b Decomposition, rune int) Decomposition { + n := len(b) + b = append(b, 0) + cc := ccc(rune) + if cc > 0 { + // Use bubble sort. + for ; n > 0; n-- { + if ccc(b[n-1]) <= cc { + break + } + b[n] = b[n-1] + } + } + b[n] = rune + return b +} + +// Recursively decompose. +func decomposeRecursive(form int, rune int, d Decomposition) Decomposition { + if isHangul(rune) { + return d + } + dcomp := chars[rune].forms[form].decomp + if len(dcomp) == 0 { + return insertOrdered(d, rune) + } + for _, c := range dcomp { + d = decomposeRecursive(form, c, d) + } + return d +} + +func completeCharFields(form int) { + // Phase 0: pre-expand decomposition. + for i := range chars { + f := &chars[i].forms[form] + if len(f.decomp) == 0 { + continue + } + exp := make(Decomposition, 0) + for _, c := range f.decomp { + exp = decomposeRecursive(form, c, exp) + } + f.expandedDecomp = exp + } + + // Phase 1: composition exclusion, mark decomposition. + for i := range chars { + c := &chars[i] + f := &c.forms[form] + + // Marks script-specific exclusions and version restricted. + f.isOneWay = c.excludeInComp + + // Singletons + f.isOneWay = f.isOneWay || len(f.decomp) == 1 + + // Non-starter decompositions + if len(f.decomp) > 1 { + chk := c.ccc != 0 || chars[f.decomp[0]].ccc != 0 + f.isOneWay = f.isOneWay || chk + } + + // Runes that decompose into more than two runes. + f.isOneWay = f.isOneWay || len(f.decomp) > 2 + + if form == FCompatibility { + f.isOneWay = f.isOneWay || hasCompatDecomp(c.codePoint) + } + + for _, rune := range f.decomp { + chars[rune].forms[form].inDecomp = true + } + } + + // Phase 2: forward and backward combining. + for i := range chars { + c := &chars[i] + f := &c.forms[form] + + if !f.isOneWay && len(f.decomp) == 2 { + f0 := &chars[f.decomp[0]].forms[form] + f1 := &chars[f.decomp[1]].forms[form] + if !f0.isOneWay { + f0.combinesForward = true + } + if !f1.isOneWay { + f1.combinesBackward = true + } + } + } + + // Phase 3: quick check values. + for i := range chars { + c := &chars[i] + f := &c.forms[form] + + switch { + case len(f.decomp) > 0: + f.quickCheck[MDecomposed] = QCNo + case isHangul(i): + f.quickCheck[MDecomposed] = QCNo + default: + f.quickCheck[MDecomposed] = QCYes + } + switch { + case f.isOneWay: + f.quickCheck[MComposed] = QCNo + case (i & 0xffff00) == JamoLBase: + f.quickCheck[MComposed] = QCYes + if JamoVBase <= i && i < JamoVEnd { + f.quickCheck[MComposed] = QCMaybe + f.combinesBackward = true + } + if JamoTBase <= i && i < JamoTEnd { + f.quickCheck[MComposed] = QCMaybe + f.combinesBackward = true + } + case !f.combinesBackward: + f.quickCheck[MComposed] = QCYes + default: + f.quickCheck[MComposed] = QCMaybe + } + } +} + +func printBytes(b []byte, name string) { + fmt.Printf("// %s: %d bytes\n", name, len(b)) + fmt.Printf("var %s = [...]byte {", name) + for i, c := range b { + switch { + case i%64 == 0: + fmt.Printf("\n// Bytes %x - %x\n", i, i+63) + case i%8 == 0: + fmt.Printf("\n") + } + fmt.Printf("0x%.2X, ", c) + } + fmt.Print("\n}\n\n") +} + +// See forminfo.go for format. +func makeEntry(f *FormInfo) uint16 { + e := uint16(0) + if f.combinesForward { + e |= 0x8 + } + if f.quickCheck[MDecomposed] == QCNo { + e |= 0x1 + } + switch f.quickCheck[MComposed] { + case QCYes: + case QCNo: + e |= 0x2 + case QCMaybe: + e |= 0x6 + default: + log.Fatalf("Illegal quickcheck value %d.", f.quickCheck[MComposed]) + } + return e +} + +// Bits +// 0..8: CCC +// 9..12: NF(C|D) qc bits. +// 13..16: NFK(C|D) qc bits. +func makeCharInfo(c Char) uint16 { + e := makeEntry(&c.forms[FCompatibility]) + e = e<<4 | makeEntry(&c.forms[FCanonical]) + e = e<<8 | uint16(c.ccc) + return e +} + +func printCharInfoTables() int { + // Quick Check + CCC trie. + t := newNode() + for i, char := range chars { + v := makeCharInfo(char) + if v != 0 { + t.insert(i, v) + } + } + return t.printTables("charInfo") +} + +func printDecompositionTables() int { + decompositions := bytes.NewBuffer(make([]byte, 0, 10000)) + size := 0 + + // Map decompositions + positionMap := make(map[string]uint16) + + // Store the uniqued decompositions in a byte buffer, + // preceded by their byte length. + for _, c := range chars { + for f := 0; f < 2; f++ { + d := c.forms[f].expandedDecomp + s := string([]int(d)) + if _, ok := positionMap[s]; !ok { + p := decompositions.Len() + decompositions.WriteByte(uint8(len(s))) + decompositions.WriteString(s) + positionMap[s] = uint16(p) + } + } + } + b := decompositions.Bytes() + printBytes(b, "decomps") + size += len(b) + + nfcT := newNode() + nfkcT := newNode() + for i, c := range chars { + d := c.forms[FCanonical].expandedDecomp + if len(d) != 0 { + nfcT.insert(i, positionMap[string([]int(d))]) + if ccc(c.codePoint) != ccc(d[0]) { + // We assume the lead ccc of a decomposition is !=0 in this case. + if ccc(d[0]) == 0 { + logger.Fatal("Expected differing CCC to be non-zero.") + } + } + } + d = c.forms[FCompatibility].expandedDecomp + if len(d) != 0 { + nfkcT.insert(i, positionMap[string([]int(d))]) + if ccc(c.codePoint) != ccc(d[0]) { + // We assume the lead ccc of a decomposition is !=0 in this case. + if ccc(d[0]) == 0 { + logger.Fatal("Expected differing CCC to be non-zero.") + } + } + } + } + size += nfcT.printTables("nfcDecomp") + size += nfkcT.printTables("nfkcDecomp") + return size +} + +func contains(sa []string, s string) bool { + for _, a := range sa { + if a == s { + return true + } + } + return false +} + +// Extract the version number from the URL. +func version() string { + // From http://www.unicode.org/standard/versions/#Version_Numbering: + // for the later Unicode versions, data files are located in + // versioned directories. + fields := strings.Split(*url, "/") + for _, f := range fields { + if match, _ := regexp.MatchString(`[0-9]\.[0-9]\.[0-9]`, f); match { + return f + } + } + logger.Fatal("unknown version") + return "Unknown" +} + +const fileHeader = `// Generated by running +// maketables --tables=%s --url=%s +// DO NOT EDIT + +package norm + +` + +func makeTables() { + size := 0 + if *tablelist == "" { + return + } + list := strings.Split(*tablelist, ",") + if *tablelist == "all" { + list = []string{"decomp", "recomp", "info"} + } + fmt.Printf(fileHeader, *tablelist, *url) + + fmt.Println("// Version is the Unicode edition from which the tables are derived.") + fmt.Printf("const Version = %q\n\n", version()) + + if contains(list, "decomp") { + size += printDecompositionTables() + } + + if contains(list, "recomp") { + // Note that we use 32 bit keys, instead of 64 bit. + // This clips the bits of three entries, but we know + // this won't cause a collision. The compiler will catch + // any changes made to UnicodeData.txt that introduces + // a collision. + // Note that the recomposition map for NFC and NFKC + // are identical. + + // Recomposition map + nrentries := 0 + for _, c := range chars { + f := c.forms[FCanonical] + if !f.isOneWay && len(f.decomp) > 0 { + nrentries++ + } + } + sz := nrentries * 8 + size += sz + fmt.Printf("// recompMap: %d bytes (entries only)\n", sz) + fmt.Println("var recompMap = map[uint32]uint32{") + for i, c := range chars { + f := c.forms[FCanonical] + d := f.decomp + if !f.isOneWay && len(d) > 0 { + key := uint32(uint16(d[0]))<<16 + uint32(uint16(d[1])) + fmt.Printf("0x%.8X: 0x%.4X,\n", key, i) + } + } + fmt.Printf("}\n\n") + } + + if contains(list, "info") { + size += printCharInfoTables() + } + fmt.Printf("// Total size of tables: %dKB (%d bytes)\n", (size+512)/1024, size) +} + +func printChars() { + if *verbose { + for _, c := range chars { + if !c.isValid() || c.state == SMissing { + continue + } + fmt.Println(c) + } + } +} + +// verifyComputed does various consistency tests. +func verifyComputed() { + for i, c := range chars { + for _, f := range c.forms { + isNo := (f.quickCheck[MDecomposed] == QCNo) + if (len(f.decomp) > 0) != isNo && !isHangul(i) { + log.Fatalf("%U: NF*D must be no if rune decomposes", i) + } + + isMaybe := f.quickCheck[MComposed] == QCMaybe + if f.combinesBackward != isMaybe { + log.Fatalf("%U: NF*C must be maybe if combinesBackward", i) + } + } + } +} + +var qcRe = regexp.MustCompile(`^([0-9A-F\.]+) *; (NF.*_QC); ([YNM]) #.*$`) + +// Use values in DerivedNormalizationProps.txt to compare against the +// values we computed. +// DerivedNormalizationProps.txt has form: +// 00C0..00C5 ; NFD_QC; N # ... +// 0374 ; NFD_QC; N # ... +// See http://unicode.org/reports/tr44/ for full explanation +func testDerived() { + if !*test { + return + } + f := openReader("DerivedNormalizationProps.txt") + defer f.Close() + input := bufio.NewReader(f) + for { + line, err := input.ReadString('\n') + if err != nil { + if err == os.EOF { + break + } + logger.Fatal(err) + } + qc := qcRe.FindStringSubmatch(line) + if qc == nil { + continue + } + rng := strings.Split(qc[1], "..") + i, err := strconv.Btoui64(rng[0], 16) + if err != nil { + log.Fatal(err) + } + j := i + if len(rng) > 1 { + j, err = strconv.Btoui64(rng[1], 16) + if err != nil { + log.Fatal(err) + } + } + var ftype, mode int + qt := strings.TrimSpace(qc[2]) + switch qt { + case "NFC_QC": + ftype, mode = FCanonical, MComposed + case "NFD_QC": + ftype, mode = FCanonical, MDecomposed + case "NFKC_QC": + ftype, mode = FCompatibility, MComposed + case "NFKD_QC": + ftype, mode = FCompatibility, MDecomposed + default: + log.Fatalf(`Unexpected quick check type "%s"`, qt) + } + var qr QCResult + switch qc[3] { + case "Y": + qr = QCYes + case "N": + qr = QCNo + case "M": + qr = QCMaybe + default: + log.Fatalf(`Unexpected quick check value "%s"`, qc[3]) + } + var lastFailed bool + // Verify current + for ; i <= j; i++ { + c := &chars[int(i)] + c.forms[ftype].verified[mode] = true + curqr := c.forms[ftype].quickCheck[mode] + if curqr != qr { + if !lastFailed { + logger.Printf("%s: %.4X..%.4X -- %s\n", + qt, int(i), int(j), line[0:50]) + } + logger.Printf("%U: FAILED %s (was %v need %v)\n", + int(i), qt, curqr, qr) + lastFailed = true + } + } + } + // Any unspecified value must be QCYes. Verify this. + for i, c := range chars { + for j, fd := range c.forms { + for k, qr := range fd.quickCheck { + if !fd.verified[k] && qr != QCYes { + m := "%U: FAIL F:%d M:%d (was %v need Yes) %s\n" + logger.Printf(m, i, j, k, qr, c.name) + } + } + } + } +} diff --git a/libgo/go/exp/norm/maketesttables.go b/libgo/go/exp/norm/maketesttables.go new file mode 100644 index 0000000..c5f6a64 --- /dev/null +++ b/libgo/go/exp/norm/maketesttables.go @@ -0,0 +1,42 @@ +// 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. + +// Generate test data for trie code. + +package main + +import ( + "fmt" +) + +func main() { + printTestTables() +} + +// We take the smallest, largest and an arbitrary value for each +// of the UTF-8 sequence lengths. +var testRunes = []int{ + 0x01, 0x0C, 0x7F, // 1-byte sequences + 0x80, 0x100, 0x7FF, // 2-byte sequences + 0x800, 0x999, 0xFFFF, // 3-byte sequences + 0x10000, 0x10101, 0x10FFFF, // 4-byte sequences +} + +const fileHeader = `// Generated by running +// maketesttables +// DO NOT EDIT + +package norm + +` + +func printTestTables() { + fmt.Print(fileHeader) + fmt.Printf("var testRunes = %#v\n\n", testRunes) + t := newNode() + for i, r := range testRunes { + t.insert(r, uint16(i)) + } + t.printTables("testdata") +} diff --git a/libgo/go/exp/norm/norm_test.go b/libgo/go/exp/norm/norm_test.go new file mode 100644 index 0000000..12dacfc --- /dev/null +++ b/libgo/go/exp/norm/norm_test.go @@ -0,0 +1,14 @@ +// 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 norm_test + +import ( + "testing" +) + +func TestPlaceHolder(t *testing.T) { + // Does nothing, just allows the Makefile to be canonical + // while waiting for the package itself to be written. +} diff --git a/libgo/go/exp/norm/normalize.go b/libgo/go/exp/norm/normalize.go new file mode 100644 index 0000000..e9d18dd --- /dev/null +++ b/libgo/go/exp/norm/normalize.go @@ -0,0 +1,99 @@ +// 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 norm contains types and functions for normalizing Unicode strings. +package norm + +// A Form denotes a canonical representation of Unicode code points. +// The Unicode-defined normalization and equivalence forms are: +// +// NFC Unicode Normalization Form C +// NFD Unicode Normalization Form D +// NFKC Unicode Normalization Form KC +// NFKD Unicode Normalization Form KD +// +// For a Form f, this documentation uses the notation f(x) to mean +// the bytes or string x converted to the given form. +// A position n in x is called a boundary if conversion to the form can +// proceed independently on both sides: +// f(x) == append(f(x[0:n]), f(x[n:])...) +// +// References: http://unicode.org/reports/tr15/ and +// http://unicode.org/notes/tn5/. +type Form int + +const ( + NFC Form = iota + NFD + NFKC + NFKD +) + +// Bytes returns f(b). May return b if f(b) = b. +func (f Form) Bytes(b []byte) []byte { + panic("not implemented") +} + +// String returns f(s). +func (f Form) String(s string) string { + panic("not implemented") +} + +// IsNormal returns true if b == f(b). +func (f Form) IsNormal(b []byte) bool { + panic("not implemented") +} + +// IsNormalString returns true if s == f(s). +func (f Form) IsNormalString(s string) bool { + panic("not implemented") +} + +// Append returns f(append(out, b...)). +// The buffer out must be empty or equal to f(out). +func (f Form) Append(out, b []byte) []byte { + panic("not implemented") +} + +// AppendString returns f(append(out, []byte(s))). +// The buffer out must be empty or equal to f(out). +func (f Form) AppendString(out []byte, s string) []byte { + panic("not implemented") +} + +// QuickSpan returns a boundary n such that b[0:n] == f(b[0:n]). +// It is not guaranteed to return the largest such n. +func (f Form) QuickSpan(b []byte) int { + panic("not implemented") +} + +// QuickSpanString returns a boundary n such that b[0:n] == f(s[0:n]). +// It is not guaranteed to return the largest such n. +func (f Form) QuickSpanString(s string) int { + panic("not implemented") +} + +// FirstBoundary returns the position i of the first boundary in b. +// It returns len(b), false if b contains no boundaries. +func (f Form) FirstBoundary(b []byte) (i int, ok bool) { + panic("not implemented") +} + +// FirstBoundaryInString return the position i of the first boundary in s. +// It returns len(s), false if s contains no boundaries. +func (f Form) FirstBoundaryInString(s string) (i int, ok bool) { + panic("not implemented") +} + +// LastBoundaryIn returns the position i of the last boundary in b. +// It returns 0, false if b contains no boundary. +func (f Form) LastBoundary(b []byte) (i int, ok bool) { + panic("not implemented") +} + +// LastBoundaryInString returns the position i of the last boundary in s. +// It returns 0, false if s contains no boundary. +func (f Form) LastBoundaryInString(s string) (i int, ok bool) { + panic("not implemented") +} diff --git a/libgo/go/exp/norm/tables.go b/libgo/go/exp/norm/tables.go new file mode 100644 index 0000000..76995c2 --- /dev/null +++ b/libgo/go/exp/norm/tables.go @@ -0,0 +1,6580 @@ +// Generated by running +// maketables --tables=all --url=http://www.unicode.org/Public/6.0.0/ucd/ +// DO NOT EDIT + +package norm + +// Version is the Unicode edition from which the tables are derived. +const Version = "6.0.0" + +// decomps: 17618 bytes +var decomps = [...]byte{ + // Bytes 0 - 3f + 0x00, 0x01, 0x20, 0x03, 0x20, 0xCC, 0x88, 0x01, + 0x61, 0x03, 0x20, 0xCC, 0x84, 0x01, 0x32, 0x01, + 0x33, 0x03, 0x20, 0xCC, 0x81, 0x02, 0xCE, 0xBC, + 0x03, 0x20, 0xCC, 0xA7, 0x01, 0x31, 0x01, 0x6F, + 0x05, 0x31, 0xE2, 0x81, 0x84, 0x34, 0x05, 0x31, + 0xE2, 0x81, 0x84, 0x32, 0x05, 0x33, 0xE2, 0x81, + 0x84, 0x34, 0x03, 0x41, 0xCC, 0x80, 0x03, 0x41, + 0xCC, 0x81, 0x03, 0x41, 0xCC, 0x82, 0x03, 0x41, + // Bytes 40 - 7f + 0xCC, 0x83, 0x03, 0x41, 0xCC, 0x88, 0x03, 0x41, + 0xCC, 0x8A, 0x03, 0x43, 0xCC, 0xA7, 0x03, 0x45, + 0xCC, 0x80, 0x03, 0x45, 0xCC, 0x81, 0x03, 0x45, + 0xCC, 0x82, 0x03, 0x45, 0xCC, 0x88, 0x03, 0x49, + 0xCC, 0x80, 0x03, 0x49, 0xCC, 0x81, 0x03, 0x49, + 0xCC, 0x82, 0x03, 0x49, 0xCC, 0x88, 0x03, 0x4E, + 0xCC, 0x83, 0x03, 0x4F, 0xCC, 0x80, 0x03, 0x4F, + 0xCC, 0x81, 0x03, 0x4F, 0xCC, 0x82, 0x03, 0x4F, + // Bytes 80 - bf + 0xCC, 0x83, 0x03, 0x4F, 0xCC, 0x88, 0x03, 0x55, + 0xCC, 0x80, 0x03, 0x55, 0xCC, 0x81, 0x03, 0x55, + 0xCC, 0x82, 0x03, 0x55, 0xCC, 0x88, 0x03, 0x59, + 0xCC, 0x81, 0x03, 0x61, 0xCC, 0x80, 0x03, 0x61, + 0xCC, 0x81, 0x03, 0x61, 0xCC, 0x82, 0x03, 0x61, + 0xCC, 0x83, 0x03, 0x61, 0xCC, 0x88, 0x03, 0x61, + 0xCC, 0x8A, 0x03, 0x63, 0xCC, 0xA7, 0x03, 0x65, + 0xCC, 0x80, 0x03, 0x65, 0xCC, 0x81, 0x03, 0x65, + // Bytes c0 - ff + 0xCC, 0x82, 0x03, 0x65, 0xCC, 0x88, 0x03, 0x69, + 0xCC, 0x80, 0x03, 0x69, 0xCC, 0x81, 0x03, 0x69, + 0xCC, 0x82, 0x03, 0x69, 0xCC, 0x88, 0x03, 0x6E, + 0xCC, 0x83, 0x03, 0x6F, 0xCC, 0x80, 0x03, 0x6F, + 0xCC, 0x81, 0x03, 0x6F, 0xCC, 0x82, 0x03, 0x6F, + 0xCC, 0x83, 0x03, 0x6F, 0xCC, 0x88, 0x03, 0x75, + 0xCC, 0x80, 0x03, 0x75, 0xCC, 0x81, 0x03, 0x75, + 0xCC, 0x82, 0x03, 0x75, 0xCC, 0x88, 0x03, 0x79, + // Bytes 100 - 13f + 0xCC, 0x81, 0x03, 0x79, 0xCC, 0x88, 0x03, 0x41, + 0xCC, 0x84, 0x03, 0x61, 0xCC, 0x84, 0x03, 0x41, + 0xCC, 0x86, 0x03, 0x61, 0xCC, 0x86, 0x03, 0x41, + 0xCC, 0xA8, 0x03, 0x61, 0xCC, 0xA8, 0x03, 0x43, + 0xCC, 0x81, 0x03, 0x63, 0xCC, 0x81, 0x03, 0x43, + 0xCC, 0x82, 0x03, 0x63, 0xCC, 0x82, 0x03, 0x43, + 0xCC, 0x87, 0x03, 0x63, 0xCC, 0x87, 0x03, 0x43, + 0xCC, 0x8C, 0x03, 0x63, 0xCC, 0x8C, 0x03, 0x44, + // Bytes 140 - 17f + 0xCC, 0x8C, 0x03, 0x64, 0xCC, 0x8C, 0x03, 0x45, + 0xCC, 0x84, 0x03, 0x65, 0xCC, 0x84, 0x03, 0x45, + 0xCC, 0x86, 0x03, 0x65, 0xCC, 0x86, 0x03, 0x45, + 0xCC, 0x87, 0x03, 0x65, 0xCC, 0x87, 0x03, 0x45, + 0xCC, 0xA8, 0x03, 0x65, 0xCC, 0xA8, 0x03, 0x45, + 0xCC, 0x8C, 0x03, 0x65, 0xCC, 0x8C, 0x03, 0x47, + 0xCC, 0x82, 0x03, 0x67, 0xCC, 0x82, 0x03, 0x47, + 0xCC, 0x86, 0x03, 0x67, 0xCC, 0x86, 0x03, 0x47, + // Bytes 180 - 1bf + 0xCC, 0x87, 0x03, 0x67, 0xCC, 0x87, 0x03, 0x47, + 0xCC, 0xA7, 0x03, 0x67, 0xCC, 0xA7, 0x03, 0x48, + 0xCC, 0x82, 0x03, 0x68, 0xCC, 0x82, 0x03, 0x49, + 0xCC, 0x83, 0x03, 0x69, 0xCC, 0x83, 0x03, 0x49, + 0xCC, 0x84, 0x03, 0x69, 0xCC, 0x84, 0x03, 0x49, + 0xCC, 0x86, 0x03, 0x69, 0xCC, 0x86, 0x03, 0x49, + 0xCC, 0xA8, 0x03, 0x69, 0xCC, 0xA8, 0x03, 0x49, + 0xCC, 0x87, 0x02, 0x49, 0x4A, 0x02, 0x69, 0x6A, + // Bytes 1c0 - 1ff + 0x03, 0x4A, 0xCC, 0x82, 0x03, 0x6A, 0xCC, 0x82, + 0x03, 0x4B, 0xCC, 0xA7, 0x03, 0x6B, 0xCC, 0xA7, + 0x03, 0x4C, 0xCC, 0x81, 0x03, 0x6C, 0xCC, 0x81, + 0x03, 0x4C, 0xCC, 0xA7, 0x03, 0x6C, 0xCC, 0xA7, + 0x03, 0x4C, 0xCC, 0x8C, 0x03, 0x6C, 0xCC, 0x8C, + 0x03, 0x4C, 0xC2, 0xB7, 0x03, 0x6C, 0xC2, 0xB7, + 0x03, 0x4E, 0xCC, 0x81, 0x03, 0x6E, 0xCC, 0x81, + 0x03, 0x4E, 0xCC, 0xA7, 0x03, 0x6E, 0xCC, 0xA7, + // Bytes 200 - 23f + 0x03, 0x4E, 0xCC, 0x8C, 0x03, 0x6E, 0xCC, 0x8C, + 0x03, 0xCA, 0xBC, 0x6E, 0x03, 0x4F, 0xCC, 0x84, + 0x03, 0x6F, 0xCC, 0x84, 0x03, 0x4F, 0xCC, 0x86, + 0x03, 0x6F, 0xCC, 0x86, 0x03, 0x4F, 0xCC, 0x8B, + 0x03, 0x6F, 0xCC, 0x8B, 0x03, 0x52, 0xCC, 0x81, + 0x03, 0x72, 0xCC, 0x81, 0x03, 0x52, 0xCC, 0xA7, + 0x03, 0x72, 0xCC, 0xA7, 0x03, 0x52, 0xCC, 0x8C, + 0x03, 0x72, 0xCC, 0x8C, 0x03, 0x53, 0xCC, 0x81, + // Bytes 240 - 27f + 0x03, 0x73, 0xCC, 0x81, 0x03, 0x53, 0xCC, 0x82, + 0x03, 0x73, 0xCC, 0x82, 0x03, 0x53, 0xCC, 0xA7, + 0x03, 0x73, 0xCC, 0xA7, 0x03, 0x53, 0xCC, 0x8C, + 0x03, 0x73, 0xCC, 0x8C, 0x03, 0x54, 0xCC, 0xA7, + 0x03, 0x74, 0xCC, 0xA7, 0x03, 0x54, 0xCC, 0x8C, + 0x03, 0x74, 0xCC, 0x8C, 0x03, 0x55, 0xCC, 0x83, + 0x03, 0x75, 0xCC, 0x83, 0x03, 0x55, 0xCC, 0x84, + 0x03, 0x75, 0xCC, 0x84, 0x03, 0x55, 0xCC, 0x86, + // Bytes 280 - 2bf + 0x03, 0x75, 0xCC, 0x86, 0x03, 0x55, 0xCC, 0x8A, + 0x03, 0x75, 0xCC, 0x8A, 0x03, 0x55, 0xCC, 0x8B, + 0x03, 0x75, 0xCC, 0x8B, 0x03, 0x55, 0xCC, 0xA8, + 0x03, 0x75, 0xCC, 0xA8, 0x03, 0x57, 0xCC, 0x82, + 0x03, 0x77, 0xCC, 0x82, 0x03, 0x59, 0xCC, 0x82, + 0x03, 0x79, 0xCC, 0x82, 0x03, 0x59, 0xCC, 0x88, + 0x03, 0x5A, 0xCC, 0x81, 0x03, 0x7A, 0xCC, 0x81, + 0x03, 0x5A, 0xCC, 0x87, 0x03, 0x7A, 0xCC, 0x87, + // Bytes 2c0 - 2ff + 0x03, 0x5A, 0xCC, 0x8C, 0x03, 0x7A, 0xCC, 0x8C, + 0x01, 0x73, 0x03, 0x4F, 0xCC, 0x9B, 0x03, 0x6F, + 0xCC, 0x9B, 0x03, 0x55, 0xCC, 0x9B, 0x03, 0x75, + 0xCC, 0x9B, 0x04, 0x44, 0x5A, 0xCC, 0x8C, 0x04, + 0x44, 0x7A, 0xCC, 0x8C, 0x04, 0x64, 0x7A, 0xCC, + 0x8C, 0x02, 0x4C, 0x4A, 0x02, 0x4C, 0x6A, 0x02, + 0x6C, 0x6A, 0x02, 0x4E, 0x4A, 0x02, 0x4E, 0x6A, + 0x02, 0x6E, 0x6A, 0x03, 0x41, 0xCC, 0x8C, 0x03, + // Bytes 300 - 33f + 0x61, 0xCC, 0x8C, 0x03, 0x49, 0xCC, 0x8C, 0x03, + 0x69, 0xCC, 0x8C, 0x03, 0x4F, 0xCC, 0x8C, 0x03, + 0x6F, 0xCC, 0x8C, 0x03, 0x55, 0xCC, 0x8C, 0x03, + 0x75, 0xCC, 0x8C, 0x05, 0x55, 0xCC, 0x88, 0xCC, + 0x84, 0x05, 0x75, 0xCC, 0x88, 0xCC, 0x84, 0x05, + 0x55, 0xCC, 0x88, 0xCC, 0x81, 0x05, 0x75, 0xCC, + 0x88, 0xCC, 0x81, 0x05, 0x55, 0xCC, 0x88, 0xCC, + 0x8C, 0x05, 0x75, 0xCC, 0x88, 0xCC, 0x8C, 0x05, + // Bytes 340 - 37f + 0x55, 0xCC, 0x88, 0xCC, 0x80, 0x05, 0x75, 0xCC, + 0x88, 0xCC, 0x80, 0x05, 0x41, 0xCC, 0x88, 0xCC, + 0x84, 0x05, 0x61, 0xCC, 0x88, 0xCC, 0x84, 0x05, + 0x41, 0xCC, 0x87, 0xCC, 0x84, 0x05, 0x61, 0xCC, + 0x87, 0xCC, 0x84, 0x04, 0xC3, 0x86, 0xCC, 0x84, + 0x04, 0xC3, 0xA6, 0xCC, 0x84, 0x03, 0x47, 0xCC, + 0x8C, 0x03, 0x67, 0xCC, 0x8C, 0x03, 0x4B, 0xCC, + 0x8C, 0x03, 0x6B, 0xCC, 0x8C, 0x03, 0x4F, 0xCC, + // Bytes 380 - 3bf + 0xA8, 0x03, 0x6F, 0xCC, 0xA8, 0x05, 0x4F, 0xCC, + 0xA8, 0xCC, 0x84, 0x05, 0x6F, 0xCC, 0xA8, 0xCC, + 0x84, 0x04, 0xC6, 0xB7, 0xCC, 0x8C, 0x04, 0xCA, + 0x92, 0xCC, 0x8C, 0x03, 0x6A, 0xCC, 0x8C, 0x02, + 0x44, 0x5A, 0x02, 0x44, 0x7A, 0x02, 0x64, 0x7A, + 0x03, 0x47, 0xCC, 0x81, 0x03, 0x67, 0xCC, 0x81, + 0x03, 0x4E, 0xCC, 0x80, 0x03, 0x6E, 0xCC, 0x80, + 0x05, 0x41, 0xCC, 0x8A, 0xCC, 0x81, 0x05, 0x61, + // Bytes 3c0 - 3ff + 0xCC, 0x8A, 0xCC, 0x81, 0x04, 0xC3, 0x86, 0xCC, + 0x81, 0x04, 0xC3, 0xA6, 0xCC, 0x81, 0x04, 0xC3, + 0x98, 0xCC, 0x81, 0x04, 0xC3, 0xB8, 0xCC, 0x81, + 0x03, 0x41, 0xCC, 0x8F, 0x03, 0x61, 0xCC, 0x8F, + 0x03, 0x41, 0xCC, 0x91, 0x03, 0x61, 0xCC, 0x91, + 0x03, 0x45, 0xCC, 0x8F, 0x03, 0x65, 0xCC, 0x8F, + 0x03, 0x45, 0xCC, 0x91, 0x03, 0x65, 0xCC, 0x91, + 0x03, 0x49, 0xCC, 0x8F, 0x03, 0x69, 0xCC, 0x8F, + // Bytes 400 - 43f + 0x03, 0x49, 0xCC, 0x91, 0x03, 0x69, 0xCC, 0x91, + 0x03, 0x4F, 0xCC, 0x8F, 0x03, 0x6F, 0xCC, 0x8F, + 0x03, 0x4F, 0xCC, 0x91, 0x03, 0x6F, 0xCC, 0x91, + 0x03, 0x52, 0xCC, 0x8F, 0x03, 0x72, 0xCC, 0x8F, + 0x03, 0x52, 0xCC, 0x91, 0x03, 0x72, 0xCC, 0x91, + 0x03, 0x55, 0xCC, 0x8F, 0x03, 0x75, 0xCC, 0x8F, + 0x03, 0x55, 0xCC, 0x91, 0x03, 0x75, 0xCC, 0x91, + 0x03, 0x53, 0xCC, 0xA6, 0x03, 0x73, 0xCC, 0xA6, + // Bytes 440 - 47f + 0x03, 0x54, 0xCC, 0xA6, 0x03, 0x74, 0xCC, 0xA6, + 0x03, 0x48, 0xCC, 0x8C, 0x03, 0x68, 0xCC, 0x8C, + 0x03, 0x41, 0xCC, 0x87, 0x03, 0x61, 0xCC, 0x87, + 0x03, 0x45, 0xCC, 0xA7, 0x03, 0x65, 0xCC, 0xA7, + 0x05, 0x4F, 0xCC, 0x88, 0xCC, 0x84, 0x05, 0x6F, + 0xCC, 0x88, 0xCC, 0x84, 0x05, 0x4F, 0xCC, 0x83, + 0xCC, 0x84, 0x05, 0x6F, 0xCC, 0x83, 0xCC, 0x84, + 0x03, 0x4F, 0xCC, 0x87, 0x03, 0x6F, 0xCC, 0x87, + // Bytes 480 - 4bf + 0x05, 0x4F, 0xCC, 0x87, 0xCC, 0x84, 0x05, 0x6F, + 0xCC, 0x87, 0xCC, 0x84, 0x03, 0x59, 0xCC, 0x84, + 0x03, 0x79, 0xCC, 0x84, 0x01, 0x68, 0x02, 0xC9, + 0xA6, 0x01, 0x6A, 0x01, 0x72, 0x02, 0xC9, 0xB9, + 0x02, 0xC9, 0xBB, 0x02, 0xCA, 0x81, 0x01, 0x77, + 0x01, 0x79, 0x03, 0x20, 0xCC, 0x86, 0x03, 0x20, + 0xCC, 0x87, 0x03, 0x20, 0xCC, 0x8A, 0x03, 0x20, + 0xCC, 0xA8, 0x03, 0x20, 0xCC, 0x83, 0x03, 0x20, + // Bytes 4c0 - 4ff + 0xCC, 0x8B, 0x02, 0xC9, 0xA3, 0x01, 0x6C, 0x01, + 0x78, 0x02, 0xCA, 0x95, 0x02, 0xCC, 0x80, 0x02, + 0xCC, 0x81, 0x02, 0xCC, 0x93, 0x04, 0xCC, 0x88, + 0xCC, 0x81, 0x02, 0xCA, 0xB9, 0x03, 0x20, 0xCD, + 0x85, 0x01, 0x3B, 0x04, 0xC2, 0xA8, 0xCC, 0x81, + 0x05, 0x20, 0xCC, 0x88, 0xCC, 0x81, 0x04, 0xCE, + 0x91, 0xCC, 0x81, 0x02, 0xC2, 0xB7, 0x04, 0xCE, + 0x95, 0xCC, 0x81, 0x04, 0xCE, 0x97, 0xCC, 0x81, + // Bytes 500 - 53f + 0x04, 0xCE, 0x99, 0xCC, 0x81, 0x04, 0xCE, 0x9F, + 0xCC, 0x81, 0x04, 0xCE, 0xA5, 0xCC, 0x81, 0x04, + 0xCE, 0xA9, 0xCC, 0x81, 0x06, 0xCE, 0xB9, 0xCC, + 0x88, 0xCC, 0x81, 0x04, 0xCE, 0x99, 0xCC, 0x88, + 0x04, 0xCE, 0xA5, 0xCC, 0x88, 0x04, 0xCE, 0xB1, + 0xCC, 0x81, 0x04, 0xCE, 0xB5, 0xCC, 0x81, 0x04, + 0xCE, 0xB7, 0xCC, 0x81, 0x04, 0xCE, 0xB9, 0xCC, + 0x81, 0x06, 0xCF, 0x85, 0xCC, 0x88, 0xCC, 0x81, + // Bytes 540 - 57f + 0x04, 0xCE, 0xB9, 0xCC, 0x88, 0x04, 0xCF, 0x85, + 0xCC, 0x88, 0x04, 0xCE, 0xBF, 0xCC, 0x81, 0x04, + 0xCF, 0x85, 0xCC, 0x81, 0x04, 0xCF, 0x89, 0xCC, + 0x81, 0x02, 0xCE, 0xB2, 0x02, 0xCE, 0xB8, 0x02, + 0xCE, 0xA5, 0x04, 0xCF, 0x92, 0xCC, 0x81, 0x04, + 0xCF, 0x92, 0xCC, 0x88, 0x02, 0xCF, 0x86, 0x02, + 0xCF, 0x80, 0x02, 0xCE, 0xBA, 0x02, 0xCF, 0x81, + 0x02, 0xCF, 0x82, 0x02, 0xCE, 0x98, 0x02, 0xCE, + // Bytes 580 - 5bf + 0xB5, 0x02, 0xCE, 0xA3, 0x04, 0xD0, 0x95, 0xCC, + 0x80, 0x04, 0xD0, 0x95, 0xCC, 0x88, 0x04, 0xD0, + 0x93, 0xCC, 0x81, 0x04, 0xD0, 0x86, 0xCC, 0x88, + 0x04, 0xD0, 0x9A, 0xCC, 0x81, 0x04, 0xD0, 0x98, + 0xCC, 0x80, 0x04, 0xD0, 0xA3, 0xCC, 0x86, 0x04, + 0xD0, 0x98, 0xCC, 0x86, 0x04, 0xD0, 0xB8, 0xCC, + 0x86, 0x04, 0xD0, 0xB5, 0xCC, 0x80, 0x04, 0xD0, + 0xB5, 0xCC, 0x88, 0x04, 0xD0, 0xB3, 0xCC, 0x81, + // Bytes 5c0 - 5ff + 0x04, 0xD1, 0x96, 0xCC, 0x88, 0x04, 0xD0, 0xBA, + 0xCC, 0x81, 0x04, 0xD0, 0xB8, 0xCC, 0x80, 0x04, + 0xD1, 0x83, 0xCC, 0x86, 0x04, 0xD1, 0xB4, 0xCC, + 0x8F, 0x04, 0xD1, 0xB5, 0xCC, 0x8F, 0x04, 0xD0, + 0x96, 0xCC, 0x86, 0x04, 0xD0, 0xB6, 0xCC, 0x86, + 0x04, 0xD0, 0x90, 0xCC, 0x86, 0x04, 0xD0, 0xB0, + 0xCC, 0x86, 0x04, 0xD0, 0x90, 0xCC, 0x88, 0x04, + 0xD0, 0xB0, 0xCC, 0x88, 0x04, 0xD0, 0x95, 0xCC, + // Bytes 600 - 63f + 0x86, 0x04, 0xD0, 0xB5, 0xCC, 0x86, 0x04, 0xD3, + 0x98, 0xCC, 0x88, 0x04, 0xD3, 0x99, 0xCC, 0x88, + 0x04, 0xD0, 0x96, 0xCC, 0x88, 0x04, 0xD0, 0xB6, + 0xCC, 0x88, 0x04, 0xD0, 0x97, 0xCC, 0x88, 0x04, + 0xD0, 0xB7, 0xCC, 0x88, 0x04, 0xD0, 0x98, 0xCC, + 0x84, 0x04, 0xD0, 0xB8, 0xCC, 0x84, 0x04, 0xD0, + 0x98, 0xCC, 0x88, 0x04, 0xD0, 0xB8, 0xCC, 0x88, + 0x04, 0xD0, 0x9E, 0xCC, 0x88, 0x04, 0xD0, 0xBE, + // Bytes 640 - 67f + 0xCC, 0x88, 0x04, 0xD3, 0xA8, 0xCC, 0x88, 0x04, + 0xD3, 0xA9, 0xCC, 0x88, 0x04, 0xD0, 0xAD, 0xCC, + 0x88, 0x04, 0xD1, 0x8D, 0xCC, 0x88, 0x04, 0xD0, + 0xA3, 0xCC, 0x84, 0x04, 0xD1, 0x83, 0xCC, 0x84, + 0x04, 0xD0, 0xA3, 0xCC, 0x88, 0x04, 0xD1, 0x83, + 0xCC, 0x88, 0x04, 0xD0, 0xA3, 0xCC, 0x8B, 0x04, + 0xD1, 0x83, 0xCC, 0x8B, 0x04, 0xD0, 0xA7, 0xCC, + 0x88, 0x04, 0xD1, 0x87, 0xCC, 0x88, 0x04, 0xD0, + // Bytes 680 - 6bf + 0xAB, 0xCC, 0x88, 0x04, 0xD1, 0x8B, 0xCC, 0x88, + 0x04, 0xD5, 0xA5, 0xD6, 0x82, 0x04, 0xD8, 0xA7, + 0xD9, 0x93, 0x04, 0xD8, 0xA7, 0xD9, 0x94, 0x04, + 0xD9, 0x88, 0xD9, 0x94, 0x04, 0xD8, 0xA7, 0xD9, + 0x95, 0x04, 0xD9, 0x8A, 0xD9, 0x94, 0x04, 0xD8, + 0xA7, 0xD9, 0xB4, 0x04, 0xD9, 0x88, 0xD9, 0xB4, + 0x04, 0xDB, 0x87, 0xD9, 0xB4, 0x04, 0xD9, 0x8A, + 0xD9, 0xB4, 0x04, 0xDB, 0x95, 0xD9, 0x94, 0x04, + // Bytes 6c0 - 6ff + 0xDB, 0x81, 0xD9, 0x94, 0x04, 0xDB, 0x92, 0xD9, + 0x94, 0x06, 0xE0, 0xA4, 0xA8, 0xE0, 0xA4, 0xBC, + 0x06, 0xE0, 0xA4, 0xB0, 0xE0, 0xA4, 0xBC, 0x06, + 0xE0, 0xA4, 0xB3, 0xE0, 0xA4, 0xBC, 0x06, 0xE0, + 0xA4, 0x95, 0xE0, 0xA4, 0xBC, 0x06, 0xE0, 0xA4, + 0x96, 0xE0, 0xA4, 0xBC, 0x06, 0xE0, 0xA4, 0x97, + 0xE0, 0xA4, 0xBC, 0x06, 0xE0, 0xA4, 0x9C, 0xE0, + 0xA4, 0xBC, 0x06, 0xE0, 0xA4, 0xA1, 0xE0, 0xA4, + // Bytes 700 - 73f + 0xBC, 0x06, 0xE0, 0xA4, 0xA2, 0xE0, 0xA4, 0xBC, + 0x06, 0xE0, 0xA4, 0xAB, 0xE0, 0xA4, 0xBC, 0x06, + 0xE0, 0xA4, 0xAF, 0xE0, 0xA4, 0xBC, 0x06, 0xE0, + 0xA7, 0x87, 0xE0, 0xA6, 0xBE, 0x06, 0xE0, 0xA7, + 0x87, 0xE0, 0xA7, 0x97, 0x06, 0xE0, 0xA6, 0xA1, + 0xE0, 0xA6, 0xBC, 0x06, 0xE0, 0xA6, 0xA2, 0xE0, + 0xA6, 0xBC, 0x06, 0xE0, 0xA6, 0xAF, 0xE0, 0xA6, + 0xBC, 0x06, 0xE0, 0xA8, 0xB2, 0xE0, 0xA8, 0xBC, + // Bytes 740 - 77f + 0x06, 0xE0, 0xA8, 0xB8, 0xE0, 0xA8, 0xBC, 0x06, + 0xE0, 0xA8, 0x96, 0xE0, 0xA8, 0xBC, 0x06, 0xE0, + 0xA8, 0x97, 0xE0, 0xA8, 0xBC, 0x06, 0xE0, 0xA8, + 0x9C, 0xE0, 0xA8, 0xBC, 0x06, 0xE0, 0xA8, 0xAB, + 0xE0, 0xA8, 0xBC, 0x06, 0xE0, 0xAD, 0x87, 0xE0, + 0xAD, 0x96, 0x06, 0xE0, 0xAD, 0x87, 0xE0, 0xAC, + 0xBE, 0x06, 0xE0, 0xAD, 0x87, 0xE0, 0xAD, 0x97, + 0x06, 0xE0, 0xAC, 0xA1, 0xE0, 0xAC, 0xBC, 0x06, + // Bytes 780 - 7bf + 0xE0, 0xAC, 0xA2, 0xE0, 0xAC, 0xBC, 0x06, 0xE0, + 0xAE, 0x92, 0xE0, 0xAF, 0x97, 0x06, 0xE0, 0xAF, + 0x86, 0xE0, 0xAE, 0xBE, 0x06, 0xE0, 0xAF, 0x87, + 0xE0, 0xAE, 0xBE, 0x06, 0xE0, 0xAF, 0x86, 0xE0, + 0xAF, 0x97, 0x06, 0xE0, 0xB1, 0x86, 0xE0, 0xB1, + 0x96, 0x06, 0xE0, 0xB2, 0xBF, 0xE0, 0xB3, 0x95, + 0x06, 0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x95, 0x06, + 0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x96, 0x06, 0xE0, + // Bytes 7c0 - 7ff + 0xB3, 0x86, 0xE0, 0xB3, 0x82, 0x09, 0xE0, 0xB3, + 0x86, 0xE0, 0xB3, 0x82, 0xE0, 0xB3, 0x95, 0x06, + 0xE0, 0xB5, 0x86, 0xE0, 0xB4, 0xBE, 0x06, 0xE0, + 0xB5, 0x87, 0xE0, 0xB4, 0xBE, 0x06, 0xE0, 0xB5, + 0x86, 0xE0, 0xB5, 0x97, 0x06, 0xE0, 0xB7, 0x99, + 0xE0, 0xB7, 0x8A, 0x06, 0xE0, 0xB7, 0x99, 0xE0, + 0xB7, 0x8F, 0x09, 0xE0, 0xB7, 0x99, 0xE0, 0xB7, + 0x8F, 0xE0, 0xB7, 0x8A, 0x06, 0xE0, 0xB7, 0x99, + // Bytes 800 - 83f + 0xE0, 0xB7, 0x9F, 0x06, 0xE0, 0xB9, 0x8D, 0xE0, + 0xB8, 0xB2, 0x06, 0xE0, 0xBB, 0x8D, 0xE0, 0xBA, + 0xB2, 0x06, 0xE0, 0xBA, 0xAB, 0xE0, 0xBA, 0x99, + 0x06, 0xE0, 0xBA, 0xAB, 0xE0, 0xBA, 0xA1, 0x03, + 0xE0, 0xBC, 0x8B, 0x06, 0xE0, 0xBD, 0x82, 0xE0, + 0xBE, 0xB7, 0x06, 0xE0, 0xBD, 0x8C, 0xE0, 0xBE, + 0xB7, 0x06, 0xE0, 0xBD, 0x91, 0xE0, 0xBE, 0xB7, + 0x06, 0xE0, 0xBD, 0x96, 0xE0, 0xBE, 0xB7, 0x06, + // Bytes 840 - 87f + 0xE0, 0xBD, 0x9B, 0xE0, 0xBE, 0xB7, 0x06, 0xE0, + 0xBD, 0x80, 0xE0, 0xBE, 0xB5, 0x06, 0xE0, 0xBD, + 0xB1, 0xE0, 0xBD, 0xB2, 0x06, 0xE0, 0xBD, 0xB1, + 0xE0, 0xBD, 0xB4, 0x06, 0xE0, 0xBE, 0xB2, 0xE0, + 0xBE, 0x80, 0x09, 0xE0, 0xBE, 0xB2, 0xE0, 0xBD, + 0xB1, 0xE0, 0xBE, 0x80, 0x06, 0xE0, 0xBE, 0xB3, + 0xE0, 0xBE, 0x80, 0x09, 0xE0, 0xBE, 0xB3, 0xE0, + 0xBD, 0xB1, 0xE0, 0xBE, 0x80, 0x06, 0xE0, 0xBD, + // Bytes 880 - 8bf + 0xB1, 0xE0, 0xBE, 0x80, 0x06, 0xE0, 0xBE, 0x92, + 0xE0, 0xBE, 0xB7, 0x06, 0xE0, 0xBE, 0x9C, 0xE0, + 0xBE, 0xB7, 0x06, 0xE0, 0xBE, 0xA1, 0xE0, 0xBE, + 0xB7, 0x06, 0xE0, 0xBE, 0xA6, 0xE0, 0xBE, 0xB7, + 0x06, 0xE0, 0xBE, 0xAB, 0xE0, 0xBE, 0xB7, 0x06, + 0xE0, 0xBE, 0x90, 0xE0, 0xBE, 0xB5, 0x06, 0xE1, + 0x80, 0xA5, 0xE1, 0x80, 0xAE, 0x03, 0xE1, 0x83, + 0x9C, 0x06, 0xE1, 0xAC, 0x85, 0xE1, 0xAC, 0xB5, + // Bytes 8c0 - 8ff + 0x06, 0xE1, 0xAC, 0x87, 0xE1, 0xAC, 0xB5, 0x06, + 0xE1, 0xAC, 0x89, 0xE1, 0xAC, 0xB5, 0x06, 0xE1, + 0xAC, 0x8B, 0xE1, 0xAC, 0xB5, 0x06, 0xE1, 0xAC, + 0x8D, 0xE1, 0xAC, 0xB5, 0x06, 0xE1, 0xAC, 0x91, + 0xE1, 0xAC, 0xB5, 0x06, 0xE1, 0xAC, 0xBA, 0xE1, + 0xAC, 0xB5, 0x06, 0xE1, 0xAC, 0xBC, 0xE1, 0xAC, + 0xB5, 0x06, 0xE1, 0xAC, 0xBE, 0xE1, 0xAC, 0xB5, + 0x06, 0xE1, 0xAC, 0xBF, 0xE1, 0xAC, 0xB5, 0x06, + // Bytes 900 - 93f + 0xE1, 0xAD, 0x82, 0xE1, 0xAC, 0xB5, 0x01, 0x41, + 0x02, 0xC3, 0x86, 0x01, 0x42, 0x01, 0x44, 0x01, + 0x45, 0x02, 0xC6, 0x8E, 0x01, 0x47, 0x01, 0x48, + 0x01, 0x49, 0x01, 0x4A, 0x01, 0x4B, 0x01, 0x4C, + 0x01, 0x4D, 0x01, 0x4E, 0x01, 0x4F, 0x02, 0xC8, + 0xA2, 0x01, 0x50, 0x01, 0x52, 0x01, 0x54, 0x01, + 0x55, 0x01, 0x57, 0x02, 0xC9, 0x90, 0x02, 0xC9, + 0x91, 0x03, 0xE1, 0xB4, 0x82, 0x01, 0x62, 0x01, + // Bytes 940 - 97f + 0x64, 0x01, 0x65, 0x02, 0xC9, 0x99, 0x02, 0xC9, + 0x9B, 0x02, 0xC9, 0x9C, 0x01, 0x67, 0x01, 0x6B, + 0x01, 0x6D, 0x02, 0xC5, 0x8B, 0x02, 0xC9, 0x94, + 0x03, 0xE1, 0xB4, 0x96, 0x03, 0xE1, 0xB4, 0x97, + 0x01, 0x70, 0x01, 0x74, 0x01, 0x75, 0x03, 0xE1, + 0xB4, 0x9D, 0x02, 0xC9, 0xAF, 0x01, 0x76, 0x03, + 0xE1, 0xB4, 0xA5, 0x02, 0xCE, 0xB3, 0x02, 0xCE, + 0xB4, 0x02, 0xCF, 0x87, 0x01, 0x69, 0x02, 0xD0, + // Bytes 980 - 9bf + 0xBD, 0x02, 0xC9, 0x92, 0x01, 0x63, 0x02, 0xC9, + 0x95, 0x02, 0xC3, 0xB0, 0x01, 0x66, 0x02, 0xC9, + 0x9F, 0x02, 0xC9, 0xA1, 0x02, 0xC9, 0xA5, 0x02, + 0xC9, 0xA8, 0x02, 0xC9, 0xA9, 0x02, 0xC9, 0xAA, + 0x03, 0xE1, 0xB5, 0xBB, 0x02, 0xCA, 0x9D, 0x02, + 0xC9, 0xAD, 0x03, 0xE1, 0xB6, 0x85, 0x02, 0xCA, + 0x9F, 0x02, 0xC9, 0xB1, 0x02, 0xC9, 0xB0, 0x02, + 0xC9, 0xB2, 0x02, 0xC9, 0xB3, 0x02, 0xC9, 0xB4, + // Bytes 9c0 - 9ff + 0x02, 0xC9, 0xB5, 0x02, 0xC9, 0xB8, 0x02, 0xCA, + 0x82, 0x02, 0xCA, 0x83, 0x02, 0xC6, 0xAB, 0x02, + 0xCA, 0x89, 0x02, 0xCA, 0x8A, 0x03, 0xE1, 0xB4, + 0x9C, 0x02, 0xCA, 0x8B, 0x02, 0xCA, 0x8C, 0x01, + 0x7A, 0x02, 0xCA, 0x90, 0x02, 0xCA, 0x91, 0x02, + 0xCA, 0x92, 0x03, 0x41, 0xCC, 0xA5, 0x03, 0x61, + 0xCC, 0xA5, 0x03, 0x42, 0xCC, 0x87, 0x03, 0x62, + 0xCC, 0x87, 0x03, 0x42, 0xCC, 0xA3, 0x03, 0x62, + // Bytes a00 - a3f + 0xCC, 0xA3, 0x03, 0x42, 0xCC, 0xB1, 0x03, 0x62, + 0xCC, 0xB1, 0x05, 0x43, 0xCC, 0xA7, 0xCC, 0x81, + 0x05, 0x63, 0xCC, 0xA7, 0xCC, 0x81, 0x03, 0x44, + 0xCC, 0x87, 0x03, 0x64, 0xCC, 0x87, 0x03, 0x44, + 0xCC, 0xA3, 0x03, 0x64, 0xCC, 0xA3, 0x03, 0x44, + 0xCC, 0xB1, 0x03, 0x64, 0xCC, 0xB1, 0x03, 0x44, + 0xCC, 0xA7, 0x03, 0x64, 0xCC, 0xA7, 0x03, 0x44, + 0xCC, 0xAD, 0x03, 0x64, 0xCC, 0xAD, 0x05, 0x45, + // Bytes a40 - a7f + 0xCC, 0x84, 0xCC, 0x80, 0x05, 0x65, 0xCC, 0x84, + 0xCC, 0x80, 0x05, 0x45, 0xCC, 0x84, 0xCC, 0x81, + 0x05, 0x65, 0xCC, 0x84, 0xCC, 0x81, 0x03, 0x45, + 0xCC, 0xAD, 0x03, 0x65, 0xCC, 0xAD, 0x03, 0x45, + 0xCC, 0xB0, 0x03, 0x65, 0xCC, 0xB0, 0x05, 0x45, + 0xCC, 0xA7, 0xCC, 0x86, 0x05, 0x65, 0xCC, 0xA7, + 0xCC, 0x86, 0x03, 0x46, 0xCC, 0x87, 0x03, 0x66, + 0xCC, 0x87, 0x03, 0x47, 0xCC, 0x84, 0x03, 0x67, + // Bytes a80 - abf + 0xCC, 0x84, 0x03, 0x48, 0xCC, 0x87, 0x03, 0x68, + 0xCC, 0x87, 0x03, 0x48, 0xCC, 0xA3, 0x03, 0x68, + 0xCC, 0xA3, 0x03, 0x48, 0xCC, 0x88, 0x03, 0x68, + 0xCC, 0x88, 0x03, 0x48, 0xCC, 0xA7, 0x03, 0x68, + 0xCC, 0xA7, 0x03, 0x48, 0xCC, 0xAE, 0x03, 0x68, + 0xCC, 0xAE, 0x03, 0x49, 0xCC, 0xB0, 0x03, 0x69, + 0xCC, 0xB0, 0x05, 0x49, 0xCC, 0x88, 0xCC, 0x81, + 0x05, 0x69, 0xCC, 0x88, 0xCC, 0x81, 0x03, 0x4B, + // Bytes ac0 - aff + 0xCC, 0x81, 0x03, 0x6B, 0xCC, 0x81, 0x03, 0x4B, + 0xCC, 0xA3, 0x03, 0x6B, 0xCC, 0xA3, 0x03, 0x4B, + 0xCC, 0xB1, 0x03, 0x6B, 0xCC, 0xB1, 0x03, 0x4C, + 0xCC, 0xA3, 0x03, 0x6C, 0xCC, 0xA3, 0x05, 0x4C, + 0xCC, 0xA3, 0xCC, 0x84, 0x05, 0x6C, 0xCC, 0xA3, + 0xCC, 0x84, 0x03, 0x4C, 0xCC, 0xB1, 0x03, 0x6C, + 0xCC, 0xB1, 0x03, 0x4C, 0xCC, 0xAD, 0x03, 0x6C, + 0xCC, 0xAD, 0x03, 0x4D, 0xCC, 0x81, 0x03, 0x6D, + // Bytes b00 - b3f + 0xCC, 0x81, 0x03, 0x4D, 0xCC, 0x87, 0x03, 0x6D, + 0xCC, 0x87, 0x03, 0x4D, 0xCC, 0xA3, 0x03, 0x6D, + 0xCC, 0xA3, 0x03, 0x4E, 0xCC, 0x87, 0x03, 0x6E, + 0xCC, 0x87, 0x03, 0x4E, 0xCC, 0xA3, 0x03, 0x6E, + 0xCC, 0xA3, 0x03, 0x4E, 0xCC, 0xB1, 0x03, 0x6E, + 0xCC, 0xB1, 0x03, 0x4E, 0xCC, 0xAD, 0x03, 0x6E, + 0xCC, 0xAD, 0x05, 0x4F, 0xCC, 0x83, 0xCC, 0x81, + 0x05, 0x6F, 0xCC, 0x83, 0xCC, 0x81, 0x05, 0x4F, + // Bytes b40 - b7f + 0xCC, 0x83, 0xCC, 0x88, 0x05, 0x6F, 0xCC, 0x83, + 0xCC, 0x88, 0x05, 0x4F, 0xCC, 0x84, 0xCC, 0x80, + 0x05, 0x6F, 0xCC, 0x84, 0xCC, 0x80, 0x05, 0x4F, + 0xCC, 0x84, 0xCC, 0x81, 0x05, 0x6F, 0xCC, 0x84, + 0xCC, 0x81, 0x03, 0x50, 0xCC, 0x81, 0x03, 0x70, + 0xCC, 0x81, 0x03, 0x50, 0xCC, 0x87, 0x03, 0x70, + 0xCC, 0x87, 0x03, 0x52, 0xCC, 0x87, 0x03, 0x72, + 0xCC, 0x87, 0x03, 0x52, 0xCC, 0xA3, 0x03, 0x72, + // Bytes b80 - bbf + 0xCC, 0xA3, 0x05, 0x52, 0xCC, 0xA3, 0xCC, 0x84, + 0x05, 0x72, 0xCC, 0xA3, 0xCC, 0x84, 0x03, 0x52, + 0xCC, 0xB1, 0x03, 0x72, 0xCC, 0xB1, 0x03, 0x53, + 0xCC, 0x87, 0x03, 0x73, 0xCC, 0x87, 0x03, 0x53, + 0xCC, 0xA3, 0x03, 0x73, 0xCC, 0xA3, 0x05, 0x53, + 0xCC, 0x81, 0xCC, 0x87, 0x05, 0x73, 0xCC, 0x81, + 0xCC, 0x87, 0x05, 0x53, 0xCC, 0x8C, 0xCC, 0x87, + 0x05, 0x73, 0xCC, 0x8C, 0xCC, 0x87, 0x05, 0x53, + // Bytes bc0 - bff + 0xCC, 0xA3, 0xCC, 0x87, 0x05, 0x73, 0xCC, 0xA3, + 0xCC, 0x87, 0x03, 0x54, 0xCC, 0x87, 0x03, 0x74, + 0xCC, 0x87, 0x03, 0x54, 0xCC, 0xA3, 0x03, 0x74, + 0xCC, 0xA3, 0x03, 0x54, 0xCC, 0xB1, 0x03, 0x74, + 0xCC, 0xB1, 0x03, 0x54, 0xCC, 0xAD, 0x03, 0x74, + 0xCC, 0xAD, 0x03, 0x55, 0xCC, 0xA4, 0x03, 0x75, + 0xCC, 0xA4, 0x03, 0x55, 0xCC, 0xB0, 0x03, 0x75, + 0xCC, 0xB0, 0x03, 0x55, 0xCC, 0xAD, 0x03, 0x75, + // Bytes c00 - c3f + 0xCC, 0xAD, 0x05, 0x55, 0xCC, 0x83, 0xCC, 0x81, + 0x05, 0x75, 0xCC, 0x83, 0xCC, 0x81, 0x05, 0x55, + 0xCC, 0x84, 0xCC, 0x88, 0x05, 0x75, 0xCC, 0x84, + 0xCC, 0x88, 0x03, 0x56, 0xCC, 0x83, 0x03, 0x76, + 0xCC, 0x83, 0x03, 0x56, 0xCC, 0xA3, 0x03, 0x76, + 0xCC, 0xA3, 0x03, 0x57, 0xCC, 0x80, 0x03, 0x77, + 0xCC, 0x80, 0x03, 0x57, 0xCC, 0x81, 0x03, 0x77, + 0xCC, 0x81, 0x03, 0x57, 0xCC, 0x88, 0x03, 0x77, + // Bytes c40 - c7f + 0xCC, 0x88, 0x03, 0x57, 0xCC, 0x87, 0x03, 0x77, + 0xCC, 0x87, 0x03, 0x57, 0xCC, 0xA3, 0x03, 0x77, + 0xCC, 0xA3, 0x03, 0x58, 0xCC, 0x87, 0x03, 0x78, + 0xCC, 0x87, 0x03, 0x58, 0xCC, 0x88, 0x03, 0x78, + 0xCC, 0x88, 0x03, 0x59, 0xCC, 0x87, 0x03, 0x79, + 0xCC, 0x87, 0x03, 0x5A, 0xCC, 0x82, 0x03, 0x7A, + 0xCC, 0x82, 0x03, 0x5A, 0xCC, 0xA3, 0x03, 0x7A, + 0xCC, 0xA3, 0x03, 0x5A, 0xCC, 0xB1, 0x03, 0x7A, + // Bytes c80 - cbf + 0xCC, 0xB1, 0x03, 0x68, 0xCC, 0xB1, 0x03, 0x74, + 0xCC, 0x88, 0x03, 0x77, 0xCC, 0x8A, 0x03, 0x79, + 0xCC, 0x8A, 0x03, 0x61, 0xCA, 0xBE, 0x04, 0xC5, + 0xBF, 0xCC, 0x87, 0x03, 0x41, 0xCC, 0xA3, 0x03, + 0x61, 0xCC, 0xA3, 0x03, 0x41, 0xCC, 0x89, 0x03, + 0x61, 0xCC, 0x89, 0x05, 0x41, 0xCC, 0x82, 0xCC, + 0x81, 0x05, 0x61, 0xCC, 0x82, 0xCC, 0x81, 0x05, + 0x41, 0xCC, 0x82, 0xCC, 0x80, 0x05, 0x61, 0xCC, + // Bytes cc0 - cff + 0x82, 0xCC, 0x80, 0x05, 0x41, 0xCC, 0x82, 0xCC, + 0x89, 0x05, 0x61, 0xCC, 0x82, 0xCC, 0x89, 0x05, + 0x41, 0xCC, 0x82, 0xCC, 0x83, 0x05, 0x61, 0xCC, + 0x82, 0xCC, 0x83, 0x05, 0x41, 0xCC, 0xA3, 0xCC, + 0x82, 0x05, 0x61, 0xCC, 0xA3, 0xCC, 0x82, 0x05, + 0x41, 0xCC, 0x86, 0xCC, 0x81, 0x05, 0x61, 0xCC, + 0x86, 0xCC, 0x81, 0x05, 0x41, 0xCC, 0x86, 0xCC, + 0x80, 0x05, 0x61, 0xCC, 0x86, 0xCC, 0x80, 0x05, + // Bytes d00 - d3f + 0x41, 0xCC, 0x86, 0xCC, 0x89, 0x05, 0x61, 0xCC, + 0x86, 0xCC, 0x89, 0x05, 0x41, 0xCC, 0x86, 0xCC, + 0x83, 0x05, 0x61, 0xCC, 0x86, 0xCC, 0x83, 0x05, + 0x41, 0xCC, 0xA3, 0xCC, 0x86, 0x05, 0x61, 0xCC, + 0xA3, 0xCC, 0x86, 0x03, 0x45, 0xCC, 0xA3, 0x03, + 0x65, 0xCC, 0xA3, 0x03, 0x45, 0xCC, 0x89, 0x03, + 0x65, 0xCC, 0x89, 0x03, 0x45, 0xCC, 0x83, 0x03, + 0x65, 0xCC, 0x83, 0x05, 0x45, 0xCC, 0x82, 0xCC, + // Bytes d40 - d7f + 0x81, 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x81, 0x05, + 0x45, 0xCC, 0x82, 0xCC, 0x80, 0x05, 0x65, 0xCC, + 0x82, 0xCC, 0x80, 0x05, 0x45, 0xCC, 0x82, 0xCC, + 0x89, 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x89, 0x05, + 0x45, 0xCC, 0x82, 0xCC, 0x83, 0x05, 0x65, 0xCC, + 0x82, 0xCC, 0x83, 0x05, 0x45, 0xCC, 0xA3, 0xCC, + 0x82, 0x05, 0x65, 0xCC, 0xA3, 0xCC, 0x82, 0x03, + 0x49, 0xCC, 0x89, 0x03, 0x69, 0xCC, 0x89, 0x03, + // Bytes d80 - dbf + 0x49, 0xCC, 0xA3, 0x03, 0x69, 0xCC, 0xA3, 0x03, + 0x4F, 0xCC, 0xA3, 0x03, 0x6F, 0xCC, 0xA3, 0x03, + 0x4F, 0xCC, 0x89, 0x03, 0x6F, 0xCC, 0x89, 0x05, + 0x4F, 0xCC, 0x82, 0xCC, 0x81, 0x05, 0x6F, 0xCC, + 0x82, 0xCC, 0x81, 0x05, 0x4F, 0xCC, 0x82, 0xCC, + 0x80, 0x05, 0x6F, 0xCC, 0x82, 0xCC, 0x80, 0x05, + 0x4F, 0xCC, 0x82, 0xCC, 0x89, 0x05, 0x6F, 0xCC, + 0x82, 0xCC, 0x89, 0x05, 0x4F, 0xCC, 0x82, 0xCC, + // Bytes dc0 - dff + 0x83, 0x05, 0x6F, 0xCC, 0x82, 0xCC, 0x83, 0x05, + 0x4F, 0xCC, 0xA3, 0xCC, 0x82, 0x05, 0x6F, 0xCC, + 0xA3, 0xCC, 0x82, 0x05, 0x4F, 0xCC, 0x9B, 0xCC, + 0x81, 0x05, 0x6F, 0xCC, 0x9B, 0xCC, 0x81, 0x05, + 0x4F, 0xCC, 0x9B, 0xCC, 0x80, 0x05, 0x6F, 0xCC, + 0x9B, 0xCC, 0x80, 0x05, 0x4F, 0xCC, 0x9B, 0xCC, + 0x89, 0x05, 0x6F, 0xCC, 0x9B, 0xCC, 0x89, 0x05, + 0x4F, 0xCC, 0x9B, 0xCC, 0x83, 0x05, 0x6F, 0xCC, + // Bytes e00 - e3f + 0x9B, 0xCC, 0x83, 0x05, 0x4F, 0xCC, 0x9B, 0xCC, + 0xA3, 0x05, 0x6F, 0xCC, 0x9B, 0xCC, 0xA3, 0x03, + 0x55, 0xCC, 0xA3, 0x03, 0x75, 0xCC, 0xA3, 0x03, + 0x55, 0xCC, 0x89, 0x03, 0x75, 0xCC, 0x89, 0x05, + 0x55, 0xCC, 0x9B, 0xCC, 0x81, 0x05, 0x75, 0xCC, + 0x9B, 0xCC, 0x81, 0x05, 0x55, 0xCC, 0x9B, 0xCC, + 0x80, 0x05, 0x75, 0xCC, 0x9B, 0xCC, 0x80, 0x05, + 0x55, 0xCC, 0x9B, 0xCC, 0x89, 0x05, 0x75, 0xCC, + // Bytes e40 - e7f + 0x9B, 0xCC, 0x89, 0x05, 0x55, 0xCC, 0x9B, 0xCC, + 0x83, 0x05, 0x75, 0xCC, 0x9B, 0xCC, 0x83, 0x05, + 0x55, 0xCC, 0x9B, 0xCC, 0xA3, 0x05, 0x75, 0xCC, + 0x9B, 0xCC, 0xA3, 0x03, 0x59, 0xCC, 0x80, 0x03, + 0x79, 0xCC, 0x80, 0x03, 0x59, 0xCC, 0xA3, 0x03, + 0x79, 0xCC, 0xA3, 0x03, 0x59, 0xCC, 0x89, 0x03, + 0x79, 0xCC, 0x89, 0x03, 0x59, 0xCC, 0x83, 0x03, + 0x79, 0xCC, 0x83, 0x04, 0xCE, 0xB1, 0xCC, 0x93, + // Bytes e80 - ebf + 0x04, 0xCE, 0xB1, 0xCC, 0x94, 0x06, 0xCE, 0xB1, + 0xCC, 0x93, 0xCC, 0x80, 0x06, 0xCE, 0xB1, 0xCC, + 0x94, 0xCC, 0x80, 0x06, 0xCE, 0xB1, 0xCC, 0x93, + 0xCC, 0x81, 0x06, 0xCE, 0xB1, 0xCC, 0x94, 0xCC, + 0x81, 0x06, 0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x82, + 0x06, 0xCE, 0xB1, 0xCC, 0x94, 0xCD, 0x82, 0x04, + 0xCE, 0x91, 0xCC, 0x93, 0x04, 0xCE, 0x91, 0xCC, + 0x94, 0x06, 0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x80, + // Bytes ec0 - eff + 0x06, 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x80, 0x06, + 0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x81, 0x06, 0xCE, + 0x91, 0xCC, 0x94, 0xCC, 0x81, 0x06, 0xCE, 0x91, + 0xCC, 0x93, 0xCD, 0x82, 0x06, 0xCE, 0x91, 0xCC, + 0x94, 0xCD, 0x82, 0x04, 0xCE, 0xB5, 0xCC, 0x93, + 0x04, 0xCE, 0xB5, 0xCC, 0x94, 0x06, 0xCE, 0xB5, + 0xCC, 0x93, 0xCC, 0x80, 0x06, 0xCE, 0xB5, 0xCC, + 0x94, 0xCC, 0x80, 0x06, 0xCE, 0xB5, 0xCC, 0x93, + // Bytes f00 - f3f + 0xCC, 0x81, 0x06, 0xCE, 0xB5, 0xCC, 0x94, 0xCC, + 0x81, 0x04, 0xCE, 0x95, 0xCC, 0x93, 0x04, 0xCE, + 0x95, 0xCC, 0x94, 0x06, 0xCE, 0x95, 0xCC, 0x93, + 0xCC, 0x80, 0x06, 0xCE, 0x95, 0xCC, 0x94, 0xCC, + 0x80, 0x06, 0xCE, 0x95, 0xCC, 0x93, 0xCC, 0x81, + 0x06, 0xCE, 0x95, 0xCC, 0x94, 0xCC, 0x81, 0x04, + 0xCE, 0xB7, 0xCC, 0x93, 0x04, 0xCE, 0xB7, 0xCC, + 0x94, 0x06, 0xCE, 0xB7, 0xCC, 0x93, 0xCC, 0x80, + // Bytes f40 - f7f + 0x06, 0xCE, 0xB7, 0xCC, 0x94, 0xCC, 0x80, 0x06, + 0xCE, 0xB7, 0xCC, 0x93, 0xCC, 0x81, 0x06, 0xCE, + 0xB7, 0xCC, 0x94, 0xCC, 0x81, 0x06, 0xCE, 0xB7, + 0xCC, 0x93, 0xCD, 0x82, 0x06, 0xCE, 0xB7, 0xCC, + 0x94, 0xCD, 0x82, 0x04, 0xCE, 0x97, 0xCC, 0x93, + 0x04, 0xCE, 0x97, 0xCC, 0x94, 0x06, 0xCE, 0x97, + 0xCC, 0x93, 0xCC, 0x80, 0x06, 0xCE, 0x97, 0xCC, + 0x94, 0xCC, 0x80, 0x06, 0xCE, 0x97, 0xCC, 0x93, + // Bytes f80 - fbf + 0xCC, 0x81, 0x06, 0xCE, 0x97, 0xCC, 0x94, 0xCC, + 0x81, 0x06, 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x82, + 0x06, 0xCE, 0x97, 0xCC, 0x94, 0xCD, 0x82, 0x04, + 0xCE, 0xB9, 0xCC, 0x93, 0x04, 0xCE, 0xB9, 0xCC, + 0x94, 0x06, 0xCE, 0xB9, 0xCC, 0x93, 0xCC, 0x80, + 0x06, 0xCE, 0xB9, 0xCC, 0x94, 0xCC, 0x80, 0x06, + 0xCE, 0xB9, 0xCC, 0x93, 0xCC, 0x81, 0x06, 0xCE, + 0xB9, 0xCC, 0x94, 0xCC, 0x81, 0x06, 0xCE, 0xB9, + // Bytes fc0 - fff + 0xCC, 0x93, 0xCD, 0x82, 0x06, 0xCE, 0xB9, 0xCC, + 0x94, 0xCD, 0x82, 0x04, 0xCE, 0x99, 0xCC, 0x93, + 0x04, 0xCE, 0x99, 0xCC, 0x94, 0x06, 0xCE, 0x99, + 0xCC, 0x93, 0xCC, 0x80, 0x06, 0xCE, 0x99, 0xCC, + 0x94, 0xCC, 0x80, 0x06, 0xCE, 0x99, 0xCC, 0x93, + 0xCC, 0x81, 0x06, 0xCE, 0x99, 0xCC, 0x94, 0xCC, + 0x81, 0x06, 0xCE, 0x99, 0xCC, 0x93, 0xCD, 0x82, + 0x06, 0xCE, 0x99, 0xCC, 0x94, 0xCD, 0x82, 0x04, + // Bytes 1000 - 103f + 0xCE, 0xBF, 0xCC, 0x93, 0x04, 0xCE, 0xBF, 0xCC, + 0x94, 0x06, 0xCE, 0xBF, 0xCC, 0x93, 0xCC, 0x80, + 0x06, 0xCE, 0xBF, 0xCC, 0x94, 0xCC, 0x80, 0x06, + 0xCE, 0xBF, 0xCC, 0x93, 0xCC, 0x81, 0x06, 0xCE, + 0xBF, 0xCC, 0x94, 0xCC, 0x81, 0x04, 0xCE, 0x9F, + 0xCC, 0x93, 0x04, 0xCE, 0x9F, 0xCC, 0x94, 0x06, + 0xCE, 0x9F, 0xCC, 0x93, 0xCC, 0x80, 0x06, 0xCE, + 0x9F, 0xCC, 0x94, 0xCC, 0x80, 0x06, 0xCE, 0x9F, + // Bytes 1040 - 107f + 0xCC, 0x93, 0xCC, 0x81, 0x06, 0xCE, 0x9F, 0xCC, + 0x94, 0xCC, 0x81, 0x04, 0xCF, 0x85, 0xCC, 0x93, + 0x04, 0xCF, 0x85, 0xCC, 0x94, 0x06, 0xCF, 0x85, + 0xCC, 0x93, 0xCC, 0x80, 0x06, 0xCF, 0x85, 0xCC, + 0x94, 0xCC, 0x80, 0x06, 0xCF, 0x85, 0xCC, 0x93, + 0xCC, 0x81, 0x06, 0xCF, 0x85, 0xCC, 0x94, 0xCC, + 0x81, 0x06, 0xCF, 0x85, 0xCC, 0x93, 0xCD, 0x82, + 0x06, 0xCF, 0x85, 0xCC, 0x94, 0xCD, 0x82, 0x04, + // Bytes 1080 - 10bf + 0xCE, 0xA5, 0xCC, 0x94, 0x06, 0xCE, 0xA5, 0xCC, + 0x94, 0xCC, 0x80, 0x06, 0xCE, 0xA5, 0xCC, 0x94, + 0xCC, 0x81, 0x06, 0xCE, 0xA5, 0xCC, 0x94, 0xCD, + 0x82, 0x04, 0xCF, 0x89, 0xCC, 0x93, 0x04, 0xCF, + 0x89, 0xCC, 0x94, 0x06, 0xCF, 0x89, 0xCC, 0x93, + 0xCC, 0x80, 0x06, 0xCF, 0x89, 0xCC, 0x94, 0xCC, + 0x80, 0x06, 0xCF, 0x89, 0xCC, 0x93, 0xCC, 0x81, + 0x06, 0xCF, 0x89, 0xCC, 0x94, 0xCC, 0x81, 0x06, + // Bytes 10c0 - 10ff + 0xCF, 0x89, 0xCC, 0x93, 0xCD, 0x82, 0x06, 0xCF, + 0x89, 0xCC, 0x94, 0xCD, 0x82, 0x04, 0xCE, 0xA9, + 0xCC, 0x93, 0x04, 0xCE, 0xA9, 0xCC, 0x94, 0x06, + 0xCE, 0xA9, 0xCC, 0x93, 0xCC, 0x80, 0x06, 0xCE, + 0xA9, 0xCC, 0x94, 0xCC, 0x80, 0x06, 0xCE, 0xA9, + 0xCC, 0x93, 0xCC, 0x81, 0x06, 0xCE, 0xA9, 0xCC, + 0x94, 0xCC, 0x81, 0x06, 0xCE, 0xA9, 0xCC, 0x93, + 0xCD, 0x82, 0x06, 0xCE, 0xA9, 0xCC, 0x94, 0xCD, + // Bytes 1100 - 113f + 0x82, 0x04, 0xCE, 0xB1, 0xCC, 0x80, 0x04, 0xCE, + 0xB5, 0xCC, 0x80, 0x04, 0xCE, 0xB7, 0xCC, 0x80, + 0x04, 0xCE, 0xB9, 0xCC, 0x80, 0x04, 0xCE, 0xBF, + 0xCC, 0x80, 0x04, 0xCF, 0x85, 0xCC, 0x80, 0x04, + 0xCF, 0x89, 0xCC, 0x80, 0x06, 0xCE, 0xB1, 0xCC, + 0x93, 0xCD, 0x85, 0x06, 0xCE, 0xB1, 0xCC, 0x94, + 0xCD, 0x85, 0x08, 0xCE, 0xB1, 0xCC, 0x93, 0xCC, + 0x80, 0xCD, 0x85, 0x08, 0xCE, 0xB1, 0xCC, 0x94, + // Bytes 1140 - 117f + 0xCC, 0x80, 0xCD, 0x85, 0x08, 0xCE, 0xB1, 0xCC, + 0x93, 0xCC, 0x81, 0xCD, 0x85, 0x08, 0xCE, 0xB1, + 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, 0x08, 0xCE, + 0xB1, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, 0x08, + 0xCE, 0xB1, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, + 0x06, 0xCE, 0x91, 0xCC, 0x93, 0xCD, 0x85, 0x06, + 0xCE, 0x91, 0xCC, 0x94, 0xCD, 0x85, 0x08, 0xCE, + 0x91, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, 0x08, + // Bytes 1180 - 11bf + 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, + 0x08, 0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x81, 0xCD, + 0x85, 0x08, 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x81, + 0xCD, 0x85, 0x08, 0xCE, 0x91, 0xCC, 0x93, 0xCD, + 0x82, 0xCD, 0x85, 0x08, 0xCE, 0x91, 0xCC, 0x94, + 0xCD, 0x82, 0xCD, 0x85, 0x06, 0xCE, 0xB7, 0xCC, + 0x93, 0xCD, 0x85, 0x06, 0xCE, 0xB7, 0xCC, 0x94, + 0xCD, 0x85, 0x08, 0xCE, 0xB7, 0xCC, 0x93, 0xCC, + // Bytes 11c0 - 11ff + 0x80, 0xCD, 0x85, 0x08, 0xCE, 0xB7, 0xCC, 0x94, + 0xCC, 0x80, 0xCD, 0x85, 0x08, 0xCE, 0xB7, 0xCC, + 0x93, 0xCC, 0x81, 0xCD, 0x85, 0x08, 0xCE, 0xB7, + 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, 0x08, 0xCE, + 0xB7, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, 0x08, + 0xCE, 0xB7, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, + 0x06, 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x85, 0x06, + 0xCE, 0x97, 0xCC, 0x94, 0xCD, 0x85, 0x08, 0xCE, + // Bytes 1200 - 123f + 0x97, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, 0x08, + 0xCE, 0x97, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, + 0x08, 0xCE, 0x97, 0xCC, 0x93, 0xCC, 0x81, 0xCD, + 0x85, 0x08, 0xCE, 0x97, 0xCC, 0x94, 0xCC, 0x81, + 0xCD, 0x85, 0x08, 0xCE, 0x97, 0xCC, 0x93, 0xCD, + 0x82, 0xCD, 0x85, 0x08, 0xCE, 0x97, 0xCC, 0x94, + 0xCD, 0x82, 0xCD, 0x85, 0x06, 0xCF, 0x89, 0xCC, + 0x93, 0xCD, 0x85, 0x06, 0xCF, 0x89, 0xCC, 0x94, + // Bytes 1240 - 127f + 0xCD, 0x85, 0x08, 0xCF, 0x89, 0xCC, 0x93, 0xCC, + 0x80, 0xCD, 0x85, 0x08, 0xCF, 0x89, 0xCC, 0x94, + 0xCC, 0x80, 0xCD, 0x85, 0x08, 0xCF, 0x89, 0xCC, + 0x93, 0xCC, 0x81, 0xCD, 0x85, 0x08, 0xCF, 0x89, + 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, 0x08, 0xCF, + 0x89, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, 0x08, + 0xCF, 0x89, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, + 0x06, 0xCE, 0xA9, 0xCC, 0x93, 0xCD, 0x85, 0x06, + // Bytes 1280 - 12bf + 0xCE, 0xA9, 0xCC, 0x94, 0xCD, 0x85, 0x08, 0xCE, + 0xA9, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, 0x08, + 0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, + 0x08, 0xCE, 0xA9, 0xCC, 0x93, 0xCC, 0x81, 0xCD, + 0x85, 0x08, 0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x81, + 0xCD, 0x85, 0x08, 0xCE, 0xA9, 0xCC, 0x93, 0xCD, + 0x82, 0xCD, 0x85, 0x08, 0xCE, 0xA9, 0xCC, 0x94, + 0xCD, 0x82, 0xCD, 0x85, 0x04, 0xCE, 0xB1, 0xCC, + // Bytes 12c0 - 12ff + 0x86, 0x04, 0xCE, 0xB1, 0xCC, 0x84, 0x06, 0xCE, + 0xB1, 0xCC, 0x80, 0xCD, 0x85, 0x04, 0xCE, 0xB1, + 0xCD, 0x85, 0x06, 0xCE, 0xB1, 0xCC, 0x81, 0xCD, + 0x85, 0x04, 0xCE, 0xB1, 0xCD, 0x82, 0x06, 0xCE, + 0xB1, 0xCD, 0x82, 0xCD, 0x85, 0x04, 0xCE, 0x91, + 0xCC, 0x86, 0x04, 0xCE, 0x91, 0xCC, 0x84, 0x04, + 0xCE, 0x91, 0xCC, 0x80, 0x04, 0xCE, 0x91, 0xCD, + 0x85, 0x03, 0x20, 0xCC, 0x93, 0x02, 0xCE, 0xB9, + // Bytes 1300 - 133f + 0x03, 0x20, 0xCD, 0x82, 0x04, 0xC2, 0xA8, 0xCD, + 0x82, 0x05, 0x20, 0xCC, 0x88, 0xCD, 0x82, 0x06, + 0xCE, 0xB7, 0xCC, 0x80, 0xCD, 0x85, 0x04, 0xCE, + 0xB7, 0xCD, 0x85, 0x06, 0xCE, 0xB7, 0xCC, 0x81, + 0xCD, 0x85, 0x04, 0xCE, 0xB7, 0xCD, 0x82, 0x06, + 0xCE, 0xB7, 0xCD, 0x82, 0xCD, 0x85, 0x04, 0xCE, + 0x95, 0xCC, 0x80, 0x04, 0xCE, 0x97, 0xCC, 0x80, + 0x04, 0xCE, 0x97, 0xCD, 0x85, 0x05, 0xE1, 0xBE, + // Bytes 1340 - 137f + 0xBF, 0xCC, 0x80, 0x05, 0x20, 0xCC, 0x93, 0xCC, + 0x80, 0x05, 0xE1, 0xBE, 0xBF, 0xCC, 0x81, 0x05, + 0x20, 0xCC, 0x93, 0xCC, 0x81, 0x05, 0xE1, 0xBE, + 0xBF, 0xCD, 0x82, 0x05, 0x20, 0xCC, 0x93, 0xCD, + 0x82, 0x04, 0xCE, 0xB9, 0xCC, 0x86, 0x04, 0xCE, + 0xB9, 0xCC, 0x84, 0x06, 0xCE, 0xB9, 0xCC, 0x88, + 0xCC, 0x80, 0x04, 0xCE, 0xB9, 0xCD, 0x82, 0x06, + 0xCE, 0xB9, 0xCC, 0x88, 0xCD, 0x82, 0x04, 0xCE, + // Bytes 1380 - 13bf + 0x99, 0xCC, 0x86, 0x04, 0xCE, 0x99, 0xCC, 0x84, + 0x04, 0xCE, 0x99, 0xCC, 0x80, 0x05, 0xE1, 0xBF, + 0xBE, 0xCC, 0x80, 0x05, 0x20, 0xCC, 0x94, 0xCC, + 0x80, 0x05, 0xE1, 0xBF, 0xBE, 0xCC, 0x81, 0x05, + 0x20, 0xCC, 0x94, 0xCC, 0x81, 0x05, 0xE1, 0xBF, + 0xBE, 0xCD, 0x82, 0x05, 0x20, 0xCC, 0x94, 0xCD, + 0x82, 0x04, 0xCF, 0x85, 0xCC, 0x86, 0x04, 0xCF, + 0x85, 0xCC, 0x84, 0x06, 0xCF, 0x85, 0xCC, 0x88, + // Bytes 13c0 - 13ff + 0xCC, 0x80, 0x04, 0xCF, 0x81, 0xCC, 0x93, 0x04, + 0xCF, 0x81, 0xCC, 0x94, 0x04, 0xCF, 0x85, 0xCD, + 0x82, 0x06, 0xCF, 0x85, 0xCC, 0x88, 0xCD, 0x82, + 0x04, 0xCE, 0xA5, 0xCC, 0x86, 0x04, 0xCE, 0xA5, + 0xCC, 0x84, 0x04, 0xCE, 0xA5, 0xCC, 0x80, 0x04, + 0xCE, 0xA1, 0xCC, 0x94, 0x04, 0xC2, 0xA8, 0xCC, + 0x80, 0x05, 0x20, 0xCC, 0x88, 0xCC, 0x80, 0x01, + 0x60, 0x06, 0xCF, 0x89, 0xCC, 0x80, 0xCD, 0x85, + // Bytes 1400 - 143f + 0x04, 0xCF, 0x89, 0xCD, 0x85, 0x06, 0xCF, 0x89, + 0xCC, 0x81, 0xCD, 0x85, 0x04, 0xCF, 0x89, 0xCD, + 0x82, 0x06, 0xCF, 0x89, 0xCD, 0x82, 0xCD, 0x85, + 0x04, 0xCE, 0x9F, 0xCC, 0x80, 0x04, 0xCE, 0xA9, + 0xCC, 0x80, 0x04, 0xCE, 0xA9, 0xCD, 0x85, 0x02, + 0xC2, 0xB4, 0x03, 0x20, 0xCC, 0x94, 0x03, 0xE2, + 0x80, 0x82, 0x03, 0xE2, 0x80, 0x83, 0x03, 0xE2, + 0x80, 0x90, 0x03, 0x20, 0xCC, 0xB3, 0x01, 0x2E, + // Bytes 1440 - 147f + 0x02, 0x2E, 0x2E, 0x03, 0x2E, 0x2E, 0x2E, 0x06, + 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0x09, 0xE2, + 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2, + 0x06, 0xE2, 0x80, 0xB5, 0xE2, 0x80, 0xB5, 0x09, + 0xE2, 0x80, 0xB5, 0xE2, 0x80, 0xB5, 0xE2, 0x80, + 0xB5, 0x02, 0x21, 0x21, 0x03, 0x20, 0xCC, 0x85, + 0x02, 0x3F, 0x3F, 0x02, 0x3F, 0x21, 0x02, 0x21, + 0x3F, 0x0C, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2, + // Bytes 1480 - 14bf + 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0x01, 0x30, + 0x01, 0x34, 0x01, 0x35, 0x01, 0x36, 0x01, 0x37, + 0x01, 0x38, 0x01, 0x39, 0x01, 0x2B, 0x03, 0xE2, + 0x88, 0x92, 0x01, 0x3D, 0x01, 0x28, 0x01, 0x29, + 0x01, 0x6E, 0x02, 0x52, 0x73, 0x03, 0x61, 0x2F, + 0x63, 0x03, 0x61, 0x2F, 0x73, 0x01, 0x43, 0x03, + 0xC2, 0xB0, 0x43, 0x03, 0x63, 0x2F, 0x6F, 0x03, + 0x63, 0x2F, 0x75, 0x02, 0xC6, 0x90, 0x03, 0xC2, + // Bytes 14c0 - 14ff + 0xB0, 0x46, 0x02, 0xC4, 0xA7, 0x02, 0x4E, 0x6F, + 0x01, 0x51, 0x02, 0x53, 0x4D, 0x03, 0x54, 0x45, + 0x4C, 0x02, 0x54, 0x4D, 0x01, 0x5A, 0x02, 0xCE, + 0xA9, 0x01, 0x46, 0x02, 0xD7, 0x90, 0x02, 0xD7, + 0x91, 0x02, 0xD7, 0x92, 0x02, 0xD7, 0x93, 0x03, + 0x46, 0x41, 0x58, 0x02, 0xCE, 0x93, 0x02, 0xCE, + 0xA0, 0x03, 0xE2, 0x88, 0x91, 0x05, 0x31, 0xE2, + 0x81, 0x84, 0x37, 0x05, 0x31, 0xE2, 0x81, 0x84, + // Bytes 1500 - 153f + 0x39, 0x06, 0x31, 0xE2, 0x81, 0x84, 0x31, 0x30, + 0x05, 0x31, 0xE2, 0x81, 0x84, 0x33, 0x05, 0x32, + 0xE2, 0x81, 0x84, 0x33, 0x05, 0x31, 0xE2, 0x81, + 0x84, 0x35, 0x05, 0x32, 0xE2, 0x81, 0x84, 0x35, + 0x05, 0x33, 0xE2, 0x81, 0x84, 0x35, 0x05, 0x34, + 0xE2, 0x81, 0x84, 0x35, 0x05, 0x31, 0xE2, 0x81, + 0x84, 0x36, 0x05, 0x35, 0xE2, 0x81, 0x84, 0x36, + 0x05, 0x31, 0xE2, 0x81, 0x84, 0x38, 0x05, 0x33, + // Bytes 1540 - 157f + 0xE2, 0x81, 0x84, 0x38, 0x05, 0x35, 0xE2, 0x81, + 0x84, 0x38, 0x05, 0x37, 0xE2, 0x81, 0x84, 0x38, + 0x04, 0x31, 0xE2, 0x81, 0x84, 0x02, 0x49, 0x49, + 0x03, 0x49, 0x49, 0x49, 0x02, 0x49, 0x56, 0x01, + 0x56, 0x02, 0x56, 0x49, 0x03, 0x56, 0x49, 0x49, + 0x04, 0x56, 0x49, 0x49, 0x49, 0x02, 0x49, 0x58, + 0x01, 0x58, 0x02, 0x58, 0x49, 0x03, 0x58, 0x49, + 0x49, 0x02, 0x69, 0x69, 0x03, 0x69, 0x69, 0x69, + // Bytes 1580 - 15bf + 0x02, 0x69, 0x76, 0x02, 0x76, 0x69, 0x03, 0x76, + 0x69, 0x69, 0x04, 0x76, 0x69, 0x69, 0x69, 0x02, + 0x69, 0x78, 0x02, 0x78, 0x69, 0x03, 0x78, 0x69, + 0x69, 0x05, 0x30, 0xE2, 0x81, 0x84, 0x33, 0x05, + 0xE2, 0x86, 0x90, 0xCC, 0xB8, 0x05, 0xE2, 0x86, + 0x92, 0xCC, 0xB8, 0x05, 0xE2, 0x86, 0x94, 0xCC, + 0xB8, 0x05, 0xE2, 0x87, 0x90, 0xCC, 0xB8, 0x05, + 0xE2, 0x87, 0x94, 0xCC, 0xB8, 0x05, 0xE2, 0x87, + // Bytes 15c0 - 15ff + 0x92, 0xCC, 0xB8, 0x05, 0xE2, 0x88, 0x83, 0xCC, + 0xB8, 0x05, 0xE2, 0x88, 0x88, 0xCC, 0xB8, 0x05, + 0xE2, 0x88, 0x8B, 0xCC, 0xB8, 0x05, 0xE2, 0x88, + 0xA3, 0xCC, 0xB8, 0x05, 0xE2, 0x88, 0xA5, 0xCC, + 0xB8, 0x06, 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB, + 0x09, 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB, 0xE2, + 0x88, 0xAB, 0x06, 0xE2, 0x88, 0xAE, 0xE2, 0x88, + 0xAE, 0x09, 0xE2, 0x88, 0xAE, 0xE2, 0x88, 0xAE, + // Bytes 1600 - 163f + 0xE2, 0x88, 0xAE, 0x05, 0xE2, 0x88, 0xBC, 0xCC, + 0xB8, 0x05, 0xE2, 0x89, 0x83, 0xCC, 0xB8, 0x05, + 0xE2, 0x89, 0x85, 0xCC, 0xB8, 0x05, 0xE2, 0x89, + 0x88, 0xCC, 0xB8, 0x03, 0x3D, 0xCC, 0xB8, 0x05, + 0xE2, 0x89, 0xA1, 0xCC, 0xB8, 0x05, 0xE2, 0x89, + 0x8D, 0xCC, 0xB8, 0x03, 0x3C, 0xCC, 0xB8, 0x03, + 0x3E, 0xCC, 0xB8, 0x05, 0xE2, 0x89, 0xA4, 0xCC, + 0xB8, 0x05, 0xE2, 0x89, 0xA5, 0xCC, 0xB8, 0x05, + // Bytes 1640 - 167f + 0xE2, 0x89, 0xB2, 0xCC, 0xB8, 0x05, 0xE2, 0x89, + 0xB3, 0xCC, 0xB8, 0x05, 0xE2, 0x89, 0xB6, 0xCC, + 0xB8, 0x05, 0xE2, 0x89, 0xB7, 0xCC, 0xB8, 0x05, + 0xE2, 0x89, 0xBA, 0xCC, 0xB8, 0x05, 0xE2, 0x89, + 0xBB, 0xCC, 0xB8, 0x05, 0xE2, 0x8A, 0x82, 0xCC, + 0xB8, 0x05, 0xE2, 0x8A, 0x83, 0xCC, 0xB8, 0x05, + 0xE2, 0x8A, 0x86, 0xCC, 0xB8, 0x05, 0xE2, 0x8A, + 0x87, 0xCC, 0xB8, 0x05, 0xE2, 0x8A, 0xA2, 0xCC, + // Bytes 1680 - 16bf + 0xB8, 0x05, 0xE2, 0x8A, 0xA8, 0xCC, 0xB8, 0x05, + 0xE2, 0x8A, 0xA9, 0xCC, 0xB8, 0x05, 0xE2, 0x8A, + 0xAB, 0xCC, 0xB8, 0x05, 0xE2, 0x89, 0xBC, 0xCC, + 0xB8, 0x05, 0xE2, 0x89, 0xBD, 0xCC, 0xB8, 0x05, + 0xE2, 0x8A, 0x91, 0xCC, 0xB8, 0x05, 0xE2, 0x8A, + 0x92, 0xCC, 0xB8, 0x05, 0xE2, 0x8A, 0xB2, 0xCC, + 0xB8, 0x05, 0xE2, 0x8A, 0xB3, 0xCC, 0xB8, 0x05, + 0xE2, 0x8A, 0xB4, 0xCC, 0xB8, 0x05, 0xE2, 0x8A, + // Bytes 16c0 - 16ff + 0xB5, 0xCC, 0xB8, 0x03, 0xE3, 0x80, 0x88, 0x03, + 0xE3, 0x80, 0x89, 0x02, 0x31, 0x30, 0x02, 0x31, + 0x31, 0x02, 0x31, 0x32, 0x02, 0x31, 0x33, 0x02, + 0x31, 0x34, 0x02, 0x31, 0x35, 0x02, 0x31, 0x36, + 0x02, 0x31, 0x37, 0x02, 0x31, 0x38, 0x02, 0x31, + 0x39, 0x02, 0x32, 0x30, 0x03, 0x28, 0x31, 0x29, + 0x03, 0x28, 0x32, 0x29, 0x03, 0x28, 0x33, 0x29, + 0x03, 0x28, 0x34, 0x29, 0x03, 0x28, 0x35, 0x29, + // Bytes 1700 - 173f + 0x03, 0x28, 0x36, 0x29, 0x03, 0x28, 0x37, 0x29, + 0x03, 0x28, 0x38, 0x29, 0x03, 0x28, 0x39, 0x29, + 0x04, 0x28, 0x31, 0x30, 0x29, 0x04, 0x28, 0x31, + 0x31, 0x29, 0x04, 0x28, 0x31, 0x32, 0x29, 0x04, + 0x28, 0x31, 0x33, 0x29, 0x04, 0x28, 0x31, 0x34, + 0x29, 0x04, 0x28, 0x31, 0x35, 0x29, 0x04, 0x28, + 0x31, 0x36, 0x29, 0x04, 0x28, 0x31, 0x37, 0x29, + 0x04, 0x28, 0x31, 0x38, 0x29, 0x04, 0x28, 0x31, + // Bytes 1740 - 177f + 0x39, 0x29, 0x04, 0x28, 0x32, 0x30, 0x29, 0x02, + 0x31, 0x2E, 0x02, 0x32, 0x2E, 0x02, 0x33, 0x2E, + 0x02, 0x34, 0x2E, 0x02, 0x35, 0x2E, 0x02, 0x36, + 0x2E, 0x02, 0x37, 0x2E, 0x02, 0x38, 0x2E, 0x02, + 0x39, 0x2E, 0x03, 0x31, 0x30, 0x2E, 0x03, 0x31, + 0x31, 0x2E, 0x03, 0x31, 0x32, 0x2E, 0x03, 0x31, + 0x33, 0x2E, 0x03, 0x31, 0x34, 0x2E, 0x03, 0x31, + 0x35, 0x2E, 0x03, 0x31, 0x36, 0x2E, 0x03, 0x31, + // Bytes 1780 - 17bf + 0x37, 0x2E, 0x03, 0x31, 0x38, 0x2E, 0x03, 0x31, + 0x39, 0x2E, 0x03, 0x32, 0x30, 0x2E, 0x03, 0x28, + 0x61, 0x29, 0x03, 0x28, 0x62, 0x29, 0x03, 0x28, + 0x63, 0x29, 0x03, 0x28, 0x64, 0x29, 0x03, 0x28, + 0x65, 0x29, 0x03, 0x28, 0x66, 0x29, 0x03, 0x28, + 0x67, 0x29, 0x03, 0x28, 0x68, 0x29, 0x03, 0x28, + 0x69, 0x29, 0x03, 0x28, 0x6A, 0x29, 0x03, 0x28, + 0x6B, 0x29, 0x03, 0x28, 0x6C, 0x29, 0x03, 0x28, + // Bytes 17c0 - 17ff + 0x6D, 0x29, 0x03, 0x28, 0x6E, 0x29, 0x03, 0x28, + 0x6F, 0x29, 0x03, 0x28, 0x70, 0x29, 0x03, 0x28, + 0x71, 0x29, 0x03, 0x28, 0x72, 0x29, 0x03, 0x28, + 0x73, 0x29, 0x03, 0x28, 0x74, 0x29, 0x03, 0x28, + 0x75, 0x29, 0x03, 0x28, 0x76, 0x29, 0x03, 0x28, + 0x77, 0x29, 0x03, 0x28, 0x78, 0x29, 0x03, 0x28, + 0x79, 0x29, 0x03, 0x28, 0x7A, 0x29, 0x01, 0x53, + 0x01, 0x59, 0x01, 0x71, 0x0C, 0xE2, 0x88, 0xAB, + // Bytes 1800 - 183f + 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB, 0xE2, 0x88, + 0xAB, 0x03, 0x3A, 0x3A, 0x3D, 0x02, 0x3D, 0x3D, + 0x03, 0x3D, 0x3D, 0x3D, 0x05, 0xE2, 0xAB, 0x9D, + 0xCC, 0xB8, 0x03, 0xE2, 0xB5, 0xA1, 0x03, 0xE6, + 0xAF, 0x8D, 0x03, 0xE9, 0xBE, 0x9F, 0x03, 0xE4, + 0xB8, 0x80, 0x03, 0xE4, 0xB8, 0xA8, 0x03, 0xE4, + 0xB8, 0xB6, 0x03, 0xE4, 0xB8, 0xBF, 0x03, 0xE4, + 0xB9, 0x99, 0x03, 0xE4, 0xBA, 0x85, 0x03, 0xE4, + // Bytes 1840 - 187f + 0xBA, 0x8C, 0x03, 0xE4, 0xBA, 0xA0, 0x03, 0xE4, + 0xBA, 0xBA, 0x03, 0xE5, 0x84, 0xBF, 0x03, 0xE5, + 0x85, 0xA5, 0x03, 0xE5, 0x85, 0xAB, 0x03, 0xE5, + 0x86, 0x82, 0x03, 0xE5, 0x86, 0x96, 0x03, 0xE5, + 0x86, 0xAB, 0x03, 0xE5, 0x87, 0xA0, 0x03, 0xE5, + 0x87, 0xB5, 0x03, 0xE5, 0x88, 0x80, 0x03, 0xE5, + 0x8A, 0x9B, 0x03, 0xE5, 0x8B, 0xB9, 0x03, 0xE5, + 0x8C, 0x95, 0x03, 0xE5, 0x8C, 0x9A, 0x03, 0xE5, + // Bytes 1880 - 18bf + 0x8C, 0xB8, 0x03, 0xE5, 0x8D, 0x81, 0x03, 0xE5, + 0x8D, 0x9C, 0x03, 0xE5, 0x8D, 0xA9, 0x03, 0xE5, + 0x8E, 0x82, 0x03, 0xE5, 0x8E, 0xB6, 0x03, 0xE5, + 0x8F, 0x88, 0x03, 0xE5, 0x8F, 0xA3, 0x03, 0xE5, + 0x9B, 0x97, 0x03, 0xE5, 0x9C, 0x9F, 0x03, 0xE5, + 0xA3, 0xAB, 0x03, 0xE5, 0xA4, 0x82, 0x03, 0xE5, + 0xA4, 0x8A, 0x03, 0xE5, 0xA4, 0x95, 0x03, 0xE5, + 0xA4, 0xA7, 0x03, 0xE5, 0xA5, 0xB3, 0x03, 0xE5, + // Bytes 18c0 - 18ff + 0xAD, 0x90, 0x03, 0xE5, 0xAE, 0x80, 0x03, 0xE5, + 0xAF, 0xB8, 0x03, 0xE5, 0xB0, 0x8F, 0x03, 0xE5, + 0xB0, 0xA2, 0x03, 0xE5, 0xB0, 0xB8, 0x03, 0xE5, + 0xB1, 0xAE, 0x03, 0xE5, 0xB1, 0xB1, 0x03, 0xE5, + 0xB7, 0x9B, 0x03, 0xE5, 0xB7, 0xA5, 0x03, 0xE5, + 0xB7, 0xB1, 0x03, 0xE5, 0xB7, 0xBE, 0x03, 0xE5, + 0xB9, 0xB2, 0x03, 0xE5, 0xB9, 0xBA, 0x03, 0xE5, + 0xB9, 0xBF, 0x03, 0xE5, 0xBB, 0xB4, 0x03, 0xE5, + // Bytes 1900 - 193f + 0xBB, 0xBE, 0x03, 0xE5, 0xBC, 0x8B, 0x03, 0xE5, + 0xBC, 0x93, 0x03, 0xE5, 0xBD, 0x90, 0x03, 0xE5, + 0xBD, 0xA1, 0x03, 0xE5, 0xBD, 0xB3, 0x03, 0xE5, + 0xBF, 0x83, 0x03, 0xE6, 0x88, 0x88, 0x03, 0xE6, + 0x88, 0xB6, 0x03, 0xE6, 0x89, 0x8B, 0x03, 0xE6, + 0x94, 0xAF, 0x03, 0xE6, 0x94, 0xB4, 0x03, 0xE6, + 0x96, 0x87, 0x03, 0xE6, 0x96, 0x97, 0x03, 0xE6, + 0x96, 0xA4, 0x03, 0xE6, 0x96, 0xB9, 0x03, 0xE6, + // Bytes 1940 - 197f + 0x97, 0xA0, 0x03, 0xE6, 0x97, 0xA5, 0x03, 0xE6, + 0x9B, 0xB0, 0x03, 0xE6, 0x9C, 0x88, 0x03, 0xE6, + 0x9C, 0xA8, 0x03, 0xE6, 0xAC, 0xA0, 0x03, 0xE6, + 0xAD, 0xA2, 0x03, 0xE6, 0xAD, 0xB9, 0x03, 0xE6, + 0xAE, 0xB3, 0x03, 0xE6, 0xAF, 0x8B, 0x03, 0xE6, + 0xAF, 0x94, 0x03, 0xE6, 0xAF, 0x9B, 0x03, 0xE6, + 0xB0, 0x8F, 0x03, 0xE6, 0xB0, 0x94, 0x03, 0xE6, + 0xB0, 0xB4, 0x03, 0xE7, 0x81, 0xAB, 0x03, 0xE7, + // Bytes 1980 - 19bf + 0x88, 0xAA, 0x03, 0xE7, 0x88, 0xB6, 0x03, 0xE7, + 0x88, 0xBB, 0x03, 0xE7, 0x88, 0xBF, 0x03, 0xE7, + 0x89, 0x87, 0x03, 0xE7, 0x89, 0x99, 0x03, 0xE7, + 0x89, 0x9B, 0x03, 0xE7, 0x8A, 0xAC, 0x03, 0xE7, + 0x8E, 0x84, 0x03, 0xE7, 0x8E, 0x89, 0x03, 0xE7, + 0x93, 0x9C, 0x03, 0xE7, 0x93, 0xA6, 0x03, 0xE7, + 0x94, 0x98, 0x03, 0xE7, 0x94, 0x9F, 0x03, 0xE7, + 0x94, 0xA8, 0x03, 0xE7, 0x94, 0xB0, 0x03, 0xE7, + // Bytes 19c0 - 19ff + 0x96, 0x8B, 0x03, 0xE7, 0x96, 0x92, 0x03, 0xE7, + 0x99, 0xB6, 0x03, 0xE7, 0x99, 0xBD, 0x03, 0xE7, + 0x9A, 0xAE, 0x03, 0xE7, 0x9A, 0xBF, 0x03, 0xE7, + 0x9B, 0xAE, 0x03, 0xE7, 0x9F, 0x9B, 0x03, 0xE7, + 0x9F, 0xA2, 0x03, 0xE7, 0x9F, 0xB3, 0x03, 0xE7, + 0xA4, 0xBA, 0x03, 0xE7, 0xA6, 0xB8, 0x03, 0xE7, + 0xA6, 0xBE, 0x03, 0xE7, 0xA9, 0xB4, 0x03, 0xE7, + 0xAB, 0x8B, 0x03, 0xE7, 0xAB, 0xB9, 0x03, 0xE7, + // Bytes 1a00 - 1a3f + 0xB1, 0xB3, 0x03, 0xE7, 0xB3, 0xB8, 0x03, 0xE7, + 0xBC, 0xB6, 0x03, 0xE7, 0xBD, 0x91, 0x03, 0xE7, + 0xBE, 0x8A, 0x03, 0xE7, 0xBE, 0xBD, 0x03, 0xE8, + 0x80, 0x81, 0x03, 0xE8, 0x80, 0x8C, 0x03, 0xE8, + 0x80, 0x92, 0x03, 0xE8, 0x80, 0xB3, 0x03, 0xE8, + 0x81, 0xBF, 0x03, 0xE8, 0x82, 0x89, 0x03, 0xE8, + 0x87, 0xA3, 0x03, 0xE8, 0x87, 0xAA, 0x03, 0xE8, + 0x87, 0xB3, 0x03, 0xE8, 0x87, 0xBC, 0x03, 0xE8, + // Bytes 1a40 - 1a7f + 0x88, 0x8C, 0x03, 0xE8, 0x88, 0x9B, 0x03, 0xE8, + 0x88, 0x9F, 0x03, 0xE8, 0x89, 0xAE, 0x03, 0xE8, + 0x89, 0xB2, 0x03, 0xE8, 0x89, 0xB8, 0x03, 0xE8, + 0x99, 0x8D, 0x03, 0xE8, 0x99, 0xAB, 0x03, 0xE8, + 0xA1, 0x80, 0x03, 0xE8, 0xA1, 0x8C, 0x03, 0xE8, + 0xA1, 0xA3, 0x03, 0xE8, 0xA5, 0xBE, 0x03, 0xE8, + 0xA6, 0x8B, 0x03, 0xE8, 0xA7, 0x92, 0x03, 0xE8, + 0xA8, 0x80, 0x03, 0xE8, 0xB0, 0xB7, 0x03, 0xE8, + // Bytes 1a80 - 1abf + 0xB1, 0x86, 0x03, 0xE8, 0xB1, 0x95, 0x03, 0xE8, + 0xB1, 0xB8, 0x03, 0xE8, 0xB2, 0x9D, 0x03, 0xE8, + 0xB5, 0xA4, 0x03, 0xE8, 0xB5, 0xB0, 0x03, 0xE8, + 0xB6, 0xB3, 0x03, 0xE8, 0xBA, 0xAB, 0x03, 0xE8, + 0xBB, 0x8A, 0x03, 0xE8, 0xBE, 0x9B, 0x03, 0xE8, + 0xBE, 0xB0, 0x03, 0xE8, 0xBE, 0xB5, 0x03, 0xE9, + 0x82, 0x91, 0x03, 0xE9, 0x85, 0x89, 0x03, 0xE9, + 0x87, 0x86, 0x03, 0xE9, 0x87, 0x8C, 0x03, 0xE9, + // Bytes 1ac0 - 1aff + 0x87, 0x91, 0x03, 0xE9, 0x95, 0xB7, 0x03, 0xE9, + 0x96, 0x80, 0x03, 0xE9, 0x98, 0x9C, 0x03, 0xE9, + 0x9A, 0xB6, 0x03, 0xE9, 0x9A, 0xB9, 0x03, 0xE9, + 0x9B, 0xA8, 0x03, 0xE9, 0x9D, 0x91, 0x03, 0xE9, + 0x9D, 0x9E, 0x03, 0xE9, 0x9D, 0xA2, 0x03, 0xE9, + 0x9D, 0xA9, 0x03, 0xE9, 0x9F, 0x8B, 0x03, 0xE9, + 0x9F, 0xAD, 0x03, 0xE9, 0x9F, 0xB3, 0x03, 0xE9, + 0xA0, 0x81, 0x03, 0xE9, 0xA2, 0xA8, 0x03, 0xE9, + // Bytes 1b00 - 1b3f + 0xA3, 0x9B, 0x03, 0xE9, 0xA3, 0x9F, 0x03, 0xE9, + 0xA6, 0x96, 0x03, 0xE9, 0xA6, 0x99, 0x03, 0xE9, + 0xA6, 0xAC, 0x03, 0xE9, 0xAA, 0xA8, 0x03, 0xE9, + 0xAB, 0x98, 0x03, 0xE9, 0xAB, 0x9F, 0x03, 0xE9, + 0xAC, 0xA5, 0x03, 0xE9, 0xAC, 0xAF, 0x03, 0xE9, + 0xAC, 0xB2, 0x03, 0xE9, 0xAC, 0xBC, 0x03, 0xE9, + 0xAD, 0x9A, 0x03, 0xE9, 0xB3, 0xA5, 0x03, 0xE9, + 0xB9, 0xB5, 0x03, 0xE9, 0xB9, 0xBF, 0x03, 0xE9, + // Bytes 1b40 - 1b7f + 0xBA, 0xA5, 0x03, 0xE9, 0xBA, 0xBB, 0x03, 0xE9, + 0xBB, 0x83, 0x03, 0xE9, 0xBB, 0x8D, 0x03, 0xE9, + 0xBB, 0x91, 0x03, 0xE9, 0xBB, 0xB9, 0x03, 0xE9, + 0xBB, 0xBD, 0x03, 0xE9, 0xBC, 0x8E, 0x03, 0xE9, + 0xBC, 0x93, 0x03, 0xE9, 0xBC, 0xA0, 0x03, 0xE9, + 0xBC, 0xBB, 0x03, 0xE9, 0xBD, 0x8A, 0x03, 0xE9, + 0xBD, 0x92, 0x03, 0xE9, 0xBE, 0x8D, 0x03, 0xE9, + 0xBE, 0x9C, 0x03, 0xE9, 0xBE, 0xA0, 0x03, 0xE3, + // Bytes 1b80 - 1bbf + 0x80, 0x92, 0x03, 0xE5, 0x8D, 0x84, 0x03, 0xE5, + 0x8D, 0x85, 0x06, 0xE3, 0x81, 0x8B, 0xE3, 0x82, + 0x99, 0x06, 0xE3, 0x81, 0x8D, 0xE3, 0x82, 0x99, + 0x06, 0xE3, 0x81, 0x8F, 0xE3, 0x82, 0x99, 0x06, + 0xE3, 0x81, 0x91, 0xE3, 0x82, 0x99, 0x06, 0xE3, + 0x81, 0x93, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x81, + 0x95, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x81, 0x97, + 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x81, 0x99, 0xE3, + // Bytes 1bc0 - 1bff + 0x82, 0x99, 0x06, 0xE3, 0x81, 0x9B, 0xE3, 0x82, + 0x99, 0x06, 0xE3, 0x81, 0x9D, 0xE3, 0x82, 0x99, + 0x06, 0xE3, 0x81, 0x9F, 0xE3, 0x82, 0x99, 0x06, + 0xE3, 0x81, 0xA1, 0xE3, 0x82, 0x99, 0x06, 0xE3, + 0x81, 0xA4, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x81, + 0xA6, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x81, 0xA8, + 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x81, 0xAF, 0xE3, + 0x82, 0x99, 0x06, 0xE3, 0x81, 0xAF, 0xE3, 0x82, + // Bytes 1c00 - 1c3f + 0x9A, 0x06, 0xE3, 0x81, 0xB2, 0xE3, 0x82, 0x99, + 0x06, 0xE3, 0x81, 0xB2, 0xE3, 0x82, 0x9A, 0x06, + 0xE3, 0x81, 0xB5, 0xE3, 0x82, 0x99, 0x06, 0xE3, + 0x81, 0xB5, 0xE3, 0x82, 0x9A, 0x06, 0xE3, 0x81, + 0xB8, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x81, 0xB8, + 0xE3, 0x82, 0x9A, 0x06, 0xE3, 0x81, 0xBB, 0xE3, + 0x82, 0x99, 0x06, 0xE3, 0x81, 0xBB, 0xE3, 0x82, + 0x9A, 0x06, 0xE3, 0x81, 0x86, 0xE3, 0x82, 0x99, + // Bytes 1c40 - 1c7f + 0x04, 0x20, 0xE3, 0x82, 0x99, 0x04, 0x20, 0xE3, + 0x82, 0x9A, 0x06, 0xE3, 0x82, 0x9D, 0xE3, 0x82, + 0x99, 0x06, 0xE3, 0x82, 0x88, 0xE3, 0x82, 0x8A, + 0x06, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0x06, + 0xE3, 0x82, 0xAD, 0xE3, 0x82, 0x99, 0x06, 0xE3, + 0x82, 0xAF, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x82, + 0xB1, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x82, 0xB3, + 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x82, 0xB5, 0xE3, + // Bytes 1c80 - 1cbf + 0x82, 0x99, 0x06, 0xE3, 0x82, 0xB7, 0xE3, 0x82, + 0x99, 0x06, 0xE3, 0x82, 0xB9, 0xE3, 0x82, 0x99, + 0x06, 0xE3, 0x82, 0xBB, 0xE3, 0x82, 0x99, 0x06, + 0xE3, 0x82, 0xBD, 0xE3, 0x82, 0x99, 0x06, 0xE3, + 0x82, 0xBF, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x83, + 0x81, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x83, 0x84, + 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x83, 0x86, 0xE3, + 0x82, 0x99, 0x06, 0xE3, 0x83, 0x88, 0xE3, 0x82, + // Bytes 1cc0 - 1cff + 0x99, 0x06, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x99, + 0x06, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A, 0x06, + 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x99, 0x06, 0xE3, + 0x83, 0x92, 0xE3, 0x82, 0x9A, 0x06, 0xE3, 0x83, + 0x95, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x83, 0x95, + 0xE3, 0x82, 0x9A, 0x06, 0xE3, 0x83, 0x98, 0xE3, + 0x82, 0x99, 0x06, 0xE3, 0x83, 0x98, 0xE3, 0x82, + 0x9A, 0x06, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x99, + // Bytes 1d00 - 1d3f + 0x06, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x9A, 0x06, + 0xE3, 0x82, 0xA6, 0xE3, 0x82, 0x99, 0x06, 0xE3, + 0x83, 0xAF, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x83, + 0xB0, 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x83, 0xB1, + 0xE3, 0x82, 0x99, 0x06, 0xE3, 0x83, 0xB2, 0xE3, + 0x82, 0x99, 0x06, 0xE3, 0x83, 0xBD, 0xE3, 0x82, + 0x99, 0x06, 0xE3, 0x82, 0xB3, 0xE3, 0x83, 0x88, + 0x03, 0xE1, 0x84, 0x80, 0x03, 0xE1, 0x84, 0x81, + // Bytes 1d40 - 1d7f + 0x03, 0xE1, 0x86, 0xAA, 0x03, 0xE1, 0x84, 0x82, + 0x03, 0xE1, 0x86, 0xAC, 0x03, 0xE1, 0x86, 0xAD, + 0x03, 0xE1, 0x84, 0x83, 0x03, 0xE1, 0x84, 0x84, + 0x03, 0xE1, 0x84, 0x85, 0x03, 0xE1, 0x86, 0xB0, + 0x03, 0xE1, 0x86, 0xB1, 0x03, 0xE1, 0x86, 0xB2, + 0x03, 0xE1, 0x86, 0xB3, 0x03, 0xE1, 0x86, 0xB4, + 0x03, 0xE1, 0x86, 0xB5, 0x03, 0xE1, 0x84, 0x9A, + 0x03, 0xE1, 0x84, 0x86, 0x03, 0xE1, 0x84, 0x87, + // Bytes 1d80 - 1dbf + 0x03, 0xE1, 0x84, 0x88, 0x03, 0xE1, 0x84, 0xA1, + 0x03, 0xE1, 0x84, 0x89, 0x03, 0xE1, 0x84, 0x8A, + 0x03, 0xE1, 0x84, 0x8B, 0x03, 0xE1, 0x84, 0x8C, + 0x03, 0xE1, 0x84, 0x8D, 0x03, 0xE1, 0x84, 0x8E, + 0x03, 0xE1, 0x84, 0x8F, 0x03, 0xE1, 0x84, 0x90, + 0x03, 0xE1, 0x84, 0x91, 0x03, 0xE1, 0x84, 0x92, + 0x03, 0xE1, 0x85, 0xA1, 0x03, 0xE1, 0x85, 0xA2, + 0x03, 0xE1, 0x85, 0xA3, 0x03, 0xE1, 0x85, 0xA4, + // Bytes 1dc0 - 1dff + 0x03, 0xE1, 0x85, 0xA5, 0x03, 0xE1, 0x85, 0xA6, + 0x03, 0xE1, 0x85, 0xA7, 0x03, 0xE1, 0x85, 0xA8, + 0x03, 0xE1, 0x85, 0xA9, 0x03, 0xE1, 0x85, 0xAA, + 0x03, 0xE1, 0x85, 0xAB, 0x03, 0xE1, 0x85, 0xAC, + 0x03, 0xE1, 0x85, 0xAD, 0x03, 0xE1, 0x85, 0xAE, + 0x03, 0xE1, 0x85, 0xAF, 0x03, 0xE1, 0x85, 0xB0, + 0x03, 0xE1, 0x85, 0xB1, 0x03, 0xE1, 0x85, 0xB2, + 0x03, 0xE1, 0x85, 0xB3, 0x03, 0xE1, 0x85, 0xB4, + // Bytes 1e00 - 1e3f + 0x03, 0xE1, 0x85, 0xB5, 0x03, 0xE1, 0x85, 0xA0, + 0x03, 0xE1, 0x84, 0x94, 0x03, 0xE1, 0x84, 0x95, + 0x03, 0xE1, 0x87, 0x87, 0x03, 0xE1, 0x87, 0x88, + 0x03, 0xE1, 0x87, 0x8C, 0x03, 0xE1, 0x87, 0x8E, + 0x03, 0xE1, 0x87, 0x93, 0x03, 0xE1, 0x87, 0x97, + 0x03, 0xE1, 0x87, 0x99, 0x03, 0xE1, 0x84, 0x9C, + 0x03, 0xE1, 0x87, 0x9D, 0x03, 0xE1, 0x87, 0x9F, + 0x03, 0xE1, 0x84, 0x9D, 0x03, 0xE1, 0x84, 0x9E, + // Bytes 1e40 - 1e7f + 0x03, 0xE1, 0x84, 0xA0, 0x03, 0xE1, 0x84, 0xA2, + 0x03, 0xE1, 0x84, 0xA3, 0x03, 0xE1, 0x84, 0xA7, + 0x03, 0xE1, 0x84, 0xA9, 0x03, 0xE1, 0x84, 0xAB, + 0x03, 0xE1, 0x84, 0xAC, 0x03, 0xE1, 0x84, 0xAD, + 0x03, 0xE1, 0x84, 0xAE, 0x03, 0xE1, 0x84, 0xAF, + 0x03, 0xE1, 0x84, 0xB2, 0x03, 0xE1, 0x84, 0xB6, + 0x03, 0xE1, 0x85, 0x80, 0x03, 0xE1, 0x85, 0x87, + 0x03, 0xE1, 0x85, 0x8C, 0x03, 0xE1, 0x87, 0xB1, + // Bytes 1e80 - 1ebf + 0x03, 0xE1, 0x87, 0xB2, 0x03, 0xE1, 0x85, 0x97, + 0x03, 0xE1, 0x85, 0x98, 0x03, 0xE1, 0x85, 0x99, + 0x03, 0xE1, 0x86, 0x84, 0x03, 0xE1, 0x86, 0x85, + 0x03, 0xE1, 0x86, 0x88, 0x03, 0xE1, 0x86, 0x91, + 0x03, 0xE1, 0x86, 0x92, 0x03, 0xE1, 0x86, 0x94, + 0x03, 0xE1, 0x86, 0x9E, 0x03, 0xE1, 0x86, 0xA1, + 0x03, 0xE4, 0xB8, 0x89, 0x03, 0xE5, 0x9B, 0x9B, + 0x03, 0xE4, 0xB8, 0x8A, 0x03, 0xE4, 0xB8, 0xAD, + // Bytes 1ec0 - 1eff + 0x03, 0xE4, 0xB8, 0x8B, 0x03, 0xE7, 0x94, 0xB2, + 0x03, 0xE4, 0xB8, 0x99, 0x03, 0xE4, 0xB8, 0x81, + 0x03, 0xE5, 0xA4, 0xA9, 0x03, 0xE5, 0x9C, 0xB0, + 0x05, 0x28, 0xE1, 0x84, 0x80, 0x29, 0x05, 0x28, + 0xE1, 0x84, 0x82, 0x29, 0x05, 0x28, 0xE1, 0x84, + 0x83, 0x29, 0x05, 0x28, 0xE1, 0x84, 0x85, 0x29, + 0x05, 0x28, 0xE1, 0x84, 0x86, 0x29, 0x05, 0x28, + 0xE1, 0x84, 0x87, 0x29, 0x05, 0x28, 0xE1, 0x84, + // Bytes 1f00 - 1f3f + 0x89, 0x29, 0x05, 0x28, 0xE1, 0x84, 0x8B, 0x29, + 0x05, 0x28, 0xE1, 0x84, 0x8C, 0x29, 0x05, 0x28, + 0xE1, 0x84, 0x8E, 0x29, 0x05, 0x28, 0xE1, 0x84, + 0x8F, 0x29, 0x05, 0x28, 0xE1, 0x84, 0x90, 0x29, + 0x05, 0x28, 0xE1, 0x84, 0x91, 0x29, 0x05, 0x28, + 0xE1, 0x84, 0x92, 0x29, 0x08, 0x28, 0xE1, 0x84, + 0x80, 0xE1, 0x85, 0xA1, 0x29, 0x08, 0x28, 0xE1, + 0x84, 0x82, 0xE1, 0x85, 0xA1, 0x29, 0x08, 0x28, + // Bytes 1f40 - 1f7f + 0xE1, 0x84, 0x83, 0xE1, 0x85, 0xA1, 0x29, 0x08, + 0x28, 0xE1, 0x84, 0x85, 0xE1, 0x85, 0xA1, 0x29, + 0x08, 0x28, 0xE1, 0x84, 0x86, 0xE1, 0x85, 0xA1, + 0x29, 0x08, 0x28, 0xE1, 0x84, 0x87, 0xE1, 0x85, + 0xA1, 0x29, 0x08, 0x28, 0xE1, 0x84, 0x89, 0xE1, + 0x85, 0xA1, 0x29, 0x08, 0x28, 0xE1, 0x84, 0x8B, + 0xE1, 0x85, 0xA1, 0x29, 0x08, 0x28, 0xE1, 0x84, + 0x8C, 0xE1, 0x85, 0xA1, 0x29, 0x08, 0x28, 0xE1, + // Bytes 1f80 - 1fbf + 0x84, 0x8E, 0xE1, 0x85, 0xA1, 0x29, 0x08, 0x28, + 0xE1, 0x84, 0x8F, 0xE1, 0x85, 0xA1, 0x29, 0x08, + 0x28, 0xE1, 0x84, 0x90, 0xE1, 0x85, 0xA1, 0x29, + 0x08, 0x28, 0xE1, 0x84, 0x91, 0xE1, 0x85, 0xA1, + 0x29, 0x08, 0x28, 0xE1, 0x84, 0x92, 0xE1, 0x85, + 0xA1, 0x29, 0x08, 0x28, 0xE1, 0x84, 0x8C, 0xE1, + 0x85, 0xAE, 0x29, 0x11, 0x28, 0xE1, 0x84, 0x8B, + 0xE1, 0x85, 0xA9, 0xE1, 0x84, 0x8C, 0xE1, 0x85, + // Bytes 1fc0 - 1fff + 0xA5, 0xE1, 0x86, 0xAB, 0x29, 0x0E, 0x28, 0xE1, + 0x84, 0x8B, 0xE1, 0x85, 0xA9, 0xE1, 0x84, 0x92, + 0xE1, 0x85, 0xAE, 0x29, 0x05, 0x28, 0xE4, 0xB8, + 0x80, 0x29, 0x05, 0x28, 0xE4, 0xBA, 0x8C, 0x29, + 0x05, 0x28, 0xE4, 0xB8, 0x89, 0x29, 0x05, 0x28, + 0xE5, 0x9B, 0x9B, 0x29, 0x05, 0x28, 0xE4, 0xBA, + 0x94, 0x29, 0x05, 0x28, 0xE5, 0x85, 0xAD, 0x29, + 0x05, 0x28, 0xE4, 0xB8, 0x83, 0x29, 0x05, 0x28, + // Bytes 2000 - 203f + 0xE5, 0x85, 0xAB, 0x29, 0x05, 0x28, 0xE4, 0xB9, + 0x9D, 0x29, 0x05, 0x28, 0xE5, 0x8D, 0x81, 0x29, + 0x05, 0x28, 0xE6, 0x9C, 0x88, 0x29, 0x05, 0x28, + 0xE7, 0x81, 0xAB, 0x29, 0x05, 0x28, 0xE6, 0xB0, + 0xB4, 0x29, 0x05, 0x28, 0xE6, 0x9C, 0xA8, 0x29, + 0x05, 0x28, 0xE9, 0x87, 0x91, 0x29, 0x05, 0x28, + 0xE5, 0x9C, 0x9F, 0x29, 0x05, 0x28, 0xE6, 0x97, + 0xA5, 0x29, 0x05, 0x28, 0xE6, 0xA0, 0xAA, 0x29, + // Bytes 2040 - 207f + 0x05, 0x28, 0xE6, 0x9C, 0x89, 0x29, 0x05, 0x28, + 0xE7, 0xA4, 0xBE, 0x29, 0x05, 0x28, 0xE5, 0x90, + 0x8D, 0x29, 0x05, 0x28, 0xE7, 0x89, 0xB9, 0x29, + 0x05, 0x28, 0xE8, 0xB2, 0xA1, 0x29, 0x05, 0x28, + 0xE7, 0xA5, 0x9D, 0x29, 0x05, 0x28, 0xE5, 0x8A, + 0xB4, 0x29, 0x05, 0x28, 0xE4, 0xBB, 0xA3, 0x29, + 0x05, 0x28, 0xE5, 0x91, 0xBC, 0x29, 0x05, 0x28, + 0xE5, 0xAD, 0xA6, 0x29, 0x05, 0x28, 0xE7, 0x9B, + // Bytes 2080 - 20bf + 0xA3, 0x29, 0x05, 0x28, 0xE4, 0xBC, 0x81, 0x29, + 0x05, 0x28, 0xE8, 0xB3, 0x87, 0x29, 0x05, 0x28, + 0xE5, 0x8D, 0x94, 0x29, 0x05, 0x28, 0xE7, 0xA5, + 0xAD, 0x29, 0x05, 0x28, 0xE4, 0xBC, 0x91, 0x29, + 0x05, 0x28, 0xE8, 0x87, 0xAA, 0x29, 0x05, 0x28, + 0xE8, 0x87, 0xB3, 0x29, 0x03, 0xE5, 0x95, 0x8F, + 0x03, 0xE5, 0xB9, 0xBC, 0x03, 0xE7, 0xAE, 0x8F, + 0x03, 0x50, 0x54, 0x45, 0x02, 0x32, 0x31, 0x02, + // Bytes 20c0 - 20ff + 0x32, 0x32, 0x02, 0x32, 0x33, 0x02, 0x32, 0x34, + 0x02, 0x32, 0x35, 0x02, 0x32, 0x36, 0x02, 0x32, + 0x37, 0x02, 0x32, 0x38, 0x02, 0x32, 0x39, 0x02, + 0x33, 0x30, 0x02, 0x33, 0x31, 0x02, 0x33, 0x32, + 0x02, 0x33, 0x33, 0x02, 0x33, 0x34, 0x02, 0x33, + 0x35, 0x06, 0xE1, 0x84, 0x80, 0xE1, 0x85, 0xA1, + 0x06, 0xE1, 0x84, 0x82, 0xE1, 0x85, 0xA1, 0x06, + 0xE1, 0x84, 0x83, 0xE1, 0x85, 0xA1, 0x06, 0xE1, + // Bytes 2100 - 213f + 0x84, 0x85, 0xE1, 0x85, 0xA1, 0x06, 0xE1, 0x84, + 0x86, 0xE1, 0x85, 0xA1, 0x06, 0xE1, 0x84, 0x87, + 0xE1, 0x85, 0xA1, 0x06, 0xE1, 0x84, 0x89, 0xE1, + 0x85, 0xA1, 0x06, 0xE1, 0x84, 0x8B, 0xE1, 0x85, + 0xA1, 0x06, 0xE1, 0x84, 0x8C, 0xE1, 0x85, 0xA1, + 0x06, 0xE1, 0x84, 0x8E, 0xE1, 0x85, 0xA1, 0x06, + 0xE1, 0x84, 0x8F, 0xE1, 0x85, 0xA1, 0x06, 0xE1, + 0x84, 0x90, 0xE1, 0x85, 0xA1, 0x06, 0xE1, 0x84, + // Bytes 2140 - 217f + 0x91, 0xE1, 0x85, 0xA1, 0x06, 0xE1, 0x84, 0x92, + 0xE1, 0x85, 0xA1, 0x0F, 0xE1, 0x84, 0x8E, 0xE1, + 0x85, 0xA1, 0xE1, 0x86, 0xB7, 0xE1, 0x84, 0x80, + 0xE1, 0x85, 0xA9, 0x0C, 0xE1, 0x84, 0x8C, 0xE1, + 0x85, 0xAE, 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xB4, + 0x06, 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xAE, 0x03, + 0xE4, 0xBA, 0x94, 0x03, 0xE5, 0x85, 0xAD, 0x03, + 0xE4, 0xB8, 0x83, 0x03, 0xE4, 0xB9, 0x9D, 0x03, + // Bytes 2180 - 21bf + 0xE6, 0xA0, 0xAA, 0x03, 0xE6, 0x9C, 0x89, 0x03, + 0xE7, 0xA4, 0xBE, 0x03, 0xE5, 0x90, 0x8D, 0x03, + 0xE7, 0x89, 0xB9, 0x03, 0xE8, 0xB2, 0xA1, 0x03, + 0xE7, 0xA5, 0x9D, 0x03, 0xE5, 0x8A, 0xB4, 0x03, + 0xE7, 0xA7, 0x98, 0x03, 0xE7, 0x94, 0xB7, 0x03, + 0xE9, 0x81, 0xA9, 0x03, 0xE5, 0x84, 0xAA, 0x03, + 0xE5, 0x8D, 0xB0, 0x03, 0xE6, 0xB3, 0xA8, 0x03, + 0xE9, 0xA0, 0x85, 0x03, 0xE4, 0xBC, 0x91, 0x03, + // Bytes 21c0 - 21ff + 0xE5, 0x86, 0x99, 0x03, 0xE6, 0xAD, 0xA3, 0x03, + 0xE5, 0xB7, 0xA6, 0x03, 0xE5, 0x8F, 0xB3, 0x03, + 0xE5, 0x8C, 0xBB, 0x03, 0xE5, 0xAE, 0x97, 0x03, + 0xE5, 0xAD, 0xA6, 0x03, 0xE7, 0x9B, 0xA3, 0x03, + 0xE4, 0xBC, 0x81, 0x03, 0xE8, 0xB3, 0x87, 0x03, + 0xE5, 0x8D, 0x94, 0x03, 0xE5, 0xA4, 0x9C, 0x02, + 0x33, 0x36, 0x02, 0x33, 0x37, 0x02, 0x33, 0x38, + 0x02, 0x33, 0x39, 0x02, 0x34, 0x30, 0x02, 0x34, + // Bytes 2200 - 223f + 0x31, 0x02, 0x34, 0x32, 0x02, 0x34, 0x33, 0x02, + 0x34, 0x34, 0x02, 0x34, 0x35, 0x02, 0x34, 0x36, + 0x02, 0x34, 0x37, 0x02, 0x34, 0x38, 0x02, 0x34, + 0x39, 0x02, 0x35, 0x30, 0x04, 0x31, 0xE6, 0x9C, + 0x88, 0x04, 0x32, 0xE6, 0x9C, 0x88, 0x04, 0x33, + 0xE6, 0x9C, 0x88, 0x04, 0x34, 0xE6, 0x9C, 0x88, + 0x04, 0x35, 0xE6, 0x9C, 0x88, 0x04, 0x36, 0xE6, + 0x9C, 0x88, 0x04, 0x37, 0xE6, 0x9C, 0x88, 0x04, + // Bytes 2240 - 227f + 0x38, 0xE6, 0x9C, 0x88, 0x04, 0x39, 0xE6, 0x9C, + 0x88, 0x05, 0x31, 0x30, 0xE6, 0x9C, 0x88, 0x05, + 0x31, 0x31, 0xE6, 0x9C, 0x88, 0x05, 0x31, 0x32, + 0xE6, 0x9C, 0x88, 0x02, 0x48, 0x67, 0x03, 0x65, + 0x72, 0x67, 0x02, 0x65, 0x56, 0x03, 0x4C, 0x54, + 0x44, 0x03, 0xE3, 0x82, 0xA2, 0x03, 0xE3, 0x82, + 0xA4, 0x03, 0xE3, 0x82, 0xA6, 0x03, 0xE3, 0x82, + 0xA8, 0x03, 0xE3, 0x82, 0xAA, 0x03, 0xE3, 0x82, + // Bytes 2280 - 22bf + 0xAB, 0x03, 0xE3, 0x82, 0xAD, 0x03, 0xE3, 0x82, + 0xAF, 0x03, 0xE3, 0x82, 0xB1, 0x03, 0xE3, 0x82, + 0xB3, 0x03, 0xE3, 0x82, 0xB5, 0x03, 0xE3, 0x82, + 0xB7, 0x03, 0xE3, 0x82, 0xB9, 0x03, 0xE3, 0x82, + 0xBB, 0x03, 0xE3, 0x82, 0xBD, 0x03, 0xE3, 0x82, + 0xBF, 0x03, 0xE3, 0x83, 0x81, 0x03, 0xE3, 0x83, + 0x84, 0x03, 0xE3, 0x83, 0x86, 0x03, 0xE3, 0x83, + 0x88, 0x03, 0xE3, 0x83, 0x8A, 0x03, 0xE3, 0x83, + // Bytes 22c0 - 22ff + 0x8B, 0x03, 0xE3, 0x83, 0x8C, 0x03, 0xE3, 0x83, + 0x8D, 0x03, 0xE3, 0x83, 0x8E, 0x03, 0xE3, 0x83, + 0x8F, 0x03, 0xE3, 0x83, 0x92, 0x03, 0xE3, 0x83, + 0x95, 0x03, 0xE3, 0x83, 0x98, 0x03, 0xE3, 0x83, + 0x9B, 0x03, 0xE3, 0x83, 0x9E, 0x03, 0xE3, 0x83, + 0x9F, 0x03, 0xE3, 0x83, 0xA0, 0x03, 0xE3, 0x83, + 0xA1, 0x03, 0xE3, 0x83, 0xA2, 0x03, 0xE3, 0x83, + 0xA4, 0x03, 0xE3, 0x83, 0xA6, 0x03, 0xE3, 0x83, + // Bytes 2300 - 233f + 0xA8, 0x03, 0xE3, 0x83, 0xA9, 0x03, 0xE3, 0x83, + 0xAA, 0x03, 0xE3, 0x83, 0xAB, 0x03, 0xE3, 0x83, + 0xAC, 0x03, 0xE3, 0x83, 0xAD, 0x03, 0xE3, 0x83, + 0xAF, 0x03, 0xE3, 0x83, 0xB0, 0x03, 0xE3, 0x83, + 0xB1, 0x03, 0xE3, 0x83, 0xB2, 0x0F, 0xE3, 0x82, + 0xA2, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A, 0xE3, + 0x83, 0xBC, 0xE3, 0x83, 0x88, 0x0C, 0xE3, 0x82, + 0xA2, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x95, 0xE3, + // Bytes 2340 - 237f + 0x82, 0xA1, 0x0F, 0xE3, 0x82, 0xA2, 0xE3, 0x83, + 0xB3, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3, + 0x82, 0xA2, 0x09, 0xE3, 0x82, 0xA2, 0xE3, 0x83, + 0xBC, 0xE3, 0x83, 0xAB, 0x0F, 0xE3, 0x82, 0xA4, + 0xE3, 0x83, 0x8B, 0xE3, 0x83, 0xB3, 0xE3, 0x82, + 0xAF, 0xE3, 0x82, 0x99, 0x09, 0xE3, 0x82, 0xA4, + 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x81, 0x09, 0xE3, + 0x82, 0xA6, 0xE3, 0x82, 0xA9, 0xE3, 0x83, 0xB3, + // Bytes 2380 - 23bf + 0x12, 0xE3, 0x82, 0xA8, 0xE3, 0x82, 0xB9, 0xE3, + 0x82, 0xAF, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88, + 0xE3, 0x82, 0x99, 0x0C, 0xE3, 0x82, 0xA8, 0xE3, + 0x83, 0xBC, 0xE3, 0x82, 0xAB, 0xE3, 0x83, 0xBC, + 0x09, 0xE3, 0x82, 0xAA, 0xE3, 0x83, 0xB3, 0xE3, + 0x82, 0xB9, 0x09, 0xE3, 0x82, 0xAA, 0xE3, 0x83, + 0xBC, 0xE3, 0x83, 0xA0, 0x09, 0xE3, 0x82, 0xAB, + 0xE3, 0x82, 0xA4, 0xE3, 0x83, 0xAA, 0x0C, 0xE3, + // Bytes 23c0 - 23ff + 0x82, 0xAB, 0xE3, 0x83, 0xA9, 0xE3, 0x83, 0x83, + 0xE3, 0x83, 0x88, 0x0C, 0xE3, 0x82, 0xAB, 0xE3, + 0x83, 0xAD, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xBC, + 0x0C, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0xE3, + 0x83, 0xAD, 0xE3, 0x83, 0xB3, 0x0C, 0xE3, 0x82, + 0xAB, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xB3, 0xE3, + 0x83, 0x9E, 0x0C, 0xE3, 0x82, 0xAD, 0xE3, 0x82, + 0x99, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0x0C, + // Bytes 2400 - 243f + 0xE3, 0x82, 0xAD, 0xE3, 0x82, 0x99, 0xE3, 0x83, + 0x8B, 0xE3, 0x83, 0xBC, 0x0C, 0xE3, 0x82, 0xAD, + 0xE3, 0x83, 0xA5, 0xE3, 0x83, 0xAA, 0xE3, 0x83, + 0xBC, 0x12, 0xE3, 0x82, 0xAD, 0xE3, 0x82, 0x99, + 0xE3, 0x83, 0xAB, 0xE3, 0x82, 0xBF, 0xE3, 0x82, + 0x99, 0xE3, 0x83, 0xBC, 0x06, 0xE3, 0x82, 0xAD, + 0xE3, 0x83, 0xAD, 0x12, 0xE3, 0x82, 0xAD, 0xE3, + 0x83, 0xAD, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, + // Bytes 2440 - 247f + 0xE3, 0x83, 0xA9, 0xE3, 0x83, 0xA0, 0x12, 0xE3, + 0x82, 0xAD, 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xA1, + 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88, 0xE3, 0x83, + 0xAB, 0x0F, 0xE3, 0x82, 0xAD, 0xE3, 0x83, 0xAD, + 0xE3, 0x83, 0xAF, 0xE3, 0x83, 0x83, 0xE3, 0x83, + 0x88, 0x0C, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, + 0xE3, 0x83, 0xA9, 0xE3, 0x83, 0xA0, 0x12, 0xE3, + 0x82, 0xAF, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xA9, + // Bytes 2480 - 24bf + 0xE3, 0x83, 0xA0, 0xE3, 0x83, 0x88, 0xE3, 0x83, + 0xB3, 0x12, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAB, + 0xE3, 0x82, 0xBB, 0xE3, 0x82, 0x99, 0xE3, 0x82, + 0xA4, 0xE3, 0x83, 0xAD, 0x0C, 0xE3, 0x82, 0xAF, + 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xBC, 0xE3, 0x83, + 0x8D, 0x09, 0xE3, 0x82, 0xB1, 0xE3, 0x83, 0xBC, + 0xE3, 0x82, 0xB9, 0x09, 0xE3, 0x82, 0xB3, 0xE3, + 0x83, 0xAB, 0xE3, 0x83, 0x8A, 0x0C, 0xE3, 0x82, + // Bytes 24c0 - 24ff + 0xB3, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x9B, 0xE3, + 0x82, 0x9A, 0x0C, 0xE3, 0x82, 0xB5, 0xE3, 0x82, + 0xA4, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAB, 0x0F, + 0xE3, 0x82, 0xB5, 0xE3, 0x83, 0xB3, 0xE3, 0x83, + 0x81, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xA0, 0x0F, + 0xE3, 0x82, 0xB7, 0xE3, 0x83, 0xAA, 0xE3, 0x83, + 0xB3, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0x09, + 0xE3, 0x82, 0xBB, 0xE3, 0x83, 0xB3, 0xE3, 0x83, + // Bytes 2500 - 253f + 0x81, 0x09, 0xE3, 0x82, 0xBB, 0xE3, 0x83, 0xB3, + 0xE3, 0x83, 0x88, 0x0C, 0xE3, 0x82, 0xBF, 0xE3, + 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xB9, + 0x09, 0xE3, 0x83, 0x86, 0xE3, 0x82, 0x99, 0xE3, + 0x82, 0xB7, 0x09, 0xE3, 0x83, 0x88, 0xE3, 0x82, + 0x99, 0xE3, 0x83, 0xAB, 0x06, 0xE3, 0x83, 0x88, + 0xE3, 0x83, 0xB3, 0x06, 0xE3, 0x83, 0x8A, 0xE3, + 0x83, 0x8E, 0x09, 0xE3, 0x83, 0x8E, 0xE3, 0x83, + // Bytes 2540 - 257f + 0x83, 0xE3, 0x83, 0x88, 0x09, 0xE3, 0x83, 0x8F, + 0xE3, 0x82, 0xA4, 0xE3, 0x83, 0x84, 0x12, 0xE3, + 0x83, 0x8F, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, + 0xE3, 0x82, 0xBB, 0xE3, 0x83, 0xB3, 0xE3, 0x83, + 0x88, 0x0C, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A, + 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x84, 0x0F, 0xE3, + 0x83, 0x8F, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xBC, + 0xE3, 0x83, 0xAC, 0xE3, 0x83, 0xAB, 0x12, 0xE3, + // Bytes 2580 - 25bf + 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xA2, + 0xE3, 0x82, 0xB9, 0xE3, 0x83, 0x88, 0xE3, 0x83, + 0xAB, 0x0C, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A, + 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAB, 0x09, 0xE3, + 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xB3, + 0x09, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x99, 0xE3, + 0x83, 0xAB, 0x12, 0xE3, 0x83, 0x95, 0xE3, 0x82, + 0xA1, 0xE3, 0x83, 0xA9, 0xE3, 0x83, 0x83, 0xE3, + // Bytes 25c0 - 25ff + 0x83, 0x88, 0xE3, 0x82, 0x99, 0x0C, 0xE3, 0x83, + 0x95, 0xE3, 0x82, 0xA3, 0xE3, 0x83, 0xBC, 0xE3, + 0x83, 0x88, 0x12, 0xE3, 0x83, 0x95, 0xE3, 0x82, + 0x99, 0xE3, 0x83, 0x83, 0xE3, 0x82, 0xB7, 0xE3, + 0x82, 0xA7, 0xE3, 0x83, 0xAB, 0x09, 0xE3, 0x83, + 0x95, 0xE3, 0x83, 0xA9, 0xE3, 0x83, 0xB3, 0x0F, + 0xE3, 0x83, 0x98, 0xE3, 0x82, 0xAF, 0xE3, 0x82, + 0xBF, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xAB, 0x09, + // Bytes 2600 - 263f + 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x82, + 0xBD, 0x0C, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, + 0xE3, 0x83, 0x8B, 0xE3, 0x83, 0x92, 0x09, 0xE3, + 0x83, 0x98, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x84, + 0x0C, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3, + 0x83, 0xB3, 0xE3, 0x82, 0xB9, 0x0F, 0xE3, 0x83, + 0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, 0xE3, + 0x82, 0xB7, 0xE3, 0x82, 0x99, 0x0C, 0xE3, 0x83, + // Bytes 2640 - 267f + 0x98, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3, + 0x82, 0xBF, 0x0F, 0xE3, 0x83, 0x9B, 0xE3, 0x82, + 0x9A, 0xE3, 0x82, 0xA4, 0xE3, 0x83, 0xB3, 0xE3, + 0x83, 0x88, 0x0C, 0xE3, 0x83, 0x9B, 0xE3, 0x82, + 0x99, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x88, 0x06, + 0xE3, 0x83, 0x9B, 0xE3, 0x83, 0xB3, 0x0F, 0xE3, + 0x83, 0x9B, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xB3, + 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0x09, 0xE3, + // Bytes 2680 - 26bf + 0x83, 0x9B, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xAB, + 0x09, 0xE3, 0x83, 0x9B, 0xE3, 0x83, 0xBC, 0xE3, + 0x83, 0xB3, 0x0C, 0xE3, 0x83, 0x9E, 0xE3, 0x82, + 0xA4, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAD, 0x09, + 0xE3, 0x83, 0x9E, 0xE3, 0x82, 0xA4, 0xE3, 0x83, + 0xAB, 0x09, 0xE3, 0x83, 0x9E, 0xE3, 0x83, 0x83, + 0xE3, 0x83, 0x8F, 0x09, 0xE3, 0x83, 0x9E, 0xE3, + 0x83, 0xAB, 0xE3, 0x82, 0xAF, 0x0F, 0xE3, 0x83, + // Bytes 26c0 - 26ff + 0x9E, 0xE3, 0x83, 0xB3, 0xE3, 0x82, 0xB7, 0xE3, + 0x83, 0xA7, 0xE3, 0x83, 0xB3, 0x0C, 0xE3, 0x83, + 0x9F, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAD, 0xE3, + 0x83, 0xB3, 0x06, 0xE3, 0x83, 0x9F, 0xE3, 0x83, + 0xAA, 0x12, 0xE3, 0x83, 0x9F, 0xE3, 0x83, 0xAA, + 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x99, 0xE3, 0x83, + 0xBC, 0xE3, 0x83, 0xAB, 0x09, 0xE3, 0x83, 0xA1, + 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0x0F, 0xE3, + // Bytes 2700 - 273f + 0x83, 0xA1, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, + 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xB3, 0x0C, 0xE3, + 0x83, 0xA1, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88, + 0xE3, 0x83, 0xAB, 0x0C, 0xE3, 0x83, 0xA4, 0xE3, + 0x83, 0xBC, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, + 0x09, 0xE3, 0x83, 0xA4, 0xE3, 0x83, 0xBC, 0xE3, + 0x83, 0xAB, 0x09, 0xE3, 0x83, 0xA6, 0xE3, 0x82, + 0xA2, 0xE3, 0x83, 0xB3, 0x0C, 0xE3, 0x83, 0xAA, + // Bytes 2740 - 277f + 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x88, 0xE3, 0x83, + 0xAB, 0x06, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xA9, + 0x0C, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x92, 0xE3, + 0x82, 0x9A, 0xE3, 0x83, 0xBC, 0x0F, 0xE3, 0x83, + 0xAB, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x95, 0xE3, + 0x82, 0x99, 0xE3, 0x83, 0xAB, 0x06, 0xE3, 0x83, + 0xAC, 0xE3, 0x83, 0xA0, 0x12, 0xE3, 0x83, 0xAC, + 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x88, 0xE3, 0x82, + // Bytes 2780 - 27bf + 0xB1, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xB3, 0x09, + 0xE3, 0x83, 0xAF, 0xE3, 0x83, 0x83, 0xE3, 0x83, + 0x88, 0x04, 0x30, 0xE7, 0x82, 0xB9, 0x04, 0x31, + 0xE7, 0x82, 0xB9, 0x04, 0x32, 0xE7, 0x82, 0xB9, + 0x04, 0x33, 0xE7, 0x82, 0xB9, 0x04, 0x34, 0xE7, + 0x82, 0xB9, 0x04, 0x35, 0xE7, 0x82, 0xB9, 0x04, + 0x36, 0xE7, 0x82, 0xB9, 0x04, 0x37, 0xE7, 0x82, + 0xB9, 0x04, 0x38, 0xE7, 0x82, 0xB9, 0x04, 0x39, + // Bytes 27c0 - 27ff + 0xE7, 0x82, 0xB9, 0x05, 0x31, 0x30, 0xE7, 0x82, + 0xB9, 0x05, 0x31, 0x31, 0xE7, 0x82, 0xB9, 0x05, + 0x31, 0x32, 0xE7, 0x82, 0xB9, 0x05, 0x31, 0x33, + 0xE7, 0x82, 0xB9, 0x05, 0x31, 0x34, 0xE7, 0x82, + 0xB9, 0x05, 0x31, 0x35, 0xE7, 0x82, 0xB9, 0x05, + 0x31, 0x36, 0xE7, 0x82, 0xB9, 0x05, 0x31, 0x37, + 0xE7, 0x82, 0xB9, 0x05, 0x31, 0x38, 0xE7, 0x82, + 0xB9, 0x05, 0x31, 0x39, 0xE7, 0x82, 0xB9, 0x05, + // Bytes 2800 - 283f + 0x32, 0x30, 0xE7, 0x82, 0xB9, 0x05, 0x32, 0x31, + 0xE7, 0x82, 0xB9, 0x05, 0x32, 0x32, 0xE7, 0x82, + 0xB9, 0x05, 0x32, 0x33, 0xE7, 0x82, 0xB9, 0x05, + 0x32, 0x34, 0xE7, 0x82, 0xB9, 0x03, 0x68, 0x50, + 0x61, 0x02, 0x64, 0x61, 0x02, 0x41, 0x55, 0x03, + 0x62, 0x61, 0x72, 0x02, 0x6F, 0x56, 0x02, 0x70, + 0x63, 0x02, 0x64, 0x6D, 0x03, 0x64, 0x6D, 0x32, + 0x03, 0x64, 0x6D, 0x33, 0x02, 0x49, 0x55, 0x06, + // Bytes 2840 - 287f + 0xE5, 0xB9, 0xB3, 0xE6, 0x88, 0x90, 0x06, 0xE6, + 0x98, 0xAD, 0xE5, 0x92, 0x8C, 0x06, 0xE5, 0xA4, + 0xA7, 0xE6, 0xAD, 0xA3, 0x06, 0xE6, 0x98, 0x8E, + 0xE6, 0xB2, 0xBB, 0x0C, 0xE6, 0xA0, 0xAA, 0xE5, + 0xBC, 0x8F, 0xE4, 0xBC, 0x9A, 0xE7, 0xA4, 0xBE, + 0x02, 0x70, 0x41, 0x02, 0x6E, 0x41, 0x03, 0xCE, + 0xBC, 0x41, 0x02, 0x6D, 0x41, 0x02, 0x6B, 0x41, + 0x02, 0x4B, 0x42, 0x02, 0x4D, 0x42, 0x02, 0x47, + // Bytes 2880 - 28bf + 0x42, 0x03, 0x63, 0x61, 0x6C, 0x04, 0x6B, 0x63, + 0x61, 0x6C, 0x02, 0x70, 0x46, 0x02, 0x6E, 0x46, + 0x03, 0xCE, 0xBC, 0x46, 0x03, 0xCE, 0xBC, 0x67, + 0x02, 0x6D, 0x67, 0x02, 0x6B, 0x67, 0x02, 0x48, + 0x7A, 0x03, 0x6B, 0x48, 0x7A, 0x03, 0x4D, 0x48, + 0x7A, 0x03, 0x47, 0x48, 0x7A, 0x03, 0x54, 0x48, + 0x7A, 0x03, 0xCE, 0xBC, 0x6C, 0x02, 0x6D, 0x6C, + 0x02, 0x64, 0x6C, 0x02, 0x6B, 0x6C, 0x02, 0x66, + // Bytes 28c0 - 28ff + 0x6D, 0x02, 0x6E, 0x6D, 0x03, 0xCE, 0xBC, 0x6D, + 0x02, 0x6D, 0x6D, 0x02, 0x63, 0x6D, 0x02, 0x6B, + 0x6D, 0x03, 0x6D, 0x6D, 0x32, 0x03, 0x63, 0x6D, + 0x32, 0x02, 0x6D, 0x32, 0x03, 0x6B, 0x6D, 0x32, + 0x03, 0x6D, 0x6D, 0x33, 0x03, 0x63, 0x6D, 0x33, + 0x02, 0x6D, 0x33, 0x03, 0x6B, 0x6D, 0x33, 0x05, + 0x6D, 0xE2, 0x88, 0x95, 0x73, 0x06, 0x6D, 0xE2, + 0x88, 0x95, 0x73, 0x32, 0x02, 0x50, 0x61, 0x03, + // Bytes 2900 - 293f + 0x6B, 0x50, 0x61, 0x03, 0x4D, 0x50, 0x61, 0x03, + 0x47, 0x50, 0x61, 0x03, 0x72, 0x61, 0x64, 0x07, + 0x72, 0x61, 0x64, 0xE2, 0x88, 0x95, 0x73, 0x08, + 0x72, 0x61, 0x64, 0xE2, 0x88, 0x95, 0x73, 0x32, + 0x02, 0x70, 0x73, 0x02, 0x6E, 0x73, 0x03, 0xCE, + 0xBC, 0x73, 0x02, 0x6D, 0x73, 0x02, 0x70, 0x56, + 0x02, 0x6E, 0x56, 0x03, 0xCE, 0xBC, 0x56, 0x02, + 0x6D, 0x56, 0x02, 0x6B, 0x56, 0x02, 0x4D, 0x56, + // Bytes 2940 - 297f + 0x02, 0x70, 0x57, 0x02, 0x6E, 0x57, 0x03, 0xCE, + 0xBC, 0x57, 0x02, 0x6D, 0x57, 0x02, 0x6B, 0x57, + 0x02, 0x4D, 0x57, 0x03, 0x6B, 0xCE, 0xA9, 0x03, + 0x4D, 0xCE, 0xA9, 0x04, 0x61, 0x2E, 0x6D, 0x2E, + 0x02, 0x42, 0x71, 0x02, 0x63, 0x63, 0x02, 0x63, + 0x64, 0x06, 0x43, 0xE2, 0x88, 0x95, 0x6B, 0x67, + 0x03, 0x43, 0x6F, 0x2E, 0x02, 0x64, 0x42, 0x02, + 0x47, 0x79, 0x02, 0x68, 0x61, 0x02, 0x48, 0x50, + // Bytes 2980 - 29bf + 0x02, 0x69, 0x6E, 0x02, 0x4B, 0x4B, 0x02, 0x4B, + 0x4D, 0x02, 0x6B, 0x74, 0x02, 0x6C, 0x6D, 0x02, + 0x6C, 0x6E, 0x03, 0x6C, 0x6F, 0x67, 0x02, 0x6C, + 0x78, 0x02, 0x6D, 0x62, 0x03, 0x6D, 0x69, 0x6C, + 0x03, 0x6D, 0x6F, 0x6C, 0x02, 0x50, 0x48, 0x04, + 0x70, 0x2E, 0x6D, 0x2E, 0x03, 0x50, 0x50, 0x4D, + 0x02, 0x50, 0x52, 0x02, 0x73, 0x72, 0x02, 0x53, + 0x76, 0x02, 0x57, 0x62, 0x05, 0x56, 0xE2, 0x88, + // Bytes 29c0 - 29ff + 0x95, 0x6D, 0x05, 0x41, 0xE2, 0x88, 0x95, 0x6D, + 0x04, 0x31, 0xE6, 0x97, 0xA5, 0x04, 0x32, 0xE6, + 0x97, 0xA5, 0x04, 0x33, 0xE6, 0x97, 0xA5, 0x04, + 0x34, 0xE6, 0x97, 0xA5, 0x04, 0x35, 0xE6, 0x97, + 0xA5, 0x04, 0x36, 0xE6, 0x97, 0xA5, 0x04, 0x37, + 0xE6, 0x97, 0xA5, 0x04, 0x38, 0xE6, 0x97, 0xA5, + 0x04, 0x39, 0xE6, 0x97, 0xA5, 0x05, 0x31, 0x30, + 0xE6, 0x97, 0xA5, 0x05, 0x31, 0x31, 0xE6, 0x97, + // Bytes 2a00 - 2a3f + 0xA5, 0x05, 0x31, 0x32, 0xE6, 0x97, 0xA5, 0x05, + 0x31, 0x33, 0xE6, 0x97, 0xA5, 0x05, 0x31, 0x34, + 0xE6, 0x97, 0xA5, 0x05, 0x31, 0x35, 0xE6, 0x97, + 0xA5, 0x05, 0x31, 0x36, 0xE6, 0x97, 0xA5, 0x05, + 0x31, 0x37, 0xE6, 0x97, 0xA5, 0x05, 0x31, 0x38, + 0xE6, 0x97, 0xA5, 0x05, 0x31, 0x39, 0xE6, 0x97, + 0xA5, 0x05, 0x32, 0x30, 0xE6, 0x97, 0xA5, 0x05, + 0x32, 0x31, 0xE6, 0x97, 0xA5, 0x05, 0x32, 0x32, + // Bytes 2a40 - 2a7f + 0xE6, 0x97, 0xA5, 0x05, 0x32, 0x33, 0xE6, 0x97, + 0xA5, 0x05, 0x32, 0x34, 0xE6, 0x97, 0xA5, 0x05, + 0x32, 0x35, 0xE6, 0x97, 0xA5, 0x05, 0x32, 0x36, + 0xE6, 0x97, 0xA5, 0x05, 0x32, 0x37, 0xE6, 0x97, + 0xA5, 0x05, 0x32, 0x38, 0xE6, 0x97, 0xA5, 0x05, + 0x32, 0x39, 0xE6, 0x97, 0xA5, 0x05, 0x33, 0x30, + 0xE6, 0x97, 0xA5, 0x05, 0x33, 0x31, 0xE6, 0x97, + 0xA5, 0x03, 0x67, 0x61, 0x6C, 0x03, 0xEA, 0x9D, + // Bytes 2a80 - 2abf + 0xAF, 0x03, 0xE8, 0xB1, 0x88, 0x03, 0xE6, 0x9B, + 0xB4, 0x03, 0xE8, 0xB3, 0x88, 0x03, 0xE6, 0xBB, + 0x91, 0x03, 0xE4, 0xB8, 0xB2, 0x03, 0xE5, 0x8F, + 0xA5, 0x03, 0xE5, 0xA5, 0x91, 0x03, 0xE5, 0x96, + 0x87, 0x03, 0xE5, 0xA5, 0x88, 0x03, 0xE6, 0x87, + 0xB6, 0x03, 0xE7, 0x99, 0xA9, 0x03, 0xE7, 0xBE, + 0x85, 0x03, 0xE8, 0x98, 0xBF, 0x03, 0xE8, 0x9E, + 0xBA, 0x03, 0xE8, 0xA3, 0xB8, 0x03, 0xE9, 0x82, + // Bytes 2ac0 - 2aff + 0x8F, 0x03, 0xE6, 0xA8, 0x82, 0x03, 0xE6, 0xB4, + 0x9B, 0x03, 0xE7, 0x83, 0x99, 0x03, 0xE7, 0x8F, + 0x9E, 0x03, 0xE8, 0x90, 0xBD, 0x03, 0xE9, 0x85, + 0xAA, 0x03, 0xE9, 0xA7, 0xB1, 0x03, 0xE4, 0xBA, + 0x82, 0x03, 0xE5, 0x8D, 0xB5, 0x03, 0xE6, 0xAC, + 0x84, 0x03, 0xE7, 0x88, 0x9B, 0x03, 0xE8, 0x98, + 0xAD, 0x03, 0xE9, 0xB8, 0x9E, 0x03, 0xE5, 0xB5, + 0x90, 0x03, 0xE6, 0xBF, 0xAB, 0x03, 0xE8, 0x97, + // Bytes 2b00 - 2b3f + 0x8D, 0x03, 0xE8, 0xA5, 0xA4, 0x03, 0xE6, 0x8B, + 0x89, 0x03, 0xE8, 0x87, 0x98, 0x03, 0xE8, 0xA0, + 0x9F, 0x03, 0xE5, 0xBB, 0x8A, 0x03, 0xE6, 0x9C, + 0x97, 0x03, 0xE6, 0xB5, 0xAA, 0x03, 0xE7, 0x8B, + 0xBC, 0x03, 0xE9, 0x83, 0x8E, 0x03, 0xE4, 0xBE, + 0x86, 0x03, 0xE5, 0x86, 0xB7, 0x03, 0xE5, 0x8B, + 0x9E, 0x03, 0xE6, 0x93, 0x84, 0x03, 0xE6, 0xAB, + 0x93, 0x03, 0xE7, 0x88, 0x90, 0x03, 0xE7, 0x9B, + // Bytes 2b40 - 2b7f + 0xA7, 0x03, 0xE8, 0x98, 0x86, 0x03, 0xE8, 0x99, + 0x9C, 0x03, 0xE8, 0xB7, 0xAF, 0x03, 0xE9, 0x9C, + 0xB2, 0x03, 0xE9, 0xAD, 0xAF, 0x03, 0xE9, 0xB7, + 0xBA, 0x03, 0xE7, 0xA2, 0x8C, 0x03, 0xE7, 0xA5, + 0xBF, 0x03, 0xE7, 0xB6, 0xA0, 0x03, 0xE8, 0x8F, + 0x89, 0x03, 0xE9, 0x8C, 0x84, 0x03, 0xE8, 0xAB, + 0x96, 0x03, 0xE5, 0xA3, 0x9F, 0x03, 0xE5, 0xBC, + 0x84, 0x03, 0xE7, 0xB1, 0xA0, 0x03, 0xE8, 0x81, + // Bytes 2b80 - 2bbf + 0xBE, 0x03, 0xE7, 0x89, 0xA2, 0x03, 0xE7, 0xA3, + 0x8A, 0x03, 0xE8, 0xB3, 0x82, 0x03, 0xE9, 0x9B, + 0xB7, 0x03, 0xE5, 0xA3, 0x98, 0x03, 0xE5, 0xB1, + 0xA2, 0x03, 0xE6, 0xA8, 0x93, 0x03, 0xE6, 0xB7, + 0x9A, 0x03, 0xE6, 0xBC, 0x8F, 0x03, 0xE7, 0xB4, + 0xAF, 0x03, 0xE7, 0xB8, 0xB7, 0x03, 0xE9, 0x99, + 0x8B, 0x03, 0xE5, 0x8B, 0x92, 0x03, 0xE8, 0x82, + 0x8B, 0x03, 0xE5, 0x87, 0x9C, 0x03, 0xE5, 0x87, + // Bytes 2bc0 - 2bff + 0x8C, 0x03, 0xE7, 0xA8, 0x9C, 0x03, 0xE7, 0xB6, + 0xBE, 0x03, 0xE8, 0x8F, 0xB1, 0x03, 0xE9, 0x99, + 0xB5, 0x03, 0xE8, 0xAE, 0x80, 0x03, 0xE6, 0x8B, + 0x8F, 0x03, 0xE8, 0xAB, 0xBE, 0x03, 0xE4, 0xB8, + 0xB9, 0x03, 0xE5, 0xAF, 0xA7, 0x03, 0xE6, 0x80, + 0x92, 0x03, 0xE7, 0x8E, 0x87, 0x03, 0xE7, 0x95, + 0xB0, 0x03, 0xE5, 0x8C, 0x97, 0x03, 0xE7, 0xA3, + 0xBB, 0x03, 0xE4, 0xBE, 0xBF, 0x03, 0xE5, 0xBE, + // Bytes 2c00 - 2c3f + 0xA9, 0x03, 0xE4, 0xB8, 0x8D, 0x03, 0xE6, 0xB3, + 0x8C, 0x03, 0xE6, 0x95, 0xB8, 0x03, 0xE7, 0xB4, + 0xA2, 0x03, 0xE5, 0x8F, 0x83, 0x03, 0xE5, 0xA1, + 0x9E, 0x03, 0xE7, 0x9C, 0x81, 0x03, 0xE8, 0x91, + 0x89, 0x03, 0xE8, 0xAA, 0xAA, 0x03, 0xE6, 0xAE, + 0xBA, 0x03, 0xE6, 0xB2, 0x88, 0x03, 0xE6, 0x8B, + 0xBE, 0x03, 0xE8, 0x8B, 0xA5, 0x03, 0xE6, 0x8E, + 0xA0, 0x03, 0xE7, 0x95, 0xA5, 0x03, 0xE4, 0xBA, + // Bytes 2c40 - 2c7f + 0xAE, 0x03, 0xE5, 0x85, 0xA9, 0x03, 0xE5, 0x87, + 0x89, 0x03, 0xE6, 0xA2, 0x81, 0x03, 0xE7, 0xB3, + 0xA7, 0x03, 0xE8, 0x89, 0xAF, 0x03, 0xE8, 0xAB, + 0x92, 0x03, 0xE9, 0x87, 0x8F, 0x03, 0xE5, 0x8B, + 0xB5, 0x03, 0xE5, 0x91, 0x82, 0x03, 0xE5, 0xBB, + 0xAC, 0x03, 0xE6, 0x97, 0x85, 0x03, 0xE6, 0xBF, + 0xBE, 0x03, 0xE7, 0xA4, 0xAA, 0x03, 0xE9, 0x96, + 0xAD, 0x03, 0xE9, 0xA9, 0xAA, 0x03, 0xE9, 0xBA, + // Bytes 2c80 - 2cbf + 0x97, 0x03, 0xE9, 0xBB, 0x8E, 0x03, 0xE6, 0x9B, + 0x86, 0x03, 0xE6, 0xAD, 0xB7, 0x03, 0xE8, 0xBD, + 0xA2, 0x03, 0xE5, 0xB9, 0xB4, 0x03, 0xE6, 0x86, + 0x90, 0x03, 0xE6, 0x88, 0x80, 0x03, 0xE6, 0x92, + 0x9A, 0x03, 0xE6, 0xBC, 0xA3, 0x03, 0xE7, 0x85, + 0x89, 0x03, 0xE7, 0x92, 0x89, 0x03, 0xE7, 0xA7, + 0x8A, 0x03, 0xE7, 0xB7, 0xB4, 0x03, 0xE8, 0x81, + 0xAF, 0x03, 0xE8, 0xBC, 0xA6, 0x03, 0xE8, 0x93, + // Bytes 2cc0 - 2cff + 0xAE, 0x03, 0xE9, 0x80, 0xA3, 0x03, 0xE9, 0x8D, + 0x8A, 0x03, 0xE5, 0x88, 0x97, 0x03, 0xE5, 0x8A, + 0xA3, 0x03, 0xE5, 0x92, 0xBD, 0x03, 0xE7, 0x83, + 0x88, 0x03, 0xE8, 0xA3, 0x82, 0x03, 0xE5, 0xBB, + 0x89, 0x03, 0xE5, 0xBF, 0xB5, 0x03, 0xE6, 0x8D, + 0xBB, 0x03, 0xE6, 0xAE, 0xAE, 0x03, 0xE7, 0xB0, + 0xBE, 0x03, 0xE7, 0x8D, 0xB5, 0x03, 0xE4, 0xBB, + 0xA4, 0x03, 0xE5, 0x9B, 0xB9, 0x03, 0xE5, 0xB6, + // Bytes 2d00 - 2d3f + 0xBA, 0x03, 0xE6, 0x80, 0x9C, 0x03, 0xE7, 0x8E, + 0xB2, 0x03, 0xE7, 0x91, 0xA9, 0x03, 0xE7, 0xBE, + 0x9A, 0x03, 0xE8, 0x81, 0x86, 0x03, 0xE9, 0x88, + 0xB4, 0x03, 0xE9, 0x9B, 0xB6, 0x03, 0xE9, 0x9D, + 0x88, 0x03, 0xE9, 0xA0, 0x98, 0x03, 0xE4, 0xBE, + 0x8B, 0x03, 0xE7, 0xA6, 0xAE, 0x03, 0xE9, 0x86, + 0xB4, 0x03, 0xE9, 0x9A, 0xB8, 0x03, 0xE6, 0x83, + 0xA1, 0x03, 0xE4, 0xBA, 0x86, 0x03, 0xE5, 0x83, + // Bytes 2d40 - 2d7f + 0x9A, 0x03, 0xE5, 0xAF, 0xAE, 0x03, 0xE5, 0xB0, + 0xBF, 0x03, 0xE6, 0x96, 0x99, 0x03, 0xE7, 0x87, + 0x8E, 0x03, 0xE7, 0x99, 0x82, 0x03, 0xE8, 0x93, + 0xBC, 0x03, 0xE9, 0x81, 0xBC, 0x03, 0xE6, 0x9A, + 0x88, 0x03, 0xE9, 0x98, 0xAE, 0x03, 0xE5, 0x8A, + 0x89, 0x03, 0xE6, 0x9D, 0xBB, 0x03, 0xE6, 0x9F, + 0xB3, 0x03, 0xE6, 0xB5, 0x81, 0x03, 0xE6, 0xBA, + 0x9C, 0x03, 0xE7, 0x90, 0x89, 0x03, 0xE7, 0x95, + // Bytes 2d80 - 2dbf + 0x99, 0x03, 0xE7, 0xA1, 0xAB, 0x03, 0xE7, 0xB4, + 0x90, 0x03, 0xE9, 0xA1, 0x9E, 0x03, 0xE6, 0x88, + 0xAE, 0x03, 0xE9, 0x99, 0xB8, 0x03, 0xE5, 0x80, + 0xAB, 0x03, 0xE5, 0xB4, 0x99, 0x03, 0xE6, 0xB7, + 0xAA, 0x03, 0xE8, 0xBC, 0xAA, 0x03, 0xE5, 0xBE, + 0x8B, 0x03, 0xE6, 0x85, 0x84, 0x03, 0xE6, 0xA0, + 0x97, 0x03, 0xE9, 0x9A, 0x86, 0x03, 0xE5, 0x88, + 0xA9, 0x03, 0xE5, 0x90, 0x8F, 0x03, 0xE5, 0xB1, + // Bytes 2dc0 - 2dff + 0xA5, 0x03, 0xE6, 0x98, 0x93, 0x03, 0xE6, 0x9D, + 0x8E, 0x03, 0xE6, 0xA2, 0xA8, 0x03, 0xE6, 0xB3, + 0xA5, 0x03, 0xE7, 0x90, 0x86, 0x03, 0xE7, 0x97, + 0xA2, 0x03, 0xE7, 0xBD, 0xB9, 0x03, 0xE8, 0xA3, + 0x8F, 0x03, 0xE8, 0xA3, 0xA1, 0x03, 0xE9, 0x9B, + 0xA2, 0x03, 0xE5, 0x8C, 0xBF, 0x03, 0xE6, 0xBA, + 0xBA, 0x03, 0xE5, 0x90, 0x9D, 0x03, 0xE7, 0x87, + 0x90, 0x03, 0xE7, 0x92, 0x98, 0x03, 0xE8, 0x97, + // Bytes 2e00 - 2e3f + 0xBA, 0x03, 0xE9, 0x9A, 0xA3, 0x03, 0xE9, 0xB1, + 0x97, 0x03, 0xE9, 0xBA, 0x9F, 0x03, 0xE6, 0x9E, + 0x97, 0x03, 0xE6, 0xB7, 0x8B, 0x03, 0xE8, 0x87, + 0xA8, 0x03, 0xE7, 0xAC, 0xA0, 0x03, 0xE7, 0xB2, + 0x92, 0x03, 0xE7, 0x8B, 0x80, 0x03, 0xE7, 0x82, + 0x99, 0x03, 0xE8, 0xAD, 0x98, 0x03, 0xE4, 0xBB, + 0x80, 0x03, 0xE8, 0x8C, 0xB6, 0x03, 0xE5, 0x88, + 0xBA, 0x03, 0xE5, 0x88, 0x87, 0x03, 0xE5, 0xBA, + // Bytes 2e40 - 2e7f + 0xA6, 0x03, 0xE6, 0x8B, 0x93, 0x03, 0xE7, 0xB3, + 0x96, 0x03, 0xE5, 0xAE, 0x85, 0x03, 0xE6, 0xB4, + 0x9E, 0x03, 0xE6, 0x9A, 0xB4, 0x03, 0xE8, 0xBC, + 0xBB, 0x03, 0xE9, 0x99, 0x8D, 0x03, 0xE5, 0xBB, + 0x93, 0x03, 0xE5, 0x85, 0x80, 0x03, 0xE5, 0x97, + 0x80, 0x03, 0xE5, 0xA1, 0x9A, 0x03, 0xE6, 0x99, + 0xB4, 0x03, 0xE5, 0x87, 0x9E, 0x03, 0xE7, 0x8C, + 0xAA, 0x03, 0xE7, 0x9B, 0x8A, 0x03, 0xE7, 0xA4, + // Bytes 2e80 - 2ebf + 0xBC, 0x03, 0xE7, 0xA5, 0x9E, 0x03, 0xE7, 0xA5, + 0xA5, 0x03, 0xE7, 0xA6, 0x8F, 0x03, 0xE9, 0x9D, + 0x96, 0x03, 0xE7, 0xB2, 0xBE, 0x03, 0xE8, 0x98, + 0x92, 0x03, 0xE8, 0xAB, 0xB8, 0x03, 0xE9, 0x80, + 0xB8, 0x03, 0xE9, 0x83, 0xBD, 0x03, 0xE9, 0xA3, + 0xAF, 0x03, 0xE9, 0xA3, 0xBC, 0x03, 0xE9, 0xA4, + 0xA8, 0x03, 0xE9, 0xB6, 0xB4, 0x03, 0xE4, 0xBE, + 0xAE, 0x03, 0xE5, 0x83, 0xA7, 0x03, 0xE5, 0x85, + // Bytes 2ec0 - 2eff + 0x8D, 0x03, 0xE5, 0x8B, 0x89, 0x03, 0xE5, 0x8B, + 0xA4, 0x03, 0xE5, 0x8D, 0x91, 0x03, 0xE5, 0x96, + 0x9D, 0x03, 0xE5, 0x98, 0x86, 0x03, 0xE5, 0x99, + 0xA8, 0x03, 0xE5, 0xA1, 0x80, 0x03, 0xE5, 0xA2, + 0xA8, 0x03, 0xE5, 0xB1, 0xA4, 0x03, 0xE6, 0x82, + 0x94, 0x03, 0xE6, 0x85, 0xA8, 0x03, 0xE6, 0x86, + 0x8E, 0x03, 0xE6, 0x87, 0xB2, 0x03, 0xE6, 0x95, + 0x8F, 0x03, 0xE6, 0x97, 0xA2, 0x03, 0xE6, 0x9A, + // Bytes 2f00 - 2f3f + 0x91, 0x03, 0xE6, 0xA2, 0x85, 0x03, 0xE6, 0xB5, + 0xB7, 0x03, 0xE6, 0xB8, 0x9A, 0x03, 0xE6, 0xBC, + 0xA2, 0x03, 0xE7, 0x85, 0xAE, 0x03, 0xE7, 0x88, + 0xAB, 0x03, 0xE7, 0x90, 0xA2, 0x03, 0xE7, 0xA2, + 0x91, 0x03, 0xE7, 0xA5, 0x89, 0x03, 0xE7, 0xA5, + 0x88, 0x03, 0xE7, 0xA5, 0x90, 0x03, 0xE7, 0xA5, + 0x96, 0x03, 0xE7, 0xA6, 0x8D, 0x03, 0xE7, 0xA6, + 0x8E, 0x03, 0xE7, 0xA9, 0x80, 0x03, 0xE7, 0xAA, + // Bytes 2f40 - 2f7f + 0x81, 0x03, 0xE7, 0xAF, 0x80, 0x03, 0xE7, 0xB8, + 0x89, 0x03, 0xE7, 0xB9, 0x81, 0x03, 0xE7, 0xBD, + 0xB2, 0x03, 0xE8, 0x80, 0x85, 0x03, 0xE8, 0x87, + 0xAD, 0x03, 0xE8, 0x89, 0xB9, 0x03, 0xE8, 0x91, + 0x97, 0x03, 0xE8, 0xA4, 0x90, 0x03, 0xE8, 0xA6, + 0x96, 0x03, 0xE8, 0xAC, 0x81, 0x03, 0xE8, 0xAC, + 0xB9, 0x03, 0xE8, 0xB3, 0x93, 0x03, 0xE8, 0xB4, + 0x88, 0x03, 0xE8, 0xBE, 0xB6, 0x03, 0xE9, 0x9B, + // Bytes 2f80 - 2fbf + 0xA3, 0x03, 0xE9, 0x9F, 0xBF, 0x03, 0xE9, 0xA0, + 0xBB, 0x03, 0xE6, 0x81, 0xB5, 0x04, 0xF0, 0xA4, + 0x8B, 0xAE, 0x03, 0xE8, 0x88, 0x98, 0x03, 0xE4, + 0xB8, 0xA6, 0x03, 0xE5, 0x86, 0xB5, 0x03, 0xE5, + 0x85, 0xA8, 0x03, 0xE4, 0xBE, 0x80, 0x03, 0xE5, + 0x85, 0x85, 0x03, 0xE5, 0x86, 0x80, 0x03, 0xE5, + 0x8B, 0x87, 0x03, 0xE5, 0x8B, 0xBA, 0x03, 0xE5, + 0x95, 0x95, 0x03, 0xE5, 0x96, 0x99, 0x03, 0xE5, + // Bytes 2fc0 - 2fff + 0x97, 0xA2, 0x03, 0xE5, 0xA2, 0xB3, 0x03, 0xE5, + 0xA5, 0x84, 0x03, 0xE5, 0xA5, 0x94, 0x03, 0xE5, + 0xA9, 0xA2, 0x03, 0xE5, 0xAC, 0xA8, 0x03, 0xE5, + 0xBB, 0x92, 0x03, 0xE5, 0xBB, 0x99, 0x03, 0xE5, + 0xBD, 0xA9, 0x03, 0xE5, 0xBE, 0xAD, 0x03, 0xE6, + 0x83, 0x98, 0x03, 0xE6, 0x85, 0x8E, 0x03, 0xE6, + 0x84, 0x88, 0x03, 0xE6, 0x85, 0xA0, 0x03, 0xE6, + 0x88, 0xB4, 0x03, 0xE6, 0x8F, 0x84, 0x03, 0xE6, + // Bytes 3000 - 303f + 0x90, 0x9C, 0x03, 0xE6, 0x91, 0x92, 0x03, 0xE6, + 0x95, 0x96, 0x03, 0xE6, 0x9C, 0x9B, 0x03, 0xE6, + 0x9D, 0x96, 0x03, 0xE6, 0xBB, 0x9B, 0x03, 0xE6, + 0xBB, 0x8B, 0x03, 0xE7, 0x80, 0x9E, 0x03, 0xE7, + 0x9E, 0xA7, 0x03, 0xE7, 0x88, 0xB5, 0x03, 0xE7, + 0x8A, 0xAF, 0x03, 0xE7, 0x91, 0xB1, 0x03, 0xE7, + 0x94, 0x86, 0x03, 0xE7, 0x94, 0xBB, 0x03, 0xE7, + 0x98, 0x9D, 0x03, 0xE7, 0x98, 0x9F, 0x03, 0xE7, + // Bytes 3040 - 307f + 0x9B, 0x9B, 0x03, 0xE7, 0x9B, 0xB4, 0x03, 0xE7, + 0x9D, 0x8A, 0x03, 0xE7, 0x9D, 0x80, 0x03, 0xE7, + 0xA3, 0x8C, 0x03, 0xE7, 0xAA, 0xB1, 0x03, 0xE7, + 0xB1, 0xBB, 0x03, 0xE7, 0xB5, 0x9B, 0x03, 0xE7, + 0xBC, 0xBE, 0x03, 0xE8, 0x8D, 0x92, 0x03, 0xE8, + 0x8F, 0xAF, 0x03, 0xE8, 0x9D, 0xB9, 0x03, 0xE8, + 0xA5, 0x81, 0x03, 0xE8, 0xA6, 0x86, 0x03, 0xE8, + 0xAA, 0xBF, 0x03, 0xE8, 0xAB, 0x8B, 0x03, 0xE8, + // Bytes 3080 - 30bf + 0xAB, 0xAD, 0x03, 0xE8, 0xAE, 0x8A, 0x03, 0xE8, + 0xBC, 0xB8, 0x03, 0xE9, 0x81, 0xB2, 0x03, 0xE9, + 0x86, 0x99, 0x03, 0xE9, 0x89, 0xB6, 0x03, 0xE9, + 0x99, 0xBC, 0x03, 0xE9, 0x9F, 0x9B, 0x03, 0xE9, + 0xA0, 0x8B, 0x03, 0xE9, 0xAC, 0x92, 0x04, 0xF0, + 0xA2, 0xA1, 0x8A, 0x04, 0xF0, 0xA2, 0xA1, 0x84, + 0x04, 0xF0, 0xA3, 0x8F, 0x95, 0x03, 0xE3, 0xAE, + 0x9D, 0x03, 0xE4, 0x80, 0x98, 0x03, 0xE4, 0x80, + // Bytes 30c0 - 30ff + 0xB9, 0x04, 0xF0, 0xA5, 0x89, 0x89, 0x04, 0xF0, + 0xA5, 0xB3, 0x90, 0x04, 0xF0, 0xA7, 0xBB, 0x93, + 0x03, 0xE9, 0xBD, 0x83, 0x03, 0xE9, 0xBE, 0x8E, + 0x02, 0x66, 0x66, 0x02, 0x66, 0x69, 0x02, 0x66, + 0x6C, 0x03, 0x66, 0x66, 0x69, 0x03, 0x66, 0x66, + 0x6C, 0x02, 0x73, 0x74, 0x04, 0xD5, 0xB4, 0xD5, + 0xB6, 0x04, 0xD5, 0xB4, 0xD5, 0xA5, 0x04, 0xD5, + 0xB4, 0xD5, 0xAB, 0x04, 0xD5, 0xBE, 0xD5, 0xB6, + // Bytes 3100 - 313f + 0x04, 0xD5, 0xB4, 0xD5, 0xAD, 0x04, 0xD7, 0x99, + 0xD6, 0xB4, 0x04, 0xD7, 0xB2, 0xD6, 0xB7, 0x02, + 0xD7, 0xA2, 0x02, 0xD7, 0x94, 0x02, 0xD7, 0x9B, + 0x02, 0xD7, 0x9C, 0x02, 0xD7, 0x9D, 0x02, 0xD7, + 0xA8, 0x02, 0xD7, 0xAA, 0x04, 0xD7, 0xA9, 0xD7, + 0x81, 0x04, 0xD7, 0xA9, 0xD7, 0x82, 0x06, 0xD7, + 0xA9, 0xD6, 0xBC, 0xD7, 0x81, 0x06, 0xD7, 0xA9, + 0xD6, 0xBC, 0xD7, 0x82, 0x04, 0xD7, 0x90, 0xD6, + // Bytes 3140 - 317f + 0xB7, 0x04, 0xD7, 0x90, 0xD6, 0xB8, 0x04, 0xD7, + 0x90, 0xD6, 0xBC, 0x04, 0xD7, 0x91, 0xD6, 0xBC, + 0x04, 0xD7, 0x92, 0xD6, 0xBC, 0x04, 0xD7, 0x93, + 0xD6, 0xBC, 0x04, 0xD7, 0x94, 0xD6, 0xBC, 0x04, + 0xD7, 0x95, 0xD6, 0xBC, 0x04, 0xD7, 0x96, 0xD6, + 0xBC, 0x04, 0xD7, 0x98, 0xD6, 0xBC, 0x04, 0xD7, + 0x99, 0xD6, 0xBC, 0x04, 0xD7, 0x9A, 0xD6, 0xBC, + 0x04, 0xD7, 0x9B, 0xD6, 0xBC, 0x04, 0xD7, 0x9C, + // Bytes 3180 - 31bf + 0xD6, 0xBC, 0x04, 0xD7, 0x9E, 0xD6, 0xBC, 0x04, + 0xD7, 0xA0, 0xD6, 0xBC, 0x04, 0xD7, 0xA1, 0xD6, + 0xBC, 0x04, 0xD7, 0xA3, 0xD6, 0xBC, 0x04, 0xD7, + 0xA4, 0xD6, 0xBC, 0x04, 0xD7, 0xA6, 0xD6, 0xBC, + 0x04, 0xD7, 0xA7, 0xD6, 0xBC, 0x04, 0xD7, 0xA8, + 0xD6, 0xBC, 0x04, 0xD7, 0xA9, 0xD6, 0xBC, 0x04, + 0xD7, 0xAA, 0xD6, 0xBC, 0x04, 0xD7, 0x95, 0xD6, + 0xB9, 0x04, 0xD7, 0x91, 0xD6, 0xBF, 0x04, 0xD7, + // Bytes 31c0 - 31ff + 0x9B, 0xD6, 0xBF, 0x04, 0xD7, 0xA4, 0xD6, 0xBF, + 0x04, 0xD7, 0x90, 0xD7, 0x9C, 0x02, 0xD9, 0xB1, + 0x02, 0xD9, 0xBB, 0x02, 0xD9, 0xBE, 0x02, 0xDA, + 0x80, 0x02, 0xD9, 0xBA, 0x02, 0xD9, 0xBF, 0x02, + 0xD9, 0xB9, 0x02, 0xDA, 0xA4, 0x02, 0xDA, 0xA6, + 0x02, 0xDA, 0x84, 0x02, 0xDA, 0x83, 0x02, 0xDA, + 0x86, 0x02, 0xDA, 0x87, 0x02, 0xDA, 0x8D, 0x02, + 0xDA, 0x8C, 0x02, 0xDA, 0x8E, 0x02, 0xDA, 0x88, + // Bytes 3200 - 323f + 0x02, 0xDA, 0x98, 0x02, 0xDA, 0x91, 0x02, 0xDA, + 0xA9, 0x02, 0xDA, 0xAF, 0x02, 0xDA, 0xB3, 0x02, + 0xDA, 0xB1, 0x02, 0xDA, 0xBA, 0x02, 0xDA, 0xBB, + 0x02, 0xDB, 0x81, 0x02, 0xDA, 0xBE, 0x02, 0xDB, + 0x92, 0x02, 0xDA, 0xAD, 0x02, 0xDB, 0x87, 0x02, + 0xDB, 0x86, 0x02, 0xDB, 0x88, 0x02, 0xDB, 0x8B, + 0x02, 0xDB, 0x85, 0x02, 0xDB, 0x89, 0x02, 0xDB, + 0x90, 0x02, 0xD9, 0x89, 0x06, 0xD9, 0x8A, 0xD9, + // Bytes 3240 - 327f + 0x94, 0xD8, 0xA7, 0x06, 0xD9, 0x8A, 0xD9, 0x94, + 0xDB, 0x95, 0x06, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, + 0x88, 0x06, 0xD9, 0x8A, 0xD9, 0x94, 0xDB, 0x87, + 0x06, 0xD9, 0x8A, 0xD9, 0x94, 0xDB, 0x86, 0x06, + 0xD9, 0x8A, 0xD9, 0x94, 0xDB, 0x88, 0x06, 0xD9, + 0x8A, 0xD9, 0x94, 0xDB, 0x90, 0x06, 0xD9, 0x8A, + 0xD9, 0x94, 0xD9, 0x89, 0x02, 0xDB, 0x8C, 0x06, + 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAC, 0x06, 0xD9, + // Bytes 3280 - 32bf + 0x8A, 0xD9, 0x94, 0xD8, 0xAD, 0x06, 0xD9, 0x8A, + 0xD9, 0x94, 0xD9, 0x85, 0x06, 0xD9, 0x8A, 0xD9, + 0x94, 0xD9, 0x8A, 0x04, 0xD8, 0xA8, 0xD8, 0xAC, + 0x04, 0xD8, 0xA8, 0xD8, 0xAD, 0x04, 0xD8, 0xA8, + 0xD8, 0xAE, 0x04, 0xD8, 0xA8, 0xD9, 0x85, 0x04, + 0xD8, 0xA8, 0xD9, 0x89, 0x04, 0xD8, 0xA8, 0xD9, + 0x8A, 0x04, 0xD8, 0xAA, 0xD8, 0xAC, 0x04, 0xD8, + 0xAA, 0xD8, 0xAD, 0x04, 0xD8, 0xAA, 0xD8, 0xAE, + // Bytes 32c0 - 32ff + 0x04, 0xD8, 0xAA, 0xD9, 0x85, 0x04, 0xD8, 0xAA, + 0xD9, 0x89, 0x04, 0xD8, 0xAA, 0xD9, 0x8A, 0x04, + 0xD8, 0xAB, 0xD8, 0xAC, 0x04, 0xD8, 0xAB, 0xD9, + 0x85, 0x04, 0xD8, 0xAB, 0xD9, 0x89, 0x04, 0xD8, + 0xAB, 0xD9, 0x8A, 0x04, 0xD8, 0xAC, 0xD8, 0xAD, + 0x04, 0xD8, 0xAC, 0xD9, 0x85, 0x04, 0xD8, 0xAD, + 0xD8, 0xAC, 0x04, 0xD8, 0xAD, 0xD9, 0x85, 0x04, + 0xD8, 0xAE, 0xD8, 0xAC, 0x04, 0xD8, 0xAE, 0xD8, + // Bytes 3300 - 333f + 0xAD, 0x04, 0xD8, 0xAE, 0xD9, 0x85, 0x04, 0xD8, + 0xB3, 0xD8, 0xAC, 0x04, 0xD8, 0xB3, 0xD8, 0xAD, + 0x04, 0xD8, 0xB3, 0xD8, 0xAE, 0x04, 0xD8, 0xB3, + 0xD9, 0x85, 0x04, 0xD8, 0xB5, 0xD8, 0xAD, 0x04, + 0xD8, 0xB5, 0xD9, 0x85, 0x04, 0xD8, 0xB6, 0xD8, + 0xAC, 0x04, 0xD8, 0xB6, 0xD8, 0xAD, 0x04, 0xD8, + 0xB6, 0xD8, 0xAE, 0x04, 0xD8, 0xB6, 0xD9, 0x85, + 0x04, 0xD8, 0xB7, 0xD8, 0xAD, 0x04, 0xD8, 0xB7, + // Bytes 3340 - 337f + 0xD9, 0x85, 0x04, 0xD8, 0xB8, 0xD9, 0x85, 0x04, + 0xD8, 0xB9, 0xD8, 0xAC, 0x04, 0xD8, 0xB9, 0xD9, + 0x85, 0x04, 0xD8, 0xBA, 0xD8, 0xAC, 0x04, 0xD8, + 0xBA, 0xD9, 0x85, 0x04, 0xD9, 0x81, 0xD8, 0xAC, + 0x04, 0xD9, 0x81, 0xD8, 0xAD, 0x04, 0xD9, 0x81, + 0xD8, 0xAE, 0x04, 0xD9, 0x81, 0xD9, 0x85, 0x04, + 0xD9, 0x81, 0xD9, 0x89, 0x04, 0xD9, 0x81, 0xD9, + 0x8A, 0x04, 0xD9, 0x82, 0xD8, 0xAD, 0x04, 0xD9, + // Bytes 3380 - 33bf + 0x82, 0xD9, 0x85, 0x04, 0xD9, 0x82, 0xD9, 0x89, + 0x04, 0xD9, 0x82, 0xD9, 0x8A, 0x04, 0xD9, 0x83, + 0xD8, 0xA7, 0x04, 0xD9, 0x83, 0xD8, 0xAC, 0x04, + 0xD9, 0x83, 0xD8, 0xAD, 0x04, 0xD9, 0x83, 0xD8, + 0xAE, 0x04, 0xD9, 0x83, 0xD9, 0x84, 0x04, 0xD9, + 0x83, 0xD9, 0x85, 0x04, 0xD9, 0x83, 0xD9, 0x89, + 0x04, 0xD9, 0x83, 0xD9, 0x8A, 0x04, 0xD9, 0x84, + 0xD8, 0xAC, 0x04, 0xD9, 0x84, 0xD8, 0xAD, 0x04, + // Bytes 33c0 - 33ff + 0xD9, 0x84, 0xD8, 0xAE, 0x04, 0xD9, 0x84, 0xD9, + 0x85, 0x04, 0xD9, 0x84, 0xD9, 0x89, 0x04, 0xD9, + 0x84, 0xD9, 0x8A, 0x04, 0xD9, 0x85, 0xD8, 0xAC, + 0x04, 0xD9, 0x85, 0xD8, 0xAD, 0x04, 0xD9, 0x85, + 0xD8, 0xAE, 0x04, 0xD9, 0x85, 0xD9, 0x85, 0x04, + 0xD9, 0x85, 0xD9, 0x89, 0x04, 0xD9, 0x85, 0xD9, + 0x8A, 0x04, 0xD9, 0x86, 0xD8, 0xAC, 0x04, 0xD9, + 0x86, 0xD8, 0xAD, 0x04, 0xD9, 0x86, 0xD8, 0xAE, + // Bytes 3400 - 343f + 0x04, 0xD9, 0x86, 0xD9, 0x85, 0x04, 0xD9, 0x86, + 0xD9, 0x89, 0x04, 0xD9, 0x86, 0xD9, 0x8A, 0x04, + 0xD9, 0x87, 0xD8, 0xAC, 0x04, 0xD9, 0x87, 0xD9, + 0x85, 0x04, 0xD9, 0x87, 0xD9, 0x89, 0x04, 0xD9, + 0x87, 0xD9, 0x8A, 0x04, 0xD9, 0x8A, 0xD8, 0xAC, + 0x04, 0xD9, 0x8A, 0xD8, 0xAD, 0x04, 0xD9, 0x8A, + 0xD8, 0xAE, 0x04, 0xD9, 0x8A, 0xD9, 0x85, 0x04, + 0xD9, 0x8A, 0xD9, 0x89, 0x04, 0xD9, 0x8A, 0xD9, + // Bytes 3440 - 347f + 0x8A, 0x04, 0xD8, 0xB0, 0xD9, 0xB0, 0x04, 0xD8, + 0xB1, 0xD9, 0xB0, 0x04, 0xD9, 0x89, 0xD9, 0xB0, + 0x05, 0x20, 0xD9, 0x8C, 0xD9, 0x91, 0x05, 0x20, + 0xD9, 0x8D, 0xD9, 0x91, 0x05, 0x20, 0xD9, 0x8E, + 0xD9, 0x91, 0x05, 0x20, 0xD9, 0x8F, 0xD9, 0x91, + 0x05, 0x20, 0xD9, 0x90, 0xD9, 0x91, 0x05, 0x20, + 0xD9, 0x91, 0xD9, 0xB0, 0x06, 0xD9, 0x8A, 0xD9, + 0x94, 0xD8, 0xB1, 0x06, 0xD9, 0x8A, 0xD9, 0x94, + // Bytes 3480 - 34bf + 0xD8, 0xB2, 0x06, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, + 0x86, 0x04, 0xD8, 0xA8, 0xD8, 0xB1, 0x04, 0xD8, + 0xA8, 0xD8, 0xB2, 0x04, 0xD8, 0xA8, 0xD9, 0x86, + 0x04, 0xD8, 0xAA, 0xD8, 0xB1, 0x04, 0xD8, 0xAA, + 0xD8, 0xB2, 0x04, 0xD8, 0xAA, 0xD9, 0x86, 0x04, + 0xD8, 0xAB, 0xD8, 0xB1, 0x04, 0xD8, 0xAB, 0xD8, + 0xB2, 0x04, 0xD8, 0xAB, 0xD9, 0x86, 0x04, 0xD9, + 0x85, 0xD8, 0xA7, 0x04, 0xD9, 0x86, 0xD8, 0xB1, + // Bytes 34c0 - 34ff + 0x04, 0xD9, 0x86, 0xD8, 0xB2, 0x04, 0xD9, 0x86, + 0xD9, 0x86, 0x04, 0xD9, 0x8A, 0xD8, 0xB1, 0x04, + 0xD9, 0x8A, 0xD8, 0xB2, 0x04, 0xD9, 0x8A, 0xD9, + 0x86, 0x06, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAE, + 0x06, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x87, 0x04, + 0xD8, 0xA8, 0xD9, 0x87, 0x04, 0xD8, 0xAA, 0xD9, + 0x87, 0x04, 0xD8, 0xB5, 0xD8, 0xAE, 0x04, 0xD9, + 0x84, 0xD9, 0x87, 0x04, 0xD9, 0x86, 0xD9, 0x87, + // Bytes 3500 - 353f + 0x04, 0xD9, 0x87, 0xD9, 0xB0, 0x04, 0xD9, 0x8A, + 0xD9, 0x87, 0x04, 0xD8, 0xAB, 0xD9, 0x87, 0x04, + 0xD8, 0xB3, 0xD9, 0x87, 0x04, 0xD8, 0xB4, 0xD9, + 0x85, 0x04, 0xD8, 0xB4, 0xD9, 0x87, 0x06, 0xD9, + 0x80, 0xD9, 0x8E, 0xD9, 0x91, 0x06, 0xD9, 0x80, + 0xD9, 0x8F, 0xD9, 0x91, 0x06, 0xD9, 0x80, 0xD9, + 0x90, 0xD9, 0x91, 0x04, 0xD8, 0xB7, 0xD9, 0x89, + 0x04, 0xD8, 0xB7, 0xD9, 0x8A, 0x04, 0xD8, 0xB9, + // Bytes 3540 - 357f + 0xD9, 0x89, 0x04, 0xD8, 0xB9, 0xD9, 0x8A, 0x04, + 0xD8, 0xBA, 0xD9, 0x89, 0x04, 0xD8, 0xBA, 0xD9, + 0x8A, 0x04, 0xD8, 0xB3, 0xD9, 0x89, 0x04, 0xD8, + 0xB3, 0xD9, 0x8A, 0x04, 0xD8, 0xB4, 0xD9, 0x89, + 0x04, 0xD8, 0xB4, 0xD9, 0x8A, 0x04, 0xD8, 0xAD, + 0xD9, 0x89, 0x04, 0xD8, 0xAD, 0xD9, 0x8A, 0x04, + 0xD8, 0xAC, 0xD9, 0x89, 0x04, 0xD8, 0xAC, 0xD9, + 0x8A, 0x04, 0xD8, 0xAE, 0xD9, 0x89, 0x04, 0xD8, + // Bytes 3580 - 35bf + 0xAE, 0xD9, 0x8A, 0x04, 0xD8, 0xB5, 0xD9, 0x89, + 0x04, 0xD8, 0xB5, 0xD9, 0x8A, 0x04, 0xD8, 0xB6, + 0xD9, 0x89, 0x04, 0xD8, 0xB6, 0xD9, 0x8A, 0x04, + 0xD8, 0xB4, 0xD8, 0xAC, 0x04, 0xD8, 0xB4, 0xD8, + 0xAD, 0x04, 0xD8, 0xB4, 0xD8, 0xAE, 0x04, 0xD8, + 0xB4, 0xD8, 0xB1, 0x04, 0xD8, 0xB3, 0xD8, 0xB1, + 0x04, 0xD8, 0xB5, 0xD8, 0xB1, 0x04, 0xD8, 0xB6, + 0xD8, 0xB1, 0x04, 0xD8, 0xA7, 0xD9, 0x8B, 0x06, + // Bytes 35c0 - 35ff + 0xD8, 0xAA, 0xD8, 0xAC, 0xD9, 0x85, 0x06, 0xD8, + 0xAA, 0xD8, 0xAD, 0xD8, 0xAC, 0x06, 0xD8, 0xAA, + 0xD8, 0xAD, 0xD9, 0x85, 0x06, 0xD8, 0xAA, 0xD8, + 0xAE, 0xD9, 0x85, 0x06, 0xD8, 0xAA, 0xD9, 0x85, + 0xD8, 0xAC, 0x06, 0xD8, 0xAA, 0xD9, 0x85, 0xD8, + 0xAD, 0x06, 0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAE, + 0x06, 0xD8, 0xAC, 0xD9, 0x85, 0xD8, 0xAD, 0x06, + 0xD8, 0xAD, 0xD9, 0x85, 0xD9, 0x8A, 0x06, 0xD8, + // Bytes 3600 - 363f + 0xAD, 0xD9, 0x85, 0xD9, 0x89, 0x06, 0xD8, 0xB3, + 0xD8, 0xAD, 0xD8, 0xAC, 0x06, 0xD8, 0xB3, 0xD8, + 0xAC, 0xD8, 0xAD, 0x06, 0xD8, 0xB3, 0xD8, 0xAC, + 0xD9, 0x89, 0x06, 0xD8, 0xB3, 0xD9, 0x85, 0xD8, + 0xAD, 0x06, 0xD8, 0xB3, 0xD9, 0x85, 0xD8, 0xAC, + 0x06, 0xD8, 0xB3, 0xD9, 0x85, 0xD9, 0x85, 0x06, + 0xD8, 0xB5, 0xD8, 0xAD, 0xD8, 0xAD, 0x06, 0xD8, + 0xB5, 0xD9, 0x85, 0xD9, 0x85, 0x06, 0xD8, 0xB4, + // Bytes 3640 - 367f + 0xD8, 0xAD, 0xD9, 0x85, 0x06, 0xD8, 0xB4, 0xD8, + 0xAC, 0xD9, 0x8A, 0x06, 0xD8, 0xB4, 0xD9, 0x85, + 0xD8, 0xAE, 0x06, 0xD8, 0xB4, 0xD9, 0x85, 0xD9, + 0x85, 0x06, 0xD8, 0xB6, 0xD8, 0xAD, 0xD9, 0x89, + 0x06, 0xD8, 0xB6, 0xD8, 0xAE, 0xD9, 0x85, 0x06, + 0xD8, 0xB7, 0xD9, 0x85, 0xD8, 0xAD, 0x06, 0xD8, + 0xB7, 0xD9, 0x85, 0xD9, 0x85, 0x06, 0xD8, 0xB7, + 0xD9, 0x85, 0xD9, 0x8A, 0x06, 0xD8, 0xB9, 0xD8, + // Bytes 3680 - 36bf + 0xAC, 0xD9, 0x85, 0x06, 0xD8, 0xB9, 0xD9, 0x85, + 0xD9, 0x85, 0x06, 0xD8, 0xB9, 0xD9, 0x85, 0xD9, + 0x89, 0x06, 0xD8, 0xBA, 0xD9, 0x85, 0xD9, 0x85, + 0x06, 0xD8, 0xBA, 0xD9, 0x85, 0xD9, 0x8A, 0x06, + 0xD8, 0xBA, 0xD9, 0x85, 0xD9, 0x89, 0x06, 0xD9, + 0x81, 0xD8, 0xAE, 0xD9, 0x85, 0x06, 0xD9, 0x82, + 0xD9, 0x85, 0xD8, 0xAD, 0x06, 0xD9, 0x82, 0xD9, + 0x85, 0xD9, 0x85, 0x06, 0xD9, 0x84, 0xD8, 0xAD, + // Bytes 36c0 - 36ff + 0xD9, 0x85, 0x06, 0xD9, 0x84, 0xD8, 0xAD, 0xD9, + 0x8A, 0x06, 0xD9, 0x84, 0xD8, 0xAD, 0xD9, 0x89, + 0x06, 0xD9, 0x84, 0xD8, 0xAC, 0xD8, 0xAC, 0x06, + 0xD9, 0x84, 0xD8, 0xAE, 0xD9, 0x85, 0x06, 0xD9, + 0x84, 0xD9, 0x85, 0xD8, 0xAD, 0x06, 0xD9, 0x85, + 0xD8, 0xAD, 0xD8, 0xAC, 0x06, 0xD9, 0x85, 0xD8, + 0xAD, 0xD9, 0x85, 0x06, 0xD9, 0x85, 0xD8, 0xAD, + 0xD9, 0x8A, 0x06, 0xD9, 0x85, 0xD8, 0xAC, 0xD8, + // Bytes 3700 - 373f + 0xAD, 0x06, 0xD9, 0x85, 0xD8, 0xAC, 0xD9, 0x85, + 0x06, 0xD9, 0x85, 0xD8, 0xAE, 0xD8, 0xAC, 0x06, + 0xD9, 0x85, 0xD8, 0xAE, 0xD9, 0x85, 0x06, 0xD9, + 0x85, 0xD8, 0xAC, 0xD8, 0xAE, 0x06, 0xD9, 0x87, + 0xD9, 0x85, 0xD8, 0xAC, 0x06, 0xD9, 0x87, 0xD9, + 0x85, 0xD9, 0x85, 0x06, 0xD9, 0x86, 0xD8, 0xAD, + 0xD9, 0x85, 0x06, 0xD9, 0x86, 0xD8, 0xAD, 0xD9, + 0x89, 0x06, 0xD9, 0x86, 0xD8, 0xAC, 0xD9, 0x85, + // Bytes 3740 - 377f + 0x06, 0xD9, 0x86, 0xD8, 0xAC, 0xD9, 0x89, 0x06, + 0xD9, 0x86, 0xD9, 0x85, 0xD9, 0x8A, 0x06, 0xD9, + 0x86, 0xD9, 0x85, 0xD9, 0x89, 0x06, 0xD9, 0x8A, + 0xD9, 0x85, 0xD9, 0x85, 0x06, 0xD8, 0xA8, 0xD8, + 0xAE, 0xD9, 0x8A, 0x06, 0xD8, 0xAA, 0xD8, 0xAC, + 0xD9, 0x8A, 0x06, 0xD8, 0xAA, 0xD8, 0xAC, 0xD9, + 0x89, 0x06, 0xD8, 0xAA, 0xD8, 0xAE, 0xD9, 0x8A, + 0x06, 0xD8, 0xAA, 0xD8, 0xAE, 0xD9, 0x89, 0x06, + // Bytes 3780 - 37bf + 0xD8, 0xAA, 0xD9, 0x85, 0xD9, 0x8A, 0x06, 0xD8, + 0xAA, 0xD9, 0x85, 0xD9, 0x89, 0x06, 0xD8, 0xAC, + 0xD9, 0x85, 0xD9, 0x8A, 0x06, 0xD8, 0xAC, 0xD8, + 0xAD, 0xD9, 0x89, 0x06, 0xD8, 0xAC, 0xD9, 0x85, + 0xD9, 0x89, 0x06, 0xD8, 0xB3, 0xD8, 0xAE, 0xD9, + 0x89, 0x06, 0xD8, 0xB5, 0xD8, 0xAD, 0xD9, 0x8A, + 0x06, 0xD8, 0xB4, 0xD8, 0xAD, 0xD9, 0x8A, 0x06, + 0xD8, 0xB6, 0xD8, 0xAD, 0xD9, 0x8A, 0x06, 0xD9, + // Bytes 37c0 - 37ff + 0x84, 0xD8, 0xAC, 0xD9, 0x8A, 0x06, 0xD9, 0x84, + 0xD9, 0x85, 0xD9, 0x8A, 0x06, 0xD9, 0x8A, 0xD8, + 0xAD, 0xD9, 0x8A, 0x06, 0xD9, 0x8A, 0xD8, 0xAC, + 0xD9, 0x8A, 0x06, 0xD9, 0x8A, 0xD9, 0x85, 0xD9, + 0x8A, 0x06, 0xD9, 0x85, 0xD9, 0x85, 0xD9, 0x8A, + 0x06, 0xD9, 0x82, 0xD9, 0x85, 0xD9, 0x8A, 0x06, + 0xD9, 0x86, 0xD8, 0xAD, 0xD9, 0x8A, 0x06, 0xD8, + 0xB9, 0xD9, 0x85, 0xD9, 0x8A, 0x06, 0xD9, 0x83, + // Bytes 3800 - 383f + 0xD9, 0x85, 0xD9, 0x8A, 0x06, 0xD9, 0x86, 0xD8, + 0xAC, 0xD8, 0xAD, 0x06, 0xD9, 0x85, 0xD8, 0xAE, + 0xD9, 0x8A, 0x06, 0xD9, 0x84, 0xD8, 0xAC, 0xD9, + 0x85, 0x06, 0xD9, 0x83, 0xD9, 0x85, 0xD9, 0x85, + 0x06, 0xD8, 0xAC, 0xD8, 0xAD, 0xD9, 0x8A, 0x06, + 0xD8, 0xAD, 0xD8, 0xAC, 0xD9, 0x8A, 0x06, 0xD9, + 0x85, 0xD8, 0xAC, 0xD9, 0x8A, 0x06, 0xD9, 0x81, + 0xD9, 0x85, 0xD9, 0x8A, 0x06, 0xD8, 0xA8, 0xD8, + // Bytes 3840 - 387f + 0xAD, 0xD9, 0x8A, 0x06, 0xD8, 0xB3, 0xD8, 0xAE, + 0xD9, 0x8A, 0x06, 0xD9, 0x86, 0xD8, 0xAC, 0xD9, + 0x8A, 0x06, 0xD8, 0xB5, 0xD9, 0x84, 0xDB, 0x92, + 0x06, 0xD9, 0x82, 0xD9, 0x84, 0xDB, 0x92, 0x08, + 0xD8, 0xA7, 0xD9, 0x84, 0xD9, 0x84, 0xD9, 0x87, + 0x08, 0xD8, 0xA7, 0xD9, 0x83, 0xD8, 0xA8, 0xD8, + 0xB1, 0x08, 0xD9, 0x85, 0xD8, 0xAD, 0xD9, 0x85, + 0xD8, 0xAF, 0x08, 0xD8, 0xB5, 0xD9, 0x84, 0xD8, + // Bytes 3880 - 38bf + 0xB9, 0xD9, 0x85, 0x08, 0xD8, 0xB1, 0xD8, 0xB3, + 0xD9, 0x88, 0xD9, 0x84, 0x08, 0xD8, 0xB9, 0xD9, + 0x84, 0xD9, 0x8A, 0xD9, 0x87, 0x08, 0xD9, 0x88, + 0xD8, 0xB3, 0xD9, 0x84, 0xD9, 0x85, 0x06, 0xD8, + 0xB5, 0xD9, 0x84, 0xD9, 0x89, 0x21, 0xD8, 0xB5, + 0xD9, 0x84, 0xD9, 0x89, 0x20, 0xD8, 0xA7, 0xD9, + 0x84, 0xD9, 0x84, 0xD9, 0x87, 0x20, 0xD8, 0xB9, + 0xD9, 0x84, 0xD9, 0x8A, 0xD9, 0x87, 0x20, 0xD9, + // Bytes 38c0 - 38ff + 0x88, 0xD8, 0xB3, 0xD9, 0x84, 0xD9, 0x85, 0x0F, + 0xD8, 0xAC, 0xD9, 0x84, 0x20, 0xD8, 0xAC, 0xD9, + 0x84, 0xD8, 0xA7, 0xD9, 0x84, 0xD9, 0x87, 0x08, + 0xD8, 0xB1, 0xDB, 0x8C, 0xD8, 0xA7, 0xD9, 0x84, + 0x01, 0x2C, 0x03, 0xE3, 0x80, 0x81, 0x03, 0xE3, + 0x80, 0x82, 0x01, 0x3A, 0x01, 0x21, 0x01, 0x3F, + 0x03, 0xE3, 0x80, 0x96, 0x03, 0xE3, 0x80, 0x97, + 0x03, 0xE2, 0x80, 0x94, 0x03, 0xE2, 0x80, 0x93, + // Bytes 3900 - 393f + 0x01, 0x5F, 0x01, 0x7B, 0x01, 0x7D, 0x03, 0xE3, + 0x80, 0x94, 0x03, 0xE3, 0x80, 0x95, 0x03, 0xE3, + 0x80, 0x90, 0x03, 0xE3, 0x80, 0x91, 0x03, 0xE3, + 0x80, 0x8A, 0x03, 0xE3, 0x80, 0x8B, 0x03, 0xE3, + 0x80, 0x8C, 0x03, 0xE3, 0x80, 0x8D, 0x03, 0xE3, + 0x80, 0x8E, 0x03, 0xE3, 0x80, 0x8F, 0x01, 0x5B, + 0x01, 0x5D, 0x01, 0x23, 0x01, 0x26, 0x01, 0x2A, + 0x01, 0x2D, 0x01, 0x3C, 0x01, 0x3E, 0x01, 0x5C, + // Bytes 3940 - 397f + 0x01, 0x24, 0x01, 0x25, 0x01, 0x40, 0x03, 0x20, + 0xD9, 0x8B, 0x04, 0xD9, 0x80, 0xD9, 0x8B, 0x03, + 0x20, 0xD9, 0x8C, 0x03, 0x20, 0xD9, 0x8D, 0x03, + 0x20, 0xD9, 0x8E, 0x04, 0xD9, 0x80, 0xD9, 0x8E, + 0x03, 0x20, 0xD9, 0x8F, 0x04, 0xD9, 0x80, 0xD9, + 0x8F, 0x03, 0x20, 0xD9, 0x90, 0x04, 0xD9, 0x80, + 0xD9, 0x90, 0x03, 0x20, 0xD9, 0x91, 0x04, 0xD9, + 0x80, 0xD9, 0x91, 0x03, 0x20, 0xD9, 0x92, 0x04, + // Bytes 3980 - 39bf + 0xD9, 0x80, 0xD9, 0x92, 0x02, 0xD8, 0xA1, 0x02, + 0xD8, 0xA7, 0x02, 0xD8, 0xA8, 0x02, 0xD8, 0xA9, + 0x02, 0xD8, 0xAA, 0x02, 0xD8, 0xAB, 0x02, 0xD8, + 0xAC, 0x02, 0xD8, 0xAD, 0x02, 0xD8, 0xAE, 0x02, + 0xD8, 0xAF, 0x02, 0xD8, 0xB0, 0x02, 0xD8, 0xB1, + 0x02, 0xD8, 0xB2, 0x02, 0xD8, 0xB3, 0x02, 0xD8, + 0xB4, 0x02, 0xD8, 0xB5, 0x02, 0xD8, 0xB6, 0x02, + 0xD8, 0xB7, 0x02, 0xD8, 0xB8, 0x02, 0xD8, 0xB9, + // Bytes 39c0 - 39ff + 0x02, 0xD8, 0xBA, 0x02, 0xD9, 0x81, 0x02, 0xD9, + 0x82, 0x02, 0xD9, 0x83, 0x02, 0xD9, 0x84, 0x02, + 0xD9, 0x85, 0x02, 0xD9, 0x86, 0x02, 0xD9, 0x87, + 0x02, 0xD9, 0x88, 0x02, 0xD9, 0x8A, 0x06, 0xD9, + 0x84, 0xD8, 0xA7, 0xD9, 0x93, 0x06, 0xD9, 0x84, + 0xD8, 0xA7, 0xD9, 0x94, 0x06, 0xD9, 0x84, 0xD8, + 0xA7, 0xD9, 0x95, 0x04, 0xD9, 0x84, 0xD8, 0xA7, + 0x01, 0x22, 0x01, 0x27, 0x01, 0x2F, 0x01, 0x5E, + // Bytes 3a00 - 3a3f + 0x01, 0x7C, 0x01, 0x7E, 0x03, 0xE2, 0xA6, 0x85, + 0x03, 0xE2, 0xA6, 0x86, 0x03, 0xE3, 0x83, 0xBB, + 0x03, 0xE3, 0x82, 0xA1, 0x03, 0xE3, 0x82, 0xA3, + 0x03, 0xE3, 0x82, 0xA5, 0x03, 0xE3, 0x82, 0xA7, + 0x03, 0xE3, 0x82, 0xA9, 0x03, 0xE3, 0x83, 0xA3, + 0x03, 0xE3, 0x83, 0xA5, 0x03, 0xE3, 0x83, 0xA7, + 0x03, 0xE3, 0x83, 0x83, 0x03, 0xE3, 0x83, 0xBC, + 0x03, 0xE3, 0x83, 0xB3, 0x03, 0xE3, 0x82, 0x99, + // Bytes 3a40 - 3a7f + 0x03, 0xE3, 0x82, 0x9A, 0x02, 0xC2, 0xA2, 0x02, + 0xC2, 0xA3, 0x02, 0xC2, 0xAC, 0x02, 0xC2, 0xA6, + 0x02, 0xC2, 0xA5, 0x03, 0xE2, 0x82, 0xA9, 0x03, + 0xE2, 0x94, 0x82, 0x03, 0xE2, 0x86, 0x90, 0x03, + 0xE2, 0x86, 0x91, 0x03, 0xE2, 0x86, 0x92, 0x03, + 0xE2, 0x86, 0x93, 0x03, 0xE2, 0x96, 0xA0, 0x03, + 0xE2, 0x97, 0x8B, 0x08, 0xF0, 0x91, 0x82, 0x99, + 0xF0, 0x91, 0x82, 0xBA, 0x08, 0xF0, 0x91, 0x82, + // Bytes 3a80 - 3abf + 0x9B, 0xF0, 0x91, 0x82, 0xBA, 0x08, 0xF0, 0x91, + 0x82, 0xA5, 0xF0, 0x91, 0x82, 0xBA, 0x08, 0xF0, + 0x9D, 0x85, 0x97, 0xF0, 0x9D, 0x85, 0xA5, 0x08, + 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, + 0x0C, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, + 0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0x0C, 0xF0, 0x9D, + 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, + 0x85, 0xAF, 0x0C, 0xF0, 0x9D, 0x85, 0x98, 0xF0, + // Bytes 3ac0 - 3aff + 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xB0, 0x0C, + 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, + 0xF0, 0x9D, 0x85, 0xB1, 0x0C, 0xF0, 0x9D, 0x85, + 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, + 0xB2, 0x08, 0xF0, 0x9D, 0x86, 0xB9, 0xF0, 0x9D, + 0x85, 0xA5, 0x08, 0xF0, 0x9D, 0x86, 0xBA, 0xF0, + 0x9D, 0x85, 0xA5, 0x0C, 0xF0, 0x9D, 0x86, 0xB9, + 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAE, + // Bytes 3b00 - 3b3f + 0x0C, 0xF0, 0x9D, 0x86, 0xBA, 0xF0, 0x9D, 0x85, + 0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0x0C, 0xF0, 0x9D, + 0x86, 0xB9, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, + 0x85, 0xAF, 0x0C, 0xF0, 0x9D, 0x86, 0xBA, 0xF0, + 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAF, 0x02, + 0xC4, 0xB1, 0x02, 0xC8, 0xB7, 0x02, 0xCE, 0x91, + 0x02, 0xCE, 0x92, 0x02, 0xCE, 0x94, 0x02, 0xCE, + 0x95, 0x02, 0xCE, 0x96, 0x02, 0xCE, 0x97, 0x02, + // Bytes 3b40 - 3b7f + 0xCE, 0x99, 0x02, 0xCE, 0x9A, 0x02, 0xCE, 0x9B, + 0x02, 0xCE, 0x9C, 0x02, 0xCE, 0x9D, 0x02, 0xCE, + 0x9E, 0x02, 0xCE, 0x9F, 0x02, 0xCE, 0xA1, 0x02, + 0xCE, 0xA4, 0x02, 0xCE, 0xA6, 0x02, 0xCE, 0xA7, + 0x02, 0xCE, 0xA8, 0x03, 0xE2, 0x88, 0x87, 0x02, + 0xCE, 0xB1, 0x02, 0xCE, 0xB6, 0x02, 0xCE, 0xB7, + 0x02, 0xCE, 0xBB, 0x02, 0xCE, 0xBD, 0x02, 0xCE, + 0xBE, 0x02, 0xCE, 0xBF, 0x02, 0xCF, 0x83, 0x02, + // Bytes 3b80 - 3bbf + 0xCF, 0x84, 0x02, 0xCF, 0x85, 0x02, 0xCF, 0x88, + 0x02, 0xCF, 0x89, 0x03, 0xE2, 0x88, 0x82, 0x02, + 0xCF, 0x9C, 0x02, 0xCF, 0x9D, 0x02, 0x30, 0x2E, + 0x02, 0x30, 0x2C, 0x02, 0x31, 0x2C, 0x02, 0x32, + 0x2C, 0x02, 0x33, 0x2C, 0x02, 0x34, 0x2C, 0x02, + 0x35, 0x2C, 0x02, 0x36, 0x2C, 0x02, 0x37, 0x2C, + 0x02, 0x38, 0x2C, 0x02, 0x39, 0x2C, 0x03, 0x28, + 0x41, 0x29, 0x03, 0x28, 0x42, 0x29, 0x03, 0x28, + // Bytes 3bc0 - 3bff + 0x43, 0x29, 0x03, 0x28, 0x44, 0x29, 0x03, 0x28, + 0x45, 0x29, 0x03, 0x28, 0x46, 0x29, 0x03, 0x28, + 0x47, 0x29, 0x03, 0x28, 0x48, 0x29, 0x03, 0x28, + 0x49, 0x29, 0x03, 0x28, 0x4A, 0x29, 0x03, 0x28, + 0x4B, 0x29, 0x03, 0x28, 0x4C, 0x29, 0x03, 0x28, + 0x4D, 0x29, 0x03, 0x28, 0x4E, 0x29, 0x03, 0x28, + 0x4F, 0x29, 0x03, 0x28, 0x50, 0x29, 0x03, 0x28, + 0x51, 0x29, 0x03, 0x28, 0x52, 0x29, 0x03, 0x28, + // Bytes 3c00 - 3c3f + 0x53, 0x29, 0x03, 0x28, 0x54, 0x29, 0x03, 0x28, + 0x55, 0x29, 0x03, 0x28, 0x56, 0x29, 0x03, 0x28, + 0x57, 0x29, 0x03, 0x28, 0x58, 0x29, 0x03, 0x28, + 0x59, 0x29, 0x03, 0x28, 0x5A, 0x29, 0x07, 0xE3, + 0x80, 0x94, 0x53, 0xE3, 0x80, 0x95, 0x02, 0x43, + 0x44, 0x02, 0x57, 0x5A, 0x02, 0x48, 0x56, 0x02, + 0x53, 0x44, 0x02, 0x53, 0x53, 0x03, 0x50, 0x50, + 0x56, 0x02, 0x57, 0x43, 0x02, 0x44, 0x4A, 0x06, + // Bytes 3c40 - 3c7f + 0xE3, 0x81, 0xBB, 0xE3, 0x81, 0x8B, 0x06, 0xE3, + 0x82, 0xB3, 0xE3, 0x82, 0xB3, 0x03, 0xE5, 0xAD, + 0x97, 0x03, 0xE5, 0x8F, 0x8C, 0x03, 0xE5, 0xA4, + 0x9A, 0x03, 0xE8, 0xA7, 0xA3, 0x03, 0xE4, 0xBA, + 0xA4, 0x03, 0xE6, 0x98, 0xA0, 0x03, 0xE7, 0x84, + 0xA1, 0x03, 0xE5, 0x89, 0x8D, 0x03, 0xE5, 0xBE, + 0x8C, 0x03, 0xE5, 0x86, 0x8D, 0x03, 0xE6, 0x96, + 0xB0, 0x03, 0xE5, 0x88, 0x9D, 0x03, 0xE7, 0xB5, + // Bytes 3c80 - 3cbf + 0x82, 0x03, 0xE8, 0xB2, 0xA9, 0x03, 0xE5, 0xA3, + 0xB0, 0x03, 0xE5, 0x90, 0xB9, 0x03, 0xE6, 0xBC, + 0x94, 0x03, 0xE6, 0x8A, 0x95, 0x03, 0xE6, 0x8D, + 0x95, 0x03, 0xE9, 0x81, 0x8A, 0x03, 0xE6, 0x8C, + 0x87, 0x03, 0xE6, 0x89, 0x93, 0x03, 0xE7, 0xA6, + 0x81, 0x03, 0xE7, 0xA9, 0xBA, 0x03, 0xE5, 0x90, + 0x88, 0x03, 0xE6, 0xBA, 0x80, 0x03, 0xE7, 0x94, + 0xB3, 0x03, 0xE5, 0x89, 0xB2, 0x03, 0xE5, 0x96, + // Bytes 3cc0 - 3cff + 0xB6, 0x09, 0xE3, 0x80, 0x94, 0xE6, 0x9C, 0xAC, + 0xE3, 0x80, 0x95, 0x09, 0xE3, 0x80, 0x94, 0xE4, + 0xB8, 0x89, 0xE3, 0x80, 0x95, 0x09, 0xE3, 0x80, + 0x94, 0xE4, 0xBA, 0x8C, 0xE3, 0x80, 0x95, 0x09, + 0xE3, 0x80, 0x94, 0xE5, 0xAE, 0x89, 0xE3, 0x80, + 0x95, 0x09, 0xE3, 0x80, 0x94, 0xE7, 0x82, 0xB9, + 0xE3, 0x80, 0x95, 0x09, 0xE3, 0x80, 0x94, 0xE6, + 0x89, 0x93, 0xE3, 0x80, 0x95, 0x09, 0xE3, 0x80, + // Bytes 3d00 - 3d3f + 0x94, 0xE7, 0x9B, 0x97, 0xE3, 0x80, 0x95, 0x09, + 0xE3, 0x80, 0x94, 0xE5, 0x8B, 0x9D, 0xE3, 0x80, + 0x95, 0x09, 0xE3, 0x80, 0x94, 0xE6, 0x95, 0x97, + 0xE3, 0x80, 0x95, 0x03, 0xE5, 0xBE, 0x97, 0x03, + 0xE5, 0x8F, 0xAF, 0x03, 0xE4, 0xB8, 0xBD, 0x03, + 0xE4, 0xB8, 0xB8, 0x03, 0xE4, 0xB9, 0x81, 0x04, + 0xF0, 0xA0, 0x84, 0xA2, 0x03, 0xE4, 0xBD, 0xA0, + 0x03, 0xE4, 0xBE, 0xBB, 0x03, 0xE5, 0x80, 0x82, + // Bytes 3d40 - 3d7f + 0x03, 0xE5, 0x81, 0xBA, 0x03, 0xE5, 0x82, 0x99, + 0x03, 0xE5, 0x83, 0x8F, 0x03, 0xE3, 0x92, 0x9E, + 0x04, 0xF0, 0xA0, 0x98, 0xBA, 0x03, 0xE5, 0x85, + 0x94, 0x03, 0xE5, 0x85, 0xA4, 0x03, 0xE5, 0x85, + 0xB7, 0x04, 0xF0, 0xA0, 0x94, 0x9C, 0x03, 0xE3, + 0x92, 0xB9, 0x03, 0xE5, 0x85, 0xA7, 0x04, 0xF0, + 0xA0, 0x95, 0x8B, 0x03, 0xE5, 0x86, 0x97, 0x03, + 0xE5, 0x86, 0xA4, 0x03, 0xE4, 0xBB, 0x8C, 0x03, + // Bytes 3d80 - 3dbf + 0xE5, 0x86, 0xAC, 0x04, 0xF0, 0xA9, 0x87, 0x9F, + 0x03, 0xE5, 0x88, 0x83, 0x03, 0xE3, 0x93, 0x9F, + 0x03, 0xE5, 0x88, 0xBB, 0x03, 0xE5, 0x89, 0x86, + 0x03, 0xE5, 0x89, 0xB7, 0x03, 0xE3, 0x94, 0x95, + 0x03, 0xE5, 0x8C, 0x85, 0x03, 0xE5, 0x8C, 0x86, + 0x03, 0xE5, 0x8D, 0x89, 0x03, 0xE5, 0x8D, 0x9A, + 0x03, 0xE5, 0x8D, 0xB3, 0x03, 0xE5, 0x8D, 0xBD, + 0x03, 0xE5, 0x8D, 0xBF, 0x04, 0xF0, 0xA0, 0xA8, + // Bytes 3dc0 - 3dff + 0xAC, 0x03, 0xE7, 0x81, 0xB0, 0x03, 0xE5, 0x8F, + 0x8A, 0x03, 0xE5, 0x8F, 0x9F, 0x04, 0xF0, 0xA0, + 0xAD, 0xA3, 0x03, 0xE5, 0x8F, 0xAB, 0x03, 0xE5, + 0x8F, 0xB1, 0x03, 0xE5, 0x90, 0x86, 0x03, 0xE5, + 0x92, 0x9E, 0x03, 0xE5, 0x90, 0xB8, 0x03, 0xE5, + 0x91, 0x88, 0x03, 0xE5, 0x91, 0xA8, 0x03, 0xE5, + 0x92, 0xA2, 0x03, 0xE5, 0x93, 0xB6, 0x03, 0xE5, + 0x94, 0x90, 0x03, 0xE5, 0x95, 0x93, 0x03, 0xE5, + // Bytes 3e00 - 3e3f + 0x95, 0xA3, 0x03, 0xE5, 0x96, 0x84, 0x03, 0xE5, + 0x96, 0xAB, 0x03, 0xE5, 0x96, 0xB3, 0x03, 0xE5, + 0x97, 0x82, 0x03, 0xE5, 0x9C, 0x96, 0x03, 0xE5, + 0x9C, 0x97, 0x03, 0xE5, 0x99, 0x91, 0x03, 0xE5, + 0x99, 0xB4, 0x03, 0xE5, 0xA3, 0xAE, 0x03, 0xE5, + 0x9F, 0x8E, 0x03, 0xE5, 0x9F, 0xB4, 0x03, 0xE5, + 0xA0, 0x8D, 0x03, 0xE5, 0x9E, 0x8B, 0x03, 0xE5, + 0xA0, 0xB2, 0x03, 0xE5, 0xA0, 0xB1, 0x03, 0xE5, + // Bytes 3e40 - 3e7f + 0xA2, 0xAC, 0x04, 0xF0, 0xA1, 0x93, 0xA4, 0x03, + 0xE5, 0xA3, 0xB2, 0x03, 0xE5, 0xA3, 0xB7, 0x03, + 0xE5, 0xA4, 0x86, 0x03, 0xE5, 0xA4, 0xA2, 0x03, + 0xE5, 0xA5, 0xA2, 0x04, 0xF0, 0xA1, 0x9A, 0xA8, + 0x04, 0xF0, 0xA1, 0x9B, 0xAA, 0x03, 0xE5, 0xA7, + 0xAC, 0x03, 0xE5, 0xA8, 0x9B, 0x03, 0xE5, 0xA8, + 0xA7, 0x03, 0xE5, 0xA7, 0x98, 0x03, 0xE5, 0xA9, + 0xA6, 0x03, 0xE3, 0x9B, 0xAE, 0x03, 0xE3, 0x9B, + // Bytes 3e80 - 3ebf + 0xBC, 0x03, 0xE5, 0xAC, 0x88, 0x03, 0xE5, 0xAC, + 0xBE, 0x04, 0xF0, 0xA1, 0xA7, 0x88, 0x03, 0xE5, + 0xAF, 0x83, 0x03, 0xE5, 0xAF, 0x98, 0x03, 0xE5, + 0xAF, 0xB3, 0x04, 0xF0, 0xA1, 0xAC, 0x98, 0x03, + 0xE5, 0xAF, 0xBF, 0x03, 0xE5, 0xB0, 0x86, 0x03, + 0xE5, 0xBD, 0x93, 0x03, 0xE3, 0x9E, 0x81, 0x03, + 0xE5, 0xB1, 0xA0, 0x03, 0xE5, 0xB3, 0x80, 0x03, + 0xE5, 0xB2, 0x8D, 0x04, 0xF0, 0xA1, 0xB7, 0xA4, + // Bytes 3ec0 - 3eff + 0x03, 0xE5, 0xB5, 0x83, 0x04, 0xF0, 0xA1, 0xB7, + 0xA6, 0x03, 0xE5, 0xB5, 0xAE, 0x03, 0xE5, 0xB5, + 0xAB, 0x03, 0xE5, 0xB5, 0xBC, 0x03, 0xE5, 0xB7, + 0xA1, 0x03, 0xE5, 0xB7, 0xA2, 0x03, 0xE3, 0xA0, + 0xAF, 0x03, 0xE5, 0xB7, 0xBD, 0x03, 0xE5, 0xB8, + 0xA8, 0x03, 0xE5, 0xB8, 0xBD, 0x03, 0xE5, 0xB9, + 0xA9, 0x03, 0xE3, 0xA1, 0xA2, 0x04, 0xF0, 0xA2, + 0x86, 0x83, 0x03, 0xE3, 0xA1, 0xBC, 0x03, 0xE5, + // Bytes 3f00 - 3f3f + 0xBA, 0xB0, 0x03, 0xE5, 0xBA, 0xB3, 0x03, 0xE5, + 0xBA, 0xB6, 0x04, 0xF0, 0xAA, 0x8E, 0x92, 0x04, + 0xF0, 0xA2, 0x8C, 0xB1, 0x03, 0xE8, 0x88, 0x81, + 0x03, 0xE5, 0xBC, 0xA2, 0x03, 0xE3, 0xA3, 0x87, + 0x04, 0xF0, 0xA3, 0x8A, 0xB8, 0x04, 0xF0, 0xA6, + 0x87, 0x9A, 0x03, 0xE5, 0xBD, 0xA2, 0x03, 0xE5, + 0xBD, 0xAB, 0x03, 0xE3, 0xA3, 0xA3, 0x03, 0xE5, + 0xBE, 0x9A, 0x03, 0xE5, 0xBF, 0x8D, 0x03, 0xE5, + // Bytes 3f40 - 3f7f + 0xBF, 0x97, 0x03, 0xE5, 0xBF, 0xB9, 0x03, 0xE6, + 0x82, 0x81, 0x03, 0xE3, 0xA4, 0xBA, 0x03, 0xE3, + 0xA4, 0x9C, 0x04, 0xF0, 0xA2, 0x9B, 0x94, 0x03, + 0xE6, 0x83, 0x87, 0x03, 0xE6, 0x85, 0x88, 0x03, + 0xE6, 0x85, 0x8C, 0x03, 0xE6, 0x85, 0xBA, 0x03, + 0xE6, 0x86, 0xB2, 0x03, 0xE6, 0x86, 0xA4, 0x03, + 0xE6, 0x86, 0xAF, 0x03, 0xE6, 0x87, 0x9E, 0x03, + 0xE6, 0x88, 0x90, 0x03, 0xE6, 0x88, 0x9B, 0x03, + // Bytes 3f80 - 3fbf + 0xE6, 0x89, 0x9D, 0x03, 0xE6, 0x8A, 0xB1, 0x03, + 0xE6, 0x8B, 0x94, 0x03, 0xE6, 0x8D, 0x90, 0x04, + 0xF0, 0xA2, 0xAC, 0x8C, 0x03, 0xE6, 0x8C, 0xBD, + 0x03, 0xE6, 0x8B, 0xBC, 0x03, 0xE6, 0x8D, 0xA8, + 0x03, 0xE6, 0x8E, 0x83, 0x03, 0xE6, 0x8F, 0xA4, + 0x04, 0xF0, 0xA2, 0xAF, 0xB1, 0x03, 0xE6, 0x90, + 0xA2, 0x03, 0xE6, 0x8F, 0x85, 0x03, 0xE6, 0x8E, + 0xA9, 0x03, 0xE3, 0xA8, 0xAE, 0x03, 0xE6, 0x91, + // Bytes 3fc0 - 3fff + 0xA9, 0x03, 0xE6, 0x91, 0xBE, 0x03, 0xE6, 0x92, + 0x9D, 0x03, 0xE6, 0x91, 0xB7, 0x03, 0xE3, 0xA9, + 0xAC, 0x03, 0xE6, 0x95, 0xAC, 0x04, 0xF0, 0xA3, + 0x80, 0x8A, 0x03, 0xE6, 0x97, 0xA3, 0x03, 0xE6, + 0x9B, 0xB8, 0x03, 0xE6, 0x99, 0x89, 0x03, 0xE3, + 0xAC, 0x99, 0x03, 0xE3, 0xAC, 0x88, 0x03, 0xE3, + 0xAB, 0xA4, 0x03, 0xE5, 0x86, 0x92, 0x03, 0xE5, + 0x86, 0x95, 0x03, 0xE6, 0x9C, 0x80, 0x03, 0xE6, + // Bytes 4000 - 403f + 0x9A, 0x9C, 0x03, 0xE8, 0x82, 0xAD, 0x03, 0xE4, + 0x8F, 0x99, 0x03, 0xE6, 0x9C, 0xA1, 0x03, 0xE6, + 0x9D, 0x9E, 0x03, 0xE6, 0x9D, 0x93, 0x04, 0xF0, + 0xA3, 0x8F, 0x83, 0x03, 0xE3, 0xAD, 0x89, 0x03, + 0xE6, 0x9F, 0xBA, 0x03, 0xE6, 0x9E, 0x85, 0x03, + 0xE6, 0xA1, 0x92, 0x04, 0xF0, 0xA3, 0x91, 0xAD, + 0x03, 0xE6, 0xA2, 0x8E, 0x03, 0xE6, 0xA0, 0x9F, + 0x03, 0xE6, 0xA4, 0x94, 0x03, 0xE6, 0xA5, 0x82, + // Bytes 4040 - 407f + 0x03, 0xE6, 0xA6, 0xA3, 0x03, 0xE6, 0xA7, 0xAA, + 0x03, 0xE6, 0xAA, 0xA8, 0x04, 0xF0, 0xA3, 0x9A, + 0xA3, 0x03, 0xE6, 0xAB, 0x9B, 0x03, 0xE3, 0xB0, + 0x98, 0x03, 0xE6, 0xAC, 0xA1, 0x04, 0xF0, 0xA3, + 0xA2, 0xA7, 0x03, 0xE6, 0xAD, 0x94, 0x03, 0xE3, + 0xB1, 0x8E, 0x03, 0xE6, 0xAD, 0xB2, 0x03, 0xE6, + 0xAE, 0x9F, 0x03, 0xE6, 0xAE, 0xBB, 0x04, 0xF0, + 0xA3, 0xAA, 0x8D, 0x04, 0xF0, 0xA1, 0xB4, 0x8B, + // Bytes 4080 - 40bf + 0x04, 0xF0, 0xA3, 0xAB, 0xBA, 0x03, 0xE6, 0xB1, + 0x8E, 0x04, 0xF0, 0xA3, 0xB2, 0xBC, 0x03, 0xE6, + 0xB2, 0xBF, 0x03, 0xE6, 0xB3, 0x8D, 0x03, 0xE6, + 0xB1, 0xA7, 0x03, 0xE6, 0xB4, 0x96, 0x03, 0xE6, + 0xB4, 0xBE, 0x03, 0xE6, 0xB5, 0xA9, 0x03, 0xE6, + 0xB5, 0xB8, 0x03, 0xE6, 0xB6, 0x85, 0x04, 0xF0, + 0xA3, 0xB4, 0x9E, 0x03, 0xE6, 0xB4, 0xB4, 0x03, + 0xE6, 0xB8, 0xAF, 0x03, 0xE6, 0xB9, 0xAE, 0x03, + // Bytes 40c0 - 40ff + 0xE3, 0xB4, 0xB3, 0x03, 0xE6, 0xBB, 0x87, 0x04, + 0xF0, 0xA3, 0xBB, 0x91, 0x03, 0xE6, 0xB7, 0xB9, + 0x03, 0xE6, 0xBD, 0xAE, 0x04, 0xF0, 0xA3, 0xBD, + 0x9E, 0x04, 0xF0, 0xA3, 0xBE, 0x8E, 0x03, 0xE6, + 0xBF, 0x86, 0x03, 0xE7, 0x80, 0xB9, 0x03, 0xE7, + 0x80, 0x9B, 0x03, 0xE3, 0xB6, 0x96, 0x03, 0xE7, + 0x81, 0x8A, 0x03, 0xE7, 0x81, 0xBD, 0x03, 0xE7, + 0x81, 0xB7, 0x03, 0xE7, 0x82, 0xAD, 0x04, 0xF0, + // Bytes 4100 - 413f + 0xA0, 0x94, 0xA5, 0x03, 0xE7, 0x85, 0x85, 0x04, + 0xF0, 0xA4, 0x89, 0xA3, 0x03, 0xE7, 0x86, 0x9C, + 0x04, 0xF0, 0xA4, 0x8E, 0xAB, 0x03, 0xE7, 0x88, + 0xA8, 0x03, 0xE7, 0x89, 0x90, 0x04, 0xF0, 0xA4, + 0x98, 0x88, 0x03, 0xE7, 0x8A, 0x80, 0x03, 0xE7, + 0x8A, 0x95, 0x04, 0xF0, 0xA4, 0x9C, 0xB5, 0x04, + 0xF0, 0xA4, 0xA0, 0x94, 0x03, 0xE7, 0x8D, 0xBA, + 0x03, 0xE7, 0x8E, 0x8B, 0x03, 0xE3, 0xBA, 0xAC, + // Bytes 4140 - 417f + 0x03, 0xE7, 0x8E, 0xA5, 0x03, 0xE3, 0xBA, 0xB8, + 0x03, 0xE7, 0x91, 0x87, 0x03, 0xE7, 0x91, 0x9C, + 0x03, 0xE7, 0x92, 0x85, 0x03, 0xE7, 0x93, 0x8A, + 0x03, 0xE3, 0xBC, 0x9B, 0x03, 0xE7, 0x94, 0xA4, + 0x04, 0xF0, 0xA4, 0xB0, 0xB6, 0x03, 0xE7, 0x94, + 0xBE, 0x04, 0xF0, 0xA4, 0xB2, 0x92, 0x04, 0xF0, + 0xA2, 0x86, 0x9F, 0x03, 0xE7, 0x98, 0x90, 0x04, + 0xF0, 0xA4, 0xBE, 0xA1, 0x04, 0xF0, 0xA4, 0xBE, + // Bytes 4180 - 41bf + 0xB8, 0x04, 0xF0, 0xA5, 0x81, 0x84, 0x03, 0xE3, + 0xBF, 0xBC, 0x03, 0xE4, 0x80, 0x88, 0x04, 0xF0, + 0xA5, 0x83, 0xB3, 0x04, 0xF0, 0xA5, 0x83, 0xB2, + 0x04, 0xF0, 0xA5, 0x84, 0x99, 0x04, 0xF0, 0xA5, + 0x84, 0xB3, 0x03, 0xE7, 0x9C, 0x9E, 0x03, 0xE7, + 0x9C, 0x9F, 0x03, 0xE7, 0x9E, 0x8B, 0x03, 0xE4, + 0x81, 0x86, 0x03, 0xE4, 0x82, 0x96, 0x04, 0xF0, + 0xA5, 0x90, 0x9D, 0x03, 0xE7, 0xA1, 0x8E, 0x03, + // Bytes 41c0 - 41ff + 0xE4, 0x83, 0xA3, 0x04, 0xF0, 0xA5, 0x98, 0xA6, + 0x04, 0xF0, 0xA5, 0x9A, 0x9A, 0x04, 0xF0, 0xA5, + 0x9B, 0x85, 0x03, 0xE7, 0xA7, 0xAB, 0x03, 0xE4, + 0x84, 0xAF, 0x03, 0xE7, 0xA9, 0x8A, 0x03, 0xE7, + 0xA9, 0x8F, 0x04, 0xF0, 0xA5, 0xA5, 0xBC, 0x04, + 0xF0, 0xA5, 0xAA, 0xA7, 0x03, 0xE7, 0xAB, 0xAE, + 0x03, 0xE4, 0x88, 0x82, 0x04, 0xF0, 0xA5, 0xAE, + 0xAB, 0x03, 0xE7, 0xAF, 0x86, 0x03, 0xE7, 0xAF, + // Bytes 4200 - 423f + 0x89, 0x03, 0xE4, 0x88, 0xA7, 0x04, 0xF0, 0xA5, + 0xB2, 0x80, 0x03, 0xE7, 0xB3, 0x92, 0x03, 0xE4, + 0x8A, 0xA0, 0x03, 0xE7, 0xB3, 0xA8, 0x03, 0xE7, + 0xB3, 0xA3, 0x03, 0xE7, 0xB4, 0x80, 0x04, 0xF0, + 0xA5, 0xBE, 0x86, 0x03, 0xE7, 0xB5, 0xA3, 0x03, + 0xE4, 0x8C, 0x81, 0x03, 0xE7, 0xB7, 0x87, 0x03, + 0xE7, 0xB8, 0x82, 0x03, 0xE7, 0xB9, 0x85, 0x03, + 0xE4, 0x8C, 0xB4, 0x04, 0xF0, 0xA6, 0x88, 0xA8, + // Bytes 4240 - 427f + 0x04, 0xF0, 0xA6, 0x89, 0x87, 0x03, 0xE4, 0x8D, + 0x99, 0x04, 0xF0, 0xA6, 0x8B, 0x99, 0x03, 0xE7, + 0xBD, 0xBA, 0x04, 0xF0, 0xA6, 0x8C, 0xBE, 0x03, + 0xE7, 0xBE, 0x95, 0x03, 0xE7, 0xBF, 0xBA, 0x04, + 0xF0, 0xA6, 0x93, 0x9A, 0x04, 0xF0, 0xA6, 0x94, + 0xA3, 0x03, 0xE8, 0x81, 0xA0, 0x04, 0xF0, 0xA6, + 0x96, 0xA8, 0x03, 0xE8, 0x81, 0xB0, 0x04, 0xF0, + 0xA3, 0x8D, 0x9F, 0x03, 0xE4, 0x8F, 0x95, 0x03, + // Bytes 4280 - 42bf + 0xE8, 0x82, 0xB2, 0x03, 0xE8, 0x84, 0x83, 0x03, + 0xE4, 0x90, 0x8B, 0x03, 0xE8, 0x84, 0xBE, 0x03, + 0xE5, 0xAA, 0xB5, 0x04, 0xF0, 0xA6, 0x9E, 0xA7, + 0x04, 0xF0, 0xA6, 0x9E, 0xB5, 0x04, 0xF0, 0xA3, + 0x8E, 0x93, 0x04, 0xF0, 0xA3, 0x8E, 0x9C, 0x03, + 0xE8, 0x88, 0x84, 0x03, 0xE8, 0xBE, 0x9E, 0x03, + 0xE4, 0x91, 0xAB, 0x03, 0xE8, 0x8A, 0x91, 0x03, + 0xE8, 0x8A, 0x8B, 0x03, 0xE8, 0x8A, 0x9D, 0x03, + // Bytes 42c0 - 42ff + 0xE5, 0x8A, 0xB3, 0x03, 0xE8, 0x8A, 0xB1, 0x03, + 0xE8, 0x8A, 0xB3, 0x03, 0xE8, 0x8A, 0xBD, 0x03, + 0xE8, 0x8B, 0xA6, 0x04, 0xF0, 0xA6, 0xAC, 0xBC, + 0x03, 0xE8, 0x8C, 0x9D, 0x03, 0xE8, 0x8D, 0xA3, + 0x03, 0xE8, 0x8E, 0xAD, 0x03, 0xE8, 0x8C, 0xA3, + 0x03, 0xE8, 0x8E, 0xBD, 0x03, 0xE8, 0x8F, 0xA7, + 0x03, 0xE8, 0x8D, 0x93, 0x03, 0xE8, 0x8F, 0x8A, + 0x03, 0xE8, 0x8F, 0x8C, 0x03, 0xE8, 0x8F, 0x9C, + // Bytes 4300 - 433f + 0x04, 0xF0, 0xA6, 0xB0, 0xB6, 0x04, 0xF0, 0xA6, + 0xB5, 0xAB, 0x04, 0xF0, 0xA6, 0xB3, 0x95, 0x03, + 0xE4, 0x94, 0xAB, 0x03, 0xE8, 0x93, 0xB1, 0x03, + 0xE8, 0x93, 0xB3, 0x03, 0xE8, 0x94, 0x96, 0x04, + 0xF0, 0xA7, 0x8F, 0x8A, 0x03, 0xE8, 0x95, 0xA4, + 0x04, 0xF0, 0xA6, 0xBC, 0xAC, 0x03, 0xE4, 0x95, + 0x9D, 0x03, 0xE4, 0x95, 0xA1, 0x04, 0xF0, 0xA6, + 0xBE, 0xB1, 0x04, 0xF0, 0xA7, 0x83, 0x92, 0x03, + // Bytes 4340 - 437f + 0xE4, 0x95, 0xAB, 0x03, 0xE8, 0x99, 0x90, 0x03, + 0xE8, 0x99, 0xA7, 0x03, 0xE8, 0x99, 0xA9, 0x03, + 0xE8, 0x9A, 0xA9, 0x03, 0xE8, 0x9A, 0x88, 0x03, + 0xE8, 0x9C, 0x8E, 0x03, 0xE8, 0x9B, 0xA2, 0x03, + 0xE8, 0x9C, 0xA8, 0x03, 0xE8, 0x9D, 0xAB, 0x03, + 0xE8, 0x9E, 0x86, 0x03, 0xE4, 0x97, 0x97, 0x03, + 0xE8, 0x9F, 0xA1, 0x03, 0xE8, 0xA0, 0x81, 0x03, + 0xE4, 0x97, 0xB9, 0x03, 0xE8, 0xA1, 0xA0, 0x04, + // Bytes 4380 - 43bf + 0xF0, 0xA7, 0x99, 0xA7, 0x03, 0xE8, 0xA3, 0x97, + 0x03, 0xE8, 0xA3, 0x9E, 0x03, 0xE4, 0x98, 0xB5, + 0x03, 0xE8, 0xA3, 0xBA, 0x03, 0xE3, 0x92, 0xBB, + 0x04, 0xF0, 0xA7, 0xA2, 0xAE, 0x04, 0xF0, 0xA7, + 0xA5, 0xA6, 0x03, 0xE4, 0x9A, 0xBE, 0x03, 0xE4, + 0x9B, 0x87, 0x03, 0xE8, 0xAA, 0xA0, 0x04, 0xF0, + 0xA7, 0xB2, 0xA8, 0x03, 0xE8, 0xB2, 0xAB, 0x03, + 0xE8, 0xB3, 0x81, 0x03, 0xE8, 0xB4, 0x9B, 0x03, + // Bytes 43c0 - 43ff + 0xE8, 0xB5, 0xB7, 0x04, 0xF0, 0xA7, 0xBC, 0xAF, + 0x04, 0xF0, 0xA0, 0xA0, 0x84, 0x03, 0xE8, 0xB7, + 0x8B, 0x03, 0xE8, 0xB6, 0xBC, 0x03, 0xE8, 0xB7, + 0xB0, 0x04, 0xF0, 0xA0, 0xA3, 0x9E, 0x03, 0xE8, + 0xBB, 0x94, 0x04, 0xF0, 0xA8, 0x97, 0x92, 0x04, + 0xF0, 0xA8, 0x97, 0xAD, 0x03, 0xE9, 0x82, 0x94, + 0x03, 0xE9, 0x83, 0xB1, 0x03, 0xE9, 0x84, 0x91, + 0x04, 0xF0, 0xA8, 0x9C, 0xAE, 0x03, 0xE9, 0x84, + // Bytes 4400 - 443f + 0x9B, 0x03, 0xE9, 0x88, 0xB8, 0x03, 0xE9, 0x8B, + 0x97, 0x03, 0xE9, 0x8B, 0x98, 0x03, 0xE9, 0x89, + 0xBC, 0x03, 0xE9, 0x8F, 0xB9, 0x03, 0xE9, 0x90, + 0x95, 0x04, 0xF0, 0xA8, 0xAF, 0xBA, 0x03, 0xE9, + 0x96, 0x8B, 0x03, 0xE4, 0xA6, 0x95, 0x03, 0xE9, + 0x96, 0xB7, 0x04, 0xF0, 0xA8, 0xB5, 0xB7, 0x03, + 0xE4, 0xA7, 0xA6, 0x03, 0xE9, 0x9B, 0x83, 0x03, + 0xE5, 0xB6, 0xB2, 0x03, 0xE9, 0x9C, 0xA3, 0x04, + // Bytes 4440 - 447f + 0xF0, 0xA9, 0x85, 0x85, 0x04, 0xF0, 0xA9, 0x88, + 0x9A, 0x03, 0xE4, 0xA9, 0xAE, 0x03, 0xE4, 0xA9, + 0xB6, 0x03, 0xE9, 0x9F, 0xA0, 0x04, 0xF0, 0xA9, + 0x90, 0x8A, 0x03, 0xE4, 0xAA, 0xB2, 0x04, 0xF0, + 0xA9, 0x92, 0x96, 0x03, 0xE9, 0xA0, 0xA9, 0x04, + 0xF0, 0xA9, 0x96, 0xB6, 0x03, 0xE9, 0xA3, 0xA2, + 0x03, 0xE4, 0xAC, 0xB3, 0x03, 0xE9, 0xA4, 0xA9, + 0x03, 0xE9, 0xA6, 0xA7, 0x03, 0xE9, 0xA7, 0x82, + // Bytes 4480 - 44bf + 0x03, 0xE9, 0xA7, 0xBE, 0x03, 0xE4, 0xAF, 0x8E, + 0x04, 0xF0, 0xA9, 0xAC, 0xB0, 0x03, 0xE9, 0xB1, + 0x80, 0x03, 0xE9, 0xB3, 0xBD, 0x03, 0xE4, 0xB3, + 0x8E, 0x03, 0xE4, 0xB3, 0xAD, 0x03, 0xE9, 0xB5, + 0xA7, 0x04, 0xF0, 0xAA, 0x83, 0x8E, 0x03, 0xE4, + 0xB3, 0xB8, 0x04, 0xF0, 0xAA, 0x84, 0x85, 0x04, + 0xF0, 0xAA, 0x88, 0x8E, 0x04, 0xF0, 0xAA, 0x8A, + 0x91, 0x03, 0xE4, 0xB5, 0x96, 0x03, 0xE9, 0xBB, + // Bytes 44c0 - 44ff + 0xBE, 0x03, 0xE9, 0xBC, 0x85, 0x03, 0xE9, 0xBC, + 0x8F, 0x03, 0xE9, 0xBC, 0x96, 0x04, 0xF0, 0xAA, + 0x98, 0x80, +} + +// nfcDecompValues: 4992 entries, 9984 bytes +// Block 2 is the null block. +var nfcDecompValues = [4992]uint16{ + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0x00c0: 0x0032, 0x00c1: 0x0036, 0x00c2: 0x003a, 0x00c3: 0x003e, 0x00c4: 0x0042, 0x00c5: 0x0046, + 0x00c7: 0x004a, 0x00c8: 0x004e, 0x00c9: 0x0052, 0x00ca: 0x0056, 0x00cb: 0x005a, + 0x00cc: 0x005e, 0x00cd: 0x0062, 0x00ce: 0x0066, 0x00cf: 0x006a, 0x00d1: 0x006e, + 0x00d2: 0x0072, 0x00d3: 0x0076, 0x00d4: 0x007a, 0x00d5: 0x007e, 0x00d6: 0x0082, + 0x00d9: 0x0086, 0x00da: 0x008a, 0x00db: 0x008e, 0x00dc: 0x0092, 0x00dd: 0x0096, + 0x00e0: 0x009a, 0x00e1: 0x009e, 0x00e2: 0x00a2, 0x00e3: 0x00a6, + 0x00e4: 0x00aa, 0x00e5: 0x00ae, 0x00e7: 0x00b2, 0x00e8: 0x00b6, 0x00e9: 0x00ba, + 0x00ea: 0x00be, 0x00eb: 0x00c2, 0x00ec: 0x00c6, 0x00ed: 0x00ca, 0x00ee: 0x00ce, 0x00ef: 0x00d2, + 0x00f1: 0x00d6, 0x00f2: 0x00da, 0x00f3: 0x00de, 0x00f4: 0x00e2, 0x00f5: 0x00e6, + 0x00f6: 0x00ea, 0x00f9: 0x00ee, 0x00fa: 0x00f2, 0x00fb: 0x00f6, + 0x00fc: 0x00fa, 0x00fd: 0x00fe, 0x00ff: 0x0102, + // Block 0x4, offset 0x100 + 0x0100: 0x0106, 0x0101: 0x010a, 0x0102: 0x010e, 0x0103: 0x0112, 0x0104: 0x0116, 0x0105: 0x011a, + 0x0106: 0x011e, 0x0107: 0x0122, 0x0108: 0x0126, 0x0109: 0x012a, 0x010a: 0x012e, 0x010b: 0x0132, + 0x010c: 0x0136, 0x010d: 0x013a, 0x010e: 0x013e, 0x010f: 0x0142, + 0x0112: 0x0146, 0x0113: 0x014a, 0x0114: 0x014e, 0x0115: 0x0152, 0x0116: 0x0156, 0x0117: 0x015a, + 0x0118: 0x015e, 0x0119: 0x0162, 0x011a: 0x0166, 0x011b: 0x016a, 0x011c: 0x016e, 0x011d: 0x0172, + 0x011e: 0x0176, 0x011f: 0x017a, 0x0120: 0x017e, 0x0121: 0x0182, 0x0122: 0x0186, 0x0123: 0x018a, + 0x0124: 0x018e, 0x0125: 0x0192, 0x0128: 0x0196, 0x0129: 0x019a, + 0x012a: 0x019e, 0x012b: 0x01a2, 0x012c: 0x01a6, 0x012d: 0x01aa, 0x012e: 0x01ae, 0x012f: 0x01b2, + 0x0130: 0x01b6, 0x0134: 0x01c0, 0x0135: 0x01c4, + 0x0136: 0x01c8, 0x0137: 0x01cc, 0x0139: 0x01d0, 0x013a: 0x01d4, 0x013b: 0x01d8, + 0x013c: 0x01dc, 0x013d: 0x01e0, 0x013e: 0x01e4, + // Block 0x5, offset 0x140 + 0x0143: 0x01f0, 0x0144: 0x01f4, 0x0145: 0x01f8, + 0x0146: 0x01fc, 0x0147: 0x0200, 0x0148: 0x0204, + 0x014c: 0x020c, 0x014d: 0x0210, 0x014e: 0x0214, 0x014f: 0x0218, 0x0150: 0x021c, 0x0151: 0x0220, + 0x0154: 0x0224, 0x0155: 0x0228, 0x0156: 0x022c, 0x0157: 0x0230, + 0x0158: 0x0234, 0x0159: 0x0238, 0x015a: 0x023c, 0x015b: 0x0240, 0x015c: 0x0244, 0x015d: 0x0248, + 0x015e: 0x024c, 0x015f: 0x0250, 0x0160: 0x0254, 0x0161: 0x0258, 0x0162: 0x025c, 0x0163: 0x0260, + 0x0164: 0x0264, 0x0165: 0x0268, 0x0168: 0x026c, 0x0169: 0x0270, + 0x016a: 0x0274, 0x016b: 0x0278, 0x016c: 0x027c, 0x016d: 0x0280, 0x016e: 0x0284, 0x016f: 0x0288, + 0x0170: 0x028c, 0x0171: 0x0290, 0x0172: 0x0294, 0x0173: 0x0298, 0x0174: 0x029c, 0x0175: 0x02a0, + 0x0176: 0x02a4, 0x0177: 0x02a8, 0x0178: 0x02ac, 0x0179: 0x02b0, 0x017a: 0x02b4, 0x017b: 0x02b8, + 0x017c: 0x02bc, 0x017d: 0x02c0, 0x017e: 0x02c4, + // Block 0x6, offset 0x180 + 0x01a0: 0x02ca, 0x01a1: 0x02ce, + 0x01af: 0x02d2, + 0x01b0: 0x02d6, + // Block 0x7, offset 0x1c0 + 0x01cd: 0x02fb, 0x01ce: 0x02ff, 0x01cf: 0x0303, 0x01d0: 0x0307, 0x01d1: 0x030b, + 0x01d2: 0x030f, 0x01d3: 0x0313, 0x01d4: 0x0317, 0x01d5: 0x031b, 0x01d6: 0x0321, 0x01d7: 0x0327, + 0x01d8: 0x032d, 0x01d9: 0x0333, 0x01da: 0x0339, 0x01db: 0x033f, 0x01dc: 0x0345, + 0x01de: 0x034b, 0x01df: 0x0351, 0x01e0: 0x0357, 0x01e1: 0x035d, 0x01e2: 0x0363, 0x01e3: 0x0368, + 0x01e6: 0x036d, 0x01e7: 0x0371, 0x01e8: 0x0375, 0x01e9: 0x0379, + 0x01ea: 0x037d, 0x01eb: 0x0381, 0x01ec: 0x0385, 0x01ed: 0x038b, 0x01ee: 0x0391, 0x01ef: 0x0396, + 0x01f0: 0x039b, 0x01f4: 0x03a8, 0x01f5: 0x03ac, + 0x01f8: 0x03b0, 0x01f9: 0x03b4, 0x01fa: 0x03b8, 0x01fb: 0x03be, + 0x01fc: 0x03c4, 0x01fd: 0x03c9, 0x01fe: 0x03ce, 0x01ff: 0x03d3, + // Block 0x8, offset 0x200 + 0x0200: 0x03d8, 0x0201: 0x03dc, 0x0202: 0x03e0, 0x0203: 0x03e4, 0x0204: 0x03e8, 0x0205: 0x03ec, + 0x0206: 0x03f0, 0x0207: 0x03f4, 0x0208: 0x03f8, 0x0209: 0x03fc, 0x020a: 0x0400, 0x020b: 0x0404, + 0x020c: 0x0408, 0x020d: 0x040c, 0x020e: 0x0410, 0x020f: 0x0414, 0x0210: 0x0418, 0x0211: 0x041c, + 0x0212: 0x0420, 0x0213: 0x0424, 0x0214: 0x0428, 0x0215: 0x042c, 0x0216: 0x0430, 0x0217: 0x0434, + 0x0218: 0x0438, 0x0219: 0x043c, 0x021a: 0x0440, 0x021b: 0x0444, + 0x021e: 0x0448, 0x021f: 0x044c, + 0x0226: 0x0450, 0x0227: 0x0454, 0x0228: 0x0458, 0x0229: 0x045c, + 0x022a: 0x0460, 0x022b: 0x0466, 0x022c: 0x046c, 0x022d: 0x0472, 0x022e: 0x0478, 0x022f: 0x047c, + 0x0230: 0x0480, 0x0231: 0x0486, 0x0232: 0x048c, 0x0233: 0x0490, + // Block 0x9, offset 0x240 + 0x0240: 0x04cc, 0x0241: 0x04cf, 0x0243: 0x04d2, 0x0244: 0x04d5, + 0x0274: 0x04da, + 0x027e: 0x04e1, + // Block 0xa, offset 0x280 + 0x0285: 0x04e3, + 0x0286: 0x04ee, 0x0287: 0x04f3, 0x0288: 0x04f6, 0x0289: 0x04fb, 0x028a: 0x0500, + 0x028c: 0x0505, 0x028e: 0x050a, 0x028f: 0x050f, 0x0290: 0x0514, + 0x02aa: 0x051b, 0x02ab: 0x0520, 0x02ac: 0x0525, 0x02ad: 0x052a, 0x02ae: 0x052f, 0x02af: 0x0534, + 0x02b0: 0x0539, + // Block 0xb, offset 0x2c0 + 0x02ca: 0x0540, 0x02cb: 0x0545, + 0x02cc: 0x054a, 0x02cd: 0x054f, 0x02ce: 0x0554, + 0x02d3: 0x0562, 0x02d4: 0x0567, + // Block 0xc, offset 0x300 + 0x0300: 0x0584, 0x0301: 0x0589, 0x0303: 0x058e, + 0x0307: 0x0593, + 0x030c: 0x0598, 0x030d: 0x059d, 0x030e: 0x05a2, + 0x0319: 0x05a7, + 0x0339: 0x05ac, + // Block 0xd, offset 0x340 + 0x0350: 0x05b1, 0x0351: 0x05b6, + 0x0353: 0x05bb, 0x0357: 0x05c0, + 0x035c: 0x05c5, 0x035d: 0x05ca, + 0x035e: 0x05cf, + 0x0376: 0x05d4, 0x0377: 0x05d9, + // Block 0xe, offset 0x380 + 0x0381: 0x05de, 0x0382: 0x05e3, + 0x0390: 0x05e8, 0x0391: 0x05ed, + 0x0392: 0x05f2, 0x0393: 0x05f7, 0x0396: 0x05fc, 0x0397: 0x0601, + 0x039a: 0x0606, 0x039b: 0x060b, 0x039c: 0x0610, 0x039d: 0x0615, + 0x039e: 0x061a, 0x039f: 0x061f, 0x03a2: 0x0624, 0x03a3: 0x0629, + 0x03a4: 0x062e, 0x03a5: 0x0633, 0x03a6: 0x0638, 0x03a7: 0x063d, + 0x03aa: 0x0642, 0x03ab: 0x0647, 0x03ac: 0x064c, 0x03ad: 0x0651, 0x03ae: 0x0656, 0x03af: 0x065b, + 0x03b0: 0x0660, 0x03b1: 0x0665, 0x03b2: 0x066a, 0x03b3: 0x066f, 0x03b4: 0x0674, 0x03b5: 0x0679, + 0x03b8: 0x067e, 0x03b9: 0x0683, + // Block 0xf, offset 0x3c0 + 0x03e2: 0x068d, 0x03e3: 0x0692, + 0x03e4: 0x0697, 0x03e5: 0x069c, 0x03e6: 0x06a1, + // Block 0x10, offset 0x400 + 0x0400: 0x06ba, 0x0402: 0x06bf, + 0x0413: 0x06c4, + // Block 0x11, offset 0x440 + 0x0469: 0x06c9, + 0x0471: 0x06d0, 0x0474: 0x06d7, + // Block 0x12, offset 0x480 + 0x0498: 0x06de, 0x0499: 0x06e5, 0x049a: 0x06ec, 0x049b: 0x06f3, 0x049c: 0x06fa, 0x049d: 0x0701, + 0x049e: 0x0708, 0x049f: 0x070f, + // Block 0x13, offset 0x4c0 + 0x04cb: 0x0716, + 0x04cc: 0x071d, + 0x04dc: 0x0724, 0x04dd: 0x072b, + 0x04df: 0x0732, + // Block 0x14, offset 0x500 + 0x0533: 0x0739, + 0x0536: 0x0740, + // Block 0x15, offset 0x540 + 0x0559: 0x0747, 0x055a: 0x074e, 0x055b: 0x0755, + 0x055e: 0x075c, + // Block 0x16, offset 0x580 + 0x0588: 0x0763, 0x058b: 0x076a, + 0x058c: 0x0771, + 0x059c: 0x0778, 0x059d: 0x077f, + // Block 0x17, offset 0x5c0 + 0x05d4: 0x0786, + // Block 0x18, offset 0x600 + 0x060a: 0x078d, 0x060b: 0x0794, + 0x060c: 0x079b, + // Block 0x19, offset 0x640 + 0x0648: 0x07a2, + // Block 0x1a, offset 0x680 + 0x0680: 0x07a9, + 0x0687: 0x07b0, 0x0688: 0x07b7, 0x068a: 0x07be, 0x068b: 0x07c5, + // Block 0x1b, offset 0x6c0 + 0x06ca: 0x07cf, 0x06cb: 0x07d6, + 0x06cc: 0x07dd, + // Block 0x1c, offset 0x700 + 0x071a: 0x07e4, 0x071c: 0x07eb, 0x071d: 0x07f2, + 0x071e: 0x07fc, + // Block 0x1d, offset 0x740 + 0x0743: 0x0823, + 0x074d: 0x082a, + 0x0752: 0x0831, 0x0757: 0x0838, + 0x075c: 0x083f, + 0x0769: 0x0846, + 0x0773: 0x084d, 0x0775: 0x0854, + 0x0776: 0x085b, 0x0778: 0x086c, + // Block 0x1e, offset 0x780 + 0x0781: 0x087d, + 0x0793: 0x0884, + 0x079d: 0x088b, + 0x07a2: 0x0892, + 0x07a7: 0x0899, + 0x07ac: 0x08a0, + 0x07b9: 0x08a7, + // Block 0x1f, offset 0x7c0 + 0x07e6: 0x08ae, + // Block 0x20, offset 0x800 + 0x0806: 0x08b9, 0x0808: 0x08c0, 0x080a: 0x08c7, + 0x080c: 0x08ce, 0x080e: 0x08d5, + 0x0812: 0x08dc, + 0x083b: 0x08e3, + 0x083d: 0x08ea, + // Block 0x21, offset 0x840 + 0x0840: 0x08f1, 0x0841: 0x08f8, 0x0843: 0x08ff, + // Block 0x22, offset 0x880 + 0x0880: 0x09ea, 0x0881: 0x09ee, 0x0882: 0x09f2, 0x0883: 0x09f6, 0x0884: 0x09fa, 0x0885: 0x09fe, + 0x0886: 0x0a02, 0x0887: 0x0a06, 0x0888: 0x0a0a, 0x0889: 0x0a10, 0x088a: 0x0a16, 0x088b: 0x0a1a, + 0x088c: 0x0a1e, 0x088d: 0x0a22, 0x088e: 0x0a26, 0x088f: 0x0a2a, 0x0890: 0x0a2e, 0x0891: 0x0a32, + 0x0892: 0x0a36, 0x0893: 0x0a3a, 0x0894: 0x0a3e, 0x0895: 0x0a44, 0x0896: 0x0a4a, 0x0897: 0x0a50, + 0x0898: 0x0a56, 0x0899: 0x0a5a, 0x089a: 0x0a5e, 0x089b: 0x0a62, 0x089c: 0x0a66, 0x089d: 0x0a6c, + 0x089e: 0x0a72, 0x089f: 0x0a76, 0x08a0: 0x0a7a, 0x08a1: 0x0a7e, 0x08a2: 0x0a82, 0x08a3: 0x0a86, + 0x08a4: 0x0a8a, 0x08a5: 0x0a8e, 0x08a6: 0x0a92, 0x08a7: 0x0a96, 0x08a8: 0x0a9a, 0x08a9: 0x0a9e, + 0x08aa: 0x0aa2, 0x08ab: 0x0aa6, 0x08ac: 0x0aaa, 0x08ad: 0x0aae, 0x08ae: 0x0ab2, 0x08af: 0x0ab8, + 0x08b0: 0x0abe, 0x08b1: 0x0ac2, 0x08b2: 0x0ac6, 0x08b3: 0x0aca, 0x08b4: 0x0ace, 0x08b5: 0x0ad2, + 0x08b6: 0x0ad6, 0x08b7: 0x0ada, 0x08b8: 0x0ade, 0x08b9: 0x0ae4, 0x08ba: 0x0aea, 0x08bb: 0x0aee, + 0x08bc: 0x0af2, 0x08bd: 0x0af6, 0x08be: 0x0afa, 0x08bf: 0x0afe, + // Block 0x23, offset 0x8c0 + 0x08c0: 0x0b02, 0x08c1: 0x0b06, 0x08c2: 0x0b0a, 0x08c3: 0x0b0e, 0x08c4: 0x0b12, 0x08c5: 0x0b16, + 0x08c6: 0x0b1a, 0x08c7: 0x0b1e, 0x08c8: 0x0b22, 0x08c9: 0x0b26, 0x08ca: 0x0b2a, 0x08cb: 0x0b2e, + 0x08cc: 0x0b32, 0x08cd: 0x0b38, 0x08ce: 0x0b3e, 0x08cf: 0x0b44, 0x08d0: 0x0b4a, 0x08d1: 0x0b50, + 0x08d2: 0x0b56, 0x08d3: 0x0b5c, 0x08d4: 0x0b62, 0x08d5: 0x0b66, 0x08d6: 0x0b6a, 0x08d7: 0x0b6e, + 0x08d8: 0x0b72, 0x08d9: 0x0b76, 0x08da: 0x0b7a, 0x08db: 0x0b7e, 0x08dc: 0x0b82, 0x08dd: 0x0b88, + 0x08de: 0x0b8e, 0x08df: 0x0b92, 0x08e0: 0x0b96, 0x08e1: 0x0b9a, 0x08e2: 0x0b9e, 0x08e3: 0x0ba2, + 0x08e4: 0x0ba6, 0x08e5: 0x0bac, 0x08e6: 0x0bb2, 0x08e7: 0x0bb8, 0x08e8: 0x0bbe, 0x08e9: 0x0bc4, + 0x08ea: 0x0bca, 0x08eb: 0x0bce, 0x08ec: 0x0bd2, 0x08ed: 0x0bd6, 0x08ee: 0x0bda, 0x08ef: 0x0bde, + 0x08f0: 0x0be2, 0x08f1: 0x0be6, 0x08f2: 0x0bea, 0x08f3: 0x0bee, 0x08f4: 0x0bf2, 0x08f5: 0x0bf6, + 0x08f6: 0x0bfa, 0x08f7: 0x0bfe, 0x08f8: 0x0c02, 0x08f9: 0x0c08, 0x08fa: 0x0c0e, 0x08fb: 0x0c14, + 0x08fc: 0x0c1a, 0x08fd: 0x0c1e, 0x08fe: 0x0c22, 0x08ff: 0x0c26, + // Block 0x24, offset 0x900 + 0x0900: 0x0c2a, 0x0901: 0x0c2e, 0x0902: 0x0c32, 0x0903: 0x0c36, 0x0904: 0x0c3a, 0x0905: 0x0c3e, + 0x0906: 0x0c42, 0x0907: 0x0c46, 0x0908: 0x0c4a, 0x0909: 0x0c4e, 0x090a: 0x0c52, 0x090b: 0x0c56, + 0x090c: 0x0c5a, 0x090d: 0x0c5e, 0x090e: 0x0c62, 0x090f: 0x0c66, 0x0910: 0x0c6a, 0x0911: 0x0c6e, + 0x0912: 0x0c72, 0x0913: 0x0c76, 0x0914: 0x0c7a, 0x0915: 0x0c7e, 0x0916: 0x0c82, 0x0917: 0x0c86, + 0x0918: 0x0c8a, 0x0919: 0x0c8e, 0x091b: 0x0c96, + 0x0920: 0x0c9b, 0x0921: 0x0c9f, 0x0922: 0x0ca3, 0x0923: 0x0ca7, + 0x0924: 0x0cab, 0x0925: 0x0cb1, 0x0926: 0x0cb7, 0x0927: 0x0cbd, 0x0928: 0x0cc3, 0x0929: 0x0cc9, + 0x092a: 0x0ccf, 0x092b: 0x0cd5, 0x092c: 0x0cdb, 0x092d: 0x0ce1, 0x092e: 0x0ce7, 0x092f: 0x0ced, + 0x0930: 0x0cf3, 0x0931: 0x0cf9, 0x0932: 0x0cff, 0x0933: 0x0d05, 0x0934: 0x0d0b, 0x0935: 0x0d11, + 0x0936: 0x0d17, 0x0937: 0x0d1d, 0x0938: 0x0d23, 0x0939: 0x0d27, 0x093a: 0x0d2b, 0x093b: 0x0d2f, + 0x093c: 0x0d33, 0x093d: 0x0d37, 0x093e: 0x0d3b, 0x093f: 0x0d41, + // Block 0x25, offset 0x940 + 0x0940: 0x0d47, 0x0941: 0x0d4d, 0x0942: 0x0d53, 0x0943: 0x0d59, 0x0944: 0x0d5f, 0x0945: 0x0d65, + 0x0946: 0x0d6b, 0x0947: 0x0d71, 0x0948: 0x0d77, 0x0949: 0x0d7b, 0x094a: 0x0d7f, 0x094b: 0x0d83, + 0x094c: 0x0d87, 0x094d: 0x0d8b, 0x094e: 0x0d8f, 0x094f: 0x0d93, 0x0950: 0x0d97, 0x0951: 0x0d9d, + 0x0952: 0x0da3, 0x0953: 0x0da9, 0x0954: 0x0daf, 0x0955: 0x0db5, 0x0956: 0x0dbb, 0x0957: 0x0dc1, + 0x0958: 0x0dc7, 0x0959: 0x0dcd, 0x095a: 0x0dd3, 0x095b: 0x0dd9, 0x095c: 0x0ddf, 0x095d: 0x0de5, + 0x095e: 0x0deb, 0x095f: 0x0df1, 0x0960: 0x0df7, 0x0961: 0x0dfd, 0x0962: 0x0e03, 0x0963: 0x0e09, + 0x0964: 0x0e0f, 0x0965: 0x0e13, 0x0966: 0x0e17, 0x0967: 0x0e1b, 0x0968: 0x0e1f, 0x0969: 0x0e25, + 0x096a: 0x0e2b, 0x096b: 0x0e31, 0x096c: 0x0e37, 0x096d: 0x0e3d, 0x096e: 0x0e43, 0x096f: 0x0e49, + 0x0970: 0x0e4f, 0x0971: 0x0e55, 0x0972: 0x0e5b, 0x0973: 0x0e5f, 0x0974: 0x0e63, 0x0975: 0x0e67, + 0x0976: 0x0e6b, 0x0977: 0x0e6f, 0x0978: 0x0e73, 0x0979: 0x0e77, + // Block 0x26, offset 0x980 + 0x0980: 0x0e7b, 0x0981: 0x0e80, 0x0982: 0x0e85, 0x0983: 0x0e8c, 0x0984: 0x0e93, 0x0985: 0x0e9a, + 0x0986: 0x0ea1, 0x0987: 0x0ea8, 0x0988: 0x0eaf, 0x0989: 0x0eb4, 0x098a: 0x0eb9, 0x098b: 0x0ec0, + 0x098c: 0x0ec7, 0x098d: 0x0ece, 0x098e: 0x0ed5, 0x098f: 0x0edc, 0x0990: 0x0ee3, 0x0991: 0x0ee8, + 0x0992: 0x0eed, 0x0993: 0x0ef4, 0x0994: 0x0efb, 0x0995: 0x0f02, + 0x0998: 0x0f09, 0x0999: 0x0f0e, 0x099a: 0x0f13, 0x099b: 0x0f1a, 0x099c: 0x0f21, 0x099d: 0x0f28, + 0x09a0: 0x0f2f, 0x09a1: 0x0f34, 0x09a2: 0x0f39, 0x09a3: 0x0f40, + 0x09a4: 0x0f47, 0x09a5: 0x0f4e, 0x09a6: 0x0f55, 0x09a7: 0x0f5c, 0x09a8: 0x0f63, 0x09a9: 0x0f68, + 0x09aa: 0x0f6d, 0x09ab: 0x0f74, 0x09ac: 0x0f7b, 0x09ad: 0x0f82, 0x09ae: 0x0f89, 0x09af: 0x0f90, + 0x09b0: 0x0f97, 0x09b1: 0x0f9c, 0x09b2: 0x0fa1, 0x09b3: 0x0fa8, 0x09b4: 0x0faf, 0x09b5: 0x0fb6, + 0x09b6: 0x0fbd, 0x09b7: 0x0fc4, 0x09b8: 0x0fcb, 0x09b9: 0x0fd0, 0x09ba: 0x0fd5, 0x09bb: 0x0fdc, + 0x09bc: 0x0fe3, 0x09bd: 0x0fea, 0x09be: 0x0ff1, 0x09bf: 0x0ff8, + // Block 0x27, offset 0x9c0 + 0x09c0: 0x0fff, 0x09c1: 0x1004, 0x09c2: 0x1009, 0x09c3: 0x1010, 0x09c4: 0x1017, 0x09c5: 0x101e, + 0x09c8: 0x1025, 0x09c9: 0x102a, 0x09ca: 0x102f, 0x09cb: 0x1036, + 0x09cc: 0x103d, 0x09cd: 0x1044, 0x09d0: 0x104b, 0x09d1: 0x1050, + 0x09d2: 0x1055, 0x09d3: 0x105c, 0x09d4: 0x1063, 0x09d5: 0x106a, 0x09d6: 0x1071, 0x09d7: 0x1078, + 0x09d9: 0x107f, 0x09db: 0x1084, 0x09dd: 0x108b, + 0x09df: 0x1092, 0x09e0: 0x1099, 0x09e1: 0x109e, 0x09e2: 0x10a3, 0x09e3: 0x10aa, + 0x09e4: 0x10b1, 0x09e5: 0x10b8, 0x09e6: 0x10bf, 0x09e7: 0x10c6, 0x09e8: 0x10cd, 0x09e9: 0x10d2, + 0x09ea: 0x10d7, 0x09eb: 0x10de, 0x09ec: 0x10e5, 0x09ed: 0x10ec, 0x09ee: 0x10f3, 0x09ef: 0x10fa, + 0x09f0: 0x1101, 0x09f1: 0x0525, 0x09f2: 0x1106, 0x09f3: 0x052a, 0x09f4: 0x110b, 0x09f5: 0x052f, + 0x09f6: 0x1110, 0x09f7: 0x0534, 0x09f8: 0x1115, 0x09f9: 0x054a, 0x09fa: 0x111a, 0x09fb: 0x054f, + 0x09fc: 0x111f, 0x09fd: 0x0554, + // Block 0x28, offset 0xa00 + 0x0a00: 0x1124, 0x0a01: 0x112b, 0x0a02: 0x1132, 0x0a03: 0x113b, 0x0a04: 0x1144, 0x0a05: 0x114d, + 0x0a06: 0x1156, 0x0a07: 0x115f, 0x0a08: 0x1168, 0x0a09: 0x116f, 0x0a0a: 0x1176, 0x0a0b: 0x117f, + 0x0a0c: 0x1188, 0x0a0d: 0x1191, 0x0a0e: 0x119a, 0x0a0f: 0x11a3, 0x0a10: 0x11ac, 0x0a11: 0x11b3, + 0x0a12: 0x11ba, 0x0a13: 0x11c3, 0x0a14: 0x11cc, 0x0a15: 0x11d5, 0x0a16: 0x11de, 0x0a17: 0x11e7, + 0x0a18: 0x11f0, 0x0a19: 0x11f7, 0x0a1a: 0x11fe, 0x0a1b: 0x1207, 0x0a1c: 0x1210, 0x0a1d: 0x1219, + 0x0a1e: 0x1222, 0x0a1f: 0x122b, 0x0a20: 0x1234, 0x0a21: 0x123b, 0x0a22: 0x1242, 0x0a23: 0x124b, + 0x0a24: 0x1254, 0x0a25: 0x125d, 0x0a26: 0x1266, 0x0a27: 0x126f, 0x0a28: 0x1278, 0x0a29: 0x127f, + 0x0a2a: 0x1286, 0x0a2b: 0x128f, 0x0a2c: 0x1298, 0x0a2d: 0x12a1, 0x0a2e: 0x12aa, 0x0a2f: 0x12b3, + 0x0a30: 0x12bc, 0x0a31: 0x12c1, 0x0a32: 0x12c6, 0x0a33: 0x12cd, 0x0a34: 0x12d2, + 0x0a36: 0x12d9, 0x0a37: 0x12de, 0x0a38: 0x12e5, 0x0a39: 0x12ea, 0x0a3a: 0x12ef, 0x0a3b: 0x04ee, + 0x0a3c: 0x12f4, 0x0a3e: 0x12fd, + // Block 0x29, offset 0xa40 + 0x0a41: 0x1304, 0x0a42: 0x130f, 0x0a43: 0x1316, 0x0a44: 0x131b, + 0x0a46: 0x1322, 0x0a47: 0x1327, 0x0a48: 0x132e, 0x0a49: 0x04f6, 0x0a4a: 0x1333, 0x0a4b: 0x04fb, + 0x0a4c: 0x1338, 0x0a4d: 0x133d, 0x0a4e: 0x1349, 0x0a4f: 0x1355, 0x0a50: 0x1361, 0x0a51: 0x1366, + 0x0a52: 0x136b, 0x0a53: 0x0514, 0x0a56: 0x1372, 0x0a57: 0x1377, + 0x0a58: 0x137e, 0x0a59: 0x1383, 0x0a5a: 0x1388, 0x0a5b: 0x0500, 0x0a5d: 0x138d, + 0x0a5e: 0x1399, 0x0a5f: 0x13a5, 0x0a60: 0x13b1, 0x0a61: 0x13b6, 0x0a62: 0x13bb, 0x0a63: 0x0539, + 0x0a64: 0x13c2, 0x0a65: 0x13c7, 0x0a66: 0x13cc, 0x0a67: 0x13d1, 0x0a68: 0x13d8, 0x0a69: 0x13dd, + 0x0a6a: 0x13e2, 0x0a6b: 0x050a, 0x0a6c: 0x13e7, 0x0a6d: 0x13ec, 0x0a6e: 0x04e3, 0x0a6f: 0x13f7, + 0x0a72: 0x13f9, 0x0a73: 0x1400, 0x0a74: 0x1405, + 0x0a76: 0x140c, 0x0a77: 0x1411, 0x0a78: 0x1418, 0x0a79: 0x0505, 0x0a7a: 0x141d, 0x0a7b: 0x050f, + 0x0a7c: 0x1422, 0x0a7d: 0x1427, + // Block 0x2a, offset 0xa80 + 0x0a80: 0x142e, 0x0a81: 0x1432, + // Block 0x2b, offset 0xac0 + 0x0ae6: 0x14d6, + 0x0aea: 0x091c, 0x0aeb: 0x0046, + // Block 0x2c, offset 0xb00 + 0x0b1a: 0x159f, 0x0b1b: 0x15a5, + 0x0b2e: 0x15ab, + // Block 0x2d, offset 0xb40 + 0x0b4d: 0x15b1, 0x0b4e: 0x15b7, 0x0b4f: 0x15bd, + // Block 0x2e, offset 0xb80 + 0x0b84: 0x15c3, + 0x0b89: 0x15c9, + 0x0b8c: 0x15cf, + 0x0ba4: 0x15d5, 0x0ba6: 0x15db, + // Block 0x2f, offset 0xbc0 + 0x0bc1: 0x1603, 0x0bc4: 0x1609, + 0x0bc7: 0x160f, 0x0bc9: 0x1615, + 0x0be0: 0x161b, 0x0be2: 0x161f, + 0x0bed: 0x1625, 0x0bee: 0x162b, 0x0bef: 0x162f, + 0x0bf0: 0x1633, 0x0bf1: 0x1639, 0x0bf4: 0x163f, 0x0bf5: 0x1645, + 0x0bf8: 0x164b, 0x0bf9: 0x1651, + // Block 0x30, offset 0xc00 + 0x0c00: 0x1657, 0x0c01: 0x165d, 0x0c04: 0x1663, 0x0c05: 0x1669, + 0x0c08: 0x166f, 0x0c09: 0x1675, + 0x0c2c: 0x167b, 0x0c2d: 0x1681, 0x0c2e: 0x1687, 0x0c2f: 0x168d, + // Block 0x31, offset 0xc40 + 0x0c60: 0x1693, 0x0c61: 0x1699, 0x0c62: 0x169f, 0x0c63: 0x16a5, + 0x0c6a: 0x16ab, 0x0c6b: 0x16b1, 0x0c6c: 0x16b7, 0x0c6d: 0x16bd, + // Block 0x32, offset 0xc80 + 0x0ca9: 0x16c3, + 0x0caa: 0x16c7, + // Block 0x33, offset 0xcc0 + 0x0cdc: 0x1814, + // Block 0x34, offset 0xd00 + 0x0d0c: 0x1b8a, 0x0d0e: 0x1b91, 0x0d10: 0x1b98, + 0x0d12: 0x1b9f, 0x0d14: 0x1ba6, 0x0d16: 0x1bad, + 0x0d18: 0x1bb4, 0x0d1a: 0x1bbb, 0x0d1c: 0x1bc2, + 0x0d1e: 0x1bc9, 0x0d20: 0x1bd0, 0x0d22: 0x1bd7, + 0x0d25: 0x1bde, 0x0d27: 0x1be5, 0x0d29: 0x1bec, + 0x0d30: 0x1bf3, 0x0d31: 0x1bfa, 0x0d33: 0x1c01, 0x0d34: 0x1c08, + 0x0d36: 0x1c0f, 0x0d37: 0x1c16, 0x0d39: 0x1c1d, 0x0d3a: 0x1c24, + 0x0d3c: 0x1c2b, 0x0d3d: 0x1c32, + // Block 0x35, offset 0xd40 + 0x0d54: 0x1c39, + 0x0d5e: 0x1c4a, + 0x0d6c: 0x1c58, 0x0d6e: 0x1c5f, + 0x0d70: 0x1c66, 0x0d72: 0x1c6d, 0x0d74: 0x1c74, + 0x0d76: 0x1c7b, 0x0d78: 0x1c82, 0x0d7a: 0x1c89, + 0x0d7c: 0x1c90, 0x0d7e: 0x1c97, + // Block 0x36, offset 0xd80 + 0x0d80: 0x1c9e, 0x0d82: 0x1ca5, 0x0d85: 0x1cac, + 0x0d87: 0x1cb3, 0x0d89: 0x1cba, + 0x0d90: 0x1cc1, 0x0d91: 0x1cc8, + 0x0d93: 0x1ccf, 0x0d94: 0x1cd6, 0x0d96: 0x1cdd, 0x0d97: 0x1ce4, + 0x0d99: 0x1ceb, 0x0d9a: 0x1cf2, 0x0d9c: 0x1cf9, 0x0d9d: 0x1d00, + 0x0db4: 0x1d07, + 0x0db7: 0x1d0e, 0x0db8: 0x1d15, 0x0db9: 0x1d1c, 0x0dba: 0x1d23, + 0x0dbe: 0x1d2a, + // Block 0x37, offset 0xdc0 + 0x0dc0: 0x2a81, 0x0dc1: 0x2a85, 0x0dc2: 0x1a9e, 0x0dc3: 0x2a89, 0x0dc4: 0x2a8d, 0x0dc5: 0x2a91, + 0x0dc6: 0x2a95, 0x0dc7: 0x1b76, 0x0dc8: 0x1b76, 0x0dc9: 0x2a99, 0x0dca: 0x1abe, 0x0dcb: 0x2a9d, + 0x0dcc: 0x2aa1, 0x0dcd: 0x2aa5, 0x0dce: 0x2aa9, 0x0dcf: 0x2aad, 0x0dd0: 0x2ab1, 0x0dd1: 0x2ab5, + 0x0dd2: 0x2ab9, 0x0dd3: 0x2abd, 0x0dd4: 0x2ac1, 0x0dd5: 0x2ac5, 0x0dd6: 0x2ac9, 0x0dd7: 0x2acd, + 0x0dd8: 0x2ad1, 0x0dd9: 0x2ad5, 0x0dda: 0x2ad9, 0x0ddb: 0x2add, 0x0ddc: 0x2ae1, 0x0ddd: 0x2ae5, + 0x0dde: 0x2ae9, 0x0ddf: 0x2aed, 0x0de0: 0x2af1, 0x0de1: 0x2af5, 0x0de2: 0x2af9, 0x0de3: 0x2afd, + 0x0de4: 0x2b01, 0x0de5: 0x2b05, 0x0de6: 0x2b09, 0x0de7: 0x2b0d, 0x0de8: 0x2b11, 0x0de9: 0x2b15, + 0x0dea: 0x2b19, 0x0deb: 0x2b1d, 0x0dec: 0x2b21, 0x0ded: 0x2b25, 0x0dee: 0x2b29, 0x0def: 0x2b2d, + 0x0df0: 0x2b31, 0x0df1: 0x2b35, 0x0df2: 0x2b39, 0x0df3: 0x2b3d, 0x0df4: 0x1a16, 0x0df5: 0x2b41, + 0x0df6: 0x2b45, 0x0df7: 0x2b49, 0x0df8: 0x2b4d, 0x0df9: 0x2b51, 0x0dfa: 0x2b55, 0x0dfb: 0x2b59, + 0x0dfc: 0x2b5d, 0x0dfd: 0x2b61, 0x0dfe: 0x2b65, 0x0dff: 0x2b69, + // Block 0x38, offset 0xe00 + 0x0e00: 0x1b3a, 0x0e01: 0x2b6d, 0x0e02: 0x2b71, 0x0e03: 0x2b75, 0x0e04: 0x2b79, 0x0e05: 0x2b7d, + 0x0e06: 0x2b81, 0x0e07: 0x2b85, 0x0e08: 0x2b89, 0x0e09: 0x2b8d, 0x0e0a: 0x2b91, 0x0e0b: 0x2b95, + 0x0e0c: 0x2b99, 0x0e0d: 0x2b9d, 0x0e0e: 0x2ba1, 0x0e0f: 0x2ba5, 0x0e10: 0x2ba9, 0x0e11: 0x2bad, + 0x0e12: 0x2bb1, 0x0e13: 0x2bb5, 0x0e14: 0x2bb9, 0x0e15: 0x2bbd, 0x0e16: 0x2bc1, 0x0e17: 0x2bc5, + 0x0e18: 0x2bc9, 0x0e19: 0x2bcd, 0x0e1a: 0x2bd1, 0x0e1b: 0x2bd5, 0x0e1c: 0x2ac1, 0x0e1d: 0x2bd9, + 0x0e1e: 0x2bdd, 0x0e1f: 0x2be1, 0x0e20: 0x2be5, 0x0e21: 0x2be9, 0x0e22: 0x2bed, 0x0e23: 0x2bf1, + 0x0e24: 0x2bf5, 0x0e25: 0x2bf9, 0x0e26: 0x2bfd, 0x0e27: 0x2c01, 0x0e28: 0x2c05, 0x0e29: 0x2c09, + 0x0e2a: 0x2c0d, 0x0e2b: 0x2c11, 0x0e2c: 0x2c15, 0x0e2d: 0x2c19, 0x0e2e: 0x2c1d, 0x0e2f: 0x2c21, + 0x0e30: 0x2c25, 0x0e31: 0x1aa6, 0x0e32: 0x2c29, 0x0e33: 0x2c2d, 0x0e34: 0x2c31, 0x0e35: 0x2c35, + 0x0e36: 0x2c39, 0x0e37: 0x2c3d, 0x0e38: 0x2c41, 0x0e39: 0x2c45, 0x0e3a: 0x2c49, 0x0e3b: 0x2c4d, + 0x0e3c: 0x2c51, 0x0e3d: 0x2c55, 0x0e3e: 0x2c59, 0x0e3f: 0x2c5d, + // Block 0x39, offset 0xe40 + 0x0e40: 0x2c61, 0x0e41: 0x18ba, 0x0e42: 0x2c65, 0x0e43: 0x2c69, 0x0e44: 0x2c6d, 0x0e45: 0x2c71, + 0x0e46: 0x2c75, 0x0e47: 0x2c79, 0x0e48: 0x2c7d, 0x0e49: 0x2c81, 0x0e4a: 0x186e, 0x0e4b: 0x2c85, + 0x0e4c: 0x2c89, 0x0e4d: 0x2c8d, 0x0e4e: 0x2c91, 0x0e4f: 0x2c95, 0x0e50: 0x2c99, 0x0e51: 0x2c9d, + 0x0e52: 0x2ca1, 0x0e53: 0x2ca5, 0x0e54: 0x2ca9, 0x0e55: 0x2cad, 0x0e56: 0x2cb1, 0x0e57: 0x2cb5, + 0x0e58: 0x2cb9, 0x0e59: 0x2cbd, 0x0e5a: 0x2cc1, 0x0e5b: 0x2cc5, 0x0e5c: 0x2cc9, 0x0e5d: 0x2ccd, + 0x0e5e: 0x2cd1, 0x0e5f: 0x2cd5, 0x0e60: 0x2cd9, 0x0e61: 0x2c21, 0x0e62: 0x2cdd, 0x0e63: 0x2ce1, + 0x0e64: 0x2ce5, 0x0e65: 0x2ce9, 0x0e66: 0x2ced, 0x0e67: 0x2cf1, 0x0e68: 0x2cf5, 0x0e69: 0x2cf9, + 0x0e6a: 0x2be1, 0x0e6b: 0x2cfd, 0x0e6c: 0x2d01, 0x0e6d: 0x2d05, 0x0e6e: 0x2d09, 0x0e6f: 0x2d0d, + 0x0e70: 0x2d11, 0x0e71: 0x2d15, 0x0e72: 0x2d19, 0x0e73: 0x2d1d, 0x0e74: 0x2d21, 0x0e75: 0x2d25, + 0x0e76: 0x2d29, 0x0e77: 0x2d2d, 0x0e78: 0x2d31, 0x0e79: 0x2d35, 0x0e7a: 0x2d39, 0x0e7b: 0x2d3d, + 0x0e7c: 0x2d41, 0x0e7d: 0x2d45, 0x0e7e: 0x2d49, 0x0e7f: 0x2ac1, + // Block 0x3a, offset 0xe80 + 0x0e80: 0x2d4d, 0x0e81: 0x2d51, 0x0e82: 0x2d55, 0x0e83: 0x2d59, 0x0e84: 0x1b72, 0x0e85: 0x2d5d, + 0x0e86: 0x2d61, 0x0e87: 0x2d65, 0x0e88: 0x2d69, 0x0e89: 0x2d6d, 0x0e8a: 0x2d71, 0x0e8b: 0x2d75, + 0x0e8c: 0x2d79, 0x0e8d: 0x2d7d, 0x0e8e: 0x2d81, 0x0e8f: 0x2d85, 0x0e90: 0x2d89, 0x0e91: 0x2173, + 0x0e92: 0x2d8d, 0x0e93: 0x2d91, 0x0e94: 0x2d95, 0x0e95: 0x2d99, 0x0e96: 0x2d9d, 0x0e97: 0x2da1, + 0x0e98: 0x2da5, 0x0e99: 0x2da9, 0x0e9a: 0x2dad, 0x0e9b: 0x2be9, 0x0e9c: 0x2db1, 0x0e9d: 0x2db5, + 0x0e9e: 0x2db9, 0x0e9f: 0x2dbd, 0x0ea0: 0x2dc1, 0x0ea1: 0x2dc5, 0x0ea2: 0x2dc9, 0x0ea3: 0x2dcd, + 0x0ea4: 0x2dd1, 0x0ea5: 0x2dd5, 0x0ea6: 0x2dd9, 0x0ea7: 0x2ddd, 0x0ea8: 0x2de1, 0x0ea9: 0x1aba, + 0x0eaa: 0x2de5, 0x0eab: 0x2de9, 0x0eac: 0x2ded, 0x0ead: 0x2df1, 0x0eae: 0x2df5, 0x0eaf: 0x2df9, + 0x0eb0: 0x2dfd, 0x0eb1: 0x2e01, 0x0eb2: 0x2e05, 0x0eb3: 0x2e09, 0x0eb4: 0x2e0d, 0x0eb5: 0x2e11, + 0x0eb6: 0x2e15, 0x0eb7: 0x19f6, 0x0eb8: 0x2e19, 0x0eb9: 0x2e1d, 0x0eba: 0x2e21, 0x0ebb: 0x2e25, + 0x0ebc: 0x2e29, 0x0ebd: 0x2e2d, 0x0ebe: 0x2e31, 0x0ebf: 0x2e35, + // Block 0x3b, offset 0xec0 + 0x0ec0: 0x2e39, 0x0ec1: 0x2e3d, 0x0ec2: 0x2e41, 0x0ec3: 0x2e45, 0x0ec4: 0x2e49, 0x0ec5: 0x2e4d, + 0x0ec6: 0x2e51, 0x0ec7: 0x2e55, 0x0ec8: 0x1a62, 0x0ec9: 0x2e59, 0x0eca: 0x1a6e, 0x0ecb: 0x2e5d, + 0x0ecc: 0x2e61, 0x0ecd: 0x2e65, 0x0ed0: 0x2e69, + 0x0ed2: 0x2e6d, 0x0ed5: 0x2e71, 0x0ed6: 0x2e75, 0x0ed7: 0x2e79, + 0x0ed8: 0x2e7d, 0x0ed9: 0x2e81, 0x0eda: 0x2e85, 0x0edb: 0x2e89, 0x0edc: 0x2e8d, 0x0edd: 0x2e91, + 0x0ede: 0x1a12, 0x0ee0: 0x2e95, 0x0ee2: 0x2e99, + 0x0ee5: 0x2e9d, 0x0ee6: 0x2ea1, + 0x0eea: 0x2ea5, 0x0eeb: 0x2ea9, 0x0eec: 0x2ead, 0x0eed: 0x2eb1, + 0x0ef0: 0x2eb5, 0x0ef1: 0x2eb9, 0x0ef2: 0x2ebd, 0x0ef3: 0x2ec1, 0x0ef4: 0x2ec5, 0x0ef5: 0x2ec9, + 0x0ef6: 0x2ecd, 0x0ef7: 0x2ed1, 0x0ef8: 0x2ed5, 0x0ef9: 0x2ed9, 0x0efa: 0x2edd, 0x0efb: 0x2ee1, + 0x0efc: 0x18d6, 0x0efd: 0x2ee5, 0x0efe: 0x2ee9, 0x0eff: 0x2eed, + // Block 0x3c, offset 0xf00 + 0x0f00: 0x2ef1, 0x0f01: 0x2ef5, 0x0f02: 0x2ef9, 0x0f03: 0x2efd, 0x0f04: 0x2f01, 0x0f05: 0x2f05, + 0x0f06: 0x2f09, 0x0f07: 0x2f0d, 0x0f08: 0x2f11, 0x0f09: 0x2f15, 0x0f0a: 0x2f19, 0x0f0b: 0x2f1d, + 0x0f0c: 0x2187, 0x0f0d: 0x2f21, 0x0f0e: 0x2f25, 0x0f0f: 0x2f29, 0x0f10: 0x2f2d, 0x0f11: 0x2197, + 0x0f12: 0x2f31, 0x0f13: 0x2f35, 0x0f14: 0x2f39, 0x0f15: 0x2f3d, 0x0f16: 0x2f41, 0x0f17: 0x2cb1, + 0x0f18: 0x2f45, 0x0f19: 0x2f49, 0x0f1a: 0x2f4d, 0x0f1b: 0x2f51, 0x0f1c: 0x2f55, 0x0f1d: 0x2f59, + 0x0f1e: 0x2f59, 0x0f1f: 0x2f5d, 0x0f20: 0x2f61, 0x0f21: 0x2f65, 0x0f22: 0x2f69, 0x0f23: 0x2f6d, + 0x0f24: 0x2f71, 0x0f25: 0x2f75, 0x0f26: 0x2f79, 0x0f27: 0x2e9d, 0x0f28: 0x2f7d, 0x0f29: 0x2f81, + 0x0f2a: 0x2f85, 0x0f2b: 0x2f89, 0x0f2c: 0x2f8d, 0x0f2d: 0x2f92, + 0x0f30: 0x2f96, 0x0f31: 0x2f9a, 0x0f32: 0x2f9e, 0x0f33: 0x2fa2, 0x0f34: 0x2fa6, 0x0f35: 0x2faa, + 0x0f36: 0x2fae, 0x0f37: 0x2fb2, 0x0f38: 0x2ecd, 0x0f39: 0x2fb6, 0x0f3a: 0x2fba, 0x0f3b: 0x2fbe, + 0x0f3c: 0x2e69, 0x0f3d: 0x2fc2, 0x0f3e: 0x2fc6, 0x0f3f: 0x2fca, + // Block 0x3d, offset 0xf40 + 0x0f40: 0x2fce, 0x0f41: 0x2fd2, 0x0f42: 0x2fd6, 0x0f43: 0x2fda, 0x0f44: 0x2fde, 0x0f45: 0x2fe2, + 0x0f46: 0x2fe6, 0x0f47: 0x2fea, 0x0f48: 0x2fee, 0x0f49: 0x2eed, 0x0f4a: 0x2ff2, 0x0f4b: 0x2ef1, + 0x0f4c: 0x2ff6, 0x0f4d: 0x2ffa, 0x0f4e: 0x2ffe, 0x0f4f: 0x3002, 0x0f50: 0x3006, 0x0f51: 0x2e6d, + 0x0f52: 0x2b15, 0x0f53: 0x300a, 0x0f54: 0x300e, 0x0f55: 0x195a, 0x0f56: 0x2c25, 0x0f57: 0x2d71, + 0x0f58: 0x3012, 0x0f59: 0x3016, 0x0f5a: 0x2f0d, 0x0f5b: 0x301a, 0x0f5c: 0x2f11, 0x0f5d: 0x301e, + 0x0f5e: 0x3022, 0x0f5f: 0x3026, 0x0f60: 0x2e75, 0x0f61: 0x302a, 0x0f62: 0x302e, 0x0f63: 0x3032, + 0x0f64: 0x3036, 0x0f65: 0x303a, 0x0f66: 0x2e79, 0x0f67: 0x303e, 0x0f68: 0x3042, 0x0f69: 0x3046, + 0x0f6a: 0x304a, 0x0f6b: 0x304e, 0x0f6c: 0x3052, 0x0f6d: 0x2f41, 0x0f6e: 0x3056, 0x0f6f: 0x305a, + 0x0f70: 0x2cb1, 0x0f71: 0x305e, 0x0f72: 0x2f51, 0x0f73: 0x3062, 0x0f74: 0x3066, 0x0f75: 0x306a, + 0x0f76: 0x306e, 0x0f77: 0x3072, 0x0f78: 0x2f65, 0x0f79: 0x3076, 0x0f7a: 0x2e99, 0x0f7b: 0x307a, + 0x0f7c: 0x2f69, 0x0f7d: 0x2bd9, 0x0f7e: 0x307e, 0x0f7f: 0x2f6d, + // Block 0x3e, offset 0xf80 + 0x0f80: 0x3082, 0x0f81: 0x2f75, 0x0f82: 0x3086, 0x0f83: 0x308a, 0x0f84: 0x308e, 0x0f85: 0x3092, + 0x0f86: 0x3096, 0x0f87: 0x2f7d, 0x0f88: 0x2e8d, 0x0f89: 0x309a, 0x0f8a: 0x2f81, 0x0f8b: 0x309e, + 0x0f8c: 0x2f85, 0x0f8d: 0x30a2, 0x0f8e: 0x1b76, 0x0f8f: 0x30a6, 0x0f90: 0x30ab, 0x0f91: 0x30b0, + 0x0f92: 0x30b5, 0x0f93: 0x30b9, 0x0f94: 0x30bd, 0x0f95: 0x30c1, 0x0f96: 0x30c6, 0x0f97: 0x30cb, + 0x0f98: 0x30d0, 0x0f99: 0x30d4, + // Block 0x3f, offset 0xfc0 + 0x0fdd: 0x3105, + 0x0fdf: 0x310a, + 0x0fea: 0x3124, 0x0feb: 0x3129, 0x0fec: 0x312e, 0x0fed: 0x3135, 0x0fee: 0x313c, 0x0fef: 0x3141, + 0x0ff0: 0x3146, 0x0ff1: 0x314b, 0x0ff2: 0x3150, 0x0ff3: 0x3155, 0x0ff4: 0x315a, 0x0ff5: 0x315f, + 0x0ff6: 0x3164, 0x0ff8: 0x3169, 0x0ff9: 0x316e, 0x0ffa: 0x3173, 0x0ffb: 0x3178, + 0x0ffc: 0x317d, 0x0ffe: 0x3182, + // Block 0x40, offset 0x1000 + 0x1000: 0x3187, 0x1001: 0x318c, 0x1003: 0x3191, 0x1004: 0x3196, + 0x1006: 0x319b, 0x1007: 0x31a0, 0x1008: 0x31a5, 0x1009: 0x31aa, 0x100a: 0x31af, 0x100b: 0x31b4, + 0x100c: 0x31b9, 0x100d: 0x31be, 0x100e: 0x31c3, + // Block 0x41, offset 0x1040 + 0x105a: 0x3a73, 0x105c: 0x3a7c, + 0x106b: 0x3a85, + // Block 0x42, offset 0x1080 + 0x109e: 0x3a8e, 0x109f: 0x3a97, 0x10a0: 0x3aa0, 0x10a1: 0x3aad, 0x10a2: 0x3aba, 0x10a3: 0x3ac7, + 0x10a4: 0x3ad4, + // Block 0x43, offset 0x10c0 + 0x10fb: 0x3ae1, + 0x10fc: 0x3aea, 0x10fd: 0x3af3, 0x10fe: 0x3b00, 0x10ff: 0x3b0d, + // Block 0x44, offset 0x1100 + 0x1100: 0x3b1a, + // Block 0x45, offset 0x1140 + 0x1140: 0x3d23, 0x1141: 0x3d27, 0x1142: 0x3d2b, 0x1143: 0x3d2f, 0x1144: 0x3d34, 0x1145: 0x2eb5, + 0x1146: 0x3d38, 0x1147: 0x3d3c, 0x1148: 0x3d40, 0x1149: 0x3d44, 0x114a: 0x2eb9, 0x114b: 0x3d48, + 0x114c: 0x3d4c, 0x114d: 0x3d50, 0x114e: 0x2ebd, 0x114f: 0x3d55, 0x1150: 0x3d59, 0x1151: 0x3d5d, + 0x1152: 0x3d61, 0x1153: 0x3d66, 0x1154: 0x3d6a, 0x1155: 0x3c71, 0x1156: 0x3d6e, 0x1157: 0x3d73, + 0x1158: 0x3d77, 0x1159: 0x3d7b, 0x115a: 0x3d7f, 0x115b: 0x2f9a, 0x115c: 0x3d83, 0x115d: 0x1866, + 0x115e: 0x3d88, 0x115f: 0x3d8c, 0x1160: 0x3d90, 0x1161: 0x3d94, 0x1162: 0x3cb9, 0x1163: 0x3d98, + 0x1164: 0x3d9c, 0x1165: 0x2fae, 0x1166: 0x2ec1, 0x1167: 0x2ec5, 0x1168: 0x2fb2, 0x1169: 0x3da0, + 0x116a: 0x3da4, 0x116b: 0x2bf1, 0x116c: 0x3da8, 0x116d: 0x2ec9, 0x116e: 0x3dac, 0x116f: 0x3db0, + 0x1170: 0x3db4, 0x1171: 0x3db8, 0x1172: 0x3db8, 0x1173: 0x3db8, 0x1174: 0x3dbc, 0x1175: 0x3dc1, + 0x1176: 0x3dc5, 0x1177: 0x3dc9, 0x1178: 0x3dcd, 0x1179: 0x3dd2, 0x117a: 0x3dd6, 0x117b: 0x3dda, + 0x117c: 0x3dde, 0x117d: 0x3de2, 0x117e: 0x3de6, 0x117f: 0x3dea, + // Block 0x46, offset 0x1180 + 0x1180: 0x3dee, 0x1181: 0x3df2, 0x1182: 0x3df6, 0x1183: 0x3dfa, 0x1184: 0x3dfe, 0x1185: 0x3e02, + 0x1186: 0x3e02, 0x1187: 0x2fba, 0x1188: 0x3e06, 0x1189: 0x3e0a, 0x118a: 0x3e0e, 0x118b: 0x3e12, + 0x118c: 0x2ed1, 0x118d: 0x3e16, 0x118e: 0x3e1a, 0x118f: 0x3e1e, 0x1190: 0x2e39, 0x1191: 0x3e22, + 0x1192: 0x3e26, 0x1193: 0x3e2a, 0x1194: 0x3e2e, 0x1195: 0x3e32, 0x1196: 0x3e36, 0x1197: 0x3e3a, + 0x1198: 0x3e3e, 0x1199: 0x3e42, 0x119a: 0x3e47, 0x119b: 0x3e4b, 0x119c: 0x3e4f, 0x119d: 0x3c55, + 0x119e: 0x3e53, 0x119f: 0x3e57, 0x11a0: 0x3e5b, 0x11a1: 0x3e60, 0x11a2: 0x3e65, 0x11a3: 0x3e69, + 0x11a4: 0x3e6d, 0x11a5: 0x3e71, 0x11a6: 0x3e75, 0x11a7: 0x3e79, 0x11a8: 0x3e7d, 0x11a9: 0x3e81, + 0x11aa: 0x3e85, 0x11ab: 0x3e85, 0x11ac: 0x3e89, 0x11ad: 0x3e8e, 0x11ae: 0x3e92, 0x11af: 0x2be1, + 0x11b0: 0x3e96, 0x11b1: 0x3e9a, 0x11b2: 0x3e9f, 0x11b3: 0x3ea3, 0x11b4: 0x3ea7, 0x11b5: 0x18ce, + 0x11b6: 0x3eab, 0x11b7: 0x3eaf, 0x11b8: 0x18d6, 0x11b9: 0x3eb3, 0x11ba: 0x3eb7, 0x11bb: 0x3ebb, + 0x11bc: 0x3ec0, 0x11bd: 0x3ec4, 0x11be: 0x3ec9, 0x11bf: 0x3ecd, + // Block 0x47, offset 0x11c0 + 0x11c0: 0x3ed1, 0x11c1: 0x3ed5, 0x11c2: 0x3ed9, 0x11c3: 0x3edd, 0x11c4: 0x3ee1, 0x11c5: 0x3ee5, + 0x11c6: 0x3ee9, 0x11c7: 0x3eed, 0x11c8: 0x3ef1, 0x11c9: 0x3ef5, 0x11ca: 0x3efa, 0x11cb: 0x3efe, + 0x11cc: 0x3f02, 0x11cd: 0x3f06, 0x11ce: 0x2b11, 0x11cf: 0x3f0a, 0x11d0: 0x18fe, 0x11d1: 0x3f0f, + 0x11d2: 0x3f0f, 0x11d3: 0x3f14, 0x11d4: 0x3f18, 0x11d5: 0x3f18, 0x11d6: 0x3f1c, 0x11d7: 0x3f20, + 0x11d8: 0x3f25, 0x11d9: 0x3f2a, 0x11da: 0x3f2e, 0x11db: 0x3f32, 0x11dc: 0x3f36, 0x11dd: 0x3f3a, + 0x11de: 0x3f3e, 0x11df: 0x3f42, 0x11e0: 0x3f46, 0x11e1: 0x3f4a, 0x11e2: 0x3f4e, 0x11e3: 0x2ee5, + 0x11e4: 0x3f52, 0x11e5: 0x3f57, 0x11e6: 0x3f5b, 0x11e7: 0x3f5f, 0x11e8: 0x2fea, 0x11e9: 0x3f5f, + 0x11ea: 0x3f63, 0x11eb: 0x2eed, 0x11ec: 0x3f67, 0x11ed: 0x3f6b, 0x11ee: 0x3f6f, 0x11ef: 0x3f73, + 0x11f0: 0x2ef1, 0x11f1: 0x2aa5, 0x11f2: 0x3f77, 0x11f3: 0x3f7b, 0x11f4: 0x3f7f, 0x11f5: 0x3f83, + 0x11f6: 0x3f87, 0x11f7: 0x3f8b, 0x11f8: 0x3f8f, 0x11f9: 0x3f94, 0x11fa: 0x3f98, 0x11fb: 0x3f9c, + 0x11fc: 0x3fa0, 0x11fd: 0x3fa4, 0x11fe: 0x3fa8, 0x11ff: 0x3fad, + // Block 0x48, offset 0x1200 + 0x1200: 0x3fb1, 0x1201: 0x3fb5, 0x1202: 0x3fb9, 0x1203: 0x3fbd, 0x1204: 0x3fc1, 0x1205: 0x3fc5, + 0x1206: 0x3fc9, 0x1207: 0x3fcd, 0x1208: 0x2ef5, 0x1209: 0x3fd1, 0x120a: 0x3fd5, 0x120b: 0x3fda, + 0x120c: 0x3fde, 0x120d: 0x3fe2, 0x120e: 0x3fe6, 0x120f: 0x2efd, 0x1210: 0x3fea, 0x1211: 0x3fee, + 0x1212: 0x3ff2, 0x1213: 0x3ff6, 0x1214: 0x3ffa, 0x1215: 0x3ffe, 0x1216: 0x4002, 0x1217: 0x4006, + 0x1218: 0x2b15, 0x1219: 0x300a, 0x121a: 0x400a, 0x121b: 0x400e, 0x121c: 0x4012, 0x121d: 0x4016, + 0x121e: 0x401b, 0x121f: 0x401f, 0x1220: 0x4023, 0x1221: 0x4027, 0x1222: 0x2f01, 0x1223: 0x402b, + 0x1224: 0x4030, 0x1225: 0x4034, 0x1226: 0x4038, 0x1227: 0x30b5, 0x1228: 0x403c, 0x1229: 0x4040, + 0x122a: 0x4044, 0x122b: 0x4048, 0x122c: 0x404c, 0x122d: 0x4051, 0x122e: 0x4055, 0x122f: 0x4059, + 0x1230: 0x405d, 0x1231: 0x4062, 0x1232: 0x4066, 0x1233: 0x406a, 0x1234: 0x406e, 0x1235: 0x2c25, + 0x1236: 0x4072, 0x1237: 0x4076, 0x1238: 0x407b, 0x1239: 0x4080, 0x123a: 0x4085, 0x123b: 0x4089, + 0x123c: 0x408e, 0x123d: 0x4092, 0x123e: 0x4096, 0x123f: 0x409a, + // Block 0x49, offset 0x1240 + 0x1240: 0x409e, 0x1241: 0x2f05, 0x1242: 0x2d71, 0x1243: 0x40a2, 0x1244: 0x40a6, 0x1245: 0x40aa, + 0x1246: 0x40ae, 0x1247: 0x40b3, 0x1248: 0x40b7, 0x1249: 0x40bb, 0x124a: 0x40bf, 0x124b: 0x3016, + 0x124c: 0x40c3, 0x124d: 0x40c7, 0x124e: 0x40cc, 0x124f: 0x40d0, 0x1250: 0x40d4, 0x1251: 0x40d9, + 0x1252: 0x40de, 0x1253: 0x40e2, 0x1254: 0x301a, 0x1255: 0x40e6, 0x1256: 0x40ea, 0x1257: 0x40ee, + 0x1258: 0x40f2, 0x1259: 0x40f6, 0x125a: 0x40fa, 0x125b: 0x40fe, 0x125c: 0x4103, 0x125d: 0x4107, + 0x125e: 0x410c, 0x125f: 0x4110, 0x1260: 0x4115, 0x1261: 0x3022, 0x1262: 0x4119, 0x1263: 0x411d, + 0x1264: 0x4122, 0x1265: 0x4126, 0x1266: 0x412a, 0x1267: 0x412f, 0x1268: 0x4134, 0x1269: 0x4138, + 0x126a: 0x413c, 0x126b: 0x4140, 0x126c: 0x4144, 0x126d: 0x4144, 0x126e: 0x4148, 0x126f: 0x414c, + 0x1270: 0x302a, 0x1271: 0x4150, 0x1272: 0x4154, 0x1273: 0x4158, 0x1274: 0x415c, 0x1275: 0x4160, + 0x1276: 0x4165, 0x1277: 0x4169, 0x1278: 0x2bed, 0x1279: 0x416e, 0x127a: 0x4173, 0x127b: 0x4177, + 0x127c: 0x417c, 0x127d: 0x4181, 0x127e: 0x4186, 0x127f: 0x418a, + // Block 0x4a, offset 0x1280 + 0x1280: 0x3042, 0x1281: 0x418e, 0x1282: 0x4193, 0x1283: 0x4198, 0x1284: 0x419d, 0x1285: 0x41a2, + 0x1286: 0x41a6, 0x1287: 0x41a6, 0x1288: 0x3046, 0x1289: 0x30bd, 0x128a: 0x41aa, 0x128b: 0x41ae, + 0x128c: 0x41b2, 0x128d: 0x41b6, 0x128e: 0x41bb, 0x128f: 0x2b59, 0x1290: 0x304e, 0x1291: 0x41bf, + 0x1292: 0x41c3, 0x1293: 0x2f2d, 0x1294: 0x41c8, 0x1295: 0x41cd, 0x1296: 0x2e89, 0x1297: 0x41d2, + 0x1298: 0x41d6, 0x1299: 0x2f39, 0x129a: 0x41da, 0x129b: 0x41de, 0x129c: 0x41e2, 0x129d: 0x41e7, + 0x129e: 0x41e7, 0x129f: 0x41ec, 0x12a0: 0x41f0, 0x12a1: 0x41f4, 0x12a2: 0x41f9, 0x12a3: 0x41fd, + 0x12a4: 0x4201, 0x12a5: 0x4205, 0x12a6: 0x420a, 0x12a7: 0x420e, 0x12a8: 0x4212, 0x12a9: 0x4216, + 0x12aa: 0x421a, 0x12ab: 0x421e, 0x12ac: 0x4223, 0x12ad: 0x4227, 0x12ae: 0x422b, 0x12af: 0x422f, + 0x12b0: 0x4233, 0x12b1: 0x4237, 0x12b2: 0x423b, 0x12b3: 0x4240, 0x12b4: 0x4245, 0x12b5: 0x4249, + 0x12b6: 0x424e, 0x12b7: 0x4252, 0x12b8: 0x4257, 0x12b9: 0x425b, 0x12ba: 0x2f51, 0x12bb: 0x425f, + 0x12bc: 0x4264, 0x12bd: 0x4269, 0x12be: 0x426d, 0x12bf: 0x4272, + // Block 0x4b, offset 0x12c0 + 0x12c0: 0x4276, 0x12c1: 0x427b, 0x12c2: 0x427f, 0x12c3: 0x4283, 0x12c4: 0x4287, 0x12c5: 0x428b, + 0x12c6: 0x428f, 0x12c7: 0x4293, 0x12c8: 0x4298, 0x12c9: 0x429d, 0x12ca: 0x42a2, 0x12cb: 0x3f14, + 0x12cc: 0x42a7, 0x12cd: 0x42ab, 0x12ce: 0x42af, 0x12cf: 0x42b3, 0x12d0: 0x42b7, 0x12d1: 0x42bb, + 0x12d2: 0x42bf, 0x12d3: 0x42c3, 0x12d4: 0x42c7, 0x12d5: 0x42cb, 0x12d6: 0x42cf, 0x12d7: 0x42d3, + 0x12d8: 0x2c31, 0x12d9: 0x42d8, 0x12da: 0x42dc, 0x12db: 0x42e0, 0x12dc: 0x42e4, 0x12dd: 0x42e8, + 0x12de: 0x42ec, 0x12df: 0x2f5d, 0x12e0: 0x42f0, 0x12e1: 0x42f4, 0x12e2: 0x42f8, 0x12e3: 0x42fc, + 0x12e4: 0x4300, 0x12e5: 0x4305, 0x12e6: 0x430a, 0x12e7: 0x430f, 0x12e8: 0x4313, 0x12e9: 0x4317, + 0x12ea: 0x431b, 0x12eb: 0x431f, 0x12ec: 0x4324, 0x12ed: 0x4328, 0x12ee: 0x432d, 0x12ef: 0x4331, + 0x12f0: 0x4335, 0x12f1: 0x433a, 0x12f2: 0x433f, 0x12f3: 0x4343, 0x12f4: 0x2b45, 0x12f5: 0x4347, + 0x12f6: 0x434b, 0x12f7: 0x434f, 0x12f8: 0x4353, 0x12f9: 0x4357, 0x12fa: 0x435b, 0x12fb: 0x306a, + 0x12fc: 0x435f, 0x12fd: 0x4363, 0x12fe: 0x4367, 0x12ff: 0x436b, + // Block 0x4c, offset 0x1300 + 0x1300: 0x436f, 0x1301: 0x4373, 0x1302: 0x4377, 0x1303: 0x437b, 0x1304: 0x1a66, 0x1305: 0x437f, + 0x1306: 0x4384, 0x1307: 0x4388, 0x1308: 0x438c, 0x1309: 0x4390, 0x130a: 0x4394, 0x130b: 0x4398, + 0x130c: 0x439d, 0x130d: 0x43a2, 0x130e: 0x43a6, 0x130f: 0x43aa, 0x1310: 0x307e, 0x1311: 0x3082, + 0x1312: 0x1a82, 0x1313: 0x43ae, 0x1314: 0x43b3, 0x1315: 0x43b7, 0x1316: 0x43bb, 0x1317: 0x43bf, + 0x1318: 0x43c3, 0x1319: 0x43c8, 0x131a: 0x43cd, 0x131b: 0x43d1, 0x131c: 0x43d5, 0x131d: 0x43d9, + 0x131e: 0x43de, 0x131f: 0x3086, 0x1320: 0x43e2, 0x1321: 0x43e7, 0x1322: 0x43ec, 0x1323: 0x43f0, + 0x1324: 0x43f4, 0x1325: 0x43f8, 0x1326: 0x43fd, 0x1327: 0x4401, 0x1328: 0x4405, 0x1329: 0x4409, + 0x132a: 0x440d, 0x132b: 0x4411, 0x132c: 0x4415, 0x132d: 0x4419, 0x132e: 0x441e, 0x132f: 0x4422, + 0x1330: 0x4426, 0x1331: 0x442a, 0x1332: 0x442f, 0x1333: 0x4433, 0x1334: 0x4437, 0x1335: 0x443b, + 0x1336: 0x443f, 0x1337: 0x4444, 0x1338: 0x4449, 0x1339: 0x444d, 0x133a: 0x4451, 0x133b: 0x4455, + 0x133c: 0x445a, 0x133d: 0x445e, 0x133e: 0x309e, 0x133f: 0x309e, + // Block 0x4d, offset 0x1340 + 0x1340: 0x4463, 0x1341: 0x4467, 0x1342: 0x446c, 0x1343: 0x4470, 0x1344: 0x4474, 0x1345: 0x4478, + 0x1346: 0x447c, 0x1347: 0x4480, 0x1348: 0x4484, 0x1349: 0x4488, 0x134a: 0x30a2, 0x134b: 0x448d, + 0x134c: 0x4491, 0x134d: 0x4495, 0x134e: 0x4499, 0x134f: 0x449d, 0x1350: 0x44a1, 0x1351: 0x44a6, + 0x1352: 0x44aa, 0x1353: 0x44af, 0x1354: 0x44b4, 0x1355: 0x1b42, 0x1356: 0x44b9, 0x1357: 0x1b52, + 0x1358: 0x44bd, 0x1359: 0x44c1, 0x135a: 0x44c5, 0x135b: 0x44c9, 0x135c: 0x1b66, 0x135d: 0x44cd, +} + +// nfcDecompLookup: 832 bytes +// Block 0 is the null block. +var nfcDecompLookup = [832]uint8{ + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0x0c3: 0x03, 0x0c4: 0x04, 0x0c5: 0x05, 0x0c6: 0x06, 0x0c7: 0x07, + 0x0c8: 0x08, 0x0cd: 0x09, 0x0ce: 0x0a, 0x0cf: 0x0b, + 0x0d0: 0x0c, 0x0d1: 0x0d, 0x0d3: 0x0e, + 0x0d8: 0x0f, 0x0db: 0x10, + 0x0e0: 0x04, 0x0e1: 0x05, 0x0e2: 0x06, 0x0e3: 0x07, + 0x0ef: 0x08, + 0x0f0: 0x0c, + // Block 0x4, offset 0x100 + 0x124: 0x11, 0x125: 0x12, 0x127: 0x13, + 0x128: 0x14, 0x129: 0x15, 0x12d: 0x16, 0x12e: 0x17, 0x12f: 0x18, + 0x131: 0x19, 0x133: 0x1a, 0x135: 0x1b, 0x137: 0x1c, + 0x13d: 0x1d, 0x13e: 0x1e, + // Block 0x5, offset 0x140 + 0x140: 0x1f, + 0x16c: 0x20, 0x16d: 0x21, + 0x178: 0x22, 0x179: 0x23, 0x17a: 0x24, 0x17b: 0x25, 0x17c: 0x26, 0x17d: 0x27, 0x17e: 0x28, 0x17f: 0x29, + // Block 0x6, offset 0x180 + 0x180: 0x2a, 0x184: 0x2b, 0x186: 0x2c, 0x187: 0x2d, + 0x188: 0x2e, 0x189: 0x2f, 0x18a: 0x30, 0x18b: 0x31, 0x18c: 0x32, + 0x1ab: 0x33, + // Block 0x7, offset 0x1c0 + 0x1c1: 0x34, 0x1c2: 0x35, 0x1c3: 0x36, + // Block 0x8, offset 0x200 + 0x224: 0x37, 0x225: 0x38, 0x226: 0x39, 0x227: 0x3a, + 0x228: 0x3b, 0x229: 0x3c, 0x22a: 0x3d, 0x22b: 0x3e, 0x22c: 0x3f, 0x22d: 0x40, + // Block 0x9, offset 0x240 + 0x242: 0x41, + // Block 0xa, offset 0x280 + 0x285: 0x42, 0x286: 0x43, 0x287: 0x44, + // Block 0xb, offset 0x2c0 + 0x2e0: 0x45, 0x2e1: 0x46, 0x2e2: 0x47, 0x2e3: 0x48, 0x2e4: 0x49, 0x2e5: 0x4a, 0x2e6: 0x4b, 0x2e7: 0x4c, + 0x2e8: 0x4d, + // Block 0xc, offset 0x300 + 0x311: 0x09, + 0x31d: 0x0a, + 0x32f: 0x0b, +} + +var nfcDecompTrie = trie{nfcDecompLookup[:], nfcDecompValues[:]} + +// nfkcDecompValues: 10176 entries, 20352 bytes +// Block 2 is the null block. +var nfkcDecompValues = [10176]uint16{ + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0x00e0: 0x0001, + 0x00e8: 0x0003, + 0x00ea: 0x0007, 0x00ef: 0x0009, + 0x00f2: 0x000d, 0x00f3: 0x000f, 0x00f4: 0x0011, 0x00f5: 0x0015, + 0x00f8: 0x0018, 0x00f9: 0x001c, 0x00fa: 0x001e, + 0x00fc: 0x0020, 0x00fd: 0x0026, 0x00fe: 0x002c, + // Block 0x4, offset 0x100 + 0x0100: 0x0032, 0x0101: 0x0036, 0x0102: 0x003a, 0x0103: 0x003e, 0x0104: 0x0042, 0x0105: 0x0046, + 0x0107: 0x004a, 0x0108: 0x004e, 0x0109: 0x0052, 0x010a: 0x0056, 0x010b: 0x005a, + 0x010c: 0x005e, 0x010d: 0x0062, 0x010e: 0x0066, 0x010f: 0x006a, 0x0111: 0x006e, + 0x0112: 0x0072, 0x0113: 0x0076, 0x0114: 0x007a, 0x0115: 0x007e, 0x0116: 0x0082, + 0x0119: 0x0086, 0x011a: 0x008a, 0x011b: 0x008e, 0x011c: 0x0092, 0x011d: 0x0096, + 0x0120: 0x009a, 0x0121: 0x009e, 0x0122: 0x00a2, 0x0123: 0x00a6, + 0x0124: 0x00aa, 0x0125: 0x00ae, 0x0127: 0x00b2, 0x0128: 0x00b6, 0x0129: 0x00ba, + 0x012a: 0x00be, 0x012b: 0x00c2, 0x012c: 0x00c6, 0x012d: 0x00ca, 0x012e: 0x00ce, 0x012f: 0x00d2, + 0x0131: 0x00d6, 0x0132: 0x00da, 0x0133: 0x00de, 0x0134: 0x00e2, 0x0135: 0x00e6, + 0x0136: 0x00ea, 0x0139: 0x00ee, 0x013a: 0x00f2, 0x013b: 0x00f6, + 0x013c: 0x00fa, 0x013d: 0x00fe, 0x013f: 0x0102, + // Block 0x5, offset 0x140 + 0x0140: 0x0106, 0x0141: 0x010a, 0x0142: 0x010e, 0x0143: 0x0112, 0x0144: 0x0116, 0x0145: 0x011a, + 0x0146: 0x011e, 0x0147: 0x0122, 0x0148: 0x0126, 0x0149: 0x012a, 0x014a: 0x012e, 0x014b: 0x0132, + 0x014c: 0x0136, 0x014d: 0x013a, 0x014e: 0x013e, 0x014f: 0x0142, + 0x0152: 0x0146, 0x0153: 0x014a, 0x0154: 0x014e, 0x0155: 0x0152, 0x0156: 0x0156, 0x0157: 0x015a, + 0x0158: 0x015e, 0x0159: 0x0162, 0x015a: 0x0166, 0x015b: 0x016a, 0x015c: 0x016e, 0x015d: 0x0172, + 0x015e: 0x0176, 0x015f: 0x017a, 0x0160: 0x017e, 0x0161: 0x0182, 0x0162: 0x0186, 0x0163: 0x018a, + 0x0164: 0x018e, 0x0165: 0x0192, 0x0168: 0x0196, 0x0169: 0x019a, + 0x016a: 0x019e, 0x016b: 0x01a2, 0x016c: 0x01a6, 0x016d: 0x01aa, 0x016e: 0x01ae, 0x016f: 0x01b2, + 0x0170: 0x01b6, 0x0172: 0x01ba, 0x0173: 0x01bd, 0x0174: 0x01c0, 0x0175: 0x01c4, + 0x0176: 0x01c8, 0x0177: 0x01cc, 0x0179: 0x01d0, 0x017a: 0x01d4, 0x017b: 0x01d8, + 0x017c: 0x01dc, 0x017d: 0x01e0, 0x017e: 0x01e4, 0x017f: 0x01e8, + // Block 0x6, offset 0x180 + 0x0180: 0x01ec, 0x0183: 0x01f0, 0x0184: 0x01f4, 0x0185: 0x01f8, + 0x0186: 0x01fc, 0x0187: 0x0200, 0x0188: 0x0204, 0x0189: 0x0208, + 0x018c: 0x020c, 0x018d: 0x0210, 0x018e: 0x0214, 0x018f: 0x0218, 0x0190: 0x021c, 0x0191: 0x0220, + 0x0194: 0x0224, 0x0195: 0x0228, 0x0196: 0x022c, 0x0197: 0x0230, + 0x0198: 0x0234, 0x0199: 0x0238, 0x019a: 0x023c, 0x019b: 0x0240, 0x019c: 0x0244, 0x019d: 0x0248, + 0x019e: 0x024c, 0x019f: 0x0250, 0x01a0: 0x0254, 0x01a1: 0x0258, 0x01a2: 0x025c, 0x01a3: 0x0260, + 0x01a4: 0x0264, 0x01a5: 0x0268, 0x01a8: 0x026c, 0x01a9: 0x0270, + 0x01aa: 0x0274, 0x01ab: 0x0278, 0x01ac: 0x027c, 0x01ad: 0x0280, 0x01ae: 0x0284, 0x01af: 0x0288, + 0x01b0: 0x028c, 0x01b1: 0x0290, 0x01b2: 0x0294, 0x01b3: 0x0298, 0x01b4: 0x029c, 0x01b5: 0x02a0, + 0x01b6: 0x02a4, 0x01b7: 0x02a8, 0x01b8: 0x02ac, 0x01b9: 0x02b0, 0x01ba: 0x02b4, 0x01bb: 0x02b8, + 0x01bc: 0x02bc, 0x01bd: 0x02c0, 0x01be: 0x02c4, 0x01bf: 0x02c8, + // Block 0x7, offset 0x1c0 + 0x01e0: 0x02ca, 0x01e1: 0x02ce, + 0x01ef: 0x02d2, + 0x01f0: 0x02d6, + // Block 0x8, offset 0x200 + 0x0204: 0x02da, 0x0205: 0x02df, + 0x0206: 0x02e4, 0x0207: 0x02e9, 0x0208: 0x02ec, 0x0209: 0x02ef, 0x020a: 0x02f2, 0x020b: 0x02f5, + 0x020c: 0x02f8, 0x020d: 0x02fb, 0x020e: 0x02ff, 0x020f: 0x0303, 0x0210: 0x0307, 0x0211: 0x030b, + 0x0212: 0x030f, 0x0213: 0x0313, 0x0214: 0x0317, 0x0215: 0x031b, 0x0216: 0x0321, 0x0217: 0x0327, + 0x0218: 0x032d, 0x0219: 0x0333, 0x021a: 0x0339, 0x021b: 0x033f, 0x021c: 0x0345, + 0x021e: 0x034b, 0x021f: 0x0351, 0x0220: 0x0357, 0x0221: 0x035d, 0x0222: 0x0363, 0x0223: 0x0368, + 0x0226: 0x036d, 0x0227: 0x0371, 0x0228: 0x0375, 0x0229: 0x0379, + 0x022a: 0x037d, 0x022b: 0x0381, 0x022c: 0x0385, 0x022d: 0x038b, 0x022e: 0x0391, 0x022f: 0x0396, + 0x0230: 0x039b, 0x0231: 0x039f, 0x0232: 0x03a2, 0x0233: 0x03a5, 0x0234: 0x03a8, 0x0235: 0x03ac, + 0x0238: 0x03b0, 0x0239: 0x03b4, 0x023a: 0x03b8, 0x023b: 0x03be, + 0x023c: 0x03c4, 0x023d: 0x03c9, 0x023e: 0x03ce, 0x023f: 0x03d3, + // Block 0x9, offset 0x240 + 0x0240: 0x03d8, 0x0241: 0x03dc, 0x0242: 0x03e0, 0x0243: 0x03e4, 0x0244: 0x03e8, 0x0245: 0x03ec, + 0x0246: 0x03f0, 0x0247: 0x03f4, 0x0248: 0x03f8, 0x0249: 0x03fc, 0x024a: 0x0400, 0x024b: 0x0404, + 0x024c: 0x0408, 0x024d: 0x040c, 0x024e: 0x0410, 0x024f: 0x0414, 0x0250: 0x0418, 0x0251: 0x041c, + 0x0252: 0x0420, 0x0253: 0x0424, 0x0254: 0x0428, 0x0255: 0x042c, 0x0256: 0x0430, 0x0257: 0x0434, + 0x0258: 0x0438, 0x0259: 0x043c, 0x025a: 0x0440, 0x025b: 0x0444, + 0x025e: 0x0448, 0x025f: 0x044c, + 0x0266: 0x0450, 0x0267: 0x0454, 0x0268: 0x0458, 0x0269: 0x045c, + 0x026a: 0x0460, 0x026b: 0x0466, 0x026c: 0x046c, 0x026d: 0x0472, 0x026e: 0x0478, 0x026f: 0x047c, + 0x0270: 0x0480, 0x0271: 0x0486, 0x0272: 0x048c, 0x0273: 0x0490, + // Block 0xa, offset 0x280 + 0x02b0: 0x0494, 0x02b1: 0x0496, 0x02b2: 0x0499, 0x02b3: 0x049b, 0x02b4: 0x049d, 0x02b5: 0x04a0, + 0x02b6: 0x04a3, 0x02b7: 0x04a6, 0x02b8: 0x04a8, + // Block 0xb, offset 0x2c0 + 0x02d8: 0x04aa, 0x02d9: 0x04ae, 0x02da: 0x04b2, 0x02db: 0x04b6, 0x02dc: 0x04ba, 0x02dd: 0x04be, + 0x02e0: 0x04c2, 0x02e1: 0x04c5, 0x02e2: 0x02c8, 0x02e3: 0x04c7, + 0x02e4: 0x04c9, + // Block 0xc, offset 0x300 + 0x0300: 0x04cc, 0x0301: 0x04cf, 0x0303: 0x04d2, 0x0304: 0x04d5, + 0x0334: 0x04da, + 0x033a: 0x04dd, + 0x033e: 0x04e1, + // Block 0xd, offset 0x340 + 0x0344: 0x0011, 0x0345: 0x04e8, + 0x0346: 0x04ee, 0x0347: 0x04f3, 0x0348: 0x04f6, 0x0349: 0x04fb, 0x034a: 0x0500, + 0x034c: 0x0505, 0x034e: 0x050a, 0x034f: 0x050f, 0x0350: 0x0514, + 0x036a: 0x051b, 0x036b: 0x0520, 0x036c: 0x0525, 0x036d: 0x052a, 0x036e: 0x052f, 0x036f: 0x0534, + 0x0370: 0x0539, + // Block 0xe, offset 0x380 + 0x038a: 0x0540, 0x038b: 0x0545, + 0x038c: 0x054a, 0x038d: 0x054f, 0x038e: 0x0554, 0x0390: 0x0559, 0x0391: 0x055c, + 0x0392: 0x055f, 0x0393: 0x050a, 0x0394: 0x0520, 0x0395: 0x056c, 0x0396: 0x056f, + 0x03b0: 0x0572, 0x03b1: 0x0575, 0x03b2: 0x0578, 0x03b4: 0x057b, 0x03b5: 0x057e, + 0x03b9: 0x0581, + // Block 0xf, offset 0x3c0 + 0x03c0: 0x0584, 0x03c1: 0x0589, 0x03c3: 0x058e, + 0x03c7: 0x0593, + 0x03cc: 0x0598, 0x03cd: 0x059d, 0x03ce: 0x05a2, + 0x03d9: 0x05a7, + 0x03f9: 0x05ac, + // Block 0x10, offset 0x400 + 0x0410: 0x05b1, 0x0411: 0x05b6, + 0x0413: 0x05bb, 0x0417: 0x05c0, + 0x041c: 0x05c5, 0x041d: 0x05ca, + 0x041e: 0x05cf, + 0x0436: 0x05d4, 0x0437: 0x05d9, + // Block 0x11, offset 0x440 + 0x0441: 0x05de, 0x0442: 0x05e3, + 0x0450: 0x05e8, 0x0451: 0x05ed, + 0x0452: 0x05f2, 0x0453: 0x05f7, 0x0456: 0x05fc, 0x0457: 0x0601, + 0x045a: 0x0606, 0x045b: 0x060b, 0x045c: 0x0610, 0x045d: 0x0615, + 0x045e: 0x061a, 0x045f: 0x061f, 0x0462: 0x0624, 0x0463: 0x0629, + 0x0464: 0x062e, 0x0465: 0x0633, 0x0466: 0x0638, 0x0467: 0x063d, + 0x046a: 0x0642, 0x046b: 0x0647, 0x046c: 0x064c, 0x046d: 0x0651, 0x046e: 0x0656, 0x046f: 0x065b, + 0x0470: 0x0660, 0x0471: 0x0665, 0x0472: 0x066a, 0x0473: 0x066f, 0x0474: 0x0674, 0x0475: 0x0679, + 0x0478: 0x067e, 0x0479: 0x0683, + // Block 0x12, offset 0x480 + 0x0487: 0x0688, + // Block 0x13, offset 0x4c0 + 0x04e2: 0x068d, 0x04e3: 0x0692, + 0x04e4: 0x0697, 0x04e5: 0x069c, 0x04e6: 0x06a1, + // Block 0x14, offset 0x500 + 0x0535: 0x06a6, + 0x0536: 0x06ab, 0x0537: 0x06b0, 0x0538: 0x06b5, + // Block 0x15, offset 0x540 + 0x0540: 0x06ba, 0x0542: 0x06bf, + 0x0553: 0x06c4, + // Block 0x16, offset 0x580 + 0x05a9: 0x06c9, + 0x05b1: 0x06d0, 0x05b4: 0x06d7, + // Block 0x17, offset 0x5c0 + 0x05d8: 0x06de, 0x05d9: 0x06e5, 0x05da: 0x06ec, 0x05db: 0x06f3, 0x05dc: 0x06fa, 0x05dd: 0x0701, + 0x05de: 0x0708, 0x05df: 0x070f, + // Block 0x18, offset 0x600 + 0x060b: 0x0716, + 0x060c: 0x071d, + 0x061c: 0x0724, 0x061d: 0x072b, + 0x061f: 0x0732, + // Block 0x19, offset 0x640 + 0x0673: 0x0739, + 0x0676: 0x0740, + // Block 0x1a, offset 0x680 + 0x0699: 0x0747, 0x069a: 0x074e, 0x069b: 0x0755, + 0x069e: 0x075c, + // Block 0x1b, offset 0x6c0 + 0x06c8: 0x0763, 0x06cb: 0x076a, + 0x06cc: 0x0771, + 0x06dc: 0x0778, 0x06dd: 0x077f, + // Block 0x1c, offset 0x700 + 0x0714: 0x0786, + // Block 0x1d, offset 0x740 + 0x074a: 0x078d, 0x074b: 0x0794, + 0x074c: 0x079b, + // Block 0x1e, offset 0x780 + 0x0788: 0x07a2, + // Block 0x1f, offset 0x7c0 + 0x07c0: 0x07a9, + 0x07c7: 0x07b0, 0x07c8: 0x07b7, 0x07ca: 0x07be, 0x07cb: 0x07c5, + // Block 0x20, offset 0x800 + 0x080a: 0x07cf, 0x080b: 0x07d6, + 0x080c: 0x07dd, + // Block 0x21, offset 0x840 + 0x085a: 0x07e4, 0x085c: 0x07eb, 0x085d: 0x07f2, + 0x085e: 0x07fc, + // Block 0x22, offset 0x880 + 0x08b3: 0x0803, + // Block 0x23, offset 0x8c0 + 0x08f3: 0x080a, + // Block 0x24, offset 0x900 + 0x091c: 0x0811, 0x091d: 0x0818, + // Block 0x25, offset 0x940 + 0x094c: 0x081f, + // Block 0x26, offset 0x980 + 0x0983: 0x0823, + 0x098d: 0x082a, + 0x0992: 0x0831, 0x0997: 0x0838, + 0x099c: 0x083f, + 0x09a9: 0x0846, + 0x09b3: 0x084d, 0x09b5: 0x0854, + 0x09b6: 0x085b, 0x09b7: 0x0862, 0x09b8: 0x086c, 0x09b9: 0x0873, + // Block 0x27, offset 0x9c0 + 0x09c1: 0x087d, + 0x09d3: 0x0884, + 0x09dd: 0x088b, + 0x09e2: 0x0892, + 0x09e7: 0x0899, + 0x09ec: 0x08a0, + 0x09f9: 0x08a7, + // Block 0x28, offset 0xa00 + 0x0a26: 0x08ae, + // Block 0x29, offset 0xa40 + 0x0a7c: 0x08b5, + // Block 0x2a, offset 0xa80 + 0x0a86: 0x08b9, 0x0a88: 0x08c0, 0x0a8a: 0x08c7, + 0x0a8c: 0x08ce, 0x0a8e: 0x08d5, + 0x0a92: 0x08dc, + 0x0abb: 0x08e3, + 0x0abd: 0x08ea, + // Block 0x2b, offset 0xac0 + 0x0ac0: 0x08f1, 0x0ac1: 0x08f8, 0x0ac3: 0x08ff, + // Block 0x2c, offset 0xb00 + 0x0b2c: 0x0906, 0x0b2d: 0x0908, 0x0b2e: 0x090b, + 0x0b30: 0x090d, 0x0b31: 0x090f, 0x0b32: 0x0911, 0x0b33: 0x0914, 0x0b34: 0x0916, 0x0b35: 0x0918, + 0x0b36: 0x091a, 0x0b37: 0x091c, 0x0b38: 0x091e, 0x0b39: 0x0920, 0x0b3a: 0x0922, + 0x0b3c: 0x0924, 0x0b3d: 0x0926, 0x0b3e: 0x0929, 0x0b3f: 0x092b, + // Block 0x2d, offset 0xb40 + 0x0b40: 0x092d, 0x0b41: 0x092f, 0x0b42: 0x0931, 0x0b43: 0x0007, 0x0b44: 0x0933, 0x0b45: 0x0936, + 0x0b46: 0x0939, 0x0b47: 0x093d, 0x0b48: 0x093f, 0x0b49: 0x0941, 0x0b4a: 0x0943, 0x0b4b: 0x0946, + 0x0b4c: 0x0949, 0x0b4d: 0x094c, 0x0b4f: 0x094e, 0x0b50: 0x0950, 0x0b51: 0x0952, + 0x0b52: 0x001e, 0x0b53: 0x0955, 0x0b54: 0x0958, 0x0b55: 0x095c, 0x0b56: 0x0960, 0x0b57: 0x0962, + 0x0b58: 0x0964, 0x0b59: 0x0966, 0x0b5a: 0x096a, 0x0b5b: 0x096d, 0x0b5c: 0x096f, 0x0b5d: 0x0559, + 0x0b5e: 0x0973, 0x0b5f: 0x0976, 0x0b60: 0x056c, 0x0b61: 0x0979, 0x0b62: 0x097c, 0x0b63: 0x049b, + 0x0b64: 0x0964, 0x0b65: 0x096d, 0x0b66: 0x0559, 0x0b67: 0x0973, 0x0b68: 0x0575, 0x0b69: 0x056c, + 0x0b6a: 0x0979, + 0x0b78: 0x097e, + // Block 0x2e, offset 0xb80 + 0x0b9b: 0x0981, 0x0b9c: 0x0984, 0x0b9d: 0x0986, + 0x0b9e: 0x0989, 0x0b9f: 0x0949, 0x0ba0: 0x098c, 0x0ba1: 0x098e, 0x0ba2: 0x0991, 0x0ba3: 0x0994, + 0x0ba4: 0x0997, 0x0ba5: 0x099a, 0x0ba6: 0x099d, 0x0ba7: 0x09a0, 0x0ba8: 0x09a4, 0x0ba9: 0x09a7, + 0x0baa: 0x09aa, 0x0bab: 0x09ae, 0x0bac: 0x09b1, 0x0bad: 0x09b4, 0x0bae: 0x09b7, 0x0baf: 0x09ba, + 0x0bb0: 0x09bd, 0x0bb1: 0x09c0, 0x0bb2: 0x09c3, 0x0bb3: 0x09c6, 0x0bb4: 0x09c9, 0x0bb5: 0x09cc, + 0x0bb6: 0x09cf, 0x0bb7: 0x09d2, 0x0bb8: 0x09d5, 0x0bb9: 0x09d9, 0x0bba: 0x09dc, 0x0bbb: 0x09df, + 0x0bbc: 0x09e1, 0x0bbd: 0x09e4, 0x0bbe: 0x09e7, 0x0bbf: 0x055c, + // Block 0x2f, offset 0xbc0 + 0x0bc0: 0x09ea, 0x0bc1: 0x09ee, 0x0bc2: 0x09f2, 0x0bc3: 0x09f6, 0x0bc4: 0x09fa, 0x0bc5: 0x09fe, + 0x0bc6: 0x0a02, 0x0bc7: 0x0a06, 0x0bc8: 0x0a0a, 0x0bc9: 0x0a10, 0x0bca: 0x0a16, 0x0bcb: 0x0a1a, + 0x0bcc: 0x0a1e, 0x0bcd: 0x0a22, 0x0bce: 0x0a26, 0x0bcf: 0x0a2a, 0x0bd0: 0x0a2e, 0x0bd1: 0x0a32, + 0x0bd2: 0x0a36, 0x0bd3: 0x0a3a, 0x0bd4: 0x0a3e, 0x0bd5: 0x0a44, 0x0bd6: 0x0a4a, 0x0bd7: 0x0a50, + 0x0bd8: 0x0a56, 0x0bd9: 0x0a5a, 0x0bda: 0x0a5e, 0x0bdb: 0x0a62, 0x0bdc: 0x0a66, 0x0bdd: 0x0a6c, + 0x0bde: 0x0a72, 0x0bdf: 0x0a76, 0x0be0: 0x0a7a, 0x0be1: 0x0a7e, 0x0be2: 0x0a82, 0x0be3: 0x0a86, + 0x0be4: 0x0a8a, 0x0be5: 0x0a8e, 0x0be6: 0x0a92, 0x0be7: 0x0a96, 0x0be8: 0x0a9a, 0x0be9: 0x0a9e, + 0x0bea: 0x0aa2, 0x0beb: 0x0aa6, 0x0bec: 0x0aaa, 0x0bed: 0x0aae, 0x0bee: 0x0ab2, 0x0bef: 0x0ab8, + 0x0bf0: 0x0abe, 0x0bf1: 0x0ac2, 0x0bf2: 0x0ac6, 0x0bf3: 0x0aca, 0x0bf4: 0x0ace, 0x0bf5: 0x0ad2, + 0x0bf6: 0x0ad6, 0x0bf7: 0x0ada, 0x0bf8: 0x0ade, 0x0bf9: 0x0ae4, 0x0bfa: 0x0aea, 0x0bfb: 0x0aee, + 0x0bfc: 0x0af2, 0x0bfd: 0x0af6, 0x0bfe: 0x0afa, 0x0bff: 0x0afe, + // Block 0x30, offset 0xc00 + 0x0c00: 0x0b02, 0x0c01: 0x0b06, 0x0c02: 0x0b0a, 0x0c03: 0x0b0e, 0x0c04: 0x0b12, 0x0c05: 0x0b16, + 0x0c06: 0x0b1a, 0x0c07: 0x0b1e, 0x0c08: 0x0b22, 0x0c09: 0x0b26, 0x0c0a: 0x0b2a, 0x0c0b: 0x0b2e, + 0x0c0c: 0x0b32, 0x0c0d: 0x0b38, 0x0c0e: 0x0b3e, 0x0c0f: 0x0b44, 0x0c10: 0x0b4a, 0x0c11: 0x0b50, + 0x0c12: 0x0b56, 0x0c13: 0x0b5c, 0x0c14: 0x0b62, 0x0c15: 0x0b66, 0x0c16: 0x0b6a, 0x0c17: 0x0b6e, + 0x0c18: 0x0b72, 0x0c19: 0x0b76, 0x0c1a: 0x0b7a, 0x0c1b: 0x0b7e, 0x0c1c: 0x0b82, 0x0c1d: 0x0b88, + 0x0c1e: 0x0b8e, 0x0c1f: 0x0b92, 0x0c20: 0x0b96, 0x0c21: 0x0b9a, 0x0c22: 0x0b9e, 0x0c23: 0x0ba2, + 0x0c24: 0x0ba6, 0x0c25: 0x0bac, 0x0c26: 0x0bb2, 0x0c27: 0x0bb8, 0x0c28: 0x0bbe, 0x0c29: 0x0bc4, + 0x0c2a: 0x0bca, 0x0c2b: 0x0bce, 0x0c2c: 0x0bd2, 0x0c2d: 0x0bd6, 0x0c2e: 0x0bda, 0x0c2f: 0x0bde, + 0x0c30: 0x0be2, 0x0c31: 0x0be6, 0x0c32: 0x0bea, 0x0c33: 0x0bee, 0x0c34: 0x0bf2, 0x0c35: 0x0bf6, + 0x0c36: 0x0bfa, 0x0c37: 0x0bfe, 0x0c38: 0x0c02, 0x0c39: 0x0c08, 0x0c3a: 0x0c0e, 0x0c3b: 0x0c14, + 0x0c3c: 0x0c1a, 0x0c3d: 0x0c1e, 0x0c3e: 0x0c22, 0x0c3f: 0x0c26, + // Block 0x31, offset 0xc40 + 0x0c40: 0x0c2a, 0x0c41: 0x0c2e, 0x0c42: 0x0c32, 0x0c43: 0x0c36, 0x0c44: 0x0c3a, 0x0c45: 0x0c3e, + 0x0c46: 0x0c42, 0x0c47: 0x0c46, 0x0c48: 0x0c4a, 0x0c49: 0x0c4e, 0x0c4a: 0x0c52, 0x0c4b: 0x0c56, + 0x0c4c: 0x0c5a, 0x0c4d: 0x0c5e, 0x0c4e: 0x0c62, 0x0c4f: 0x0c66, 0x0c50: 0x0c6a, 0x0c51: 0x0c6e, + 0x0c52: 0x0c72, 0x0c53: 0x0c76, 0x0c54: 0x0c7a, 0x0c55: 0x0c7e, 0x0c56: 0x0c82, 0x0c57: 0x0c86, + 0x0c58: 0x0c8a, 0x0c59: 0x0c8e, 0x0c5a: 0x0c92, 0x0c5b: 0x0b9a, + 0x0c60: 0x0c9b, 0x0c61: 0x0c9f, 0x0c62: 0x0ca3, 0x0c63: 0x0ca7, + 0x0c64: 0x0cab, 0x0c65: 0x0cb1, 0x0c66: 0x0cb7, 0x0c67: 0x0cbd, 0x0c68: 0x0cc3, 0x0c69: 0x0cc9, + 0x0c6a: 0x0ccf, 0x0c6b: 0x0cd5, 0x0c6c: 0x0cdb, 0x0c6d: 0x0ce1, 0x0c6e: 0x0ce7, 0x0c6f: 0x0ced, + 0x0c70: 0x0cf3, 0x0c71: 0x0cf9, 0x0c72: 0x0cff, 0x0c73: 0x0d05, 0x0c74: 0x0d0b, 0x0c75: 0x0d11, + 0x0c76: 0x0d17, 0x0c77: 0x0d1d, 0x0c78: 0x0d23, 0x0c79: 0x0d27, 0x0c7a: 0x0d2b, 0x0c7b: 0x0d2f, + 0x0c7c: 0x0d33, 0x0c7d: 0x0d37, 0x0c7e: 0x0d3b, 0x0c7f: 0x0d41, + // Block 0x32, offset 0xc80 + 0x0c80: 0x0d47, 0x0c81: 0x0d4d, 0x0c82: 0x0d53, 0x0c83: 0x0d59, 0x0c84: 0x0d5f, 0x0c85: 0x0d65, + 0x0c86: 0x0d6b, 0x0c87: 0x0d71, 0x0c88: 0x0d77, 0x0c89: 0x0d7b, 0x0c8a: 0x0d7f, 0x0c8b: 0x0d83, + 0x0c8c: 0x0d87, 0x0c8d: 0x0d8b, 0x0c8e: 0x0d8f, 0x0c8f: 0x0d93, 0x0c90: 0x0d97, 0x0c91: 0x0d9d, + 0x0c92: 0x0da3, 0x0c93: 0x0da9, 0x0c94: 0x0daf, 0x0c95: 0x0db5, 0x0c96: 0x0dbb, 0x0c97: 0x0dc1, + 0x0c98: 0x0dc7, 0x0c99: 0x0dcd, 0x0c9a: 0x0dd3, 0x0c9b: 0x0dd9, 0x0c9c: 0x0ddf, 0x0c9d: 0x0de5, + 0x0c9e: 0x0deb, 0x0c9f: 0x0df1, 0x0ca0: 0x0df7, 0x0ca1: 0x0dfd, 0x0ca2: 0x0e03, 0x0ca3: 0x0e09, + 0x0ca4: 0x0e0f, 0x0ca5: 0x0e13, 0x0ca6: 0x0e17, 0x0ca7: 0x0e1b, 0x0ca8: 0x0e1f, 0x0ca9: 0x0e25, + 0x0caa: 0x0e2b, 0x0cab: 0x0e31, 0x0cac: 0x0e37, 0x0cad: 0x0e3d, 0x0cae: 0x0e43, 0x0caf: 0x0e49, + 0x0cb0: 0x0e4f, 0x0cb1: 0x0e55, 0x0cb2: 0x0e5b, 0x0cb3: 0x0e5f, 0x0cb4: 0x0e63, 0x0cb5: 0x0e67, + 0x0cb6: 0x0e6b, 0x0cb7: 0x0e6f, 0x0cb8: 0x0e73, 0x0cb9: 0x0e77, + // Block 0x33, offset 0xcc0 + 0x0cc0: 0x0e7b, 0x0cc1: 0x0e80, 0x0cc2: 0x0e85, 0x0cc3: 0x0e8c, 0x0cc4: 0x0e93, 0x0cc5: 0x0e9a, + 0x0cc6: 0x0ea1, 0x0cc7: 0x0ea8, 0x0cc8: 0x0eaf, 0x0cc9: 0x0eb4, 0x0cca: 0x0eb9, 0x0ccb: 0x0ec0, + 0x0ccc: 0x0ec7, 0x0ccd: 0x0ece, 0x0cce: 0x0ed5, 0x0ccf: 0x0edc, 0x0cd0: 0x0ee3, 0x0cd1: 0x0ee8, + 0x0cd2: 0x0eed, 0x0cd3: 0x0ef4, 0x0cd4: 0x0efb, 0x0cd5: 0x0f02, + 0x0cd8: 0x0f09, 0x0cd9: 0x0f0e, 0x0cda: 0x0f13, 0x0cdb: 0x0f1a, 0x0cdc: 0x0f21, 0x0cdd: 0x0f28, + 0x0ce0: 0x0f2f, 0x0ce1: 0x0f34, 0x0ce2: 0x0f39, 0x0ce3: 0x0f40, + 0x0ce4: 0x0f47, 0x0ce5: 0x0f4e, 0x0ce6: 0x0f55, 0x0ce7: 0x0f5c, 0x0ce8: 0x0f63, 0x0ce9: 0x0f68, + 0x0cea: 0x0f6d, 0x0ceb: 0x0f74, 0x0cec: 0x0f7b, 0x0ced: 0x0f82, 0x0cee: 0x0f89, 0x0cef: 0x0f90, + 0x0cf0: 0x0f97, 0x0cf1: 0x0f9c, 0x0cf2: 0x0fa1, 0x0cf3: 0x0fa8, 0x0cf4: 0x0faf, 0x0cf5: 0x0fb6, + 0x0cf6: 0x0fbd, 0x0cf7: 0x0fc4, 0x0cf8: 0x0fcb, 0x0cf9: 0x0fd0, 0x0cfa: 0x0fd5, 0x0cfb: 0x0fdc, + 0x0cfc: 0x0fe3, 0x0cfd: 0x0fea, 0x0cfe: 0x0ff1, 0x0cff: 0x0ff8, + // Block 0x34, offset 0xd00 + 0x0d00: 0x0fff, 0x0d01: 0x1004, 0x0d02: 0x1009, 0x0d03: 0x1010, 0x0d04: 0x1017, 0x0d05: 0x101e, + 0x0d08: 0x1025, 0x0d09: 0x102a, 0x0d0a: 0x102f, 0x0d0b: 0x1036, + 0x0d0c: 0x103d, 0x0d0d: 0x1044, 0x0d10: 0x104b, 0x0d11: 0x1050, + 0x0d12: 0x1055, 0x0d13: 0x105c, 0x0d14: 0x1063, 0x0d15: 0x106a, 0x0d16: 0x1071, 0x0d17: 0x1078, + 0x0d19: 0x107f, 0x0d1b: 0x1084, 0x0d1d: 0x108b, + 0x0d1f: 0x1092, 0x0d20: 0x1099, 0x0d21: 0x109e, 0x0d22: 0x10a3, 0x0d23: 0x10aa, + 0x0d24: 0x10b1, 0x0d25: 0x10b8, 0x0d26: 0x10bf, 0x0d27: 0x10c6, 0x0d28: 0x10cd, 0x0d29: 0x10d2, + 0x0d2a: 0x10d7, 0x0d2b: 0x10de, 0x0d2c: 0x10e5, 0x0d2d: 0x10ec, 0x0d2e: 0x10f3, 0x0d2f: 0x10fa, + 0x0d30: 0x1101, 0x0d31: 0x0525, 0x0d32: 0x1106, 0x0d33: 0x052a, 0x0d34: 0x110b, 0x0d35: 0x052f, + 0x0d36: 0x1110, 0x0d37: 0x0534, 0x0d38: 0x1115, 0x0d39: 0x054a, 0x0d3a: 0x111a, 0x0d3b: 0x054f, + 0x0d3c: 0x111f, 0x0d3d: 0x0554, + // Block 0x35, offset 0xd40 + 0x0d40: 0x1124, 0x0d41: 0x112b, 0x0d42: 0x1132, 0x0d43: 0x113b, 0x0d44: 0x1144, 0x0d45: 0x114d, + 0x0d46: 0x1156, 0x0d47: 0x115f, 0x0d48: 0x1168, 0x0d49: 0x116f, 0x0d4a: 0x1176, 0x0d4b: 0x117f, + 0x0d4c: 0x1188, 0x0d4d: 0x1191, 0x0d4e: 0x119a, 0x0d4f: 0x11a3, 0x0d50: 0x11ac, 0x0d51: 0x11b3, + 0x0d52: 0x11ba, 0x0d53: 0x11c3, 0x0d54: 0x11cc, 0x0d55: 0x11d5, 0x0d56: 0x11de, 0x0d57: 0x11e7, + 0x0d58: 0x11f0, 0x0d59: 0x11f7, 0x0d5a: 0x11fe, 0x0d5b: 0x1207, 0x0d5c: 0x1210, 0x0d5d: 0x1219, + 0x0d5e: 0x1222, 0x0d5f: 0x122b, 0x0d60: 0x1234, 0x0d61: 0x123b, 0x0d62: 0x1242, 0x0d63: 0x124b, + 0x0d64: 0x1254, 0x0d65: 0x125d, 0x0d66: 0x1266, 0x0d67: 0x126f, 0x0d68: 0x1278, 0x0d69: 0x127f, + 0x0d6a: 0x1286, 0x0d6b: 0x128f, 0x0d6c: 0x1298, 0x0d6d: 0x12a1, 0x0d6e: 0x12aa, 0x0d6f: 0x12b3, + 0x0d70: 0x12bc, 0x0d71: 0x12c1, 0x0d72: 0x12c6, 0x0d73: 0x12cd, 0x0d74: 0x12d2, + 0x0d76: 0x12d9, 0x0d77: 0x12de, 0x0d78: 0x12e5, 0x0d79: 0x12ea, 0x0d7a: 0x12ef, 0x0d7b: 0x04ee, + 0x0d7c: 0x12f4, 0x0d7d: 0x12f9, 0x0d7e: 0x12fd, 0x0d7f: 0x12f9, + // Block 0x36, offset 0xd80 + 0x0d80: 0x1300, 0x0d81: 0x1309, 0x0d82: 0x130f, 0x0d83: 0x1316, 0x0d84: 0x131b, + 0x0d86: 0x1322, 0x0d87: 0x1327, 0x0d88: 0x132e, 0x0d89: 0x04f6, 0x0d8a: 0x1333, 0x0d8b: 0x04fb, + 0x0d8c: 0x1338, 0x0d8d: 0x1343, 0x0d8e: 0x134f, 0x0d8f: 0x135b, 0x0d90: 0x1361, 0x0d91: 0x1366, + 0x0d92: 0x136b, 0x0d93: 0x0514, 0x0d96: 0x1372, 0x0d97: 0x1377, + 0x0d98: 0x137e, 0x0d99: 0x1383, 0x0d9a: 0x1388, 0x0d9b: 0x0500, 0x0d9d: 0x1393, + 0x0d9e: 0x139f, 0x0d9f: 0x13ab, 0x0da0: 0x13b1, 0x0da1: 0x13b6, 0x0da2: 0x13bb, 0x0da3: 0x0539, + 0x0da4: 0x13c2, 0x0da5: 0x13c7, 0x0da6: 0x13cc, 0x0da7: 0x13d1, 0x0da8: 0x13d8, 0x0da9: 0x13dd, + 0x0daa: 0x13e2, 0x0dab: 0x050a, 0x0dac: 0x13e7, 0x0dad: 0x13f1, 0x0dae: 0x04e8, 0x0daf: 0x13f7, + 0x0db2: 0x13f9, 0x0db3: 0x1400, 0x0db4: 0x1405, + 0x0db6: 0x140c, 0x0db7: 0x1411, 0x0db8: 0x1418, 0x0db9: 0x0505, 0x0dba: 0x141d, 0x0dbb: 0x050f, + 0x0dbc: 0x1422, 0x0dbd: 0x0011, 0x0dbe: 0x142a, + // Block 0x37, offset 0xdc0 + 0x0dc0: 0x0001, 0x0dc1: 0x0001, 0x0dc2: 0x0001, 0x0dc3: 0x0001, 0x0dc4: 0x0001, 0x0dc5: 0x0001, + 0x0dc6: 0x0001, 0x0dc7: 0x0001, 0x0dc8: 0x0001, 0x0dc9: 0x0001, 0x0dca: 0x0001, + 0x0dd1: 0x1436, + 0x0dd7: 0x143a, + 0x0de4: 0x143e, 0x0de5: 0x1440, 0x0de6: 0x1443, + 0x0def: 0x0001, + 0x0df3: 0x1447, 0x0df4: 0x144e, + 0x0df6: 0x1458, 0x0df7: 0x145f, + 0x0dfc: 0x1469, 0x0dfe: 0x146c, + // Block 0x38, offset 0xe00 + 0x0e07: 0x1470, 0x0e08: 0x1473, 0x0e09: 0x1476, + 0x0e17: 0x1479, + 0x0e1f: 0x0001, + 0x0e30: 0x1486, 0x0e31: 0x097c, 0x0e34: 0x1488, 0x0e35: 0x148a, + 0x0e36: 0x148c, 0x0e37: 0x148e, 0x0e38: 0x1490, 0x0e39: 0x1492, 0x0e3a: 0x1494, 0x0e3b: 0x1496, + 0x0e3c: 0x149a, 0x0e3d: 0x149c, 0x0e3e: 0x149e, 0x0e3f: 0x14a0, + // Block 0x39, offset 0xe40 + 0x0e40: 0x1486, 0x0e41: 0x001c, 0x0e42: 0x000d, 0x0e43: 0x000f, 0x0e44: 0x1488, 0x0e45: 0x148a, + 0x0e46: 0x148c, 0x0e47: 0x148e, 0x0e48: 0x1490, 0x0e49: 0x1492, 0x0e4a: 0x1494, 0x0e4b: 0x1496, + 0x0e4c: 0x149a, 0x0e4d: 0x149c, 0x0e4e: 0x149e, 0x0e50: 0x0007, 0x0e51: 0x0941, + 0x0e52: 0x001e, 0x0e53: 0x04c7, 0x0e54: 0x0943, 0x0e55: 0x0494, 0x0e56: 0x094e, 0x0e57: 0x04c5, + 0x0e58: 0x0950, 0x0e59: 0x14a0, 0x0e5a: 0x0960, 0x0e5b: 0x02c8, 0x0e5c: 0x0962, + 0x0e68: 0x14a2, + // Block 0x3a, offset 0xe80 + 0x0e80: 0x14a5, 0x0e81: 0x14a9, 0x0e82: 0x14ad, 0x0e83: 0x14af, 0x0e85: 0x14b3, + 0x0e86: 0x14b7, 0x0e87: 0x14bb, 0x0e89: 0x14be, 0x0e8a: 0x094c, 0x0e8b: 0x0916, + 0x0e8c: 0x0916, 0x0e8d: 0x0916, 0x0e8e: 0x0494, 0x0e8f: 0x14c2, 0x0e90: 0x0918, 0x0e91: 0x0918, + 0x0e92: 0x091e, 0x0e93: 0x04c5, 0x0e95: 0x0922, 0x0e96: 0x14c5, + 0x0e99: 0x0929, 0x0e9a: 0x14c8, 0x0e9b: 0x092b, 0x0e9c: 0x092b, 0x0e9d: 0x092b, + 0x0ea0: 0x14ca, 0x0ea1: 0x14cd, 0x0ea2: 0x14d1, + 0x0ea4: 0x14d4, 0x0ea6: 0x14d6, 0x0ea8: 0x14d4, + 0x0eaa: 0x091c, 0x0eab: 0x0046, 0x0eac: 0x090b, 0x0ead: 0x14ad, 0x0eaf: 0x0941, + 0x0eb0: 0x090f, 0x0eb1: 0x14d9, 0x0eb3: 0x0920, 0x0eb4: 0x001e, 0x0eb5: 0x14db, + 0x0eb6: 0x14de, 0x0eb7: 0x14e1, 0x0eb8: 0x14e4, 0x0eb9: 0x097c, 0x0ebb: 0x14e7, + 0x0ebc: 0x056f, 0x0ebd: 0x0973, 0x0ebe: 0x14eb, 0x0ebf: 0x14ee, + // Block 0x3b, offset 0xec0 + 0x0ec0: 0x14f1, 0x0ec5: 0x090d, + 0x0ec6: 0x093f, 0x0ec7: 0x0941, 0x0ec8: 0x097c, 0x0ec9: 0x0499, + 0x0ed0: 0x14f5, 0x0ed1: 0x14fb, + 0x0ed2: 0x1501, 0x0ed3: 0x1508, 0x0ed4: 0x150e, 0x0ed5: 0x1514, 0x0ed6: 0x151a, 0x0ed7: 0x1520, + 0x0ed8: 0x1526, 0x0ed9: 0x152c, 0x0eda: 0x1532, 0x0edb: 0x1538, 0x0edc: 0x153e, 0x0edd: 0x1544, + 0x0ede: 0x154a, 0x0edf: 0x1550, 0x0ee0: 0x0918, 0x0ee1: 0x1555, 0x0ee2: 0x1558, 0x0ee3: 0x155c, + 0x0ee4: 0x155f, 0x0ee5: 0x1561, 0x0ee6: 0x1564, 0x0ee7: 0x1568, 0x0ee8: 0x156d, 0x0ee9: 0x1570, + 0x0eea: 0x1572, 0x0eeb: 0x1575, 0x0eec: 0x091e, 0x0eed: 0x14ad, 0x0eee: 0x090d, 0x0eef: 0x0920, + 0x0ef0: 0x097c, 0x0ef1: 0x1579, 0x0ef2: 0x157c, 0x0ef3: 0x1580, 0x0ef4: 0x096d, 0x0ef5: 0x1583, + 0x0ef6: 0x1586, 0x0ef7: 0x158a, 0x0ef8: 0x158f, 0x0ef9: 0x04c7, 0x0efa: 0x1592, 0x0efb: 0x1595, + 0x0efc: 0x04c5, 0x0efd: 0x0984, 0x0efe: 0x093f, 0x0eff: 0x0950, + // Block 0x3c, offset 0xf00 + 0x0f09: 0x1599, + 0x0f1a: 0x159f, 0x0f1b: 0x15a5, + 0x0f2e: 0x15ab, + // Block 0x3d, offset 0xf40 + 0x0f4d: 0x15b1, 0x0f4e: 0x15b7, 0x0f4f: 0x15bd, + // Block 0x3e, offset 0xf80 + 0x0f84: 0x15c3, + 0x0f89: 0x15c9, + 0x0f8c: 0x15cf, + 0x0fa4: 0x15d5, 0x0fa6: 0x15db, + 0x0fac: 0x15e1, 0x0fad: 0x15e8, 0x0faf: 0x15f2, + 0x0fb0: 0x15f9, + // Block 0x3f, offset 0xfc0 + 0x0fc1: 0x1603, 0x0fc4: 0x1609, + 0x0fc7: 0x160f, 0x0fc9: 0x1615, + 0x0fe0: 0x161b, 0x0fe2: 0x161f, + 0x0fed: 0x1625, 0x0fee: 0x162b, 0x0fef: 0x162f, + 0x0ff0: 0x1633, 0x0ff1: 0x1639, 0x0ff4: 0x163f, 0x0ff5: 0x1645, + 0x0ff8: 0x164b, 0x0ff9: 0x1651, + // Block 0x40, offset 0x1000 + 0x1000: 0x1657, 0x1001: 0x165d, 0x1004: 0x1663, 0x1005: 0x1669, + 0x1008: 0x166f, 0x1009: 0x1675, + 0x102c: 0x167b, 0x102d: 0x1681, 0x102e: 0x1687, 0x102f: 0x168d, + // Block 0x41, offset 0x1040 + 0x1060: 0x1693, 0x1061: 0x1699, 0x1062: 0x169f, 0x1063: 0x16a5, + 0x106a: 0x16ab, 0x106b: 0x16b1, 0x106c: 0x16b7, 0x106d: 0x16bd, + // Block 0x42, offset 0x1080 + 0x10a9: 0x16c3, + 0x10aa: 0x16c7, + // Block 0x43, offset 0x10c0 + 0x10e0: 0x001c, 0x10e1: 0x000d, 0x10e2: 0x000f, 0x10e3: 0x1488, + 0x10e4: 0x148a, 0x10e5: 0x148c, 0x10e6: 0x148e, 0x10e7: 0x1490, 0x10e8: 0x1492, 0x10e9: 0x16cb, + 0x10ea: 0x16ce, 0x10eb: 0x16d1, 0x10ec: 0x16d4, 0x10ed: 0x16d7, 0x10ee: 0x16da, 0x10ef: 0x16dd, + 0x10f0: 0x16e0, 0x10f1: 0x16e3, 0x10f2: 0x16e6, 0x10f3: 0x16e9, 0x10f4: 0x16ec, 0x10f5: 0x16f0, + 0x10f6: 0x16f4, 0x10f7: 0x16f8, 0x10f8: 0x16fc, 0x10f9: 0x1700, 0x10fa: 0x1704, 0x10fb: 0x1708, + 0x10fc: 0x170c, 0x10fd: 0x1710, 0x10fe: 0x1715, 0x10ff: 0x171a, + // Block 0x44, offset 0x1100 + 0x1100: 0x171f, 0x1101: 0x1724, 0x1102: 0x1729, 0x1103: 0x172e, 0x1104: 0x1733, 0x1105: 0x1738, + 0x1106: 0x173d, 0x1107: 0x1742, 0x1108: 0x1747, 0x1109: 0x174a, 0x110a: 0x174d, 0x110b: 0x1750, + 0x110c: 0x1753, 0x110d: 0x1756, 0x110e: 0x1759, 0x110f: 0x175c, 0x1110: 0x175f, 0x1111: 0x1762, + 0x1112: 0x1766, 0x1113: 0x176a, 0x1114: 0x176e, 0x1115: 0x1772, 0x1116: 0x1776, 0x1117: 0x177a, + 0x1118: 0x177e, 0x1119: 0x1782, 0x111a: 0x1786, 0x111b: 0x178a, 0x111c: 0x178e, 0x111d: 0x1792, + 0x111e: 0x1796, 0x111f: 0x179a, 0x1120: 0x179e, 0x1121: 0x17a2, 0x1122: 0x17a6, 0x1123: 0x17aa, + 0x1124: 0x17ae, 0x1125: 0x17b2, 0x1126: 0x17b6, 0x1127: 0x17ba, 0x1128: 0x17be, 0x1129: 0x17c2, + 0x112a: 0x17c6, 0x112b: 0x17ca, 0x112c: 0x17ce, 0x112d: 0x17d2, 0x112e: 0x17d6, 0x112f: 0x17da, + 0x1130: 0x17de, 0x1131: 0x17e2, 0x1132: 0x17e6, 0x1133: 0x17ea, 0x1134: 0x17ee, 0x1135: 0x17f2, + 0x1136: 0x0906, 0x1137: 0x090b, 0x1138: 0x14ad, 0x1139: 0x090d, 0x113a: 0x090f, 0x113b: 0x14d9, + 0x113c: 0x0914, 0x113d: 0x0916, 0x113e: 0x0918, 0x113f: 0x091a, + // Block 0x45, offset 0x1140 + 0x1140: 0x091c, 0x1141: 0x091e, 0x1142: 0x0920, 0x1143: 0x0922, 0x1144: 0x0924, 0x1145: 0x0929, + 0x1146: 0x14c8, 0x1147: 0x092b, 0x1148: 0x17f6, 0x1149: 0x092d, 0x114a: 0x092f, 0x114b: 0x155f, + 0x114c: 0x0931, 0x114d: 0x1570, 0x114e: 0x17f8, 0x114f: 0x14d4, 0x1150: 0x0007, 0x1151: 0x093d, + 0x1152: 0x0984, 0x1153: 0x093f, 0x1154: 0x0941, 0x1155: 0x098c, 0x1156: 0x094c, 0x1157: 0x0494, + 0x1158: 0x097c, 0x1159: 0x0499, 0x115a: 0x094e, 0x115b: 0x04c5, 0x115c: 0x0950, 0x115d: 0x14a0, + 0x115e: 0x001e, 0x115f: 0x0960, 0x1160: 0x17fa, 0x1161: 0x049b, 0x1162: 0x02c8, 0x1163: 0x0962, + 0x1164: 0x0964, 0x1165: 0x096d, 0x1166: 0x04a6, 0x1167: 0x04c7, 0x1168: 0x04a8, 0x1169: 0x09df, + 0x116a: 0x1486, + // Block 0x46, offset 0x1180 + 0x118c: 0x17fc, + // Block 0x47, offset 0x11c0 + 0x11f4: 0x1809, 0x11f5: 0x180d, + 0x11f6: 0x1810, + // Block 0x48, offset 0x1200 + 0x121c: 0x1814, + // Block 0x49, offset 0x1240 + 0x127c: 0x0499, 0x127d: 0x155f, + // Block 0x4a, offset 0x1280 + 0x12af: 0x181a, + // Block 0x4b, offset 0x12c0 + 0x12df: 0x181e, + // Block 0x4c, offset 0x1300 + 0x1333: 0x1822, + // Block 0x4d, offset 0x1340 + 0x1340: 0x1826, 0x1341: 0x182a, 0x1342: 0x182e, 0x1343: 0x1832, 0x1344: 0x1836, 0x1345: 0x183a, + 0x1346: 0x183e, 0x1347: 0x1842, 0x1348: 0x1846, 0x1349: 0x184a, 0x134a: 0x184e, 0x134b: 0x1852, + 0x134c: 0x1856, 0x134d: 0x185a, 0x134e: 0x185e, 0x134f: 0x1862, 0x1350: 0x1866, 0x1351: 0x186a, + 0x1352: 0x186e, 0x1353: 0x1872, 0x1354: 0x1876, 0x1355: 0x187a, 0x1356: 0x187e, 0x1357: 0x1882, + 0x1358: 0x1886, 0x1359: 0x188a, 0x135a: 0x188e, 0x135b: 0x1892, 0x135c: 0x1896, 0x135d: 0x189a, + 0x135e: 0x189e, 0x135f: 0x18a2, 0x1360: 0x18a6, 0x1361: 0x18aa, 0x1362: 0x18ae, 0x1363: 0x18b2, + 0x1364: 0x18b6, 0x1365: 0x18ba, 0x1366: 0x18be, 0x1367: 0x18c2, 0x1368: 0x18c6, 0x1369: 0x18ca, + 0x136a: 0x18ce, 0x136b: 0x18d2, 0x136c: 0x18d6, 0x136d: 0x18da, 0x136e: 0x18de, 0x136f: 0x18e2, + 0x1370: 0x18e6, 0x1371: 0x18ea, 0x1372: 0x18ee, 0x1373: 0x18f2, 0x1374: 0x18f6, 0x1375: 0x18fa, + 0x1376: 0x18fe, 0x1377: 0x1902, 0x1378: 0x1906, 0x1379: 0x190a, 0x137a: 0x190e, 0x137b: 0x1912, + 0x137c: 0x1916, 0x137d: 0x191a, 0x137e: 0x191e, 0x137f: 0x1922, + // Block 0x4e, offset 0x1380 + 0x1380: 0x1926, 0x1381: 0x192a, 0x1382: 0x192e, 0x1383: 0x1932, 0x1384: 0x1936, 0x1385: 0x193a, + 0x1386: 0x193e, 0x1387: 0x1942, 0x1388: 0x1946, 0x1389: 0x194a, 0x138a: 0x194e, 0x138b: 0x1952, + 0x138c: 0x1956, 0x138d: 0x195a, 0x138e: 0x195e, 0x138f: 0x1962, 0x1390: 0x1966, 0x1391: 0x196a, + 0x1392: 0x196e, 0x1393: 0x1972, 0x1394: 0x1976, 0x1395: 0x197a, 0x1396: 0x197e, 0x1397: 0x1982, + 0x1398: 0x1986, 0x1399: 0x198a, 0x139a: 0x198e, 0x139b: 0x1992, 0x139c: 0x1996, 0x139d: 0x199a, + 0x139e: 0x199e, 0x139f: 0x19a2, 0x13a0: 0x19a6, 0x13a1: 0x19aa, 0x13a2: 0x19ae, 0x13a3: 0x19b2, + 0x13a4: 0x19b6, 0x13a5: 0x19ba, 0x13a6: 0x19be, 0x13a7: 0x19c2, 0x13a8: 0x19c6, 0x13a9: 0x19ca, + 0x13aa: 0x19ce, 0x13ab: 0x19d2, 0x13ac: 0x19d6, 0x13ad: 0x19da, 0x13ae: 0x19de, 0x13af: 0x19e2, + 0x13b0: 0x19e6, 0x13b1: 0x19ea, 0x13b2: 0x19ee, 0x13b3: 0x19f2, 0x13b4: 0x19f6, 0x13b5: 0x19fa, + 0x13b6: 0x19fe, 0x13b7: 0x1a02, 0x13b8: 0x1a06, 0x13b9: 0x1a0a, 0x13ba: 0x1a0e, 0x13bb: 0x1a12, + 0x13bc: 0x1a16, 0x13bd: 0x1a1a, 0x13be: 0x1a1e, 0x13bf: 0x1a22, + // Block 0x4f, offset 0x13c0 + 0x13c0: 0x1a26, 0x13c1: 0x1a2a, 0x13c2: 0x1a2e, 0x13c3: 0x1a32, 0x13c4: 0x1a36, 0x13c5: 0x1a3a, + 0x13c6: 0x1a3e, 0x13c7: 0x1a42, 0x13c8: 0x1a46, 0x13c9: 0x1a4a, 0x13ca: 0x1a4e, 0x13cb: 0x1a52, + 0x13cc: 0x1a56, 0x13cd: 0x1a5a, 0x13ce: 0x1a5e, 0x13cf: 0x1a62, 0x13d0: 0x1a66, 0x13d1: 0x1a6a, + 0x13d2: 0x1a6e, 0x13d3: 0x1a72, 0x13d4: 0x1a76, 0x13d5: 0x1a7a, 0x13d6: 0x1a7e, 0x13d7: 0x1a82, + 0x13d8: 0x1a86, 0x13d9: 0x1a8a, 0x13da: 0x1a8e, 0x13db: 0x1a92, 0x13dc: 0x1a96, 0x13dd: 0x1a9a, + 0x13de: 0x1a9e, 0x13df: 0x1aa2, 0x13e0: 0x1aa6, 0x13e1: 0x1aaa, 0x13e2: 0x1aae, 0x13e3: 0x1ab2, + 0x13e4: 0x1ab6, 0x13e5: 0x1aba, 0x13e6: 0x1abe, 0x13e7: 0x1ac2, 0x13e8: 0x1ac6, 0x13e9: 0x1aca, + 0x13ea: 0x1ace, 0x13eb: 0x1ad2, 0x13ec: 0x1ad6, 0x13ed: 0x1ada, 0x13ee: 0x1ade, 0x13ef: 0x1ae2, + 0x13f0: 0x1ae6, 0x13f1: 0x1aea, 0x13f2: 0x1aee, 0x13f3: 0x1af2, 0x13f4: 0x1af6, 0x13f5: 0x1afa, + 0x13f6: 0x1afe, 0x13f7: 0x1b02, 0x13f8: 0x1b06, 0x13f9: 0x1b0a, 0x13fa: 0x1b0e, 0x13fb: 0x1b12, + 0x13fc: 0x1b16, 0x13fd: 0x1b1a, 0x13fe: 0x1b1e, 0x13ff: 0x1b22, + // Block 0x50, offset 0x1400 + 0x1400: 0x1b26, 0x1401: 0x1b2a, 0x1402: 0x1b2e, 0x1403: 0x1b32, 0x1404: 0x1b36, 0x1405: 0x1b3a, + 0x1406: 0x1b3e, 0x1407: 0x1b42, 0x1408: 0x1b46, 0x1409: 0x1b4a, 0x140a: 0x1b4e, 0x140b: 0x1b52, + 0x140c: 0x1b56, 0x140d: 0x1b5a, 0x140e: 0x1b5e, 0x140f: 0x1b62, 0x1410: 0x1b66, 0x1411: 0x1b6a, + 0x1412: 0x1b6e, 0x1413: 0x1b72, 0x1414: 0x1b76, 0x1415: 0x1b7a, + // Block 0x51, offset 0x1440 + 0x1440: 0x0001, + 0x1476: 0x1b7e, 0x1478: 0x1882, 0x1479: 0x1b82, 0x147a: 0x1b86, + // Block 0x52, offset 0x1480 + 0x148c: 0x1b8a, 0x148e: 0x1b91, 0x1490: 0x1b98, + 0x1492: 0x1b9f, 0x1494: 0x1ba6, 0x1496: 0x1bad, + 0x1498: 0x1bb4, 0x149a: 0x1bbb, 0x149c: 0x1bc2, + 0x149e: 0x1bc9, 0x14a0: 0x1bd0, 0x14a2: 0x1bd7, + 0x14a5: 0x1bde, 0x14a7: 0x1be5, 0x14a9: 0x1bec, + 0x14b0: 0x1bf3, 0x14b1: 0x1bfa, 0x14b3: 0x1c01, 0x14b4: 0x1c08, + 0x14b6: 0x1c0f, 0x14b7: 0x1c16, 0x14b9: 0x1c1d, 0x14ba: 0x1c24, + 0x14bc: 0x1c2b, 0x14bd: 0x1c32, + // Block 0x53, offset 0x14c0 + 0x14d4: 0x1c39, + 0x14db: 0x1c40, 0x14dc: 0x1c45, + 0x14de: 0x1c4a, 0x14df: 0x1c51, + 0x14ec: 0x1c58, 0x14ee: 0x1c5f, + 0x14f0: 0x1c66, 0x14f2: 0x1c6d, 0x14f4: 0x1c74, + 0x14f6: 0x1c7b, 0x14f8: 0x1c82, 0x14fa: 0x1c89, + 0x14fc: 0x1c90, 0x14fe: 0x1c97, + // Block 0x54, offset 0x1500 + 0x1500: 0x1c9e, 0x1502: 0x1ca5, 0x1505: 0x1cac, + 0x1507: 0x1cb3, 0x1509: 0x1cba, + 0x1510: 0x1cc1, 0x1511: 0x1cc8, + 0x1513: 0x1ccf, 0x1514: 0x1cd6, 0x1516: 0x1cdd, 0x1517: 0x1ce4, + 0x1519: 0x1ceb, 0x151a: 0x1cf2, 0x151c: 0x1cf9, 0x151d: 0x1d00, + 0x1534: 0x1d07, + 0x1537: 0x1d0e, 0x1538: 0x1d15, 0x1539: 0x1d1c, 0x153a: 0x1d23, + 0x153e: 0x1d2a, 0x153f: 0x1d31, + // Block 0x55, offset 0x1540 + 0x1571: 0x1d38, 0x1572: 0x1d3c, 0x1573: 0x1d40, 0x1574: 0x1d44, 0x1575: 0x1d48, + 0x1576: 0x1d4c, 0x1577: 0x1d50, 0x1578: 0x1d54, 0x1579: 0x1d58, 0x157a: 0x1d5c, 0x157b: 0x1d60, + 0x157c: 0x1d64, 0x157d: 0x1d68, 0x157e: 0x1d6c, 0x157f: 0x1d70, + // Block 0x56, offset 0x1580 + 0x1580: 0x1d74, 0x1581: 0x1d78, 0x1582: 0x1d7c, 0x1583: 0x1d80, 0x1584: 0x1d84, 0x1585: 0x1d88, + 0x1586: 0x1d8c, 0x1587: 0x1d90, 0x1588: 0x1d94, 0x1589: 0x1d98, 0x158a: 0x1d9c, 0x158b: 0x1da0, + 0x158c: 0x1da4, 0x158d: 0x1da8, 0x158e: 0x1dac, 0x158f: 0x1db0, 0x1590: 0x1db4, 0x1591: 0x1db8, + 0x1592: 0x1dbc, 0x1593: 0x1dc0, 0x1594: 0x1dc4, 0x1595: 0x1dc8, 0x1596: 0x1dcc, 0x1597: 0x1dd0, + 0x1598: 0x1dd4, 0x1599: 0x1dd8, 0x159a: 0x1ddc, 0x159b: 0x1de0, 0x159c: 0x1de4, 0x159d: 0x1de8, + 0x159e: 0x1dec, 0x159f: 0x1df0, 0x15a0: 0x1df4, 0x15a1: 0x1df8, 0x15a2: 0x1dfc, 0x15a3: 0x1e00, + 0x15a4: 0x1e04, 0x15a5: 0x1e08, 0x15a6: 0x1e0c, 0x15a7: 0x1e10, 0x15a8: 0x1e14, 0x15a9: 0x1e18, + 0x15aa: 0x1e1c, 0x15ab: 0x1e20, 0x15ac: 0x1e24, 0x15ad: 0x1e28, 0x15ae: 0x1e2c, 0x15af: 0x1e30, + 0x15b0: 0x1e34, 0x15b1: 0x1e38, 0x15b2: 0x1e3c, 0x15b3: 0x1e40, 0x15b4: 0x1e44, 0x15b5: 0x1e48, + 0x15b6: 0x1e4c, 0x15b7: 0x1e50, 0x15b8: 0x1e54, 0x15b9: 0x1e58, 0x15ba: 0x1e5c, 0x15bb: 0x1e60, + 0x15bc: 0x1e64, 0x15bd: 0x1e68, 0x15be: 0x1e6c, 0x15bf: 0x1e70, + // Block 0x57, offset 0x15c0 + 0x15c0: 0x1e74, 0x15c1: 0x1e78, 0x15c2: 0x1e7c, 0x15c3: 0x1e80, 0x15c4: 0x1e84, 0x15c5: 0x1e88, + 0x15c6: 0x1e8c, 0x15c7: 0x1e90, 0x15c8: 0x1e94, 0x15c9: 0x1e98, 0x15ca: 0x1e9c, 0x15cb: 0x1ea0, + 0x15cc: 0x1ea4, 0x15cd: 0x1ea8, 0x15ce: 0x1eac, + 0x15d2: 0x1826, 0x15d3: 0x183e, 0x15d4: 0x1eb0, 0x15d5: 0x1eb4, 0x15d6: 0x1eb8, 0x15d7: 0x1ebc, + 0x15d8: 0x1ec0, 0x15d9: 0x1ec4, 0x15da: 0x1836, 0x15db: 0x1ec8, 0x15dc: 0x1ecc, 0x15dd: 0x1ed0, + 0x15de: 0x1ed4, 0x15df: 0x1846, + // Block 0x58, offset 0x1600 + 0x1600: 0x1ed8, 0x1601: 0x1ede, 0x1602: 0x1ee4, 0x1603: 0x1eea, 0x1604: 0x1ef0, 0x1605: 0x1ef6, + 0x1606: 0x1efc, 0x1607: 0x1f02, 0x1608: 0x1f08, 0x1609: 0x1f0e, 0x160a: 0x1f14, 0x160b: 0x1f1a, + 0x160c: 0x1f20, 0x160d: 0x1f26, 0x160e: 0x1f2c, 0x160f: 0x1f35, 0x1610: 0x1f3e, 0x1611: 0x1f47, + 0x1612: 0x1f50, 0x1613: 0x1f59, 0x1614: 0x1f62, 0x1615: 0x1f6b, 0x1616: 0x1f74, 0x1617: 0x1f7d, + 0x1618: 0x1f86, 0x1619: 0x1f8f, 0x161a: 0x1f98, 0x161b: 0x1fa1, 0x161c: 0x1faa, 0x161d: 0x1fb3, + 0x161e: 0x1fc5, 0x1620: 0x1fd4, 0x1621: 0x1fda, 0x1622: 0x1fe0, 0x1623: 0x1fe6, + 0x1624: 0x1fec, 0x1625: 0x1ff2, 0x1626: 0x1ff8, 0x1627: 0x1ffe, 0x1628: 0x2004, 0x1629: 0x200a, + 0x162a: 0x2010, 0x162b: 0x2016, 0x162c: 0x201c, 0x162d: 0x2022, 0x162e: 0x2028, 0x162f: 0x202e, + 0x1630: 0x2034, 0x1631: 0x203a, 0x1632: 0x2040, 0x1633: 0x2046, 0x1634: 0x204c, 0x1635: 0x2052, + 0x1636: 0x2058, 0x1637: 0x205e, 0x1638: 0x2064, 0x1639: 0x206a, 0x163a: 0x2070, 0x163b: 0x2076, + 0x163c: 0x207c, 0x163d: 0x2082, 0x163e: 0x2088, 0x163f: 0x208e, + // Block 0x59, offset 0x1640 + 0x1640: 0x2094, 0x1641: 0x209a, 0x1642: 0x20a0, 0x1643: 0x20a6, 0x1644: 0x20ac, 0x1645: 0x20b0, + 0x1646: 0x192e, 0x1647: 0x20b4, + 0x1650: 0x20b8, 0x1651: 0x20bc, + 0x1652: 0x20bf, 0x1653: 0x20c2, 0x1654: 0x20c5, 0x1655: 0x20c8, 0x1656: 0x20cb, 0x1657: 0x20ce, + 0x1658: 0x20d1, 0x1659: 0x20d4, 0x165a: 0x20d7, 0x165b: 0x20da, 0x165c: 0x20dd, 0x165d: 0x20e0, + 0x165e: 0x20e3, 0x165f: 0x20e6, 0x1660: 0x1d38, 0x1661: 0x1d44, 0x1662: 0x1d50, 0x1663: 0x1d58, + 0x1664: 0x1d78, 0x1665: 0x1d7c, 0x1666: 0x1d88, 0x1667: 0x1d90, 0x1668: 0x1d94, 0x1669: 0x1d9c, + 0x166a: 0x1da0, 0x166b: 0x1da4, 0x166c: 0x1da8, 0x166d: 0x1dac, 0x166e: 0x20e9, 0x166f: 0x20f0, + 0x1670: 0x20f7, 0x1671: 0x20fe, 0x1672: 0x2105, 0x1673: 0x210c, 0x1674: 0x2113, 0x1675: 0x211a, + 0x1676: 0x2121, 0x1677: 0x2128, 0x1678: 0x212f, 0x1679: 0x2136, 0x167a: 0x213d, 0x167b: 0x2144, + 0x167c: 0x214b, 0x167d: 0x215b, 0x167e: 0x2168, + // Block 0x5a, offset 0x1680 + 0x1680: 0x1826, 0x1681: 0x183e, 0x1682: 0x1eb0, 0x1683: 0x1eb4, 0x1684: 0x216f, 0x1685: 0x2173, + 0x1686: 0x2177, 0x1687: 0x1852, 0x1688: 0x217b, 0x1689: 0x1882, 0x168a: 0x194a, 0x168b: 0x197a, + 0x168c: 0x1976, 0x168d: 0x194e, 0x168e: 0x1abe, 0x168f: 0x18a2, 0x1690: 0x1942, 0x1691: 0x217f, + 0x1692: 0x2183, 0x1693: 0x2187, 0x1694: 0x218b, 0x1695: 0x218f, 0x1696: 0x2193, 0x1697: 0x2197, + 0x1698: 0x219b, 0x1699: 0x219f, 0x169a: 0x21a3, 0x169b: 0x18ba, 0x169c: 0x21a7, 0x169d: 0x21ab, + 0x169e: 0x21af, 0x169f: 0x21b3, 0x16a0: 0x21b7, 0x16a1: 0x21bb, 0x16a2: 0x21bf, 0x16a3: 0x21c3, + 0x16a4: 0x1eb8, 0x16a5: 0x1ebc, 0x16a6: 0x1ec0, 0x16a7: 0x21c7, 0x16a8: 0x21cb, 0x16a9: 0x21cf, + 0x16aa: 0x21d3, 0x16ab: 0x21d7, 0x16ac: 0x21db, 0x16ad: 0x21df, 0x16ae: 0x21e3, 0x16af: 0x21e7, + 0x16b0: 0x21eb, 0x16b1: 0x21ef, 0x16b2: 0x21f2, 0x16b3: 0x21f5, 0x16b4: 0x21f8, 0x16b5: 0x21fb, + 0x16b6: 0x21fe, 0x16b7: 0x2201, 0x16b8: 0x2204, 0x16b9: 0x2207, 0x16ba: 0x220a, 0x16bb: 0x220d, + 0x16bc: 0x2210, 0x16bd: 0x2213, 0x16be: 0x2216, 0x16bf: 0x2219, + // Block 0x5b, offset 0x16c0 + 0x16c0: 0x221c, 0x16c1: 0x2221, 0x16c2: 0x2226, 0x16c3: 0x222b, 0x16c4: 0x2230, 0x16c5: 0x2235, + 0x16c6: 0x223a, 0x16c7: 0x223f, 0x16c8: 0x2244, 0x16c9: 0x2249, 0x16ca: 0x224f, 0x16cb: 0x2255, + 0x16cc: 0x225b, 0x16cd: 0x225e, 0x16ce: 0x2262, 0x16cf: 0x2265, 0x16d0: 0x2269, 0x16d1: 0x226d, + 0x16d2: 0x2271, 0x16d3: 0x2275, 0x16d4: 0x2279, 0x16d5: 0x227d, 0x16d6: 0x2281, 0x16d7: 0x2285, + 0x16d8: 0x2289, 0x16d9: 0x228d, 0x16da: 0x2291, 0x16db: 0x2295, 0x16dc: 0x2299, 0x16dd: 0x229d, + 0x16de: 0x22a1, 0x16df: 0x22a5, 0x16e0: 0x22a9, 0x16e1: 0x22ad, 0x16e2: 0x22b1, 0x16e3: 0x22b5, + 0x16e4: 0x22b9, 0x16e5: 0x22bd, 0x16e6: 0x22c1, 0x16e7: 0x22c5, 0x16e8: 0x22c9, 0x16e9: 0x22cd, + 0x16ea: 0x22d1, 0x16eb: 0x22d5, 0x16ec: 0x22d9, 0x16ed: 0x22dd, 0x16ee: 0x22e1, 0x16ef: 0x22e5, + 0x16f0: 0x22e9, 0x16f1: 0x22ed, 0x16f2: 0x22f1, 0x16f3: 0x22f5, 0x16f4: 0x22f9, 0x16f5: 0x22fd, + 0x16f6: 0x2301, 0x16f7: 0x2305, 0x16f8: 0x2309, 0x16f9: 0x230d, 0x16fa: 0x2311, 0x16fb: 0x2315, + 0x16fc: 0x2319, 0x16fd: 0x231d, 0x16fe: 0x2321, + // Block 0x5c, offset 0x1700 + 0x1700: 0x2325, 0x1701: 0x2335, 0x1702: 0x2342, 0x1703: 0x2352, 0x1704: 0x235c, 0x1705: 0x236c, + 0x1706: 0x2376, 0x1707: 0x2380, 0x1708: 0x2393, 0x1709: 0x23a0, 0x170a: 0x23aa, 0x170b: 0x23b4, + 0x170c: 0x23be, 0x170d: 0x23cb, 0x170e: 0x23d8, 0x170f: 0x23e5, 0x1710: 0x23f2, 0x1711: 0x23ff, + 0x1712: 0x240c, 0x1713: 0x2419, 0x1714: 0x242c, 0x1715: 0x2433, 0x1716: 0x2446, 0x1717: 0x2459, + 0x1718: 0x2469, 0x1719: 0x2476, 0x171a: 0x2489, 0x171b: 0x249c, 0x171c: 0x24a9, 0x171d: 0x24b3, + 0x171e: 0x24bd, 0x171f: 0x24ca, 0x1720: 0x24d7, 0x1721: 0x24e7, 0x1722: 0x24f7, 0x1723: 0x2501, + 0x1724: 0x250b, 0x1725: 0x2518, 0x1726: 0x2522, 0x1727: 0x252c, 0x1728: 0x2533, 0x1729: 0x253a, + 0x172a: 0x2544, 0x172b: 0x254e, 0x172c: 0x2561, 0x172d: 0x256e, 0x172e: 0x257e, 0x172f: 0x2591, + 0x1730: 0x259e, 0x1731: 0x25a8, 0x1732: 0x25b2, 0x1733: 0x25c5, 0x1734: 0x25d2, 0x1735: 0x25e5, + 0x1736: 0x25ef, 0x1737: 0x25ff, 0x1738: 0x2609, 0x1739: 0x2616, 0x173a: 0x2620, 0x173b: 0x262d, + 0x173c: 0x263d, 0x173d: 0x264a, 0x173e: 0x265a, 0x173f: 0x2667, + // Block 0x5d, offset 0x1740 + 0x1740: 0x266e, 0x1741: 0x267e, 0x1742: 0x2688, 0x1743: 0x2692, 0x1744: 0x269f, 0x1745: 0x26a9, + 0x1746: 0x26b3, 0x1747: 0x26bd, 0x1748: 0x26cd, 0x1749: 0x26da, 0x174a: 0x26e1, 0x174b: 0x26f4, + 0x174c: 0x26fe, 0x174d: 0x270e, 0x174e: 0x271b, 0x174f: 0x2728, 0x1750: 0x2732, 0x1751: 0x273c, + 0x1752: 0x2749, 0x1753: 0x2750, 0x1754: 0x275d, 0x1755: 0x276d, 0x1756: 0x2774, 0x1757: 0x2787, + 0x1758: 0x2791, 0x1759: 0x2796, 0x175a: 0x279b, 0x175b: 0x27a0, 0x175c: 0x27a5, 0x175d: 0x27aa, + 0x175e: 0x27af, 0x175f: 0x27b4, 0x1760: 0x27b9, 0x1761: 0x27be, 0x1762: 0x27c3, 0x1763: 0x27c9, + 0x1764: 0x27cf, 0x1765: 0x27d5, 0x1766: 0x27db, 0x1767: 0x27e1, 0x1768: 0x27e7, 0x1769: 0x27ed, + 0x176a: 0x27f3, 0x176b: 0x27f9, 0x176c: 0x27ff, 0x176d: 0x2805, 0x176e: 0x280b, 0x176f: 0x2811, + 0x1770: 0x2817, 0x1771: 0x281d, 0x1772: 0x2821, 0x1773: 0x2824, 0x1774: 0x2827, 0x1775: 0x282b, + 0x1776: 0x282e, 0x1777: 0x2831, 0x1778: 0x2834, 0x1779: 0x2838, 0x177a: 0x283c, 0x177b: 0x283f, + 0x177c: 0x2846, 0x177d: 0x284d, 0x177e: 0x2854, 0x177f: 0x285b, + // Block 0x5e, offset 0x1780 + 0x1780: 0x2868, 0x1781: 0x286b, 0x1782: 0x286e, 0x1783: 0x2872, 0x1784: 0x2875, 0x1785: 0x2878, + 0x1786: 0x287b, 0x1787: 0x287e, 0x1788: 0x2881, 0x1789: 0x2885, 0x178a: 0x288a, 0x178b: 0x288d, + 0x178c: 0x2890, 0x178d: 0x2894, 0x178e: 0x2898, 0x178f: 0x289b, 0x1790: 0x289e, 0x1791: 0x28a1, + 0x1792: 0x28a5, 0x1793: 0x28a9, 0x1794: 0x28ad, 0x1795: 0x28b1, 0x1796: 0x28b5, 0x1797: 0x28b8, + 0x1798: 0x28bb, 0x1799: 0x28be, 0x179a: 0x28c1, 0x179b: 0x28c4, 0x179c: 0x28c8, 0x179d: 0x28cb, + 0x179e: 0x28ce, 0x179f: 0x28d1, 0x17a0: 0x28d5, 0x17a1: 0x28d9, 0x17a2: 0x28dc, 0x17a3: 0x28e0, + 0x17a4: 0x28e4, 0x17a5: 0x28e8, 0x17a6: 0x28eb, 0x17a7: 0x28ef, 0x17a8: 0x28f5, 0x17a9: 0x28fc, + 0x17aa: 0x28ff, 0x17ab: 0x2903, 0x17ac: 0x2907, 0x17ad: 0x290b, 0x17ae: 0x290f, 0x17af: 0x2917, + 0x17b0: 0x2920, 0x17b1: 0x2923, 0x17b2: 0x2926, 0x17b3: 0x292a, 0x17b4: 0x292d, 0x17b5: 0x2930, + 0x17b6: 0x2933, 0x17b7: 0x2937, 0x17b8: 0x293a, 0x17b9: 0x293d, 0x17ba: 0x2940, 0x17bb: 0x2943, + 0x17bc: 0x2946, 0x17bd: 0x294a, 0x17be: 0x294d, 0x17bf: 0x2950, + // Block 0x5f, offset 0x17c0 + 0x17c0: 0x2953, 0x17c1: 0x2957, 0x17c2: 0x295b, 0x17c3: 0x2960, 0x17c4: 0x2963, 0x17c5: 0x2966, + 0x17c6: 0x2969, 0x17c7: 0x2970, 0x17c8: 0x2974, 0x17c9: 0x2977, 0x17ca: 0x297a, 0x17cb: 0x297d, + 0x17cc: 0x2980, 0x17cd: 0x2983, 0x17ce: 0x2986, 0x17cf: 0x2989, 0x17d0: 0x298c, 0x17d1: 0x298f, + 0x17d2: 0x2992, 0x17d3: 0x2996, 0x17d4: 0x2999, 0x17d5: 0x299c, 0x17d6: 0x29a0, 0x17d7: 0x29a4, + 0x17d8: 0x29a7, 0x17d9: 0x29ac, 0x17da: 0x29b0, 0x17db: 0x29b3, 0x17dc: 0x29b6, 0x17dd: 0x29b9, + 0x17de: 0x29bc, 0x17df: 0x29c2, 0x17e0: 0x29c8, 0x17e1: 0x29cd, 0x17e2: 0x29d2, 0x17e3: 0x29d7, + 0x17e4: 0x29dc, 0x17e5: 0x29e1, 0x17e6: 0x29e6, 0x17e7: 0x29eb, 0x17e8: 0x29f0, 0x17e9: 0x29f5, + 0x17ea: 0x29fb, 0x17eb: 0x2a01, 0x17ec: 0x2a07, 0x17ed: 0x2a0d, 0x17ee: 0x2a13, 0x17ef: 0x2a19, + 0x17f0: 0x2a1f, 0x17f1: 0x2a25, 0x17f2: 0x2a2b, 0x17f3: 0x2a31, 0x17f4: 0x2a37, 0x17f5: 0x2a3d, + 0x17f6: 0x2a43, 0x17f7: 0x2a49, 0x17f8: 0x2a4f, 0x17f9: 0x2a55, 0x17fa: 0x2a5b, 0x17fb: 0x2a61, + 0x17fc: 0x2a67, 0x17fd: 0x2a6d, 0x17fe: 0x2a73, 0x17ff: 0x2a79, + // Block 0x60, offset 0x1800 + 0x1830: 0x2a7d, + // Block 0x61, offset 0x1840 + 0x1840: 0x2a81, 0x1841: 0x2a85, 0x1842: 0x1a9e, 0x1843: 0x2a89, 0x1844: 0x2a8d, 0x1845: 0x2a91, + 0x1846: 0x2a95, 0x1847: 0x1b76, 0x1848: 0x1b76, 0x1849: 0x2a99, 0x184a: 0x1abe, 0x184b: 0x2a9d, + 0x184c: 0x2aa1, 0x184d: 0x2aa5, 0x184e: 0x2aa9, 0x184f: 0x2aad, 0x1850: 0x2ab1, 0x1851: 0x2ab5, + 0x1852: 0x2ab9, 0x1853: 0x2abd, 0x1854: 0x2ac1, 0x1855: 0x2ac5, 0x1856: 0x2ac9, 0x1857: 0x2acd, + 0x1858: 0x2ad1, 0x1859: 0x2ad5, 0x185a: 0x2ad9, 0x185b: 0x2add, 0x185c: 0x2ae1, 0x185d: 0x2ae5, + 0x185e: 0x2ae9, 0x185f: 0x2aed, 0x1860: 0x2af1, 0x1861: 0x2af5, 0x1862: 0x2af9, 0x1863: 0x2afd, + 0x1864: 0x2b01, 0x1865: 0x2b05, 0x1866: 0x2b09, 0x1867: 0x2b0d, 0x1868: 0x2b11, 0x1869: 0x2b15, + 0x186a: 0x2b19, 0x186b: 0x2b1d, 0x186c: 0x2b21, 0x186d: 0x2b25, 0x186e: 0x2b29, 0x186f: 0x2b2d, + 0x1870: 0x2b31, 0x1871: 0x2b35, 0x1872: 0x2b39, 0x1873: 0x2b3d, 0x1874: 0x1a16, 0x1875: 0x2b41, + 0x1876: 0x2b45, 0x1877: 0x2b49, 0x1878: 0x2b4d, 0x1879: 0x2b51, 0x187a: 0x2b55, 0x187b: 0x2b59, + 0x187c: 0x2b5d, 0x187d: 0x2b61, 0x187e: 0x2b65, 0x187f: 0x2b69, + // Block 0x62, offset 0x1880 + 0x1880: 0x1b3a, 0x1881: 0x2b6d, 0x1882: 0x2b71, 0x1883: 0x2b75, 0x1884: 0x2b79, 0x1885: 0x2b7d, + 0x1886: 0x2b81, 0x1887: 0x2b85, 0x1888: 0x2b89, 0x1889: 0x2b8d, 0x188a: 0x2b91, 0x188b: 0x2b95, + 0x188c: 0x2b99, 0x188d: 0x2b9d, 0x188e: 0x2ba1, 0x188f: 0x2ba5, 0x1890: 0x2ba9, 0x1891: 0x2bad, + 0x1892: 0x2bb1, 0x1893: 0x2bb5, 0x1894: 0x2bb9, 0x1895: 0x2bbd, 0x1896: 0x2bc1, 0x1897: 0x2bc5, + 0x1898: 0x2bc9, 0x1899: 0x2bcd, 0x189a: 0x2bd1, 0x189b: 0x2bd5, 0x189c: 0x2ac1, 0x189d: 0x2bd9, + 0x189e: 0x2bdd, 0x189f: 0x2be1, 0x18a0: 0x2be5, 0x18a1: 0x2be9, 0x18a2: 0x2bed, 0x18a3: 0x2bf1, + 0x18a4: 0x2bf5, 0x18a5: 0x2bf9, 0x18a6: 0x2bfd, 0x18a7: 0x2c01, 0x18a8: 0x2c05, 0x18a9: 0x2c09, + 0x18aa: 0x2c0d, 0x18ab: 0x2c11, 0x18ac: 0x2c15, 0x18ad: 0x2c19, 0x18ae: 0x2c1d, 0x18af: 0x2c21, + 0x18b0: 0x2c25, 0x18b1: 0x1aa6, 0x18b2: 0x2c29, 0x18b3: 0x2c2d, 0x18b4: 0x2c31, 0x18b5: 0x2c35, + 0x18b6: 0x2c39, 0x18b7: 0x2c3d, 0x18b8: 0x2c41, 0x18b9: 0x2c45, 0x18ba: 0x2c49, 0x18bb: 0x2c4d, + 0x18bc: 0x2c51, 0x18bd: 0x2c55, 0x18be: 0x2c59, 0x18bf: 0x2c5d, + // Block 0x63, offset 0x18c0 + 0x18c0: 0x2c61, 0x18c1: 0x18ba, 0x18c2: 0x2c65, 0x18c3: 0x2c69, 0x18c4: 0x2c6d, 0x18c5: 0x2c71, + 0x18c6: 0x2c75, 0x18c7: 0x2c79, 0x18c8: 0x2c7d, 0x18c9: 0x2c81, 0x18ca: 0x186e, 0x18cb: 0x2c85, + 0x18cc: 0x2c89, 0x18cd: 0x2c8d, 0x18ce: 0x2c91, 0x18cf: 0x2c95, 0x18d0: 0x2c99, 0x18d1: 0x2c9d, + 0x18d2: 0x2ca1, 0x18d3: 0x2ca5, 0x18d4: 0x2ca9, 0x18d5: 0x2cad, 0x18d6: 0x2cb1, 0x18d7: 0x2cb5, + 0x18d8: 0x2cb9, 0x18d9: 0x2cbd, 0x18da: 0x2cc1, 0x18db: 0x2cc5, 0x18dc: 0x2cc9, 0x18dd: 0x2ccd, + 0x18de: 0x2cd1, 0x18df: 0x2cd5, 0x18e0: 0x2cd9, 0x18e1: 0x2c21, 0x18e2: 0x2cdd, 0x18e3: 0x2ce1, + 0x18e4: 0x2ce5, 0x18e5: 0x2ce9, 0x18e6: 0x2ced, 0x18e7: 0x2cf1, 0x18e8: 0x2cf5, 0x18e9: 0x2cf9, + 0x18ea: 0x2be1, 0x18eb: 0x2cfd, 0x18ec: 0x2d01, 0x18ed: 0x2d05, 0x18ee: 0x2d09, 0x18ef: 0x2d0d, + 0x18f0: 0x2d11, 0x18f1: 0x2d15, 0x18f2: 0x2d19, 0x18f3: 0x2d1d, 0x18f4: 0x2d21, 0x18f5: 0x2d25, + 0x18f6: 0x2d29, 0x18f7: 0x2d2d, 0x18f8: 0x2d31, 0x18f9: 0x2d35, 0x18fa: 0x2d39, 0x18fb: 0x2d3d, + 0x18fc: 0x2d41, 0x18fd: 0x2d45, 0x18fe: 0x2d49, 0x18ff: 0x2ac1, + // Block 0x64, offset 0x1900 + 0x1900: 0x2d4d, 0x1901: 0x2d51, 0x1902: 0x2d55, 0x1903: 0x2d59, 0x1904: 0x1b72, 0x1905: 0x2d5d, + 0x1906: 0x2d61, 0x1907: 0x2d65, 0x1908: 0x2d69, 0x1909: 0x2d6d, 0x190a: 0x2d71, 0x190b: 0x2d75, + 0x190c: 0x2d79, 0x190d: 0x2d7d, 0x190e: 0x2d81, 0x190f: 0x2d85, 0x1910: 0x2d89, 0x1911: 0x2173, + 0x1912: 0x2d8d, 0x1913: 0x2d91, 0x1914: 0x2d95, 0x1915: 0x2d99, 0x1916: 0x2d9d, 0x1917: 0x2da1, + 0x1918: 0x2da5, 0x1919: 0x2da9, 0x191a: 0x2dad, 0x191b: 0x2be9, 0x191c: 0x2db1, 0x191d: 0x2db5, + 0x191e: 0x2db9, 0x191f: 0x2dbd, 0x1920: 0x2dc1, 0x1921: 0x2dc5, 0x1922: 0x2dc9, 0x1923: 0x2dcd, + 0x1924: 0x2dd1, 0x1925: 0x2dd5, 0x1926: 0x2dd9, 0x1927: 0x2ddd, 0x1928: 0x2de1, 0x1929: 0x1aba, + 0x192a: 0x2de5, 0x192b: 0x2de9, 0x192c: 0x2ded, 0x192d: 0x2df1, 0x192e: 0x2df5, 0x192f: 0x2df9, + 0x1930: 0x2dfd, 0x1931: 0x2e01, 0x1932: 0x2e05, 0x1933: 0x2e09, 0x1934: 0x2e0d, 0x1935: 0x2e11, + 0x1936: 0x2e15, 0x1937: 0x19f6, 0x1938: 0x2e19, 0x1939: 0x2e1d, 0x193a: 0x2e21, 0x193b: 0x2e25, + 0x193c: 0x2e29, 0x193d: 0x2e2d, 0x193e: 0x2e31, 0x193f: 0x2e35, + // Block 0x65, offset 0x1940 + 0x1940: 0x2e39, 0x1941: 0x2e3d, 0x1942: 0x2e41, 0x1943: 0x2e45, 0x1944: 0x2e49, 0x1945: 0x2e4d, + 0x1946: 0x2e51, 0x1947: 0x2e55, 0x1948: 0x1a62, 0x1949: 0x2e59, 0x194a: 0x1a6e, 0x194b: 0x2e5d, + 0x194c: 0x2e61, 0x194d: 0x2e65, 0x1950: 0x2e69, + 0x1952: 0x2e6d, 0x1955: 0x2e71, 0x1956: 0x2e75, 0x1957: 0x2e79, + 0x1958: 0x2e7d, 0x1959: 0x2e81, 0x195a: 0x2e85, 0x195b: 0x2e89, 0x195c: 0x2e8d, 0x195d: 0x2e91, + 0x195e: 0x1a12, 0x1960: 0x2e95, 0x1962: 0x2e99, + 0x1965: 0x2e9d, 0x1966: 0x2ea1, + 0x196a: 0x2ea5, 0x196b: 0x2ea9, 0x196c: 0x2ead, 0x196d: 0x2eb1, + 0x1970: 0x2eb5, 0x1971: 0x2eb9, 0x1972: 0x2ebd, 0x1973: 0x2ec1, 0x1974: 0x2ec5, 0x1975: 0x2ec9, + 0x1976: 0x2ecd, 0x1977: 0x2ed1, 0x1978: 0x2ed5, 0x1979: 0x2ed9, 0x197a: 0x2edd, 0x197b: 0x2ee1, + 0x197c: 0x18d6, 0x197d: 0x2ee5, 0x197e: 0x2ee9, 0x197f: 0x2eed, + // Block 0x66, offset 0x1980 + 0x1980: 0x2ef1, 0x1981: 0x2ef5, 0x1982: 0x2ef9, 0x1983: 0x2efd, 0x1984: 0x2f01, 0x1985: 0x2f05, + 0x1986: 0x2f09, 0x1987: 0x2f0d, 0x1988: 0x2f11, 0x1989: 0x2f15, 0x198a: 0x2f19, 0x198b: 0x2f1d, + 0x198c: 0x2187, 0x198d: 0x2f21, 0x198e: 0x2f25, 0x198f: 0x2f29, 0x1990: 0x2f2d, 0x1991: 0x2197, + 0x1992: 0x2f31, 0x1993: 0x2f35, 0x1994: 0x2f39, 0x1995: 0x2f3d, 0x1996: 0x2f41, 0x1997: 0x2cb1, + 0x1998: 0x2f45, 0x1999: 0x2f49, 0x199a: 0x2f4d, 0x199b: 0x2f51, 0x199c: 0x2f55, 0x199d: 0x2f59, + 0x199e: 0x2f59, 0x199f: 0x2f5d, 0x19a0: 0x2f61, 0x19a1: 0x2f65, 0x19a2: 0x2f69, 0x19a3: 0x2f6d, + 0x19a4: 0x2f71, 0x19a5: 0x2f75, 0x19a6: 0x2f79, 0x19a7: 0x2e9d, 0x19a8: 0x2f7d, 0x19a9: 0x2f81, + 0x19aa: 0x2f85, 0x19ab: 0x2f89, 0x19ac: 0x2f8d, 0x19ad: 0x2f92, + 0x19b0: 0x2f96, 0x19b1: 0x2f9a, 0x19b2: 0x2f9e, 0x19b3: 0x2fa2, 0x19b4: 0x2fa6, 0x19b5: 0x2faa, + 0x19b6: 0x2fae, 0x19b7: 0x2fb2, 0x19b8: 0x2ecd, 0x19b9: 0x2fb6, 0x19ba: 0x2fba, 0x19bb: 0x2fbe, + 0x19bc: 0x2e69, 0x19bd: 0x2fc2, 0x19be: 0x2fc6, 0x19bf: 0x2fca, + // Block 0x67, offset 0x19c0 + 0x19c0: 0x2fce, 0x19c1: 0x2fd2, 0x19c2: 0x2fd6, 0x19c3: 0x2fda, 0x19c4: 0x2fde, 0x19c5: 0x2fe2, + 0x19c6: 0x2fe6, 0x19c7: 0x2fea, 0x19c8: 0x2fee, 0x19c9: 0x2eed, 0x19ca: 0x2ff2, 0x19cb: 0x2ef1, + 0x19cc: 0x2ff6, 0x19cd: 0x2ffa, 0x19ce: 0x2ffe, 0x19cf: 0x3002, 0x19d0: 0x3006, 0x19d1: 0x2e6d, + 0x19d2: 0x2b15, 0x19d3: 0x300a, 0x19d4: 0x300e, 0x19d5: 0x195a, 0x19d6: 0x2c25, 0x19d7: 0x2d71, + 0x19d8: 0x3012, 0x19d9: 0x3016, 0x19da: 0x2f0d, 0x19db: 0x301a, 0x19dc: 0x2f11, 0x19dd: 0x301e, + 0x19de: 0x3022, 0x19df: 0x3026, 0x19e0: 0x2e75, 0x19e1: 0x302a, 0x19e2: 0x302e, 0x19e3: 0x3032, + 0x19e4: 0x3036, 0x19e5: 0x303a, 0x19e6: 0x2e79, 0x19e7: 0x303e, 0x19e8: 0x3042, 0x19e9: 0x3046, + 0x19ea: 0x304a, 0x19eb: 0x304e, 0x19ec: 0x3052, 0x19ed: 0x2f41, 0x19ee: 0x3056, 0x19ef: 0x305a, + 0x19f0: 0x2cb1, 0x19f1: 0x305e, 0x19f2: 0x2f51, 0x19f3: 0x3062, 0x19f4: 0x3066, 0x19f5: 0x306a, + 0x19f6: 0x306e, 0x19f7: 0x3072, 0x19f8: 0x2f65, 0x19f9: 0x3076, 0x19fa: 0x2e99, 0x19fb: 0x307a, + 0x19fc: 0x2f69, 0x19fd: 0x2bd9, 0x19fe: 0x307e, 0x19ff: 0x2f6d, + // Block 0x68, offset 0x1a00 + 0x1a00: 0x3082, 0x1a01: 0x2f75, 0x1a02: 0x3086, 0x1a03: 0x308a, 0x1a04: 0x308e, 0x1a05: 0x3092, + 0x1a06: 0x3096, 0x1a07: 0x2f7d, 0x1a08: 0x2e8d, 0x1a09: 0x309a, 0x1a0a: 0x2f81, 0x1a0b: 0x309e, + 0x1a0c: 0x2f85, 0x1a0d: 0x30a2, 0x1a0e: 0x1b76, 0x1a0f: 0x30a6, 0x1a10: 0x30ab, 0x1a11: 0x30b0, + 0x1a12: 0x30b5, 0x1a13: 0x30b9, 0x1a14: 0x30bd, 0x1a15: 0x30c1, 0x1a16: 0x30c6, 0x1a17: 0x30cb, + 0x1a18: 0x30d0, 0x1a19: 0x30d4, + // Block 0x69, offset 0x1a40 + 0x1a40: 0x30d8, 0x1a41: 0x30db, 0x1a42: 0x30de, 0x1a43: 0x30e1, 0x1a44: 0x30e5, 0x1a45: 0x30e9, + 0x1a46: 0x30e9, + 0x1a53: 0x30ec, 0x1a54: 0x30f1, 0x1a55: 0x30f6, 0x1a56: 0x30fb, 0x1a57: 0x3100, + 0x1a5d: 0x3105, + 0x1a5f: 0x310a, 0x1a60: 0x310f, 0x1a61: 0x14db, 0x1a62: 0x14e4, 0x1a63: 0x3112, + 0x1a64: 0x3115, 0x1a65: 0x3118, 0x1a66: 0x311b, 0x1a67: 0x311e, 0x1a68: 0x3121, 0x1a69: 0x1494, + 0x1a6a: 0x3124, 0x1a6b: 0x3129, 0x1a6c: 0x312e, 0x1a6d: 0x3135, 0x1a6e: 0x313c, 0x1a6f: 0x3141, + 0x1a70: 0x3146, 0x1a71: 0x314b, 0x1a72: 0x3150, 0x1a73: 0x3155, 0x1a74: 0x315a, 0x1a75: 0x315f, + 0x1a76: 0x3164, 0x1a78: 0x3169, 0x1a79: 0x316e, 0x1a7a: 0x3173, 0x1a7b: 0x3178, + 0x1a7c: 0x317d, 0x1a7e: 0x3182, + // Block 0x6a, offset 0x1a80 + 0x1a80: 0x3187, 0x1a81: 0x318c, 0x1a83: 0x3191, 0x1a84: 0x3196, + 0x1a86: 0x319b, 0x1a87: 0x31a0, 0x1a88: 0x31a5, 0x1a89: 0x31aa, 0x1a8a: 0x31af, 0x1a8b: 0x31b4, + 0x1a8c: 0x31b9, 0x1a8d: 0x31be, 0x1a8e: 0x31c3, 0x1a8f: 0x31c8, 0x1a90: 0x31cd, 0x1a91: 0x31cd, + 0x1a92: 0x31d0, 0x1a93: 0x31d0, 0x1a94: 0x31d0, 0x1a95: 0x31d0, 0x1a96: 0x31d3, 0x1a97: 0x31d3, + 0x1a98: 0x31d3, 0x1a99: 0x31d3, 0x1a9a: 0x31d6, 0x1a9b: 0x31d6, 0x1a9c: 0x31d6, 0x1a9d: 0x31d6, + 0x1a9e: 0x31d9, 0x1a9f: 0x31d9, 0x1aa0: 0x31d9, 0x1aa1: 0x31d9, 0x1aa2: 0x31dc, 0x1aa3: 0x31dc, + 0x1aa4: 0x31dc, 0x1aa5: 0x31dc, 0x1aa6: 0x31df, 0x1aa7: 0x31df, 0x1aa8: 0x31df, 0x1aa9: 0x31df, + 0x1aaa: 0x31e2, 0x1aab: 0x31e2, 0x1aac: 0x31e2, 0x1aad: 0x31e2, 0x1aae: 0x31e5, 0x1aaf: 0x31e5, + 0x1ab0: 0x31e5, 0x1ab1: 0x31e5, 0x1ab2: 0x31e8, 0x1ab3: 0x31e8, 0x1ab4: 0x31e8, 0x1ab5: 0x31e8, + 0x1ab6: 0x31eb, 0x1ab7: 0x31eb, 0x1ab8: 0x31eb, 0x1ab9: 0x31eb, 0x1aba: 0x31ee, 0x1abb: 0x31ee, + 0x1abc: 0x31ee, 0x1abd: 0x31ee, 0x1abe: 0x31f1, 0x1abf: 0x31f1, + // Block 0x6b, offset 0x1ac0 + 0x1ac0: 0x31f1, 0x1ac1: 0x31f1, 0x1ac2: 0x31f4, 0x1ac3: 0x31f4, 0x1ac4: 0x31f7, 0x1ac5: 0x31f7, + 0x1ac6: 0x31fa, 0x1ac7: 0x31fa, 0x1ac8: 0x31fd, 0x1ac9: 0x31fd, 0x1aca: 0x3200, 0x1acb: 0x3200, + 0x1acc: 0x3203, 0x1acd: 0x3203, 0x1ace: 0x3206, 0x1acf: 0x3206, 0x1ad0: 0x3206, 0x1ad1: 0x3206, + 0x1ad2: 0x3209, 0x1ad3: 0x3209, 0x1ad4: 0x3209, 0x1ad5: 0x3209, 0x1ad6: 0x320c, 0x1ad7: 0x320c, + 0x1ad8: 0x320c, 0x1ad9: 0x320c, 0x1ada: 0x320f, 0x1adb: 0x320f, 0x1adc: 0x320f, 0x1add: 0x320f, + 0x1ade: 0x3212, 0x1adf: 0x3212, 0x1ae0: 0x3215, 0x1ae1: 0x3215, 0x1ae2: 0x3215, 0x1ae3: 0x3215, + 0x1ae4: 0x06ba, 0x1ae5: 0x06ba, 0x1ae6: 0x3218, 0x1ae7: 0x3218, 0x1ae8: 0x3218, 0x1ae9: 0x3218, + 0x1aea: 0x321b, 0x1aeb: 0x321b, 0x1aec: 0x321b, 0x1aed: 0x321b, 0x1aee: 0x321e, 0x1aef: 0x321e, + 0x1af0: 0x06c4, 0x1af1: 0x06c4, + // Block 0x6c, offset 0x1b00 + 0x1b13: 0x3221, 0x1b14: 0x3221, 0x1b15: 0x3221, 0x1b16: 0x3221, 0x1b17: 0x3224, + 0x1b18: 0x3224, 0x1b19: 0x3227, 0x1b1a: 0x3227, 0x1b1b: 0x322a, 0x1b1c: 0x322a, 0x1b1d: 0x06b0, + 0x1b1e: 0x322d, 0x1b1f: 0x322d, 0x1b20: 0x3230, 0x1b21: 0x3230, 0x1b22: 0x3233, 0x1b23: 0x3233, + 0x1b24: 0x3236, 0x1b25: 0x3236, 0x1b26: 0x3236, 0x1b27: 0x3236, 0x1b28: 0x3239, 0x1b29: 0x3239, + 0x1b2a: 0x323c, 0x1b2b: 0x323c, 0x1b2c: 0x3243, 0x1b2d: 0x3243, 0x1b2e: 0x324a, 0x1b2f: 0x324a, + 0x1b30: 0x3251, 0x1b31: 0x3251, 0x1b32: 0x3258, 0x1b33: 0x3258, 0x1b34: 0x325f, 0x1b35: 0x325f, + 0x1b36: 0x3266, 0x1b37: 0x3266, 0x1b38: 0x3266, 0x1b39: 0x326d, 0x1b3a: 0x326d, 0x1b3b: 0x326d, + 0x1b3c: 0x3274, 0x1b3d: 0x3274, 0x1b3e: 0x3274, 0x1b3f: 0x3274, + // Block 0x6d, offset 0x1b40 + 0x1b40: 0x3277, 0x1b41: 0x327e, 0x1b42: 0x3285, 0x1b43: 0x326d, 0x1b44: 0x328c, 0x1b45: 0x3293, + 0x1b46: 0x3298, 0x1b47: 0x329d, 0x1b48: 0x32a2, 0x1b49: 0x32a7, 0x1b4a: 0x32ac, 0x1b4b: 0x32b1, + 0x1b4c: 0x32b6, 0x1b4d: 0x32bb, 0x1b4e: 0x32c0, 0x1b4f: 0x32c5, 0x1b50: 0x32ca, 0x1b51: 0x32cf, + 0x1b52: 0x32d4, 0x1b53: 0x32d9, 0x1b54: 0x32de, 0x1b55: 0x32e3, 0x1b56: 0x32e8, 0x1b57: 0x32ed, + 0x1b58: 0x32f2, 0x1b59: 0x32f7, 0x1b5a: 0x32fc, 0x1b5b: 0x3301, 0x1b5c: 0x3306, 0x1b5d: 0x330b, + 0x1b5e: 0x3310, 0x1b5f: 0x3315, 0x1b60: 0x331a, 0x1b61: 0x331f, 0x1b62: 0x3324, 0x1b63: 0x3329, + 0x1b64: 0x332e, 0x1b65: 0x3333, 0x1b66: 0x3338, 0x1b67: 0x333d, 0x1b68: 0x3342, 0x1b69: 0x3347, + 0x1b6a: 0x334c, 0x1b6b: 0x3351, 0x1b6c: 0x3356, 0x1b6d: 0x335b, 0x1b6e: 0x3360, 0x1b6f: 0x3365, + 0x1b70: 0x336a, 0x1b71: 0x336f, 0x1b72: 0x3374, 0x1b73: 0x3379, 0x1b74: 0x337e, 0x1b75: 0x3383, + 0x1b76: 0x3388, 0x1b77: 0x338d, 0x1b78: 0x3392, 0x1b79: 0x3397, 0x1b7a: 0x339c, 0x1b7b: 0x33a1, + 0x1b7c: 0x33a6, 0x1b7d: 0x33ab, 0x1b7e: 0x33b0, 0x1b7f: 0x33b5, + // Block 0x6e, offset 0x1b80 + 0x1b80: 0x33ba, 0x1b81: 0x33bf, 0x1b82: 0x33c4, 0x1b83: 0x33c9, 0x1b84: 0x33ce, 0x1b85: 0x33d3, + 0x1b86: 0x33d8, 0x1b87: 0x33dd, 0x1b88: 0x33e2, 0x1b89: 0x33e7, 0x1b8a: 0x33ec, 0x1b8b: 0x33f1, + 0x1b8c: 0x33f6, 0x1b8d: 0x33fb, 0x1b8e: 0x3400, 0x1b8f: 0x3405, 0x1b90: 0x340a, 0x1b91: 0x340f, + 0x1b92: 0x3414, 0x1b93: 0x3419, 0x1b94: 0x341e, 0x1b95: 0x3423, 0x1b96: 0x3428, 0x1b97: 0x342d, + 0x1b98: 0x3432, 0x1b99: 0x3437, 0x1b9a: 0x343c, 0x1b9b: 0x3441, 0x1b9c: 0x3446, 0x1b9d: 0x344b, + 0x1b9e: 0x3450, 0x1b9f: 0x3456, 0x1ba0: 0x345c, 0x1ba1: 0x3462, 0x1ba2: 0x3468, 0x1ba3: 0x346e, + 0x1ba4: 0x3474, 0x1ba5: 0x347b, 0x1ba6: 0x3285, 0x1ba7: 0x3482, 0x1ba8: 0x326d, 0x1ba9: 0x328c, + 0x1baa: 0x3489, 0x1bab: 0x348e, 0x1bac: 0x32a2, 0x1bad: 0x3493, 0x1bae: 0x32a7, 0x1baf: 0x32ac, + 0x1bb0: 0x3498, 0x1bb1: 0x349d, 0x1bb2: 0x32c0, 0x1bb3: 0x34a2, 0x1bb4: 0x32c5, 0x1bb5: 0x32ca, + 0x1bb6: 0x34a7, 0x1bb7: 0x34ac, 0x1bb8: 0x32d4, 0x1bb9: 0x34b1, 0x1bba: 0x32d9, 0x1bbb: 0x32de, + 0x1bbc: 0x336f, 0x1bbd: 0x3374, 0x1bbe: 0x3383, 0x1bbf: 0x3388, + // Block 0x6f, offset 0x1bc0 + 0x1bc0: 0x338d, 0x1bc1: 0x33a1, 0x1bc2: 0x33a6, 0x1bc3: 0x33ab, 0x1bc4: 0x33b0, 0x1bc5: 0x33c4, + 0x1bc6: 0x33c9, 0x1bc7: 0x33ce, 0x1bc8: 0x34b6, 0x1bc9: 0x33e2, 0x1bca: 0x34bb, 0x1bcb: 0x34c0, + 0x1bcc: 0x3400, 0x1bcd: 0x34c5, 0x1bce: 0x3405, 0x1bcf: 0x340a, 0x1bd0: 0x344b, 0x1bd1: 0x34ca, + 0x1bd2: 0x34cf, 0x1bd3: 0x3432, 0x1bd4: 0x34d4, 0x1bd5: 0x3437, 0x1bd6: 0x343c, 0x1bd7: 0x3277, + 0x1bd8: 0x327e, 0x1bd9: 0x34d9, 0x1bda: 0x3285, 0x1bdb: 0x34e0, 0x1bdc: 0x3293, 0x1bdd: 0x3298, + 0x1bde: 0x329d, 0x1bdf: 0x32a2, 0x1be0: 0x34e7, 0x1be1: 0x32b1, 0x1be2: 0x32b6, 0x1be3: 0x32bb, + 0x1be4: 0x32c0, 0x1be5: 0x34ec, 0x1be6: 0x32d4, 0x1be7: 0x32e3, 0x1be8: 0x32e8, 0x1be9: 0x32ed, + 0x1bea: 0x32f2, 0x1beb: 0x32f7, 0x1bec: 0x3301, 0x1bed: 0x3306, 0x1bee: 0x330b, 0x1bef: 0x3310, + 0x1bf0: 0x3315, 0x1bf1: 0x331a, 0x1bf2: 0x34f1, 0x1bf3: 0x331f, 0x1bf4: 0x3324, 0x1bf5: 0x3329, + 0x1bf6: 0x332e, 0x1bf7: 0x3333, 0x1bf8: 0x3338, 0x1bf9: 0x3342, 0x1bfa: 0x3347, 0x1bfb: 0x334c, + 0x1bfc: 0x3351, 0x1bfd: 0x3356, 0x1bfe: 0x335b, 0x1bff: 0x3360, + // Block 0x70, offset 0x1c00 + 0x1c00: 0x3365, 0x1c01: 0x336a, 0x1c02: 0x3379, 0x1c03: 0x337e, 0x1c04: 0x3392, 0x1c05: 0x3397, + 0x1c06: 0x339c, 0x1c07: 0x33a1, 0x1c08: 0x33a6, 0x1c09: 0x33b5, 0x1c0a: 0x33ba, 0x1c0b: 0x33bf, + 0x1c0c: 0x33c4, 0x1c0d: 0x34f6, 0x1c0e: 0x33d3, 0x1c0f: 0x33d8, 0x1c10: 0x33dd, 0x1c11: 0x33e2, + 0x1c12: 0x33f1, 0x1c13: 0x33f6, 0x1c14: 0x33fb, 0x1c15: 0x3400, 0x1c16: 0x34fb, 0x1c17: 0x340f, + 0x1c18: 0x3414, 0x1c19: 0x3500, 0x1c1a: 0x3423, 0x1c1b: 0x3428, 0x1c1c: 0x342d, 0x1c1d: 0x3432, + 0x1c1e: 0x3505, 0x1c1f: 0x3285, 0x1c20: 0x34e0, 0x1c21: 0x32a2, 0x1c22: 0x34e7, 0x1c23: 0x32c0, + 0x1c24: 0x34ec, 0x1c25: 0x32d4, 0x1c26: 0x350a, 0x1c27: 0x3315, 0x1c28: 0x350f, 0x1c29: 0x3514, + 0x1c2a: 0x3519, 0x1c2b: 0x33a1, 0x1c2c: 0x33a6, 0x1c2d: 0x33c4, 0x1c2e: 0x3400, 0x1c2f: 0x34fb, + 0x1c30: 0x3432, 0x1c31: 0x3505, 0x1c32: 0x351e, 0x1c33: 0x3525, 0x1c34: 0x352c, 0x1c35: 0x3533, + 0x1c36: 0x3538, 0x1c37: 0x353d, 0x1c38: 0x3542, 0x1c39: 0x3547, 0x1c3a: 0x354c, 0x1c3b: 0x3551, + 0x1c3c: 0x3556, 0x1c3d: 0x355b, 0x1c3e: 0x3560, 0x1c3f: 0x3565, + // Block 0x71, offset 0x1c40 + 0x1c40: 0x356a, 0x1c41: 0x356f, 0x1c42: 0x3574, 0x1c43: 0x3579, 0x1c44: 0x357e, 0x1c45: 0x3583, + 0x1c46: 0x3588, 0x1c47: 0x358d, 0x1c48: 0x3592, 0x1c49: 0x3597, 0x1c4a: 0x359c, 0x1c4b: 0x35a1, + 0x1c4c: 0x3514, 0x1c4d: 0x35a6, 0x1c4e: 0x35ab, 0x1c4f: 0x35b0, 0x1c50: 0x35b5, 0x1c51: 0x3533, + 0x1c52: 0x3538, 0x1c53: 0x353d, 0x1c54: 0x3542, 0x1c55: 0x3547, 0x1c56: 0x354c, 0x1c57: 0x3551, + 0x1c58: 0x3556, 0x1c59: 0x355b, 0x1c5a: 0x3560, 0x1c5b: 0x3565, 0x1c5c: 0x356a, 0x1c5d: 0x356f, + 0x1c5e: 0x3574, 0x1c5f: 0x3579, 0x1c60: 0x357e, 0x1c61: 0x3583, 0x1c62: 0x3588, 0x1c63: 0x358d, + 0x1c64: 0x3592, 0x1c65: 0x3597, 0x1c66: 0x359c, 0x1c67: 0x35a1, 0x1c68: 0x3514, 0x1c69: 0x35a6, + 0x1c6a: 0x35ab, 0x1c6b: 0x35b0, 0x1c6c: 0x35b5, 0x1c6d: 0x3597, 0x1c6e: 0x359c, 0x1c6f: 0x35a1, + 0x1c70: 0x3514, 0x1c71: 0x350f, 0x1c72: 0x3519, 0x1c73: 0x333d, 0x1c74: 0x3306, 0x1c75: 0x330b, + 0x1c76: 0x3310, 0x1c77: 0x3597, 0x1c78: 0x359c, 0x1c79: 0x35a1, 0x1c7a: 0x333d, 0x1c7b: 0x3342, + 0x1c7c: 0x35ba, 0x1c7d: 0x35ba, + // Block 0x72, offset 0x1c80 + 0x1c90: 0x35bf, 0x1c91: 0x35c6, + 0x1c92: 0x35c6, 0x1c93: 0x35cd, 0x1c94: 0x35d4, 0x1c95: 0x35db, 0x1c96: 0x35e2, 0x1c97: 0x35e9, + 0x1c98: 0x35f0, 0x1c99: 0x35f0, 0x1c9a: 0x35f7, 0x1c9b: 0x35fe, 0x1c9c: 0x3605, 0x1c9d: 0x360c, + 0x1c9e: 0x3613, 0x1c9f: 0x361a, 0x1ca0: 0x361a, 0x1ca1: 0x3621, 0x1ca2: 0x3628, 0x1ca3: 0x3628, + 0x1ca4: 0x362f, 0x1ca5: 0x362f, 0x1ca6: 0x3636, 0x1ca7: 0x363d, 0x1ca8: 0x363d, 0x1ca9: 0x3644, + 0x1caa: 0x364b, 0x1cab: 0x364b, 0x1cac: 0x3652, 0x1cad: 0x3652, 0x1cae: 0x3659, 0x1caf: 0x3660, + 0x1cb0: 0x3660, 0x1cb1: 0x3667, 0x1cb2: 0x3667, 0x1cb3: 0x366e, 0x1cb4: 0x3675, 0x1cb5: 0x367c, + 0x1cb6: 0x3683, 0x1cb7: 0x3683, 0x1cb8: 0x368a, 0x1cb9: 0x3691, 0x1cba: 0x3698, 0x1cbb: 0x369f, + 0x1cbc: 0x36a6, 0x1cbd: 0x36a6, 0x1cbe: 0x36ad, 0x1cbf: 0x36b4, + // Block 0x73, offset 0x1cc0 + 0x1cc0: 0x36bb, 0x1cc1: 0x36c2, 0x1cc2: 0x36c9, 0x1cc3: 0x36d0, 0x1cc4: 0x36d0, 0x1cc5: 0x36d7, + 0x1cc6: 0x36d7, 0x1cc7: 0x36de, 0x1cc8: 0x36de, 0x1cc9: 0x36e5, 0x1cca: 0x36ec, 0x1ccb: 0x36f3, + 0x1ccc: 0x36fa, 0x1ccd: 0x3701, 0x1cce: 0x3708, 0x1ccf: 0x370f, + 0x1cd2: 0x3716, 0x1cd3: 0x371d, 0x1cd4: 0x3724, 0x1cd5: 0x372b, 0x1cd6: 0x3732, 0x1cd7: 0x3739, + 0x1cd8: 0x3739, 0x1cd9: 0x3740, 0x1cda: 0x3747, 0x1cdb: 0x374e, 0x1cdc: 0x3755, 0x1cdd: 0x3755, + 0x1cde: 0x375c, 0x1cdf: 0x3763, 0x1ce0: 0x376a, 0x1ce1: 0x3771, 0x1ce2: 0x3778, 0x1ce3: 0x377f, + 0x1ce4: 0x3786, 0x1ce5: 0x378d, 0x1ce6: 0x3794, 0x1ce7: 0x379b, 0x1ce8: 0x37a2, 0x1ce9: 0x37a9, + 0x1cea: 0x37b0, 0x1ceb: 0x37b7, 0x1cec: 0x37be, 0x1ced: 0x37c5, 0x1cee: 0x37cc, 0x1cef: 0x37d3, + 0x1cf0: 0x37da, 0x1cf1: 0x37e1, 0x1cf2: 0x37e8, 0x1cf3: 0x37ef, 0x1cf4: 0x36ad, 0x1cf5: 0x36bb, + 0x1cf6: 0x37f6, 0x1cf7: 0x37fd, 0x1cf8: 0x3804, 0x1cf9: 0x380b, 0x1cfa: 0x3812, 0x1cfb: 0x3819, + 0x1cfc: 0x3812, 0x1cfd: 0x3804, 0x1cfe: 0x3820, 0x1cff: 0x3827, + // Block 0x74, offset 0x1d00 + 0x1d00: 0x382e, 0x1d01: 0x3835, 0x1d02: 0x383c, 0x1d03: 0x3819, 0x1d04: 0x367c, 0x1d05: 0x3636, + 0x1d06: 0x3843, 0x1d07: 0x384a, + 0x1d30: 0x3851, 0x1d31: 0x3858, 0x1d32: 0x385f, 0x1d33: 0x3868, 0x1d34: 0x3871, 0x1d35: 0x387a, + 0x1d36: 0x3883, 0x1d37: 0x388c, 0x1d38: 0x3895, 0x1d39: 0x389e, 0x1d3a: 0x38a5, 0x1d3b: 0x38c7, + 0x1d3c: 0x38d7, + // Block 0x75, offset 0x1d40 + 0x1d50: 0x38e0, 0x1d51: 0x38e2, + 0x1d52: 0x38e6, 0x1d53: 0x38ea, 0x1d54: 0x04e1, 0x1d55: 0x38ec, 0x1d56: 0x38ee, 0x1d57: 0x38f0, + 0x1d58: 0x38f4, 0x1d59: 0x1443, + 0x1d70: 0x1440, 0x1d71: 0x38f8, 0x1d72: 0x38fc, 0x1d73: 0x3900, 0x1d74: 0x3900, 0x1d75: 0x149c, + 0x1d76: 0x149e, 0x1d77: 0x3902, 0x1d78: 0x3904, 0x1d79: 0x3906, 0x1d7a: 0x390a, 0x1d7b: 0x390e, + 0x1d7c: 0x3912, 0x1d7d: 0x3916, 0x1d7e: 0x391a, 0x1d7f: 0x16c3, + // Block 0x76, offset 0x1d80 + 0x1d80: 0x16c7, 0x1d81: 0x391e, 0x1d82: 0x3922, 0x1d83: 0x3926, 0x1d84: 0x392a, + 0x1d87: 0x392e, 0x1d88: 0x3930, 0x1d89: 0x146c, 0x1d8a: 0x146c, 0x1d8b: 0x146c, + 0x1d8c: 0x146c, 0x1d8d: 0x3900, 0x1d8e: 0x3900, 0x1d8f: 0x3900, 0x1d90: 0x38e0, 0x1d91: 0x38e2, + 0x1d92: 0x143e, 0x1d94: 0x04e1, 0x1d95: 0x38ea, 0x1d96: 0x38ee, 0x1d97: 0x38ec, + 0x1d98: 0x38f8, 0x1d99: 0x149c, 0x1d9a: 0x149e, 0x1d9b: 0x3902, 0x1d9c: 0x3904, 0x1d9d: 0x3906, + 0x1d9e: 0x390a, 0x1d9f: 0x3932, 0x1da0: 0x3934, 0x1da1: 0x3936, 0x1da2: 0x1494, 0x1da3: 0x3938, + 0x1da4: 0x393a, 0x1da5: 0x393c, 0x1da6: 0x149a, 0x1da8: 0x393e, 0x1da9: 0x3940, + 0x1daa: 0x3942, 0x1dab: 0x3944, + 0x1db0: 0x3946, 0x1db1: 0x394a, 0x1db2: 0x394f, 0x1db4: 0x3953, + 0x1db6: 0x3957, 0x1db7: 0x395b, 0x1db8: 0x3960, 0x1db9: 0x3964, 0x1dba: 0x3969, 0x1dbb: 0x396d, + 0x1dbc: 0x3972, 0x1dbd: 0x3976, 0x1dbe: 0x397b, 0x1dbf: 0x397f, + // Block 0x77, offset 0x1dc0 + 0x1dc0: 0x3984, 0x1dc1: 0x068d, 0x1dc2: 0x068d, 0x1dc3: 0x0692, 0x1dc4: 0x0692, 0x1dc5: 0x0697, + 0x1dc6: 0x0697, 0x1dc7: 0x069c, 0x1dc8: 0x069c, 0x1dc9: 0x06a1, 0x1dca: 0x06a1, 0x1dcb: 0x06a1, + 0x1dcc: 0x06a1, 0x1dcd: 0x3987, 0x1dce: 0x3987, 0x1dcf: 0x398a, 0x1dd0: 0x398a, 0x1dd1: 0x398a, + 0x1dd2: 0x398a, 0x1dd3: 0x398d, 0x1dd4: 0x398d, 0x1dd5: 0x3990, 0x1dd6: 0x3990, 0x1dd7: 0x3990, + 0x1dd8: 0x3990, 0x1dd9: 0x3993, 0x1dda: 0x3993, 0x1ddb: 0x3993, 0x1ddc: 0x3993, 0x1ddd: 0x3996, + 0x1dde: 0x3996, 0x1ddf: 0x3996, 0x1de0: 0x3996, 0x1de1: 0x3999, 0x1de2: 0x3999, 0x1de3: 0x3999, + 0x1de4: 0x3999, 0x1de5: 0x399c, 0x1de6: 0x399c, 0x1de7: 0x399c, 0x1de8: 0x399c, 0x1de9: 0x399f, + 0x1dea: 0x399f, 0x1deb: 0x39a2, 0x1dec: 0x39a2, 0x1ded: 0x39a5, 0x1dee: 0x39a5, 0x1def: 0x39a8, + 0x1df0: 0x39a8, 0x1df1: 0x39ab, 0x1df2: 0x39ab, 0x1df3: 0x39ab, 0x1df4: 0x39ab, 0x1df5: 0x39ae, + 0x1df6: 0x39ae, 0x1df7: 0x39ae, 0x1df8: 0x39ae, 0x1df9: 0x39b1, 0x1dfa: 0x39b1, 0x1dfb: 0x39b1, + 0x1dfc: 0x39b1, 0x1dfd: 0x39b4, 0x1dfe: 0x39b4, 0x1dff: 0x39b4, + // Block 0x78, offset 0x1e00 + 0x1e00: 0x39b4, 0x1e01: 0x39b7, 0x1e02: 0x39b7, 0x1e03: 0x39b7, 0x1e04: 0x39b7, 0x1e05: 0x39ba, + 0x1e06: 0x39ba, 0x1e07: 0x39ba, 0x1e08: 0x39ba, 0x1e09: 0x39bd, 0x1e0a: 0x39bd, 0x1e0b: 0x39bd, + 0x1e0c: 0x39bd, 0x1e0d: 0x39c0, 0x1e0e: 0x39c0, 0x1e0f: 0x39c0, 0x1e10: 0x39c0, 0x1e11: 0x39c3, + 0x1e12: 0x39c3, 0x1e13: 0x39c3, 0x1e14: 0x39c3, 0x1e15: 0x39c6, 0x1e16: 0x39c6, 0x1e17: 0x39c6, + 0x1e18: 0x39c6, 0x1e19: 0x39c9, 0x1e1a: 0x39c9, 0x1e1b: 0x39c9, 0x1e1c: 0x39c9, 0x1e1d: 0x39cc, + 0x1e1e: 0x39cc, 0x1e1f: 0x39cc, 0x1e20: 0x39cc, 0x1e21: 0x39cf, 0x1e22: 0x39cf, 0x1e23: 0x39cf, + 0x1e24: 0x39cf, 0x1e25: 0x39d2, 0x1e26: 0x39d2, 0x1e27: 0x39d2, 0x1e28: 0x39d2, 0x1e29: 0x39d5, + 0x1e2a: 0x39d5, 0x1e2b: 0x39d5, 0x1e2c: 0x39d5, 0x1e2d: 0x39d8, 0x1e2e: 0x39d8, 0x1e2f: 0x3239, + 0x1e30: 0x3239, 0x1e31: 0x39db, 0x1e32: 0x39db, 0x1e33: 0x39db, 0x1e34: 0x39db, 0x1e35: 0x39de, + 0x1e36: 0x39de, 0x1e37: 0x39e5, 0x1e38: 0x39e5, 0x1e39: 0x39ec, 0x1e3a: 0x39ec, 0x1e3b: 0x39f3, + 0x1e3c: 0x39f3, + // Block 0x79, offset 0x1e40 + 0x1e41: 0x38ec, 0x1e42: 0x39f8, 0x1e43: 0x3932, 0x1e44: 0x3940, 0x1e45: 0x3942, + 0x1e46: 0x3934, 0x1e47: 0x39fa, 0x1e48: 0x149c, 0x1e49: 0x149e, 0x1e4a: 0x3936, 0x1e4b: 0x1494, + 0x1e4c: 0x38e0, 0x1e4d: 0x3938, 0x1e4e: 0x143e, 0x1e4f: 0x39fc, 0x1e50: 0x1486, 0x1e51: 0x001c, + 0x1e52: 0x000d, 0x1e53: 0x000f, 0x1e54: 0x1488, 0x1e55: 0x148a, 0x1e56: 0x148c, 0x1e57: 0x148e, + 0x1e58: 0x1490, 0x1e59: 0x1492, 0x1e5a: 0x38ea, 0x1e5b: 0x04e1, 0x1e5c: 0x393a, 0x1e5d: 0x149a, + 0x1e5e: 0x393c, 0x1e5f: 0x38ee, 0x1e60: 0x3944, 0x1e61: 0x0906, 0x1e62: 0x090b, 0x1e63: 0x14ad, + 0x1e64: 0x090d, 0x1e65: 0x090f, 0x1e66: 0x14d9, 0x1e67: 0x0914, 0x1e68: 0x0916, 0x1e69: 0x0918, + 0x1e6a: 0x091a, 0x1e6b: 0x091c, 0x1e6c: 0x091e, 0x1e6d: 0x0920, 0x1e6e: 0x0922, 0x1e6f: 0x0924, + 0x1e70: 0x0929, 0x1e71: 0x14c8, 0x1e72: 0x092b, 0x1e73: 0x17f6, 0x1e74: 0x092d, 0x1e75: 0x092f, + 0x1e76: 0x155f, 0x1e77: 0x0931, 0x1e78: 0x1570, 0x1e79: 0x17f8, 0x1e7a: 0x14d4, 0x1e7b: 0x392e, + 0x1e7c: 0x393e, 0x1e7d: 0x3930, 0x1e7e: 0x39fe, 0x1e7f: 0x3900, + // Block 0x7a, offset 0x1e80 + 0x1e80: 0x13f7, 0x1e81: 0x0007, 0x1e82: 0x093d, 0x1e83: 0x0984, 0x1e84: 0x093f, 0x1e85: 0x0941, + 0x1e86: 0x098c, 0x1e87: 0x094c, 0x1e88: 0x0494, 0x1e89: 0x097c, 0x1e8a: 0x0499, 0x1e8b: 0x094e, + 0x1e8c: 0x04c5, 0x1e8d: 0x0950, 0x1e8e: 0x14a0, 0x1e8f: 0x001e, 0x1e90: 0x0960, 0x1e91: 0x17fa, + 0x1e92: 0x049b, 0x1e93: 0x02c8, 0x1e94: 0x0962, 0x1e95: 0x0964, 0x1e96: 0x096d, 0x1e97: 0x04a6, + 0x1e98: 0x04c7, 0x1e99: 0x04a8, 0x1e9a: 0x09df, 0x1e9b: 0x3902, 0x1e9c: 0x3a00, 0x1e9d: 0x3904, + 0x1e9e: 0x3a02, 0x1e9f: 0x3a04, 0x1ea0: 0x3a08, 0x1ea1: 0x38e6, 0x1ea2: 0x391e, 0x1ea3: 0x3922, + 0x1ea4: 0x38e2, 0x1ea5: 0x3a0c, 0x1ea6: 0x2321, 0x1ea7: 0x3a10, 0x1ea8: 0x3a14, 0x1ea9: 0x3a18, + 0x1eaa: 0x3a1c, 0x1eab: 0x3a20, 0x1eac: 0x3a24, 0x1ead: 0x3a28, 0x1eae: 0x3a2c, 0x1eaf: 0x3a30, + 0x1eb0: 0x3a34, 0x1eb1: 0x2269, 0x1eb2: 0x226d, 0x1eb3: 0x2271, 0x1eb4: 0x2275, 0x1eb5: 0x2279, + 0x1eb6: 0x227d, 0x1eb7: 0x2281, 0x1eb8: 0x2285, 0x1eb9: 0x2289, 0x1eba: 0x228d, 0x1ebb: 0x2291, + 0x1ebc: 0x2295, 0x1ebd: 0x2299, 0x1ebe: 0x229d, 0x1ebf: 0x22a1, + // Block 0x7b, offset 0x1ec0 + 0x1ec0: 0x22a5, 0x1ec1: 0x22a9, 0x1ec2: 0x22ad, 0x1ec3: 0x22b1, 0x1ec4: 0x22b5, 0x1ec5: 0x22b9, + 0x1ec6: 0x22bd, 0x1ec7: 0x22c1, 0x1ec8: 0x22c5, 0x1ec9: 0x22c9, 0x1eca: 0x22cd, 0x1ecb: 0x22d1, + 0x1ecc: 0x22d5, 0x1ecd: 0x22d9, 0x1ece: 0x22dd, 0x1ecf: 0x22e1, 0x1ed0: 0x22e5, 0x1ed1: 0x22e9, + 0x1ed2: 0x22ed, 0x1ed3: 0x22f1, 0x1ed4: 0x22f5, 0x1ed5: 0x22f9, 0x1ed6: 0x22fd, 0x1ed7: 0x2301, + 0x1ed8: 0x2305, 0x1ed9: 0x2309, 0x1eda: 0x230d, 0x1edb: 0x2311, 0x1edc: 0x2315, 0x1edd: 0x3a38, + 0x1ede: 0x3a3c, 0x1edf: 0x3a40, 0x1ee0: 0x1e04, 0x1ee1: 0x1d38, 0x1ee2: 0x1d3c, 0x1ee3: 0x1d40, + 0x1ee4: 0x1d44, 0x1ee5: 0x1d48, 0x1ee6: 0x1d4c, 0x1ee7: 0x1d50, 0x1ee8: 0x1d54, 0x1ee9: 0x1d58, + 0x1eea: 0x1d5c, 0x1eeb: 0x1d60, 0x1eec: 0x1d64, 0x1eed: 0x1d68, 0x1eee: 0x1d6c, 0x1eef: 0x1d70, + 0x1ef0: 0x1d74, 0x1ef1: 0x1d78, 0x1ef2: 0x1d7c, 0x1ef3: 0x1d80, 0x1ef4: 0x1d84, 0x1ef5: 0x1d88, + 0x1ef6: 0x1d8c, 0x1ef7: 0x1d90, 0x1ef8: 0x1d94, 0x1ef9: 0x1d98, 0x1efa: 0x1d9c, 0x1efb: 0x1da0, + 0x1efc: 0x1da4, 0x1efd: 0x1da8, 0x1efe: 0x1dac, + // Block 0x7c, offset 0x1f00 + 0x1f02: 0x1db0, 0x1f03: 0x1db4, 0x1f04: 0x1db8, 0x1f05: 0x1dbc, + 0x1f06: 0x1dc0, 0x1f07: 0x1dc4, 0x1f0a: 0x1dc8, 0x1f0b: 0x1dcc, + 0x1f0c: 0x1dd0, 0x1f0d: 0x1dd4, 0x1f0e: 0x1dd8, 0x1f0f: 0x1ddc, + 0x1f12: 0x1de0, 0x1f13: 0x1de4, 0x1f14: 0x1de8, 0x1f15: 0x1dec, 0x1f16: 0x1df0, 0x1f17: 0x1df4, + 0x1f1a: 0x1df8, 0x1f1b: 0x1dfc, 0x1f1c: 0x1e00, + 0x1f20: 0x3a44, 0x1f21: 0x3a47, 0x1f22: 0x3a4a, 0x1f23: 0x0009, + 0x1f24: 0x3a4d, 0x1f25: 0x3a50, 0x1f26: 0x3a53, 0x1f28: 0x3a57, 0x1f29: 0x3a5b, + 0x1f2a: 0x3a5f, 0x1f2b: 0x3a63, 0x1f2c: 0x3a67, 0x1f2d: 0x3a6b, 0x1f2e: 0x3a6f, + // Block 0x7d, offset 0x1f40 + 0x1f5a: 0x3a73, 0x1f5c: 0x3a7c, + 0x1f6b: 0x3a85, + // Block 0x7e, offset 0x1f80 + 0x1f9e: 0x3a8e, 0x1f9f: 0x3a97, 0x1fa0: 0x3aa0, 0x1fa1: 0x3aad, 0x1fa2: 0x3aba, 0x1fa3: 0x3ac7, + 0x1fa4: 0x3ad4, + // Block 0x7f, offset 0x1fc0 + 0x1ffb: 0x3ae1, + 0x1ffc: 0x3aea, 0x1ffd: 0x3af3, 0x1ffe: 0x3b00, 0x1fff: 0x3b0d, + // Block 0x80, offset 0x2000 + 0x2000: 0x3b1a, + // Block 0x81, offset 0x2040 + 0x2040: 0x0906, 0x2041: 0x090b, 0x2042: 0x14ad, 0x2043: 0x090d, 0x2044: 0x090f, 0x2045: 0x14d9, + 0x2046: 0x0914, 0x2047: 0x0916, 0x2048: 0x0918, 0x2049: 0x091a, 0x204a: 0x091c, 0x204b: 0x091e, + 0x204c: 0x0920, 0x204d: 0x0922, 0x204e: 0x0924, 0x204f: 0x0929, 0x2050: 0x14c8, 0x2051: 0x092b, + 0x2052: 0x17f6, 0x2053: 0x092d, 0x2054: 0x092f, 0x2055: 0x155f, 0x2056: 0x0931, 0x2057: 0x1570, + 0x2058: 0x17f8, 0x2059: 0x14d4, 0x205a: 0x0007, 0x205b: 0x093d, 0x205c: 0x0984, 0x205d: 0x093f, + 0x205e: 0x0941, 0x205f: 0x098c, 0x2060: 0x094c, 0x2061: 0x0494, 0x2062: 0x097c, 0x2063: 0x0499, + 0x2064: 0x094e, 0x2065: 0x04c5, 0x2066: 0x0950, 0x2067: 0x14a0, 0x2068: 0x001e, 0x2069: 0x0960, + 0x206a: 0x17fa, 0x206b: 0x049b, 0x206c: 0x02c8, 0x206d: 0x0962, 0x206e: 0x0964, 0x206f: 0x096d, + 0x2070: 0x04a6, 0x2071: 0x04c7, 0x2072: 0x04a8, 0x2073: 0x09df, 0x2074: 0x0906, 0x2075: 0x090b, + 0x2076: 0x14ad, 0x2077: 0x090d, 0x2078: 0x090f, 0x2079: 0x14d9, 0x207a: 0x0914, 0x207b: 0x0916, + 0x207c: 0x0918, 0x207d: 0x091a, 0x207e: 0x091c, 0x207f: 0x091e, + // Block 0x82, offset 0x2080 + 0x2080: 0x0920, 0x2081: 0x0922, 0x2082: 0x0924, 0x2083: 0x0929, 0x2084: 0x14c8, 0x2085: 0x092b, + 0x2086: 0x17f6, 0x2087: 0x092d, 0x2088: 0x092f, 0x2089: 0x155f, 0x208a: 0x0931, 0x208b: 0x1570, + 0x208c: 0x17f8, 0x208d: 0x14d4, 0x208e: 0x0007, 0x208f: 0x093d, 0x2090: 0x0984, 0x2091: 0x093f, + 0x2092: 0x0941, 0x2093: 0x098c, 0x2094: 0x094c, 0x2096: 0x097c, 0x2097: 0x0499, + 0x2098: 0x094e, 0x2099: 0x04c5, 0x209a: 0x0950, 0x209b: 0x14a0, 0x209c: 0x001e, 0x209d: 0x0960, + 0x209e: 0x17fa, 0x209f: 0x049b, 0x20a0: 0x02c8, 0x20a1: 0x0962, 0x20a2: 0x0964, 0x20a3: 0x096d, + 0x20a4: 0x04a6, 0x20a5: 0x04c7, 0x20a6: 0x04a8, 0x20a7: 0x09df, 0x20a8: 0x0906, 0x20a9: 0x090b, + 0x20aa: 0x14ad, 0x20ab: 0x090d, 0x20ac: 0x090f, 0x20ad: 0x14d9, 0x20ae: 0x0914, 0x20af: 0x0916, + 0x20b0: 0x0918, 0x20b1: 0x091a, 0x20b2: 0x091c, 0x20b3: 0x091e, 0x20b4: 0x0920, 0x20b5: 0x0922, + 0x20b6: 0x0924, 0x20b7: 0x0929, 0x20b8: 0x14c8, 0x20b9: 0x092b, 0x20ba: 0x17f6, 0x20bb: 0x092d, + 0x20bc: 0x092f, 0x20bd: 0x155f, 0x20be: 0x0931, 0x20bf: 0x1570, + // Block 0x83, offset 0x20c0 + 0x20c0: 0x17f8, 0x20c1: 0x14d4, 0x20c2: 0x0007, 0x20c3: 0x093d, 0x20c4: 0x0984, 0x20c5: 0x093f, + 0x20c6: 0x0941, 0x20c7: 0x098c, 0x20c8: 0x094c, 0x20c9: 0x0494, 0x20ca: 0x097c, 0x20cb: 0x0499, + 0x20cc: 0x094e, 0x20cd: 0x04c5, 0x20ce: 0x0950, 0x20cf: 0x14a0, 0x20d0: 0x001e, 0x20d1: 0x0960, + 0x20d2: 0x17fa, 0x20d3: 0x049b, 0x20d4: 0x02c8, 0x20d5: 0x0962, 0x20d6: 0x0964, 0x20d7: 0x096d, + 0x20d8: 0x04a6, 0x20d9: 0x04c7, 0x20da: 0x04a8, 0x20db: 0x09df, 0x20dc: 0x0906, + 0x20de: 0x14ad, 0x20df: 0x090d, 0x20e2: 0x0914, + 0x20e5: 0x091a, 0x20e6: 0x091c, 0x20e9: 0x0922, + 0x20ea: 0x0924, 0x20eb: 0x0929, 0x20ec: 0x14c8, 0x20ee: 0x17f6, 0x20ef: 0x092d, + 0x20f0: 0x092f, 0x20f1: 0x155f, 0x20f2: 0x0931, 0x20f3: 0x1570, 0x20f4: 0x17f8, 0x20f5: 0x14d4, + 0x20f6: 0x0007, 0x20f7: 0x093d, 0x20f8: 0x0984, 0x20f9: 0x093f, 0x20fb: 0x098c, + 0x20fd: 0x0494, 0x20fe: 0x097c, 0x20ff: 0x0499, + // Block 0x84, offset 0x2100 + 0x2100: 0x094e, 0x2101: 0x04c5, 0x2102: 0x0950, 0x2103: 0x14a0, 0x2105: 0x0960, + 0x2106: 0x17fa, 0x2107: 0x049b, 0x2108: 0x02c8, 0x2109: 0x0962, 0x210a: 0x0964, 0x210b: 0x096d, + 0x210c: 0x04a6, 0x210d: 0x04c7, 0x210e: 0x04a8, 0x210f: 0x09df, 0x2110: 0x0906, 0x2111: 0x090b, + 0x2112: 0x14ad, 0x2113: 0x090d, 0x2114: 0x090f, 0x2115: 0x14d9, 0x2116: 0x0914, 0x2117: 0x0916, + 0x2118: 0x0918, 0x2119: 0x091a, 0x211a: 0x091c, 0x211b: 0x091e, 0x211c: 0x0920, 0x211d: 0x0922, + 0x211e: 0x0924, 0x211f: 0x0929, 0x2120: 0x14c8, 0x2121: 0x092b, 0x2122: 0x17f6, 0x2123: 0x092d, + 0x2124: 0x092f, 0x2125: 0x155f, 0x2126: 0x0931, 0x2127: 0x1570, 0x2128: 0x17f8, 0x2129: 0x14d4, + 0x212a: 0x0007, 0x212b: 0x093d, 0x212c: 0x0984, 0x212d: 0x093f, 0x212e: 0x0941, 0x212f: 0x098c, + 0x2130: 0x094c, 0x2131: 0x0494, 0x2132: 0x097c, 0x2133: 0x0499, 0x2134: 0x094e, 0x2135: 0x04c5, + 0x2136: 0x0950, 0x2137: 0x14a0, 0x2138: 0x001e, 0x2139: 0x0960, 0x213a: 0x17fa, 0x213b: 0x049b, + 0x213c: 0x02c8, 0x213d: 0x0962, 0x213e: 0x0964, 0x213f: 0x096d, + // Block 0x85, offset 0x2140 + 0x2140: 0x04a6, 0x2141: 0x04c7, 0x2142: 0x04a8, 0x2143: 0x09df, 0x2144: 0x0906, 0x2145: 0x090b, + 0x2147: 0x090d, 0x2148: 0x090f, 0x2149: 0x14d9, 0x214a: 0x0914, + 0x214d: 0x091a, 0x214e: 0x091c, 0x214f: 0x091e, 0x2150: 0x0920, 0x2151: 0x0922, + 0x2152: 0x0924, 0x2153: 0x0929, 0x2154: 0x14c8, 0x2156: 0x17f6, 0x2157: 0x092d, + 0x2158: 0x092f, 0x2159: 0x155f, 0x215a: 0x0931, 0x215b: 0x1570, 0x215c: 0x17f8, + 0x215e: 0x0007, 0x215f: 0x093d, 0x2160: 0x0984, 0x2161: 0x093f, 0x2162: 0x0941, 0x2163: 0x098c, + 0x2164: 0x094c, 0x2165: 0x0494, 0x2166: 0x097c, 0x2167: 0x0499, 0x2168: 0x094e, 0x2169: 0x04c5, + 0x216a: 0x0950, 0x216b: 0x14a0, 0x216c: 0x001e, 0x216d: 0x0960, 0x216e: 0x17fa, 0x216f: 0x049b, + 0x2170: 0x02c8, 0x2171: 0x0962, 0x2172: 0x0964, 0x2173: 0x096d, 0x2174: 0x04a6, 0x2175: 0x04c7, + 0x2176: 0x04a8, 0x2177: 0x09df, 0x2178: 0x0906, 0x2179: 0x090b, 0x217b: 0x090d, + 0x217c: 0x090f, 0x217d: 0x14d9, 0x217e: 0x0914, + // Block 0x86, offset 0x2180 + 0x2180: 0x0918, 0x2181: 0x091a, 0x2182: 0x091c, 0x2183: 0x091e, 0x2184: 0x0920, + 0x2186: 0x0924, 0x218a: 0x17f6, 0x218b: 0x092d, + 0x218c: 0x092f, 0x218d: 0x155f, 0x218e: 0x0931, 0x218f: 0x1570, 0x2190: 0x17f8, + 0x2192: 0x0007, 0x2193: 0x093d, 0x2194: 0x0984, 0x2195: 0x093f, 0x2196: 0x0941, 0x2197: 0x098c, + 0x2198: 0x094c, 0x2199: 0x0494, 0x219a: 0x097c, 0x219b: 0x0499, 0x219c: 0x094e, 0x219d: 0x04c5, + 0x219e: 0x0950, 0x219f: 0x14a0, 0x21a0: 0x001e, 0x21a1: 0x0960, 0x21a2: 0x17fa, 0x21a3: 0x049b, + 0x21a4: 0x02c8, 0x21a5: 0x0962, 0x21a6: 0x0964, 0x21a7: 0x096d, 0x21a8: 0x04a6, 0x21a9: 0x04c7, + 0x21aa: 0x04a8, 0x21ab: 0x09df, 0x21ac: 0x0906, 0x21ad: 0x090b, 0x21ae: 0x14ad, 0x21af: 0x090d, + 0x21b0: 0x090f, 0x21b1: 0x14d9, 0x21b2: 0x0914, 0x21b3: 0x0916, 0x21b4: 0x0918, 0x21b5: 0x091a, + 0x21b6: 0x091c, 0x21b7: 0x091e, 0x21b8: 0x0920, 0x21b9: 0x0922, 0x21ba: 0x0924, 0x21bb: 0x0929, + 0x21bc: 0x14c8, 0x21bd: 0x092b, 0x21be: 0x17f6, 0x21bf: 0x092d, + // Block 0x87, offset 0x21c0 + 0x21c0: 0x092f, 0x21c1: 0x155f, 0x21c2: 0x0931, 0x21c3: 0x1570, 0x21c4: 0x17f8, 0x21c5: 0x14d4, + 0x21c6: 0x0007, 0x21c7: 0x093d, 0x21c8: 0x0984, 0x21c9: 0x093f, 0x21ca: 0x0941, 0x21cb: 0x098c, + 0x21cc: 0x094c, 0x21cd: 0x0494, 0x21ce: 0x097c, 0x21cf: 0x0499, 0x21d0: 0x094e, 0x21d1: 0x04c5, + 0x21d2: 0x0950, 0x21d3: 0x14a0, 0x21d4: 0x001e, 0x21d5: 0x0960, 0x21d6: 0x17fa, 0x21d7: 0x049b, + 0x21d8: 0x02c8, 0x21d9: 0x0962, 0x21da: 0x0964, 0x21db: 0x096d, 0x21dc: 0x04a6, 0x21dd: 0x04c7, + 0x21de: 0x04a8, 0x21df: 0x09df, 0x21e0: 0x0906, 0x21e1: 0x090b, 0x21e2: 0x14ad, 0x21e3: 0x090d, + 0x21e4: 0x090f, 0x21e5: 0x14d9, 0x21e6: 0x0914, 0x21e7: 0x0916, 0x21e8: 0x0918, 0x21e9: 0x091a, + 0x21ea: 0x091c, 0x21eb: 0x091e, 0x21ec: 0x0920, 0x21ed: 0x0922, 0x21ee: 0x0924, 0x21ef: 0x0929, + 0x21f0: 0x14c8, 0x21f1: 0x092b, 0x21f2: 0x17f6, 0x21f3: 0x092d, 0x21f4: 0x092f, 0x21f5: 0x155f, + 0x21f6: 0x0931, 0x21f7: 0x1570, 0x21f8: 0x17f8, 0x21f9: 0x14d4, 0x21fa: 0x0007, 0x21fb: 0x093d, + 0x21fc: 0x0984, 0x21fd: 0x093f, 0x21fe: 0x0941, 0x21ff: 0x098c, + // Block 0x88, offset 0x2200 + 0x2200: 0x094c, 0x2201: 0x0494, 0x2202: 0x097c, 0x2203: 0x0499, 0x2204: 0x094e, 0x2205: 0x04c5, + 0x2206: 0x0950, 0x2207: 0x14a0, 0x2208: 0x001e, 0x2209: 0x0960, 0x220a: 0x17fa, 0x220b: 0x049b, + 0x220c: 0x02c8, 0x220d: 0x0962, 0x220e: 0x0964, 0x220f: 0x096d, 0x2210: 0x04a6, 0x2211: 0x04c7, + 0x2212: 0x04a8, 0x2213: 0x09df, 0x2214: 0x0906, 0x2215: 0x090b, 0x2216: 0x14ad, 0x2217: 0x090d, + 0x2218: 0x090f, 0x2219: 0x14d9, 0x221a: 0x0914, 0x221b: 0x0916, 0x221c: 0x0918, 0x221d: 0x091a, + 0x221e: 0x091c, 0x221f: 0x091e, 0x2220: 0x0920, 0x2221: 0x0922, 0x2222: 0x0924, 0x2223: 0x0929, + 0x2224: 0x14c8, 0x2225: 0x092b, 0x2226: 0x17f6, 0x2227: 0x092d, 0x2228: 0x092f, 0x2229: 0x155f, + 0x222a: 0x0931, 0x222b: 0x1570, 0x222c: 0x17f8, 0x222d: 0x14d4, 0x222e: 0x0007, 0x222f: 0x093d, + 0x2230: 0x0984, 0x2231: 0x093f, 0x2232: 0x0941, 0x2233: 0x098c, 0x2234: 0x094c, 0x2235: 0x0494, + 0x2236: 0x097c, 0x2237: 0x0499, 0x2238: 0x094e, 0x2239: 0x04c5, 0x223a: 0x0950, 0x223b: 0x14a0, + 0x223c: 0x001e, 0x223d: 0x0960, 0x223e: 0x17fa, 0x223f: 0x049b, + // Block 0x89, offset 0x2240 + 0x2240: 0x02c8, 0x2241: 0x0962, 0x2242: 0x0964, 0x2243: 0x096d, 0x2244: 0x04a6, 0x2245: 0x04c7, + 0x2246: 0x04a8, 0x2247: 0x09df, 0x2248: 0x0906, 0x2249: 0x090b, 0x224a: 0x14ad, 0x224b: 0x090d, + 0x224c: 0x090f, 0x224d: 0x14d9, 0x224e: 0x0914, 0x224f: 0x0916, 0x2250: 0x0918, 0x2251: 0x091a, + 0x2252: 0x091c, 0x2253: 0x091e, 0x2254: 0x0920, 0x2255: 0x0922, 0x2256: 0x0924, 0x2257: 0x0929, + 0x2258: 0x14c8, 0x2259: 0x092b, 0x225a: 0x17f6, 0x225b: 0x092d, 0x225c: 0x092f, 0x225d: 0x155f, + 0x225e: 0x0931, 0x225f: 0x1570, 0x2260: 0x17f8, 0x2261: 0x14d4, 0x2262: 0x0007, 0x2263: 0x093d, + 0x2264: 0x0984, 0x2265: 0x093f, 0x2266: 0x0941, 0x2267: 0x098c, 0x2268: 0x094c, 0x2269: 0x0494, + 0x226a: 0x097c, 0x226b: 0x0499, 0x226c: 0x094e, 0x226d: 0x04c5, 0x226e: 0x0950, 0x226f: 0x14a0, + 0x2270: 0x001e, 0x2271: 0x0960, 0x2272: 0x17fa, 0x2273: 0x049b, 0x2274: 0x02c8, 0x2275: 0x0962, + 0x2276: 0x0964, 0x2277: 0x096d, 0x2278: 0x04a6, 0x2279: 0x04c7, 0x227a: 0x04a8, 0x227b: 0x09df, + 0x227c: 0x0906, 0x227d: 0x090b, 0x227e: 0x14ad, 0x227f: 0x090d, + // Block 0x8a, offset 0x2280 + 0x2280: 0x090f, 0x2281: 0x14d9, 0x2282: 0x0914, 0x2283: 0x0916, 0x2284: 0x0918, 0x2285: 0x091a, + 0x2286: 0x091c, 0x2287: 0x091e, 0x2288: 0x0920, 0x2289: 0x0922, 0x228a: 0x0924, 0x228b: 0x0929, + 0x228c: 0x14c8, 0x228d: 0x092b, 0x228e: 0x17f6, 0x228f: 0x092d, 0x2290: 0x092f, 0x2291: 0x155f, + 0x2292: 0x0931, 0x2293: 0x1570, 0x2294: 0x17f8, 0x2295: 0x14d4, 0x2296: 0x0007, 0x2297: 0x093d, + 0x2298: 0x0984, 0x2299: 0x093f, 0x229a: 0x0941, 0x229b: 0x098c, 0x229c: 0x094c, 0x229d: 0x0494, + 0x229e: 0x097c, 0x229f: 0x0499, 0x22a0: 0x094e, 0x22a1: 0x04c5, 0x22a2: 0x0950, 0x22a3: 0x14a0, + 0x22a4: 0x001e, 0x22a5: 0x0960, 0x22a6: 0x17fa, 0x22a7: 0x049b, 0x22a8: 0x02c8, 0x22a9: 0x0962, + 0x22aa: 0x0964, 0x22ab: 0x096d, 0x22ac: 0x04a6, 0x22ad: 0x04c7, 0x22ae: 0x04a8, 0x22af: 0x09df, + 0x22b0: 0x0906, 0x22b1: 0x090b, 0x22b2: 0x14ad, 0x22b3: 0x090d, 0x22b4: 0x090f, 0x22b5: 0x14d9, + 0x22b6: 0x0914, 0x22b7: 0x0916, 0x22b8: 0x0918, 0x22b9: 0x091a, 0x22ba: 0x091c, 0x22bb: 0x091e, + 0x22bc: 0x0920, 0x22bd: 0x0922, 0x22be: 0x0924, 0x22bf: 0x0929, + // Block 0x8b, offset 0x22c0 + 0x22c0: 0x14c8, 0x22c1: 0x092b, 0x22c2: 0x17f6, 0x22c3: 0x092d, 0x22c4: 0x092f, 0x22c5: 0x155f, + 0x22c6: 0x0931, 0x22c7: 0x1570, 0x22c8: 0x17f8, 0x22c9: 0x14d4, 0x22ca: 0x0007, 0x22cb: 0x093d, + 0x22cc: 0x0984, 0x22cd: 0x093f, 0x22ce: 0x0941, 0x22cf: 0x098c, 0x22d0: 0x094c, 0x22d1: 0x0494, + 0x22d2: 0x097c, 0x22d3: 0x0499, 0x22d4: 0x094e, 0x22d5: 0x04c5, 0x22d6: 0x0950, 0x22d7: 0x14a0, + 0x22d8: 0x001e, 0x22d9: 0x0960, 0x22da: 0x17fa, 0x22db: 0x049b, 0x22dc: 0x02c8, 0x22dd: 0x0962, + 0x22de: 0x0964, 0x22df: 0x096d, 0x22e0: 0x04a6, 0x22e1: 0x04c7, 0x22e2: 0x04a8, 0x22e3: 0x09df, + 0x22e4: 0x3b27, 0x22e5: 0x3b2a, 0x22e8: 0x3b2d, 0x22e9: 0x3b30, + 0x22ea: 0x14eb, 0x22eb: 0x3b33, 0x22ec: 0x3b36, 0x22ed: 0x3b39, 0x22ee: 0x3b3c, 0x22ef: 0x057b, + 0x22f0: 0x3b3f, 0x22f1: 0x3b42, 0x22f2: 0x3b45, 0x22f3: 0x3b48, 0x22f4: 0x3b4b, 0x22f5: 0x3b4e, + 0x22f6: 0x3b51, 0x22f7: 0x14ee, 0x22f8: 0x3b54, 0x22f9: 0x057b, 0x22fa: 0x0581, 0x22fb: 0x3b57, + 0x22fc: 0x055f, 0x22fd: 0x3b5a, 0x22fe: 0x3b5d, 0x22ff: 0x3b60, + // Block 0x8c, offset 0x2300 + 0x2300: 0x14d6, 0x2301: 0x3b63, 0x2302: 0x3b67, 0x2303: 0x0559, 0x2304: 0x0973, 0x2305: 0x0976, + 0x2306: 0x057e, 0x2307: 0x3b6a, 0x2308: 0x3b6d, 0x2309: 0x055c, 0x230a: 0x12fd, 0x230b: 0x0572, + 0x230c: 0x3b70, 0x230d: 0x0015, 0x230e: 0x3b73, 0x230f: 0x3b76, 0x2310: 0x3b79, 0x2311: 0x056f, + 0x2312: 0x0575, 0x2313: 0x0578, 0x2314: 0x3b7c, 0x2315: 0x3b7f, 0x2316: 0x3b82, 0x2317: 0x056c, + 0x2318: 0x0979, 0x2319: 0x3b85, 0x231a: 0x3b88, 0x231b: 0x3b8b, 0x231c: 0x057e, 0x231d: 0x055c, + 0x231e: 0x0572, 0x231f: 0x056c, 0x2320: 0x0575, 0x2321: 0x056f, 0x2322: 0x3b2d, 0x2323: 0x3b30, + 0x2324: 0x14eb, 0x2325: 0x3b33, 0x2326: 0x3b36, 0x2327: 0x3b39, 0x2328: 0x3b3c, 0x2329: 0x057b, + 0x232a: 0x3b3f, 0x232b: 0x3b42, 0x232c: 0x3b45, 0x232d: 0x3b48, 0x232e: 0x3b4b, 0x232f: 0x3b4e, + 0x2330: 0x3b51, 0x2331: 0x14ee, 0x2332: 0x3b54, 0x2333: 0x057b, 0x2334: 0x0581, 0x2335: 0x3b57, + 0x2336: 0x055f, 0x2337: 0x3b5a, 0x2338: 0x3b5d, 0x2339: 0x3b60, 0x233a: 0x14d6, 0x233b: 0x3b63, + 0x233c: 0x3b67, 0x233d: 0x0559, 0x233e: 0x0973, 0x233f: 0x0976, + // Block 0x8d, offset 0x2340 + 0x2340: 0x057e, 0x2341: 0x3b6a, 0x2342: 0x3b6d, 0x2343: 0x055c, 0x2344: 0x12fd, 0x2345: 0x0572, + 0x2346: 0x3b70, 0x2347: 0x0015, 0x2348: 0x3b73, 0x2349: 0x3b76, 0x234a: 0x3b79, 0x234b: 0x056f, + 0x234c: 0x0575, 0x234d: 0x0578, 0x234e: 0x3b7c, 0x234f: 0x3b7f, 0x2350: 0x3b82, 0x2351: 0x056c, + 0x2352: 0x0979, 0x2353: 0x3b85, 0x2354: 0x3b88, 0x2355: 0x3b8b, 0x2356: 0x057e, 0x2357: 0x055c, + 0x2358: 0x0572, 0x2359: 0x056c, 0x235a: 0x0575, 0x235b: 0x056f, 0x235c: 0x3b2d, 0x235d: 0x3b30, + 0x235e: 0x14eb, 0x235f: 0x3b33, 0x2360: 0x3b36, 0x2361: 0x3b39, 0x2362: 0x3b3c, 0x2363: 0x057b, + 0x2364: 0x3b3f, 0x2365: 0x3b42, 0x2366: 0x3b45, 0x2367: 0x3b48, 0x2368: 0x3b4b, 0x2369: 0x3b4e, + 0x236a: 0x3b51, 0x236b: 0x14ee, 0x236c: 0x3b54, 0x236d: 0x057b, 0x236e: 0x0581, 0x236f: 0x3b57, + 0x2370: 0x055f, 0x2371: 0x3b5a, 0x2372: 0x3b5d, 0x2373: 0x3b60, 0x2374: 0x14d6, 0x2375: 0x3b63, + 0x2376: 0x3b67, 0x2377: 0x0559, 0x2378: 0x0973, 0x2379: 0x0976, 0x237a: 0x057e, 0x237b: 0x3b6a, + 0x237c: 0x3b6d, 0x237d: 0x055c, 0x237e: 0x12fd, 0x237f: 0x0572, + // Block 0x8e, offset 0x2380 + 0x2380: 0x3b70, 0x2381: 0x0015, 0x2382: 0x3b73, 0x2383: 0x3b76, 0x2384: 0x3b79, 0x2385: 0x056f, + 0x2386: 0x0575, 0x2387: 0x0578, 0x2388: 0x3b7c, 0x2389: 0x3b7f, 0x238a: 0x3b82, 0x238b: 0x056c, + 0x238c: 0x0979, 0x238d: 0x3b85, 0x238e: 0x3b88, 0x238f: 0x3b8b, 0x2390: 0x057e, 0x2391: 0x055c, + 0x2392: 0x0572, 0x2393: 0x056c, 0x2394: 0x0575, 0x2395: 0x056f, 0x2396: 0x3b2d, 0x2397: 0x3b30, + 0x2398: 0x14eb, 0x2399: 0x3b33, 0x239a: 0x3b36, 0x239b: 0x3b39, 0x239c: 0x3b3c, 0x239d: 0x057b, + 0x239e: 0x3b3f, 0x239f: 0x3b42, 0x23a0: 0x3b45, 0x23a1: 0x3b48, 0x23a2: 0x3b4b, 0x23a3: 0x3b4e, + 0x23a4: 0x3b51, 0x23a5: 0x14ee, 0x23a6: 0x3b54, 0x23a7: 0x057b, 0x23a8: 0x0581, 0x23a9: 0x3b57, + 0x23aa: 0x055f, 0x23ab: 0x3b5a, 0x23ac: 0x3b5d, 0x23ad: 0x3b60, 0x23ae: 0x14d6, 0x23af: 0x3b63, + 0x23b0: 0x3b67, 0x23b1: 0x0559, 0x23b2: 0x0973, 0x23b3: 0x0976, 0x23b4: 0x057e, 0x23b5: 0x3b6a, + 0x23b6: 0x3b6d, 0x23b7: 0x055c, 0x23b8: 0x12fd, 0x23b9: 0x0572, 0x23ba: 0x3b70, 0x23bb: 0x0015, + 0x23bc: 0x3b73, 0x23bd: 0x3b76, 0x23be: 0x3b79, 0x23bf: 0x056f, + // Block 0x8f, offset 0x23c0 + 0x23c0: 0x0575, 0x23c1: 0x0578, 0x23c2: 0x3b7c, 0x23c3: 0x3b7f, 0x23c4: 0x3b82, 0x23c5: 0x056c, + 0x23c6: 0x0979, 0x23c7: 0x3b85, 0x23c8: 0x3b88, 0x23c9: 0x3b8b, 0x23ca: 0x057e, 0x23cb: 0x055c, + 0x23cc: 0x0572, 0x23cd: 0x056c, 0x23ce: 0x0575, 0x23cf: 0x056f, 0x23d0: 0x3b2d, 0x23d1: 0x3b30, + 0x23d2: 0x14eb, 0x23d3: 0x3b33, 0x23d4: 0x3b36, 0x23d5: 0x3b39, 0x23d6: 0x3b3c, 0x23d7: 0x057b, + 0x23d8: 0x3b3f, 0x23d9: 0x3b42, 0x23da: 0x3b45, 0x23db: 0x3b48, 0x23dc: 0x3b4b, 0x23dd: 0x3b4e, + 0x23de: 0x3b51, 0x23df: 0x14ee, 0x23e0: 0x3b54, 0x23e1: 0x057b, 0x23e2: 0x0581, 0x23e3: 0x3b57, + 0x23e4: 0x055f, 0x23e5: 0x3b5a, 0x23e6: 0x3b5d, 0x23e7: 0x3b60, 0x23e8: 0x14d6, 0x23e9: 0x3b63, + 0x23ea: 0x3b67, 0x23eb: 0x0559, 0x23ec: 0x0973, 0x23ed: 0x0976, 0x23ee: 0x057e, 0x23ef: 0x3b6a, + 0x23f0: 0x3b6d, 0x23f1: 0x055c, 0x23f2: 0x12fd, 0x23f3: 0x0572, 0x23f4: 0x3b70, 0x23f5: 0x0015, + 0x23f6: 0x3b73, 0x23f7: 0x3b76, 0x23f8: 0x3b79, 0x23f9: 0x056f, 0x23fa: 0x0575, 0x23fb: 0x0578, + 0x23fc: 0x3b7c, 0x23fd: 0x3b7f, 0x23fe: 0x3b82, 0x23ff: 0x056c, + // Block 0x90, offset 0x2400 + 0x2400: 0x0979, 0x2401: 0x3b85, 0x2402: 0x3b88, 0x2403: 0x3b8b, 0x2404: 0x057e, 0x2405: 0x055c, + 0x2406: 0x0572, 0x2407: 0x056c, 0x2408: 0x0575, 0x2409: 0x056f, 0x240a: 0x3b8f, 0x240b: 0x3b92, + 0x240e: 0x1486, 0x240f: 0x001c, 0x2410: 0x000d, 0x2411: 0x000f, + 0x2412: 0x1488, 0x2413: 0x148a, 0x2414: 0x148c, 0x2415: 0x148e, 0x2416: 0x1490, 0x2417: 0x1492, + 0x2418: 0x1486, 0x2419: 0x001c, 0x241a: 0x000d, 0x241b: 0x000f, 0x241c: 0x1488, 0x241d: 0x148a, + 0x241e: 0x148c, 0x241f: 0x148e, 0x2420: 0x1490, 0x2421: 0x1492, 0x2422: 0x1486, 0x2423: 0x001c, + 0x2424: 0x000d, 0x2425: 0x000f, 0x2426: 0x1488, 0x2427: 0x148a, 0x2428: 0x148c, 0x2429: 0x148e, + 0x242a: 0x1490, 0x242b: 0x1492, 0x242c: 0x1486, 0x242d: 0x001c, 0x242e: 0x000d, 0x242f: 0x000f, + 0x2430: 0x1488, 0x2431: 0x148a, 0x2432: 0x148c, 0x2433: 0x148e, 0x2434: 0x1490, 0x2435: 0x1492, + 0x2436: 0x1486, 0x2437: 0x001c, 0x2438: 0x000d, 0x2439: 0x000f, 0x243a: 0x1488, 0x243b: 0x148a, + 0x243c: 0x148c, 0x243d: 0x148e, 0x243e: 0x1490, 0x243f: 0x1492, + // Block 0x91, offset 0x2440 + 0x2440: 0x3b95, 0x2441: 0x3b98, 0x2442: 0x3b9b, 0x2443: 0x3b9e, 0x2444: 0x3ba1, 0x2445: 0x3ba4, + 0x2446: 0x3ba7, 0x2447: 0x3baa, 0x2448: 0x3bad, 0x2449: 0x3bb0, 0x244a: 0x3bb3, + 0x2450: 0x3bb6, 0x2451: 0x3bba, + 0x2452: 0x3bbe, 0x2453: 0x3bc2, 0x2454: 0x3bc6, 0x2455: 0x3bca, 0x2456: 0x3bce, 0x2457: 0x3bd2, + 0x2458: 0x3bd6, 0x2459: 0x3bda, 0x245a: 0x3bde, 0x245b: 0x3be2, 0x245c: 0x3be6, 0x245d: 0x3bea, + 0x245e: 0x3bee, 0x245f: 0x3bf2, 0x2460: 0x3bf6, 0x2461: 0x3bfa, 0x2462: 0x3bfe, 0x2463: 0x3c02, + 0x2464: 0x3c06, 0x2465: 0x3c0a, 0x2466: 0x3c0e, 0x2467: 0x3c12, 0x2468: 0x3c16, 0x2469: 0x3c1a, + 0x246a: 0x3c1e, 0x246b: 0x14ad, 0x246c: 0x092b, 0x246d: 0x3c26, 0x246e: 0x3c29, + 0x2470: 0x0906, 0x2471: 0x090b, 0x2472: 0x14ad, 0x2473: 0x090d, 0x2474: 0x090f, 0x2475: 0x14d9, + 0x2476: 0x0914, 0x2477: 0x0916, 0x2478: 0x0918, 0x2479: 0x091a, 0x247a: 0x091c, 0x247b: 0x091e, + 0x247c: 0x0920, 0x247d: 0x0922, 0x247e: 0x0924, 0x247f: 0x0929, + // Block 0x92, offset 0x2480 + 0x2480: 0x14c8, 0x2481: 0x092b, 0x2482: 0x17f6, 0x2483: 0x092d, 0x2484: 0x092f, 0x2485: 0x155f, + 0x2486: 0x0931, 0x2487: 0x1570, 0x2488: 0x17f8, 0x2489: 0x14d4, 0x248a: 0x3c2c, 0x248b: 0x293d, + 0x248c: 0x3c2f, 0x248d: 0x3c32, 0x248e: 0x3c35, 0x248f: 0x3c39, + // Block 0x93, offset 0x24c0 + 0x24d0: 0x3c3c, + // Block 0x94, offset 0x2500 + 0x2500: 0x3c3f, 0x2501: 0x3c46, 0x2502: 0x2291, + 0x2510: 0x1922, 0x2511: 0x3c4d, + 0x2512: 0x3c51, 0x2513: 0x1cb3, 0x2514: 0x183e, 0x2515: 0x3c55, 0x2516: 0x3c59, 0x2517: 0x1ed0, + 0x2518: 0x3c5d, 0x2519: 0x3c61, 0x251a: 0x3c65, 0x251b: 0x2d49, 0x251c: 0x3c69, 0x251d: 0x3c6d, + 0x251e: 0x3c71, 0x251f: 0x3c75, 0x2520: 0x3c79, 0x2521: 0x3c7d, 0x2522: 0x19b2, 0x2523: 0x3c81, + 0x2524: 0x3c85, 0x2525: 0x3c89, 0x2526: 0x3c8d, 0x2527: 0x3c91, 0x2528: 0x3c95, 0x2529: 0x1826, + 0x252a: 0x1eb0, 0x252b: 0x3c99, 0x252c: 0x21c7, 0x252d: 0x1ebc, 0x252e: 0x21cb, 0x252f: 0x3c9d, + 0x2530: 0x1a92, 0x2531: 0x3ca1, 0x2532: 0x3ca5, 0x2533: 0x3ca9, 0x2534: 0x3cad, 0x2535: 0x3cb1, + 0x2536: 0x2183, 0x2537: 0x194a, 0x2538: 0x3cb5, 0x2539: 0x3cb9, 0x253a: 0x3cbd, + // Block 0x95, offset 0x2540 + 0x2540: 0x3cc1, 0x2541: 0x3ccb, 0x2542: 0x3cd5, 0x2543: 0x3cdf, 0x2544: 0x3ce9, 0x2545: 0x3cf3, + 0x2546: 0x3cfd, 0x2547: 0x3d07, 0x2548: 0x3d11, + 0x2550: 0x3d1b, 0x2551: 0x3d1f, + // Block 0x96, offset 0x2580 + 0x2580: 0x3d23, 0x2581: 0x3d27, 0x2582: 0x3d2b, 0x2583: 0x3d2f, 0x2584: 0x3d34, 0x2585: 0x2eb5, + 0x2586: 0x3d38, 0x2587: 0x3d3c, 0x2588: 0x3d40, 0x2589: 0x3d44, 0x258a: 0x2eb9, 0x258b: 0x3d48, + 0x258c: 0x3d4c, 0x258d: 0x3d50, 0x258e: 0x2ebd, 0x258f: 0x3d55, 0x2590: 0x3d59, 0x2591: 0x3d5d, + 0x2592: 0x3d61, 0x2593: 0x3d66, 0x2594: 0x3d6a, 0x2595: 0x3c71, 0x2596: 0x3d6e, 0x2597: 0x3d73, + 0x2598: 0x3d77, 0x2599: 0x3d7b, 0x259a: 0x3d7f, 0x259b: 0x2f9a, 0x259c: 0x3d83, 0x259d: 0x1866, + 0x259e: 0x3d88, 0x259f: 0x3d8c, 0x25a0: 0x3d90, 0x25a1: 0x3d94, 0x25a2: 0x3cb9, 0x25a3: 0x3d98, + 0x25a4: 0x3d9c, 0x25a5: 0x2fae, 0x25a6: 0x2ec1, 0x25a7: 0x2ec5, 0x25a8: 0x2fb2, 0x25a9: 0x3da0, + 0x25aa: 0x3da4, 0x25ab: 0x2bf1, 0x25ac: 0x3da8, 0x25ad: 0x2ec9, 0x25ae: 0x3dac, 0x25af: 0x3db0, + 0x25b0: 0x3db4, 0x25b1: 0x3db8, 0x25b2: 0x3db8, 0x25b3: 0x3db8, 0x25b4: 0x3dbc, 0x25b5: 0x3dc1, + 0x25b6: 0x3dc5, 0x25b7: 0x3dc9, 0x25b8: 0x3dcd, 0x25b9: 0x3dd2, 0x25ba: 0x3dd6, 0x25bb: 0x3dda, + 0x25bc: 0x3dde, 0x25bd: 0x3de2, 0x25be: 0x3de6, 0x25bf: 0x3dea, + // Block 0x97, offset 0x25c0 + 0x25c0: 0x3dee, 0x25c1: 0x3df2, 0x25c2: 0x3df6, 0x25c3: 0x3dfa, 0x25c4: 0x3dfe, 0x25c5: 0x3e02, + 0x25c6: 0x3e02, 0x25c7: 0x2fba, 0x25c8: 0x3e06, 0x25c9: 0x3e0a, 0x25ca: 0x3e0e, 0x25cb: 0x3e12, + 0x25cc: 0x2ed1, 0x25cd: 0x3e16, 0x25ce: 0x3e1a, 0x25cf: 0x3e1e, 0x25d0: 0x2e39, 0x25d1: 0x3e22, + 0x25d2: 0x3e26, 0x25d3: 0x3e2a, 0x25d4: 0x3e2e, 0x25d5: 0x3e32, 0x25d6: 0x3e36, 0x25d7: 0x3e3a, + 0x25d8: 0x3e3e, 0x25d9: 0x3e42, 0x25da: 0x3e47, 0x25db: 0x3e4b, 0x25dc: 0x3e4f, 0x25dd: 0x3c55, + 0x25de: 0x3e53, 0x25df: 0x3e57, 0x25e0: 0x3e5b, 0x25e1: 0x3e60, 0x25e2: 0x3e65, 0x25e3: 0x3e69, + 0x25e4: 0x3e6d, 0x25e5: 0x3e71, 0x25e6: 0x3e75, 0x25e7: 0x3e79, 0x25e8: 0x3e7d, 0x25e9: 0x3e81, + 0x25ea: 0x3e85, 0x25eb: 0x3e85, 0x25ec: 0x3e89, 0x25ed: 0x3e8e, 0x25ee: 0x3e92, 0x25ef: 0x2be1, + 0x25f0: 0x3e96, 0x25f1: 0x3e9a, 0x25f2: 0x3e9f, 0x25f3: 0x3ea3, 0x25f4: 0x3ea7, 0x25f5: 0x18ce, + 0x25f6: 0x3eab, 0x25f7: 0x3eaf, 0x25f8: 0x18d6, 0x25f9: 0x3eb3, 0x25fa: 0x3eb7, 0x25fb: 0x3ebb, + 0x25fc: 0x3ec0, 0x25fd: 0x3ec4, 0x25fe: 0x3ec9, 0x25ff: 0x3ecd, + // Block 0x98, offset 0x2600 + 0x2600: 0x3ed1, 0x2601: 0x3ed5, 0x2602: 0x3ed9, 0x2603: 0x3edd, 0x2604: 0x3ee1, 0x2605: 0x3ee5, + 0x2606: 0x3ee9, 0x2607: 0x3eed, 0x2608: 0x3ef1, 0x2609: 0x3ef5, 0x260a: 0x3efa, 0x260b: 0x3efe, + 0x260c: 0x3f02, 0x260d: 0x3f06, 0x260e: 0x2b11, 0x260f: 0x3f0a, 0x2610: 0x18fe, 0x2611: 0x3f0f, + 0x2612: 0x3f0f, 0x2613: 0x3f14, 0x2614: 0x3f18, 0x2615: 0x3f18, 0x2616: 0x3f1c, 0x2617: 0x3f20, + 0x2618: 0x3f25, 0x2619: 0x3f2a, 0x261a: 0x3f2e, 0x261b: 0x3f32, 0x261c: 0x3f36, 0x261d: 0x3f3a, + 0x261e: 0x3f3e, 0x261f: 0x3f42, 0x2620: 0x3f46, 0x2621: 0x3f4a, 0x2622: 0x3f4e, 0x2623: 0x2ee5, + 0x2624: 0x3f52, 0x2625: 0x3f57, 0x2626: 0x3f5b, 0x2627: 0x3f5f, 0x2628: 0x2fea, 0x2629: 0x3f5f, + 0x262a: 0x3f63, 0x262b: 0x2eed, 0x262c: 0x3f67, 0x262d: 0x3f6b, 0x262e: 0x3f6f, 0x262f: 0x3f73, + 0x2630: 0x2ef1, 0x2631: 0x2aa5, 0x2632: 0x3f77, 0x2633: 0x3f7b, 0x2634: 0x3f7f, 0x2635: 0x3f83, + 0x2636: 0x3f87, 0x2637: 0x3f8b, 0x2638: 0x3f8f, 0x2639: 0x3f94, 0x263a: 0x3f98, 0x263b: 0x3f9c, + 0x263c: 0x3fa0, 0x263d: 0x3fa4, 0x263e: 0x3fa8, 0x263f: 0x3fad, + // Block 0x99, offset 0x2640 + 0x2640: 0x3fb1, 0x2641: 0x3fb5, 0x2642: 0x3fb9, 0x2643: 0x3fbd, 0x2644: 0x3fc1, 0x2645: 0x3fc5, + 0x2646: 0x3fc9, 0x2647: 0x3fcd, 0x2648: 0x2ef5, 0x2649: 0x3fd1, 0x264a: 0x3fd5, 0x264b: 0x3fda, + 0x264c: 0x3fde, 0x264d: 0x3fe2, 0x264e: 0x3fe6, 0x264f: 0x2efd, 0x2650: 0x3fea, 0x2651: 0x3fee, + 0x2652: 0x3ff2, 0x2653: 0x3ff6, 0x2654: 0x3ffa, 0x2655: 0x3ffe, 0x2656: 0x4002, 0x2657: 0x4006, + 0x2658: 0x2b15, 0x2659: 0x300a, 0x265a: 0x400a, 0x265b: 0x400e, 0x265c: 0x4012, 0x265d: 0x4016, + 0x265e: 0x401b, 0x265f: 0x401f, 0x2660: 0x4023, 0x2661: 0x4027, 0x2662: 0x2f01, 0x2663: 0x402b, + 0x2664: 0x4030, 0x2665: 0x4034, 0x2666: 0x4038, 0x2667: 0x30b5, 0x2668: 0x403c, 0x2669: 0x4040, + 0x266a: 0x4044, 0x266b: 0x4048, 0x266c: 0x404c, 0x266d: 0x4051, 0x266e: 0x4055, 0x266f: 0x4059, + 0x2670: 0x405d, 0x2671: 0x4062, 0x2672: 0x4066, 0x2673: 0x406a, 0x2674: 0x406e, 0x2675: 0x2c25, + 0x2676: 0x4072, 0x2677: 0x4076, 0x2678: 0x407b, 0x2679: 0x4080, 0x267a: 0x4085, 0x267b: 0x4089, + 0x267c: 0x408e, 0x267d: 0x4092, 0x267e: 0x4096, 0x267f: 0x409a, + // Block 0x9a, offset 0x2680 + 0x2680: 0x409e, 0x2681: 0x2f05, 0x2682: 0x2d71, 0x2683: 0x40a2, 0x2684: 0x40a6, 0x2685: 0x40aa, + 0x2686: 0x40ae, 0x2687: 0x40b3, 0x2688: 0x40b7, 0x2689: 0x40bb, 0x268a: 0x40bf, 0x268b: 0x3016, + 0x268c: 0x40c3, 0x268d: 0x40c7, 0x268e: 0x40cc, 0x268f: 0x40d0, 0x2690: 0x40d4, 0x2691: 0x40d9, + 0x2692: 0x40de, 0x2693: 0x40e2, 0x2694: 0x301a, 0x2695: 0x40e6, 0x2696: 0x40ea, 0x2697: 0x40ee, + 0x2698: 0x40f2, 0x2699: 0x40f6, 0x269a: 0x40fa, 0x269b: 0x40fe, 0x269c: 0x4103, 0x269d: 0x4107, + 0x269e: 0x410c, 0x269f: 0x4110, 0x26a0: 0x4115, 0x26a1: 0x3022, 0x26a2: 0x4119, 0x26a3: 0x411d, + 0x26a4: 0x4122, 0x26a5: 0x4126, 0x26a6: 0x412a, 0x26a7: 0x412f, 0x26a8: 0x4134, 0x26a9: 0x4138, + 0x26aa: 0x413c, 0x26ab: 0x4140, 0x26ac: 0x4144, 0x26ad: 0x4144, 0x26ae: 0x4148, 0x26af: 0x414c, + 0x26b0: 0x302a, 0x26b1: 0x4150, 0x26b2: 0x4154, 0x26b3: 0x4158, 0x26b4: 0x415c, 0x26b5: 0x4160, + 0x26b6: 0x4165, 0x26b7: 0x4169, 0x26b8: 0x2bed, 0x26b9: 0x416e, 0x26ba: 0x4173, 0x26bb: 0x4177, + 0x26bc: 0x417c, 0x26bd: 0x4181, 0x26be: 0x4186, 0x26bf: 0x418a, + // Block 0x9b, offset 0x26c0 + 0x26c0: 0x3042, 0x26c1: 0x418e, 0x26c2: 0x4193, 0x26c3: 0x4198, 0x26c4: 0x419d, 0x26c5: 0x41a2, + 0x26c6: 0x41a6, 0x26c7: 0x41a6, 0x26c8: 0x3046, 0x26c9: 0x30bd, 0x26ca: 0x41aa, 0x26cb: 0x41ae, + 0x26cc: 0x41b2, 0x26cd: 0x41b6, 0x26ce: 0x41bb, 0x26cf: 0x2b59, 0x26d0: 0x304e, 0x26d1: 0x41bf, + 0x26d2: 0x41c3, 0x26d3: 0x2f2d, 0x26d4: 0x41c8, 0x26d5: 0x41cd, 0x26d6: 0x2e89, 0x26d7: 0x41d2, + 0x26d8: 0x41d6, 0x26d9: 0x2f39, 0x26da: 0x41da, 0x26db: 0x41de, 0x26dc: 0x41e2, 0x26dd: 0x41e7, + 0x26de: 0x41e7, 0x26df: 0x41ec, 0x26e0: 0x41f0, 0x26e1: 0x41f4, 0x26e2: 0x41f9, 0x26e3: 0x41fd, + 0x26e4: 0x4201, 0x26e5: 0x4205, 0x26e6: 0x420a, 0x26e7: 0x420e, 0x26e8: 0x4212, 0x26e9: 0x4216, + 0x26ea: 0x421a, 0x26eb: 0x421e, 0x26ec: 0x4223, 0x26ed: 0x4227, 0x26ee: 0x422b, 0x26ef: 0x422f, + 0x26f0: 0x4233, 0x26f1: 0x4237, 0x26f2: 0x423b, 0x26f3: 0x4240, 0x26f4: 0x4245, 0x26f5: 0x4249, + 0x26f6: 0x424e, 0x26f7: 0x4252, 0x26f8: 0x4257, 0x26f9: 0x425b, 0x26fa: 0x2f51, 0x26fb: 0x425f, + 0x26fc: 0x4264, 0x26fd: 0x4269, 0x26fe: 0x426d, 0x26ff: 0x4272, + // Block 0x9c, offset 0x2700 + 0x2700: 0x4276, 0x2701: 0x427b, 0x2702: 0x427f, 0x2703: 0x4283, 0x2704: 0x4287, 0x2705: 0x428b, + 0x2706: 0x428f, 0x2707: 0x4293, 0x2708: 0x4298, 0x2709: 0x429d, 0x270a: 0x42a2, 0x270b: 0x3f14, + 0x270c: 0x42a7, 0x270d: 0x42ab, 0x270e: 0x42af, 0x270f: 0x42b3, 0x2710: 0x42b7, 0x2711: 0x42bb, + 0x2712: 0x42bf, 0x2713: 0x42c3, 0x2714: 0x42c7, 0x2715: 0x42cb, 0x2716: 0x42cf, 0x2717: 0x42d3, + 0x2718: 0x2c31, 0x2719: 0x42d8, 0x271a: 0x42dc, 0x271b: 0x42e0, 0x271c: 0x42e4, 0x271d: 0x42e8, + 0x271e: 0x42ec, 0x271f: 0x2f5d, 0x2720: 0x42f0, 0x2721: 0x42f4, 0x2722: 0x42f8, 0x2723: 0x42fc, + 0x2724: 0x4300, 0x2725: 0x4305, 0x2726: 0x430a, 0x2727: 0x430f, 0x2728: 0x4313, 0x2729: 0x4317, + 0x272a: 0x431b, 0x272b: 0x431f, 0x272c: 0x4324, 0x272d: 0x4328, 0x272e: 0x432d, 0x272f: 0x4331, + 0x2730: 0x4335, 0x2731: 0x433a, 0x2732: 0x433f, 0x2733: 0x4343, 0x2734: 0x2b45, 0x2735: 0x4347, + 0x2736: 0x434b, 0x2737: 0x434f, 0x2738: 0x4353, 0x2739: 0x4357, 0x273a: 0x435b, 0x273b: 0x306a, + 0x273c: 0x435f, 0x273d: 0x4363, 0x273e: 0x4367, 0x273f: 0x436b, + // Block 0x9d, offset 0x2740 + 0x2740: 0x436f, 0x2741: 0x4373, 0x2742: 0x4377, 0x2743: 0x437b, 0x2744: 0x1a66, 0x2745: 0x437f, + 0x2746: 0x4384, 0x2747: 0x4388, 0x2748: 0x438c, 0x2749: 0x4390, 0x274a: 0x4394, 0x274b: 0x4398, + 0x274c: 0x439d, 0x274d: 0x43a2, 0x274e: 0x43a6, 0x274f: 0x43aa, 0x2750: 0x307e, 0x2751: 0x3082, + 0x2752: 0x1a82, 0x2753: 0x43ae, 0x2754: 0x43b3, 0x2755: 0x43b7, 0x2756: 0x43bb, 0x2757: 0x43bf, + 0x2758: 0x43c3, 0x2759: 0x43c8, 0x275a: 0x43cd, 0x275b: 0x43d1, 0x275c: 0x43d5, 0x275d: 0x43d9, + 0x275e: 0x43de, 0x275f: 0x3086, 0x2760: 0x43e2, 0x2761: 0x43e7, 0x2762: 0x43ec, 0x2763: 0x43f0, + 0x2764: 0x43f4, 0x2765: 0x43f8, 0x2766: 0x43fd, 0x2767: 0x4401, 0x2768: 0x4405, 0x2769: 0x4409, + 0x276a: 0x440d, 0x276b: 0x4411, 0x276c: 0x4415, 0x276d: 0x4419, 0x276e: 0x441e, 0x276f: 0x4422, + 0x2770: 0x4426, 0x2771: 0x442a, 0x2772: 0x442f, 0x2773: 0x4433, 0x2774: 0x4437, 0x2775: 0x443b, + 0x2776: 0x443f, 0x2777: 0x4444, 0x2778: 0x4449, 0x2779: 0x444d, 0x277a: 0x4451, 0x277b: 0x4455, + 0x277c: 0x445a, 0x277d: 0x445e, 0x277e: 0x309e, 0x277f: 0x309e, + // Block 0x9e, offset 0x2780 + 0x2780: 0x4463, 0x2781: 0x4467, 0x2782: 0x446c, 0x2783: 0x4470, 0x2784: 0x4474, 0x2785: 0x4478, + 0x2786: 0x447c, 0x2787: 0x4480, 0x2788: 0x4484, 0x2789: 0x4488, 0x278a: 0x30a2, 0x278b: 0x448d, + 0x278c: 0x4491, 0x278d: 0x4495, 0x278e: 0x4499, 0x278f: 0x449d, 0x2790: 0x44a1, 0x2791: 0x44a6, + 0x2792: 0x44aa, 0x2793: 0x44af, 0x2794: 0x44b4, 0x2795: 0x1b42, 0x2796: 0x44b9, 0x2797: 0x1b52, + 0x2798: 0x44bd, 0x2799: 0x44c1, 0x279a: 0x44c5, 0x279b: 0x44c9, 0x279c: 0x1b66, 0x279d: 0x44cd, +} + +// nfkcDecompLookup: 960 bytes +// Block 0 is the null block. +var nfkcDecompLookup = [960]uint8{ + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0x0c2: 0x03, 0x0c3: 0x04, 0x0c4: 0x05, 0x0c5: 0x06, 0x0c6: 0x07, 0x0c7: 0x08, + 0x0c8: 0x09, 0x0ca: 0x0a, 0x0cb: 0x0b, 0x0cd: 0x0c, 0x0ce: 0x0d, 0x0cf: 0x0e, + 0x0d0: 0x0f, 0x0d1: 0x10, 0x0d3: 0x11, 0x0d6: 0x12, + 0x0d8: 0x13, 0x0d9: 0x14, 0x0db: 0x15, + 0x0e0: 0x04, 0x0e1: 0x05, 0x0e2: 0x06, 0x0e3: 0x07, + 0x0ea: 0x08, 0x0ef: 0x09, + 0x0f0: 0x0e, + // Block 0x4, offset 0x100 + 0x124: 0x16, 0x125: 0x17, 0x127: 0x18, + 0x128: 0x19, 0x129: 0x1a, 0x12d: 0x1b, 0x12e: 0x1c, 0x12f: 0x1d, + 0x131: 0x1e, 0x133: 0x1f, 0x135: 0x20, 0x137: 0x21, + 0x138: 0x22, 0x13a: 0x23, 0x13b: 0x24, 0x13c: 0x25, 0x13d: 0x26, 0x13e: 0x27, + // Block 0x5, offset 0x140 + 0x140: 0x28, 0x143: 0x29, + 0x16c: 0x2a, 0x16d: 0x2b, + 0x174: 0x2c, 0x175: 0x2d, 0x176: 0x2e, + 0x178: 0x2f, 0x179: 0x30, 0x17a: 0x31, 0x17b: 0x32, 0x17c: 0x33, 0x17d: 0x34, 0x17e: 0x35, 0x17f: 0x36, + // Block 0x6, offset 0x180 + 0x180: 0x37, 0x181: 0x38, 0x182: 0x39, 0x184: 0x3a, 0x185: 0x3b, 0x186: 0x3c, 0x187: 0x3d, + 0x188: 0x3e, 0x189: 0x3f, 0x18a: 0x40, 0x18b: 0x41, 0x18c: 0x42, + 0x191: 0x43, 0x192: 0x44, 0x193: 0x45, + 0x1a8: 0x46, 0x1a9: 0x47, 0x1ab: 0x48, + 0x1b1: 0x49, 0x1b5: 0x4a, + 0x1ba: 0x4b, 0x1bb: 0x4c, 0x1bc: 0x4d, 0x1bd: 0x4e, 0x1be: 0x4f, 0x1bf: 0x50, + // Block 0x7, offset 0x1c0 + 0x1c0: 0x51, 0x1c1: 0x52, 0x1c2: 0x53, 0x1c3: 0x54, 0x1c4: 0x55, 0x1c5: 0x56, 0x1c6: 0x57, + 0x1c8: 0x58, 0x1c9: 0x59, 0x1ca: 0x5a, 0x1cb: 0x5b, 0x1cc: 0x5c, 0x1cd: 0x5d, 0x1ce: 0x5e, 0x1cf: 0x5f, + // Block 0x8, offset 0x200 + 0x21d: 0x60, + // Block 0x9, offset 0x240 + 0x264: 0x61, 0x265: 0x62, 0x266: 0x63, 0x267: 0x64, + 0x268: 0x65, 0x269: 0x66, 0x26a: 0x67, 0x26b: 0x68, 0x26c: 0x69, 0x26d: 0x6a, 0x26e: 0x6b, 0x26f: 0x6c, + 0x270: 0x6d, 0x271: 0x6e, 0x272: 0x6f, 0x273: 0x70, 0x274: 0x71, 0x275: 0x72, 0x276: 0x73, 0x277: 0x74, + 0x278: 0x75, 0x279: 0x76, 0x27a: 0x77, 0x27b: 0x78, 0x27c: 0x79, 0x27d: 0x7a, 0x27e: 0x7b, 0x27f: 0x7c, + // Block 0xa, offset 0x280 + 0x282: 0x7d, + // Block 0xb, offset 0x2c0 + 0x2c5: 0x7e, 0x2c6: 0x7f, 0x2c7: 0x80, + 0x2d0: 0x81, 0x2d1: 0x82, 0x2d2: 0x83, 0x2d3: 0x84, 0x2d4: 0x85, 0x2d5: 0x86, 0x2d6: 0x87, 0x2d7: 0x88, + 0x2d8: 0x89, 0x2d9: 0x8a, 0x2da: 0x8b, 0x2db: 0x8c, 0x2dc: 0x8d, 0x2dd: 0x8e, 0x2de: 0x8f, 0x2df: 0x90, + // Block 0xc, offset 0x300 + 0x304: 0x91, 0x305: 0x92, 0x306: 0x93, + 0x308: 0x94, 0x309: 0x95, + // Block 0xd, offset 0x340 + 0x360: 0x96, 0x361: 0x97, 0x362: 0x98, 0x363: 0x99, 0x364: 0x9a, 0x365: 0x9b, 0x366: 0x9c, 0x367: 0x9d, + 0x368: 0x9e, + // Block 0xe, offset 0x380 + 0x391: 0x0a, + 0x39d: 0x0b, 0x39f: 0x0c, + 0x3af: 0x0d, +} + +var nfkcDecompTrie = trie{nfkcDecompLookup[:], nfkcDecompValues[:]} + +// recompMap: 7448 bytes (entries only) +var recompMap = map[uint32]uint32{ + 0x00410300: 0x00C0, + 0x00410301: 0x00C1, + 0x00410302: 0x00C2, + 0x00410303: 0x00C3, + 0x00410308: 0x00C4, + 0x0041030A: 0x00C5, + 0x00430327: 0x00C7, + 0x00450300: 0x00C8, + 0x00450301: 0x00C9, + 0x00450302: 0x00CA, + 0x00450308: 0x00CB, + 0x00490300: 0x00CC, + 0x00490301: 0x00CD, + 0x00490302: 0x00CE, + 0x00490308: 0x00CF, + 0x004E0303: 0x00D1, + 0x004F0300: 0x00D2, + 0x004F0301: 0x00D3, + 0x004F0302: 0x00D4, + 0x004F0303: 0x00D5, + 0x004F0308: 0x00D6, + 0x00550300: 0x00D9, + 0x00550301: 0x00DA, + 0x00550302: 0x00DB, + 0x00550308: 0x00DC, + 0x00590301: 0x00DD, + 0x00610300: 0x00E0, + 0x00610301: 0x00E1, + 0x00610302: 0x00E2, + 0x00610303: 0x00E3, + 0x00610308: 0x00E4, + 0x0061030A: 0x00E5, + 0x00630327: 0x00E7, + 0x00650300: 0x00E8, + 0x00650301: 0x00E9, + 0x00650302: 0x00EA, + 0x00650308: 0x00EB, + 0x00690300: 0x00EC, + 0x00690301: 0x00ED, + 0x00690302: 0x00EE, + 0x00690308: 0x00EF, + 0x006E0303: 0x00F1, + 0x006F0300: 0x00F2, + 0x006F0301: 0x00F3, + 0x006F0302: 0x00F4, + 0x006F0303: 0x00F5, + 0x006F0308: 0x00F6, + 0x00750300: 0x00F9, + 0x00750301: 0x00FA, + 0x00750302: 0x00FB, + 0x00750308: 0x00FC, + 0x00790301: 0x00FD, + 0x00790308: 0x00FF, + 0x00410304: 0x0100, + 0x00610304: 0x0101, + 0x00410306: 0x0102, + 0x00610306: 0x0103, + 0x00410328: 0x0104, + 0x00610328: 0x0105, + 0x00430301: 0x0106, + 0x00630301: 0x0107, + 0x00430302: 0x0108, + 0x00630302: 0x0109, + 0x00430307: 0x010A, + 0x00630307: 0x010B, + 0x0043030C: 0x010C, + 0x0063030C: 0x010D, + 0x0044030C: 0x010E, + 0x0064030C: 0x010F, + 0x00450304: 0x0112, + 0x00650304: 0x0113, + 0x00450306: 0x0114, + 0x00650306: 0x0115, + 0x00450307: 0x0116, + 0x00650307: 0x0117, + 0x00450328: 0x0118, + 0x00650328: 0x0119, + 0x0045030C: 0x011A, + 0x0065030C: 0x011B, + 0x00470302: 0x011C, + 0x00670302: 0x011D, + 0x00470306: 0x011E, + 0x00670306: 0x011F, + 0x00470307: 0x0120, + 0x00670307: 0x0121, + 0x00470327: 0x0122, + 0x00670327: 0x0123, + 0x00480302: 0x0124, + 0x00680302: 0x0125, + 0x00490303: 0x0128, + 0x00690303: 0x0129, + 0x00490304: 0x012A, + 0x00690304: 0x012B, + 0x00490306: 0x012C, + 0x00690306: 0x012D, + 0x00490328: 0x012E, + 0x00690328: 0x012F, + 0x00490307: 0x0130, + 0x004A0302: 0x0134, + 0x006A0302: 0x0135, + 0x004B0327: 0x0136, + 0x006B0327: 0x0137, + 0x004C0301: 0x0139, + 0x006C0301: 0x013A, + 0x004C0327: 0x013B, + 0x006C0327: 0x013C, + 0x004C030C: 0x013D, + 0x006C030C: 0x013E, + 0x004E0301: 0x0143, + 0x006E0301: 0x0144, + 0x004E0327: 0x0145, + 0x006E0327: 0x0146, + 0x004E030C: 0x0147, + 0x006E030C: 0x0148, + 0x004F0304: 0x014C, + 0x006F0304: 0x014D, + 0x004F0306: 0x014E, + 0x006F0306: 0x014F, + 0x004F030B: 0x0150, + 0x006F030B: 0x0151, + 0x00520301: 0x0154, + 0x00720301: 0x0155, + 0x00520327: 0x0156, + 0x00720327: 0x0157, + 0x0052030C: 0x0158, + 0x0072030C: 0x0159, + 0x00530301: 0x015A, + 0x00730301: 0x015B, + 0x00530302: 0x015C, + 0x00730302: 0x015D, + 0x00530327: 0x015E, + 0x00730327: 0x015F, + 0x0053030C: 0x0160, + 0x0073030C: 0x0161, + 0x00540327: 0x0162, + 0x00740327: 0x0163, + 0x0054030C: 0x0164, + 0x0074030C: 0x0165, + 0x00550303: 0x0168, + 0x00750303: 0x0169, + 0x00550304: 0x016A, + 0x00750304: 0x016B, + 0x00550306: 0x016C, + 0x00750306: 0x016D, + 0x0055030A: 0x016E, + 0x0075030A: 0x016F, + 0x0055030B: 0x0170, + 0x0075030B: 0x0171, + 0x00550328: 0x0172, + 0x00750328: 0x0173, + 0x00570302: 0x0174, + 0x00770302: 0x0175, + 0x00590302: 0x0176, + 0x00790302: 0x0177, + 0x00590308: 0x0178, + 0x005A0301: 0x0179, + 0x007A0301: 0x017A, + 0x005A0307: 0x017B, + 0x007A0307: 0x017C, + 0x005A030C: 0x017D, + 0x007A030C: 0x017E, + 0x004F031B: 0x01A0, + 0x006F031B: 0x01A1, + 0x0055031B: 0x01AF, + 0x0075031B: 0x01B0, + 0x0041030C: 0x01CD, + 0x0061030C: 0x01CE, + 0x0049030C: 0x01CF, + 0x0069030C: 0x01D0, + 0x004F030C: 0x01D1, + 0x006F030C: 0x01D2, + 0x0055030C: 0x01D3, + 0x0075030C: 0x01D4, + 0x00DC0304: 0x01D5, + 0x00FC0304: 0x01D6, + 0x00DC0301: 0x01D7, + 0x00FC0301: 0x01D8, + 0x00DC030C: 0x01D9, + 0x00FC030C: 0x01DA, + 0x00DC0300: 0x01DB, + 0x00FC0300: 0x01DC, + 0x00C40304: 0x01DE, + 0x00E40304: 0x01DF, + 0x02260304: 0x01E0, + 0x02270304: 0x01E1, + 0x00C60304: 0x01E2, + 0x00E60304: 0x01E3, + 0x0047030C: 0x01E6, + 0x0067030C: 0x01E7, + 0x004B030C: 0x01E8, + 0x006B030C: 0x01E9, + 0x004F0328: 0x01EA, + 0x006F0328: 0x01EB, + 0x01EA0304: 0x01EC, + 0x01EB0304: 0x01ED, + 0x01B7030C: 0x01EE, + 0x0292030C: 0x01EF, + 0x006A030C: 0x01F0, + 0x00470301: 0x01F4, + 0x00670301: 0x01F5, + 0x004E0300: 0x01F8, + 0x006E0300: 0x01F9, + 0x00C50301: 0x01FA, + 0x00E50301: 0x01FB, + 0x00C60301: 0x01FC, + 0x00E60301: 0x01FD, + 0x00D80301: 0x01FE, + 0x00F80301: 0x01FF, + 0x0041030F: 0x0200, + 0x0061030F: 0x0201, + 0x00410311: 0x0202, + 0x00610311: 0x0203, + 0x0045030F: 0x0204, + 0x0065030F: 0x0205, + 0x00450311: 0x0206, + 0x00650311: 0x0207, + 0x0049030F: 0x0208, + 0x0069030F: 0x0209, + 0x00490311: 0x020A, + 0x00690311: 0x020B, + 0x004F030F: 0x020C, + 0x006F030F: 0x020D, + 0x004F0311: 0x020E, + 0x006F0311: 0x020F, + 0x0052030F: 0x0210, + 0x0072030F: 0x0211, + 0x00520311: 0x0212, + 0x00720311: 0x0213, + 0x0055030F: 0x0214, + 0x0075030F: 0x0215, + 0x00550311: 0x0216, + 0x00750311: 0x0217, + 0x00530326: 0x0218, + 0x00730326: 0x0219, + 0x00540326: 0x021A, + 0x00740326: 0x021B, + 0x0048030C: 0x021E, + 0x0068030C: 0x021F, + 0x00410307: 0x0226, + 0x00610307: 0x0227, + 0x00450327: 0x0228, + 0x00650327: 0x0229, + 0x00D60304: 0x022A, + 0x00F60304: 0x022B, + 0x00D50304: 0x022C, + 0x00F50304: 0x022D, + 0x004F0307: 0x022E, + 0x006F0307: 0x022F, + 0x022E0304: 0x0230, + 0x022F0304: 0x0231, + 0x00590304: 0x0232, + 0x00790304: 0x0233, + 0x00A80301: 0x0385, + 0x03910301: 0x0386, + 0x03950301: 0x0388, + 0x03970301: 0x0389, + 0x03990301: 0x038A, + 0x039F0301: 0x038C, + 0x03A50301: 0x038E, + 0x03A90301: 0x038F, + 0x03CA0301: 0x0390, + 0x03990308: 0x03AA, + 0x03A50308: 0x03AB, + 0x03B10301: 0x03AC, + 0x03B50301: 0x03AD, + 0x03B70301: 0x03AE, + 0x03B90301: 0x03AF, + 0x03CB0301: 0x03B0, + 0x03B90308: 0x03CA, + 0x03C50308: 0x03CB, + 0x03BF0301: 0x03CC, + 0x03C50301: 0x03CD, + 0x03C90301: 0x03CE, + 0x03D20301: 0x03D3, + 0x03D20308: 0x03D4, + 0x04150300: 0x0400, + 0x04150308: 0x0401, + 0x04130301: 0x0403, + 0x04060308: 0x0407, + 0x041A0301: 0x040C, + 0x04180300: 0x040D, + 0x04230306: 0x040E, + 0x04180306: 0x0419, + 0x04380306: 0x0439, + 0x04350300: 0x0450, + 0x04350308: 0x0451, + 0x04330301: 0x0453, + 0x04560308: 0x0457, + 0x043A0301: 0x045C, + 0x04380300: 0x045D, + 0x04430306: 0x045E, + 0x0474030F: 0x0476, + 0x0475030F: 0x0477, + 0x04160306: 0x04C1, + 0x04360306: 0x04C2, + 0x04100306: 0x04D0, + 0x04300306: 0x04D1, + 0x04100308: 0x04D2, + 0x04300308: 0x04D3, + 0x04150306: 0x04D6, + 0x04350306: 0x04D7, + 0x04D80308: 0x04DA, + 0x04D90308: 0x04DB, + 0x04160308: 0x04DC, + 0x04360308: 0x04DD, + 0x04170308: 0x04DE, + 0x04370308: 0x04DF, + 0x04180304: 0x04E2, + 0x04380304: 0x04E3, + 0x04180308: 0x04E4, + 0x04380308: 0x04E5, + 0x041E0308: 0x04E6, + 0x043E0308: 0x04E7, + 0x04E80308: 0x04EA, + 0x04E90308: 0x04EB, + 0x042D0308: 0x04EC, + 0x044D0308: 0x04ED, + 0x04230304: 0x04EE, + 0x04430304: 0x04EF, + 0x04230308: 0x04F0, + 0x04430308: 0x04F1, + 0x0423030B: 0x04F2, + 0x0443030B: 0x04F3, + 0x04270308: 0x04F4, + 0x04470308: 0x04F5, + 0x042B0308: 0x04F8, + 0x044B0308: 0x04F9, + 0x06270653: 0x0622, + 0x06270654: 0x0623, + 0x06480654: 0x0624, + 0x06270655: 0x0625, + 0x064A0654: 0x0626, + 0x06D50654: 0x06C0, + 0x06C10654: 0x06C2, + 0x06D20654: 0x06D3, + 0x0928093C: 0x0929, + 0x0930093C: 0x0931, + 0x0933093C: 0x0934, + 0x09C709BE: 0x09CB, + 0x09C709D7: 0x09CC, + 0x0B470B56: 0x0B48, + 0x0B470B3E: 0x0B4B, + 0x0B470B57: 0x0B4C, + 0x0B920BD7: 0x0B94, + 0x0BC60BBE: 0x0BCA, + 0x0BC70BBE: 0x0BCB, + 0x0BC60BD7: 0x0BCC, + 0x0C460C56: 0x0C48, + 0x0CBF0CD5: 0x0CC0, + 0x0CC60CD5: 0x0CC7, + 0x0CC60CD6: 0x0CC8, + 0x0CC60CC2: 0x0CCA, + 0x0CCA0CD5: 0x0CCB, + 0x0D460D3E: 0x0D4A, + 0x0D470D3E: 0x0D4B, + 0x0D460D57: 0x0D4C, + 0x0DD90DCA: 0x0DDA, + 0x0DD90DCF: 0x0DDC, + 0x0DDC0DCA: 0x0DDD, + 0x0DD90DDF: 0x0DDE, + 0x1025102E: 0x1026, + 0x1B051B35: 0x1B06, + 0x1B071B35: 0x1B08, + 0x1B091B35: 0x1B0A, + 0x1B0B1B35: 0x1B0C, + 0x1B0D1B35: 0x1B0E, + 0x1B111B35: 0x1B12, + 0x1B3A1B35: 0x1B3B, + 0x1B3C1B35: 0x1B3D, + 0x1B3E1B35: 0x1B40, + 0x1B3F1B35: 0x1B41, + 0x1B421B35: 0x1B43, + 0x00410325: 0x1E00, + 0x00610325: 0x1E01, + 0x00420307: 0x1E02, + 0x00620307: 0x1E03, + 0x00420323: 0x1E04, + 0x00620323: 0x1E05, + 0x00420331: 0x1E06, + 0x00620331: 0x1E07, + 0x00C70301: 0x1E08, + 0x00E70301: 0x1E09, + 0x00440307: 0x1E0A, + 0x00640307: 0x1E0B, + 0x00440323: 0x1E0C, + 0x00640323: 0x1E0D, + 0x00440331: 0x1E0E, + 0x00640331: 0x1E0F, + 0x00440327: 0x1E10, + 0x00640327: 0x1E11, + 0x0044032D: 0x1E12, + 0x0064032D: 0x1E13, + 0x01120300: 0x1E14, + 0x01130300: 0x1E15, + 0x01120301: 0x1E16, + 0x01130301: 0x1E17, + 0x0045032D: 0x1E18, + 0x0065032D: 0x1E19, + 0x00450330: 0x1E1A, + 0x00650330: 0x1E1B, + 0x02280306: 0x1E1C, + 0x02290306: 0x1E1D, + 0x00460307: 0x1E1E, + 0x00660307: 0x1E1F, + 0x00470304: 0x1E20, + 0x00670304: 0x1E21, + 0x00480307: 0x1E22, + 0x00680307: 0x1E23, + 0x00480323: 0x1E24, + 0x00680323: 0x1E25, + 0x00480308: 0x1E26, + 0x00680308: 0x1E27, + 0x00480327: 0x1E28, + 0x00680327: 0x1E29, + 0x0048032E: 0x1E2A, + 0x0068032E: 0x1E2B, + 0x00490330: 0x1E2C, + 0x00690330: 0x1E2D, + 0x00CF0301: 0x1E2E, + 0x00EF0301: 0x1E2F, + 0x004B0301: 0x1E30, + 0x006B0301: 0x1E31, + 0x004B0323: 0x1E32, + 0x006B0323: 0x1E33, + 0x004B0331: 0x1E34, + 0x006B0331: 0x1E35, + 0x004C0323: 0x1E36, + 0x006C0323: 0x1E37, + 0x1E360304: 0x1E38, + 0x1E370304: 0x1E39, + 0x004C0331: 0x1E3A, + 0x006C0331: 0x1E3B, + 0x004C032D: 0x1E3C, + 0x006C032D: 0x1E3D, + 0x004D0301: 0x1E3E, + 0x006D0301: 0x1E3F, + 0x004D0307: 0x1E40, + 0x006D0307: 0x1E41, + 0x004D0323: 0x1E42, + 0x006D0323: 0x1E43, + 0x004E0307: 0x1E44, + 0x006E0307: 0x1E45, + 0x004E0323: 0x1E46, + 0x006E0323: 0x1E47, + 0x004E0331: 0x1E48, + 0x006E0331: 0x1E49, + 0x004E032D: 0x1E4A, + 0x006E032D: 0x1E4B, + 0x00D50301: 0x1E4C, + 0x00F50301: 0x1E4D, + 0x00D50308: 0x1E4E, + 0x00F50308: 0x1E4F, + 0x014C0300: 0x1E50, + 0x014D0300: 0x1E51, + 0x014C0301: 0x1E52, + 0x014D0301: 0x1E53, + 0x00500301: 0x1E54, + 0x00700301: 0x1E55, + 0x00500307: 0x1E56, + 0x00700307: 0x1E57, + 0x00520307: 0x1E58, + 0x00720307: 0x1E59, + 0x00520323: 0x1E5A, + 0x00720323: 0x1E5B, + 0x1E5A0304: 0x1E5C, + 0x1E5B0304: 0x1E5D, + 0x00520331: 0x1E5E, + 0x00720331: 0x1E5F, + 0x00530307: 0x1E60, + 0x00730307: 0x1E61, + 0x00530323: 0x1E62, + 0x00730323: 0x1E63, + 0x015A0307: 0x1E64, + 0x015B0307: 0x1E65, + 0x01600307: 0x1E66, + 0x01610307: 0x1E67, + 0x1E620307: 0x1E68, + 0x1E630307: 0x1E69, + 0x00540307: 0x1E6A, + 0x00740307: 0x1E6B, + 0x00540323: 0x1E6C, + 0x00740323: 0x1E6D, + 0x00540331: 0x1E6E, + 0x00740331: 0x1E6F, + 0x0054032D: 0x1E70, + 0x0074032D: 0x1E71, + 0x00550324: 0x1E72, + 0x00750324: 0x1E73, + 0x00550330: 0x1E74, + 0x00750330: 0x1E75, + 0x0055032D: 0x1E76, + 0x0075032D: 0x1E77, + 0x01680301: 0x1E78, + 0x01690301: 0x1E79, + 0x016A0308: 0x1E7A, + 0x016B0308: 0x1E7B, + 0x00560303: 0x1E7C, + 0x00760303: 0x1E7D, + 0x00560323: 0x1E7E, + 0x00760323: 0x1E7F, + 0x00570300: 0x1E80, + 0x00770300: 0x1E81, + 0x00570301: 0x1E82, + 0x00770301: 0x1E83, + 0x00570308: 0x1E84, + 0x00770308: 0x1E85, + 0x00570307: 0x1E86, + 0x00770307: 0x1E87, + 0x00570323: 0x1E88, + 0x00770323: 0x1E89, + 0x00580307: 0x1E8A, + 0x00780307: 0x1E8B, + 0x00580308: 0x1E8C, + 0x00780308: 0x1E8D, + 0x00590307: 0x1E8E, + 0x00790307: 0x1E8F, + 0x005A0302: 0x1E90, + 0x007A0302: 0x1E91, + 0x005A0323: 0x1E92, + 0x007A0323: 0x1E93, + 0x005A0331: 0x1E94, + 0x007A0331: 0x1E95, + 0x00680331: 0x1E96, + 0x00740308: 0x1E97, + 0x0077030A: 0x1E98, + 0x0079030A: 0x1E99, + 0x017F0307: 0x1E9B, + 0x00410323: 0x1EA0, + 0x00610323: 0x1EA1, + 0x00410309: 0x1EA2, + 0x00610309: 0x1EA3, + 0x00C20301: 0x1EA4, + 0x00E20301: 0x1EA5, + 0x00C20300: 0x1EA6, + 0x00E20300: 0x1EA7, + 0x00C20309: 0x1EA8, + 0x00E20309: 0x1EA9, + 0x00C20303: 0x1EAA, + 0x00E20303: 0x1EAB, + 0x1EA00302: 0x1EAC, + 0x1EA10302: 0x1EAD, + 0x01020301: 0x1EAE, + 0x01030301: 0x1EAF, + 0x01020300: 0x1EB0, + 0x01030300: 0x1EB1, + 0x01020309: 0x1EB2, + 0x01030309: 0x1EB3, + 0x01020303: 0x1EB4, + 0x01030303: 0x1EB5, + 0x1EA00306: 0x1EB6, + 0x1EA10306: 0x1EB7, + 0x00450323: 0x1EB8, + 0x00650323: 0x1EB9, + 0x00450309: 0x1EBA, + 0x00650309: 0x1EBB, + 0x00450303: 0x1EBC, + 0x00650303: 0x1EBD, + 0x00CA0301: 0x1EBE, + 0x00EA0301: 0x1EBF, + 0x00CA0300: 0x1EC0, + 0x00EA0300: 0x1EC1, + 0x00CA0309: 0x1EC2, + 0x00EA0309: 0x1EC3, + 0x00CA0303: 0x1EC4, + 0x00EA0303: 0x1EC5, + 0x1EB80302: 0x1EC6, + 0x1EB90302: 0x1EC7, + 0x00490309: 0x1EC8, + 0x00690309: 0x1EC9, + 0x00490323: 0x1ECA, + 0x00690323: 0x1ECB, + 0x004F0323: 0x1ECC, + 0x006F0323: 0x1ECD, + 0x004F0309: 0x1ECE, + 0x006F0309: 0x1ECF, + 0x00D40301: 0x1ED0, + 0x00F40301: 0x1ED1, + 0x00D40300: 0x1ED2, + 0x00F40300: 0x1ED3, + 0x00D40309: 0x1ED4, + 0x00F40309: 0x1ED5, + 0x00D40303: 0x1ED6, + 0x00F40303: 0x1ED7, + 0x1ECC0302: 0x1ED8, + 0x1ECD0302: 0x1ED9, + 0x01A00301: 0x1EDA, + 0x01A10301: 0x1EDB, + 0x01A00300: 0x1EDC, + 0x01A10300: 0x1EDD, + 0x01A00309: 0x1EDE, + 0x01A10309: 0x1EDF, + 0x01A00303: 0x1EE0, + 0x01A10303: 0x1EE1, + 0x01A00323: 0x1EE2, + 0x01A10323: 0x1EE3, + 0x00550323: 0x1EE4, + 0x00750323: 0x1EE5, + 0x00550309: 0x1EE6, + 0x00750309: 0x1EE7, + 0x01AF0301: 0x1EE8, + 0x01B00301: 0x1EE9, + 0x01AF0300: 0x1EEA, + 0x01B00300: 0x1EEB, + 0x01AF0309: 0x1EEC, + 0x01B00309: 0x1EED, + 0x01AF0303: 0x1EEE, + 0x01B00303: 0x1EEF, + 0x01AF0323: 0x1EF0, + 0x01B00323: 0x1EF1, + 0x00590300: 0x1EF2, + 0x00790300: 0x1EF3, + 0x00590323: 0x1EF4, + 0x00790323: 0x1EF5, + 0x00590309: 0x1EF6, + 0x00790309: 0x1EF7, + 0x00590303: 0x1EF8, + 0x00790303: 0x1EF9, + 0x03B10313: 0x1F00, + 0x03B10314: 0x1F01, + 0x1F000300: 0x1F02, + 0x1F010300: 0x1F03, + 0x1F000301: 0x1F04, + 0x1F010301: 0x1F05, + 0x1F000342: 0x1F06, + 0x1F010342: 0x1F07, + 0x03910313: 0x1F08, + 0x03910314: 0x1F09, + 0x1F080300: 0x1F0A, + 0x1F090300: 0x1F0B, + 0x1F080301: 0x1F0C, + 0x1F090301: 0x1F0D, + 0x1F080342: 0x1F0E, + 0x1F090342: 0x1F0F, + 0x03B50313: 0x1F10, + 0x03B50314: 0x1F11, + 0x1F100300: 0x1F12, + 0x1F110300: 0x1F13, + 0x1F100301: 0x1F14, + 0x1F110301: 0x1F15, + 0x03950313: 0x1F18, + 0x03950314: 0x1F19, + 0x1F180300: 0x1F1A, + 0x1F190300: 0x1F1B, + 0x1F180301: 0x1F1C, + 0x1F190301: 0x1F1D, + 0x03B70313: 0x1F20, + 0x03B70314: 0x1F21, + 0x1F200300: 0x1F22, + 0x1F210300: 0x1F23, + 0x1F200301: 0x1F24, + 0x1F210301: 0x1F25, + 0x1F200342: 0x1F26, + 0x1F210342: 0x1F27, + 0x03970313: 0x1F28, + 0x03970314: 0x1F29, + 0x1F280300: 0x1F2A, + 0x1F290300: 0x1F2B, + 0x1F280301: 0x1F2C, + 0x1F290301: 0x1F2D, + 0x1F280342: 0x1F2E, + 0x1F290342: 0x1F2F, + 0x03B90313: 0x1F30, + 0x03B90314: 0x1F31, + 0x1F300300: 0x1F32, + 0x1F310300: 0x1F33, + 0x1F300301: 0x1F34, + 0x1F310301: 0x1F35, + 0x1F300342: 0x1F36, + 0x1F310342: 0x1F37, + 0x03990313: 0x1F38, + 0x03990314: 0x1F39, + 0x1F380300: 0x1F3A, + 0x1F390300: 0x1F3B, + 0x1F380301: 0x1F3C, + 0x1F390301: 0x1F3D, + 0x1F380342: 0x1F3E, + 0x1F390342: 0x1F3F, + 0x03BF0313: 0x1F40, + 0x03BF0314: 0x1F41, + 0x1F400300: 0x1F42, + 0x1F410300: 0x1F43, + 0x1F400301: 0x1F44, + 0x1F410301: 0x1F45, + 0x039F0313: 0x1F48, + 0x039F0314: 0x1F49, + 0x1F480300: 0x1F4A, + 0x1F490300: 0x1F4B, + 0x1F480301: 0x1F4C, + 0x1F490301: 0x1F4D, + 0x03C50313: 0x1F50, + 0x03C50314: 0x1F51, + 0x1F500300: 0x1F52, + 0x1F510300: 0x1F53, + 0x1F500301: 0x1F54, + 0x1F510301: 0x1F55, + 0x1F500342: 0x1F56, + 0x1F510342: 0x1F57, + 0x03A50314: 0x1F59, + 0x1F590300: 0x1F5B, + 0x1F590301: 0x1F5D, + 0x1F590342: 0x1F5F, + 0x03C90313: 0x1F60, + 0x03C90314: 0x1F61, + 0x1F600300: 0x1F62, + 0x1F610300: 0x1F63, + 0x1F600301: 0x1F64, + 0x1F610301: 0x1F65, + 0x1F600342: 0x1F66, + 0x1F610342: 0x1F67, + 0x03A90313: 0x1F68, + 0x03A90314: 0x1F69, + 0x1F680300: 0x1F6A, + 0x1F690300: 0x1F6B, + 0x1F680301: 0x1F6C, + 0x1F690301: 0x1F6D, + 0x1F680342: 0x1F6E, + 0x1F690342: 0x1F6F, + 0x03B10300: 0x1F70, + 0x03B50300: 0x1F72, + 0x03B70300: 0x1F74, + 0x03B90300: 0x1F76, + 0x03BF0300: 0x1F78, + 0x03C50300: 0x1F7A, + 0x03C90300: 0x1F7C, + 0x1F000345: 0x1F80, + 0x1F010345: 0x1F81, + 0x1F020345: 0x1F82, + 0x1F030345: 0x1F83, + 0x1F040345: 0x1F84, + 0x1F050345: 0x1F85, + 0x1F060345: 0x1F86, + 0x1F070345: 0x1F87, + 0x1F080345: 0x1F88, + 0x1F090345: 0x1F89, + 0x1F0A0345: 0x1F8A, + 0x1F0B0345: 0x1F8B, + 0x1F0C0345: 0x1F8C, + 0x1F0D0345: 0x1F8D, + 0x1F0E0345: 0x1F8E, + 0x1F0F0345: 0x1F8F, + 0x1F200345: 0x1F90, + 0x1F210345: 0x1F91, + 0x1F220345: 0x1F92, + 0x1F230345: 0x1F93, + 0x1F240345: 0x1F94, + 0x1F250345: 0x1F95, + 0x1F260345: 0x1F96, + 0x1F270345: 0x1F97, + 0x1F280345: 0x1F98, + 0x1F290345: 0x1F99, + 0x1F2A0345: 0x1F9A, + 0x1F2B0345: 0x1F9B, + 0x1F2C0345: 0x1F9C, + 0x1F2D0345: 0x1F9D, + 0x1F2E0345: 0x1F9E, + 0x1F2F0345: 0x1F9F, + 0x1F600345: 0x1FA0, + 0x1F610345: 0x1FA1, + 0x1F620345: 0x1FA2, + 0x1F630345: 0x1FA3, + 0x1F640345: 0x1FA4, + 0x1F650345: 0x1FA5, + 0x1F660345: 0x1FA6, + 0x1F670345: 0x1FA7, + 0x1F680345: 0x1FA8, + 0x1F690345: 0x1FA9, + 0x1F6A0345: 0x1FAA, + 0x1F6B0345: 0x1FAB, + 0x1F6C0345: 0x1FAC, + 0x1F6D0345: 0x1FAD, + 0x1F6E0345: 0x1FAE, + 0x1F6F0345: 0x1FAF, + 0x03B10306: 0x1FB0, + 0x03B10304: 0x1FB1, + 0x1F700345: 0x1FB2, + 0x03B10345: 0x1FB3, + 0x03AC0345: 0x1FB4, + 0x03B10342: 0x1FB6, + 0x1FB60345: 0x1FB7, + 0x03910306: 0x1FB8, + 0x03910304: 0x1FB9, + 0x03910300: 0x1FBA, + 0x03910345: 0x1FBC, + 0x00A80342: 0x1FC1, + 0x1F740345: 0x1FC2, + 0x03B70345: 0x1FC3, + 0x03AE0345: 0x1FC4, + 0x03B70342: 0x1FC6, + 0x1FC60345: 0x1FC7, + 0x03950300: 0x1FC8, + 0x03970300: 0x1FCA, + 0x03970345: 0x1FCC, + 0x1FBF0300: 0x1FCD, + 0x1FBF0301: 0x1FCE, + 0x1FBF0342: 0x1FCF, + 0x03B90306: 0x1FD0, + 0x03B90304: 0x1FD1, + 0x03CA0300: 0x1FD2, + 0x03B90342: 0x1FD6, + 0x03CA0342: 0x1FD7, + 0x03990306: 0x1FD8, + 0x03990304: 0x1FD9, + 0x03990300: 0x1FDA, + 0x1FFE0300: 0x1FDD, + 0x1FFE0301: 0x1FDE, + 0x1FFE0342: 0x1FDF, + 0x03C50306: 0x1FE0, + 0x03C50304: 0x1FE1, + 0x03CB0300: 0x1FE2, + 0x03C10313: 0x1FE4, + 0x03C10314: 0x1FE5, + 0x03C50342: 0x1FE6, + 0x03CB0342: 0x1FE7, + 0x03A50306: 0x1FE8, + 0x03A50304: 0x1FE9, + 0x03A50300: 0x1FEA, + 0x03A10314: 0x1FEC, + 0x00A80300: 0x1FED, + 0x1F7C0345: 0x1FF2, + 0x03C90345: 0x1FF3, + 0x03CE0345: 0x1FF4, + 0x03C90342: 0x1FF6, + 0x1FF60345: 0x1FF7, + 0x039F0300: 0x1FF8, + 0x03A90300: 0x1FFA, + 0x03A90345: 0x1FFC, + 0x21900338: 0x219A, + 0x21920338: 0x219B, + 0x21940338: 0x21AE, + 0x21D00338: 0x21CD, + 0x21D40338: 0x21CE, + 0x21D20338: 0x21CF, + 0x22030338: 0x2204, + 0x22080338: 0x2209, + 0x220B0338: 0x220C, + 0x22230338: 0x2224, + 0x22250338: 0x2226, + 0x223C0338: 0x2241, + 0x22430338: 0x2244, + 0x22450338: 0x2247, + 0x22480338: 0x2249, + 0x003D0338: 0x2260, + 0x22610338: 0x2262, + 0x224D0338: 0x226D, + 0x003C0338: 0x226E, + 0x003E0338: 0x226F, + 0x22640338: 0x2270, + 0x22650338: 0x2271, + 0x22720338: 0x2274, + 0x22730338: 0x2275, + 0x22760338: 0x2278, + 0x22770338: 0x2279, + 0x227A0338: 0x2280, + 0x227B0338: 0x2281, + 0x22820338: 0x2284, + 0x22830338: 0x2285, + 0x22860338: 0x2288, + 0x22870338: 0x2289, + 0x22A20338: 0x22AC, + 0x22A80338: 0x22AD, + 0x22A90338: 0x22AE, + 0x22AB0338: 0x22AF, + 0x227C0338: 0x22E0, + 0x227D0338: 0x22E1, + 0x22910338: 0x22E2, + 0x22920338: 0x22E3, + 0x22B20338: 0x22EA, + 0x22B30338: 0x22EB, + 0x22B40338: 0x22EC, + 0x22B50338: 0x22ED, + 0x304B3099: 0x304C, + 0x304D3099: 0x304E, + 0x304F3099: 0x3050, + 0x30513099: 0x3052, + 0x30533099: 0x3054, + 0x30553099: 0x3056, + 0x30573099: 0x3058, + 0x30593099: 0x305A, + 0x305B3099: 0x305C, + 0x305D3099: 0x305E, + 0x305F3099: 0x3060, + 0x30613099: 0x3062, + 0x30643099: 0x3065, + 0x30663099: 0x3067, + 0x30683099: 0x3069, + 0x306F3099: 0x3070, + 0x306F309A: 0x3071, + 0x30723099: 0x3073, + 0x3072309A: 0x3074, + 0x30753099: 0x3076, + 0x3075309A: 0x3077, + 0x30783099: 0x3079, + 0x3078309A: 0x307A, + 0x307B3099: 0x307C, + 0x307B309A: 0x307D, + 0x30463099: 0x3094, + 0x309D3099: 0x309E, + 0x30AB3099: 0x30AC, + 0x30AD3099: 0x30AE, + 0x30AF3099: 0x30B0, + 0x30B13099: 0x30B2, + 0x30B33099: 0x30B4, + 0x30B53099: 0x30B6, + 0x30B73099: 0x30B8, + 0x30B93099: 0x30BA, + 0x30BB3099: 0x30BC, + 0x30BD3099: 0x30BE, + 0x30BF3099: 0x30C0, + 0x30C13099: 0x30C2, + 0x30C43099: 0x30C5, + 0x30C63099: 0x30C7, + 0x30C83099: 0x30C9, + 0x30CF3099: 0x30D0, + 0x30CF309A: 0x30D1, + 0x30D23099: 0x30D3, + 0x30D2309A: 0x30D4, + 0x30D53099: 0x30D6, + 0x30D5309A: 0x30D7, + 0x30D83099: 0x30D9, + 0x30D8309A: 0x30DA, + 0x30DB3099: 0x30DC, + 0x30DB309A: 0x30DD, + 0x30A63099: 0x30F4, + 0x30EF3099: 0x30F7, + 0x30F03099: 0x30F8, + 0x30F13099: 0x30F9, + 0x30F23099: 0x30FA, + 0x30FD3099: 0x30FE, + 0x109910BA: 0x1109A, + 0x109B10BA: 0x1109C, + 0x10A510BA: 0x110AB, +} + +// charInfoValues: 10944 entries, 21888 bytes +// Block 2 is the null block. +var charInfoValues = [10944]uint16{ + // Block 0x0, offset 0x0 + 0x003c: 0x8800, 0x003d: 0x8800, 0x003e: 0x8800, + // Block 0x1, offset 0x40 + 0x0041: 0x8800, 0x0042: 0x8800, 0x0043: 0x8800, 0x0044: 0x8800, 0x0045: 0x8800, + 0x0046: 0x8800, 0x0047: 0x8800, 0x0048: 0x8800, 0x0049: 0x8800, 0x004a: 0x8800, 0x004b: 0x8800, + 0x004c: 0x8800, 0x004d: 0x8800, 0x004e: 0x8800, 0x004f: 0x8800, 0x0050: 0x8800, + 0x0052: 0x8800, 0x0053: 0x8800, 0x0054: 0x8800, 0x0055: 0x8800, 0x0056: 0x8800, 0x0057: 0x8800, + 0x0058: 0x8800, 0x0059: 0x8800, 0x005a: 0x8800, + 0x0061: 0x8800, 0x0062: 0x8800, 0x0063: 0x8800, + 0x0064: 0x8800, 0x0065: 0x8800, 0x0066: 0x8800, 0x0067: 0x8800, 0x0068: 0x8800, 0x0069: 0x8800, + 0x006a: 0x8800, 0x006b: 0x8800, 0x006c: 0x8800, 0x006d: 0x8800, 0x006e: 0x8800, 0x006f: 0x8800, + 0x0070: 0x8800, 0x0072: 0x8800, 0x0073: 0x8800, 0x0074: 0x8800, 0x0075: 0x8800, + 0x0076: 0x8800, 0x0077: 0x8800, 0x0078: 0x8800, 0x0079: 0x8800, 0x007a: 0x8800, + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0x00e0: 0x3000, + 0x00e8: 0x3800, + 0x00ea: 0x3000, 0x00ef: 0x3000, + 0x00f2: 0x3000, 0x00f3: 0x3000, 0x00f4: 0x3000, 0x00f5: 0x3000, + 0x00f8: 0x3000, 0x00f9: 0x3000, 0x00fa: 0x3000, + 0x00fc: 0x3000, 0x00fd: 0x3000, 0x00fe: 0x3000, + // Block 0x4, offset 0x100 + 0x0100: 0x1100, 0x0101: 0x1100, 0x0102: 0x9900, 0x0103: 0x1100, 0x0104: 0x9900, 0x0105: 0x9900, + 0x0106: 0x8800, 0x0107: 0x9900, 0x0108: 0x1100, 0x0109: 0x1100, 0x010a: 0x9900, 0x010b: 0x1100, + 0x010c: 0x1100, 0x010d: 0x1100, 0x010e: 0x1100, 0x010f: 0x9900, 0x0111: 0x1100, + 0x0112: 0x1100, 0x0113: 0x1100, 0x0114: 0x9900, 0x0115: 0x9900, 0x0116: 0x9900, + 0x0118: 0x8800, 0x0119: 0x1100, 0x011a: 0x1100, 0x011b: 0x1100, 0x011c: 0x9900, 0x011d: 0x1100, + 0x0120: 0x1100, 0x0121: 0x1100, 0x0122: 0x9900, 0x0123: 0x1100, + 0x0124: 0x9900, 0x0125: 0x9900, 0x0126: 0x8800, 0x0127: 0x9900, 0x0128: 0x1100, 0x0129: 0x1100, + 0x012a: 0x9900, 0x012b: 0x1100, 0x012c: 0x1100, 0x012d: 0x1100, 0x012e: 0x1100, 0x012f: 0x9900, + 0x0131: 0x1100, 0x0132: 0x1100, 0x0133: 0x1100, 0x0134: 0x9900, 0x0135: 0x9900, + 0x0136: 0x9900, 0x0138: 0x8800, 0x0139: 0x1100, 0x013a: 0x1100, 0x013b: 0x1100, + 0x013c: 0x9900, 0x013d: 0x1100, 0x013f: 0x1100, + // Block 0x5, offset 0x140 + 0x0140: 0x1100, 0x0141: 0x1100, 0x0142: 0x9900, 0x0143: 0x9900, 0x0144: 0x1100, 0x0145: 0x1100, + 0x0146: 0x1100, 0x0147: 0x1100, 0x0148: 0x1100, 0x0149: 0x1100, 0x014a: 0x1100, 0x014b: 0x1100, + 0x014c: 0x1100, 0x014d: 0x1100, 0x014e: 0x1100, 0x014f: 0x1100, + 0x0152: 0x9900, 0x0153: 0x9900, 0x0154: 0x1100, 0x0155: 0x1100, 0x0156: 0x1100, 0x0157: 0x1100, + 0x0158: 0x1100, 0x0159: 0x1100, 0x015a: 0x1100, 0x015b: 0x1100, 0x015c: 0x1100, 0x015d: 0x1100, + 0x015e: 0x1100, 0x015f: 0x1100, 0x0160: 0x1100, 0x0161: 0x1100, 0x0162: 0x1100, 0x0163: 0x1100, + 0x0164: 0x1100, 0x0165: 0x1100, 0x0168: 0x1100, 0x0169: 0x1100, + 0x016a: 0x1100, 0x016b: 0x1100, 0x016c: 0x1100, 0x016d: 0x1100, 0x016e: 0x1100, 0x016f: 0x1100, + 0x0170: 0x1100, 0x0172: 0x3000, 0x0173: 0x3000, 0x0174: 0x1100, 0x0175: 0x1100, + 0x0176: 0x1100, 0x0177: 0x1100, 0x0179: 0x1100, 0x017a: 0x1100, 0x017b: 0x1100, + 0x017c: 0x1100, 0x017d: 0x1100, 0x017e: 0x1100, 0x017f: 0x3000, + // Block 0x6, offset 0x180 + 0x0180: 0x3000, 0x0183: 0x1100, 0x0184: 0x1100, 0x0185: 0x1100, + 0x0186: 0x1100, 0x0187: 0x1100, 0x0188: 0x1100, 0x0189: 0x3000, + 0x018c: 0x9900, 0x018d: 0x9900, 0x018e: 0x1100, 0x018f: 0x1100, 0x0190: 0x1100, 0x0191: 0x1100, + 0x0194: 0x1100, 0x0195: 0x1100, 0x0196: 0x1100, 0x0197: 0x1100, + 0x0198: 0x1100, 0x0199: 0x1100, 0x019a: 0x9900, 0x019b: 0x9900, 0x019c: 0x1100, 0x019d: 0x1100, + 0x019e: 0x1100, 0x019f: 0x1100, 0x01a0: 0x9900, 0x01a1: 0x9900, 0x01a2: 0x1100, 0x01a3: 0x1100, + 0x01a4: 0x1100, 0x01a5: 0x1100, 0x01a8: 0x9900, 0x01a9: 0x9900, + 0x01aa: 0x9900, 0x01ab: 0x9900, 0x01ac: 0x1100, 0x01ad: 0x1100, 0x01ae: 0x1100, 0x01af: 0x1100, + 0x01b0: 0x1100, 0x01b1: 0x1100, 0x01b2: 0x1100, 0x01b3: 0x1100, 0x01b4: 0x1100, 0x01b5: 0x1100, + 0x01b6: 0x1100, 0x01b7: 0x1100, 0x01b8: 0x1100, 0x01b9: 0x1100, 0x01ba: 0x1100, 0x01bb: 0x1100, + 0x01bc: 0x1100, 0x01bd: 0x1100, 0x01be: 0x1100, 0x01bf: 0x3800, + // Block 0x7, offset 0x1c0 + 0x01e0: 0x9900, 0x01e1: 0x9900, + 0x01ef: 0x9900, + 0x01f0: 0x9900, + 0x01f7: 0x8800, + // Block 0x8, offset 0x200 + 0x0204: 0x3000, 0x0205: 0x3000, + 0x0206: 0x3000, 0x0207: 0x3000, 0x0208: 0x3000, 0x0209: 0x3000, 0x020a: 0x3000, 0x020b: 0x3000, + 0x020c: 0x3000, 0x020d: 0x1100, 0x020e: 0x1100, 0x020f: 0x1100, 0x0210: 0x1100, 0x0211: 0x1100, + 0x0212: 0x1100, 0x0213: 0x1100, 0x0214: 0x1100, 0x0215: 0x1100, 0x0216: 0x1100, 0x0217: 0x1100, + 0x0218: 0x1100, 0x0219: 0x1100, 0x021a: 0x1100, 0x021b: 0x1100, 0x021c: 0x1100, + 0x021e: 0x1100, 0x021f: 0x1100, 0x0220: 0x1100, 0x0221: 0x1100, 0x0222: 0x1100, 0x0223: 0x1100, + 0x0226: 0x1100, 0x0227: 0x1100, 0x0228: 0x1100, 0x0229: 0x1100, + 0x022a: 0x9900, 0x022b: 0x9900, 0x022c: 0x1100, 0x022d: 0x1100, 0x022e: 0x1100, 0x022f: 0x1100, + 0x0230: 0x1100, 0x0231: 0x3000, 0x0232: 0x3000, 0x0233: 0x3000, 0x0234: 0x1100, 0x0235: 0x1100, + 0x0238: 0x1100, 0x0239: 0x1100, 0x023a: 0x1100, 0x023b: 0x1100, + 0x023c: 0x1100, 0x023d: 0x1100, 0x023e: 0x1100, 0x023f: 0x1100, + // Block 0x9, offset 0x240 + 0x0240: 0x1100, 0x0241: 0x1100, 0x0242: 0x1100, 0x0243: 0x1100, 0x0244: 0x1100, 0x0245: 0x1100, + 0x0246: 0x1100, 0x0247: 0x1100, 0x0248: 0x1100, 0x0249: 0x1100, 0x024a: 0x1100, 0x024b: 0x1100, + 0x024c: 0x1100, 0x024d: 0x1100, 0x024e: 0x1100, 0x024f: 0x1100, 0x0250: 0x1100, 0x0251: 0x1100, + 0x0252: 0x1100, 0x0253: 0x1100, 0x0254: 0x1100, 0x0255: 0x1100, 0x0256: 0x1100, 0x0257: 0x1100, + 0x0258: 0x1100, 0x0259: 0x1100, 0x025a: 0x1100, 0x025b: 0x1100, + 0x025e: 0x1100, 0x025f: 0x1100, + 0x0266: 0x9900, 0x0267: 0x9900, 0x0268: 0x9900, 0x0269: 0x9900, + 0x026a: 0x1100, 0x026b: 0x1100, 0x026c: 0x1100, 0x026d: 0x1100, 0x026e: 0x9900, 0x026f: 0x9900, + 0x0270: 0x1100, 0x0271: 0x1100, 0x0272: 0x1100, 0x0273: 0x1100, + // Block 0xa, offset 0x280 + 0x0292: 0x8800, + 0x02b0: 0x3000, 0x02b1: 0x3000, 0x02b2: 0x3000, 0x02b3: 0x3000, 0x02b4: 0x3000, 0x02b5: 0x3000, + 0x02b6: 0x3000, 0x02b7: 0x3000, 0x02b8: 0x3000, + // Block 0xb, offset 0x2c0 + 0x02d8: 0x3000, 0x02d9: 0x3000, 0x02da: 0x3000, 0x02db: 0x3000, 0x02dc: 0x3000, 0x02dd: 0x3000, + 0x02e0: 0x3000, 0x02e1: 0x3000, 0x02e2: 0x3000, 0x02e3: 0x3000, + 0x02e4: 0x3000, + // Block 0xc, offset 0x300 + 0x0300: 0x66e6, 0x0301: 0x66e6, 0x0302: 0x66e6, 0x0303: 0x66e6, 0x0304: 0x66e6, 0x0305: 0x00e6, + 0x0306: 0x66e6, 0x0307: 0x66e6, 0x0308: 0x66e6, 0x0309: 0x66e6, 0x030a: 0x66e6, 0x030b: 0x66e6, + 0x030c: 0x66e6, 0x030d: 0x00e6, 0x030e: 0x00e6, 0x030f: 0x66e6, 0x0310: 0x00e6, 0x0311: 0x66e6, + 0x0312: 0x00e6, 0x0313: 0x66e6, 0x0314: 0x66e6, 0x0315: 0x00e8, 0x0316: 0x00dc, 0x0317: 0x00dc, + 0x0318: 0x00dc, 0x0319: 0x00dc, 0x031a: 0x00e8, 0x031b: 0x66d8, 0x031c: 0x00dc, 0x031d: 0x00dc, + 0x031e: 0x00dc, 0x031f: 0x00dc, 0x0320: 0x00dc, 0x0321: 0x00ca, 0x0322: 0x00ca, 0x0323: 0x66dc, + 0x0324: 0x66dc, 0x0325: 0x66dc, 0x0326: 0x66dc, 0x0327: 0x66ca, 0x0328: 0x66ca, 0x0329: 0x00dc, + 0x032a: 0x00dc, 0x032b: 0x00dc, 0x032c: 0x00dc, 0x032d: 0x66dc, 0x032e: 0x66dc, 0x032f: 0x00dc, + 0x0330: 0x66dc, 0x0331: 0x66dc, 0x0332: 0x00dc, 0x0333: 0x00dc, 0x0334: 0x0001, 0x0335: 0x0001, + 0x0336: 0x0001, 0x0337: 0x0001, 0x0338: 0x6601, 0x0339: 0x00dc, 0x033a: 0x00dc, 0x033b: 0x00dc, + 0x033c: 0x00dc, 0x033d: 0x00e6, 0x033e: 0x00e6, 0x033f: 0x00e6, + // Block 0xd, offset 0x340 + 0x0340: 0x33e6, 0x0341: 0x33e6, 0x0342: 0x66e6, 0x0343: 0x33e6, 0x0344: 0x33e6, 0x0345: 0x66f0, + 0x0346: 0x00e6, 0x0347: 0x00dc, 0x0348: 0x00dc, 0x0349: 0x00dc, 0x034a: 0x00e6, 0x034b: 0x00e6, + 0x034c: 0x00e6, 0x034d: 0x00dc, 0x034e: 0x00dc, 0x0350: 0x00e6, 0x0351: 0x00e6, + 0x0352: 0x00e6, 0x0353: 0x00dc, 0x0354: 0x00dc, 0x0355: 0x00dc, 0x0356: 0x00dc, 0x0357: 0x00e6, + 0x0358: 0x00e8, 0x0359: 0x00dc, 0x035a: 0x00dc, 0x035b: 0x00e6, 0x035c: 0x00e9, 0x035d: 0x00ea, + 0x035e: 0x00ea, 0x035f: 0x00e9, 0x0360: 0x00ea, 0x0361: 0x00ea, 0x0362: 0x00e9, 0x0363: 0x00e6, + 0x0364: 0x00e6, 0x0365: 0x00e6, 0x0366: 0x00e6, 0x0367: 0x00e6, 0x0368: 0x00e6, 0x0369: 0x00e6, + 0x036a: 0x00e6, 0x036b: 0x00e6, 0x036c: 0x00e6, 0x036d: 0x00e6, 0x036e: 0x00e6, 0x036f: 0x00e6, + 0x0374: 0x3300, + 0x037a: 0x3000, + 0x037e: 0x3300, + // Block 0xe, offset 0x380 + 0x0384: 0x3000, 0x0385: 0x3100, + 0x0386: 0x1100, 0x0387: 0x3300, 0x0388: 0x1100, 0x0389: 0x1100, 0x038a: 0x1100, + 0x038c: 0x1100, 0x038e: 0x1100, 0x038f: 0x1100, 0x0390: 0x1100, 0x0391: 0x8800, + 0x0395: 0x8800, 0x0397: 0x8800, + 0x0399: 0x8800, + 0x039f: 0x8800, 0x03a1: 0x8800, + 0x03a5: 0x8800, 0x03a9: 0x8800, + 0x03aa: 0x1100, 0x03ab: 0x1100, 0x03ac: 0x9900, 0x03ad: 0x1100, 0x03ae: 0x9900, 0x03af: 0x1100, + 0x03b0: 0x1100, 0x03b1: 0x8800, 0x03b5: 0x8800, + 0x03b7: 0x8800, 0x03b9: 0x8800, + 0x03bf: 0x8800, + // Block 0xf, offset 0x3c0 + 0x03c1: 0x8800, 0x03c5: 0x8800, + 0x03c9: 0x8800, 0x03ca: 0x9900, 0x03cb: 0x9900, + 0x03cc: 0x1100, 0x03cd: 0x1100, 0x03ce: 0x9900, 0x03d0: 0x3000, 0x03d1: 0x3000, + 0x03d2: 0x3800, 0x03d3: 0x3100, 0x03d4: 0x3100, 0x03d5: 0x3000, 0x03d6: 0x3000, + 0x03f0: 0x3000, 0x03f1: 0x3000, 0x03f2: 0x3000, 0x03f4: 0x3000, 0x03f5: 0x3000, + 0x03f9: 0x3000, + // Block 0x10, offset 0x400 + 0x0400: 0x1100, 0x0401: 0x1100, 0x0403: 0x1100, + 0x0406: 0x8800, 0x0407: 0x1100, + 0x040c: 0x1100, 0x040d: 0x1100, 0x040e: 0x1100, 0x0410: 0x8800, + 0x0413: 0x8800, 0x0415: 0x8800, 0x0416: 0x8800, 0x0417: 0x8800, + 0x0418: 0x8800, 0x0419: 0x1100, 0x041a: 0x8800, + 0x041e: 0x8800, 0x0423: 0x8800, + 0x0427: 0x8800, + 0x042b: 0x8800, 0x042d: 0x8800, + 0x0430: 0x8800, 0x0433: 0x8800, 0x0435: 0x8800, + 0x0436: 0x8800, 0x0437: 0x8800, 0x0438: 0x8800, 0x0439: 0x1100, 0x043a: 0x8800, + 0x043e: 0x8800, + // Block 0x11, offset 0x440 + 0x0443: 0x8800, + 0x0447: 0x8800, 0x044b: 0x8800, + 0x044d: 0x8800, 0x0450: 0x1100, 0x0451: 0x1100, + 0x0453: 0x1100, 0x0456: 0x8800, 0x0457: 0x1100, + 0x045c: 0x1100, 0x045d: 0x1100, + 0x045e: 0x1100, + 0x0474: 0x8800, 0x0475: 0x8800, + 0x0476: 0x1100, 0x0477: 0x1100, + // Block 0x12, offset 0x480 + 0x0483: 0x00e6, 0x0484: 0x00e6, 0x0485: 0x00e6, + 0x0486: 0x00e6, 0x0487: 0x00e6, + // Block 0x13, offset 0x4c0 + 0x04c1: 0x1100, 0x04c2: 0x1100, + 0x04d0: 0x1100, 0x04d1: 0x1100, + 0x04d2: 0x1100, 0x04d3: 0x1100, 0x04d6: 0x1100, 0x04d7: 0x1100, + 0x04d8: 0x8800, 0x04d9: 0x8800, 0x04da: 0x1100, 0x04db: 0x1100, 0x04dc: 0x1100, 0x04dd: 0x1100, + 0x04de: 0x1100, 0x04df: 0x1100, 0x04e2: 0x1100, 0x04e3: 0x1100, + 0x04e4: 0x1100, 0x04e5: 0x1100, 0x04e6: 0x1100, 0x04e7: 0x1100, 0x04e8: 0x8800, 0x04e9: 0x8800, + 0x04ea: 0x1100, 0x04eb: 0x1100, 0x04ec: 0x1100, 0x04ed: 0x1100, 0x04ee: 0x1100, 0x04ef: 0x1100, + 0x04f0: 0x1100, 0x04f1: 0x1100, 0x04f2: 0x1100, 0x04f3: 0x1100, 0x04f4: 0x1100, 0x04f5: 0x1100, + 0x04f8: 0x1100, 0x04f9: 0x1100, + // Block 0x14, offset 0x500 + 0x0507: 0x3000, + 0x0511: 0x00dc, + 0x0512: 0x00e6, 0x0513: 0x00e6, 0x0514: 0x00e6, 0x0515: 0x00e6, 0x0516: 0x00dc, 0x0517: 0x00e6, + 0x0518: 0x00e6, 0x0519: 0x00e6, 0x051a: 0x00de, 0x051b: 0x00dc, 0x051c: 0x00e6, 0x051d: 0x00e6, + 0x051e: 0x00e6, 0x051f: 0x00e6, 0x0520: 0x00e6, 0x0521: 0x00e6, 0x0522: 0x00dc, 0x0523: 0x00dc, + 0x0524: 0x00dc, 0x0525: 0x00dc, 0x0526: 0x00dc, 0x0527: 0x00dc, 0x0528: 0x00e6, 0x0529: 0x00e6, + 0x052a: 0x00dc, 0x052b: 0x00e6, 0x052c: 0x00e6, 0x052d: 0x00de, 0x052e: 0x00e4, 0x052f: 0x00e6, + 0x0530: 0x000a, 0x0531: 0x000b, 0x0532: 0x000c, 0x0533: 0x000d, 0x0534: 0x000e, 0x0535: 0x000f, + 0x0536: 0x0010, 0x0537: 0x0011, 0x0538: 0x0012, 0x0539: 0x0013, 0x053a: 0x0013, 0x053b: 0x0014, + 0x053c: 0x0015, 0x053d: 0x0016, 0x053f: 0x0017, + // Block 0x15, offset 0x540 + 0x0541: 0x0018, 0x0542: 0x0019, 0x0544: 0x00e6, 0x0545: 0x00dc, + 0x0547: 0x0012, + // Block 0x16, offset 0x580 + 0x0590: 0x00e6, 0x0591: 0x00e6, + 0x0592: 0x00e6, 0x0593: 0x00e6, 0x0594: 0x00e6, 0x0595: 0x00e6, 0x0596: 0x00e6, 0x0597: 0x00e6, + 0x0598: 0x001e, 0x0599: 0x001f, 0x059a: 0x0020, + 0x05a2: 0x1100, 0x05a3: 0x1100, + 0x05a4: 0x1100, 0x05a5: 0x1100, 0x05a6: 0x1100, 0x05a7: 0x8800, + // Block 0x17, offset 0x5c0 + 0x05c8: 0x8800, 0x05ca: 0x8800, 0x05cb: 0x001b, + 0x05cc: 0x001c, 0x05cd: 0x001d, 0x05ce: 0x001e, 0x05cf: 0x001f, 0x05d0: 0x0020, 0x05d1: 0x0021, + 0x05d2: 0x0022, 0x05d3: 0x66e6, 0x05d4: 0x66e6, 0x05d5: 0x66dc, 0x05d6: 0x00dc, 0x05d7: 0x00e6, + 0x05d8: 0x00e6, 0x05d9: 0x00e6, 0x05da: 0x00e6, 0x05db: 0x00e6, 0x05dc: 0x00dc, 0x05dd: 0x00e6, + 0x05de: 0x00e6, 0x05df: 0x00dc, + 0x05f0: 0x0023, 0x05f5: 0x3000, + 0x05f6: 0x3000, 0x05f7: 0x3000, 0x05f8: 0x3000, + // Block 0x18, offset 0x600 + 0x0600: 0x1100, 0x0601: 0x8800, 0x0602: 0x1100, + 0x0612: 0x8800, 0x0613: 0x1100, 0x0615: 0x8800, 0x0616: 0x00e6, 0x0617: 0x00e6, + 0x0618: 0x00e6, 0x0619: 0x00e6, 0x061a: 0x00e6, 0x061b: 0x00e6, 0x061c: 0x00e6, + 0x061f: 0x00e6, 0x0620: 0x00e6, 0x0621: 0x00e6, 0x0622: 0x00e6, 0x0623: 0x00dc, + 0x0624: 0x00e6, 0x0627: 0x00e6, 0x0628: 0x00e6, + 0x062a: 0x00dc, 0x062b: 0x00e6, 0x062c: 0x00e6, 0x062d: 0x00dc, + // Block 0x19, offset 0x640 + 0x0651: 0x0024, + 0x0670: 0x00e6, 0x0671: 0x00dc, 0x0672: 0x00e6, 0x0673: 0x00e6, 0x0674: 0x00dc, 0x0675: 0x00e6, + 0x0676: 0x00e6, 0x0677: 0x00dc, 0x0678: 0x00dc, 0x0679: 0x00dc, 0x067a: 0x00e6, 0x067b: 0x00dc, + 0x067c: 0x00dc, 0x067d: 0x00e6, 0x067e: 0x00dc, 0x067f: 0x00e6, + // Block 0x1a, offset 0x680 + 0x0680: 0x00e6, 0x0681: 0x00e6, 0x0682: 0x00dc, 0x0683: 0x00e6, 0x0684: 0x00dc, 0x0685: 0x00e6, + 0x0686: 0x00dc, 0x0687: 0x00e6, 0x0688: 0x00dc, 0x0689: 0x00e6, 0x068a: 0x00e6, + // Block 0x1b, offset 0x6c0 + 0x06eb: 0x00e6, 0x06ec: 0x00e6, 0x06ed: 0x00e6, 0x06ee: 0x00e6, 0x06ef: 0x00e6, + 0x06f0: 0x00e6, 0x06f1: 0x00e6, 0x06f2: 0x00dc, 0x06f3: 0x00e6, + // Block 0x1c, offset 0x700 + 0x0716: 0x00e6, 0x0717: 0x00e6, + 0x0718: 0x00e6, 0x0719: 0x00e6, 0x071b: 0x00e6, 0x071c: 0x00e6, 0x071d: 0x00e6, + 0x071e: 0x00e6, 0x071f: 0x00e6, 0x0720: 0x00e6, 0x0721: 0x00e6, 0x0722: 0x00e6, 0x0723: 0x00e6, + 0x0725: 0x00e6, 0x0726: 0x00e6, 0x0727: 0x00e6, 0x0729: 0x00e6, + 0x072a: 0x00e6, 0x072b: 0x00e6, 0x072c: 0x00e6, 0x072d: 0x00e6, + // Block 0x1d, offset 0x740 + 0x0759: 0x00dc, 0x075a: 0x00dc, 0x075b: 0x00dc, + // Block 0x1e, offset 0x780 + 0x07a8: 0x8800, 0x07a9: 0x1100, + 0x07b0: 0x8800, 0x07b1: 0x1100, 0x07b3: 0x8800, 0x07b4: 0x1100, + 0x07bc: 0x6607, + // Block 0x1f, offset 0x7c0 + 0x07cd: 0x0009, 0x07d1: 0x00e6, + 0x07d2: 0x00dc, 0x07d3: 0x00e6, 0x07d4: 0x00e6, + 0x07d8: 0x3300, 0x07d9: 0x3300, 0x07da: 0x3300, 0x07db: 0x3300, 0x07dc: 0x3300, 0x07dd: 0x3300, + 0x07de: 0x3300, 0x07df: 0x3300, + // Block 0x20, offset 0x800 + 0x083c: 0x0007, 0x083e: 0x6600, + // Block 0x21, offset 0x840 + 0x0847: 0x8800, 0x084b: 0x1100, + 0x084c: 0x1100, 0x084d: 0x0009, + 0x0857: 0x6600, + 0x085c: 0x3300, 0x085d: 0x3300, + 0x085f: 0x3300, + // Block 0x22, offset 0x880 + 0x08b3: 0x3300, + 0x08b6: 0x3300, + 0x08bc: 0x0007, + // Block 0x23, offset 0x8c0 + 0x08cd: 0x0009, + 0x08d9: 0x3300, 0x08da: 0x3300, 0x08db: 0x3300, + 0x08de: 0x3300, + // Block 0x24, offset 0x900 + 0x093c: 0x0007, + // Block 0x25, offset 0x940 + 0x094d: 0x0009, + // Block 0x26, offset 0x980 + 0x0987: 0x8800, 0x0988: 0x1100, 0x098b: 0x1100, + 0x098c: 0x1100, 0x098d: 0x0009, + 0x0996: 0x6600, 0x0997: 0x6600, + 0x099c: 0x3300, 0x099d: 0x3300, + // Block 0x27, offset 0x9c0 + 0x09d2: 0x8800, 0x09d4: 0x1100, + 0x09fe: 0x6600, + // Block 0x28, offset 0xa00 + 0x0a06: 0x8800, 0x0a07: 0x8800, 0x0a0a: 0x1100, 0x0a0b: 0x1100, + 0x0a0c: 0x1100, 0x0a0d: 0x0009, + 0x0a17: 0x6600, + // Block 0x29, offset 0xa40 + 0x0a46: 0x8800, 0x0a48: 0x1100, + 0x0a4d: 0x0009, + 0x0a55: 0x0054, 0x0a56: 0x665b, + // Block 0x2a, offset 0xa80 + 0x0abc: 0x0007, 0x0abf: 0x8800, + // Block 0x2b, offset 0xac0 + 0x0ac0: 0x1100, 0x0ac2: 0x6600, + 0x0ac6: 0x8800, 0x0ac7: 0x1100, 0x0ac8: 0x1100, 0x0aca: 0x9900, 0x0acb: 0x1100, + 0x0acd: 0x0009, + 0x0ad5: 0x6600, 0x0ad6: 0x6600, + // Block 0x2c, offset 0xb00 + 0x0b3e: 0x6600, + // Block 0x2d, offset 0xb40 + 0x0b4a: 0x6609, + 0x0b4f: 0x6600, + 0x0b59: 0x8800, 0x0b5a: 0x1100, 0x0b5c: 0x9900, 0x0b5d: 0x1100, + 0x0b5e: 0x1100, 0x0b5f: 0x6600, + // Block 0x2e, offset 0xb80 + 0x0bb3: 0x3000, + 0x0bb8: 0x0067, 0x0bb9: 0x0067, 0x0bba: 0x0009, + // Block 0x2f, offset 0xbc0 + 0x0bc8: 0x006b, 0x0bc9: 0x006b, 0x0bca: 0x006b, 0x0bcb: 0x006b, + // Block 0x30, offset 0xc00 + 0x0c33: 0x3000, + 0x0c38: 0x0076, 0x0c39: 0x0076, + // Block 0x31, offset 0xc40 + 0x0c48: 0x007a, 0x0c49: 0x007a, 0x0c4a: 0x007a, 0x0c4b: 0x007a, + 0x0c5c: 0x3000, 0x0c5d: 0x3000, + // Block 0x32, offset 0xc80 + 0x0c8c: 0x3000, + 0x0c98: 0x00dc, 0x0c99: 0x00dc, + 0x0cb5: 0x00dc, + 0x0cb7: 0x00dc, 0x0cb9: 0x00d8, + // Block 0x33, offset 0xcc0 + 0x0cc3: 0x3300, + 0x0ccd: 0x3300, + 0x0cd2: 0x3300, 0x0cd7: 0x3300, + 0x0cdc: 0x3300, + 0x0ce9: 0x3300, + 0x0cf1: 0x0081, 0x0cf2: 0x0082, 0x0cf3: 0x3300, 0x0cf4: 0x0084, 0x0cf5: 0x3300, + 0x0cf6: 0x3300, 0x0cf7: 0x3000, 0x0cf8: 0x3300, 0x0cf9: 0x3000, 0x0cfa: 0x0082, 0x0cfb: 0x0082, + 0x0cfc: 0x0082, 0x0cfd: 0x0082, + // Block 0x34, offset 0xd00 + 0x0d00: 0x0082, 0x0d01: 0x3300, 0x0d02: 0x00e6, 0x0d03: 0x00e6, 0x0d04: 0x0009, + 0x0d06: 0x00e6, 0x0d07: 0x00e6, + 0x0d13: 0x3300, + 0x0d1d: 0x3300, + 0x0d22: 0x3300, + 0x0d27: 0x3300, + 0x0d2c: 0x3300, + 0x0d39: 0x3300, + // Block 0x35, offset 0xd40 + 0x0d46: 0x00dc, + // Block 0x36, offset 0xd80 + 0x0da5: 0x8800, 0x0da6: 0x1100, + 0x0dae: 0x6600, + 0x0db7: 0x0007, 0x0db9: 0x0009, 0x0dba: 0x0009, + // Block 0x37, offset 0xdc0 + 0x0dcd: 0x00dc, + // Block 0x38, offset 0xe00 + 0x0e3c: 0x3000, + // Block 0x39, offset 0xe40 + 0x0e61: 0x6600, 0x0e62: 0x6600, 0x0e63: 0x6600, + 0x0e64: 0x6600, 0x0e65: 0x6600, 0x0e66: 0x6600, 0x0e67: 0x6600, 0x0e68: 0x6600, 0x0e69: 0x6600, + 0x0e6a: 0x6600, 0x0e6b: 0x6600, 0x0e6c: 0x6600, 0x0e6d: 0x6600, 0x0e6e: 0x6600, 0x0e6f: 0x6600, + 0x0e70: 0x6600, 0x0e71: 0x6600, 0x0e72: 0x6600, 0x0e73: 0x6600, 0x0e74: 0x6600, 0x0e75: 0x6600, + // Block 0x3a, offset 0xe80 + 0x0ea8: 0x6600, 0x0ea9: 0x6600, + 0x0eaa: 0x6600, 0x0eab: 0x6600, 0x0eac: 0x6600, 0x0ead: 0x6600, 0x0eae: 0x6600, 0x0eaf: 0x6600, + 0x0eb0: 0x6600, 0x0eb1: 0x6600, 0x0eb2: 0x6600, 0x0eb3: 0x6600, 0x0eb4: 0x6600, 0x0eb5: 0x6600, + 0x0eb6: 0x6600, 0x0eb7: 0x6600, 0x0eb8: 0x6600, 0x0eb9: 0x6600, 0x0eba: 0x6600, 0x0ebb: 0x6600, + 0x0ebc: 0x6600, 0x0ebd: 0x6600, 0x0ebe: 0x6600, 0x0ebf: 0x6600, + // Block 0x3b, offset 0xec0 + 0x0ec0: 0x6600, 0x0ec1: 0x6600, 0x0ec2: 0x6600, + // Block 0x3c, offset 0xf00 + 0x0f1d: 0x00e6, + 0x0f1e: 0x00e6, 0x0f1f: 0x00e6, + // Block 0x3d, offset 0xf40 + 0x0f54: 0x0009, + 0x0f74: 0x0009, + // Block 0x3e, offset 0xf80 + 0x0f92: 0x0009, + 0x0f9d: 0x00e6, + // Block 0x3f, offset 0xfc0 + 0x0fe9: 0x00e4, + // Block 0x40, offset 0x1000 + 0x1039: 0x00de, 0x103a: 0x00e6, 0x103b: 0x00dc, + // Block 0x41, offset 0x1040 + 0x1057: 0x00e6, + 0x1058: 0x00dc, + // Block 0x42, offset 0x1080 + 0x10a0: 0x0009, + 0x10b5: 0x00e6, + 0x10b6: 0x00e6, 0x10b7: 0x00e6, 0x10b8: 0x00e6, 0x10b9: 0x00e6, 0x10ba: 0x00e6, 0x10bb: 0x00e6, + 0x10bc: 0x00e6, 0x10bf: 0x00dc, + // Block 0x43, offset 0x10c0 + 0x10c5: 0x8800, + 0x10c6: 0x1100, 0x10c7: 0x8800, 0x10c8: 0x1100, 0x10c9: 0x8800, 0x10ca: 0x1100, 0x10cb: 0x8800, + 0x10cc: 0x1100, 0x10cd: 0x8800, 0x10ce: 0x1100, 0x10d1: 0x8800, + 0x10d2: 0x1100, + 0x10f4: 0x0007, 0x10f5: 0x6600, + 0x10fa: 0x8800, 0x10fb: 0x1100, + 0x10fc: 0x8800, 0x10fd: 0x1100, 0x10fe: 0x8800, 0x10ff: 0x8800, + // Block 0x44, offset 0x1100 + 0x1100: 0x1100, 0x1101: 0x1100, 0x1102: 0x8800, 0x1103: 0x1100, 0x1104: 0x0009, + 0x112b: 0x00e6, 0x112c: 0x00dc, 0x112d: 0x00e6, 0x112e: 0x00e6, 0x112f: 0x00e6, + 0x1130: 0x00e6, 0x1131: 0x00e6, 0x1132: 0x00e6, 0x1133: 0x00e6, + // Block 0x45, offset 0x1140 + 0x116a: 0x0009, + // Block 0x46, offset 0x1180 + 0x11a6: 0x0007, + 0x11b2: 0x0009, 0x11b3: 0x0009, + // Block 0x47, offset 0x11c0 + 0x11f7: 0x0007, + // Block 0x48, offset 0x1200 + 0x1210: 0x00e6, 0x1211: 0x00e6, + 0x1212: 0x00e6, 0x1214: 0x0001, 0x1215: 0x00dc, 0x1216: 0x00dc, 0x1217: 0x00dc, + 0x1218: 0x00dc, 0x1219: 0x00dc, 0x121a: 0x00e6, 0x121b: 0x00e6, 0x121c: 0x00dc, 0x121d: 0x00dc, + 0x121e: 0x00dc, 0x121f: 0x00dc, 0x1220: 0x00e6, 0x1222: 0x0001, 0x1223: 0x0001, + 0x1224: 0x0001, 0x1225: 0x0001, 0x1226: 0x0001, 0x1227: 0x0001, 0x1228: 0x0001, + 0x122d: 0x00dc, + // Block 0x49, offset 0x1240 + 0x126c: 0x3000, 0x126d: 0x3000, 0x126e: 0x3000, + 0x1270: 0x3000, 0x1271: 0x3000, 0x1272: 0x3000, 0x1273: 0x3000, 0x1274: 0x3000, 0x1275: 0x3000, + 0x1276: 0x3000, 0x1277: 0x3000, 0x1278: 0x3000, 0x1279: 0x3000, 0x127a: 0x3000, + 0x127c: 0x3000, 0x127d: 0x3000, 0x127e: 0x3000, 0x127f: 0x3000, + // Block 0x4a, offset 0x1280 + 0x1280: 0x3000, 0x1281: 0x3000, 0x1282: 0x3000, 0x1283: 0x3000, 0x1284: 0x3000, 0x1285: 0x3000, + 0x1286: 0x3000, 0x1287: 0x3000, 0x1288: 0x3000, 0x1289: 0x3000, 0x128a: 0x3000, 0x128b: 0x3000, + 0x128c: 0x3000, 0x128d: 0x3000, 0x128f: 0x3000, 0x1290: 0x3000, 0x1291: 0x3000, + 0x1292: 0x3000, 0x1293: 0x3000, 0x1294: 0x3000, 0x1295: 0x3000, 0x1296: 0x3000, 0x1297: 0x3000, + 0x1298: 0x3000, 0x1299: 0x3000, 0x129a: 0x3000, 0x129b: 0x3000, 0x129c: 0x3000, 0x129d: 0x3000, + 0x129e: 0x3000, 0x129f: 0x3000, 0x12a0: 0x3000, 0x12a1: 0x3000, 0x12a2: 0x3000, 0x12a3: 0x3000, + 0x12a4: 0x3000, 0x12a5: 0x3000, 0x12a6: 0x3000, 0x12a7: 0x3000, 0x12a8: 0x3000, 0x12a9: 0x3000, + 0x12aa: 0x3000, + 0x12b8: 0x3000, + // Block 0x4b, offset 0x12c0 + 0x12db: 0x3000, 0x12dc: 0x3000, 0x12dd: 0x3000, + 0x12de: 0x3000, 0x12df: 0x3000, 0x12e0: 0x3000, 0x12e1: 0x3000, 0x12e2: 0x3000, 0x12e3: 0x3000, + 0x12e4: 0x3000, 0x12e5: 0x3000, 0x12e6: 0x3000, 0x12e7: 0x3000, 0x12e8: 0x3000, 0x12e9: 0x3000, + 0x12ea: 0x3000, 0x12eb: 0x3000, 0x12ec: 0x3000, 0x12ed: 0x3000, 0x12ee: 0x3000, 0x12ef: 0x3000, + 0x12f0: 0x3000, 0x12f1: 0x3000, 0x12f2: 0x3000, 0x12f3: 0x3000, 0x12f4: 0x3000, 0x12f5: 0x3000, + 0x12f6: 0x3000, 0x12f7: 0x3000, 0x12f8: 0x3000, 0x12f9: 0x3000, 0x12fa: 0x3000, 0x12fb: 0x3000, + 0x12fc: 0x3000, 0x12fd: 0x3000, 0x12fe: 0x3000, 0x12ff: 0x3000, + // Block 0x4c, offset 0x1300 + 0x1300: 0x00e6, 0x1301: 0x00e6, 0x1302: 0x00dc, 0x1303: 0x00e6, 0x1304: 0x00e6, 0x1305: 0x00e6, + 0x1306: 0x00e6, 0x1307: 0x00e6, 0x1308: 0x00e6, 0x1309: 0x00e6, 0x130a: 0x00dc, 0x130b: 0x00e6, + 0x130c: 0x00e6, 0x130d: 0x00ea, 0x130e: 0x00d6, 0x130f: 0x00dc, 0x1310: 0x00ca, 0x1311: 0x00e6, + 0x1312: 0x00e6, 0x1313: 0x00e6, 0x1314: 0x00e6, 0x1315: 0x00e6, 0x1316: 0x00e6, 0x1317: 0x00e6, + 0x1318: 0x00e6, 0x1319: 0x00e6, 0x131a: 0x00e6, 0x131b: 0x00e6, 0x131c: 0x00e6, 0x131d: 0x00e6, + 0x131e: 0x00e6, 0x131f: 0x00e6, 0x1320: 0x00e6, 0x1321: 0x00e6, 0x1322: 0x00e6, 0x1323: 0x00e6, + 0x1324: 0x00e6, 0x1325: 0x00e6, 0x1326: 0x00e6, + 0x133c: 0x00e9, 0x133d: 0x00dc, 0x133e: 0x00e6, 0x133f: 0x00dc, + // Block 0x4d, offset 0x1340 + 0x1340: 0x1100, 0x1341: 0x1100, 0x1342: 0x1100, 0x1343: 0x1100, 0x1344: 0x1100, 0x1345: 0x1100, + 0x1346: 0x1100, 0x1347: 0x1100, 0x1348: 0x1100, 0x1349: 0x1100, 0x134a: 0x1100, 0x134b: 0x1100, + 0x134c: 0x1100, 0x134d: 0x1100, 0x134e: 0x1100, 0x134f: 0x1100, 0x1350: 0x1100, 0x1351: 0x1100, + 0x1352: 0x1100, 0x1353: 0x1100, 0x1354: 0x1100, 0x1355: 0x1100, 0x1356: 0x1100, 0x1357: 0x1100, + 0x1358: 0x1100, 0x1359: 0x1100, 0x135a: 0x1100, 0x135b: 0x1100, 0x135c: 0x1100, 0x135d: 0x1100, + 0x135e: 0x1100, 0x135f: 0x1100, 0x1360: 0x1100, 0x1361: 0x1100, 0x1362: 0x1100, 0x1363: 0x1100, + 0x1364: 0x1100, 0x1365: 0x1100, 0x1366: 0x1100, 0x1367: 0x1100, 0x1368: 0x1100, 0x1369: 0x1100, + 0x136a: 0x1100, 0x136b: 0x1100, 0x136c: 0x1100, 0x136d: 0x1100, 0x136e: 0x1100, 0x136f: 0x1100, + 0x1370: 0x1100, 0x1371: 0x1100, 0x1372: 0x1100, 0x1373: 0x1100, 0x1374: 0x1100, 0x1375: 0x1100, + 0x1376: 0x9900, 0x1377: 0x9900, 0x1378: 0x1100, 0x1379: 0x1100, 0x137a: 0x1100, 0x137b: 0x1100, + 0x137c: 0x1100, 0x137d: 0x1100, 0x137e: 0x1100, 0x137f: 0x1100, + // Block 0x4e, offset 0x1380 + 0x1380: 0x1100, 0x1381: 0x1100, 0x1382: 0x1100, 0x1383: 0x1100, 0x1384: 0x1100, 0x1385: 0x1100, + 0x1386: 0x1100, 0x1387: 0x1100, 0x1388: 0x1100, 0x1389: 0x1100, 0x138a: 0x1100, 0x138b: 0x1100, + 0x138c: 0x1100, 0x138d: 0x1100, 0x138e: 0x1100, 0x138f: 0x1100, 0x1390: 0x1100, 0x1391: 0x1100, + 0x1392: 0x1100, 0x1393: 0x1100, 0x1394: 0x1100, 0x1395: 0x1100, 0x1396: 0x1100, 0x1397: 0x1100, + 0x1398: 0x1100, 0x1399: 0x1100, 0x139a: 0x9900, 0x139b: 0x9900, 0x139c: 0x1100, 0x139d: 0x1100, + 0x139e: 0x1100, 0x139f: 0x1100, 0x13a0: 0x1100, 0x13a1: 0x1100, 0x13a2: 0x9900, 0x13a3: 0x9900, + 0x13a4: 0x1100, 0x13a5: 0x1100, 0x13a6: 0x1100, 0x13a7: 0x1100, 0x13a8: 0x1100, 0x13a9: 0x1100, + 0x13aa: 0x1100, 0x13ab: 0x1100, 0x13ac: 0x1100, 0x13ad: 0x1100, 0x13ae: 0x1100, 0x13af: 0x1100, + 0x13b0: 0x1100, 0x13b1: 0x1100, 0x13b2: 0x1100, 0x13b3: 0x1100, 0x13b4: 0x1100, 0x13b5: 0x1100, + 0x13b6: 0x1100, 0x13b7: 0x1100, 0x13b8: 0x1100, 0x13b9: 0x1100, 0x13ba: 0x1100, 0x13bb: 0x1100, + 0x13bc: 0x1100, 0x13bd: 0x1100, 0x13be: 0x1100, 0x13bf: 0x1100, + // Block 0x4f, offset 0x13c0 + 0x13c0: 0x1100, 0x13c1: 0x1100, 0x13c2: 0x1100, 0x13c3: 0x1100, 0x13c4: 0x1100, 0x13c5: 0x1100, + 0x13c6: 0x1100, 0x13c7: 0x1100, 0x13c8: 0x1100, 0x13c9: 0x1100, 0x13ca: 0x1100, 0x13cb: 0x1100, + 0x13cc: 0x1100, 0x13cd: 0x1100, 0x13ce: 0x1100, 0x13cf: 0x1100, 0x13d0: 0x1100, 0x13d1: 0x1100, + 0x13d2: 0x1100, 0x13d3: 0x1100, 0x13d4: 0x1100, 0x13d5: 0x1100, 0x13d6: 0x1100, 0x13d7: 0x1100, + 0x13d8: 0x1100, 0x13d9: 0x1100, 0x13da: 0x3000, 0x13db: 0x3100, + 0x13e0: 0x9900, 0x13e1: 0x9900, 0x13e2: 0x1100, 0x13e3: 0x1100, + 0x13e4: 0x1100, 0x13e5: 0x1100, 0x13e6: 0x1100, 0x13e7: 0x1100, 0x13e8: 0x1100, 0x13e9: 0x1100, + 0x13ea: 0x1100, 0x13eb: 0x1100, 0x13ec: 0x1100, 0x13ed: 0x1100, 0x13ee: 0x1100, 0x13ef: 0x1100, + 0x13f0: 0x1100, 0x13f1: 0x1100, 0x13f2: 0x1100, 0x13f3: 0x1100, 0x13f4: 0x1100, 0x13f5: 0x1100, + 0x13f6: 0x1100, 0x13f7: 0x1100, 0x13f8: 0x9900, 0x13f9: 0x9900, 0x13fa: 0x1100, 0x13fb: 0x1100, + 0x13fc: 0x1100, 0x13fd: 0x1100, 0x13fe: 0x1100, 0x13ff: 0x1100, + // Block 0x50, offset 0x1400 + 0x1400: 0x1100, 0x1401: 0x1100, 0x1402: 0x1100, 0x1403: 0x1100, 0x1404: 0x1100, 0x1405: 0x1100, + 0x1406: 0x1100, 0x1407: 0x1100, 0x1408: 0x1100, 0x1409: 0x1100, 0x140a: 0x1100, 0x140b: 0x1100, + 0x140c: 0x9900, 0x140d: 0x9900, 0x140e: 0x1100, 0x140f: 0x1100, 0x1410: 0x1100, 0x1411: 0x1100, + 0x1412: 0x1100, 0x1413: 0x1100, 0x1414: 0x1100, 0x1415: 0x1100, 0x1416: 0x1100, 0x1417: 0x1100, + 0x1418: 0x1100, 0x1419: 0x1100, 0x141a: 0x1100, 0x141b: 0x1100, 0x141c: 0x1100, 0x141d: 0x1100, + 0x141e: 0x1100, 0x141f: 0x1100, 0x1420: 0x1100, 0x1421: 0x1100, 0x1422: 0x1100, 0x1423: 0x1100, + 0x1424: 0x1100, 0x1425: 0x1100, 0x1426: 0x1100, 0x1427: 0x1100, 0x1428: 0x1100, 0x1429: 0x1100, + 0x142a: 0x1100, 0x142b: 0x1100, 0x142c: 0x1100, 0x142d: 0x1100, 0x142e: 0x1100, 0x142f: 0x1100, + 0x1430: 0x1100, 0x1431: 0x1100, 0x1432: 0x1100, 0x1433: 0x1100, 0x1434: 0x1100, 0x1435: 0x1100, + 0x1436: 0x1100, 0x1437: 0x1100, 0x1438: 0x1100, 0x1439: 0x1100, + // Block 0x51, offset 0x1440 + 0x1440: 0x9900, 0x1441: 0x9900, 0x1442: 0x9900, 0x1443: 0x9900, 0x1444: 0x9900, 0x1445: 0x9900, + 0x1446: 0x9900, 0x1447: 0x9900, 0x1448: 0x9900, 0x1449: 0x9900, 0x144a: 0x9900, 0x144b: 0x9900, + 0x144c: 0x9900, 0x144d: 0x9900, 0x144e: 0x9900, 0x144f: 0x9900, 0x1450: 0x9900, 0x1451: 0x9900, + 0x1452: 0x1100, 0x1453: 0x1100, 0x1454: 0x1100, 0x1455: 0x1100, + 0x1458: 0x9900, 0x1459: 0x9900, 0x145a: 0x1100, 0x145b: 0x1100, 0x145c: 0x1100, 0x145d: 0x1100, + 0x1460: 0x9900, 0x1461: 0x9900, 0x1462: 0x9900, 0x1463: 0x9900, + 0x1464: 0x9900, 0x1465: 0x9900, 0x1466: 0x9900, 0x1467: 0x9900, 0x1468: 0x9900, 0x1469: 0x9900, + 0x146a: 0x9900, 0x146b: 0x9900, 0x146c: 0x9900, 0x146d: 0x9900, 0x146e: 0x9900, 0x146f: 0x9900, + 0x1470: 0x9900, 0x1471: 0x9900, 0x1472: 0x1100, 0x1473: 0x1100, 0x1474: 0x1100, 0x1475: 0x1100, + 0x1476: 0x1100, 0x1477: 0x1100, 0x1478: 0x9900, 0x1479: 0x9900, 0x147a: 0x1100, 0x147b: 0x1100, + 0x147c: 0x1100, 0x147d: 0x1100, 0x147e: 0x1100, 0x147f: 0x1100, + // Block 0x52, offset 0x1480 + 0x1480: 0x9900, 0x1481: 0x9900, 0x1482: 0x1100, 0x1483: 0x1100, 0x1484: 0x1100, 0x1485: 0x1100, + 0x1488: 0x9900, 0x1489: 0x9900, 0x148a: 0x1100, 0x148b: 0x1100, + 0x148c: 0x1100, 0x148d: 0x1100, 0x1490: 0x9900, 0x1491: 0x9900, + 0x1492: 0x1100, 0x1493: 0x1100, 0x1494: 0x1100, 0x1495: 0x1100, 0x1496: 0x1100, 0x1497: 0x1100, + 0x1499: 0x9900, 0x149b: 0x1100, 0x149d: 0x1100, + 0x149f: 0x1100, 0x14a0: 0x9900, 0x14a1: 0x9900, 0x14a2: 0x9900, 0x14a3: 0x9900, + 0x14a4: 0x9900, 0x14a5: 0x9900, 0x14a6: 0x9900, 0x14a7: 0x9900, 0x14a8: 0x9900, 0x14a9: 0x9900, + 0x14aa: 0x9900, 0x14ab: 0x9900, 0x14ac: 0x9900, 0x14ad: 0x9900, 0x14ae: 0x9900, 0x14af: 0x9900, + 0x14b0: 0x9900, 0x14b1: 0x3300, 0x14b2: 0x1100, 0x14b3: 0x3300, 0x14b4: 0x9900, 0x14b5: 0x3300, + 0x14b6: 0x1100, 0x14b7: 0x3300, 0x14b8: 0x1100, 0x14b9: 0x3300, 0x14ba: 0x1100, 0x14bb: 0x3300, + 0x14bc: 0x9900, 0x14bd: 0x3300, + // Block 0x53, offset 0x14c0 + 0x14c0: 0x1100, 0x14c1: 0x1100, 0x14c2: 0x1100, 0x14c3: 0x1100, 0x14c4: 0x1100, 0x14c5: 0x1100, + 0x14c6: 0x1100, 0x14c7: 0x1100, 0x14c8: 0x1100, 0x14c9: 0x1100, 0x14ca: 0x1100, 0x14cb: 0x1100, + 0x14cc: 0x1100, 0x14cd: 0x1100, 0x14ce: 0x1100, 0x14cf: 0x1100, 0x14d0: 0x1100, 0x14d1: 0x1100, + 0x14d2: 0x1100, 0x14d3: 0x1100, 0x14d4: 0x1100, 0x14d5: 0x1100, 0x14d6: 0x1100, 0x14d7: 0x1100, + 0x14d8: 0x1100, 0x14d9: 0x1100, 0x14da: 0x1100, 0x14db: 0x1100, 0x14dc: 0x1100, 0x14dd: 0x1100, + 0x14de: 0x1100, 0x14df: 0x1100, 0x14e0: 0x1100, 0x14e1: 0x1100, 0x14e2: 0x1100, 0x14e3: 0x1100, + 0x14e4: 0x1100, 0x14e5: 0x1100, 0x14e6: 0x1100, 0x14e7: 0x1100, 0x14e8: 0x1100, 0x14e9: 0x1100, + 0x14ea: 0x1100, 0x14eb: 0x1100, 0x14ec: 0x1100, 0x14ed: 0x1100, 0x14ee: 0x1100, 0x14ef: 0x1100, + 0x14f0: 0x1100, 0x14f1: 0x1100, 0x14f2: 0x1100, 0x14f3: 0x1100, 0x14f4: 0x1100, + 0x14f6: 0x9900, 0x14f7: 0x1100, 0x14f8: 0x1100, 0x14f9: 0x1100, 0x14fa: 0x1100, 0x14fb: 0x3300, + 0x14fc: 0x1100, 0x14fd: 0x3000, 0x14fe: 0x3300, 0x14ff: 0x3800, + // Block 0x54, offset 0x1500 + 0x1500: 0x3000, 0x1501: 0x3100, 0x1502: 0x1100, 0x1503: 0x1100, 0x1504: 0x1100, + 0x1506: 0x9900, 0x1507: 0x1100, 0x1508: 0x1100, 0x1509: 0x3300, 0x150a: 0x1100, 0x150b: 0x3300, + 0x150c: 0x1100, 0x150d: 0x3100, 0x150e: 0x3100, 0x150f: 0x3100, 0x1510: 0x1100, 0x1511: 0x1100, + 0x1512: 0x1100, 0x1513: 0x3300, 0x1516: 0x1100, 0x1517: 0x1100, + 0x1518: 0x1100, 0x1519: 0x1100, 0x151a: 0x1100, 0x151b: 0x3300, 0x151d: 0x3100, + 0x151e: 0x3100, 0x151f: 0x3100, 0x1520: 0x1100, 0x1521: 0x1100, 0x1522: 0x1100, 0x1523: 0x3300, + 0x1524: 0x1100, 0x1525: 0x1100, 0x1526: 0x1100, 0x1527: 0x1100, 0x1528: 0x1100, 0x1529: 0x1100, + 0x152a: 0x1100, 0x152b: 0x3300, 0x152c: 0x1100, 0x152d: 0x3100, 0x152e: 0x3300, 0x152f: 0x3300, + 0x1532: 0x1100, 0x1533: 0x1100, 0x1534: 0x1100, + 0x1536: 0x9900, 0x1537: 0x1100, 0x1538: 0x1100, 0x1539: 0x3300, 0x153a: 0x1100, 0x153b: 0x3300, + 0x153c: 0x1100, 0x153d: 0x3300, 0x153e: 0x3800, + // Block 0x55, offset 0x1540 + 0x1540: 0x3300, 0x1541: 0x3300, 0x1542: 0x3000, 0x1543: 0x3000, 0x1544: 0x3000, 0x1545: 0x3000, + 0x1546: 0x3000, 0x1547: 0x3000, 0x1548: 0x3000, 0x1549: 0x3000, 0x154a: 0x3000, + 0x1551: 0x3000, + 0x1557: 0x3000, + 0x1564: 0x3000, 0x1565: 0x3000, 0x1566: 0x3000, + 0x156f: 0x3000, + 0x1573: 0x3000, 0x1574: 0x3000, + 0x1576: 0x3000, 0x1577: 0x3000, + 0x157c: 0x3000, 0x157e: 0x3000, + // Block 0x56, offset 0x1580 + 0x1587: 0x3000, 0x1588: 0x3000, 0x1589: 0x3000, + 0x1597: 0x3000, + 0x159f: 0x3000, + 0x15b0: 0x3000, 0x15b1: 0x3000, 0x15b4: 0x3000, 0x15b5: 0x3000, + 0x15b6: 0x3000, 0x15b7: 0x3000, 0x15b8: 0x3000, 0x15b9: 0x3000, 0x15ba: 0x3000, 0x15bb: 0x3000, + 0x15bc: 0x3000, 0x15bd: 0x3000, 0x15be: 0x3000, 0x15bf: 0x3000, + // Block 0x57, offset 0x15c0 + 0x15c0: 0x3000, 0x15c1: 0x3000, 0x15c2: 0x3000, 0x15c3: 0x3000, 0x15c4: 0x3000, 0x15c5: 0x3000, + 0x15c6: 0x3000, 0x15c7: 0x3000, 0x15c8: 0x3000, 0x15c9: 0x3000, 0x15ca: 0x3000, 0x15cb: 0x3000, + 0x15cc: 0x3000, 0x15cd: 0x3000, 0x15ce: 0x3000, 0x15d0: 0x3000, 0x15d1: 0x3000, + 0x15d2: 0x3000, 0x15d3: 0x3000, 0x15d4: 0x3000, 0x15d5: 0x3000, 0x15d6: 0x3000, 0x15d7: 0x3000, + 0x15d8: 0x3000, 0x15d9: 0x3000, 0x15da: 0x3000, 0x15db: 0x3000, 0x15dc: 0x3000, + 0x15e8: 0x3000, + // Block 0x58, offset 0x1600 + 0x1610: 0x00e6, 0x1611: 0x00e6, + 0x1612: 0x0001, 0x1613: 0x0001, 0x1614: 0x00e6, 0x1615: 0x00e6, 0x1616: 0x00e6, 0x1617: 0x00e6, + 0x1618: 0x0001, 0x1619: 0x0001, 0x161a: 0x0001, 0x161b: 0x00e6, 0x161c: 0x00e6, + 0x1621: 0x00e6, + 0x1625: 0x0001, 0x1626: 0x0001, 0x1627: 0x00e6, 0x1628: 0x00dc, 0x1629: 0x00e6, + 0x162a: 0x0001, 0x162b: 0x0001, 0x162c: 0x00dc, 0x162d: 0x00dc, 0x162e: 0x00dc, 0x162f: 0x00dc, + 0x1630: 0x00e6, + // Block 0x59, offset 0x1640 + 0x1640: 0x3000, 0x1641: 0x3000, 0x1642: 0x3000, 0x1643: 0x3000, 0x1645: 0x3000, + 0x1646: 0x3000, 0x1647: 0x3000, 0x1649: 0x3000, 0x164a: 0x3000, 0x164b: 0x3000, + 0x164c: 0x3000, 0x164d: 0x3000, 0x164e: 0x3000, 0x164f: 0x3000, 0x1650: 0x3000, 0x1651: 0x3000, + 0x1652: 0x3000, 0x1653: 0x3000, 0x1655: 0x3000, 0x1656: 0x3000, + 0x1659: 0x3000, 0x165a: 0x3000, 0x165b: 0x3000, 0x165c: 0x3000, 0x165d: 0x3000, + 0x1660: 0x3000, 0x1661: 0x3000, 0x1662: 0x3000, + 0x1664: 0x3000, 0x1666: 0x3300, 0x1668: 0x3000, + 0x166a: 0x3300, 0x166b: 0x3300, 0x166c: 0x3000, 0x166d: 0x3000, 0x166f: 0x3000, + 0x1670: 0x3000, 0x1671: 0x3000, 0x1673: 0x3000, 0x1674: 0x3000, 0x1675: 0x3000, + 0x1676: 0x3000, 0x1677: 0x3000, 0x1678: 0x3000, 0x1679: 0x3000, 0x167b: 0x3000, + 0x167c: 0x3000, 0x167d: 0x3000, 0x167e: 0x3000, 0x167f: 0x3000, + // Block 0x5a, offset 0x1680 + 0x1680: 0x3000, 0x1685: 0x3000, + 0x1686: 0x3000, 0x1687: 0x3000, 0x1688: 0x3000, 0x1689: 0x3000, + 0x1690: 0x3000, 0x1691: 0x3000, + 0x1692: 0x3000, 0x1693: 0x3000, 0x1694: 0x3000, 0x1695: 0x3000, 0x1696: 0x3000, 0x1697: 0x3000, + 0x1698: 0x3000, 0x1699: 0x3000, 0x169a: 0x3000, 0x169b: 0x3000, 0x169c: 0x3000, 0x169d: 0x3000, + 0x169e: 0x3000, 0x169f: 0x3000, 0x16a0: 0x3000, 0x16a1: 0x3000, 0x16a2: 0x3000, 0x16a3: 0x3000, + 0x16a4: 0x3000, 0x16a5: 0x3000, 0x16a6: 0x3000, 0x16a7: 0x3000, 0x16a8: 0x3000, 0x16a9: 0x3000, + 0x16aa: 0x3000, 0x16ab: 0x3000, 0x16ac: 0x3000, 0x16ad: 0x3000, 0x16ae: 0x3000, 0x16af: 0x3000, + 0x16b0: 0x3000, 0x16b1: 0x3000, 0x16b2: 0x3000, 0x16b3: 0x3000, 0x16b4: 0x3000, 0x16b5: 0x3000, + 0x16b6: 0x3000, 0x16b7: 0x3000, 0x16b8: 0x3000, 0x16b9: 0x3000, 0x16ba: 0x3000, 0x16bb: 0x3000, + 0x16bc: 0x3000, 0x16bd: 0x3000, 0x16be: 0x3000, 0x16bf: 0x3000, + // Block 0x5b, offset 0x16c0 + 0x16c9: 0x3000, + 0x16d0: 0x8800, + 0x16d2: 0x8800, 0x16d4: 0x8800, + 0x16da: 0x1100, 0x16db: 0x1100, + 0x16ee: 0x1100, + // Block 0x5c, offset 0x1700 + 0x170d: 0x1100, 0x170e: 0x1100, 0x170f: 0x1100, 0x1710: 0x8800, + 0x1712: 0x8800, 0x1714: 0x8800, + // Block 0x5d, offset 0x1740 + 0x1743: 0x8800, 0x1744: 0x1100, + 0x1748: 0x8800, 0x1749: 0x1100, 0x174b: 0x8800, + 0x174c: 0x1100, + 0x1763: 0x8800, + 0x1764: 0x1100, 0x1765: 0x8800, 0x1766: 0x1100, + 0x176c: 0x3000, 0x176d: 0x3000, 0x176f: 0x3000, + 0x1770: 0x3000, + 0x177c: 0x8800, + // Block 0x5e, offset 0x1780 + 0x1781: 0x1100, 0x1783: 0x8800, 0x1784: 0x1100, 0x1785: 0x8800, + 0x1787: 0x1100, 0x1788: 0x8800, 0x1789: 0x1100, + 0x178d: 0x8800, + 0x17a0: 0x1100, 0x17a1: 0x8800, 0x17a2: 0x1100, + 0x17a4: 0x8800, 0x17a5: 0x8800, + 0x17ad: 0x1100, 0x17ae: 0x1100, 0x17af: 0x1100, + 0x17b0: 0x1100, 0x17b1: 0x1100, 0x17b2: 0x8800, 0x17b3: 0x8800, 0x17b4: 0x1100, 0x17b5: 0x1100, + 0x17b6: 0x8800, 0x17b7: 0x8800, 0x17b8: 0x1100, 0x17b9: 0x1100, 0x17ba: 0x8800, 0x17bb: 0x8800, + 0x17bc: 0x8800, 0x17bd: 0x8800, + // Block 0x5f, offset 0x17c0 + 0x17c0: 0x1100, 0x17c1: 0x1100, 0x17c2: 0x8800, 0x17c3: 0x8800, 0x17c4: 0x1100, 0x17c5: 0x1100, + 0x17c6: 0x8800, 0x17c7: 0x8800, 0x17c8: 0x1100, 0x17c9: 0x1100, + 0x17d1: 0x8800, + 0x17d2: 0x8800, + 0x17e2: 0x8800, + 0x17e8: 0x8800, 0x17e9: 0x8800, + 0x17eb: 0x8800, 0x17ec: 0x1100, 0x17ed: 0x1100, 0x17ee: 0x1100, 0x17ef: 0x1100, + 0x17f2: 0x8800, 0x17f3: 0x8800, 0x17f4: 0x8800, 0x17f5: 0x8800, + // Block 0x60, offset 0x1800 + 0x1820: 0x1100, 0x1821: 0x1100, 0x1822: 0x1100, 0x1823: 0x1100, + 0x182a: 0x1100, 0x182b: 0x1100, 0x182c: 0x1100, 0x182d: 0x1100, + // Block 0x61, offset 0x1840 + 0x1869: 0x3300, + 0x186a: 0x3300, + // Block 0x62, offset 0x1880 + 0x18a0: 0x3000, 0x18a1: 0x3000, 0x18a2: 0x3000, 0x18a3: 0x3000, + 0x18a4: 0x3000, 0x18a5: 0x3000, 0x18a6: 0x3000, 0x18a7: 0x3000, 0x18a8: 0x3000, 0x18a9: 0x3000, + 0x18aa: 0x3000, 0x18ab: 0x3000, 0x18ac: 0x3000, 0x18ad: 0x3000, 0x18ae: 0x3000, 0x18af: 0x3000, + 0x18b0: 0x3000, 0x18b1: 0x3000, 0x18b2: 0x3000, 0x18b3: 0x3000, 0x18b4: 0x3000, 0x18b5: 0x3000, + 0x18b6: 0x3000, 0x18b7: 0x3000, 0x18b8: 0x3000, 0x18b9: 0x3000, 0x18ba: 0x3000, 0x18bb: 0x3000, + 0x18bc: 0x3000, 0x18bd: 0x3000, 0x18be: 0x3000, 0x18bf: 0x3000, + // Block 0x63, offset 0x18c0 + 0x18c0: 0x3000, 0x18c1: 0x3000, 0x18c2: 0x3000, 0x18c3: 0x3000, 0x18c4: 0x3000, 0x18c5: 0x3000, + 0x18c6: 0x3000, 0x18c7: 0x3000, 0x18c8: 0x3000, 0x18c9: 0x3000, 0x18ca: 0x3000, 0x18cb: 0x3000, + 0x18cc: 0x3000, 0x18cd: 0x3000, 0x18ce: 0x3000, 0x18cf: 0x3000, 0x18d0: 0x3000, 0x18d1: 0x3000, + 0x18d2: 0x3000, 0x18d3: 0x3000, 0x18d4: 0x3000, 0x18d5: 0x3000, 0x18d6: 0x3000, 0x18d7: 0x3000, + 0x18d8: 0x3000, 0x18d9: 0x3000, 0x18da: 0x3000, 0x18db: 0x3000, 0x18dc: 0x3000, 0x18dd: 0x3000, + 0x18de: 0x3000, 0x18df: 0x3000, 0x18e0: 0x3000, 0x18e1: 0x3000, 0x18e2: 0x3000, 0x18e3: 0x3000, + 0x18e4: 0x3000, 0x18e5: 0x3000, 0x18e6: 0x3000, 0x18e7: 0x3000, 0x18e8: 0x3000, 0x18e9: 0x3000, + 0x18ea: 0x3000, 0x18eb: 0x3000, 0x18ec: 0x3000, 0x18ed: 0x3000, 0x18ee: 0x3000, 0x18ef: 0x3000, + 0x18f0: 0x3000, 0x18f1: 0x3000, 0x18f2: 0x3000, 0x18f3: 0x3000, 0x18f4: 0x3000, 0x18f5: 0x3000, + 0x18f6: 0x3000, 0x18f7: 0x3000, 0x18f8: 0x3000, 0x18f9: 0x3000, 0x18fa: 0x3000, 0x18fb: 0x3000, + 0x18fc: 0x3000, 0x18fd: 0x3000, 0x18fe: 0x3000, 0x18ff: 0x3000, + // Block 0x64, offset 0x1900 + 0x1900: 0x3000, 0x1901: 0x3000, 0x1902: 0x3000, 0x1903: 0x3000, 0x1904: 0x3000, 0x1905: 0x3000, + 0x1906: 0x3000, 0x1907: 0x3000, 0x1908: 0x3000, 0x1909: 0x3000, 0x190a: 0x3000, 0x190b: 0x3000, + 0x190c: 0x3000, 0x190d: 0x3000, 0x190e: 0x3000, 0x190f: 0x3000, 0x1910: 0x3000, 0x1911: 0x3000, + 0x1912: 0x3000, 0x1913: 0x3000, 0x1914: 0x3000, 0x1915: 0x3000, 0x1916: 0x3000, 0x1917: 0x3000, + 0x1918: 0x3000, 0x1919: 0x3000, 0x191a: 0x3000, 0x191b: 0x3000, 0x191c: 0x3000, 0x191d: 0x3000, + 0x191e: 0x3000, 0x191f: 0x3000, 0x1920: 0x3000, 0x1921: 0x3000, 0x1922: 0x3000, 0x1923: 0x3000, + 0x1924: 0x3000, 0x1925: 0x3000, 0x1926: 0x3000, 0x1927: 0x3000, 0x1928: 0x3000, 0x1929: 0x3000, + 0x192a: 0x3000, + // Block 0x65, offset 0x1940 + 0x194c: 0x3000, + // Block 0x66, offset 0x1980 + 0x19b4: 0x3000, 0x19b5: 0x3000, + 0x19b6: 0x3000, + // Block 0x67, offset 0x19c0 + 0x19dc: 0x3300, + // Block 0x68, offset 0x1a00 + 0x1a3c: 0x3000, 0x1a3d: 0x3000, + // Block 0x69, offset 0x1a40 + 0x1a6f: 0x00e6, + 0x1a70: 0x00e6, 0x1a71: 0x00e6, + // Block 0x6a, offset 0x1a80 + 0x1aaf: 0x3000, + 0x1abf: 0x0009, + // Block 0x6b, offset 0x1ac0 + 0x1ae0: 0x00e6, 0x1ae1: 0x00e6, 0x1ae2: 0x00e6, 0x1ae3: 0x00e6, + 0x1ae4: 0x00e6, 0x1ae5: 0x00e6, 0x1ae6: 0x00e6, 0x1ae7: 0x00e6, 0x1ae8: 0x00e6, 0x1ae9: 0x00e6, + 0x1aea: 0x00e6, 0x1aeb: 0x00e6, 0x1aec: 0x00e6, 0x1aed: 0x00e6, 0x1aee: 0x00e6, 0x1aef: 0x00e6, + 0x1af0: 0x00e6, 0x1af1: 0x00e6, 0x1af2: 0x00e6, 0x1af3: 0x00e6, 0x1af4: 0x00e6, 0x1af5: 0x00e6, + 0x1af6: 0x00e6, 0x1af7: 0x00e6, 0x1af8: 0x00e6, 0x1af9: 0x00e6, 0x1afa: 0x00e6, 0x1afb: 0x00e6, + 0x1afc: 0x00e6, 0x1afd: 0x00e6, 0x1afe: 0x00e6, 0x1aff: 0x00e6, + // Block 0x6c, offset 0x1b00 + 0x1b1f: 0x3000, + // Block 0x6d, offset 0x1b40 + 0x1b73: 0x3000, + // Block 0x6e, offset 0x1b80 + 0x1b80: 0x3000, 0x1b81: 0x3000, 0x1b82: 0x3000, 0x1b83: 0x3000, 0x1b84: 0x3000, 0x1b85: 0x3000, + 0x1b86: 0x3000, 0x1b87: 0x3000, 0x1b88: 0x3000, 0x1b89: 0x3000, 0x1b8a: 0x3000, 0x1b8b: 0x3000, + 0x1b8c: 0x3000, 0x1b8d: 0x3000, 0x1b8e: 0x3000, 0x1b8f: 0x3000, 0x1b90: 0x3000, 0x1b91: 0x3000, + 0x1b92: 0x3000, 0x1b93: 0x3000, 0x1b94: 0x3000, 0x1b95: 0x3000, + // Block 0x6f, offset 0x1bc0 + 0x1bc0: 0x3000, + 0x1bea: 0x00da, 0x1beb: 0x00e4, 0x1bec: 0x00e8, 0x1bed: 0x00de, 0x1bee: 0x00e0, 0x1bef: 0x00e0, + 0x1bf6: 0x3000, 0x1bf8: 0x3000, 0x1bf9: 0x3000, 0x1bfa: 0x3000, + // Block 0x70, offset 0x1c00 + 0x1c06: 0x8800, 0x1c0b: 0x8800, + 0x1c0c: 0x1100, 0x1c0d: 0x8800, 0x1c0e: 0x1100, 0x1c0f: 0x8800, 0x1c10: 0x1100, 0x1c11: 0x8800, + 0x1c12: 0x1100, 0x1c13: 0x8800, 0x1c14: 0x1100, 0x1c15: 0x8800, 0x1c16: 0x1100, 0x1c17: 0x8800, + 0x1c18: 0x1100, 0x1c19: 0x8800, 0x1c1a: 0x1100, 0x1c1b: 0x8800, 0x1c1c: 0x1100, 0x1c1d: 0x8800, + 0x1c1e: 0x1100, 0x1c1f: 0x8800, 0x1c20: 0x1100, 0x1c21: 0x8800, 0x1c22: 0x1100, + 0x1c24: 0x8800, 0x1c25: 0x1100, 0x1c26: 0x8800, 0x1c27: 0x1100, 0x1c28: 0x8800, 0x1c29: 0x1100, + 0x1c2f: 0x8800, + 0x1c30: 0x1100, 0x1c31: 0x1100, 0x1c32: 0x8800, 0x1c33: 0x1100, 0x1c34: 0x1100, 0x1c35: 0x8800, + 0x1c36: 0x1100, 0x1c37: 0x1100, 0x1c38: 0x8800, 0x1c39: 0x1100, 0x1c3a: 0x1100, 0x1c3b: 0x8800, + 0x1c3c: 0x1100, 0x1c3d: 0x1100, + // Block 0x71, offset 0x1c40 + 0x1c54: 0x1100, + 0x1c59: 0x6608, 0x1c5a: 0x6608, 0x1c5b: 0x3000, 0x1c5c: 0x3000, 0x1c5d: 0x8800, + 0x1c5e: 0x1100, 0x1c5f: 0x3000, + 0x1c66: 0x8800, + 0x1c6b: 0x8800, 0x1c6c: 0x1100, 0x1c6d: 0x8800, 0x1c6e: 0x1100, 0x1c6f: 0x8800, + 0x1c70: 0x1100, 0x1c71: 0x8800, 0x1c72: 0x1100, 0x1c73: 0x8800, 0x1c74: 0x1100, 0x1c75: 0x8800, + 0x1c76: 0x1100, 0x1c77: 0x8800, 0x1c78: 0x1100, 0x1c79: 0x8800, 0x1c7a: 0x1100, 0x1c7b: 0x8800, + 0x1c7c: 0x1100, 0x1c7d: 0x8800, 0x1c7e: 0x1100, 0x1c7f: 0x8800, + // Block 0x72, offset 0x1c80 + 0x1c80: 0x1100, 0x1c81: 0x8800, 0x1c82: 0x1100, 0x1c84: 0x8800, 0x1c85: 0x1100, + 0x1c86: 0x8800, 0x1c87: 0x1100, 0x1c88: 0x8800, 0x1c89: 0x1100, + 0x1c8f: 0x8800, 0x1c90: 0x1100, 0x1c91: 0x1100, + 0x1c92: 0x8800, 0x1c93: 0x1100, 0x1c94: 0x1100, 0x1c95: 0x8800, 0x1c96: 0x1100, 0x1c97: 0x1100, + 0x1c98: 0x8800, 0x1c99: 0x1100, 0x1c9a: 0x1100, 0x1c9b: 0x8800, 0x1c9c: 0x1100, 0x1c9d: 0x1100, + 0x1caf: 0x8800, + 0x1cb0: 0x8800, 0x1cb1: 0x8800, 0x1cb2: 0x8800, 0x1cb4: 0x1100, + 0x1cb7: 0x1100, 0x1cb8: 0x1100, 0x1cb9: 0x1100, 0x1cba: 0x1100, + 0x1cbd: 0x8800, 0x1cbe: 0x1100, 0x1cbf: 0x3000, + // Block 0x73, offset 0x1cc0 + 0x1cf1: 0x3000, 0x1cf2: 0x3000, 0x1cf3: 0x3000, 0x1cf4: 0x3000, 0x1cf5: 0x3000, + 0x1cf6: 0x3000, 0x1cf7: 0x3000, 0x1cf8: 0x3000, 0x1cf9: 0x3000, 0x1cfa: 0x3000, 0x1cfb: 0x3000, + 0x1cfc: 0x3000, 0x1cfd: 0x3000, 0x1cfe: 0x3000, 0x1cff: 0x3000, + // Block 0x74, offset 0x1d00 + 0x1d00: 0x3000, 0x1d01: 0x3000, 0x1d02: 0x3000, 0x1d03: 0x3000, 0x1d04: 0x3000, 0x1d05: 0x3000, + 0x1d06: 0x3000, 0x1d07: 0x3000, 0x1d08: 0x3000, 0x1d09: 0x3000, 0x1d0a: 0x3000, 0x1d0b: 0x3000, + 0x1d0c: 0x3000, 0x1d0d: 0x3000, 0x1d0e: 0x3000, + 0x1d12: 0x3000, 0x1d13: 0x3000, 0x1d14: 0x3000, 0x1d15: 0x3000, 0x1d16: 0x3000, 0x1d17: 0x3000, + 0x1d18: 0x3000, 0x1d19: 0x3000, 0x1d1a: 0x3000, 0x1d1b: 0x3000, 0x1d1c: 0x3000, 0x1d1d: 0x3000, + 0x1d1e: 0x3000, 0x1d1f: 0x3000, + // Block 0x75, offset 0x1d40 + 0x1d40: 0x3000, 0x1d41: 0x3000, 0x1d42: 0x3000, 0x1d43: 0x3000, 0x1d44: 0x3000, 0x1d45: 0x3000, + 0x1d46: 0x3000, 0x1d47: 0x3000, 0x1d48: 0x3000, 0x1d49: 0x3000, 0x1d4a: 0x3000, 0x1d4b: 0x3000, + 0x1d4c: 0x3000, 0x1d4d: 0x3000, 0x1d4e: 0x3000, 0x1d4f: 0x3000, 0x1d50: 0x3000, 0x1d51: 0x3000, + 0x1d52: 0x3000, 0x1d53: 0x3000, 0x1d54: 0x3000, 0x1d55: 0x3000, 0x1d56: 0x3000, 0x1d57: 0x3000, + 0x1d58: 0x3000, 0x1d59: 0x3000, 0x1d5a: 0x3000, 0x1d5b: 0x3000, 0x1d5c: 0x3000, 0x1d5d: 0x3000, + 0x1d5e: 0x3000, 0x1d60: 0x3000, 0x1d61: 0x3000, 0x1d62: 0x3000, 0x1d63: 0x3000, + 0x1d64: 0x3000, 0x1d65: 0x3000, 0x1d66: 0x3000, 0x1d67: 0x3000, 0x1d68: 0x3000, 0x1d69: 0x3000, + 0x1d6a: 0x3000, 0x1d6b: 0x3000, 0x1d6c: 0x3000, 0x1d6d: 0x3000, 0x1d6e: 0x3000, 0x1d6f: 0x3000, + 0x1d70: 0x3000, 0x1d71: 0x3000, 0x1d72: 0x3000, 0x1d73: 0x3000, 0x1d74: 0x3000, 0x1d75: 0x3000, + 0x1d76: 0x3000, 0x1d77: 0x3000, 0x1d78: 0x3000, 0x1d79: 0x3000, 0x1d7a: 0x3000, 0x1d7b: 0x3000, + 0x1d7c: 0x3000, 0x1d7d: 0x3000, 0x1d7e: 0x3000, 0x1d7f: 0x3000, + // Block 0x76, offset 0x1d80 + 0x1d80: 0x3000, 0x1d81: 0x3000, 0x1d82: 0x3000, 0x1d83: 0x3000, 0x1d84: 0x3000, 0x1d85: 0x3000, + 0x1d86: 0x3000, 0x1d87: 0x3000, + 0x1d90: 0x3000, 0x1d91: 0x3000, + 0x1d92: 0x3000, 0x1d93: 0x3000, 0x1d94: 0x3000, 0x1d95: 0x3000, 0x1d96: 0x3000, 0x1d97: 0x3000, + 0x1d98: 0x3000, 0x1d99: 0x3000, 0x1d9a: 0x3000, 0x1d9b: 0x3000, 0x1d9c: 0x3000, 0x1d9d: 0x3000, + 0x1d9e: 0x3000, 0x1d9f: 0x3000, 0x1da0: 0x3000, 0x1da1: 0x3000, 0x1da2: 0x3000, 0x1da3: 0x3000, + 0x1da4: 0x3000, 0x1da5: 0x3000, 0x1da6: 0x3000, 0x1da7: 0x3000, 0x1da8: 0x3000, 0x1da9: 0x3000, + 0x1daa: 0x3000, 0x1dab: 0x3000, 0x1dac: 0x3000, 0x1dad: 0x3000, 0x1dae: 0x3000, 0x1daf: 0x3000, + 0x1db0: 0x3000, 0x1db1: 0x3000, 0x1db2: 0x3000, 0x1db3: 0x3000, 0x1db4: 0x3000, 0x1db5: 0x3000, + 0x1db6: 0x3000, 0x1db7: 0x3000, 0x1db8: 0x3000, 0x1db9: 0x3000, 0x1dba: 0x3000, 0x1dbb: 0x3000, + 0x1dbc: 0x3000, 0x1dbd: 0x3000, 0x1dbe: 0x3000, + // Block 0x77, offset 0x1dc0 + 0x1dc0: 0x3000, 0x1dc1: 0x3000, 0x1dc2: 0x3000, 0x1dc3: 0x3000, 0x1dc4: 0x3000, 0x1dc5: 0x3000, + 0x1dc6: 0x3000, 0x1dc7: 0x3000, 0x1dc8: 0x3000, 0x1dc9: 0x3000, 0x1dca: 0x3000, 0x1dcb: 0x3000, + 0x1dcc: 0x3000, 0x1dcd: 0x3000, 0x1dce: 0x3000, 0x1dcf: 0x3000, 0x1dd0: 0x3000, 0x1dd1: 0x3000, + 0x1dd2: 0x3000, 0x1dd3: 0x3000, 0x1dd4: 0x3000, 0x1dd5: 0x3000, 0x1dd6: 0x3000, 0x1dd7: 0x3000, + 0x1dd8: 0x3000, 0x1dd9: 0x3000, 0x1dda: 0x3000, 0x1ddb: 0x3000, 0x1ddc: 0x3000, 0x1ddd: 0x3000, + 0x1dde: 0x3000, 0x1ddf: 0x3000, 0x1de0: 0x3000, 0x1de1: 0x3000, 0x1de2: 0x3000, 0x1de3: 0x3000, + 0x1de4: 0x3000, 0x1de5: 0x3000, 0x1de6: 0x3000, 0x1de7: 0x3000, 0x1de8: 0x3000, 0x1de9: 0x3000, + 0x1dea: 0x3000, 0x1deb: 0x3000, 0x1dec: 0x3000, 0x1ded: 0x3000, 0x1dee: 0x3000, 0x1def: 0x3000, + 0x1df0: 0x3000, 0x1df1: 0x3000, 0x1df2: 0x3000, 0x1df3: 0x3000, 0x1df4: 0x3000, 0x1df5: 0x3000, + 0x1df6: 0x3000, 0x1df7: 0x3000, 0x1df8: 0x3000, 0x1df9: 0x3000, 0x1dfa: 0x3000, 0x1dfb: 0x3000, + 0x1dfc: 0x3000, 0x1dfd: 0x3000, 0x1dfe: 0x3000, + // Block 0x78, offset 0x1e00 + 0x1e2f: 0x00e6, + 0x1e3c: 0x00e6, 0x1e3d: 0x00e6, + // Block 0x79, offset 0x1e40 + 0x1e70: 0x00e6, 0x1e71: 0x00e6, + // Block 0x7a, offset 0x1e80 + 0x1eb0: 0x3000, + // Block 0x7b, offset 0x1ec0 + 0x1ec6: 0x0009, + // Block 0x7c, offset 0x1f00 + 0x1f04: 0x0009, + 0x1f20: 0x00e6, 0x1f21: 0x00e6, 0x1f22: 0x00e6, 0x1f23: 0x00e6, + 0x1f24: 0x00e6, 0x1f25: 0x00e6, 0x1f26: 0x00e6, 0x1f27: 0x00e6, 0x1f28: 0x00e6, 0x1f29: 0x00e6, + 0x1f2a: 0x00e6, 0x1f2b: 0x00e6, 0x1f2c: 0x00e6, 0x1f2d: 0x00e6, 0x1f2e: 0x00e6, 0x1f2f: 0x00e6, + 0x1f30: 0x00e6, 0x1f31: 0x00e6, + // Block 0x7d, offset 0x1f40 + 0x1f6b: 0x00dc, 0x1f6c: 0x00dc, 0x1f6d: 0x00dc, + // Block 0x7e, offset 0x1f80 + 0x1f93: 0x0009, + // Block 0x7f, offset 0x1fc0 + 0x1ff3: 0x0007, + // Block 0x80, offset 0x2000 + 0x2000: 0x0009, + // Block 0x81, offset 0x2040 + 0x2070: 0x00e6, 0x2072: 0x00e6, 0x2073: 0x00e6, 0x2074: 0x00dc, + 0x2077: 0x00e6, 0x2078: 0x00e6, + 0x207e: 0x00e6, 0x207f: 0x00e6, + // Block 0x82, offset 0x2080 + 0x2081: 0x00e6, + // Block 0x83, offset 0x20c0 + 0x20ed: 0x0009, + // Block 0x84, offset 0x2100 + 0x2100: 0x1100, 0x2101: 0x1100, 0x2102: 0x1100, 0x2103: 0x1100, 0x2104: 0x1100, 0x2105: 0x1100, + 0x2106: 0x1100, 0x2107: 0x1100, 0x2108: 0x1100, 0x2109: 0x1100, 0x210a: 0x1100, 0x210b: 0x1100, + 0x210c: 0x1100, 0x210d: 0x1100, 0x210e: 0x1100, 0x210f: 0x1100, 0x2110: 0x1100, 0x2111: 0x1100, + 0x2112: 0x1100, 0x2113: 0x1100, 0x2114: 0x1100, 0x2115: 0x1100, 0x2116: 0x1100, 0x2117: 0x1100, + 0x2118: 0x1100, 0x2119: 0x1100, 0x211a: 0x1100, 0x211b: 0x1100, 0x211c: 0x1100, 0x211d: 0x1100, + 0x211e: 0x1100, 0x211f: 0x1100, 0x2120: 0x1100, 0x2121: 0x1100, 0x2122: 0x1100, 0x2123: 0x1100, + 0x2124: 0x1100, 0x2125: 0x1100, 0x2126: 0x1100, 0x2127: 0x1100, 0x2128: 0x1100, 0x2129: 0x1100, + 0x212a: 0x1100, 0x212b: 0x1100, 0x212c: 0x1100, 0x212d: 0x1100, 0x212e: 0x1100, 0x212f: 0x1100, + 0x2130: 0x1100, 0x2131: 0x1100, 0x2132: 0x1100, 0x2133: 0x1100, 0x2134: 0x1100, 0x2135: 0x1100, + 0x2136: 0x1100, 0x2137: 0x1100, 0x2138: 0x1100, 0x2139: 0x1100, 0x213a: 0x1100, 0x213b: 0x1100, + 0x213c: 0x1100, 0x213d: 0x1100, 0x213e: 0x1100, 0x213f: 0x1100, + // Block 0x85, offset 0x2140 + 0x2140: 0x1100, 0x2141: 0x1100, 0x2142: 0x1100, 0x2143: 0x1100, 0x2144: 0x1100, 0x2145: 0x1100, + 0x2146: 0x1100, 0x2147: 0x1100, 0x2148: 0x1100, 0x2149: 0x1100, 0x214a: 0x1100, 0x214b: 0x1100, + 0x214c: 0x1100, 0x214d: 0x1100, 0x214e: 0x1100, 0x214f: 0x1100, 0x2150: 0x1100, 0x2151: 0x1100, + 0x2152: 0x1100, 0x2153: 0x1100, 0x2154: 0x1100, 0x2155: 0x1100, 0x2156: 0x1100, 0x2157: 0x1100, + 0x2158: 0x1100, 0x2159: 0x1100, 0x215a: 0x1100, 0x215b: 0x1100, 0x215c: 0x1100, 0x215d: 0x1100, + 0x215e: 0x1100, 0x215f: 0x1100, 0x2160: 0x1100, 0x2161: 0x1100, 0x2162: 0x1100, 0x2163: 0x1100, + // Block 0x86, offset 0x2180 + 0x2180: 0x3300, 0x2181: 0x3300, 0x2182: 0x3300, 0x2183: 0x3300, 0x2184: 0x3300, 0x2185: 0x3300, + 0x2186: 0x3300, 0x2187: 0x3300, 0x2188: 0x3300, 0x2189: 0x3300, 0x218a: 0x3300, 0x218b: 0x3300, + 0x218c: 0x3300, 0x218d: 0x3300, 0x218e: 0x3300, 0x218f: 0x3300, 0x2190: 0x3300, 0x2191: 0x3300, + 0x2192: 0x3300, 0x2193: 0x3300, 0x2194: 0x3300, 0x2195: 0x3300, 0x2196: 0x3300, 0x2197: 0x3300, + 0x2198: 0x3300, 0x2199: 0x3300, 0x219a: 0x3300, 0x219b: 0x3300, 0x219c: 0x3300, 0x219d: 0x3300, + 0x219e: 0x3300, 0x219f: 0x3300, 0x21a0: 0x3300, 0x21a1: 0x3300, 0x21a2: 0x3300, 0x21a3: 0x3300, + 0x21a4: 0x3300, 0x21a5: 0x3300, 0x21a6: 0x3300, 0x21a7: 0x3300, 0x21a8: 0x3300, 0x21a9: 0x3300, + 0x21aa: 0x3300, 0x21ab: 0x3300, 0x21ac: 0x3300, 0x21ad: 0x3300, 0x21ae: 0x3300, 0x21af: 0x3300, + 0x21b0: 0x3300, 0x21b1: 0x3300, 0x21b2: 0x3300, 0x21b3: 0x3300, 0x21b4: 0x3300, 0x21b5: 0x3300, + 0x21b6: 0x3300, 0x21b7: 0x3300, 0x21b8: 0x3300, 0x21b9: 0x3300, 0x21ba: 0x3300, 0x21bb: 0x3300, + 0x21bc: 0x3300, 0x21bd: 0x3300, 0x21be: 0x3300, 0x21bf: 0x3300, + // Block 0x87, offset 0x21c0 + 0x21c0: 0x3300, 0x21c1: 0x3300, 0x21c2: 0x3300, 0x21c3: 0x3300, 0x21c4: 0x3300, 0x21c5: 0x3300, + 0x21c6: 0x3300, 0x21c7: 0x3300, 0x21c8: 0x3300, 0x21c9: 0x3300, 0x21ca: 0x3300, 0x21cb: 0x3300, + 0x21cc: 0x3300, 0x21cd: 0x3300, 0x21d0: 0x3300, + 0x21d2: 0x3300, 0x21d5: 0x3300, 0x21d6: 0x3300, 0x21d7: 0x3300, + 0x21d8: 0x3300, 0x21d9: 0x3300, 0x21da: 0x3300, 0x21db: 0x3300, 0x21dc: 0x3300, 0x21dd: 0x3300, + 0x21de: 0x3300, 0x21e0: 0x3300, 0x21e2: 0x3300, + 0x21e5: 0x3300, 0x21e6: 0x3300, + 0x21ea: 0x3300, 0x21eb: 0x3300, 0x21ec: 0x3300, 0x21ed: 0x3300, + 0x21f0: 0x3300, 0x21f1: 0x3300, 0x21f2: 0x3300, 0x21f3: 0x3300, 0x21f4: 0x3300, 0x21f5: 0x3300, + 0x21f6: 0x3300, 0x21f7: 0x3300, 0x21f8: 0x3300, 0x21f9: 0x3300, 0x21fa: 0x3300, 0x21fb: 0x3300, + 0x21fc: 0x3300, 0x21fd: 0x3300, 0x21fe: 0x3300, 0x21ff: 0x3300, + // Block 0x88, offset 0x2200 + 0x2200: 0x3300, 0x2201: 0x3300, 0x2202: 0x3300, 0x2203: 0x3300, 0x2204: 0x3300, 0x2205: 0x3300, + 0x2206: 0x3300, 0x2207: 0x3300, 0x2208: 0x3300, 0x2209: 0x3300, 0x220a: 0x3300, 0x220b: 0x3300, + 0x220c: 0x3300, 0x220d: 0x3300, 0x220e: 0x3300, 0x220f: 0x3300, 0x2210: 0x3300, 0x2211: 0x3300, + 0x2212: 0x3300, 0x2213: 0x3300, 0x2214: 0x3300, 0x2215: 0x3300, 0x2216: 0x3300, 0x2217: 0x3300, + 0x2218: 0x3300, 0x2219: 0x3300, 0x221a: 0x3300, 0x221b: 0x3300, 0x221c: 0x3300, 0x221d: 0x3300, + 0x221e: 0x3300, 0x221f: 0x3300, 0x2220: 0x3300, 0x2221: 0x3300, 0x2222: 0x3300, 0x2223: 0x3300, + 0x2224: 0x3300, 0x2225: 0x3300, 0x2226: 0x3300, 0x2227: 0x3300, 0x2228: 0x3300, 0x2229: 0x3300, + 0x222a: 0x3300, 0x222b: 0x3300, 0x222c: 0x3300, 0x222d: 0x3300, + 0x2230: 0x3300, 0x2231: 0x3300, 0x2232: 0x3300, 0x2233: 0x3300, 0x2234: 0x3300, 0x2235: 0x3300, + 0x2236: 0x3300, 0x2237: 0x3300, 0x2238: 0x3300, 0x2239: 0x3300, 0x223a: 0x3300, 0x223b: 0x3300, + 0x223c: 0x3300, 0x223d: 0x3300, 0x223e: 0x3300, 0x223f: 0x3300, + // Block 0x89, offset 0x2240 + 0x2240: 0x3300, 0x2241: 0x3300, 0x2242: 0x3300, 0x2243: 0x3300, 0x2244: 0x3300, 0x2245: 0x3300, + 0x2246: 0x3300, 0x2247: 0x3300, 0x2248: 0x3300, 0x2249: 0x3300, 0x224a: 0x3300, 0x224b: 0x3300, + 0x224c: 0x3300, 0x224d: 0x3300, 0x224e: 0x3300, 0x224f: 0x3300, 0x2250: 0x3300, 0x2251: 0x3300, + 0x2252: 0x3300, 0x2253: 0x3300, 0x2254: 0x3300, 0x2255: 0x3300, 0x2256: 0x3300, 0x2257: 0x3300, + 0x2258: 0x3300, 0x2259: 0x3300, + // Block 0x8a, offset 0x2280 + 0x2280: 0x3000, 0x2281: 0x3000, 0x2282: 0x3000, 0x2283: 0x3000, 0x2284: 0x3000, 0x2285: 0x3000, + 0x2286: 0x3000, + 0x2293: 0x3000, 0x2294: 0x3000, 0x2295: 0x3000, 0x2296: 0x3000, 0x2297: 0x3000, + 0x229d: 0x3300, + 0x229e: 0x001a, 0x229f: 0x3300, 0x22a0: 0x3000, 0x22a1: 0x3000, 0x22a2: 0x3000, 0x22a3: 0x3000, + 0x22a4: 0x3000, 0x22a5: 0x3000, 0x22a6: 0x3000, 0x22a7: 0x3000, 0x22a8: 0x3000, 0x22a9: 0x3000, + 0x22aa: 0x3300, 0x22ab: 0x3300, 0x22ac: 0x3300, 0x22ad: 0x3300, 0x22ae: 0x3300, 0x22af: 0x3300, + 0x22b0: 0x3300, 0x22b1: 0x3300, 0x22b2: 0x3300, 0x22b3: 0x3300, 0x22b4: 0x3300, 0x22b5: 0x3300, + 0x22b6: 0x3300, 0x22b8: 0x3300, 0x22b9: 0x3300, 0x22ba: 0x3300, 0x22bb: 0x3300, + 0x22bc: 0x3300, 0x22be: 0x3300, + // Block 0x8b, offset 0x22c0 + 0x22c0: 0x3300, 0x22c1: 0x3300, 0x22c3: 0x3300, 0x22c4: 0x3300, + 0x22c6: 0x3300, 0x22c7: 0x3300, 0x22c8: 0x3300, 0x22c9: 0x3300, 0x22ca: 0x3300, 0x22cb: 0x3300, + 0x22cc: 0x3300, 0x22cd: 0x3300, 0x22ce: 0x3300, 0x22cf: 0x3000, 0x22d0: 0x3000, 0x22d1: 0x3000, + 0x22d2: 0x3000, 0x22d3: 0x3000, 0x22d4: 0x3000, 0x22d5: 0x3000, 0x22d6: 0x3000, 0x22d7: 0x3000, + 0x22d8: 0x3000, 0x22d9: 0x3000, 0x22da: 0x3000, 0x22db: 0x3000, 0x22dc: 0x3000, 0x22dd: 0x3000, + 0x22de: 0x3000, 0x22df: 0x3000, 0x22e0: 0x3000, 0x22e1: 0x3000, 0x22e2: 0x3000, 0x22e3: 0x3000, + 0x22e4: 0x3000, 0x22e5: 0x3000, 0x22e6: 0x3000, 0x22e7: 0x3000, 0x22e8: 0x3000, 0x22e9: 0x3000, + 0x22ea: 0x3000, 0x22eb: 0x3000, 0x22ec: 0x3000, 0x22ed: 0x3000, 0x22ee: 0x3000, 0x22ef: 0x3000, + 0x22f0: 0x3000, 0x22f1: 0x3000, 0x22f2: 0x3000, 0x22f3: 0x3000, 0x22f4: 0x3000, 0x22f5: 0x3000, + 0x22f6: 0x3000, 0x22f7: 0x3000, 0x22f8: 0x3000, 0x22f9: 0x3000, 0x22fa: 0x3000, 0x22fb: 0x3000, + 0x22fc: 0x3000, 0x22fd: 0x3000, 0x22fe: 0x3000, 0x22ff: 0x3000, + // Block 0x8c, offset 0x2300 + 0x2300: 0x3000, 0x2301: 0x3000, 0x2302: 0x3000, 0x2303: 0x3000, 0x2304: 0x3000, 0x2305: 0x3000, + 0x2306: 0x3000, 0x2307: 0x3000, 0x2308: 0x3000, 0x2309: 0x3000, 0x230a: 0x3000, 0x230b: 0x3000, + 0x230c: 0x3000, 0x230d: 0x3000, 0x230e: 0x3000, 0x230f: 0x3000, 0x2310: 0x3000, 0x2311: 0x3000, + 0x2312: 0x3000, 0x2313: 0x3000, 0x2314: 0x3000, 0x2315: 0x3000, 0x2316: 0x3000, 0x2317: 0x3000, + 0x2318: 0x3000, 0x2319: 0x3000, 0x231a: 0x3000, 0x231b: 0x3000, 0x231c: 0x3000, 0x231d: 0x3000, + 0x231e: 0x3000, 0x231f: 0x3000, 0x2320: 0x3000, 0x2321: 0x3000, 0x2322: 0x3000, 0x2323: 0x3000, + 0x2324: 0x3000, 0x2325: 0x3000, 0x2326: 0x3000, 0x2327: 0x3000, 0x2328: 0x3000, 0x2329: 0x3000, + 0x232a: 0x3000, 0x232b: 0x3000, 0x232c: 0x3000, 0x232d: 0x3000, 0x232e: 0x3000, 0x232f: 0x3000, + 0x2330: 0x3000, 0x2331: 0x3000, + // Block 0x8d, offset 0x2340 + 0x2353: 0x3000, 0x2354: 0x3000, 0x2355: 0x3000, 0x2356: 0x3000, 0x2357: 0x3000, + 0x2358: 0x3000, 0x2359: 0x3000, 0x235a: 0x3000, 0x235b: 0x3000, 0x235c: 0x3000, 0x235d: 0x3000, + 0x235e: 0x3000, 0x235f: 0x3000, 0x2360: 0x3000, 0x2361: 0x3000, 0x2362: 0x3000, 0x2363: 0x3000, + 0x2364: 0x3000, 0x2365: 0x3000, 0x2366: 0x3000, 0x2367: 0x3000, 0x2368: 0x3000, 0x2369: 0x3000, + 0x236a: 0x3000, 0x236b: 0x3000, 0x236c: 0x3000, 0x236d: 0x3000, 0x236e: 0x3000, 0x236f: 0x3000, + 0x2370: 0x3000, 0x2371: 0x3000, 0x2372: 0x3000, 0x2373: 0x3000, 0x2374: 0x3000, 0x2375: 0x3000, + 0x2376: 0x3000, 0x2377: 0x3000, 0x2378: 0x3000, 0x2379: 0x3000, 0x237a: 0x3000, 0x237b: 0x3000, + 0x237c: 0x3000, 0x237d: 0x3000, 0x237e: 0x3000, 0x237f: 0x3000, + // Block 0x8e, offset 0x2380 + 0x2380: 0x3000, 0x2381: 0x3000, 0x2382: 0x3000, 0x2383: 0x3000, 0x2384: 0x3000, 0x2385: 0x3000, + 0x2386: 0x3000, 0x2387: 0x3000, 0x2388: 0x3000, 0x2389: 0x3000, 0x238a: 0x3000, 0x238b: 0x3000, + 0x238c: 0x3000, 0x238d: 0x3000, 0x238e: 0x3000, 0x238f: 0x3000, 0x2390: 0x3000, 0x2391: 0x3000, + 0x2392: 0x3000, 0x2393: 0x3000, 0x2394: 0x3000, 0x2395: 0x3000, 0x2396: 0x3000, 0x2397: 0x3000, + 0x2398: 0x3000, 0x2399: 0x3000, 0x239a: 0x3000, 0x239b: 0x3000, 0x239c: 0x3000, 0x239d: 0x3000, + 0x239e: 0x3000, 0x239f: 0x3000, 0x23a0: 0x3000, 0x23a1: 0x3000, 0x23a2: 0x3000, 0x23a3: 0x3000, + 0x23a4: 0x3000, 0x23a5: 0x3000, 0x23a6: 0x3000, 0x23a7: 0x3000, 0x23a8: 0x3000, 0x23a9: 0x3000, + 0x23aa: 0x3000, 0x23ab: 0x3000, 0x23ac: 0x3000, 0x23ad: 0x3000, 0x23ae: 0x3000, 0x23af: 0x3000, + 0x23b0: 0x3000, 0x23b1: 0x3000, 0x23b2: 0x3000, 0x23b3: 0x3000, 0x23b4: 0x3000, 0x23b5: 0x3000, + 0x23b6: 0x3000, 0x23b7: 0x3000, 0x23b8: 0x3000, 0x23b9: 0x3000, 0x23ba: 0x3000, 0x23bb: 0x3000, + 0x23bc: 0x3000, 0x23bd: 0x3000, + // Block 0x8f, offset 0x23c0 + 0x23d0: 0x3000, 0x23d1: 0x3000, + 0x23d2: 0x3000, 0x23d3: 0x3000, 0x23d4: 0x3000, 0x23d5: 0x3000, 0x23d6: 0x3000, 0x23d7: 0x3000, + 0x23d8: 0x3000, 0x23d9: 0x3000, 0x23da: 0x3000, 0x23db: 0x3000, 0x23dc: 0x3000, 0x23dd: 0x3000, + 0x23de: 0x3000, 0x23df: 0x3000, 0x23e0: 0x3000, 0x23e1: 0x3000, 0x23e2: 0x3000, 0x23e3: 0x3000, + 0x23e4: 0x3000, 0x23e5: 0x3000, 0x23e6: 0x3000, 0x23e7: 0x3000, 0x23e8: 0x3000, 0x23e9: 0x3000, + 0x23ea: 0x3000, 0x23eb: 0x3000, 0x23ec: 0x3000, 0x23ed: 0x3000, 0x23ee: 0x3000, 0x23ef: 0x3000, + 0x23f0: 0x3000, 0x23f1: 0x3000, 0x23f2: 0x3000, 0x23f3: 0x3000, 0x23f4: 0x3000, 0x23f5: 0x3000, + 0x23f6: 0x3000, 0x23f7: 0x3000, 0x23f8: 0x3000, 0x23f9: 0x3000, 0x23fa: 0x3000, 0x23fb: 0x3000, + 0x23fc: 0x3000, 0x23fd: 0x3000, 0x23fe: 0x3000, 0x23ff: 0x3000, + // Block 0x90, offset 0x2400 + 0x2400: 0x3000, 0x2401: 0x3000, 0x2402: 0x3000, 0x2403: 0x3000, 0x2404: 0x3000, 0x2405: 0x3000, + 0x2406: 0x3000, 0x2407: 0x3000, 0x2408: 0x3000, 0x2409: 0x3000, 0x240a: 0x3000, 0x240b: 0x3000, + 0x240c: 0x3000, 0x240d: 0x3000, 0x240e: 0x3000, 0x240f: 0x3000, + 0x2412: 0x3000, 0x2413: 0x3000, 0x2414: 0x3000, 0x2415: 0x3000, 0x2416: 0x3000, 0x2417: 0x3000, + 0x2418: 0x3000, 0x2419: 0x3000, 0x241a: 0x3000, 0x241b: 0x3000, 0x241c: 0x3000, 0x241d: 0x3000, + 0x241e: 0x3000, 0x241f: 0x3000, 0x2420: 0x3000, 0x2421: 0x3000, 0x2422: 0x3000, 0x2423: 0x3000, + 0x2424: 0x3000, 0x2425: 0x3000, 0x2426: 0x3000, 0x2427: 0x3000, 0x2428: 0x3000, 0x2429: 0x3000, + 0x242a: 0x3000, 0x242b: 0x3000, 0x242c: 0x3000, 0x242d: 0x3000, 0x242e: 0x3000, 0x242f: 0x3000, + 0x2430: 0x3000, 0x2431: 0x3000, 0x2432: 0x3000, 0x2433: 0x3000, 0x2434: 0x3000, 0x2435: 0x3000, + 0x2436: 0x3000, 0x2437: 0x3000, 0x2438: 0x3000, 0x2439: 0x3000, 0x243a: 0x3000, 0x243b: 0x3000, + 0x243c: 0x3000, 0x243d: 0x3000, 0x243e: 0x3000, 0x243f: 0x3000, + // Block 0x91, offset 0x2440 + 0x2440: 0x3000, 0x2441: 0x3000, 0x2442: 0x3000, 0x2443: 0x3000, 0x2444: 0x3000, 0x2445: 0x3000, + 0x2446: 0x3000, 0x2447: 0x3000, + 0x2470: 0x3000, 0x2471: 0x3000, 0x2472: 0x3000, 0x2473: 0x3000, 0x2474: 0x3000, 0x2475: 0x3000, + 0x2476: 0x3000, 0x2477: 0x3000, 0x2478: 0x3000, 0x2479: 0x3000, 0x247a: 0x3000, 0x247b: 0x3000, + 0x247c: 0x3000, + // Block 0x92, offset 0x2480 + 0x2490: 0x3000, 0x2491: 0x3000, + 0x2492: 0x3000, 0x2493: 0x3000, 0x2494: 0x3000, 0x2495: 0x3000, 0x2496: 0x3000, 0x2497: 0x3000, + 0x2498: 0x3000, 0x2499: 0x3000, + 0x24a0: 0x00e6, 0x24a1: 0x00e6, 0x24a2: 0x00e6, 0x24a3: 0x00e6, + 0x24a4: 0x00e6, 0x24a5: 0x00e6, 0x24a6: 0x00e6, + 0x24b0: 0x3000, 0x24b1: 0x3000, 0x24b2: 0x3000, 0x24b3: 0x3000, 0x24b4: 0x3000, 0x24b5: 0x3000, + 0x24b6: 0x3000, 0x24b7: 0x3000, 0x24b8: 0x3000, 0x24b9: 0x3000, 0x24ba: 0x3000, 0x24bb: 0x3000, + 0x24bc: 0x3000, 0x24bd: 0x3000, 0x24be: 0x3000, 0x24bf: 0x3000, + // Block 0x93, offset 0x24c0 + 0x24c0: 0x3000, 0x24c1: 0x3000, 0x24c2: 0x3000, 0x24c3: 0x3000, 0x24c4: 0x3000, + 0x24c7: 0x3000, 0x24c8: 0x3000, 0x24c9: 0x3000, 0x24ca: 0x3000, 0x24cb: 0x3000, + 0x24cc: 0x3000, 0x24cd: 0x3000, 0x24ce: 0x3000, 0x24cf: 0x3000, 0x24d0: 0x3000, 0x24d1: 0x3000, + 0x24d2: 0x3000, 0x24d4: 0x3000, 0x24d5: 0x3000, 0x24d6: 0x3000, 0x24d7: 0x3000, + 0x24d8: 0x3000, 0x24d9: 0x3000, 0x24da: 0x3000, 0x24db: 0x3000, 0x24dc: 0x3000, 0x24dd: 0x3000, + 0x24de: 0x3000, 0x24df: 0x3000, 0x24e0: 0x3000, 0x24e1: 0x3000, 0x24e2: 0x3000, 0x24e3: 0x3000, + 0x24e4: 0x3000, 0x24e5: 0x3000, 0x24e6: 0x3000, 0x24e8: 0x3000, 0x24e9: 0x3000, + 0x24ea: 0x3000, 0x24eb: 0x3000, + 0x24f0: 0x3000, 0x24f1: 0x3000, 0x24f2: 0x3000, 0x24f4: 0x3000, + 0x24f6: 0x3000, 0x24f7: 0x3000, 0x24f8: 0x3000, 0x24f9: 0x3000, 0x24fa: 0x3000, 0x24fb: 0x3000, + 0x24fc: 0x3000, 0x24fd: 0x3000, 0x24fe: 0x3000, 0x24ff: 0x3000, + // Block 0x94, offset 0x2500 + 0x2500: 0x3000, 0x2501: 0x3000, 0x2502: 0x3000, 0x2503: 0x3000, 0x2504: 0x3000, 0x2505: 0x3000, + 0x2506: 0x3000, 0x2507: 0x3000, 0x2508: 0x3000, 0x2509: 0x3000, 0x250a: 0x3000, 0x250b: 0x3000, + 0x250c: 0x3000, 0x250d: 0x3000, 0x250e: 0x3000, 0x250f: 0x3000, 0x2510: 0x3000, 0x2511: 0x3000, + 0x2512: 0x3000, 0x2513: 0x3000, 0x2514: 0x3000, 0x2515: 0x3000, 0x2516: 0x3000, 0x2517: 0x3000, + 0x2518: 0x3000, 0x2519: 0x3000, 0x251a: 0x3000, 0x251b: 0x3000, 0x251c: 0x3000, 0x251d: 0x3000, + 0x251e: 0x3000, 0x251f: 0x3000, 0x2520: 0x3000, 0x2521: 0x3000, 0x2522: 0x3000, 0x2523: 0x3000, + 0x2524: 0x3000, 0x2525: 0x3000, 0x2526: 0x3000, 0x2527: 0x3000, 0x2528: 0x3000, 0x2529: 0x3000, + 0x252a: 0x3000, 0x252b: 0x3000, 0x252c: 0x3000, 0x252d: 0x3000, 0x252e: 0x3000, 0x252f: 0x3000, + 0x2530: 0x3000, 0x2531: 0x3000, 0x2532: 0x3000, 0x2533: 0x3000, 0x2534: 0x3000, 0x2535: 0x3000, + 0x2536: 0x3000, 0x2537: 0x3000, 0x2538: 0x3000, 0x2539: 0x3000, 0x253a: 0x3000, 0x253b: 0x3000, + 0x253c: 0x3000, + // Block 0x95, offset 0x2540 + 0x2541: 0x3000, 0x2542: 0x3000, 0x2543: 0x3000, 0x2544: 0x3000, 0x2545: 0x3000, + 0x2546: 0x3000, 0x2547: 0x3000, 0x2548: 0x3000, 0x2549: 0x3000, 0x254a: 0x3000, 0x254b: 0x3000, + 0x254c: 0x3000, 0x254d: 0x3000, 0x254e: 0x3000, 0x254f: 0x3000, 0x2550: 0x3000, 0x2551: 0x3000, + 0x2552: 0x3000, 0x2553: 0x3000, 0x2554: 0x3000, 0x2555: 0x3000, 0x2556: 0x3000, 0x2557: 0x3000, + 0x2558: 0x3000, 0x2559: 0x3000, 0x255a: 0x3000, 0x255b: 0x3000, 0x255c: 0x3000, 0x255d: 0x3000, + 0x255e: 0x3000, 0x255f: 0x3000, 0x2560: 0x3000, 0x2561: 0x3000, 0x2562: 0x3000, 0x2563: 0x3000, + 0x2564: 0x3000, 0x2565: 0x3000, 0x2566: 0x3000, 0x2567: 0x3000, 0x2568: 0x3000, 0x2569: 0x3000, + 0x256a: 0x3000, 0x256b: 0x3000, 0x256c: 0x3000, 0x256d: 0x3000, 0x256e: 0x3000, 0x256f: 0x3000, + 0x2570: 0x3000, 0x2571: 0x3000, 0x2572: 0x3000, 0x2573: 0x3000, 0x2574: 0x3000, 0x2575: 0x3000, + 0x2576: 0x3000, 0x2577: 0x3000, 0x2578: 0x3000, 0x2579: 0x3000, 0x257a: 0x3000, 0x257b: 0x3000, + 0x257c: 0x3000, 0x257d: 0x3000, 0x257e: 0x3000, 0x257f: 0x3000, + // Block 0x96, offset 0x2580 + 0x2582: 0x3000, 0x2583: 0x3000, 0x2584: 0x3000, 0x2585: 0x3000, + 0x2586: 0x3000, 0x2587: 0x3000, 0x258a: 0x3000, 0x258b: 0x3000, + 0x258c: 0x3000, 0x258d: 0x3000, 0x258e: 0x3000, 0x258f: 0x3000, + 0x2592: 0x3000, 0x2593: 0x3000, 0x2594: 0x3000, 0x2595: 0x3000, 0x2596: 0x3000, 0x2597: 0x3000, + 0x259a: 0x3000, 0x259b: 0x3000, 0x259c: 0x3000, + 0x25a0: 0x3000, 0x25a1: 0x3000, 0x25a2: 0x3000, 0x25a3: 0x3000, + 0x25a4: 0x3000, 0x25a5: 0x3000, 0x25a6: 0x3000, 0x25a8: 0x3000, 0x25a9: 0x3000, + 0x25aa: 0x3000, 0x25ab: 0x3000, 0x25ac: 0x3000, 0x25ad: 0x3000, 0x25ae: 0x3000, + // Block 0x97, offset 0x25c0 + 0x25fd: 0x00dc, + // Block 0x98, offset 0x2600 + 0x260d: 0x00dc, 0x260f: 0x00e6, + 0x2638: 0x00e6, 0x2639: 0x0001, 0x263a: 0x00dc, + 0x263f: 0x0009, + // Block 0x99, offset 0x2640 + 0x2659: 0x8800, 0x265a: 0x1100, 0x265b: 0x8800, 0x265c: 0x1100, + 0x2665: 0x8800, + 0x266b: 0x1100, + 0x2679: 0x0009, 0x267a: 0x6607, + // Block 0x9a, offset 0x2680 + 0x269e: 0x3300, 0x269f: 0x3300, 0x26a0: 0x3300, 0x26a1: 0x3300, 0x26a2: 0x3300, 0x26a3: 0x3300, + 0x26a4: 0x3300, 0x26a5: 0x00d8, 0x26a6: 0x00d8, 0x26a7: 0x0001, 0x26a8: 0x0001, 0x26a9: 0x0001, + 0x26ad: 0x00e2, 0x26ae: 0x00d8, 0x26af: 0x00d8, + 0x26b0: 0x00d8, 0x26b1: 0x00d8, 0x26b2: 0x00d8, + 0x26bb: 0x00dc, + 0x26bc: 0x00dc, 0x26bd: 0x00dc, 0x26be: 0x00dc, 0x26bf: 0x00dc, + // Block 0x9b, offset 0x26c0 + 0x26c0: 0x00dc, 0x26c1: 0x00dc, 0x26c2: 0x00dc, 0x26c5: 0x00e6, + 0x26c6: 0x00e6, 0x26c7: 0x00e6, 0x26c8: 0x00e6, 0x26c9: 0x00e6, 0x26ca: 0x00dc, 0x26cb: 0x00dc, + 0x26ea: 0x00e6, 0x26eb: 0x00e6, 0x26ec: 0x00e6, 0x26ed: 0x00e6, + 0x26fb: 0x3300, + 0x26fc: 0x3300, 0x26fd: 0x3300, 0x26fe: 0x3300, 0x26ff: 0x3300, + // Block 0x9c, offset 0x2700 + 0x2700: 0x3300, + // Block 0x9d, offset 0x2740 + 0x2742: 0x00e6, 0x2743: 0x00e6, 0x2744: 0x00e6, + // Block 0x9e, offset 0x2780 + 0x2780: 0x3000, 0x2781: 0x3000, 0x2782: 0x3000, 0x2783: 0x3000, 0x2784: 0x3000, 0x2785: 0x3000, + 0x2786: 0x3000, 0x2787: 0x3000, 0x2788: 0x3000, 0x2789: 0x3000, 0x278a: 0x3000, 0x278b: 0x3000, + 0x278c: 0x3000, 0x278d: 0x3000, 0x278e: 0x3000, 0x278f: 0x3000, 0x2790: 0x3000, 0x2791: 0x3000, + 0x2792: 0x3000, 0x2793: 0x3000, 0x2794: 0x3000, 0x2796: 0x3000, 0x2797: 0x3000, + 0x2798: 0x3000, 0x2799: 0x3000, 0x279a: 0x3000, 0x279b: 0x3000, 0x279c: 0x3000, 0x279d: 0x3000, + 0x279e: 0x3000, 0x279f: 0x3000, 0x27a0: 0x3000, 0x27a1: 0x3000, 0x27a2: 0x3000, 0x27a3: 0x3000, + 0x27a4: 0x3000, 0x27a5: 0x3000, 0x27a6: 0x3000, 0x27a7: 0x3000, 0x27a8: 0x3000, 0x27a9: 0x3000, + 0x27aa: 0x3000, 0x27ab: 0x3000, 0x27ac: 0x3000, 0x27ad: 0x3000, 0x27ae: 0x3000, 0x27af: 0x3000, + 0x27b0: 0x3000, 0x27b1: 0x3000, 0x27b2: 0x3000, 0x27b3: 0x3000, 0x27b4: 0x3000, 0x27b5: 0x3000, + 0x27b6: 0x3000, 0x27b7: 0x3000, 0x27b8: 0x3000, 0x27b9: 0x3000, 0x27ba: 0x3000, 0x27bb: 0x3000, + 0x27bc: 0x3000, 0x27bd: 0x3000, 0x27be: 0x3000, 0x27bf: 0x3000, + // Block 0x9f, offset 0x27c0 + 0x27c0: 0x3000, 0x27c1: 0x3000, 0x27c2: 0x3000, 0x27c3: 0x3000, 0x27c4: 0x3000, 0x27c5: 0x3000, + 0x27c6: 0x3000, 0x27c7: 0x3000, 0x27c8: 0x3000, 0x27c9: 0x3000, 0x27ca: 0x3000, 0x27cb: 0x3000, + 0x27cc: 0x3000, 0x27cd: 0x3000, 0x27ce: 0x3000, 0x27cf: 0x3000, 0x27d0: 0x3000, 0x27d1: 0x3000, + 0x27d2: 0x3000, 0x27d3: 0x3000, 0x27d4: 0x3000, 0x27d5: 0x3000, 0x27d6: 0x3000, 0x27d7: 0x3000, + 0x27d8: 0x3000, 0x27d9: 0x3000, 0x27da: 0x3000, 0x27db: 0x3000, 0x27dc: 0x3000, + 0x27de: 0x3000, 0x27df: 0x3000, 0x27e2: 0x3000, + 0x27e5: 0x3000, 0x27e6: 0x3000, 0x27e9: 0x3000, + 0x27ea: 0x3000, 0x27eb: 0x3000, 0x27ec: 0x3000, 0x27ee: 0x3000, 0x27ef: 0x3000, + 0x27f0: 0x3000, 0x27f1: 0x3000, 0x27f2: 0x3000, 0x27f3: 0x3000, 0x27f4: 0x3000, 0x27f5: 0x3000, + 0x27f6: 0x3000, 0x27f7: 0x3000, 0x27f8: 0x3000, 0x27f9: 0x3000, 0x27fb: 0x3000, + 0x27fd: 0x3000, 0x27fe: 0x3000, 0x27ff: 0x3000, + // Block 0xa0, offset 0x2800 + 0x2800: 0x3000, 0x2801: 0x3000, 0x2802: 0x3000, 0x2803: 0x3000, 0x2805: 0x3000, + 0x2806: 0x3000, 0x2807: 0x3000, 0x2808: 0x3000, 0x2809: 0x3000, 0x280a: 0x3000, 0x280b: 0x3000, + 0x280c: 0x3000, 0x280d: 0x3000, 0x280e: 0x3000, 0x280f: 0x3000, 0x2810: 0x3000, 0x2811: 0x3000, + 0x2812: 0x3000, 0x2813: 0x3000, 0x2814: 0x3000, 0x2815: 0x3000, 0x2816: 0x3000, 0x2817: 0x3000, + 0x2818: 0x3000, 0x2819: 0x3000, 0x281a: 0x3000, 0x281b: 0x3000, 0x281c: 0x3000, 0x281d: 0x3000, + 0x281e: 0x3000, 0x281f: 0x3000, 0x2820: 0x3000, 0x2821: 0x3000, 0x2822: 0x3000, 0x2823: 0x3000, + 0x2824: 0x3000, 0x2825: 0x3000, 0x2826: 0x3000, 0x2827: 0x3000, 0x2828: 0x3000, 0x2829: 0x3000, + 0x282a: 0x3000, 0x282b: 0x3000, 0x282c: 0x3000, 0x282d: 0x3000, 0x282e: 0x3000, 0x282f: 0x3000, + 0x2830: 0x3000, 0x2831: 0x3000, 0x2832: 0x3000, 0x2833: 0x3000, 0x2834: 0x3000, 0x2835: 0x3000, + 0x2836: 0x3000, 0x2837: 0x3000, 0x2838: 0x3000, 0x2839: 0x3000, 0x283a: 0x3000, 0x283b: 0x3000, + 0x283c: 0x3000, 0x283d: 0x3000, 0x283e: 0x3000, 0x283f: 0x3000, + // Block 0xa1, offset 0x2840 + 0x2840: 0x3000, 0x2841: 0x3000, 0x2842: 0x3000, 0x2843: 0x3000, 0x2844: 0x3000, 0x2845: 0x3000, + 0x2847: 0x3000, 0x2848: 0x3000, 0x2849: 0x3000, 0x284a: 0x3000, + 0x284d: 0x3000, 0x284e: 0x3000, 0x284f: 0x3000, 0x2850: 0x3000, 0x2851: 0x3000, + 0x2852: 0x3000, 0x2853: 0x3000, 0x2854: 0x3000, 0x2856: 0x3000, 0x2857: 0x3000, + 0x2858: 0x3000, 0x2859: 0x3000, 0x285a: 0x3000, 0x285b: 0x3000, 0x285c: 0x3000, + 0x285e: 0x3000, 0x285f: 0x3000, 0x2860: 0x3000, 0x2861: 0x3000, 0x2862: 0x3000, 0x2863: 0x3000, + 0x2864: 0x3000, 0x2865: 0x3000, 0x2866: 0x3000, 0x2867: 0x3000, 0x2868: 0x3000, 0x2869: 0x3000, + 0x286a: 0x3000, 0x286b: 0x3000, 0x286c: 0x3000, 0x286d: 0x3000, 0x286e: 0x3000, 0x286f: 0x3000, + 0x2870: 0x3000, 0x2871: 0x3000, 0x2872: 0x3000, 0x2873: 0x3000, 0x2874: 0x3000, 0x2875: 0x3000, + 0x2876: 0x3000, 0x2877: 0x3000, 0x2878: 0x3000, 0x2879: 0x3000, 0x287b: 0x3000, + 0x287c: 0x3000, 0x287d: 0x3000, 0x287e: 0x3000, + // Block 0xa2, offset 0x2880 + 0x2880: 0x3000, 0x2881: 0x3000, 0x2882: 0x3000, 0x2883: 0x3000, 0x2884: 0x3000, + 0x2886: 0x3000, 0x288a: 0x3000, 0x288b: 0x3000, + 0x288c: 0x3000, 0x288d: 0x3000, 0x288e: 0x3000, 0x288f: 0x3000, 0x2890: 0x3000, + 0x2892: 0x3000, 0x2893: 0x3000, 0x2894: 0x3000, 0x2895: 0x3000, 0x2896: 0x3000, 0x2897: 0x3000, + 0x2898: 0x3000, 0x2899: 0x3000, 0x289a: 0x3000, 0x289b: 0x3000, 0x289c: 0x3000, 0x289d: 0x3000, + 0x289e: 0x3000, 0x289f: 0x3000, 0x28a0: 0x3000, 0x28a1: 0x3000, 0x28a2: 0x3000, 0x28a3: 0x3000, + 0x28a4: 0x3000, 0x28a5: 0x3000, 0x28a6: 0x3000, 0x28a7: 0x3000, 0x28a8: 0x3000, 0x28a9: 0x3000, + 0x28aa: 0x3000, 0x28ab: 0x3000, 0x28ac: 0x3000, 0x28ad: 0x3000, 0x28ae: 0x3000, 0x28af: 0x3000, + 0x28b0: 0x3000, 0x28b1: 0x3000, 0x28b2: 0x3000, 0x28b3: 0x3000, 0x28b4: 0x3000, 0x28b5: 0x3000, + 0x28b6: 0x3000, 0x28b7: 0x3000, 0x28b8: 0x3000, 0x28b9: 0x3000, 0x28ba: 0x3000, 0x28bb: 0x3000, + 0x28bc: 0x3000, 0x28bd: 0x3000, 0x28be: 0x3000, 0x28bf: 0x3000, + // Block 0xa3, offset 0x28c0 + 0x28c0: 0x3000, 0x28c1: 0x3000, 0x28c2: 0x3000, 0x28c3: 0x3000, 0x28c4: 0x3000, 0x28c5: 0x3000, + 0x28c6: 0x3000, 0x28c7: 0x3000, 0x28c8: 0x3000, 0x28c9: 0x3000, 0x28ca: 0x3000, 0x28cb: 0x3000, + 0x28cc: 0x3000, 0x28cd: 0x3000, 0x28ce: 0x3000, 0x28cf: 0x3000, 0x28d0: 0x3000, 0x28d1: 0x3000, + 0x28d2: 0x3000, 0x28d3: 0x3000, 0x28d4: 0x3000, 0x28d5: 0x3000, 0x28d6: 0x3000, 0x28d7: 0x3000, + 0x28d8: 0x3000, 0x28d9: 0x3000, 0x28da: 0x3000, 0x28db: 0x3000, 0x28dc: 0x3000, 0x28dd: 0x3000, + 0x28de: 0x3000, 0x28df: 0x3000, 0x28e0: 0x3000, 0x28e1: 0x3000, 0x28e2: 0x3000, 0x28e3: 0x3000, + 0x28e4: 0x3000, 0x28e5: 0x3000, 0x28e8: 0x3000, 0x28e9: 0x3000, + 0x28ea: 0x3000, 0x28eb: 0x3000, 0x28ec: 0x3000, 0x28ed: 0x3000, 0x28ee: 0x3000, 0x28ef: 0x3000, + 0x28f0: 0x3000, 0x28f1: 0x3000, 0x28f2: 0x3000, 0x28f3: 0x3000, 0x28f4: 0x3000, 0x28f5: 0x3000, + 0x28f6: 0x3000, 0x28f7: 0x3000, 0x28f8: 0x3000, 0x28f9: 0x3000, 0x28fa: 0x3000, 0x28fb: 0x3000, + 0x28fc: 0x3000, 0x28fd: 0x3000, 0x28fe: 0x3000, 0x28ff: 0x3000, + // Block 0xa4, offset 0x2900 + 0x2900: 0x3000, 0x2901: 0x3000, 0x2902: 0x3000, 0x2903: 0x3000, 0x2904: 0x3000, 0x2905: 0x3000, + 0x2906: 0x3000, 0x2907: 0x3000, 0x2908: 0x3000, 0x2909: 0x3000, 0x290a: 0x3000, 0x290b: 0x3000, + 0x290e: 0x3000, 0x290f: 0x3000, 0x2910: 0x3000, 0x2911: 0x3000, + 0x2912: 0x3000, 0x2913: 0x3000, 0x2914: 0x3000, 0x2915: 0x3000, 0x2916: 0x3000, 0x2917: 0x3000, + 0x2918: 0x3000, 0x2919: 0x3000, 0x291a: 0x3000, 0x291b: 0x3000, 0x291c: 0x3000, 0x291d: 0x3000, + 0x291e: 0x3000, 0x291f: 0x3000, 0x2920: 0x3000, 0x2921: 0x3000, 0x2922: 0x3000, 0x2923: 0x3000, + 0x2924: 0x3000, 0x2925: 0x3000, 0x2926: 0x3000, 0x2927: 0x3000, 0x2928: 0x3000, 0x2929: 0x3000, + 0x292a: 0x3000, 0x292b: 0x3000, 0x292c: 0x3000, 0x292d: 0x3000, 0x292e: 0x3000, 0x292f: 0x3000, + 0x2930: 0x3000, 0x2931: 0x3000, 0x2932: 0x3000, 0x2933: 0x3000, 0x2934: 0x3000, 0x2935: 0x3000, + 0x2936: 0x3000, 0x2937: 0x3000, 0x2938: 0x3000, 0x2939: 0x3000, 0x293a: 0x3000, 0x293b: 0x3000, + 0x293c: 0x3000, 0x293d: 0x3000, 0x293e: 0x3000, 0x293f: 0x3000, + // Block 0xa5, offset 0x2940 + 0x2940: 0x3000, 0x2941: 0x3000, 0x2942: 0x3000, 0x2943: 0x3000, 0x2944: 0x3000, 0x2945: 0x3000, + 0x2946: 0x3000, 0x2947: 0x3000, 0x2948: 0x3000, 0x2949: 0x3000, 0x294a: 0x3000, + 0x2950: 0x3000, 0x2951: 0x3000, + 0x2952: 0x3000, 0x2953: 0x3000, 0x2954: 0x3000, 0x2955: 0x3000, 0x2956: 0x3000, 0x2957: 0x3000, + 0x2958: 0x3000, 0x2959: 0x3000, 0x295a: 0x3000, 0x295b: 0x3000, 0x295c: 0x3000, 0x295d: 0x3000, + 0x295e: 0x3000, 0x295f: 0x3000, 0x2960: 0x3000, 0x2961: 0x3000, 0x2962: 0x3000, 0x2963: 0x3000, + 0x2964: 0x3000, 0x2965: 0x3000, 0x2966: 0x3000, 0x2967: 0x3000, 0x2968: 0x3000, 0x2969: 0x3000, + 0x296a: 0x3000, 0x296b: 0x3000, 0x296c: 0x3000, 0x296d: 0x3000, 0x296e: 0x3000, + 0x2970: 0x3000, 0x2971: 0x3000, 0x2972: 0x3000, 0x2973: 0x3000, 0x2974: 0x3000, 0x2975: 0x3000, + 0x2976: 0x3000, 0x2977: 0x3000, 0x2978: 0x3000, 0x2979: 0x3000, 0x297a: 0x3000, 0x297b: 0x3000, + 0x297c: 0x3000, 0x297d: 0x3000, 0x297e: 0x3000, 0x297f: 0x3000, + // Block 0xa6, offset 0x2980 + 0x2980: 0x3000, 0x2981: 0x3000, 0x2982: 0x3000, 0x2983: 0x3000, 0x2984: 0x3000, 0x2985: 0x3000, + 0x2986: 0x3000, 0x2987: 0x3000, 0x2988: 0x3000, 0x2989: 0x3000, 0x298a: 0x3000, 0x298b: 0x3000, + 0x298c: 0x3000, 0x298d: 0x3000, 0x298e: 0x3000, 0x298f: 0x3000, + // Block 0xa7, offset 0x29c0 + 0x29d0: 0x3000, + // Block 0xa8, offset 0x2a00 + 0x2a00: 0x3000, 0x2a01: 0x3000, 0x2a02: 0x3000, + 0x2a10: 0x3000, 0x2a11: 0x3000, + 0x2a12: 0x3000, 0x2a13: 0x3000, 0x2a14: 0x3000, 0x2a15: 0x3000, 0x2a16: 0x3000, 0x2a17: 0x3000, + 0x2a18: 0x3000, 0x2a19: 0x3000, 0x2a1a: 0x3000, 0x2a1b: 0x3000, 0x2a1c: 0x3000, 0x2a1d: 0x3000, + 0x2a1e: 0x3000, 0x2a1f: 0x3000, 0x2a20: 0x3000, 0x2a21: 0x3000, 0x2a22: 0x3000, 0x2a23: 0x3000, + 0x2a24: 0x3000, 0x2a25: 0x3000, 0x2a26: 0x3000, 0x2a27: 0x3000, 0x2a28: 0x3000, 0x2a29: 0x3000, + 0x2a2a: 0x3000, 0x2a2b: 0x3000, 0x2a2c: 0x3000, 0x2a2d: 0x3000, 0x2a2e: 0x3000, 0x2a2f: 0x3000, + 0x2a30: 0x3000, 0x2a31: 0x3000, 0x2a32: 0x3000, 0x2a33: 0x3000, 0x2a34: 0x3000, 0x2a35: 0x3000, + 0x2a36: 0x3000, 0x2a37: 0x3000, 0x2a38: 0x3000, 0x2a39: 0x3000, 0x2a3a: 0x3000, + // Block 0xa9, offset 0x2a40 + 0x2a40: 0x3000, 0x2a41: 0x3000, 0x2a42: 0x3000, 0x2a43: 0x3000, 0x2a44: 0x3000, 0x2a45: 0x3000, + 0x2a46: 0x3000, 0x2a47: 0x3000, 0x2a48: 0x3000, + 0x2a50: 0x3000, 0x2a51: 0x3000, + // Block 0xaa, offset 0x2a80 + 0x2a80: 0x3300, 0x2a81: 0x3300, 0x2a82: 0x3300, 0x2a83: 0x3300, 0x2a84: 0x3300, 0x2a85: 0x3300, + 0x2a86: 0x3300, 0x2a87: 0x3300, 0x2a88: 0x3300, 0x2a89: 0x3300, 0x2a8a: 0x3300, 0x2a8b: 0x3300, + 0x2a8c: 0x3300, 0x2a8d: 0x3300, 0x2a8e: 0x3300, 0x2a8f: 0x3300, 0x2a90: 0x3300, 0x2a91: 0x3300, + 0x2a92: 0x3300, 0x2a93: 0x3300, 0x2a94: 0x3300, 0x2a95: 0x3300, 0x2a96: 0x3300, 0x2a97: 0x3300, + 0x2a98: 0x3300, 0x2a99: 0x3300, 0x2a9a: 0x3300, 0x2a9b: 0x3300, 0x2a9c: 0x3300, 0x2a9d: 0x3300, +} + +// charInfoLookup: 1152 bytes +// Block 0 is the null block. +var charInfoLookup = [1152]uint8{ + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0x0c2: 0x03, 0x0c3: 0x04, 0x0c4: 0x05, 0x0c5: 0x06, 0x0c6: 0x07, 0x0c7: 0x08, + 0x0c8: 0x09, 0x0ca: 0x0a, 0x0cb: 0x0b, 0x0cc: 0x0c, 0x0cd: 0x0d, 0x0ce: 0x0e, 0x0cf: 0x0f, + 0x0d0: 0x10, 0x0d1: 0x11, 0x0d2: 0x12, 0x0d3: 0x13, 0x0d6: 0x14, 0x0d7: 0x15, + 0x0d8: 0x16, 0x0d9: 0x17, 0x0db: 0x18, 0x0dc: 0x19, 0x0dd: 0x1a, 0x0df: 0x1b, + 0x0e0: 0x04, 0x0e1: 0x05, 0x0e2: 0x06, 0x0e3: 0x07, + 0x0ea: 0x08, 0x0eb: 0x09, 0x0ec: 0x09, 0x0ed: 0x0a, 0x0ef: 0x0b, + 0x0f0: 0x11, + // Block 0x4, offset 0x100 + 0x120: 0x1c, 0x121: 0x1d, 0x124: 0x1e, 0x125: 0x1f, 0x126: 0x20, 0x127: 0x21, + 0x128: 0x22, 0x129: 0x23, 0x12a: 0x24, 0x12b: 0x25, 0x12c: 0x20, 0x12d: 0x26, 0x12e: 0x27, 0x12f: 0x28, + 0x131: 0x29, 0x132: 0x2a, 0x133: 0x2b, 0x134: 0x2c, 0x135: 0x28, 0x137: 0x2d, + 0x138: 0x2e, 0x139: 0x2f, 0x13a: 0x30, 0x13b: 0x31, 0x13c: 0x32, 0x13d: 0x33, 0x13e: 0x34, 0x13f: 0x35, + // Block 0x5, offset 0x140 + 0x140: 0x36, 0x142: 0x37, 0x143: 0x38, 0x145: 0x39, 0x146: 0x3a, 0x147: 0x3b, + 0x14d: 0x3c, + 0x15c: 0x3d, 0x15f: 0x3e, + 0x162: 0x3f, 0x164: 0x40, + 0x168: 0x41, 0x169: 0x42, 0x16c: 0x43, 0x16d: 0x44, 0x16e: 0x45, 0x16f: 0x46, + 0x170: 0x47, 0x173: 0x48, 0x174: 0x49, 0x175: 0x4a, 0x176: 0x4b, 0x177: 0x4c, + 0x178: 0x4d, 0x179: 0x4e, 0x17a: 0x4f, 0x17b: 0x50, 0x17c: 0x51, 0x17d: 0x52, 0x17e: 0x53, 0x17f: 0x54, + // Block 0x6, offset 0x180 + 0x180: 0x55, 0x181: 0x56, 0x182: 0x57, 0x183: 0x58, 0x184: 0x59, 0x185: 0x5a, 0x186: 0x5b, 0x187: 0x5c, + 0x188: 0x5d, 0x189: 0x5e, 0x18a: 0x5f, 0x18b: 0x60, 0x18c: 0x61, + 0x191: 0x62, 0x192: 0x63, 0x193: 0x64, + 0x1a8: 0x65, 0x1a9: 0x66, 0x1ab: 0x67, + 0x1b1: 0x68, 0x1b3: 0x69, 0x1b5: 0x6a, 0x1b7: 0x6b, + 0x1ba: 0x6c, 0x1bb: 0x6d, 0x1bc: 0x63, 0x1bd: 0x63, 0x1be: 0x63, 0x1bf: 0x6e, + // Block 0x7, offset 0x1c0 + 0x1c0: 0x6f, 0x1c1: 0x70, 0x1c2: 0x71, 0x1c3: 0x72, 0x1c4: 0x73, 0x1c5: 0x63, 0x1c6: 0x74, + 0x1c8: 0x75, 0x1c9: 0x76, 0x1ca: 0x63, 0x1cb: 0x77, 0x1cc: 0x63, 0x1cd: 0x63, 0x1ce: 0x63, 0x1cf: 0x63, + // Block 0x8, offset 0x200 + 0x219: 0x78, 0x21b: 0x79, 0x21d: 0x7a, + 0x220: 0x7b, 0x223: 0x7c, 0x224: 0x7d, 0x225: 0x7e, 0x226: 0x7f, 0x227: 0x80, + 0x22a: 0x81, 0x22b: 0x82, 0x22f: 0x83, + 0x230: 0x84, 0x231: 0x84, 0x232: 0x84, 0x233: 0x84, 0x234: 0x84, 0x235: 0x84, 0x236: 0x84, 0x237: 0x84, + 0x238: 0x84, 0x239: 0x84, 0x23a: 0x84, 0x23b: 0x84, 0x23c: 0x84, 0x23d: 0x84, 0x23e: 0x84, 0x23f: 0x84, + // Block 0x9, offset 0x240 + 0x240: 0x84, 0x241: 0x84, 0x242: 0x84, 0x243: 0x84, 0x244: 0x84, 0x245: 0x84, 0x246: 0x84, 0x247: 0x84, + 0x248: 0x84, 0x249: 0x84, 0x24a: 0x84, 0x24b: 0x84, 0x24c: 0x84, 0x24d: 0x84, 0x24e: 0x84, 0x24f: 0x84, + 0x250: 0x84, 0x251: 0x84, 0x252: 0x84, 0x253: 0x84, 0x254: 0x84, 0x255: 0x84, 0x256: 0x84, 0x257: 0x84, + 0x258: 0x84, 0x259: 0x84, 0x25a: 0x84, 0x25b: 0x84, 0x25c: 0x84, 0x25d: 0x84, 0x25e: 0x84, 0x25f: 0x84, + 0x260: 0x84, 0x261: 0x84, 0x262: 0x84, 0x263: 0x84, 0x264: 0x84, 0x265: 0x84, 0x266: 0x84, 0x267: 0x84, + 0x268: 0x84, 0x269: 0x84, 0x26a: 0x84, 0x26b: 0x84, 0x26c: 0x84, 0x26d: 0x84, 0x26e: 0x84, 0x26f: 0x84, + 0x270: 0x84, 0x271: 0x84, 0x272: 0x84, 0x273: 0x84, 0x274: 0x84, 0x275: 0x84, 0x276: 0x84, 0x277: 0x84, + 0x278: 0x84, 0x279: 0x84, 0x27a: 0x84, 0x27b: 0x84, 0x27c: 0x84, 0x27d: 0x84, 0x27e: 0x84, 0x27f: 0x84, + // Block 0xa, offset 0x280 + 0x280: 0x84, 0x281: 0x84, 0x282: 0x84, 0x283: 0x84, 0x284: 0x84, 0x285: 0x84, 0x286: 0x84, 0x287: 0x84, + 0x288: 0x84, 0x289: 0x84, 0x28a: 0x84, 0x28b: 0x84, 0x28c: 0x84, 0x28d: 0x84, 0x28e: 0x84, 0x28f: 0x84, + 0x290: 0x84, 0x291: 0x84, 0x292: 0x84, 0x293: 0x84, 0x294: 0x84, 0x295: 0x84, 0x296: 0x84, 0x297: 0x84, + 0x298: 0x84, 0x299: 0x84, 0x29a: 0x84, 0x29b: 0x84, 0x29c: 0x84, 0x29d: 0x84, 0x29e: 0x85, + // Block 0xb, offset 0x2c0 + 0x2e4: 0x86, 0x2e5: 0x86, 0x2e6: 0x86, 0x2e7: 0x86, + 0x2e8: 0x87, 0x2e9: 0x88, 0x2ea: 0x86, 0x2eb: 0x89, 0x2ec: 0x8a, 0x2ed: 0x8b, 0x2ee: 0x8c, 0x2ef: 0x8d, + 0x2f0: 0x63, 0x2f1: 0x63, 0x2f2: 0x63, 0x2f3: 0x63, 0x2f4: 0x8e, 0x2f5: 0x8f, 0x2f6: 0x90, 0x2f7: 0x91, + 0x2f8: 0x92, 0x2f9: 0x93, 0x2fa: 0x63, 0x2fb: 0x94, 0x2fc: 0x95, 0x2fd: 0x63, 0x2fe: 0x77, 0x2ff: 0x96, + // Block 0xc, offset 0x300 + 0x307: 0x97, + 0x328: 0x98, + // Block 0xd, offset 0x340 + 0x341: 0x7b, 0x342: 0x99, + // Block 0xe, offset 0x380 + 0x385: 0x9a, 0x386: 0x9b, 0x387: 0x9c, + 0x389: 0x9d, + 0x390: 0x63, 0x391: 0x9e, 0x392: 0x9f, 0x393: 0xa0, 0x394: 0xa1, 0x395: 0xa2, 0x396: 0x63, 0x397: 0x63, + 0x398: 0x63, 0x399: 0x63, 0x39a: 0xa3, 0x39b: 0x63, 0x39c: 0x63, 0x39d: 0x63, 0x39e: 0x63, 0x39f: 0xa4, + // Block 0xf, offset 0x3c0 + 0x3c4: 0xa5, 0x3c5: 0xa6, 0x3c6: 0xa7, + 0x3c8: 0xa8, 0x3c9: 0xa9, + // Block 0x10, offset 0x400 + 0x420: 0x86, 0x421: 0x86, 0x422: 0x86, 0x423: 0x86, 0x424: 0x86, 0x425: 0x86, 0x426: 0x86, 0x427: 0x86, + 0x428: 0xaa, + // Block 0x11, offset 0x440 + 0x450: 0x0c, 0x451: 0x0d, + 0x45d: 0x0e, 0x45f: 0x0f, + 0x46f: 0x10, +} + +var charInfoTrie = trie{charInfoLookup[:], charInfoValues[:]} + +// Total size of tables: 78KB (80234 bytes) diff --git a/libgo/go/exp/norm/trie.go b/libgo/go/exp/norm/trie.go new file mode 100644 index 0000000..6b65401 --- /dev/null +++ b/libgo/go/exp/norm/trie.go @@ -0,0 +1,234 @@ +// 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 norm + +type trie struct { + index []uint8 + values []uint16 +} + +const ( + t1 = 0x00 // 0000 0000 + tx = 0x80 // 1000 0000 + t2 = 0xC0 // 1100 0000 + t3 = 0xE0 // 1110 0000 + t4 = 0xF0 // 1111 0000 + t5 = 0xF8 // 1111 1000 + t6 = 0xFC // 1111 1100 + te = 0xFE // 1111 1110 + + maskx = 0x3F // 0011 1111 + mask2 = 0x1F // 0001 1111 + mask3 = 0x0F // 0000 1111 + mask4 = 0x07 // 0000 0111 +) + +// lookup returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func (t *trie) lookup(s []byte) (v uint16, sz int) { + c0 := s[0] + switch { + case c0 < tx: + return t.values[c0], 1 + case c0 < t2: + return 0, 1 + case c0 < t3: + if len(s) < 2 { + return 0, 0 + } + i := t.index[c0] + c1 := s[1] + if c1 < tx || t2 <= c1 { + return 0, 1 + } + o := uint16(i)<<6 + uint16(c1)&maskx + return t.values[o], 2 + case c0 < t4: + if len(s) < 3 { + return 0, 0 + } + i := t.index[c0] + c1 := s[1] + if c1 < tx || t2 <= c1 { + return 0, 1 + } + o := uint16(i)<<6 + uint16(c1)&maskx + i = t.index[o] + c2 := s[2] + if c2 < tx || t2 <= c2 { + return 0, 2 + } + o = uint16(i)<<6 + uint16(c2)&maskx + return t.values[o], 3 + case c0 < t5: + if len(s) < 4 { + return 0, 0 + } + i := t.index[c0] + c1 := s[1] + if c1 < tx || t2 <= c1 { + return 0, 1 + } + o := uint16(i)<<6 + uint16(c1)&maskx + i = t.index[o] + c2 := s[2] + if c2 < tx || t2 <= c2 { + return 0, 2 + } + o = uint16(i)<<6 + uint16(c2)&maskx + i = t.index[o] + c3 := s[3] + if c3 < tx || t2 <= c3 { + return 0, 3 + } + o = uint16(i)<<6 + uint16(c3)&maskx + return t.values[o], 4 + case c0 < t6: + if len(s) < 5 { + return 0, 0 + } + return 0, 5 + case c0 < te: + if len(s) < 6 { + return 0, 0 + } + return 0, 6 + } + // Illegal rune + return 0, 1 +} + +// lookupString returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func (t *trie) lookupString(s string) (v uint16, sz int) { + c0 := s[0] + switch { + case c0 < tx: + return t.values[c0], 1 + case c0 < t2: + return 0, 1 + case c0 < t3: + if len(s) < 2 { + return 0, 0 + } + i := t.index[c0] + c1 := s[1] + if c1 < tx || t2 <= c1 { + return 0, 1 + } + o := uint16(i)<<6 + uint16(c1)&maskx + return t.values[o], 2 + case c0 < t4: + if len(s) < 3 { + return 0, 0 + } + i := t.index[c0] + c1 := s[1] + if c1 < tx || t2 <= c1 { + return 0, 1 + } + o := uint16(i)<<6 + uint16(c1)&maskx + i = t.index[o] + c2 := s[2] + if c2 < tx || t2 <= c2 { + return 0, 2 + } + o = uint16(i)<<6 + uint16(c2)&maskx + return t.values[o], 3 + case c0 < t5: + if len(s) < 4 { + return 0, 0 + } + i := t.index[c0] + c1 := s[1] + if c1 < tx || t2 <= c1 { + return 0, 1 + } + o := uint16(i)<<6 + uint16(c1)&maskx + i = t.index[o] + c2 := s[2] + if c2 < tx || t2 <= c2 { + return 0, 2 + } + o = uint16(i)<<6 + uint16(c2)&maskx + i = t.index[o] + c3 := s[3] + if c3 < tx || t2 <= c3 { + return 0, 3 + } + o = uint16(i)<<6 + uint16(c3)&maskx + return t.values[o], 4 + case c0 < t6: + if len(s) < 5 { + return 0, 0 + } + return 0, 5 + case c0 < te: + if len(s) < 6 { + return 0, 0 + } + return 0, 6 + } + // Illegal rune + return 0, 1 +} + +// lookupUnsafe returns the trie value for the first UTF-8 encoding in s. +// s must hold a full encoding. +func (t *trie) lookupUnsafe(s []byte) uint16 { + c0 := s[0] + if c0 < tx { + return t.values[c0] + } + if c0 < t2 { + return 0 + } + i := t.index[c0] + o := uint16(i)<<6 + uint16(s[1])&maskx + if c0 < t3 { + return t.values[o] + } + i = t.index[o] + o = uint16(i)<<6 + uint16(s[2])&maskx + if c0 < t4 { + return t.values[o] + } + i = t.index[o] + o = uint16(i)<<6 + uint16(s[3])&maskx + if c0 < t5 { + return t.values[o] + } + return 0 +} + +// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s. +// s must hold a full encoding. +func (t *trie) lookupStringUnsafe(s string) uint16 { + c0 := s[0] + if c0 < tx { + return t.values[c0] + } + if c0 < t2 { + return 0 + } + i := t.index[c0] + o := uint16(i)<<6 + uint16(s[1])&maskx + if c0 < t3 { + return t.values[o] + } + i = t.index[o] + o = uint16(i)<<6 + uint16(s[2])&maskx + if c0 < t4 { + return t.values[o] + } + i = t.index[o] + o = uint16(i)<<6 + uint16(s[3])&maskx + if c0 < t5 { + return t.values[o] + } + return 0 +} diff --git a/libgo/go/exp/norm/trie_test.go b/libgo/go/exp/norm/trie_test.go new file mode 100644 index 0000000..ad87d97 --- /dev/null +++ b/libgo/go/exp/norm/trie_test.go @@ -0,0 +1,107 @@ +package norm + +import ( + "testing" + "utf8" +) + +// Test data is located in triedata_test.go; generated by maketesttables. +var testdata = testdataTrie + +// Test cases for illegal runes. +type trietest struct { + size int + bytes []byte +} + +var tests = []trietest{ + // illegal runes + {1, []byte{0x80}}, + {1, []byte{0xFF}}, + {1, []byte{t2, tx - 1}}, + {1, []byte{t2, t2}}, + {2, []byte{t3, tx, tx - 1}}, + {2, []byte{t3, tx, t2}}, + {1, []byte{t3, tx - 1, tx}}, + {3, []byte{t4, tx, tx, tx - 1}}, + {3, []byte{t4, tx, tx, t2}}, + {1, []byte{t4, t2, tx, tx - 1}}, + {2, []byte{t4, tx, t2, tx - 1}}, + + // short runes + {0, []byte{t2}}, + {0, []byte{t3, tx}}, + {0, []byte{t4, tx, tx}}, + {0, []byte{t5, tx, tx, tx}}, + {0, []byte{t6, tx, tx, tx, tx}}, +} + +func mkUtf8(rune int) ([]byte, int) { + var b [utf8.UTFMax]byte + sz := utf8.EncodeRune(b[:], rune) + return b[:sz], sz +} + +func TestLookup(t *testing.T) { + for i, tt := range testRunes { + b, szg := mkUtf8(tt) + v, szt := testdata.lookup(b) + if int(v) != i { + t.Errorf("lookup(%U): found value %#x, expected %#x", i, v, i) + } + if szt != szg { + t.Errorf("lookup(%U): found size %d, expected %d", i, szt, szg) + } + } + for i, tt := range tests { + v, sz := testdata.lookup(tt.bytes) + if int(v) != 0 { + t.Errorf("lookup of illegal rune, case %d: found value %#x, expected 0", i, v) + } + if sz != tt.size { + t.Errorf("lookup of illegal rune, case %d: found size %d, expected %d", i, sz, tt.size) + } + } +} + +func TestLookupUnsafe(t *testing.T) { + for i, tt := range testRunes { + b, _ := mkUtf8(tt) + v := testdata.lookupUnsafe(b) + if int(v) != i { + t.Errorf("lookupUnsafe(%U): found value %#x, expected %#x", i, v, i) + } + } +} + +func TestLookupString(t *testing.T) { + for i, tt := range testRunes { + b, szg := mkUtf8(tt) + v, szt := testdata.lookupString(string(b)) + if int(v) != i { + t.Errorf("lookup(%U): found value %#x, expected %#x", i, v, i) + } + if szt != szg { + t.Errorf("lookup(%U): found size %d, expected %d", i, szt, szg) + } + } + for i, tt := range tests { + v, sz := testdata.lookupString(string(tt.bytes)) + if int(v) != 0 { + t.Errorf("lookup of illegal rune, case %d: found value %#x, expected 0", i, v) + } + if sz != tt.size { + t.Errorf("lookup of illegal rune, case %d: found size %d, expected %d", i, sz, tt.size) + } + } +} + +func TestLookupStringUnsafe(t *testing.T) { + for i, tt := range testRunes { + b, _ := mkUtf8(tt) + v := testdata.lookupStringUnsafe(string(b)) + if int(v) != i { + t.Errorf("lookupUnsafe(%U): found value %#x, expected %#x", i, v, i) + } + } +} diff --git a/libgo/go/exp/norm/triedata_test.go b/libgo/go/exp/norm/triedata_test.go new file mode 100644 index 0000000..f886e60 --- /dev/null +++ b/libgo/go/exp/norm/triedata_test.go @@ -0,0 +1,63 @@ +// Generated by running +// maketesttables +// DO NOT EDIT + +package norm + +var testRunes = []int{1, 12, 127, 128, 256, 2047, 2048, 2457, 65535, 65536, 65793, 1114111} + +// testdataValues: 768 entries, 1536 bytes +// Block 2 is the null block. +var testdataValues = [768]uint16{ + // Block 0x0, offset 0x0 + 0x000c: 0x0001, + // Block 0x1, offset 0x40 + 0x007f: 0x0002, + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0x00c0: 0x0003, + // Block 0x4, offset 0x100 + 0x0100: 0x0004, + // Block 0x5, offset 0x140 + 0x017f: 0x0005, + // Block 0x6, offset 0x180 + 0x0180: 0x0006, + // Block 0x7, offset 0x1c0 + 0x01d9: 0x0007, + // Block 0x8, offset 0x200 + 0x023f: 0x0008, + // Block 0x9, offset 0x240 + 0x0240: 0x0009, + // Block 0xa, offset 0x280 + 0x0281: 0x000a, + // Block 0xb, offset 0x2c0 + 0x02ff: 0x000b, +} + +// testdataLookup: 640 bytes +// Block 0 is the null block. +var testdataLookup = [640]uint8{ + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0x0c2: 0x03, 0x0c4: 0x04, + 0x0df: 0x05, + 0x0e0: 0x04, + 0x0ef: 0x05, + 0x0f0: 0x07, 0x0f4: 0x09, + // Block 0x4, offset 0x100 + 0x120: 0x06, 0x126: 0x07, + // Block 0x5, offset 0x140 + 0x17f: 0x08, + // Block 0x6, offset 0x180 + 0x180: 0x09, 0x184: 0x0a, + // Block 0x7, offset 0x1c0 + 0x1d0: 0x06, + // Block 0x8, offset 0x200 + 0x23f: 0x0b, + // Block 0x9, offset 0x240 + 0x24f: 0x08, +} + +var testdataTrie = trie{testdataLookup[:], testdataValues[:]} diff --git a/libgo/go/exp/norm/triegen.go b/libgo/go/exp/norm/triegen.go new file mode 100644 index 0000000..2b7eeee --- /dev/null +++ b/libgo/go/exp/norm/triegen.go @@ -0,0 +1,211 @@ +// 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. + +// Trie table generator. +// Used by make*tables tools to generate a go file with trie data structures +// for mapping UTF-8 to a 16-bit value. All but the last byte in a UTF-8 byte +// sequence are used to lookup offsets in the index table to be used for the +// next byte. The last byte is used to index into a table with 16-bit values. + +package main + +import ( + "fmt" + "hash/crc32" + "log" + "utf8" +) + +// Intermediate trie structure +type trieNode struct { + table [256]*trieNode + value uint16 + b byte + leaf bool +} + +func newNode() *trieNode { + return new(trieNode) +} + +func (n trieNode) String() string { + s := fmt.Sprint("trieNode{table: { non-nil at index: ") + for i, v := range n.table { + if v != nil { + s += fmt.Sprintf("%d, ", i) + } + } + s += fmt.Sprintf("}, value:%#x, b:%#x leaf:%v}", n.value, n.b, n.leaf) + return s +} + +func (n trieNode) isInternal() bool { + internal := true + for i := 0; i < 256; i++ { + if nn := n.table[i]; nn != nil { + if !internal && !nn.leaf { + log.Fatalf("triegen: isInternal: node contains both leaf and non-leaf children (%v)", n) + } + internal = internal && !nn.leaf + } + } + return internal +} + +func (n *trieNode) insert(rune int, value uint16) { + var p [utf8.UTFMax]byte + sz := utf8.EncodeRune(p[:], rune) + + for i := 0; i < sz; i++ { + if n.leaf { + log.Fatalf("triegen: insert: node (%#v) should not be a leaf", n) + } + nn := n.table[p[i]] + if nn == nil { + nn = newNode() + nn.b = p[i] + n.table[p[i]] = nn + } + n = nn + } + n.value = value + n.leaf = true +} + +type nodeIndex struct { + lookupBlocks []*trieNode + valueBlocks []*trieNode + + lookupBlockIdx map[uint32]uint16 + valueBlockIdx map[uint32]uint16 +} + +func newIndex() *nodeIndex { + index := &nodeIndex{} + index.lookupBlocks = make([]*trieNode, 0) + index.valueBlocks = make([]*trieNode, 0) + index.lookupBlockIdx = make(map[uint32]uint16) + index.valueBlockIdx = make(map[uint32]uint16) + return index +} + +func computeOffsets(index *nodeIndex, n *trieNode) uint16 { + if n.leaf { + return n.value + } + hasher := crc32.New(crc32.MakeTable(crc32.IEEE)) + // We only index continuation bytes. + for i := 0; i < 64; i++ { + var v uint16 = 0 + if nn := n.table[0x80+i]; nn != nil { + v = computeOffsets(index, nn) + } + hasher.Write([]byte{uint8(v >> 8), uint8(v)}) + } + h := hasher.Sum32() + if n.isInternal() { + v, ok := index.lookupBlockIdx[h] + if !ok { + v = uint16(len(index.lookupBlocks)) + index.lookupBlocks = append(index.lookupBlocks, n) + index.lookupBlockIdx[h] = v + } + n.value = v + } else { + v, ok := index.valueBlockIdx[h] + if !ok { + v = uint16(len(index.valueBlocks)) + index.valueBlocks = append(index.valueBlocks, n) + index.valueBlockIdx[h] = v + } + n.value = v + } + return n.value +} + +func printValueBlock(nr int, n *trieNode, offset int) { + boff := nr * 64 + fmt.Printf("\n// Block %#x, offset %#x", nr, boff) + var printnewline bool + for i := 0; i < 64; i++ { + if i%6 == 0 { + printnewline = true + } + v := uint16(0) + if nn := n.table[i+offset]; nn != nil { + v = nn.value + } + if v != 0 { + if printnewline { + fmt.Printf("\n") + printnewline = false + } + fmt.Printf("%#04x:%#04x, ", nr*64+i, v) + } + } +} + +func printLookupBlock(nr int, n *trieNode, offset int) { + boff := nr * 64 + fmt.Printf("\n// Block %#x, offset %#x", nr, boff) + var printnewline bool + for i := 0; i < 64; i++ { + if i%8 == 0 { + printnewline = true + } + v := uint16(0) + if nn := n.table[i+offset]; nn != nil { + v = nn.value + } + if v != 0 { + if printnewline { + fmt.Printf("\n") + printnewline = false + } + fmt.Printf("%#03x:%#02x, ", boff+i, v) + } + } +} + +// printTables returns the size in bytes of the generated tables. +func (t *trieNode) printTables(name string) int { + index := newIndex() + // Values for 7-bit ASCII are stored in first two block, followed by nil block. + index.valueBlocks = append(index.valueBlocks, nil, nil, nil) + // First byte of multi-byte UTF-8 codepoints are indexed in 4th block. + index.lookupBlocks = append(index.lookupBlocks, nil, nil, nil, nil) + // Index starter bytes of multi-byte UTF-8. + for i := 0xC0; i < 0x100; i++ { + if t.table[i] != nil { + computeOffsets(index, t.table[i]) + } + } + + nv := len(index.valueBlocks) * 64 + fmt.Printf("// %sValues: %d entries, %d bytes\n", name, nv, nv*2) + fmt.Printf("// Block 2 is the null block.\n") + fmt.Printf("var %sValues = [%d]uint16 {", name, nv) + printValueBlock(0, t, 0) + printValueBlock(1, t, 64) + printValueBlock(2, newNode(), 0) + for i := 3; i < len(index.valueBlocks); i++ { + printValueBlock(i, index.valueBlocks[i], 0x80) + } + fmt.Print("\n}\n\n") + + ni := len(index.lookupBlocks) * 64 + fmt.Printf("// %sLookup: %d bytes\n", name, ni) + fmt.Printf("// Block 0 is the null block.\n") + fmt.Printf("var %sLookup = [%d]uint8 {", name, ni) + printLookupBlock(0, newNode(), 0) + printLookupBlock(1, newNode(), 0) + printLookupBlock(2, newNode(), 0) + printLookupBlock(3, t, 0xC0) + for i := 4; i < len(index.lookupBlocks); i++ { + printLookupBlock(i, index.lookupBlocks[i], 0x80) + } + fmt.Print("\n}\n\n") + fmt.Printf("var %sTrie = trie{ %sLookup[:], %sValues[:] }\n\n", name, name, name) + return nv*2 + ni +} diff --git a/libgo/go/exp/ogle/abort.go b/libgo/go/exp/ogle/abort.go deleted file mode 100644 index 311a7b3..0000000 --- a/libgo/go/exp/ogle/abort.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ogle - -import ( - "os" - "runtime" -) - -// An aborter aborts the thread's current computation, usually -// passing the error to a waiting thread. -type aborter interface { - Abort(err os.Error) -} - -type ogleAborter chan os.Error - -func (a ogleAborter) Abort(err os.Error) { - a <- err - runtime.Goexit() -} - -// try executes a computation; if the computation Aborts, try returns -// the error passed to abort. -func try(f func(a aborter)) os.Error { - a := make(ogleAborter) - go func() { - f(a) - a <- nil - }() - err := <-a - return err -} diff --git a/libgo/go/exp/ogle/arch.go b/libgo/go/exp/ogle/arch.go deleted file mode 100644 index 52b1c97..0000000 --- a/libgo/go/exp/ogle/arch.go +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ogle - -import ( - "debug/proc" - "math" -) - -type Arch interface { - // ToWord converts an array of up to 8 bytes in memory order - // to a word. - ToWord(data []byte) proc.Word - // FromWord converts a word to an array of up to 8 bytes in - // memory order. - FromWord(v proc.Word, out []byte) - // ToFloat32 converts a word to a float. The order of this - // word will be the order returned by ToWord on the memory - // representation of a float, and thus may require reversing. - ToFloat32(bits uint32) float32 - // FromFloat32 converts a float to a word. This should return - // a word that can be passed to FromWord to get the memory - // representation of a float on this architecture. - FromFloat32(f float32) uint32 - // ToFloat64 is to float64 as ToFloat32 is to float32. - ToFloat64(bits uint64) float64 - // FromFloat64 is to float64 as FromFloat32 is to float32. - FromFloat64(f float64) uint64 - - // IntSize returns the number of bytes in an 'int'. - IntSize() int - // PtrSize returns the number of bytes in a 'uintptr'. - PtrSize() int - // FloatSize returns the number of bytes in a 'float'. - FloatSize() int - // Align rounds offset up to the appropriate offset for a - // basic type with the given width. - Align(offset, width int) int - - // G returns the current G pointer. - G(regs proc.Regs) proc.Word - - // ClosureSize returns the number of bytes expected by - // ParseClosure. - ClosureSize() int - // ParseClosure takes ClosureSize bytes read from a return PC - // in a remote process, determines if the code is a closure, - // and returns the frame size of the closure if it is. - ParseClosure(data []byte) (frame int, ok bool) -} - -type ArchLSB struct{} - -func (ArchLSB) ToWord(data []byte) proc.Word { - var v proc.Word - for i, b := range data { - v |= proc.Word(b) << (uint(i) * 8) - } - return v -} - -func (ArchLSB) FromWord(v proc.Word, out []byte) { - for i := range out { - out[i] = byte(v) - v >>= 8 - } -} - -func (ArchLSB) ToFloat32(bits uint32) float32 { - // TODO(austin) Do these definitions depend on my current - // architecture? - return math.Float32frombits(bits) -} - -func (ArchLSB) FromFloat32(f float32) uint32 { return math.Float32bits(f) } - -func (ArchLSB) ToFloat64(bits uint64) float64 { return math.Float64frombits(bits) } - -func (ArchLSB) FromFloat64(f float64) uint64 { return math.Float64bits(f) } - -type ArchAlignedMultiple struct{} - -func (ArchAlignedMultiple) Align(offset, width int) int { - return ((offset - 1) | (width - 1)) + 1 -} - -type amd64 struct { - ArchLSB - ArchAlignedMultiple - gReg int -} - -func (a *amd64) IntSize() int { return 4 } - -func (a *amd64) PtrSize() int { return 8 } - -func (a *amd64) FloatSize() int { return 4 } - -func (a *amd64) G(regs proc.Regs) proc.Word { - // See src/pkg/runtime/mkasmh - if a.gReg == -1 { - ns := regs.Names() - for i, n := range ns { - if n == "r15" { - a.gReg = i - break - } - } - } - - return regs.Get(a.gReg) -} - -func (a *amd64) ClosureSize() int { return 8 } - -func (a *amd64) ParseClosure(data []byte) (int, bool) { - if data[0] == 0x48 && data[1] == 0x81 && data[2] == 0xc4 && data[7] == 0xc3 { - return int(a.ToWord(data[3:7]) + 8), true - } - return 0, false -} - -var Amd64 = &amd64{gReg: -1} diff --git a/libgo/go/exp/ogle/cmd.go b/libgo/go/exp/ogle/cmd.go deleted file mode 100644 index a8db523..0000000 --- a/libgo/go/exp/ogle/cmd.go +++ /dev/null @@ -1,373 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package ogle is the beginning of a debugger for Go. -package ogle - -import ( - "bufio" - "debug/elf" - "debug/proc" - "exp/eval" - "fmt" - "go/scanner" - "go/token" - "os" - "strconv" - "strings" -) - -var fset = token.NewFileSet() -var world *eval.World -var curProc *Process - -func Main() { - world = eval.NewWorld() - defineFuncs() - r := bufio.NewReader(os.Stdin) - for { - print("; ") - line, err := r.ReadSlice('\n') - if err != nil { - break - } - - // Try line as a command - cmd, rest := getCmd(line) - if cmd != nil { - err := cmd.handler(rest) - if err != nil { - scanner.PrintError(os.Stderr, err) - } - continue - } - - // Try line as code - code, err := world.Compile(fset, string(line)) - if err != nil { - scanner.PrintError(os.Stderr, err) - continue - } - v, err := code.Run() - if err != nil { - fmt.Fprintf(os.Stderr, err.String()) - continue - } - if v != nil { - println(v.String()) - } - } -} - -// newScanner creates a new scanner that scans that given input bytes. -func newScanner(input []byte) (*scanner.Scanner, *scanner.ErrorVector) { - sc := new(scanner.Scanner) - ev := new(scanner.ErrorVector) - file := fset.AddFile("input", fset.Base(), len(input)) - sc.Init(file, input, ev, 0) - return sc, ev -} - -/* - * Commands - */ - -// A UsageError occurs when a command is called with illegal arguments. -type UsageError string - -func (e UsageError) String() string { return string(e) } - -// A cmd represents a single command with a handler. -type cmd struct { - cmd string - handler func([]byte) os.Error -} - -var cmds = []cmd{ - {"load", cmdLoad}, - {"bt", cmdBt}, -} - -// getCmd attempts to parse an input line as a registered command. If -// successful, it returns the command and the bytes remaining after -// the command, which should be passed to the command. -func getCmd(line []byte) (*cmd, []byte) { - sc, _ := newScanner(line) - pos, tok, lit := sc.Scan() - if sc.ErrorCount != 0 || tok != token.IDENT { - return nil, nil - } - - slit := string(lit) - for i := range cmds { - if cmds[i].cmd == slit { - return &cmds[i], line[fset.Position(pos).Offset+len(lit):] - } - } - return nil, nil -} - -// cmdLoad starts or attaches to a process. Its form is similar to -// import: -// -// load [sym] "path" [;] -// -// sym specifies the name to give to the process. If not given, the -// name is derived from the path of the process. If ".", then the -// packages from the remote process are defined into the current -// namespace. If given, this symbol is defined as a package -// containing the process' packages. -// -// path gives the path of the process to start or attach to. If it is -// "pid:", then attach to the given PID. Otherwise, treat it as -// a file path and space-separated arguments and start a new process. -// -// load always sets the current process to the loaded process. -func cmdLoad(args []byte) os.Error { - ident, path, err := parseLoad(args) - if err != nil { - return err - } - if curProc != nil { - return UsageError("multiple processes not implemented") - } - if ident != "." { - return UsageError("process identifiers not implemented") - } - - // Parse argument and start or attach to process - var fname string - var tproc proc.Process - if len(path) >= 4 && path[0:4] == "pid:" { - pid, err := strconv.Atoi(path[4:]) - if err != nil { - return err - } - fname, err = os.Readlink(fmt.Sprintf("/proc/%d/exe", pid)) - if err != nil { - return err - } - tproc, err = proc.Attach(pid) - if err != nil { - return err - } - println("Attached to", pid) - } else { - parts := strings.Split(path, " ", -1) - if len(parts) == 0 { - fname = "" - } else { - fname = parts[0] - } - tproc, err = proc.StartProcess(fname, parts, &os.ProcAttr{Files: []*os.File{os.Stdin, os.Stdout, os.Stderr}}) - if err != nil { - return err - } - println("Started", path) - // TODO(austin) If we fail after this point, kill tproc - // before detaching. - } - - // Get symbols - f, err := os.Open(fname) - if err != nil { - tproc.Detach() - return err - } - defer f.Close() - elf, err := elf.NewFile(f) - if err != nil { - tproc.Detach() - return err - } - curProc, err = NewProcessElf(tproc, elf) - if err != nil { - tproc.Detach() - return err - } - - // Prepare new process - curProc.OnGoroutineCreate().AddHandler(EventPrint) - curProc.OnGoroutineExit().AddHandler(EventPrint) - - err = curProc.populateWorld(world) - if err != nil { - tproc.Detach() - return err - } - - return nil -} - -func parseLoad(args []byte) (ident string, path string, err os.Error) { - err = UsageError("Usage: load [sym] \"path\"") - sc, ev := newScanner(args) - - var toks [4]token.Token - var lits [4]string - for i := range toks { - _, toks[i], lits[i] = sc.Scan() - } - if sc.ErrorCount != 0 { - err = ev.GetError(scanner.NoMultiples) - return - } - - i := 0 - switch toks[i] { - case token.PERIOD, token.IDENT: - ident = string(lits[i]) - i++ - } - - if toks[i] != token.STRING { - return - } - path, uerr := strconv.Unquote(string(lits[i])) - if uerr != nil { - err = uerr - return - } - i++ - - if toks[i] == token.SEMICOLON { - i++ - } - if toks[i] != token.EOF { - return - } - - return ident, path, nil -} - -// cmdBt prints a backtrace for the current goroutine. It takes no -// arguments. -func cmdBt(args []byte) os.Error { - err := parseNoArgs(args, "Usage: bt") - if err != nil { - return err - } - - if curProc == nil || curProc.curGoroutine == nil { - return NoCurrentGoroutine{} - } - - f := curProc.curGoroutine.frame - if f == nil { - fmt.Println("No frames on stack") - return nil - } - - for f.Inner() != nil { - f = f.Inner() - } - - for i := 0; i < 100; i++ { - if f == curProc.curGoroutine.frame { - fmt.Printf("=> ") - } else { - fmt.Printf(" ") - } - fmt.Printf("%8x %v\n", f.pc, f) - f, err = f.Outer() - if err != nil { - return err - } - if f == nil { - return nil - } - } - - fmt.Println("...") - return nil -} - -func parseNoArgs(args []byte, usage string) os.Error { - sc, ev := newScanner(args) - _, tok, _ := sc.Scan() - if sc.ErrorCount != 0 { - return ev.GetError(scanner.NoMultiples) - } - if tok != token.EOF { - return UsageError(usage) - } - return nil -} - -/* - * Functions - */ - -// defineFuncs populates world with the built-in functions. -func defineFuncs() { - t, v := eval.FuncFromNativeTyped(fnOut, fnOutSig) - world.DefineConst("Out", t, v) - t, v = eval.FuncFromNativeTyped(fnContWait, fnContWaitSig) - world.DefineConst("ContWait", t, v) - t, v = eval.FuncFromNativeTyped(fnBpSet, fnBpSetSig) - world.DefineConst("BpSet", t, v) -} - -// printCurFrame prints the current stack frame, as it would appear in -// a backtrace. -func printCurFrame() { - if curProc == nil || curProc.curGoroutine == nil { - return - } - f := curProc.curGoroutine.frame - if f == nil { - return - } - fmt.Printf("=> %8x %v\n", f.pc, f) -} - -// fnOut moves the current frame to the caller of the current frame. -func fnOutSig() {} -func fnOut(t *eval.Thread, args []eval.Value, res []eval.Value) { - if curProc == nil { - t.Abort(NoCurrentGoroutine{}) - } - err := curProc.Out() - if err != nil { - t.Abort(err) - } - // TODO(austin) Only in the command form - printCurFrame() -} - -// fnContWait continues the current process and waits for a stopping event. -func fnContWaitSig() {} -func fnContWait(t *eval.Thread, args []eval.Value, res []eval.Value) { - if curProc == nil { - t.Abort(NoCurrentGoroutine{}) - } - err := curProc.ContWait() - if err != nil { - t.Abort(err) - } - // TODO(austin) Only in the command form - ev := curProc.Event() - if ev != nil { - fmt.Printf("%v\n", ev) - } - printCurFrame() -} - -// fnBpSet sets a breakpoint at the entry to the named function. -func fnBpSetSig(string) {} -func fnBpSet(t *eval.Thread, args []eval.Value, res []eval.Value) { - // TODO(austin) This probably shouldn't take a symbol name. - // Perhaps it should take an interface that provides PC's. - // Functions and instructions can implement that interface and - // we can have something to translate file:line pairs. - if curProc == nil { - t.Abort(NoCurrentGoroutine{}) - } - name := args[0].(eval.StringValue).Get(t) - fn := curProc.syms.LookupFunc(name) - if fn == nil { - t.Abort(UsageError("no such function " + name)) - } - curProc.OnBreakpoint(proc.Word(fn.Entry)).AddHandler(EventStop) -} diff --git a/libgo/go/exp/ogle/event.go b/libgo/go/exp/ogle/event.go deleted file mode 100644 index d7092de..0000000 --- a/libgo/go/exp/ogle/event.go +++ /dev/null @@ -1,280 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ogle - -import ( - "debug/proc" - "fmt" - "os" -) - -/* - * Hooks and events - */ - -// An EventHandler is a function that takes an event and returns a -// response to that event and possibly an error. If an event handler -// returns an error, the process stops and no other handlers for that -// event are executed. -type EventHandler func(e Event) (EventAction, os.Error) - -// An EventAction is an event handler's response to an event. If all -// of an event's handlers execute without returning errors, their -// results are combined as follows: If any handler returned -// EAContinue, then the process resumes (without returning from -// WaitStop); otherwise, if any handler returned EAStop, the process -// remains stopped; otherwise, if all handlers returned EADefault, the -// process resumes. A handler may return EARemoveSelf bit-wise or'd -// with any other action to indicate that the handler should be -// removed from the hook. -type EventAction int - -const ( - EARemoveSelf EventAction = 0x100 - EADefault EventAction = iota - EAStop - EAContinue -) - -// A EventHook allows event handlers to be added and removed. -type EventHook interface { - AddHandler(EventHandler) - RemoveHandler(EventHandler) - NumHandler() int - handle(e Event) (EventAction, os.Error) - String() string -} - -// EventHook is almost, but not quite, suitable for user-defined -// events. If we want user-defined events, make EventHook a struct, -// special-case adding and removing handlers in breakpoint hooks, and -// provide a public interface for posting events to hooks. - -type Event interface { - Process() *Process - Goroutine() *Goroutine - String() string -} - -type commonHook struct { - // Head of handler chain - head *handler - // Number of non-internal handlers - len int -} - -type handler struct { - eh EventHandler - // True if this handler must be run before user-defined - // handlers in order to ensure correctness. - internal bool - // True if this handler has been removed from the chain. - removed bool - next *handler -} - -func (h *commonHook) AddHandler(eh EventHandler) { - h.addHandler(eh, false) -} - -func (h *commonHook) addHandler(eh EventHandler, internal bool) { - // Ensure uniqueness of handlers - h.RemoveHandler(eh) - - if !internal { - h.len++ - } - // Add internal handlers to the beginning - if internal || h.head == nil { - h.head = &handler{eh, internal, false, h.head} - return - } - // Add handler after internal handlers - // TODO(austin) This should probably go on the end instead - prev := h.head - for prev.next != nil && prev.internal { - prev = prev.next - } - prev.next = &handler{eh, internal, false, prev.next} -} - -func (h *commonHook) RemoveHandler(eh EventHandler) { - plink := &h.head - for l := *plink; l != nil; plink, l = &l.next, l.next { - if l.eh == eh { - if !l.internal { - h.len-- - } - l.removed = true - *plink = l.next - break - } - } -} - -func (h *commonHook) NumHandler() int { return h.len } - -func (h *commonHook) handle(e Event) (EventAction, os.Error) { - action := EADefault - plink := &h.head - for l := *plink; l != nil; plink, l = &l.next, l.next { - if l.removed { - continue - } - a, err := l.eh(e) - if a&EARemoveSelf == EARemoveSelf { - if !l.internal { - h.len-- - } - l.removed = true - *plink = l.next - a &^= EARemoveSelf - } - if err != nil { - return EAStop, err - } - if a > action { - action = a - } - } - return action, nil -} - -type commonEvent struct { - // The process of this event - p *Process - // The goroutine of this event. - t *Goroutine -} - -func (e *commonEvent) Process() *Process { return e.p } - -func (e *commonEvent) Goroutine() *Goroutine { return e.t } - -/* - * Standard event handlers - */ - -// EventPrint is a standard event handler that prints events as they -// occur. It will not cause the process to stop. -func EventPrint(ev Event) (EventAction, os.Error) { - // TODO(austin) Include process name here? - fmt.Fprintf(os.Stderr, "*** %v\n", ev.String()) - return EADefault, nil -} - -// EventStop is a standard event handler that causes the process to stop. -func EventStop(ev Event) (EventAction, os.Error) { - return EAStop, nil -} - -/* - * Breakpoints - */ - -type breakpointHook struct { - commonHook - p *Process - pc proc.Word -} - -// A Breakpoint event occurs when a process reaches a particular -// program counter. When this event is handled, the current goroutine -// will be the goroutine that reached the program counter. -type Breakpoint struct { - commonEvent - osThread proc.Thread - pc proc.Word -} - -func (h *breakpointHook) AddHandler(eh EventHandler) { - h.addHandler(eh, false) -} - -func (h *breakpointHook) addHandler(eh EventHandler, internal bool) { - // We register breakpoint events lazily to avoid holding - // references to breakpoints without handlers. Be sure to use - // the "canonical" breakpoint if there is one. - if cur, ok := h.p.breakpointHooks[h.pc]; ok { - h = cur - } - oldhead := h.head - h.commonHook.addHandler(eh, internal) - if oldhead == nil && h.head != nil { - h.p.proc.AddBreakpoint(h.pc) - h.p.breakpointHooks[h.pc] = h - } -} - -func (h *breakpointHook) RemoveHandler(eh EventHandler) { - oldhead := h.head - h.commonHook.RemoveHandler(eh) - if oldhead != nil && h.head == nil { - h.p.proc.RemoveBreakpoint(h.pc) - h.p.breakpointHooks[h.pc] = nil, false - } -} - -func (h *breakpointHook) String() string { - // TODO(austin) Include process name? - // TODO(austin) Use line:pc or at least sym+%#x - return fmt.Sprintf("breakpoint at %#x", h.pc) -} - -func (b *Breakpoint) PC() proc.Word { return b.pc } - -func (b *Breakpoint) String() string { - // TODO(austin) Include process name and goroutine - // TODO(austin) Use line:pc or at least sym+%#x - return fmt.Sprintf("breakpoint at %#x", b.pc) -} - -/* - * Goroutine create/exit - */ - -type goroutineCreateHook struct { - commonHook -} - -func (h *goroutineCreateHook) String() string { return "goroutine create" } - -// A GoroutineCreate event occurs when a process creates a new -// goroutine. When this event is handled, the current goroutine will -// be the newly created goroutine. -type GoroutineCreate struct { - commonEvent - parent *Goroutine -} - -// Parent returns the goroutine that created this goroutine. May be -// nil if this event is the creation of the first goroutine. -func (e *GoroutineCreate) Parent() *Goroutine { return e.parent } - -func (e *GoroutineCreate) String() string { - // TODO(austin) Include process name - if e.parent == nil { - return fmt.Sprintf("%v created", e.t) - } - return fmt.Sprintf("%v created by %v", e.t, e.parent) -} - -type goroutineExitHook struct { - commonHook -} - -func (h *goroutineExitHook) String() string { return "goroutine exit" } - -// A GoroutineExit event occurs when a Go goroutine exits. -type GoroutineExit struct { - commonEvent -} - -func (e *GoroutineExit) String() string { - // TODO(austin) Include process name - //return fmt.Sprintf("%v exited", e.t); - // For debugging purposes - return fmt.Sprintf("goroutine %#x exited", e.t.g.addr().base) -} diff --git a/libgo/go/exp/ogle/frame.go b/libgo/go/exp/ogle/frame.go deleted file mode 100644 index 1538362..0000000 --- a/libgo/go/exp/ogle/frame.go +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ogle - -import ( - "debug/gosym" - "debug/proc" - "fmt" - "os" -) - -// A Frame represents a single frame on a remote call stack. -type Frame struct { - // pc is the PC of the next instruction that will execute in - // this frame. For lower frames, this is the instruction - // following the CALL instruction. - pc, sp, fp proc.Word - // The runtime.Stktop of the active stack segment - stk remoteStruct - // The function this stack frame is in - fn *gosym.Func - // The path and line of the CALL or current instruction. Note - // that this differs slightly from the meaning of Frame.pc. - path string - line int - // The inner and outer frames of this frame. outer is filled - // in lazily. - inner, outer *Frame -} - -// newFrame returns the top-most Frame of the given g's thread. -func newFrame(g remoteStruct) (*Frame, os.Error) { - var f *Frame - err := try(func(a aborter) { f = aNewFrame(a, g) }) - return f, err -} - -func aNewFrame(a aborter, g remoteStruct) *Frame { - p := g.r.p - var pc, sp proc.Word - - // Is this G alive? - switch g.field(p.f.G.Status).(remoteInt).aGet(a) { - case p.runtime.Gidle, p.runtime.Gmoribund, p.runtime.Gdead: - return nil - } - - // Find the OS thread for this G - - // TODO(austin) Ideally, we could look at the G's state and - // figure out if it's on an OS thread or not. However, this - // is difficult because the state isn't updated atomically - // with scheduling changes. - for _, t := range p.proc.Threads() { - regs, err := t.Regs() - if err != nil { - // TODO(austin) What to do? - continue - } - thisg := p.G(regs) - if thisg == g.addr().base { - // Found this G's OS thread - pc = regs.PC() - sp = regs.SP() - - // If this thread crashed, try to recover it - if pc == 0 { - pc = p.peekUintptr(a, pc) - sp += 8 - } - - break - } - } - - if pc == 0 && sp == 0 { - // G is not mapped to an OS thread. Use the - // scheduler's stored PC and SP. - sched := g.field(p.f.G.Sched).(remoteStruct) - pc = proc.Word(sched.field(p.f.Gobuf.Pc).(remoteUint).aGet(a)) - sp = proc.Word(sched.field(p.f.Gobuf.Sp).(remoteUint).aGet(a)) - } - - // Get Stktop - stk := g.field(p.f.G.Stackbase).(remotePtr).aGet(a).(remoteStruct) - - return prepareFrame(a, pc, sp, stk, nil) -} - -// prepareFrame creates a Frame from the PC and SP within that frame, -// as well as the active stack segment. This function takes care of -// traversing stack breaks and unwinding closures. -func prepareFrame(a aborter, pc, sp proc.Word, stk remoteStruct, inner *Frame) *Frame { - // Based on src/pkg/runtime/amd64/traceback.c:traceback - p := stk.r.p - top := inner == nil - - // Get function - var path string - var line int - var fn *gosym.Func - - for i := 0; i < 100; i++ { - // Traverse segmented stack breaks - if p.sys.lessstack != nil && pc == proc.Word(p.sys.lessstack.Value) { - // Get stk->gobuf.pc - pc = proc.Word(stk.field(p.f.Stktop.Gobuf).(remoteStruct).field(p.f.Gobuf.Pc).(remoteUint).aGet(a)) - // Get stk->gobuf.sp - sp = proc.Word(stk.field(p.f.Stktop.Gobuf).(remoteStruct).field(p.f.Gobuf.Sp).(remoteUint).aGet(a)) - // Get stk->stackbase - stk = stk.field(p.f.Stktop.Stackbase).(remotePtr).aGet(a).(remoteStruct) - continue - } - - // Get the PC of the call instruction - callpc := pc - if !top && (p.sys.goexit == nil || pc != proc.Word(p.sys.goexit.Value)) { - callpc-- - } - - // Look up function - path, line, fn = p.syms.PCToLine(uint64(callpc)) - if fn != nil { - break - } - - // Closure? - var buf = make([]byte, p.ClosureSize()) - if _, err := p.Peek(pc, buf); err != nil { - break - } - spdelta, ok := p.ParseClosure(buf) - if ok { - sp += proc.Word(spdelta) - pc = p.peekUintptr(a, sp-proc.Word(p.PtrSize())) - } - } - if fn == nil { - return nil - } - - // Compute frame pointer - var fp proc.Word - if fn.FrameSize < p.PtrSize() { - fp = sp + proc.Word(p.PtrSize()) - } else { - fp = sp + proc.Word(fn.FrameSize) - } - // TODO(austin) To really figure out if we're in the prologue, - // we need to disassemble the function and look for the call - // to morestack. For now, just special case the entry point. - // - // TODO(austin) What if we're in the call to morestack in the - // prologue? Then top == false. - if top && pc == proc.Word(fn.Entry) { - // We're in the function prologue, before SP - // has been adjusted for the frame. - fp -= proc.Word(fn.FrameSize - p.PtrSize()) - } - - return &Frame{pc, sp, fp, stk, fn, path, line, inner, nil} -} - -// Outer returns the Frame that called this Frame, or nil if this is -// the outermost frame. -func (f *Frame) Outer() (*Frame, os.Error) { - var fr *Frame - err := try(func(a aborter) { fr = f.aOuter(a) }) - return fr, err -} - -func (f *Frame) aOuter(a aborter) *Frame { - // Is there a cached outer frame - if f.outer != nil { - return f.outer - } - - p := f.stk.r.p - - sp := f.fp - if f.fn == p.sys.newproc && f.fn == p.sys.deferproc { - // TODO(rsc) The compiler inserts two push/pop's - // around calls to go and defer. Russ says this - // should get fixed in the compiler, but we account - // for it for now. - sp += proc.Word(2 * p.PtrSize()) - } - - pc := p.peekUintptr(a, f.fp-proc.Word(p.PtrSize())) - if pc < 0x1000 { - return nil - } - - // TODO(austin) Register this frame for shoot-down. - - f.outer = prepareFrame(a, pc, sp, f.stk, f) - return f.outer -} - -// Inner returns the Frame called by this Frame, or nil if this is the -// innermost frame. -func (f *Frame) Inner() *Frame { return f.inner } - -func (f *Frame) String() string { - res := f.fn.Name - if f.pc > proc.Word(f.fn.Value) { - res += fmt.Sprintf("+%#x", f.pc-proc.Word(f.fn.Entry)) - } - return res + fmt.Sprintf(" %s:%d", f.path, f.line) -} diff --git a/libgo/go/exp/ogle/goroutine.go b/libgo/go/exp/ogle/goroutine.go deleted file mode 100644 index 5104ec6..0000000 --- a/libgo/go/exp/ogle/goroutine.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ogle - -import ( - "debug/proc" - "exp/eval" - "fmt" - "os" -) - -// A Goroutine represents a goroutine in a remote process. -type Goroutine struct { - g remoteStruct - frame *Frame - dead bool -} - -func (t *Goroutine) String() string { - if t.dead { - return "" - } - // TODO(austin) Give threads friendly ID's, possibly including - // the name of the entry function. - return fmt.Sprintf("thread %#x", t.g.addr().base) -} - -// isG0 returns true if this thread if the internal idle thread -func (t *Goroutine) isG0() bool { return t.g.addr().base == t.g.r.p.sys.g0.addr().base } - -func (t *Goroutine) resetFrame() (err os.Error) { - // TODO(austin) Reuse any live part of the current frame stack - // so existing references to Frame's keep working. - t.frame, err = newFrame(t.g) - return -} - -// Out selects the caller frame of the current frame. -func (t *Goroutine) Out() os.Error { - f, err := t.frame.Outer() - if f != nil { - t.frame = f - } - return err -} - -// In selects the frame called by the current frame. -func (t *Goroutine) In() os.Error { - f := t.frame.Inner() - if f != nil { - t.frame = f - } - return nil -} - -func readylockedBP(ev Event) (EventAction, os.Error) { - b := ev.(*Breakpoint) - p := b.Process() - - // The new g is the only argument to this function, so the - // stack will have the return address, then the G*. - regs, err := b.osThread.Regs() - if err != nil { - return EAStop, err - } - sp := regs.SP() - addr := sp + proc.Word(p.PtrSize()) - arg := remotePtr{remote{addr, p}, p.runtime.G} - var gp eval.Value - err = try(func(a aborter) { gp = arg.aGet(a) }) - if err != nil { - return EAStop, err - } - if gp == nil { - return EAStop, UnknownGoroutine{b.osThread, 0} - } - gs := gp.(remoteStruct) - g := &Goroutine{gs, nil, false} - p.goroutines[gs.addr().base] = g - - // Enqueue goroutine creation event - parent := b.Goroutine() - if parent.isG0() { - parent = nil - } - p.postEvent(&GoroutineCreate{commonEvent{p, g}, parent}) - - // If we don't have any thread selected, select this one - if p.curGoroutine == nil { - p.curGoroutine = g - } - - return EADefault, nil -} - -func goexitBP(ev Event) (EventAction, os.Error) { - b := ev.(*Breakpoint) - p := b.Process() - - g := b.Goroutine() - g.dead = true - - addr := g.g.addr().base - p.goroutines[addr] = nil, false - - // Enqueue thread exit event - p.postEvent(&GoroutineExit{commonEvent{p, g}}) - - // If we just exited our selected goroutine, selected another - if p.curGoroutine == g { - p.selectSomeGoroutine() - } - - return EADefault, nil -} diff --git a/libgo/go/exp/ogle/main.go b/libgo/go/exp/ogle/main.go deleted file mode 100644 index 1999ecc..0000000 --- a/libgo/go/exp/ogle/main.go +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import "exp/ogle" - -func main() { ogle.Main() } diff --git a/libgo/go/exp/ogle/process.go b/libgo/go/exp/ogle/process.go deleted file mode 100644 index 7c803b3..0000000 --- a/libgo/go/exp/ogle/process.go +++ /dev/null @@ -1,521 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ogle - -import ( - "debug/elf" - "debug/gosym" - "debug/proc" - "exp/eval" - "fmt" - "log" - "os" - "reflect" -) - -// A FormatError indicates a failure to process information in or -// about a remote process, such as unexpected or missing information -// in the object file or runtime structures. -type FormatError string - -func (e FormatError) String() string { return string(e) } - -// An UnknownArchitecture occurs when trying to load an object file -// that indicates an architecture not supported by the debugger. -type UnknownArchitecture elf.Machine - -func (e UnknownArchitecture) String() string { - return "unknown architecture: " + elf.Machine(e).String() -} - -// A ProcessNotStopped error occurs when attempting to read or write -// memory or registers of a process that is not stopped. -type ProcessNotStopped struct{} - -func (e ProcessNotStopped) String() string { return "process not stopped" } - -// An UnknownGoroutine error is an internal error representing an -// unrecognized G structure pointer. -type UnknownGoroutine struct { - OSThread proc.Thread - Goroutine proc.Word -} - -func (e UnknownGoroutine) String() string { - return fmt.Sprintf("internal error: unknown goroutine (G %#x)", e.Goroutine) -} - -// A NoCurrentGoroutine error occurs when no goroutine is currently -// selected in a process (or when there are no goroutines in a -// process). -type NoCurrentGoroutine struct{} - -func (e NoCurrentGoroutine) String() string { return "no current goroutine" } - -// A Process represents a remote attached process. -type Process struct { - Arch - proc proc.Process - - // The symbol table of this process - syms *gosym.Table - - // A possibly-stopped OS thread, or nil - threadCache proc.Thread - - // Types parsed from the remote process - types map[proc.Word]*remoteType - - // Types and values from the remote runtime package - runtime runtimeValues - - // Runtime field indexes - f runtimeIndexes - - // Globals from the sys package (or from no package) - sys struct { - lessstack, goexit, newproc, deferproc, newprocreadylocked *gosym.Func - allg remotePtr - g0 remoteStruct - } - - // Event queue - posted []Event - pending []Event - event Event - - // Event hooks - breakpointHooks map[proc.Word]*breakpointHook - goroutineCreateHook *goroutineCreateHook - goroutineExitHook *goroutineExitHook - - // Current goroutine, or nil if there are no goroutines - curGoroutine *Goroutine - - // Goroutines by the address of their G structure - goroutines map[proc.Word]*Goroutine -} - -/* - * Process creation - */ - -// NewProcess constructs a new remote process around a traced -// process, an architecture, and a symbol table. -func NewProcess(tproc proc.Process, arch Arch, syms *gosym.Table) (*Process, os.Error) { - p := &Process{ - Arch: arch, - proc: tproc, - syms: syms, - types: make(map[proc.Word]*remoteType), - breakpointHooks: make(map[proc.Word]*breakpointHook), - goroutineCreateHook: new(goroutineCreateHook), - goroutineExitHook: new(goroutineExitHook), - goroutines: make(map[proc.Word]*Goroutine), - } - - // Fill in remote runtime - p.bootstrap() - - switch { - case p.sys.allg.addr().base == 0: - return nil, FormatError("failed to find runtime symbol 'allg'") - case p.sys.g0.addr().base == 0: - return nil, FormatError("failed to find runtime symbol 'g0'") - case p.sys.newprocreadylocked == nil: - return nil, FormatError("failed to find runtime symbol 'newprocreadylocked'") - case p.sys.goexit == nil: - return nil, FormatError("failed to find runtime symbol 'sys.goexit'") - } - - // Get current goroutines - p.goroutines[p.sys.g0.addr().base] = &Goroutine{p.sys.g0, nil, false} - err := try(func(a aborter) { - g := p.sys.allg.aGet(a) - for g != nil { - gs := g.(remoteStruct) - fmt.Printf("*** Found goroutine at %#x\n", gs.addr().base) - p.goroutines[gs.addr().base] = &Goroutine{gs, nil, false} - g = gs.field(p.f.G.Alllink).(remotePtr).aGet(a) - } - }) - if err != nil { - return nil, err - } - - // Create internal breakpoints to catch new and exited goroutines - p.OnBreakpoint(proc.Word(p.sys.newprocreadylocked.Entry)).(*breakpointHook).addHandler(readylockedBP, true) - p.OnBreakpoint(proc.Word(p.sys.goexit.Entry)).(*breakpointHook).addHandler(goexitBP, true) - - // Select current frames - for _, g := range p.goroutines { - g.resetFrame() - } - - p.selectSomeGoroutine() - - return p, nil -} - -func elfGoSyms(f *elf.File) (*gosym.Table, os.Error) { - text := f.Section(".text") - symtab := f.Section(".gosymtab") - pclntab := f.Section(".gopclntab") - if text == nil || symtab == nil || pclntab == nil { - return nil, nil - } - - symdat, err := symtab.Data() - if err != nil { - return nil, err - } - pclndat, err := pclntab.Data() - if err != nil { - return nil, err - } - - pcln := gosym.NewLineTable(pclndat, text.Addr) - tab, err := gosym.NewTable(symdat, pcln) - if err != nil { - return nil, err - } - - return tab, nil -} - -// NewProcessElf constructs a new remote process around a traced -// process and the process' ELF object. -func NewProcessElf(tproc proc.Process, f *elf.File) (*Process, os.Error) { - syms, err := elfGoSyms(f) - if err != nil { - return nil, err - } - if syms == nil { - return nil, FormatError("Failed to find symbol table") - } - var arch Arch - switch f.Machine { - case elf.EM_X86_64: - arch = Amd64 - default: - return nil, UnknownArchitecture(f.Machine) - } - return NewProcess(tproc, arch, syms) -} - -// bootstrap constructs the runtime structure of a remote process. -func (p *Process) bootstrap() { - // Manually construct runtime types - p.runtime.String = newManualType(eval.TypeOfNative(rt1String{}), p.Arch) - p.runtime.Slice = newManualType(eval.TypeOfNative(rt1Slice{}), p.Arch) - p.runtime.Eface = newManualType(eval.TypeOfNative(rt1Eface{}), p.Arch) - - p.runtime.Type = newManualType(eval.TypeOfNative(rt1Type{}), p.Arch) - p.runtime.CommonType = newManualType(eval.TypeOfNative(rt1CommonType{}), p.Arch) - p.runtime.UncommonType = newManualType(eval.TypeOfNative(rt1UncommonType{}), p.Arch) - p.runtime.StructField = newManualType(eval.TypeOfNative(rt1StructField{}), p.Arch) - p.runtime.StructType = newManualType(eval.TypeOfNative(rt1StructType{}), p.Arch) - p.runtime.PtrType = newManualType(eval.TypeOfNative(rt1PtrType{}), p.Arch) - p.runtime.ArrayType = newManualType(eval.TypeOfNative(rt1ArrayType{}), p.Arch) - p.runtime.SliceType = newManualType(eval.TypeOfNative(rt1SliceType{}), p.Arch) - - p.runtime.Stktop = newManualType(eval.TypeOfNative(rt1Stktop{}), p.Arch) - p.runtime.Gobuf = newManualType(eval.TypeOfNative(rt1Gobuf{}), p.Arch) - p.runtime.G = newManualType(eval.TypeOfNative(rt1G{}), p.Arch) - - // Get addresses of type.*runtime.XType for discrimination. - rtv := reflect.Indirect(reflect.ValueOf(&p.runtime)) - rtvt := rtv.Type() - for i := 0; i < rtv.NumField(); i++ { - n := rtvt.Field(i).Name - if n[0] != 'P' || n[1] < 'A' || n[1] > 'Z' { - continue - } - sym := p.syms.LookupSym("type.*runtime." + n[1:]) - if sym == nil { - continue - } - rtv.Field(i).SetUint(sym.Value) - } - - // Get runtime field indexes - fillRuntimeIndexes(&p.runtime, &p.f) - - // Fill G status - p.runtime.runtimeGStatus = rt1GStatus - - // Get globals - p.sys.lessstack = p.syms.LookupFunc("sys.lessstack") - p.sys.goexit = p.syms.LookupFunc("goexit") - p.sys.newproc = p.syms.LookupFunc("sys.newproc") - p.sys.deferproc = p.syms.LookupFunc("sys.deferproc") - p.sys.newprocreadylocked = p.syms.LookupFunc("newprocreadylocked") - if allg := p.syms.LookupSym("allg"); allg != nil { - p.sys.allg = remotePtr{remote{proc.Word(allg.Value), p}, p.runtime.G} - } - if g0 := p.syms.LookupSym("g0"); g0 != nil { - p.sys.g0 = p.runtime.G.mk(remote{proc.Word(g0.Value), p}).(remoteStruct) - } -} - -func (p *Process) selectSomeGoroutine() { - // Once we have friendly goroutine ID's, there might be a more - // reasonable behavior for this. - p.curGoroutine = nil - for _, g := range p.goroutines { - if !g.isG0() && g.frame != nil { - p.curGoroutine = g - return - } - } -} - -/* - * Process memory - */ - -func (p *Process) someStoppedOSThread() proc.Thread { - if p.threadCache != nil { - if _, err := p.threadCache.Stopped(); err == nil { - return p.threadCache - } - } - - for _, t := range p.proc.Threads() { - if _, err := t.Stopped(); err == nil { - p.threadCache = t - return t - } - } - return nil -} - -func (p *Process) Peek(addr proc.Word, out []byte) (int, os.Error) { - thr := p.someStoppedOSThread() - if thr == nil { - return 0, ProcessNotStopped{} - } - return thr.Peek(addr, out) -} - -func (p *Process) Poke(addr proc.Word, b []byte) (int, os.Error) { - thr := p.someStoppedOSThread() - if thr == nil { - return 0, ProcessNotStopped{} - } - return thr.Poke(addr, b) -} - -func (p *Process) peekUintptr(a aborter, addr proc.Word) proc.Word { - return proc.Word(mkUintptr(remote{addr, p}).(remoteUint).aGet(a)) -} - -/* - * Events - */ - -// OnBreakpoint returns the hook that is run when the program reaches -// the given program counter. -func (p *Process) OnBreakpoint(pc proc.Word) EventHook { - if bp, ok := p.breakpointHooks[pc]; ok { - return bp - } - // The breakpoint will register itself when a handler is added - return &breakpointHook{commonHook{nil, 0}, p, pc} -} - -// OnGoroutineCreate returns the hook that is run when a goroutine is created. -func (p *Process) OnGoroutineCreate() EventHook { - return p.goroutineCreateHook -} - -// OnGoroutineExit returns the hook that is run when a goroutine exits. -func (p *Process) OnGoroutineExit() EventHook { return p.goroutineExitHook } - -// osThreadToGoroutine looks up the goroutine running on an OS thread. -func (p *Process) osThreadToGoroutine(t proc.Thread) (*Goroutine, os.Error) { - regs, err := t.Regs() - if err != nil { - return nil, err - } - g := p.G(regs) - gt, ok := p.goroutines[g] - if !ok { - return nil, UnknownGoroutine{t, g} - } - return gt, nil -} - -// causesToEvents translates the stop causes of the underlying process -// into an event queue. -func (p *Process) causesToEvents() ([]Event, os.Error) { - // Count causes we're interested in - nev := 0 - for _, t := range p.proc.Threads() { - if c, err := t.Stopped(); err == nil { - switch c := c.(type) { - case proc.Breakpoint: - nev++ - case proc.Signal: - // TODO(austin) - //nev++; - } - } - } - - // Translate causes to events - events := make([]Event, nev) - i := 0 - for _, t := range p.proc.Threads() { - if c, err := t.Stopped(); err == nil { - switch c := c.(type) { - case proc.Breakpoint: - gt, err := p.osThreadToGoroutine(t) - if err != nil { - return nil, err - } - events[i] = &Breakpoint{commonEvent{p, gt}, t, proc.Word(c)} - i++ - case proc.Signal: - // TODO(austin) - } - } - } - - return events, nil -} - -// postEvent appends an event to the posted queue. These events will -// be processed before any currently pending events. -func (p *Process) postEvent(ev Event) { - p.posted = append(p.posted, ev) -} - -// processEvents processes events in the event queue until no events -// remain, a handler returns EAStop, or a handler returns an error. -// It returns either EAStop or EAContinue and possibly an error. -func (p *Process) processEvents() (EventAction, os.Error) { - var ev Event - for len(p.posted) > 0 { - ev, p.posted = p.posted[0], p.posted[1:] - action, err := p.processEvent(ev) - if action == EAStop { - return action, err - } - } - - for len(p.pending) > 0 { - ev, p.pending = p.pending[0], p.pending[1:] - action, err := p.processEvent(ev) - if action == EAStop { - return action, err - } - } - - return EAContinue, nil -} - -// processEvent processes a single event, without manipulating the -// event queues. It returns either EAStop or EAContinue and possibly -// an error. -func (p *Process) processEvent(ev Event) (EventAction, os.Error) { - p.event = ev - - var action EventAction - var err os.Error - switch ev := p.event.(type) { - case *Breakpoint: - hook, ok := p.breakpointHooks[ev.pc] - if !ok { - break - } - p.curGoroutine = ev.Goroutine() - action, err = hook.handle(ev) - - case *GoroutineCreate: - p.curGoroutine = ev.Goroutine() - action, err = p.goroutineCreateHook.handle(ev) - - case *GoroutineExit: - action, err = p.goroutineExitHook.handle(ev) - - default: - log.Panicf("Unknown event type %T in queue", p.event) - } - - if err != nil { - return EAStop, err - } else if action == EAStop { - return EAStop, nil - } - return EAContinue, nil -} - -// Event returns the last event that caused the process to stop. This -// may return nil if the process has never been stopped by an event. -// -// TODO(austin) Return nil if the user calls p.Stop()? -func (p *Process) Event() Event { return p.event } - -/* - * Process control - */ - -// TODO(austin) Cont, WaitStop, and Stop. Need to figure out how -// event handling works with these. Originally I did it only in -// WaitStop, but if you Cont and there are pending events, then you -// have to not actually continue and wait until a WaitStop to process -// them, even if the event handlers will tell you to continue. We -// could handle them in both Cont and WaitStop to avoid this problem, -// but it's still weird if an event happens after the Cont and before -// the WaitStop that the handlers say to continue from. Or we could -// handle them on a separate thread. Then obviously you get weird -// asynchronous things, like prints while the user it typing a command, -// but that's not necessarily a bad thing. - -// ContWait resumes process execution and waits for an event to occur -// that stops the process. -func (p *Process) ContWait() os.Error { - for { - a, err := p.processEvents() - if err != nil { - return err - } else if a == EAStop { - break - } - err = p.proc.Continue() - if err != nil { - return err - } - err = p.proc.WaitStop() - if err != nil { - return err - } - for _, g := range p.goroutines { - g.resetFrame() - } - p.pending, err = p.causesToEvents() - if err != nil { - return err - } - } - return nil -} - -// Out selects the caller frame of the current frame. -func (p *Process) Out() os.Error { - if p.curGoroutine == nil { - return NoCurrentGoroutine{} - } - return p.curGoroutine.Out() -} - -// In selects the frame called by the current frame. -func (p *Process) In() os.Error { - if p.curGoroutine == nil { - return NoCurrentGoroutine{} - } - return p.curGoroutine.In() -} diff --git a/libgo/go/exp/ogle/rruntime.go b/libgo/go/exp/ogle/rruntime.go deleted file mode 100644 index 950418b..0000000 --- a/libgo/go/exp/ogle/rruntime.go +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ogle - -import ( - "debug/proc" - "exp/eval" - "reflect" -) - -// This file contains remote runtime definitions. Using reflection, -// we convert all of these to interpreter types and layout their -// remote representations using the architecture rules. -// -// We could get most of these definitions from our own runtime -// package; however, some of them differ in convenient ways, some of -// them are not defined or exported by the runtime, and having our own -// definitions makes it easy to support multiple remote runtime -// versions. This may turn out to be overkill. -// -// All of these structures are prefixed with rt1 to indicate the -// runtime version and to mark them as types used only as templates -// for remote types. - -/* - * Runtime data headers - * - * See $GOROOT/src/pkg/runtime/runtime.h - */ - -type rt1String struct { - str uintptr - len int -} - -type rt1Slice struct { - array uintptr - len int - cap int -} - -type rt1Eface struct { - typ uintptr - ptr uintptr -} - -/* - * Runtime type structures - * - * See $GOROOT/src/pkg/runtime/type.h and $GOROOT/src/pkg/runtime/type.go - */ - -type rt1UncommonType struct { - name *string - pkgPath *string - //methods []method; -} - -type rt1CommonType struct { - size uintptr - hash uint32 - alg, align, fieldAlign uint8 - string *string - uncommonType *rt1UncommonType -} - -type rt1Type struct { - // While Type is technically an Eface, treating the - // discriminator as an opaque pointer and taking advantage of - // the commonType prologue on all Type's makes type parsing - // much simpler. - typ uintptr - ptr *rt1CommonType -} - -type rt1StructField struct { - name *string - pkgPath *string - typ *rt1Type - tag *string - offset uintptr -} - -type rt1StructType struct { - rt1CommonType - fields []rt1StructField -} - -type rt1PtrType struct { - rt1CommonType - elem *rt1Type -} - -type rt1SliceType struct { - rt1CommonType - elem *rt1Type -} - -type rt1ArrayType struct { - rt1CommonType - elem *rt1Type - len uintptr -} - -/* - * Runtime scheduler structures - * - * See $GOROOT/src/pkg/runtime/runtime.h - */ - -// Fields beginning with _ are only for padding - -type rt1Stktop struct { - stackguard uintptr - stackbase *rt1Stktop - gobuf rt1Gobuf - _args uint32 - _fp uintptr -} - -type rt1Gobuf struct { - sp uintptr - pc uintptr - g *rt1G - r0 uintptr -} - -type rt1G struct { - _stackguard uintptr - stackbase *rt1Stktop - _defer uintptr - sched rt1Gobuf - _stack0 uintptr - _entry uintptr - alllink *rt1G - _param uintptr - status int16 - // Incomplete -} - -var rt1GStatus = runtimeGStatus{ - Gidle: 0, - Grunnable: 1, - Grunning: 2, - Gsyscall: 3, - Gwaiting: 4, - Gmoribund: 5, - Gdead: 6, -} - -// runtimeIndexes stores the indexes of fields in the runtime -// structures. It is filled in using reflection, so the name of the -// fields must match the names of the remoteType's in runtimeValues -// exactly and the names of the index fields must be the capitalized -// version of the names of the fields in the runtime structures above. -type runtimeIndexes struct { - String struct { - Str, Len int - } - Slice struct { - Array, Len, Cap int - } - Eface struct { - Typ, Ptr int - } - - UncommonType struct { - Name, PkgPath int - } - CommonType struct { - Size, Hash, Alg, Align, FieldAlign, String, UncommonType int - } - Type struct { - Typ, Ptr int - } - StructField struct { - Name, PkgPath, Typ, Tag, Offset int - } - StructType struct { - Fields int - } - PtrType struct { - Elem int - } - SliceType struct { - Elem int - } - ArrayType struct { - Elem, Len int - } - - Stktop struct { - Stackguard, Stackbase, Gobuf int - } - Gobuf struct { - Sp, Pc, G int - } - G struct { - Stackbase, Sched, Status, Alllink int - } -} - -// Values of G status codes -type runtimeGStatus struct { - Gidle, Grunnable, Grunning, Gsyscall, Gwaiting, Gmoribund, Gdead int64 -} - -// runtimeValues stores the types and values that correspond to those -// in the remote runtime package. -type runtimeValues struct { - // Runtime data headers - String, Slice, Eface *remoteType - // Runtime type structures - Type, CommonType, UncommonType, StructField, StructType, PtrType, - ArrayType, SliceType *remoteType - // Runtime scheduler structures - Stktop, Gobuf, G *remoteType - // Addresses of *runtime.XType types. These are the - // discriminators on the runtime.Type interface. We use local - // reflection to fill these in from the remote symbol table, - // so the names must match the runtime names. - PBoolType, - PUint8Type, PUint16Type, PUint32Type, PUint64Type, PUintType, PUintptrType, - PInt8Type, PInt16Type, PInt32Type, PInt64Type, PIntType, - PFloat32Type, PFloat64Type, PFloatType, - PArrayType, PStringType, PStructType, PPtrType, PFuncType, - PInterfaceType, PSliceType, PMapType, PChanType, - PDotDotDotType, PUnsafePointerType proc.Word - // G status values - runtimeGStatus -} - -// fillRuntimeIndexes fills a runtimeIndexes structure will the field -// indexes gathered from the remoteTypes recorded in a runtimeValues -// structure. -func fillRuntimeIndexes(runtime *runtimeValues, out *runtimeIndexes) { - outv := reflect.Indirect(reflect.ValueOf(out)) - outt := outv.Type() - runtimev := reflect.Indirect(reflect.ValueOf(runtime)) - - // out contains fields corresponding to each runtime type - for i := 0; i < outt.NumField(); i++ { - // Find the interpreter type for this runtime type - name := outt.Field(i).Name - et := runtimev.FieldByName(name).Interface().(*remoteType).Type.(*eval.StructType) - - // Get the field indexes of the interpreter struct type - indexes := make(map[string]int, len(et.Elems)) - for j, f := range et.Elems { - if f.Anonymous { - continue - } - name := f.Name - if name[0] >= 'a' && name[0] <= 'z' { - name = string(name[0]+'A'-'a') + name[1:] - } - indexes[name] = j - } - - // Fill this field of out - outStructv := outv.Field(i) - outStructt := outStructv.Type() - for j := 0; j < outStructt.NumField(); j++ { - f := outStructv.Field(j) - name := outStructt.Field(j).Name - f.SetInt(int64(indexes[name])) - } - } -} diff --git a/libgo/go/exp/ogle/rtype.go b/libgo/go/exp/ogle/rtype.go deleted file mode 100644 index b3c3557..0000000 --- a/libgo/go/exp/ogle/rtype.go +++ /dev/null @@ -1,288 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ogle - -import ( - "debug/proc" - "exp/eval" - "fmt" - "log" -) - -const debugParseRemoteType = false - -// A remoteType is the local representation of a type in a remote process. -type remoteType struct { - eval.Type - // The size of values of this type in bytes. - size int - // The field alignment of this type. Only used for - // manually-constructed types. - fieldAlign int - // The maker function to turn a remote address of a value of - // this type into an interpreter Value. - mk maker -} - -var manualTypes = make(map[Arch]map[eval.Type]*remoteType) - -// newManualType constructs a remote type from an interpreter Type -// using the size and alignment properties of the given architecture. -// Most types are parsed directly out of the remote process, but to do -// so we need to layout the structures that describe those types ourselves. -func newManualType(t eval.Type, arch Arch) *remoteType { - if nt, ok := t.(*eval.NamedType); ok { - t = nt.Def - } - - // Get the type map for this architecture - typeMap := manualTypes[arch] - if typeMap == nil { - typeMap = make(map[eval.Type]*remoteType) - manualTypes[arch] = typeMap - - // Construct basic types for this architecture - basicType := func(t eval.Type, mk maker, size int, fieldAlign int) { - t = t.(*eval.NamedType).Def - if fieldAlign == 0 { - fieldAlign = size - } - typeMap[t] = &remoteType{t, size, fieldAlign, mk} - } - basicType(eval.Uint8Type, mkUint8, 1, 0) - basicType(eval.Uint32Type, mkUint32, 4, 0) - basicType(eval.UintptrType, mkUintptr, arch.PtrSize(), 0) - basicType(eval.Int16Type, mkInt16, 2, 0) - basicType(eval.Int32Type, mkInt32, 4, 0) - basicType(eval.IntType, mkInt, arch.IntSize(), 0) - basicType(eval.StringType, mkString, arch.PtrSize()+arch.IntSize(), arch.PtrSize()) - } - - if rt, ok := typeMap[t]; ok { - return rt - } - - var rt *remoteType - switch t := t.(type) { - case *eval.PtrType: - var elem *remoteType - mk := func(r remote) eval.Value { return remotePtr{r, elem} } - rt = &remoteType{t, arch.PtrSize(), arch.PtrSize(), mk} - // Construct the element type after registering the - // type to break cycles. - typeMap[eval.Type(t)] = rt - elem = newManualType(t.Elem, arch) - - case *eval.ArrayType: - elem := newManualType(t.Elem, arch) - mk := func(r remote) eval.Value { return remoteArray{r, t.Len, elem} } - rt = &remoteType{t, elem.size * int(t.Len), elem.fieldAlign, mk} - - case *eval.SliceType: - elem := newManualType(t.Elem, arch) - mk := func(r remote) eval.Value { return remoteSlice{r, elem} } - rt = &remoteType{t, arch.PtrSize() + 2*arch.IntSize(), arch.PtrSize(), mk} - - case *eval.StructType: - layout := make([]remoteStructField, len(t.Elems)) - offset := 0 - fieldAlign := 0 - for i, f := range t.Elems { - elem := newManualType(f.Type, arch) - if fieldAlign == 0 { - fieldAlign = elem.fieldAlign - } - offset = arch.Align(offset, elem.fieldAlign) - layout[i].offset = offset - layout[i].fieldType = elem - offset += elem.size - } - mk := func(r remote) eval.Value { return remoteStruct{r, layout} } - rt = &remoteType{t, offset, fieldAlign, mk} - - default: - log.Panicf("cannot manually construct type %T", t) - } - - typeMap[t] = rt - return rt -} - -var prtIndent = "" - -// parseRemoteType parses a Type structure in a remote process to -// construct the corresponding interpreter type and remote type. -func parseRemoteType(a aborter, rs remoteStruct) *remoteType { - addr := rs.addr().base - p := rs.addr().p - - // We deal with circular types by discovering cycles at - // NamedTypes. If a type cycles back to something other than - // a named type, we're guaranteed that there will be a named - // type somewhere in that cycle. Thus, we continue down, - // re-parsing types until we reach the named type in the - // cycle. In order to still create one remoteType per remote - // type, we insert an empty remoteType in the type map the - // first time we encounter the type and re-use that structure - // the second time we encounter it. - - rt, ok := p.types[addr] - if ok && rt.Type != nil { - return rt - } else if !ok { - rt = &remoteType{} - p.types[addr] = rt - } - - if debugParseRemoteType { - sym := p.syms.SymByAddr(uint64(addr)) - name := "" - if sym != nil { - name = sym.Name - } - log.Printf("%sParsing type at %#x (%s)", prtIndent, addr, name) - prtIndent += " " - defer func() { prtIndent = prtIndent[0 : len(prtIndent)-1] }() - } - - // Get Type header - itype := proc.Word(rs.field(p.f.Type.Typ).(remoteUint).aGet(a)) - typ := rs.field(p.f.Type.Ptr).(remotePtr).aGet(a).(remoteStruct) - - // Is this a named type? - var nt *eval.NamedType - uncommon := typ.field(p.f.CommonType.UncommonType).(remotePtr).aGet(a) - if uncommon != nil { - name := uncommon.(remoteStruct).field(p.f.UncommonType.Name).(remotePtr).aGet(a) - if name != nil { - // TODO(austin) Declare type in appropriate remote package - nt = eval.NewNamedType(name.(remoteString).aGet(a)) - rt.Type = nt - } - } - - // Create type - var t eval.Type - var mk maker - switch itype { - case p.runtime.PBoolType: - t = eval.BoolType - mk = mkBool - case p.runtime.PUint8Type: - t = eval.Uint8Type - mk = mkUint8 - case p.runtime.PUint16Type: - t = eval.Uint16Type - mk = mkUint16 - case p.runtime.PUint32Type: - t = eval.Uint32Type - mk = mkUint32 - case p.runtime.PUint64Type: - t = eval.Uint64Type - mk = mkUint64 - case p.runtime.PUintType: - t = eval.UintType - mk = mkUint - case p.runtime.PUintptrType: - t = eval.UintptrType - mk = mkUintptr - case p.runtime.PInt8Type: - t = eval.Int8Type - mk = mkInt8 - case p.runtime.PInt16Type: - t = eval.Int16Type - mk = mkInt16 - case p.runtime.PInt32Type: - t = eval.Int32Type - mk = mkInt32 - case p.runtime.PInt64Type: - t = eval.Int64Type - mk = mkInt64 - case p.runtime.PIntType: - t = eval.IntType - mk = mkInt - case p.runtime.PFloat32Type: - t = eval.Float32Type - mk = mkFloat32 - case p.runtime.PFloat64Type: - t = eval.Float64Type - mk = mkFloat64 - case p.runtime.PStringType: - t = eval.StringType - mk = mkString - - case p.runtime.PArrayType: - // Cast to an ArrayType - typ := p.runtime.ArrayType.mk(typ.addr()).(remoteStruct) - len := int64(typ.field(p.f.ArrayType.Len).(remoteUint).aGet(a)) - elem := parseRemoteType(a, typ.field(p.f.ArrayType.Elem).(remotePtr).aGet(a).(remoteStruct)) - t = eval.NewArrayType(len, elem.Type) - mk = func(r remote) eval.Value { return remoteArray{r, len, elem} } - - case p.runtime.PStructType: - // Cast to a StructType - typ := p.runtime.StructType.mk(typ.addr()).(remoteStruct) - fs := typ.field(p.f.StructType.Fields).(remoteSlice).aGet(a) - - fields := make([]eval.StructField, fs.Len) - layout := make([]remoteStructField, fs.Len) - for i := range fields { - f := fs.Base.(remoteArray).elem(int64(i)).(remoteStruct) - elemrs := f.field(p.f.StructField.Typ).(remotePtr).aGet(a).(remoteStruct) - elem := parseRemoteType(a, elemrs) - fields[i].Type = elem.Type - name := f.field(p.f.StructField.Name).(remotePtr).aGet(a) - if name == nil { - fields[i].Anonymous = true - } else { - fields[i].Name = name.(remoteString).aGet(a) - } - layout[i].offset = int(f.field(p.f.StructField.Offset).(remoteUint).aGet(a)) - layout[i].fieldType = elem - } - - t = eval.NewStructType(fields) - mk = func(r remote) eval.Value { return remoteStruct{r, layout} } - - case p.runtime.PPtrType: - // Cast to a PtrType - typ := p.runtime.PtrType.mk(typ.addr()).(remoteStruct) - elem := parseRemoteType(a, typ.field(p.f.PtrType.Elem).(remotePtr).aGet(a).(remoteStruct)) - t = eval.NewPtrType(elem.Type) - mk = func(r remote) eval.Value { return remotePtr{r, elem} } - - case p.runtime.PSliceType: - // Cast to a SliceType - typ := p.runtime.SliceType.mk(typ.addr()).(remoteStruct) - elem := parseRemoteType(a, typ.field(p.f.SliceType.Elem).(remotePtr).aGet(a).(remoteStruct)) - t = eval.NewSliceType(elem.Type) - mk = func(r remote) eval.Value { return remoteSlice{r, elem} } - - case p.runtime.PMapType, p.runtime.PChanType, p.runtime.PFuncType, p.runtime.PInterfaceType, p.runtime.PUnsafePointerType, p.runtime.PDotDotDotType: - // TODO(austin) - t = eval.UintptrType - mk = mkUintptr - - default: - sym := p.syms.SymByAddr(uint64(itype)) - name := "" - if sym != nil { - name = sym.Name - } - err := fmt.Sprintf("runtime type at %#x has unexpected type %#x (%s)", addr, itype, name) - a.Abort(FormatError(err)) - } - - // Fill in the remote type - if nt != nil { - nt.Complete(t) - } else { - rt.Type = t - } - rt.size = int(typ.field(p.f.CommonType.Size).(remoteUint).aGet(a)) - rt.mk = mk - - return rt -} diff --git a/libgo/go/exp/ogle/rvalue.go b/libgo/go/exp/ogle/rvalue.go deleted file mode 100644 index 3d630f9..0000000 --- a/libgo/go/exp/ogle/rvalue.go +++ /dev/null @@ -1,515 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ogle - -import ( - "debug/proc" - "exp/eval" - "fmt" -) - -// A RemoteMismatchError occurs when an operation that requires two -// identical remote processes is given different process. For -// example, this occurs when trying to set a pointer in one process to -// point to something in another process. -type RemoteMismatchError string - -func (e RemoteMismatchError) String() string { return string(e) } - -// A ReadOnlyError occurs when attempting to set or assign to a -// read-only value. -type ReadOnlyError string - -func (e ReadOnlyError) String() string { return string(e) } - -// A maker is a function that converts a remote address into an -// interpreter Value. -type maker func(remote) eval.Value - -type remoteValue interface { - addr() remote -} - -// remote represents an address in a remote process. -type remote struct { - base proc.Word - p *Process -} - -func (v remote) Get(a aborter, size int) uint64 { - // TODO(austin) This variable might temporarily be in a - // register. We could trace the assembly back from the - // current PC, looking for the beginning of the function or a - // call (both of which guarantee that the variable is in - // memory), or an instruction that loads the variable into a - // register. - // - // TODO(austin) If this is a local variable, it might not be - // live at this PC. In fact, because the compiler reuses - // slots, there might even be a different local variable at - // this location right now. A simple solution to both - // problems is to include the range of PC's over which a local - // variable is live in the symbol table. - // - // TODO(austin) We need to prevent the remote garbage - // collector from collecting objects out from under us. - var arr [8]byte - buf := arr[0:size] - _, err := v.p.Peek(v.base, buf) - if err != nil { - a.Abort(err) - } - return uint64(v.p.ToWord(buf)) -} - -func (v remote) Set(a aborter, size int, x uint64) { - var arr [8]byte - buf := arr[0:size] - v.p.FromWord(proc.Word(x), buf) - _, err := v.p.Poke(v.base, buf) - if err != nil { - a.Abort(err) - } -} - -func (v remote) plus(x proc.Word) remote { return remote{v.base + x, v.p} } - -func tryRVString(f func(a aborter) string) string { - var s string - err := try(func(a aborter) { s = f(a) }) - if err != nil { - return fmt.Sprintf("", err) - } - return s -} - -/* - * Bool - */ - -type remoteBool struct { - r remote -} - -func (v remoteBool) String() string { - return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) }) -} - -func (v remoteBool) Assign(t *eval.Thread, o eval.Value) { - v.Set(t, o.(eval.BoolValue).Get(t)) -} - -func (v remoteBool) Get(t *eval.Thread) bool { return v.aGet(t) } - -func (v remoteBool) aGet(a aborter) bool { return v.r.Get(a, 1) != 0 } - -func (v remoteBool) Set(t *eval.Thread, x bool) { - v.aSet(t, x) -} - -func (v remoteBool) aSet(a aborter, x bool) { - if x { - v.r.Set(a, 1, 1) - } else { - v.r.Set(a, 1, 0) - } -} - -func (v remoteBool) addr() remote { return v.r } - -func mkBool(r remote) eval.Value { return remoteBool{r} } - -/* - * Uint - */ - -type remoteUint struct { - r remote - size int -} - -func (v remoteUint) String() string { - return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) }) -} - -func (v remoteUint) Assign(t *eval.Thread, o eval.Value) { - v.Set(t, o.(eval.UintValue).Get(t)) -} - -func (v remoteUint) Get(t *eval.Thread) uint64 { - return v.aGet(t) -} - -func (v remoteUint) aGet(a aborter) uint64 { return v.r.Get(a, v.size) } - -func (v remoteUint) Set(t *eval.Thread, x uint64) { - v.aSet(t, x) -} - -func (v remoteUint) aSet(a aborter, x uint64) { v.r.Set(a, v.size, x) } - -func (v remoteUint) addr() remote { return v.r } - -func mkUint8(r remote) eval.Value { return remoteUint{r, 1} } - -func mkUint16(r remote) eval.Value { return remoteUint{r, 2} } - -func mkUint32(r remote) eval.Value { return remoteUint{r, 4} } - -func mkUint64(r remote) eval.Value { return remoteUint{r, 8} } - -func mkUint(r remote) eval.Value { return remoteUint{r, r.p.IntSize()} } - -func mkUintptr(r remote) eval.Value { return remoteUint{r, r.p.PtrSize()} } - -/* - * Int - */ - -type remoteInt struct { - r remote - size int -} - -func (v remoteInt) String() string { - return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) }) -} - -func (v remoteInt) Assign(t *eval.Thread, o eval.Value) { - v.Set(t, o.(eval.IntValue).Get(t)) -} - -func (v remoteInt) Get(t *eval.Thread) int64 { return v.aGet(t) } - -func (v remoteInt) aGet(a aborter) int64 { return int64(v.r.Get(a, v.size)) } - -func (v remoteInt) Set(t *eval.Thread, x int64) { - v.aSet(t, x) -} - -func (v remoteInt) aSet(a aborter, x int64) { v.r.Set(a, v.size, uint64(x)) } - -func (v remoteInt) addr() remote { return v.r } - -func mkInt8(r remote) eval.Value { return remoteInt{r, 1} } - -func mkInt16(r remote) eval.Value { return remoteInt{r, 2} } - -func mkInt32(r remote) eval.Value { return remoteInt{r, 4} } - -func mkInt64(r remote) eval.Value { return remoteInt{r, 8} } - -func mkInt(r remote) eval.Value { return remoteInt{r, r.p.IntSize()} } - -/* - * Float - */ - -type remoteFloat struct { - r remote - size int -} - -func (v remoteFloat) String() string { - return tryRVString(func(a aborter) string { return fmt.Sprintf("%v", v.aGet(a)) }) -} - -func (v remoteFloat) Assign(t *eval.Thread, o eval.Value) { - v.Set(t, o.(eval.FloatValue).Get(t)) -} - -func (v remoteFloat) Get(t *eval.Thread) float64 { - return v.aGet(t) -} - -func (v remoteFloat) aGet(a aborter) float64 { - bits := v.r.Get(a, v.size) - switch v.size { - case 4: - return float64(v.r.p.ToFloat32(uint32(bits))) - case 8: - return v.r.p.ToFloat64(bits) - } - panic("Unexpected float size") -} - -func (v remoteFloat) Set(t *eval.Thread, x float64) { - v.aSet(t, x) -} - -func (v remoteFloat) aSet(a aborter, x float64) { - var bits uint64 - switch v.size { - case 4: - bits = uint64(v.r.p.FromFloat32(float32(x))) - case 8: - bits = v.r.p.FromFloat64(x) - default: - panic("Unexpected float size") - } - v.r.Set(a, v.size, bits) -} - -func (v remoteFloat) addr() remote { return v.r } - -func mkFloat32(r remote) eval.Value { return remoteFloat{r, 4} } - -func mkFloat64(r remote) eval.Value { return remoteFloat{r, 8} } - -func mkFloat(r remote) eval.Value { return remoteFloat{r, r.p.FloatSize()} } - -/* - * String - */ - -type remoteString struct { - r remote -} - -func (v remoteString) String() string { - return tryRVString(func(a aborter) string { return v.aGet(a) }) -} - -func (v remoteString) Assign(t *eval.Thread, o eval.Value) { - v.Set(t, o.(eval.StringValue).Get(t)) -} - -func (v remoteString) Get(t *eval.Thread) string { - return v.aGet(t) -} - -func (v remoteString) aGet(a aborter) string { - rs := v.r.p.runtime.String.mk(v.r).(remoteStruct) - str := proc.Word(rs.field(v.r.p.f.String.Str).(remoteUint).aGet(a)) - len := rs.field(v.r.p.f.String.Len).(remoteInt).aGet(a) - - bytes := make([]uint8, len) - _, err := v.r.p.Peek(str, bytes) - if err != nil { - a.Abort(err) - } - return string(bytes) -} - -func (v remoteString) Set(t *eval.Thread, x string) { - v.aSet(t, x) -} - -func (v remoteString) aSet(a aborter, x string) { - // TODO(austin) This isn't generally possible without the - // ability to allocate remote memory. - a.Abort(ReadOnlyError("remote strings cannot be assigned to")) -} - -func mkString(r remote) eval.Value { return remoteString{r} } - -/* - * Array - */ - -type remoteArray struct { - r remote - len int64 - elemType *remoteType -} - -func (v remoteArray) String() string { - res := "{" - for i := int64(0); i < v.len; i++ { - if i > 0 { - res += ", " - } - res += v.elem(i).String() - } - return res + "}" -} - -func (v remoteArray) Assign(t *eval.Thread, o eval.Value) { - // TODO(austin) Could do a bigger memcpy if o is a - // remoteArray in the same Process. - oa := o.(eval.ArrayValue) - for i := int64(0); i < v.len; i++ { - v.Elem(t, i).Assign(t, oa.Elem(t, i)) - } -} - -func (v remoteArray) Get(t *eval.Thread) eval.ArrayValue { - return v -} - -func (v remoteArray) Elem(t *eval.Thread, i int64) eval.Value { - return v.elem(i) -} - -func (v remoteArray) elem(i int64) eval.Value { - return v.elemType.mk(v.r.plus(proc.Word(int64(v.elemType.size) * i))) -} - -func (v remoteArray) Sub(i int64, len int64) eval.ArrayValue { - return remoteArray{v.r.plus(proc.Word(int64(v.elemType.size) * i)), len, v.elemType} -} - -/* - * Struct - */ - -type remoteStruct struct { - r remote - layout []remoteStructField -} - -type remoteStructField struct { - offset int - fieldType *remoteType -} - -func (v remoteStruct) String() string { - res := "{" - for i := range v.layout { - if i > 0 { - res += ", " - } - res += v.field(i).String() - } - return res + "}" -} - -func (v remoteStruct) Assign(t *eval.Thread, o eval.Value) { - // TODO(austin) Could do a bigger memcpy. - oa := o.(eval.StructValue) - l := len(v.layout) - for i := 0; i < l; i++ { - v.Field(t, i).Assign(t, oa.Field(t, i)) - } -} - -func (v remoteStruct) Get(t *eval.Thread) eval.StructValue { - return v -} - -func (v remoteStruct) Field(t *eval.Thread, i int) eval.Value { - return v.field(i) -} - -func (v remoteStruct) field(i int) eval.Value { - f := &v.layout[i] - return f.fieldType.mk(v.r.plus(proc.Word(f.offset))) -} - -func (v remoteStruct) addr() remote { return v.r } - -/* - * Pointer - */ - -// TODO(austin) Comparing two remote pointers for equality in the -// interpreter will crash it because the Value's returned from -// remotePtr.Get() will be structs. - -type remotePtr struct { - r remote - elemType *remoteType -} - -func (v remotePtr) String() string { - return tryRVString(func(a aborter) string { - e := v.aGet(a) - if e == nil { - return "" - } - return "&" + e.String() - }) -} - -func (v remotePtr) Assign(t *eval.Thread, o eval.Value) { - v.Set(t, o.(eval.PtrValue).Get(t)) -} - -func (v remotePtr) Get(t *eval.Thread) eval.Value { - return v.aGet(t) -} - -func (v remotePtr) aGet(a aborter) eval.Value { - addr := proc.Word(v.r.Get(a, v.r.p.PtrSize())) - if addr == 0 { - return nil - } - return v.elemType.mk(remote{addr, v.r.p}) -} - -func (v remotePtr) Set(t *eval.Thread, x eval.Value) { - v.aSet(t, x) -} - -func (v remotePtr) aSet(a aborter, x eval.Value) { - if x == nil { - v.r.Set(a, v.r.p.PtrSize(), 0) - return - } - xr, ok := x.(remoteValue) - if !ok || v.r.p != xr.addr().p { - a.Abort(RemoteMismatchError("remote pointer must point within the same process")) - } - v.r.Set(a, v.r.p.PtrSize(), uint64(xr.addr().base)) -} - -func (v remotePtr) addr() remote { return v.r } - -/* - * Slice - */ - -type remoteSlice struct { - r remote - elemType *remoteType -} - -func (v remoteSlice) String() string { - return tryRVString(func(a aborter) string { - b := v.aGet(a).Base - if b == nil { - return "" - } - return b.String() - }) -} - -func (v remoteSlice) Assign(t *eval.Thread, o eval.Value) { - v.Set(t, o.(eval.SliceValue).Get(t)) -} - -func (v remoteSlice) Get(t *eval.Thread) eval.Slice { - return v.aGet(t) -} - -func (v remoteSlice) aGet(a aborter) eval.Slice { - rs := v.r.p.runtime.Slice.mk(v.r).(remoteStruct) - base := proc.Word(rs.field(v.r.p.f.Slice.Array).(remoteUint).aGet(a)) - nel := rs.field(v.r.p.f.Slice.Len).(remoteInt).aGet(a) - cap := rs.field(v.r.p.f.Slice.Cap).(remoteInt).aGet(a) - if base == 0 { - return eval.Slice{nil, nel, cap} - } - return eval.Slice{remoteArray{remote{base, v.r.p}, nel, v.elemType}, nel, cap} -} - -func (v remoteSlice) Set(t *eval.Thread, x eval.Slice) { - v.aSet(t, x) -} - -func (v remoteSlice) aSet(a aborter, x eval.Slice) { - rs := v.r.p.runtime.Slice.mk(v.r).(remoteStruct) - if x.Base == nil { - rs.field(v.r.p.f.Slice.Array).(remoteUint).aSet(a, 0) - } else { - ar, ok := x.Base.(remoteArray) - if !ok || v.r.p != ar.r.p { - a.Abort(RemoteMismatchError("remote slice must point within the same process")) - } - rs.field(v.r.p.f.Slice.Array).(remoteUint).aSet(a, uint64(ar.r.base)) - } - rs.field(v.r.p.f.Slice.Len).(remoteInt).aSet(a, x.Len) - rs.field(v.r.p.f.Slice.Cap).(remoteInt).aSet(a, x.Cap) -} diff --git a/libgo/go/exp/ogle/vars.go b/libgo/go/exp/ogle/vars.go deleted file mode 100644 index 8a3a147..0000000 --- a/libgo/go/exp/ogle/vars.go +++ /dev/null @@ -1,272 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ogle - -import ( - "debug/gosym" - "debug/proc" - "exp/eval" - "log" - "os" -) - -/* - * Remote frame pointers - */ - -// A NotOnStack error occurs when attempting to access a variable in a -// remote frame where that remote frame is not on the current stack. -type NotOnStack struct { - Fn *gosym.Func - Goroutine *Goroutine -} - -func (e NotOnStack) String() string { - return "function " + e.Fn.Name + " not on " + e.Goroutine.String() + "'s stack" -} - -// A remoteFramePtr is an implementation of eval.PtrValue that -// represents a pointer to a function frame in a remote process. When -// accessed, this locates the function on the current goroutine's -// stack and returns a structure containing the local variables of -// that function. -type remoteFramePtr struct { - p *Process - fn *gosym.Func - rt *remoteType -} - -func (v remoteFramePtr) String() string { - // TODO(austin): This could be a really awesome string method - return "" -} - -func (v remoteFramePtr) Assign(t *eval.Thread, o eval.Value) { - v.Set(t, o.(eval.PtrValue).Get(t)) -} - -func (v remoteFramePtr) Get(t *eval.Thread) eval.Value { - g := v.p.curGoroutine - if g == nil || g.frame == nil { - t.Abort(NoCurrentGoroutine{}) - } - - for f := g.frame; f != nil; f = f.aOuter(t) { - if f.fn != v.fn { - continue - } - - // TODO(austin): Register for shootdown with f - return v.rt.mk(remote{f.fp, v.p}) - } - - t.Abort(NotOnStack{v.fn, g}) - panic("fail") -} - -func (v remoteFramePtr) Set(t *eval.Thread, x eval.Value) { - // Theoretically this could be a static error. If remote - // packages were packages, remote frames could just be defined - // as constants. - t.Abort(ReadOnlyError("remote frames cannot be assigned to")) -} - -/* - * Remote packages - */ - -// TODO(austin): Remote packages are implemented as structs right now, -// which has some weird consequences. You can attempt to assign to a -// remote package. It also produces terrible error messages. -// Ideally, these would actually be packages, but somehow first-class -// so they could be assigned to other names. - -// A remotePackage is an implementation of eval.StructValue that -// represents a package in a remote process. It's essentially a -// regular struct, except it cannot be assigned to. -type remotePackage struct { - defs []eval.Value -} - -func (v remotePackage) String() string { return "" } - -func (v remotePackage) Assign(t *eval.Thread, o eval.Value) { - t.Abort(ReadOnlyError("remote packages cannot be assigned to")) -} - -func (v remotePackage) Get(t *eval.Thread) eval.StructValue { - return v -} - -func (v remotePackage) Field(t *eval.Thread, i int) eval.Value { - return v.defs[i] -} - -/* - * Remote variables - */ - -// populateWorld defines constants in the given world for each package -// in this process. These packages are structs that, in turn, contain -// fields for each global and function in that package. -func (p *Process) populateWorld(w *eval.World) os.Error { - type def struct { - t eval.Type - v eval.Value - } - packages := make(map[string]map[string]def) - - for _, s := range p.syms.Syms { - if s.ReceiverName() != "" { - // TODO(austin) - continue - } - - // Package - pkgName := s.PackageName() - switch pkgName { - case "", "type", "extratype", "string", "go": - // "go" is really "go.string" - continue - } - pkg, ok := packages[pkgName] - if !ok { - pkg = make(map[string]def) - packages[pkgName] = pkg - } - - // Symbol name - name := s.BaseName() - if _, ok := pkg[name]; ok { - log.Printf("Multiple definitions of symbol %s", s.Name) - continue - } - - // Symbol type - rt, err := p.typeOfSym(&s) - if err != nil { - return err - } - - // Definition - switch s.Type { - case 'D', 'd', 'B', 'b': - // Global variable - if rt == nil { - continue - } - pkg[name] = def{rt.Type, rt.mk(remote{proc.Word(s.Value), p})} - - case 'T', 't', 'L', 'l': - // Function - s := s.Func - // TODO(austin): Ideally, this would *also* be - // callable. How does that interact with type - // conversion syntax? - rt, err := p.makeFrameType(s) - if err != nil { - return err - } - pkg[name] = def{eval.NewPtrType(rt.Type), remoteFramePtr{p, s, rt}} - } - } - - // TODO(austin): Define remote types - - // Define packages - for pkgName, defs := range packages { - fields := make([]eval.StructField, len(defs)) - vals := make([]eval.Value, len(defs)) - i := 0 - for name, def := range defs { - fields[i].Name = name - fields[i].Type = def.t - vals[i] = def.v - i++ - } - pkgType := eval.NewStructType(fields) - pkgVal := remotePackage{vals} - - err := w.DefineConst(pkgName, pkgType, pkgVal) - if err != nil { - log.Printf("while defining package %s: %v", pkgName, err) - } - } - - return nil -} - -// typeOfSym returns the type associated with a symbol. If the symbol -// has no type, returns nil. -func (p *Process) typeOfSym(s *gosym.Sym) (*remoteType, os.Error) { - if s.GoType == 0 { - return nil, nil - } - addr := proc.Word(s.GoType) - var rt *remoteType - err := try(func(a aborter) { rt = parseRemoteType(a, p.runtime.Type.mk(remote{addr, p}).(remoteStruct)) }) - if err != nil { - return nil, err - } - return rt, nil -} - -// makeFrameType constructs a struct type for the frame of a function. -// The offsets in this struct type are such that the struct can be -// instantiated at this function's frame pointer. -func (p *Process) makeFrameType(s *gosym.Func) (*remoteType, os.Error) { - n := len(s.Params) + len(s.Locals) - fields := make([]eval.StructField, n) - layout := make([]remoteStructField, n) - i := 0 - - // TODO(austin): There can be multiple locals/parameters with - // the same name. We probably need liveness information to do - // anything about this. Once we have that, perhaps we give - // such fields interface{} type? Or perhaps we disambiguate - // the names with numbers. Disambiguation is annoying for - // things like "i", where there's an obvious right answer. - - for _, param := range s.Params { - rt, err := p.typeOfSym(param) - if err != nil { - return nil, err - } - if rt == nil { - //fmt.Printf(" (no type)\n"); - continue - } - // TODO(austin): Why do local variables carry their - // package name? - fields[i].Name = param.BaseName() - fields[i].Type = rt.Type - // Parameters have positive offsets from FP - layout[i].offset = int(param.Value) - layout[i].fieldType = rt - i++ - } - - for _, local := range s.Locals { - rt, err := p.typeOfSym(local) - if err != nil { - return nil, err - } - if rt == nil { - continue - } - fields[i].Name = local.BaseName() - fields[i].Type = rt.Type - // Locals have negative offsets from FP - PtrSize - layout[i].offset = -int(local.Value) - p.PtrSize() - layout[i].fieldType = rt - i++ - } - - fields = fields[0:i] - layout = layout[0:i] - t := eval.NewStructType(fields) - mk := func(r remote) eval.Value { return remoteStruct{r, layout} } - return &remoteType{t, 0, 0, mk}, nil -} diff --git a/libgo/go/exp/regexp/all_test.go b/libgo/go/exp/regexp/all_test.go new file mode 100644 index 0000000..77f32ca --- /dev/null +++ b/libgo/go/exp/regexp/all_test.go @@ -0,0 +1,429 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package regexp + +import ( + "os" + "strings" + "testing" +) + +var good_re = []string{ + ``, + `.`, + `^.$`, + `a`, + `a*`, + `a+`, + `a?`, + `a|b`, + `a*|b*`, + `(a*|b)(c*|d)`, + `[a-z]`, + `[a-abc-c\-\]\[]`, + `[a-z]+`, + `[abc]`, + `[^1234]`, + `[^\n]`, + `\!\\`, +} + +/* +type stringError struct { + re string + err os.Error +} + +var bad_re = []stringError{ + {`*`, ErrBareClosure}, + {`+`, ErrBareClosure}, + {`?`, ErrBareClosure}, + {`(abc`, ErrUnmatchedLpar}, + {`abc)`, ErrUnmatchedRpar}, + {`x[a-z`, ErrUnmatchedLbkt}, + {`abc]`, ErrUnmatchedRbkt}, + {`[z-a]`, ErrBadRange}, + {`abc\`, ErrExtraneousBackslash}, + {`a**`, ErrBadClosure}, + {`a*+`, ErrBadClosure}, + {`a??`, ErrBadClosure}, + {`\x`, ErrBadBackslash}, +} +*/ + +func compileTest(t *testing.T, expr string, error os.Error) *Regexp { + re, err := Compile(expr) + if err != error { + t.Error("compiling `", expr, "`; unexpected error: ", err.String()) + } + return re +} + +func TestGoodCompile(t *testing.T) { + for i := 0; i < len(good_re); i++ { + compileTest(t, good_re[i], nil) + } +} + +/* +func TestBadCompile(t *testing.T) { + for i := 0; i < len(bad_re); i++ { + compileTest(t, bad_re[i].re, bad_re[i].err) + } +} +*/ + +func matchTest(t *testing.T, test *FindTest) { + re := compileTest(t, test.pat, nil) + if re == nil { + return + } + m := re.MatchString(test.text) + if m != (len(test.matches) > 0) { + t.Errorf("MatchString failure on %s: %t should be %t", test, m, len(test.matches) > 0) + } + // now try bytes + m = re.Match([]byte(test.text)) + if m != (len(test.matches) > 0) { + t.Errorf("Match failure on %s: %t should be %t", test, m, len(test.matches) > 0) + } +} + +func TestMatch(t *testing.T) { + for _, test := range findTests { + matchTest(t, &test) + } +} + +func matchFunctionTest(t *testing.T, test *FindTest) { + m, err := MatchString(test.pat, test.text) + if err == nil { + return + } + if m != (len(test.matches) > 0) { + t.Errorf("Match failure on %s: %t should be %t", test, m, len(test.matches) > 0) + } +} + +func TestMatchFunction(t *testing.T) { + for _, test := range findTests { + matchFunctionTest(t, &test) + } +} + +type ReplaceTest struct { + pattern, replacement, input, output string +} + +var replaceTests = []ReplaceTest{ + // Test empty input and/or replacement, with pattern that matches the empty string. + {"", "", "", ""}, + {"", "x", "", "x"}, + {"", "", "abc", "abc"}, + {"", "x", "abc", "xaxbxcx"}, + + // Test empty input and/or replacement, with pattern that does not match the empty string. + {"b", "", "", ""}, + {"b", "x", "", ""}, + {"b", "", "abc", "ac"}, + {"b", "x", "abc", "axc"}, + {"y", "", "", ""}, + {"y", "x", "", ""}, + {"y", "", "abc", "abc"}, + {"y", "x", "abc", "abc"}, + + // Multibyte characters -- verify that we don't try to match in the middle + // of a character. + {"[a-c]*", "x", "\u65e5", "x\u65e5x"}, + {"[^\u65e5]", "x", "abc\u65e5def", "xxx\u65e5xxx"}, + + // Start and end of a string. + {"^[a-c]*", "x", "abcdabc", "xdabc"}, + {"[a-c]*$", "x", "abcdabc", "abcdx"}, + {"^[a-c]*$", "x", "abcdabc", "abcdabc"}, + {"^[a-c]*", "x", "abc", "x"}, + {"[a-c]*$", "x", "abc", "x"}, + {"^[a-c]*$", "x", "abc", "x"}, + {"^[a-c]*", "x", "dabce", "xdabce"}, + {"[a-c]*$", "x", "dabce", "dabcex"}, + {"^[a-c]*$", "x", "dabce", "dabce"}, + {"^[a-c]*", "x", "", "x"}, + {"[a-c]*$", "x", "", "x"}, + {"^[a-c]*$", "x", "", "x"}, + + {"^[a-c]+", "x", "abcdabc", "xdabc"}, + {"[a-c]+$", "x", "abcdabc", "abcdx"}, + {"^[a-c]+$", "x", "abcdabc", "abcdabc"}, + {"^[a-c]+", "x", "abc", "x"}, + {"[a-c]+$", "x", "abc", "x"}, + {"^[a-c]+$", "x", "abc", "x"}, + {"^[a-c]+", "x", "dabce", "dabce"}, + {"[a-c]+$", "x", "dabce", "dabce"}, + {"^[a-c]+$", "x", "dabce", "dabce"}, + {"^[a-c]+", "x", "", ""}, + {"[a-c]+$", "x", "", ""}, + {"^[a-c]+$", "x", "", ""}, + + // Other cases. + {"abc", "def", "abcdefg", "defdefg"}, + {"bc", "BC", "abcbcdcdedef", "aBCBCdcdedef"}, + {"abc", "", "abcdabc", "d"}, + {"x", "xXx", "xxxXxxx", "xXxxXxxXxXxXxxXxxXx"}, + {"abc", "d", "", ""}, + {"abc", "d", "abc", "d"}, + {".+", "x", "abc", "x"}, + {"[a-c]*", "x", "def", "xdxexfx"}, + {"[a-c]+", "x", "abcbcdcdedef", "xdxdedef"}, + {"[a-c]*", "x", "abcbcdcdedef", "xdxdxexdxexfx"}, +} + +type ReplaceFuncTest struct { + pattern string + replacement func(string) string + input, output string +} + +var replaceFuncTests = []ReplaceFuncTest{ + {"[a-c]", func(s string) string { return "x" + s + "y" }, "defabcdef", "defxayxbyxcydef"}, + {"[a-c]+", func(s string) string { return "x" + s + "y" }, "defabcdef", "defxabcydef"}, + {"[a-c]*", func(s string) string { return "x" + s + "y" }, "defabcdef", "xydxyexyfxabcydxyexyfxy"}, +} + +func TestReplaceAll(t *testing.T) { + for _, tc := range replaceTests { + re, err := Compile(tc.pattern) + if err != nil { + t.Errorf("Unexpected error compiling %q: %v", tc.pattern, err) + continue + } + actual := re.ReplaceAllString(tc.input, tc.replacement) + if actual != tc.output { + t.Errorf("%q.Replace(%q,%q) = %q; want %q", + tc.pattern, tc.input, tc.replacement, actual, tc.output) + } + // now try bytes + actual = string(re.ReplaceAll([]byte(tc.input), []byte(tc.replacement))) + if actual != tc.output { + t.Errorf("%q.Replace(%q,%q) = %q; want %q", + tc.pattern, tc.input, tc.replacement, actual, tc.output) + } + } +} + +func TestReplaceAllFunc(t *testing.T) { + for _, tc := range replaceFuncTests { + re, err := Compile(tc.pattern) + if err != nil { + t.Errorf("Unexpected error compiling %q: %v", tc.pattern, err) + continue + } + actual := re.ReplaceAllStringFunc(tc.input, tc.replacement) + if actual != tc.output { + t.Errorf("%q.ReplaceFunc(%q,%q) = %q; want %q", + tc.pattern, tc.input, tc.replacement, actual, tc.output) + } + // now try bytes + actual = string(re.ReplaceAllFunc([]byte(tc.input), func(s []byte) []byte { return []byte(tc.replacement(string(s))) })) + if actual != tc.output { + t.Errorf("%q.ReplaceFunc(%q,%q) = %q; want %q", + tc.pattern, tc.input, tc.replacement, actual, tc.output) + } + } +} + +type MetaTest struct { + pattern, output, literal string + isLiteral bool +} + +var metaTests = []MetaTest{ + {``, ``, ``, true}, + {`foo`, `foo`, `foo`, true}, + {`foo\.\$`, `foo\\\.\\\$`, `foo.$`, true}, // has meta but no operator + {`foo.\$`, `foo\.\\\$`, `foo`, false}, // has escaped operators and real operators + {`!@#$%^&*()_+-=[{]}\|,<.>/?~`, `!@#\$%\^&\*\(\)_\+-=\[\{\]\}\\\|,<\.>/\?~`, `!@#`, false}, +} + +func TestQuoteMeta(t *testing.T) { + for _, tc := range metaTests { + // Verify that QuoteMeta returns the expected string. + quoted := QuoteMeta(tc.pattern) + if quoted != tc.output { + t.Errorf("QuoteMeta(`%s`) = `%s`; want `%s`", + tc.pattern, quoted, tc.output) + continue + } + + // Verify that the quoted string is in fact treated as expected + // by Compile -- i.e. that it matches the original, unquoted string. + if tc.pattern != "" { + re, err := Compile(quoted) + if err != nil { + t.Errorf("Unexpected error compiling QuoteMeta(`%s`): %v", tc.pattern, err) + continue + } + src := "abc" + tc.pattern + "def" + repl := "xyz" + replaced := re.ReplaceAllString(src, repl) + expected := "abcxyzdef" + if replaced != expected { + t.Errorf("QuoteMeta(`%s`).Replace(`%s`,`%s`) = `%s`; want `%s`", + tc.pattern, src, repl, replaced, expected) + } + } + } +} + +func TestLiteralPrefix(t *testing.T) { + for _, tc := range metaTests { + // Literal method needs to scan the pattern. + re := MustCompile(tc.pattern) + str, complete := re.LiteralPrefix() + if complete != tc.isLiteral { + t.Errorf("LiteralPrefix(`%s`) = %t; want %t", tc.pattern, complete, tc.isLiteral) + } + if str != tc.literal { + t.Errorf("LiteralPrefix(`%s`) = `%s`; want `%s`", tc.pattern, str, tc.literal) + } + } +} + +type numSubexpCase struct { + input string + expected int +} + +var numSubexpCases = []numSubexpCase{ + {``, 0}, + {`.*`, 0}, + {`abba`, 0}, + {`ab(b)a`, 1}, + {`ab(.*)a`, 1}, + {`(.*)ab(.*)a`, 2}, + {`(.*)(ab)(.*)a`, 3}, + {`(.*)((a)b)(.*)a`, 4}, + {`(.*)(\(ab)(.*)a`, 3}, + {`(.*)(\(a\)b)(.*)a`, 3}, +} + +func TestNumSubexp(t *testing.T) { + for _, c := range numSubexpCases { + re := MustCompile(c.input) + n := re.NumSubexp() + if n != c.expected { + t.Errorf("NumSubexp for %q returned %d, expected %d", c.input, n, c.expected) + } + } +} + +func BenchmarkLiteral(b *testing.B) { + x := strings.Repeat("x", 50) + "y" + b.StopTimer() + re := MustCompile("y") + b.StartTimer() + for i := 0; i < b.N; i++ { + if !re.MatchString(x) { + println("no match!") + break + } + } +} + +func BenchmarkNotLiteral(b *testing.B) { + x := strings.Repeat("x", 50) + "y" + b.StopTimer() + re := MustCompile(".y") + b.StartTimer() + for i := 0; i < b.N; i++ { + if !re.MatchString(x) { + println("no match!") + break + } + } +} + +func BenchmarkMatchClass(b *testing.B) { + b.StopTimer() + x := strings.Repeat("xxxx", 20) + "w" + re := MustCompile("[abcdw]") + b.StartTimer() + for i := 0; i < b.N; i++ { + if !re.MatchString(x) { + println("no match!") + break + } + } +} + +func BenchmarkMatchClass_InRange(b *testing.B) { + b.StopTimer() + // 'b' is between 'a' and 'c', so the charclass + // range checking is no help here. + x := strings.Repeat("bbbb", 20) + "c" + re := MustCompile("[ac]") + b.StartTimer() + for i := 0; i < b.N; i++ { + if !re.MatchString(x) { + println("no match!") + break + } + } +} + +func BenchmarkReplaceAll(b *testing.B) { + x := "abcdefghijklmnopqrstuvwxyz" + b.StopTimer() + re := MustCompile("[cjrw]") + b.StartTimer() + for i := 0; i < b.N; i++ { + re.ReplaceAllString(x, "") + } +} + +func BenchmarkAnchoredLiteralShortNonMatch(b *testing.B) { + b.StopTimer() + x := []byte("abcdefghijklmnopqrstuvwxyz") + re := MustCompile("^zbc(d|e)") + b.StartTimer() + for i := 0; i < b.N; i++ { + re.Match(x) + } +} + +func BenchmarkAnchoredLiteralLongNonMatch(b *testing.B) { + b.StopTimer() + x := []byte("abcdefghijklmnopqrstuvwxyz") + for i := 0; i < 15; i++ { + x = append(x, x...) + } + re := MustCompile("^zbc(d|e)") + b.StartTimer() + for i := 0; i < b.N; i++ { + re.Match(x) + } +} + +func BenchmarkAnchoredShortMatch(b *testing.B) { + b.StopTimer() + x := []byte("abcdefghijklmnopqrstuvwxyz") + re := MustCompile("^.bc(d|e)") + b.StartTimer() + for i := 0; i < b.N; i++ { + re.Match(x) + } +} + +func BenchmarkAnchoredLongMatch(b *testing.B) { + b.StopTimer() + x := []byte("abcdefghijklmnopqrstuvwxyz") + for i := 0; i < 15; i++ { + x = append(x, x...) + } + re := MustCompile("^.bc(d|e)") + b.StartTimer() + for i := 0; i < b.N; i++ { + re.Match(x) + } +} diff --git a/libgo/go/exp/regexp/exec.go b/libgo/go/exp/regexp/exec.go new file mode 100644 index 0000000..0670bb9 --- /dev/null +++ b/libgo/go/exp/regexp/exec.go @@ -0,0 +1,295 @@ +package regexp + +import "exp/regexp/syntax" + +// A queue is a 'sparse array' holding pending threads of execution. +// See http://research.swtch.com/2008/03/using-uninitialized-memory-for-fun-and.html +type queue struct { + sparse []uint32 + dense []entry +} + +// A entry is an entry on a queue. +// It holds both the instruction pc and the actual thread. +// Some queue entries are just place holders so that the machine +// knows it has considered that pc. Such entries have t == nil. +type entry struct { + pc uint32 + t *thread +} + +// A thread is the state of a single path through the machine: +// an instruction and a corresponding capture array. +// See http://swtch.com/~rsc/regexp/regexp2.html +type thread struct { + inst *syntax.Inst + cap []int +} + +// A machine holds all the state during an NFA simulation for p. +type machine struct { + re *Regexp // corresponding Regexp + p *syntax.Prog // compiled program + q0, q1 queue // two queues for runq, nextq + pool []*thread // pool of available threads + matched bool // whether a match was found + matchcap []int // capture information for the match +} + +// progMachine returns a new machine running the prog p. +func progMachine(p *syntax.Prog) *machine { + m := &machine{p: p} + n := len(m.p.Inst) + m.q0 = queue{make([]uint32, n), make([]entry, 0, n)} + m.q1 = queue{make([]uint32, n), make([]entry, 0, n)} + ncap := p.NumCap + if ncap < 2 { + ncap = 2 + } + m.matchcap = make([]int, ncap) + return m +} + +// alloc allocates a new thread with the given instruction. +// It uses the free pool if possible. +func (m *machine) alloc(i *syntax.Inst) *thread { + var t *thread + if n := len(m.pool); n > 0 { + t = m.pool[n-1] + m.pool = m.pool[:n-1] + } else { + t = new(thread) + t.cap = make([]int, cap(m.matchcap)) + } + t.cap = t.cap[:len(m.matchcap)] + t.inst = i + return t +} + +// free returns t to the free pool. +func (m *machine) free(t *thread) { + m.pool = append(m.pool, t) +} + +// match runs the machine over the input starting at pos. +// It reports whether a match was found. +// If so, m.matchcap holds the submatch information. +func (m *machine) match(i input, pos int) bool { + startCond := m.re.cond + if startCond == ^syntax.EmptyOp(0) { // impossible + return false + } + m.matched = false + for i := range m.matchcap { + m.matchcap[i] = -1 + } + runq, nextq := &m.q0, &m.q1 + rune, rune1 := endOfText, endOfText + width, width1 := 0, 0 + rune, width = i.step(pos) + if rune != endOfText { + rune1, width1 = i.step(pos + width) + } + // TODO: Let caller specify the initial flag setting. + // For now assume pos == 0 is beginning of text and + // pos != 0 is not even beginning of line. + // TODO: Word boundary. + var flag syntax.EmptyOp + if pos == 0 { + flag = syntax.EmptyBeginText | syntax.EmptyBeginLine + } + + // Update flag using lookahead rune. + if rune1 == '\n' { + flag |= syntax.EmptyEndLine + } + if rune1 == endOfText { + flag |= syntax.EmptyEndText + } + + for { + if len(runq.dense) == 0 { + if startCond&syntax.EmptyBeginText != 0 && pos != 0 { + // Anchored match, past beginning of text. + break + } + if m.matched { + // Have match; finished exploring alternatives. + break + } + if len(m.re.prefix) > 0 && rune1 != m.re.prefixRune && i.canCheckPrefix() { + // Match requires literal prefix; fast search for it. + advance := i.index(m.re, pos) + if advance < 0 { + break + } + pos += advance + rune, width = i.step(pos) + rune1, width1 = i.step(pos + width) + } + } + if !m.matched { + if len(m.matchcap) > 0 { + m.matchcap[0] = pos + } + m.add(runq, uint32(m.p.Start), pos, m.matchcap, flag) + } + // TODO: word boundary + flag = 0 + if rune == '\n' { + flag |= syntax.EmptyBeginLine + } + if rune1 == '\n' { + flag |= syntax.EmptyEndLine + } + if rune1 == endOfText { + flag |= syntax.EmptyEndText + } + m.step(runq, nextq, pos, pos+width, rune, flag) + if width == 0 { + break + } + pos += width + rune, width = rune1, width1 + if rune != endOfText { + rune1, width1 = i.step(pos + width) + } + runq, nextq = nextq, runq + } + m.clear(nextq) + return m.matched +} + +// clear frees all threads on the thread queue. +func (m *machine) clear(q *queue) { + for _, d := range q.dense { + if d.t != nil { + m.free(d.t) + } + } + q.dense = q.dense[:0] +} + +// step executes one step of the machine, running each of the threads +// on runq and appending new threads to nextq. +// The step processes the rune c (which may be endOfText), +// which starts at position pos and ends at nextPos. +// nextCond gives the setting for the empty-width flags after c. +func (m *machine) step(runq, nextq *queue, pos, nextPos, c int, nextCond syntax.EmptyOp) { + for j := 0; j < len(runq.dense); j++ { + d := &runq.dense[j] + t := d.t + if t == nil { + continue + } + /* + * If we support leftmost-longest matching: + if longest && matched && match[0] < t.cap[0] { + m.free(t) + continue + } + */ + + i := t.inst + switch i.Op { + default: + panic("bad inst") + + case syntax.InstMatch: + if len(t.cap) > 0 { + t.cap[1] = pos + copy(m.matchcap, t.cap) + } + m.matched = true + for _, d := range runq.dense[j+1:] { + if d.t != nil { + m.free(d.t) + } + } + runq.dense = runq.dense[:0] + + case syntax.InstRune: + if i.MatchRune(c) { + m.add(nextq, i.Out, nextPos, t.cap, nextCond) + } + } + m.free(t) + } + runq.dense = runq.dense[:0] +} + +// add adds an entry to q for pc, unless the q already has such an entry. +// It also recursively adds an entry for all instructions reachable from pc by following +// empty-width conditions satisfied by cond. pos gives the current position +// in the input. +func (m *machine) add(q *queue, pc uint32, pos int, cap []int, cond syntax.EmptyOp) { + if pc == 0 { + return + } + if j := q.sparse[pc]; j < uint32(len(q.dense)) && q.dense[j].pc == pc { + return + } + + j := len(q.dense) + q.dense = q.dense[:j+1] + d := &q.dense[j] + d.t = nil + d.pc = pc + q.sparse[pc] = uint32(j) + + i := &m.p.Inst[pc] + switch i.Op { + default: + panic("unhandled") + case syntax.InstFail: + // nothing + case syntax.InstAlt, syntax.InstAltMatch: + m.add(q, i.Out, pos, cap, cond) + m.add(q, i.Arg, pos, cap, cond) + case syntax.InstEmptyWidth: + if syntax.EmptyOp(i.Arg)&^cond == 0 { + m.add(q, i.Out, pos, cap, cond) + } + case syntax.InstNop: + m.add(q, i.Out, pos, cap, cond) + case syntax.InstCapture: + if int(i.Arg) < len(cap) { + opos := cap[i.Arg] + cap[i.Arg] = pos + m.add(q, i.Out, pos, cap, cond) + cap[i.Arg] = opos + } else { + m.add(q, i.Out, pos, cap, cond) + } + case syntax.InstMatch, syntax.InstRune: + t := m.alloc(i) + if len(t.cap) > 0 { + copy(t.cap, cap) + } + d.t = t + } +} + +// empty is a non-nil 0-element slice, +// so doExecute can avoid an allocation +// when 0 captures are requested from a successful match. +var empty = make([]int, 0) + +// doExecute finds the leftmost match in the input and returns +// the position of its subexpressions. +func (re *Regexp) doExecute(i input, pos int, ncap int) []int { + m := re.get() + m.matchcap = m.matchcap[:ncap] + if !m.match(i, pos) { + re.put(m) + return nil + } + if ncap == 0 { + re.put(m) + return empty // empty but not nil + } + cap := make([]int, ncap) + copy(cap, m.matchcap) + re.put(m) + return cap +} diff --git a/libgo/go/exp/regexp/find_test.go b/libgo/go/exp/regexp/find_test.go new file mode 100644 index 0000000..dddc348 --- /dev/null +++ b/libgo/go/exp/regexp/find_test.go @@ -0,0 +1,472 @@ +// 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 regexp + +import ( + "fmt" + "strings" + "testing" +) + +// For each pattern/text pair, what is the expected output of each function? +// We can derive the textual results from the indexed results, the non-submatch +// results from the submatched results, the single results from the 'all' results, +// and the byte results from the string results. Therefore the table includes +// only the FindAllStringSubmatchIndex result. +type FindTest struct { + pat string + text string + matches [][]int +} + +func (t FindTest) String() string { + return fmt.Sprintf("pat: %#q text: %#q", t.pat, t.text) +} + +var findTests = []FindTest{ + {``, ``, build(1, 0, 0)}, + {`^abcdefg`, "abcdefg", build(1, 0, 7)}, + {`a+`, "baaab", build(1, 1, 4)}, + {"abcd..", "abcdef", build(1, 0, 6)}, + {`a`, "a", build(1, 0, 1)}, + {`x`, "y", nil}, + {`b`, "abc", build(1, 1, 2)}, + {`.`, "a", build(1, 0, 1)}, + {`.*`, "abcdef", build(1, 0, 6)}, + {`^`, "abcde", build(1, 0, 0)}, + {`$`, "abcde", build(1, 5, 5)}, + {`^abcd$`, "abcd", build(1, 0, 4)}, + {`^bcd'`, "abcdef", nil}, + {`^abcd$`, "abcde", nil}, + {`a+`, "baaab", build(1, 1, 4)}, + {`a*`, "baaab", build(3, 0, 0, 1, 4, 5, 5)}, + {`[a-z]+`, "abcd", build(1, 0, 4)}, + {`[^a-z]+`, "ab1234cd", build(1, 2, 6)}, + {`[a\-\]z]+`, "az]-bcz", build(2, 0, 4, 6, 7)}, + {`[^\n]+`, "abcd\n", build(1, 0, 4)}, + {`[日本語]+`, "日本語日本語", build(1, 0, 18)}, + {`日本語+`, "日本語", build(1, 0, 9)}, + {`日本語+`, "日本語語語語", build(1, 0, 18)}, + {`()`, "", build(1, 0, 0, 0, 0)}, + {`(a)`, "a", build(1, 0, 1, 0, 1)}, + {`(.)(.)`, "日a", build(1, 0, 4, 0, 3, 3, 4)}, + {`(.*)`, "", build(1, 0, 0, 0, 0)}, + {`(.*)`, "abcd", build(1, 0, 4, 0, 4)}, + {`(..)(..)`, "abcd", build(1, 0, 4, 0, 2, 2, 4)}, + {`(([^xyz]*)(d))`, "abcd", build(1, 0, 4, 0, 4, 0, 3, 3, 4)}, + {`((a|b|c)*(d))`, "abcd", build(1, 0, 4, 0, 4, 2, 3, 3, 4)}, + {`(((a|b|c)*)(d))`, "abcd", build(1, 0, 4, 0, 4, 0, 3, 2, 3, 3, 4)}, + {`\a\f\n\r\t\v`, "\a\f\n\r\t\v", build(1, 0, 6)}, + {`[\a\f\n\r\t\v]+`, "\a\f\n\r\t\v", build(1, 0, 6)}, + + {`a*(|(b))c*`, "aacc", build(1, 0, 4, 2, 2, -1, -1)}, + {`(.*).*`, "ab", build(1, 0, 2, 0, 2)}, + {`[.]`, ".", build(1, 0, 1)}, + {`/$`, "/abc/", build(1, 4, 5)}, + {`/$`, "/abc", nil}, + + // multiple matches + {`.`, "abc", build(3, 0, 1, 1, 2, 2, 3)}, + {`(.)`, "abc", build(3, 0, 1, 0, 1, 1, 2, 1, 2, 2, 3, 2, 3)}, + {`.(.)`, "abcd", build(2, 0, 2, 1, 2, 2, 4, 3, 4)}, + {`ab*`, "abbaab", build(3, 0, 3, 3, 4, 4, 6)}, + {`a(b*)`, "abbaab", build(3, 0, 3, 1, 3, 3, 4, 4, 4, 4, 6, 5, 6)}, + + // fixed bugs + {`ab$`, "cab", build(1, 1, 3)}, + {`axxb$`, "axxcb", nil}, + {`data`, "daXY data", build(1, 5, 9)}, + {`da(.)a$`, "daXY data", build(1, 5, 9, 7, 8)}, + {`zx+`, "zzx", build(1, 1, 3)}, + + // can backslash-escape any punctuation + {`\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\{\|\}\~`, + `!"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, build(1, 0, 31)}, + {`[\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\{\|\}\~]+`, + `!"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, build(1, 0, 31)}, + {"\\`", "`", build(1, 0, 1)}, + {"[\\`]+", "`", build(1, 0, 1)}, + + // long set of matches (longer than startSize) + { + ".", + "qwertyuiopasdfghjklzxcvbnm1234567890", + build(36, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, + 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, + 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, + 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36), + }, +} + +// build is a helper to construct a [][]int by extracting n sequences from x. +// This represents n matches with len(x)/n submatches each. +func build(n int, x ...int) [][]int { + ret := make([][]int, n) + runLength := len(x) / n + j := 0 + for i := range ret { + ret[i] = make([]int, runLength) + copy(ret[i], x[j:]) + j += runLength + if j > len(x) { + panic("invalid build entry") + } + } + return ret +} + +// First the simple cases. + +func TestFind(t *testing.T) { + for _, test := range findTests { + re := MustCompile(test.pat) + if re.String() != test.pat { + t.Errorf("String() = `%s`; should be `%s`", re.String(), test.pat) + } + result := re.Find([]byte(test.text)) + switch { + case len(test.matches) == 0 && len(result) == 0: + // ok + case test.matches == nil && result != nil: + t.Errorf("expected no match; got one: %s", test) + case test.matches != nil && result == nil: + t.Errorf("expected match; got none: %s", test) + case test.matches != nil && result != nil: + expect := test.text[test.matches[0][0]:test.matches[0][1]] + if expect != string(result) { + t.Errorf("expected %q got %q: %s", expect, result, test) + } + } + } +} + +func TestFindString(t *testing.T) { + for _, test := range findTests { + result := MustCompile(test.pat).FindString(test.text) + switch { + case len(test.matches) == 0 && len(result) == 0: + // ok + case test.matches == nil && result != "": + t.Errorf("expected no match; got one: %s", test) + case test.matches != nil && result == "": + // Tricky because an empty result has two meanings: no match or empty match. + if test.matches[0][0] != test.matches[0][1] { + t.Errorf("expected match; got none: %s", test) + } + case test.matches != nil && result != "": + expect := test.text[test.matches[0][0]:test.matches[0][1]] + if expect != result { + t.Errorf("expected %q got %q: %s", expect, result, test) + } + } + } +} + +func testFindIndex(test *FindTest, result []int, t *testing.T) { + switch { + case len(test.matches) == 0 && len(result) == 0: + // ok + case test.matches == nil && result != nil: + t.Errorf("expected no match; got one: %s", test) + case test.matches != nil && result == nil: + t.Errorf("expected match; got none: %s", test) + case test.matches != nil && result != nil: + expect := test.matches[0] + if expect[0] != result[0] || expect[1] != result[1] { + t.Errorf("expected %v got %v: %s", expect, result, test) + } + } +} + +func TestFindIndex(t *testing.T) { + for _, test := range findTests { + testFindIndex(&test, MustCompile(test.pat).FindIndex([]byte(test.text)), t) + } +} + +func TestFindStringIndex(t *testing.T) { + for _, test := range findTests { + testFindIndex(&test, MustCompile(test.pat).FindStringIndex(test.text), t) + } +} + +func TestFindReaderIndex(t *testing.T) { + for _, test := range findTests { + testFindIndex(&test, MustCompile(test.pat).FindReaderIndex(strings.NewReader(test.text)), t) + } +} + +// Now come the simple All cases. + +func TestFindAll(t *testing.T) { + for _, test := range findTests { + result := MustCompile(test.pat).FindAll([]byte(test.text), -1) + switch { + case test.matches == nil && result == nil: + // ok + case test.matches == nil && result != nil: + t.Errorf("expected no match; got one: %s", test) + case test.matches != nil && result == nil: + t.Fatalf("expected match; got none: %s", test) + case test.matches != nil && result != nil: + if len(test.matches) != len(result) { + t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test) + continue + } + for k, e := range test.matches { + expect := test.text[e[0]:e[1]] + if expect != string(result[k]) { + t.Errorf("match %d: expected %q got %q: %s", k, expect, result[k], test) + } + } + } + } +} + +func TestFindAllString(t *testing.T) { + for _, test := range findTests { + result := MustCompile(test.pat).FindAllString(test.text, -1) + switch { + case test.matches == nil && result == nil: + // ok + case test.matches == nil && result != nil: + t.Errorf("expected no match; got one: %s", test) + case test.matches != nil && result == nil: + t.Errorf("expected match; got none: %s", test) + case test.matches != nil && result != nil: + if len(test.matches) != len(result) { + t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test) + continue + } + for k, e := range test.matches { + expect := test.text[e[0]:e[1]] + if expect != result[k] { + t.Errorf("expected %q got %q: %s", expect, result, test) + } + } + } + } +} + +func testFindAllIndex(test *FindTest, result [][]int, t *testing.T) { + switch { + case test.matches == nil && result == nil: + // ok + case test.matches == nil && result != nil: + t.Errorf("expected no match; got one: %s", test) + case test.matches != nil && result == nil: + t.Errorf("expected match; got none: %s", test) + case test.matches != nil && result != nil: + if len(test.matches) != len(result) { + t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test) + return + } + for k, e := range test.matches { + if e[0] != result[k][0] || e[1] != result[k][1] { + t.Errorf("match %d: expected %v got %v: %s", k, e, result[k], test) + } + } + } +} + +func TestFindAllIndex(t *testing.T) { + for _, test := range findTests { + testFindAllIndex(&test, MustCompile(test.pat).FindAllIndex([]byte(test.text), -1), t) + } +} + +func TestFindAllStringIndex(t *testing.T) { + for _, test := range findTests { + testFindAllIndex(&test, MustCompile(test.pat).FindAllStringIndex(test.text, -1), t) + } +} + +// Now come the Submatch cases. + +func testSubmatchBytes(test *FindTest, n int, submatches []int, result [][]byte, t *testing.T) { + if len(submatches) != len(result)*2 { + t.Errorf("match %d: expected %d submatches; got %d: %s", n, len(submatches)/2, len(result), test) + return + } + for k := 0; k < len(submatches); k += 2 { + if submatches[k] == -1 { + if result[k/2] != nil { + t.Errorf("match %d: expected nil got %q: %s", n, result, test) + } + continue + } + expect := test.text[submatches[k]:submatches[k+1]] + if expect != string(result[k/2]) { + t.Errorf("match %d: expected %q got %q: %s", n, expect, result, test) + return + } + } +} + +func TestFindSubmatch(t *testing.T) { + for _, test := range findTests { + result := MustCompile(test.pat).FindSubmatch([]byte(test.text)) + switch { + case test.matches == nil && result == nil: + // ok + case test.matches == nil && result != nil: + t.Errorf("expected no match; got one: %s", test) + case test.matches != nil && result == nil: + t.Errorf("expected match; got none: %s", test) + case test.matches != nil && result != nil: + testSubmatchBytes(&test, 0, test.matches[0], result, t) + } + } +} + +func testSubmatchString(test *FindTest, n int, submatches []int, result []string, t *testing.T) { + if len(submatches) != len(result)*2 { + t.Errorf("match %d: expected %d submatches; got %d: %s", n, len(submatches)/2, len(result), test) + return + } + for k := 0; k < len(submatches); k += 2 { + if submatches[k] == -1 { + if result[k/2] != "" { + t.Errorf("match %d: expected nil got %q: %s", n, result, test) + } + continue + } + expect := test.text[submatches[k]:submatches[k+1]] + if expect != result[k/2] { + t.Errorf("match %d: expected %q got %q: %s", n, expect, result, test) + return + } + } +} + +func TestFindStringSubmatch(t *testing.T) { + for _, test := range findTests { + result := MustCompile(test.pat).FindStringSubmatch(test.text) + switch { + case test.matches == nil && result == nil: + // ok + case test.matches == nil && result != nil: + t.Errorf("expected no match; got one: %s", test) + case test.matches != nil && result == nil: + t.Errorf("expected match; got none: %s", test) + case test.matches != nil && result != nil: + testSubmatchString(&test, 0, test.matches[0], result, t) + } + } +} + +func testSubmatchIndices(test *FindTest, n int, expect, result []int, t *testing.T) { + if len(expect) != len(result) { + t.Errorf("match %d: expected %d matches; got %d: %s", n, len(expect)/2, len(result)/2, test) + return + } + for k, e := range expect { + if e != result[k] { + t.Errorf("match %d: submatch error: expected %v got %v: %s", n, expect, result, test) + } + } +} + +func testFindSubmatchIndex(test *FindTest, result []int, t *testing.T) { + switch { + case test.matches == nil && result == nil: + // ok + case test.matches == nil && result != nil: + t.Errorf("expected no match; got one: %s", test) + case test.matches != nil && result == nil: + t.Errorf("expected match; got none: %s", test) + case test.matches != nil && result != nil: + testSubmatchIndices(test, 0, test.matches[0], result, t) + } +} + +func TestFindSubmatchIndex(t *testing.T) { + for _, test := range findTests { + testFindSubmatchIndex(&test, MustCompile(test.pat).FindSubmatchIndex([]byte(test.text)), t) + } +} + +func TestFindStringSubmatchIndex(t *testing.T) { + for _, test := range findTests { + testFindSubmatchIndex(&test, MustCompile(test.pat).FindStringSubmatchIndex(test.text), t) + } +} + +func TestFindReaderSubmatchIndex(t *testing.T) { + for _, test := range findTests { + testFindSubmatchIndex(&test, MustCompile(test.pat).FindReaderSubmatchIndex(strings.NewReader(test.text)), t) + } +} + +// Now come the monster AllSubmatch cases. + +func TestFindAllSubmatch(t *testing.T) { + for _, test := range findTests { + result := MustCompile(test.pat).FindAllSubmatch([]byte(test.text), -1) + switch { + case test.matches == nil && result == nil: + // ok + case test.matches == nil && result != nil: + t.Errorf("expected no match; got one: %s", test) + case test.matches != nil && result == nil: + t.Errorf("expected match; got none: %s", test) + case len(test.matches) != len(result): + t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test) + case test.matches != nil && result != nil: + for k, match := range test.matches { + testSubmatchBytes(&test, k, match, result[k], t) + } + } + } +} + +func TestFindAllStringSubmatch(t *testing.T) { + for _, test := range findTests { + result := MustCompile(test.pat).FindAllStringSubmatch(test.text, -1) + switch { + case test.matches == nil && result == nil: + // ok + case test.matches == nil && result != nil: + t.Errorf("expected no match; got one: %s", test) + case test.matches != nil && result == nil: + t.Errorf("expected match; got none: %s", test) + case len(test.matches) != len(result): + t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test) + case test.matches != nil && result != nil: + for k, match := range test.matches { + testSubmatchString(&test, k, match, result[k], t) + } + } + } +} + +func testFindAllSubmatchIndex(test *FindTest, result [][]int, t *testing.T) { + switch { + case test.matches == nil && result == nil: + // ok + case test.matches == nil && result != nil: + t.Errorf("expected no match; got one: %s", test) + case test.matches != nil && result == nil: + t.Errorf("expected match; got none: %s", test) + case len(test.matches) != len(result): + t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test) + case test.matches != nil && result != nil: + for k, match := range test.matches { + testSubmatchIndices(test, k, match, result[k], t) + } + } +} + +func TestFindAllSubmatchIndex(t *testing.T) { + for _, test := range findTests { + testFindAllSubmatchIndex(&test, MustCompile(test.pat).FindAllSubmatchIndex([]byte(test.text), -1), t) + } +} + +func TestFindAllStringSubmatchIndex(t *testing.T) { + for _, test := range findTests { + testFindAllSubmatchIndex(&test, MustCompile(test.pat).FindAllStringSubmatchIndex(test.text, -1), t) + } +} diff --git a/libgo/go/exp/regexp/regexp.go b/libgo/go/exp/regexp/regexp.go new file mode 100644 index 0000000..1b75900 --- /dev/null +++ b/libgo/go/exp/regexp/regexp.go @@ -0,0 +1,795 @@ +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package regexp implements a simple regular expression library. +// +// The syntax of the regular expressions accepted is the same +// general syntax used by Perl, Python, and other languages. +// More precisely, it is the syntax accepted by RE2 and described at +// http://code.google.com/p/re2/wiki/Syntax, except for \C. +// +// All characters are UTF-8-encoded code points. +// +// There are 16 methods of Regexp that match a regular expression and identify +// the matched text. Their names are matched by this regular expression: +// +// Find(All)?(String)?(Submatch)?(Index)? +// +// If 'All' is present, the routine matches successive non-overlapping +// matches of the entire expression. Empty matches abutting a preceding +// match are ignored. The return value is a slice containing the successive +// return values of the corresponding non-'All' routine. These routines take +// an extra integer argument, n; if n >= 0, the function returns at most n +// matches/submatches. +// +// If 'String' is present, the argument is a string; otherwise it is a slice +// of bytes; return values are adjusted as appropriate. +// +// If 'Submatch' is present, the return value is a slice identifying the +// successive submatches of the expression. Submatches are matches of +// parenthesized subexpressions within the regular expression, numbered from +// left to right in order of opening parenthesis. Submatch 0 is the match of +// the entire expression, submatch 1 the match of the first parenthesized +// subexpression, and so on. +// +// If 'Index' is present, matches and submatches are identified by byte index +// pairs within the input string: result[2*n:2*n+1] identifies the indexes of +// the nth submatch. The pair for n==0 identifies the match of the entire +// expression. If 'Index' is not present, the match is identified by the +// text of the match/submatch. If an index is negative, it means that +// subexpression did not match any string in the input. +// +// There is also a subset of the methods that can be applied to text read +// from a RuneReader: +// +// MatchReader, FindReaderIndex, FindReaderSubmatchIndex +// +// This set may grow. Note that regular expression matches may need to +// examine text beyond the text returned by a match, so the methods that +// match text from a RuneReader may read arbitrarily far into the input +// before returning. +// +// (There are a few other methods that do not match this pattern.) +// +package regexp + +import ( + "bytes" + "exp/regexp/syntax" + "io" + "os" + "strings" + "sync" + "utf8" +) + +var debug = false + +// Error is the local type for a parsing error. +type Error string + +func (e Error) String() string { + return string(e) +} + +// Regexp is the representation of a compiled regular expression. +// The public interface is entirely through methods. +// A Regexp is safe for concurrent use by multiple goroutines. +type Regexp struct { + // read-only after Compile + expr string // as passed to Compile + prog *syntax.Prog // compiled program + prefix string // required prefix in unanchored matches + prefixBytes []byte // prefix, as a []byte + prefixComplete bool // prefix is the entire regexp + prefixRune int // first rune in prefix + cond syntax.EmptyOp // empty-width conditions required at start of match + + // cache of machines for running regexp + mu sync.Mutex + machine []*machine +} + +// String returns the source text used to compile the regular expression. +func (re *Regexp) String() string { + return re.expr +} + +// Compile parses a regular expression and returns, if successful, a Regexp +// object that can be used to match against text. +func Compile(expr string) (*Regexp, os.Error) { + re, err := syntax.Parse(expr, syntax.Perl) + if err != nil { + return nil, err + } + prog, err := syntax.Compile(re) + if err != nil { + return nil, err + } + regexp := &Regexp{ + expr: expr, + prog: prog, + } + regexp.prefix, regexp.prefixComplete = prog.Prefix() + if regexp.prefix != "" { + // TODO(rsc): Remove this allocation by adding + // IndexString to package bytes. + regexp.prefixBytes = []byte(regexp.prefix) + regexp.prefixRune, _ = utf8.DecodeRuneInString(regexp.prefix) + } + regexp.cond = prog.StartCond() + return regexp, nil +} + +// get returns a machine to use for matching re. +// It uses the re's machine cache if possible, to avoid +// unnecessary allocation. +func (re *Regexp) get() *machine { + re.mu.Lock() + if n := len(re.machine); n > 0 { + z := re.machine[n-1] + re.machine = re.machine[:n-1] + re.mu.Unlock() + return z + } + re.mu.Unlock() + z := progMachine(re.prog) + z.re = re + return z +} + +// put returns a machine to the re's machine cache. +// There is no attempt to limit the size of the cache, so it will +// grow to the maximum number of simultaneous matches +// run using re. (The cache empties when re gets garbage collected.) +func (re *Regexp) put(z *machine) { + re.mu.Lock() + re.machine = append(re.machine, z) + re.mu.Unlock() +} + +// MustCompile is like Compile but panics if the expression cannot be parsed. +// It simplifies safe initialization of global variables holding compiled regular +// expressions. +func MustCompile(str string) *Regexp { + regexp, error := Compile(str) + if error != nil { + panic(`regexp: compiling "` + str + `": ` + error.String()) + } + return regexp +} + +// NumSubexp returns the number of parenthesized subexpressions in this Regexp. +func (re *Regexp) NumSubexp() int { + // NumCap/2 because captures count ( and ) separately. + // -1 because NumCap counts $0 but NumSubexp does not. + return re.prog.NumCap/2 - 1 +} + +const endOfText = -1 + +// input abstracts different representations of the input text. It provides +// one-character lookahead. +type input interface { + step(pos int) (rune int, width int) // advance one rune + canCheckPrefix() bool // can we look ahead without losing info? + hasPrefix(re *Regexp) bool + index(re *Regexp, pos int) int +} + +// inputString scans a string. +type inputString struct { + str string +} + +func newInputString(str string) *inputString { + return &inputString{str: str} +} + +func (i *inputString) step(pos int) (int, int) { + if pos < len(i.str) { + return utf8.DecodeRuneInString(i.str[pos:len(i.str)]) + } + return endOfText, 0 +} + +func (i *inputString) canCheckPrefix() bool { + return true +} + +func (i *inputString) hasPrefix(re *Regexp) bool { + return strings.HasPrefix(i.str, re.prefix) +} + +func (i *inputString) index(re *Regexp, pos int) int { + return strings.Index(i.str[pos:], re.prefix) +} + +// inputBytes scans a byte slice. +type inputBytes struct { + str []byte +} + +func newInputBytes(str []byte) *inputBytes { + return &inputBytes{str: str} +} + +func (i *inputBytes) step(pos int) (int, int) { + if pos < len(i.str) { + return utf8.DecodeRune(i.str[pos:len(i.str)]) + } + return endOfText, 0 +} + +func (i *inputBytes) canCheckPrefix() bool { + return true +} + +func (i *inputBytes) hasPrefix(re *Regexp) bool { + return bytes.HasPrefix(i.str, re.prefixBytes) +} + +func (i *inputBytes) index(re *Regexp, pos int) int { + return bytes.Index(i.str[pos:], re.prefixBytes) +} + +// inputReader scans a RuneReader. +type inputReader struct { + r io.RuneReader + atEOT bool + pos int +} + +func newInputReader(r io.RuneReader) *inputReader { + return &inputReader{r: r} +} + +func (i *inputReader) step(pos int) (int, int) { + if !i.atEOT && pos != i.pos { + return endOfText, 0 + + } + r, w, err := i.r.ReadRune() + if err != nil { + i.atEOT = true + return endOfText, 0 + } + i.pos += w + return r, w +} + +func (i *inputReader) canCheckPrefix() bool { + return false +} + +func (i *inputReader) hasPrefix(re *Regexp) bool { + return false +} + +func (i *inputReader) index(re *Regexp, pos int) int { + return -1 +} + +// LiteralPrefix returns a literal string that must begin any match +// of the regular expression re. It returns the boolean true if the +// literal string comprises the entire regular expression. +func (re *Regexp) LiteralPrefix() (prefix string, complete bool) { + return re.prefix, re.prefixComplete +} + +// MatchReader returns whether the Regexp matches the text read by the +// RuneReader. The return value is a boolean: true for match, false for no +// match. +func (re *Regexp) MatchReader(r io.RuneReader) bool { + return re.doExecute(newInputReader(r), 0, 0) != nil +} + +// MatchString returns whether the Regexp matches the string s. +// The return value is a boolean: true for match, false for no match. +func (re *Regexp) MatchString(s string) bool { + return re.doExecute(newInputString(s), 0, 0) != nil +} + +// Match returns whether the Regexp matches the byte slice b. +// The return value is a boolean: true for match, false for no match. +func (re *Regexp) Match(b []byte) bool { + return re.doExecute(newInputBytes(b), 0, 0) != nil +} + +// MatchReader checks whether a textual regular expression matches the text +// read by the RuneReader. More complicated queries need to use Compile and +// the full Regexp interface. +func MatchReader(pattern string, r io.RuneReader) (matched bool, error os.Error) { + re, err := Compile(pattern) + if err != nil { + return false, err + } + return re.MatchReader(r), nil +} + +// MatchString checks whether a textual regular expression +// matches a string. More complicated queries need +// to use Compile and the full Regexp interface. +func MatchString(pattern string, s string) (matched bool, error os.Error) { + re, err := Compile(pattern) + if err != nil { + return false, err + } + return re.MatchString(s), nil +} + +// Match checks whether a textual regular expression +// matches a byte slice. More complicated queries need +// to use Compile and the full Regexp interface. +func Match(pattern string, b []byte) (matched bool, error os.Error) { + re, err := Compile(pattern) + if err != nil { + return false, err + } + return re.Match(b), nil +} + +// ReplaceAllString returns a copy of src in which all matches for the Regexp +// have been replaced by repl. No support is provided for expressions +// (e.g. \1 or $1) in the replacement string. +func (re *Regexp) ReplaceAllString(src, repl string) string { + return re.ReplaceAllStringFunc(src, func(string) string { return repl }) +} + +// ReplaceAllStringFunc returns a copy of src in which all matches for the +// Regexp have been replaced by the return value of of function repl (whose +// first argument is the matched string). No support is provided for +// expressions (e.g. \1 or $1) in the replacement string. +func (re *Regexp) ReplaceAllStringFunc(src string, repl func(string) string) string { + lastMatchEnd := 0 // end position of the most recent match + searchPos := 0 // position where we next look for a match + buf := new(bytes.Buffer) + for searchPos <= len(src) { + a := re.doExecute(newInputString(src), searchPos, 2) + if len(a) == 0 { + break // no more matches + } + + // Copy the unmatched characters before this match. + io.WriteString(buf, src[lastMatchEnd:a[0]]) + + // Now insert a copy of the replacement string, but not for a + // match of the empty string immediately after another match. + // (Otherwise, we get double replacement for patterns that + // match both empty and nonempty strings.) + if a[1] > lastMatchEnd || a[0] == 0 { + io.WriteString(buf, repl(src[a[0]:a[1]])) + } + lastMatchEnd = a[1] + + // Advance past this match; always advance at least one character. + _, width := utf8.DecodeRuneInString(src[searchPos:]) + if searchPos+width > a[1] { + searchPos += width + } else if searchPos+1 > a[1] { + // This clause is only needed at the end of the input + // string. In that case, DecodeRuneInString returns width=0. + searchPos++ + } else { + searchPos = a[1] + } + } + + // Copy the unmatched characters after the last match. + io.WriteString(buf, src[lastMatchEnd:]) + + return buf.String() +} + +// ReplaceAll returns a copy of src in which all matches for the Regexp +// have been replaced by repl. No support is provided for expressions +// (e.g. \1 or $1) in the replacement text. +func (re *Regexp) ReplaceAll(src, repl []byte) []byte { + return re.ReplaceAllFunc(src, func([]byte) []byte { return repl }) +} + +// ReplaceAllFunc returns a copy of src in which all matches for the +// Regexp have been replaced by the return value of of function repl (whose +// first argument is the matched []byte). No support is provided for +// expressions (e.g. \1 or $1) in the replacement string. +func (re *Regexp) ReplaceAllFunc(src []byte, repl func([]byte) []byte) []byte { + lastMatchEnd := 0 // end position of the most recent match + searchPos := 0 // position where we next look for a match + buf := new(bytes.Buffer) + for searchPos <= len(src) { + a := re.doExecute(newInputBytes(src), searchPos, 2) + if len(a) == 0 { + break // no more matches + } + + // Copy the unmatched characters before this match. + buf.Write(src[lastMatchEnd:a[0]]) + + // Now insert a copy of the replacement string, but not for a + // match of the empty string immediately after another match. + // (Otherwise, we get double replacement for patterns that + // match both empty and nonempty strings.) + if a[1] > lastMatchEnd || a[0] == 0 { + buf.Write(repl(src[a[0]:a[1]])) + } + lastMatchEnd = a[1] + + // Advance past this match; always advance at least one character. + _, width := utf8.DecodeRune(src[searchPos:]) + if searchPos+width > a[1] { + searchPos += width + } else if searchPos+1 > a[1] { + // This clause is only needed at the end of the input + // string. In that case, DecodeRuneInString returns width=0. + searchPos++ + } else { + searchPos = a[1] + } + } + + // Copy the unmatched characters after the last match. + buf.Write(src[lastMatchEnd:]) + + return buf.Bytes() +} + +var specialBytes = []byte(`\.+*?()|[]{}^$`) + +func special(b byte) bool { + return bytes.IndexByte(specialBytes, b) >= 0 +} + +// QuoteMeta returns a string that quotes all regular expression metacharacters +// inside the argument text; the returned string is a regular expression matching +// the literal text. For example, QuoteMeta(`[foo]`) returns `\[foo\]`. +func QuoteMeta(s string) string { + b := make([]byte, 2*len(s)) + + // A byte loop is correct because all metacharacters are ASCII. + j := 0 + for i := 0; i < len(s); i++ { + if special(s[i]) { + b[j] = '\\' + j++ + } + b[j] = s[i] + j++ + } + return string(b[0:j]) +} + +// Find matches in slice b if b is non-nil, otherwise find matches in string s. +func (re *Regexp) allMatches(s string, b []byte, n int, deliver func([]int)) { + var end int + if b == nil { + end = len(s) + } else { + end = len(b) + } + + for pos, i, prevMatchEnd := 0, 0, -1; i < n && pos <= end; { + var in input + if b == nil { + in = newInputString(s) + } else { + in = newInputBytes(b) + } + matches := re.doExecute(in, pos, re.prog.NumCap) + if len(matches) == 0 { + break + } + + accept := true + if matches[1] == pos { + // We've found an empty match. + if matches[0] == prevMatchEnd { + // We don't allow an empty match right + // after a previous match, so ignore it. + accept = false + } + var width int + // TODO: use step() + if b == nil { + _, width = utf8.DecodeRuneInString(s[pos:end]) + } else { + _, width = utf8.DecodeRune(b[pos:end]) + } + if width > 0 { + pos += width + } else { + pos = end + 1 + } + } else { + pos = matches[1] + } + prevMatchEnd = matches[1] + + if accept { + deliver(matches) + i++ + } + } +} + +// Find returns a slice holding the text of the leftmost match in b of the regular expression. +// A return value of nil indicates no match. +func (re *Regexp) Find(b []byte) []byte { + a := re.doExecute(newInputBytes(b), 0, 2) + if a == nil { + return nil + } + return b[a[0]:a[1]] +} + +// FindIndex returns a two-element slice of integers defining the location of +// the leftmost match in b of the regular expression. The match itself is at +// b[loc[0]:loc[1]]. +// A return value of nil indicates no match. +func (re *Regexp) FindIndex(b []byte) (loc []int) { + a := re.doExecute(newInputBytes(b), 0, 2) + if a == nil { + return nil + } + return a[0:2] +} + +// FindString returns a string holding the text of the leftmost match in s of the regular +// expression. If there is no match, the return value is an empty string, +// but it will also be empty if the regular expression successfully matches +// an empty string. Use FindStringIndex or FindStringSubmatch if it is +// necessary to distinguish these cases. +func (re *Regexp) FindString(s string) string { + a := re.doExecute(newInputString(s), 0, 2) + if a == nil { + return "" + } + return s[a[0]:a[1]] +} + +// FindStringIndex returns a two-element slice of integers defining the +// location of the leftmost match in s of the regular expression. The match +// itself is at s[loc[0]:loc[1]]. +// A return value of nil indicates no match. +func (re *Regexp) FindStringIndex(s string) []int { + a := re.doExecute(newInputString(s), 0, 2) + if a == nil { + return nil + } + return a[0:2] +} + +// FindReaderIndex returns a two-element slice of integers defining the +// location of the leftmost match of the regular expression in text read from +// the RuneReader. The match itself is at s[loc[0]:loc[1]]. A return +// value of nil indicates no match. +func (re *Regexp) FindReaderIndex(r io.RuneReader) []int { + a := re.doExecute(newInputReader(r), 0, 2) + if a == nil { + return nil + } + return a[0:2] +} + +// FindSubmatch returns a slice of slices holding the text of the leftmost +// match of the regular expression in b and the matches, if any, of its +// subexpressions, as defined by the 'Submatch' descriptions in the package +// comment. +// A return value of nil indicates no match. +func (re *Regexp) FindSubmatch(b []byte) [][]byte { + a := re.doExecute(newInputBytes(b), 0, re.prog.NumCap) + if a == nil { + return nil + } + ret := make([][]byte, len(a)/2) + for i := range ret { + if a[2*i] >= 0 { + ret[i] = b[a[2*i]:a[2*i+1]] + } + } + return ret +} + +// FindSubmatchIndex returns a slice holding the index pairs identifying the +// leftmost match of the regular expression in b and the matches, if any, of +// its subexpressions, as defined by the 'Submatch' and 'Index' descriptions +// in the package comment. +// A return value of nil indicates no match. +func (re *Regexp) FindSubmatchIndex(b []byte) []int { + return re.doExecute(newInputBytes(b), 0, re.prog.NumCap) +} + +// FindStringSubmatch returns a slice of strings holding the text of the +// leftmost match of the regular expression in s and the matches, if any, of +// its subexpressions, as defined by the 'Submatch' description in the +// package comment. +// A return value of nil indicates no match. +func (re *Regexp) FindStringSubmatch(s string) []string { + a := re.doExecute(newInputString(s), 0, re.prog.NumCap) + if a == nil { + return nil + } + ret := make([]string, len(a)/2) + for i := range ret { + if a[2*i] >= 0 { + ret[i] = s[a[2*i]:a[2*i+1]] + } + } + return ret +} + +// FindStringSubmatchIndex returns a slice holding the index pairs +// identifying the leftmost match of the regular expression in s and the +// matches, if any, of its subexpressions, as defined by the 'Submatch' and +// 'Index' descriptions in the package comment. +// A return value of nil indicates no match. +func (re *Regexp) FindStringSubmatchIndex(s string) []int { + return re.doExecute(newInputString(s), 0, re.prog.NumCap) +} + +// FindReaderSubmatchIndex returns a slice holding the index pairs +// identifying the leftmost match of the regular expression of text read by +// the RuneReader, and the matches, if any, of its subexpressions, as defined +// by the 'Submatch' and 'Index' descriptions in the package comment. A +// return value of nil indicates no match. +func (re *Regexp) FindReaderSubmatchIndex(r io.RuneReader) []int { + return re.doExecute(newInputReader(r), 0, re.prog.NumCap) +} + +const startSize = 10 // The size at which to start a slice in the 'All' routines. + +// FindAll is the 'All' version of Find; it returns a slice of all successive +// matches of the expression, as defined by the 'All' description in the +// package comment. +// A return value of nil indicates no match. +func (re *Regexp) FindAll(b []byte, n int) [][]byte { + if n < 0 { + n = len(b) + 1 + } + result := make([][]byte, 0, startSize) + re.allMatches("", b, n, func(match []int) { + result = append(result, b[match[0]:match[1]]) + }) + if len(result) == 0 { + return nil + } + return result +} + +// FindAllIndex is the 'All' version of FindIndex; it returns a slice of all +// successive matches of the expression, as defined by the 'All' description +// in the package comment. +// A return value of nil indicates no match. +func (re *Regexp) FindAllIndex(b []byte, n int) [][]int { + if n < 0 { + n = len(b) + 1 + } + result := make([][]int, 0, startSize) + re.allMatches("", b, n, func(match []int) { + result = append(result, match[0:2]) + }) + if len(result) == 0 { + return nil + } + return result +} + +// FindAllString is the 'All' version of FindString; it returns a slice of all +// successive matches of the expression, as defined by the 'All' description +// in the package comment. +// A return value of nil indicates no match. +func (re *Regexp) FindAllString(s string, n int) []string { + if n < 0 { + n = len(s) + 1 + } + result := make([]string, 0, startSize) + re.allMatches(s, nil, n, func(match []int) { + result = append(result, s[match[0]:match[1]]) + }) + if len(result) == 0 { + return nil + } + return result +} + +// FindAllStringIndex is the 'All' version of FindStringIndex; it returns a +// slice of all successive matches of the expression, as defined by the 'All' +// description in the package comment. +// A return value of nil indicates no match. +func (re *Regexp) FindAllStringIndex(s string, n int) [][]int { + if n < 0 { + n = len(s) + 1 + } + result := make([][]int, 0, startSize) + re.allMatches(s, nil, n, func(match []int) { + result = append(result, match[0:2]) + }) + if len(result) == 0 { + return nil + } + return result +} + +// FindAllSubmatch is the 'All' version of FindSubmatch; it returns a slice +// of all successive matches of the expression, as defined by the 'All' +// description in the package comment. +// A return value of nil indicates no match. +func (re *Regexp) FindAllSubmatch(b []byte, n int) [][][]byte { + if n < 0 { + n = len(b) + 1 + } + result := make([][][]byte, 0, startSize) + re.allMatches("", b, n, func(match []int) { + slice := make([][]byte, len(match)/2) + for j := range slice { + if match[2*j] >= 0 { + slice[j] = b[match[2*j]:match[2*j+1]] + } + } + result = append(result, slice) + }) + if len(result) == 0 { + return nil + } + return result +} + +// FindAllSubmatchIndex is the 'All' version of FindSubmatchIndex; it returns +// a slice of all successive matches of the expression, as defined by the +// 'All' description in the package comment. +// A return value of nil indicates no match. +func (re *Regexp) FindAllSubmatchIndex(b []byte, n int) [][]int { + if n < 0 { + n = len(b) + 1 + } + result := make([][]int, 0, startSize) + re.allMatches("", b, n, func(match []int) { + result = append(result, match) + }) + if len(result) == 0 { + return nil + } + return result +} + +// FindAllStringSubmatch is the 'All' version of FindStringSubmatch; it +// returns a slice of all successive matches of the expression, as defined by +// the 'All' description in the package comment. +// A return value of nil indicates no match. +func (re *Regexp) FindAllStringSubmatch(s string, n int) [][]string { + if n < 0 { + n = len(s) + 1 + } + result := make([][]string, 0, startSize) + re.allMatches(s, nil, n, func(match []int) { + slice := make([]string, len(match)/2) + for j := range slice { + if match[2*j] >= 0 { + slice[j] = s[match[2*j]:match[2*j+1]] + } + } + result = append(result, slice) + }) + if len(result) == 0 { + return nil + } + return result +} + +// FindAllStringSubmatchIndex is the 'All' version of +// FindStringSubmatchIndex; it returns a slice of all successive matches of +// the expression, as defined by the 'All' description in the package +// comment. +// A return value of nil indicates no match. +func (re *Regexp) FindAllStringSubmatchIndex(s string, n int) [][]int { + if n < 0 { + n = len(s) + 1 + } + result := make([][]int, 0, startSize) + re.allMatches(s, nil, n, func(match []int) { + result = append(result, match) + }) + if len(result) == 0 { + return nil + } + return result +} diff --git a/libgo/go/exp/regexp/syntax/compile.go b/libgo/go/exp/regexp/syntax/compile.go new file mode 100644 index 0000000..5ea2425 --- /dev/null +++ b/libgo/go/exp/regexp/syntax/compile.go @@ -0,0 +1,269 @@ +package syntax + +import ( + "os" + "unicode" +) + +// A patchList is a list of instruction pointers that need to be filled in (patched). +// Because the pointers haven't been filled in yet, we can reuse their storage +// to hold the list. It's kind of sleazy, but works well in practice. +// See http://swtch.com/~rsc/regexp/regexp1.html for inspiration. +// +// These aren't really pointers: they're integers, so we can reinterpret them +// this way without using package unsafe. A value l denotes +// p.inst[l>>1].Out (l&1==0) or .Arg (l&1==1). +// l == 0 denotes the empty list, okay because we start every program +// with a fail instruction, so we'll never want to point at its output link. +type patchList uint32 + +func (l patchList) next(p *Prog) patchList { + i := &p.Inst[l>>1] + if l&1 == 0 { + return patchList(i.Out) + } + return patchList(i.Arg) +} + +func (l patchList) patch(p *Prog, val uint32) { + for l != 0 { + i := &p.Inst[l>>1] + if l&1 == 0 { + l = patchList(i.Out) + i.Out = val + } else { + l = patchList(i.Arg) + i.Arg = val + } + } +} + +func (l1 patchList) append(p *Prog, l2 patchList) patchList { + if l1 == 0 { + return l2 + } + if l2 == 0 { + return l1 + } + + last := l1 + for { + next := last.next(p) + if next == 0 { + break + } + last = next + } + + i := &p.Inst[last>>1] + if last&1 == 0 { + i.Out = uint32(l2) + } else { + i.Arg = uint32(l2) + } + return l1 +} + +// A frag represents a compiled program fragment. +type frag struct { + i uint32 // index of first instruction + out patchList // where to record end instruction +} + +type compiler struct { + p *Prog +} + +// Compile compiles the regexp into a program to be executed. +func Compile(re *Regexp) (*Prog, os.Error) { + var c compiler + c.init() + f := c.compile(re) + f.out.patch(c.p, c.inst(InstMatch).i) + c.p.Start = int(f.i) + return c.p, nil +} + +func (c *compiler) init() { + c.p = new(Prog) + c.p.NumCap = 2 // implicit ( and ) for whole match $0 + c.inst(InstFail) +} + +var anyRuneNotNL = []int{0, '\n' - 1, '\n' - 1, unicode.MaxRune} +var anyRune = []int{0, unicode.MaxRune} + +func (c *compiler) compile(re *Regexp) frag { + switch re.Op { + case OpNoMatch: + return c.fail() + case OpEmptyMatch: + return c.nop() + case OpLiteral: + if len(re.Rune) == 0 { + return c.nop() + } + var f frag + for j := range re.Rune { + f1 := c.rune(re.Rune[j : j+1]) + if j == 0 { + f = f1 + } else { + f = c.cat(f, f1) + } + } + return f + case OpCharClass: + return c.rune(re.Rune) + case OpAnyCharNotNL: + return c.rune(anyRuneNotNL) + case OpAnyChar: + return c.rune(anyRune) + case OpBeginLine: + return c.empty(EmptyBeginLine) + case OpEndLine: + return c.empty(EmptyEndLine) + case OpBeginText: + return c.empty(EmptyBeginText) + case OpEndText: + return c.empty(EmptyEndText) + case OpWordBoundary: + return c.empty(EmptyWordBoundary) + case OpNoWordBoundary: + return c.empty(EmptyNoWordBoundary) + case OpCapture: + bra := c.cap(uint32(re.Cap << 1)) + sub := c.compile(re.Sub[0]) + ket := c.cap(uint32(re.Cap<<1 | 1)) + return c.cat(c.cat(bra, sub), ket) + case OpStar: + return c.star(c.compile(re.Sub[0]), re.Flags&NonGreedy != 0) + case OpPlus: + return c.plus(c.compile(re.Sub[0]), re.Flags&NonGreedy != 0) + case OpQuest: + return c.quest(c.compile(re.Sub[0]), re.Flags&NonGreedy != 0) + case OpConcat: + if len(re.Sub) == 0 { + return c.nop() + } + var f frag + for i, sub := range re.Sub { + if i == 0 { + f = c.compile(sub) + } else { + f = c.cat(f, c.compile(sub)) + } + } + return f + case OpAlternate: + var f frag + for _, sub := range re.Sub { + f = c.alt(f, c.compile(sub)) + } + return f + } + panic("regexp: unhandled case in compile") +} + +func (c *compiler) inst(op InstOp) frag { + // TODO: impose length limit + f := frag{i: uint32(len(c.p.Inst))} + c.p.Inst = append(c.p.Inst, Inst{Op: op}) + return f +} + +func (c *compiler) nop() frag { + f := c.inst(InstNop) + f.out = patchList(f.i << 1) + return f +} + +func (c *compiler) fail() frag { + return frag{} +} + +func (c *compiler) cap(arg uint32) frag { + f := c.inst(InstCapture) + f.out = patchList(f.i << 1) + c.p.Inst[f.i].Arg = arg + + if c.p.NumCap < int(arg)+1 { + c.p.NumCap = int(arg) + 1 + } + return f +} + +func (c *compiler) cat(f1, f2 frag) frag { + // concat of failure is failure + if f1.i == 0 || f2.i == 0 { + return frag{} + } + + // TODO: elide nop + + f1.out.patch(c.p, f2.i) + return frag{f1.i, f2.out} +} + +func (c *compiler) alt(f1, f2 frag) frag { + // alt of failure is other + if f1.i == 0 { + return f2 + } + if f2.i == 0 { + return f1 + } + + f := c.inst(InstAlt) + i := &c.p.Inst[f.i] + i.Out = f1.i + i.Arg = f2.i + f.out = f1.out.append(c.p, f2.out) + return f +} + +func (c *compiler) quest(f1 frag, nongreedy bool) frag { + f := c.inst(InstAlt) + i := &c.p.Inst[f.i] + if nongreedy { + i.Arg = f1.i + f.out = patchList(f.i << 1) + } else { + i.Out = f1.i + f.out = patchList(f.i<<1 | 1) + } + f.out = f.out.append(c.p, f1.out) + return f +} + +func (c *compiler) star(f1 frag, nongreedy bool) frag { + f := c.inst(InstAlt) + i := &c.p.Inst[f.i] + if nongreedy { + i.Arg = f1.i + f.out = patchList(f.i << 1) + } else { + i.Out = f1.i + f.out = patchList(f.i<<1 | 1) + } + f1.out.patch(c.p, f.i) + return f +} + +func (c *compiler) plus(f1 frag, nongreedy bool) frag { + return frag{f1.i, c.star(f1, nongreedy).out} +} + +func (c *compiler) empty(op EmptyOp) frag { + f := c.inst(InstEmptyWidth) + c.p.Inst[f.i].Arg = uint32(op) + f.out = patchList(f.i << 1) + return f +} + +func (c *compiler) rune(rune []int) frag { + f := c.inst(InstRune) + c.p.Inst[f.i].Rune = rune + f.out = patchList(f.i << 1) + return f +} diff --git a/libgo/go/exp/regexp/syntax/parse.go b/libgo/go/exp/regexp/syntax/parse.go new file mode 100644 index 0000000..4eed182 --- /dev/null +++ b/libgo/go/exp/regexp/syntax/parse.go @@ -0,0 +1,1797 @@ +// 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 syntax + +import ( + "os" + "sort" + "strings" + "unicode" + "utf8" +) + +// An Error describes a failure to parse a regular expression +// and gives the offending expression. +type Error struct { + Code ErrorCode + Expr string +} + +func (e *Error) String() string { + return "error parsing regexp: " + e.Code.String() + ": `" + e.Expr + "`" +} + +// An ErrorCode describes a failure to parse a regular expression. +type ErrorCode string + +const ( + // Unexpected error + ErrInternalError ErrorCode = "regexp/syntax: internal error" + + // Parse errors + ErrInvalidCharClass ErrorCode = "invalid character class" + ErrInvalidCharRange ErrorCode = "invalid character class range" + ErrInvalidEscape ErrorCode = "invalid escape sequence" + ErrInvalidNamedCapture ErrorCode = "invalid named capture" + ErrInvalidPerlOp ErrorCode = "invalid or unsupported Perl syntax" + ErrInvalidRepeatOp ErrorCode = "invalid nested repetition operator" + ErrInvalidRepeatSize ErrorCode = "invalid repeat count" + ErrInvalidUTF8 ErrorCode = "invalid UTF-8" + ErrMissingBracket ErrorCode = "missing closing ]" + ErrMissingParen ErrorCode = "missing closing )" + ErrMissingRepeatArgument ErrorCode = "missing argument to repetition operator" + ErrTrailingBackslash ErrorCode = "trailing backslash at end of expression" +) + +func (e ErrorCode) String() string { + return string(e) +} + +// Flags control the behavior of the parser and record information about regexp context. +type Flags uint16 + +const ( + FoldCase Flags = 1 << iota // case-insensitive match + Literal // treat pattern as literal string + ClassNL // allow character classes like [^a-z] and [[:space:]] to match newline + DotNL // allow . to match newline + OneLine // treat ^ and $ as only matching at beginning and end of text + NonGreedy // make repetition operators default to non-greedy + PerlX // allow Perl extensions + UnicodeGroups // allow \p{Han}, \P{Han} for Unicode group and negation + WasDollar // regexp OpEndText was $, not \z + Simple // regexp contains no counted repetition + + MatchNL = ClassNL | DotNL + + Perl = ClassNL | OneLine | PerlX | UnicodeGroups // as close to Perl as possible + POSIX Flags = 0 // POSIX syntax +) + +// Pseudo-ops for parsing stack. +const ( + opLeftParen = opPseudo + iota + opVerticalBar +) + +type parser struct { + flags Flags // parse mode flags + stack []*Regexp // stack of parsed expressions + free *Regexp + numCap int // number of capturing groups seen + wholeRegexp string + tmpClass []int // temporary char class work space +} + +func (p *parser) newRegexp(op Op) *Regexp { + re := p.free + if re != nil { + p.free = re.Sub0[0] + *re = Regexp{} + } else { + re = new(Regexp) + } + re.Op = op + return re +} + +func (p *parser) reuse(re *Regexp) { + re.Sub0[0] = p.free + p.free = re +} + +// Parse stack manipulation. + +// push pushes the regexp re onto the parse stack and returns the regexp. +func (p *parser) push(re *Regexp) *Regexp { + if re.Op == OpCharClass && len(re.Rune) == 2 && re.Rune[0] == re.Rune[1] { + // Single rune. + if p.maybeConcat(re.Rune[0], p.flags&^FoldCase) { + return nil + } + re.Op = OpLiteral + re.Rune = re.Rune[:1] + re.Flags = p.flags &^ FoldCase + } else if re.Op == OpCharClass && len(re.Rune) == 4 && + re.Rune[0] == re.Rune[1] && re.Rune[2] == re.Rune[3] && + unicode.SimpleFold(re.Rune[0]) == re.Rune[2] && + unicode.SimpleFold(re.Rune[2]) == re.Rune[0] || + re.Op == OpCharClass && len(re.Rune) == 2 && + re.Rune[0]+1 == re.Rune[1] && + unicode.SimpleFold(re.Rune[0]) == re.Rune[1] && + unicode.SimpleFold(re.Rune[1]) == re.Rune[0] { + // Case-insensitive rune like [Aa] or [Δδ]. + if p.maybeConcat(re.Rune[0], p.flags|FoldCase) { + return nil + } + + // Rewrite as (case-insensitive) literal. + re.Op = OpLiteral + re.Rune = re.Rune[:1] + re.Flags = p.flags | FoldCase + } else { + // Incremental concatenation. + p.maybeConcat(-1, 0) + } + + p.stack = append(p.stack, re) + return re +} + +// maybeConcat implements incremental concatenation +// of literal runes into string nodes. The parser calls this +// before each push, so only the top fragment of the stack +// might need processing. Since this is called before a push, +// the topmost literal is no longer subject to operators like * +// (Otherwise ab* would turn into (ab)*.) +// If r >= 0 and there's a node left over, maybeConcat uses it +// to push r with the given flags. +// maybeConcat reports whether r was pushed. +func (p *parser) maybeConcat(r int, flags Flags) bool { + n := len(p.stack) + if n < 2 { + return false + } + + re1 := p.stack[n-1] + re2 := p.stack[n-2] + if re1.Op != OpLiteral || re2.Op != OpLiteral || re1.Flags&FoldCase != re2.Flags&FoldCase { + return false + } + + // Push re1 into re2. + re2.Rune = append(re2.Rune, re1.Rune...) + + // Reuse re1 if possible. + if r >= 0 { + re1.Rune = re1.Rune0[:1] + re1.Rune[0] = r + re1.Flags = flags + return true + } + + p.stack = p.stack[:n-1] + p.reuse(re1) + return false // did not push r +} + +// newLiteral returns a new OpLiteral Regexp with the given flags +func (p *parser) newLiteral(r int, flags Flags) *Regexp { + re := p.newRegexp(OpLiteral) + re.Flags = flags + re.Rune0[0] = r + re.Rune = re.Rune0[:1] + return re +} + +// literal pushes a literal regexp for the rune r on the stack +// and returns that regexp. +func (p *parser) literal(r int) { + p.push(p.newLiteral(r, p.flags)) +} + +// op pushes a regexp with the given op onto the stack +// and returns that regexp. +func (p *parser) op(op Op) *Regexp { + re := p.newRegexp(op) + re.Flags = p.flags + return p.push(re) +} + +// repeat replaces the top stack element with itself repeated +// according to op. +func (p *parser) repeat(op Op, min, max int, opstr, t, lastRepeat string) (string, os.Error) { + flags := p.flags + if p.flags&PerlX != 0 { + if len(t) > 0 && t[0] == '?' { + t = t[1:] + flags ^= NonGreedy + } + if lastRepeat != "" { + // In Perl it is not allowed to stack repetition operators: + // a** is a syntax error, not a doubled star, and a++ means + // something else entirely, which we don't support! + return "", &Error{ErrInvalidRepeatOp, lastRepeat[:len(lastRepeat)-len(t)]} + } + } + n := len(p.stack) + if n == 0 { + return "", &Error{ErrMissingRepeatArgument, opstr} + } + sub := p.stack[n-1] + re := p.newRegexp(op) + re.Min = min + re.Max = max + re.Flags = flags + re.Sub = re.Sub0[:1] + re.Sub[0] = sub + p.stack[n-1] = re + return t, nil +} + +// concat replaces the top of the stack (above the topmost '|' or '(') with its concatenation. +func (p *parser) concat() *Regexp { + p.maybeConcat(-1, 0) + + // Scan down to find pseudo-operator | or (. + i := len(p.stack) + for i > 0 && p.stack[i-1].Op < opPseudo { + i-- + } + subs := p.stack[i:] + p.stack = p.stack[:i] + + // Empty concatenation is special case. + if len(subs) == 0 { + return p.push(p.newRegexp(OpEmptyMatch)) + } + + return p.push(p.collapse(subs, OpConcat)) +} + +// alternate replaces the top of the stack (above the topmost '(') with its alternation. +func (p *parser) alternate() *Regexp { + // Scan down to find pseudo-operator (. + // There are no | above (. + i := len(p.stack) + for i > 0 && p.stack[i-1].Op < opPseudo { + i-- + } + subs := p.stack[i:] + p.stack = p.stack[:i] + + // Make sure top class is clean. + // All the others already are (see swapVerticalBar). + if len(subs) > 0 { + cleanAlt(subs[len(subs)-1]) + } + + // Empty alternate is special case + // (shouldn't happen but easy to handle). + if len(subs) == 0 { + return p.push(p.newRegexp(OpNoMatch)) + } + + return p.push(p.collapse(subs, OpAlternate)) +} + +// cleanAlt cleans re for eventual inclusion in an alternation. +func cleanAlt(re *Regexp) { + switch re.Op { + case OpCharClass: + re.Rune = cleanClass(&re.Rune) + if len(re.Rune) == 2 && re.Rune[0] == 0 && re.Rune[1] == unicode.MaxRune { + re.Rune = nil + re.Op = OpAnyChar + return + } + if len(re.Rune) == 4 && re.Rune[0] == 0 && re.Rune[1] == '\n'-1 && re.Rune[2] == '\n'+1 && re.Rune[3] == unicode.MaxRune { + re.Rune = nil + re.Op = OpAnyCharNotNL + return + } + if cap(re.Rune)-len(re.Rune) > 100 { + // re.Rune will not grow any more. + // Make a copy or inline to reclaim storage. + re.Rune = append(re.Rune0[:0], re.Rune...) + } + } +} + +// collapse returns the result of applying op to sub. +// If sub contains op nodes, they all get hoisted up +// so that there is never a concat of a concat or an +// alternate of an alternate. +func (p *parser) collapse(subs []*Regexp, op Op) *Regexp { + if len(subs) == 1 { + return subs[0] + } + re := p.newRegexp(op) + re.Sub = re.Sub0[:0] + for _, sub := range subs { + if sub.Op == op { + re.Sub = append(re.Sub, sub.Sub...) + p.reuse(sub) + } else { + re.Sub = append(re.Sub, sub) + } + } + if op == OpAlternate { + re.Sub = p.factor(re.Sub, re.Flags) + if len(re.Sub) == 1 { + old := re + re = re.Sub[0] + p.reuse(old) + } + } + return re +} + +// factor factors common prefixes from the alternation list sub. +// It returns a replacement list that reuses the same storage and +// frees (passes to p.reuse) any removed *Regexps. +// +// For example, +// ABC|ABD|AEF|BCX|BCY +// simplifies by literal prefix extraction to +// A(B(C|D)|EF)|BC(X|Y) +// which simplifies by character class introduction to +// A(B[CD]|EF)|BC[XY] +// +func (p *parser) factor(sub []*Regexp, flags Flags) []*Regexp { + if len(sub) < 2 { + return sub + } + + // Round 1: Factor out common literal prefixes. + var str []int + var strflags Flags + start := 0 + out := sub[:0] + for i := 0; i <= len(sub); i++ { + // Invariant: the Regexps that were in sub[0:start] have been + // used or marked for reuse, and the slice space has been reused + // for out (len(out) <= start). + // + // Invariant: sub[start:i] consists of regexps that all begin + // with str as modified by strflags. + var istr []int + var iflags Flags + if i < len(sub) { + istr, iflags = p.leadingString(sub[i]) + if iflags == strflags { + same := 0 + for same < len(str) && same < len(istr) && str[same] == istr[same] { + same++ + } + if same > 0 { + // Matches at least one rune in current range. + // Keep going around. + str = str[:same] + continue + } + } + } + + // Found end of a run with common leading literal string: + // sub[start:i] all begin with str[0:len(str)], but sub[i] + // does not even begin with str[0]. + // + // Factor out common string and append factored expression to out. + if i == start { + // Nothing to do - run of length 0. + } else if i == start+1 { + // Just one: don't bother factoring. + out = append(out, sub[start]) + } else { + // Construct factored form: prefix(suffix1|suffix2|...) + prefix := p.newRegexp(OpLiteral) + prefix.Flags = strflags + prefix.Rune = append(prefix.Rune[:0], str...) + + for j := start; j < i; j++ { + sub[j] = p.removeLeadingString(sub[j], len(str)) + } + suffix := p.collapse(sub[start:i], OpAlternate) // recurse + + re := p.newRegexp(OpConcat) + re.Sub = append(re.Sub[:0], prefix, suffix) + out = append(out, re) + } + + // Prepare for next iteration. + start = i + str = istr + strflags = iflags + } + sub = out + + // Round 2: Factor out common complex prefixes, + // just the first piece of each concatenation, + // whatever it is. This is good enough a lot of the time. + start = 0 + out = sub[:0] + var first *Regexp + for i := 0; i <= len(sub); i++ { + // Invariant: the Regexps that were in sub[0:start] have been + // used or marked for reuse, and the slice space has been reused + // for out (len(out) <= start). + // + // Invariant: sub[start:i] consists of regexps that all begin + // with str as modified by strflags. + var ifirst *Regexp + if i < len(sub) { + ifirst = p.leadingRegexp(sub[i]) + if first != nil && first.Equal(ifirst) { + continue + } + } + + // Found end of a run with common leading regexp: + // sub[start:i] all begin with first but sub[i] does not. + // + // Factor out common regexp and append factored expression to out. + if i == start { + // Nothing to do - run of length 0. + } else if i == start+1 { + // Just one: don't bother factoring. + out = append(out, sub[start]) + } else { + // Construct factored form: prefix(suffix1|suffix2|...) + prefix := first + + for j := start; j < i; j++ { + reuse := j != start // prefix came from sub[start] + sub[j] = p.removeLeadingRegexp(sub[j], reuse) + } + suffix := p.collapse(sub[start:i], OpAlternate) // recurse + + re := p.newRegexp(OpConcat) + re.Sub = append(re.Sub[:0], prefix, suffix) + out = append(out, re) + } + + // Prepare for next iteration. + start = i + first = ifirst + } + sub = out + + // Round 3: Collapse runs of single literals into character classes. + start = 0 + out = sub[:0] + for i := 0; i <= len(sub); i++ { + // Invariant: the Regexps that were in sub[0:start] have been + // used or marked for reuse, and the slice space has been reused + // for out (len(out) <= start). + // + // Invariant: sub[start:i] consists of regexps that are either + // literal runes or character classes. + if i < len(sub) && isCharClass(sub[i]) { + continue + } + + // sub[i] is not a char or char class; + // emit char class for sub[start:i]... + if i == start { + // Nothing to do - run of length 0. + } else if i == start+1 { + out = append(out, sub[start]) + } else { + // Make new char class. + // Start with most complex regexp in sub[start]. + max := start + for j := start + 1; j < i; j++ { + if sub[max].Op < sub[j].Op || sub[max].Op == sub[j].Op && len(sub[max].Rune) < len(sub[j].Rune) { + max = j + } + } + sub[start], sub[max] = sub[max], sub[start] + + for j := start + 1; j < i; j++ { + mergeCharClass(sub[start], sub[j]) + p.reuse(sub[j]) + } + cleanAlt(sub[start]) + out = append(out, sub[start]) + } + + // ... and then emit sub[i]. + if i < len(sub) { + out = append(out, sub[i]) + } + start = i + 1 + } + sub = out + + // Round 4: Collapse runs of empty matches into a single empty match. + start = 0 + out = sub[:0] + for i := range sub { + if i+1 < len(sub) && sub[i].Op == OpEmptyMatch && sub[i+1].Op == OpEmptyMatch { + continue + } + out = append(out, sub[i]) + } + sub = out + + return sub +} + +// leadingString returns the leading literal string that re begins with. +// The string refers to storage in re or its children. +func (p *parser) leadingString(re *Regexp) ([]int, Flags) { + if re.Op == OpConcat && len(re.Sub) > 0 { + re = re.Sub[0] + } + if re.Op != OpLiteral { + return nil, 0 + } + return re.Rune, re.Flags & FoldCase +} + +// removeLeadingString removes the first n leading runes +// from the beginning of re. It returns the replacement for re. +func (p *parser) removeLeadingString(re *Regexp, n int) *Regexp { + if re.Op == OpConcat && len(re.Sub) > 0 { + // Removing a leading string in a concatenation + // might simplify the concatenation. + sub := re.Sub[0] + sub = p.removeLeadingString(sub, n) + re.Sub[0] = sub + if sub.Op == OpEmptyMatch { + p.reuse(sub) + switch len(re.Sub) { + case 0, 1: + // Impossible but handle. + re.Op = OpEmptyMatch + re.Sub = nil + case 2: + old := re + re = re.Sub[1] + p.reuse(old) + default: + copy(re.Sub, re.Sub[1:]) + re.Sub = re.Sub[:len(re.Sub)-1] + } + } + return re + } + + if re.Op == OpLiteral { + re.Rune = re.Rune[:copy(re.Rune, re.Rune[n:])] + if len(re.Rune) == 0 { + re.Op = OpEmptyMatch + } + } + return re +} + +// leadingRegexp returns the leading regexp that re begins with. +// The regexp refers to storage in re or its children. +func (p *parser) leadingRegexp(re *Regexp) *Regexp { + if re.Op == OpEmptyMatch { + return nil + } + if re.Op == OpConcat && len(re.Sub) > 0 { + sub := re.Sub[0] + if sub.Op == OpEmptyMatch { + return nil + } + return sub + } + return re +} + +// removeLeadingRegexp removes the leading regexp in re. +// It returns the replacement for re. +// If reuse is true, it passes the removed regexp (if no longer needed) to p.reuse. +func (p *parser) removeLeadingRegexp(re *Regexp, reuse bool) *Regexp { + if re.Op == OpConcat && len(re.Sub) > 0 { + if reuse { + p.reuse(re.Sub[0]) + } + re.Sub = re.Sub[:copy(re.Sub, re.Sub[1:])] + switch len(re.Sub) { + case 0: + re.Op = OpEmptyMatch + re.Sub = nil + case 1: + old := re + re = re.Sub[0] + p.reuse(old) + } + return re + } + re.Op = OpEmptyMatch + return re +} + +func literalRegexp(s string, flags Flags) *Regexp { + re := &Regexp{Op: OpLiteral} + re.Flags = flags + re.Rune = re.Rune0[:0] // use local storage for small strings + for _, c := range s { + if len(re.Rune) >= cap(re.Rune) { + // string is too long to fit in Rune0. let Go handle it + re.Rune = []int(s) + break + } + re.Rune = append(re.Rune, c) + } + return re +} + +// Parsing. + +func Parse(s string, flags Flags) (*Regexp, os.Error) { + if flags&Literal != 0 { + // Trivial parser for literal string. + if err := checkUTF8(s); err != nil { + return nil, err + } + return literalRegexp(s, flags), nil + } + + // Otherwise, must do real work. + var ( + p parser + err os.Error + c int + op Op + lastRepeat string + min, max int + ) + p.flags = flags + p.wholeRegexp = s + t := s + for t != "" { + repeat := "" + BigSwitch: + switch t[0] { + default: + if c, t, err = nextRune(t); err != nil { + return nil, err + } + p.literal(c) + + case '(': + if p.flags&PerlX != 0 && len(t) >= 2 && t[1] == '?' { + // Flag changes and non-capturing groups. + if t, err = p.parsePerlFlags(t); err != nil { + return nil, err + } + break + } + p.numCap++ + p.op(opLeftParen).Cap = p.numCap + t = t[1:] + case '|': + if err = p.parseVerticalBar(); err != nil { + return nil, err + } + t = t[1:] + case ')': + if err = p.parseRightParen(); err != nil { + return nil, err + } + t = t[1:] + case '^': + if p.flags&OneLine != 0 { + p.op(OpBeginText) + } else { + p.op(OpBeginLine) + } + t = t[1:] + case '$': + if p.flags&OneLine != 0 { + p.op(OpEndText).Flags |= WasDollar + } else { + p.op(OpEndLine) + } + t = t[1:] + case '.': + if p.flags&DotNL != 0 { + p.op(OpAnyChar) + } else { + p.op(OpAnyCharNotNL) + } + t = t[1:] + case '[': + if t, err = p.parseClass(t); err != nil { + return nil, err + } + case '*', '+', '?': + switch t[0] { + case '*': + op = OpStar + case '+': + op = OpPlus + case '?': + op = OpQuest + } + if t, err = p.repeat(op, min, max, t[:1], t[1:], lastRepeat); err != nil { + return nil, err + } + case '{': + op = OpRepeat + min, max, tt, ok := p.parseRepeat(t) + if !ok { + // If the repeat cannot be parsed, { is a literal. + p.literal('{') + t = t[1:] + break + } + if t, err = p.repeat(op, min, max, t[:len(t)-len(tt)], tt, lastRepeat); err != nil { + return nil, err + } + case '\\': + if p.flags&PerlX != 0 && len(t) >= 2 { + switch t[1] { + case 'A': + p.op(OpBeginText) + t = t[2:] + break BigSwitch + case 'b': + p.op(OpWordBoundary) + t = t[2:] + break BigSwitch + case 'B': + p.op(OpNoWordBoundary) + t = t[2:] + break BigSwitch + case 'C': + // any byte; not supported + return nil, &Error{ErrInvalidEscape, t[:2]} + case 'Q': + // \Q ... \E: the ... is always literals + var lit string + if i := strings.Index(t, `\E`); i < 0 { + lit = t[2:] + t = "" + } else { + lit = t[2:i] + t = t[i+2:] + } + p.push(literalRegexp(lit, p.flags)) + break BigSwitch + case 'z': + p.op(OpEndText) + t = t[2:] + break BigSwitch + } + } + + re := p.newRegexp(OpCharClass) + re.Flags = p.flags + + // Look for Unicode character group like \p{Han} + if len(t) >= 2 && (t[1] == 'p' || t[1] == 'P') { + r, rest, err := p.parseUnicodeClass(t, re.Rune0[:0]) + if err != nil { + return nil, err + } + if r != nil { + re.Rune = r + t = rest + p.push(re) + break BigSwitch + } + } + + // Perl character class escape. + if r, rest := p.parsePerlClassEscape(t, re.Rune0[:0]); r != nil { + re.Rune = r + t = rest + p.push(re) + break BigSwitch + } + p.reuse(re) + + // Ordinary single-character escape. + if c, t, err = p.parseEscape(t); err != nil { + return nil, err + } + p.literal(c) + } + lastRepeat = repeat + } + + p.concat() + if p.swapVerticalBar() { + // pop vertical bar + p.stack = p.stack[:len(p.stack)-1] + } + p.alternate() + + n := len(p.stack) + if n != 1 { + return nil, &Error{ErrMissingParen, s} + } + return p.stack[0], nil +} + +// parseRepeat parses {min} (max=min) or {min,} (max=-1) or {min,max}. +// If s is not of that form, it returns ok == false. +func (p *parser) parseRepeat(s string) (min, max int, rest string, ok bool) { + if s == "" || s[0] != '{' { + return + } + s = s[1:] + if min, s, ok = p.parseInt(s); !ok { + return + } + if s == "" { + return + } + if s[0] != ',' { + max = min + } else { + s = s[1:] + if s == "" { + return + } + if s[0] == '}' { + max = -1 + } else if max, s, ok = p.parseInt(s); !ok { + return + } + } + if s == "" || s[0] != '}' { + return + } + rest = s[1:] + ok = true + return +} + +// parsePerlFlags parses a Perl flag setting or non-capturing group or both, +// like (?i) or (?: or (?i:. It removes the prefix from s and updates the parse state. +// The caller must have ensured that s begins with "(?". +func (p *parser) parsePerlFlags(s string) (rest string, err os.Error) { + t := s + + // Check for named captures, first introduced in Python's regexp library. + // As usual, there are three slightly different syntaxes: + // + // (?Pexpr) the original, introduced by Python + // (?expr) the .NET alteration, adopted by Perl 5.10 + // (?'name'expr) another .NET alteration, adopted by Perl 5.10 + // + // Perl 5.10 gave in and implemented the Python version too, + // but they claim that the last two are the preferred forms. + // PCRE and languages based on it (specifically, PHP and Ruby) + // support all three as well. EcmaScript 4 uses only the Python form. + // + // In both the open source world (via Code Search) and the + // Google source tree, (?Pname) is the dominant form, + // so that's the one we implement. One is enough. + if len(t) > 4 && t[2] == 'P' && t[3] == '<' { + // Pull out name. + end := strings.IndexRune(t, '>') + if end < 0 { + if err = checkUTF8(t); err != nil { + return "", err + } + return "", &Error{ErrInvalidNamedCapture, s} + } + + capture := t[:end+1] // "(?P" + name := t[4:end] // "name" + if err = checkUTF8(name); err != nil { + return "", err + } + if !isValidCaptureName(name) { + return "", &Error{ErrInvalidNamedCapture, capture} + } + + // Like ordinary capture, but named. + p.numCap++ + re := p.op(opLeftParen) + re.Cap = p.numCap + re.Name = name + return t[end+1:], nil + } + + // Non-capturing group. Might also twiddle Perl flags. + var c int + t = t[2:] // skip (? + flags := p.flags + sign := +1 + sawFlag := false +Loop: + for t != "" { + if c, t, err = nextRune(t); err != nil { + return "", err + } + switch c { + default: + break Loop + + // Flags. + case 'i': + flags |= FoldCase + sawFlag = true + case 'm': + flags &^= OneLine + sawFlag = true + case 's': + flags |= DotNL + sawFlag = true + case 'U': + flags |= NonGreedy + sawFlag = true + + // Switch to negation. + case '-': + if sign < 0 { + break Loop + } + sign = -1 + // Invert flags so that | above turn into &^ and vice versa. + // We'll invert flags again before using it below. + flags = ^flags + sawFlag = false + + // End of flags, starting group or not. + case ':', ')': + if sign < 0 { + if !sawFlag { + break Loop + } + flags = ^flags + } + if c == ':' { + // Open new group + p.op(opLeftParen) + } + p.flags = flags + return t, nil + } + } + + return "", &Error{ErrInvalidPerlOp, s[:len(s)-len(t)]} +} + +// isValidCaptureName reports whether name +// is a valid capture name: [A-Za-z0-9_]+. +// PCRE limits names to 32 bytes. +// Python rejects names starting with digits. +// We don't enforce either of those. +func isValidCaptureName(name string) bool { + if name == "" { + return false + } + for _, c := range name { + if c != '_' && !isalnum(c) { + return false + } + } + return true +} + +// parseInt parses a decimal integer. +func (p *parser) parseInt(s string) (n int, rest string, ok bool) { + if s == "" || s[0] < '0' || '9' < s[0] { + return + } + // Disallow leading zeros. + if len(s) >= 2 && s[0] == '0' && '0' <= s[1] && s[1] <= '9' { + return + } + for s != "" && '0' <= s[0] && s[0] <= '9' { + // Avoid overflow. + if n >= 1e8 { + return + } + n = n*10 + int(s[0]) - '0' + s = s[1:] + } + rest = s + ok = true + return +} + +// can this be represented as a character class? +// single-rune literal string, char class, ., and .|\n. +func isCharClass(re *Regexp) bool { + return re.Op == OpLiteral && len(re.Rune) == 1 || + re.Op == OpCharClass || + re.Op == OpAnyCharNotNL || + re.Op == OpAnyChar +} + +// does re match r? +func matchRune(re *Regexp, r int) bool { + switch re.Op { + case OpLiteral: + return len(re.Rune) == 1 && re.Rune[0] == r + case OpCharClass: + for i := 0; i < len(re.Rune); i += 2 { + if re.Rune[i] <= r && r <= re.Rune[i+1] { + return true + } + } + return false + case OpAnyCharNotNL: + return r != '\n' + case OpAnyChar: + return true + } + return false +} + +// parseVerticalBar handles a | in the input. +func (p *parser) parseVerticalBar() os.Error { + p.concat() + + // The concatenation we just parsed is on top of the stack. + // If it sits above an opVerticalBar, swap it below + // (things below an opVerticalBar become an alternation). + // Otherwise, push a new vertical bar. + if !p.swapVerticalBar() { + p.op(opVerticalBar) + } + + return nil +} + +// mergeCharClass makes dst = dst|src. +// The caller must ensure that dst.Op >= src.Op, +// to reduce the amount of copying. +func mergeCharClass(dst, src *Regexp) { + switch dst.Op { + case OpAnyChar: + // src doesn't add anything. + case OpAnyCharNotNL: + // src might add \n + if matchRune(src, '\n') { + dst.Op = OpAnyChar + } + case OpCharClass: + // src is simpler, so either literal or char class + if src.Op == OpLiteral { + dst.Rune = appendRange(dst.Rune, src.Rune[0], src.Rune[0]) + } else { + dst.Rune = appendClass(dst.Rune, src.Rune) + } + case OpLiteral: + // both literal + if src.Rune[0] == dst.Rune[0] { + break + } + dst.Op = OpCharClass + dst.Rune = append(dst.Rune, dst.Rune[0]) + dst.Rune = appendRange(dst.Rune, src.Rune[0], src.Rune[0]) + } +} + +// If the top of the stack is an element followed by an opVerticalBar +// swapVerticalBar swaps the two and returns true. +// Otherwise it returns false. +func (p *parser) swapVerticalBar() bool { + // If above and below vertical bar are literal or char class, + // can merge into a single char class. + n := len(p.stack) + if n >= 3 && p.stack[n-2].Op == opVerticalBar && isCharClass(p.stack[n-1]) && isCharClass(p.stack[n-3]) { + re1 := p.stack[n-1] + re3 := p.stack[n-3] + // Make re3 the more complex of the two. + if re1.Op > re3.Op { + re1, re3 = re3, re1 + p.stack[n-3] = re3 + } + mergeCharClass(re3, re1) + p.reuse(re1) + p.stack = p.stack[:n-1] + return true + } + + if n >= 2 { + re1 := p.stack[n-1] + re2 := p.stack[n-2] + if re2.Op == opVerticalBar { + if n >= 3 { + // Now out of reach. + // Clean opportunistically. + cleanAlt(p.stack[n-3]) + } + p.stack[n-2] = re1 + p.stack[n-1] = re2 + return true + } + } + return false +} + +// parseRightParen handles a ) in the input. +func (p *parser) parseRightParen() os.Error { + p.concat() + if p.swapVerticalBar() { + // pop vertical bar + p.stack = p.stack[:len(p.stack)-1] + } + p.alternate() + + n := len(p.stack) + if n < 2 { + return &Error{ErrInternalError, ""} + } + re1 := p.stack[n-1] + re2 := p.stack[n-2] + p.stack = p.stack[:n-2] + if re2.Op != opLeftParen { + return &Error{ErrMissingParen, p.wholeRegexp} + } + if re2.Cap == 0 { + // Just for grouping. + p.push(re1) + } else { + re2.Op = OpCapture + re2.Sub = re2.Sub0[:1] + re2.Sub[0] = re1 + p.push(re2) + } + return nil +} + +// parseEscape parses an escape sequence at the beginning of s +// and returns the rune. +func (p *parser) parseEscape(s string) (r int, rest string, err os.Error) { + t := s[1:] + if t == "" { + return 0, "", &Error{ErrTrailingBackslash, ""} + } + c, t, err := nextRune(t) + if err != nil { + return 0, "", err + } + +Switch: + switch c { + default: + if c < utf8.RuneSelf && !isalnum(c) { + // Escaped non-word characters are always themselves. + // PCRE is not quite so rigorous: it accepts things like + // \q, but we don't. We once rejected \_, but too many + // programs and people insist on using it, so allow \_. + return c, t, nil + } + + // Octal escapes. + case '1', '2', '3', '4', '5', '6', '7': + // Single non-zero digit is a backreference; not supported + if t == "" || t[0] < '0' || t[0] > '7' { + break + } + fallthrough + case '0': + // Consume up to three octal digits; already have one. + r = c - '0' + for i := 1; i < 3; i++ { + if t == "" || t[0] < '0' || t[0] > '7' { + break + } + r = r*8 + int(t[0]) - '0' + t = t[1:] + } + return r, t, nil + + // Hexadecimal escapes. + case 'x': + if t == "" { + break + } + if c, t, err = nextRune(t); err != nil { + return 0, "", err + } + if c == '{' { + // Any number of digits in braces. + // Perl accepts any text at all; it ignores all text + // after the first non-hex digit. We require only hex digits, + // and at least one. + nhex := 0 + r = 0 + for { + if t == "" { + break Switch + } + if c, t, err = nextRune(t); err != nil { + return 0, "", err + } + if c == '}' { + break + } + v := unhex(c) + if v < 0 { + break Switch + } + r = r*16 + v + if r > unicode.MaxRune { + break Switch + } + nhex++ + } + if nhex == 0 { + break Switch + } + return r, t, nil + } + + // Easy case: two hex digits. + x := unhex(c) + if c, t, err = nextRune(t); err != nil { + return 0, "", err + } + y := unhex(c) + if x < 0 || y < 0 { + break + } + return x*16 + y, t, nil + + // C escapes. There is no case 'b', to avoid misparsing + // the Perl word-boundary \b as the C backspace \b + // when in POSIX mode. In Perl, /\b/ means word-boundary + // but /[\b]/ means backspace. We don't support that. + // If you want a backspace, embed a literal backspace + // character or use \x08. + case 'a': + return '\a', t, err + case 'f': + return '\f', t, err + case 'n': + return '\n', t, err + case 'r': + return '\r', t, err + case 't': + return '\t', t, err + case 'v': + return '\v', t, err + } + return 0, "", &Error{ErrInvalidEscape, s[:len(s)-len(t)]} +} + +// parseClassChar parses a character class character at the beginning of s +// and returns it. +func (p *parser) parseClassChar(s, wholeClass string) (r int, rest string, err os.Error) { + if s == "" { + return 0, "", &Error{Code: ErrMissingBracket, Expr: wholeClass} + } + + // Allow regular escape sequences even though + // many need not be escaped in this context. + if s[0] == '\\' { + return p.parseEscape(s) + } + + return nextRune(s) +} + +type charGroup struct { + sign int + class []int +} + +// parsePerlClassEscape parses a leading Perl character class escape like \d +// from the beginning of s. If one is present, it appends the characters to r +// and returns the new slice r and the remainder of the string. +func (p *parser) parsePerlClassEscape(s string, r []int) (out []int, rest string) { + if p.flags&PerlX == 0 || len(s) < 2 || s[0] != '\\' { + return + } + g := perlGroup[s[0:2]] + if g.sign == 0 { + return + } + return p.appendGroup(r, g), s[2:] +} + +// parseNamedClass parses a leading POSIX named character class like [:alnum:] +// from the beginning of s. If one is present, it appends the characters to r +// and returns the new slice r and the remainder of the string. +func (p *parser) parseNamedClass(s string, r []int) (out []int, rest string, err os.Error) { + if len(s) < 2 || s[0] != '[' || s[1] != ':' { + return + } + + i := strings.Index(s[2:], ":]") + if i < 0 { + return + } + i += 2 + name, s := s[0:i+2], s[i+2:] + g := posixGroup[name] + if g.sign == 0 { + return nil, "", &Error{ErrInvalidCharRange, name} + } + return p.appendGroup(r, g), s, nil +} + +func (p *parser) appendGroup(r []int, g charGroup) []int { + if p.flags&FoldCase == 0 { + if g.sign < 0 { + r = appendNegatedClass(r, g.class) + } else { + r = appendClass(r, g.class) + } + } else { + tmp := p.tmpClass[:0] + tmp = appendFoldedClass(tmp, g.class) + p.tmpClass = tmp + tmp = cleanClass(&p.tmpClass) + if g.sign < 0 { + r = appendNegatedClass(r, tmp) + } else { + r = appendClass(r, tmp) + } + } + return r +} + +// unicodeTable returns the unicode.RangeTable identified by name +// and the table of additional fold-equivalent code points. +func unicodeTable(name string) (*unicode.RangeTable, *unicode.RangeTable) { + if t := unicode.Categories[name]; t != nil { + return t, unicode.FoldCategory[name] + } + if t := unicode.Scripts[name]; t != nil { + return t, unicode.FoldScript[name] + } + return nil, nil +} + +// parseUnicodeClass parses a leading Unicode character class like \p{Han} +// from the beginning of s. If one is present, it appends the characters to r +// and returns the new slice r and the remainder of the string. +func (p *parser) parseUnicodeClass(s string, r []int) (out []int, rest string, err os.Error) { + if p.flags&UnicodeGroups == 0 || len(s) < 2 || s[0] != '\\' || s[1] != 'p' && s[1] != 'P' { + return + } + + // Committed to parse or return error. + sign := +1 + if s[1] == 'P' { + sign = -1 + } + t := s[2:] + c, t, err := nextRune(t) + if err != nil { + return + } + var seq, name string + if c != '{' { + // Single-letter name. + seq = s[:len(s)-len(t)] + name = seq[2:] + } else { + // Name is in braces. + end := strings.IndexRune(s, '}') + if end < 0 { + if err = checkUTF8(s); err != nil { + return + } + return nil, "", &Error{ErrInvalidCharRange, s} + } + seq, t = s[:end+1], s[end+1:] + name = s[3:end] + if err = checkUTF8(name); err != nil { + return + } + } + + // Group can have leading negation too. \p{^Han} == \P{Han}, \P{^Han} == \p{Han}. + if name != "" && name[0] == '^' { + sign = -sign + name = name[1:] + } + + tab, fold := unicodeTable(name) + if tab == nil { + return nil, "", &Error{ErrInvalidCharRange, seq} + } + + if p.flags&FoldCase == 0 || fold == nil { + if sign > 0 { + r = appendTable(r, tab) + } else { + r = appendNegatedTable(r, tab) + } + } else { + // Merge and clean tab and fold in a temporary buffer. + // This is necessary for the negative case and just tidy + // for the positive case. + tmp := p.tmpClass[:0] + tmp = appendTable(tmp, tab) + tmp = appendTable(tmp, fold) + p.tmpClass = tmp + tmp = cleanClass(&p.tmpClass) + if sign > 0 { + r = appendClass(r, tmp) + } else { + r = appendNegatedClass(r, tmp) + } + } + return r, t, nil +} + +// parseClass parses a character class at the beginning of s +// and pushes it onto the parse stack. +func (p *parser) parseClass(s string) (rest string, err os.Error) { + t := s[1:] // chop [ + re := p.newRegexp(OpCharClass) + re.Flags = p.flags + re.Rune = re.Rune0[:0] + + sign := +1 + if t != "" && t[0] == '^' { + sign = -1 + t = t[1:] + + // If character class does not match \n, add it here, + // so that negation later will do the right thing. + if p.flags&ClassNL == 0 { + re.Rune = append(re.Rune, '\n', '\n') + } + } + + class := re.Rune + first := true // ] and - are okay as first char in class + for t == "" || t[0] != ']' || first { + // POSIX: - is only okay unescaped as first or last in class. + // Perl: - is okay anywhere. + if t != "" && t[0] == '-' && p.flags&PerlX == 0 && !first && (len(t) == 1 || t[1] != ']') { + _, size := utf8.DecodeRuneInString(t[1:]) + return "", &Error{Code: ErrInvalidCharRange, Expr: t[:1+size]} + } + first = false + + // Look for POSIX [:alnum:] etc. + if len(t) > 2 && t[0] == '[' && t[1] == ':' { + nclass, nt, err := p.parseNamedClass(t, class) + if err != nil { + return "", err + } + if nclass != nil { + class, t = nclass, nt + continue + } + } + + // Look for Unicode character group like \p{Han}. + nclass, nt, err := p.parseUnicodeClass(t, class) + if err != nil { + return "", err + } + if nclass != nil { + class, t = nclass, nt + continue + } + + // Look for Perl character class symbols (extension). + if nclass, nt := p.parsePerlClassEscape(t, class); nclass != nil { + class, t = nclass, nt + continue + } + + // Single character or simple range. + rng := t + var lo, hi int + if lo, t, err = p.parseClassChar(t, s); err != nil { + return "", err + } + hi = lo + // [a-] means (a|-) so check for final ]. + if len(t) >= 2 && t[0] == '-' && t[1] != ']' { + t = t[1:] + if hi, t, err = p.parseClassChar(t, s); err != nil { + return "", err + } + if hi < lo { + rng = rng[:len(rng)-len(t)] + return "", &Error{Code: ErrInvalidCharRange, Expr: rng} + } + } + if p.flags&FoldCase == 0 { + class = appendRange(class, lo, hi) + } else { + class = appendFoldedRange(class, lo, hi) + } + } + t = t[1:] // chop ] + + // Use &re.Rune instead of &class to avoid allocation. + re.Rune = class + class = cleanClass(&re.Rune) + if sign < 0 { + class = negateClass(class) + } + re.Rune = class + p.push(re) + return t, nil +} + +// cleanClass sorts the ranges (pairs of elements of r), +// merges them, and eliminates duplicates. +func cleanClass(rp *[]int) []int { + + // Sort by lo increasing, hi decreasing to break ties. + sort.Sort(ranges{rp}) + + r := *rp + if len(r) < 2 { + return r + } + + // Merge abutting, overlapping. + w := 2 // write index + for i := 2; i < len(r); i += 2 { + lo, hi := r[i], r[i+1] + if lo <= r[w-1]+1 { + // merge with previous range + if hi > r[w-1] { + r[w-1] = hi + } + continue + } + // new disjoint range + r[w] = lo + r[w+1] = hi + w += 2 + } + + return r[:w] +} + +// appendRange returns the result of appending the range lo-hi to the class r. +func appendRange(r []int, lo, hi int) []int { + // Expand last range or next to last range if it overlaps or abuts. + // Checking two ranges helps when appending case-folded + // alphabets, so that one range can be expanding A-Z and the + // other expanding a-z. + n := len(r) + for i := 2; i <= 4; i += 2 { // twice, using i=2, i=4 + if n >= i { + rlo, rhi := r[n-i], r[n-i+1] + if lo <= rhi+1 && rlo <= hi+1 { + if lo < rlo { + r[n-i] = lo + } + if hi > rhi { + r[n-i+1] = hi + } + return r + } + } + } + + return append(r, lo, hi) +} + +const ( + // minimum and maximum runes involved in folding. + // checked during test. + minFold = 0x0041 + maxFold = 0x1044f +) + +// appendFoldedRange returns the result of appending the range lo-hi +// and its case folding-equivalent runes to the class r. +func appendFoldedRange(r []int, lo, hi int) []int { + // Optimizations. + if lo <= minFold && hi >= maxFold { + // Range is full: folding can't add more. + return appendRange(r, lo, hi) + } + if hi < minFold || lo > maxFold { + // Range is outside folding possibilities. + return appendRange(r, lo, hi) + } + if lo < minFold { + // [lo, minFold-1] needs no folding. + r = appendRange(r, lo, minFold-1) + lo = minFold + } + if hi > maxFold { + // [maxFold+1, hi] needs no folding. + r = appendRange(r, maxFold+1, hi) + hi = maxFold + } + + // Brute force. Depend on appendRange to coalesce ranges on the fly. + for c := lo; c <= hi; c++ { + r = appendRange(r, c, c) + f := unicode.SimpleFold(c) + for f != c { + r = appendRange(r, f, f) + f = unicode.SimpleFold(f) + } + } + return r +} + +// appendClass returns the result of appending the class x to the class r. +// It assume x is clean. +func appendClass(r []int, x []int) []int { + for i := 0; i < len(x); i += 2 { + r = appendRange(r, x[i], x[i+1]) + } + return r +} + +// appendFolded returns the result of appending the case folding of the class x to the class r. +func appendFoldedClass(r []int, x []int) []int { + for i := 0; i < len(x); i += 2 { + r = appendFoldedRange(r, x[i], x[i+1]) + } + return r +} + +// appendNegatedClass returns the result of appending the negation of the class x to the class r. +// It assumes x is clean. +func appendNegatedClass(r []int, x []int) []int { + nextLo := 0 + for i := 0; i < len(x); i += 2 { + lo, hi := x[i], x[i+1] + if nextLo <= lo-1 { + r = appendRange(r, nextLo, lo-1) + } + nextLo = hi + 1 + } + if nextLo <= unicode.MaxRune { + r = appendRange(r, nextLo, unicode.MaxRune) + } + return r +} + +// appendTable returns the result of appending x to the class r. +func appendTable(r []int, x *unicode.RangeTable) []int { + for _, xr := range x.R16 { + lo, hi, stride := int(xr.Lo), int(xr.Hi), int(xr.Stride) + if stride == 1 { + r = appendRange(r, lo, hi) + continue + } + for c := lo; c <= hi; c += stride { + r = appendRange(r, c, c) + } + } + for _, xr := range x.R32 { + lo, hi, stride := int(xr.Lo), int(xr.Hi), int(xr.Stride) + if stride == 1 { + r = appendRange(r, lo, hi) + continue + } + for c := lo; c <= hi; c += stride { + r = appendRange(r, c, c) + } + } + return r +} + +// appendNegatedTable returns the result of appending the negation of x to the class r. +func appendNegatedTable(r []int, x *unicode.RangeTable) []int { + nextLo := 0 // lo end of next class to add + for _, xr := range x.R16 { + lo, hi, stride := int(xr.Lo), int(xr.Hi), int(xr.Stride) + if stride == 1 { + if nextLo <= lo-1 { + r = appendRange(r, nextLo, lo-1) + } + nextLo = hi + 1 + continue + } + for c := lo; c <= hi; c += stride { + if nextLo <= c-1 { + r = appendRange(r, nextLo, c-1) + } + nextLo = c + 1 + } + } + for _, xr := range x.R32 { + lo, hi, stride := int(xr.Lo), int(xr.Hi), int(xr.Stride) + if stride == 1 { + if nextLo <= lo-1 { + r = appendRange(r, nextLo, lo-1) + } + nextLo = hi + 1 + continue + } + for c := lo; c <= hi; c += stride { + if nextLo <= c-1 { + r = appendRange(r, nextLo, c-1) + } + nextLo = c + 1 + } + } + if nextLo <= unicode.MaxRune { + r = appendRange(r, nextLo, unicode.MaxRune) + } + return r +} + +// negateClass overwrites r and returns r's negation. +// It assumes the class r is already clean. +func negateClass(r []int) []int { + nextLo := 0 // lo end of next class to add + w := 0 // write index + for i := 0; i < len(r); i += 2 { + lo, hi := r[i], r[i+1] + if nextLo <= lo-1 { + r[w] = nextLo + r[w+1] = lo - 1 + w += 2 + } + nextLo = hi + 1 + } + r = r[:w] + if nextLo <= unicode.MaxRune { + // It's possible for the negation to have one more + // range - this one - than the original class, so use append. + r = append(r, nextLo, unicode.MaxRune) + } + return r +} + +// ranges implements sort.Interface on a []rune. +// The choice of receiver type definition is strange +// but avoids an allocation since we already have +// a *[]int. +type ranges struct { + p *[]int +} + +func (ra ranges) Less(i, j int) bool { + p := *ra.p + i *= 2 + j *= 2 + return p[i] < p[j] || p[i] == p[j] && p[i+1] > p[j+1] +} + +func (ra ranges) Len() int { + return len(*ra.p) / 2 +} + +func (ra ranges) Swap(i, j int) { + p := *ra.p + i *= 2 + j *= 2 + p[i], p[i+1], p[j], p[j+1] = p[j], p[j+1], p[i], p[i+1] +} + +func checkUTF8(s string) os.Error { + for s != "" { + rune, size := utf8.DecodeRuneInString(s) + if rune == utf8.RuneError && size == 1 { + return &Error{Code: ErrInvalidUTF8, Expr: s} + } + s = s[size:] + } + return nil +} + +func nextRune(s string) (c int, t string, err os.Error) { + c, size := utf8.DecodeRuneInString(s) + if c == utf8.RuneError && size == 1 { + return 0, "", &Error{Code: ErrInvalidUTF8, Expr: s} + } + return c, s[size:], nil +} + +func isalnum(c int) bool { + return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' +} + +func unhex(c int) int { + if '0' <= c && c <= '9' { + return c - '0' + } + if 'a' <= c && c <= 'f' { + return c - 'a' + 10 + } + if 'A' <= c && c <= 'F' { + return c - 'A' + 10 + } + return -1 +} diff --git a/libgo/go/exp/regexp/syntax/parse_test.go b/libgo/go/exp/regexp/syntax/parse_test.go new file mode 100644 index 0000000..779b9af --- /dev/null +++ b/libgo/go/exp/regexp/syntax/parse_test.go @@ -0,0 +1,350 @@ +// 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 syntax + +import ( + "bytes" + "fmt" + "testing" + "unicode" +) + +var parseTests = []struct { + Regexp string + Dump string +}{ + // Base cases + {`a`, `lit{a}`}, + {`a.`, `cat{lit{a}dot{}}`}, + {`a.b`, `cat{lit{a}dot{}lit{b}}`}, + {`ab`, `str{ab}`}, + {`a.b.c`, `cat{lit{a}dot{}lit{b}dot{}lit{c}}`}, + {`abc`, `str{abc}`}, + {`a|^`, `alt{lit{a}bol{}}`}, + {`a|b`, `cc{0x61-0x62}`}, + {`(a)`, `cap{lit{a}}`}, + {`(a)|b`, `alt{cap{lit{a}}lit{b}}`}, + {`a*`, `star{lit{a}}`}, + {`a+`, `plus{lit{a}}`}, + {`a?`, `que{lit{a}}`}, + {`a{2}`, `rep{2,2 lit{a}}`}, + {`a{2,3}`, `rep{2,3 lit{a}}`}, + {`a{2,}`, `rep{2,-1 lit{a}}`}, + {`a*?`, `nstar{lit{a}}`}, + {`a+?`, `nplus{lit{a}}`}, + {`a??`, `nque{lit{a}}`}, + {`a{2}?`, `nrep{2,2 lit{a}}`}, + {`a{2,3}?`, `nrep{2,3 lit{a}}`}, + {`a{2,}?`, `nrep{2,-1 lit{a}}`}, + {``, `emp{}`}, + {`|`, `emp{}`}, // alt{emp{}emp{}} but got factored + {`|x|`, `alt{emp{}lit{x}emp{}}`}, + {`.`, `dot{}`}, + {`^`, `bol{}`}, + {`$`, `eol{}`}, + {`\|`, `lit{|}`}, + {`\(`, `lit{(}`}, + {`\)`, `lit{)}`}, + {`\*`, `lit{*}`}, + {`\+`, `lit{+}`}, + {`\?`, `lit{?}`}, + {`{`, `lit{{}`}, + {`}`, `lit{}}`}, + {`\.`, `lit{.}`}, + {`\^`, `lit{^}`}, + {`\$`, `lit{$}`}, + {`\\`, `lit{\}`}, + {`[ace]`, `cc{0x61 0x63 0x65}`}, + {`[abc]`, `cc{0x61-0x63}`}, + {`[a-z]`, `cc{0x61-0x7a}`}, + {`[a]`, `lit{a}`}, + {`\-`, `lit{-}`}, + {`-`, `lit{-}`}, + {`\_`, `lit{_}`}, + {`abc`, `str{abc}`}, + {`abc|def`, `alt{str{abc}str{def}}`}, + {`abc|def|ghi`, `alt{str{abc}str{def}str{ghi}}`}, + + // Posix and Perl extensions + {`[[:lower:]]`, `cc{0x61-0x7a}`}, + {`[a-z]`, `cc{0x61-0x7a}`}, + {`[^[:lower:]]`, `cc{0x0-0x60 0x7b-0x10ffff}`}, + {`[[:^lower:]]`, `cc{0x0-0x60 0x7b-0x10ffff}`}, + {`(?i)[[:lower:]]`, `cc{0x41-0x5a 0x61-0x7a 0x17f 0x212a}`}, + {`(?i)[a-z]`, `cc{0x41-0x5a 0x61-0x7a 0x17f 0x212a}`}, + {`(?i)[^[:lower:]]`, `cc{0x0-0x40 0x5b-0x60 0x7b-0x17e 0x180-0x2129 0x212b-0x10ffff}`}, + {`(?i)[[:^lower:]]`, `cc{0x0-0x40 0x5b-0x60 0x7b-0x17e 0x180-0x2129 0x212b-0x10ffff}`}, + {`\d`, `cc{0x30-0x39}`}, + {`\D`, `cc{0x0-0x2f 0x3a-0x10ffff}`}, + {`\s`, `cc{0x9-0xa 0xc-0xd 0x20}`}, + {`\S`, `cc{0x0-0x8 0xb 0xe-0x1f 0x21-0x10ffff}`}, + {`\w`, `cc{0x30-0x39 0x41-0x5a 0x5f 0x61-0x7a}`}, + {`\W`, `cc{0x0-0x2f 0x3a-0x40 0x5b-0x5e 0x60 0x7b-0x10ffff}`}, + {`(?i)\w`, `cc{0x30-0x39 0x41-0x5a 0x5f 0x61-0x7a 0x17f 0x212a}`}, + {`(?i)\W`, `cc{0x0-0x2f 0x3a-0x40 0x5b-0x5e 0x60 0x7b-0x17e 0x180-0x2129 0x212b-0x10ffff}`}, + {`[^\\]`, `cc{0x0-0x5b 0x5d-0x10ffff}`}, + // { `\C`, `byte{}` }, // probably never + + // Unicode, negatives, and a double negative. + {`\p{Braille}`, `cc{0x2800-0x28ff}`}, + {`\P{Braille}`, `cc{0x0-0x27ff 0x2900-0x10ffff}`}, + {`\p{^Braille}`, `cc{0x0-0x27ff 0x2900-0x10ffff}`}, + {`\P{^Braille}`, `cc{0x2800-0x28ff}`}, + {`\pZ`, `cc{0x20 0xa0 0x1680 0x180e 0x2000-0x200a 0x2028-0x2029 0x202f 0x205f 0x3000}`}, + {`[\p{Braille}]`, `cc{0x2800-0x28ff}`}, + {`[\P{Braille}]`, `cc{0x0-0x27ff 0x2900-0x10ffff}`}, + {`[\p{^Braille}]`, `cc{0x0-0x27ff 0x2900-0x10ffff}`}, + {`[\P{^Braille}]`, `cc{0x2800-0x28ff}`}, + {`[\pZ]`, `cc{0x20 0xa0 0x1680 0x180e 0x2000-0x200a 0x2028-0x2029 0x202f 0x205f 0x3000}`}, + {`\p{Lu}`, mkCharClass(unicode.IsUpper)}, + {`[\p{Lu}]`, mkCharClass(unicode.IsUpper)}, + {`(?i)[\p{Lu}]`, mkCharClass(isUpperFold)}, + + // Hex, octal. + {`[\012-\234]\141`, `cat{cc{0xa-0x9c}lit{a}}`}, + {`[\x{41}-\x7a]\x61`, `cat{cc{0x41-0x7a}lit{a}}`}, + + // More interesting regular expressions. + {`a{,2}`, `str{a{,2}}`}, + {`\.\^\$\\`, `str{.^$\}`}, + {`[a-zABC]`, `cc{0x41-0x43 0x61-0x7a}`}, + {`[^a]`, `cc{0x0-0x60 0x62-0x10ffff}`}, + {`[α-ε☺]`, `cc{0x3b1-0x3b5 0x263a}`}, // utf-8 + {`a*{`, `cat{star{lit{a}}lit{{}}`}, + + // Test precedences + {`(?:ab)*`, `star{str{ab}}`}, + {`(ab)*`, `star{cap{str{ab}}}`}, + {`ab|cd`, `alt{str{ab}str{cd}}`}, + {`a(b|c)d`, `cat{lit{a}cap{cc{0x62-0x63}}lit{d}}`}, + + // Test flattening. + {`(?:a)`, `lit{a}`}, + {`(?:ab)(?:cd)`, `str{abcd}`}, + {`(?:a+b+)(?:c+d+)`, `cat{plus{lit{a}}plus{lit{b}}plus{lit{c}}plus{lit{d}}}`}, + {`(?:a+|b+)|(?:c+|d+)`, `alt{plus{lit{a}}plus{lit{b}}plus{lit{c}}plus{lit{d}}}`}, + {`(?:a|b)|(?:c|d)`, `cc{0x61-0x64}`}, + {`a|.`, `dot{}`}, + {`.|a`, `dot{}`}, + {`(?:[abc]|A|Z|hello|world)`, `alt{cc{0x41 0x5a 0x61-0x63}str{hello}str{world}}`}, + {`(?:[abc]|A|Z)`, `cc{0x41 0x5a 0x61-0x63}`}, + + // Test Perl quoted literals + {`\Q+|*?{[\E`, `str{+|*?{[}`}, + {`\Q+\E+`, `plus{lit{+}}`}, + {`\Q\\E`, `lit{\}`}, + {`\Q\\\E`, `str{\\}`}, + + // Test Perl \A and \z + {`(?m)^`, `bol{}`}, + {`(?m)$`, `eol{}`}, + {`(?-m)^`, `bot{}`}, + {`(?-m)$`, `eot{}`}, + {`(?m)\A`, `bot{}`}, + {`(?m)\z`, `eot{\z}`}, + {`(?-m)\A`, `bot{}`}, + {`(?-m)\z`, `eot{\z}`}, + + // Test named captures + {`(?Pa)`, `cap{name:lit{a}}`}, + + // Case-folded literals + {`[Aa]`, `litfold{A}`}, + {`[\x{100}\x{101}]`, `litfold{Ā}`}, + {`[Δδ]`, `litfold{Δ}`}, + + // Strings + {`abcde`, `str{abcde}`}, + {`[Aa][Bb]cd`, `cat{strfold{AB}str{cd}}`}, + + // Factoring. + {`abc|abd|aef|bcx|bcy`, `alt{cat{lit{a}alt{cat{lit{b}cc{0x63-0x64}}str{ef}}}cat{str{bc}cc{0x78-0x79}}}`}, + {`ax+y|ax+z|ay+w`, `cat{lit{a}alt{cat{plus{lit{x}}cc{0x79-0x7a}}cat{plus{lit{y}}lit{w}}}}`}, +} + +const testFlags = MatchNL | PerlX | UnicodeGroups + +// Test Parse -> Dump. +func TestParseDump(t *testing.T) { + for _, tt := range parseTests { + re, err := Parse(tt.Regexp, testFlags) + if err != nil { + t.Errorf("Parse(%#q): %v", tt.Regexp, err) + continue + } + d := dump(re) + if d != tt.Dump { + t.Errorf("Parse(%#q).Dump() = %#q want %#q", tt.Regexp, d, tt.Dump) + } + } +} + +// dump prints a string representation of the regexp showing +// the structure explicitly. +func dump(re *Regexp) string { + var b bytes.Buffer + dumpRegexp(&b, re) + return b.String() +} + +var opNames = []string{ + OpNoMatch: "no", + OpEmptyMatch: "emp", + OpLiteral: "lit", + OpCharClass: "cc", + OpAnyCharNotNL: "dnl", + OpAnyChar: "dot", + OpBeginLine: "bol", + OpEndLine: "eol", + OpBeginText: "bot", + OpEndText: "eot", + OpWordBoundary: "wb", + OpNoWordBoundary: "nwb", + OpCapture: "cap", + OpStar: "star", + OpPlus: "plus", + OpQuest: "que", + OpRepeat: "rep", + OpConcat: "cat", + OpAlternate: "alt", +} + +// dumpRegexp writes an encoding of the syntax tree for the regexp re to b. +// It is used during testing to distinguish between parses that might print +// the same using re's String method. +func dumpRegexp(b *bytes.Buffer, re *Regexp) { + if int(re.Op) >= len(opNames) || opNames[re.Op] == "" { + fmt.Fprintf(b, "op%d", re.Op) + } else { + switch re.Op { + default: + b.WriteString(opNames[re.Op]) + case OpStar, OpPlus, OpQuest, OpRepeat: + if re.Flags&NonGreedy != 0 { + b.WriteByte('n') + } + b.WriteString(opNames[re.Op]) + case OpLiteral: + if len(re.Rune) > 1 { + b.WriteString("str") + } else { + b.WriteString("lit") + } + if re.Flags&FoldCase != 0 { + for _, r := range re.Rune { + if unicode.SimpleFold(r) != r { + b.WriteString("fold") + break + } + } + } + } + } + b.WriteByte('{') + switch re.Op { + case OpEndText: + if re.Flags&WasDollar == 0 { + b.WriteString(`\z`) + } + case OpLiteral: + for _, r := range re.Rune { + b.WriteRune(r) + } + case OpConcat, OpAlternate: + for _, sub := range re.Sub { + dumpRegexp(b, sub) + } + case OpStar, OpPlus, OpQuest: + dumpRegexp(b, re.Sub[0]) + case OpRepeat: + fmt.Fprintf(b, "%d,%d ", re.Min, re.Max) + dumpRegexp(b, re.Sub[0]) + case OpCapture: + if re.Name != "" { + b.WriteString(re.Name) + b.WriteByte(':') + } + dumpRegexp(b, re.Sub[0]) + case OpCharClass: + sep := "" + for i := 0; i < len(re.Rune); i += 2 { + b.WriteString(sep) + sep = " " + lo, hi := re.Rune[i], re.Rune[i+1] + if lo == hi { + fmt.Fprintf(b, "%#x", lo) + } else { + fmt.Fprintf(b, "%#x-%#x", lo, hi) + } + } + } + b.WriteByte('}') +} + +func mkCharClass(f func(int) bool) string { + re := &Regexp{Op: OpCharClass} + lo := -1 + for i := 0; i <= unicode.MaxRune; i++ { + if f(i) { + if lo < 0 { + lo = i + } + } else { + if lo >= 0 { + re.Rune = append(re.Rune, lo, i-1) + lo = -1 + } + } + } + if lo >= 0 { + re.Rune = append(re.Rune, lo, unicode.MaxRune) + } + return dump(re) +} + +func isUpperFold(rune int) bool { + if unicode.IsUpper(rune) { + return true + } + c := unicode.SimpleFold(rune) + for c != rune { + if unicode.IsUpper(c) { + return true + } + c = unicode.SimpleFold(c) + } + return false +} + +func TestFoldConstants(t *testing.T) { + last := -1 + for i := 0; i <= unicode.MaxRune; i++ { + if unicode.SimpleFold(i) == i { + continue + } + if last == -1 && minFold != i { + t.Errorf("minFold=%#U should be %#U", minFold, i) + } + last = i + } + if maxFold != last { + t.Errorf("maxFold=%#U should be %#U", maxFold, last) + } +} + +func TestAppendRangeCollapse(t *testing.T) { + // AppendRange should collapse each of the new ranges + // into the earlier ones (it looks back two ranges), so that + // the slice never grows very large. + // Note that we are not calling cleanClass. + var r []int + for i := 'A'; i <= 'Z'; i++ { + r = appendRange(r, i, i) + r = appendRange(r, i+'a'-'A', i+'a'-'A') + } + if string(r) != "AZaz" { + t.Errorf("appendRange interlaced A-Z a-z = %s, want AZaz", string(r)) + } +} diff --git a/libgo/go/exp/regexp/syntax/perl_groups.go b/libgo/go/exp/regexp/syntax/perl_groups.go new file mode 100644 index 0000000..05b392c --- /dev/null +++ b/libgo/go/exp/regexp/syntax/perl_groups.go @@ -0,0 +1,130 @@ +// GENERATED BY make_perl_groups.pl; DO NOT EDIT. +// make_perl_groups.pl >perl_groups.go + +package syntax + +var code1 = []int{ /* \d */ + 0x30, 0x39, +} + +var code2 = []int{ /* \s */ + 0x9, 0xa, + 0xc, 0xd, + 0x20, 0x20, +} + +var code3 = []int{ /* \w */ + 0x30, 0x39, + 0x41, 0x5a, + 0x5f, 0x5f, + 0x61, 0x7a, +} + +var perlGroup = map[string]charGroup{ + `\d`: {+1, code1}, + `\D`: {-1, code1}, + `\s`: {+1, code2}, + `\S`: {-1, code2}, + `\w`: {+1, code3}, + `\W`: {-1, code3}, +} +var code4 = []int{ /* [:alnum:] */ + 0x30, 0x39, + 0x41, 0x5a, + 0x61, 0x7a, +} + +var code5 = []int{ /* [:alpha:] */ + 0x41, 0x5a, + 0x61, 0x7a, +} + +var code6 = []int{ /* [:ascii:] */ + 0x0, 0x7f, +} + +var code7 = []int{ /* [:blank:] */ + 0x9, 0x9, + 0x20, 0x20, +} + +var code8 = []int{ /* [:cntrl:] */ + 0x0, 0x1f, + 0x7f, 0x7f, +} + +var code9 = []int{ /* [:digit:] */ + 0x30, 0x39, +} + +var code10 = []int{ /* [:graph:] */ + 0x21, 0x7e, +} + +var code11 = []int{ /* [:lower:] */ + 0x61, 0x7a, +} + +var code12 = []int{ /* [:print:] */ + 0x20, 0x7e, +} + +var code13 = []int{ /* [:punct:] */ + 0x21, 0x2f, + 0x3a, 0x40, + 0x5b, 0x60, + 0x7b, 0x7e, +} + +var code14 = []int{ /* [:space:] */ + 0x9, 0xd, + 0x20, 0x20, +} + +var code15 = []int{ /* [:upper:] */ + 0x41, 0x5a, +} + +var code16 = []int{ /* [:word:] */ + 0x30, 0x39, + 0x41, 0x5a, + 0x5f, 0x5f, + 0x61, 0x7a, +} + +var code17 = []int{ /* [:xdigit:] */ + 0x30, 0x39, + 0x41, 0x46, + 0x61, 0x66, +} + +var posixGroup = map[string]charGroup{ + `[:alnum:]`: {+1, code4}, + `[:^alnum:]`: {-1, code4}, + `[:alpha:]`: {+1, code5}, + `[:^alpha:]`: {-1, code5}, + `[:ascii:]`: {+1, code6}, + `[:^ascii:]`: {-1, code6}, + `[:blank:]`: {+1, code7}, + `[:^blank:]`: {-1, code7}, + `[:cntrl:]`: {+1, code8}, + `[:^cntrl:]`: {-1, code8}, + `[:digit:]`: {+1, code9}, + `[:^digit:]`: {-1, code9}, + `[:graph:]`: {+1, code10}, + `[:^graph:]`: {-1, code10}, + `[:lower:]`: {+1, code11}, + `[:^lower:]`: {-1, code11}, + `[:print:]`: {+1, code12}, + `[:^print:]`: {-1, code12}, + `[:punct:]`: {+1, code13}, + `[:^punct:]`: {-1, code13}, + `[:space:]`: {+1, code14}, + `[:^space:]`: {-1, code14}, + `[:upper:]`: {+1, code15}, + `[:^upper:]`: {-1, code15}, + `[:word:]`: {+1, code16}, + `[:^word:]`: {-1, code16}, + `[:xdigit:]`: {+1, code17}, + `[:^xdigit:]`: {-1, code17}, +} diff --git a/libgo/go/exp/regexp/syntax/prog.go b/libgo/go/exp/regexp/syntax/prog.go new file mode 100644 index 0000000..bf85b72 --- /dev/null +++ b/libgo/go/exp/regexp/syntax/prog.go @@ -0,0 +1,237 @@ +package syntax + +import ( + "bytes" + "strconv" +) + +// Compiled program. +// May not belong in this package, but convenient for now. + +// A Prog is a compiled regular expression program. +type Prog struct { + Inst []Inst + Start int // index of start instruction + NumCap int // number of InstCapture insts in re +} + +// An InstOp is an instruction opcode. +type InstOp uint8 + +const ( + InstAlt InstOp = iota + InstAltMatch + InstCapture + InstEmptyWidth + InstMatch + InstFail + InstNop + InstRune +) + +// An EmptyOp specifies a kind or mixture of zero-width assertions. +type EmptyOp uint8 + +const ( + EmptyBeginLine EmptyOp = 1 << iota + EmptyEndLine + EmptyBeginText + EmptyEndText + EmptyWordBoundary + EmptyNoWordBoundary +) + +// An Inst is a single instruction in a regular expression program. +type Inst struct { + Op InstOp + Out uint32 // all but InstMatch, InstFail + Arg uint32 // InstAlt, InstAltMatch, InstCapture, InstEmptyWidth + Rune []int +} + +func (p *Prog) String() string { + var b bytes.Buffer + dumpProg(&b, p) + return b.String() +} + +// skipNop follows any no-op or capturing instructions +// and returns the resulting pc. +func (p *Prog) skipNop(pc uint32) *Inst { + i := &p.Inst[pc] + for i.Op == InstNop || i.Op == InstCapture { + pc = i.Out + i = &p.Inst[pc] + } + return i +} + +// Prefix returns a literal string that all matches for the +// regexp must start with. Complete is true if the prefix +// is the entire match. +func (p *Prog) Prefix() (prefix string, complete bool) { + i := p.skipNop(uint32(p.Start)) + + // Avoid allocation of buffer if prefix is empty. + if i.Op != InstRune || len(i.Rune) != 1 { + return "", i.Op == InstMatch + } + + // Have prefix; gather characters. + var buf bytes.Buffer + for i.Op == InstRune && len(i.Rune) == 1 { + buf.WriteRune(i.Rune[0]) + i = p.skipNop(i.Out) + } + return buf.String(), i.Op == InstMatch +} + +// StartCond returns the leading empty-width conditions that must +// be true in any match. It returns ^EmptyOp(0) if no matches are possible. +func (p *Prog) StartCond() EmptyOp { + var flag EmptyOp + pc := uint32(p.Start) + i := &p.Inst[pc] +Loop: + for { + switch i.Op { + case InstEmptyWidth: + flag |= EmptyOp(i.Arg) + case InstFail: + return ^EmptyOp(0) + case InstCapture, InstNop: + // skip + default: + break Loop + } + pc = i.Out + i = &p.Inst[pc] + } + return flag +} + +// MatchRune returns true if the instruction matches (and consumes) r. +// It should only be called when i.Op == InstRune. +func (i *Inst) MatchRune(r int) bool { + rune := i.Rune + + // Special case: single-rune slice is from literal string, not char class. + // TODO: Case folding. + if len(rune) == 1 { + return r == rune[0] + } + + // Peek at the first few pairs. + // Should handle ASCII well. + for j := 0; j < len(rune) && j <= 8; j += 2 { + if r < rune[j] { + return false + } + if r <= rune[j+1] { + return true + } + } + + // Otherwise binary search. + lo := 0 + hi := len(rune) / 2 + for lo < hi { + m := lo + (hi-lo)/2 + if c := rune[2*m]; c <= r { + if r <= rune[2*m+1] { + return true + } + lo = m + 1 + } else { + hi = m + } + } + return false +} + +// As per re2's Prog::IsWordChar. Determines whether rune is an ASCII word char. +// Since we act on runes, it would be easy to support Unicode here. +func wordRune(rune int) bool { + return rune == '_' || + ('A' <= rune && rune <= 'Z') || + ('a' <= rune && rune <= 'z') || + ('0' <= rune && rune <= '9') +} + +// MatchEmptyWidth returns true if the instruction matches +// an empty string between the runes before and after. +// It should only be called when i.Op == InstEmptyWidth. +func (i *Inst) MatchEmptyWidth(before int, after int) bool { + switch EmptyOp(i.Arg) { + case EmptyBeginLine: + return before == '\n' || before == -1 + case EmptyEndLine: + return after == '\n' || after == -1 + case EmptyBeginText: + return before == -1 + case EmptyEndText: + return after == -1 + case EmptyWordBoundary: + return wordRune(before) != wordRune(after) + case EmptyNoWordBoundary: + return wordRune(before) == wordRune(after) + } + panic("unknown empty width arg") +} + +func (i *Inst) String() string { + var b bytes.Buffer + dumpInst(&b, i) + return b.String() +} + +func bw(b *bytes.Buffer, args ...string) { + for _, s := range args { + b.WriteString(s) + } +} + +func dumpProg(b *bytes.Buffer, p *Prog) { + for j := range p.Inst { + i := &p.Inst[j] + pc := strconv.Itoa(j) + if len(pc) < 3 { + b.WriteString(" "[len(pc):]) + } + if j == p.Start { + pc += "*" + } + bw(b, pc, "\t") + dumpInst(b, i) + bw(b, "\n") + } +} + +func u32(i uint32) string { + return strconv.Uitoa64(uint64(i)) +} + +func dumpInst(b *bytes.Buffer, i *Inst) { + switch i.Op { + case InstAlt: + bw(b, "alt -> ", u32(i.Out), ", ", u32(i.Arg)) + case InstAltMatch: + bw(b, "altmatch -> ", u32(i.Out), ", ", u32(i.Arg)) + case InstCapture: + bw(b, "cap ", u32(i.Arg), " -> ", u32(i.Out)) + case InstEmptyWidth: + bw(b, "empty ", u32(i.Arg), " -> ", u32(i.Out)) + case InstMatch: + bw(b, "match") + case InstFail: + bw(b, "fail") + case InstNop: + bw(b, "nop -> ", u32(i.Out)) + case InstRune: + if i.Rune == nil { + // shouldn't happen + bw(b, "rune ") + } + bw(b, "rune ", strconv.QuoteToASCII(string(i.Rune)), " -> ", u32(i.Out)) + } +} diff --git a/libgo/go/exp/regexp/syntax/prog_test.go b/libgo/go/exp/regexp/syntax/prog_test.go new file mode 100644 index 0000000..7be4281 --- /dev/null +++ b/libgo/go/exp/regexp/syntax/prog_test.go @@ -0,0 +1,91 @@ +package syntax + +import ( + "testing" +) + +var compileTests = []struct { + Regexp string + Prog string +}{ + {"a", ` 0 fail + 1* rune "a" -> 2 + 2 match +`}, + {"[A-M][n-z]", ` 0 fail + 1* rune "AM" -> 2 + 2 rune "nz" -> 3 + 3 match +`}, + {"", ` 0 fail + 1* nop -> 2 + 2 match +`}, + {"a?", ` 0 fail + 1 rune "a" -> 3 + 2* alt -> 1, 3 + 3 match +`}, + {"a??", ` 0 fail + 1 rune "a" -> 3 + 2* alt -> 3, 1 + 3 match +`}, + {"a+", ` 0 fail + 1* rune "a" -> 2 + 2 alt -> 1, 3 + 3 match +`}, + {"a+?", ` 0 fail + 1* rune "a" -> 2 + 2 alt -> 3, 1 + 3 match +`}, + {"a*", ` 0 fail + 1 rune "a" -> 2 + 2* alt -> 1, 3 + 3 match +`}, + {"a*?", ` 0 fail + 1 rune "a" -> 2 + 2* alt -> 3, 1 + 3 match +`}, + {"a+b+", ` 0 fail + 1* rune "a" -> 2 + 2 alt -> 1, 3 + 3 rune "b" -> 4 + 4 alt -> 3, 5 + 5 match +`}, + {"(a+)(b+)", ` 0 fail + 1* cap 2 -> 2 + 2 rune "a" -> 3 + 3 alt -> 2, 4 + 4 cap 3 -> 5 + 5 cap 4 -> 6 + 6 rune "b" -> 7 + 7 alt -> 6, 8 + 8 cap 5 -> 9 + 9 match +`}, + {"a+|b+", ` 0 fail + 1 rune "a" -> 2 + 2 alt -> 1, 6 + 3 rune "b" -> 4 + 4 alt -> 3, 6 + 5* alt -> 1, 3 + 6 match +`}, +} + +func TestCompile(t *testing.T) { + for _, tt := range compileTests { + re, _ := Parse(tt.Regexp, Perl) + p, _ := Compile(re) + s := p.String() + if s != tt.Prog { + t.Errorf("compiled %#q:\n--- have\n%s---\n--- want\n%s---", tt.Regexp, s, tt.Prog) + } + } +} diff --git a/libgo/go/exp/regexp/syntax/regexp.go b/libgo/go/exp/regexp/syntax/regexp.go new file mode 100644 index 0000000..00a4add --- /dev/null +++ b/libgo/go/exp/regexp/syntax/regexp.go @@ -0,0 +1,284 @@ +// 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 syntax parses regular expressions into syntax trees. +// WORK IN PROGRESS. +package syntax + +// Note to implementers: +// In this package, re is always a *Regexp and r is always a rune. + +import ( + "bytes" + "strconv" + "strings" + "unicode" +) + +// A Regexp is a node in a regular expression syntax tree. +type Regexp struct { + Op Op // operator + Flags Flags + Sub []*Regexp // subexpressions, if any + Sub0 [1]*Regexp // storage for short Sub + Rune []int // matched runes, for OpLiteral, OpCharClass + Rune0 [2]int // storage for short Rune + Min, Max int // min, max for OpRepeat + Cap int // capturing index, for OpCapture + Name string // capturing name, for OpCapture +} + +// An Op is a single regular expression operator. +type Op uint8 + +// Operators are listed in precedence order, tightest binding to weakest. +// Character class operators are listed simplest to most complex +// (OpLiteral, OpCharClass, OpAnyCharNotNL, OpAnyChar). + +const ( + OpNoMatch Op = 1 + iota // matches no strings + OpEmptyMatch // matches empty string + OpLiteral // matches Runes sequence + OpCharClass // matches Runes interpreted as range pair list + OpAnyCharNotNL // matches any character + OpAnyChar // matches any character + OpBeginLine // matches empty string at beginning of line + OpEndLine // matches empty string at end of line + OpBeginText // matches empty string at beginning of text + OpEndText // matches empty string at end of text + OpWordBoundary // matches word boundary `\b` + OpNoWordBoundary // matches word non-boundary `\B` + OpCapture // capturing subexpression with index Cap, optional name Name + OpStar // matches Sub[0] zero or more times + OpPlus // matches Sub[0] one or more times + OpQuest // matches Sub[0] zero or one times + OpRepeat // matches Sub[0] at least Min times, at most Max (Max == -1 is no limit) + OpConcat // matches concatenation of Subs + OpAlternate // matches alternation of Subs +) + +const opPseudo Op = 128 // where pseudo-ops start + +// Equal returns true if x and y have identical structure. +func (x *Regexp) Equal(y *Regexp) bool { + if x == nil || y == nil { + return x == y + } + if x.Op != y.Op { + return false + } + switch x.Op { + case OpEndText: + // The parse flags remember whether this is \z or \Z. + if x.Flags&WasDollar != y.Flags&WasDollar { + return false + } + + case OpLiteral, OpCharClass: + if len(x.Rune) != len(y.Rune) { + return false + } + for i, r := range x.Rune { + if r != y.Rune[i] { + return false + } + } + + case OpAlternate, OpConcat: + if len(x.Sub) != len(y.Sub) { + return false + } + for i, sub := range x.Sub { + if !sub.Equal(y.Sub[i]) { + return false + } + } + + case OpStar, OpPlus, OpQuest: + if x.Flags&NonGreedy != y.Flags&NonGreedy || !x.Sub[0].Equal(y.Sub[0]) { + return false + } + + case OpRepeat: + if x.Flags&NonGreedy != y.Flags&NonGreedy || x.Min != y.Min || x.Max != y.Max || !x.Sub[0].Equal(y.Sub[0]) { + return false + } + + case OpCapture: + if x.Cap != y.Cap || x.Name != y.Name || !x.Sub[0].Equal(y.Sub[0]) { + return false + } + } + return true +} + +// writeRegexp writes the Perl syntax for the regular expression re to b. +func writeRegexp(b *bytes.Buffer, re *Regexp) { + switch re.Op { + default: + b.WriteString("") + case OpNoMatch: + b.WriteString(`[^\x00-\x{10FFFF}]`) + case OpEmptyMatch: + b.WriteString(`(?:)`) + case OpLiteral: + if re.Flags&FoldCase != 0 { + b.WriteString(`(?i:`) + } + for _, r := range re.Rune { + escape(b, r, false) + } + if re.Flags&FoldCase != 0 { + b.WriteString(`)`) + } + case OpCharClass: + if len(re.Rune)%2 != 0 { + b.WriteString(`[invalid char class]`) + break + } + b.WriteRune('[') + if len(re.Rune) == 0 { + b.WriteString(`^\x00-\x{10FFFF}`) + } else if re.Rune[0] == 0 && re.Rune[len(re.Rune)-1] == unicode.MaxRune { + // Contains 0 and MaxRune. Probably a negated class. + // Print the gaps. + b.WriteRune('^') + for i := 1; i < len(re.Rune)-1; i += 2 { + lo, hi := re.Rune[i]+1, re.Rune[i+1]-1 + escape(b, lo, lo == '-') + if lo != hi { + b.WriteRune('-') + escape(b, hi, hi == '-') + } + } + } else { + for i := 0; i < len(re.Rune); i += 2 { + lo, hi := re.Rune[i], re.Rune[i+1] + escape(b, lo, lo == '-') + if lo != hi { + b.WriteRune('-') + escape(b, hi, hi == '-') + } + } + } + b.WriteRune(']') + case OpAnyCharNotNL: + b.WriteString(`[^\n]`) + case OpAnyChar: + b.WriteRune('.') + case OpBeginLine: + b.WriteRune('^') + case OpEndLine: + b.WriteRune('$') + case OpBeginText: + b.WriteString(`\A`) + case OpEndText: + b.WriteString(`\z`) + case OpWordBoundary: + b.WriteString(`\b`) + case OpNoWordBoundary: + b.WriteString(`\B`) + case OpCapture: + if re.Name != "" { + b.WriteString(`(?P<`) + b.WriteString(re.Name) + b.WriteRune('>') + } else { + b.WriteRune('(') + } + if re.Sub[0].Op != OpEmptyMatch { + writeRegexp(b, re.Sub[0]) + } + b.WriteRune(')') + case OpStar, OpPlus, OpQuest, OpRepeat: + if sub := re.Sub[0]; sub.Op > OpCapture { + b.WriteString(`(?:`) + writeRegexp(b, sub) + b.WriteString(`)`) + } else { + writeRegexp(b, sub) + } + switch re.Op { + case OpStar: + b.WriteRune('*') + case OpPlus: + b.WriteRune('+') + case OpQuest: + b.WriteRune('?') + case OpRepeat: + b.WriteRune('{') + b.WriteString(strconv.Itoa(re.Min)) + if re.Max != re.Min { + b.WriteRune(',') + if re.Max >= 0 { + b.WriteString(strconv.Itoa(re.Max)) + } + } + b.WriteRune('}') + } + case OpConcat: + for _, sub := range re.Sub { + if sub.Op == OpAlternate { + b.WriteString(`(?:`) + writeRegexp(b, sub) + b.WriteString(`)`) + } else { + writeRegexp(b, sub) + } + } + case OpAlternate: + for i, sub := range re.Sub { + if i > 0 { + b.WriteRune('|') + } + writeRegexp(b, sub) + } + } +} + +func (re *Regexp) String() string { + var b bytes.Buffer + writeRegexp(&b, re) + return b.String() +} + +const meta = `\.+*?()|[]{}^$` + +func escape(b *bytes.Buffer, r int, force bool) { + if unicode.IsPrint(r) { + if strings.IndexRune(meta, r) >= 0 || force { + b.WriteRune('\\') + } + b.WriteRune(r) + return + } + + switch r { + case '\a': + b.WriteString(`\a`) + case '\f': + b.WriteString(`\f`) + case '\n': + b.WriteString(`\n`) + case '\r': + b.WriteString(`\r`) + case '\t': + b.WriteString(`\t`) + case '\v': + b.WriteString(`\v`) + default: + if r < 0x100 { + b.WriteString(`\x`) + s := strconv.Itob(r, 16) + if len(s) == 1 { + b.WriteRune('0') + } + b.WriteString(s) + break + } + b.WriteString(`\x{`) + b.WriteString(strconv.Itob(r, 16)) + b.WriteString(`}`) + } +} diff --git a/libgo/go/exp/regexp/syntax/simplify.go b/libgo/go/exp/regexp/syntax/simplify.go new file mode 100644 index 0000000..7239041 --- /dev/null +++ b/libgo/go/exp/regexp/syntax/simplify.go @@ -0,0 +1,151 @@ +// 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 syntax + +// Simplify returns a regexp equivalent to re but without counted repetitions +// and with various other simplifications, such as rewriting /(?:a+)+/ to /a+/. +// The resulting regexp will execute correctly but its string representation +// will not produce the same parse tree, because capturing parentheses +// may have been duplicated or removed. For example, the simplified form +// for /(x){1,2}/ is /(x)(x)?/ but both parentheses capture as $1. +// The returned regexp may share structure with or be the original. +func (re *Regexp) Simplify() *Regexp { + if re == nil { + return nil + } + switch re.Op { + case OpCapture, OpConcat, OpAlternate: + // Simplify children, building new Regexp if children change. + nre := re + for i, sub := range re.Sub { + nsub := sub.Simplify() + if nre == re && nsub != sub { + // Start a copy. + nre = new(Regexp) + *nre = *re + nre.Rune = nil + nre.Sub = append(nre.Sub0[:0], re.Sub[:i]...) + } + if nre != re { + nre.Sub = append(nre.Sub, nsub) + } + } + return nre + + case OpStar, OpPlus, OpQuest: + sub := re.Sub[0].Simplify() + return simplify1(re.Op, re.Flags, sub, re) + + case OpRepeat: + // Special special case: x{0} matches the empty string + // and doesn't even need to consider x. + if re.Min == 0 && re.Max == 0 { + return &Regexp{Op: OpEmptyMatch} + } + + // The fun begins. + sub := re.Sub[0].Simplify() + + // x{n,} means at least n matches of x. + if re.Max == -1 { + // Special case: x{0,} is x*. + if re.Min == 0 { + return simplify1(OpStar, re.Flags, sub, nil) + } + + // Special case: x{1,} is x+. + if re.Min == 1 { + return simplify1(OpPlus, re.Flags, sub, nil) + } + + // General case: x{4,} is xxxx+. + nre := &Regexp{Op: OpConcat} + nre.Sub = nre.Sub0[:0] + for i := 0; i < re.Min-1; i++ { + nre.Sub = append(nre.Sub, sub) + } + nre.Sub = append(nre.Sub, simplify1(OpPlus, re.Flags, sub, nil)) + return nre + } + + // Special case x{0} handled above. + + // Special case: x{1} is just x. + if re.Min == 1 && re.Max == 1 { + return sub + } + + // General case: x{n,m} means n copies of x and m copies of x? + // The machine will do less work if we nest the final m copies, + // so that x{2,5} = xx(x(x(x)?)?)? + + // Build leading prefix: xx. + var prefix *Regexp + if re.Min > 0 { + prefix = &Regexp{Op: OpConcat} + prefix.Sub = prefix.Sub0[:0] + for i := 0; i < re.Min; i++ { + prefix.Sub = append(prefix.Sub, sub) + } + } + + // Build and attach suffix: (x(x(x)?)?)? + if re.Max > re.Min { + suffix := simplify1(OpQuest, re.Flags, sub, nil) + for i := re.Min + 1; i < re.Max; i++ { + nre2 := &Regexp{Op: OpConcat} + nre2.Sub = append(nre2.Sub0[:0], sub, suffix) + suffix = simplify1(OpQuest, re.Flags, nre2, nil) + } + if prefix == nil { + return suffix + } + prefix.Sub = append(prefix.Sub, suffix) + } + if prefix != nil { + return prefix + } + + // Some degenerate case like min > max or min < max < 0. + // Handle as impossible match. + return &Regexp{Op: OpNoMatch} + } + + return re +} + +// simplify1 implements Simplify for the unary OpStar, +// OpPlus, and OpQuest operators. It returns the simple regexp +// equivalent to +// +// Regexp{Op: op, Flags: flags, Sub: {sub}} +// +// under the assumption that sub is already simple, and +// without first allocating that structure. If the regexp +// to be returned turns out to be equivalent to re, simplify1 +// returns re instead. +// +// simplify1 is factored out of Simplify because the implementation +// for other operators generates these unary expressions. +// Letting them call simplify1 makes sure the expressions they +// generate are simple. +func simplify1(op Op, flags Flags, sub, re *Regexp) *Regexp { + // Special case: repeat the empty string as much as + // you want, but it's still the empty string. + if sub.Op == OpEmptyMatch { + return sub + } + // The operators are idempotent if the flags match. + if op == sub.Op && flags&NonGreedy == sub.Flags&NonGreedy { + return sub + } + if re != nil && re.Op == op && re.Flags&NonGreedy == flags&NonGreedy && sub == re.Sub[0] { + return re + } + + re = &Regexp{Op: op, Flags: flags} + re.Sub = append(re.Sub0[:0], sub) + return re +} diff --git a/libgo/go/exp/regexp/syntax/simplify_test.go b/libgo/go/exp/regexp/syntax/simplify_test.go new file mode 100644 index 0000000..c8cec21 --- /dev/null +++ b/libgo/go/exp/regexp/syntax/simplify_test.go @@ -0,0 +1,151 @@ +// 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 syntax + +import "testing" + +var simplifyTests = []struct { + Regexp string + Simple string +}{ + // Already-simple constructs + {`a`, `a`}, + {`ab`, `ab`}, + {`a|b`, `[a-b]`}, + {`ab|cd`, `ab|cd`}, + {`(ab)*`, `(ab)*`}, + {`(ab)+`, `(ab)+`}, + {`(ab)?`, `(ab)?`}, + {`.`, `.`}, + {`^`, `^`}, + {`$`, `$`}, + {`[ac]`, `[ac]`}, + {`[^ac]`, `[^ac]`}, + + // Posix character classes + {`[[:alnum:]]`, `[0-9A-Za-z]`}, + {`[[:alpha:]]`, `[A-Za-z]`}, + {`[[:blank:]]`, `[\t ]`}, + {`[[:cntrl:]]`, `[\x00-\x1f\x7f]`}, + {`[[:digit:]]`, `[0-9]`}, + {`[[:graph:]]`, `[!-~]`}, + {`[[:lower:]]`, `[a-z]`}, + {`[[:print:]]`, `[ -~]`}, + {`[[:punct:]]`, "[!-/:-@\\[-`\\{-~]"}, + {`[[:space:]]`, `[\t-\r ]`}, + {`[[:upper:]]`, `[A-Z]`}, + {`[[:xdigit:]]`, `[0-9A-Fa-f]`}, + + // Perl character classes + {`\d`, `[0-9]`}, + {`\s`, `[\t-\n\f-\r ]`}, + {`\w`, `[0-9A-Z_a-z]`}, + {`\D`, `[^0-9]`}, + {`\S`, `[^\t-\n\f-\r ]`}, + {`\W`, `[^0-9A-Z_a-z]`}, + {`[\d]`, `[0-9]`}, + {`[\s]`, `[\t-\n\f-\r ]`}, + {`[\w]`, `[0-9A-Z_a-z]`}, + {`[\D]`, `[^0-9]`}, + {`[\S]`, `[^\t-\n\f-\r ]`}, + {`[\W]`, `[^0-9A-Z_a-z]`}, + + // Posix repetitions + {`a{1}`, `a`}, + {`a{2}`, `aa`}, + {`a{5}`, `aaaaa`}, + {`a{0,1}`, `a?`}, + // The next three are illegible because Simplify inserts (?:) + // parens instead of () parens to avoid creating extra + // captured subexpressions. The comments show a version with fewer parens. + {`(a){0,2}`, `(?:(a)(a)?)?`}, // (aa?)? + {`(a){0,4}`, `(?:(a)(?:(a)(?:(a)(a)?)?)?)?`}, // (a(a(aa?)?)?)? + {`(a){2,6}`, `(a)(a)(?:(a)(?:(a)(?:(a)(a)?)?)?)?`}, // aa(a(a(aa?)?)?)? + {`a{0,2}`, `(?:aa?)?`}, // (aa?)? + {`a{0,4}`, `(?:a(?:a(?:aa?)?)?)?`}, // (a(a(aa?)?)?)? + {`a{2,6}`, `aa(?:a(?:a(?:aa?)?)?)?`}, // aa(a(a(aa?)?)?)? + {`a{0,}`, `a*`}, + {`a{1,}`, `a+`}, + {`a{2,}`, `aa+`}, + {`a{5,}`, `aaaaa+`}, + + // Test that operators simplify their arguments. + {`(?:a{1,}){1,}`, `a+`}, + {`(a{1,}b{1,})`, `(a+b+)`}, + {`a{1,}|b{1,}`, `a+|b+`}, + {`(?:a{1,})*`, `(?:a+)*`}, + {`(?:a{1,})+`, `a+`}, + {`(?:a{1,})?`, `(?:a+)?`}, + {``, `(?:)`}, + {`a{0}`, `(?:)`}, + + // Character class simplification + {`[ab]`, `[a-b]`}, + {`[a-za-za-z]`, `[a-z]`}, + {`[A-Za-zA-Za-z]`, `[A-Za-z]`}, + {`[ABCDEFGH]`, `[A-H]`}, + {`[AB-CD-EF-GH]`, `[A-H]`}, + {`[W-ZP-XE-R]`, `[E-Z]`}, + {`[a-ee-gg-m]`, `[a-m]`}, + {`[a-ea-ha-m]`, `[a-m]`}, + {`[a-ma-ha-e]`, `[a-m]`}, + {`[a-zA-Z0-9 -~]`, `[ -~]`}, + + // Empty character classes + {`[^[:cntrl:][:^cntrl:]]`, `[^\x00-\x{10FFFF}]`}, + + // Full character classes + {`[[:cntrl:][:^cntrl:]]`, `.`}, + + // Unicode case folding. + {`(?i)A`, `(?i:A)`}, + {`(?i)a`, `(?i:a)`}, + {`(?i)[A]`, `(?i:A)`}, + {`(?i)[a]`, `(?i:A)`}, + {`(?i)K`, `(?i:K)`}, + {`(?i)k`, `(?i:k)`}, + {`(?i)\x{212a}`, "(?i:\u212A)"}, + {`(?i)[K]`, "[Kk\u212A]"}, + {`(?i)[k]`, "[Kk\u212A]"}, + {`(?i)[\x{212a}]`, "[Kk\u212A]"}, + {`(?i)[a-z]`, "[A-Za-z\u017F\u212A]"}, + {`(?i)[\x00-\x{FFFD}]`, "[\\x00-\uFFFD]"}, + {`(?i)[\x00-\x{10FFFF}]`, `.`}, + + // Empty string as a regular expression. + // The empty string must be preserved inside parens in order + // to make submatches work right, so these tests are less + // interesting than they might otherwise be. String inserts + // explicit (?:) in place of non-parenthesized empty strings, + // to make them easier to spot for other parsers. + {`(a|b|)`, `([a-b]|(?:))`}, + {`(|)`, `()`}, + {`a()`, `a()`}, + {`(()|())`, `(()|())`}, + {`(a|)`, `(a|(?:))`}, + {`ab()cd()`, `ab()cd()`}, + {`()`, `()`}, + {`()*`, `()*`}, + {`()+`, `()+`}, + {`()?`, `()?`}, + {`(){0}`, `(?:)`}, + {`(){1}`, `()`}, + {`(){1,}`, `()+`}, + {`(){0,2}`, `(?:()()?)?`}, +} + +func TestSimplify(t *testing.T) { + for _, tt := range simplifyTests { + re, err := Parse(tt.Regexp, MatchNL|Perl&^OneLine) + if err != nil { + t.Errorf("Parse(%#q) = error %v", tt.Regexp, err) + continue + } + s := re.Simplify().String() + if s != tt.Simple { + t.Errorf("Simplify(%#q) = %#q, want %#q", tt.Regexp, s, tt.Simple) + } + } +} diff --git a/libgo/go/exp/template/html/context.go b/libgo/go/exp/template/html/context.go new file mode 100644 index 0000000..4110068 --- /dev/null +++ b/libgo/go/exp/template/html/context.go @@ -0,0 +1,98 @@ +// 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 html + +import ( + "fmt" +) + +// context describes the state an HTML parser must be in when it reaches the +// portion of HTML produced by evaluating a particular template node. +// +// The zero value of type context is the start context for a template that +// produces an HTML fragment as defined at +// http://www.w3.org/TR/html5/the-end.html#parsing-html-fragments +// where the context element is null. +type context struct { + state state + delim delim +} + +func (c context) String() string { + return fmt.Sprintf("context{state: %s, delim: %s", c.state, c.delim) +} + +// eq is true if the two contexts are identical field-wise. +func (c context) eq(d context) bool { + return c.state == d.state && c.delim == d.delim +} + +// state describes a high-level HTML parser state. +// +// It bounds the top of the element stack, and by extension the HTML +// insertion mode, but also contains state that does not correspond to +// anything in the HTML5 parsing algorithm because a single token +// production in the HTML grammar may contain embedded actions in a template. +// For instance, the quoted HTML attribute produced by +//
+// is a single token in HTML's grammar but in a template spans several nodes. +type state uint8 + +const ( + // statePCDATA is parsed character data. An HTML parser is in + // this state when its parse position is outside an HTML tag, + // directive, comment, and special element body. + statePCDATA state = iota + // stateTag occurs before an HTML attribute or the end of a tag. + stateTag + // stateURI occurs inside an HTML attribute whose content is a URI. + stateURI + // stateError is an infectious error state outside any valid + // HTML/CSS/JS construct. + stateError +) + +var stateNames = [...]string{ + statePCDATA: "statePCDATA", + stateTag: "stateTag", + stateURI: "stateURI", + stateError: "stateError", +} + +func (s state) String() string { + if uint(s) < uint(len(stateNames)) { + return stateNames[s] + } + return fmt.Sprintf("illegal state %d", uint(s)) +} + +// delim is the delimiter that will end the current HTML attribute. +type delim uint8 + +const ( + // delimNone occurs outside any attribute. + delimNone delim = iota + // delimDoubleQuote occurs when a double quote (") closes the attribute. + delimDoubleQuote + // delimSingleQuote occurs when a single quote (') closes the attribute. + delimSingleQuote + // delimSpaceOrTagEnd occurs when a space or right angle bracket (>) + // closes the attribute. + delimSpaceOrTagEnd +) + +var delimNames = [...]string{ + delimNone: "delimNone", + delimDoubleQuote: "delimDoubleQuote", + delimSingleQuote: "delimSingleQuote", + delimSpaceOrTagEnd: "delimSpaceOrTagEnd", +} + +func (d delim) String() string { + if uint(d) < uint(len(delimNames)) { + return delimNames[d] + } + return fmt.Sprintf("illegal delim %d", uint(d)) +} diff --git a/libgo/go/exp/template/html/escape.go b/libgo/go/exp/template/html/escape.go new file mode 100644 index 0000000..e0e87b9 --- /dev/null +++ b/libgo/go/exp/template/html/escape.go @@ -0,0 +1,105 @@ +// 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 html is a specialization of exp/template that automates the +// construction of safe HTML output. +// At the moment, the escaping is naive. All dynamic content is assumed to be +// plain text interpolated in an HTML PCDATA context. +package html + +import ( + "template" + "template/parse" +) + +// Escape rewrites each action in the template to guarantee the output is +// HTML-escaped. +func Escape(t *template.Template) { + // If the parser shares trees based on common-subexpression + // joining then we will need to avoid multiply escaping the same action. + escapeListNode(t.Tree.Root) +} + +// escapeNode dispatches to escape helpers by type. +func escapeNode(node parse.Node) { + switch n := node.(type) { + case *parse.ListNode: + escapeListNode(n) + case *parse.TextNode: + // Nothing to do. + case *parse.ActionNode: + escapeActionNode(n) + case *parse.IfNode: + escapeIfNode(n) + case *parse.RangeNode: + escapeRangeNode(n) + case *parse.TemplateNode: + // Nothing to do. + case *parse.WithNode: + escapeWithNode(n) + default: + panic("handling for " + node.String() + " not implemented") + // TODO: Handle other inner node types. + } +} + +// escapeListNode recursively escapes its input's children. +func escapeListNode(node *parse.ListNode) { + if node == nil { + return + } + children := node.Nodes + for _, child := range children { + escapeNode(child) + } +} + +// escapeActionNode adds a pipeline call to the end that escapes the result +// of the expression before it is interpolated into the template output. +func escapeActionNode(node *parse.ActionNode) { + pipe := node.Pipe + + cmds := pipe.Cmds + nCmds := len(cmds) + + // If it already has an escaping command, do not interfere. + if nCmds != 0 { + if lastCmd := cmds[nCmds-1]; len(lastCmd.Args) != 0 { + // TODO: Recognize url and js as escaping functions once + // we have enough context to know whether additional + // escaping is necessary. + if arg, ok := lastCmd.Args[0].(*parse.IdentifierNode); ok && arg.Ident == "html" { + return + } + } + } + + htmlEscapeCommand := parse.CommandNode{ + NodeType: parse.NodeCommand, + Args: []parse.Node{parse.NewIdentifier("html")}, + } + + node.Pipe.Cmds = append(node.Pipe.Cmds, &htmlEscapeCommand) +} + +// escapeIfNode recursively escapes the if and then clauses but leaves the +// condition unchanged. +func escapeIfNode(node *parse.IfNode) { + escapeListNode(node.List) + escapeListNode(node.ElseList) +} + +// escapeRangeNode recursively escapes the loop body and else clause but +// leaves the series unchanged. +func escapeRangeNode(node *parse.RangeNode) { + escapeListNode(node.List) + escapeListNode(node.ElseList) +} + +// escapeWithNode recursively escapes the scope body and else clause but +// leaves the pipeline unchanged. +func escapeWithNode(node *parse.WithNode) { + escapeListNode(node.List) + escapeListNode(node.ElseList) +} diff --git a/libgo/go/exp/template/html/escape_test.go b/libgo/go/exp/template/html/escape_test.go new file mode 100644 index 0000000..345a752 --- /dev/null +++ b/libgo/go/exp/template/html/escape_test.go @@ -0,0 +1,75 @@ +// 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 html + +import ( + "bytes" + "template" + "testing" +) + +type data struct { + F, T bool + C, G, H string + A, E []string +} + +var testData = data{ + F: false, + T: true, + C: "", + G: "", + H: "", + A: []string{"", ""}, + E: []string{}, +} + +type testCase struct { + name string + input string + output string +} + +var testCases = []testCase{ + {"if", "{{if .T}}Hello{{end}}, {{.C}}!", "Hello, <Cincinatti>!"}, + {"else", "{{if .F}}{{.H}}{{else}}{{.G}}{{end}}!", "<Goodbye>!"}, + {"overescaping", "Hello, {{.C | html}}!", "Hello, <Cincinatti>!"}, + {"assignment", "{{if $x := .H}}{{$x}}{{end}}", "<Hello>"}, + {"withBody", "{{with .H}}{{.}}{{end}}", "<Hello>"}, + {"withElse", "{{with .E}}{{.}}{{else}}{{.H}}{{end}}", "<Hello>"}, + {"rangeBody", "{{range .A}}{{.}}{{end}}", "<a><b>"}, + {"rangeElse", "{{range .E}}{{.}}{{else}}{{.H}}{{end}}", "<Hello>"}, + {"nonStringValue", "{{.T}}", "true"}, + {"constant", ``, ``}, +} + +func TestAutoesc(t *testing.T) { + for _, testCase := range testCases { + name := testCase.name + tmpl := template.New(name) + tmpl, err := tmpl.Parse(testCase.input) + if err != nil { + t.Errorf("%s: failed to parse template: %s", name, err) + continue + } + + Escape(tmpl) + + buffer := new(bytes.Buffer) + + err = tmpl.Execute(buffer, testData) + if err != nil { + t.Errorf("%s: template execution failed: %s", name, err) + continue + } + + output := testCase.output + actual := buffer.String() + if output != actual { + t.Errorf("%s: escaped output: %q != %q", + name, output, actual) + } + } +} diff --git a/libgo/go/exp/wingui/winapi.go b/libgo/go/exp/wingui/winapi.go index c96f452..31b57a2 100644 --- a/libgo/go/exp/wingui/winapi.go +++ b/libgo/go/exp/wingui/winapi.go @@ -5,26 +5,9 @@ package main import ( - "syscall" "unsafe" ) -func loadDll(fname string) uint32 { - h, e := syscall.LoadLibrary(fname) - if e != 0 { - abortf("LoadLibrary(%s) failed with err=%d.\n", fname, e) - } - return h -} - -func getSysProcAddr(m uint32, pname string) uintptr { - p, e := syscall.GetProcAddress(m, pname) - if e != 0 { - abortf("GetProcAddress(%s) failed with err=%d.\n", pname, e) - } - return uintptr(p) -} - type Wndclassex struct { Size uint32 Style uint32 @@ -96,7 +79,7 @@ const ( // Some button control styles BS_DEFPUSHBUTTON = 1 - // Some colour constants + // Some color constants COLOR_WINDOW = 5 COLOR_BTNFACE = 15 @@ -108,13 +91,13 @@ const ( ) var ( - // Some globaly known cusrors + // Some globally known cursors IDC_ARROW = MakeIntResource(32512) IDC_IBEAM = MakeIntResource(32513) IDC_WAIT = MakeIntResource(32514) IDC_CROSS = MakeIntResource(32515) - // Some globaly known icons + // Some globally known icons IDI_APPLICATION = MakeIntResource(32512) IDI_HAND = MakeIntResource(32513) IDI_QUESTION = MakeIntResource(32514) diff --git a/libgo/go/exp/wingui/zwinapi.go b/libgo/go/exp/wingui/zwinapi.go index 6ae6330..4c009dd 100644 --- a/libgo/go/exp/wingui/zwinapi.go +++ b/libgo/go/exp/wingui/zwinapi.go @@ -7,29 +7,29 @@ import "unsafe" import "syscall" var ( - modkernel32 = loadDll("kernel32.dll") - moduser32 = loadDll("user32.dll") - - procGetModuleHandleW = getSysProcAddr(modkernel32, "GetModuleHandleW") - procRegisterClassExW = getSysProcAddr(moduser32, "RegisterClassExW") - procCreateWindowExW = getSysProcAddr(moduser32, "CreateWindowExW") - procDefWindowProcW = getSysProcAddr(moduser32, "DefWindowProcW") - procDestroyWindow = getSysProcAddr(moduser32, "DestroyWindow") - procPostQuitMessage = getSysProcAddr(moduser32, "PostQuitMessage") - procShowWindow = getSysProcAddr(moduser32, "ShowWindow") - procUpdateWindow = getSysProcAddr(moduser32, "UpdateWindow") - procGetMessageW = getSysProcAddr(moduser32, "GetMessageW") - procTranslateMessage = getSysProcAddr(moduser32, "TranslateMessage") - procDispatchMessageW = getSysProcAddr(moduser32, "DispatchMessageW") - procLoadIconW = getSysProcAddr(moduser32, "LoadIconW") - procLoadCursorW = getSysProcAddr(moduser32, "LoadCursorW") - procSetCursor = getSysProcAddr(moduser32, "SetCursor") - procSendMessageW = getSysProcAddr(moduser32, "SendMessageW") - procPostMessageW = getSysProcAddr(moduser32, "PostMessageW") + modkernel32 = syscall.NewLazyDLL("kernel32.dll") + moduser32 = syscall.NewLazyDLL("user32.dll") + + procGetModuleHandleW = modkernel32.NewProc("GetModuleHandleW") + procRegisterClassExW = moduser32.NewProc("RegisterClassExW") + procCreateWindowExW = moduser32.NewProc("CreateWindowExW") + procDefWindowProcW = moduser32.NewProc("DefWindowProcW") + procDestroyWindow = moduser32.NewProc("DestroyWindow") + procPostQuitMessage = moduser32.NewProc("PostQuitMessage") + procShowWindow = moduser32.NewProc("ShowWindow") + procUpdateWindow = moduser32.NewProc("UpdateWindow") + procGetMessageW = moduser32.NewProc("GetMessageW") + procTranslateMessage = moduser32.NewProc("TranslateMessage") + procDispatchMessageW = moduser32.NewProc("DispatchMessageW") + procLoadIconW = moduser32.NewProc("LoadIconW") + procLoadCursorW = moduser32.NewProc("LoadCursorW") + procSetCursor = moduser32.NewProc("SetCursor") + procSendMessageW = moduser32.NewProc("SendMessageW") + procPostMessageW = moduser32.NewProc("PostMessageW") ) func GetModuleHandle(modname *uint16) (handle uint32, errno int) { - r0, _, e1 := syscall.Syscall(procGetModuleHandleW, 1, uintptr(unsafe.Pointer(modname)), 0, 0) + r0, _, e1 := syscall.Syscall(procGetModuleHandleW.Addr(), 1, uintptr(unsafe.Pointer(modname)), 0, 0) handle = uint32(r0) if handle == 0 { if e1 != 0 { @@ -44,7 +44,7 @@ func GetModuleHandle(modname *uint16) (handle uint32, errno int) { } func RegisterClassEx(wndclass *Wndclassex) (atom uint16, errno int) { - r0, _, e1 := syscall.Syscall(procRegisterClassExW, 1, uintptr(unsafe.Pointer(wndclass)), 0, 0) + r0, _, e1 := syscall.Syscall(procRegisterClassExW.Addr(), 1, uintptr(unsafe.Pointer(wndclass)), 0, 0) atom = uint16(r0) if atom == 0 { if e1 != 0 { @@ -59,7 +59,7 @@ func RegisterClassEx(wndclass *Wndclassex) (atom uint16, errno int) { } func CreateWindowEx(exstyle uint32, classname *uint16, windowname *uint16, style uint32, x int32, y int32, width int32, height int32, wndparent uint32, menu uint32, instance uint32, param uintptr) (hwnd uint32, errno int) { - r0, _, e1 := syscall.Syscall12(procCreateWindowExW, 12, uintptr(exstyle), uintptr(unsafe.Pointer(classname)), uintptr(unsafe.Pointer(windowname)), uintptr(style), uintptr(x), uintptr(y), uintptr(width), uintptr(height), uintptr(wndparent), uintptr(menu), uintptr(instance), uintptr(param)) + r0, _, e1 := syscall.Syscall12(procCreateWindowExW.Addr(), 12, uintptr(exstyle), uintptr(unsafe.Pointer(classname)), uintptr(unsafe.Pointer(windowname)), uintptr(style), uintptr(x), uintptr(y), uintptr(width), uintptr(height), uintptr(wndparent), uintptr(menu), uintptr(instance), uintptr(param)) hwnd = uint32(r0) if hwnd == 0 { if e1 != 0 { @@ -74,13 +74,13 @@ func CreateWindowEx(exstyle uint32, classname *uint16, windowname *uint16, style } func DefWindowProc(hwnd uint32, msg uint32, wparam int32, lparam int32) (lresult int32) { - r0, _, _ := syscall.Syscall6(procDefWindowProcW, 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0) + r0, _, _ := syscall.Syscall6(procDefWindowProcW.Addr(), 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0) lresult = int32(r0) return } func DestroyWindow(hwnd uint32) (errno int) { - r1, _, e1 := syscall.Syscall(procDestroyWindow, 1, uintptr(hwnd), 0, 0) + r1, _, e1 := syscall.Syscall(procDestroyWindow.Addr(), 1, uintptr(hwnd), 0, 0) if int(r1) == 0 { if e1 != 0 { errno = int(e1) @@ -94,18 +94,18 @@ func DestroyWindow(hwnd uint32) (errno int) { } func PostQuitMessage(exitcode int32) { - syscall.Syscall(procPostQuitMessage, 1, uintptr(exitcode), 0, 0) + syscall.Syscall(procPostQuitMessage.Addr(), 1, uintptr(exitcode), 0, 0) return } func ShowWindow(hwnd uint32, cmdshow int32) (wasvisible bool) { - r0, _, _ := syscall.Syscall(procShowWindow, 2, uintptr(hwnd), uintptr(cmdshow), 0) + r0, _, _ := syscall.Syscall(procShowWindow.Addr(), 2, uintptr(hwnd), uintptr(cmdshow), 0) wasvisible = bool(r0 != 0) return } func UpdateWindow(hwnd uint32) (errno int) { - r1, _, e1 := syscall.Syscall(procUpdateWindow, 1, uintptr(hwnd), 0, 0) + r1, _, e1 := syscall.Syscall(procUpdateWindow.Addr(), 1, uintptr(hwnd), 0, 0) if int(r1) == 0 { if e1 != 0 { errno = int(e1) @@ -119,7 +119,7 @@ func UpdateWindow(hwnd uint32) (errno int) { } func GetMessage(msg *Msg, hwnd uint32, MsgFilterMin uint32, MsgFilterMax uint32) (ret int32, errno int) { - r0, _, e1 := syscall.Syscall6(procGetMessageW, 4, uintptr(unsafe.Pointer(msg)), uintptr(hwnd), uintptr(MsgFilterMin), uintptr(MsgFilterMax), 0, 0) + r0, _, e1 := syscall.Syscall6(procGetMessageW.Addr(), 4, uintptr(unsafe.Pointer(msg)), uintptr(hwnd), uintptr(MsgFilterMin), uintptr(MsgFilterMax), 0, 0) ret = int32(r0) if ret == -1 { if e1 != 0 { @@ -134,19 +134,19 @@ func GetMessage(msg *Msg, hwnd uint32, MsgFilterMin uint32, MsgFilterMax uint32) } func TranslateMessage(msg *Msg) (done bool) { - r0, _, _ := syscall.Syscall(procTranslateMessage, 1, uintptr(unsafe.Pointer(msg)), 0, 0) + r0, _, _ := syscall.Syscall(procTranslateMessage.Addr(), 1, uintptr(unsafe.Pointer(msg)), 0, 0) done = bool(r0 != 0) return } func DispatchMessage(msg *Msg) (ret int32) { - r0, _, _ := syscall.Syscall(procDispatchMessageW, 1, uintptr(unsafe.Pointer(msg)), 0, 0) + r0, _, _ := syscall.Syscall(procDispatchMessageW.Addr(), 1, uintptr(unsafe.Pointer(msg)), 0, 0) ret = int32(r0) return } func LoadIcon(instance uint32, iconname *uint16) (icon uint32, errno int) { - r0, _, e1 := syscall.Syscall(procLoadIconW, 2, uintptr(instance), uintptr(unsafe.Pointer(iconname)), 0) + r0, _, e1 := syscall.Syscall(procLoadIconW.Addr(), 2, uintptr(instance), uintptr(unsafe.Pointer(iconname)), 0) icon = uint32(r0) if icon == 0 { if e1 != 0 { @@ -161,7 +161,7 @@ func LoadIcon(instance uint32, iconname *uint16) (icon uint32, errno int) { } func LoadCursor(instance uint32, cursorname *uint16) (cursor uint32, errno int) { - r0, _, e1 := syscall.Syscall(procLoadCursorW, 2, uintptr(instance), uintptr(unsafe.Pointer(cursorname)), 0) + r0, _, e1 := syscall.Syscall(procLoadCursorW.Addr(), 2, uintptr(instance), uintptr(unsafe.Pointer(cursorname)), 0) cursor = uint32(r0) if cursor == 0 { if e1 != 0 { @@ -176,7 +176,7 @@ func LoadCursor(instance uint32, cursorname *uint16) (cursor uint32, errno int) } func SetCursor(cursor uint32) (precursor uint32, errno int) { - r0, _, e1 := syscall.Syscall(procSetCursor, 1, uintptr(cursor), 0, 0) + r0, _, e1 := syscall.Syscall(procSetCursor.Addr(), 1, uintptr(cursor), 0, 0) precursor = uint32(r0) if precursor == 0 { if e1 != 0 { @@ -191,13 +191,13 @@ func SetCursor(cursor uint32) (precursor uint32, errno int) { } func SendMessage(hwnd uint32, msg uint32, wparam int32, lparam int32) (lresult int32) { - r0, _, _ := syscall.Syscall6(procSendMessageW, 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0) + r0, _, _ := syscall.Syscall6(procSendMessageW.Addr(), 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0) lresult = int32(r0) return } func PostMessage(hwnd uint32, msg uint32, wparam int32, lparam int32) (errno int) { - r1, _, e1 := syscall.Syscall6(procPostMessageW, 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0) + r1, _, e1 := syscall.Syscall6(procPostMessageW.Addr(), 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0) if int(r1) == 0 { if e1 != 0 { errno = int(e1) diff --git a/libgo/go/expvar/expvar.go b/libgo/go/expvar/expvar.go index 7123d4b..7b733fa 100644 --- a/libgo/go/expvar/expvar.go +++ b/libgo/go/expvar/expvar.go @@ -189,7 +189,6 @@ func (f Func) String() string { return string(v) } - // All published variables. var vars map[string]Var = make(map[string]Var) var mutex sync.Mutex diff --git a/libgo/go/expvar/expvar_test.go b/libgo/go/expvar/expvar_test.go index 94926d9..8f7a481 100644 --- a/libgo/go/expvar/expvar_test.go +++ b/libgo/go/expvar/expvar_test.go @@ -76,33 +76,33 @@ func TestString(t *testing.T) { } func TestMapCounter(t *testing.T) { - colours := NewMap("bike-shed-colours") + colors := NewMap("bike-shed-colors") - colours.Add("red", 1) - colours.Add("red", 2) - colours.Add("blue", 4) - colours.AddFloat("green", 4.125) - if x := colours.m["red"].(*Int).i; x != 3 { - t.Errorf("colours.m[\"red\"] = %v, want 3", x) + colors.Add("red", 1) + colors.Add("red", 2) + colors.Add("blue", 4) + colors.AddFloat("green", 4.125) + if x := colors.m["red"].(*Int).i; x != 3 { + t.Errorf("colors.m[\"red\"] = %v, want 3", x) } - if x := colours.m["blue"].(*Int).i; x != 4 { - t.Errorf("colours.m[\"blue\"] = %v, want 4", x) + if x := colors.m["blue"].(*Int).i; x != 4 { + t.Errorf("colors.m[\"blue\"] = %v, want 4", x) } - if x := colours.m["green"].(*Float).f; x != 4.125 { - t.Errorf("colours.m[\"green\"] = %v, want 3.14", x) + if x := colors.m["green"].(*Float).f; x != 4.125 { + t.Errorf("colors.m[\"green\"] = %v, want 3.14", x) } - // colours.String() should be '{"red":3, "blue":4}', + // colors.String() should be '{"red":3, "blue":4}', // though the order of red and blue could vary. - s := colours.String() + s := colors.String() var j interface{} err := json.Unmarshal([]byte(s), &j) if err != nil { - t.Errorf("colours.String() isn't valid JSON: %v", err) + t.Errorf("colors.String() isn't valid JSON: %v", err) } m, ok := j.(map[string]interface{}) if !ok { - t.Error("colours.String() didn't produce a map.") + t.Error("colors.String() didn't produce a map.") } red := m["red"] x, ok := red.(float64) diff --git a/libgo/go/flag/export_test.go b/libgo/go/flag/export_test.go index b5e3243..7b19080 100644 --- a/libgo/go/flag/export_test.go +++ b/libgo/go/flag/export_test.go @@ -9,24 +9,14 @@ import "os" // Additional routines compiled into the package only during testing. // ResetForTesting clears all flag state and sets the usage function as directed. -// After calling ResetForTesting, parse errors in flag handling will panic rather -// than exit the program. +// After calling ResetForTesting, parse errors in flag handling will not +// exit the program. func ResetForTesting(usage func()) { - flags = &allFlags{make(map[string]*Flag), make(map[string]*Flag), os.Args[1:]} + commandLine = NewFlagSet(os.Args[0], ContinueOnError) Usage = usage - panicOnError = true } -// ParseForTesting parses the flag state using the provided arguments. It -// should be called after 1) ResetForTesting and 2) setting up the new flags. -// The return value reports whether the parse was error-free. -func ParseForTesting(args []string) (result bool) { - defer func() { - if recover() != nil { - result = false - } - }() - os.Args = args - Parse() - return true +// CommandLine returns the default FlagSet. +func CommandLine() *FlagSet { + return commandLine } diff --git a/libgo/go/flag/flag.go b/libgo/go/flag/flag.go index 9ed20e0..01bbc37 100644 --- a/libgo/go/flag/flag.go +++ b/libgo/go/flag/flag.go @@ -50,18 +50,12 @@ Integer flags accept 1234, 0664, 0x1234 and may be negative. Boolean flags may be 1, 0, t, f, true, false, TRUE, FALSE, True, False. - It is safe to call flag.Parse multiple times, possibly after changing - os.Args. This makes it possible to implement command lines with - subcommands that enable additional flags, as in: - - flag.Bool(...) // global options - flag.Parse() // parse leading command - subcmd := flag.Arg(0) - switch subcmd { - // add per-subcommand options - } - os.Args = flag.Args() - flag.Parse() + The default set of command-line flags is controlled by + top-level functions. The FlagSet type allows one to define + independent sets of flags, such as to implement subcommands + in a command-line interface. The methods of FlagSet are + analogous to the top-level functions for the command-line + flag set. */ package flag @@ -72,6 +66,9 @@ import ( "strconv" ) +// ErrHelp is the error returned if the flag -help is invoked but no such flag is defined. +var ErrHelp = os.NewError("flag: help requested") + // -- Bool Value type boolValue bool @@ -190,6 +187,30 @@ type Value interface { Set(string) bool } +// ErrorHandling defines how to handle flag parsing errors. +type ErrorHandling int + +const ( + ContinueOnError ErrorHandling = iota + ExitOnError + PanicOnError +) + +// A FlagSet represents a set of defined flags. +type FlagSet struct { + // Usage is the function called when an error occurs while parsing flags. + // The field is a function (not a method) that may be changed to point to + // a custom error handler. + Usage func() + + name string + actual map[string]*Flag + formal map[string]*Flag + args []string // arguments after flags + exitOnError bool // does the program exit if there's an error? + errorHandling ErrorHandling +} + // A Flag represents the state of a flag. type Flag struct { Name string // name as it appears on command line @@ -198,17 +219,9 @@ type Flag struct { DefValue string // default value (as text); for usage message } -type allFlags struct { - actual map[string]*Flag - formal map[string]*Flag - args []string // arguments after flags -} - -var flags *allFlags - // sortFlags returns the flags as a slice in lexicographical sorted order. func sortFlags(flags map[string]*Flag) []*Flag { - list := make(sort.StringArray, len(flags)) + list := make(sort.StringSlice, len(flags)) i := 0 for _, f := range flags { list[i] = f.Name @@ -224,43 +237,67 @@ func sortFlags(flags map[string]*Flag) []*Flag { // 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 sortFlags(flags.formal) { - fn(f) +func (f *FlagSet) VisitAll(fn func(*Flag)) { + for _, flag := range sortFlags(f.formal) { + fn(flag) } } +// VisitAll visits the command-line flags in lexicographical order, calling +// fn for each. It visits all flags, even those not set. +func VisitAll(fn func(*Flag)) { + commandLine.VisitAll(fn) +} + // 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 sortFlags(flags.actual) { - fn(f) +func (f *FlagSet) Visit(fn func(*Flag)) { + for _, flag := range sortFlags(f.actual) { + fn(flag) } } +// Visit visits the command-line flags in lexicographical order, calling fn +// for each. It visits only those flags that have been set. +func Visit(fn func(*Flag)) { + commandLine.Visit(fn) +} + // Lookup returns the Flag structure of the named flag, returning nil if none exists. +func (f *FlagSet) Lookup(name string) *Flag { + return f.formal[name] +} + +// Lookup returns the Flag structure of the named command-line flag, +// returning nil if none exists. func Lookup(name string) *Flag { - return flags.formal[name] + return commandLine.formal[name] } // Set sets the value of the named flag. It returns true if the set succeeded; false if // there is no such flag defined. -func Set(name, value string) bool { - f, ok := flags.formal[name] +func (f *FlagSet) Set(name, value string) bool { + flag, ok := f.formal[name] if !ok { return false } - ok = f.Value.Set(value) + ok = flag.Value.Set(value) if !ok { return false } - flags.actual[name] = f + f.actual[name] = flag return true } -// PrintDefaults prints to standard error the default values of all defined flags. -func PrintDefaults() { - VisitAll(func(f *Flag) { +// Set sets the value of the named command-line flag. It returns true if the +// set succeeded; false if there is no such flag defined. +func Set(name, value string) bool { + return commandLine.Set(name, value) +} + +// PrintDefaults prints to standard error the default values of all defined flags in the set. +func (f *FlagSet) PrintDefaults() { + f.VisitAll(func(f *Flag) { format := " -%s=%s: %s\n" if _, ok := f.Value.(*stringValue); ok { // put quotes on the value @@ -270,174 +307,304 @@ func PrintDefaults() { }) } -// Usage prints to standard error a default usage message documenting all defined flags. +// PrintDefaults prints to standard error the default values of all defined command-line flags. +func PrintDefaults() { + commandLine.PrintDefaults() +} + +// defaultUsage is the default function to print a usage message. +func defaultUsage(f *FlagSet) { + fmt.Fprintf(os.Stderr, "Usage of %s:\n", f.name) + f.PrintDefaults() +} + +// Usage prints to standard error a usage message documenting all defined command-line flags. // The function is a variable that may be changed to point to a custom function. var Usage = func() { - fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) - PrintDefaults() + defaultUsage(commandLine) } -var panicOnError = false +// NFlag returns the number of flags that have been set. +func (f *FlagSet) NFlag() int { return len(f.actual) } -// 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") +// NFlag returns the number of command-line flags that have been set. +func NFlag() int { return len(commandLine.actual) } + +// Arg returns the i'th argument. Arg(0) is the first remaining argument +// after flags have been processed. +func (f *FlagSet) Arg(i int) string { + if i < 0 || i >= len(f.args) { + return "" } - os.Exit(2) + return f.args[i] } -// 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 // after flags have been processed. func Arg(i int) string { - if i < 0 || i >= len(flags.args) { - return "" - } - return flags.args[i] + return commandLine.Arg(i) } // NArg is the number of arguments remaining after flags have been processed. -func NArg() int { return len(flags.args) } +func (f *FlagSet) NArg() int { return len(f.args) } + +// NArg is the number of arguments remaining after flags have been processed. +func NArg() int { return len(commandLine.args) } + +// Args returns the non-flag arguments. +func (f *FlagSet) Args() []string { return f.args } // Args returns the non-flag command-line arguments. -func Args() []string { return flags.args } +func Args() []string { return commandLine.args } + +// BoolVar defines a bool flag with specified name, default value, and usage string. +// The argument p points to a bool variable in which to store the value of the flag. +func (f *FlagSet) BoolVar(p *bool, name string, value bool, usage string) { + f.Var(newBoolValue(value, p), name, usage) +} // BoolVar defines a bool flag with specified name, default value, and usage string. // The argument p points to a bool variable in which to store the value of the flag. func BoolVar(p *bool, name string, value bool, usage string) { - Var(newBoolValue(value, p), name, usage) + commandLine.Var(newBoolValue(value, p), name, usage) } // Bool defines a bool flag with specified name, default value, and usage string. // The return value is the address of a bool variable that stores the value of the flag. -func Bool(name string, value bool, usage string) *bool { +func (f *FlagSet) Bool(name string, value bool, usage string) *bool { p := new(bool) - BoolVar(p, name, value, usage) + f.BoolVar(p, name, value, usage) return p } +// Bool defines a bool flag with specified name, default value, and usage string. +// The return value is the address of a bool variable that stores the value of the flag. +func Bool(name string, value bool, usage string) *bool { + return commandLine.Bool(name, value, usage) +} + +// IntVar defines an int flag with specified name, default value, and usage string. +// The argument p points to an int variable in which to store the value of the flag. +func (f *FlagSet) IntVar(p *int, name string, value int, usage string) { + f.Var(newIntValue(value, p), name, usage) +} + // IntVar defines an int flag with specified name, default value, and usage string. // The argument p points to an int variable in which to store the value of the flag. func IntVar(p *int, name string, value int, usage string) { - Var(newIntValue(value, p), name, usage) + commandLine.Var(newIntValue(value, p), name, usage) } // Int defines an int flag with specified name, default value, and usage string. // The return value is the address of an int variable that stores the value of the flag. -func Int(name string, value int, usage string) *int { +func (f *FlagSet) Int(name string, value int, usage string) *int { p := new(int) - IntVar(p, name, value, usage) + f.IntVar(p, name, value, usage) return p } +// Int defines an int flag with specified name, default value, and usage string. +// The return value is the address of an int variable that stores the value of the flag. +func Int(name string, value int, usage string) *int { + return commandLine.Int(name, value, usage) +} + +// Int64Var defines an int64 flag with specified name, default value, and usage string. +// The argument p points to an int64 variable in which to store the value of the flag. +func (f *FlagSet) Int64Var(p *int64, name string, value int64, usage string) { + f.Var(newInt64Value(value, p), name, usage) +} + // Int64Var defines an int64 flag with specified name, default value, and usage string. // The argument p points to an int64 variable in which to store the value of the flag. func Int64Var(p *int64, name string, value int64, usage string) { - Var(newInt64Value(value, p), name, usage) + commandLine.Var(newInt64Value(value, p), name, usage) } // Int64 defines an int64 flag with specified name, default value, and usage string. // The return value is the address of an int64 variable that stores the value of the flag. -func Int64(name string, value int64, usage string) *int64 { +func (f *FlagSet) Int64(name string, value int64, usage string) *int64 { p := new(int64) - Int64Var(p, name, value, usage) + f.Int64Var(p, name, value, usage) return p } +// Int64 defines an int64 flag with specified name, default value, and usage string. +// The return value is the address of an int64 variable that stores the value of the flag. +func Int64(name string, value int64, usage string) *int64 { + return commandLine.Int64(name, value, usage) +} + // UintVar defines a uint flag with specified name, default value, and usage string. // The argument p points to a uint variable in which to store the value of the flag. +func (f *FlagSet) UintVar(p *uint, name string, value uint, usage string) { + f.Var(newUintValue(value, p), name, usage) +} + +// UintVar defines a uint flag with specified name, default value, and usage string. +// The argument p points to a uint variable in which to store the value of the flag. func UintVar(p *uint, name string, value uint, usage string) { - Var(newUintValue(value, p), name, usage) + commandLine.Var(newUintValue(value, p), name, usage) } // Uint defines a uint flag with specified name, default value, and usage string. -// The return value is the address of a uint variable that stores the value of the flag. -func Uint(name string, value uint, usage string) *uint { +// The return value is the address of a uint variable that stores the value of the flag. +func (f *FlagSet) Uint(name string, value uint, usage string) *uint { p := new(uint) - UintVar(p, name, value, usage) + f.UintVar(p, name, value, usage) return p } +// Uint defines a uint flag with specified name, default value, and usage string. +// The return value is the address of a uint variable that stores the value of the flag. +func Uint(name string, value uint, usage string) *uint { + return commandLine.Uint(name, value, usage) +} + +// Uint64Var defines a uint64 flag with specified name, default value, and usage string. +// The argument p points to a uint64 variable in which to store the value of the flag. +func (f *FlagSet) Uint64Var(p *uint64, name string, value uint64, usage string) { + f.Var(newUint64Value(value, p), name, usage) +} + // Uint64Var defines a uint64 flag with specified name, default value, and usage string. // The argument p points to a uint64 variable in which to store the value of the flag. func Uint64Var(p *uint64, name string, value uint64, usage string) { - Var(newUint64Value(value, p), name, usage) + commandLine.Var(newUint64Value(value, p), name, usage) } // Uint64 defines a uint64 flag with specified name, default value, and usage string. // The return value is the address of a uint64 variable that stores the value of the flag. -func Uint64(name string, value uint64, usage string) *uint64 { +func (f *FlagSet) Uint64(name string, value uint64, usage string) *uint64 { p := new(uint64) - Uint64Var(p, name, value, usage) + f.Uint64Var(p, name, value, usage) return p } +// Uint64 defines a uint64 flag with specified name, default value, and usage string. +// The return value is the address of a uint64 variable that stores the value of the flag. +func Uint64(name string, value uint64, usage string) *uint64 { + return commandLine.Uint64(name, value, usage) +} + +// StringVar defines a string flag with specified name, default value, and usage string. +// The argument p points to a string variable in which to store the value of the flag. +func (f *FlagSet) StringVar(p *string, name string, value string, usage string) { + f.Var(newStringValue(value, p), name, usage) +} + // StringVar defines a string flag with specified name, default value, and usage string. // The argument p points to a string variable in which to store the value of the flag. -func StringVar(p *string, name, value string, usage string) { - Var(newStringValue(value, p), name, usage) +func StringVar(p *string, name string, value string, usage string) { + commandLine.Var(newStringValue(value, p), name, usage) } // String defines a string flag with specified name, default value, and usage string. // The return value is the address of a string variable that stores the value of the flag. -func String(name, value string, usage string) *string { +func (f *FlagSet) String(name string, value string, usage string) *string { p := new(string) - StringVar(p, name, value, usage) + f.StringVar(p, name, value, usage) return p } +// String defines a string flag with specified name, default value, and usage string. +// The return value is the address of a string variable that stores the value of the flag. +func String(name string, value string, usage string) *string { + return commandLine.String(name, value, usage) +} + +// Float64Var defines a float64 flag with specified name, default value, and usage string. +// The argument p points to a float64 variable in which to store the value of the flag. +func (f *FlagSet) Float64Var(p *float64, name string, value float64, usage string) { + f.Var(newFloat64Value(value, p), name, usage) +} + // Float64Var defines a float64 flag with specified name, default value, and usage string. // The argument p points to a float64 variable in which to store the value of the flag. func Float64Var(p *float64, name string, value float64, usage string) { - Var(newFloat64Value(value, p), name, usage) + commandLine.Var(newFloat64Value(value, p), name, usage) } // Float64 defines a float64 flag with specified name, default value, and usage string. // The return value is the address of a float64 variable that stores the value of the flag. -func Float64(name string, value float64, usage string) *float64 { +func (f *FlagSet) Float64(name string, value float64, usage string) *float64 { p := new(float64) - Float64Var(p, name, value, usage) + f.Float64Var(p, name, value, usage) return p } -// Var defines a user-typed flag with specified name, default value, and usage string. -// The argument p points to a Value variable in which to store the value of the flag. -func Var(value Value, name string, usage string) { +// Float64 defines an int flag with specified name, default value, and usage string. +// The return value is the address of a float64 variable that stores the value of the flag. +func Float64(name string, value float64, usage string) *float64 { + return commandLine.Float64(name, value, usage) +} + +// Var defines a flag with the specified name and usage string. The type and +// value of the flag are represented by the first argument, of type Value, which +// typically holds a user-defined implementation of Value. For instance, the +// caller could create a flag that turns a comma-separated string into a slice +// of strings by giving the slice the methods of Value; in particular, Set would +// decompose the comma-separated string into the slice. +func (f *FlagSet) Var(value Value, name string, usage string) { // Remember the default value as a string; it won't change. - f := &Flag{name, usage, value, value.String()} - _, alreadythere := flags.formal[name] + flag := &Flag{name, usage, value, value.String()} + _, alreadythere := f.formal[name] if alreadythere { - fmt.Fprintln(os.Stderr, "flag redefined:", name) + fmt.Fprintf(os.Stderr, "%s flag redefined: %s\n", f.name, name) panic("flag redefinition") // Happens only if flags are declared with identical names } - flags.formal[name] = f + f.formal[name] = flag +} + +// Var defines a flag with the specified name and usage string. The type and +// value of the flag are represented by the first argument, of type Value, which +// typically holds a user-defined implementation of Value. For instance, the +// caller could create a flag that turns a comma-separated string into a slice +// of strings by giving the slice the methods of Value; in particular, Set would +// decompose the comma-separated string into the slice. +func Var(value Value, name string, usage string) { + commandLine.Var(value, name, usage) +} + +// failf prints to standard error a formatted error and usage message and +// returns the error. +func (f *FlagSet) failf(format string, a ...interface{}) os.Error { + err := fmt.Errorf(format, a...) + fmt.Fprintln(os.Stderr, err) + f.usage() + return err } +// usage calls the Usage method for the flag set, or the usage function if +// the flag set is commandLine. +func (f *FlagSet) usage() { + if f == commandLine { + Usage() + } else { + f.Usage() + } +} -func (f *allFlags) parseOne() (ok bool) { +// parseOne parses one flag. It returns whether a flag was seen. +func (f *FlagSet) parseOne() (bool, os.Error) { if len(f.args) == 0 { - return false + return false, nil } s := f.args[0] if len(s) == 0 || s[0] != '-' || len(s) == 1 { - return false + return false, nil } num_minuses := 1 if s[1] == '-' { num_minuses++ if len(s) == 2 { // "--" terminates the flags f.args = f.args[1:] - return false + return false, nil } } name := s[num_minuses:] if len(name) == 0 || name[0] == '-' || name[0] == '=' { - failf("bad flag syntax: %s\n", s) + return false, f.failf("bad flag syntax: %s", s) } // it's a flag. does it have an argument? @@ -452,15 +619,19 @@ func (f *allFlags) parseOne() (ok bool) { break } } - m := flags.formal + m := f.formal flag, alreadythere := m[name] // BUG if !alreadythere { - failf("flag provided but not defined: -%s\n", name) + if name == "help" || name == "h" { // special case for nice help message. + f.usage() + return false, ErrHelp + } + return false, f.failf("flag provided but not defined: -%s", name) } if fv, ok := flag.Value.(*boolValue); ok { // special case: doesn't need an arg if has_value { if !fv.Set(value) { - failf("invalid boolean value %q for flag: -%s\n", value, name) + f.failf("invalid boolean value %q for flag: -%s", value, name) } } else { fv.Set("true") @@ -473,25 +644,62 @@ func (f *allFlags) parseOne() (ok bool) { value, f.args = f.args[0], f.args[1:] } if !has_value { - failf("flag needs an argument: -%s\n", name) + return false, f.failf("flag needs an argument: -%s", name) } ok = flag.Value.Set(value) if !ok { - failf("invalid value %q for flag: -%s\n", value, name) + return false, f.failf("invalid value %q for flag: -%s", value, name) } } - flags.actual[name] = flag - return true + f.actual[name] = flag + return true, nil +} + +// Parse parses flag definitions from the argument list, which should not +// include the command name. Must be called after all flags in the FlagSet +// are defined and before flags are accessed by the program. +// The return value will be ErrHelp if -help was set but not defined. +func (f *FlagSet) Parse(arguments []string) os.Error { + f.args = arguments + for { + seen, err := f.parseOne() + if seen { + continue + } + if err == nil { + break + } + switch f.errorHandling { + case ContinueOnError: + return err + case ExitOnError: + os.Exit(2) + case PanicOnError: + panic(err) + } + } + return nil } -// Parse parses the command-line flags. Must be called after all flags are defined -// and before any are accessed by the program. +// Parse parses the command-line flags from os.Args[1:]. Must be called +// after all flags are defined and before flags are accessed by the program. func Parse() { - flags.args = os.Args[1:] - for flags.parseOne() { - } + // Ignore errors; commandLine is set for ExitOnError. + commandLine.Parse(os.Args[1:]) } -func init() { - flags = &allFlags{make(map[string]*Flag), make(map[string]*Flag), os.Args[1:]} +// The default set of command-line flags, parsed from os.Args. +var commandLine = NewFlagSet(os.Args[0], ExitOnError) + +// NewFlagSet returns a new, empty flag set with the specified name and +// error handling property. +func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet { + f := &FlagSet{ + name: name, + actual: make(map[string]*Flag), + formal: make(map[string]*Flag), + errorHandling: errorHandling, + } + f.Usage = func() { defaultUsage(f) } + return f } diff --git a/libgo/go/flag/flag_test.go b/libgo/go/flag/flag_test.go index 1e47d12..63d0a9f 100644 --- a/libgo/go/flag/flag_test.go +++ b/libgo/go/flag/flag_test.go @@ -89,7 +89,7 @@ func TestEverything(t *testing.T) { func TestUsage(t *testing.T) { called := false ResetForTesting(func() { called = true }) - if ParseForTesting([]string{"a.out", "-x"}) { + if CommandLine().Parse([]string{"-x"}) == nil { t.Error("parse did not fail for unknown flag") } if !called { @@ -97,19 +97,17 @@ func TestUsage(t *testing.T) { } } -func TestParse(t *testing.T) { - ResetForTesting(func() { t.Error("bad parse") }) - boolFlag := Bool("bool", false, "bool value") - bool2Flag := Bool("bool2", false, "bool2 value") - intFlag := Int("int", 0, "int value") - int64Flag := Int64("int64", 0, "int64 value") - uintFlag := Uint("uint", 0, "uint value") - uint64Flag := Uint64("uint64", 0, "uint64 value") - stringFlag := String("string", "0", "string value") - float64Flag := Float64("float64", 0, "float64 value") +func testParse(f *FlagSet, t *testing.T) { + boolFlag := f.Bool("bool", false, "bool value") + bool2Flag := f.Bool("bool2", false, "bool2 value") + intFlag := f.Int("int", 0, "int value") + int64Flag := f.Int64("int64", 0, "int64 value") + uintFlag := f.Uint("uint", 0, "uint value") + uint64Flag := f.Uint64("uint64", 0, "uint64 value") + stringFlag := f.String("string", "0", "string value") + float64Flag := f.Float64("float64", 0, "float64 value") extra := "one-extra-argument" args := []string{ - "a.out", "-bool", "-bool2=true", "--int", "22", @@ -120,8 +118,8 @@ func TestParse(t *testing.T) { "-float64", "2718e28", extra, } - if !ParseForTesting(args) { - t.Fatal("parse failed") + if err := f.Parse(args); err != nil { + t.Fatal(err) } if *boolFlag != true { t.Error("bool flag should be true, is ", *boolFlag) @@ -147,14 +145,23 @@ func TestParse(t *testing.T) { if *float64Flag != 2718e28 { t.Error("float64 flag should be 2718e28, is ", *float64Flag) } - if len(Args()) != 1 { - t.Error("expected one argument, got", len(Args())) - } else if Args()[0] != extra { - t.Errorf("expected argument %q got %q", extra, Args()[0]) + if len(f.Args()) != 1 { + t.Error("expected one argument, got", len(f.Args())) + } else if f.Args()[0] != extra { + t.Errorf("expected argument %q got %q", extra, f.Args()[0]) } } -// Declare a user-defined flag. +func TestParse(t *testing.T) { + ResetForTesting(func() { t.Error("bad parse") }) + testParse(CommandLine(), t) +} + +func TestFlagSetParse(t *testing.T) { + testParse(NewFlagSet("test", ContinueOnError), t) +} + +// Declare a user-defined flag type. type flagVar []string func (f *flagVar) String() string { @@ -167,11 +174,11 @@ func (f *flagVar) Set(value string) bool { } func TestUserDefined(t *testing.T) { - ResetForTesting(func() { t.Fatal("bad parse") }) + flags := NewFlagSet("test", ContinueOnError) var v flagVar - Var(&v, "v", "usage") - if !ParseForTesting([]string{"a.out", "-v", "1", "-v", "2", "-v=3"}) { - t.Error("parse failed") + flags.Var(&v, "v", "usage") + if err := flags.Parse([]string{"-v", "1", "-v", "2", "-v=3"}); err != nil { + t.Error(err) } if len(v) != 3 { t.Fatal("expected 3 args; got ", len(v)) @@ -182,13 +189,17 @@ func TestUserDefined(t *testing.T) { } } +// This tests that one can reset the flags. This still works but not well, and is +// superseded by FlagSet. func TestChangingArgs(t *testing.T) { ResetForTesting(func() { t.Fatal("bad parse") }) oldArgs := os.Args defer func() { os.Args = oldArgs }() os.Args = []string{"cmd", "-before", "subcmd", "-after", "args"} before := Bool("before", false, "") - Parse() + if err := CommandLine().Parse(os.Args[1:]); err != nil { + t.Fatal(err) + } cmd := Arg(0) os.Args = Args() after := Bool("after", false, "") @@ -199,3 +210,46 @@ func TestChangingArgs(t *testing.T) { t.Fatalf("expected true subcmd true [args] got %v %v %v %v", *before, cmd, *after, args) } } + +// Test that -help invokes the usage message and returns ErrHelp. +func TestHelp(t *testing.T) { + var helpCalled = false + fs := NewFlagSet("help test", ContinueOnError) + fs.Usage = func() { helpCalled = true } + var flag bool + fs.BoolVar(&flag, "flag", false, "regular flag") + // Regular flag invocation should work + err := fs.Parse([]string{"-flag=true"}) + if err != nil { + t.Fatal("expected no error; got ", err) + } + if !flag { + t.Error("flag was not set by -flag") + } + if helpCalled { + t.Error("help called for regular flag") + helpCalled = false // reset for next test + } + // Help flag should work as expected. + err = fs.Parse([]string{"-help"}) + if err == nil { + t.Fatal("error expected") + } + if err != ErrHelp { + t.Fatal("expected ErrHelp; got ", err) + } + if !helpCalled { + t.Fatal("help was not called") + } + // If we define a help flag, that should override. + var help bool + fs.BoolVar(&help, "help", false, "help flag") + helpCalled = false + err = fs.Parse([]string{"-help"}) + if err != nil { + t.Fatal("expected no error for defined -help; got ", err) + } + if helpCalled { + t.Fatal("help was called; should not have been for defined help flag") + } +} diff --git a/libgo/go/fmt/doc.go b/libgo/go/fmt/doc.go index e4d4f18..35a11e1 100644 --- a/libgo/go/fmt/doc.go +++ b/libgo/go/fmt/doc.go @@ -25,9 +25,10 @@ %c the character represented by the corresponding Unicode code point %d base 10 %o base 8 + %q a single-quoted character literal safely escaped with Go syntax. %x base 16, with lower-case letters for a-f %X base 16, with upper-case letters for A-F - %U Unicode format: U+1234; same as "U+%0.4X" + %U Unicode format: U+1234; same as "U+%04X" Floating-point and complex constituents: %b decimalless scientific notation with exponent a power of two, in the manner of strconv.Ftoa32, e.g. -123456p-78 @@ -62,11 +63,13 @@ number of characters to output, truncating if necessary. Other flags: - + always print a sign for numeric values + + always print a sign for numeric values; + guarantee ASCII-only output for %q (%+q) - pad with spaces on the right rather than the left (left-justify the field) # alternate format: add leading 0 for octal (%#o), 0x for hex (%#x); 0X for hex (%#X); suppress 0x for %p (%#p); - print a raw (backquoted) string if possible for %q (%#q) + print a raw (backquoted) string if possible for %q (%#q); + write e.g. U+0078 'x' if the character is printable for %U (%#U). ' ' (space) leave a space for elided sign in numbers (% d); put spaces between bytes printing strings or slices in hex (% x, % X) 0 pad with leading zeros rather than spaces @@ -134,10 +137,10 @@ The formats behave analogously to those of Printf with the following exceptions: - %p is not implemented - %T is not implemented - %e %E %f %F %g %g are all equivalent and scan any floating point or complex value - %s and %v on strings scan a space-delimited token + %p is not implemented + %T is not implemented + %e %E %f %F %g %G are all equivalent and scan any floating point or complex value + %s and %v on strings scan a space-delimited token The familiar base-setting prefixes 0 (octal) and 0x (hexadecimal) are accepted when scanning integers without a diff --git a/libgo/go/fmt/fmt_test.go b/libgo/go/fmt/fmt_test.go index b3c0c5a..1142c9f 100644 --- a/libgo/go/fmt/fmt_test.go +++ b/libgo/go/fmt/fmt_test.go @@ -43,7 +43,6 @@ func TestFmtInterface(t *testing.T) { } } - const b32 uint32 = 1<<32 - 1 const b64 uint64 = 1<<64 - 1 @@ -132,12 +131,26 @@ var fmttests = []struct { {"%q", `"`, `"\""`}, {"%q", "\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`}, {"%q", "abc\xffdef", `"abc\xffdef"`}, - {"%q", "\u263a", `"\u263a"`}, + {"%q", "\u263a", `"☺"`}, + {"%+q", "\u263a", `"\u263a"`}, {"%q", "\U0010ffff", `"\U0010ffff"`}, + // escaped characters + {"%q", 'x', `'x'`}, + {"%q", 0, `'\x00'`}, + {"%q", '\n', `'\n'`}, + {"%q", '\u0e00', `'\u0e00'`}, // not a printable rune. + {"%q", '\U000c2345', `'\U000c2345'`}, // not a printable rune. + {"%q", int64(0x7FFFFFFF), `%!q(int64=2147483647)`}, + {"%q", uint64(0xFFFFFFFF), `%!q(uint64=4294967295)`}, + {"%q", '"', `'"'`}, + {"%q", '\'', `'\''`}, + {"%q", "\u263a", `"☺"`}, + {"%+q", "\u263a", `"\u263a"`}, + // width {"%5s", "abc", " abc"}, - {"%2s", "\u263a", " \u263a"}, + {"%2s", "\u263a", " ☺"}, {"%-5s", "abc", "abc "}, {"%-8q", "abc", `"abc" `}, {"%05s", "abc", "00abc"}, @@ -147,9 +160,9 @@ var fmttests = []struct { {"%.5s", "日本語日本語", "日本語日本"}, {"%.5s", []byte("日本語日本語"), "日本語日本"}, {"%.5q", "abcdefghijklmnopqrstuvwxyz", `"abcde"`}, - {"%.3q", "日本語日本語", `"\u65e5\u672c\u8a9e"`}, - {"%.3q", []byte("日本語日本語"), `"\u65e5\u672c\u8a9e"`}, - {"%10.1q", "日本語日本語", ` "\u65e5"`}, + {"%.3q", "日本語日本語", `"日本語"`}, + {"%.3q", []byte("日本語日本語"), `"日本語"`}, + {"%10.1q", "日本語日本語", ` "日"`}, // integers {"%d", 12345, "12345"}, @@ -167,6 +180,8 @@ var fmttests = []struct { {"%+d", 0, "+0"}, {"% d", 0, " 0"}, {"% d", 12345, " 12345"}, + {"%.0d", 0, ""}, + {"%.d", 0, ""}, // unicode format {"%U", 0x1, "U+0001"}, @@ -176,6 +191,12 @@ var fmttests = []struct { {"%U", 0x12345, "U+12345"}, {"%10.6U", 0xABC, " U+000ABC"}, {"%-10.6U", 0xABC, "U+000ABC "}, + {"%U", '\n', `U+000A`}, + {"%#U", '\n', `U+000A`}, + {"%U", 'x', `U+0078`}, + {"%#U", 'x', `U+0078 'x'`}, + {"%U", '\u263a', `U+263A`}, + {"%#U", '\u263a', `U+263A '☺'`}, // floats {"%+.3e", 0.0, "+0.000e+00"}, @@ -456,28 +477,36 @@ func TestCountMallocs(t *testing.T) { if testing.Short() { return } + runtime.UpdateMemStats() mallocs := 0 - runtime.MemStats.Mallocs for i := 0; i < 100; i++ { Sprintf("") } + runtime.UpdateMemStats() mallocs += runtime.MemStats.Mallocs Printf("mallocs per Sprintf(\"\"): %d\n", mallocs/100) + runtime.UpdateMemStats() mallocs = 0 - runtime.MemStats.Mallocs for i := 0; i < 100; i++ { Sprintf("xxx") } + runtime.UpdateMemStats() mallocs += runtime.MemStats.Mallocs Printf("mallocs per Sprintf(\"xxx\"): %d\n", mallocs/100) + runtime.UpdateMemStats() mallocs = 0 - runtime.MemStats.Mallocs for i := 0; i < 100; i++ { Sprintf("%x", i) } + runtime.UpdateMemStats() mallocs += runtime.MemStats.Mallocs Printf("mallocs per Sprintf(\"%%x\"): %d\n", mallocs/100) + runtime.UpdateMemStats() mallocs = 0 - runtime.MemStats.Mallocs for i := 0; i < 100; i++ { Sprintf("%x %x", i, i) } + runtime.UpdateMemStats() mallocs += runtime.MemStats.Mallocs Printf("mallocs per Sprintf(\"%%x %%x\"): %d\n", mallocs/100) } @@ -614,7 +643,6 @@ func TestBlankln(t *testing.T) { } } - // Check Formatter with Sprint, Sprintln, Sprintf func TestFormatterPrintln(t *testing.T) { f := F(1) @@ -663,3 +691,56 @@ func TestWidthAndPrecision(t *testing.T) { } } } + +// A type that panics in String. +type Panic struct { + message interface{} +} + +// Value receiver. +func (p Panic) GoString() string { + panic(p.message) +} + +// Value receiver. +func (p Panic) String() string { + panic(p.message) +} + +// A type that panics in Format. +type PanicF struct { + message interface{} +} + +// Value receiver. +func (p PanicF) Format(f State, c int) { + panic(p.message) +} + +var panictests = []struct { + fmt string + in interface{} + out string +}{ + // String + {"%d", (*Panic)(nil), ""}, // nil pointer special case + {"%d", Panic{io.ErrUnexpectedEOF}, "%d(PANIC=unexpected EOF)"}, + {"%d", Panic{3}, "%d(PANIC=3)"}, + // GoString + {"%#v", (*Panic)(nil), ""}, // nil pointer special case + {"%#v", Panic{io.ErrUnexpectedEOF}, "%v(PANIC=unexpected EOF)"}, + {"%#v", Panic{3}, "%v(PANIC=3)"}, + // Format + {"%s", (*PanicF)(nil), ""}, // nil pointer special case + {"%s", PanicF{io.ErrUnexpectedEOF}, "%s(PANIC=unexpected EOF)"}, + {"%s", PanicF{3}, "%s(PANIC=3)"}, +} + +func TestPanics(t *testing.T) { + for _, tt := range panictests { + s := Sprintf(tt.fmt, tt.in) + if s != tt.out { + t.Errorf("%q: got %q expected %q", tt.fmt, s, tt.out) + } + } +} diff --git a/libgo/go/fmt/format.go b/libgo/go/fmt/format.go index f9d2b4f..24b15a2 100644 --- a/libgo/go/fmt/format.go +++ b/libgo/go/fmt/format.go @@ -7,6 +7,7 @@ package fmt import ( "bytes" "strconv" + "unicode" "utf8" ) @@ -50,6 +51,7 @@ type fmt struct { sharp bool space bool unicode bool + uniQuote bool // Use 'x'= prefix for %U if printable. zero bool } @@ -63,6 +65,7 @@ func (f *fmt) clearflags() { f.sharp = false f.space = false f.unicode = false + f.uniQuote = false f.zero = false } @@ -163,6 +166,11 @@ func (f *fmt) fmt_boolean(v bool) { // integer; interprets prec but not wid. Once formatted, result is sent to pad() // and then flags are cleared. func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) { + // precision of 0 and value of 0 means "print nothing" + if f.precPresent && f.prec == 0 && a == 0 { + return + } + var buf []byte = f.intbuf[0:] negative := signedness == signed && a < 0 if negative { @@ -232,6 +240,24 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) { i-- buf[i] = ' ' } + + // If we want a quoted char for %#U, move the data up to make room. + if f.unicode && f.uniQuote && a >= 0 && a <= unicode.MaxRune && unicode.IsPrint(int(a)) { + runeWidth := utf8.RuneLen(int(a)) + width := 1 + 1 + runeWidth + 1 // space, quote, rune, quote + copy(buf[i-width:], buf[i:]) // guaranteed to have enough room. + i -= width + // Now put " 'x'" at the end. + j := len(buf) - width + buf[j] = ' ' + j++ + buf[j] = '\'' + j++ + utf8.EncodeRune(buf[j:], int(a)) + j += runeWidth + buf[j] = '\'' + } + f.pad(buf[i:]) } @@ -291,7 +317,23 @@ func (f *fmt) fmt_q(s string) { if f.sharp && strconv.CanBackquote(s) { quoted = "`" + s + "`" } else { - quoted = strconv.Quote(s) + if f.plus { + quoted = strconv.QuoteToASCII(s) + } else { + quoted = strconv.Quote(s) + } + } + f.padString(quoted) +} + +// fmt_qc formats the integer as a single-quoted, escaped Go character constant. +// If the character is not valid Unicode, it will print '\ufffd'. +func (f *fmt) fmt_qc(c int64) { + var quoted string + if f.plus { + quoted = strconv.QuoteRuneToASCII(int(c)) + } else { + quoted = strconv.QuoteRune(int(c)) } f.padString(quoted) } diff --git a/libgo/go/fmt/print.go b/libgo/go/fmt/print.go index 10e0fe7..7387349 100644 --- a/libgo/go/fmt/print.go +++ b/libgo/go/fmt/print.go @@ -9,6 +9,7 @@ import ( "io" "os" "reflect" + "unicode" "utf8" ) @@ -21,6 +22,7 @@ var ( nilBytes = []byte("nil") mapBytes = []byte("map[") missingBytes = []byte("(MISSING)") + panicBytes = []byte("(PANIC=") extraBytes = []byte("%!(EXTRA ") irparenBytes = []byte("i)") bytesBytes = []byte("[]byte{") @@ -41,7 +43,7 @@ type State interface { Precision() (prec int, ok bool) // Flag returns whether the flag c, a character, has been set. - Flag(int) bool + Flag(c int) bool } // Formatter is the interface implemented by values with a custom formatter. @@ -51,7 +53,7 @@ type Formatter interface { Format(f State, c int) } -// Stringer is implemented by any value that has a String method(), +// Stringer is implemented by any value that has a String method, // which defines the ``native'' format for that value. // The String method is used to print values passed as an operand // to a %s or %v format or to an unformatted printer such as Print. @@ -59,7 +61,7 @@ type Stringer interface { String() string } -// GoStringer is implemented by any value that has a GoString() method, +// GoStringer is implemented by any value that has a GoString method, // which defines the Go syntax for that value. // The GoString method is used to print values passed as an operand // to a %#v format. @@ -68,10 +70,11 @@ type GoStringer interface { } type pp struct { - n int - buf bytes.Buffer - runeBuf [utf8.UTFMax]byte - fmt fmt + n int + panicking bool + buf bytes.Buffer + runeBuf [utf8.UTFMax]byte + fmt fmt } // A cache holds a set of reusable objects. @@ -110,6 +113,7 @@ var ppFree = newCache(func() interface{} { return new(pp) }) // Allocate a new pp struct or grab a cached one. func newPrinter() *pp { p := ppFree.get().(*pp) + p.panicking = false p.fmt.init(&p.buf) return p } @@ -158,19 +162,18 @@ func (p *pp) Write(b []byte) (ret int, err os.Error) { // Fprintf formats according to a format specifier and writes to w. // It returns the number of bytes written and any write error encountered. -func Fprintf(w io.Writer, format string, a ...interface{}) (n int, error os.Error) { +func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err os.Error) { p := newPrinter() p.doPrintf(format, a) - n64, error := p.buf.WriteTo(w) + n64, err := p.buf.WriteTo(w) p.free() - return int(n64), error + return int(n64), err } // Printf formats according to a format specifier and writes to standard output. // It returns the number of bytes written and any write error encountered. -func Printf(format string, a ...interface{}) (n int, errno os.Error) { - n, errno = Fprintf(os.Stdout, format, a...) - return n, errno +func Printf(format string, a ...interface{}) (n int, err os.Error) { + return Fprintf(os.Stdout, format, a...) } // Sprintf formats according to a format specifier and returns the resulting string. @@ -185,7 +188,7 @@ func Sprintf(format string, a ...interface{}) string { // Errorf formats according to a format specifier and returns the string // converted to an os.ErrorString, which satisfies the os.Error interface. func Errorf(format string, a ...interface{}) os.Error { - return os.ErrorString(Sprintf(format, a...)) + return os.NewError(Sprintf(format, a...)) } // These routines do not take a format string @@ -193,20 +196,19 @@ func Errorf(format string, a ...interface{}) os.Error { // Fprint formats using the default formats for its operands and writes to w. // Spaces are added between operands when neither is a string. // It returns the number of bytes written and any write error encountered. -func Fprint(w io.Writer, a ...interface{}) (n int, error os.Error) { +func Fprint(w io.Writer, a ...interface{}) (n int, err os.Error) { p := newPrinter() p.doPrint(a, false, false) - n64, error := p.buf.WriteTo(w) + n64, err := p.buf.WriteTo(w) p.free() - return int(n64), error + return int(n64), err } // Print formats using the default formats for its operands and writes to standard output. // Spaces are added between operands when neither is a string. // It returns the number of bytes written and any write error encountered. -func Print(a ...interface{}) (n int, errno os.Error) { - n, errno = Fprint(os.Stdout, a...) - return n, errno +func Print(a ...interface{}) (n int, err os.Error) { + return Fprint(os.Stdout, a...) } // Sprint formats using the default formats for its operands and returns the resulting string. @@ -226,20 +228,19 @@ func Sprint(a ...interface{}) string { // Fprintln formats using the default formats for its operands and writes to w. // Spaces are always added between operands and a newline is appended. // It returns the number of bytes written and any write error encountered. -func Fprintln(w io.Writer, a ...interface{}) (n int, error os.Error) { +func Fprintln(w io.Writer, a ...interface{}) (n int, err os.Error) { p := newPrinter() p.doPrint(a, true, true) - n64, error := p.buf.WriteTo(w) + n64, err := p.buf.WriteTo(w) p.free() - return int(n64), error + return int(n64), err } // Println formats using the default formats for its operands and writes to standard output. // Spaces are always added between operands and a newline is appended. // It returns the number of bytes written and any write error encountered. -func Println(a ...interface{}) (n int, errno os.Error) { - n, errno = Fprintln(os.Stdout, a...) - return n, errno +func Println(a ...interface{}) (n int, err os.Error) { + return Fprintln(os.Stdout, a...) } // Sprintln formats using the default formats for its operands and returns the resulting string. @@ -252,7 +253,6 @@ func Sprintln(a ...interface{}) string { return s } - // Get the i'th arg of the struct value. // If the arg itself is an interface, return a value for // the thing inside the interface, not the interface itself. @@ -332,6 +332,12 @@ func (p *pp) fmtInt64(v int64, verb int, value interface{}) { p.fmt.integer(v, 10, signed, ldigits) case 'o': p.fmt.integer(v, 8, signed, ldigits) + case 'q': + if 0 <= v && v <= unicode.MaxRune { + p.fmt.fmt_qc(v) + } else { + p.badVerb(verb, value) + } case 'x': p.fmt.integer(v, 16, signed, ldigits) case 'U': @@ -356,6 +362,8 @@ func (p *pp) fmt0x64(v uint64, leading0x bool) { // temporarily turning on the unicode flag and tweaking the precision. func (p *pp) fmtUnicode(v int64) { precPresent := p.fmt.precPresent + sharp := p.fmt.sharp + p.fmt.sharp = false prec := p.fmt.prec if !precPresent { // If prec is already set, leave it alone; otherwise 4 is minimum. @@ -363,10 +371,13 @@ func (p *pp) fmtUnicode(v int64) { p.fmt.precPresent = true } p.fmt.unicode = true // turn on U+ + p.fmt.uniQuote = sharp p.fmt.integer(int64(v), 16, unsigned, udigits) p.fmt.unicode = false + p.fmt.uniQuote = false p.fmt.prec = prec p.fmt.precPresent = precPresent + p.fmt.sharp = sharp } func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) { @@ -385,6 +396,12 @@ func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) { } case 'o': p.fmt.integer(int64(v), 8, unsigned, ldigits) + case 'q': + if 0 <= v && v <= unicode.MaxRune { + p.fmt.fmt_qc(int64(v)) + } else { + p.badVerb(verb, value) + } case 'x': p.fmt.integer(int64(v), 16, unsigned, ldigits) case 'X': @@ -548,6 +565,31 @@ var ( uintptrBits = reflect.TypeOf(uintptr(0)).Bits() ) +func (p *pp) catchPanic(val interface{}, verb int) { + if err := recover(); err != nil { + // If it's a nil pointer, just say "". The likeliest causes are a + // Stringer that fails to guard against nil or a nil pointer for a + // value receiver, and in either case, "" is a nice result. + if v := reflect.ValueOf(val); v.Kind() == reflect.Ptr && v.IsNil() { + p.buf.Write(nilAngleBytes) + return + } + // Otherwise print a concise panic message. Most of the time the panic + // value will print itself nicely. + if p.panicking { + // Nested panics; the recursion in printField cannot succeed. + panic(err) + } + p.buf.WriteByte('%') + p.add(verb) + p.buf.Write(panicBytes) + p.panicking = true + p.printField(err, 'v', false, false, 0) + p.panicking = false + p.buf.WriteByte(')') + } +} + func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth int) (wasString bool) { if field == nil { if verb == 'T' || verb == 'v' { @@ -570,6 +612,7 @@ func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth } // Is it a Formatter? if formatter, ok := field.(Formatter); ok { + defer p.catchPanic(field, verb) formatter.Format(p, verb) return false // this value is not a string @@ -582,6 +625,7 @@ func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth if goSyntax { p.fmt.sharp = false if stringer, ok := field.(GoStringer); ok { + defer p.catchPanic(field, verb) // Print the result of GoString unadorned. p.fmtString(stringer.GoString(), 's', false, field) return false // this value is not a string @@ -589,6 +633,7 @@ func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth } else { // Is it a Stringer? if stringer, ok := field.(Stringer); ok { + defer p.catchPanic(field, verb) p.printField(stringer.String(), verb, plus, false, depth) return false // this value is not a string } @@ -883,6 +928,10 @@ func (p *pp) doPrintf(format string, a []interface{}) { } } else { p.fmt.prec, p.fmt.precPresent, i = parsenum(format, i+1, end) + if !p.fmt.precPresent { + p.fmt.prec = 0 + p.fmt.precPresent = true + } } } if i >= end { diff --git a/libgo/go/fmt/scan.go b/libgo/go/fmt/scan.go index 42bc52c..259451d 100644 --- a/libgo/go/fmt/scan.go +++ b/libgo/go/fmt/scan.go @@ -35,6 +35,10 @@ 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 + // SkipSpace skips space in the input. Newlines are treated as space + // unless the scan operation is Scanln, Fscanln or Sscanln, in which case + // a newline is treated as EOF. + SkipSpace() // 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 @@ -167,7 +171,7 @@ type ssave struct { // satisfies io.Reader. It will never be called when used as // intended, so there is no need to make it actually work. func (s *ss) Read(buf []byte) (n int, err os.Error) { - return 0, os.ErrorString("ScanState's Read should not be called. Use ReadRune") + return 0, os.NewError("ScanState's Read should not be called. Use ReadRune") } func (s *ss) ReadRune() (rune int, size int, err os.Error) { @@ -231,6 +235,7 @@ func (s *ss) UnreadRune() os.Error { } else { s.peekRune = s.prevRune } + s.prevRune = -1 s.count-- return nil } @@ -240,7 +245,7 @@ func (s *ss) error(err os.Error) { } func (s *ss) errorString(err string) { - panic(scanError{os.ErrorString(err)}) + panic(scanError{os.NewError(err)}) } func (s *ss) Token(skipSpace bool, f func(int) bool) (tok []byte, err os.Error) { @@ -266,6 +271,12 @@ func notSpace(r int) bool { return !unicode.IsSpace(r) } +// skipSpace provides Scan() methods the ability to skip space and newline characters +// in keeping with the current scanning mode set by format strings and Scan()/Scanln(). +func (s *ss) SkipSpace() { + s.skipSpace(false) +} + // 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. @@ -324,7 +335,6 @@ func (r *readRune) ReadRune() (rune int, size int, err os.Error) { return } - var ssFree = newCache(func() interface{} { return new(ss) }) // Allocate a new ss struct or grab a cached one. @@ -398,7 +408,6 @@ 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. @@ -426,8 +435,8 @@ func (s *ss) typeError(field interface{}, expected string) { s.errorString("expected field of type pointer to " + expected + "; found " + reflect.TypeOf(field).String()) } -var complexError = os.ErrorString("syntax error scanning complex number") -var boolError = os.ErrorString("syntax error scanning boolean") +var complexError = os.NewError("syntax error scanning complex number") +var boolError = os.NewError("syntax error scanning boolean") // consume reads the next rune in the input and reports whether it is in the ok string. // If accept is true, it puts the character into the input token. @@ -457,6 +466,14 @@ func (s *ss) peek(ok string) bool { return strings.IndexRune(ok, rune) >= 0 } +func (s *ss) notEOF() { + // Guarantee there is data to be read. + if rune := s.getRune(); rune == eof { + panic(os.EOF) + } + s.UnreadRune() +} + // accept checks the next rune in the input. If it's a byte (sic) in the string, it puts it in the // buffer and returns true. Otherwise it return false. func (s *ss) accept(ok string) bool { @@ -476,11 +493,13 @@ func (s *ss) okVerb(verb int, okVerbs, typ string) bool { // scanBool returns the value of the boolean represented by the next token. func (s *ss) scanBool(verb int) bool { + s.skipSpace(false) + s.notEOF() if !s.okVerb(verb, "tv", "boolean") { return false } // Syntax-checking a boolean is annoying. We're not fastidious about case. - switch s.mustReadRune() { + switch s.getRune() { case '0': return false case '1': @@ -531,8 +550,11 @@ func (s *ss) getBase(verb int) (base int, digits string) { // scanNumber returns the numerical string with specified digits starting here. func (s *ss) scanNumber(digits string, haveDigits bool) string { - if !haveDigits && !s.accept(digits) { - s.errorString("expected integer") + if !haveDigits { + s.notEOF() + if !s.accept(digits) { + s.errorString("expected integer") + } } for s.accept(digits) { } @@ -541,7 +563,8 @@ func (s *ss) scanNumber(digits string, haveDigits bool) string { // scanRune returns the next rune value in the input. func (s *ss) scanRune(bitSize int) int64 { - rune := int64(s.mustReadRune()) + s.notEOF() + rune := int64(s.getRune()) n := uint(bitSize) x := (rune << (64 - n)) >> (64 - n) if x != rune { @@ -575,6 +598,7 @@ func (s *ss) scanInt(verb int, bitSize int) int64 { return s.scanRune(bitSize) } s.skipSpace(false) + s.notEOF() base, digits := s.getBase(verb) haveDigits := false if verb == 'U' { @@ -607,6 +631,7 @@ func (s *ss) scanUint(verb int, bitSize int) uint64 { return uint64(s.scanRune(bitSize)) } s.skipSpace(false) + s.notEOF() base, digits := s.getBase(verb) haveDigits := false if verb == 'U' { @@ -727,6 +752,7 @@ func (s *ss) scanComplex(verb int, n int) complex128 { return 0 } s.skipSpace(false) + s.notEOF() sreal, simag := s.complexTokens() real := s.convertFloat(sreal, n/2) imag := s.convertFloat(simag, n/2) @@ -740,6 +766,7 @@ func (s *ss) convertString(verb int) (str string) { return "" } s.skipSpace(false) + s.notEOF() switch verb { case 'q': str = s.quotedString() @@ -748,16 +775,13 @@ func (s *ss) convertString(verb int) (str string) { default: 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 { - s.errorString("Scan: no data for string") - } return } // quotedString returns the double- or back-quoted string represented by the next input characters. func (s *ss) quotedString() string { - quote := s.mustReadRune() + s.notEOF() + quote := s.getRune() switch quote { case '`': // Back-quoted: Anything goes until EOF or back quote. @@ -827,6 +851,7 @@ func (s *ss) hexByte() (b byte, ok bool) { // hexString returns the space-delimited hexpair-encoded string. func (s *ss) hexString() string { + s.notEOF() for { b, ok := s.hexByte() if !ok { @@ -860,6 +885,7 @@ func (s *ss) scanOne(verb int, field interface{}) { } return } + switch v := field.(type) { case *bool: *v = s.scanBool(verb) @@ -894,11 +920,13 @@ func (s *ss) scanOne(verb int, field interface{}) { case *float32: if s.okVerb(verb, floatVerbs, "float32") { s.skipSpace(false) + s.notEOF() *v = float32(s.convertFloat(s.floatToken(), 32)) } case *float64: if s.okVerb(verb, floatVerbs, "float64") { s.skipSpace(false) + s.notEOF() *v = s.convertFloat(s.floatToken(), 64) } case *string: @@ -927,7 +955,7 @@ func (s *ss) scanOne(verb int, field interface{}) { // For now, can only handle (renamed) []byte. typ := v.Type() if typ.Elem().Kind() != reflect.Uint8 { - goto CantHandle + s.errorString("Scan: can't handle type: " + val.Type().String()) } str := s.convertString(verb) v.Set(reflect.MakeSlice(typ, len(str), len(str))) @@ -936,23 +964,23 @@ func (s *ss) scanOne(verb int, field interface{}) { } case reflect.Float32, reflect.Float64: s.skipSpace(false) + s.notEOF() v.SetFloat(s.convertFloat(s.floatToken(), v.Type().Bits())) case reflect.Complex64, reflect.Complex128: v.SetComplex(s.scanComplex(verb, v.Type().Bits())) default: - CantHandle: s.errorString("Scan: can't handle type: " + val.Type().String()) } } } -// errorHandler turns local panics into error returns. EOFs are benign. +// errorHandler turns local panics into error returns. func errorHandler(errp *os.Error) { if e := recover(); e != nil { if se, ok := e.(scanError); ok { // catch local error - if se.err != os.EOF { - *errp = se.err - } + *errp = se.err + } else if eof, ok := e.(os.Error); ok && eof == os.EOF { // out of input + *errp = eof } else { panic(e) } diff --git a/libgo/go/fmt/scan_test.go b/libgo/go/fmt/scan_test.go index da13eb2..3f06e57 100644 --- a/libgo/go/fmt/scan_test.go +++ b/libgo/go/fmt/scan_test.go @@ -94,7 +94,7 @@ func (x *Xs) Scan(state ScanState, verb int) os.Error { } s := string(tok) if !regexp.MustCompile("^" + string(verb) + "+$").MatchString(s) { - return os.ErrorString("syntax error for xs") + return os.NewError("syntax error for xs") } *x = Xs(s) return nil @@ -298,6 +298,8 @@ var scanfTests = []ScanfTest{ // Fixed bugs {"%d\n", "27\n", &intVal, 27}, // ok {"%d\n", "28 \n", &intVal, 28}, // was: "unexpected newline" + {"%v", "0", &intVal, 0}, // was: "EOF"; 0 was taken as base prefix and not counted. + {"%v", "0", &uintVal, uint(0)}, // was: "EOF"; 0 was taken as base prefix and not counted. } var overflowTests = []ScanTest{ @@ -660,6 +662,68 @@ func TestEOF(t *testing.T) { } } +// Verify that we see an EOF error if we run out of input. +// This was a buglet: we used to get "expected integer". +func TestEOFAtEndOfInput(t *testing.T) { + var i, j int + n, err := Sscanf("23", "%d %d", &i, &j) + if n != 1 || i != 23 { + t.Errorf("Sscanf expected one value of 23; got %d %d", n, i) + } + if err != os.EOF { + t.Errorf("Sscanf expected EOF; got %q", err) + } + n, err = Sscan("234", &i, &j) + if n != 1 || i != 234 { + t.Errorf("Sscan expected one value of 234; got %d %d", n, i) + } + if err != os.EOF { + t.Errorf("Sscan expected EOF; got %q", err) + } + // Trailing space is tougher. + n, err = Sscan("234 ", &i, &j) + if n != 1 || i != 234 { + t.Errorf("Sscan expected one value of 234; got %d %d", n, i) + } + if err != os.EOF { + t.Errorf("Sscan expected EOF; got %q", err) + } +} + +var eofTests = []struct { + format string + v interface{} +}{ + {"%s", &stringVal}, + {"%q", &stringVal}, + {"%x", &stringVal}, + {"%v", &stringVal}, + {"%v", &bytesVal}, + {"%v", &intVal}, + {"%v", &uintVal}, + {"%v", &boolVal}, + {"%v", &float32Val}, + {"%v", &complex64Val}, + {"%v", &renamedStringVal}, + {"%v", &renamedBytesVal}, + {"%v", &renamedIntVal}, + {"%v", &renamedUintVal}, + {"%v", &renamedBoolVal}, + {"%v", &renamedFloat32Val}, + {"%v", &renamedComplex64Val}, +} + +func TestEOFAllTypes(t *testing.T) { + for i, test := range eofTests { + if _, err := Sscanf("", test.format, test.v); err != os.EOF { + t.Errorf("#%d: %s %T not eof on empty string: %s", i, test.format, test.v, err) + } + if _, err := Sscanf(" ", test.format, test.v); err != os.EOF { + t.Errorf("#%d: %s %T not eof on trailing blanks: %s", i, test.format, test.v, err) + } + } +} + // Verify that, at least when using bufio, successive calls to Fscan do not lose runes. func TestUnreadRuneWithBufio(t *testing.T) { r := bufio.NewReader(strings.NewReader("123αb")) @@ -756,7 +820,7 @@ func (r *RecursiveInt) Scan(state ScanState, verb int) (err os.Error) { next := new(RecursiveInt) _, err = Fscanf(state, ".%v", next) if err != nil { - if err == os.ErrorString("input does not match format") || err == io.ErrUnexpectedEOF { + if err == os.NewError("input does not match format") || err == io.ErrUnexpectedEOF { err = nil } return diff --git a/libgo/go/go/ast/ast.go b/libgo/go/go/ast/ast.go index 2fc1a60..22bd5ee 100644 --- a/libgo/go/go/ast/ast.go +++ b/libgo/go/go/ast/ast.go @@ -13,7 +13,6 @@ import ( "utf8" ) - // ---------------------------------------------------------------------------- // Interfaces // @@ -31,35 +30,30 @@ import ( // That position information is needed to properly position comments // when printing the construct. - // All node types implement the Node interface. type Node interface { Pos() token.Pos // position of first character belonging to the node End() token.Pos // position of first character immediately after the node } - // All expression nodes implement the Expr interface. type Expr interface { Node exprNode() } - // All statement nodes implement the Stmt interface. type Stmt interface { Node stmtNode() } - // All declaration nodes implement the Decl interface. type Decl interface { Node declNode() } - // ---------------------------------------------------------------------------- // Comments @@ -69,11 +63,9 @@ type Comment struct { Text string // comment text (excluding '\n' for //-style comments) } - func (c *Comment) Pos() token.Pos { return c.Slash } func (c *Comment) End() token.Pos { return token.Pos(int(c.Slash) + len(c.Text)) } - // A CommentGroup represents a sequence of comments // with no other tokens and no empty lines between. // @@ -81,11 +73,9 @@ type CommentGroup struct { List []*Comment // len(List) > 0 } - func (g *CommentGroup) Pos() token.Pos { return g.List[0].Pos() } func (g *CommentGroup) End() token.Pos { return g.List[len(g.List)-1].End() } - // ---------------------------------------------------------------------------- // Expressions and types @@ -101,7 +91,6 @@ type Field struct { Comment *CommentGroup // line comments; or nil } - func (f *Field) Pos() token.Pos { if len(f.Names) > 0 { return f.Names[0].Pos() @@ -109,7 +98,6 @@ func (f *Field) Pos() token.Pos { return f.Type.Pos() } - func (f *Field) End() token.Pos { if f.Tag != nil { return f.Tag.End() @@ -117,15 +105,13 @@ func (f *Field) End() token.Pos { return f.Type.End() } - // A FieldList represents a list of Fields, enclosed by parentheses or braces. type FieldList struct { Opening token.Pos // position of opening parenthesis/brace, if any - List []*Field // field list + List []*Field // field list; or nil Closing token.Pos // position of closing parenthesis/brace, if any } - func (f *FieldList) Pos() token.Pos { if f.Opening.IsValid() { return f.Opening @@ -138,7 +124,6 @@ func (f *FieldList) Pos() token.Pos { return token.NoPos } - func (f *FieldList) End() token.Pos { if f.Closing.IsValid() { return f.Closing + 1 @@ -151,7 +136,6 @@ func (f *FieldList) End() token.Pos { return token.NoPos } - // NumFields returns the number of (named and anonymous fields) in a FieldList. func (f *FieldList) NumFields() int { n := 0 @@ -167,7 +151,6 @@ func (f *FieldList) NumFields() int { return n } - // An expression is represented by a tree consisting of one // or more of the following concrete expression nodes. // @@ -298,7 +281,6 @@ type ( } ) - // The direction of a channel type is indicated by one // of the following constants. // @@ -309,7 +291,6 @@ const ( RECV ) - // A type is represented by a tree consisting of one // or more of the following type-specific expression // nodes. @@ -334,7 +315,7 @@ type ( // A FuncType node represents a function type. FuncType struct { Func token.Pos // position of "func" keyword - Params *FieldList // (incoming) parameters + Params *FieldList // (incoming) parameters; or nil Results *FieldList // (outgoing) results; or nil } @@ -360,7 +341,6 @@ type ( } ) - // Pos and End implementations for expression/type nodes. // func (x *BadExpr) Pos() token.Pos { return x.From } @@ -391,7 +371,6 @@ func (x *InterfaceType) Pos() token.Pos { return x.Interface } func (x *MapType) Pos() token.Pos { return x.Map } func (x *ChanType) Pos() token.Pos { return x.Begin } - func (x *BadExpr) End() token.Pos { return x.To } func (x *Ident) End() token.Pos { return token.Pos(int(x.NamePos) + len(x.Name)) } func (x *Ellipsis) End() token.Pos { @@ -430,7 +409,6 @@ func (x *InterfaceType) End() token.Pos { return x.Methods.End() } func (x *MapType) End() token.Pos { return x.Value.End() } func (x *ChanType) End() token.Pos { return x.Value.End() } - // exprNode() ensures that only expression/type nodes can be // assigned to an ExprNode. // @@ -458,7 +436,6 @@ func (x *InterfaceType) exprNode() {} func (x *MapType) exprNode() {} func (x *ChanType) exprNode() {} - // ---------------------------------------------------------------------------- // Convenience functions for Idents @@ -469,7 +446,6 @@ var noPos token.Pos // func NewIdent(name string) *Ident { return &Ident{noPos, name, nil} } - // IsExported returns whether name is an exported Go symbol // (i.e., whether it begins with an uppercase letter). // @@ -478,13 +454,11 @@ func IsExported(name string) bool { return unicode.IsUpper(ch) } - // IsExported returns whether id is an exported Go symbol // (i.e., whether it begins with an uppercase letter). // func (id *Ident) IsExported() bool { return IsExported(id.Name) } - func (id *Ident) String() string { if id != nil { return id.Name @@ -492,7 +466,6 @@ func (id *Ident) String() string { return "" } - // ---------------------------------------------------------------------------- // Statements @@ -515,10 +488,10 @@ type ( // An EmptyStmt node represents an empty statement. // The "position" of the empty statement is the position - // of the immediately preceeding semicolon. + // of the immediately preceding semicolon. // EmptyStmt struct { - Semicolon token.Pos // position of preceeding ";" + Semicolon token.Pos // position of preceding ";" } // A LabeledStmt node represents a labeled statement. @@ -596,7 +569,7 @@ type ( // An IfStmt node represents an if statement. IfStmt struct { If token.Pos // position of "if" keyword - Init Stmt // initalization statement; or nil + Init Stmt // initialization statement; or nil Cond Expr // condition Body *BlockStmt Else Stmt // else branch; or nil @@ -613,7 +586,7 @@ type ( // A SwitchStmt node represents an expression switch statement. SwitchStmt struct { Switch token.Pos // position of "switch" keyword - Init Stmt // initalization statement; or nil + Init Stmt // initialization statement; or nil Tag Expr // tag expression; or nil Body *BlockStmt // CaseClauses only } @@ -621,7 +594,7 @@ type ( // An TypeSwitchStmt node represents a type switch statement. TypeSwitchStmt struct { Switch token.Pos // position of "switch" keyword - Init Stmt // initalization statement; or nil + Init Stmt // initialization statement; or nil Assign Stmt // x := y.(type) or y.(type) Body *BlockStmt // CaseClauses only } @@ -643,7 +616,7 @@ type ( // A ForStmt represents a for statement. ForStmt struct { For token.Pos // position of "for" keyword - Init Stmt // initalization statement; or nil + Init Stmt // initialization statement; or nil Cond Expr // condition; or nil Post Stmt // post iteration statement; or nil Body *BlockStmt @@ -660,7 +633,6 @@ type ( } ) - // Pos and End implementations for statement nodes. // func (s *BadStmt) Pos() token.Pos { return s.From } @@ -685,7 +657,6 @@ func (s *SelectStmt) Pos() token.Pos { return s.Select } func (s *ForStmt) Pos() token.Pos { return s.For } func (s *RangeStmt) Pos() token.Pos { return s.For } - func (s *BadStmt) End() token.Pos { return s.To } func (s *DeclStmt) End() token.Pos { return s.Decl.End() } func (s *EmptyStmt) End() token.Pos { @@ -737,7 +708,6 @@ func (s *SelectStmt) End() token.Pos { return s.Body.End() } func (s *ForStmt) End() token.Pos { return s.Body.End() } func (s *RangeStmt) End() token.Pos { return s.Body.End() } - // stmtNode() ensures that only statement nodes can be // assigned to a StmtNode. // @@ -763,7 +733,6 @@ func (s *SelectStmt) stmtNode() {} func (s *ForStmt) stmtNode() {} func (s *RangeStmt) stmtNode() {} - // ---------------------------------------------------------------------------- // Declarations @@ -805,7 +774,6 @@ type ( } ) - // Pos and End implementations for spec nodes. // func (s *ImportSpec) Pos() token.Pos { @@ -817,7 +785,6 @@ func (s *ImportSpec) Pos() token.Pos { func (s *ValueSpec) Pos() token.Pos { return s.Names[0].Pos() } func (s *TypeSpec) Pos() token.Pos { return s.Name.Pos() } - func (s *ImportSpec) End() token.Pos { return s.Path.End() } func (s *ValueSpec) End() token.Pos { if n := len(s.Values); n > 0 { @@ -830,7 +797,6 @@ func (s *ValueSpec) End() token.Pos { } func (s *TypeSpec) End() token.Pos { return s.Type.End() } - // specNode() ensures that only spec nodes can be // assigned to a Spec. // @@ -838,7 +804,6 @@ func (s *ImportSpec) specNode() {} func (s *ValueSpec) specNode() {} func (s *TypeSpec) specNode() {} - // A declaration is represented by one of the following declaration nodes. // type ( @@ -880,14 +845,12 @@ type ( } ) - // Pos and End implementations for declaration nodes. // func (d *BadDecl) Pos() token.Pos { return d.From } func (d *GenDecl) Pos() token.Pos { return d.TokPos } func (d *FuncDecl) Pos() token.Pos { return d.Type.Pos() } - func (d *BadDecl) End() token.Pos { return d.To } func (d *GenDecl) End() token.Pos { if d.Rparen.IsValid() { @@ -902,7 +865,6 @@ func (d *FuncDecl) End() token.Pos { return d.Type.End() } - // declNode() ensures that only declaration nodes can be // assigned to a DeclNode. // @@ -910,7 +872,6 @@ func (d *BadDecl) declNode() {} func (d *GenDecl) declNode() {} func (d *FuncDecl) declNode() {} - // ---------------------------------------------------------------------------- // Files and packages @@ -931,7 +892,6 @@ type File struct { Comments []*CommentGroup // list of all comments in the source file } - func (f *File) Pos() token.Pos { return f.Package } func (f *File) End() token.Pos { if n := len(f.Decls); n > 0 { @@ -940,17 +900,15 @@ func (f *File) End() token.Pos { return f.Name.End() } - // A Package node represents a set of source files // collectively building a Go package. // type Package struct { - Name string // package name - Scope *Scope // package scope - Imports map[string]*Scope // map of import path -> package scope across all files - Files map[string]*File // Go source files by filename + Name string // package name + Scope *Scope // package scope across all files + Imports map[string]*Object // map of package id -> package object + Files map[string]*File // Go source files by filename } - func (p *Package) Pos() token.Pos { return token.NoPos } func (p *Package) End() token.Pos { return token.NoPos } diff --git a/libgo/go/go/ast/filter.go b/libgo/go/go/ast/filter.go index 090d08d..2673343 100644 --- a/libgo/go/go/ast/filter.go +++ b/libgo/go/go/ast/filter.go @@ -20,25 +20,25 @@ func identListExports(list []*Ident) []*Ident { return list[0:j] } - -// isExportedType assumes that typ is a correct type. -func isExportedType(typ Expr) bool { - switch t := typ.(type) { +// fieldName assumes that x is the type of an anonymous field and +// returns the corresponding field name. If x is not an acceptable +// anonymous field, the result is nil. +// +func fieldName(x Expr) *Ident { + switch t := x.(type) { case *Ident: - return t.IsExported() - case *ParenExpr: - return isExportedType(t.X) + return t case *SelectorExpr: - // assume t.X is a typename - return t.Sel.IsExported() + if _, ok := t.X.(*Ident); ok { + return t.Sel + } case *StarExpr: - return isExportedType(t.X) + return fieldName(t.X) } - return false + return nil } - -func fieldListExports(fields *FieldList, incomplete *bool) { +func fieldListExports(fields *FieldList) (removedFields bool) { if fields == nil { return } @@ -53,12 +53,13 @@ func fieldListExports(fields *FieldList, incomplete *bool) { // fields, so this is not absolutely correct. // However, this cannot be done w/o complete // type information.) - exported = isExportedType(f.Type) + name := fieldName(f.Type) + exported = name != nil && name.IsExported() } else { n := len(f.Names) f.Names = identListExports(f.Names) if len(f.Names) < n { - *incomplete = true + removedFields = true } exported = len(f.Names) > 0 } @@ -69,12 +70,12 @@ func fieldListExports(fields *FieldList, incomplete *bool) { } } if j < len(list) { - *incomplete = true + removedFields = true } fields.List = list[0:j] + return } - func paramListExports(fields *FieldList) { if fields == nil { return @@ -84,18 +85,21 @@ func paramListExports(fields *FieldList) { } } - func typeExports(typ Expr) { switch t := typ.(type) { case *ArrayType: typeExports(t.Elt) case *StructType: - fieldListExports(t.Fields, &t.Incomplete) + if fieldListExports(t.Fields) { + t.Incomplete = true + } case *FuncType: paramListExports(t.Params) paramListExports(t.Results) case *InterfaceType: - fieldListExports(t.Methods, &t.Incomplete) + if fieldListExports(t.Methods) { + t.Incomplete = true + } case *MapType: typeExports(t.Key) typeExports(t.Value) @@ -104,7 +108,6 @@ func typeExports(typ Expr) { } } - func specExports(spec Spec) bool { switch s := spec.(type) { case *ValueSpec: @@ -122,7 +125,6 @@ func specExports(spec Spec) bool { return false } - func specListExports(list []Spec) []Spec { j := 0 for _, s := range list { @@ -134,7 +136,6 @@ func specListExports(list []Spec) []Spec { return list[0:j] } - func declExports(decl Decl) bool { switch d := decl.(type) { case *GenDecl: @@ -147,7 +148,6 @@ func declExports(decl Decl) bool { return false } - // FileExports trims the AST for a Go source file in place such that only // exported nodes remain: all top-level identifiers which are not exported // and their associated information (such as type, initial value, or function @@ -170,7 +170,6 @@ func FileExports(src *File) bool { return j > 0 } - // PackageExports trims the AST for a Go package in place such that only // exported nodes remain. The pkg.Files list is not changed, so that file // names and top-level package comments don't get lost. @@ -188,7 +187,6 @@ func PackageExports(pkg *Package) bool { return hasExports } - // ---------------------------------------------------------------------------- // General filtering @@ -205,6 +203,37 @@ func filterIdentList(list []*Ident, f Filter) []*Ident { return list[0:j] } +func filterFieldList(fields *FieldList, filter Filter) (removedFields bool) { + if fields == nil { + return false + } + list := fields.List + j := 0 + for _, f := range list { + keepField := false + if len(f.Names) == 0 { + // anonymous field + name := fieldName(f.Type) + keepField = name != nil && filter(name.Name) + } else { + n := len(f.Names) + f.Names = filterIdentList(f.Names, filter) + if len(f.Names) < n { + removedFields = true + } + keepField = len(f.Names) > 0 + } + if keepField { + list[j] = f + j++ + } + } + if j < len(list) { + removedFields = true + } + fields.List = list[0:j] + return +} func filterSpec(spec Spec, f Filter) bool { switch s := spec.(type) { @@ -212,12 +241,25 @@ func filterSpec(spec Spec, f Filter) bool { s.Names = filterIdentList(s.Names, f) return len(s.Names) > 0 case *TypeSpec: - return f(s.Name.Name) + if f(s.Name.Name) { + return true + } + switch t := s.Type.(type) { + case *StructType: + if filterFieldList(t.Fields, f) { + t.Incomplete = true + } + return len(t.Fields.List) > 0 + case *InterfaceType: + if filterFieldList(t.Methods, f) { + t.Incomplete = true + } + return len(t.Methods.List) > 0 + } } return false } - func filterSpecList(list []Spec, f Filter) []Spec { j := 0 for _, s := range list { @@ -229,8 +271,14 @@ func filterSpecList(list []Spec, f Filter) []Spec { return list[0:j] } - -func filterDecl(decl Decl, f Filter) bool { +// FilterDecl trims the AST for a Go declaration in place by removing +// all names (including struct field and interface method names, but +// not from parameter lists) that don't pass through the filter f. +// +// FilterDecl returns true if there are any declared names left after +// filtering; it returns false otherwise. +// +func FilterDecl(decl Decl, f Filter) bool { switch d := decl.(type) { case *GenDecl: d.Specs = filterSpecList(d.Specs, f) @@ -241,12 +289,11 @@ func filterDecl(decl Decl, f Filter) bool { return false } - // FilterFile trims the AST for a Go file in place by removing all -// names from top-level declarations (but not from parameter lists -// or inside types) that don't pass through the filter f. If the -// declaration is empty afterwards, the declaration is removed from -// the AST. +// names from top-level declarations (including struct field and +// interface method names, but not from parameter lists) that don't +// pass through the filter f. If the declaration is empty afterwards, +// the declaration is removed from the AST. // The File.comments list is not changed. // // FilterFile returns true if there are any top-level declarations @@ -255,7 +302,7 @@ func filterDecl(decl Decl, f Filter) bool { func FilterFile(src *File, f Filter) bool { j := 0 for _, d := range src.Decls { - if filterDecl(d, f) { + if FilterDecl(d, f) { src.Decls[j] = d j++ } @@ -264,12 +311,11 @@ func FilterFile(src *File, f Filter) bool { return j > 0 } - // FilterPackage trims the AST for a Go package in place by removing all -// names from top-level declarations (but not from parameter lists -// or inside types) that don't pass through the filter f. If the -// declaration is empty afterwards, the declaration is removed from -// the AST. +// names from top-level declarations (including struct field and +// interface method names, but not from parameter lists) that don't +// pass through the filter f. If the declaration is empty afterwards, +// the declaration is removed from the AST. // The pkg.Files list is not changed, so that file names and top-level // package comments don't get lost. // @@ -286,7 +332,6 @@ func FilterPackage(pkg *Package, f Filter) bool { return hasDecls } - // ---------------------------------------------------------------------------- // Merging of package files @@ -306,7 +351,6 @@ const ( // var separator = &Comment{noPos, "//"} - // MergePackageFiles creates a file AST by merging the ASTs of the // files belonging to a package. The mode flags control merging behavior. // diff --git a/libgo/go/go/ast/print.go b/libgo/go/go/ast/print.go index 81e1da1..62a3048 100644 --- a/libgo/go/go/ast/print.go +++ b/libgo/go/go/ast/print.go @@ -14,11 +14,9 @@ import ( "reflect" ) - // A FieldFilter may be provided to Fprint to control the output. type FieldFilter func(name string, value reflect.Value) bool - // NotNilFilter returns true for field values that are not nil; // it returns false otherwise. func NotNilFilter(_ string, v reflect.Value) bool { @@ -29,7 +27,6 @@ func NotNilFilter(_ string, v reflect.Value) bool { return true } - // 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 @@ -68,14 +65,12 @@ func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (n i return } - // Print prints x to standard output, skipping nil fields. // 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 @@ -87,7 +82,6 @@ type printer struct { line int // current line number } - var indent = []byte(". ") func (p *printer) Write(data []byte) (n int, err os.Error) { @@ -120,14 +114,12 @@ func (p *printer) Write(data []byte) (n int, err os.Error) { return } - // localError wraps locally caught os.Errors so we can distinguish // them from genuine panics which we don't want to return as errors. type localError struct { err os.Error } - // printf is a convenience wrapper that takes care of print errors. func (p *printer) printf(format string, args ...interface{}) { n, err := fmt.Fprintf(p, format, args...) @@ -137,7 +129,6 @@ func (p *printer) printf(format string, args ...interface{}) { } } - // Implementation note: Print is written for AST nodes but could be // used to print arbitrary data structures; such a version should // probably be in a different package. diff --git a/libgo/go/go/ast/print_test.go b/libgo/go/go/ast/print_test.go index 0820dcf..f4e8f7a 100644 --- a/libgo/go/go/ast/print_test.go +++ b/libgo/go/go/ast/print_test.go @@ -10,7 +10,6 @@ import ( "testing" ) - var tests = []struct { x interface{} // x is printed as s s string @@ -49,11 +48,10 @@ var tests = []struct { 3 }`}, } - // Split s into lines, trim whitespace from all lines, and return // the concatenated non-empty lines. func trim(s string) string { - lines := strings.Split(s, "\n", -1) + lines := strings.Split(s, "\n") i := 0 for _, line := range lines { line = strings.TrimSpace(line) @@ -65,7 +63,6 @@ func trim(s string) string { return strings.Join(lines[0:i], "\n") } - func TestPrint(t *testing.T) { var buf bytes.Buffer for _, test := range tests { diff --git a/libgo/go/go/ast/resolve.go b/libgo/go/go/ast/resolve.go index fddc3ba..3927a79 100644 --- a/libgo/go/go/ast/resolve.go +++ b/libgo/go/go/ast/resolve.go @@ -11,25 +11,22 @@ import ( "go/scanner" "go/token" "os" + "strconv" ) - type pkgBuilder struct { scanner.ErrorVector fset *token.FileSet } - func (p *pkgBuilder) error(pos token.Pos, msg string) { p.Error(p.fset.Position(pos), msg) } - func (p *pkgBuilder) errorf(pos token.Pos, format string, args ...interface{}) { p.error(pos, fmt.Sprintf(format, args...)) } - func (p *pkgBuilder) declare(scope, altScope *Scope, obj *Object) { alt := scope.Insert(obj) if alt == nil && altScope != nil { @@ -45,7 +42,6 @@ func (p *pkgBuilder) declare(scope, altScope *Scope, obj *Object) { } } - func resolve(scope *Scope, ident *Ident) bool { for ; scope != nil; scope = scope.Outer { if obj := scope.Lookup(ident.Name); obj != nil { @@ -56,13 +52,16 @@ func resolve(scope *Scope, ident *Ident) bool { return false } - -// NewPackage uses an Importer to resolve imports. Given an importPath, -// an importer returns the imported package's name, its scope of exported -// objects, and an error, if any. -// -type Importer func(path string) (name string, scope *Scope, err os.Error) - +// An Importer resolves import paths to package Objects. +// The imports map records the packages already imported, +// indexed by package id (canonical import path). +// An Importer must determine the canonical import path and +// check the map to see if it is already present in the imports map. +// If so, the Importer can return the map entry. Otherwise, the +// Importer should load the package data for the given path into +// a new *Object (pkg), record pkg in the imports map, and then +// return pkg. +type Importer func(imports map[string]*Object, path string) (pkg *Object, err os.Error) // NewPackage creates a new Package node from a set of File nodes. It resolves // unresolved identifiers across files and updates each file's Unresolved list @@ -70,7 +69,7 @@ type Importer func(path string) (name string, scope *Scope, err os.Error) // used to resolve identifiers not declared in any of the package files. Any // remaining unresolved identifiers are reported as undeclared. If the files // belong to different packages, one package name is selected and files with -// different package name are reported and then ignored. +// different package names are reported and then ignored. // The result is a package node and a scanner.ErrorList if there were errors. // func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer, universe *Scope) (*Package, os.Error) { @@ -96,14 +95,8 @@ func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer, } } - // imports maps import paths to package names and scopes - // TODO(gri): Eventually we like to get to the import scope from - // a package object. Then we can have a map path -> Obj. - type importedPkg struct { - name string - scope *Scope - } - imports := make(map[string]*importedPkg) + // package global mapping of imported package ids to package objects + imports := make(map[string]*Object) // complete file scopes with imports and resolve identifiers for _, file := range files { @@ -117,42 +110,41 @@ func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer, importErrors := false fileScope := NewScope(pkgScope) for _, spec := range file.Imports { - // add import to global map of imports - path := string(spec.Path.Value) - path = path[1 : len(path)-1] // strip ""'s - pkg := imports[path] - if pkg == nil { - if importer == nil { - importErrors = true - continue - } - name, scope, err := importer(path) - if err != nil { - p.errorf(spec.Path.Pos(), "could not import %s (%s)", path, err) - importErrors = true - continue - } - pkg = &importedPkg{name, scope} - imports[path] = pkg - // TODO(gri) If a local package name != "." is provided, - // global identifier resolution could proceed even if the - // import failed. Consider adjusting the logic here a bit. + if importer == nil { + importErrors = true + continue + } + path, _ := strconv.Unquote(string(spec.Path.Value)) + pkg, err := importer(imports, path) + if err != nil { + p.errorf(spec.Path.Pos(), "could not import %s (%s)", path, err) + importErrors = true + continue } + // TODO(gri) If a local package name != "." is provided, + // global identifier resolution could proceed even if the + // import failed. Consider adjusting the logic here a bit. + // local name overrides imported package name - name := pkg.name + name := pkg.Name if spec.Name != nil { name = spec.Name.Name } + // add import to file scope if name == "." { // merge imported scope with file scope - for _, obj := range pkg.scope.Objects { + for _, obj := range pkg.Data.(*Scope).Objects { p.declare(fileScope, pkgScope, obj) } } else { // declare imported package object in file scope + // (do not re-use pkg in the file scope but create + // a new object instead; the Decl field is different + // for different files) obj := NewObj(Pkg, name) obj.Decl = spec + obj.Data = pkg.Data p.declare(fileScope, pkgScope, obj) } } @@ -161,8 +153,8 @@ func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer, if importErrors { // don't use the universe scope without correct imports // (objects in the universe may be shadowed by imports; - // with missing imports identifiers might get resolved - // wrongly) + // with missing imports, identifiers might get resolved + // incorrectly to universe objects) pkgScope.Outer = nil } i := 0 @@ -178,11 +170,5 @@ func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer, pkgScope.Outer = universe // reset universe scope } - // collect all import paths and respective package scopes - importedScopes := make(map[string]*Scope) - for path, pkg := range imports { - importedScopes[path] = pkg.scope - } - - return &Package{pkgName, pkgScope, importedScopes, files}, p.GetError(scanner.Sorted) + return &Package{pkgName, pkgScope, imports, files}, p.GetError(scanner.Sorted) } diff --git a/libgo/go/go/ast/scope.go b/libgo/go/go/ast/scope.go index 830d88a..92e3669 100644 --- a/libgo/go/go/ast/scope.go +++ b/libgo/go/go/ast/scope.go @@ -12,7 +12,6 @@ import ( "go/token" ) - // A Scope maintains the set of named language entities declared // in the scope and a link to the immediately surrounding (outer) // scope. @@ -22,14 +21,12 @@ type Scope struct { 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 return &Scope{outer, make(map[string]*Object, n)} } - // Lookup returns the object with the given name if it is // found in scope s, otherwise it returns nil. Outer scopes // are ignored. @@ -38,7 +35,6 @@ func (s *Scope) Lookup(name string) *Object { return s.Objects[name] } - // Insert attempts to insert a named object obj into the scope s. // If the scope already contains an object alt with the same name, // Insert leaves the scope unchanged and returns alt. Otherwise @@ -51,7 +47,6 @@ func (s *Scope) Insert(obj *Object) (alt *Object) { return } - // Debugging support func (s *Scope) String() string { var buf bytes.Buffer @@ -66,27 +61,35 @@ func (s *Scope) String() string { return buf.String() } - // ---------------------------------------------------------------------------- // Objects +// TODO(gri) Consider replacing the Object struct with an interface +// and a corresponding set of object implementations. + // An Object describes a named language entity such as a package, // constant, type, variable, function (incl. methods), or label. // +// The Data fields contains object-specific data: +// +// Kind Data type Data value +// Pkg *Scope package scope +// Con int iota for the respective declaration +// Con != nil constant value +// type Object struct { Kind ObjKind Name string // declared name Decl interface{} // corresponding Field, XxxSpec, FuncDecl, or LabeledStmt; or nil + Data interface{} // object-specific data; 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 ObjKind, name string) *Object { return &Object{Kind: kind, Name: name} } - // 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). @@ -126,7 +129,6 @@ func (obj *Object) Pos() token.Pos { return token.NoPos } - // ObKind describes what an object represents. type ObjKind int @@ -141,7 +143,6 @@ const ( Lbl // label ) - var objKindStrings = [...]string{ Bad: "bad", Pkg: "package", @@ -152,5 +153,4 @@ var objKindStrings = [...]string{ Lbl: "label", } - func (kind ObjKind) String() string { return objKindStrings[kind] } diff --git a/libgo/go/go/ast/walk.go b/libgo/go/go/ast/walk.go index 95c4b3a..181cfd1 100644 --- a/libgo/go/go/ast/walk.go +++ b/libgo/go/go/ast/walk.go @@ -13,7 +13,6 @@ type Visitor interface { Visit(node Node) (w Visitor) } - // Helper functions for common node lists. They may be empty. func walkIdentList(v Visitor, list []*Ident) { @@ -22,28 +21,24 @@ func walkIdentList(v Visitor, list []*Ident) { } } - func walkExprList(v Visitor, list []Expr) { for _, x := range list { Walk(v, x) } } - func walkStmtList(v Visitor, list []Stmt) { for _, x := range list { Walk(v, x) } } - func walkDeclList(v Visitor, list []Decl) { for _, x := range list { Walk(v, x) } } - // TODO(gri): Investigate if providing a closure to Walk leads to // simpler use (and may help eliminate Inspect in turn). @@ -369,7 +364,6 @@ func Walk(v Visitor, node Node) { v.Visit(nil) } - type inspector func(Node) bool func (f inspector) Visit(node Node) Visitor { @@ -379,7 +373,6 @@ func (f inspector) Visit(node Node) Visitor { return nil } - // Inspect traverses an AST in depth-first order: It starts by calling // f(node); node must not be nil. If f returns true, Inspect invokes f // for all the non-nil children of node, recursively. diff --git a/libgo/go/go/build/build.go b/libgo/go/go/build/build.go new file mode 100644 index 0000000..97f92bfb --- /dev/null +++ b/libgo/go/go/build/build.go @@ -0,0 +1,444 @@ +// 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 build provides tools for building Go packages. +package build + +import ( + "bytes" + "exec" + "fmt" + "os" + "path/filepath" + "regexp" + "runtime" + "strings" +) + +// Build produces a build Script for the given package. +func Build(tree *Tree, pkg string, info *DirInfo) (*Script, os.Error) { + s := &Script{} + b := &build{ + script: s, + path: filepath.Join(tree.SrcDir(), pkg), + } + b.obj = b.abs("_obj") + string(filepath.Separator) + + b.goarch = runtime.GOARCH + if g := os.Getenv("GOARCH"); g != "" { + b.goarch = g + } + var err os.Error + b.arch, err = ArchChar(b.goarch) + if err != nil { + return nil, err + } + + // add import object files to list of Inputs + for _, pkg := range info.Imports { + t, p, err := FindTree(pkg) + if err != nil && err != ErrNotFound { + // FindTree should always be able to suggest an import + // path and tree. The path must be malformed + // (for example, an absolute or relative path). + return nil, os.NewError("build: invalid import: " + pkg) + } + s.addInput(filepath.Join(t.PkgDir(), p+".a")) + } + + // .go files to be built with gc + gofiles := b.abss(info.GoFiles...) + s.addInput(gofiles...) + + var ofiles []string // object files to be linked or packed + + // make build directory + b.mkdir(b.obj) + s.addIntermediate(b.obj) + + // cgo + if len(info.CgoFiles) > 0 { + cgoFiles := b.abss(info.CgoFiles...) + s.addInput(cgoFiles...) + cgoCFiles := b.abss(info.CFiles...) + s.addInput(cgoCFiles...) + outGo, outObj := b.cgo(cgoFiles, cgoCFiles) + gofiles = append(gofiles, outGo...) + ofiles = append(ofiles, outObj...) + s.addIntermediate(outGo...) + s.addIntermediate(outObj...) + } + + // compile + if len(gofiles) > 0 { + ofile := b.obj + "_go_." + b.arch + b.gc(ofile, gofiles...) + ofiles = append(ofiles, ofile) + s.addIntermediate(ofile) + } + + // assemble + for _, sfile := range info.SFiles { + ofile := b.obj + sfile[:len(sfile)-1] + b.arch + sfile = b.abs(sfile) + s.addInput(sfile) + b.asm(ofile, sfile) + ofiles = append(ofiles, ofile) + s.addIntermediate(ofile) + } + + if len(ofiles) == 0 { + return nil, os.NewError("make: no object files to build") + } + + // choose target file + var targ string + if info.IsCommand() { + // use the last part of the import path as binary name + _, bin := filepath.Split(pkg) + if runtime.GOOS == "windows" { + bin += ".exe" + } + targ = filepath.Join(tree.BinDir(), bin) + } else { + targ = filepath.Join(tree.PkgDir(), pkg+".a") + } + + // make target directory + targDir, _ := filepath.Split(targ) + b.mkdir(targDir) + + // link binary or pack object + if info.IsCommand() { + b.ld(targ, ofiles...) + } else { + b.gopack(targ, ofiles...) + } + s.Output = append(s.Output, targ) + + return b.script, nil +} + +// A Script describes the build process for a Go package. +// The Input, Intermediate, and Output fields are lists of absolute paths. +type Script struct { + Cmd []*Cmd + Input []string + Intermediate []string + Output []string +} + +func (s *Script) addInput(file ...string) { + s.Input = append(s.Input, file...) +} + +func (s *Script) addIntermediate(file ...string) { + s.Intermediate = append(s.Intermediate, file...) +} + +// Run runs the Script's Cmds in order. +func (s *Script) Run() os.Error { + for _, c := range s.Cmd { + if err := c.Run(); err != nil { + return err + } + } + return nil +} + +// Stale returns true if the build's inputs are newer than its outputs. +func (s *Script) Stale() bool { + var latest int64 + // get latest mtime of outputs + for _, file := range s.Output { + fi, err := os.Stat(file) + if err != nil { + // any error reading output files means stale + return true + } + if m := fi.Mtime_ns; m > latest { + latest = m + } + } + for _, file := range s.Input { + fi, err := os.Stat(file) + if err != nil || fi.Mtime_ns > latest { + // any error reading input files means stale + // (attempt to rebuild to figure out why) + return true + } + } + return false +} + +// Clean removes the Script's Intermediate files. +// It tries to remove every file and returns the first error it encounters. +func (s *Script) Clean() (err os.Error) { + // Reverse order so that directories get removed after the files they contain. + for i := len(s.Intermediate) - 1; i >= 0; i-- { + if e := os.Remove(s.Intermediate[i]); err == nil { + err = e + } + } + return +} + +// Nuke removes the Script's Intermediate and Output files. +// It tries to remove every file and returns the first error it encounters. +func (s *Script) Nuke() (err os.Error) { + // Reverse order so that directories get removed after the files they contain. + for i := len(s.Output) - 1; i >= 0; i-- { + if e := os.Remove(s.Output[i]); err == nil { + err = e + } + } + if e := s.Clean(); err == nil { + err = e + } + return +} + +// A Cmd describes an individual build command. +type Cmd struct { + Args []string // command-line + Stdout string // write standard output to this file, "" is passthrough + Dir string // working directory + Env []string // environment + Input []string // file paths (dependencies) + Output []string // file paths +} + +func (c *Cmd) String() string { + return strings.Join(c.Args, " ") +} + +// Run executes the Cmd. +func (c *Cmd) Run() os.Error { + if c.Args[0] == "mkdir" { + for _, p := range c.Output { + if err := os.MkdirAll(p, 0777); err != nil { + return fmt.Errorf("command %q: %v", c, err) + } + } + return nil + } + out := new(bytes.Buffer) + cmd := exec.Command(c.Args[0], c.Args[1:]...) + cmd.Dir = c.Dir + cmd.Env = c.Env + cmd.Stdout = out + cmd.Stderr = out + if c.Stdout != "" { + f, err := os.Create(c.Stdout) + if err != nil { + return err + } + defer f.Close() + cmd.Stdout = f + } + if err := cmd.Run(); err != nil { + return fmt.Errorf("command %q: %v\n%v", c, err, out) + } + return nil +} + +// ArchChar returns the architecture character for the given goarch. +// For example, ArchChar("amd64") returns "6". +func ArchChar(goarch string) (string, os.Error) { + switch goarch { + case "386": + return "8", nil + case "amd64": + return "6", nil + case "arm": + return "5", nil + } + return "", os.NewError("unsupported GOARCH " + goarch) +} + +type build struct { + script *Script + path string + obj string + goarch string + arch string +} + +func (b *build) abs(file string) string { + if filepath.IsAbs(file) { + return file + } + return filepath.Join(b.path, file) +} + +func (b *build) abss(file ...string) []string { + s := make([]string, len(file)) + for i, f := range file { + s[i] = b.abs(f) + } + return s +} + +func (b *build) add(c Cmd) { + b.script.Cmd = append(b.script.Cmd, &c) +} + +func (b *build) mkdir(name string) { + b.add(Cmd{ + Args: []string{"mkdir", "-p", name}, + Output: []string{name}, + }) +} + +func (b *build) gc(ofile string, gofiles ...string) { + gc := b.arch + "g" + args := append([]string{gc, "-o", ofile}, gcImportArgs...) + args = append(args, gofiles...) + b.add(Cmd{ + Args: args, + Input: gofiles, + Output: []string{ofile}, + }) +} + +func (b *build) asm(ofile string, sfile string) { + asm := b.arch + "a" + b.add(Cmd{ + Args: []string{asm, "-o", ofile, sfile}, + Input: []string{sfile}, + Output: []string{ofile}, + }) +} + +func (b *build) ld(targ string, ofiles ...string) { + ld := b.arch + "l" + args := append([]string{ld, "-o", targ}, ldImportArgs...) + args = append(args, ofiles...) + b.add(Cmd{ + Args: args, + Input: ofiles, + Output: []string{targ}, + }) +} + +func (b *build) gopack(targ string, ofiles ...string) { + b.add(Cmd{ + Args: append([]string{"gopack", "grc", targ}, ofiles...), + Input: ofiles, + Output: []string{targ}, + }) +} + +func (b *build) cc(ofile string, cfiles ...string) { + cc := b.arch + "c" + dir := fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH) + inc := filepath.Join(runtime.GOROOT(), "pkg", dir) + args := []string{cc, "-FVw", "-I", inc, "-o", ofile} + b.add(Cmd{ + Args: append(args, cfiles...), + Input: cfiles, + Output: []string{ofile}, + }) +} + +func (b *build) gccCompile(ofile, cfile string) { + b.add(Cmd{ + Args: b.gccArgs("-o", ofile, "-c", cfile), + Input: []string{cfile}, + Output: []string{ofile}, + }) +} + +func (b *build) gccLink(ofile string, ofiles ...string) { + b.add(Cmd{ + Args: append(b.gccArgs("-o", ofile), ofiles...), + Input: ofiles, + Output: []string{ofile}, + }) +} + +func (b *build) gccArgs(args ...string) []string { + // TODO(adg): HOST_CC + a := []string{"gcc", "-I", b.path, "-g", "-fPIC", "-O2"} + switch b.arch { + case "8": + a = append(a, "-m32") + case "6": + a = append(a, "-m64") + } + return append(a, args...) +} + +var cgoRe = regexp.MustCompile(`[/\\:]`) + +func (b *build) cgo(cgofiles, cgocfiles []string) (outGo, outObj []string) { + // cgo + // TODO(adg): CGOPKGPATH + // TODO(adg): CGO_FLAGS + gofiles := []string{b.obj + "_cgo_gotypes.go"} + cfiles := []string{b.obj + "_cgo_main.c", b.obj + "_cgo_export.c"} + for _, fn := range cgofiles { + f := b.obj + cgoRe.ReplaceAllString(fn[:len(fn)-2], "_") + gofiles = append(gofiles, f+"cgo1.go") + cfiles = append(cfiles, f+"cgo2.c") + } + defunC := b.obj + "_cgo_defun.c" + output := append([]string{defunC}, cfiles...) + output = append(output, gofiles...) + b.add(Cmd{ + Args: append([]string{"cgo", "--"}, cgofiles...), + Dir: b.path, + Env: append(os.Environ(), "GOARCH="+b.goarch), + Input: cgofiles, + Output: output, + }) + outGo = append(outGo, gofiles...) + exportH := filepath.Join(b.path, "_cgo_export.h") + b.script.addIntermediate(defunC, exportH, b.obj+"_cgo_flags") + b.script.addIntermediate(cfiles...) + + // cc _cgo_defun.c + defunObj := b.obj + "_cgo_defun." + b.arch + b.cc(defunObj, defunC) + outObj = append(outObj, defunObj) + + // gcc + linkobj := make([]string, 0, len(cfiles)) + for _, cfile := range cfiles { + ofile := cfile[:len(cfile)-1] + "o" + b.gccCompile(ofile, cfile) + linkobj = append(linkobj, ofile) + if !strings.HasSuffix(ofile, "_cgo_main.o") { + outObj = append(outObj, ofile) + } else { + b.script.addIntermediate(ofile) + } + } + for _, cfile := range cgocfiles { + ofile := b.obj + cgoRe.ReplaceAllString(cfile[:len(cfile)-1], "_") + "o" + b.gccCompile(ofile, cfile) + linkobj = append(linkobj, ofile) + outObj = append(outObj, ofile) + } + dynObj := b.obj + "_cgo_.o" + b.gccLink(dynObj, linkobj...) + b.script.addIntermediate(dynObj) + + // cgo -dynimport + importC := b.obj + "_cgo_import.c" + b.add(Cmd{ + Args: []string{"cgo", "-dynimport", dynObj}, + Stdout: importC, + Input: []string{dynObj}, + Output: []string{importC}, + }) + b.script.addIntermediate(importC) + + // cc _cgo_import.ARCH + importObj := b.obj + "_cgo_import." + b.arch + b.cc(importObj, importC) + outObj = append(outObj, importObj) + + return +} diff --git a/libgo/go/go/build/build_test.go b/libgo/go/go/build/build_test.go new file mode 100644 index 0000000..e59d876 --- /dev/null +++ b/libgo/go/go/build/build_test.go @@ -0,0 +1,61 @@ +// 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 build + +import ( + "exec" + "path/filepath" + "testing" +) + +var buildPkgs = []string{ + "go/build/pkgtest", + "go/build/cmdtest", + "go/build/cgotest", +} + +const cmdtestOutput = "3" + +func TestBuild(t *testing.T) { + for _, pkg := range buildPkgs { + tree := Path[0] // Goroot + dir := filepath.Join(tree.SrcDir(), pkg) + + info, err := ScanDir(dir, true) + if err != nil { + t.Error("ScanDir:", err) + continue + } + + s, err := Build(tree, pkg, info) + if err != nil { + t.Error("Build:", err) + continue + } + + if err := s.Run(); err != nil { + t.Error("Run:", err) + continue + } + + if pkg == "go/build/cmdtest" { + bin := s.Output[0] + b, err := exec.Command(bin).CombinedOutput() + if err != nil { + t.Errorf("exec: %s: %v", bin, err) + continue + } + if string(b) != cmdtestOutput { + t.Errorf("cmdtest output: %s want: %s", b, cmdtestOutput) + } + } + + defer func(s *Script) { + if err := s.Nuke(); err != nil { + t.Errorf("nuking: %v", err) + } + }(s) + } +} diff --git a/libgo/go/go/build/cgotest/cgotest.go b/libgo/go/go/build/cgotest/cgotest.go new file mode 100644 index 0000000..93bbf06 --- /dev/null +++ b/libgo/go/go/build/cgotest/cgotest.go @@ -0,0 +1,19 @@ +// 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 cgotest + +/* +char* greeting = "hello, world"; +*/ +// #include "cgotest.h" +import "C" +import "unsafe" + +var Greeting = C.GoString(C.greeting) + +func DoAdd(x, y int) (sum int) { + C.Add(C.int(x), C.int(y), (*C.int)(unsafe.Pointer(&sum))) + return +} diff --git a/libgo/go/go/build/cmdtest/main.go b/libgo/go/go/build/cmdtest/main.go new file mode 100644 index 0000000..bed4f48 --- /dev/null +++ b/libgo/go/go/build/cmdtest/main.go @@ -0,0 +1,12 @@ +// 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 main + +import "go/build/pkgtest" + +func main() { + pkgtest.Foo() + print(int(pkgtest.Sqrt(9))) +} diff --git a/libgo/go/go/build/dir.go b/libgo/go/go/build/dir.go new file mode 100644 index 0000000..e0000b5 --- /dev/null +++ b/libgo/go/go/build/dir.go @@ -0,0 +1,172 @@ +// 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 build + +import ( + "go/parser" + "go/token" + "log" + "os" + "path/filepath" + "strconv" + "strings" + "runtime" +) + +type DirInfo struct { + GoFiles []string // .go files in dir (excluding CgoFiles) + CgoFiles []string // .go files that import "C" + CFiles []string // .c files in dir + SFiles []string // .s files in dir + Imports []string // All packages imported by goFiles + PkgName string // Name of package in dir +} + +func (d *DirInfo) IsCommand() bool { + return d.PkgName == "main" +} + +// ScanDir returns a structure with details about the Go content found +// in the given directory. The file lists exclude: +// +// - files in package main (unless allowMain is true) +// - files in package documentation +// - files ending in _test.go +// - files starting with _ or . +// +// Only files that satisfy the goodOSArch function are included. +func ScanDir(dir string, allowMain bool) (info *DirInfo, err os.Error) { + f, err := os.Open(dir) + if err != nil { + return nil, err + } + dirs, err := f.Readdir(-1) + f.Close() + if err != nil { + return nil, err + } + + var di DirInfo + imported := make(map[string]bool) + fset := token.NewFileSet() + for i := range dirs { + d := &dirs[i] + if strings.HasPrefix(d.Name, "_") || + strings.HasPrefix(d.Name, ".") { + continue + } + if !goodOSArch(d.Name) { + continue + } + + switch filepath.Ext(d.Name) { + case ".go": + if strings.HasSuffix(d.Name, "_test.go") { + continue + } + case ".c": + di.CFiles = append(di.CFiles, d.Name) + continue + case ".s": + di.SFiles = append(di.SFiles, d.Name) + continue + default: + continue + } + + filename := filepath.Join(dir, d.Name) + pf, err := parser.ParseFile(fset, filename, nil, parser.ImportsOnly) + if err != nil { + return nil, err + } + s := string(pf.Name.Name) + if s == "main" && !allowMain { + continue + } + if s == "documentation" { + continue + } + if di.PkgName == "" { + di.PkgName = s + } else if di.PkgName != s { + // Only if all files in the directory are in package main + // do we return PkgName=="main". + // A mix of main and another package reverts + // to the original (allowMain=false) behaviour. + if s == "main" || di.PkgName == "main" { + return ScanDir(dir, false) + } + return nil, os.NewError("multiple package names in " + dir) + } + isCgo := false + for _, spec := range pf.Imports { + quoted := string(spec.Path.Value) + path, err := strconv.Unquote(quoted) + if err != nil { + log.Panicf("%s: parser returned invalid quoted string: <%s>", filename, quoted) + } + imported[path] = true + if path == "C" { + isCgo = true + } + } + if isCgo { + di.CgoFiles = append(di.CgoFiles, d.Name) + } else { + di.GoFiles = append(di.GoFiles, d.Name) + } + } + di.Imports = make([]string, len(imported)) + i := 0 + for p := range imported { + di.Imports[i] = p + i++ + } + return &di, nil +} + +// goodOSArch returns false if the filename contains a $GOOS or $GOARCH +// suffix which does not match the current system. +// The recognized filename formats are: +// +// name_$(GOOS).* +// name_$(GOARCH).* +// name_$(GOOS)_$(GOARCH).* +// +func goodOSArch(filename string) bool { + if dot := strings.Index(filename, "."); dot != -1 { + filename = filename[:dot] + } + l := strings.Split(filename, "_") + n := len(l) + if n == 0 { + return true + } + if good, known := goodOS[l[n-1]]; known { + return good + } + if good, known := goodArch[l[n-1]]; known { + if !good || n < 2 { + return false + } + good, known = goodOS[l[n-2]] + return good || !known + } + return true +} + +var goodOS = make(map[string]bool) +var goodArch = make(map[string]bool) + +func init() { + goodOS = make(map[string]bool) + goodArch = make(map[string]bool) + for _, v := range strings.Fields(goosList) { + goodOS[v] = v == runtime.GOOS + } + for _, v := range strings.Fields(goarchList) { + goodArch[v] = v == runtime.GOARCH + } +} diff --git a/libgo/go/go/build/path.go b/libgo/go/go/build/path.go new file mode 100644 index 0000000..e39b5f8 --- /dev/null +++ b/libgo/go/go/build/path.go @@ -0,0 +1,182 @@ +// 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 build + +import ( + "fmt" + "log" + "os" + "path/filepath" + "runtime" +) + +// Path is a validated list of Trees derived from $GOROOT and $GOPATH at init. +var Path []*Tree + +// Tree describes a Go source tree, either $GOROOT or one from $GOPATH. +type Tree struct { + Path string + Goroot bool +} + +func newTree(p string) (*Tree, os.Error) { + if !filepath.IsAbs(p) { + return nil, os.NewError("must be absolute") + } + ep, err := filepath.EvalSymlinks(p) + if err != nil { + return nil, err + } + return &Tree{Path: ep}, nil +} + +// SrcDir returns the tree's package source directory. +func (t *Tree) SrcDir() string { + if t.Goroot { + return filepath.Join(t.Path, "src", "pkg") + } + return filepath.Join(t.Path, "src") +} + +// PkgDir returns the tree's package object directory. +func (t *Tree) PkgDir() string { + goos, goarch := runtime.GOOS, runtime.GOARCH + if e := os.Getenv("GOOS"); e != "" { + goos = e + } + if e := os.Getenv("GOARCH"); e != "" { + goarch = e + } + return filepath.Join(t.Path, "pkg", goos+"_"+goarch) +} + +// BinDir returns the tree's binary executable directory. +func (t *Tree) BinDir() string { + if t.Goroot { + if gobin := os.Getenv("GOBIN"); gobin != "" { + return gobin + } + } + return filepath.Join(t.Path, "bin") +} + +// HasSrc returns whether the given package's +// source can be found inside this Tree. +func (t *Tree) HasSrc(pkg string) bool { + fi, err := os.Stat(filepath.Join(t.SrcDir(), pkg)) + if err != nil { + return false + } + return fi.IsDirectory() +} + +// HasPkg returns whether the given package's +// object file can be found inside this Tree. +func (t *Tree) HasPkg(pkg string) bool { + fi, err := os.Stat(filepath.Join(t.PkgDir(), pkg+".a")) + if err != nil { + return false + } + return fi.IsRegular() + // TODO(adg): check object version is consistent +} + +var ( + ErrNotFound = os.NewError("go/build: package could not be found locally") + ErrTreeNotFound = os.NewError("go/build: no valid GOROOT or GOPATH could be found") +) + +// FindTree takes an import or filesystem path and returns the +// tree where the package source should be and the package import path. +func FindTree(path string) (tree *Tree, pkg string, err os.Error) { + if isLocalPath(path) { + if path, err = filepath.Abs(path); err != nil { + return + } + if path, err = filepath.EvalSymlinks(path); err != nil { + return + } + for _, t := range Path { + tpath := t.SrcDir() + string(filepath.Separator) + if !filepath.HasPrefix(path, tpath) { + continue + } + tree = t + pkg = path[len(tpath):] + return + } + err = fmt.Errorf("path %q not inside a GOPATH", path) + return + } + tree = defaultTree + pkg = path + for _, t := range Path { + if t.HasSrc(pkg) { + tree = t + return + } + } + if tree == nil { + err = ErrTreeNotFound + } else { + err = ErrNotFound + } + return +} + +// isLocalPath returns whether the given path is local (/foo ./foo ../foo . ..) +// Windows paths that starts with drive letter (c:\foo c:foo) are considered local. +func isLocalPath(s string) bool { + const sep = string(filepath.Separator) + return s == "." || s == ".." || + filepath.HasPrefix(s, sep) || + filepath.HasPrefix(s, "."+sep) || filepath.HasPrefix(s, ".."+sep) || + filepath.VolumeName(s) != "" +} + +var ( + // argument lists used by the build's gc and ld methods + gcImportArgs []string + ldImportArgs []string + + // default tree for remote packages + defaultTree *Tree +) + +// set up Path: parse and validate GOROOT and GOPATH variables +func init() { + root := runtime.GOROOT() + t, err := newTree(root) + if err != nil { + log.Printf("go/build: invalid GOROOT %q: %v", root, err) + } else { + t.Goroot = true + Path = []*Tree{t} + } + + for _, p := range filepath.SplitList(os.Getenv("GOPATH")) { + if p == "" { + continue + } + t, err := newTree(p) + if err != nil { + log.Printf("go/build: invalid GOPATH %q: %v", p, err) + continue + } + Path = append(Path, t) + gcImportArgs = append(gcImportArgs, "-I", t.PkgDir()) + ldImportArgs = append(ldImportArgs, "-L", t.PkgDir()) + + // select first GOPATH entry as default + if defaultTree == nil { + defaultTree = t + } + } + + // use GOROOT if no valid GOPATH specified + if defaultTree == nil && len(Path) > 0 { + defaultTree = Path[0] + } +} diff --git a/libgo/go/go/build/pkgtest/pkgtest.go b/libgo/go/go/build/pkgtest/pkgtest.go new file mode 100644 index 0000000..9322f5e --- /dev/null +++ b/libgo/go/go/build/pkgtest/pkgtest.go @@ -0,0 +1,9 @@ +// 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 pkgtest + +func Foo() {} + +func Sqrt(x float64) float64 diff --git a/libgo/go/go/build/syslist_test.go b/libgo/go/go/build/syslist_test.go new file mode 100644 index 0000000..eb0e5dc --- /dev/null +++ b/libgo/go/go/build/syslist_test.go @@ -0,0 +1,62 @@ +// 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 build + +import ( + "runtime" + "testing" +) + +var ( + thisOS = runtime.GOOS + thisArch = runtime.GOARCH + otherOS = anotherOS() + otherArch = anotherArch() +) + +func anotherOS() string { + if thisOS != "darwin" { + return "darwin" + } + return "linux" +} + +func anotherArch() string { + if thisArch != "amd64" { + return "amd64" + } + return "386" +} + +type GoodFileTest struct { + name string + result bool +} + +var tests = []GoodFileTest{ + {"file.go", true}, + {"file.c", true}, + {"file_foo.go", true}, + {"file_" + thisArch + ".go", true}, + {"file_" + otherArch + ".go", false}, + {"file_" + thisOS + ".go", true}, + {"file_" + otherOS + ".go", false}, + {"file_" + thisOS + "_" + thisArch + ".go", true}, + {"file_" + otherOS + "_" + thisArch + ".go", false}, + {"file_" + thisOS + "_" + otherArch + ".go", false}, + {"file_" + otherOS + "_" + otherArch + ".go", false}, + {"file_foo_" + thisArch + ".go", true}, + {"file_foo_" + otherArch + ".go", false}, + {"file_" + thisOS + ".c", true}, + {"file_" + otherOS + ".c", false}, +} + +func TestGoodOSArch(t *testing.T) { + for _, test := range tests { + if goodOSArch(test.name) != test.result { + t.Fatalf("goodOSArch(%q) != %v", test.name, test.result) + } + } +} diff --git a/libgo/go/go/doc/comment.go b/libgo/go/go/doc/comment.go index f1ebfa9..e198922 100644 --- a/libgo/go/go/doc/comment.go +++ b/libgo/go/go/doc/comment.go @@ -11,13 +11,11 @@ import ( "io" "regexp" "strings" - "template" // for htmlEscape + "template" // for HTMLEscape ) - func isWhitespace(ch byte) bool { return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' } - func stripTrailingWhitespace(s string) string { i := len(s) for i > 0 && isWhitespace(s[i-1]) { @@ -26,7 +24,6 @@ func stripTrailingWhitespace(s string) string { return s[0:i] } - // CommentText returns the text of comment, // with the comment markers - //, /*, and */ - removed. func CommentText(comment *ast.CommentGroup) string { @@ -58,7 +55,7 @@ func CommentText(comment *ast.CommentGroup) string { } // Split on newlines. - cl := strings.Split(c, "\n", -1) + cl := strings.Split(c, "\n") // Walk lines, stripping trailing white space and adding to list. for _, l := range cl { @@ -85,7 +82,6 @@ func CommentText(comment *ast.CommentGroup) string { return strings.Join(lines, "\n") } - // Split bytes into lines. func split(text []byte) [][]byte { // count lines @@ -119,7 +115,6 @@ func split(text []byte) [][]byte { return out } - var ( ldquo = []byte("“") rdquo = []byte("”") @@ -148,7 +143,6 @@ func commentEscape(w io.Writer, s []byte, nice bool) { template.HTMLEscape(w, s[last:]) } - const ( // Regexp for Go identifiers identRx = `[a-zA-Z_][a-zA-Z_0-9]*` // TODO(gri) ASCII only for now - fix this @@ -176,7 +170,6 @@ var ( html_endpre = []byte("\n") ) - // Emphasize and escape a line of text for HTML. URLs are converted into links; // if the URL also appears in the words map, the link is taken from the map (if // the corresponding map value is the empty string, the URL is not converted @@ -235,7 +228,6 @@ func emphasize(w io.Writer, line []byte, words map[string]string, nice bool) { commentEscape(w, line, nice) } - func indentLen(s []byte) int { i := 0 for i < len(s) && (s[i] == ' ' || s[i] == '\t') { @@ -244,10 +236,8 @@ func indentLen(s []byte) int { return i } - func isBlank(s []byte) bool { return len(s) == 0 || (len(s) == 1 && s[0] == '\n') } - func commonPrefix(a, b []byte) []byte { i := 0 for i < len(a) && i < len(b) && a[i] == b[i] { @@ -256,7 +246,6 @@ func commonPrefix(a, b []byte) []byte { return a[0:i] } - func unindent(block [][]byte) { if len(block) == 0 { return @@ -279,7 +268,6 @@ func unindent(block [][]byte) { } } - // Convert comment text to formatted HTML. // The comment was prepared by DocReader, // so it is known not to have leading, trailing blank lines diff --git a/libgo/go/go/doc/doc.go b/libgo/go/go/doc/doc.go index 29d205d..c7fed97 100644 --- a/libgo/go/go/doc/doc.go +++ b/libgo/go/go/doc/doc.go @@ -12,7 +12,6 @@ import ( "sort" ) - // ---------------------------------------------------------------------------- type typeDoc struct { @@ -25,7 +24,6 @@ type typeDoc struct { methods map[string]*ast.FuncDecl } - // docReader accumulates documentation for a single package. // It modifies the AST: Comments (declaration documentation) // that have been collected by the DocReader are set to nil @@ -42,14 +40,12 @@ type docReader struct { bugs []*ast.CommentGroup } - func (doc *docReader) init(pkgName string) { doc.pkgName = pkgName doc.types = make(map[string]*typeDoc) doc.funcs = make(map[string]*ast.FuncDecl) } - func (doc *docReader) addDoc(comments *ast.CommentGroup) { if doc.doc == nil { // common case: just one package comment @@ -71,7 +67,6 @@ func (doc *docReader) addDoc(comments *ast.CommentGroup) { doc.doc = &ast.CommentGroup{list} } - func (doc *docReader) addType(decl *ast.GenDecl) { spec := decl.Specs[0].(*ast.TypeSpec) typ := doc.lookupTypeDoc(spec.Name.Name) @@ -84,7 +79,6 @@ func (doc *docReader) addType(decl *ast.GenDecl) { } } - func (doc *docReader) lookupTypeDoc(name string) *typeDoc { if name == "" { return nil // no type docs for anonymous types @@ -98,7 +92,6 @@ func (doc *docReader) lookupTypeDoc(name string) *typeDoc { return tdoc } - func baseTypeName(typ ast.Expr) string { switch t := typ.(type) { case *ast.Ident: @@ -113,7 +106,6 @@ func baseTypeName(typ ast.Expr) string { return "" } - func (doc *docReader) addValue(decl *ast.GenDecl) { // determine if decl should be associated with a type // Heuristic: For each typed entry, determine the type name, if any. @@ -165,7 +157,6 @@ func (doc *docReader) addValue(decl *ast.GenDecl) { *values = append(*values, decl) } - // Helper function to set the table entry for function f. Makes sure that // at least one f with associated documentation is stored in table, if there // are multiple f's with the same name. @@ -183,7 +174,6 @@ func setFunc(table map[string]*ast.FuncDecl, f *ast.FuncDecl) { table[name] = f } - func (doc *docReader) addFunc(fun *ast.FuncDecl) { name := fun.Name.Name @@ -238,7 +228,6 @@ func (doc *docReader) addFunc(fun *ast.FuncDecl) { setFunc(doc.funcs, fun) } - func (doc *docReader) addDecl(decl ast.Decl) { switch d := decl.(type) { case *ast.GenDecl: @@ -271,7 +260,6 @@ func (doc *docReader) addDecl(decl ast.Decl) { } } - func copyCommentList(list []*ast.Comment) []*ast.Comment { return append([]*ast.Comment(nil), list...) } @@ -281,7 +269,6 @@ var ( bug_content = regexp.MustCompile("[^ \n\r\t]+") // at least one non-whitespace char ) - // addFile adds the AST for a source file to the docReader. // Adding the same AST multiple times is a no-op. // @@ -313,7 +300,6 @@ func (doc *docReader) addFile(src *ast.File) { src.Comments = nil // consumed unassociated comments - remove from ast.File node } - func NewFileDoc(file *ast.File) *PackageDoc { var r docReader r.init(file.Name.Name) @@ -321,7 +307,6 @@ func NewFileDoc(file *ast.File) *PackageDoc { return r.newDoc("", nil) } - func NewPackageDoc(pkg *ast.Package, importpath string) *PackageDoc { var r docReader r.init(pkg.Name) @@ -335,7 +320,6 @@ func NewPackageDoc(pkg *ast.Package, importpath string) *PackageDoc { return r.newDoc(importpath, filenames) } - // ---------------------------------------------------------------------------- // Conversion to external representation @@ -353,7 +337,6 @@ type sortValueDoc []*ValueDoc func (p sortValueDoc) Len() int { return len(p) } func (p sortValueDoc) Swap(i, j int) { p[i], p[j] = p[j], p[i] } - func declName(d *ast.GenDecl) string { if len(d.Specs) != 1 { return "" @@ -369,7 +352,6 @@ func declName(d *ast.GenDecl) string { return "" } - func (p sortValueDoc) Less(i, j int) bool { // sort by name // pull blocks (name = "") up to top @@ -380,7 +362,6 @@ func (p sortValueDoc) Less(i, j int) bool { return p[i].order < p[j].order } - func makeValueDocs(list []*ast.GenDecl, tok token.Token) []*ValueDoc { d := make([]*ValueDoc, len(list)) // big enough in any case n := 0 @@ -396,7 +377,6 @@ func makeValueDocs(list []*ast.GenDecl, tok token.Token) []*ValueDoc { return d } - // FuncDoc is the documentation for a func declaration, // either a top-level function or a method function. // @@ -413,7 +393,6 @@ func (p sortFuncDoc) Len() int { return len(p) } func (p sortFuncDoc) Swap(i, j int) { p[i], p[j] = p[j], p[i] } func (p sortFuncDoc) Less(i, j int) bool { return p[i].Name < p[j].Name } - func makeFuncDocs(m map[string]*ast.FuncDecl) []*FuncDoc { d := make([]*FuncDoc, len(m)) i := 0 @@ -433,7 +412,6 @@ func makeFuncDocs(m map[string]*ast.FuncDecl) []*FuncDoc { return d } - // TypeDoc is the documentation for a declared type. // Consts and Vars are sorted lists of constants and variables of (mostly) that type. // Factories is a sorted list of factory functions that return that type. @@ -463,7 +441,6 @@ func (p sortTypeDoc) Less(i, j int) bool { return p[i].order < p[j].order } - // NOTE(rsc): This would appear not to be correct for type ( ) // blocks, but the doc extractor above has split them into // individual declarations. @@ -520,7 +497,6 @@ func (doc *docReader) makeTypeDocs(m map[string]*typeDoc) []*TypeDoc { return d } - func makeBugDocs(list []*ast.CommentGroup) []string { d := make([]string, len(list)) for i, g := range list { @@ -529,7 +505,6 @@ func makeBugDocs(list []*ast.CommentGroup) []string { return d } - // PackageDoc is the documentation for an entire package. // type PackageDoc struct { @@ -544,14 +519,13 @@ type PackageDoc struct { Bugs []string } - // newDoc returns the accumulated documentation for the package. // func (doc *docReader) newDoc(importpath string, filenames []string) *PackageDoc { p := new(PackageDoc) p.PackageName = doc.pkgName p.ImportPath = importpath - sort.SortStrings(filenames) + sort.Strings(filenames) p.Filenames = filenames p.Doc = CommentText(doc.doc) // makeTypeDocs may extend the list of doc.values and @@ -565,12 +539,23 @@ func (doc *docReader) newDoc(importpath string, filenames []string) *PackageDoc return p } - // ---------------------------------------------------------------------------- // Filtering by name type Filter func(string) bool +func matchFields(fields *ast.FieldList, f Filter) bool { + if fields != nil { + for _, field := range fields.List { + for _, name := range field.Names { + if f(name.Name) { + return true + } + } + } + } + return false +} func matchDecl(d *ast.GenDecl, f Filter) bool { for _, d := range d.Specs { @@ -585,12 +570,21 @@ func matchDecl(d *ast.GenDecl, f Filter) bool { if f(v.Name.Name) { return true } + switch t := v.Type.(type) { + case *ast.StructType: + if matchFields(t.Fields, f) { + return true + } + case *ast.InterfaceType: + if matchFields(t.Methods, f) { + return true + } + } } } return false } - func filterValueDocs(a []*ValueDoc, f Filter) []*ValueDoc { w := 0 for _, vd := range a { @@ -602,7 +596,6 @@ func filterValueDocs(a []*ValueDoc, f Filter) []*ValueDoc { return a[0:w] } - func filterFuncDocs(a []*FuncDoc, f Filter) []*FuncDoc { w := 0 for _, fd := range a { @@ -614,7 +607,6 @@ func filterFuncDocs(a []*FuncDoc, f Filter) []*FuncDoc { return a[0:w] } - func filterTypeDocs(a []*TypeDoc, f Filter) []*TypeDoc { w := 0 for _, td := range a { @@ -637,7 +629,6 @@ func filterTypeDocs(a []*TypeDoc, f Filter) []*TypeDoc { return a[0:w] } - // Filter eliminates documentation for names that don't pass through the filter f. // TODO: Recognize "Type.Method" as a name. // diff --git a/libgo/go/go/parser/interface.go b/libgo/go/go/parser/interface.go index b4780e0..4f980fc 100644 --- a/libgo/go/go/parser/interface.go +++ b/libgo/go/go/parser/interface.go @@ -17,7 +17,6 @@ import ( "path/filepath" ) - // If src != nil, readSource converts src to a []byte if possible; // otherwise it returns an error. If src == nil, readSource returns // the result of reading the file specified by filename. @@ -42,20 +41,21 @@ func readSource(filename string, src interface{}) ([]byte, os.Error) { } return buf.Bytes(), nil default: - return nil, os.ErrorString("invalid source") + return nil, os.NewError("invalid source") } } return ioutil.ReadFile(filename) } - -func (p *parser) parseEOF() os.Error { - p.expect(token.EOF) - return p.GetError(scanner.Sorted) +func (p *parser) errors() os.Error { + mode := scanner.Sorted + if p.mode&SpuriousErrors == 0 { + mode = scanner.NoMultiples + } + return p.GetError(mode) } - // ParseExpr parses a Go expression and returns the corresponding // AST node. The fset, filename, and src arguments have the same interpretation // as for ParseFile. If there is an error, the result expression @@ -73,9 +73,10 @@ func ParseExpr(fset *token.FileSet, filename string, src interface{}) (ast.Expr, if p.tok == token.SEMICOLON { p.next() // consume automatically inserted semicolon, if any } - return x, p.parseEOF() -} + p.expect(token.EOF) + return x, p.errors() +} // ParseStmtList parses a list of Go statements and returns the list // of corresponding AST nodes. The fset, filename, and src arguments have the same @@ -90,9 +91,11 @@ func ParseStmtList(fset *token.FileSet, filename string, src interface{}) ([]ast var p parser p.init(fset, filename, data, 0) - return p.parseStmtList(), p.parseEOF() -} + list := p.parseStmtList() + p.expect(token.EOF) + return list, p.errors() +} // ParseDeclList parses a list of Go declarations and returns the list // of corresponding AST nodes. The fset, filename, and src arguments have the same @@ -107,9 +110,11 @@ func ParseDeclList(fset *token.FileSet, filename string, src interface{}) ([]ast var p parser p.init(fset, filename, data, 0) - return p.parseDeclList(), p.parseEOF() -} + list := p.parseDeclList() + p.expect(token.EOF) + return list, p.errors() +} // ParseFile parses the source code of a single Go source file and returns // the corresponding ast.File node. The source code may be provided via @@ -139,9 +144,10 @@ func ParseFile(fset *token.FileSet, filename string, src interface{}, mode uint) var p parser p.init(fset, filename, data, mode) - return p.parseFile(), p.GetError(scanner.NoMultiples) // parseFile() reads to EOF -} + file := p.parseFile() // parseFile reads to EOF + return file, p.errors() +} // ParseFiles calls ParseFile for each file in the filenames list and returns // a map of package name -> package AST with all the packages found. The mode @@ -171,7 +177,6 @@ func ParseFiles(fset *token.FileSet, filenames []string, mode uint) (pkgs map[st return } - // ParseDir calls ParseFile for the files in the directory specified by path and // returns a map of package name -> package AST with all the packages found. If // filter != nil, only the files with os.FileInfo entries passing through the filter diff --git a/libgo/go/go/parser/parser.go b/libgo/go/go/parser/parser.go index afa9ae5..9c14d16 100644 --- a/libgo/go/go/parser/parser.go +++ b/libgo/go/go/parser/parser.go @@ -16,7 +16,6 @@ import ( "go/token" ) - // 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. @@ -27,9 +26,9 @@ const ( ParseComments // parse comments and add them to AST Trace // print a trace of parsed productions DeclarationErrors // report declaration errors + SpuriousErrors // report all (not just the first) errors per line ) - // The parser structure holds the parser's internal state. type parser struct { file *token.File @@ -54,7 +53,7 @@ type parser struct { // Non-syntactic parser control exprLev int // < 0: in control clause, >= 0: in expression - // Ordinary identifer scopes + // Ordinary identifier scopes pkgScope *ast.Scope // pkgScope.Outer == nil topScope *ast.Scope // top-most scope; may be pkgScope unresolved []*ast.Ident // unresolved identifiers @@ -66,7 +65,6 @@ type parser struct { targetStack [][]*ast.Ident // stack of unresolved labels } - // scannerMode returns the scanner mode bits given the parser's mode bits. func scannerMode(mode uint) uint { var m uint = scanner.InsertSemis @@ -76,7 +74,6 @@ func scannerMode(mode uint) uint { return m } - 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)) @@ -95,7 +92,6 @@ func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode uin p.openLabelScope() } - // ---------------------------------------------------------------------------- // Scoping support @@ -103,18 +99,15 @@ 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 @@ -130,15 +123,16 @@ func (p *parser) closeLabelScope() { p.labelScope = p.labelScope.Outer } - -func (p *parser) declare(decl interface{}, scope *ast.Scope, kind ast.ObjKind, idents ...*ast.Ident) { +func (p *parser) declare(decl, data interface{}, scope *ast.Scope, kind ast.ObjKind, idents ...*ast.Ident) { for _, ident := range idents { assert(ident.Obj == nil, "identifier already declared or resolved") + obj := ast.NewObj(kind, ident.Name) + // remember the corresponding declaration for redeclaration + // errors and global variable resolution/typechecking phase + obj.Decl = decl + obj.Data = data + ident.Obj = obj 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 if alt := scope.Insert(obj); alt != nil && p.mode&DeclarationErrors != 0 { prevDecl := "" if pos := alt.Pos(); pos.IsValid() { @@ -146,12 +140,10 @@ func (p *parser) declare(decl interface{}, scope *ast.Scope, kind ast.ObjKind, i } 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 @@ -159,17 +151,17 @@ func (p *parser) shortVarDecl(idents []*ast.Ident) { n := 0 // number of new variables for _, ident := range idents { assert(ident.Obj == nil, "identifier already declared or resolved") + 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 + ident.Obj = obj 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 == nil { + if alt := p.topScope.Insert(obj); alt != nil { + ident.Obj = alt // redeclaration + } else { n++ // new declaration - alt = obj } - ident.Obj = alt } } if n == 0 && p.mode&DeclarationErrors != 0 { @@ -177,13 +169,11 @@ func (p *parser) shortVarDecl(idents []*ast.Ident) { } } - // The unresolved object is a sentinel to mark identifiers that have been added // to the list of unresolved identifiers. The sentinel is only used for verifying // internal consistency. var unresolved = new(ast.Object) - func (p *parser) resolve(x ast.Expr) { // nothing to do if x is not an identifier or the blank identifier ident, _ := x.(*ast.Ident) @@ -209,7 +199,6 @@ func (p *parser) resolve(x ast.Expr) { p.unresolved = append(p.unresolved, ident) } - // ---------------------------------------------------------------------------- // Parsing support @@ -227,21 +216,18 @@ func (p *parser) printTrace(a ...interface{}) { fmt.Println(a...) } - func trace(p *parser, msg string) *parser { p.printTrace(msg, "(") p.indent++ return p } - // Usage pattern: defer un(trace(p, "...")); func un(p *parser) { p.indent-- p.printTrace(")") } - // Advance to the next token. func (p *parser) next0() { // Because of one-token look-ahead, print the previous token @@ -283,7 +269,6 @@ func (p *parser) consumeComment() (comment *ast.Comment, endline int) { return } - // Consume a group of adjacent comments, add it to the parser's // comments list, and return it together with the line at which // the last comment in the group ends. An empty line or non-comment @@ -305,7 +290,6 @@ func (p *parser) consumeCommentGroup() (comments *ast.CommentGroup, endline int) return } - // Advance to the next non-comment token. In the process, collect // any comment groups encountered, and remember the last lead and // and line comments. @@ -356,12 +340,10 @@ func (p *parser) next() { } } - func (p *parser) error(pos token.Pos, msg string) { p.Error(p.file.Position(pos), msg) } - func (p *parser) errorExpected(pos token.Pos, msg string) { msg = "expected " + msg if pos == p.pos { @@ -379,7 +361,6 @@ func (p *parser) errorExpected(pos token.Pos, msg string) { p.error(pos, msg) } - func (p *parser) expect(tok token.Token) token.Pos { pos := p.pos if p.tok != tok { @@ -389,21 +370,18 @@ func (p *parser) expect(tok token.Token) token.Pos { return pos } - func (p *parser) expectSemi() { if p.tok != token.RPAREN && p.tok != token.RBRACE { p.expect(token.SEMICOLON) } } - func assert(cond bool, msg string) { if !cond { panic("go/parser internal error: " + msg) } } - // ---------------------------------------------------------------------------- // Identifiers @@ -419,7 +397,6 @@ func (p *parser) parseIdent() *ast.Ident { return &ast.Ident{pos, name, nil} } - func (p *parser) parseIdentList() (list []*ast.Ident) { if p.trace { defer un(trace(p, "IdentList")) @@ -434,7 +411,6 @@ func (p *parser) parseIdentList() (list []*ast.Ident) { return } - // ---------------------------------------------------------------------------- // Common productions @@ -444,16 +420,15 @@ func (p *parser) parseExprList(lhs bool) (list []ast.Expr) { defer un(trace(p, "ExpressionList")) } - list = append(list, p.parseExpr(lhs)) + list = append(list, p.checkExpr(p.parseExpr(lhs))) for p.tok == token.COMMA { p.next() - list = append(list, p.parseExpr(lhs)) + list = append(list, p.checkExpr(p.parseExpr(lhs))) } return } - func (p *parser) parseLhsList() []ast.Expr { list := p.parseExprList(true) switch p.tok { @@ -477,12 +452,10 @@ func (p *parser) parseLhsList() []ast.Expr { return list } - func (p *parser) parseRhsList() []ast.Expr { return p.parseExprList(false) } - // ---------------------------------------------------------------------------- // Types @@ -503,7 +476,6 @@ func (p *parser) parseType() ast.Expr { return typ } - // If the result is an identifier, it is not resolved. func (p *parser) parseTypeName() ast.Expr { if p.trace { @@ -524,7 +496,6 @@ func (p *parser) parseTypeName() ast.Expr { return ident } - func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr { if p.trace { defer un(trace(p, "ArrayType")) @@ -544,7 +515,6 @@ func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr { return &ast.ArrayType{lbrack, len, elt} } - func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident { idents := make([]*ast.Ident, len(list)) for i, x := range list { @@ -559,7 +529,6 @@ func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident { return idents } - func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field { if p.trace { defer un(trace(p, "FieldDecl")) @@ -596,12 +565,11 @@ func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field { p.expectSemi() // call before accessing p.linecomment field := &ast.Field{doc, idents, typ, tag, p.lineComment} - p.declare(field, scope, ast.Var, idents...) + p.declare(field, nil, scope, ast.Var, idents...) return field } - func (p *parser) parseStructType() *ast.StructType { if p.trace { defer un(trace(p, "StructType")) @@ -623,7 +591,6 @@ func (p *parser) parseStructType() *ast.StructType { return &ast.StructType{pos, &ast.FieldList{lbrace, list, rbrace}, false} } - func (p *parser) parsePointerType() *ast.StarExpr { if p.trace { defer un(trace(p, "PointerType")) @@ -635,7 +602,6 @@ func (p *parser) parsePointerType() *ast.StarExpr { return &ast.StarExpr{star, base} } - func (p *parser) tryVarType(isParam bool) ast.Expr { if isParam && p.tok == token.ELLIPSIS { pos := p.pos @@ -653,7 +619,6 @@ func (p *parser) tryVarType(isParam bool) ast.Expr { return p.tryIdentOrType(false) } - func (p *parser) parseVarType(isParam bool) ast.Expr { typ := p.tryVarType(isParam) if typ == nil { @@ -665,7 +630,6 @@ func (p *parser) parseVarType(isParam bool) ast.Expr { return typ } - func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) { if p.trace { defer un(trace(p, "VarList")) @@ -693,7 +657,6 @@ func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) { return } - func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params []*ast.Field) { if p.trace { defer un(trace(p, "ParameterList")) @@ -707,7 +670,7 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [ 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...) + p.declare(field, nil, scope, ast.Var, idents...) if p.tok == token.COMMA { p.next() } @@ -719,7 +682,7 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [ 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...) + p.declare(field, nil, scope, ast.Var, idents...) if p.tok != token.COMMA { break } @@ -738,7 +701,6 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [ return } - func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldList { if p.trace { defer un(trace(p, "Parameters")) @@ -754,7 +716,6 @@ func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldLi return &ast.FieldList{lparen, params, rparen} } - func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList { if p.trace { defer un(trace(p, "Result")) @@ -774,7 +735,6 @@ func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList { return nil } - func (p *parser) parseSignature(scope *ast.Scope) (params, results *ast.FieldList) { if p.trace { defer un(trace(p, "Signature")) @@ -786,7 +746,6 @@ func (p *parser) parseSignature(scope *ast.Scope) (params, results *ast.FieldLis return } - func (p *parser) parseFuncType() (*ast.FuncType, *ast.Scope) { if p.trace { defer un(trace(p, "FuncType")) @@ -799,7 +758,6 @@ func (p *parser) parseFuncType() (*ast.FuncType, *ast.Scope) { return &ast.FuncType{pos, params, results}, scope } - func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field { if p.trace { defer un(trace(p, "MethodSpec")) @@ -818,16 +776,16 @@ func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field { } else { // embedded interface typ = x + p.resolve(typ) } p.expectSemi() // call before accessing p.linecomment spec := &ast.Field{doc, idents, typ, nil, p.lineComment} - p.declare(spec, scope, ast.Fun, idents...) + p.declare(spec, nil, scope, ast.Fun, idents...) return spec } - func (p *parser) parseInterfaceType() *ast.InterfaceType { if p.trace { defer un(trace(p, "InterfaceType")) @@ -846,7 +804,6 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType { return &ast.InterfaceType{pos, &ast.FieldList{lbrace, list, rbrace}, false} } - func (p *parser) parseMapType() *ast.MapType { if p.trace { defer un(trace(p, "MapType")) @@ -861,7 +818,6 @@ func (p *parser) parseMapType() *ast.MapType { return &ast.MapType{pos, key, value} } - func (p *parser) parseChanType() *ast.ChanType { if p.trace { defer un(trace(p, "ChanType")) @@ -885,7 +841,6 @@ func (p *parser) parseChanType() *ast.ChanType { return &ast.ChanType{pos, dir, value} } - // If the result is an identifier, it is not resolved. func (p *parser) tryIdentOrType(ellipsisOk bool) ast.Expr { switch p.tok { @@ -918,7 +873,6 @@ func (p *parser) tryIdentOrType(ellipsisOk bool) ast.Expr { return nil } - func (p *parser) tryType() ast.Expr { typ := p.tryIdentOrType(false) if typ != nil { @@ -927,7 +881,6 @@ func (p *parser) tryType() ast.Expr { return typ } - // ---------------------------------------------------------------------------- // Blocks @@ -943,7 +896,6 @@ func (p *parser) parseStmtList() (list []ast.Stmt) { return } - func (p *parser) parseBody(scope *ast.Scope) *ast.BlockStmt { if p.trace { defer un(trace(p, "Body")) @@ -960,7 +912,6 @@ func (p *parser) parseBody(scope *ast.Scope) *ast.BlockStmt { return &ast.BlockStmt{lbrace, list, rbrace} } - func (p *parser) parseBlockStmt() *ast.BlockStmt { if p.trace { defer un(trace(p, "BlockStmt")) @@ -975,7 +926,6 @@ func (p *parser) parseBlockStmt() *ast.BlockStmt { return &ast.BlockStmt{lbrace, list, rbrace} } - // ---------------------------------------------------------------------------- // Expressions @@ -997,7 +947,6 @@ func (p *parser) parseFuncTypeOrLit() ast.Expr { return &ast.FuncLit{typ, body} } - // parseOperand may return an expression or a raw type (incl. array // types of the form [...]T. Callers must verify the result. // If lhs is set and the result is an identifier, it is not resolved. @@ -1024,7 +973,7 @@ func (p *parser) parseOperand(lhs bool) ast.Expr { lparen := p.pos p.next() p.exprLev++ - x := p.parseRhs() + x := p.parseRhsOrType() // types may be parenthesized: (some type) p.exprLev-- rparen := p.expect(token.RPAREN) return &ast.ParenExpr{lparen, x, rparen} @@ -1047,7 +996,6 @@ func (p *parser) parseOperand(lhs bool) ast.Expr { return &ast.BadExpr{pos, p.pos} } - func (p *parser) parseSelector(x ast.Expr) ast.Expr { if p.trace { defer un(trace(p, "Selector")) @@ -1058,7 +1006,6 @@ func (p *parser) parseSelector(x ast.Expr) ast.Expr { return &ast.SelectorExpr{x, sel} } - func (p *parser) parseTypeAssertion(x ast.Expr) ast.Expr { if p.trace { defer un(trace(p, "TypeAssertion")) @@ -1077,7 +1024,6 @@ func (p *parser) parseTypeAssertion(x ast.Expr) ast.Expr { return &ast.TypeAssertExpr{x, typ} } - func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr { if p.trace { defer un(trace(p, "IndexOrSlice")) @@ -1106,7 +1052,6 @@ func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr { return &ast.IndexExpr{x, lbrack, low, rbrack} } - func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr { if p.trace { defer un(trace(p, "CallOrConversion")) @@ -1117,7 +1062,7 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr { var list []ast.Expr var ellipsis token.Pos for p.tok != token.RPAREN && p.tok != token.EOF && !ellipsis.IsValid() { - list = append(list, p.parseRhs()) + list = append(list, p.parseRhsOrType()) // builtins may expect a type: make(some type, ...) if p.tok == token.ELLIPSIS { ellipsis = p.pos p.next() @@ -1133,7 +1078,6 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr { return &ast.CallExpr{fun, lparen, list, ellipsis, rparen} } - func (p *parser) parseElement(keyOk bool) ast.Expr { if p.trace { defer un(trace(p, "Element")) @@ -1143,7 +1087,7 @@ func (p *parser) parseElement(keyOk bool) ast.Expr { return p.parseLiteralValue(nil) } - x := p.parseExpr(keyOk) // don't resolve if map key + x := p.checkExpr(p.parseExpr(keyOk)) // don't resolve if map key if keyOk { if p.tok == token.COLON { colon := p.pos @@ -1156,7 +1100,6 @@ func (p *parser) parseElement(keyOk bool) ast.Expr { return x } - func (p *parser) parseElementList() (list []ast.Expr) { if p.trace { defer un(trace(p, "ElementList")) @@ -1173,7 +1116,6 @@ func (p *parser) parseElementList() (list []ast.Expr) { return } - func (p *parser) parseLiteralValue(typ ast.Expr) ast.Expr { if p.trace { defer un(trace(p, "LiteralValue")) @@ -1190,7 +1132,6 @@ func (p *parser) parseLiteralValue(typ ast.Expr) ast.Expr { return &ast.CompositeLit{typ, lbrace, elts, rbrace} } - // checkExpr checks that x is an expression (and not a type). func (p *parser) checkExpr(x ast.Expr) ast.Expr { switch t := unparen(x).(type) { @@ -1205,19 +1146,14 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr { case *ast.IndexExpr: case *ast.SliceExpr: case *ast.TypeAssertExpr: - if t.Type == nil { - // the form X.(type) is only allowed in type switch expressions - p.errorExpected(x.Pos(), "expression") - x = &ast.BadExpr{x.Pos(), x.End()} - } + // If t.Type == nil we have a type assertion of the form + // y.(type), which is only allowed in type switch expressions. + // It's hard to exclude those but for the case where we are in + // a type switch. Instead be lenient and test this in the type + // checker. case *ast.CallExpr: case *ast.StarExpr: case *ast.UnaryExpr: - if t.Op == token.RANGE { - // the range operator is only allowed at the top of a for statement - p.errorExpected(x.Pos(), "expression") - x = &ast.BadExpr{x.Pos(), x.End()} - } case *ast.BinaryExpr: default: // all other nodes are not proper expressions @@ -1227,7 +1163,6 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr { return x } - // isTypeName returns true iff x is a (qualified) TypeName. func isTypeName(x ast.Expr) bool { switch t := x.(type) { @@ -1242,7 +1177,6 @@ func isTypeName(x ast.Expr) bool { return true } - // isLiteralType returns true iff x is a legal composite literal type. func isLiteralType(x ast.Expr) bool { switch t := x.(type) { @@ -1260,7 +1194,6 @@ func isLiteralType(x ast.Expr) bool { return true } - // If x is of the form *T, deref returns T, otherwise it returns x. func deref(x ast.Expr) ast.Expr { if p, isPtr := x.(*ast.StarExpr); isPtr { @@ -1269,7 +1202,6 @@ func deref(x ast.Expr) ast.Expr { return x } - // If x is of the form (T), unparen returns unparen(T), otherwise it returns x. func unparen(x ast.Expr) ast.Expr { if p, isParen := x.(*ast.ParenExpr); isParen { @@ -1278,7 +1210,6 @@ func unparen(x ast.Expr) ast.Expr { return x } - // checkExprOrType checks that x is an expression or a type // (and not a raw type such as [...]T). // @@ -1287,11 +1218,6 @@ func (p *parser) checkExprOrType(x ast.Expr) ast.Expr { case *ast.ParenExpr: panic("unreachable") case *ast.UnaryExpr: - if t.Op == token.RANGE { - // the range operator is only allowed at the top of a for statement - p.errorExpected(x.Pos(), "expression") - x = &ast.BadExpr{x.Pos(), x.End()} - } case *ast.ArrayType: if len, isEllipsis := t.Len.(*ast.Ellipsis); isEllipsis { p.error(len.Pos(), "expected array length, found '...'") @@ -1303,7 +1229,6 @@ func (p *parser) checkExprOrType(x ast.Expr) ast.Expr { return x } - // If lhs is set and the result is an identifier, it is not resolved. func (p *parser) parsePrimaryExpr(lhs bool) ast.Expr { if p.trace { @@ -1358,7 +1283,6 @@ L: return x } - // If lhs is set and the result is an identifier, it is not resolved. func (p *parser) parseUnaryExpr(lhs bool) ast.Expr { if p.trace { @@ -1366,7 +1290,7 @@ func (p *parser) parseUnaryExpr(lhs bool) ast.Expr { } switch p.tok { - case token.ADD, token.SUB, token.NOT, token.XOR, token.AND, token.RANGE: + case token.ADD, token.SUB, token.NOT, token.XOR, token.AND: pos, op := p.pos, p.tok p.next() x := p.parseUnaryExpr(false) @@ -1396,7 +1320,6 @@ func (p *parser) parseUnaryExpr(lhs bool) ast.Expr { return p.parsePrimaryExpr(lhs) } - // If lhs is set and the result is an identifier, it is not resolved. func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr { if p.trace { @@ -1420,10 +1343,10 @@ func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr { return x } - // If lhs is set and the result is an identifier, it is not resolved. -// TODO(gri): parseExpr may return a type or even a raw type ([..]int) - -// should reject when a type/raw type is obviously not allowed +// The result may be a type or even a raw type ([...]int). Callers must +// check the result (using checkExpr or checkExprOrType), depending on +// context. func (p *parser) parseExpr(lhs bool) ast.Expr { if p.trace { defer un(trace(p, "Expression")) @@ -1432,16 +1355,29 @@ func (p *parser) parseExpr(lhs bool) ast.Expr { return p.parseBinaryExpr(lhs, token.LowestPrec+1) } - func (p *parser) parseRhs() ast.Expr { - return p.parseExpr(false) + return p.checkExpr(p.parseExpr(false)) } +func (p *parser) parseRhsOrType() ast.Expr { + return p.checkExprOrType(p.parseExpr(false)) +} // ---------------------------------------------------------------------------- // Statements -func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt { +// Parsing modes for parseSimpleStmt. +const ( + basic = iota + labelOk + rangeOk +) + +// parseSimpleStmt returns true as 2nd result if it parsed the assignment +// of a range clause (with mode == rangeOk). The returned statement is an +// assignment with a right-hand side that is a single unary expression of +// the form "range x". No guarantees are given for the left-hand side. +func (p *parser) parseSimpleStmt(mode int) (ast.Stmt, bool) { if p.trace { defer un(trace(p, "SimpleStmt")) } @@ -1454,11 +1390,20 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt { token.SUB_ASSIGN, token.MUL_ASSIGN, token.QUO_ASSIGN, token.REM_ASSIGN, token.AND_ASSIGN, token.OR_ASSIGN, token.XOR_ASSIGN, token.SHL_ASSIGN, token.SHR_ASSIGN, token.AND_NOT_ASSIGN: - // assignment statement + // assignment statement, possibly part of a range clause pos, tok := p.pos, p.tok p.next() - y := p.parseRhsList() - return &ast.AssignStmt{x, pos, tok, y} + var y []ast.Expr + isRange := false + if mode == rangeOk && p.tok == token.RANGE && (tok == token.DEFINE || tok == token.ASSIGN) { + pos := p.pos + p.next() + y = []ast.Expr{&ast.UnaryExpr{pos, token.RANGE, p.parseRhs()}} + isRange = true + } else { + y = p.parseRhsList() + } + return &ast.AssignStmt{x, pos, tok, y}, isRange } if len(x) > 1 { @@ -1471,38 +1416,43 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt { // labeled statement colon := p.pos p.next() - if label, isIdent := x[0].(*ast.Ident); labelOk && isIdent { + if label, isIdent := x[0].(*ast.Ident); mode == labelOk && isIdent { // 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.declare(stmt, nil, p.labelScope, ast.Lbl, label) + return stmt, false } - p.error(x[0].Pos(), "illegal label declaration") - return &ast.BadStmt{x[0].Pos(), colon + 1} + // The label declaration typically starts at x[0].Pos(), but the label + // declaration may be erroneous due to a token after that position (and + // before the ':'). If SpuriousErrors is not set, the (only) error re- + // ported for the line is the illegal label error instead of the token + // before the ':' that caused the problem. Thus, use the (latest) colon + // position for error reporting. + p.error(colon, "illegal label declaration") + return &ast.BadStmt{x[0].Pos(), colon + 1}, false case token.ARROW: // send statement arrow := p.pos p.next() // consume "<-" y := p.parseRhs() - return &ast.SendStmt{x[0], arrow, y} + return &ast.SendStmt{x[0], arrow, y}, false case token.INC, token.DEC: // increment or decrement s := &ast.IncDecStmt{x[0], p.pos, p.tok} p.next() // consume "++" or "--" - return s + return s, false } // expression - return &ast.ExprStmt{x[0]} + return &ast.ExprStmt{x[0]}, false } - func (p *parser) parseCallExpr() *ast.CallExpr { - x := p.parseRhs() + x := p.parseRhsOrType() // could be a conversion: (some type)(x) if call, isCall := x.(*ast.CallExpr); isCall { return call } @@ -1510,7 +1460,6 @@ func (p *parser) parseCallExpr() *ast.CallExpr { return nil } - func (p *parser) parseGoStmt() ast.Stmt { if p.trace { defer un(trace(p, "GoStmt")) @@ -1526,7 +1475,6 @@ func (p *parser) parseGoStmt() ast.Stmt { return &ast.GoStmt{pos, call} } - func (p *parser) parseDeferStmt() ast.Stmt { if p.trace { defer un(trace(p, "DeferStmt")) @@ -1542,7 +1490,6 @@ func (p *parser) parseDeferStmt() ast.Stmt { return &ast.DeferStmt{pos, call} } - func (p *parser) parseReturnStmt() *ast.ReturnStmt { if p.trace { defer un(trace(p, "ReturnStmt")) @@ -1559,7 +1506,6 @@ func (p *parser) parseReturnStmt() *ast.ReturnStmt { return &ast.ReturnStmt{pos, x} } - func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt { if p.trace { defer un(trace(p, "BranchStmt")) @@ -1578,7 +1524,6 @@ func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt { return &ast.BranchStmt{pos, tok, label} } - func (p *parser) makeExpr(s ast.Stmt) ast.Expr { if s == nil { return nil @@ -1590,7 +1535,6 @@ func (p *parser) makeExpr(s ast.Stmt) ast.Expr { return &ast.BadExpr{s.Pos(), s.End()} } - func (p *parser) parseIfStmt() *ast.IfStmt { if p.trace { defer un(trace(p, "IfStmt")) @@ -1609,7 +1553,7 @@ func (p *parser) parseIfStmt() *ast.IfStmt { p.next() x = p.parseRhs() } else { - s = p.parseSimpleStmt(false) + s, _ = p.parseSimpleStmt(basic) if p.tok == token.SEMICOLON { p.next() x = p.parseRhs() @@ -1633,7 +1577,6 @@ func (p *parser) parseIfStmt() *ast.IfStmt { return &ast.IfStmt{pos, s, x, body, else_} } - func (p *parser) parseTypeList() (list []ast.Expr) { if p.trace { defer un(trace(p, "TypeList")) @@ -1648,7 +1591,6 @@ func (p *parser) parseTypeList() (list []ast.Expr) { return } - func (p *parser) parseCaseClause(exprSwitch bool) *ast.CaseClause { if p.trace { defer un(trace(p, "CaseClause")) @@ -1675,7 +1617,6 @@ func (p *parser) parseCaseClause(exprSwitch bool) *ast.CaseClause { return &ast.CaseClause{pos, list, colon, body} } - func isExprSwitch(s ast.Stmt) bool { if s == nil { return true @@ -1689,7 +1630,6 @@ func isExprSwitch(s ast.Stmt) bool { return false } - func (p *parser) parseSwitchStmt() ast.Stmt { if p.trace { defer un(trace(p, "SwitchStmt")) @@ -1704,14 +1644,14 @@ func (p *parser) parseSwitchStmt() ast.Stmt { prevLev := p.exprLev p.exprLev = -1 if p.tok != token.SEMICOLON { - s2 = p.parseSimpleStmt(false) + s2, _ = p.parseSimpleStmt(basic) } if p.tok == token.SEMICOLON { p.next() s1 = s2 s2 = nil if p.tok != token.LBRACE { - s2 = p.parseSimpleStmt(false) + s2, _ = p.parseSimpleStmt(basic) } } p.exprLev = prevLev @@ -1735,7 +1675,6 @@ func (p *parser) parseSwitchStmt() ast.Stmt { return &ast.TypeSwitchStmt{pos, s1, s2, body} } - func (p *parser) parseCommClause() *ast.CommClause { if p.trace { defer un(trace(p, "CommClause")) @@ -1797,7 +1736,6 @@ func (p *parser) parseCommClause() *ast.CommClause { return &ast.CommClause{pos, comm, colon, body} } - func (p *parser) parseSelectStmt() *ast.SelectStmt { if p.trace { defer un(trace(p, "SelectStmt")) @@ -1816,7 +1754,6 @@ func (p *parser) parseSelectStmt() *ast.SelectStmt { return &ast.SelectStmt{pos, body} } - func (p *parser) parseForStmt() ast.Stmt { if p.trace { defer un(trace(p, "ForStmt")) @@ -1827,22 +1764,23 @@ func (p *parser) parseForStmt() ast.Stmt { defer p.closeScope() var s1, s2, s3 ast.Stmt + var isRange bool if p.tok != token.LBRACE { prevLev := p.exprLev p.exprLev = -1 if p.tok != token.SEMICOLON { - s2 = p.parseSimpleStmt(false) + s2, isRange = p.parseSimpleStmt(rangeOk) } - if p.tok == token.SEMICOLON { + if !isRange && p.tok == token.SEMICOLON { p.next() s1 = s2 s2 = nil if p.tok != token.SEMICOLON { - s2 = p.parseSimpleStmt(false) + s2, _ = p.parseSimpleStmt(basic) } p.expectSemi() if p.tok != token.LBRACE { - s3 = p.parseSimpleStmt(false) + s3, _ = p.parseSimpleStmt(basic) } } p.exprLev = prevLev @@ -1851,12 +1789,8 @@ func (p *parser) parseForStmt() ast.Stmt { body := p.parseBlockStmt() p.expectSemi() - if as, isAssign := s2.(*ast.AssignStmt); isAssign { - // possibly a for statement with a range clause; check assignment operator - if as.Tok != token.ASSIGN && as.Tok != token.DEFINE { - p.errorExpected(as.TokPos, "'=' or ':='") - return &ast.BadStmt{pos, body.End()} - } + if isRange { + as := s2.(*ast.AssignStmt) // check lhs var key, value ast.Expr switch len(as.Lhs) { @@ -1868,25 +1802,16 @@ func (p *parser) parseForStmt() ast.Stmt { p.errorExpected(as.Lhs[0].Pos(), "1 or 2 expressions") return &ast.BadStmt{pos, body.End()} } - // check rhs - if len(as.Rhs) != 1 { - p.errorExpected(as.Rhs[0].Pos(), "1 expression") - return &ast.BadStmt{pos, body.End()} - } - if rhs, isUnary := as.Rhs[0].(*ast.UnaryExpr); isUnary && rhs.Op == token.RANGE { - // 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} - } - p.errorExpected(s2.Pos(), "range clause") - return &ast.BadStmt{pos, body.End()} + // parseSimpleStmt returned a right-hand side that + // is a single unary expression of the form "range x" + x := as.Rhs[0].(*ast.UnaryExpr).X + return &ast.RangeStmt{pos, key, value, as.TokPos, as.Tok, x, body} } // regular for statement return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body} } - func (p *parser) parseStmt() (s ast.Stmt) { if p.trace { defer un(trace(p, "Statement")) @@ -1900,7 +1825,7 @@ func (p *parser) parseStmt() (s ast.Stmt) { token.IDENT, token.INT, token.FLOAT, token.CHAR, token.STRING, token.FUNC, token.LPAREN, // operand token.LBRACK, token.STRUCT, // composite type token.MUL, token.AND, token.ARROW, token.ADD, token.SUB, token.XOR: // unary operators - s = p.parseSimpleStmt(true) + s, _ = p.parseSimpleStmt(labelOk) // because of the required look-ahead, labeled statements are // parsed by parseSimpleStmt - don't expect a semicolon after // them @@ -1943,13 +1868,11 @@ func (p *parser) parseStmt() (s ast.Stmt) { return } - // ---------------------------------------------------------------------------- // Declarations type parseSpecFunction func(p *parser, doc *ast.CommentGroup, iota int) ast.Spec - func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec { if p.trace { defer un(trace(p, "ImportSpec")) @@ -1980,7 +1903,6 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec { return spec } - func parseConstSpec(p *parser, doc *ast.CommentGroup, iota int) ast.Spec { if p.trace { defer un(trace(p, "ConstSpec")) @@ -2000,12 +1922,11 @@ func parseConstSpec(p *parser, doc *ast.CommentGroup, iota int) ast.Spec { // 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...) + p.declare(spec, iota, p.topScope, ast.Con, idents...) return spec } - func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec { if p.trace { defer un(trace(p, "TypeSpec")) @@ -2018,7 +1939,7 @@ func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec { // containing block. // (Global identifiers are resolved in a separate phase after parsing.) spec := &ast.TypeSpec{doc, ident, nil, nil} - p.declare(spec, p.topScope, ast.Typ, ident) + p.declare(spec, nil, p.topScope, ast.Typ, ident) spec.Type = p.parseType() p.expectSemi() // call before accessing p.linecomment @@ -2027,7 +1948,6 @@ func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec { return spec } - func parseVarSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec { if p.trace { defer un(trace(p, "VarSpec")) @@ -2047,12 +1967,11 @@ func parseVarSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec { // 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...) + p.declare(spec, nil, p.topScope, ast.Var, idents...) return spec } - func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.GenDecl { if p.trace { defer un(trace(p, "GenDecl("+keyword.String()+")")) @@ -2077,7 +1996,6 @@ func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.Gen return &ast.GenDecl{doc, pos, keyword, lparen, list, rparen} } - func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList { if p.trace { defer un(trace(p, "Receiver")) @@ -2105,7 +2023,6 @@ func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList { return par } - func (p *parser) parseFuncDecl() *ast.FuncDecl { if p.trace { defer un(trace(p, "FunctionDecl")) @@ -2139,14 +2056,13 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl { // 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) + p.declare(decl, nil, p.pkgScope, ast.Fun, ident) } } return decl } - func (p *parser) parseDecl() ast.Decl { if p.trace { defer un(trace(p, "Declaration")) @@ -2177,7 +2093,6 @@ func (p *parser) parseDecl() ast.Decl { return p.parseGenDecl(p.tok, f) } - func (p *parser) parseDeclList() (list []ast.Decl) { if p.trace { defer un(trace(p, "DeclList")) @@ -2190,7 +2105,6 @@ func (p *parser) parseDeclList() (list []ast.Decl) { return } - // ---------------------------------------------------------------------------- // Source files @@ -2243,6 +2157,5 @@ func (p *parser) parseFile() *ast.File { } } - // TODO(gri): store p.imports in AST return &ast.File{doc, pos, ident, decls, p.pkgScope, p.imports, p.unresolved[0:i], p.comments} } diff --git a/libgo/go/go/parser/parser_test.go b/libgo/go/go/parser/parser_test.go index 5b52f51..39a78e5 100644 --- a/libgo/go/go/parser/parser_test.go +++ b/libgo/go/go/parser/parser_test.go @@ -10,7 +10,6 @@ import ( "testing" ) - var fset = token.NewFileSet() var illegalInputs = []interface{}{ @@ -22,9 +21,26 @@ var illegalInputs = []interface{}{ `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 */`, + `package p; func f() { if _ = range x; true {} };`, + `package p; func f() { switch _ = range x; true {} };`, + `package p; func f() { for _ = range x ; ; {} };`, + `package p; func f() { for ; ; _ = range x {} };`, + `package p; func f() { for ; _ = range x ; {} };`, + `package p; var a = [1]int; /* illegal expression */`, + `package p; var a = [...]int; /* illegal expression */`, + `package p; var a = struct{} /* illegal expression */`, + `package p; var a = func(); /* illegal expression */`, + `package p; var a = interface{} /* illegal expression */`, + `package p; var a = []int /* illegal expression */`, + `package p; var a = map[int]int /* illegal expression */`, + `package p; var a = chan int; /* illegal expression */`, + `package p; var a = []int{[]int}; /* illegal expression */`, + `package p; var a = ([]int); /* illegal expression */`, + `package p; var a = a[[]int:[]int]; /* illegal expression */`, + `package p; var a = <- chan int; /* illegal expression */`, + `package p; func f() { select { case _ <- chan int: } };`, } - func TestParseIllegalInputs(t *testing.T) { for _, src := range illegalInputs { _, err := ParseFile(fset, "", src, 0) @@ -34,7 +50,6 @@ func TestParseIllegalInputs(t *testing.T) { } } - var validPrograms = []interface{}{ "package p\n", `package p;`, @@ -54,9 +69,9 @@ var validPrograms = []interface{}{ `package p; func f() { select { case x := (<-c): } };`, `package p; func f() { if ; true {} };`, `package p; func f() { switch ; {} };`, + `package p; func f() { for _ = range "foo" + "bar" {} };`, } - func TestParseValidPrograms(t *testing.T) { for _, src := range validPrograms { _, err := ParseFile(fset, "", src, 0) @@ -66,13 +81,11 @@ func TestParseValidPrograms(t *testing.T) { } } - var validFiles = []string{ "parser.go", "parser_test.go", } - func TestParse3(t *testing.T) { for _, filename := range validFiles { _, err := ParseFile(fset, filename, nil, DeclarationErrors) @@ -82,7 +95,6 @@ func TestParse3(t *testing.T) { } } - func nameFilter(filename string) bool { switch filename { case "parser.go": @@ -94,10 +106,8 @@ func nameFilter(filename string) bool { return true } - func dirFilter(f *os.FileInfo) bool { return nameFilter(f.Name) } - func TestParse4(t *testing.T) { path := "." pkgs, err := ParseDir(fset, path, dirFilter, 0) diff --git a/libgo/go/go/printer/nodes.go b/libgo/go/go/printer/nodes.go index 86c3279..9cd975e 100644 --- a/libgo/go/go/printer/nodes.go +++ b/libgo/go/go/printer/nodes.go @@ -14,7 +14,6 @@ import ( "go/token" ) - // Other formatting issues: // - better comment formatting for /*-style comments at the end of a line (e.g. a declaration) // when the comment spans multiple lines; if such a comment is just two lines, formatting is @@ -23,7 +22,6 @@ import ( // - should use blank instead of tab to separate one-line function bodies from // the function header unless there is a group of consecutive one-liners - // ---------------------------------------------------------------------------- // Common AST nodes. @@ -33,7 +31,7 @@ import ( // line break was printed; returns false otherwise. // // TODO(gri): linebreak may add too many lines if the next statement at "line" -// is preceeded by comments because the computation of n assumes +// is preceded by comments because the computation of n assumes // the current position before the comment and the target position // after the comment. Thus, after interspersing such comments, the // space taken up by them is not considered to reduce the number of @@ -56,7 +54,6 @@ func (p *printer) linebreak(line, min int, ws whiteSpace, newSection bool) (prin return } - // setComment sets g as the next comment if g != nil and if node comments // are enabled - this mode is used when printing source code fragments such // as exports only. It assumes that there are no other pending comments to @@ -78,7 +75,6 @@ func (p *printer) setComment(g *ast.CommentGroup) { p.cindex = 0 } - type exprListMode uint const ( @@ -90,7 +86,6 @@ const ( periodSep // elements are separated by periods ) - // Sets multiLine to true if the identifier list spans multiple lines. // If indent is set, a multi-line identifier list is indented after the // first linebreak encountered. @@ -107,7 +102,6 @@ func (p *printer) identList(list []*ast.Ident, indent bool, multiLine *bool) { p.exprList(token.NoPos, xlist, 1, mode, multiLine, token.NoPos) } - // 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 @@ -215,12 +209,13 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp } if i > 0 { - if mode&commaSep != 0 { + switch { + case mode&commaSep != 0: p.print(token.COMMA) - } - if mode&periodSep != 0 { + case mode&periodSep != 0: p.print(token.PERIOD) } + needsBlank := mode&periodSep == 0 // period-separated list elements don't need a blank if prevLine < line && prevLine > 0 && line > 0 { // lines are broken using newlines so comments remain aligned // unless forceFF is set or there are multiple expressions on @@ -229,11 +224,12 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp ws = ignore *multiLine = true prevBreak = i + needsBlank = false // we got a line break instead } - } else if mode&periodSep == 0 { + } + if needsBlank { p.print(blank) } - // period-separated list elements don't need a blank } if isPair && size > 0 && len(list) > 1 { @@ -269,7 +265,6 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp } } - // Sets multiLine to true if the the parameter list spans multiple lines. func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) { p.print(fields.Opening, token.LPAREN) @@ -300,7 +295,6 @@ func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) { p.print(fields.Closing, token.RPAREN) } - // Sets multiLine to true if the signature spans multiple lines. func (p *printer) signature(params, result *ast.FieldList, multiLine *bool) { p.parameters(params, multiLine) @@ -316,7 +310,6 @@ func (p *printer) signature(params, result *ast.FieldList, multiLine *bool) { } } - func identListSize(list []*ast.Ident, maxSize int) (size int) { for i, x := range list { if i > 0 { @@ -330,7 +323,6 @@ func identListSize(list []*ast.Ident, maxSize int) (size int) { return } - func (p *printer) isOneLineFieldList(list []*ast.Field) bool { if len(list) != 1 { return false // allow only one field @@ -349,18 +341,11 @@ func (p *printer) isOneLineFieldList(list []*ast.Field) bool { return namesSize+typeSize <= maxSize } - func (p *printer) setLineComment(text string) { p.setComment(&ast.CommentGroup{[]*ast.Comment{&ast.Comment{token.NoPos, text}}}) } - func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) { - p.nesting++ - defer func() { - p.nesting-- - }() - lbrace := fields.Opening list := fields.List rbrace := fields.Closing @@ -438,8 +423,8 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) if len(list) > 0 { p.print(formfeed) } - p.flush(p.fset.Position(rbrace), token.RBRACE) // make sure we don't loose the last line comment - p.setLineComment("// contains unexported fields") + p.flush(p.fset.Position(rbrace), token.RBRACE) // make sure we don't lose the last line comment + p.setLineComment("// contains filtered or unexported fields") } } else { // interface @@ -465,15 +450,14 @@ func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) if len(list) > 0 { p.print(formfeed) } - p.flush(p.fset.Position(rbrace), token.RBRACE) // make sure we don't loose the last line comment - p.setLineComment("// contains unexported methods") + p.flush(p.fset.Position(rbrace), token.RBRACE) // make sure we don't lose the last line comment + p.setLineComment("// contains filtered or unexported methods") } } p.print(unindent, formfeed, rbrace, token.RBRACE) } - // ---------------------------------------------------------------------------- // Expressions @@ -532,7 +516,6 @@ func walkBinary(e *ast.BinaryExpr) (has4, has5 bool, maxProblem int) { return } - func cutoff(e *ast.BinaryExpr, depth int) int { has4, has5, maxProblem := walkBinary(e) if maxProblem > 0 { @@ -550,7 +533,6 @@ func cutoff(e *ast.BinaryExpr, depth int) int { return 4 } - func diffPrec(expr ast.Expr, prec int) int { x, ok := expr.(*ast.BinaryExpr) if !ok || prec != x.Op.Precedence() { @@ -559,7 +541,6 @@ func diffPrec(expr ast.Expr, prec int) int { return 0 } - func reduceDepth(depth int) int { depth-- if depth < 1 { @@ -568,7 +549,6 @@ func reduceDepth(depth int) int { return depth } - // Format the binary expression: decide the cutoff and then format. // Let's call depth == 1 Normal mode, and depth > 1 Compact mode. // (Algorithm suggestion by Russ Cox.) @@ -646,13 +626,11 @@ func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiL } } - func isBinary(expr ast.Expr) bool { _, ok := expr.(*ast.BinaryExpr) return ok } - // If the expression contains one or more selector expressions, splits it into // two expressions at the rightmost period. Writes entire expr to suffix when // selector isn't found. Rewrites AST nodes for calls, index expressions and @@ -692,7 +670,6 @@ func splitSelector(expr ast.Expr) (body, suffix ast.Expr) { return } - // Convert an expression into an expression list split at the periods of // selector expressions. func selectorExprList(expr ast.Expr) (list []ast.Expr) { @@ -711,7 +688,6 @@ func selectorExprList(expr ast.Expr) (list []ast.Expr) { return } - // Sets multiLine to true if the expression spans multiple lines. func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) { p.print(expr.Pos()) @@ -898,19 +874,16 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, multiLine *bool) { return } - func (p *printer) expr0(x ast.Expr, depth int, multiLine *bool) { 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, multiLine) } - // ---------------------------------------------------------------------------- // Statements @@ -935,7 +908,6 @@ func (p *printer) stmtList(list []ast.Stmt, _indent int, nextIsRBrace bool) { } } - // block prints an *ast.BlockStmt; it always spans at least two lines. func (p *printer) block(s *ast.BlockStmt, indent int) { p.print(s.Pos(), token.LBRACE) @@ -944,7 +916,6 @@ func (p *printer) block(s *ast.BlockStmt, indent int) { p.print(s.Rbrace, token.RBRACE) } - func isTypeName(x ast.Expr) bool { switch t := x.(type) { case *ast.Ident: @@ -955,7 +926,6 @@ func isTypeName(x ast.Expr) bool { return false } - func stripParens(x ast.Expr) ast.Expr { if px, strip := x.(*ast.ParenExpr); strip { // parentheses must not be stripped if there are any @@ -982,7 +952,6 @@ func stripParens(x ast.Expr) ast.Expr { return x } - func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, post ast.Stmt) { p.print(blank) needsBlank := false @@ -1017,7 +986,6 @@ func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, po } } - // Sets multiLine to true if the statements spans multiple lines. func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) { p.print(stmt.Pos()) @@ -1156,8 +1124,14 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) { case *ast.SelectStmt: p.print(token.SELECT, blank) - p.block(s.Body, 0) - *multiLine = true + body := s.Body + if len(body.List) == 0 && !p.commentBefore(p.fset.Position(body.Rbrace)) { + // print empty select statement w/o comments on one line + p.print(body.Lbrace, token.LBRACE, body.Rbrace, token.RBRACE) + } else { + p.block(body, 0) + *multiLine = true + } case *ast.ForStmt: p.print(token.FOR) @@ -1185,10 +1159,98 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) { return } - // ---------------------------------------------------------------------------- // Declarations +// The keepTypeColumn function determines if the type column of a series of +// consecutive const or var declarations must be kept, or if initialization +// values (V) can be placed in the type column (T) instead. The i'th entry +// in the result slice is true if the type column in spec[i] must be kept. +// +// For example, the declaration: +// +// const ( +// foobar int = 42 // comment +// x = 7 // comment +// foo +// bar = 991 +// ) +// +// leads to the type/values matrix below. A run of value columns (V) can +// be moved into the type column if there is no type for any of the values +// in that column (we only move entire columns so that they align properly). +// +// matrix formatted result +// matrix +// T V -> T V -> true there is a T and so the type +// - V - V true column must be kept +// - - - - false +// - V V - false V is moved into T column +// +func keepTypeColumn(specs []ast.Spec) []bool { + m := make([]bool, len(specs)) + + populate := func(i, j int, keepType bool) { + if keepType { + for ; i < j; i++ { + m[i] = true + } + } + } + + i0 := -1 // if i0 >= 0 we are in a run and i0 is the start of the run + var keepType bool + for i, s := range specs { + t := s.(*ast.ValueSpec) + if t.Values != nil { + if i0 < 0 { + // start of a run of ValueSpecs with non-nil Values + i0 = i + keepType = false + } + } else { + if i0 >= 0 { + // end of a run + populate(i0, i, keepType) + i0 = -1 + } + } + if t.Type != nil { + keepType = true + } + } + if i0 >= 0 { + // end of a run + populate(i0, len(specs), keepType) + } + + return m +} + +func (p *printer) valueSpec(s *ast.ValueSpec, keepType, doIndent bool, multiLine *bool) { + p.setComment(s.Doc) + p.identList(s.Names, doIndent, multiLine) // always present + extraTabs := 3 + if s.Type != nil || keepType { + p.print(vtab) + extraTabs-- + } + if s.Type != nil { + p.expr(s.Type, multiLine) + } + if s.Values != nil { + p.print(vtab, token.ASSIGN) + p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiLine, token.NoPos) + extraTabs-- + } + if s.Comment != nil { + for ; extraTabs > 0; extraTabs-- { + p.print(vtab) + } + p.setComment(s.Comment) + } +} + // The parameter n is the number of specs in the group. If doIndent is set, // multi-line identifier lists in the spec are indented when the first // linebreak is encountered. @@ -1206,38 +1268,20 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) { p.setComment(s.Comment) case *ast.ValueSpec: + if n != 1 { + p.internalError("expected n = 1; got", n) + } p.setComment(s.Doc) p.identList(s.Names, doIndent, multiLine) // always present - if n == 1 { - if s.Type != nil { - p.print(blank) - p.expr(s.Type, multiLine) - } - if s.Values != nil { - p.print(blank, token.ASSIGN) - p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiLine, token.NoPos) - } - p.setComment(s.Comment) - - } else { - extraTabs := 3 - if s.Type != nil { - p.print(vtab) - p.expr(s.Type, multiLine) - extraTabs-- - } - if s.Values != nil { - p.print(vtab, token.ASSIGN) - p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiLine, token.NoPos) - extraTabs-- - } - if s.Comment != nil { - for ; extraTabs > 0; extraTabs-- { - p.print(vtab) - } - p.setComment(s.Comment) - } + if s.Type != nil { + p.print(blank) + p.expr(s.Type, multiLine) } + if s.Values != nil { + p.print(blank, token.ASSIGN) + p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiLine, token.NoPos) + } + p.setComment(s.Comment) case *ast.TypeSpec: p.setComment(s.Doc) @@ -1255,7 +1299,6 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) { } } - // Sets multiLine to true if the declaration spans multiple lines. func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) { p.setComment(d.Doc) @@ -1264,15 +1307,29 @@ func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) { if d.Lparen.IsValid() { // group of parenthesized declarations p.print(d.Lparen, token.LPAREN) - if len(d.Specs) > 0 { + if n := len(d.Specs); n > 0 { p.print(indent, formfeed) - var ml bool - for i, s := range d.Specs { - if i > 0 { - p.linebreak(p.fset.Position(s.Pos()).Line, 1, ignore, ml) + if n > 1 && (d.Tok == token.CONST || d.Tok == token.VAR) { + // two or more grouped const/var declarations: + // determine if the type column must be kept + keepType := keepTypeColumn(d.Specs) + var ml bool + for i, s := range d.Specs { + if i > 0 { + p.linebreak(p.fset.Position(s.Pos()).Line, 1, ignore, ml) + } + ml = false + p.valueSpec(s.(*ast.ValueSpec), keepType[i], false, &ml) + } + } else { + var ml bool + for i, s := range d.Specs { + if i > 0 { + p.linebreak(p.fset.Position(s.Pos()).Line, 1, ignore, ml) + } + ml = false + p.spec(s, n, false, &ml) } - ml = false - p.spec(s, len(d.Specs), false, &ml) } p.print(unindent, formfeed) *multiLine = true @@ -1285,7 +1342,6 @@ func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) { } } - // nodeSize determines the size of n in chars after formatting. // The result is <= maxSize if the node fits on one line with at // most maxSize chars and the formatted output doesn't contain @@ -1303,7 +1359,7 @@ func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) { size = maxSize + 1 // assume n doesn't fit p.nodeSizes[n] = size - // nodeSize computation must be indendent of particular + // nodeSize computation must be independent of particular // style so that we always get the same decision; print // in RawFormat cfg := Config{Mode: RawFormat} @@ -1323,7 +1379,6 @@ func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) { return } - func (p *printer) isOneLineFunc(b *ast.BlockStmt, headerSize int) bool { pos1 := b.Pos() pos2 := b.Rbrace @@ -1347,18 +1402,12 @@ func (p *printer) isOneLineFunc(b *ast.BlockStmt, headerSize int) bool { return headerSize+bodySize <= maxSize } - // Sets multiLine to true if the function body spans multiple lines. func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLine *bool) { if b == nil { return } - p.nesting++ - defer func() { - p.nesting-- - }() - if p.isOneLineFunc(b, headerSize) { sep := vtab if isLit { @@ -1384,7 +1433,6 @@ func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLi *multiLine = true } - // distance returns the column difference between from and to if both // are on the same line; if they are on different lines (or unknown) // the result is infinity. @@ -1396,7 +1444,6 @@ func (p *printer) distance(from0 token.Pos, to token.Position) int { return infinity } - // Sets multiLine to true if the declaration spans multiple lines. func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) { p.setComment(d.Doc) @@ -1410,7 +1457,6 @@ func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) { p.funcBody(d.Body, p.distance(d.Pos(), p.pos), false, multiLine) } - // Sets multiLine to true if the declaration spans multiple lines. func (p *printer) decl(decl ast.Decl, multiLine *bool) { switch d := decl.(type) { @@ -1425,7 +1471,6 @@ func (p *printer) decl(decl ast.Decl, multiLine *bool) { } } - // ---------------------------------------------------------------------------- // Files @@ -1440,7 +1485,6 @@ func declToken(decl ast.Decl) (tok token.Token) { return } - func (p *printer) file(src *ast.File) { p.setComment(src.Doc) p.print(src.Pos(), token.PACKAGE, blank) diff --git a/libgo/go/go/printer/performance_test.go b/libgo/go/go/printer/performance_test.go index 31de0b7..84fb280 100644 --- a/libgo/go/go/printer/performance_test.go +++ b/libgo/go/go/printer/performance_test.go @@ -17,17 +17,14 @@ import ( "testing" ) - var testfile *ast.File - func testprint(out io.Writer, file *ast.File) { if _, err := (&Config{TabIndent | UseSpaces, 8}).Fprint(out, fset, file); err != nil { log.Fatalf("print error: %s", err) } } - // cannot initialize in init because (printer) Fprint launches goroutines. func initialize() { const filename = "testdata/parser.go" @@ -51,7 +48,6 @@ func initialize() { testfile = file } - func BenchmarkPrint(b *testing.B) { if testfile == nil { initialize() diff --git a/libgo/go/go/printer/printer.go b/libgo/go/go/printer/printer.go index 01ebf78..871fefa 100644 --- a/libgo/go/go/printer/printer.go +++ b/libgo/go/go/printer/printer.go @@ -17,7 +17,6 @@ import ( "tabwriter" ) - const debug = false // enable for debugging @@ -33,7 +32,6 @@ const ( unindent = whiteSpace('<') ) - var ( esc = []byte{tabwriter.Escape} htab = []byte{'\t'} @@ -42,16 +40,13 @@ var ( formfeeds = []byte("\f\f\f\f\f\f\f\f") // more than the max determined by nlines ) - // Special positions var noPos token.Position // use noPos when a position is needed but not known var infinity = 1 << 30 - // Use ignoreMultiLine if the multiLine information is not important. var ignoreMultiLine = new(bool) - // A pmode value represents the current printer mode. type pmode int @@ -60,7 +55,6 @@ const ( noExtraLinebreak ) - type printer struct { // Configuration (does not change after initialization) output io.Writer @@ -69,7 +63,6 @@ type printer struct { errors chan os.Error // Current state - nesting int // nesting level (0: top-level (package scope), >0: functions/decls.) written int // number of bytes written indent int // current indentation mode pmode // current printer mode @@ -98,7 +91,6 @@ type printer struct { nodeSizes map[ast.Node]int } - func (p *printer) init(output io.Writer, cfg *Config, fset *token.FileSet, nodeSizes map[ast.Node]int) { p.output = output p.Config = *cfg @@ -108,7 +100,6 @@ func (p *printer) init(output io.Writer, cfg *Config, fset *token.FileSet, nodeS p.nodeSizes = nodeSizes } - func (p *printer) internalError(msg ...interface{}) { if debug { fmt.Print(p.pos.String() + ": ") @@ -117,7 +108,6 @@ func (p *printer) internalError(msg ...interface{}) { } } - // escape escapes string s by bracketing it with tabwriter.Escape. // Escaped strings pass through tabwriter unchanged. (Note that // valid Go programs cannot contain tabwriter.Escape bytes since @@ -131,26 +121,20 @@ func (p *printer) escape(s string) string { return p.litbuf.String() } - // nlines returns the adjusted number of linebreaks given the desired number -// of breaks n such that min <= result <= max where max depends on the current -// nesting level. +// of breaks n such that min <= result <= max. // func (p *printer) nlines(n, min int) int { - if n < min { + const max = 2 // max. number of newlines + switch { + case n < min: return min - } - max := 3 // max. number of newlines at the top level (p.nesting == 0) - if p.nesting > 0 { - max = 2 // max. number of newlines everywhere else - } - if n > max { + case n > max: return max } return n } - // write0 writes raw (uninterpreted) data to p.output and handles errors. // write0 does not indent after newlines, and does not HTML-escape or update p.pos. // @@ -165,7 +149,6 @@ func (p *printer) write0(data []byte) { } } - // write interprets data and writes it to p.output. It inserts indentation // after a line break unless in a tabwriter escape sequence. // It updates p.pos as a side-effect. @@ -220,7 +203,6 @@ func (p *printer) write(data []byte) { p.pos.Column += d } - func (p *printer) writeNewlines(n int, useFF bool) { if n > 0 { n = p.nlines(n, 0) @@ -232,7 +214,6 @@ func (p *printer) writeNewlines(n int, useFF bool) { } } - // writeItem writes data at position pos. data is the text corresponding to // a single lexical token, but may also be comment text. pos is the actual // (or at least very accurately estimated) position of the data in the original @@ -261,7 +242,6 @@ func (p *printer) writeItem(pos token.Position, data string) { p.last = p.pos } - // writeCommentPrefix writes the whitespace before a comment. // If there is any pending whitespace, it consumes as much of // it as is likely to help position the comment nicely. @@ -368,7 +348,6 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev *ast.Comment } } - // TODO(gri): It should be possible to convert the code below from using // []byte to string and in the process eliminate some conversions. @@ -398,7 +377,6 @@ func split(text []byte) [][]byte { return lines } - func isBlank(s []byte) bool { for _, b := range s { if b > ' ' { @@ -408,7 +386,6 @@ func isBlank(s []byte) bool { return true } - func commonPrefix(a, b []byte) []byte { i := 0 for i < len(a) && i < len(b) && a[i] == b[i] && (a[i] <= ' ' || a[i] == '*') { @@ -417,7 +394,6 @@ func commonPrefix(a, b []byte) []byte { return a[0:i] } - func stripCommonPrefix(lines [][]byte) { if len(lines) < 2 { return // at most one line - nothing to do @@ -545,7 +521,6 @@ func stripCommonPrefix(lines [][]byte) { } } - func (p *printer) writeComment(comment *ast.Comment) { text := comment.Text @@ -575,7 +550,6 @@ func (p *printer) writeComment(comment *ast.Comment) { } } - // writeCommentSuffix writes a line break after a comment if indicated // and processes any leftover indentation information. If a line break // is needed, the kind of break (newline vs formfeed) depends on the @@ -589,7 +563,7 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) { // ignore trailing whitespace p.wsbuf[i] = ignore case indent, unindent: - // don't loose indentation information + // don't lose indentation information case newline, formfeed: // if we need a line break, keep exactly one // but remember if we dropped any formfeeds @@ -613,7 +587,6 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (droppedFF bool) { return } - // intersperseComments consumes all comments that appear before the next token // tok and prints it together with the buffered whitespace (i.e., the whitespace // that needs to be written before the next token). A heuristic is used to mix @@ -651,7 +624,6 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (dro return false } - // whiteWhitespace writes the first n whitespace entries. func (p *printer) writeWhitespace(n int) { // write entries @@ -701,7 +673,6 @@ func (p *printer) writeWhitespace(n int) { p.wsbuf = p.wsbuf[0:i] } - // ---------------------------------------------------------------------------- // Printing interface @@ -724,7 +695,6 @@ func mayCombine(prev token.Token, next byte) (b bool) { return } - // print prints a list of "items" (roughly corresponding to syntactic // tokens, but also including whitespace and formatting information). // It is the only print function that should be called directly from @@ -812,7 +782,6 @@ func (p *printer) print(args ...interface{}) { } } - // commentBefore returns true iff the current comment occurs // before the next position in the source code. // @@ -820,7 +789,6 @@ func (p *printer) commentBefore(next token.Position) bool { return p.cindex < len(p.comments) && p.fset.Position(p.comments[p.cindex].List[0].Pos()).Offset < next.Offset } - // Flush prints any pending comments and whitespace occurring // textually before the position of the next token tok. Flush // returns true if a pending formfeed character was dropped @@ -838,7 +806,6 @@ func (p *printer) flush(next token.Position, tok token.Token) (droppedFF bool) { return } - // ---------------------------------------------------------------------------- // Trimmer @@ -854,7 +821,6 @@ type trimmer struct { space bytes.Buffer } - // trimmer is implemented as a state machine. // It can be in one of the following states: const ( @@ -863,7 +829,6 @@ const ( inText // inside text ) - // Design note: It is tempting to eliminate extra blanks occurring in // whitespace in this function as it could simplify some // of the blanks logic in the node printing functions. @@ -941,7 +906,6 @@ func (p *trimmer) Write(data []byte) (n int, err os.Error) { return } - // ---------------------------------------------------------------------------- // Public interface @@ -952,14 +916,12 @@ const ( UseSpaces // use spaces instead of tabs for alignment ) - // A Config node controls the output of Fprint. type Config struct { Mode uint // default: 0 Tabwidth int // default: 8 } - // 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 @@ -994,11 +956,9 @@ func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{ go func() { switch n := node.(type) { case ast.Expr: - p.nesting = 1 p.useNodeComments = true p.expr(n, ignoreMultiLine) case ast.Stmt: - p.nesting = 1 p.useNodeComments = true // A labeled statement will un-indent to position the // label. Set indent to 1 so we don't get indent "underflow". @@ -1007,15 +967,12 @@ func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{ } p.stmt(n, false, ignoreMultiLine) case ast.Decl: - p.nesting = 1 p.useNodeComments = true p.decl(n, ignoreMultiLine) case ast.Spec: - p.nesting = 1 p.useNodeComments = true p.spec(n, 1, false, ignoreMultiLine) case *ast.File: - p.nesting = 0 p.comments = n.Comments p.useNodeComments = n.Comments == nil p.file(n) @@ -1036,7 +993,6 @@ func (cfg *Config) fprint(output io.Writer, fset *token.FileSet, node interface{ return p.written, err } - // 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. @@ -1047,7 +1003,6 @@ func (cfg *Config) Fprint(output io.Writer, fset *token.FileSet, node interface{ 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. // diff --git a/libgo/go/go/printer/printer_test.go b/libgo/go/go/printer/printer_test.go index 090f92a..ff2d906 100644 --- a/libgo/go/go/printer/printer_test.go +++ b/libgo/go/go/printer/printer_test.go @@ -16,19 +16,15 @@ import ( "time" ) - const ( dataDir = "testdata" tabwidth = 8 ) - var update = flag.Bool("update", false, "update golden files") - var fset = token.NewFileSet() - func lineString(text []byte, i int) string { i0 := i for i < len(text) && text[i] != '\n' { @@ -37,7 +33,6 @@ func lineString(text []byte, i int) string { return string(text[i0:i]) } - type checkMode uint const ( @@ -45,7 +40,6 @@ const ( rawFormat ) - func runcheck(t *testing.T, source, golden string, mode checkMode) { // parse source prog, err := parser.ParseFile(fset, source, nil, parser.ParseComments) @@ -109,7 +103,6 @@ func runcheck(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) @@ -135,7 +128,6 @@ func check(t *testing.T, source, golden string, mode checkMode) { } } - type entry struct { source, golden string mode checkMode @@ -154,7 +146,6 @@ var data = []entry{ {"slow.input", "slow.golden", 0}, } - func TestFiles(t *testing.T) { for i, e := range data { source := filepath.Join(dataDir, e.source) @@ -168,7 +159,6 @@ func TestFiles(t *testing.T) { } } - // TestLineComments, using a simple test case, checks that consequtive line // comments are properly terminated with a newline even if the AST position // information is incorrect. diff --git a/libgo/go/go/printer/testdata/comments.golden b/libgo/go/go/printer/testdata/comments.golden index a86d661..7b33225 100644 --- a/libgo/go/go/printer/testdata/comments.golden +++ b/libgo/go/go/printer/testdata/comments.golden @@ -22,7 +22,7 @@ const ( _ = iota + 10 _ // comments - _ = 10 // comment + _ = 10 // comment _ T = 20 // comment ) @@ -38,9 +38,9 @@ const ( _ // comment _ // comment _ = iota + 10 - _ // comment - _ = 10 - _ = 20 // comment + _ // comment + _ = 10 + _ = 20 // comment _ T = 0 // comment ) @@ -106,7 +106,6 @@ type S3 struct { var x int // x var () - // This comment SHOULD be associated with the next declaration. func f0() { const pi = 3.14 // pi @@ -128,12 +127,10 @@ func f1() { f0() } - func _() { // this comment should be properly indented } - func _(x int) int { if x < 0 { // the tab printed before this comment's // must not affect the remaining lines return -x // this statement should be properly indented @@ -144,7 +141,6 @@ func _(x int) int { return x } - func typeswitch(x interface{}) { switch v := x.(type) { case bool, int, float: @@ -211,7 +207,6 @@ func _() { aligned line */ } - func _() { /* freestanding comment @@ -292,7 +287,6 @@ func _() { aligned line */ } - func _() { /* freestanding comment @@ -409,7 +403,6 @@ func _() { */ } - // Some interesting interspersed comments func _( /* this */ x /* is */ /* an */ int) { } @@ -434,9 +427,8 @@ func _() { _ = []int{0, 1 /* don't introduce a newline after this comment - was issue 1365 */ } } - // Comments immediately adjacent to punctuation (for which the go/printer -// may obly have estimated position information) must remain after the punctuation. +// may only have estimated position information) must remain after the punctuation. func _() { _ = T{ 1, // comment after comma @@ -466,7 +458,6 @@ func _() { } } - // Line comments with tabs func _() { var finput *bufio.Reader // input file @@ -479,5 +470,4 @@ func _() { var lflag bool // -l - disable line directives } - /* This comment is the last entry in this file. It must be printed and should be followed by a newline */ diff --git a/libgo/go/go/printer/testdata/comments.input b/libgo/go/go/printer/testdata/comments.input index 14cd4cf..2a9a86b 100644 --- a/libgo/go/go/printer/testdata/comments.input +++ b/libgo/go/go/printer/testdata/comments.input @@ -434,7 +434,7 @@ func _() { // Comments immediately adjacent to punctuation (for which the go/printer -// may obly have estimated position information) must remain after the punctuation. +// may only have estimated position information) must remain after the punctuation. func _() { _ = T{ 1, // comment after comma diff --git a/libgo/go/go/printer/testdata/comments.x b/libgo/go/go/printer/testdata/comments.x index 4d7a928a..ae77292 100644 --- a/libgo/go/go/printer/testdata/comments.x +++ b/libgo/go/go/printer/testdata/comments.x @@ -2,13 +2,12 @@ // package main - // The SZ struct; it is empty. type SZ struct{} // The S0 struct; no field is exported. type S0 struct { - // contains unexported fields + // contains filtered or unexported fields } // The S1 struct; some fields are not exported. @@ -16,7 +15,7 @@ type S1 struct { S0 A, B, C float // 3 exported fields D int // 2 unexported fields - // contains unexported fields + // contains filtered or unexported fields } // The S2 struct; all fields are exported. @@ -30,14 +29,14 @@ type SZ interface{} // The I0 interface; no method is exported. type I0 interface { - // contains unexported methods + // contains filtered or unexported methods } // The I1 interface; some methods are not exported. type I1 interface { I0 F(x float) float // exported methods - // contains unexported methods + // contains filtered or unexported methods } // The I2 interface; all methods are exported. @@ -53,5 +52,5 @@ type S3 struct { F1 int // line comment for F1 // lead comment for F2 F2 int // line comment for F2 - // contains unexported fields + // contains filtered or unexported fields } diff --git a/libgo/go/go/printer/testdata/declarations.golden b/libgo/go/go/printer/testdata/declarations.golden index c1b2558..970533e 100644 --- a/libgo/go/go/printer/testdata/declarations.golden +++ b/libgo/go/go/printer/testdata/declarations.golden @@ -44,7 +44,6 @@ import _ "os" import _ "os" import _ "os" - import _ "fmt" import _ "fmt" import _ "fmt" @@ -116,7 +115,6 @@ import _ "io" var _ int - // printing of constant literals const ( _ = "foobar" @@ -158,9 +156,7 @@ const ( bar` ) - func _() { - // the following decls need a semicolon at the end type _ int type _ *int type _ []int @@ -175,7 +171,6 @@ func _() { var _ chan int var _ func() int - // the following decls don't need a semicolon at the end type _ struct{} type _ *struct{} type _ []struct{} @@ -205,7 +200,6 @@ func _() { var _ func() interface{} } - // don't lose blank lines in grouped declarations const ( _ int = 0 @@ -222,7 +216,6 @@ const ( _ ) - type ( _ int _ struct{} @@ -233,7 +226,6 @@ type ( _ map[string]int ) - var ( _ int = 0 _ float = 1 @@ -246,7 +238,6 @@ var ( _ bool ) - // don't lose blank lines in this struct type _ struct { String struct { @@ -295,7 +286,6 @@ type _ struct { } } - // no tabs for single or ungrouped decls func _() { const xxxxxx = 0 @@ -331,11 +321,11 @@ func _() { ) // some entries have a type const ( - xxxxxx = 1 - x = 2 - xxx = 3 + xxxxxx = 1 + x = 2 + xxx = 3 yyyyyyyy float = iota - yyyy = "bar" + yyyy = "bar" yyy yy = 2 ) @@ -365,7 +355,7 @@ func _() { xxx string yyyyyyyy int = 1234 y float = 3.14 - yyyy = "bar" + yyyy = "bar" yyy string = "foo" ) // mixed entries - all comments should be aligned @@ -373,7 +363,7 @@ func _() { a, b, c int x = 10 d int // comment - y = 20 // comment + y = 20 // comment f, ff, fff, ffff int = 0, 1, 2, 3 // comment ) // respect original line breaks @@ -401,6 +391,32 @@ func _() { ) } +// alignment of "=" in consecutive lines (extended example from issue 1414) +const ( + umax uint = ^uint(0) // maximum value for a uint + bpu = 1 << (5 + umax>>63) // bits per uint + foo + bar = -1 +) + +// typical enum +const ( + a MyType = iota + abcd + b + c + def +) + +// excerpt from godoc.go +var ( + goroot = flag.String("goroot", runtime.GOROOT(), "Go root directory") + testDir = flag.String("testdir", "", "Go root subdirectory - for testing only (faster startups)") + pkgPath = flag.String("path", "", "additional package directories (colon-separated)") + filter = flag.String("filter", "", "filter file containing permitted package directory paths") + filterMin = flag.Int("filter_minutes", 0, "filter file update interval in minutes; disabled if <= 0") + filterDelay delayTime // actual filter update interval in minutes; usually filterDelay == filterMin, but filterDelay may back off exponentially +) // formatting of structs type _ struct{} @@ -469,14 +485,12 @@ type _ struct { r, s float // this line should be indented } - // difficult cases type _ struct { bool // comment text []byte // comment } - // formatting of interfaces type EI interface{} @@ -502,7 +516,6 @@ type _ interface { // this comment must not change indentation gggggggggggg(x, y, z int) // hurray } - // formatting of variable declarations func _() { type day struct { @@ -520,7 +533,6 @@ func _() { ) } - // formatting of multi-line variable declarations var a1, b1, c1 int // all on one line @@ -533,7 +545,6 @@ var ( a4, b4, c4 int // this line should be indented ) - func _() { var privateKey2 = &Block{Type: "RSA PRIVATE KEY", Headers: map[string]string{}, @@ -545,7 +556,6 @@ func _() { } } - func _() { var Universe = Scope{ Names: map[string]*Ident{ @@ -589,7 +599,6 @@ func _() { } } - // alignment of map composite entries var _ = map[int]int{ // small key sizes: always align even if size ratios are large @@ -613,21 +622,18 @@ var _ = map[int]int{ abcde: a, // align with previous line } - func _() { var _ = T{ a, // must introduce trailing comma } } - // formatting of function results func _() func() {} func _() func(int) { return nil } func _() func(int) int { return nil } func _() func(int) func(int) func() { return nil } - // formatting of consecutive single-line functions func _() {} func _() {} @@ -655,7 +661,6 @@ func _() int { return x } - // making function declarations safe for new semicolon rules func _() { /* multi-line func because of comment */ } @@ -664,7 +669,6 @@ func _() { /* multi-line func because block is on multiple lines */ } - // ellipsis parameters func _(...int) func _(...*int) @@ -686,7 +690,6 @@ func _(x ...func(...int)) func _(x ...map[string]int) func _(x ...chan int) - // these parameter lists must remain multi-line since they are multi-line in the source func _(bool, int) { diff --git a/libgo/go/go/printer/testdata/declarations.input b/libgo/go/go/printer/testdata/declarations.input index c8b37e1..c613409 100644 --- a/libgo/go/go/printer/testdata/declarations.input +++ b/libgo/go/go/printer/testdata/declarations.input @@ -159,7 +159,6 @@ bar` func _() { - // the following decls need a semicolon at the end type _ int type _ *int type _ []int @@ -174,7 +173,6 @@ func _() { var _ chan int var _ func() int - // the following decls don't need a semicolon at the end type _ struct{} type _ *struct{} type _ []struct{} @@ -400,6 +398,33 @@ func _() { ) } +// alignment of "=" in consecutive lines (extended example from issue 1414) +const ( + umax uint = ^uint(0) // maximum value for a uint + bpu = 1 << (5 + umax>>63) // bits per uint + foo + bar = -1 +) + +// typical enum +const ( + a MyType = iota + abcd + b + c + def +) + +// excerpt from godoc.go +var ( + goroot = flag.String("goroot", runtime.GOROOT(), "Go root directory") + testDir = flag.String("testdir", "", "Go root subdirectory - for testing only (faster startups)") + pkgPath = flag.String("path", "", "additional package directories (colon-separated)") + filter = flag.String("filter", "", "filter file containing permitted package directory paths") + filterMin = flag.Int("filter_minutes", 0, "filter file update interval in minutes; disabled if <= 0") + filterDelay delayTime // actual filter update interval in minutes; usually filterDelay == filterMin, but filterDelay may back off exponentially +) + // formatting of structs type _ struct{} diff --git a/libgo/go/go/printer/testdata/expressions.golden b/libgo/go/go/printer/testdata/expressions.golden index 3d0f144..d0cf24a 100644 --- a/libgo/go/go/printer/testdata/expressions.golden +++ b/libgo/go/go/printer/testdata/expressions.golden @@ -17,7 +17,6 @@ var ( p *int ) - func _() { // no spaces around simple or parenthesized expressions _ = (a + 0) @@ -115,7 +114,6 @@ func _() { x < y || z > 42 } - func _() { _ = a + b _ = a + b + c @@ -187,7 +185,6 @@ func _() { _ = token(matchType + xlength< 42 } - func _() { _ = a + b _ = a + b + c @@ -187,7 +185,6 @@ func _() { _ = token(matchType + xlength<" @@ -65,16 +58,13 @@ func (e *Error) String() string { return e.Msg } - // An ErrorList is a (possibly sorted) list of Errors. type ErrorList []*Error - // ErrorList implements the sort Interface. func (p ErrorList) Len() int { return len(p) } func (p ErrorList) Swap(i, j int) { p[i], p[j] = p[j], p[i] } - func (p ErrorList) Less(i, j int) bool { e := &p[i].Pos f := &p[j].Pos @@ -95,7 +85,6 @@ func (p ErrorList) Less(i, j int) bool { return false } - func (p ErrorList) String() string { switch len(p) { case 0: @@ -106,7 +95,6 @@ func (p ErrorList) String() string { return fmt.Sprintf("%s (and %d more errors)", p[0].String(), len(p)-1) } - // These constants control the construction of the ErrorList // returned by GetErrors. // @@ -116,20 +104,17 @@ const ( NoMultiples // sort error list and leave only the first error per line ) - // GetErrorList returns the list of errors collected by an ErrorVector. // The construction of the ErrorList returned is controlled by the mode // parameter. If there are no errors, the result is nil. // func (h *ErrorVector) GetErrorList(mode int) ErrorList { - if h.errors.Len() == 0 { + if len(h.errors) == 0 { return nil } - list := make(ErrorList, h.errors.Len()) - for i := 0; i < h.errors.Len(); i++ { - list[i] = h.errors.At(i).(*Error) - } + list := make(ErrorList, len(h.errors)) + copy(list, h.errors) if mode >= Sorted { sort.Sort(list) @@ -151,26 +136,23 @@ func (h *ErrorVector) GetErrorList(mode int) ErrorList { return list } - // GetError is like GetErrorList, but it returns an os.Error instead // so that a nil result can be assigned to an os.Error variable and // remains nil. // func (h *ErrorVector) GetError(mode int) os.Error { - if h.errors.Len() == 0 { + if len(h.errors) == 0 { return nil } return h.GetErrorList(mode) } - // ErrorVector implements the ErrorHandler interface. func (h *ErrorVector) Error(pos token.Position, msg string) { - h.errors.Push(&Error{pos, msg}) + h.errors = append(h.errors, &Error{pos, msg}) } - // PrintError is a utility function that prints a list of errors to w, // one error per line, if the err parameter is an ErrorList. Otherwise // it prints the err string. diff --git a/libgo/go/go/scanner/scanner.go b/libgo/go/go/scanner/scanner.go index 07b7454..7f3dd23 100644 --- a/libgo/go/go/scanner/scanner.go +++ b/libgo/go/go/scanner/scanner.go @@ -22,6 +22,7 @@ package scanner import ( "bytes" + "fmt" "go/token" "path/filepath" "strconv" @@ -29,7 +30,6 @@ import ( "utf8" ) - // A Scanner holds the scanner's internal state while processing // a given text. It can be allocated as part of another data // structure but must be initialized via Init before use. @@ -53,7 +53,6 @@ type Scanner struct { ErrorCount int // number of errors encountered } - // Read the next Unicode char into S.ch. // S.ch < 0 means end-of-file. // @@ -87,7 +86,6 @@ func (S *Scanner) next() { } } - // The mode parameter to the Init function is a set of flags (or 0). // They control scanner behavior. // @@ -133,37 +131,6 @@ func (S *Scanner) Init(file *token.File, src []byte, err ErrorHandler, mode uint S.next() } - -func charString(ch int) string { - var s string - switch ch { - case -1: - return `EOF` - case '\a': - s = `\a` - case '\b': - s = `\b` - case '\f': - s = `\f` - case '\n': - s = `\n` - case '\r': - s = `\r` - case '\t': - s = `\t` - case '\v': - s = `\v` - case '\\': - s = `\\` - case '\'': - s = `\'` - default: - s = string(ch) - } - return "'" + s + "' (U+" + strconv.Itob(ch, 16) + ")" -} - - func (S *Scanner) error(offs int, msg string) { if S.err != nil { S.err.Error(S.file.Position(S.file.Pos(offs)), msg) @@ -171,7 +138,6 @@ func (S *Scanner) error(offs int, msg string) { S.ErrorCount++ } - var prefix = []byte("//line ") func (S *Scanner) interpretLineComment(text []byte) { @@ -192,7 +158,6 @@ func (S *Scanner) interpretLineComment(text []byte) { } } - func (S *Scanner) scanComment() { // initial '/' already consumed; S.ch == '/' || S.ch == '*' offs := S.offset - 1 // position of initial '/' @@ -224,7 +189,6 @@ func (S *Scanner) scanComment() { S.error(offs, "comment not terminated") } - func (S *Scanner) findLineEnd() bool { // initial '/' already consumed @@ -269,17 +233,14 @@ func (S *Scanner) findLineEnd() bool { return false } - func isLetter(ch int) bool { return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch) } - func isDigit(ch int) bool { return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch) } - func (S *Scanner) scanIdentifier() token.Token { offs := S.offset for isLetter(S.ch) || isDigit(S.ch) { @@ -288,7 +249,6 @@ func (S *Scanner) scanIdentifier() token.Token { return token.Lookup(S.src[offs:S.offset]) } - func digitVal(ch int) int { switch { case '0' <= ch && ch <= '9': @@ -301,14 +261,12 @@ func digitVal(ch int) int { return 16 // larger than any legal digit val } - func (S *Scanner) scanMantissa(base int) { for digitVal(S.ch) < base { S.next() } } - func (S *Scanner) scanNumber(seenDecimalPoint bool) token.Token { // digitVal(S.ch) < 10 tok := token.INT @@ -327,6 +285,10 @@ func (S *Scanner) scanNumber(seenDecimalPoint bool) token.Token { // hexadecimal int S.next() S.scanMantissa(16) + if S.offset-offs <= 2 { + // only scanned "0x" or "0X" + S.error(offs, "illegal hexadecimal number") + } } else { // octal int or float seenDecimalDigit := false @@ -376,7 +338,6 @@ exit: return tok } - func (S *Scanner) scanEscape(quote int) { offs := S.offset @@ -421,7 +382,6 @@ func (S *Scanner) scanEscape(quote int) { } } - func (S *Scanner) scanChar() { // '\'' opening already consumed offs := S.offset - 1 @@ -448,7 +408,6 @@ func (S *Scanner) scanChar() { } } - func (S *Scanner) scanString() { // '"' opening already consumed offs := S.offset - 1 @@ -468,7 +427,6 @@ func (S *Scanner) scanString() { S.next() } - func (S *Scanner) scanRawString() { // '`' opening already consumed offs := S.offset - 1 @@ -485,14 +443,12 @@ func (S *Scanner) scanRawString() { S.next() } - func (S *Scanner) skipWhitespace() { for S.ch == ' ' || S.ch == '\t' || S.ch == '\n' && !S.insertSemi || S.ch == '\r' { S.next() } } - // Helper functions for scanning multi-byte tokens such as >> += >>= . // Different routines recognize different length tok_i based on matches // of ch_i. If a token ends in '=', the result is tok1 or tok3 @@ -507,7 +463,6 @@ func (S *Scanner) switch2(tok0, tok1 token.Token) token.Token { return tok0 } - func (S *Scanner) switch3(tok0, tok1 token.Token, ch2 int, tok2 token.Token) token.Token { if S.ch == '=' { S.next() @@ -520,7 +475,6 @@ func (S *Scanner) switch3(tok0, tok1 token.Token, ch2 int, tok2 token.Token) tok return tok0 } - func (S *Scanner) switch4(tok0, tok1 token.Token, ch2 int, tok2, tok3 token.Token) token.Token { if S.ch == '=' { S.next() @@ -537,7 +491,6 @@ func (S *Scanner) switch4(tok0, tok1 token.Token, ch2 int, tok2, tok3 token.Toke return tok0 } - // Scan scans the next token and returns the token position, // the token, and the literal string corresponding to the // token. The source end is indicated by token.EOF. @@ -700,7 +653,7 @@ scanAgain: tok = S.switch3(token.OR, token.OR_ASSIGN, '|', token.LOR) default: if S.mode&AllowIllegalChars == 0 { - S.error(offs, "illegal character "+charString(ch)) + S.error(offs, fmt.Sprintf("illegal character %#U", ch)) } insertSemi = S.insertSemi // preserve insertSemi info } diff --git a/libgo/go/go/scanner/scanner_test.go b/libgo/go/go/scanner/scanner_test.go index 8afb00e..eb9e1cb 100644 --- a/libgo/go/go/scanner/scanner_test.go +++ b/libgo/go/go/scanner/scanner_test.go @@ -12,10 +12,8 @@ import ( "testing" ) - var fset = token.NewFileSet() - const /* class */ ( special = iota literal @@ -23,7 +21,6 @@ const /* class */ ( keyword ) - func tokenclass(tok token.Token) int { switch { case tok.IsLiteral(): @@ -36,14 +33,12 @@ func tokenclass(tok token.Token) int { return special } - type elt struct { tok token.Token lit string class int } - var tokens = [...]elt{ // Special tokens {token.COMMENT, "/* a comment */", special}, @@ -89,7 +84,7 @@ var tokens = [...]elt{ literal, }, - // Operators and delimitors + // Operators and delimiters {token.ADD, "+", operator}, {token.SUB, "-", operator}, {token.MUL, "*", operator}, @@ -178,7 +173,6 @@ var tokens = [...]elt{ {token.VAR, "var", keyword}, } - const whitespace = " \t \n\n\n" // to separate tokens type testErrorHandler struct { @@ -189,7 +183,6 @@ func (h *testErrorHandler) Error(pos token.Position, msg string) { h.t.Errorf("Error() called (msg = %s)", msg) } - func newlineCount(s string) int { n := 0 for i := 0; i < len(s); i++ { @@ -200,7 +193,6 @@ func newlineCount(s string) int { return n } - func checkPos(t *testing.T, lit string, p token.Pos, expected token.Position) { pos := fset.Position(p) if pos.Filename != expected.Filename { @@ -217,7 +209,6 @@ func checkPos(t *testing.T, lit string, p token.Pos, expected token.Position) { } } - // Verify that calling Scan() provides the correct results. func TestScan(t *testing.T) { // make source @@ -271,7 +262,6 @@ func TestScan(t *testing.T) { } } - func checkSemi(t *testing.T, line string, mode uint) { var S Scanner file := fset.AddFile("TestSemis", fset.Base(), len(line)) @@ -305,7 +295,6 @@ func checkSemi(t *testing.T, line string, mode uint) { } } - var lines = []string{ // # indicates a semicolon present in the source // $ indicates an automatically inserted semicolon @@ -429,7 +418,6 @@ var lines = []string{ "package main$", } - func TestSemis(t *testing.T) { for _, line := range lines { checkSemi(t, line, AllowIllegalChars|InsertSemis) @@ -463,25 +451,31 @@ var segments = []segment{ {"\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 unixsegments = []segment{ + {"\n//line /bar:42\n line42", "/bar", 42}, +} + var winsegments = []segment{ + {"\n//line c:\\bar:42\n line42", "c:\\bar", 42}, {"\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) { + segs := segments if runtime.GOOS == "windows" { - segments = append(segments, winsegments...) + segs = append(segs, winsegments...) + } else { + segs = append(segs, unixsegments...) } // make source var src string - for _, e := range segments { + for _, e := range segs { src += e.srcline } @@ -489,7 +483,7 @@ func TestLineComments(t *testing.T) { var S Scanner file := fset.AddFile(filepath.Join("dir", "TestLineComments"), fset.Base(), len(src)) S.Init(file, []byte(src), nil, 0) - for _, s := range segments { + for _, s := range segs { p, _, lit := S.Scan() pos := file.Position(p) checkPos(t, lit, p, token.Position{s.filename, pos.Offset, s.line, pos.Column}) @@ -500,7 +494,6 @@ func TestLineComments(t *testing.T) { } } - // Verify that initializing the same scanner more then once works correctly. func TestInit(t *testing.T) { var s Scanner @@ -536,7 +529,6 @@ func TestInit(t *testing.T) { } } - func TestIllegalChars(t *testing.T) { var s Scanner @@ -558,7 +550,6 @@ func TestIllegalChars(t *testing.T) { } } - func TestStdErrorHander(t *testing.T) { const src = "@\n" + // illegal character, cause an error "@ @\n" + // two errors on the same line @@ -601,21 +592,18 @@ func TestStdErrorHander(t *testing.T) { } } - type errorCollector struct { cnt int // number of errors encountered msg string // last error message encountered pos token.Position // last error position encountered } - func (h *errorCollector) Error(pos token.Position, msg string) { h.cnt++ h.msg = msg h.pos = pos } - func checkError(t *testing.T, src string, tok token.Token, pos int, err string) { var s Scanner var h errorCollector @@ -643,14 +631,15 @@ func checkError(t *testing.T, src string, tok token.Token, pos int, err string) } } - var errors = []struct { src string tok token.Token pos int err string }{ - {`#`, token.ILLEGAL, 0, "illegal character '#' (U+23)"}, + {"\a", token.ILLEGAL, 0, "illegal character U+0007"}, + {`#`, token.ILLEGAL, 0, "illegal character U+0023 '#'"}, + {`…`, token.ILLEGAL, 0, "illegal character U+2026 '…'"}, {`' '`, token.CHAR, 0, ""}, {`''`, token.CHAR, 0, "illegal character literal"}, {`'\8'`, token.CHAR, 2, "unknown escape sequence"}, @@ -670,11 +659,12 @@ var errors = []struct { {"078e0", token.FLOAT, 0, ""}, {"078", token.INT, 0, "illegal octal number"}, {"07800000009", token.INT, 0, "illegal octal number"}, + {"0x", token.INT, 0, "illegal hexadecimal number"}, + {"0X", token.INT, 0, "illegal hexadecimal number"}, {"\"abc\x00def\"", token.STRING, 4, "illegal character NUL"}, {"\"abc\x80def\"", token.STRING, 4, "illegal UTF-8 encoding"}, } - func TestScanErrors(t *testing.T) { for _, e := range errors { checkError(t, e.src, e.tok, e.pos, e.err) diff --git a/libgo/go/go/token/position.go b/libgo/go/go/token/position.go index 8c35eeb..c559e19 100644 --- a/libgo/go/go/token/position.go +++ b/libgo/go/go/token/position.go @@ -12,7 +12,6 @@ import ( "sync" ) - // Position describes an arbitrary source position // including the file, line, and column location. // A Position is valid if the line number is > 0. @@ -24,11 +23,9 @@ type Position struct { Column int // column number, starting at 1 (character count) } - // IsValid returns true if the position is valid. func (pos *Position) IsValid() bool { return pos.Line > 0 } - // String returns a string in one of several forms: // // file:line:column valid position with file name @@ -50,7 +47,6 @@ func (pos Position) String() string { return s } - // Pos is a compact encoding of a source position within a file set. // It can be converted into a Position for a more convenient, but much // larger, representation. @@ -73,7 +69,6 @@ func (pos Position) String() string { // type Pos int - // The zero value for Pos is NoPos; there is no file and line information // associated with it, and NoPos().IsValid() is false. NoPos is always // smaller than any other Pos value. The corresponding Position value @@ -81,18 +76,15 @@ type Pos int // const NoPos Pos = 0 - // IsValid returns true if the position is valid. func (p Pos) IsValid() bool { return p != NoPos } - func searchFiles(a []*File, x int) int { return sort.Search(len(a), func(i int) bool { return a[i].base > x }) - 1 } - func (s *FileSet) file(p Pos) *File { if f := s.last; f != nil && f.base <= int(p) && int(p) <= f.base+f.size { return f @@ -108,7 +100,6 @@ func (s *FileSet) file(p Pos) *File { return nil } - // File returns the file which contains the position p. // If no such file is found (for instance for p == NoPos), // the result is nil. @@ -122,7 +113,6 @@ func (s *FileSet) File(p Pos) (f *File) { return } - func (f *File) position(p Pos) (pos Position) { offset := int(p) - f.base pos.Offset = offset @@ -130,12 +120,11 @@ func (f *File) position(p Pos) (pos Position) { return } - // Position converts a Pos in the fileset into a general Position. func (s *FileSet) Position(p Pos) (pos Position) { if p != NoPos { // TODO(gri) consider optimizing the case where p - // is in the last file addded, or perhaps + // is in the last file added, or perhaps // looked at - will eliminate one level // of search s.mutex.RLock() @@ -147,14 +136,12 @@ func (s *FileSet) Position(p Pos) (pos Position) { return } - type lineInfo struct { offset int filename string line int } - // AddLineInfo adds alternative file and line number information for // a given file offset. The offset must be larger than the offset for // the previously added alternative line info and smaller than the @@ -171,7 +158,6 @@ func (f *File) AddLineInfo(offset int, filename string, line int) { f.set.mutex.Unlock() } - // A File is a handle for a file belonging to a FileSet. // A File has a name, size, and line offset table. // @@ -186,25 +172,21 @@ type File struct { infos []lineInfo } - // Name returns the file name of file f as registered with AddFile. func (f *File) Name() string { return f.name } - // Base returns the base offset of file f as registered with AddFile. func (f *File) Base() int { return f.base } - // Size returns the size of file f as registered with AddFile. func (f *File) Size() int { return f.size } - // LineCount returns the number of lines in file f. func (f *File) LineCount() int { f.set.mutex.RLock() @@ -213,7 +195,6 @@ func (f *File) LineCount() int { return n } - // AddLine adds the line offset for a new line. // The line offset must be larger than the offset for the previous line // and smaller than the file size; otherwise the line offset is ignored. @@ -226,7 +207,6 @@ func (f *File) AddLine(offset int) { f.set.mutex.Unlock() } - // SetLines sets the line offsets for a file and returns true if successful. // The line offsets are the offsets of the first character of each line; // for instance for the content "ab\nc\n" the line offsets are {0, 3}. @@ -251,7 +231,6 @@ func (f *File) SetLines(lines []int) bool { return true } - // SetLinesForContent sets the line offsets for the given file content. func (f *File) SetLinesForContent(content []byte) { var lines []int @@ -272,7 +251,6 @@ func (f *File) SetLinesForContent(content []byte) { f.set.mutex.Unlock() } - // Pos returns the Pos value for the given file offset; // the offset must be <= f.Size(). // f.Pos(f.Offset(p)) == p. @@ -284,7 +262,6 @@ func (f *File) Pos(offset int) Pos { return Pos(f.base + offset) } - // Offset returns the offset for the given file position p; // p must be a valid Pos value in that file. // f.Offset(f.Pos(offset)) == offset. @@ -296,7 +273,6 @@ func (f *File) Offset(p Pos) int { return int(p) - f.base } - // Line returns the line number for the given file position p; // p must be a Pos value in that file or NoPos. // @@ -305,7 +281,6 @@ func (f *File) Line(p Pos) int { return f.Position(p).Line } - // Position returns the Position value for the given file position p; // p must be a Pos value in that file or NoPos. // @@ -319,7 +294,6 @@ func (f *File) Position(p Pos) (pos Position) { return } - func searchInts(a []int, x int) int { // This function body is a manually inlined version of: // @@ -342,12 +316,10 @@ func searchInts(a []int, x int) int { return i - 1 } - func searchLineInfos(a []lineInfo, x int) int { return sort.Search(len(a), func(i int) bool { return a[i].offset > x }) - 1 } - // info returns the file name, line, and column number for a file offset. func (f *File) info(offset int) (filename string, line, column int) { filename = f.name @@ -367,7 +339,6 @@ func (f *File) info(offset int) (filename string, line, column int) { return } - // A FileSet represents a set of source files. // Methods of file sets are synchronized; multiple goroutines // may invoke them concurrently. @@ -379,7 +350,6 @@ type FileSet struct { last *File // cache of last file looked up } - // NewFileSet creates a new file set. func NewFileSet() *FileSet { s := new(FileSet) @@ -387,7 +357,6 @@ func NewFileSet() *FileSet { return s } - // Base returns the minimum base offset that must be provided to // AddFile when adding the next file. // @@ -399,7 +368,6 @@ func (s *FileSet) Base() int { } - // AddFile adds a new file with a given filename, base offset, and file size // to the file set s and returns the file. Multiple files may have the same // name. The base offset must not be smaller than the FileSet's Base(), and @@ -434,7 +402,6 @@ func (s *FileSet) AddFile(filename string, base, size int) *File { return f } - // Files returns the files added to the file set. func (s *FileSet) Files() <-chan *File { ch := make(chan *File) diff --git a/libgo/go/go/token/position_test.go b/libgo/go/go/token/position_test.go index 979c9b1..30bec59 100644 --- a/libgo/go/go/token/position_test.go +++ b/libgo/go/go/token/position_test.go @@ -9,7 +9,6 @@ import ( "testing" ) - func checkPos(t *testing.T, msg string, p, q Position) { if p.Filename != q.Filename { t.Errorf("%s: expected filename = %q; got %q", msg, q.Filename, p.Filename) @@ -25,7 +24,6 @@ func checkPos(t *testing.T, msg string, p, q Position) { } } - func TestNoPos(t *testing.T) { if NoPos.IsValid() { t.Errorf("NoPos should not be valid") @@ -36,7 +34,6 @@ func TestNoPos(t *testing.T) { checkPos(t, "fset NoPos", fset.Position(NoPos), Position{}) } - var tests = []struct { filename string source []byte // may be nil @@ -53,7 +50,6 @@ var tests = []struct { {"h", []byte("package p\n\nimport \"fmt\"\n "), 25, []int{0, 10, 11, 24}}, } - func linecol(lines []int, offs int) (int, int) { prevLineOffs := 0 for line, lineOffs := range lines { @@ -65,7 +61,6 @@ func linecol(lines []int, offs int) (int, int) { return len(lines), offs - prevLineOffs + 1 } - func verifyPositions(t *testing.T, fset *FileSet, f *File, lines []int) { for offs := 0; offs < f.Size(); offs++ { p := f.Pos(offs) @@ -80,7 +75,6 @@ func verifyPositions(t *testing.T, fset *FileSet, f *File, lines []int) { } } - func makeTestSource(size int, lines []int) []byte { src := make([]byte, size) for _, offs := range lines { @@ -91,7 +85,6 @@ func makeTestSource(size int, lines []int) []byte { return src } - func TestPositions(t *testing.T) { const delta = 7 // a non-zero base offset increment fset := NewFileSet() @@ -150,7 +143,6 @@ func TestPositions(t *testing.T) { } } - func TestLineInfo(t *testing.T) { fset := NewFileSet() f := fset.AddFile("foo", fset.Base(), 500) @@ -170,7 +162,6 @@ func TestLineInfo(t *testing.T) { } } - func TestFiles(t *testing.T) { fset := NewFileSet() for i, test := range tests { diff --git a/libgo/go/go/token/token.go b/libgo/go/go/token/token.go index c2ec80a..5573740 100644 --- a/libgo/go/go/token/token.go +++ b/libgo/go/go/token/token.go @@ -9,7 +9,6 @@ package token import "strconv" - // Token is the set of lexical tokens of the Go programming language. type Token int @@ -124,7 +123,6 @@ const ( keyword_end ) - var tokens = [...]string{ ILLEGAL: "ILLEGAL", @@ -225,7 +223,6 @@ var tokens = [...]string{ VAR: "var", } - // String returns the string corresponding to the token tok. // For operators, delimiters, and keywords the string is the actual // token character sequence (e.g., for the token ADD, the string is @@ -243,7 +240,6 @@ func (tok Token) String() string { return s } - // A set of constants for precedence-based expression parsing. // Non-operators have lowest precedence, followed by operators // starting with precedence 1 up to unary operators. The highest @@ -256,7 +252,6 @@ const ( HighestPrec = 7 ) - // Precedence returns the operator precedence of the binary // operator op. If op is not a binary operator, the result // is LowestPrecedence. @@ -277,7 +272,6 @@ func (op Token) Precedence() int { return LowestPrec } - var keywords map[string]Token func init() { @@ -287,7 +281,6 @@ func init() { } } - // Lookup maps an identifier to its keyword token or IDENT (if not a keyword). // func Lookup(ident []byte) Token { @@ -299,7 +292,6 @@ func Lookup(ident []byte) Token { return IDENT } - // Predicates // IsLiteral returns true for tokens corresponding to identifiers diff --git a/libgo/go/go/typechecker/scope.go b/libgo/go/go/typechecker/scope.go index a4bee6e..d73d1a4 100644 --- a/libgo/go/go/typechecker/scope.go +++ b/libgo/go/go/typechecker/scope.go @@ -12,18 +12,15 @@ package typechecker import "go/ast" - func (tc *typechecker) openScope() *ast.Scope { tc.topScope = ast.NewScope(tc.topScope) return tc.topScope } - func (tc *typechecker) closeScope() { tc.topScope = tc.topScope.Outer } - // 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. @@ -40,13 +37,11 @@ func (tc *typechecker) declInScope(scope *ast.Scope, kind ast.ObjKind, name *ast return obj } - // decl is the same as declInScope(tc.topScope, ...) 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) } - // find returns the object with the given name if visible in the current scope hierarchy. // If no such object is found, an error is reported and a bad object is returned instead. func (tc *typechecker) find(name *ast.Ident) (obj *ast.Object) { @@ -61,7 +56,6 @@ func (tc *typechecker) find(name *ast.Ident) (obj *ast.Object) { return } - // 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 *Type, name *ast.Ident) (obj *ast.Object) { diff --git a/libgo/go/go/typechecker/type.go b/libgo/go/go/typechecker/type.go index 62b4e9d..1b88eb5 100644 --- a/libgo/go/go/typechecker/type.go +++ b/libgo/go/go/typechecker/type.go @@ -6,7 +6,6 @@ package typechecker import "go/ast" - // A Type represents a Go type. type Type struct { Form Form @@ -18,13 +17,11 @@ type Type struct { 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 @@ -45,7 +42,6 @@ const ( Tuple ) - var formStrings = [...]string{ BadType: "badType", Unresolved: "unresolved", @@ -62,10 +58,8 @@ var formStrings = [...]string{ Tuple: "tuple", } - func (form Form) String() string { return formStrings[form] } - // The list of basic type id's. const ( Bool = iota @@ -96,7 +90,6 @@ const ( // TODO(gri) ideal types are missing ) - var BasicTypes = map[uint]string{ Bool: "bool", Byte: "byte", diff --git a/libgo/go/go/typechecker/typechecker.go b/libgo/go/go/typechecker/typechecker.go index b151f58..2448016 100644 --- a/libgo/go/go/typechecker/typechecker.go +++ b/libgo/go/go/typechecker/typechecker.go @@ -17,19 +17,16 @@ import ( "os" ) - // TODO(gri) don't report errors for objects/types that are marked as bad. const debug = true // set for debugging output - // An importer takes an import path and returns the data describing the // respective package's exported interface. The data format is TBD. // type Importer func(path string) ([]byte, os.Error) - // CheckPackage typechecks a package and augments the AST by setting // *ast.Object, *ast.Type, and *ast.Scope fields accordingly. If an // importer is provided, it is used to handle imports, otherwise they @@ -46,7 +43,6 @@ func CheckPackage(fset *token.FileSet, pkg *ast.Package, importer Importer) os.E return tc.GetError(scanner.Sorted) } - // CheckFile typechecks a single file, but otherwise behaves like // CheckPackage. If the complete package consists of more than just // one file, the file may not typecheck without errors. @@ -57,7 +53,6 @@ func CheckFile(fset *token.FileSet, file *ast.File, importer Importer) os.Error return CheckPackage(fset, pkg, importer) } - // ---------------------------------------------------------------------------- // Typechecker state @@ -71,19 +66,16 @@ type typechecker struct { iota int // current value of iota } - func (tc *typechecker) Errorf(pos token.Pos, format string, args ...interface{}) { tc.Error(tc.fset.Position(pos), fmt.Sprintf(format, args...)) } - func assert(pred bool) { if !pred { panic("internal error") } } - /* Typechecking is done in several phases: @@ -158,7 +150,6 @@ func (tc *typechecker) checkPackage(pkg *ast.Package) { pkg.Scope = tc.topScope } - func (tc *typechecker) declGlobal(global ast.Decl) { switch d := global.(type) { case *ast.BadDecl: @@ -218,7 +209,6 @@ func (tc *typechecker) declGlobal(global ast.Decl) { } } - // If x is of the form *T, deref returns T, otherwise it returns x. func deref(x ast.Expr) ast.Expr { if p, isPtr := x.(*ast.StarExpr); isPtr { @@ -227,7 +217,6 @@ func deref(x ast.Expr) ast.Expr { return x } - func (tc *typechecker) bindMethod(method *ast.FuncDecl) { // a method is declared in the receiver base type's scope var scope *ast.Scope @@ -259,7 +248,6 @@ func (tc *typechecker) bindMethod(method *ast.FuncDecl) { tc.declInScope(scope, ast.Fun, method.Name, method, 0) } - func (tc *typechecker) resolve(obj *ast.Object) { // check for declaration cycles if tc.cyclemap[obj] { @@ -318,7 +306,6 @@ func (tc *typechecker) resolve(obj *ast.Object) { } } - func (tc *typechecker) checkBlock(body []ast.Stmt, ftype *Type) { tc.openScope() defer tc.closeScope() @@ -338,7 +325,6 @@ func (tc *typechecker) checkBlock(body []ast.Stmt, ftype *Type) { } } - // ---------------------------------------------------------------------------- // Types @@ -350,7 +336,6 @@ func unparen(x ast.Expr) ast.Expr { return x } - func (tc *typechecker) declFields(scope *ast.Scope, fields *ast.FieldList, ref bool) (n uint) { if fields != nil { for _, f := range fields.List { @@ -365,7 +350,6 @@ func (tc *typechecker) declFields(scope *ast.Scope, fields *ast.FieldList, ref b return n } - func (tc *typechecker) declSignature(typ *Type, recv, params, results *ast.FieldList) { assert((typ.Form == Method) == (recv != nil)) typ.Params = ast.NewScope(nil) @@ -374,7 +358,6 @@ func (tc *typechecker) declSignature(typ *Type, recv, params, results *ast.Field typ.N = tc.declFields(typ.Params, results, true) } - func (tc *typechecker) typeFor(def *Type, x ast.Expr, ref bool) (typ *Type) { x = unparen(x) @@ -472,17 +455,14 @@ func (tc *typechecker) typeFor(def *Type, x ast.Expr, ref bool) (typ *Type) { return } - // ---------------------------------------------------------------------------- // TODO(gri) implement these place holders func (tc *typechecker) declConst(*ast.Object) { } - func (tc *typechecker) declVar(*ast.Object) { } - func (tc *typechecker) checkStmt(ast.Stmt) { } diff --git a/libgo/go/go/typechecker/typechecker_test.go b/libgo/go/go/typechecker/typechecker_test.go index d16e069..4bad449 100644 --- a/libgo/go/go/typechecker/typechecker_test.go +++ b/libgo/go/go/typechecker/typechecker_test.go @@ -41,7 +41,6 @@ import ( "testing" ) - const testDir = "./testdata" // location of test packages var fset = token.NewFileSet() @@ -51,7 +50,6 @@ var ( trace = flag.Bool("trace", false, "print package names") ) - // ERROR comments must be of the form /* ERROR "rx" */ and rx is // a regular expression that matches the expected error message. var errRx = regexp.MustCompile(`^/\* *ERROR *"([^"]*)" *\*/$`) @@ -91,12 +89,10 @@ func expectedErrors(t *testing.T, pkg *ast.Package) (list scanner.ErrorList) { return } - func testFilter(f *os.FileInfo) bool { return strings.HasSuffix(f.Name, ".src") && f.Name[0] != '.' } - func checkError(t *testing.T, expected, found *scanner.Error) { rx, err := regexp.Compile(expected.Msg) if err != nil { @@ -120,7 +116,6 @@ func checkError(t *testing.T, expected, found *scanner.Error) { } } - func TestTypeCheck(t *testing.T) { flag.Parse() pkgRx, err := regexp.Compile(*pkgPat) diff --git a/libgo/go/go/typechecker/universe.go b/libgo/go/go/typechecker/universe.go index abc8bbb..81c14a0 100644 --- a/libgo/go/go/typechecker/universe.go +++ b/libgo/go/go/typechecker/universe.go @@ -11,7 +11,6 @@ import "go/ast" // The Universe scope contains all predeclared identifiers. var Universe *ast.Scope - func def(obj *ast.Object) { alt := Universe.Insert(obj) if alt != nil { @@ -19,7 +18,6 @@ func def(obj *ast.Object) { } } - func init() { Universe = ast.NewScope(nil) diff --git a/libgo/go/go/types/check.go b/libgo/go/go/types/check.go new file mode 100644 index 0000000..87e3e93 --- /dev/null +++ b/libgo/go/go/types/check.go @@ -0,0 +1,226 @@ +// 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. + +// This file implements the Check function, which typechecks a package. + +package types + +import ( + "fmt" + "go/ast" + "go/scanner" + "go/token" + "os" + "strconv" +) + +const debug = false + +type checker struct { + fset *token.FileSet + scanner.ErrorVector + types map[ast.Expr]Type +} + +func (c *checker) errorf(pos token.Pos, format string, args ...interface{}) string { + msg := fmt.Sprintf(format, args...) + c.Error(c.fset.Position(pos), msg) + return msg +} + +// collectFields collects struct fields tok = token.STRUCT), interface methods +// (tok = token.INTERFACE), and function arguments/results (tok = token.FUNC). +func (c *checker) collectFields(tok token.Token, list *ast.FieldList, cycleOk bool) (fields ObjList, tags []string, isVariadic bool) { + if list != nil { + for _, field := range list.List { + ftype := field.Type + if t, ok := ftype.(*ast.Ellipsis); ok { + ftype = t.Elt + isVariadic = true + } + typ := c.makeType(ftype, cycleOk) + tag := "" + if field.Tag != nil { + assert(field.Tag.Kind == token.STRING) + tag, _ = strconv.Unquote(field.Tag.Value) + } + if len(field.Names) > 0 { + // named fields + for _, name := range field.Names { + obj := name.Obj + obj.Type = typ + fields = append(fields, obj) + if tok == token.STRUCT { + tags = append(tags, tag) + } + } + } else { + // anonymous field + switch tok { + case token.STRUCT: + tags = append(tags, tag) + fallthrough + case token.FUNC: + obj := ast.NewObj(ast.Var, "") + obj.Type = typ + fields = append(fields, obj) + case token.INTERFACE: + utyp := Underlying(typ) + if typ, ok := utyp.(*Interface); ok { + // TODO(gri) This is not good enough. Check for double declarations! + fields = append(fields, typ.Methods...) + } else if _, ok := utyp.(*Bad); !ok { + // if utyp is Bad, don't complain (the root cause was reported before) + c.errorf(ftype.Pos(), "interface contains embedded non-interface type") + } + default: + panic("unreachable") + } + } + } + } + return +} + +// makeType makes a new type for an AST type specification x or returns +// the type referred to by a type name x. If cycleOk is set, a type may +// refer to itself directly or indirectly; otherwise cycles are errors. +// +func (c *checker) makeType(x ast.Expr, cycleOk bool) (typ Type) { + if debug { + fmt.Printf("makeType (cycleOk = %v)\n", cycleOk) + ast.Print(c.fset, x) + defer func() { + fmt.Printf("-> %T %v\n\n", typ, typ) + }() + } + + switch t := x.(type) { + case *ast.BadExpr: + return &Bad{} + + case *ast.Ident: + // type name + obj := t.Obj + if obj == nil { + // unresolved identifier (error has been reported before) + return &Bad{Msg: "unresolved identifier"} + } + if obj.Kind != ast.Typ { + msg := c.errorf(t.Pos(), "%s is not a type", t.Name) + return &Bad{Msg: msg} + } + c.checkObj(obj, cycleOk) + if !cycleOk && obj.Type.(*Name).Underlying == nil { + // TODO(gri) Enable this message again once its position + // is independent of the underlying map implementation. + // msg := c.errorf(obj.Pos(), "illegal cycle in declaration of %s", obj.Name) + msg := "illegal cycle" + return &Bad{Msg: msg} + } + return obj.Type.(Type) + + case *ast.ParenExpr: + return c.makeType(t.X, cycleOk) + + case *ast.SelectorExpr: + // qualified identifier + // TODO (gri) eventually, this code belongs to expression + // type checking - here for the time being + if ident, ok := t.X.(*ast.Ident); ok { + if obj := ident.Obj; obj != nil { + if obj.Kind != ast.Pkg { + msg := c.errorf(ident.Pos(), "%s is not a package", obj.Name) + return &Bad{Msg: msg} + } + // TODO(gri) we have a package name but don't + // have the mapping from package name to package + // scope anymore (created in ast.NewPackage). + return &Bad{} // for now + } + } + // TODO(gri) can this really happen (the parser should have excluded this)? + msg := c.errorf(t.Pos(), "expected qualified identifier") + return &Bad{Msg: msg} + + case *ast.StarExpr: + return &Pointer{Base: c.makeType(t.X, true)} + + case *ast.ArrayType: + if t.Len != nil { + // TODO(gri) compute length + return &Array{Elt: c.makeType(t.Elt, cycleOk)} + } + return &Slice{Elt: c.makeType(t.Elt, true)} + + case *ast.StructType: + fields, tags, _ := c.collectFields(token.STRUCT, t.Fields, cycleOk) + return &Struct{Fields: fields, Tags: tags} + + case *ast.FuncType: + params, _, _ := c.collectFields(token.FUNC, t.Params, true) + results, _, isVariadic := c.collectFields(token.FUNC, t.Results, true) + return &Func{Recv: nil, Params: params, Results: results, IsVariadic: isVariadic} + + case *ast.InterfaceType: + methods, _, _ := c.collectFields(token.INTERFACE, t.Methods, cycleOk) + methods.Sort() + return &Interface{Methods: methods} + + case *ast.MapType: + return &Map{Key: c.makeType(t.Key, true), Elt: c.makeType(t.Key, true)} + + case *ast.ChanType: + return &Chan{Dir: t.Dir, Elt: c.makeType(t.Value, true)} + } + + panic(fmt.Sprintf("unreachable (%T)", x)) +} + +// checkObj type checks an object. +func (c *checker) checkObj(obj *ast.Object, ref bool) { + if obj.Type != nil { + // object has already been type checked + return + } + + switch obj.Kind { + case ast.Bad: + // ignore + + case ast.Con: + // TODO(gri) complete this + + case ast.Typ: + typ := &Name{Obj: obj} + obj.Type = typ // "mark" object so recursion terminates + typ.Underlying = Underlying(c.makeType(obj.Decl.(*ast.TypeSpec).Type, ref)) + + case ast.Var: + // TODO(gri) complete this + + case ast.Fun: + // TODO(gri) complete this + + default: + panic("unreachable") + } +} + +// Check typechecks a package. +// It augments the AST by assigning types to all ast.Objects and returns a map +// of types for all expression nodes in statements, and a scanner.ErrorList if +// there are errors. +// +func Check(fset *token.FileSet, pkg *ast.Package) (types map[ast.Expr]Type, err os.Error) { + var c checker + c.fset = fset + c.types = make(map[ast.Expr]Type) + + for _, obj := range pkg.Scope.Objects { + c.checkObj(obj, false) + } + + return c.types, c.GetError(scanner.NoMultiples) +} diff --git a/libgo/go/go/types/check_test.go b/libgo/go/go/types/check_test.go new file mode 100644 index 0000000..8be653f --- /dev/null +++ b/libgo/go/go/types/check_test.go @@ -0,0 +1,215 @@ +// 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. + +// This file implements a typechecker test harness. The packages specified +// in tests are typechecked. Error messages reported by the typechecker are +// compared against the error messages expected in the test files. +// +// Expected errors are indicated in the test files by putting a comment +// of the form /* ERROR "rx" */ immediately following an offending token. +// The harness will verify that an error matching the regular expression +// rx is reported at that source position. Consecutive comments may be +// used to indicate multiple errors for the same token position. +// +// For instance, the following test file indicates that a "not declared" +// error should be reported for the undeclared variable x: +// +// package p +// func f() { +// _ = x /* ERROR "not declared" */ + 1 +// } + +package types + +import ( + "fmt" + "go/ast" + "go/parser" + "go/scanner" + "go/token" + "io/ioutil" + "os" + "regexp" + "testing" +) + +// The test filenames do not end in .go so that they are invisible +// to gofmt since they contain comments that must not change their +// positions relative to surrounding tokens. + +var tests = []struct { + name string + files []string +}{ + {"test0", []string{"testdata/test0.src"}}, +} + +var fset = token.NewFileSet() + +// TODO(gri) This functionality should be in token.Fileset. +func getFile(filename string) *token.File { + for f := range fset.Files() { + if f.Name() == filename { + return f + } + } + return nil +} + +// TODO(gri) This functionality should be in token.Fileset. +func getPos(filename string, offset int) token.Pos { + if f := getFile(filename); f != nil { + return f.Pos(offset) + } + return token.NoPos +} + +// TODO(gri) Need to revisit parser interface. We should be able to use parser.ParseFiles +// or a similar function instead. +func parseFiles(t *testing.T, testname string, filenames []string) (map[string]*ast.File, os.Error) { + files := make(map[string]*ast.File) + var errors scanner.ErrorList + for _, filename := range filenames { + if _, exists := files[filename]; exists { + t.Fatalf("%s: duplicate file %s", testname, filename) + } + file, err := parser.ParseFile(fset, filename, nil, parser.DeclarationErrors) + if file == nil { + t.Fatalf("%s: could not parse file %s", testname, filename) + } + files[filename] = file + if err != nil { + // if the parser returns a non-scanner.ErrorList error + // the file couldn't be read in the first place and + // file == nil; in that case we shouldn't reach here + errors = append(errors, err.(scanner.ErrorList)...) + } + + } + return files, errors +} + +// ERROR comments must be of the form /* ERROR "rx" */ and rx is +// a regular expression that matches the expected error message. +// +var errRx = regexp.MustCompile(`^/\* *ERROR *"([^"]*)" *\*/$`) + +// expectedErrors collects the regular expressions of ERROR comments found +// in files and returns them as a map of error positions to error messages. +// +func expectedErrors(t *testing.T, testname string, files map[string]*ast.File) map[token.Pos]string { + errors := make(map[token.Pos]string) + for filename := range files { + src, err := ioutil.ReadFile(filename) + if err != nil { + t.Fatalf("%s: could not read %s", testname, filename) + } + + var s scanner.Scanner + // file was parsed already - do not add it again to the file + // set otherwise the position information returned here will + // not match the position information collected by the parser + s.Init(getFile(filename), src, nil, scanner.ScanComments) + var prev token.Pos // position of last non-comment token + + scanFile: + for { + pos, tok, lit := s.Scan() + switch tok { + case token.EOF: + break scanFile + case token.COMMENT: + s := errRx.FindStringSubmatch(lit) + if len(s) == 2 { + errors[prev] = string(s[1]) + } + default: + prev = pos + } + } + } + return errors +} + +func eliminate(t *testing.T, expected map[token.Pos]string, errors os.Error) { + if errors == nil { + return + } + for _, error := range errors.(scanner.ErrorList) { + // error.Pos is a token.Position, but we want + // a token.Pos so we can do a map lookup + // TODO(gri) Need to move scanner.Errors over + // to use token.Pos and file set info. + pos := getPos(error.Pos.Filename, error.Pos.Offset) + if msg, found := expected[pos]; found { + // we expect a message at pos; check if it matches + rx, err := regexp.Compile(msg) + if err != nil { + t.Errorf("%s: %v", error.Pos, err) + continue + } + if match := rx.MatchString(error.Msg); !match { + t.Errorf("%s: %q does not match %q", error.Pos, error.Msg, msg) + continue + } + // we have a match - eliminate this error + expected[pos] = "", false + } else { + // To keep in mind when analyzing failed test output: + // If the same error position occurs multiple times in errors, + // this message will be triggered (because the first error at + // the position removes this position from the expected errors). + t.Errorf("%s: no (multiple?) error expected, but found: %s", error.Pos, error.Msg) + } + } +} + +func check(t *testing.T, testname string, testfiles []string) { + // TODO(gri) Eventually all these different phases should be + // subsumed into a single function call that takes + // a set of files and creates a fully resolved and + // type-checked AST. + + files, err := parseFiles(t, testname, testfiles) + + // we are expecting the following errors + // (collect these after parsing the files so that + // they are found in the file set) + errors := expectedErrors(t, testname, files) + + // verify errors returned by the parser + eliminate(t, errors, err) + + // verify errors returned after resolving identifiers + pkg, err := ast.NewPackage(fset, files, GcImporter, Universe) + eliminate(t, errors, err) + + // verify errors returned by the typechecker + _, err = Check(fset, pkg) + eliminate(t, errors, err) + + // there should be no expected errors left + if len(errors) > 0 { + t.Errorf("%s: %d errors not reported:", testname, len(errors)) + for pos, msg := range errors { + t.Errorf("%s: %s\n", fset.Position(pos), msg) + } + } +} + +func TestCheck(t *testing.T) { + // For easy debugging w/o changing the testing code, + // if there is a local test file, only test that file. + const testfile = "test.go" + if fi, err := os.Stat(testfile); err == nil && fi.IsRegular() { + fmt.Printf("WARNING: Testing only %s (remove it to run all tests)\n", testfile) + check(t, testfile, []string{testfile}) + return + } + + // Otherwise, run all the tests. + for _, test := range tests { + check(t, test.name, test.files) + } +} diff --git a/libgo/go/go/types/const.go b/libgo/go/go/types/const.go index 6fdc22f..1ef95d9 100644 --- a/libgo/go/go/types/const.go +++ b/libgo/go/go/types/const.go @@ -12,7 +12,6 @@ import ( "strconv" ) - // TODO(gri) Consider changing the API so Const is an interface // and operations on consts don't have to type switch. @@ -28,20 +27,17 @@ type Const struct { val interface{} } - // Representation of complex values. type cmplx struct { re, im *big.Rat } - func assert(cond bool) { if !cond { panic("go/types internal error: assertion failed") } } - // MakeConst makes an ideal constant from a literal // token and the corresponding literal string. func MakeConst(tok token.Token, lit string) Const { @@ -75,14 +71,12 @@ func MakeConst(tok token.Token, lit string) Const { panic("unreachable") } - // MakeZero returns the zero constant for the given type. func MakeZero(typ *Type) Const { // TODO(gri) fix this return Const{0} } - // Match attempts to match the internal constant representations of x and y. // If the attempt is successful, the result is the values of x and y, // if necessary converted to have the same internal representation; otherwise @@ -132,7 +126,6 @@ func (x Const) Match(y Const) (u, v Const) { return } - // Convert attempts to convert the constant x to a given type. // If the attempt is successful, the result is the new constant; // otherwise the result is invalid. @@ -148,7 +141,6 @@ func (x Const) Convert(typ *Type) Const { return x } - func (x Const) String() string { switch x := x.val.(type) { case bool: @@ -169,12 +161,10 @@ func (x Const) String() string { panic("unreachable") } - func (x Const) UnaryOp(op token.Token) Const { panic("unimplemented") } - func (x Const) BinaryOp(op token.Token, y Const) Const { var z interface{} switch x := x.val.(type) { @@ -194,7 +184,6 @@ func (x Const) BinaryOp(op token.Token, y Const) Const { return Const{z} } - func binaryBoolOp(x bool, op token.Token, y bool) interface{} { switch op { case token.EQL: @@ -205,7 +194,6 @@ func binaryBoolOp(x bool, op token.Token, y bool) interface{} { panic("unreachable") } - func binaryIntOp(x *big.Int, op token.Token, y *big.Int) interface{} { var z big.Int switch op { @@ -247,7 +235,6 @@ func binaryIntOp(x *big.Int, op token.Token, y *big.Int) interface{} { panic("unreachable") } - func binaryFloatOp(x *big.Rat, op token.Token, y *big.Rat) interface{} { var z big.Rat switch op { @@ -275,7 +262,6 @@ func binaryFloatOp(x *big.Rat, op token.Token, y *big.Rat) interface{} { panic("unreachable") } - func binaryCmplxOp(x cmplx, op token.Token, y cmplx) interface{} { a, b := x.re, x.im c, d := y.re, y.im @@ -325,7 +311,6 @@ func binaryCmplxOp(x cmplx, op token.Token, y cmplx) interface{} { panic("unreachable") } - func binaryStringOp(x string, op token.Token, y string) interface{} { switch op { case token.ADD: diff --git a/libgo/go/go/types/exportdata.go b/libgo/go/go/types/exportdata.go index cb08ffe..3835203 100644 --- a/libgo/go/go/types/exportdata.go +++ b/libgo/go/go/types/exportdata.go @@ -15,7 +15,6 @@ import ( "strings" ) - func readGopackHeader(buf *bufio.Reader) (name string, size int, err os.Error) { // See $GOROOT/include/ar.h. hdr := make([]byte, 64+12+6+6+8+10+2) @@ -29,20 +28,18 @@ func readGopackHeader(buf *bufio.Reader) (name string, size int, err os.Error) { s := strings.TrimSpace(string(hdr[64+12+6+6+8:][:10])) size, err = strconv.Atoi(s) if err != nil || hdr[len(hdr)-2] != '`' || hdr[len(hdr)-1] != '\n' { - err = os.ErrorString("invalid archive header") + err = os.NewError("invalid archive header") return } name = strings.TrimSpace(string(hdr[:64])) return } - type dataReader struct { *bufio.Reader io.Closer } - // ExportData returns a readCloser positioned at the beginning of the // export data section of the given object/archive file, or an error. // It is the caller's responsibility to close the readCloser. @@ -80,7 +77,7 @@ func ExportData(filename string) (rc io.ReadCloser, err os.Error) { return } if name != "__.SYMDEF" { - err = os.ErrorString("go archive does not begin with __.SYMDEF") + err = os.NewError("go archive does not begin with __.SYMDEF") return } const block = 4096 @@ -102,7 +99,7 @@ func ExportData(filename string) (rc io.ReadCloser, err os.Error) { return } if name != "__.PKGDEF" { - err = os.ErrorString("go archive is missing __.PKGDEF") + err = os.NewError("go archive is missing __.PKGDEF") return } @@ -117,7 +114,7 @@ func ExportData(filename string) (rc io.ReadCloser, err os.Error) { // Now at __.PKGDEF in archive or still at beginning of file. // Either way, line should begin with "go object ". if !strings.HasPrefix(string(line), "go object ") { - err = os.ErrorString("not a go object file") + err = os.NewError("not a go object file") return } diff --git a/libgo/go/go/types/gcimporter.go b/libgo/go/go/types/gcimporter.go index 30adc04..6ab1806 100644 --- a/libgo/go/go/types/gcimporter.go +++ b/libgo/go/go/types/gcimporter.go @@ -20,7 +20,6 @@ import ( "strconv" ) - const trace = false // set to true for debugging var ( @@ -28,7 +27,6 @@ var ( pkgExts = [...]string{".a", ".5", ".6", ".8"} ) - // findPkg returns the filename and package id for an import path. // If no file was found, an empty filename is returned. func findPkg(path string) (filename, id string) { @@ -69,20 +67,17 @@ func findPkg(path string) (filename, id string) { return } - // gcParser parses the exports inside a gc compiler-produced // object/archive file and populates its scope with the results. type gcParser struct { scanner scanner.Scanner - tok int // current token - lit string // literal string; only valid for Ident, Int, String tokens - id string // package id of imported package - scope *ast.Scope // scope of imported package; alias for deps[id] - deps map[string]*ast.Scope // package id -> package scope + tok int // current token + lit string // literal string; only valid for Ident, Int, String tokens + id string // package id of imported package + imports map[string]*ast.Object // package id -> package object } - -func (p *gcParser) init(filename, id string, src io.Reader) { +func (p *gcParser) init(filename, id string, src io.Reader, imports map[string]*ast.Object) { p.scanner.Init(src) p.scanner.Error = func(_ *scanner.Scanner, msg string) { p.error(msg) } p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanStrings | scanner.ScanComments | scanner.SkipComments @@ -90,11 +85,9 @@ func (p *gcParser) init(filename, id string, src io.Reader) { p.scanner.Filename = filename // for good error messages p.next() p.id = id - p.scope = ast.NewScope(nil) - p.deps = map[string]*ast.Scope{"unsafe": Unsafe, id: p.scope} + p.imports = imports } - func (p *gcParser) next() { p.tok = p.scanner.Scan() switch p.tok { @@ -108,11 +101,10 @@ func (p *gcParser) next() { } } - // GcImporter implements the ast.Importer signature. -func GcImporter(path string) (name string, scope *ast.Scope, err os.Error) { +func GcImporter(imports map[string]*ast.Object, path string) (pkg *ast.Object, err os.Error) { if path == "unsafe" { - return path, Unsafe, nil + return Unsafe, nil } defer func() { @@ -126,10 +118,14 @@ func GcImporter(path string) (name string, scope *ast.Scope, err os.Error) { filename, id := findPkg(path) if filename == "" { - err = os.ErrorString("can't find import: " + id) + err = os.NewError("can't find import: " + id) return } + if pkg = imports[id]; pkg != nil { + return // package was imported before + } + buf, err := ExportData(filename) if err != nil { return @@ -137,17 +133,15 @@ func GcImporter(path string) (name string, scope *ast.Scope, err os.Error) { defer buf.Close() if trace { - fmt.Printf("importing %s\n", filename) + fmt.Printf("importing %s (%s)\n", id, filename) } var p gcParser - p.init(filename, id, buf) - name, scope = p.parseExport() - + p.init(filename, id, buf, imports) + pkg = p.parseExport() return } - // ---------------------------------------------------------------------------- // Error handling @@ -157,26 +151,22 @@ type importError struct { err os.Error } - func (e importError) String() string { return fmt.Sprintf("import error %s (byte offset = %d): %s", e.pos, e.pos.Offset, e.err) } - func (p *gcParser) error(err interface{}) { if s, ok := err.(string); ok { - err = os.ErrorString(s) + err = os.NewError(s) } // panic with a runtime.Error if err is not an os.Error panic(importError{p.scanner.Pos(), err.(os.Error)}) } - func (p *gcParser) errorf(format string, args ...interface{}) { p.error(fmt.Sprintf(format, args...)) } - func (p *gcParser) expect(tok int) string { lit := p.lit if p.tok != tok { @@ -186,7 +176,6 @@ func (p *gcParser) expect(tok int) string { return lit } - func (p *gcParser) expectSpecial(tok string) { sep := 'x' // not white space i := 0 @@ -200,7 +189,6 @@ func (p *gcParser) expectSpecial(tok string) { } } - func (p *gcParser) expectKeyword(keyword string) { lit := p.expect(scanner.Ident) if lit != keyword { @@ -208,29 +196,37 @@ func (p *gcParser) expectKeyword(keyword string) { } } - // ---------------------------------------------------------------------------- // Import declarations // ImportPath = string_lit . // -func (p *gcParser) parsePkgId() *ast.Scope { +func (p *gcParser) parsePkgId() *ast.Object { id, err := strconv.Unquote(p.expect(scanner.String)) if err != nil { p.error(err) } - scope := p.scope // id == "" stands for the imported package id - if id != "" { - if scope = p.deps[id]; scope == nil { - scope = ast.NewScope(nil) - p.deps[id] = scope - } + switch id { + case "": + // id == "" stands for the imported package id + // (only known at time of package installation) + id = p.id + case "unsafe": + // package unsafe is not in the imports map - handle explicitly + return Unsafe } - return scope -} + pkg := p.imports[id] + if pkg == nil { + scope = ast.NewScope(nil) + pkg = ast.NewObj(ast.Pkg, "") + pkg.Data = scope + p.imports[id] = pkg + } + return pkg +} // dotIdentifier = ( ident | '·' ) { ident | int | '·' } . func (p *gcParser) parseDotIdent() string { @@ -249,17 +245,17 @@ func (p *gcParser) parseDotIdent() string { return ident } - // ExportedName = ImportPath "." dotIdentifier . // func (p *gcParser) parseExportedName(kind ast.ObjKind) *ast.Object { - scope := p.parsePkgId() + pkg := p.parsePkgId() p.expect('.') name := p.parseDotIdent() // a type may have been declared before - if it exists // already in the respective package scope, return that // type + scope := pkg.Data.(*ast.Scope) if kind == ast.Typ { if obj := scope.Lookup(name); obj != nil { assert(obj.Kind == ast.Typ) @@ -283,7 +279,6 @@ func (p *gcParser) parseExportedName(kind ast.ObjKind) *ast.Object { return obj } - // ---------------------------------------------------------------------------- // Types @@ -297,7 +292,6 @@ func (p *gcParser) parseBasicType() Type { return obj.Type.(Type) } - // ArrayType = "[" int_lit "]" Type . // func (p *gcParser) parseArrayType() Type { @@ -312,7 +306,6 @@ func (p *gcParser) parseArrayType() Type { return &Array{Len: n, Elt: elt} } - // MapType = "map" "[" Type "]" Type . // func (p *gcParser) parseMapType() Type { @@ -324,7 +317,6 @@ func (p *gcParser) parseMapType() Type { return &Map{Key: key, Elt: elt} } - // Name = identifier | "?" . // func (p *gcParser) parseName() (name string) { @@ -341,156 +333,171 @@ func (p *gcParser) parseName() (name string) { return } - // Field = Name Type [ ":" string_lit ] . // -func (p *gcParser) parseField(scope *ast.Scope) { - // TODO(gri) The code below is not correct for anonymous fields: - // The name is the type name; it should not be empty. +func (p *gcParser) parseField() (fld *ast.Object, tag string) { name := p.parseName() ftyp := p.parseType() if name == "" { // anonymous field - ftyp must be T or *T and T must be a type name - ftyp = Deref(ftyp) - if ftyp, ok := ftyp.(*Name); ok { - name = ftyp.Obj.Name - } else { + if _, ok := Deref(ftyp).(*Name); !ok { p.errorf("anonymous field expected") } } if p.tok == ':' { p.next() - tag := p.expect(scanner.String) - _ = tag // TODO(gri) store tag somewhere + tag = p.expect(scanner.String) } - fld := ast.NewObj(ast.Var, name) + fld = ast.NewObj(ast.Var, name) fld.Type = ftyp - scope.Insert(fld) + return } - // StructType = "struct" "{" [ FieldList ] "}" . // FieldList = Field { ";" Field } . // func (p *gcParser) parseStructType() Type { + var fields []*ast.Object + var tags []string + + parseField := func() { + fld, tag := p.parseField() + fields = append(fields, fld) + tags = append(tags, tag) + } + p.expectKeyword("struct") p.expect('{') - scope := ast.NewScope(nil) if p.tok != '}' { - p.parseField(scope) + parseField() for p.tok == ';' { p.next() - p.parseField(scope) + parseField() } } p.expect('}') - return &Struct{} -} + return &Struct{Fields: fields, Tags: tags} +} -// Parameter = ( identifier | "?" ) [ "..." ] Type . +// Parameter = ( identifier | "?" ) [ "..." ] Type [ ":" string_lit ] . // -func (p *gcParser) parseParameter(scope *ast.Scope, isVariadic *bool) { +func (p *gcParser) parseParameter() (par *ast.Object, isVariadic bool) { name := p.parseName() if name == "" { name = "_" // cannot access unnamed identifiers } - if isVariadic != nil { - if *isVariadic { - p.error("... not on final argument") - } - if p.tok == '.' { - p.expectSpecial("...") - *isVariadic = true - } + if p.tok == '.' { + p.expectSpecial("...") + isVariadic = true } ptyp := p.parseType() - par := ast.NewObj(ast.Var, name) + // ignore argument tag + if p.tok == ':' { + p.next() + p.expect(scanner.String) + } + par = ast.NewObj(ast.Var, name) par.Type = ptyp - scope.Insert(par) + return } - // Parameters = "(" [ ParameterList ] ")" . // ParameterList = { Parameter "," } Parameter . // -func (p *gcParser) parseParameters(scope *ast.Scope, isVariadic *bool) { +func (p *gcParser) parseParameters() (list []*ast.Object, isVariadic bool) { + parseParameter := func() { + par, variadic := p.parseParameter() + list = append(list, par) + if variadic { + if isVariadic { + p.error("... not on final argument") + } + isVariadic = true + } + } + p.expect('(') if p.tok != ')' { - p.parseParameter(scope, isVariadic) + parseParameter() for p.tok == ',' { p.next() - p.parseParameter(scope, isVariadic) + parseParameter() } } p.expect(')') -} + return +} // Signature = Parameters [ Result ] . // Result = Type | Parameters . // -func (p *gcParser) parseSignature(scope *ast.Scope, isVariadic *bool) { - p.parseParameters(scope, isVariadic) +func (p *gcParser) parseSignature() *Func { + params, isVariadic := p.parseParameters() // optional result type + var results []*ast.Object switch p.tok { case scanner.Ident, scanner.String, '[', '*', '<': // single, unnamed result result := ast.NewObj(ast.Var, "_") result.Type = p.parseType() - scope.Insert(result) + results = []*ast.Object{result} case '(': // named or multiple result(s) - p.parseParameters(scope, nil) + var variadic bool + results, variadic = p.parseParameters() + if variadic { + p.error("... not permitted on result type") + } } -} - -// FuncType = "func" Signature . -// -func (p *gcParser) parseFuncType() Type { - // "func" already consumed - scope := ast.NewScope(nil) - isVariadic := false - p.parseSignature(scope, &isVariadic) - return &Func{IsVariadic: isVariadic} + return &Func{Params: params, Results: results, IsVariadic: isVariadic} } - // MethodSpec = identifier Signature . // -func (p *gcParser) parseMethodSpec(scope *ast.Scope) { +func (p *gcParser) parseMethodSpec() *ast.Object { if p.tok == scanner.Ident { p.expect(scanner.Ident) } else { + // TODO(gri) should this be parseExportedName here? p.parsePkgId() p.expect('.') p.parseDotIdent() } - isVariadic := false - p.parseSignature(scope, &isVariadic) -} + p.parseSignature() + // TODO(gri) compute method object + return ast.NewObj(ast.Fun, "_") +} // InterfaceType = "interface" "{" [ MethodList ] "}" . // MethodList = MethodSpec { ";" MethodSpec } . // func (p *gcParser) parseInterfaceType() Type { + var methods ObjList + + parseMethod := func() { + meth := p.parseMethodSpec() + methods = append(methods, meth) + } + p.expectKeyword("interface") p.expect('{') - scope := ast.NewScope(nil) if p.tok != '}' { - p.parseMethodSpec(scope) + parseMethod() for p.tok == ';' { p.next() - p.parseMethodSpec(scope) + parseMethod() } } p.expect('}') - return &Interface{} -} + methods.Sort() + return &Interface{Methods: methods} +} // ChanType = ( "chan" [ "<-" ] | "<-" "chan" ) Type . // @@ -511,7 +518,6 @@ func (p *gcParser) parseChanType() Type { return &Chan{Dir: dir, Elt: elt} } - // Type = // BasicType | TypeName | ArrayType | SliceType | StructType | // PointerType | FuncType | InterfaceType | MapType | ChanType | @@ -520,6 +526,7 @@ func (p *gcParser) parseChanType() Type { // TypeName = ExportedName . // SliceType = "[" "]" Type . // PointerType = "*" Type . +// FuncType = "func" Signature . // func (p *gcParser) parseType() Type { switch p.tok { @@ -530,8 +537,9 @@ func (p *gcParser) parseType() Type { case "struct": return p.parseStructType() case "func": - p.next() // parseFuncType assumes "func" is already consumed - return p.parseFuncType() + // FuncType + p.next() + return p.parseSignature() case "interface": return p.parseInterfaceType() case "map": @@ -567,7 +575,6 @@ func (p *gcParser) parseType() Type { return nil } - // ---------------------------------------------------------------------------- // Declarations @@ -578,12 +585,12 @@ func (p *gcParser) parseImportDecl() { // The identifier has no semantic meaning in the import data. // It exists so that error messages can print the real package // name: binary.ByteOrder instead of "encoding/binary".ByteOrder. - // TODO(gri): Save package id -> package name mapping. - p.expect(scanner.Ident) - p.parsePkgId() + name := p.expect(scanner.Ident) + pkg := p.parsePkgId() + assert(pkg.Name == "" || pkg.Name == name) + pkg.Name = name } - // int_lit = [ "+" | "-" ] { "0" ... "9" } . // func (p *gcParser) parseInt() (sign, val string) { @@ -598,7 +605,6 @@ func (p *gcParser) parseInt() (sign, val string) { return } - // number = int_lit [ "p" int_lit ] . // func (p *gcParser) parseNumber() Const { @@ -629,7 +635,6 @@ func (p *gcParser) parseNumber() Const { return Const{mant} } - // ConstDecl = "const" ExportedName [ Type ] "=" Literal . // Literal = bool_lit | int_lit | float_lit | complex_lit | string_lit . // bool_lit = "true" | "false" . @@ -681,24 +686,28 @@ func (p *gcParser) parseConstDecl() { if obj.Type == nil { obj.Type = typ } - _ = x // TODO(gri) store x somewhere + obj.Data = x } - // TypeDecl = "type" ExportedName Type . // func (p *gcParser) parseTypeDecl() { p.expectKeyword("type") obj := p.parseExportedName(ast.Typ) + + // The type object may have been imported before and thus already + // have a type associated with it. We still need to parse the type + // structure, but throw it away if the object already has a type. + // This ensures that all imports refer to the same type object for + // a given type declaration. typ := p.parseType() - name := obj.Type.(*Name) - assert(name.Underlying == nil) - assert(Underlying(typ) == typ) - name.Underlying = typ + if name := obj.Type.(*Name); name.Underlying == nil { + assert(Underlying(typ) == typ) + name.Underlying = typ + } } - // VarDecl = "var" ExportedName Type . // func (p *gcParser) parseVarDecl() { @@ -707,32 +716,26 @@ func (p *gcParser) parseVarDecl() { obj.Type = p.parseType() } - // FuncDecl = "func" ExportedName Signature . // func (p *gcParser) parseFuncDecl() { // "func" already consumed obj := p.parseExportedName(ast.Fun) - obj.Type = p.parseFuncType() + obj.Type = p.parseSignature() } - // MethodDecl = "func" Receiver identifier Signature . // Receiver = "(" ( identifier | "?" ) [ "*" ] ExportedName ")" . // func (p *gcParser) parseMethodDecl() { // "func" already consumed - scope := ast.NewScope(nil) // method scope p.expect('(') - p.parseParameter(scope, nil) // receiver + p.parseParameter() // receiver p.expect(')') p.expect(scanner.Ident) - isVariadic := false - p.parseSignature(scope, &isVariadic) - + p.parseSignature() } - // Decl = [ ImportDecl | ConstDecl | TypeDecl | VarDecl | FuncDecl | MethodDecl ] "\n" . // func (p *gcParser) parseDecl() { @@ -756,14 +759,13 @@ func (p *gcParser) parseDecl() { p.expect('\n') } - // ---------------------------------------------------------------------------- // Export // Export = "PackageClause { Decl } "$$" . // PackageClause = "package" identifier [ "safe" ] "\n" . // -func (p *gcParser) parseExport() (string, *ast.Scope) { +func (p *gcParser) parseExport() *ast.Object { p.expectKeyword("package") name := p.expect(scanner.Ident) if p.tok != '\n' { @@ -774,6 +776,11 @@ func (p *gcParser) parseExport() (string, *ast.Scope) { } p.expect('\n') + assert(p.imports[p.id] == nil) + pkg := ast.NewObj(ast.Pkg, name) + pkg.Data = ast.NewScope(nil) + p.imports[p.id] = pkg + for p.tok != '$' && p.tok != scanner.EOF { p.parseDecl() } @@ -788,5 +795,5 @@ func (p *gcParser) parseExport() (string, *ast.Scope) { p.errorf("expected no scanner errors, got %d", n) } - return name, p.scope + return pkg } diff --git a/libgo/go/go/types/gcimporter_test.go b/libgo/go/go/types/gcimporter_test.go index 556e761..ec87f5d 100644 --- a/libgo/go/go/types/gcimporter_test.go +++ b/libgo/go/go/types/gcimporter_test.go @@ -6,6 +6,7 @@ package types import ( "exec" + "go/ast" "io/ioutil" "path/filepath" "runtime" @@ -14,7 +15,6 @@ import ( "time" ) - var gcName, gcPath string // compiler name and path func init() { @@ -34,31 +34,23 @@ func init() { gcPath, _ = exec.LookPath(gcName) } - func compile(t *testing.T, dirname, filename string) { - cmd, err := exec.Run(gcPath, []string{gcPath, filename}, nil, dirname, exec.DevNull, exec.Pipe, exec.MergeWithStdout) + cmd := exec.Command(gcPath, filename) + cmd.Dir = dirname + out, err := cmd.CombinedOutput() if err != nil { t.Errorf("%s %s failed: %s", gcName, filename, err) return } - defer cmd.Close() - - msg, err := cmd.Wait(0) - if err != nil { - t.Errorf("%s %s failed: %s", gcName, filename, err) - return - } - - if !msg.Exited() || msg.ExitStatus() != 0 { - t.Errorf("%s %s failed: exit status = %d", gcName, filename, msg.ExitStatus()) - output, _ := ioutil.ReadAll(cmd.Stdout) - t.Log(string(output)) - } + t.Logf("%s", string(out)) } +// Use the same global imports map for all tests. The effect is +// as if all tested packages were imported into a single package. +var imports = make(map[string]*ast.Object) func testPath(t *testing.T, path string) bool { - _, _, err := GcImporter(path) + _, err := GcImporter(imports, path) if err != nil { t.Errorf("testPath(%s): %s", path, err) return false @@ -66,7 +58,6 @@ func testPath(t *testing.T, path string) bool { return true } - const maxTime = 3e9 // maximum allotted testing time in ns func testDir(t *testing.T, dir string, endTime int64) (nimports int) { @@ -98,7 +89,6 @@ func testDir(t *testing.T, dir string, endTime int64) (nimports int) { return } - func TestGcImport(t *testing.T) { compile(t, "testdata", "exports.go") diff --git a/libgo/go/go/types/testdata/exports.go b/libgo/go/go/types/testdata/exports.go index 13efe01..ed63bf9 100644 --- a/libgo/go/go/types/testdata/exports.go +++ b/libgo/go/go/types/testdata/exports.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// This file is used to generate a .6 object file which +// This file is used to generate an object file which // serves as test file for gcimporter_test.go. package exports @@ -11,19 +11,17 @@ import ( "go/ast" ) - const ( C0 int = 0 - C1 = 3.14159265 - C2 = 2.718281828i - C3 = -123.456e-789 - C4 = +123.456E+789 - C5 = 1234i - C6 = "foo\n" - C7 = `bar\n` + C1 = 3.14159265 + C2 = 2.718281828i + C3 = -123.456e-789 + C4 = +123.456E+789 + C5 = 1234i + C6 = "foo\n" + C7 = `bar\n` ) - type ( T1 int T2 [10]int @@ -38,7 +36,7 @@ type ( T9 struct { a int b, c float32 - d []string "tag" + d []string `go:"tag"` } T10 struct { T8 @@ -72,18 +70,15 @@ type ( T28 func(T28) T28 ) - var ( V0 int V1 = -991.0 ) - func F1() {} func F2(x int) {} func F3() int { return 0 } func F4() float32 { return 0 } func F5(a, b, c int, u, v, w struct{ x, y T1 }, more ...interface{}) (p, q, r chan<- T10) - func (p *T1) M1() diff --git a/libgo/go/go/types/types.go b/libgo/go/go/types/types.go index 2ee645d..3aa8968 100644 --- a/libgo/go/go/types/types.go +++ b/libgo/go/go/types/types.go @@ -7,21 +7,27 @@ // package types -import "go/ast" - +import ( + "go/ast" + "sort" +) // All types implement the Type interface. type Type interface { isType() } - // All concrete types embed ImplementsType which // ensures that all types implement the Type interface. type ImplementsType struct{} func (t *ImplementsType) isType() {} +// A Bad type is a non-nil placeholder type when we don't know a type. +type Bad struct { + ImplementsType + Msg string // for better error reporting/debugging +} // A Basic represents a (unnamed) basic type. type Basic struct { @@ -29,7 +35,6 @@ type Basic struct { // TODO(gri) need a field specifying the exact basic type } - // An Array represents an array type [Len]Elt. type Array struct { ImplementsType @@ -37,50 +42,52 @@ type Array struct { Elt Type } - // A Slice represents a slice type []Elt. type Slice struct { ImplementsType Elt Type } - // A Struct represents a struct type struct{...}. +// Anonymous fields are represented by objects with empty names. type Struct struct { ImplementsType - // TODO(gri) need to remember fields. + Fields ObjList // struct fields; or nil + Tags []string // corresponding tags; or nil + // TODO(gri) This type needs some rethinking: + // - at the moment anonymous fields are marked with "" object names, + // and their names have to be reconstructed + // - there is no scope for fast lookup (but the parser creates one) } - // A Pointer represents a pointer type *Base. type Pointer struct { ImplementsType Base Type } - // A Func represents a function type func(...) (...). +// Unnamed parameters are represented by objects with empty names. type Func struct { ImplementsType - IsVariadic bool - // TODO(gri) need to remember parameters. + Recv *ast.Object // nil if not a method + Params ObjList // (incoming) parameters from left to right; or nil + Results ObjList // (outgoing) results from left to right; or nil + IsVariadic bool // true if the last parameter's type is of the form ...T } - // An Interface represents an interface type interface{...}. type Interface struct { ImplementsType - // TODO(gri) need to remember methods. + Methods ObjList // interface methods sorted by name; or nil } - // A Map represents a map type map[Key]Elt. type Map struct { ImplementsType Key, Elt Type } - // A Chan represents a channel type chan Elt, <-chan Elt, or chan<-Elt. type Chan struct { ImplementsType @@ -88,7 +95,6 @@ type Chan struct { Elt Type } - // A Name represents a named type as declared in a type declaration. type Name struct { ImplementsType @@ -97,7 +103,6 @@ type Name struct { // TODO(gri) need to remember fields and methods. } - // If typ is a pointer type, Deref returns the pointer's base type; // otherwise it returns typ. func Deref(typ Type) Type { @@ -107,16 +112,144 @@ func Deref(typ Type) Type { return typ } - // Underlying returns the underlying type of a type. func Underlying(typ Type) Type { if typ, ok := typ.(*Name); ok { utyp := typ.Underlying - if _, ok := utyp.(*Basic); ok { - return typ + if _, ok := utyp.(*Basic); !ok { + return utyp } - return utyp - + // the underlying type of a type name referring + // to an (untyped) basic type is the basic type + // name } return typ } + +// An ObjList represents an ordered (in some fashion) list of objects. +type ObjList []*ast.Object + +// ObjList implements sort.Interface. +func (list ObjList) Len() int { return len(list) } +func (list ObjList) Less(i, j int) bool { return list[i].Name < list[j].Name } +func (list ObjList) Swap(i, j int) { list[i], list[j] = list[j], list[i] } + +// Sort sorts an object list by object name. +func (list ObjList) Sort() { sort.Sort(list) } + +// identicalTypes returns true if both lists a and b have the +// same length and corresponding objects have identical types. +func identicalTypes(a, b ObjList) bool { + if len(a) == len(b) { + for i, x := range a { + y := b[i] + if !Identical(x.Type.(Type), y.Type.(Type)) { + return false + } + } + return true + } + return false +} + +// Identical returns true if two types are identical. +func Identical(x, y Type) bool { + if x == y { + return true + } + + switch x := x.(type) { + case *Bad: + // A Bad type is always identical to any other type + // (to avoid spurious follow-up errors). + return true + + case *Basic: + if y, ok := y.(*Basic); ok { + panic("unimplemented") + _ = y + } + + case *Array: + // Two array types are identical if they have identical element types + // and the same array length. + if y, ok := y.(*Array); ok { + return x.Len == y.Len && Identical(x.Elt, y.Elt) + } + + case *Slice: + // Two slice types are identical if they have identical element types. + if y, ok := y.(*Slice); ok { + return Identical(x.Elt, y.Elt) + } + + case *Struct: + // Two struct types are identical if they have the same sequence of fields, + // and if corresponding fields have the same names, and identical types, + // and identical tags. Two anonymous fields are considered to have the same + // name. Lower-case field names from different packages are always different. + if y, ok := y.(*Struct); ok { + // TODO(gri) handle structs from different packages + if identicalTypes(x.Fields, y.Fields) { + for i, f := range x.Fields { + g := y.Fields[i] + if f.Name != g.Name || x.Tags[i] != y.Tags[i] { + return false + } + } + return true + } + } + + case *Pointer: + // Two pointer types are identical if they have identical base types. + if y, ok := y.(*Pointer); ok { + return Identical(x.Base, y.Base) + } + + case *Func: + // Two function types are identical if they have the same number of parameters + // and result values, corresponding parameter and result types are identical, + // and either both functions are variadic or neither is. Parameter and result + // names are not required to match. + if y, ok := y.(*Func); ok { + return identicalTypes(x.Params, y.Params) && + identicalTypes(x.Results, y.Results) && + x.IsVariadic == y.IsVariadic + } + + case *Interface: + // Two interface types are identical if they have the same set of methods with + // the same names and identical function types. Lower-case method names from + // different packages are always different. The order of the methods is irrelevant. + if y, ok := y.(*Interface); ok { + return identicalTypes(x.Methods, y.Methods) // methods are sorted + } + + case *Map: + // Two map types are identical if they have identical key and value types. + if y, ok := y.(*Map); ok { + return Identical(x.Key, y.Key) && Identical(x.Elt, y.Elt) + } + + case *Chan: + // Two channel types are identical if they have identical value types + // and the same direction. + if y, ok := y.(*Chan); ok { + return x.Dir == y.Dir && Identical(x.Elt, y.Elt) + } + + case *Name: + // Two named types are identical if their type names originate + // in the same type declaration. + if y, ok := y.(*Name); ok { + return x.Obj == y.Obj || + // permit bad objects to be equal to avoid + // follow up errors + x.Obj != nil && x.Obj.Kind == ast.Bad || + y.Obj != nil && y.Obj.Kind == ast.Bad + } + } + + return false +} diff --git a/libgo/go/go/types/universe.go b/libgo/go/go/types/universe.go index 2a54a8a..6ae88e5 100644 --- a/libgo/go/go/types/universe.go +++ b/libgo/go/go/types/universe.go @@ -9,14 +9,12 @@ package types import "go/ast" - var ( - scope, // current scope to use for initialization - Universe, - Unsafe *ast.Scope + scope *ast.Scope // current scope to use for initialization + Universe *ast.Scope + Unsafe *ast.Object // package unsafe ) - func define(kind ast.ObjKind, name string) *ast.Object { obj := ast.NewObj(kind, name) if scope.Insert(obj) != nil { @@ -25,7 +23,6 @@ func define(kind ast.ObjKind, name string) *ast.Object { return obj } - func defType(name string) *Name { obj := define(ast.Typ, name) typ := &Name{Underlying: &Basic{}, Obj: obj} @@ -33,19 +30,16 @@ func defType(name string) *Name { return typ } - func defConst(name string) { obj := define(ast.Con, name) _ = obj // TODO(gri) fill in other properties } - func defFun(name string) { obj := define(ast.Fun, name) _ = obj // TODO(gri) fill in other properties } - var ( Bool, Int, @@ -54,10 +48,9 @@ var ( String *Name ) - func init() { - Universe = ast.NewScope(nil) - scope = Universe + scope = ast.NewScope(nil) + Universe = scope Bool = defType("bool") defType("byte") // TODO(gri) should be an alias for uint8 @@ -98,8 +91,10 @@ func init() { defFun("real") defFun("recover") - Unsafe = ast.NewScope(nil) - scope = Unsafe + scope = ast.NewScope(nil) + Unsafe = ast.NewObj(ast.Pkg, "unsafe") + Unsafe.Data = scope + defType("Pointer") defFun("Alignof") diff --git a/libgo/go/gob/codec_test.go b/libgo/go/gob/codec_test.go index 8961336..a5fb91c 100644 --- a/libgo/go/gob/codec_test.go +++ b/libgo/go/gob/codec_test.go @@ -330,7 +330,7 @@ func newDecodeStateFromData(data []byte) *decoderState { // Test instruction execution for decoding. // Do not run the machine yet; instead do individual instructions crafted by hand. func TestScalarDecInstructions(t *testing.T) { - ovfl := os.ErrorString("overflow") + ovfl := os.NewError("overflow") // bool { @@ -573,30 +573,32 @@ func TestEndToEnd(t *testing.T) { s1 := "string1" s2 := "string2" type T1 struct { - A, B, C int - M map[string]*float64 - N *[3]float64 - Strs *[2]string - Int64s *[]int64 - RI complex64 - S string - Y []byte - T *T2 + A, B, C int + M map[string]*float64 + EmptyMap map[string]int // to check that we receive a non-nil map. + N *[3]float64 + Strs *[2]string + Int64s *[]int64 + RI complex64 + S string + Y []byte + T *T2 } pi := 3.14159 e := 2.71828 t1 := &T1{ - A: 17, - B: 18, - C: -5, - M: map[string]*float64{"pi": &pi, "e": &e}, - N: &[3]float64{1.5, 2.5, 3.5}, - Strs: &[2]string{s1, s2}, - Int64s: &[]int64{77, 89, 123412342134}, - RI: 17 - 23i, - S: "Now is the time", - Y: []byte("hello, sailor"), - T: &T2{"this is T2"}, + A: 17, + B: 18, + C: -5, + M: map[string]*float64{"pi": &pi, "e": &e}, + EmptyMap: make(map[string]int), + N: &[3]float64{1.5, 2.5, 3.5}, + Strs: &[2]string{s1, s2}, + Int64s: &[]int64{77, 89, 123412342134}, + RI: 17 - 23i, + S: "Now is the time", + Y: []byte("hello, sailor"), + T: &T2{"this is T2"}, } b := new(bytes.Buffer) err := NewEncoder(b).Encode(t1) @@ -611,6 +613,13 @@ func TestEndToEnd(t *testing.T) { if !reflect.DeepEqual(t1, &_t1) { t.Errorf("encode expected %v got %v", *t1, _t1) } + // Be absolutely sure the received map is non-nil. + if t1.EmptyMap == nil { + t.Errorf("nil map sent") + } + if _t1.EmptyMap == nil { + t.Errorf("nil map received") + } } func TestOverflow(t *testing.T) { @@ -782,7 +791,6 @@ func TestOverflow(t *testing.T) { } } - func TestNesting(t *testing.T) { type RT struct { A string @@ -980,7 +988,6 @@ func TestIgnoredFields(t *testing.T) { } } - func TestBadRecursiveType(t *testing.T) { type Rec ***Rec var rec Rec diff --git a/libgo/go/gob/decode.go b/libgo/go/gob/decode.go index 0e86df6..bf7cb95 100644 --- a/libgo/go/gob/decode.go +++ b/libgo/go/gob/decode.go @@ -17,9 +17,9 @@ import ( ) var ( - errBadUint = os.ErrorString("gob: encoded unsigned integer out of range") - errBadType = os.ErrorString("gob: unknown type id or corrupted data") - errRange = os.ErrorString("gob: bad data: field numbers out of bounds") + errBadUint = os.NewError("gob: encoded unsigned integer out of range") + errBadType = os.NewError("gob: unknown type id or corrupted data") + errRange = os.NewError("gob: bad data: field numbers out of bounds") ) // decoderState is the execution state of an instance of the decoder. A new state @@ -54,8 +54,8 @@ func (dec *Decoder) freeDecoderState(d *decoderState) { dec.freeList = d } -func overflow(name string) os.ErrorString { - return os.ErrorString(`value for "` + name + `" out of range`) +func overflow(name string) os.Error { + return os.NewError(`value for "` + name + `" out of range`) } // decodeUintReader reads an encoded unsigned integer from an io.Reader. @@ -135,10 +135,10 @@ type decOp func(i *decInstr, state *decoderState, p unsafe.Pointer) // The 'instructions' of the decoding machine type decInstr struct { op decOp - field int // field number of the wire type - indir int // how many pointer indirections to reach the value in the struct - offset uintptr // offset in the structure of the field to encode - ovfl os.ErrorString // error message for overflow/underflow (for arrays, of the elements) + field int // field number of the wire type + indir int // how many pointer indirections to reach the value in the struct + offset uintptr // offset in the structure of the field to encode + ovfl os.Error // error message for overflow/underflow (for arrays, of the elements) } // Since the encoder writes no zeros, if we arrive at a decoder we have @@ -172,7 +172,7 @@ func ignoreTwoUints(i *decInstr, state *decoderState, p unsafe.Pointer) { state.decodeUint() } -// decBool decodes a uiint and stores it as a boolean through p. +// decBool decodes a uint and stores it as a boolean through p. func decBool(i *decInstr, state *decoderState, p unsafe.Pointer) { if i.indir > 0 { if *(*unsafe.Pointer)(p) == nil { @@ -367,7 +367,7 @@ func decComplex64(i *decInstr, state *decoderState, p unsafe.Pointer) { p = *(*unsafe.Pointer)(p) } storeFloat32(i, state, p) - storeFloat32(i, state, unsafe.Pointer(uintptr(p)+uintptr(unsafe.Sizeof(float32(0))))) + storeFloat32(i, state, unsafe.Pointer(uintptr(p)+unsafe.Sizeof(float32(0)))) } // decComplex128 decodes a pair of unsigned integers, treats them as a @@ -552,7 +552,7 @@ func (dec *Decoder) ignoreSingle(engine *decEngine) { } // decodeArrayHelper does the work for decoding arrays and slices. -func (dec *Decoder) decodeArrayHelper(state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, length, elemIndir int, ovfl os.ErrorString) { +func (dec *Decoder) decodeArrayHelper(state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, length, elemIndir int, ovfl os.Error) { instr := &decInstr{elemOp, 0, elemIndir, 0, ovfl} for i := 0; i < length; i++ { up := unsafe.Pointer(p) @@ -567,7 +567,7 @@ func (dec *Decoder) decodeArrayHelper(state *decoderState, p uintptr, elemOp dec // decodeArray decodes an array and stores it through p, that is, p points to the zeroth element. // The length is an unsigned integer preceding the elements. Even though the length is redundant // (it's part of the type), it's a useful check and is included in the encoding. -func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, length, indir, elemIndir int, ovfl os.ErrorString) { +func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, length, indir, elemIndir int, ovfl os.Error) { if indir > 0 { p = allocate(atyp, p, 1) // All but the last level has been allocated by dec.Indirect } @@ -579,7 +579,7 @@ func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, p uintpt // decodeIntoValue is a helper for map decoding. Since maps are decoded using reflection, // unlike the other items we can't use a pointer directly. -func decodeIntoValue(state *decoderState, op decOp, indir int, v reflect.Value, ovfl os.ErrorString) reflect.Value { +func decodeIntoValue(state *decoderState, op decOp, indir int, v reflect.Value, ovfl os.Error) reflect.Value { instr := &decInstr{op, 0, indir, 0, ovfl} up := unsafe.Pointer(unsafeAddr(v)) if indir > 1 { @@ -593,7 +593,7 @@ func decodeIntoValue(state *decoderState, op decOp, indir int, v reflect.Value, // Maps are encoded as a length followed by key:value pairs. // Because the internals of maps are not visible to us, we must // use reflection rather than pointer magic. -func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, p uintptr, keyOp, elemOp decOp, indir, keyIndir, elemIndir int, ovfl os.ErrorString) { +func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, p uintptr, keyOp, elemOp decOp, indir, keyIndir, elemIndir int, ovfl os.Error) { if indir > 0 { p = allocate(mtyp, p, 1) // All but the last level has been allocated by dec.Indirect } @@ -616,7 +616,7 @@ func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, p uintptr, // ignoreArrayHelper does the work for discarding arrays and slices. func (dec *Decoder) ignoreArrayHelper(state *decoderState, elemOp decOp, length int) { - instr := &decInstr{elemOp, 0, 0, 0, os.ErrorString("no error")} + instr := &decInstr{elemOp, 0, 0, 0, os.NewError("no error")} for i := 0; i < length; i++ { elemOp(instr, state, nil) } @@ -633,8 +633,8 @@ func (dec *Decoder) ignoreArray(state *decoderState, elemOp decOp, length int) { // ignoreMap discards the data for a map value with no destination. func (dec *Decoder) ignoreMap(state *decoderState, keyOp, elemOp decOp) { n := int(state.decodeUint()) - keyInstr := &decInstr{keyOp, 0, 0, 0, os.ErrorString("no error")} - elemInstr := &decInstr{elemOp, 0, 0, 0, os.ErrorString("no error")} + keyInstr := &decInstr{keyOp, 0, 0, 0, os.NewError("no error")} + elemInstr := &decInstr{elemOp, 0, 0, 0, os.NewError("no error")} for i := 0; i < n; i++ { keyOp(keyInstr, state, nil) elemOp(elemInstr, state, nil) @@ -643,7 +643,7 @@ func (dec *Decoder) ignoreMap(state *decoderState, keyOp, elemOp decOp) { // decodeSlice decodes a slice and stores the slice header through p. // Slices are encoded as an unsigned length followed by the elements. -func (dec *Decoder) decodeSlice(atyp reflect.Type, state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, indir, elemIndir int, ovfl os.ErrorString) { +func (dec *Decoder) decodeSlice(atyp reflect.Type, state *decoderState, p uintptr, elemOp decOp, elemWid uintptr, indir, elemIndir int, ovfl os.Error) { n := int(uintptr(state.decodeUint())) if indir > 0 { up := unsafe.Pointer(p) @@ -741,7 +741,7 @@ func (dec *Decoder) ignoreInterface(state *decoderState) { // decodeGobDecoder decodes something implementing the GobDecoder interface. // The data is encoded as a byte slice. -func (dec *Decoder) decodeGobDecoder(state *decoderState, v reflect.Value, index int) { +func (dec *Decoder) decodeGobDecoder(state *decoderState, v reflect.Value) { // Read the bytes for the value. b := make([]byte, state.decodeUint()) _, err := state.b.Read(b) @@ -969,7 +969,7 @@ func (dec *Decoder) gobDecodeOpFor(ut *userTypeInfo) (*decOp, int) { } else { v = reflect.ValueOf(unsafe.Unreflect(rcvrType, p)) } - state.dec.decodeGobDecoder(state, v, methodIndex(rcvrType, gobDecodeMethodName)) + state.dec.decodeGobDecoder(state, v) } return &op, int(ut.indir) @@ -1064,10 +1064,10 @@ func (dec *Decoder) compileSingle(remoteId typeId, ut *userTypeInfo) (engine *de engine.instr = make([]decInstr, 1) // one item name := rt.String() // best we can do if !dec.compatibleType(rt, remoteId, make(map[reflect.Type]typeId)) { - return nil, os.ErrorString("gob: wrong type received for local value " + name + ": " + dec.typeString(remoteId)) + return nil, os.NewError("gob: wrong type received for local value " + name + ": " + dec.typeString(remoteId)) } op, indir := dec.decOpFor(remoteId, rt, name, make(map[reflect.Type]*decOp)) - ovfl := os.ErrorString(`value for "` + name + `" out of range`) + ovfl := os.NewError(`value for "` + name + `" out of range`) engine.instr[singletonField] = decInstr{*op, singletonField, indir, 0, ovfl} engine.numInstr = 1 return diff --git a/libgo/go/gob/decoder.go b/libgo/go/gob/decoder.go index ea2f62e..2819471 100644 --- a/libgo/go/gob/decoder.go +++ b/libgo/go/gob/decoder.go @@ -44,7 +44,7 @@ func NewDecoder(r io.Reader) *Decoder { func (dec *Decoder) recvType(id typeId) { // Have we already seen this type? That's an error if id < firstUserId || dec.wireType[id] != nil { - dec.err = os.ErrorString("gob: duplicate type received") + dec.err = os.NewError("gob: duplicate type received") return } @@ -143,7 +143,7 @@ func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId { // will be absorbed by recvMessage.) if dec.buf.Len() > 0 { if !isInterface { - dec.err = os.ErrorString("extra data in buffer") + dec.err = os.NewError("extra data in buffer") break } dec.nextUint() @@ -155,8 +155,8 @@ func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId { // Decode reads the next value from the connection and stores // it in the data represented by the empty interface value. // If e is nil, the value will be discarded. Otherwise, -// the value underlying e must either be the correct type for the next -// data item received, and must be a pointer. +// the value underlying e must be a pointer to the +// correct type for the next data item received. func (dec *Decoder) Decode(e interface{}) os.Error { if e == nil { return dec.DecodeValue(reflect.Value{}) @@ -165,7 +165,7 @@ func (dec *Decoder) Decode(e interface{}) os.Error { // If e represents a value as opposed to a pointer, the answer won't // get back to the caller. Make sure it's a pointer. if value.Type().Kind() != reflect.Ptr { - dec.err = os.ErrorString("gob: attempt to decode into a non-pointer") + dec.err = os.NewError("gob: attempt to decode into a non-pointer") return dec.err } return dec.DecodeValue(value) @@ -180,7 +180,7 @@ func (dec *Decoder) DecodeValue(v reflect.Value) os.Error { if v.Kind() == reflect.Ptr && !v.IsNil() { // That's okay, we'll store through the pointer. } else if !v.CanSet() { - return os.ErrorString("gob: DecodeValue of unassignable value") + return os.NewError("gob: DecodeValue of unassignable value") } } // Make sure we're single-threaded through here. diff --git a/libgo/go/gob/doc.go b/libgo/go/gob/doc.go index 850759b..35d882a 100644 --- a/libgo/go/gob/doc.go +++ b/libgo/go/gob/doc.go @@ -29,29 +29,29 @@ receiver and transmitter will do all necessary indirection and dereferencing to convert between gobs and actual Go values. For instance, a gob type that is schematically, - struct { a, b int } + struct { A, B int } can be sent from or received into any of these Go types: - struct { a, b int } // the same - *struct { a, b int } // extra indirection of the struct - struct { *a, **b int } // extra indirection of the fields - struct { a, b int64 } // different concrete value type; see below + struct { A, B int } // the same + *struct { A, B int } // extra indirection of the struct + struct { *A, **B int } // extra indirection of the fields + struct { A, B int64 } // different concrete value type; see below It may also be received into any of these: - struct { a, b int } // the same - struct { b, a int } // ordering doesn't matter; matching is by name - struct { a, b, c int } // extra field (c) ignored - struct { b int } // missing field (a) ignored; data will be dropped - struct { b, c int } // missing field (a) ignored; extra field (c) ignored. + struct { A, B int } // the same + struct { B, A int } // ordering doesn't matter; matching is by name + struct { A, B, C int } // extra field (C) ignored + struct { B int } // missing field (A) ignored; data will be dropped + struct { B, C int } // missing field (A) ignored; extra field (C) ignored. Attempting to receive into these types will draw a decode error: - struct { a int; b uint } // change of signedness for b - struct { a int; b float } // change of type for b + struct { A int; B uint } // change of signedness for B + struct { A int; B float } // change of type for B struct { } // no field names in common - struct { c, d int } // no field names in common + struct { C, D int } // no field names in common Integers are transmitted two ways: arbitrary precision signed integers or arbitrary precision unsigned integers. There is no int8, int16 etc. @@ -113,6 +113,11 @@ uninterpreted bytes of the value. All other slices and arrays are sent as an unsigned count followed by that many elements using the standard gob encoding for their type, recursively. +Maps are sent as an unsigned count followed by that man key, element +pairs. Empty but non-nil maps are sent, so if the sender has allocated +a map, the receiver will allocate a map even no elements are +transmitted. + Structs are sent as a sequence of (field number, field value) pairs. The field value is sent using the standard gob encoding for its type, recursively. If a field has the zero value for its type, it is omitted from the transmission. The @@ -269,12 +274,12 @@ StructValue: /* For implementers and the curious, here is an encoded example. Given - type Point struct {x, y int} + type Point struct {X, Y int} and the value p := Point{22, 33} the bytes transmitted that encode p will be: 1f ff 81 03 01 01 05 50 6f 69 6e 74 01 ff 82 00 - 01 02 01 01 78 01 04 00 01 01 79 01 04 00 00 00 + 01 02 01 01 58 01 04 00 01 01 59 01 04 00 00 00 07 ff 82 01 2c 01 42 00 They are determined as follows. @@ -310,13 +315,13 @@ reserved). 02 // There are two fields in the type (len(structType.field)) 01 // Start of first field structure; add 1 to get field number 0: field[0].name 01 // 1 byte - 78 // structType.field[0].name = "x" + 58 // structType.field[0].name = "X" 01 // Add 1 to get field number 1: field[0].id 04 // structType.field[0].typeId is 2 (signed int). 00 // End of structType.field[0]; start structType.field[1]; set field number to -1. 01 // Add 1 to get field number 0: field[1].name 01 // 1 byte - 79 // structType.field[1].name = "y" + 59 // structType.field[1].name = "Y" 01 // Add 1 to get field number 1: field[0].id 04 // struct.Type.field[1].typeId is 2 (signed int). 00 // End of structType.field[1]; end of structType.field. diff --git a/libgo/go/gob/encode.go b/libgo/go/gob/encode.go index f9e691a..317014e 100644 --- a/libgo/go/gob/encode.go +++ b/libgo/go/gob/encode.go @@ -11,7 +11,7 @@ import ( "unsafe" ) -const uint64Size = unsafe.Sizeof(uint64(0)) +const uint64Size = int(unsafe.Sizeof(uint64(0))) // encoderState is the global execution state of an instance of the encoder. // Field numbers are delta encoded and always increase. The field @@ -62,7 +62,7 @@ func (state *encoderState) encodeUint(x uint64) { var n, m int m = uint64Size for n = 1; x > 0; n++ { - state.buf[m] = uint8(x & 0xFF) + state.buf[m] = uint8(x) x >>= 8 m-- } @@ -466,9 +466,30 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) { enc.freeEncoderState(state) } +// isZero returns whether the value is the zero of its type. +func isZero(val reflect.Value) bool { + switch val.Kind() { + case reflect.Array, reflect.Map, reflect.Slice, reflect.String: + return val.Len() == 0 + case reflect.Bool: + return !val.Bool() + case reflect.Complex64, reflect.Complex128: + return val.Complex() == 0 + case reflect.Chan, reflect.Func, reflect.Ptr: + return val.IsNil() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return val.Int() == 0 + case reflect.Float32, reflect.Float64: + return val.Float() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return val.Uint() == 0 + } + panic("unknown type in isZero " + val.Type().String()) +} + // encGobEncoder encodes a value that implements the GobEncoder interface. // The data is sent as a byte array. -func (enc *Encoder) encodeGobEncoder(b *bytes.Buffer, v reflect.Value, index int) { +func (enc *Encoder) encodeGobEncoder(b *bytes.Buffer, v reflect.Value) { // TODO: should we catch panics from the called method? // We know it's a GobEncoder, so just call the method directly. data, err := v.Interface().(GobEncoder).GobEncode() @@ -557,7 +578,9 @@ func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp // the iteration. v := reflect.ValueOf(unsafe.Unreflect(t, unsafe.Pointer(p))) mv := reflect.Indirect(v) - if !state.sendZero && mv.Len() == 0 { + // We send zero-length (but non-nil) maps because the + // receiver might want to use the map. (Maps don't use append.) + if !state.sendZero && mv.IsNil() { return } state.update(i) @@ -592,17 +615,6 @@ func (enc *Encoder) encOpFor(rt reflect.Type, inProgress map[reflect.Type]*encOp return &op, indir } -// methodIndex returns which method of rt implements the method. -func methodIndex(rt reflect.Type, method string) int { - for i := 0; i < rt.NumMethod(); i++ { - if rt.Method(i).Name == method { - return i - } - } - errorf("internal error: can't find method %s", method) - return 0 -} - // gobEncodeOpFor returns the op for a type that is known to implement // GobEncoder. func (enc *Encoder) gobEncodeOpFor(ut *userTypeInfo) (*encOp, int) { @@ -623,8 +635,11 @@ func (enc *Encoder) gobEncodeOpFor(ut *userTypeInfo) (*encOp, int) { } else { v = reflect.ValueOf(unsafe.Unreflect(rt, p)) } + if !state.sendZero && isZero(v) { + return + } state.update(i) - state.enc.encodeGobEncoder(state.b, v, methodIndex(rt, gobEncodeMethodName)) + state.enc.encodeGobEncoder(state.b, v) } return &op, int(ut.encIndir) // encIndir: op will get called with p == address of receiver. } diff --git a/libgo/go/gob/encoder.go b/libgo/go/gob/encoder.go index 65ee5bf..96101d9 100644 --- a/libgo/go/gob/encoder.go +++ b/libgo/go/gob/encoder.go @@ -50,7 +50,7 @@ func (enc *Encoder) popWriter() { } func (enc *Encoder) badType(rt reflect.Type) { - enc.setError(os.ErrorString("gob: can't encode type " + rt.String())) + enc.setError(os.NewError("gob: can't encode type " + rt.String())) } func (enc *Encoder) setError(err os.Error) { diff --git a/libgo/go/gob/encoder_test.go b/libgo/go/gob/encoder_test.go index 792afbd..f5ee423 100644 --- a/libgo/go/gob/encoder_test.go +++ b/libgo/go/gob/encoder_test.go @@ -549,3 +549,32 @@ func TestMapBug1(t *testing.T) { t.Errorf("mismatch: %v %v", in, out) } } + +func TestGobMapInterfaceEncode(t *testing.T) { + m := map[string]interface{}{ + "up": uintptr(0), + "i0": []int{-1}, + "i1": []int8{-1}, + "i2": []int16{-1}, + "i3": []int32{-1}, + "i4": []int64{-1}, + "u0": []uint{1}, + "u1": []uint8{1}, + "u2": []uint16{1}, + "u3": []uint32{1}, + "u4": []uint64{1}, + "f0": []float32{1}, + "f1": []float64{1}, + "c0": []complex64{complex(2, -2)}, + "c1": []complex128{complex(2, float64(-2))}, + "us": []uintptr{0}, + "bo": []bool{false}, + "st": []string{"s"}, + } + buf := bytes.NewBuffer(nil) + enc := NewEncoder(buf) + err := enc.Encode(m) + if err != nil { + t.Errorf("gob.Encode map: %s", err) + } +} diff --git a/libgo/go/gob/gobencdec_test.go b/libgo/go/gob/gobencdec_test.go index e94534f..371a43c 100644 --- a/libgo/go/gob/gobencdec_test.go +++ b/libgo/go/gob/gobencdec_test.go @@ -44,7 +44,7 @@ func (g *ByteStruct) GobEncode() ([]byte, os.Error) { func (g *ByteStruct) GobDecode(data []byte) os.Error { if g == nil { - return os.ErrorString("NIL RECEIVER") + return os.NewError("NIL RECEIVER") } // Expect N sequential-valued bytes. if len(data) == 0 { @@ -53,7 +53,7 @@ func (g *ByteStruct) GobDecode(data []byte) os.Error { g.a = data[0] for i, c := range data { if c != g.a+byte(i) { - return os.ErrorString("invalid data sequence") + return os.NewError("invalid data sequence") } } return nil @@ -71,7 +71,7 @@ func (g *StringStruct) GobDecode(data []byte) os.Error { a := data[0] for i, c := range data { if c != a+byte(i) { - return os.ErrorString("invalid data sequence") + return os.NewError("invalid data sequence") } } g.s = string(data) @@ -84,7 +84,7 @@ func (a *ArrayStruct) GobEncode() ([]byte, os.Error) { func (a *ArrayStruct) GobDecode(data []byte) os.Error { if len(data) != len(a.a) { - return os.ErrorString("wrong length in array decode") + return os.NewError("wrong length in array decode") } copy(a.a[:], data) return nil @@ -384,7 +384,7 @@ func TestGobEncoderFieldTypeError(t *testing.T) { y := &GobTest1{} err = dec.Decode(y) if err == nil { - t.Fatal("expected decode error for mistmatched fields (non-encoder to decoder)") + t.Fatal("expected decode error for mismatched fields (non-encoder to decoder)") } if strings.Index(err.String(), "type") < 0 { t.Fatal("expected type error; got", err) @@ -466,3 +466,25 @@ func TestGobEncoderIgnoreNonStructField(t *testing.T) { t.Errorf("expected 17 got %c", x.X) } } + +func TestGobEncoderIgnoreNilEncoder(t *testing.T) { + b := new(bytes.Buffer) + // First a field that's a structure. + enc := NewEncoder(b) + err := enc.Encode(GobTest0{X: 18}) // G is nil + if err != nil { + t.Fatal("encode error:", err) + } + dec := NewDecoder(b) + x := new(GobTest0) + err = dec.Decode(x) + if err != nil { + t.Fatal("decode error:", err) + } + if x.X != 18 { + t.Errorf("expected x.X = 18, got %v", x.X) + } + if x.G != nil { + t.Errorf("expected x.G = nil, got %v", x.G) + } +} diff --git a/libgo/go/gob/timing_test.go b/libgo/go/gob/timing_test.go index 645f4fe..2a2be73 100644 --- a/libgo/go/gob/timing_test.go +++ b/libgo/go/gob/timing_test.go @@ -53,6 +53,7 @@ func TestCountEncodeMallocs(t *testing.T) { var buf bytes.Buffer enc := NewEncoder(&buf) bench := &Bench{7, 3.2, "now is the time", []byte("for all good men")} + runtime.UpdateMemStats() mallocs := 0 - runtime.MemStats.Mallocs const count = 1000 for i := 0; i < count; i++ { @@ -61,6 +62,7 @@ func TestCountEncodeMallocs(t *testing.T) { t.Fatal("encode:", err) } } + runtime.UpdateMemStats() mallocs += runtime.MemStats.Mallocs fmt.Printf("mallocs per encode of type Bench: %d\n", mallocs/count) } @@ -77,6 +79,7 @@ func TestCountDecodeMallocs(t *testing.T) { } } dec := NewDecoder(&buf) + runtime.UpdateMemStats() mallocs := 0 - runtime.MemStats.Mallocs for i := 0; i < count; i++ { *bench = Bench{} @@ -85,6 +88,7 @@ func TestCountDecodeMallocs(t *testing.T) { t.Fatal("decode:", err) } } + runtime.UpdateMemStats() mallocs += runtime.MemStats.Mallocs fmt.Printf("mallocs per decode of type Bench: %d\n", mallocs/count) } diff --git a/libgo/go/gob/type.go b/libgo/go/gob/type.go index c5b8fb5..b2f716c 100644 --- a/libgo/go/gob/type.go +++ b/libgo/go/gob/type.go @@ -67,7 +67,7 @@ func validUserType(rt reflect.Type) (ut *userTypeInfo, err os.Error) { ut.base = pt.Elem() if ut.base == slowpoke { // ut.base lapped slowpoke // recursive pointer type. - return nil, os.ErrorString("can't represent recursive pointer type " + ut.base.String()) + return nil, os.NewError("can't represent recursive pointer type " + ut.base.String()) } if ut.indir%2 == 0 { slowpoke = slowpoke.Elem() @@ -80,14 +80,9 @@ func validUserType(rt reflect.Type) (ut *userTypeInfo, err os.Error) { return } -const ( - gobEncodeMethodName = "GobEncode" - gobDecodeMethodName = "GobDecode" -) - var ( - gobEncoderInterfaceType = reflect.TypeOf(new(GobEncoder)).Elem() - gobDecoderInterfaceType = reflect.TypeOf(new(GobDecoder)).Elem() + gobEncoderInterfaceType = reflect.TypeOf((*GobEncoder)(nil)).Elem() + gobDecoderInterfaceType = reflect.TypeOf((*GobDecoder)(nil)).Elem() ) // implementsInterface reports whether the type implements the @@ -508,7 +503,7 @@ func newTypeObject(name string, ut *userTypeInfo, rt reflect.Type) (gobType, os. return st, nil default: - return nil, os.ErrorString("gob NewTypeObject can't handle type: " + rt.String()) + return nil, os.NewError("gob NewTypeObject can't handle type: " + rt.String()) } return nil, nil } @@ -673,7 +668,7 @@ func mustGetTypeInfo(rt reflect.Type) *typeInfo { // A type that implements GobEncoder and GobDecoder has complete // control over the representation of its data and may therefore // contain things such as private fields, channels, and functions, -// which are not usually transmissable in gob streams. +// which are not usually transmissible in gob streams. // // Note: Since gobs can be stored permanently, It is good design // to guarantee the encoding used by a GobEncoder is stable as the @@ -767,7 +762,25 @@ func registerBasics() { Register(float64(0)) Register(complex64(0i)) Register(complex128(0i)) + Register(uintptr(0)) Register(false) Register("") Register([]byte(nil)) + Register([]int(nil)) + Register([]int8(nil)) + Register([]int16(nil)) + Register([]int32(nil)) + Register([]int64(nil)) + Register([]uint(nil)) + Register([]uint8(nil)) + Register([]uint16(nil)) + Register([]uint32(nil)) + Register([]uint64(nil)) + Register([]float32(nil)) + Register([]float64(nil)) + Register([]complex64(nil)) + Register([]complex128(nil)) + Register([]uintptr(nil)) + Register([]bool(nil)) + Register([]string(nil)) } diff --git a/libgo/go/hash/crc32/crc32.go b/libgo/go/hash/crc32/crc32.go index 88a4499..0245b1e 100644 --- a/libgo/go/hash/crc32/crc32.go +++ b/libgo/go/hash/crc32/crc32.go @@ -10,6 +10,7 @@ package crc32 import ( "hash" "os" + "sync" ) // The size of a CRC-32 checksum in bytes. @@ -35,8 +36,34 @@ const ( // Table is a 256-word table representing the polynomial for efficient processing. type Table [256]uint32 +// castagnoliTable points to a lazily initialized Table for the Castagnoli +// polynomial. MakeTable will always return this value when asked to make a +// Castagnoli table so we can compare against it to find when the caller is +// using this polynomial. +var castagnoliTable *Table +var castagnoliOnce sync.Once + +func castagnoliInit() { + castagnoliTable = makeTable(Castagnoli) +} + +// IEEETable is the table for the IEEE polynomial. +var IEEETable = makeTable(IEEE) + // MakeTable returns the Table constructed from the specified polynomial. func MakeTable(poly uint32) *Table { + switch poly { + case IEEE: + return IEEETable + case Castagnoli: + castagnoliOnce.Do(castagnoliInit) + return castagnoliTable + } + return makeTable(poly) +} + +// makeTable returns the Table constructed from the specified polynomial. +func makeTable(poly uint32) *Table { t := new(Table) for i := 0; i < 256; i++ { crc := uint32(i) @@ -52,9 +79,6 @@ func MakeTable(poly uint32) *Table { return t } -// IEEETable is the table for the IEEE polynomial. -var IEEETable = MakeTable(IEEE) - // digest represents the partial evaluation of a checksum. type digest struct { crc uint32 @@ -83,11 +107,14 @@ func update(crc uint32, tab *Table, p []byte) uint32 { // Update returns the result of adding the bytes in p to the crc. func Update(crc uint32, tab *Table, p []byte) uint32 { + if tab == castagnoliTable { + return updateCastagnoli(crc, p) + } return update(crc, tab, p) } func (d *digest) Write(p []byte) (n int, err os.Error) { - d.crc = update(d.crc, d.tab, p) + d.crc = Update(d.crc, d.tab, p) return len(p), nil } @@ -105,7 +132,7 @@ func (d *digest) Sum() []byte { // Checksum returns the CRC-32 checksum of data // using the polynomial represented by the Table. -func Checksum(data []byte, tab *Table) uint32 { return update(0, tab, data) } +func Checksum(data []byte, tab *Table) uint32 { return Update(0, tab, data) } // ChecksumIEEE returns the CRC-32 checksum of data // using the IEEE polynomial. diff --git a/libgo/go/hash/crc32/crc32_amd64.go b/libgo/go/hash/crc32/crc32_amd64.go new file mode 100644 index 0000000..83349bc --- /dev/null +++ b/libgo/go/hash/crc32/crc32_amd64.go @@ -0,0 +1,25 @@ +// 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 crc32 + +// This file contains the code to call the SSE 4.2 version of the Castagnoli +// CRC. + +// haveSSE42 is defined in crc_amd64.s and uses CPUID to test for SSE 4.2 +// support. +func haveSSE42() bool + +// castagnoliSSE42 is defined in crc_amd64.s and uses the SSE4.2 CRC32 +// instruction. +func castagnoliSSE42(uint32, []byte) uint32 + +var sse42 = haveSSE42() + +func updateCastagnoli(crc uint32, p []byte) uint32 { + if sse42 { + return castagnoliSSE42(crc, p) + } + return update(crc, castagnoliTable, p) +} diff --git a/libgo/go/hash/crc32/crc32_generic.go b/libgo/go/hash/crc32/crc32_generic.go new file mode 100644 index 0000000..27aabd9 --- /dev/null +++ b/libgo/go/hash/crc32/crc32_generic.go @@ -0,0 +1,12 @@ +// 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 crc32 + +// The file contains the generic version of updateCastagnoli which just calls +// the software implementation. + +func updateCastagnoli(crc uint32, p []byte) uint32 { + return update(crc, castagnoliTable, p) +} diff --git a/libgo/go/hash/crc32/crc32_test.go b/libgo/go/hash/crc32/crc32_test.go index cf5743c..7e82dd7 100644 --- a/libgo/go/hash/crc32/crc32_test.go +++ b/libgo/go/hash/crc32/crc32_test.go @@ -10,53 +10,73 @@ import ( ) type test struct { - out uint32 - in string + ieee, castagnoli uint32 + in string } var golden = []test{ - {0x0, ""}, - {0xe8b7be43, "a"}, - {0x9e83486d, "ab"}, - {0x352441c2, "abc"}, - {0xed82cd11, "abcd"}, - {0x8587d865, "abcde"}, - {0x4b8e39ef, "abcdef"}, - {0x312a6aa6, "abcdefg"}, - {0xaeef2a50, "abcdefgh"}, - {0x8da988af, "abcdefghi"}, - {0x3981703a, "abcdefghij"}, - {0x6b9cdfe7, "Discard medicine more than two years old."}, - {0xc90ef73f, "He who has a shady past knows that nice guys finish last."}, - {0xb902341f, "I wouldn't marry him with a ten foot pole."}, - {0x42080e8, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"}, - {0x154c6d11, "The days of the digital watch are numbered. -Tom Stoppard"}, - {0x4c418325, "Nepal premier won't resign."}, - {0x33955150, "For every action there is an equal and opposite government program."}, - {0x26216a4b, "His money is twice tainted: 'taint yours and 'taint mine."}, - {0x1abbe45e, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"}, - {0xc89a94f7, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"}, - {0xab3abe14, "size: a.out: bad magic"}, - {0xbab102b6, "The major problem is with sendmail. -Mark Horton"}, - {0x999149d7, "Give me a rock, paper and scissors and I will move the world. CCFestoon"}, - {0x6d52a33c, "If the enemy is within range, then so are you."}, - {0x90631e8d, "It's well we cannot hear the screams/That we create in others' dreams."}, - {0x78309130, "You remind me of a TV show, but that's all right: I watch it anyway."}, - {0x7d0a377f, "C is as portable as Stonehedge!!"}, - {0x8c79fd79, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"}, - {0xa20b7167, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"}, - {0x8e0bb443, "How can you write a big system without C++? -Paul Glick"}, + {0x0, 0x0, ""}, + {0xe8b7be43, 0xc1d04330, "a"}, + {0x9e83486d, 0xe2a22936, "ab"}, + {0x352441c2, 0x364b3fb7, "abc"}, + {0xed82cd11, 0x92c80a31, "abcd"}, + {0x8587d865, 0xc450d697, "abcde"}, + {0x4b8e39ef, 0x53bceff1, "abcdef"}, + {0x312a6aa6, 0xe627f441, "abcdefg"}, + {0xaeef2a50, 0xa9421b7, "abcdefgh"}, + {0x8da988af, 0x2ddc99fc, "abcdefghi"}, + {0x3981703a, 0xe6599437, "abcdefghij"}, + {0x6b9cdfe7, 0xb2cc01fe, "Discard medicine more than two years old."}, + {0xc90ef73f, 0xe28207f, "He who has a shady past knows that nice guys finish last."}, + {0xb902341f, 0xbe93f964, "I wouldn't marry him with a ten foot pole."}, + {0x42080e8, 0x9e3be0c3, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"}, + {0x154c6d11, 0xf505ef04, "The days of the digital watch are numbered. -Tom Stoppard"}, + {0x4c418325, 0x85d3dc82, "Nepal premier won't resign."}, + {0x33955150, 0xc5142380, "For every action there is an equal and opposite government program."}, + {0x26216a4b, 0x75eb77dd, "His money is twice tainted: 'taint yours and 'taint mine."}, + {0x1abbe45e, 0x91ebe9f7, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"}, + {0xc89a94f7, 0xf0b1168e, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"}, + {0xab3abe14, 0x572b74e2, "size: a.out: bad magic"}, + {0xbab102b6, 0x8a58a6d5, "The major problem is with sendmail. -Mark Horton"}, + {0x999149d7, 0x9c426c50, "Give me a rock, paper and scissors and I will move the world. CCFestoon"}, + {0x6d52a33c, 0x735400a4, "If the enemy is within range, then so are you."}, + {0x90631e8d, 0xbec49c95, "It's well we cannot hear the screams/That we create in others' dreams."}, + {0x78309130, 0xa95a2079, "You remind me of a TV show, but that's all right: I watch it anyway."}, + {0x7d0a377f, 0xde2e65c5, "C is as portable as Stonehedge!!"}, + {0x8c79fd79, 0x297a88ed, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"}, + {0xa20b7167, 0x66ed1d8b, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"}, + {0x8e0bb443, 0xdcded527, "How can you write a big system without C++? -Paul Glick"}, } func TestGolden(t *testing.T) { - for i := 0; i < len(golden); i++ { - g := golden[i] - c := NewIEEE() - io.WriteString(c, g.in) - s := c.Sum32() - if s != g.out { - t.Errorf("crc32(%s) = 0x%x want 0x%x", g.in, s, g.out) - t.FailNow() + castagnoliTab := MakeTable(Castagnoli) + + for _, g := range golden { + ieee := NewIEEE() + io.WriteString(ieee, g.in) + s := ieee.Sum32() + if s != g.ieee { + t.Errorf("IEEE(%s) = 0x%x want 0x%x", g.in, s, g.ieee) + } + + castagnoli := New(castagnoliTab) + io.WriteString(castagnoli, g.in) + s = castagnoli.Sum32() + if s != g.castagnoli { + t.Errorf("Castagnoli(%s) = 0x%x want 0x%x", g.in, s, g.castagnoli) + } + + if len(g.in) > 0 { + // The SSE4.2 implementation of this has code to deal + // with misaligned data so we ensure that we test that + // too. + castagnoli = New(castagnoliTab) + io.WriteString(castagnoli, g.in[:1]) + io.WriteString(castagnoli, g.in[1:]) + s = castagnoli.Sum32() + if s != g.castagnoli { + t.Errorf("Castagnoli[misaligned](%s) = 0x%x want 0x%x", g.in, s, g.castagnoli) + } } } } @@ -69,6 +89,7 @@ func BenchmarkCrc32KB(b *testing.B) { } c := NewIEEE() b.StartTimer() + b.SetBytes(int64(len(data))) for i := 0; i < b.N; i++ { c.Write(data) diff --git a/libgo/go/hash/fnv/fnv.go b/libgo/go/hash/fnv/fnv.go index 9a1c6a0..3ff7d7c 100644 --- a/libgo/go/hash/fnv/fnv.go +++ b/libgo/go/hash/fnv/fnv.go @@ -11,7 +11,6 @@ import ( "encoding/binary" "hash" "os" - "unsafe" ) type ( @@ -102,31 +101,31 @@ func (s *sum64a) Write(data []byte) (int, os.Error) { return len(data), nil } -func (s *sum32) Size() int { return unsafe.Sizeof(*s) } -func (s *sum32a) Size() int { return unsafe.Sizeof(*s) } -func (s *sum64) Size() int { return unsafe.Sizeof(*s) } -func (s *sum64a) Size() int { return unsafe.Sizeof(*s) } +func (s *sum32) Size() int { return 4 } +func (s *sum32a) Size() int { return 4 } +func (s *sum64) Size() int { return 8 } +func (s *sum64a) Size() int { return 8 } func (s *sum32) Sum() []byte { - a := make([]byte, unsafe.Sizeof(*s)) + a := make([]byte, 4) binary.BigEndian.PutUint32(a, uint32(*s)) return a } func (s *sum32a) Sum() []byte { - a := make([]byte, unsafe.Sizeof(*s)) + a := make([]byte, 4) binary.BigEndian.PutUint32(a, uint32(*s)) return a } func (s *sum64) Sum() []byte { - a := make([]byte, unsafe.Sizeof(*s)) + a := make([]byte, 8) binary.BigEndian.PutUint64(a, uint64(*s)) return a } func (s *sum64a) Sum() []byte { - a := make([]byte, unsafe.Sizeof(*s)) + a := make([]byte, 8) binary.BigEndian.PutUint64(a, uint64(*s)) return a } diff --git a/libgo/go/html/const.go b/libgo/go/html/const.go new file mode 100644 index 0000000..9078d26 --- /dev/null +++ b/libgo/go/html/const.go @@ -0,0 +1,90 @@ +// 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 html + +// Section 11.2.3.2 of the HTML5 specification says "The following elements +// have varying levels of special parsing rules". +// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#the-stack-of-open-elements +var isSpecialElement = map[string]bool{ + "address": true, + "applet": true, + "area": true, + "article": true, + "aside": true, + "base": true, + "basefont": true, + "bgsound": true, + "blockquote": true, + "body": true, + "br": true, + "button": true, + "caption": true, + "center": true, + "col": true, + "colgroup": true, + "command": true, + "dd": true, + "details": true, + "dir": true, + "div": true, + "dl": true, + "dt": true, + "embed": true, + "fieldset": true, + "figcaption": true, + "figure": true, + "footer": true, + "form": true, + "frame": true, + "frameset": true, + "h1": true, + "h2": true, + "h3": true, + "h4": true, + "h5": true, + "h6": true, + "head": true, + "header": true, + "hgroup": true, + "hr": true, + "html": true, + "iframe": true, + "img": true, + "input": true, + "isindex": true, + "li": true, + "link": true, + "listing": true, + "marquee": true, + "menu": true, + "meta": true, + "nav": true, + "noembed": true, + "noframes": true, + "noscript": true, + "object": true, + "ol": true, + "p": true, + "param": true, + "plaintext": true, + "pre": true, + "script": true, + "section": true, + "select": true, + "style": true, + "summary": true, + "table": true, + "tbody": true, + "td": true, + "textarea": true, + "tfoot": true, + "th": true, + "thead": true, + "title": true, + "tr": true, + "ul": true, + "wbr": true, + "xmp": true, +} diff --git a/libgo/go/html/doc.go b/libgo/go/html/doc.go index 55135c3..5bc0630 100644 --- a/libgo/go/html/doc.go +++ b/libgo/go/html/doc.go @@ -4,6 +4,7 @@ /* Package html implements an HTML5-compliant tokenizer and parser. +INCOMPLETE. Tokenization is done by creating a Tokenizer for an io.Reader r. It is the caller's responsibility to ensure that r provides UTF-8 encoded HTML. diff --git a/libgo/go/html/entity.go b/libgo/go/html/entity.go index 1530290..21263e2 100644 --- a/libgo/go/html/entity.go +++ b/libgo/go/html/entity.go @@ -4,6 +4,9 @@ package html +// All entities that do not end with ';' are 6 or fewer bytes long. +const longestEntityWithoutSemicolon = 6 + // entity is a map from HTML entity names to their values. The semicolon matters: // http://www.whatwg.org/specs/web-apps/current-work/multipage/named-character-references.html // lists both "amp" and "amp;" as two separate entries. diff --git a/libgo/go/html/entity_test.go b/libgo/go/html/entity_test.go index a1eb4d4..2cf49d6 100644 --- a/libgo/go/html/entity_test.go +++ b/libgo/go/html/entity_test.go @@ -17,6 +17,9 @@ func TestEntityLength(t *testing.T) { if 1+len(k) < utf8.RuneLen(v) { t.Error("escaped entity &" + k + " is shorter than its UTF-8 encoding " + string(v)) } + if len(k) > longestEntityWithoutSemicolon && k[len(k)-1] != ';' { + t.Errorf("entity name %s is %d characters, but longestEntityWithoutSemicolon=%d", k, len(k), longestEntityWithoutSemicolon) + } } for k, v := range entity2 { if 1+len(k) < utf8.RuneLen(v[0])+utf8.RuneLen(v[1]) { diff --git a/libgo/go/html/escape.go b/libgo/go/html/escape.go index 2799f69..0de97c5 100644 --- a/libgo/go/html/escape.go +++ b/libgo/go/html/escape.go @@ -53,7 +53,8 @@ var replacementTable = [...]int{ // unescapeEntity reads an entity like "<" from b[src:] and writes the // corresponding "<" to b[dst:], returning the incremented dst and src cursors. // Precondition: b[src] == '&' && dst <= src. -func unescapeEntity(b []byte, dst, src int) (dst1, src1 int) { +// attribute should be true if parsing an attribute value. +func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) { // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#consume-a-character-reference // i starts at 1 because we already know that s[0] == '&'. @@ -121,12 +122,11 @@ func unescapeEntity(b []byte, dst, src int) (dst1, src1 int) { // Consume the maximum number of characters possible, with the // consumed characters matching one of the named references. - // TODO(nigeltao): unescape("¬it;") should be "¬it;" for i < len(s) { c := s[i] i++ // Lower-cased characters are more common in entities, so we check for them first. - if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' { + if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' { continue } if c != ';' { @@ -136,11 +136,25 @@ func unescapeEntity(b []byte, dst, src int) (dst1, src1 int) { } entityName := string(s[1:i]) - if x := entity[entityName]; x != 0 { + if entityName == "" { + // No-op. + } else if attribute && entityName[len(entityName)-1] != ';' && len(s) > i && s[i] == '=' { + // No-op. + } else if x := entity[entityName]; x != 0 { return dst + utf8.EncodeRune(b[dst:], x), src + i - } else if x := entity2[entityName]; x[0] != 0 { // Check if it's a two-character entity. + } else if x := entity2[entityName]; x[0] != 0 { dst1 := dst + utf8.EncodeRune(b[dst:], x[0]) return dst1 + utf8.EncodeRune(b[dst1:], x[1]), src + i + } else if !attribute { + maxLen := len(entityName) - 1 + if maxLen > longestEntityWithoutSemicolon { + maxLen = longestEntityWithoutSemicolon + } + for j := maxLen; j > 1; j-- { + if x := entity[entityName[:j]]; x != 0 { + return dst + utf8.EncodeRune(b[dst:], x), src + j + 1 + } + } } dst1, src1 = dst+i, src+i @@ -152,11 +166,11 @@ func unescapeEntity(b []byte, dst, src int) (dst1, src1 int) { func unescape(b []byte) []byte { for i, c := range b { if c == '&' { - dst, src := unescapeEntity(b, i, i) + dst, src := unescapeEntity(b, i, i, false) for src < len(b) { c := b[src] if c == '&' { - dst, src = unescapeEntity(b, dst, src) + dst, src = unescapeEntity(b, dst, src, false) } else { b[dst] = c dst, src = dst+1, src+1 diff --git a/libgo/go/html/node.go b/libgo/go/html/node.go new file mode 100644 index 0000000..4ecfd6c --- /dev/null +++ b/libgo/go/html/node.go @@ -0,0 +1,147 @@ +// 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 html + +// A NodeType is the type of a Node. +type NodeType int + +const ( + ErrorNode NodeType = iota + TextNode + DocumentNode + ElementNode + CommentNode + DoctypeNode + scopeMarkerNode +) + +// Section 11.2.3.3 says "scope markers are inserted when entering applet +// elements, buttons, object elements, marquees, table cells, and table +// captions, and are used to prevent formatting from 'leaking'". +var scopeMarker = Node{Type: scopeMarkerNode} + +// A Node consists of a NodeType and some Data (tag name for element nodes, +// content for text) and are part of a tree of Nodes. Element nodes may also +// contain a slice of Attributes. Data is unescaped, so that it looks like +// "a 0 { + return (*s)[i-1] + } + return nil +} + +// index returns the index of the top-most occurence of n in the stack, or -1 +// if n is not present. +func (s *nodeStack) index(n *Node) int { + for i := len(*s) - 1; i >= 0; i-- { + if (*s)[i] == n { + return i + } + } + return -1 +} + +// insert inserts a node at the given index. +func (s *nodeStack) insert(i int, n *Node) { + (*s) = append(*s, nil) + copy((*s)[i+1:], (*s)[i:]) + (*s)[i] = n +} + +// remove removes a node from the stack. It is a no-op if n is not present. +func (s *nodeStack) remove(n *Node) { + i := s.index(n) + if i == -1 { + return + } + copy((*s)[i:], (*s)[i+1:]) + j := len(*s) - 1 + (*s)[j] = nil + *s = (*s)[:j] +} + +// forTag returns the top-most element node with the given tag. +func (s *nodeStack) forTag(tag string) *Node { + for i := len(*s) - 1; i >= 0; i-- { + n := (*s)[i] + if n.Type == ElementNode && n.Data == tag { + return n + } + } + return nil +} diff --git a/libgo/go/html/parse.go b/libgo/go/html/parse.go index 2ef90a8..519ebe5 100644 --- a/libgo/go/html/parse.go +++ b/libgo/go/html/parse.go @@ -9,29 +9,6 @@ import ( "os" ) -// A NodeType is the type of a Node. -type NodeType int - -const ( - ErrorNode NodeType = iota - TextNode - DocumentNode - ElementNode - CommentNode -) - -// A Node consists of a NodeType and some Data (tag name for element nodes, -// content for text) and are part of a tree of Nodes. Element nodes may also -// contain a slice of Attributes. Data is unescaped, so that it looks like -// "a 0 { - return p.stack[n-1] + if n := p.oe.top(); n != nil { + return n } return p.doc } -// pop pops the top of the stack of open elements. -// It will panic if the stack is empty. -func (p *parser) pop() *Node { - n := len(p.stack) - ret := p.stack[n-1] - p.stack = p.stack[:n-1] - return ret -} - -// stopTags for use in popUntil. These come from section 10.2.3.2. +// stopTags for use in popUntil. These come from section 11.2.3.2. var ( defaultScopeStopTags = []string{"applet", "caption", "html", "table", "td", "th", "marquee", "object"} listItemScopeStopTags = []string{"applet", "caption", "html", "table", "td", "th", "marquee", "object", "ol", "ul"} @@ -102,11 +64,11 @@ var ( // popUntil([]string{"html, "table"}, "table") would return true and leave: // ["html", "body", "font"] func (p *parser) popUntil(stopTags []string, matchTags ...string) bool { - for i := len(p.stack) - 1; i >= 0; i-- { - tag := p.stack[i].Data + for i := len(p.oe) - 1; i >= 0; i-- { + tag := p.oe[i].Data for _, t := range matchTags { if t == tag { - p.stack = p.stack[:i] + p.oe = p.oe[:i] return true } } @@ -119,20 +81,24 @@ func (p *parser) popUntil(stopTags []string, matchTags ...string) bool { return false } -// addChild adds a child node n to the top element, and pushes n if it is an -// element node (text nodes are not part of the stack of open elements). +// addChild adds a child node n to the top element, and pushes n onto the stack +// of open elements if it is an element node. func (p *parser) addChild(n *Node) { - m := p.top() - m.Child = append(m.Child, n) + p.top().Add(n) if n.Type == ElementNode { - p.push(n) + p.oe = append(p.oe, n) } } -// addText calls addChild with a text node. +// addText adds text to the preceding node if it is a text node, or else it +// calls addChild with a new text node. func (p *parser) addText(text string) { - // TODO: merge s with previous text, if the preceding node is a text node. // TODO: distinguish whitespace text from others. + t := p.top() + if i := len(t.Child); i > 0 && t.Child[i-1].Type == TextNode { + t.Child[i-1].Data += text + return + } p.addChild(&Node{ Type: TextNode, Data: text, @@ -148,15 +114,50 @@ func (p *parser) addElement(tag string, attr []Attribute) { }) } -// Section 10.2.3.3. +// Section 11.2.3.3. func (p *parser) addFormattingElement(tag string, attr []Attribute) { p.addElement(tag, attr) + p.afe = append(p.afe, p.top()) // TODO. } -// Section 10.2.3.3. +// Section 11.2.3.3. +func (p *parser) clearActiveFormattingElements() { + for { + n := p.afe.pop() + if len(p.afe) == 0 || n.Type == scopeMarkerNode { + return + } + } +} + +// Section 11.2.3.3. func (p *parser) reconstructActiveFormattingElements() { - // TODO. + n := p.afe.top() + if n == nil { + return + } + if n.Type == scopeMarkerNode || p.oe.index(n) != -1 { + return + } + i := len(p.afe) - 1 + for n.Type != scopeMarkerNode && p.oe.index(n) == -1 { + if i == 0 { + i = -1 + break + } + i-- + n = p.afe[i] + } + for { + i++ + n = p.afe[i] + p.addChild(n.clone()) + p.afe[i] = n + if i == len(p.afe)-1 { + break + } + } } // read reads the next token. This is usually from the tokenizer, but it may @@ -180,12 +181,12 @@ func (p *parser) read() os.Error { return nil } -// Section 10.2.4. +// Section 11.2.4. func (p *parser) acknowledgeSelfClosingTag() { p.hasSelfClosingToken = false } -// An insertion mode (section 10.2.3.1) is the state transition function from +// An insertion mode (section 11.2.3.1) is the state transition function from // a particular state in the HTML5 parser's state machine. It updates the // parser's fields depending on parser.token (where ErrorToken means EOF). In // addition to returning the next insertionMode state, it also returns whether @@ -194,7 +195,7 @@ type insertionMode func(*parser) (insertionMode, bool) // useTheRulesFor runs the delegate insertionMode over p, returning the actual // insertionMode unless the delegate caused a state transition. -// Section 10.2.3.1, "using the rules for". +// Section 11.2.3.1, "using the rules for". func useTheRulesFor(p *parser, actual, delegate insertionMode) (insertionMode, bool) { im, consumed := delegate(p) if im != delegate { @@ -203,13 +204,21 @@ func useTheRulesFor(p *parser, actual, delegate insertionMode) (insertionMode, b return actual, consumed } -// Section 10.2.5.4. +// Section 11.2.5.4.1. func initialIM(p *parser) (insertionMode, bool) { - // TODO: check p.tok for DOCTYPE. + if p.tok.Type == DoctypeToken { + p.addChild(&Node{ + Type: DoctypeNode, + Data: p.tok.Data, + }) + return beforeHTMLIM, true + } + // TODO: set "quirks mode"? It's defined in the DOM spec instead of HTML5 proper, + // and so switching on "quirks mode" might belong in a different package. return beforeHTMLIM, false } -// Section 10.2.5.5. +// Section 11.2.5.4.2. func beforeHTMLIM(p *parser) (insertionMode, bool) { var ( add bool @@ -243,7 +252,7 @@ func beforeHTMLIM(p *parser) (insertionMode, bool) { return beforeHeadIM, !implied } -// Section 10.2.5.6. +// Section 11.2.5.4.3. func beforeHeadIM(p *parser) (insertionMode, bool) { var ( add bool @@ -280,7 +289,7 @@ func beforeHeadIM(p *parser) (insertionMode, bool) { return inHeadIM, !implied } -// Section 10.2.5.7. +// Section 11.2.5.4.4. func inHeadIM(p *parser) (insertionMode, bool) { var ( pop bool @@ -305,7 +314,7 @@ func inHeadIM(p *parser) (insertionMode, bool) { // TODO. } if pop || implied { - n := p.pop() + n := p.oe.pop() if n.Data != "head" { panic("html: bad parser state") } @@ -314,7 +323,7 @@ func inHeadIM(p *parser) (insertionMode, bool) { return inHeadIM, !implied } -// Section 10.2.5.9. +// Section 11.2.5.4.6. func afterHeadIM(p *parser) (insertionMode, bool) { var ( add bool @@ -354,17 +363,18 @@ func afterHeadIM(p *parser) (insertionMode, bool) { return inBodyIM, !implied } -// Section 10.2.5.10. +// Section 11.2.5.4.7. func inBodyIM(p *parser) (insertionMode, bool) { var endP bool switch p.tok.Type { case TextToken: + p.reconstructActiveFormattingElements() p.addText(p.tok.Data) p.framesetOK = false case StartTagToken: switch p.tok.Data { case "address", "article", "aside", "blockquote", "center", "details", "dir", "div", "dl", "fieldset", "figcaption", "figure", "footer", "header", "hgroup", "menu", "nav", "ol", "p", "section", "summary", "ul": - // TODO: Do the proper "does the stack of open elements has a p element in button scope" algorithm in section 10.2.3.2. + // TODO: Do the proper "does the stack of open elements has a p element in button scope" algorithm in section 11.2.3.2. n := p.top() if n.Type == ElementNode && n.Data == "p" { endP = true @@ -375,16 +385,24 @@ func inBodyIM(p *parser) (insertionMode, bool) { // TODO: auto-insert

if necessary. switch n := p.top(); n.Data { case "h1", "h2", "h3", "h4", "h5", "h6": - p.pop() + p.oe.pop() } p.addElement(p.tok.Data, p.tok.Attr) + case "a": + if n := p.afe.forTag("a"); n != nil { + p.inBodyEndTagFormatting("a") + p.oe.remove(n) + p.afe.remove(n) + } + p.reconstructActiveFormattingElements() + p.addFormattingElement(p.tok.Data, p.tok.Attr) case "b", "big", "code", "em", "font", "i", "s", "small", "strike", "strong", "tt", "u": p.reconstructActiveFormattingElements() p.addFormattingElement(p.tok.Data, p.tok.Attr) case "area", "br", "embed", "img", "input", "keygen", "wbr": p.reconstructActiveFormattingElements() p.addElement(p.tok.Data, p.tok.Attr) - p.pop() + p.oe.pop() p.acknowledgeSelfClosingTag() p.framesetOK = false case "table": @@ -395,11 +413,12 @@ func inBodyIM(p *parser) (insertionMode, bool) { case "hr": // TODO: auto-insert

if necessary. p.addElement(p.tok.Data, p.tok.Attr) - p.pop() + p.oe.pop() p.acknowledgeSelfClosingTag() p.framesetOK = false default: // TODO. + p.addElement(p.tok.Data, p.tok.Attr) } case EndTagToken: switch p.tok.Data { @@ -407,18 +426,17 @@ func inBodyIM(p *parser) (insertionMode, bool) { // TODO: autoclose the stack of open elements. return afterBodyIM, true case "a", "b", "big", "code", "em", "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u": - // TODO: implement the "adoption agency" algorithm: - // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#adoptionAgency + p.inBodyEndTagFormatting(p.tok.Data) + default: + // TODO: any other end tag if p.tok.Data == p.top().Data { - p.pop() + p.oe.pop() } - default: - // TODO. } } if endP { // TODO: do the proper algorithm. - n := p.pop() + n := p.oe.pop() if n.Type != ElementNode || n.Data != "p" { panic("unreachable") } @@ -426,7 +444,123 @@ func inBodyIM(p *parser) (insertionMode, bool) { return inBodyIM, !endP } -// Section 10.2.5.12. +func (p *parser) inBodyEndTagFormatting(tag string) { + // This is the "adoption agency" algorithm, described at + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#adoptionAgency + + // TODO: this is a fairly literal line-by-line translation of that algorithm. + // Once the code successfully parses the comprehensive test suite, we should + // refactor this code to be more idiomatic. + + // Steps 1-3. The outer loop. + for i := 0; i < 8; i++ { + // Step 4. Find the formatting element. + var formattingElement *Node + for j := len(p.afe) - 1; j >= 0; j-- { + if p.afe[j].Type == scopeMarkerNode { + break + } + if p.afe[j].Data == tag { + formattingElement = p.afe[j] + break + } + } + if formattingElement == nil { + return + } + feIndex := p.oe.index(formattingElement) + if feIndex == -1 { + p.afe.remove(formattingElement) + return + } + + // Steps 5-6. Find the furthest block. + var furthestBlock *Node + for _, e := range p.oe[feIndex:] { + if isSpecialElement[e.Data] { + furthestBlock = e + break + } + } + if furthestBlock == nil { + e := p.oe.pop() + for e != formattingElement { + e = p.oe.pop() + } + p.afe.remove(e) + return + } + + // Steps 7-8. Find the common ancestor and bookmark node. + commonAncestor := p.oe[feIndex-1] + bookmark := p.afe.index(formattingElement) + + // Step 9. The inner loop. Find the lastNode to reparent. + lastNode := furthestBlock + node := furthestBlock + x := p.oe.index(node) + // Steps 9.1-9.3. + for j := 0; j < 3; j++ { + // Step 9.4. + x-- + node = p.oe[x] + // Step 9.5. + if p.afe.index(node) == -1 { + p.oe.remove(node) + continue + } + // Step 9.6. + if node == formattingElement { + break + } + // Step 9.7. + clone := node.clone() + p.afe[p.afe.index(node)] = clone + p.oe[p.oe.index(node)] = clone + node = clone + // Step 9.8. + if lastNode == furthestBlock { + bookmark = p.afe.index(node) + 1 + } + // Step 9.9. + if lastNode.Parent != nil { + lastNode.Parent.Remove(lastNode) + } + node.Add(lastNode) + // Step 9.10. + lastNode = node + } + + // Step 10. Reparent lastNode to the common ancestor, + // or for misnested table nodes, to the foster parent. + if lastNode.Parent != nil { + lastNode.Parent.Remove(lastNode) + } + switch commonAncestor.Data { + case "table", "tbody", "tfoot", "thead", "tr": + // TODO: fix up misnested table nodes; find the foster parent. + fallthrough + default: + commonAncestor.Add(lastNode) + } + + // Steps 11-13. Reparent nodes from the furthest block's children + // to a clone of the formatting element. + clone := formattingElement.clone() + reparentChildren(clone, furthestBlock) + furthestBlock.Add(clone) + + // Step 14. Fix up the list of active formatting elements. + p.afe.remove(formattingElement) + p.afe.insert(bookmark, clone) + + // Step 15. Fix up the stack of open elements. + p.oe.remove(formattingElement) + p.oe.insert(p.oe.index(furthestBlock)+1, clone) + } +} + +// Section 11.2.5.4.9. func inTableIM(p *parser) (insertionMode, bool) { var ( add bool @@ -457,7 +591,7 @@ func inTableIM(p *parser) (insertionMode, bool) { switch p.tok.Data { case "table": if p.popUntil(tableScopeStopTags, "table") { - // TODO: "reset the insertion mode appropriately" as per 10.2.3.1. + // TODO: "reset the insertion mode appropriately" as per 11.2.3.1. return inBodyIM, false } // Ignore the token. @@ -476,7 +610,7 @@ func inTableIM(p *parser) (insertionMode, bool) { return inTableIM, true } -// Section 10.2.5.16. +// Section 11.2.5.4.13. func inTableBodyIM(p *parser) (insertionMode, bool) { var ( add bool @@ -524,7 +658,7 @@ func inTableBodyIM(p *parser) (insertionMode, bool) { return useTheRulesFor(p, inTableBodyIM, inTableIM) } -// Section 10.2.5.17. +// Section 11.2.5.4.14. func inRowIM(p *parser) (insertionMode, bool) { switch p.tok.Type { case ErrorToken: @@ -536,7 +670,7 @@ func inRowIM(p *parser) (insertionMode, bool) { case "td", "th": // TODO: clear the stack back to a table row context. p.addElement(p.tok.Data, p.tok.Attr) - // TODO: insert a marker at the end of the list of active formatting elements. + p.afe = append(p.afe, &scopeMarker) return inCellIM, true default: // TODO. @@ -563,7 +697,7 @@ func inRowIM(p *parser) (insertionMode, bool) { return useTheRulesFor(p, inRowIM, inTableIM) } -// Section 10.2.5.18. +// Section 11.2.5.4.15. func inCellIM(p *parser) (insertionMode, bool) { var ( closeTheCellAndReprocess bool @@ -588,14 +722,14 @@ func inCellIM(p *parser) (insertionMode, bool) { } if closeTheCellAndReprocess { if p.popUntil(tableScopeStopTags, "td") || p.popUntil(tableScopeStopTags, "th") { - // TODO: clear the list of active formatting elements up to the last marker. + p.clearActiveFormattingElements() return inRowIM, false } } return useTheRulesFor(p, inCellIM, inBodyIM) } -// Section 10.2.5.22. +// Section 11.2.5.4.18. func afterBodyIM(p *parser) (insertionMode, bool) { switch p.tok.Type { case ErrorToken: @@ -616,7 +750,7 @@ func afterBodyIM(p *parser) (insertionMode, bool) { return afterBodyIM, true } -// Section 10.2.5.25. +// Section 11.2.5.4.21. func afterAfterBodyIM(p *parser) (insertionMode, bool) { switch p.tok.Type { case ErrorToken: diff --git a/libgo/go/html/parse_test.go b/libgo/go/html/parse_test.go index 3fa35d5..7d918d2 100644 --- a/libgo/go/html/parse_test.go +++ b/libgo/go/html/parse_test.go @@ -85,6 +85,10 @@ func dumpLevel(w io.Writer, n *Node, level int) os.Error { fmt.Fprintf(w, "%q", EscapeString(n.Data)) case CommentNode: return os.NewError("COMMENT") + case DoctypeNode: + fmt.Fprintf(w, "", EscapeString(n.Data)) + case scopeMarkerNode: + return os.NewError("unexpected scopeMarkerNode") default: return os.NewError("unknown node type") } @@ -119,7 +123,7 @@ func TestParser(t *testing.T) { rc := make(chan io.Reader) go readDat(filename, rc) // TODO(nigeltao): Process all test cases, not just a subset. - for i := 0; i < 22; i++ { + for i := 0; i < 25; i++ { // Parse the #data section. b, err := ioutil.ReadAll(<-rc) if err != nil { diff --git a/libgo/go/html/testdata/webkit/comments01.dat b/libgo/go/html/testdata/webkit/comments01.dat index 388d952..44f1876 100644 --- a/libgo/go/html/testdata/webkit/comments01.dat +++ b/libgo/go/html/testdata/webkit/comments01.dat @@ -28,8 +28,7 @@ FOO -| "BAZ" +| #data FOOBAZ @@ -61,8 +60,7 @@ FOO -| "BAZ" +| #data FOOBAZ @@ -124,3 +122,14 @@ FOOBAZ | | | + +#data +FOOBAZ +#errors +#document +| +| +| +| "FOO" +| +| "BAZ" diff --git a/libgo/go/html/testdata/webkit/doctype01.dat b/libgo/go/html/testdata/webkit/doctype01.dat index 575129c..ae45732 100644 --- a/libgo/go/html/testdata/webkit/doctype01.dat +++ b/libgo/go/html/testdata/webkit/doctype01.dat @@ -132,7 +132,7 @@ Hello #errors #document -| +| | | | @@ -142,7 +142,7 @@ Hello #errors #document -| +| | | | @@ -152,7 +152,7 @@ Hello #errors #document -| +| | | | @@ -222,7 +222,7 @@ Hello #errors #document -| +| | | | @@ -232,7 +232,7 @@ Hello #errors #document -| +| | | | @@ -242,7 +242,7 @@ Hello #errors #document -| +| | | | @@ -252,7 +252,7 @@ Hello #errors #document -| +| | | | @@ -263,7 +263,7 @@ "http://www.w3.org/TR/html4/strict.dtd">Hello #errors #document -| +| | | | @@ -284,7 +284,7 @@ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> #errors #document -| +| | | | @@ -294,7 +294,7 @@ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"> #errors #document -| +| | | | @@ -309,8 +309,7 @@ | | | -| " -]>" +| "]>" #data #errors #document -| +| | | | @@ -327,9 +326,45 @@ Mine! #errors #document -| +| | | | | | "Mine!" + +#data + +#errors +#document +| +| +| +| + +#data + +#errors +#document +| +| +| +| + +#data + +#errors +#document +| +| +| +| + +#data + +#errors +#document +| +| +| +| diff --git a/libgo/go/html/testdata/webkit/dom2string.js b/libgo/go/html/testdata/webkit/dom2string.js deleted file mode 100644 index 45897fd..0000000 --- a/libgo/go/html/testdata/webkit/dom2string.js +++ /dev/null @@ -1,135 +0,0 @@ -String.prototype.toAsciiLowerCase = function () { - var output = ""; - for (var i = 0, len = this.length; i < len; ++i) { - if (this.charCodeAt(i) >= 0x41 && this.charCodeAt(i) <= 0x5A) { - output += String.fromCharCode(this.charCodeAt(i) + 0x20) - } else { - output += this.charAt(i); - } - } - return output; -} - -function indent(ancestors) { - var str = ""; - if (ancestors > 0) { - while (ancestors--) - str += " "; - } - return str; -} - -function dom2string(node, ancestors) { - var str = ""; - if (typeof ancestors == "undefined") - var ancestors = 0; - if (!node.firstChild) - return "| "; - var parent = node; - var current = node.firstChild; - var next = null; - var misnested = null; - for (;;) { - str += "\n| " + indent(ancestors); - switch (current.nodeType) { - case 10: - str += ''; - break; - case 8: - try { - str += ''; - } catch (e) { - str += ''; - } - if (parent != current.parentNode) { - return str += ' (misnested... aborting)'; - } - break; - case 7: - str += ''; - break; - case 4: - str += ''; - break; - case 3: - str += '"' + current.nodeValue + '"'; - if (parent != current.parentNode) { - return str += ' (misnested... aborting)'; - } - break; - case 1: - str += "<"; - switch (current.namespaceURI) { - case "http://www.w3.org/2000/svg": - str += "svg "; - break; - case "http://www.w3.org/1998/Math/MathML": - str += "math "; - break; - } - if (current.localName && current.namespaceURI && current.namespaceURI != null) { - str += current.localName; - } else { - str += current.nodeName.toAsciiLowerCase(); - } - str += '>'; - if (parent != current.parentNode) { - return str += ' (misnested... aborting)'; - } else { - if (current.attributes) { - var attrNames = []; - var attrPos = {}; - for (var j = 0; j < current.attributes.length; j += 1) { - if (current.attributes[j].specified) { - var name = ""; - switch (current.attributes[j].namespaceURI) { - case "http://www.w3.org/XML/1998/namespace": - name += "xml "; - break; - case "http://www.w3.org/2000/xmlns/": - name += "xmlns "; - break; - case "http://www.w3.org/1999/xlink": - name += "xlink "; - break; - } - if (current.attributes[j].localName) { - name += current.attributes[j].localName; - } else { - name += current.attributes[j].nodeName; - } - attrNames.push(name); - attrPos[name] = j; - } - } - if (attrNames.length > 0) { - attrNames.sort(); - for (var j = 0; j < attrNames.length; j += 1) { - str += "\n| " + indent(1 + ancestors) + attrNames[j]; - str += '="' + current.attributes[attrPos[attrNames[j]]].nodeValue + '"'; - } - } - } - if (next = current.firstChild) { - parent = current; - current = next; - ancestors++; - continue; - } - } - break; - } - for (;;) { - if (next = current.nextSibling) { - current = next; - break; - } - current = current.parentNode; - parent = parent.parentNode; - ancestors--; - if (current == node) { - return str.substring(1); - } - } - } -} diff --git a/libgo/go/html/testdata/webkit/entities01.dat b/libgo/go/html/testdata/webkit/entities01.dat index 926642e..c8073b7 100644 --- a/libgo/go/html/testdata/webkit/entities01.dat +++ b/libgo/go/html/testdata/webkit/entities01.dat @@ -189,15 +189,6 @@ FOO�ZOO | "FOO�ZOO" #data -FOO ZOO -#errors -#document -| -| -| -| "FOO ZOO" - -#data FOOxZOO #errors #document diff --git a/libgo/go/html/testdata/webkit/entities02.dat b/libgo/go/html/testdata/webkit/entities02.dat index 0b4dd66..e2fb42a 100644 --- a/libgo/go/html/testdata/webkit/entities02.dat +++ b/libgo/go/html/testdata/webkit/entities02.dat @@ -127,3 +127,123 @@ | |
| bar="ZZ>" + +#data +
+#errors +#document +| +| +| +|
+| bar="ZZ£_id=23" + +#data +
+#errors +#document +| +| +| +|
+| bar="ZZ&prod_id=23" + +#data +
+#errors +#document +| +| +| +|
+| bar="ZZ£_id=23" + +#data +
+#errors +#document +| +| +| +|
+| bar="ZZ∏_id=23" + +#data +
+#errors +#document +| +| +| +|
+| bar="ZZ£=23" + +#data +
+#errors +#document +| +| +| +|
+| bar="ZZ&prod=23" + +#data +
ZZ£_id=23
+#errors +#document +| +| +| +|
+| "ZZ£_id=23" + +#data +
ZZ&prod_id=23
+#errors +#document +| +| +| +|
+| "ZZ&prod_id=23" + +#data +
ZZ£_id=23
+#errors +#document +| +| +| +|
+| "ZZ£_id=23" + +#data +
ZZ∏_id=23
+#errors +#document +| +| +| +|
+| "ZZ∏_id=23" + +#data +
ZZ£=23
+#errors +#document +| +| +| +|
+| "ZZ£=23" + +#data +
ZZ&prod=23
+#errors +#document +| +| +| +|
+| "ZZ&prod=23" diff --git a/libgo/go/html/testdata/webkit/tests1.dat b/libgo/go/html/testdata/webkit/tests1.dat index ad58d31..cbf8bdd 100644 --- a/libgo/go/html/testdata/webkit/tests1.dat +++ b/libgo/go/html/testdata/webkit/tests1.dat @@ -259,7 +259,7 @@ Line: 1 Col: 24 End tag (a) violates step 1, paragraph 1 of the adoption agency | "Z" #data - +