Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/os/env.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package os

func Getenv(key string) string {
return ""
}
32 changes: 32 additions & 0 deletions src/os/errors.go
Original file line number Diff line number Diff line change
@@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not complete (it doesn't unwrap the error) but I guess it's fine for now.

}

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 }
6 changes: 6 additions & 0 deletions src/os/exec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package os

type Signal interface {
String() string
Signal() // to distinguish from other Stringers
}
21 changes: 20 additions & 1 deletion src/os/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package os

import (
"errors"
"syscall"
)

// Portable analogs of some common system call errors.
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
Expand Down
5 changes: 5 additions & 0 deletions src/os/sys.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package os

func Hostname() (name string, err error) {
return "", ErrNotImplemented
}
9 changes: 9 additions & 0 deletions src/reflect/deepequal.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package reflect

func DeepEqual(x, y interface{}) bool {
if x == nil || y == nil {
return x == y
}

panic("unimplemented: reflect.DeepEqual()")
}
83 changes: 81 additions & 2 deletions src/reflect/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ""
Expand Down Expand Up @@ -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.
Expand All @@ -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) {
Comment on lines +495 to +496
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Get and Lookup will need tests. Please add them to testdata/reflect.go. You can probably just try to lookup a few tags and if they are present, print them (just like many other properties of types/values are printed).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it may be better to use something other than a string for StructTag eventually. The last time I looked through the standard library, no package was using StructTag as a string but instead just called the Get and Lookup functions. Therefore, I think it would be feasible to do the key/value splitting at compile time, avoiding the code size cost of doing it at runtime (and possibly speeding things up as well, although that's not the goal).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure you actually need Get and Lookup? You could perhaps simplify things by stubbing them out. At least when I tested the encoding/json package, I think I managed to do without for a proof-of-concept.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the StructTag type with it's functions is actively used in common libraries github.com/BurntSushi/toml and gopkg.in/yaml.v2

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added your proposal to do it at compile time as a TODO comment. For this MR i focused on getting more libraries to compile.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked both libraries.

  • github.com/BurntSushi/toml passes the .Tag field as a StructTag to getOptions and only uses the .Get function. That would allow doing the key/value parsing at compile time.
  • gopkg.in/yaml.v2 unfortunately does use the raw string. It looks like they fall back to using the whole string if the struct tag is not in a key/value format. I think they shouldn't do this as it breaks the convention, but it's probably hard to persuade them to change this (there is probably code that depends on this behavior).

Not sure what to do here, maybe using raw strings is better after all (even though it will likely increase code size). Maybe there are optimizations possible here, but I'm not sure whether that's possible in a sane way.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you write this code yourself or did you copy it? If you copied it, it should have a copyright note (just like the strconv.go file).

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 {
Expand Down
42 changes: 42 additions & 0 deletions src/reflect/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()")
}
Expand Down Expand Up @@ -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()")
}
8 changes: 8 additions & 0 deletions src/runtime/error.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package runtime

// The Error interface identifies a run time error.
type Error interface {
error

RuntimeError()
}
6 changes: 6 additions & 0 deletions src/runtime/mprof.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package runtime

// Stack is a stub, not implemented
func Stack(buf []byte, all bool) int {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could add this to stack.go, which has similar functions (to avoid yet another small file).

None of these are likely to be implemented considering what TinyGo is designed for.

return 0
}
15 changes: 15 additions & 0 deletions src/sync/map.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
}
11 changes: 11 additions & 0 deletions src/sync/mutex.go
Original file line number Diff line number Diff line change
Expand Up @@ -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() }
34 changes: 34 additions & 0 deletions src/syscall/net.go
Original file line number Diff line number Diff line change
@@ -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)
}