From f068eb658184729edabb5c644fbdefac53bb8508 Mon Sep 17 00:00:00 2001 From: cornelk Date: Wed, 13 May 2020 18:31:05 +0300 Subject: [PATCH 1/6] extend stdlib to allow import of more packages --- src/os/env.go | 5 +++ src/os/errors.go | 32 ++++++++++++++++ src/os/exec.go | 6 +++ src/os/file.go | 21 +++++++++- src/os/sys.go | 5 +++ src/reflect/deepequal.go | 9 +++++ src/reflect/type.go | 83 +++++++++++++++++++++++++++++++++++++++- src/reflect/value.go | 42 ++++++++++++++++++++ src/runtime/error.go | 8 ++++ src/runtime/mprof.go | 6 +++ src/sync/map.go | 15 ++++++++ src/sync/mutex.go | 11 ++++++ src/syscall/net.go | 34 ++++++++++++++++ 13 files changed, 274 insertions(+), 3 deletions(-) create mode 100644 src/os/env.go create mode 100644 src/os/errors.go create mode 100644 src/os/exec.go create mode 100644 src/os/sys.go create mode 100644 src/reflect/deepequal.go create mode 100644 src/runtime/error.go create mode 100644 src/runtime/mprof.go create mode 100644 src/syscall/net.go diff --git a/src/os/env.go b/src/os/env.go new file mode 100644 index 0000000000..3a250df080 --- /dev/null +++ b/src/os/env.go @@ -0,0 +1,5 @@ +package os + +func Getenv(key string) string { + return "" +} diff --git a/src/os/errors.go b/src/os/errors.go new file mode 100644 index 0000000000..45c09f77bc --- /dev/null +++ b/src/os/errors.go @@ -0,0 +1,32 @@ +package os + +import ( + "errors" +) + +var ( + ErrInvalid = errors.New("invalid argument") + ErrPermission = errors.New("permission denied") + ErrClosed = errors.New("file already closed") +) + +func IsPermission(err error) bool { + return err == ErrPermission +} + +func NewSyscallError(syscall string, err error) error { + if err == nil { + return nil + } + return &SyscallError{syscall, err} +} + +// SyscallError records an error from a specific system call. +type SyscallError struct { + Syscall string + Err error +} + +func (e *SyscallError) Error() string { return e.Syscall + ": " + e.Err.Error() } + +func (e *SyscallError) Unwrap() error { return e.Err } diff --git a/src/os/exec.go b/src/os/exec.go new file mode 100644 index 0000000000..66cc799997 --- /dev/null +++ b/src/os/exec.go @@ -0,0 +1,6 @@ +package os + +type Signal interface { + String() string + Signal() // to distinguish from other Stringers +} diff --git a/src/os/file.go b/src/os/file.go index 6f4a8cc140..eb6343f7d9 100644 --- a/src/os/file.go +++ b/src/os/file.go @@ -7,6 +7,7 @@ package os import ( "errors" + "syscall" ) // Portable analogs of some common system call errors. @@ -91,6 +92,10 @@ func (f *File) Read(b []byte) (n int, err error) { return } +func (f *File) ReadAt(b []byte, off int64) (n int, err error) { + return 0, ErrNotImplemented +} + // Write writes len(b) bytes to the File. It returns the number of bytes written // and an error, if any. Write returns a non-nil error when n != len(b). func (f *File) Write(b []byte) (n int, err error) { @@ -125,6 +130,20 @@ func (f *File) Stat() (FileInfo, error) { return nil, &PathError{"stat", f.name, ErrNotImplemented} } +// Sync is a stub, not yet implemented +func (f *File) Sync() error { + return ErrNotImplemented +} + +func (f *File) SyscallConn() (syscall.RawConn, error) { + return nil, ErrNotImplemented +} + +// Fd returns the file handle referencing the open file. +func (f *File) Fd() uintptr { + panic("unimplemented: os.file.Fd()") +} + const ( PathSeparator = '/' // OS-specific path separator PathListSeparator = ':' // OS-specific path list separator @@ -194,7 +213,7 @@ type FileInfo interface { Name() string // base name of the file Size() int64 // length in bytes for regular files; system-dependent for others Mode() FileMode // file mode bits - // ModTime() time.Time // modification time + // TODO ModTime() time.Time // modification time IsDir() bool // abbreviation for Mode().IsDir() Sys() interface{} // underlying data source (can return nil) } diff --git a/src/os/sys.go b/src/os/sys.go new file mode 100644 index 0000000000..ba300e40d8 --- /dev/null +++ b/src/os/sys.go @@ -0,0 +1,5 @@ +package os + +func Hostname() (name string, err error) { + return "", ErrNotImplemented +} diff --git a/src/reflect/deepequal.go b/src/reflect/deepequal.go new file mode 100644 index 0000000000..32719c34db --- /dev/null +++ b/src/reflect/deepequal.go @@ -0,0 +1,9 @@ +package reflect + +func DeepEqual(x, y interface{}) bool { + if x == nil || y == nil { + return x == y + } + + panic("unimplemented: reflect.DeepEqual()") +} diff --git a/src/reflect/type.go b/src/reflect/type.go index 44dc10cb15..f7745fd710 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -227,7 +227,7 @@ func (t Type) Field(i int) StructField { // There is a tag. var tagNum uintptr tagNum, p = readVarint(p) - field.Tag = readStringSidetable(unsafe.Pointer(&structNamesSidetable), tagNum) + field.Tag = StructTag(readStringSidetable(unsafe.Pointer(&structNamesSidetable), tagNum)) } else { // There is no tag. field.Tag = "" @@ -445,6 +445,22 @@ func (t Type) Comparable() bool { } } +func (t Type) ConvertibleTo(u Type) bool { + panic("unimplemented: (reflect.Type).ConvertibleTo()") +} + +func (t Type) NumMethod() int { + panic("unimplemented: (reflect.Type).NumMethod()") +} + +func (t Type) Name() string { + panic("unimplemented: (reflect.Type).Name()") +} + +func (t Type) Key() Type { + panic("unimplemented: (reflect.Type).Key()") +} + // A StructField describes a single field in a struct. type StructField struct { // Name indicates the field name. @@ -455,11 +471,74 @@ type StructField struct { PkgPath string Type Type - Tag string + Tag StructTag // field tag string Anonymous bool Offset uintptr } +// A StructTag is the tag string in a struct field. +type StructTag string + +// Get returns the value associated with key in the tag string. +func (tag StructTag) Get(key string) string { + v, _ := tag.Lookup(key) + return v +} + +// Lookup returns the value associated with key in the tag string. +func (tag StructTag) Lookup(key string) (value string, ok bool) { + for tag != "" { + // Skip leading space. + i := 0 + for i < len(tag) && tag[i] == ' ' { + i++ + } + tag = tag[i:] + if tag == "" { + break + } + + // Scan to colon. A space, a quote or a control character is a syntax error. + // Strictly speaking, control chars include the range [0x7f, 0x9f], not just + // [0x00, 0x1f], but in practice, we ignore the multi-byte control characters + // as it is simpler to inspect the tag's bytes than the tag's runes. + i = 0 + for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f { + i++ + } + if i == 0 || i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' { + break + } + name := string(tag[:i]) + tag = tag[i+1:] + + // Scan quoted string to find value. + i = 1 + for i < len(tag) && tag[i] != '"' { + if tag[i] == '\\' { + i++ + } + i++ + } + if i >= len(tag) { + break + } + qvalue := string(tag[:i+1]) + tag = tag[i+1:] + + if key == name { + // TODO strconv causes import cycle + //value, err := strconv.Unquote(qvalue) + //if err != nil { + // break + //} + //return value, true + return qvalue, true + } + } + return "", false +} + // TypeError is the error that is used in a panic when invoking a method on a // type that is not applicable to that type. type TypeError struct { diff --git a/src/reflect/value.go b/src/reflect/value.go index e71eaee8b9..087ddfa15b 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -661,6 +661,18 @@ func (v Value) checkAddressable() { } } +func (v Value) OverflowInt(x int64) bool { + panic("unimplemented: reflect.OverflowInt()") +} + +func (v Value) OverflowUint(x uint64) bool { + panic("unimplemented: reflect.OverflowUint()") +} + +func (v Value) Convert(t Type) Value { + panic("unimplemented: (reflect.Value).Convert()") +} + func MakeSlice(typ Type, len, cap int) Value { panic("unimplemented: reflect.MakeSlice()") } @@ -700,3 +712,33 @@ func (e *ValueError) Error() string { // Calls to this function are converted to LLVM intrinsic calls such as // llvm.memcpy.p0i8.p0i8.i32(). func memcpy(dst, src unsafe.Pointer, size uintptr) + +// Copy copies the contents of src into dst until either +// dst has been filled or src has been exhausted. +func Copy(dst, src Value) int { + panic("unimplemented: reflect.Copy()") +} + +// Append appends the values x to a slice s and returns the resulting slice. +// As in Go, each x's value must be assignable to the slice's element type. +func Append(s Value, x ...Value) Value { + panic("unimplemented: reflect.Append()") +} + +func (v Value) SetMapIndex(key, elem Value) { + panic("unimplemented: (reflect.Value).SetMapIndex()") +} + +// FieldByIndex returns the nested field corresponding to index. +func (v Value) FieldByIndex(index []int) Value { + panic("unimplemented: (reflect.Value).FieldByIndex()") +} + +func (v Value) FieldByName(name string) Value { + panic("unimplemented: (reflect.Value).FieldByName()") +} + +// MakeMap creates a new map with the specified type. +func MakeMap(typ Type) Value { + panic("unimplemented: reflect.MakeMap()") +} diff --git a/src/runtime/error.go b/src/runtime/error.go new file mode 100644 index 0000000000..3ae5ea3aae --- /dev/null +++ b/src/runtime/error.go @@ -0,0 +1,8 @@ +package runtime + +// The Error interface identifies a run time error. +type Error interface { + error + + RuntimeError() +} diff --git a/src/runtime/mprof.go b/src/runtime/mprof.go new file mode 100644 index 0000000000..6e9a4717be --- /dev/null +++ b/src/runtime/mprof.go @@ -0,0 +1,6 @@ +package runtime + +// Stack is a stub, not implemented +func Stack(buf []byte, all bool) int { + return 0 +} diff --git a/src/sync/map.go b/src/sync/map.go index 7d3cde8a6d..5eeff9d38e 100644 --- a/src/sync/map.go +++ b/src/sync/map.go @@ -42,3 +42,18 @@ func (m *Map) Store(key, value interface{}) { } m.m[key] = value } + +func (m *Map) Range(f func(key, value interface{}) bool) { + m.lock.Lock() + defer m.lock.Unlock() + + if m.m == nil { + return + } + + for k, v := range m.m { + if !f(k, v) { + break + } + } +} diff --git a/src/sync/mutex.go b/src/sync/mutex.go index acc02de3a3..7284300fda 100644 --- a/src/sync/mutex.go +++ b/src/sync/mutex.go @@ -74,3 +74,14 @@ type Locker interface { Lock() Unlock() } + +// RLocker returns a Locker interface that implements +// the Lock and Unlock methods by calling rw.RLock and rw.RUnlock. +func (rw *RWMutex) RLocker() Locker { + return (*rlocker)(rw) +} + +type rlocker RWMutex + +func (r *rlocker) Lock() { (*RWMutex)(r).RLock() } +func (r *rlocker) Unlock() { (*RWMutex)(r).RUnlock() } diff --git a/src/syscall/net.go b/src/syscall/net.go new file mode 100644 index 0000000000..531fa80d8f --- /dev/null +++ b/src/syscall/net.go @@ -0,0 +1,34 @@ +// Copyright 2017 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 syscall + +// A RawConn is a raw network connection. +type RawConn interface { + // Control invokes f on the underlying connection's file + // descriptor or handle. + // The file descriptor fd is guaranteed to remain valid while + // f executes but not after f returns. + Control(f func(fd uintptr)) error + + // Read invokes f on the underlying connection's file + // descriptor or handle; f is expected to try to read from the + // file descriptor. + // If f returns true, Read returns. Otherwise Read blocks + // waiting for the connection to be ready for reading and + // tries again repeatedly. + // The file descriptor is guaranteed to remain valid while f + // executes but not after f returns. + Read(f func(fd uintptr) (done bool)) error + + // Write is like Read but for writing. + Write(f func(fd uintptr) (done bool)) error +} + +// Conn is implemented by some types in the net and os packages to provide +// access to the underlying file descriptor or handle. +type Conn interface { + // SyscallConn returns a raw network connection. + SyscallConn() (RawConn, error) +} From 8b46fa3998bd2828db3f95a17da294e1d7296ac2 Mon Sep 17 00:00:00 2001 From: cornelk Date: Thu, 21 May 2020 13:55:43 +0300 Subject: [PATCH 2/6] os: move errors to separate file --- src/os/errors.go | 7 +++++++ src/os/file.go | 10 ---------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/os/errors.go b/src/os/errors.go index 45c09f77bc..9b34655431 100644 --- a/src/os/errors.go +++ b/src/os/errors.go @@ -8,6 +8,13 @@ var ( ErrInvalid = errors.New("invalid argument") ErrPermission = errors.New("permission denied") ErrClosed = errors.New("file already closed") + + // Portable analogs of some common system call errors. + // Note that these are exported for use in the Filesystem interface. + ErrUnsupported = errors.New("operation not supported") + ErrNotImplemented = errors.New("operation not implemented") + ErrNotExist = errors.New("file not found") + ErrExist = errors.New("file exists") ) func IsPermission(err error) bool { diff --git a/src/os/file.go b/src/os/file.go index eb6343f7d9..a059a421ab 100644 --- a/src/os/file.go +++ b/src/os/file.go @@ -6,19 +6,9 @@ package os import ( - "errors" "syscall" ) -// Portable analogs of some common system call errors. -// Note that these are exported for use in the Filesystem interface. -var ( - ErrUnsupported = errors.New("operation not supported") - ErrNotImplemented = errors.New("operation not implemented") - ErrNotExist = errors.New("file not found") - ErrExist = errors.New("file exists") -) - // Mkdir creates a directory. If the operation fails, it will return an error of // type *PathError. func Mkdir(path string, perm FileMode) error { From ab9dc3dc4681e1c30ff942f0bdb73d72ddc3fe28 Mon Sep 17 00:00:00 2001 From: cornelk Date: Thu, 21 May 2020 14:28:51 +0300 Subject: [PATCH 3/6] reflect: reimplement Unquote --- src/reflect/strconv.go | 248 +++++++++++++++++++++++++++++++++++++++++ src/reflect/type.go | 12 +- 2 files changed, 253 insertions(+), 7 deletions(-) create mode 100644 src/reflect/strconv.go diff --git a/src/reflect/strconv.go b/src/reflect/strconv.go new file mode 100644 index 0000000000..77cf5085d2 --- /dev/null +++ b/src/reflect/strconv.go @@ -0,0 +1,248 @@ +// 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 reflect + +import ( + "unicode/utf8" +) + +// ErrSyntax indicates that a value does not have the right syntax for the target type. +var ErrSyntax = badSyntax{} + +type badSyntax struct{} + +func (badSyntax) Error() string { + return "invalid syntax" +} + +func unhex(b byte) (v rune, ok bool) { + c := rune(b) + switch { + case '0' <= c && c <= '9': + return c - '0', true + case 'a' <= c && c <= 'f': + return c - 'a' + 10, true + case 'A' <= c && c <= 'F': + return c - 'A' + 10, true + } + return +} + +// UnquoteChar decodes the first character or byte in the escaped string +// or character literal represented by the string s. +// It returns four values: +// +// 1) value, the decoded Unicode code point or byte value; +// 2) multibyte, a boolean indicating whether the decoded character requires a multibyte UTF-8 representation; +// 3) tail, the remainder of the string after the character; and +// 4) an error that will be nil if the character is syntactically valid. +// +// The second argument, quote, specifies the type of literal being parsed +// and therefore which escaped quote character is permitted. +// If set to a single quote, it permits the sequence \' and disallows unescaped '. +// If set to a double quote, it permits \" and disallows unescaped ". +// If set to zero, it does not permit either escape and allows both quote characters to appear unescaped. +func UnquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, err error) { + // easy cases + if len(s) == 0 { + err = ErrSyntax + return + } + switch c := s[0]; { + case c == quote && (quote == '\'' || quote == '"'): + err = ErrSyntax + return + case c >= utf8.RuneSelf: + r, size := utf8.DecodeRuneInString(s) + return r, true, s[size:], nil + case c != '\\': + return rune(s[0]), false, s[1:], nil + } + + // hard case: c is backslash + if len(s) <= 1 { + err = ErrSyntax + return + } + c := s[1] + s = s[2:] + + switch c { + case 'a': + value = '\a' + case 'b': + value = '\b' + case 'f': + value = '\f' + case 'n': + value = '\n' + case 'r': + value = '\r' + case 't': + value = '\t' + case 'v': + value = '\v' + case 'x', 'u', 'U': + n := 0 + switch c { + case 'x': + n = 2 + case 'u': + n = 4 + case 'U': + n = 8 + } + var v rune + if len(s) < n { + err = ErrSyntax + return + } + for j := 0; j < n; j++ { + x, ok := unhex(s[j]) + if !ok { + err = ErrSyntax + return + } + v = v<<4 | x + } + s = s[n:] + if c == 'x' { + // single-byte string, possibly not UTF-8 + value = v + break + } + if v > utf8.MaxRune { + err = ErrSyntax + return + } + value = v + multibyte = true + case '0', '1', '2', '3', '4', '5', '6', '7': + v := rune(c) - '0' + if len(s) < 2 { + err = ErrSyntax + return + } + for j := 0; j < 2; j++ { // one digit already; two more + x := rune(s[j]) - '0' + if x < 0 || x > 7 { + err = ErrSyntax + return + } + v = (v << 3) | x + } + s = s[2:] + if v > 255 { + err = ErrSyntax + return + } + value = v + case '\\': + value = '\\' + case '\'', '"': + if c != quote { + err = ErrSyntax + return + } + value = rune(c) + default: + err = ErrSyntax + return + } + tail = s + return +} + +// Unquote interprets s as a single-quoted, double-quoted, +// or backquoted Go string literal, returning the string value +// that s quotes. (If s is single-quoted, it would be a Go +// character literal; Unquote returns the corresponding +// one-character string.) +func Unquote(s string) (string, error) { + n := len(s) + if n < 2 { + return "", ErrSyntax + } + quote := s[0] + if quote != s[n-1] { + return "", ErrSyntax + } + s = s[1 : n-1] + + if quote == '`' { + if contains(s, '`') { + return "", ErrSyntax + } + if contains(s, '\r') { + // -1 because we know there is at least one \r to remove. + buf := make([]byte, 0, len(s)-1) + for i := 0; i < len(s); i++ { + if s[i] != '\r' { + buf = append(buf, s[i]) + } + } + return string(buf), nil + } + return s, nil + } + if quote != '"' && quote != '\'' { + return "", ErrSyntax + } + if contains(s, '\n') { + return "", ErrSyntax + } + + // Is it trivial? Avoid allocation. + if !contains(s, '\\') && !contains(s, quote) { + switch quote { + case '"': + if utf8.ValidString(s) { + return s, nil + } + case '\'': + r, size := utf8.DecodeRuneInString(s) + if size == len(s) && (r != utf8.RuneError || size != 1) { + return s, nil + } + } + } + + var runeTmp [utf8.UTFMax]byte + buf := make([]byte, 0, 3*len(s)/2) // Try to avoid more allocations. + for len(s) > 0 { + c, multibyte, ss, err := UnquoteChar(s, quote) + if err != nil { + return "", err + } + s = ss + if c < utf8.RuneSelf || !multibyte { + buf = append(buf, byte(c)) + } else { + n := utf8.EncodeRune(runeTmp[:], c) + buf = append(buf, runeTmp[:n]...) + } + if quote == '\'' && len(s) != 0 { + // single-quoted must be single character + return "", ErrSyntax + } + } + return string(buf), nil +} + +// contains reports whether the string contains the byte c. +func contains(s string, c byte) bool { + return IndexByteString(s, c) != -1 +} + +// Index finds the index of the first instance of the specified byte in the string. +// If the byte is not found, this returns -1. +func IndexByteString(s string, c byte) int { + for i := 0; i < len(s); i++ { + if s[i] == c { + return i + } + } + return -1 +} diff --git a/src/reflect/type.go b/src/reflect/type.go index f7745fd710..6c54e1270a 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -527,13 +527,11 @@ func (tag StructTag) Lookup(key string) (value string, ok bool) { tag = tag[i+1:] if key == name { - // TODO strconv causes import cycle - //value, err := strconv.Unquote(qvalue) - //if err != nil { - // break - //} - //return value, true - return qvalue, true + value, err := Unquote(qvalue) + if err != nil { + break + } + return value, true } } return "", false From c5d15788e22780b10a51c8c354991ecce30591ce Mon Sep 17 00:00:00 2001 From: cornelk Date: Thu, 21 May 2020 15:04:42 +0300 Subject: [PATCH 4/6] add struct tag test --- testdata/reflect.go | 14 ++++++++++++++ testdata/reflect.txt | 3 +++ 2 files changed, 17 insertions(+) diff --git a/testdata/reflect.go b/testdata/reflect.go index 40b1969c04..c4df84601b 100644 --- a/testdata/reflect.go +++ b/testdata/reflect.go @@ -264,6 +264,9 @@ func main() { default: println("type assertion failed (but should succeed)") } + + println("\nstruct tags") + TestStructTag() } func emptyFunc() { @@ -352,3 +355,14 @@ func assertSize(ok bool, typ string) { } type unreferencedType int + +func TestStructTag() { + type S struct { + F string `species:"gopher" color:"blue"` + } + + s := S{} + st := reflect.TypeOf(s) + field := st.Field(0) + println(field.Tag.Get("color"), field.Tag.Get("species")) +} diff --git a/testdata/reflect.txt b/testdata/reflect.txt index 283613068d..eeaa9c6f80 100644 --- a/testdata/reflect.txt +++ b/testdata/reflect.txt @@ -336,3 +336,6 @@ float64 8 64 complex64 8 64 complex128 16 128 type assertion succeeded for unreferenced type + +struct tags +blue gopher From d865e6e073b19ad9a9b4cf0fc1915e9b50dcae1f Mon Sep 17 00:00:00 2001 From: cornelk Date: Thu, 21 May 2020 15:05:44 +0300 Subject: [PATCH 5/6] reflect: add TODO to do split at compile time --- src/reflect/type.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/reflect/type.go b/src/reflect/type.go index 6c54e1270a..cf821984c8 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -479,6 +479,9 @@ type StructField struct { // A StructTag is the tag string in a struct field. type StructTag string +// TODO: it would be feasible to do the key/value splitting at compile time, +// avoiding the code size cost of doing it at runtime + // Get returns the value associated with key in the tag string. func (tag StructTag) Get(key string) string { v, _ := tag.Lookup(key) From 76d38a3a170db7d256bd8664291a1824e678ab79 Mon Sep 17 00:00:00 2001 From: cornelk Date: Thu, 18 Jun 2020 22:06:39 +0300 Subject: [PATCH 6/6] add copyright header do not export strconv functions in reflect --- src/reflect/strconv.go | 54 +++++++++++++++++++++--------------------- src/reflect/type.go | 6 ++++- src/runtime/mprof.go | 6 ----- src/runtime/stack.go | 4 ++++ 4 files changed, 36 insertions(+), 34 deletions(-) delete mode 100644 src/runtime/mprof.go diff --git a/src/reflect/strconv.go b/src/reflect/strconv.go index 77cf5085d2..9b07cb458d 100644 --- a/src/reflect/strconv.go +++ b/src/reflect/strconv.go @@ -8,8 +8,8 @@ import ( "unicode/utf8" ) -// ErrSyntax indicates that a value does not have the right syntax for the target type. -var ErrSyntax = badSyntax{} +// errSyntax indicates that a value does not have the right syntax for the target type. +var errSyntax = badSyntax{} type badSyntax struct{} @@ -30,7 +30,7 @@ func unhex(b byte) (v rune, ok bool) { return } -// UnquoteChar decodes the first character or byte in the escaped string +// unquoteChar decodes the first character or byte in the escaped string // or character literal represented by the string s. // It returns four values: // @@ -44,15 +44,15 @@ func unhex(b byte) (v rune, ok bool) { // If set to a single quote, it permits the sequence \' and disallows unescaped '. // If set to a double quote, it permits \" and disallows unescaped ". // If set to zero, it does not permit either escape and allows both quote characters to appear unescaped. -func UnquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, err error) { +func unquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, err error) { // easy cases if len(s) == 0 { - err = ErrSyntax + err = errSyntax return } switch c := s[0]; { case c == quote && (quote == '\'' || quote == '"'): - err = ErrSyntax + err = errSyntax return case c >= utf8.RuneSelf: r, size := utf8.DecodeRuneInString(s) @@ -63,7 +63,7 @@ func UnquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, // hard case: c is backslash if len(s) <= 1 { - err = ErrSyntax + err = errSyntax return } c := s[1] @@ -96,13 +96,13 @@ func UnquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, } var v rune if len(s) < n { - err = ErrSyntax + err = errSyntax return } for j := 0; j < n; j++ { x, ok := unhex(s[j]) if !ok { - err = ErrSyntax + err = errSyntax return } v = v<<4 | x @@ -114,7 +114,7 @@ func UnquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, break } if v > utf8.MaxRune { - err = ErrSyntax + err = errSyntax return } value = v @@ -122,20 +122,20 @@ func UnquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, case '0', '1', '2', '3', '4', '5', '6', '7': v := rune(c) - '0' if len(s) < 2 { - err = ErrSyntax + err = errSyntax return } for j := 0; j < 2; j++ { // one digit already; two more x := rune(s[j]) - '0' if x < 0 || x > 7 { - err = ErrSyntax + err = errSyntax return } v = (v << 3) | x } s = s[2:] if v > 255 { - err = ErrSyntax + err = errSyntax return } value = v @@ -143,37 +143,37 @@ func UnquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, value = '\\' case '\'', '"': if c != quote { - err = ErrSyntax + err = errSyntax return } value = rune(c) default: - err = ErrSyntax + err = errSyntax return } tail = s return } -// Unquote interprets s as a single-quoted, double-quoted, +// unquote interprets s as a single-quoted, double-quoted, // or backquoted Go string literal, returning the string value // that s quotes. (If s is single-quoted, it would be a Go -// character literal; Unquote returns the corresponding +// character literal; unquote returns the corresponding // one-character string.) -func Unquote(s string) (string, error) { +func unquote(s string) (string, error) { n := len(s) if n < 2 { - return "", ErrSyntax + return "", errSyntax } quote := s[0] if quote != s[n-1] { - return "", ErrSyntax + return "", errSyntax } s = s[1 : n-1] if quote == '`' { if contains(s, '`') { - return "", ErrSyntax + return "", errSyntax } if contains(s, '\r') { // -1 because we know there is at least one \r to remove. @@ -188,10 +188,10 @@ func Unquote(s string) (string, error) { return s, nil } if quote != '"' && quote != '\'' { - return "", ErrSyntax + return "", errSyntax } if contains(s, '\n') { - return "", ErrSyntax + return "", errSyntax } // Is it trivial? Avoid allocation. @@ -212,7 +212,7 @@ func Unquote(s string) (string, error) { var runeTmp [utf8.UTFMax]byte buf := make([]byte, 0, 3*len(s)/2) // Try to avoid more allocations. for len(s) > 0 { - c, multibyte, ss, err := UnquoteChar(s, quote) + c, multibyte, ss, err := unquoteChar(s, quote) if err != nil { return "", err } @@ -225,7 +225,7 @@ func Unquote(s string) (string, error) { } if quote == '\'' && len(s) != 0 { // single-quoted must be single character - return "", ErrSyntax + return "", errSyntax } } return string(buf), nil @@ -233,12 +233,12 @@ func Unquote(s string) (string, error) { // contains reports whether the string contains the byte c. func contains(s string, c byte) bool { - return IndexByteString(s, c) != -1 + return indexByteString(s, c) != -1 } // Index finds the index of the first instance of the specified byte in the string. // If the byte is not found, this returns -1. -func IndexByteString(s string, c byte) int { +func indexByteString(s string, c byte) int { for i := 0; i < len(s); i++ { if s[i] == c { return i diff --git a/src/reflect/type.go b/src/reflect/type.go index cf821984c8..237a5a6a9e 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -1,3 +1,7 @@ +// 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 reflect import ( @@ -530,7 +534,7 @@ func (tag StructTag) Lookup(key string) (value string, ok bool) { tag = tag[i+1:] if key == name { - value, err := Unquote(qvalue) + value, err := unquote(qvalue) if err != nil { break } diff --git a/src/runtime/mprof.go b/src/runtime/mprof.go deleted file mode 100644 index 6e9a4717be..0000000000 --- a/src/runtime/mprof.go +++ /dev/null @@ -1,6 +0,0 @@ -package runtime - -// Stack is a stub, not implemented -func Stack(buf []byte, all bool) int { - return 0 -} diff --git a/src/runtime/stack.go b/src/runtime/stack.go index c2cff3d0fa..5ef9b7ad24 100644 --- a/src/runtime/stack.go +++ b/src/runtime/stack.go @@ -14,3 +14,7 @@ func (f *Func) Name() string { func Caller(skip int) (pc uintptr, file string, line int, ok bool) { return 0, "", 0, false } + +func Stack(buf []byte, all bool) int { + return 0 +}