diff --git a/rune/Makefile b/rune/Makefile index 2bbb12d3edbcf4ff811881cf1cadacb949cc6fe0..9706781bb51ea83556e159a230b031d8a8744e25 100644 --- a/rune/Makefile +++ b/rune/Makefile @@ -22,7 +22,8 @@ ifeq ($(DEBUG),1) GCFLAGS=-gcflags "-N -l" endif -PROTO_DIR := libenclave/proto +PROTO_DIR := libenclave/proto libenclave/intelsgx/proto +PROTOS := $(foreach dir,$(PROTO_DIR),$(patsubst %.proto,%.pb.go,$(wildcard $(dir)/*.proto))) GO_BUILD := $(GO) build $(MOD_VENDOR) -buildmode=pie $(GCFLAGS) $(EXTRA_FLAGS) -tags "$(BUILDTAGS)" \ -ldflags "-X main.gitCommit=$(COMMIT) -X main.version=$(VERSION) $(EXTRA_LDFLAGS)" @@ -31,7 +32,7 @@ GO_BUILD_STATIC := CGO_ENABLED=1 $(GO) build $(MOD_VENDOR) $(GCFLAGS) $(EXTRA_FL .DEFAULT: rune -rune: $(patsubst %.proto,%.pb.go,$(wildcard $(PROTO_DIR)/*.proto)) +rune: $(PROTOS) $(GO_BUILD) -o rune . %.pb.go: %.proto @@ -124,7 +125,7 @@ clean: rm -f contrib/cmd/recvtty/recvtty rm -rf release rm -rf man/man8 - rm -f libenclave/proto/*.pb.go + rm -f $(PROTOS) make -C libenclave/internal/runtime/pal/skeleton clean validate: diff --git a/rune/go.mod b/rune/go.mod index 4e39f4db4db4b87c6ab00ea2729c6e022079c1d9..e226fc4969418b81c2080538b64f0f9702876235 100644 --- a/rune/go.mod +++ b/rune/go.mod @@ -9,6 +9,7 @@ require ( github.com/coreos/go-systemd/v22 v22.0.0 github.com/cyphar/filepath-securejoin v0.2.2 github.com/docker/go-units v0.4.0 + github.com/go-restruct/restruct v0.0.0-20191227155143-5734170a48a1 github.com/godbus/dbus/v5 v5.0.3 github.com/golang/protobuf v1.3.5 github.com/moby/sys/mountinfo v0.1.3 diff --git a/rune/go.sum b/rune/go.sum index fc16a9b10d51da4a835925cb9b19a0488aeb0570..c2d9d24c0cae8e8d17515d7808f936654a6ef9b6 100644 --- a/rune/go.sum +++ b/rune/go.sum @@ -11,10 +11,13 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSY github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/go-restruct/restruct v0.0.0-20191227155143-5734170a48a1 h1:LoN2wx/aN8JPGebG+2DaUyk4M+xRcqJXfuIbs8AWHdE= +github.com/go-restruct/restruct v0.0.0-20191227155143-5734170a48a1/go.mod h1:KqrpKpn4M8OLznErihXTGLlsXFGeLxHUrLRRI/1YjGk= github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls= @@ -42,8 +45,10 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5I github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q= github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 h1:b6uOv7YOFK0TYG7HtkIgExQo+2RdLuwRft63jn2HWj8= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= diff --git a/rune/libenclave/intelsgx/aesmd.go b/rune/libenclave/intelsgx/aesmd.go new file mode 100644 index 0000000000000000000000000000000000000000..0696771fa2ad783290ef5ab18a21c17c19b7ac5a --- /dev/null +++ b/rune/libenclave/intelsgx/aesmd.go @@ -0,0 +1,183 @@ +package intelsgx // import "github.com/opencontainers/runc/libenclave/intelsgx" + +import ( + "bytes" + "encoding/binary" + "encoding/hex" + "fmt" + "github.com/go-restruct/restruct" + "github.com/golang/protobuf/proto" + pb "github.com/opencontainers/runc/libenclave/intelsgx/proto" + "github.com/sirupsen/logrus" + "net" +) + +const ( + aesmdSocket = "/var/run/aesmd/aesm.socket" +) + +func dialAesmd() (*net.UnixConn, error) { + addr, err := net.ResolveUnixAddr("unix", aesmdSocket) + if err != nil { + return nil, err + } + + conn, err := net.DialUnix("unix", nil, addr) + if err != nil { + return nil, err + } + + return conn, nil +} + +func GetToken(sig []byte) ([]byte, error) { + if len(sig) != SigStructLength { + return nil, fmt.Errorf("signature not match SIGSTRUCT") + } + + s := &SigStruct{} + if err := restruct.Unpack(sig, binary.LittleEndian, &s); err != nil { + return nil, err + } + + mrenclave := s.EnclaveHash[:] + modulus := s.Modulus[:] + attributes := s.Attributes[:] + + logrus.Debugf("SIGSTRUCT:") + _ = s.Header[:] + logrus.Debugf(" Enclave Vendor: %#08x\n", + s.Vendor) + logrus.Debugf(" Enclave Build Date: %d-%d-%d\n", + s.BuildYear, s.BuildMonth, s.BuildDay) + logrus.Debugf(" Software Defined: %#08x\n", + s.SwDefined) + logrus.Debugf(" ISV assigned Product Family ID: 0x%v\n", + hex.EncodeToString(s.ISVFamilyId[:])) + logrus.Debugf(" ISV assigned Produdct ID: %#04x\n", + s.ISVProdId) + logrus.Debugf(" ISV assigned Extended Product ID: 0x%v\n", + hex.EncodeToString(s.ISVExtProdId[:])) + logrus.Debugf(" ISV assigned SVN: %d\n", s.ISVSvn) + logrus.Debugf(" Enclave Attributes: 0x%v\n", + hex.EncodeToString(attributes)) + logrus.Debugf(" Enclave Attributes Mask: 0x%v\n", + hex.EncodeToString(s.AttributesMask[:])) + logrus.Debugf(" Enclave Misc Select: %#08x\n", + s.MiscSelect) + logrus.Debugf(" Enclave Misc Mask: %#08x\n", + s.MiscMask) + logrus.Debugf(" Enclave Hash: 0x%v\n", + hex.EncodeToString(mrenclave)) + logrus.Debugf(" Modulus: 0x%v...\n", + hex.EncodeToString(modulus[:32])) + logrus.Debugf(" Exponent: %d\n", + s.Exponent) + logrus.Debugf(" Signature: 0x%v...\n", + hex.EncodeToString(s.Signature[:32])) + logrus.Debugf(" Q1: 0x%v...\n", + hex.EncodeToString(s.Q1[:32])) + logrus.Debugf(" Q2: 0x%v...\n", + hex.EncodeToString(s.Q2[:32])) + + conn, err := dialAesmd() + if err != nil { + return nil, err + } + defer conn.Close() + + req := pb.GetTokenRequestMessage{} + req.Req = &pb.GetTokenRequest{ + Enclavehash: mrenclave, + Modulus: modulus, + Attributes: attributes, + Timeout: 10000, + } + + var rdata []byte + rdata, err = proto.Marshal(&req) + if err != nil { + return nil, err + } + + msgSize := uint32(len(rdata)) + byteBuf := bytes.NewBuffer([]byte{}) + binary.Write(byteBuf, binary.LittleEndian, &msgSize) + if _, err = conn.Write(byteBuf.Bytes()); err != nil { + return nil, err + } + + if _, err = conn.Write(rdata); err != nil { + return nil, err + } + + rdata = append(rdata[:4]) + if _, err = conn.Read(rdata); err != nil { + return nil, err + } + + byteBuf = bytes.NewBuffer(rdata) + if err = binary.Read(byteBuf, binary.LittleEndian, &msgSize); err != nil { + return nil, err + } + + rdata = make([]byte, msgSize) + var msgSizeRead int + msgSizeRead, err = conn.Read(rdata) + if err != nil { + return nil, err + } + + if msgSizeRead != int(msgSize) { + return nil, fmt.Errorf("invalid response size (returned %d, expected %d)", + msgSizeRead, msgSize) + } + + resp := pb.GetTokenResponseMessage{} + resp.Resp = &pb.GetTokenResponse{} + if err := proto.Unmarshal(rdata, &resp); err != nil { + return nil, err + } + + if resp.Resp.GetError() != 0 { + return nil, fmt.Errorf("failed to get EINITTOKEN (error code = %d)", + resp.Resp.GetError()) + } + + token := resp.Resp.GetToken() + if len(token) != EinittokenLength { + return nil, fmt.Errorf("invalid length of token: (returned %d, expected %d)", + len(resp.Resp.GetToken()), EinittokenLength) + } + + tok := &Einittoken{} + if err := restruct.Unpack(token, binary.LittleEndian, &tok); err != nil { + return nil, err + } + + logrus.Debugf("EINITTOKEN:\n") + logrus.Debugf(" Valid: %d\n", + tok.Valid) + logrus.Debugf(" Enclave Attributes: 0x%v\n", + hex.EncodeToString(tok.Attributes[:])) + logrus.Debugf(" Enclave Hash: 0x%v\n", + hex.EncodeToString(tok.MrEnclave[:])) + logrus.Debugf(" Enclave Signer: 0x%v\n", + hex.EncodeToString(tok.MrSigner[:])) + logrus.Debugf(" Launch Enclave's CPU SVN : 0x%v\n", + hex.EncodeToString(tok.CpuSvnLe[:])) + logrus.Debugf(" Launch Enclave's ISV assigned Product ID: %#04x\n", + tok.ISVProdIdLe) + logrus.Debugf(" Launch Enclave's ISV assigned SVN: %d\n", + tok.ISVSvnLe) + logrus.Debugf(" Launch Enclave's Masked Misc Select: %#08x\n", + tok.MaskedMiscSelectLe) + logrus.Debugf(" Launch Enclave's Masked Attributes: 0x%v\n", + hex.EncodeToString(tok.MaskedAttributesLe[:])) + logrus.Debugf(" Key ID: 0x%v\n", + hex.EncodeToString(tok.KeyId[:])) + logrus.Debugf(" MAC: 0x%v\n", + hex.EncodeToString(tok.Mac[:])) + + return resp.Resp.GetToken(), nil +} diff --git a/runectl/proto/aesm-service.proto b/rune/libenclave/intelsgx/proto/aesm-service.proto similarity index 79% rename from runectl/proto/aesm-service.proto rename to rune/libenclave/intelsgx/proto/aesm-service.proto index 61f77870eecef371dabed0baa68eb408b3dd49e7..a4d2f4b232716ebba5aeb48b917025f25caf898b 100644 --- a/runectl/proto/aesm-service.proto +++ b/rune/libenclave/intelsgx/proto/aesm-service.proto @@ -1,6 +1,6 @@ syntax = "proto3"; -package aesm_service; // import "github.com/inclavare-containers/runectl/proto" +package aesm_service; // import "github.com/opencontainers/runc/libenclave/intelsgx/proto" message GetTokenRequest { bytes enclavehash = 1; diff --git a/rune/vendor/github.com/go-restruct/restruct/.gitignore b/rune/vendor/github.com/go-restruct/restruct/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..2d830686d42dea576f9194b0eb41b15df24cdcc1 --- /dev/null +++ b/rune/vendor/github.com/go-restruct/restruct/.gitignore @@ -0,0 +1 @@ +coverage.out diff --git a/rune/vendor/github.com/go-restruct/restruct/.travis.yml b/rune/vendor/github.com/go-restruct/restruct/.travis.yml new file mode 100644 index 0000000000000000000000000000000000000000..eb9cadd3fbd7ff40340dd36a9c597a6ec6e898ed --- /dev/null +++ b/rune/vendor/github.com/go-restruct/restruct/.travis.yml @@ -0,0 +1,12 @@ +language: go +go: + - '1.7' + - '1.11' + - '1.12' + - '1.13' + - tip +script: + - go test -coverprofile=coverage.txt -covermode=atomic + - "if [[ $TRAVIS_GO_VERSION == 1.13 ]]; then bash <(curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh) -b $(go env GOPATH)/bin v1.20.0 && golangci-lint run; fi" +after_success: + - bash <(curl -s https://codecov.io/bash) diff --git a/rune/vendor/github.com/go-restruct/restruct/CONTRIBUTORS.md b/rune/vendor/github.com/go-restruct/restruct/CONTRIBUTORS.md new file mode 100644 index 0000000000000000000000000000000000000000..2a3db9f48b295ec06673243e87559cfd92f52135 --- /dev/null +++ b/rune/vendor/github.com/go-restruct/restruct/CONTRIBUTORS.md @@ -0,0 +1,6 @@ +restruct is an open source project that anyone can contribute to. This file contains a list of all contributors up to this point. This list is obtained by running `git shortlog -s` and is listed in alphabetical order. If this file falls out of date and is missing a name, or an entry should be changed, please [file an issue](https://github.com/go-restruct/restruct/issues/new). + + * [Dave Cheney](https://github.com/davecheney) + * [John Chadwick](https://github.com/jchv) + * [jlojosnegros](https://github.com/jlojosnegros) + diff --git a/rune/vendor/github.com/go-restruct/restruct/LICENSE.md b/rune/vendor/github.com/go-restruct/restruct/LICENSE.md new file mode 100644 index 0000000000000000000000000000000000000000..f7660ee57fad59d0004c59fdec949e217ad23a31 --- /dev/null +++ b/rune/vendor/github.com/go-restruct/restruct/LICENSE.md @@ -0,0 +1,15 @@ +ISC License + +Copyright © 2015, John Chadwick + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. diff --git a/rune/vendor/github.com/go-restruct/restruct/README.md b/rune/vendor/github.com/go-restruct/restruct/README.md new file mode 100644 index 0000000000000000000000000000000000000000..c077601691ec12aadd16d859b626856cb059682d --- /dev/null +++ b/rune/vendor/github.com/go-restruct/restruct/README.md @@ -0,0 +1,58 @@ +# restruct [![Build Status](https://travis-ci.org/go-restruct/restruct.svg)](https://travis-ci.org/go-restruct/restruct) [![codecov.io](http://codecov.io/github/go-restruct/restruct/coverage.svg?branch=master)](http://codecov.io/github/go-restruct/restruct?branch=master) [![godoc.org](http://img.shields.io/badge/godoc-reference-5272B4.svg?style=flat-square)](https://godoc.org/github.com/go-restruct/restruct) [![Go Report Card](https://goreportcard.com/badge/github.com/go-restruct/restruct)](https://goreportcard.com/report/github.com/go-restruct/restruct) +`restruct` is a library for reading and writing binary data in Go. Similar to +lunixbochs `struc` and `encoding/binary`, this library reads data based on the +layout of structures and, like `struc`, based on what is contained in struct +tags. + +To install Restruct, use the following command: + +``` +go get github.com/go-restruct/restruct +``` + +`restruct` aims to provide a clean, flexible, robust implementation of struct +packing. In the future, through fast-path optimizations and code generation, it +also aims to be quick, but it is currently very slow. + +`restruct` currently requires Go 1.7+. + +## Status + + * As of writing, coverage is hovering around 95%, but more thorough testing + is always useful and desirable. + * Unpacking and packing are fully functional. + * More optimizations are probably possible. + +## Example + +```go +package main + +import ( + "encoding/binary" + "io/ioutil" + "os" + + "github.com/go-restruct/restruct" +) + +type Record struct { + Message string `struct:"[128]byte"` +} + +type Container struct { + Version int `struct:"int32"` + NumRecord int `struct:"int32,sizeof=Records"` + Records []Record +} + +func main() { + var c Container + + file, _ := os.Open("records") + defer file.Close() + data, _ := ioutil.ReadAll(file) + + restruct.Unpack(data, binary.LittleEndian, &c) +} +``` diff --git a/rune/vendor/github.com/go-restruct/restruct/arrayof.go b/rune/vendor/github.com/go-restruct/restruct/arrayof.go new file mode 100644 index 0000000000000000000000000000000000000000..7fdf89fdea94df1c1f6aa4a54b3c97c8ccc3a3db --- /dev/null +++ b/rune/vendor/github.com/go-restruct/restruct/arrayof.go @@ -0,0 +1,5 @@ +package restruct + +// RegisterArrayType is deprecated; it is now a noop. +func RegisterArrayType(array interface{}) { +} diff --git a/rune/vendor/github.com/go-restruct/restruct/decoder.go b/rune/vendor/github.com/go-restruct/restruct/decoder.go new file mode 100644 index 0000000000000000000000000000000000000000..96f15b72ba1f22c80390074c31a046bea01f4da2 --- /dev/null +++ b/rune/vendor/github.com/go-restruct/restruct/decoder.go @@ -0,0 +1,413 @@ +package restruct + +import ( + "encoding/binary" + "fmt" + "math" + "reflect" + "strings" +) + +// Unpacker is a type capable of unpacking a binary representation of itself +// into a native representation. The Unpack function is expected to consume +// a number of bytes from the buffer, then return a slice of the remaining +// bytes in the buffer. You may use a pointer receiver even if the type is +// used by value. +type Unpacker interface { + Unpack(buf []byte, order binary.ByteOrder) ([]byte, error) +} + +type decoder struct { + structstack + order binary.ByteOrder + sfields []field + bitCounter uint8 + bitSize int +} + +func putBit(buf []byte, bitSize int, bit int, val byte) { + bit = bitSize - 1 - bit + buf[len(buf)-bit/8-1] |= (val) << (uint(bit) % 8) +} + +func (d *decoder) readBit() byte { + value := (d.buf[0] >> uint(7-d.bitCounter)) & 1 + d.bitCounter++ + if d.bitCounter >= 8 { + d.buf = d.buf[1:] + d.bitCounter -= 8 + } + return value +} + +func (d *decoder) readBits(f field, outBuf []byte) { + var decodedBits int + + // Determine encoded size in bits. + if d.bitSize == 0 { + decodedBits = 8 * len(outBuf) + } else { + decodedBits = int(d.bitSize) + } + + // Crop output buffer to relevant bytes only. + outBuf = outBuf[len(outBuf)-(decodedBits+7)/8:] + + if d.bitCounter == 0 && decodedBits%8 == 0 { + // Fast path: we are fully byte-aligned. + copy(outBuf, d.buf) + d.buf = d.buf[len(outBuf):] + } else { + // Slow path: work bit-by-bit. + // TODO: This needs to be optimized in a way that can be easily + // understood; the previous optimized version was simply too hard to + // reason about. + for i := 0; i < decodedBits; i++ { + putBit(outBuf, decodedBits, i, d.readBit()) + } + } +} + +func (d *decoder) read8(f field) uint8 { + b := make([]byte, 1) + d.readBits(f, b) + return uint8(b[0]) +} + +func (d *decoder) read16(f field) uint16 { + b := make([]byte, 2) + d.readBits(f, b) + return d.order.Uint16(b) +} + +func (d *decoder) read32(f field) uint32 { + b := make([]byte, 4) + d.readBits(f, b) + return d.order.Uint32(b) +} + +func (d *decoder) read64(f field) uint64 { + b := make([]byte, 8) + d.readBits(f, b) + return d.order.Uint64(b) +} + +func (d *decoder) readS8(f field) int8 { return int8(d.read8(f)) } + +func (d *decoder) readS16(f field) int16 { return int16(d.read16(f)) } + +func (d *decoder) readS32(f field) int32 { return int32(d.read32(f)) } + +func (d *decoder) readS64(f field) int64 { return int64(d.read64(f)) } + +func (d *decoder) readBytes(count int) []byte { + x := d.buf[0:count] + d.buf = d.buf[count:] + return x +} + +func (d *decoder) skipBits(count int) { + d.bitCounter += uint8(count % 8) + if d.bitCounter > 8 { + d.bitCounter -= 8 + count += 8 + } + d.buf = d.buf[count/8:] +} + +func (d *decoder) skip(f field, v reflect.Value) { + d.skipBits(d.fieldbits(f, v)) +} + +func (d *decoder) unpacker(v reflect.Value) (Unpacker, bool) { + if s, ok := v.Interface().(Unpacker); ok { + return s, true + } + + if !v.CanAddr() { + return nil, false + } + + if s, ok := v.Addr().Interface().(Unpacker); ok { + return s, true + } + + return nil, false +} + +func (d *decoder) setUint(f field, v reflect.Value, x uint64) { + switch v.Kind() { + case reflect.Bool: + b := x != 0 + if f.Flags&InvertedBoolFlag == InvertedBoolFlag { + b = !b + } + v.SetBool(b) + default: + v.SetUint(x) + } +} + +func (d *decoder) setInt(f field, v reflect.Value, x int64) { + switch v.Kind() { + case reflect.Bool: + b := x != 0 + if f.Flags&InvertedBoolFlag == InvertedBoolFlag { + b = !b + } + v.SetBool(b) + default: + v.SetInt(x) + } +} + +func (d *decoder) switc(f field, v reflect.Value, on interface{}) { + var def *switchcase + + if v.Kind() != reflect.Struct { + panic(fmt.Errorf("%s: only switches on structs are valid", f.Name)) + } + + sfields := cachedFieldsFromStruct(f.BinaryType) + l := len(sfields) + + // Zero out values for decoding. + for i := 0; i < l; i++ { + v := v.Field(f.Index) + v.Set(reflect.Zero(v.Type())) + } + + for i := 0; i < l; i++ { + f := sfields[i] + v := v.Field(f.Index) + + if f.Flags&DefaultFlag != 0 { + if def != nil { + panic(fmt.Errorf("%s: only one default case is allowed", f.Name)) + } + def = &switchcase{f, v} + continue + } + + if f.CaseExpr == nil { + panic(fmt.Errorf("%s: only cases are valid inside switches", f.Name)) + } + + if d.evalExpr(f.CaseExpr) == on { + d.read(f, v) + return + } + } + + if def != nil { + d.read(def.f, def.v) + } +} + +func (d *decoder) read(f field, v reflect.Value) { + if f.Flags&RootFlag == RootFlag { + d.setancestor(f, v, d.root()) + return + } + + if f.Flags&ParentFlag == ParentFlag { + for i := 1; i < len(d.stack); i++ { + if d.setancestor(f, v, d.ancestor(i)) { + break + } + } + return + } + + if f.SwitchExpr != nil { + d.switc(f, v, d.evalExpr(f.SwitchExpr)) + return + } + + struc := d.ancestor(0) + + if f.Name != "_" { + if s, ok := d.unpacker(v); ok { + var err error + d.buf, err = s.Unpack(d.buf, d.order) + if err != nil { + panic(err) + } + return + } + } else { + d.skipBits(d.fieldbits(f, v)) + return + } + + if !d.evalIf(f) { + return + } + + sfields := d.sfields + order := d.order + + if f.Order != nil { + d.order = f.Order + defer func() { d.order = order }() + } + + if f.Skip != 0 { + d.skipBits(f.Skip * 8) + } + + d.bitSize = d.evalBits(f) + alen := d.evalSize(f) + + if alen == 0 && f.SIndex != -1 { + sv := struc.Field(f.SIndex) + l := len(sfields) + for i := 0; i < l; i++ { + if sfields[i].Index != f.SIndex { + continue + } + sf := sfields[i] + // Must use different codepath for signed/unsigned. + switch sf.BinaryType.Kind() { + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + alen = int(sv.Int()) + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + alen = int(sv.Uint()) + default: + panic(fmt.Errorf("unsupported size type %s: %s", sf.BinaryType.String(), sf.Name)) + } + break + } + } + + switch f.BinaryType.Kind() { + case reflect.Array: + l := f.BinaryType.Len() + + // If the underlying value is a slice, initialize it. + if f.NativeType.Kind() == reflect.Slice { + v.Set(reflect.MakeSlice(reflect.SliceOf(f.NativeType.Elem()), l, l)) + } + + switch f.NativeType.Kind() { + case reflect.String: + // When using strings, treat as C string. + str := string(d.readBytes(d.fieldbytes(f, v))) + nul := strings.IndexByte(str, 0) + if nul != -1 { + str = str[0:nul] + } + v.SetString(str) + case reflect.Slice, reflect.Array: + ef := f.Elem() + for i := 0; i < l; i++ { + d.read(ef, v.Index(i)) + } + default: + panic(fmt.Errorf("invalid array cast type: %s", f.NativeType.String())) + } + + case reflect.Struct: + d.push(v) + d.sfields = cachedFieldsFromStruct(f.BinaryType) + l := len(d.sfields) + for i := 0; i < l; i++ { + f := d.sfields[i] + v := v.Field(f.Index) + if v.CanSet() { + d.read(f, v) + } else { + d.skip(f, v) + } + } + d.sfields = sfields + d.pop(v) + + case reflect.Ptr: + v.Set(reflect.New(v.Type().Elem())) + d.read(f.Elem(), v.Elem()) + + case reflect.Slice, reflect.String: + fixed := func() { + switch f.NativeType.Elem().Kind() { + case reflect.Uint8: + v.SetBytes(d.readBytes(d.fieldbytes(f, v))) + default: + ef := f.Elem() + for i := 0; i < alen; i++ { + d.read(ef, v.Index(i)) + } + } + } + switch f.NativeType.Kind() { + case reflect.String: + v.SetString(string(d.readBytes(alen))) + case reflect.Array: + if f.WhileExpr != nil { + i := 0 + ef := f.Elem() + for d.evalWhile(f) { + d.read(ef, v.Index(i)) + i++ + } + } else { + fixed() + } + case reflect.Slice: + if f.WhileExpr != nil { + switch f.NativeType.Kind() { + case reflect.Slice: + ef := f.Elem() + for d.evalWhile(f) { + nv := reflect.New(ef.NativeType).Elem() + d.read(ef, nv) + v.Set(reflect.Append(v, nv)) + } + } + } else { + v.Set(reflect.MakeSlice(f.NativeType, alen, alen)) + fixed() + } + default: + panic(fmt.Errorf("invalid array cast type: %s", f.NativeType.String())) + } + + case reflect.Int8: + d.setInt(f, v, int64(d.readS8(f))) + case reflect.Int16: + d.setInt(f, v, int64(d.readS16(f))) + case reflect.Int32: + d.setInt(f, v, int64(d.readS32(f))) + case reflect.Int64: + d.setInt(f, v, d.readS64(f)) + + case reflect.Uint8, reflect.Bool: + d.setUint(f, v, uint64(d.read8(f))) + case reflect.Uint16: + d.setUint(f, v, uint64(d.read16(f))) + case reflect.Uint32: + d.setUint(f, v, uint64(d.read32(f))) + case reflect.Uint64: + d.setUint(f, v, d.read64(f)) + + case reflect.Float32: + v.SetFloat(float64(math.Float32frombits(d.read32(f)))) + case reflect.Float64: + v.SetFloat(math.Float64frombits(d.read64(f))) + + case reflect.Complex64: + v.SetComplex(complex( + float64(math.Float32frombits(d.read32(f))), + float64(math.Float32frombits(d.read32(f))), + )) + case reflect.Complex128: + v.SetComplex(complex( + math.Float64frombits(d.read64(f)), + math.Float64frombits(d.read64(f)), + )) + } + + if f.InExpr != nil { + v.Set(reflect.ValueOf(d.evalExpr(f.InExpr))) + } +} diff --git a/rune/vendor/github.com/go-restruct/restruct/encoder.go b/rune/vendor/github.com/go-restruct/restruct/encoder.go new file mode 100644 index 0000000000000000000000000000000000000000..9b5207fc6315bea0c7a242e687f66c7083c3885c --- /dev/null +++ b/rune/vendor/github.com/go-restruct/restruct/encoder.go @@ -0,0 +1,364 @@ +package restruct + +import ( + "encoding/binary" + "fmt" + "math" + "reflect" +) + +// Packer is a type capable of packing a native value into a binary +// representation. The Pack function is expected to overwrite a number of +// bytes in buf then return a slice of the remaining buffer. Note that you +// must also implement SizeOf, and returning an incorrect SizeOf will cause +// the encoder to crash. The SizeOf should be equal to the number of bytes +// consumed from the buffer slice in Pack. You may use a pointer receiver even +// if the type is used by value. +type Packer interface { + Sizer + Pack(buf []byte, order binary.ByteOrder) ([]byte, error) +} + +type encoder struct { + structstack + order binary.ByteOrder + sfields []field + bitCounter int + bitSize int +} + +func getBit(buf []byte, bitSize int, bit int) byte { + bit = bitSize - 1 - bit + return (buf[len(buf)-bit/8-1] >> (uint(bit) % 8)) & 1 +} + +func (e *encoder) writeBit(value byte) { + e.buf[0] |= (value & 1) << uint(7-e.bitCounter) + e.bitCounter++ + if e.bitCounter >= 8 { + e.buf = e.buf[1:] + e.bitCounter -= 8 + } +} + +func (e *encoder) writeBits(f field, inBuf []byte) { + var encodedBits int + + // Determine encoded size in bits. + if e.bitSize == 0 { + encodedBits = 8 * len(inBuf) + } else { + encodedBits = int(e.bitSize) + } + + // Crop input buffer to relevant bytes only. + inBuf = inBuf[len(inBuf)-(encodedBits+7)/8:] + + if e.bitCounter == 0 && encodedBits%8 == 0 { + // Fast path: we are fully byte-aligned. + copy(e.buf, inBuf) + e.buf = e.buf[len(inBuf):] + } else { + // Slow path: work bit-by-bit. + // TODO: This needs to be optimized in a way that can be easily + // understood; the previous optimized version was simply too hard to + // reason about. + for i := 0; i < encodedBits; i++ { + e.writeBit(getBit(inBuf, encodedBits, i)) + } + } +} + +func (e *encoder) write8(f field, x uint8) { + b := make([]byte, 1) + b[0] = x + e.writeBits(f, b) +} + +func (e *encoder) write16(f field, x uint16) { + b := make([]byte, 2) + e.order.PutUint16(b, x) + e.writeBits(f, b) +} + +func (e *encoder) write32(f field, x uint32) { + b := make([]byte, 4) + e.order.PutUint32(b, x) + e.writeBits(f, b) +} + +func (e *encoder) write64(f field, x uint64) { + b := make([]byte, 8) + e.order.PutUint64(b, x) + e.writeBits(f, b) +} + +func (e *encoder) writeS8(f field, x int8) { e.write8(f, uint8(x)) } + +func (e *encoder) writeS16(f field, x int16) { e.write16(f, uint16(x)) } + +func (e *encoder) writeS32(f field, x int32) { e.write32(f, uint32(x)) } + +func (e *encoder) writeS64(f field, x int64) { e.write64(f, uint64(x)) } + +func (e *encoder) skipBits(count int) { + e.bitCounter += count % 8 + if e.bitCounter > 8 { + e.bitCounter -= 8 + count += 8 + } + e.buf = e.buf[count/8:] +} + +func (e *encoder) skip(f field, v reflect.Value) { + e.skipBits(e.fieldbits(f, v)) +} + +func (e *encoder) packer(v reflect.Value) (Packer, bool) { + if s, ok := v.Interface().(Packer); ok { + return s, true + } + + if !v.CanAddr() { + return nil, false + } + + if s, ok := v.Addr().Interface().(Packer); ok { + return s, true + } + + return nil, false +} + +func (e *encoder) intFromField(f field, v reflect.Value) int64 { + switch v.Kind() { + case reflect.Bool: + b := v.Bool() + if f.Flags&InvertedBoolFlag == InvertedBoolFlag { + b = !b + } + if b { + if f.Flags&VariantBoolFlag == VariantBoolFlag { + return -1 + } + return 1 + } + return 0 + default: + return v.Int() + } +} + +func (e *encoder) uintFromField(f field, v reflect.Value) uint64 { + switch v.Kind() { + case reflect.Bool: + b := v.Bool() + if f.Flags&InvertedBoolFlag == InvertedBoolFlag { + b = !b + } + if b { + if f.Flags&VariantBoolFlag == VariantBoolFlag { + return ^uint64(0) + } + return 1 + } + return 0 + default: + return v.Uint() + } +} + +func (e *encoder) switc(f field, v reflect.Value, on interface{}) { + var def *switchcase + + if v.Kind() != reflect.Struct { + panic(fmt.Errorf("%s: only switches on structs are valid", f.Name)) + } + + sfields := cachedFieldsFromStruct(f.BinaryType) + l := len(sfields) + + for i := 0; i < l; i++ { + f := sfields[i] + v := v.Field(f.Index) + + if f.Flags&DefaultFlag != 0 { + if def != nil { + panic(fmt.Errorf("%s: only one default case is allowed", f.Name)) + } + def = &switchcase{f, v} + continue + } + + if f.CaseExpr == nil { + panic(fmt.Errorf("%s: only cases are valid inside switches", f.Name)) + } + + if e.evalExpr(f.CaseExpr) == on { + e.write(f, v) + return + } + } + + if def != nil { + e.write(def.f, def.v) + } +} + +func (e *encoder) write(f field, v reflect.Value) { + if f.Flags&RootFlag == RootFlag { + e.setancestor(f, v, e.root()) + return + } + + if f.Flags&ParentFlag == ParentFlag { + for i := 1; i < len(e.stack); i++ { + if e.setancestor(f, v, e.ancestor(i)) { + break + } + } + return + } + + if f.SwitchExpr != nil { + e.switc(f, v, e.evalExpr(f.SwitchExpr)) + return + } + + struc := e.ancestor(0) + + if f.Name != "_" { + if s, ok := e.packer(v); ok { + var err error + e.buf, err = s.Pack(e.buf, e.order) + if err != nil { + panic(err) + } + return + } + } else { + e.skipBits(e.fieldbits(f, v)) + return + } + + if !e.evalIf(f) { + return + } + + sfields := e.sfields + order := e.order + + if f.Order != nil { + e.order = f.Order + defer func() { e.order = order }() + } + + if f.Skip != 0 { + e.skipBits(f.Skip * 8) + } + + e.bitSize = e.evalBits(f) + + // If this is a sizeof field, pull the current slice length into it. + if f.TIndex != -1 { + sv := struc.Field(f.TIndex) + + switch f.BinaryType.Kind() { + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + v.SetInt(int64(sv.Len())) + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + v.SetUint(uint64(sv.Len())) + default: + panic(fmt.Errorf("unsupported size type %s: %s", f.BinaryType.String(), f.Name)) + } + } + + ov := v + if f.OutExpr != nil { + ov = reflect.ValueOf(e.evalExpr(f.OutExpr)) + } + + switch f.BinaryType.Kind() { + case reflect.Ptr: + // Skip if pointer is nil. + if v.IsNil() { + return + } + + e.write(f.Elem(), v.Elem()) + + case reflect.Array, reflect.Slice, reflect.String: + switch f.NativeType.Kind() { + case reflect.Slice, reflect.String: + if f.SizeExpr != nil { + if l := e.evalSize(f); l != ov.Len() { + panic(fmt.Errorf("length does not match size expression (%d != %d)", ov.Len(), l)) + } + } + fallthrough + case reflect.Array: + ef := f.Elem() + len := ov.Len() + cap := len + if f.BinaryType.Kind() == reflect.Array { + cap = f.BinaryType.Len() + } + for i := 0; i < len; i++ { + e.write(ef, ov.Index(i)) + } + for i := len; i < cap; i++ { + e.write(ef, reflect.New(f.BinaryType.Elem()).Elem()) + } + default: + panic(fmt.Errorf("invalid array cast type: %s", f.NativeType.String())) + } + + case reflect.Struct: + e.push(ov) + e.sfields = cachedFieldsFromStruct(f.BinaryType) + l := len(e.sfields) + for i := 0; i < l; i++ { + sf := e.sfields[i] + sv := ov.Field(sf.Index) + if sv.CanSet() { + e.write(sf, sv) + } else { + e.skip(sf, sv) + } + } + e.sfields = sfields + e.pop(ov) + + case reflect.Int8: + e.writeS8(f, int8(e.intFromField(f, ov))) + case reflect.Int16: + e.writeS16(f, int16(e.intFromField(f, ov))) + case reflect.Int32: + e.writeS32(f, int32(e.intFromField(f, ov))) + case reflect.Int64: + e.writeS64(f, int64(e.intFromField(f, ov))) + + case reflect.Uint8, reflect.Bool: + e.write8(f, uint8(e.uintFromField(f, ov))) + case reflect.Uint16: + e.write16(f, uint16(e.uintFromField(f, ov))) + case reflect.Uint32: + e.write32(f, uint32(e.uintFromField(f, ov))) + case reflect.Uint64: + e.write64(f, uint64(e.uintFromField(f, ov))) + + case reflect.Float32: + e.write32(f, math.Float32bits(float32(ov.Float()))) + case reflect.Float64: + e.write64(f, math.Float64bits(float64(ov.Float()))) + + case reflect.Complex64: + x := ov.Complex() + e.write32(f, math.Float32bits(float32(real(x)))) + e.write32(f, math.Float32bits(float32(imag(x)))) + case reflect.Complex128: + x := ov.Complex() + e.write64(f, math.Float64bits(float64(real(x)))) + e.write64(f, math.Float64bits(float64(imag(x)))) + } +} diff --git a/rune/vendor/github.com/go-restruct/restruct/expr.go b/rune/vendor/github.com/go-restruct/restruct/expr.go new file mode 100644 index 0000000000000000000000000000000000000000..02d0ee6124cbb3fd2362dd6fd00dbe146a3c7655 --- /dev/null +++ b/rune/vendor/github.com/go-restruct/restruct/expr.go @@ -0,0 +1,17 @@ +package restruct + +import ( + "github.com/go-restruct/restruct/expr" +) + +var ( + expressionsEnabled = false + stdLibResolver = expr.NewMapResolver(exprStdLib) +) + +// EnableExprBeta enables you to use restruct expr while it is still in beta. +// Use at your own risk. Functionality may change in unforeseen, incompatible +// ways at any time. +func EnableExprBeta() { + expressionsEnabled = true +} diff --git a/rune/vendor/github.com/go-restruct/restruct/expr/ast.go b/rune/vendor/github.com/go-restruct/restruct/expr/ast.go new file mode 100644 index 0000000000000000000000000000000000000000..c7cb7d0646ee2ea1d1c75c2669f7e8b19ff42f82 --- /dev/null +++ b/rune/vendor/github.com/go-restruct/restruct/expr/ast.go @@ -0,0 +1,247 @@ +package expr + +import ( + "fmt" + "strconv" +) + +type node interface { + source() string +} + +type unaryop int + +const ( + unaryplus unaryop = iota + unarynegate + unarynot + unarybitnot + unaryderef + unaryref +) + +type binaryop int + +const ( + binarylogicalor binaryop = iota + binarylogicaland + binaryequal + binarynotequal + binarylesser + binarylesserequal + binarygreater + binarygreaterequal + binaryadd + binarysub + binaryor + binaryxor + binarymul + binarydiv + binaryrem + binarylsh + binaryrsh + binaryand + binaryandnot + binarymember + binarycall + binarysubscript + binarygroup +) + +// Identifier node. +type identnode struct { + pos int + ident string +} + +func newidentnode(t token) identnode { + return identnode{t.pos, t.sval} +} + +func (n identnode) source() string { + return n.ident +} + +// Integer literal node. +type intnode struct { + pos int + uval uint64 + ival int64 + sign bool +} + +func newintnode(t token) intnode { + return intnode{pos: t.pos, uval: t.uval, ival: t.ival, sign: t.sign} +} + +func (n intnode) source() string { + if n.sign { + return strconv.FormatInt(n.ival, 10) + } + return strconv.FormatUint(n.uval, 10) +} + +// Float literal node. +type floatnode struct { + pos int + fval float64 +} + +func newfloatnode(t token) floatnode { + return floatnode{pos: t.pos, fval: t.fval} +} + +func (n floatnode) source() string { + return strconv.FormatFloat(n.fval, 'f', -1, 64) +} + +// Bool literal node. +type boolnode struct { + pos int + val bool +} + +func newboolnode(t token) boolnode { + return boolnode{t.pos, t.bval} +} + +func (n boolnode) source() string { + if n.val { + return "true" + } + return "false" +} + +// String literal node. +type strnode struct { + pos int + val string +} + +func newstrnode(t token) strnode { + return strnode{t.pos, t.sval} +} + +func (n strnode) source() string { + return fmt.Sprintf("%q", n.val) +} + +// Rune literal node. +type runenode struct { + pos int + val rune +} + +func newrunenode(t token) runenode { + return runenode{t.pos, rune(t.ival)} +} + +func (n runenode) source() string { + return fmt.Sprintf("%q", n.val) +} + +// Nil node. +type nilnode struct { + pos int +} + +func newnilnode(t token) nilnode { + return nilnode{t.pos} +} + +func (nilnode) source() string { + return "nil" +} + +// Unary expression node. +type unaryexpr struct { + op unaryop + n node +} + +func (n unaryexpr) source() string { + operand := n.n.source() + switch n.op { + case unaryplus: + return "+" + operand + case unarynegate: + return "-" + operand + case unarynot: + return "!" + operand + case unarybitnot: + return "^" + operand + case unaryderef: + return "*" + operand + case unaryref: + return "&" + operand + } + panic("invalid unary expr?") +} + +// Binary expression node. +type binaryexpr struct { + op binaryop + a, b node +} + +func (n binaryexpr) source() string { + a, b := n.a.source(), n.b.source() + switch n.op { + case binarylogicalor: + return a + " || " + b + case binarylogicaland: + return a + " && " + b + case binaryequal: + return a + " == " + b + case binarynotequal: + return a + " != " + b + case binarylesser: + return a + " < " + b + case binarylesserequal: + return a + " <= " + b + case binarygreater: + return a + " > " + b + case binarygreaterequal: + return a + " >= " + b + case binaryadd: + return a + " + " + b + case binarysub: + return a + " - " + b + case binaryor: + return a + " | " + b + case binaryxor: + return a + " ^ " + b + case binarymul: + return a + " * " + b + case binarydiv: + return a + " / " + b + case binaryrem: + return a + " % " + b + case binarylsh: + return a + " << " + b + case binaryrsh: + return a + " >> " + b + case binaryand: + return a + " & " + b + case binaryandnot: + return a + " &^ " + b + case binarymember: + return a + "." + b + case binarycall: + return a + "(" + b + ")" + case binarysubscript: + return a + "[" + b + "]" + case binarygroup: + return a + ", " + b + } + panic("invalid binary expr?") +} + +// Ternary expression node. +type ternaryexpr struct { + a, b, c node +} + +func (n ternaryexpr) source() string { + return n.a.source() + " ? " + n.b.source() + " : " + n.c.source() +} diff --git a/rune/vendor/github.com/go-restruct/restruct/expr/env.go b/rune/vendor/github.com/go-restruct/restruct/expr/env.go new file mode 100644 index 0000000000000000000000000000000000000000..5700f6d2ab00271860e42718a52e4e2c4ae40da9 --- /dev/null +++ b/rune/vendor/github.com/go-restruct/restruct/expr/env.go @@ -0,0 +1,162 @@ +package expr + +import "reflect" + +// Assertions. +var ( + _ = TypeResolver(&TypeResolverAdapter{}) + _ = TypeResolver(&MetaTypeResolver{}) + _ = Resolver(&MetaResolver{}) + _ = TypeResolver(&StructTypeResolver{}) + _ = Resolver(&StructResolver{}) + _ = TypeResolver(&MapTypeResolver{}) + _ = Resolver(&MapResolver{}) +) + +// TypeResolver resolves types. +type TypeResolver interface { + TypeResolve(ident string) Type +} + +// Resolver resolves runtime values. +type Resolver interface { + Resolve(ident string) Value +} + +// TypeResolverAdapter adapts a runtime resolver to a type resolver by taking +// types of values retrieve from Resolve. +type TypeResolverAdapter struct { + Resolver +} + +// NewTypeResolverAdapter creates a new TypeResolverAdapter from a resolver. +func NewTypeResolverAdapter(r Resolver) *TypeResolverAdapter { + return &TypeResolverAdapter{r} +} + +// TypeResolve implements TypeResolver. +func (r *TypeResolverAdapter) TypeResolve(ident string) Type { + return r.Resolve(ident).Type() +} + +// MetaTypeResolver runs multiple type resolvers serially. +type MetaTypeResolver struct { + resolvers []TypeResolver +} + +// NewMetaTypeResolver creates a new meta type resolver. +func NewMetaTypeResolver() *MetaTypeResolver { + return &MetaTypeResolver{} +} + +// AddResolver adds a new resolver below other resolvers. +func (r *MetaTypeResolver) AddResolver(n TypeResolver) { + r.resolvers = append(r.resolvers, n) +} + +// TypeResolve implements TypeResolver. +func (r *MetaTypeResolver) TypeResolve(ident string) Type { + for _, resolver := range r.resolvers { + if t := resolver.TypeResolve(ident); t != nil { + return t + } + } + return nil +} + +// MetaResolver runs multiple resolvers serially. +type MetaResolver struct { + resolvers []Resolver +} + +// NewMetaResolver creates a new meta resolver. +func NewMetaResolver() *MetaResolver { + return &MetaResolver{} +} + +// AddResolver adds a new resolver below other resolvers. +func (r *MetaResolver) AddResolver(n Resolver) { + r.resolvers = append(r.resolvers, n) +} + +// Resolve implements Resolver. +func (r *MetaResolver) Resolve(ident string) Value { + for _, resolver := range r.resolvers { + if t := resolver.Resolve(ident); t != nil { + return t + } + } + return nil +} + +// StructTypeResolver resolves types of struct fields. +type StructTypeResolver struct { + struc *StructType +} + +// NewStructTypeResolver creates a new struct type resolver. +func NewStructTypeResolver(s interface{}) *StructTypeResolver { + return &StructTypeResolver{TypeOf(s).(*StructType)} +} + +// TypeResolve implements TypeResolver. +func (r *StructTypeResolver) TypeResolve(ident string) Type { + if f, ok := r.struc.FieldByName(ident); ok { + return f.Type + } + return nil +} + +// StructResolver resolves struct fields. +type StructResolver struct { + struc reflect.Value +} + +// NewStructResolver creates a new struct resolver. +func NewStructResolver(s reflect.Value) *StructResolver { + return &StructResolver{s} +} + +// Resolve implements Resolver. +func (r *StructResolver) Resolve(ident string) Value { + if sv := r.struc.FieldByName(ident); sv.IsValid() { + return ValueOf(sv.Interface()) + } + return nil +} + +// MapTypeResolver resolves map keys. +type MapTypeResolver struct { + m map[string]Type +} + +// NewMapTypeResolver creates a new struct resolver. +func NewMapTypeResolver(m map[string]Type) *MapTypeResolver { + return &MapTypeResolver{m} +} + +// TypeResolve implements TypeResolver. +func (r *MapTypeResolver) TypeResolve(ident string) Type { + if t, ok := r.m[ident]; ok { + return t + } + return nil +} + +// MapResolver resolves map keys. +type MapResolver struct { + m map[string]Value +} + +// NewMapResolver creates a new struct resolver. +func NewMapResolver(m map[string]Value) *MapResolver { + return &MapResolver{m} +} + +// Resolve implements Resolver. +func (r *MapResolver) Resolve(ident string) Value { + if v, ok := r.m[ident]; ok { + return v + } + return nil +} diff --git a/rune/vendor/github.com/go-restruct/restruct/expr/eval.go b/rune/vendor/github.com/go-restruct/restruct/expr/eval.go new file mode 100644 index 0000000000000000000000000000000000000000..182f16425ebc76026c6549c80823d803a9ee3b2f --- /dev/null +++ b/rune/vendor/github.com/go-restruct/restruct/expr/eval.go @@ -0,0 +1,166 @@ +package expr + +import ( + "fmt" +) + +// EvalProgram returns the result of executing the program with the given resolver. +func EvalProgram(resolver Resolver, program *Program) (v interface{}, err error) { + defer func() { + if r := recover(); r != nil { + if rerr, ok := r.(error); ok { + err = rerr + } else { + panic(r) + } + } + }() + + v = evalnode(resolver, program.root).RawValue() + return +} + +// Eval returns the result of evaluating the provided expression. +func Eval(resolver Resolver, expr string) (interface{}, error) { + return EvalProgram(resolver, ParseString(expr)) +} + +func evalnode(resolver Resolver, node node) Value { + switch n := node.(type) { + case identnode: + v := resolver.Resolve(n.ident) + if v == nil { + panic(fmt.Errorf("unresolved name %s", n.ident)) + } + return v + case intnode: + if n.sign { + return literalintval(n.ival) + } + return literaluintval(n.uval) + case floatnode: + return literalfloatval(n.fval) + case boolnode: + return literalboolval(n.val) + case strnode: + return literalstrval(n.val) + case runenode: + return literalintval(int64(n.val)) + case nilnode: + return literalnilval() + case unaryexpr: + return evalunary(resolver, n) + case binaryexpr: + return evalbinary(resolver, n) + case ternaryexpr: + return evalternary(resolver, n) + default: + panic("invalid node") + } +} + +func evalunary(resolver Resolver, node unaryexpr) Value { + n := evalnode(resolver, node.n) + switch node.op { + case unaryplus: + return n + case unarynegate: + return n.Negate() + case unarynot: + return n.Not() + case unarybitnot: + return n.BitNot() + case unaryderef: + return n.Deref() + case unaryref: + return n.Ref() + default: + panic("invalid unary expression") + } +} + +func flattengroup(n node) []node { + if n, ok := n.(binaryexpr); ok { + if n.op == binarygroup { + return append(flattengroup(n.a), flattengroup(n.b)...) + } + } + return []node{n} +} + +func evalbinary(resolver Resolver, node binaryexpr) Value { + a := evalnode(resolver, node.a) + switch node.op { + case binarymember: + if id, ok := node.b.(identnode); ok { + return a.Dot(id.ident) + } + panic(fmt.Errorf("expected ident node, got %T", node.b)) + case binarycall: + in := []Value{} + for _, n := range flattengroup(node.b) { + in = append(in, evalnode(resolver, n)) + } + return a.Call(in) + case binarygroup: + return evalnode(resolver, node.b) + } + + b := evalnode(resolver, node.b) + switch node.op { + case binarylogicalor: + return a.LogicalOr(b) + case binarylogicaland: + return a.LogicalAnd(b) + case binaryequal: + return a.Equal(b) + case binarynotequal: + return a.NotEqual(b) + case binarylesser: + return a.Lesser(b) + case binarylesserequal: + return a.LesserEqual(b) + case binarygreater: + return a.Greater(b) + case binarygreaterequal: + return a.GreaterEqual(b) + case binaryadd: + return a.Add(b) + case binarysub: + return a.Sub(b) + case binaryor: + return a.Or(b) + case binaryxor: + return a.Xor(b) + case binarymul: + return a.Mul(b) + case binarydiv: + return a.Div(b) + case binaryrem: + return a.Rem(b) + case binarylsh: + return a.Lsh(b) + case binaryrsh: + return a.Rsh(b) + case binaryand: + return a.And(b) + case binaryandnot: + return a.AndNot(b) + case binarysubscript: + return a.Index(b) + default: + panic("invalid binary expression") + } +} + +func evalternary(resolver Resolver, node ternaryexpr) Value { + a := evalnode(resolver, node.a).Value().Interface() + cond, ok := a.(bool) + if !ok { + panic(fmt.Errorf("unexpected type %T for ternary", cond)) + } + if cond { + return evalnode(resolver, node.b) + } + return evalnode(resolver, node.c) +} diff --git a/rune/vendor/github.com/go-restruct/restruct/expr/lex.go b/rune/vendor/github.com/go-restruct/restruct/expr/lex.go new file mode 100644 index 0000000000000000000000000000000000000000..c79c63ebc82f88d923cff2574b942afcfe8d27c9 --- /dev/null +++ b/rune/vendor/github.com/go-restruct/restruct/expr/lex.go @@ -0,0 +1,523 @@ +package expr + +//go:generate stringer -type=tokenkind + +import ( + "fmt" + "io" + "strconv" + "unicode" + "unicode/utf8" +) + +func lower(ch rune) rune { + return ('a' - 'A') | ch +} + +func isdecimal(ch rune) bool { + return '0' <= ch && ch <= '9' +} + +func isoctal(ch rune) bool { + return '0' <= ch && ch <= '7' +} + +func ishex(ch rune) bool { + return '0' <= ch && ch <= '9' || 'a' <= lower(ch) && lower(ch) <= 'f' +} + +func isletter(c rune) bool { + return 'a' <= lower(c) && lower(c) <= 'z' || c == '_' || c >= utf8.RuneSelf && unicode.IsLetter(c) +} + +func isdigit(c rune) bool { + return isdecimal(c) || c >= utf8.RuneSelf && unicode.IsDigit(c) +} + +func isnumber(c rune) bool { + return isdigit(c) || ishex(c) || c == '.' || lower(c) == 'x' +} + +func isident(c rune) bool { + return isletter(c) || isdigit(c) +} + +func iswhitespace(c rune) bool { + return c == ' ' || c == '\t' +} + +// tokenkind is an enumeration of different kinds of tokens. +type tokenkind int + +// This is a definition of all possible token kinds. +const ( + niltoken tokenkind = iota + errtoken + eoftoken + + identtoken + inttoken + floattoken + booltoken + strtoken + runetoken + + addtoken + subtoken + multoken + quotoken + remtoken + + andtoken + nottoken + ortoken + xortoken + shltoken + shrtoken + andnottoken + + logicalandtoken + logicalortoken + + equaltoken + lessertoken + greatertoken + notequaltoken + lesserequaltoken + greaterequaltoken + + leftparentoken + leftbrackettoken + commatoken + periodtoken + + rightparentoken + rightbrackettoken + colontoken + ternarytoken + + boolkeyword + bytekeyword + float32keyword + float64keyword + intkeyword + int8keyword + int16keyword + int32keyword + int64keyword + uintkeyword + uint8keyword + uint16keyword + uint32keyword + uint64keyword + uintptrkeyword + nilkeyword +) + +var keywordmap = map[string]tokenkind{ + "bool": boolkeyword, + "byte": bytekeyword, + "float32": float32keyword, + "float64": float64keyword, + "int": intkeyword, + "int8": int8keyword, + "int16": int16keyword, + "int32": int32keyword, + "int64": int64keyword, + "uint": uintkeyword, + "uint8": uint8keyword, + "uint16": uint16keyword, + "uint32": uint32keyword, + "uint64": uint64keyword, + "uintptr": uintptrkeyword, + "nil": nilkeyword, +} + +const eof = utf8.MaxRune + 0x0001 + +// token contains information for a single lexical token. +type token struct { + kind tokenkind + pos int + + sval string + ival int64 + uval uint64 + fval float64 + bval bool + sign bool + eval error +} + +// scanner scans lexical tokens from the expression. +type scanner struct { + r io.RuneScanner + p int + eof bool +} + +func newscanner(r io.RuneScanner) *scanner { + return &scanner{r: r} +} + +func (s *scanner) readrune() rune { + if s.eof { + return eof + } + c, _, err := s.r.ReadRune() + if err == io.EOF { + s.eof = true + return eof + } else if err != nil { + panic(err) + } + s.p++ + return c +} + +func (s *scanner) unreadrune() { + if s.eof { + return + } + if err := s.r.UnreadRune(); err != nil { + panic(err) + } + s.p-- +} + +func (s *scanner) skipws() { + for { + c := s.readrune() + if !iswhitespace(c) { + s.unreadrune() + return + } + } +} + +func (s *scanner) accept(c rune) bool { + if s.readrune() == c { + return true + } + s.unreadrune() + return false +} + +func (s *scanner) expect(c rune) { + r := s.readrune() + if r != c { + panic(fmt.Errorf("expected %c", r)) + } +} + +func (s *scanner) peekmatch(f func(rune) bool) bool { + c := s.readrune() + s.unreadrune() + return f(c) +} + +func (s *scanner) acceptfn(f func(rune) bool) (rune, bool) { + r := s.readrune() + if f(r) { + return r, true + } + s.unreadrune() + return r, false +} + +func (s *scanner) expectfn(f func(rune) bool) rune { + r, ok := s.acceptfn(f) + if !ok { + panic(fmt.Errorf("unexpected %c", r)) + } + return r +} + +func (s *scanner) tokensym(k tokenkind, src string) token { + return token{kind: k, sval: src} +} + +func (s *scanner) errsymf(format string, a ...interface{}) token { + return token{kind: errtoken, eval: fmt.Errorf(format, a...)} +} + +func (s *scanner) scanident() token { + t := token{kind: identtoken} + if r, ok := s.acceptfn(isletter); ok { + t.sval = string(r) + } else { + return s.errsymf("unexpected ident start token: %c", r) + } + for { + if r, ok := s.acceptfn(isident); ok { + t.sval += string(r) + continue + } + break + } + // Handle boolean constant. + if t.sval == "true" { + t.kind = booltoken + t.bval = true + } + if t.sval == "false" { + t.kind = booltoken + t.bval = false + } + // Handle keywords. + if k, ok := keywordmap[t.sval]; ok { + t.kind = k + } + return t +} + +func (s *scanner) scannumber(t token) token { + if r, ok := s.acceptfn(isnumber); ok { + t.sval += string(r) + } else { + return s.errsymf("unexpected int start token: %c", r) + } + for { + if r, ok := s.acceptfn(isnumber); ok { + t.sval += string(r) + continue + } + break + } + var err error + if t.uval, err = strconv.ParseUint(t.sval, 0, 64); err == nil { + t.ival = int64(t.uval) + t.fval = float64(t.ival) + t.kind = inttoken + t.sign = false + } else if t.ival, err = strconv.ParseInt(t.sval, 0, 64); err == nil { + t.uval = uint64(t.ival) + t.fval = float64(t.ival) + t.kind = inttoken + t.sign = true + } else if t.fval, err = strconv.ParseFloat(t.sval, 64); err == nil { + t.ival = int64(t.fval) + t.uval = uint64(t.fval) + t.kind = floattoken + } else { + return token{kind: errtoken, eval: err} + } + return t +} + +func runebytes(r rune) []byte { + runebuf := [4]byte{} + l := utf8.EncodeRune(runebuf[:], rune(r)) + return runebuf[:l] +} + +func (s *scanner) scanescape(quote byte) []byte { + switch { + case s.accept('a'): + return []byte{'\a'} + case s.accept('b'): + return []byte{'\b'} + case s.accept('f'): + return []byte{'\f'} + case s.accept('n'): + return []byte{'\n'} + case s.accept('r'): + return []byte{'\r'} + case s.accept('t'): + return []byte{'\t'} + case s.accept('v'): + return []byte{'\v'} + case s.accept('\\'): + return []byte{'\\'} + case s.accept(rune(quote)): + return []byte{quote} + case s.peekmatch(isoctal): + octal := string([]rune{s.expectfn(isoctal), s.expectfn(isoctal), s.expectfn(isoctal)}) + code, err := strconv.ParseUint(octal, 8, 8) + if err != nil { + panic(err) + } + return []byte{byte(code)} + case s.accept('x'): + hex := string([]rune{s.expectfn(ishex), s.expectfn(ishex)}) + code, err := strconv.ParseUint(hex, 16, 8) + if err != nil { + panic(err) + } + return []byte{byte(code)} + case s.accept('u'): + hex := string([]rune{ + s.expectfn(ishex), s.expectfn(ishex), s.expectfn(ishex), s.expectfn(ishex), + }) + code, err := strconv.ParseUint(hex, 16, 16) + if err != nil { + panic(err) + } + return runebytes(rune(code)) + case s.accept('U'): + hex := string([]rune{ + s.expectfn(ishex), s.expectfn(ishex), s.expectfn(ishex), s.expectfn(ishex), + s.expectfn(ishex), s.expectfn(ishex), s.expectfn(ishex), s.expectfn(ishex), + }) + code, err := strconv.ParseUint(hex, 16, 32) + if err != nil { + panic(err) + } + return runebytes(rune(code)) + default: + panic(fmt.Errorf("unexpected escape code %c", s.readrune())) + } +} + +func (s *scanner) scanstring(quote byte) token { + str := []byte{} + for { + switch { + case s.accept(rune(quote)): + return token{kind: strtoken, sval: string(str)} + case s.accept('\\'): + str = append(str, s.scanescape(quote)...) + default: + str = append(str, runebytes(s.readrune())...) + } + } +} + +func (s *scanner) scanrune() token { + defer s.expect('\'') + switch { + case s.accept('\\'): + r := []rune(string(s.scanescape('\''))) + return token{kind: runetoken, ival: int64(r[0])} + default: + return token{kind: runetoken, ival: int64(s.readrune())} + } +} + +func (s *scanner) scan() (t token) { + defer func() { + if r := recover(); r != nil { + if err, ok := r.(error); ok { + t = token{kind: errtoken, pos: s.p, eval: err} + } else { + panic(r) + } + } + }() + + s.skipws() + + p := s.p + + defer func() { + t.pos = p + }() + + switch { + case s.accept(eof): + p = s.p + return token{kind: eoftoken} + case s.peekmatch(isletter): + return s.scanident() + case s.peekmatch(isdigit): + return s.scannumber(token{}) + case s.accept('"'): + return s.scanstring('"') + case s.accept('\''): + return s.scanrune() + case s.accept('$'): + s.expect('\'') + return s.scanstring('\'') + case s.accept('+'): + return s.tokensym(addtoken, "+") + case s.accept('-'): + switch { + default: + return s.tokensym(subtoken, "-") + case s.peekmatch(isdigit): + return s.scannumber(token{sval: "-"}) + } + case s.accept('*'): + return s.tokensym(multoken, "*") + case s.accept('/'): + return s.tokensym(quotoken, "/") + case s.accept('%'): + return s.tokensym(remtoken, "%") + case s.accept('&'): + switch { + default: + return s.tokensym(andtoken, "&") + case s.accept('&'): + return s.tokensym(logicalandtoken, "&&") + case s.accept('^'): + return s.tokensym(andnottoken, "&^") + } + case s.accept('|'): + switch { + default: + return s.tokensym(ortoken, "|") + case s.accept('|'): + return s.tokensym(logicalortoken, "||") + } + case s.accept('^'): + switch { + default: + return s.tokensym(xortoken, "^") + } + case s.accept('<'): + switch { + default: + return s.tokensym(lessertoken, "<") + case s.accept('='): + return s.tokensym(lesserequaltoken, "<=") + case s.accept('<'): + return s.tokensym(shltoken, "<<") + } + case s.accept('>'): + switch { + default: + return s.tokensym(greatertoken, ">") + case s.accept('='): + return s.tokensym(greaterequaltoken, ">=") + case s.accept('>'): + return s.tokensym(shrtoken, ">>") + } + case s.accept('='): + switch { + case s.accept('='): + return s.tokensym(equaltoken, "==") + default: + return s.errsymf("unexpected rune %c", s.readrune()) + } + case s.accept('!'): + switch { + case s.accept('='): + return s.tokensym(notequaltoken, "!=") + default: + return s.tokensym(nottoken, "!") + } + case s.accept('('): + return s.tokensym(leftparentoken, "(") + case s.accept('['): + return s.tokensym(leftbrackettoken, "[") + case s.accept(','): + return s.tokensym(commatoken, ",") + case s.accept('.'): + switch { + default: + return s.tokensym(periodtoken, ".") + case s.peekmatch(isdigit): + return s.scannumber(token{sval: "."}) + } + case s.accept(')'): + return s.tokensym(rightparentoken, ")") + case s.accept(']'): + return s.tokensym(rightbrackettoken, "]") + case s.accept(':'): + return s.tokensym(colontoken, ":") + case s.accept('?'): + return s.tokensym(ternarytoken, "?") + default: + return s.errsymf("unexpected rune %c", s.readrune()) + } +} diff --git a/rune/vendor/github.com/go-restruct/restruct/expr/package.go b/rune/vendor/github.com/go-restruct/restruct/expr/package.go new file mode 100644 index 0000000000000000000000000000000000000000..19f895d75c391357443fef1a773227a99e05d71a --- /dev/null +++ b/rune/vendor/github.com/go-restruct/restruct/expr/package.go @@ -0,0 +1,29 @@ +package expr + +// Package represents a package value. +type Package struct { + types map[string]Type + symbols map[string]Value +} + +// NewPackage creates a new package. +func NewPackage(symbols map[string]Value) Package { + pkg := Package{symbols: symbols, types: map[string]Type{}} + for key := range symbols { + pkg.types[key] = pkg.symbols[key].Type() + } + return pkg +} + +// Symbol returns a symbol, or nil if the symbol doesn't exist. +func (p Package) Symbol(ident string) Value { + if symbol, ok := p.symbols[ident]; ok { + return symbol + } + return nil +} + +// Type returns the type for this package. +func (p Package) Type() Type { + return NewPackageType(p.types) +} diff --git a/rune/vendor/github.com/go-restruct/restruct/expr/parse.go b/rune/vendor/github.com/go-restruct/restruct/expr/parse.go new file mode 100644 index 0000000000000000000000000000000000000000..587bce5afb2a66b2318516269f8ed26a6486a45f --- /dev/null +++ b/rune/vendor/github.com/go-restruct/restruct/expr/parse.go @@ -0,0 +1,251 @@ +package expr + +import ( + "bytes" + "fmt" + "io" +) + +// Program represents a parsed expression. +type Program struct { + root node +} + +// Parse parses an expression into a program. +func Parse(r io.RuneScanner) *Program { + return &Program{newparser(newscanner(r)).parse()} +} + +// ParseString parses an expression from a string. +func ParseString(s string) *Program { + return Parse(bytes.NewBufferString(s)) +} + +type parser struct { + s *scanner + + a bool + t token +} + +func newparser(s *scanner) *parser { + return &parser{s: s} +} + +func (p *parser) readtoken() *token { + if !p.a { + p.a = true + p.t = p.s.scan() + } + return &p.t +} + +func (p *parser) consume() { + p.a = false +} + +func (p *parser) accept(k tokenkind) bool { + if p.readtoken().kind == k { + p.consume() + return true + } + return false +} + +func (p *parser) expect(k tokenkind) { + if p.readtoken().kind != k { + panic(fmt.Errorf("expected %s token, got %s", k, p.t.kind)) + } + p.consume() +} + +// This parser is strongly based on byuu's modified recursive-descent algorithm +// (particularly the 'depth' parameter.) +// https://github.com/byuu/bsnes/blob/master/nall/string/eval/parser.hpp +func (p *parser) parseexpr(depth int) node { + var n node + + unary := func(op unaryop, depth int) { + n = unaryexpr{op: op, n: p.parseexpr(depth)} + } + + binary := func(op binaryop, depth int) { + if n == nil { + panic("unexpected binary op") + } + n = binaryexpr{op: op, a: n, b: p.parseexpr(depth)} + } + + ternary := func(depth int) { + t := ternaryexpr{} + t.a = n + t.b = p.parseexpr(depth) + p.expect(colontoken) + t.c = p.parseexpr(depth) + n = t + } + + switch { + case p.accept(identtoken): + n = newidentnode(p.t) + case p.accept(inttoken): + n = newintnode(p.t) + case p.accept(floattoken): + n = newfloatnode(p.t) + case p.accept(booltoken): + n = newboolnode(p.t) + case p.accept(strtoken): + n = newstrnode(p.t) + case p.accept(runetoken): + n = newrunenode(p.t) + case p.accept(nilkeyword): + n = newnilnode(p.t) + case p.accept(leftparentoken): + n = p.parseexpr(1) + default: + } + + for { + if depth >= 8 { + break + } + if n != nil && p.accept(periodtoken) { + binary(binarymember, 8) + continue + } + if n != nil && p.accept(leftparentoken) { + binary(binarycall, 1) + continue + } + if n != nil && p.accept(leftbrackettoken) { + binary(binarysubscript, 1) + continue + } + if n == nil && p.accept(addtoken) { + unary(unaryplus, 7) + } + if n == nil && p.accept(subtoken) { + unary(unarynegate, 7) + } + if n == nil && p.accept(nottoken) { + unary(unarynot, 7) + } + if n == nil && p.accept(xortoken) { + unary(unarybitnot, 7) + } + if n == nil && p.accept(multoken) { + unary(unaryderef, 7) + } + if n == nil && p.accept(andtoken) { + unary(unaryref, 7) + } + if depth >= 7 { + break + } + if p.accept(multoken) { + binary(binarymul, 7) + continue + } + if p.accept(quotoken) { + binary(binarydiv, 7) + continue + } + if p.accept(remtoken) { + binary(binaryrem, 7) + continue + } + if p.accept(shltoken) { + binary(binarylsh, 7) + continue + } + if p.accept(shrtoken) { + binary(binaryrsh, 7) + continue + } + if p.accept(andtoken) { + binary(binaryand, 7) + continue + } + if depth >= 6 { + break + } + if p.accept(addtoken) { + binary(binaryadd, 6) + continue + } + if p.accept(subtoken) { + binary(binarysub, 6) + continue + } + if p.accept(ortoken) { + binary(binaryor, 6) + continue + } + if p.accept(xortoken) { + binary(binaryxor, 6) + continue + } + if depth >= 5 { + break + } + if p.accept(equaltoken) { + binary(binaryequal, 5) + continue + } + if p.accept(notequaltoken) { + binary(binarynotequal, 5) + continue + } + if p.accept(lessertoken) { + binary(binarylesser, 5) + continue + } + if p.accept(lesserequaltoken) { + binary(binarylesserequal, 5) + continue + } + if p.accept(greatertoken) { + binary(binarygreater, 5) + continue + } + if p.accept(greaterequaltoken) { + binary(binarygreaterequal, 5) + continue + } + if depth >= 4 { + break + } + if p.accept(logicalandtoken) { + binary(binarylogicaland, 4) + continue + } + if depth >= 3 { + break + } + if p.accept(logicalortoken) { + binary(binarylogicalor, 3) + continue + } + if p.accept(ternarytoken) { + ternary(3) + continue + } + if depth >= 2 { + break + } + if p.accept(commatoken) { + binary(binarygroup, 2) + continue + } + if depth >= 1 && (p.accept(rightparentoken) || p.accept(rightbrackettoken)) { + break + } + p.expect(eoftoken) + break + } + return n +} + +func (p *parser) parse() node { + return p.parseexpr(0) +} diff --git a/rune/vendor/github.com/go-restruct/restruct/expr/tokenkind_string.go b/rune/vendor/github.com/go-restruct/restruct/expr/tokenkind_string.go new file mode 100644 index 0000000000000000000000000000000000000000..12b6bfea0cc11272b3705e7835bbac4206116566 --- /dev/null +++ b/rune/vendor/github.com/go-restruct/restruct/expr/tokenkind_string.go @@ -0,0 +1,75 @@ +// Code generated by "stringer -type=tokenkind"; DO NOT EDIT. + +package expr + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[niltoken-0] + _ = x[errtoken-1] + _ = x[eoftoken-2] + _ = x[identtoken-3] + _ = x[inttoken-4] + _ = x[floattoken-5] + _ = x[booltoken-6] + _ = x[strtoken-7] + _ = x[runetoken-8] + _ = x[addtoken-9] + _ = x[subtoken-10] + _ = x[multoken-11] + _ = x[quotoken-12] + _ = x[remtoken-13] + _ = x[andtoken-14] + _ = x[nottoken-15] + _ = x[ortoken-16] + _ = x[xortoken-17] + _ = x[shltoken-18] + _ = x[shrtoken-19] + _ = x[andnottoken-20] + _ = x[logicalandtoken-21] + _ = x[logicalortoken-22] + _ = x[equaltoken-23] + _ = x[lessertoken-24] + _ = x[greatertoken-25] + _ = x[notequaltoken-26] + _ = x[lesserequaltoken-27] + _ = x[greaterequaltoken-28] + _ = x[leftparentoken-29] + _ = x[leftbrackettoken-30] + _ = x[commatoken-31] + _ = x[periodtoken-32] + _ = x[rightparentoken-33] + _ = x[rightbrackettoken-34] + _ = x[colontoken-35] + _ = x[ternarytoken-36] + _ = x[boolkeyword-37] + _ = x[bytekeyword-38] + _ = x[float32keyword-39] + _ = x[float64keyword-40] + _ = x[intkeyword-41] + _ = x[int8keyword-42] + _ = x[int16keyword-43] + _ = x[int32keyword-44] + _ = x[int64keyword-45] + _ = x[uintkeyword-46] + _ = x[uint8keyword-47] + _ = x[uint16keyword-48] + _ = x[uint32keyword-49] + _ = x[uint64keyword-50] + _ = x[uintptrkeyword-51] + _ = x[nilkeyword-52] +} + +const _tokenkind_name = "niltokenerrtokeneoftokenidenttokeninttokenfloattokenbooltokenstrtokenrunetokenaddtokensubtokenmultokenquotokenremtokenandtokennottokenortokenxortokenshltokenshrtokenandnottokenlogicalandtokenlogicalortokenequaltokenlessertokengreatertokennotequaltokenlesserequaltokengreaterequaltokenleftparentokenleftbrackettokencommatokenperiodtokenrightparentokenrightbrackettokencolontokenternarytokenboolkeywordbytekeywordfloat32keywordfloat64keywordintkeywordint8keywordint16keywordint32keywordint64keyworduintkeyworduint8keyworduint16keyworduint32keyworduint64keyworduintptrkeywordnilkeyword" + +var _tokenkind_index = [...]uint16{0, 8, 16, 24, 34, 42, 52, 61, 69, 78, 86, 94, 102, 110, 118, 126, 134, 141, 149, 157, 165, 176, 191, 205, 215, 226, 238, 251, 267, 284, 298, 314, 324, 335, 350, 367, 377, 389, 400, 411, 425, 439, 449, 460, 472, 484, 496, 507, 519, 532, 545, 558, 572, 582} + +func (i tokenkind) String() string { + if i < 0 || i >= tokenkind(len(_tokenkind_index)-1) { + return "tokenkind(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _tokenkind_name[_tokenkind_index[i]:_tokenkind_index[i+1]] +} diff --git a/rune/vendor/github.com/go-restruct/restruct/expr/type.go b/rune/vendor/github.com/go-restruct/restruct/expr/type.go new file mode 100644 index 0000000000000000000000000000000000000000..f863ea87c6dd40af17f80e39fd18e72c96666172 --- /dev/null +++ b/rune/vendor/github.com/go-restruct/restruct/expr/type.go @@ -0,0 +1,595 @@ +package expr + +import ( + "errors" + "fmt" + "reflect" + "sync" +) + +var ( + primType = map[reflect.Kind]Type{ + reflect.Bool: NewPrimitiveType(Bool), + reflect.Int: NewPrimitiveType(Int), + reflect.Int8: NewPrimitiveType(Int8), + reflect.Int16: NewPrimitiveType(Int16), + reflect.Int32: NewPrimitiveType(Int32), + reflect.Int64: NewPrimitiveType(Int64), + reflect.Uint: NewPrimitiveType(Uint), + reflect.Uint8: NewPrimitiveType(Uint8), + reflect.Uint16: NewPrimitiveType(Uint16), + reflect.Uint32: NewPrimitiveType(Uint32), + reflect.Uint64: NewPrimitiveType(Uint64), + reflect.Uintptr: NewPrimitiveType(Uintptr), + reflect.Float32: NewPrimitiveType(Float32), + reflect.Float64: NewPrimitiveType(Float64), + reflect.String: NewPrimitiveType(String), + } + + primRType = map[Kind]reflect.Type{ + Bool: reflect.TypeOf(bool(false)), + Int: reflect.TypeOf(int(0)), + Int8: reflect.TypeOf(int8(0)), + Int16: reflect.TypeOf(int16(0)), + Int32: reflect.TypeOf(int32(0)), + Int64: reflect.TypeOf(int64(0)), + Uint: reflect.TypeOf(uint(0)), + Uint8: reflect.TypeOf(uint8(0)), + Uint16: reflect.TypeOf(uint16(0)), + Uint32: reflect.TypeOf(uint32(0)), + Uint64: reflect.TypeOf(uint64(0)), + Uintptr: reflect.TypeOf(uintptr(0)), + Float32: reflect.TypeOf(float32(0)), + Float64: reflect.TypeOf(float64(0)), + String: reflect.TypeOf(string("")), + } + + // ErrInvalidKind occurs when you call an inappropriate method for a given kind. + ErrInvalidKind = errors.New("invalid kind") + + // ErrNotRepresentable occurs when a type is encountered that is not supported by the language. + ErrNotRepresentable = errors.New("type cannot be represented") + + // ErrUntypedNil occurs when an untyped nil is used inappropriately. + ErrUntypedNil = errors.New("untyped nil value") +) + +// NoSuchFieldError is returned when an unknown field is accessed. +type NoSuchFieldError struct { + field string +} + +func (err NoSuchFieldError) Error() string { + return fmt.Sprintf("no such field: %s", err.field) +} + +// Kind is the most basic type descriptor. +type Kind int + +// Enumeration of valid kinds of types. +const ( + Invalid Kind = iota + + // Primitives + Bool + Int + Int8 + Int16 + Int32 + Int64 + Uint + Uint8 + Uint16 + Uint32 + Uint64 + Uintptr + Float32 + Float64 + String + + // Untyped constants + UntypedBool + UntypedInt + UntypedFloat + UntypedNil + + // Composite types + Array + Slice + Struct + Map + Ptr + Func + Pkg +) + +// Type is the representation of an expr type. +type Type interface { + Kind() Kind + String() string +} + +// PrimitiveType is the type of primitives. +type PrimitiveType struct { + kind Kind +} + +// NewPrimitiveType returns a new primitive type. +func NewPrimitiveType(k Kind) Type { + if k < Bool || k > String { + panic("not a primitive kind") + } + return &PrimitiveType{kind: k} +} + +// String implements Type. +func (t PrimitiveType) String() string { + switch t.kind { + case Bool: + return "bool" + case Int: + return "int" + case Int8: + return "int8" + case Int16: + return "int16" + case Int32: + return "int32" + case Int64: + return "int64" + case Uint: + return "uint" + case Uint8: + return "uint8" + case Uint16: + return "uint16" + case Uint32: + return "uint32" + case Uint64: + return "uint64" + case Uintptr: + return "uintptr" + case Float32: + return "float32" + case Float64: + return "float64" + case String: + return "string" + default: + return "" + } +} + +// Kind implements Type. +func (t PrimitiveType) Kind() Kind { + return t.kind +} + +// littype is the type of literals. +type littype struct { + kind Kind +} + +// NewLiteralType returns a new primitive type. +func NewLiteralType(k Kind) Type { + if k < UntypedBool || k > UntypedNil { + panic("not a primitive kind") + } + return &littype{kind: k} +} + +// String implements Type. +func (t littype) String() string { + switch t.kind { + case UntypedBool: + return "untyped bool constant" + case UntypedInt: + return "untyped int constant" + case UntypedFloat: + return "untyped float constant" + case UntypedNil: + return "untyped nil value" + default: + return "" + } +} + +func (t littype) Kind() Kind { return t.kind } + +// PackageType is the type of a package. +type PackageType struct { + symbols map[string]Type +} + +// NewPackageType returns a new package with the given symbols. +func NewPackageType(symbols map[string]Type) *PackageType { + return &PackageType{symbols} +} + +// String implements Type. +func (PackageType) String() string { + return "package" +} + +// Kind implements Type. +func (PackageType) Kind() Kind { + return Pkg +} + +// Symbol returns a symbol by the given name, or nil if none could be found. +func (t PackageType) Symbol(ident string) Type { + if s, ok := t.symbols[ident]; ok { + return s + } + return nil +} + +// ArrayType is the type of array-like values. +type ArrayType struct { + count int + elem Type +} + +// NewArrayType returns a new array type. +func NewArrayType(count int, elem Type) *ArrayType { + return &ArrayType{count: count, elem: elem} +} + +// String implements Type. +func (t ArrayType) String() string { + return fmt.Sprintf("[%d]%s", t.count, t.elem.String()) +} + +// Kind implements Type. +func (ArrayType) Kind() Kind { + return Array +} + +// Elem is the type of element in the array. +func (t ArrayType) Elem() Type { + return t.elem +} + +// Len is the length of the array. +func (t ArrayType) Len() int { + return t.count +} + +// SliceType is the type of array-like values. +type SliceType struct { + elem Type +} + +// NewSliceType returns a new array type. +func NewSliceType(elem Type) *SliceType { + return &SliceType{elem: elem} +} + +// String implements Type. +func (t SliceType) String() string { + return "[]" + t.elem.String() +} + +// Kind implements Type. +func (SliceType) Kind() Kind { + return Slice +} + +// Elem is the type of element in the slice. +func (t SliceType) Elem() Type { + return t.elem +} + +// MapType is the type of maps. +type MapType struct { + key, val Type +} + +// NewMapType returns a new map type. +func NewMapType(key Type, val Type) Type { + return MapType{key: key, val: val} +} + +// String implements Type. +func (t MapType) String() string { + return "map[" + t.key.String() + "]" + t.val.String() +} + +// Kind implements Type. +func (MapType) Kind() Kind { + return Map +} + +// Key is the type of the map's keys. +func (t MapType) Key() Type { + return t.key +} + +// Value is the type of the map's values. +func (t MapType) Value() Type { + return t.val +} + +// Field represents a struct field. +type Field struct { + Name string + Type Type +} + +// StructType is the type of struct values. +type StructType struct { + fields []Field + fieldMap map[string]Field +} + +// NewStructType returns a new struct type. +func NewStructType(fields []Field) *StructType { + fieldMap := map[string]Field{} + for _, field := range fields { + fieldMap[field.Name] = field + } + return &StructType{fields: fields, fieldMap: fieldMap} +} + +// String implements Type. +func (t StructType) String() string { + return "struct" +} + +// Kind implements Type. +func (StructType) Kind() Kind { + return Struct +} + +// NumFields returns the number of fields in the struct. +func (t StructType) NumFields() int { + return len(t.fields) +} + +// Field returns the nth field in the struct. +func (t StructType) Field(i int) Field { + return t.fields[i] +} + +// FieldByName returns the field with the given name. +func (t StructType) FieldByName(name string) (Field, bool) { + f, ok := t.fieldMap[name] + return f, ok +} + +// PtrType is the type of pointers. +type PtrType struct { + elem Type +} + +// NewPtrType returns a new pointer type. +func NewPtrType(elem Type) *PtrType { + return &PtrType{elem: elem} +} + +// String implements Type. +func (t PtrType) String() string { + return "*" + t.elem.String() +} + +// Kind implements Type. +func (PtrType) Kind() Kind { + return Ptr +} + +// Elem returns the element being pointed to by the pointer. +func (t PtrType) Elem() Type { + return t.elem +} + +// FuncType is the type of function values. +type FuncType struct { + in []Type + out []Type + variadic bool +} + +// NewFuncType returns a new function type. +func NewFuncType(in []Type, out []Type, variadic bool) *FuncType { + return &FuncType{in: in, out: out, variadic: variadic} +} + +// String implements Type. +func (t FuncType) String() string { + return "func" +} + +// Kind implements Type. +func (FuncType) Kind() Kind { + return Func +} + +// NumIn returns the number of input parameters. +func (t FuncType) NumIn() int { + return len(t.in) +} + +// In gets the nth input parameter. +func (t FuncType) In(i int) Type { + return t.in[i] +} + +// IsVariadic returns true for variadic functions. +func (t FuncType) IsVariadic() bool { + return t.variadic +} + +// NumOut returns the number of output parameters. +func (t FuncType) NumOut() int { + return len(t.out) +} + +// Out gets the nth output parameter. +func (t FuncType) Out(i int) Type { + return t.out[i] +} + +// TypeEqual returns true if the two types are equal. +func TypeEqual(a, b Type) bool { + // TODO: this could be a bit more precise. + return reflect.DeepEqual(a, b) +} + +// toreflecttype converts an expr type into a runtime type. +func toreflecttype(t Type) reflect.Type { + switch t := t.(type) { + case *PrimitiveType: + return primRType[t.Kind()] + case *ArrayType: + return reflect.ArrayOf(t.Len(), toreflecttype(t.Elem())) + case *SliceType: + return reflect.SliceOf(toreflecttype(t.Elem())) + case *StructType: + fields := make([]reflect.StructField, 0, t.NumFields()) + for i := 0; i < t.NumFields(); i++ { + field := t.Field(i) + fields = append(fields, reflect.StructField{ + Name: field.Name, + Type: toreflecttype(field.Type), + }) + } + return reflect.StructOf(fields) + case *MapType: + return reflect.MapOf(toreflecttype(t.Key()), toreflecttype(t.Value())) + case *PtrType: + return reflect.PtrTo(toreflecttype(t.Elem())) + case *FuncType: + nin := t.NumIn() + in := make([]reflect.Type, 0, nin) + for i := 0; i < nin; i++ { + in = append(in, toreflecttype(t.In(i))) + } + nout := t.NumOut() + out := make([]reflect.Type, 0, nout) + for i := 0; i < nout; i++ { + out = append(out, toreflecttype(t.Out(i))) + } + return reflect.FuncOf(in, out, t.IsVariadic()) + default: + panic(ErrNotRepresentable) + } +} + +var typemap = map[reflect.Type]Type{} +var typemutex = sync.Mutex{} + +func savetype(reflect reflect.Type, expr Type) Type { + typemutex.Lock() + defer typemutex.Unlock() + + typemap[reflect] = expr + return expr +} + +func loadtype(reflect reflect.Type) (Type, bool) { + typemutex.Lock() + defer typemutex.Unlock() + + if expr, ok := typemap[reflect]; ok { + return expr, true + } + return nil, false +} + +// fromreflecttype converts a runtime type into an expr type. +func fromreflecttype(t reflect.Type) Type { + if et, ok := loadtype(t); ok { + return et + } + + switch t.Kind() { + case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, + reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, + reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64, + reflect.String: + return primType[t.Kind()] + case reflect.Array: + return NewArrayType(t.Len(), fromreflecttype(t.Elem())) + case reflect.Func: + nin := t.NumIn() + in := make([]Type, 0, nin) + for i := 0; i < nin; i++ { + in = append(in, fromreflecttype(t.In(i))) + } + nout := t.NumOut() + out := make([]Type, 0, nout) + for i := 0; i < nout; i++ { + out = append(out, fromreflecttype(t.Out(i))) + } + return NewFuncType(in, out, t.IsVariadic()) + case reflect.Map: + return NewMapType(fromreflecttype(t.Key()), fromreflecttype(t.Elem())) + case reflect.Ptr: + et := &PtrType{} + savetype(t, et) + *et = *NewPtrType(fromreflecttype(t.Elem())) + return et + case reflect.Slice: + et := &SliceType{} + savetype(t, et) + *et = *NewSliceType(fromreflecttype(t.Elem())) + return et + case reflect.Struct: + fields := make([]Field, 0, t.NumField()) + for i := 0; i < t.NumField(); i++ { + field := t.Field(i) + fields = append(fields, Field{ + Name: field.Name, + Type: fromreflecttype(field.Type), + }) + } + return NewStructType(fields) + default: + panic(ErrNotRepresentable) + } +} + +func assignable(from Type, to Type) bool { + if TypeEqual(from, to) { + return true + } + + switch from.Kind() { + case UntypedNil: + switch to.Kind() { + case Ptr, Func, Slice, Map: + return true + } + + case UntypedBool: + switch to.Kind() { + case Bool: + return true + } + + case UntypedInt: + // TODO: Range and overflow checks. + switch to.Kind() { + case Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: + return true + case Float32, Float64: + return true + } + + case UntypedFloat: + switch to.Kind() { + case Float32, Float64: + return true + } + } + return false +} + +// TypeOf returns the type of a runtime value. +func TypeOf(i interface{}) Type { + if pkg, ok := i.(Package); ok { + return pkg.Type() + } + + return fromreflecttype(reflect.TypeOf(i)) +} diff --git a/rune/vendor/github.com/go-restruct/restruct/expr/value.go b/rune/vendor/github.com/go-restruct/restruct/expr/value.go new file mode 100644 index 0000000000000000000000000000000000000000..40896a0bf8cb5957b0df9316a7a8aee50ce50d67 --- /dev/null +++ b/rune/vendor/github.com/go-restruct/restruct/expr/value.go @@ -0,0 +1,910 @@ +package expr + +import ( + "fmt" + "reflect" +) + +// InvalidOpError is returned when an attempt is made to perform an operation +// on a type that is not supported. +type InvalidOpError struct { + Op string + V Value +} + +func (e InvalidOpError) Error() string { + return fmt.Sprintf("invalid operation: operator %s not defined for %v (%s)", e.Op, e.V.Value(), e.V.Type()) +} + +// ConversionError is returned when an invalid type conversion is attempted. +type ConversionError struct { + From Type + To Type +} + +func (e ConversionError) Error() string { + return fmt.Sprintf("cannot convert %s to %s", e.From, e.To) +} + +// ReferenceError is returned when it is not possible to take the address of a +// value. +type ReferenceError struct{} + +func (e ReferenceError) Error() string { + return "could not take reference of value" +} + +// Value represents a value at runtime. +type Value interface { + Type() Type + Value() reflect.Value + RawValue() interface{} + + Negate() Value + Not() Value + BitNot() Value + Deref() Value + Ref() Value + Dot(ident string) Value + + LogicalOr(rhs Value) Value + LogicalAnd(rhs Value) Value + Equal(rhs Value) Value + NotEqual(rhs Value) Value + Lesser(rhs Value) Value + LesserEqual(rhs Value) Value + Greater(rhs Value) Value + GreaterEqual(rhs Value) Value + Add(rhs Value) Value + Sub(rhs Value) Value + Or(rhs Value) Value + Xor(rhs Value) Value + Mul(rhs Value) Value + Div(rhs Value) Value + Rem(rhs Value) Value + Lsh(rhs Value) Value + Rsh(rhs Value) Value + And(rhs Value) Value + AndNot(rhs Value) Value + Index(rhs Value) Value + Call(in []Value) Value +} + +type val struct { + v reflect.Value + t Type +} + +func promote(from Value, to Type) Value { + if TypeEqual(from.Type(), to) { + return from + } + + ftype := from.Type() + switch ftype.Kind() { + case UntypedBool: + switch to.Kind() { + case Bool: + return val{from.Value(), to} + default: + panic(ConversionError{From: ftype, To: to}) + } + case UntypedFloat: + switch to.Kind() { + case Float32: + return val{reflect.ValueOf(float32(reflect.ValueOf(from.Value).Float())), to} + case Float64: + return val{reflect.ValueOf(float64(reflect.ValueOf(from.Value).Float())), to} + default: + panic(ConversionError{From: ftype, To: to}) + } + case UntypedInt: + ival, uval, fval := int64(0), uint64(0), float64(0) + switch n := from.RawValue().(type) { + case int64: + ival = int64(n) + uval = uint64(n) + fval = float64(n) + case uint64: + ival = int64(n) + uval = uint64(n) + fval = float64(n) + } + switch to.Kind() { + case Int: + return val{reflect.ValueOf(int(ival)), to} + case Int8: + return val{reflect.ValueOf(int8(ival)), to} + case Int16: + return val{reflect.ValueOf(int16(ival)), to} + case Int32: + return val{reflect.ValueOf(int32(ival)), to} + case Int64: + return val{reflect.ValueOf(int64(ival)), to} + case Uint: + return val{reflect.ValueOf(uint(uval)), to} + case Uint8: + return val{reflect.ValueOf(uint8(uval)), to} + case Uint16: + return val{reflect.ValueOf(uint16(uval)), to} + case Uint32: + return val{reflect.ValueOf(uint32(uval)), to} + case Uint64: + return val{reflect.ValueOf(uint64(uval)), to} + case Uintptr: + return val{reflect.ValueOf(uintptr(uval)), to} + case Float32: + return val{reflect.ValueOf(float32(fval)), to} + case Float64: + return val{reflect.ValueOf(float64(fval)), to} + default: + panic(ConversionError{From: ftype, To: to}) + } + case UntypedNil: + return val{reflect.Zero(toreflecttype(to)), to} + default: + panic(ConversionError{From: ftype, To: to}) + } +} + +func coerce1(v Value) Value { + if v.Type().Kind() == UntypedInt { + switch n := v.RawValue().(type) { + case uint64: + return val{reflect.ValueOf(int(n)), NewPrimitiveType(Int)} + case int64: + return val{reflect.ValueOf(int(n)), NewPrimitiveType(Int)} + } + } + return v +} + +func coerce(lhs Value, rhs Value) (Value, Value) { + if TypeEqual(lhs.Type(), rhs.Type()) { + return coerce1(lhs), coerce1(rhs) + } else if assignable(lhs.Type(), rhs.Type()) { + return promote(lhs, rhs.Type()), rhs + } else if assignable(rhs.Type(), lhs.Type()) { + return lhs, promote(rhs, lhs.Type()) + } + panic(ConversionError{From: lhs.Type(), To: rhs.Type()}) +} + +func (v val) Type() Type { + return v.t +} + +func (v val) Value() reflect.Value { + return v.v +} + +func (v val) RawValue() interface{} { + return v.v.Interface() +} + +func (v val) Negate() Value { + switch n := v.RawValue().(type) { + case int: + return val{reflect.ValueOf(-n), v.t} + case int8: + return val{reflect.ValueOf(-n), v.t} + case int16: + return val{reflect.ValueOf(-n), v.t} + case int32: + return val{reflect.ValueOf(-n), v.t} + case int64: + return val{reflect.ValueOf(-n), v.t} + case uint: + return val{reflect.ValueOf(-n), v.t} + case uint8: + return val{reflect.ValueOf(-n), v.t} + case uint16: + return val{reflect.ValueOf(-n), v.t} + case uint32: + return val{reflect.ValueOf(-n), v.t} + case uint64: + return val{reflect.ValueOf(-n), v.t} + case uintptr: + return val{reflect.ValueOf(-n), v.t} + case float32: + return val{reflect.ValueOf(-n), v.t} + case float64: + return val{reflect.ValueOf(-n), v.t} + default: + panic(InvalidOpError{Op: "-", V: v}) + } +} + +func (v val) Not() Value { + switch n := v.RawValue().(type) { + case bool: + return val{reflect.ValueOf(!n), v.t} + default: + panic(InvalidOpError{Op: "!", V: v}) + } +} + +func (v val) BitNot() Value { + switch n := v.RawValue().(type) { + case int: + return val{reflect.ValueOf(^n), v.t} + case int8: + return val{reflect.ValueOf(^n), v.t} + case int16: + return val{reflect.ValueOf(^n), v.t} + case int32: + return val{reflect.ValueOf(^n), v.t} + case int64: + return val{reflect.ValueOf(^n), v.t} + case uint: + return val{reflect.ValueOf(^n), v.t} + case uint8: + return val{reflect.ValueOf(^n), v.t} + case uint16: + return val{reflect.ValueOf(^n), v.t} + case uint32: + return val{reflect.ValueOf(^n), v.t} + case uint64: + return val{reflect.ValueOf(^n), v.t} + case uintptr: + return val{reflect.ValueOf(^n), v.t} + default: + panic(InvalidOpError{Op: "^", V: v}) + } +} + +func (v val) Deref() Value { + ptrtype, ok := v.t.(*PtrType) + if !ok { + panic(InvalidOpError{Op: "*", V: v}) + } + return val{v.v.Elem(), ptrtype.Elem()} +} + +func (v val) Ref() Value { + if !v.v.CanAddr() { + panic(ReferenceError{}) + } + return val{v.v.Addr(), NewPtrType(v.t)} +} + +func (v val) Dot(ident string) Value { + switch v.t.(type) { + case *PackageType: + if sv := v.RawValue().(Package).Symbol(ident); sv != nil { + return sv + } + case *StructType: + if sv := v.v.FieldByName(ident); sv.IsValid() { + return val{sv, TypeOf(sv.Interface())} + } + case *PtrType: + return v.Deref().Dot(ident) + } + panic(InvalidOpError{Op: ".", V: v}) +} + +func (v val) LogicalOr(rhs Value) Value { + lv, ok := v.RawValue().(bool) + if !ok { + panic(InvalidOpError{Op: "||", V: v}) + } + + rv, ok := rhs.RawValue().(bool) + if !ok { + panic(InvalidOpError{Op: "||", V: rhs}) + } + + return val{reflect.ValueOf(lv || rv), NewPrimitiveType(Bool)} +} + +func (v val) LogicalAnd(rhs Value) Value { + lv, ok := v.RawValue().(bool) + if !ok { + panic(InvalidOpError{Op: "&&", V: v}) + } + + rv, ok := rhs.RawValue().(bool) + if !ok { + panic(InvalidOpError{Op: "&&", V: rhs}) + } + + return val{reflect.ValueOf(lv && rv), NewPrimitiveType(Bool)} +} + +func (v val) Equal(rhs Value) Value { + l, r := coerce(v, rhs) + return val{reflect.ValueOf(l.RawValue() == r.RawValue()), NewPrimitiveType(Bool)} +} + +func (v val) NotEqual(rhs Value) Value { + l, r := coerce(v, rhs) + return val{reflect.ValueOf(l.RawValue() != r.RawValue()), NewPrimitiveType(Bool)} +} + +func (v val) Lesser(rhs Value) Value { + l, r := coerce(v, rhs) + switch lv := l.RawValue().(type) { + case int: + return val{reflect.ValueOf(lv < r.RawValue().(int)), NewPrimitiveType(Bool)} + case int8: + return val{reflect.ValueOf(lv < r.RawValue().(int8)), NewPrimitiveType(Bool)} + case int16: + return val{reflect.ValueOf(lv < r.RawValue().(int16)), NewPrimitiveType(Bool)} + case int32: + return val{reflect.ValueOf(lv < r.RawValue().(int32)), NewPrimitiveType(Bool)} + case int64: + return val{reflect.ValueOf(lv < r.RawValue().(int64)), NewPrimitiveType(Bool)} + case uint: + return val{reflect.ValueOf(lv < r.RawValue().(uint)), NewPrimitiveType(Bool)} + case uint8: + return val{reflect.ValueOf(lv < r.RawValue().(uint8)), NewPrimitiveType(Bool)} + case uint16: + return val{reflect.ValueOf(lv < r.RawValue().(uint16)), NewPrimitiveType(Bool)} + case uint32: + return val{reflect.ValueOf(lv < r.RawValue().(uint32)), NewPrimitiveType(Bool)} + case uint64: + return val{reflect.ValueOf(lv < r.RawValue().(uint64)), NewPrimitiveType(Bool)} + case uintptr: + return val{reflect.ValueOf(lv < r.RawValue().(uintptr)), NewPrimitiveType(Bool)} + case float32: + return val{reflect.ValueOf(lv < r.RawValue().(float32)), NewPrimitiveType(Bool)} + case float64: + return val{reflect.ValueOf(lv < r.RawValue().(float64)), NewPrimitiveType(Bool)} + default: + panic(InvalidOpError{Op: "<", V: l}) + } +} + +func (v val) LesserEqual(rhs Value) Value { + l, r := coerce(v, rhs) + switch lv := l.RawValue().(type) { + case int: + return val{reflect.ValueOf(lv <= r.RawValue().(int)), NewPrimitiveType(Bool)} + case int8: + return val{reflect.ValueOf(lv <= r.RawValue().(int8)), NewPrimitiveType(Bool)} + case int16: + return val{reflect.ValueOf(lv <= r.RawValue().(int16)), NewPrimitiveType(Bool)} + case int32: + return val{reflect.ValueOf(lv <= r.RawValue().(int32)), NewPrimitiveType(Bool)} + case int64: + return val{reflect.ValueOf(lv <= r.RawValue().(int64)), NewPrimitiveType(Bool)} + case uint: + return val{reflect.ValueOf(lv <= r.RawValue().(uint)), NewPrimitiveType(Bool)} + case uint8: + return val{reflect.ValueOf(lv <= r.RawValue().(uint8)), NewPrimitiveType(Bool)} + case uint16: + return val{reflect.ValueOf(lv <= r.RawValue().(uint16)), NewPrimitiveType(Bool)} + case uint32: + return val{reflect.ValueOf(lv <= r.RawValue().(uint32)), NewPrimitiveType(Bool)} + case uint64: + return val{reflect.ValueOf(lv <= r.RawValue().(uint64)), NewPrimitiveType(Bool)} + case uintptr: + return val{reflect.ValueOf(lv <= r.RawValue().(uintptr)), NewPrimitiveType(Bool)} + case float32: + return val{reflect.ValueOf(lv <= r.RawValue().(float32)), NewPrimitiveType(Bool)} + case float64: + return val{reflect.ValueOf(lv <= r.RawValue().(float64)), NewPrimitiveType(Bool)} + default: + panic(InvalidOpError{Op: "<=", V: l}) + } +} + +func (v val) Greater(rhs Value) Value { + l, r := coerce(v, rhs) + switch lv := l.RawValue().(type) { + case int: + return val{reflect.ValueOf(lv > r.RawValue().(int)), NewPrimitiveType(Bool)} + case int8: + return val{reflect.ValueOf(lv > r.RawValue().(int8)), NewPrimitiveType(Bool)} + case int16: + return val{reflect.ValueOf(lv > r.RawValue().(int16)), NewPrimitiveType(Bool)} + case int32: + return val{reflect.ValueOf(lv > r.RawValue().(int32)), NewPrimitiveType(Bool)} + case int64: + return val{reflect.ValueOf(lv > r.RawValue().(int64)), NewPrimitiveType(Bool)} + case uint: + return val{reflect.ValueOf(lv > r.RawValue().(uint)), NewPrimitiveType(Bool)} + case uint8: + return val{reflect.ValueOf(lv > r.RawValue().(uint8)), NewPrimitiveType(Bool)} + case uint16: + return val{reflect.ValueOf(lv > r.RawValue().(uint16)), NewPrimitiveType(Bool)} + case uint32: + return val{reflect.ValueOf(lv > r.RawValue().(uint32)), NewPrimitiveType(Bool)} + case uint64: + return val{reflect.ValueOf(lv > r.RawValue().(uint64)), NewPrimitiveType(Bool)} + case uintptr: + return val{reflect.ValueOf(lv > r.RawValue().(uintptr)), NewPrimitiveType(Bool)} + case float32: + return val{reflect.ValueOf(lv > r.RawValue().(float32)), NewPrimitiveType(Bool)} + case float64: + return val{reflect.ValueOf(lv > r.RawValue().(float64)), NewPrimitiveType(Bool)} + default: + panic(InvalidOpError{Op: ">", V: l}) + } +} + +func (v val) GreaterEqual(rhs Value) Value { + l, r := coerce(v, rhs) + switch lv := l.RawValue().(type) { + case int: + return val{reflect.ValueOf(lv >= r.RawValue().(int)), NewPrimitiveType(Bool)} + case int8: + return val{reflect.ValueOf(lv >= r.RawValue().(int8)), NewPrimitiveType(Bool)} + case int16: + return val{reflect.ValueOf(lv >= r.RawValue().(int16)), NewPrimitiveType(Bool)} + case int32: + return val{reflect.ValueOf(lv >= r.RawValue().(int32)), NewPrimitiveType(Bool)} + case int64: + return val{reflect.ValueOf(lv >= r.RawValue().(int64)), NewPrimitiveType(Bool)} + case uint: + return val{reflect.ValueOf(lv >= r.RawValue().(uint)), NewPrimitiveType(Bool)} + case uint8: + return val{reflect.ValueOf(lv >= r.RawValue().(uint8)), NewPrimitiveType(Bool)} + case uint16: + return val{reflect.ValueOf(lv >= r.RawValue().(uint16)), NewPrimitiveType(Bool)} + case uint32: + return val{reflect.ValueOf(lv >= r.RawValue().(uint32)), NewPrimitiveType(Bool)} + case uint64: + return val{reflect.ValueOf(lv >= r.RawValue().(uint64)), NewPrimitiveType(Bool)} + case uintptr: + return val{reflect.ValueOf(lv >= r.RawValue().(uintptr)), NewPrimitiveType(Bool)} + case float32: + return val{reflect.ValueOf(lv >= r.RawValue().(float32)), NewPrimitiveType(Bool)} + case float64: + return val{reflect.ValueOf(lv >= r.RawValue().(float64)), NewPrimitiveType(Bool)} + default: + panic(InvalidOpError{Op: ">=", V: l}) + } +} + +func (v val) Add(rhs Value) Value { + l, r := coerce(v, rhs) + switch lv := l.RawValue().(type) { + case int: + return val{reflect.ValueOf(lv + r.RawValue().(int)), NewPrimitiveType(Int)} + case int8: + return val{reflect.ValueOf(lv + r.RawValue().(int8)), NewPrimitiveType(Int8)} + case int16: + return val{reflect.ValueOf(lv + r.RawValue().(int16)), NewPrimitiveType(Int16)} + case int32: + return val{reflect.ValueOf(lv + r.RawValue().(int32)), NewPrimitiveType(Int32)} + case int64: + return val{reflect.ValueOf(lv + r.RawValue().(int64)), NewPrimitiveType(Int64)} + case uint: + return val{reflect.ValueOf(lv + r.RawValue().(uint)), NewPrimitiveType(Uint)} + case uint8: + return val{reflect.ValueOf(lv + r.RawValue().(uint8)), NewPrimitiveType(Uint8)} + case uint16: + return val{reflect.ValueOf(lv + r.RawValue().(uint16)), NewPrimitiveType(Uint16)} + case uint32: + return val{reflect.ValueOf(lv + r.RawValue().(uint32)), NewPrimitiveType(Uint32)} + case uint64: + return val{reflect.ValueOf(lv + r.RawValue().(uint64)), NewPrimitiveType(Uint64)} + case uintptr: + return val{reflect.ValueOf(lv + r.RawValue().(uintptr)), NewPrimitiveType(Uintptr)} + case float32: + return val{reflect.ValueOf(lv + r.RawValue().(float32)), NewPrimitiveType(Float32)} + case float64: + return val{reflect.ValueOf(lv + r.RawValue().(float64)), NewPrimitiveType(Float64)} + case string: + return val{reflect.ValueOf(lv + r.RawValue().(string)), NewPrimitiveType(String)} + default: + panic(InvalidOpError{Op: "+", V: l}) + } +} + +func (v val) Sub(rhs Value) Value { + l, r := coerce(v, rhs) + switch lv := l.RawValue().(type) { + case int: + return val{reflect.ValueOf(lv - r.RawValue().(int)), NewPrimitiveType(Int)} + case int8: + return val{reflect.ValueOf(lv - r.RawValue().(int8)), NewPrimitiveType(Int8)} + case int16: + return val{reflect.ValueOf(lv - r.RawValue().(int16)), NewPrimitiveType(Int16)} + case int32: + return val{reflect.ValueOf(lv - r.RawValue().(int32)), NewPrimitiveType(Int32)} + case int64: + return val{reflect.ValueOf(lv - r.RawValue().(int64)), NewPrimitiveType(Int64)} + case uint: + return val{reflect.ValueOf(lv - r.RawValue().(uint)), NewPrimitiveType(Uint)} + case uint8: + return val{reflect.ValueOf(lv - r.RawValue().(uint8)), NewPrimitiveType(Uint8)} + case uint16: + return val{reflect.ValueOf(lv - r.RawValue().(uint16)), NewPrimitiveType(Uint16)} + case uint32: + return val{reflect.ValueOf(lv - r.RawValue().(uint32)), NewPrimitiveType(Uint32)} + case uint64: + return val{reflect.ValueOf(lv - r.RawValue().(uint64)), NewPrimitiveType(Uint64)} + case uintptr: + return val{reflect.ValueOf(lv - r.RawValue().(uintptr)), NewPrimitiveType(Uintptr)} + case float32: + return val{reflect.ValueOf(lv - r.RawValue().(float32)), NewPrimitiveType(Float32)} + case float64: + return val{reflect.ValueOf(lv - r.RawValue().(float64)), NewPrimitiveType(Float64)} + default: + panic(InvalidOpError{Op: "-", V: l}) + } +} + +func (v val) Or(rhs Value) Value { + l, r := coerce(v, rhs) + switch lv := l.RawValue().(type) { + case int: + return val{reflect.ValueOf(lv | r.RawValue().(int)), NewPrimitiveType(Int)} + case int8: + return val{reflect.ValueOf(lv | r.RawValue().(int8)), NewPrimitiveType(Int8)} + case int16: + return val{reflect.ValueOf(lv | r.RawValue().(int16)), NewPrimitiveType(Int16)} + case int32: + return val{reflect.ValueOf(lv | r.RawValue().(int32)), NewPrimitiveType(Int32)} + case int64: + return val{reflect.ValueOf(lv | r.RawValue().(int64)), NewPrimitiveType(Int64)} + case uint: + return val{reflect.ValueOf(lv | r.RawValue().(uint)), NewPrimitiveType(Uint)} + case uint8: + return val{reflect.ValueOf(lv | r.RawValue().(uint8)), NewPrimitiveType(Uint8)} + case uint16: + return val{reflect.ValueOf(lv | r.RawValue().(uint16)), NewPrimitiveType(Uint16)} + case uint32: + return val{reflect.ValueOf(lv | r.RawValue().(uint32)), NewPrimitiveType(Uint32)} + case uint64: + return val{reflect.ValueOf(lv | r.RawValue().(uint64)), NewPrimitiveType(Uint64)} + case uintptr: + return val{reflect.ValueOf(lv | r.RawValue().(uintptr)), NewPrimitiveType(Uintptr)} + default: + panic(InvalidOpError{Op: "|", V: l}) + } +} + +func (v val) Xor(rhs Value) Value { + l, r := coerce(v, rhs) + switch lv := l.RawValue().(type) { + case int: + return val{reflect.ValueOf(lv ^ r.RawValue().(int)), NewPrimitiveType(Int)} + case int8: + return val{reflect.ValueOf(lv ^ r.RawValue().(int8)), NewPrimitiveType(Int8)} + case int16: + return val{reflect.ValueOf(lv ^ r.RawValue().(int16)), NewPrimitiveType(Int16)} + case int32: + return val{reflect.ValueOf(lv ^ r.RawValue().(int32)), NewPrimitiveType(Int32)} + case int64: + return val{reflect.ValueOf(lv ^ r.RawValue().(int64)), NewPrimitiveType(Int64)} + case uint: + return val{reflect.ValueOf(lv ^ r.RawValue().(uint)), NewPrimitiveType(Uint)} + case uint8: + return val{reflect.ValueOf(lv ^ r.RawValue().(uint8)), NewPrimitiveType(Uint8)} + case uint16: + return val{reflect.ValueOf(lv ^ r.RawValue().(uint16)), NewPrimitiveType(Uint16)} + case uint32: + return val{reflect.ValueOf(lv ^ r.RawValue().(uint32)), NewPrimitiveType(Uint32)} + case uint64: + return val{reflect.ValueOf(lv ^ r.RawValue().(uint64)), NewPrimitiveType(Uint64)} + case uintptr: + return val{reflect.ValueOf(lv ^ r.RawValue().(uintptr)), NewPrimitiveType(Uintptr)} + default: + panic(InvalidOpError{Op: "^", V: l}) + } +} + +func (v val) Mul(rhs Value) Value { + l, r := coerce(v, rhs) + switch lv := l.RawValue().(type) { + case int: + return val{reflect.ValueOf(lv * r.RawValue().(int)), NewPrimitiveType(Int)} + case int8: + return val{reflect.ValueOf(lv * r.RawValue().(int8)), NewPrimitiveType(Int8)} + case int16: + return val{reflect.ValueOf(lv * r.RawValue().(int16)), NewPrimitiveType(Int16)} + case int32: + return val{reflect.ValueOf(lv * r.RawValue().(int32)), NewPrimitiveType(Int32)} + case int64: + return val{reflect.ValueOf(lv * r.RawValue().(int64)), NewPrimitiveType(Int64)} + case uint: + return val{reflect.ValueOf(lv * r.RawValue().(uint)), NewPrimitiveType(Uint)} + case uint8: + return val{reflect.ValueOf(lv * r.RawValue().(uint8)), NewPrimitiveType(Uint8)} + case uint16: + return val{reflect.ValueOf(lv * r.RawValue().(uint16)), NewPrimitiveType(Uint16)} + case uint32: + return val{reflect.ValueOf(lv * r.RawValue().(uint32)), NewPrimitiveType(Uint32)} + case uint64: + return val{reflect.ValueOf(lv * r.RawValue().(uint64)), NewPrimitiveType(Uint64)} + case uintptr: + return val{reflect.ValueOf(lv * r.RawValue().(uintptr)), NewPrimitiveType(Uintptr)} + case float32: + return val{reflect.ValueOf(lv * r.RawValue().(float32)), NewPrimitiveType(Float32)} + case float64: + return val{reflect.ValueOf(lv * r.RawValue().(float64)), NewPrimitiveType(Float64)} + default: + panic(InvalidOpError{Op: "*", V: l}) + } +} + +func (v val) Div(rhs Value) Value { + l, r := coerce(v, rhs) + switch lv := l.RawValue().(type) { + case int: + return val{reflect.ValueOf(lv / r.RawValue().(int)), NewPrimitiveType(Int)} + case int8: + return val{reflect.ValueOf(lv / r.RawValue().(int8)), NewPrimitiveType(Int8)} + case int16: + return val{reflect.ValueOf(lv / r.RawValue().(int16)), NewPrimitiveType(Int16)} + case int32: + return val{reflect.ValueOf(lv / r.RawValue().(int32)), NewPrimitiveType(Int32)} + case int64: + return val{reflect.ValueOf(lv / r.RawValue().(int64)), NewPrimitiveType(Int64)} + case uint: + return val{reflect.ValueOf(lv / r.RawValue().(uint)), NewPrimitiveType(Uint)} + case uint8: + return val{reflect.ValueOf(lv / r.RawValue().(uint8)), NewPrimitiveType(Uint8)} + case uint16: + return val{reflect.ValueOf(lv / r.RawValue().(uint16)), NewPrimitiveType(Uint16)} + case uint32: + return val{reflect.ValueOf(lv / r.RawValue().(uint32)), NewPrimitiveType(Uint32)} + case uint64: + return val{reflect.ValueOf(lv / r.RawValue().(uint64)), NewPrimitiveType(Uint64)} + case uintptr: + return val{reflect.ValueOf(lv / r.RawValue().(uintptr)), NewPrimitiveType(Uintptr)} + case float32: + return val{reflect.ValueOf(lv / r.RawValue().(float32)), NewPrimitiveType(Float32)} + case float64: + return val{reflect.ValueOf(lv / r.RawValue().(float64)), NewPrimitiveType(Float64)} + default: + panic(InvalidOpError{Op: "/", V: l}) + } +} + +func (v val) Rem(rhs Value) Value { + l, r := coerce(v, rhs) + switch lv := l.RawValue().(type) { + case int: + return val{reflect.ValueOf(lv % r.RawValue().(int)), NewPrimitiveType(Int)} + case int8: + return val{reflect.ValueOf(lv % r.RawValue().(int8)), NewPrimitiveType(Int8)} + case int16: + return val{reflect.ValueOf(lv % r.RawValue().(int16)), NewPrimitiveType(Int16)} + case int32: + return val{reflect.ValueOf(lv % r.RawValue().(int32)), NewPrimitiveType(Int32)} + case int64: + return val{reflect.ValueOf(lv % r.RawValue().(int64)), NewPrimitiveType(Int64)} + case uint: + return val{reflect.ValueOf(lv % r.RawValue().(uint)), NewPrimitiveType(Uint)} + case uint8: + return val{reflect.ValueOf(lv % r.RawValue().(uint8)), NewPrimitiveType(Uint8)} + case uint16: + return val{reflect.ValueOf(lv % r.RawValue().(uint16)), NewPrimitiveType(Uint16)} + case uint32: + return val{reflect.ValueOf(lv % r.RawValue().(uint32)), NewPrimitiveType(Uint32)} + case uint64: + return val{reflect.ValueOf(lv % r.RawValue().(uint64)), NewPrimitiveType(Uint64)} + case uintptr: + return val{reflect.ValueOf(lv % r.RawValue().(uintptr)), NewPrimitiveType(Uintptr)} + default: + panic(InvalidOpError{Op: "%", V: l}) + } +} + +func (v val) Lsh(rhs Value) Value { + l := coerce1(v) + shift := uint64(0) + + switch rv := rhs.RawValue().(type) { + case uint: + shift = uint64(rv) + case uint8: + shift = uint64(rv) + case uint16: + shift = uint64(rv) + case uint32: + shift = uint64(rv) + case uint64: + shift = uint64(rv) + case uintptr: + shift = uint64(rv) + default: + panic(InvalidOpError{Op: "<<", V: rhs}) + } + + switch lv := l.RawValue().(type) { + case int: + return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Int)} + case int8: + return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Int8)} + case int16: + return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Int16)} + case int32: + return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Int32)} + case int64: + return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Int64)} + case uint: + return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Uint)} + case uint8: + return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Uint8)} + case uint16: + return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Uint16)} + case uint32: + return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Uint32)} + case uint64: + return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Uint64)} + case uintptr: + return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Uintptr)} + default: + panic(InvalidOpError{Op: "<<", V: l}) + } +} + +func (v val) Rsh(rhs Value) Value { + l := coerce1(v) + shift := uint64(0) + + switch rv := rhs.RawValue().(type) { + case uint: + shift = uint64(rv) + case uint8: + shift = uint64(rv) + case uint16: + shift = uint64(rv) + case uint32: + shift = uint64(rv) + case uint64: + shift = uint64(rv) + case uintptr: + shift = uint64(rv) + default: + panic(InvalidOpError{Op: ">>", V: rhs}) + } + + switch lv := l.RawValue().(type) { + case int: + return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Int)} + case int8: + return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Int8)} + case int16: + return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Int16)} + case int32: + return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Int32)} + case int64: + return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Int64)} + case uint: + return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Uint)} + case uint8: + return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Uint8)} + case uint16: + return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Uint16)} + case uint32: + return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Uint32)} + case uint64: + return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Uint64)} + case uintptr: + return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Uintptr)} + default: + panic(InvalidOpError{Op: ">>", V: l}) + } +} + +func (v val) And(rhs Value) Value { + l, r := coerce(v, rhs) + switch lv := l.RawValue().(type) { + case int: + return val{reflect.ValueOf(lv & r.RawValue().(int)), NewPrimitiveType(Int)} + case int8: + return val{reflect.ValueOf(lv & r.RawValue().(int8)), NewPrimitiveType(Int8)} + case int16: + return val{reflect.ValueOf(lv & r.RawValue().(int16)), NewPrimitiveType(Int16)} + case int32: + return val{reflect.ValueOf(lv & r.RawValue().(int32)), NewPrimitiveType(Int32)} + case int64: + return val{reflect.ValueOf(lv & r.RawValue().(int64)), NewPrimitiveType(Int64)} + case uint: + return val{reflect.ValueOf(lv & r.RawValue().(uint)), NewPrimitiveType(Uint)} + case uint8: + return val{reflect.ValueOf(lv & r.RawValue().(uint8)), NewPrimitiveType(Uint8)} + case uint16: + return val{reflect.ValueOf(lv & r.RawValue().(uint16)), NewPrimitiveType(Uint16)} + case uint32: + return val{reflect.ValueOf(lv & r.RawValue().(uint32)), NewPrimitiveType(Uint32)} + case uint64: + return val{reflect.ValueOf(lv & r.RawValue().(uint64)), NewPrimitiveType(Uint64)} + case uintptr: + return val{reflect.ValueOf(lv & r.RawValue().(uintptr)), NewPrimitiveType(Uintptr)} + default: + panic(InvalidOpError{Op: "&", V: l}) + } +} + +func (v val) AndNot(rhs Value) Value { + l, r := coerce(v, rhs) + switch lv := l.RawValue().(type) { + case int: + return val{reflect.ValueOf(lv &^ r.RawValue().(int)), NewPrimitiveType(Int)} + case int8: + return val{reflect.ValueOf(lv &^ r.RawValue().(int8)), NewPrimitiveType(Int8)} + case int16: + return val{reflect.ValueOf(lv &^ r.RawValue().(int16)), NewPrimitiveType(Int16)} + case int32: + return val{reflect.ValueOf(lv &^ r.RawValue().(int32)), NewPrimitiveType(Int32)} + case int64: + return val{reflect.ValueOf(lv &^ r.RawValue().(int64)), NewPrimitiveType(Int64)} + case uint: + return val{reflect.ValueOf(lv &^ r.RawValue().(uint)), NewPrimitiveType(Uint)} + case uint8: + return val{reflect.ValueOf(lv &^ r.RawValue().(uint8)), NewPrimitiveType(Uint8)} + case uint16: + return val{reflect.ValueOf(lv &^ r.RawValue().(uint16)), NewPrimitiveType(Uint16)} + case uint32: + return val{reflect.ValueOf(lv &^ r.RawValue().(uint32)), NewPrimitiveType(Uint32)} + case uint64: + return val{reflect.ValueOf(lv &^ r.RawValue().(uint64)), NewPrimitiveType(Uint64)} + case uintptr: + return val{reflect.ValueOf(lv &^ r.RawValue().(uintptr)), NewPrimitiveType(Uintptr)} + default: + panic(InvalidOpError{Op: "&^", V: l}) + } +} + +func (v val) Index(rhs Value) Value { + if v.t.Kind() == String { + index := promote(rhs, NewPrimitiveType(Int)).RawValue().(int) + return val{reflect.ValueOf(v.RawValue().(string)[index]), NewPrimitiveType(Uint8)} + } + switch t := v.t.(type) { + case *ArrayType: + return val{v.v.Index(promote(rhs, NewPrimitiveType(Int)).RawValue().(int)), t.Elem()} + case *SliceType: + return val{v.v.Index(promote(rhs, NewPrimitiveType(Int)).RawValue().(int)), t.Elem()} + case *MapType: + return val{v.v.MapIndex(promote(rhs, t.Key()).Value()), t.Value()} + default: + panic(InvalidOpError{Op: "[]", V: v}) + } +} + +func (v val) Call(in []Value) Value { + ft, ok := v.t.(*FuncType) + if !ok { + panic("Call invoked on non-function") + } + if len(in) != ft.NumIn() { + panic("invalid number of arguments to function") + } + inconv := []reflect.Value{} + for i, n := range in { + inconv = append(inconv, promote(n, ft.In(i)).Value()) + } + out := v.v.Call(inconv) + if len(out) != 1 { + panic("only functions returning 1 value are supported") + } + return val{out[0], ft.Out(0)} +} + +// ValueOf returns a Value for the given runtime value. +func ValueOf(i interface{}) Value { + return val{reflect.ValueOf(i), TypeOf(i)} +} + +func literalboolval(v bool) Value { + return val{reflect.ValueOf(v), NewLiteralType(UntypedBool)} +} + +func literalstrval(v string) Value { + return val{reflect.ValueOf(v), NewPrimitiveType(String)} +} + +func literalintval(v int64) Value { + return val{reflect.ValueOf(v), NewLiteralType(UntypedInt)} +} + +func literaluintval(v uint64) Value { + return val{reflect.ValueOf(v), NewLiteralType(UntypedInt)} +} + +func literalfloatval(v float64) Value { + return val{reflect.ValueOf(v), NewLiteralType(UntypedFloat)} +} + +func literalnilval() Value { + return val{reflect.ValueOf(interface{}(nil)), NewLiteralType(UntypedNil)} +} diff --git a/rune/vendor/github.com/go-restruct/restruct/expr_18.go b/rune/vendor/github.com/go-restruct/restruct/expr_18.go new file mode 100644 index 0000000000000000000000000000000000000000..d367734923a640c285759500aaf44617269f5982 --- /dev/null +++ b/rune/vendor/github.com/go-restruct/restruct/expr_18.go @@ -0,0 +1,9 @@ +// +build !go1.9 + +package restruct + +import ( + "github.com/go-restruct/restruct/expr" +) + +var exprStdLib = map[string]expr.Value{} diff --git a/rune/vendor/github.com/go-restruct/restruct/expr_19.go b/rune/vendor/github.com/go-restruct/restruct/expr_19.go new file mode 100644 index 0000000000000000000000000000000000000000..0d510e81d04b557844d65f8294fa93581da03beb --- /dev/null +++ b/rune/vendor/github.com/go-restruct/restruct/expr_19.go @@ -0,0 +1,54 @@ +// +build go1.9 + +package restruct + +import ( + "math/bits" + + "github.com/go-restruct/restruct/expr" +) + +var exprStdLib = map[string]expr.Value{ + "bits": expr.ValueOf(expr.NewPackage(map[string]expr.Value{ + "LeadingZeros": expr.ValueOf(bits.LeadingZeros), + "LeadingZeros8": expr.ValueOf(bits.LeadingZeros8), + "LeadingZeros16": expr.ValueOf(bits.LeadingZeros16), + "LeadingZeros32": expr.ValueOf(bits.LeadingZeros32), + "LeadingZeros64": expr.ValueOf(bits.LeadingZeros64), + + "Len": expr.ValueOf(bits.Len), + "Len8": expr.ValueOf(bits.Len8), + "Len16": expr.ValueOf(bits.Len16), + "Len32": expr.ValueOf(bits.Len32), + "Len64": expr.ValueOf(bits.Len64), + + "OnesCount": expr.ValueOf(bits.OnesCount), + "OnesCount8": expr.ValueOf(bits.OnesCount8), + "OnesCount16": expr.ValueOf(bits.OnesCount16), + "OnesCount32": expr.ValueOf(bits.OnesCount32), + "OnesCount64": expr.ValueOf(bits.OnesCount64), + + "Reverse": expr.ValueOf(bits.Reverse), + "Reverse8": expr.ValueOf(bits.Reverse8), + "Reverse16": expr.ValueOf(bits.Reverse16), + "Reverse32": expr.ValueOf(bits.Reverse32), + "Reverse64": expr.ValueOf(bits.Reverse64), + + "ReverseBytes": expr.ValueOf(bits.ReverseBytes), + "ReverseBytes16": expr.ValueOf(bits.ReverseBytes16), + "ReverseBytes32": expr.ValueOf(bits.ReverseBytes32), + "ReverseBytes64": expr.ValueOf(bits.ReverseBytes64), + + "RotateLeft": expr.ValueOf(bits.RotateLeft), + "RotateLeft8": expr.ValueOf(bits.RotateLeft8), + "RotateLeft16": expr.ValueOf(bits.RotateLeft16), + "RotateLeft32": expr.ValueOf(bits.RotateLeft32), + "RotateLeft64": expr.ValueOf(bits.RotateLeft64), + + "TrailingZeros": expr.ValueOf(bits.TrailingZeros), + "TrailingZeros8": expr.ValueOf(bits.TrailingZeros8), + "TrailingZeros16": expr.ValueOf(bits.TrailingZeros16), + "TrailingZeros32": expr.ValueOf(bits.TrailingZeros32), + "TrailingZeros64": expr.ValueOf(bits.TrailingZeros64), + })), +} diff --git a/rune/vendor/github.com/go-restruct/restruct/field.go b/rune/vendor/github.com/go-restruct/restruct/field.go new file mode 100644 index 0000000000000000000000000000000000000000..ad64761abf1c665184c9d9b46607c019114002ee --- /dev/null +++ b/rune/vendor/github.com/go-restruct/restruct/field.go @@ -0,0 +1,399 @@ +package restruct + +import ( + "encoding/binary" + "errors" + "fmt" + "reflect" + "sync" + + "github.com/go-restruct/restruct/expr" +) + +// ErrInvalidSize is returned when sizefrom is used on an invalid type. +var ErrInvalidSize = errors.New("size specified on fixed size type") + +// ErrInvalidSizeOf is returned when sizefrom is used on an invalid type. +var ErrInvalidSizeOf = errors.New("sizeof specified on fixed size type") + +// ErrInvalidSizeFrom is returned when sizefrom is used on an invalid type. +var ErrInvalidSizeFrom = errors.New("sizefrom specified on fixed size type") + +// ErrInvalidBits is returned when bits is used on an invalid type. +var ErrInvalidBits = errors.New("bits specified on non-bitwise type") + +// FieldFlags is a type for flags that can be applied to fields individually. +type FieldFlags uint64 + +const ( + // VariantBoolFlag causes the true value of a boolean to be ~0 instead of + // just 1 (all bits are set.) This emulates the behavior of VARIANT_BOOL. + VariantBoolFlag FieldFlags = 1 << iota + + // InvertedBoolFlag causes the true and false states of a boolean to be + // flipped in binary. + InvertedBoolFlag + + // RootFlag is set when the field points to the root struct. + RootFlag + + // ParentFlag is set when the field points to the parent struct. + ParentFlag + + // DefaultFlag is set when the field is designated as a switch case default. + DefaultFlag +) + +// Sizer is a type which has a defined size in binary. The SizeOf function +// returns how many bytes the type will consume in memory. This is used during +// encoding for allocation and therefore must equal the exact number of bytes +// the encoded form needs. You may use a pointer receiver even if the type is +// used by value. +type Sizer interface { + SizeOf() int +} + +// BitSizer is an interface for types that need to specify their own size in +// bit-level granularity. It has the same effect as Sizer. +type BitSizer interface { + BitSize() int +} + +// field represents a structure field, similar to reflect.StructField. +type field struct { + Name string + Index int + BinaryType reflect.Type + NativeType reflect.Type + Order binary.ByteOrder + SIndex int // Index of size field for a slice/string. + TIndex int // Index of target of sizeof field. + Skip int + Trivial bool + BitSize uint8 + Flags FieldFlags + IsRoot bool + IsParent bool + + IfExpr *expr.Program + SizeExpr *expr.Program + BitsExpr *expr.Program + InExpr *expr.Program + OutExpr *expr.Program + WhileExpr *expr.Program + SwitchExpr *expr.Program + CaseExpr *expr.Program +} + +// fields represents a structure. +type fields []field + +var fieldCache = map[reflect.Type][]field{} +var cacheMutex = sync.RWMutex{} + +// Elem constructs a transient field representing an element of an array, slice, +// or pointer. +func (f *field) Elem() field { + // Special cases for string types, grumble grumble. + t := f.BinaryType + if t.Kind() == reflect.String { + t = reflect.TypeOf([]byte{}) + } + + dt := f.NativeType + if dt.Kind() == reflect.String { + dt = reflect.TypeOf([]byte{}) + } + + return field{ + Name: "*" + f.Name, + Index: -1, + BinaryType: t.Elem(), + NativeType: dt.Elem(), + Order: f.Order, + TIndex: -1, + SIndex: -1, + Skip: 0, + Trivial: isTypeTrivial(t.Elem()), + } +} + +// fieldFromType returns a field from a reflected type. +func fieldFromType(typ reflect.Type) field { + return field{ + Index: -1, + BinaryType: typ, + NativeType: typ, + Order: nil, + TIndex: -1, + SIndex: -1, + Skip: 0, + Trivial: isTypeTrivial(typ), + } +} + +func validBitType(typ reflect.Type) bool { + switch typ.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, + reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, + reflect.Uint32, reflect.Uint64, reflect.Float32, + reflect.Complex64, reflect.Complex128: + return true + default: + return false + } +} + +func validSizeType(typ reflect.Type) bool { + switch typ.Kind() { + case reflect.Slice, reflect.String: + return true + default: + return false + } +} + +func parseExpr(sources ...string) *expr.Program { + for _, s := range sources { + if s != "" { + return expr.ParseString(s) + } + } + return nil +} + +// fieldsFromStruct returns a slice of fields for binary packing and unpacking. +func fieldsFromStruct(typ reflect.Type) (result fields) { + if typ.Kind() != reflect.Struct { + panic(fmt.Errorf("tried to get fields from non-struct type %s", typ.Kind().String())) + } + + count := typ.NumField() + + sizeOfMap := map[string]int{} + + for i := 0; i < count; i++ { + val := typ.Field(i) + + // Skip unexported names (except _) + if val.PkgPath != "" && val.Name != "_" { + continue + } + + // Parse struct tag + opts := mustParseTag(val.Tag.Get("struct")) + if opts.Ignore { + continue + } + + if opts.RootFlag { + result = append(result, field{ + Name: val.Name, + Index: i, + Flags: RootFlag, + }) + continue + } + + if opts.ParentFlag { + result = append(result, field{ + Name: val.Name, + Index: i, + Flags: ParentFlag, + }) + continue + } + + // Derive type + ftyp := val.Type + if opts.Type != nil { + ftyp = opts.Type + } + + // SizeOf + sindex := -1 + tindex := -1 + if j, ok := sizeOfMap[val.Name]; ok { + if !validSizeType(val.Type) { + panic(ErrInvalidSizeOf) + } + sindex = j + result[sindex].TIndex = i + delete(sizeOfMap, val.Name) + } else if opts.SizeOf != "" { + sizeOfMap[opts.SizeOf] = i + } + + // SizeFrom + if opts.SizeFrom != "" { + if !validSizeType(val.Type) { + panic(ErrInvalidSizeFrom) + } + for j := 0; j < i; j++ { + val := result[j] + if opts.SizeFrom == val.Name { + sindex = j + result[sindex].TIndex = i + } + } + if sindex == -1 { + panic(fmt.Errorf("couldn't find SizeFrom field %s", opts.SizeFrom)) + } + } + + // Expr + ifExpr := parseExpr(opts.IfExpr, val.Tag.Get("struct-if")) + sizeExpr := parseExpr(opts.SizeExpr, val.Tag.Get("struct-size")) + bitsExpr := parseExpr(opts.BitsExpr, val.Tag.Get("struct-bits")) + inExpr := parseExpr(opts.InExpr, val.Tag.Get("struct-in")) + outExpr := parseExpr(opts.OutExpr, val.Tag.Get("struct-out")) + whileExpr := parseExpr(opts.WhileExpr, val.Tag.Get("struct-while")) + switchExpr := parseExpr(opts.SwitchExpr, val.Tag.Get("struct-switch")) + caseExpr := parseExpr(opts.CaseExpr, val.Tag.Get("struct-case")) + if sizeExpr != nil && !validSizeType(val.Type) { + panic(ErrInvalidSize) + } + if bitsExpr != nil && !validBitType(ftyp) { + panic(ErrInvalidBits) + } + + // Flags + flags := FieldFlags(0) + if opts.VariantBoolFlag { + flags |= VariantBoolFlag + } + if opts.InvertedBoolFlag { + flags |= InvertedBoolFlag + } + if opts.DefaultFlag { + flags |= DefaultFlag + } + + result = append(result, field{ + Name: val.Name, + Index: i, + BinaryType: ftyp, + NativeType: val.Type, + Order: opts.Order, + SIndex: sindex, + TIndex: tindex, + Skip: opts.Skip, + Trivial: isTypeTrivial(ftyp), + BitSize: opts.BitSize, + Flags: flags, + IfExpr: ifExpr, + SizeExpr: sizeExpr, + BitsExpr: bitsExpr, + InExpr: inExpr, + OutExpr: outExpr, + WhileExpr: whileExpr, + SwitchExpr: switchExpr, + CaseExpr: caseExpr, + }) + } + + for fieldName := range sizeOfMap { + panic(fmt.Errorf("couldn't find SizeOf field %s", fieldName)) + } + + return +} + +func cachedFieldsFromStruct(typ reflect.Type) (result fields) { + cacheMutex.RLock() + result, ok := fieldCache[typ] + cacheMutex.RUnlock() + + if ok { + return + } + + result = fieldsFromStruct(typ) + + cacheMutex.Lock() + fieldCache[typ] = result + cacheMutex.Unlock() + + return +} + +// isTypeTrivial determines if a given type is constant-size. +func isTypeTrivial(typ reflect.Type) bool { + if typ == nil { + return false + } + switch typ.Kind() { + case reflect.Bool, + reflect.Int, + reflect.Int8, + reflect.Int16, + reflect.Int32, + reflect.Int64, + reflect.Uint, + reflect.Uint8, + reflect.Uint16, + reflect.Uint32, + reflect.Uint64, + reflect.Uintptr, + reflect.Float32, + reflect.Float64, + reflect.Complex64, + reflect.Complex128: + return true + case reflect.Array, reflect.Ptr: + return isTypeTrivial(typ.Elem()) + case reflect.Struct: + for _, field := range cachedFieldsFromStruct(typ) { + if !isTypeTrivial(field.BinaryType) { + return false + } + } + return true + default: + return false + } +} + +func (f *field) sizer(v reflect.Value) (Sizer, bool) { + if s, ok := v.Interface().(Sizer); ok { + return s, true + } + + if !v.CanAddr() { + return nil, false + } + + if s, ok := v.Addr().Interface().(Sizer); ok { + return s, true + } + + return nil, false +} + +func (f *field) bitSizer(v reflect.Value) (BitSizer, bool) { + if s, ok := v.Interface().(BitSizer); ok { + return s, true + } + + if !v.CanAddr() { + return nil, false + } + + if s, ok := v.Addr().Interface().(BitSizer); ok { + return s, true + } + + return nil, false +} + +func (f *field) bitSizeUsingInterface(val reflect.Value) (int, bool) { + if s, ok := f.bitSizer(val); ok { + return s.BitSize(), true + } + + if s, ok := f.sizer(val); ok { + return s.SizeOf() * 8, true + } + + return 0, false +} diff --git a/rune/vendor/github.com/go-restruct/restruct/go.mod b/rune/vendor/github.com/go-restruct/restruct/go.mod new file mode 100644 index 0000000000000000000000000000000000000000..d11e1c276728cd68f044cadb9b1dad12d01e9ec2 --- /dev/null +++ b/rune/vendor/github.com/go-restruct/restruct/go.mod @@ -0,0 +1,8 @@ +module github.com/go-restruct/restruct + +go 1.12 + +require ( + github.com/pkg/errors v0.8.1 + github.com/stretchr/testify v1.4.0 +) diff --git a/rune/vendor/github.com/go-restruct/restruct/go.sum b/rune/vendor/github.com/go-restruct/restruct/go.sum new file mode 100644 index 0000000000000000000000000000000000000000..6d94a7b3223cf6d217205726f30282b95330be62 --- /dev/null +++ b/rune/vendor/github.com/go-restruct/restruct/go.sum @@ -0,0 +1,12 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/rune/vendor/github.com/go-restruct/restruct/packing.go b/rune/vendor/github.com/go-restruct/restruct/packing.go new file mode 100644 index 0000000000000000000000000000000000000000..a54025ded581a4e9d0447315baf3205f40bce114 --- /dev/null +++ b/rune/vendor/github.com/go-restruct/restruct/packing.go @@ -0,0 +1,162 @@ +/* +Package restruct implements packing and unpacking of raw binary formats. + +Structures can be created with struct tags annotating the on-disk or in-memory +layout of the structure, using the "struct" struct tag, like so: + + struct { + Length int `struct:"int32,sizeof=Packets"` + Packets []struct{ + Source string `struct:"[16]byte"` + Timestamp int `struct:"int32,big"` + Data [256]byte `struct:"skip=8"` + } + } + +To unpack data in memory to this structure, simply use Unpack with a byte slice: + + msg := Message{} + restruct.Unpack(data, binary.LittleEndian, &msg) +*/ +package restruct + +import ( + "encoding/binary" + "reflect" +) + +func fieldFromIntf(v interface{}) (field, reflect.Value) { + val := reflect.ValueOf(v) + if val.Kind() == reflect.Ptr { + val = val.Elem() + } + f := fieldFromType(val.Type()) + return f, val +} + +/* +Unpack reads data from a byteslice into a value. + +Two types of values are directly supported here: Unpackers and structs. You can +pass them by value or by pointer, although it is an error if Restruct is +unable to set a value because it is unaddressable. + +For structs, each field will be read sequentially based on a straightforward +interpretation of the type. For example, an int32 will be read as a 32-bit +signed integer, taking 4 bytes of memory. Structures and arrays are laid out +flat with no padding or metadata. + +Unexported fields are ignored, except for fields named _ - those fields will +be treated purely as padding. Padding will not be preserved through packing +and unpacking. + +The behavior of deserialization can be customized using struct tags. The +following struct tag syntax is supported: + + `struct:"[flags...]"` + +Flags are comma-separated keys. The following are available: + + type A bare type name, e.g. int32 or []string. For integer + types, it is possible to specify the number of bits, + allowing the definition of bitfields, by appending a + colon followed by the number of bits. For example, + uint32:20 would specify a field that is 20 bits long. + + sizeof=[Field] Specifies that the field should be treated as a count of + the number of elements in Field. + + sizefrom=[Field] Specifies that the field should determine the number of + elements in itself by reading the counter in Field. + + skip=[Count] Skips Count bytes before the field. You can use this to + e.g. emulate C structure alignment. + + big,msb Specifies big endian byte order. When applied to + structs, this will apply to all fields under the struct. + + little,lsb Specifies little endian byte order. When applied to + structs, this will apply to all fields under the struct. + + variantbool Specifies that the boolean `true` value should be + encoded as -1 instead of 1. + + invertedbool Specifies that the `true` and `false` encodings for + boolean should be swapped. +*/ +func Unpack(data []byte, order binary.ByteOrder, v interface{}) (err error) { + defer func() { + if r := recover(); r != nil { + var ok bool + if err, ok = r.(error); !ok { + panic(err) + } + } + }() + + f, val := fieldFromIntf(v) + ss := structstack{allowexpr: expressionsEnabled, buf: data} + d := decoder{structstack: ss, order: order} + d.read(f, val) + + return +} + +/* +SizeOf returns the binary encoded size of the given value, in bytes. +*/ +func SizeOf(v interface{}) (size int, err error) { + defer func() { + if r := recover(); r != nil { + err = r.(error) + } + }() + + ss := structstack{allowexpr: expressionsEnabled} + f, val := fieldFromIntf(v) + return ss.fieldbytes(f, val), nil +} + +/* +BitSize returns the binary encoded size of the given value, in bits. +*/ +func BitSize(v interface{}) (size int, err error) { + defer func() { + if r := recover(); r != nil { + err = r.(error) + } + }() + + ss := structstack{allowexpr: expressionsEnabled} + f, val := fieldFromIntf(v) + return ss.fieldbits(f, val), nil +} + +/* +Pack writes data from a datastructure into a byteslice. + +Two types of values are directly supported here: Packers and structs. You can +pass them by value or by pointer. + +Each structure is serialized in the same way it would be deserialized with +Unpack. See Unpack documentation for the struct tag format. +*/ +func Pack(order binary.ByteOrder, v interface{}) (data []byte, err error) { + defer func() { + if r := recover(); r != nil { + data = nil + err = r.(error) + } + }() + + ss := structstack{allowexpr: expressionsEnabled, buf: []byte{}} + + f, val := fieldFromIntf(v) + data = make([]byte, ss.fieldbytes(f, val)) + + ss.buf = data + e := encoder{structstack: ss, order: order} + e.write(f, val) + + return +} diff --git a/rune/vendor/github.com/go-restruct/restruct/structstack.go b/rune/vendor/github.com/go-restruct/restruct/structstack.go new file mode 100644 index 0000000000000000000000000000000000000000..6e056a53a1f443bb1e0c19cf3977f06f2ac7df10 --- /dev/null +++ b/rune/vendor/github.com/go-restruct/restruct/structstack.go @@ -0,0 +1,286 @@ +package restruct + +import ( + "fmt" + "reflect" + + "github.com/go-restruct/restruct/expr" +) + +type switchcase struct { + f field + v reflect.Value +} + +type structstack struct { + buf []byte + stack []reflect.Value + allowexpr bool +} + +func (s *structstack) Resolve(ident string) expr.Value { + switch ident { + case "_eof": + return expr.ValueOf(len(s.buf) == 0) + default: + if t := stdLibResolver.Resolve(ident); t != nil { + return t + } + if len(s.stack) > 0 { + if sv := s.stack[len(s.stack)-1].FieldByName(ident); sv.IsValid() { + return expr.ValueOf(sv.Interface()) + } + } + return nil + } +} + +func (s *structstack) evalBits(f field) int { + bits := 0 + if f.BitSize != 0 { + bits = int(f.BitSize) + } + if f.BitsExpr != nil { + bits = reflect.ValueOf(s.evalExpr(f.BitsExpr)).Convert(reflect.TypeOf(int(0))).Interface().(int) + } + return bits +} + +func (s *structstack) evalSize(f field) int { + size := 0 + if f.SizeExpr != nil { + size = reflect.ValueOf(s.evalExpr(f.SizeExpr)).Convert(reflect.TypeOf(int(0))).Interface().(int) + } + return size +} + +func (s *structstack) evalIf(f field) bool { + if f.IfExpr == nil { + return true + } + if b, ok := s.evalExpr(f.IfExpr).(bool); ok { + return b + } + panic("expected bool value for if expr") +} + +func (s *structstack) evalWhile(f field) bool { + if b, ok := s.evalExpr(f.WhileExpr).(bool); ok { + return b + } + panic("expected bool value for while expr") +} + +func (s *structstack) switcbits(f field, v reflect.Value, on interface{}) (size int) { + var def *switchcase + + if v.Kind() != reflect.Struct { + panic(fmt.Errorf("%s: only switches on structs are valid", f.Name)) + } + + sfields := cachedFieldsFromStruct(f.BinaryType) + l := len(sfields) + + for i := 0; i < l; i++ { + f := sfields[i] + v := v.Field(f.Index) + + if f.Flags&DefaultFlag != 0 { + if def != nil { + panic(fmt.Errorf("%s: only one default case is allowed", f.Name)) + } + def = &switchcase{f, v} + continue + } + + if f.CaseExpr == nil { + panic(fmt.Errorf("%s: only cases are valid inside switches", f.Name)) + } + + if s.evalExpr(f.CaseExpr) == on { + return s.fieldbits(f, v) + } + } + + if def != nil { + return s.fieldbits(def.f, def.v) + } + + return 0 +} + +// fieldbits determines the encoded size of a field in bits. +func (s *structstack) fieldbits(f field, val reflect.Value) (size int) { + skipBits := f.Skip * 8 + + if f.Flags&RootFlag == RootFlag { + s.setancestor(f, val, s.root()) + return 0 + } + + if f.Flags&ParentFlag == ParentFlag { + for i := 1; i < len(s.stack); i++ { + if s.setancestor(f, val, s.ancestor(i)) { + break + } + } + return 0 + } + + if f.SwitchExpr != nil { + return s.switcbits(f, val, s.evalExpr(f.SwitchExpr)) + } + + if f.Name != "_" { + if s, ok := f.bitSizeUsingInterface(val); ok { + return s + } + } else { + // Non-trivial, unnamed fields do not make sense. You can't set a field + // with no name, so the elements can't possibly differ. + // N.B.: Though skip will still work, use struct{} instead for skip. + if !isTypeTrivial(val.Type()) { + return skipBits + } + } + + if !s.evalIf(f) { + return 0 + } + + if b := s.evalBits(f); b != 0 { + return b + } + + alen := 1 + switch f.BinaryType.Kind() { + case reflect.Int8, reflect.Uint8, reflect.Bool: + return 8 + skipBits + case reflect.Int16, reflect.Uint16: + return 16 + skipBits + case reflect.Int, reflect.Int32, + reflect.Uint, reflect.Uint32, + reflect.Float32: + return 32 + skipBits + case reflect.Int64, reflect.Uint64, + reflect.Float64, reflect.Complex64: + return 64 + skipBits + case reflect.Complex128: + return 128 + skipBits + case reflect.Slice, reflect.String: + switch f.NativeType.Kind() { + case reflect.Slice, reflect.String, reflect.Array, reflect.Ptr: + alen = val.Len() + default: + return 0 + } + fallthrough + case reflect.Array, reflect.Ptr: + size += skipBits + + // If array type, get length from type. + if f.BinaryType.Kind() == reflect.Array { + alen = f.BinaryType.Len() + } + + // Optimization: if the array/slice is empty, bail now. + if alen == 0 { + return size + } + + switch f.NativeType.Kind() { + case reflect.Ptr: + return s.fieldbits(f.Elem(), val.Elem()) + case reflect.Slice, reflect.String, reflect.Array: + // Optimization: if the element type is trivial, we can derive the + // length from a single element. + elem := f.Elem() + if elem.Trivial { + size += s.fieldbits(elem, reflect.Zero(elem.BinaryType)) * alen + } else { + for i := 0; i < alen; i++ { + size += s.fieldbits(elem, val.Index(i)) + } + } + } + return size + case reflect.Struct: + size += skipBits + s.push(val) + for _, field := range cachedFieldsFromStruct(f.BinaryType) { + if field.BitSize != 0 { + size += int(field.BitSize) + } else { + size += s.fieldbits(field, val.Field(field.Index)) + } + } + s.pop(val) + return size + default: + return 0 + } +} + +// fieldbytes returns the effective size in bytes, for the few cases where +// byte sizes are needed. +func (s *structstack) fieldbytes(f field, val reflect.Value) (size int) { + return (s.fieldbits(f, val) + 7) / 8 +} + +func (s *structstack) fieldsbits(fields fields, val reflect.Value) (size int) { + for _, field := range fields { + size += s.fieldbits(field, val.Field(field.Index)) + } + return +} + +func (s *structstack) evalExpr(program *expr.Program) interface{} { + if !s.allowexpr { + panic("call restruct.EnableExprBeta() to eanble expressions beta") + } + v, err := expr.EvalProgram(s, program) + if err != nil { + panic(err) + } + return v +} + +func (s *structstack) push(v reflect.Value) { + s.stack = append(s.stack, v) +} + +func (s *structstack) pop(v reflect.Value) { + var p reflect.Value + s.stack, p = s.stack[:len(s.stack)-1], s.stack[len(s.stack)-1] + if p != v { + panic("struct stack misaligned") + } +} + +func (s *structstack) setancestor(f field, v reflect.Value, ancestor reflect.Value) bool { + if ancestor.Kind() != reflect.Ptr { + if !ancestor.CanAddr() { + return false + } + ancestor = ancestor.Addr() + } + if ancestor.Type().AssignableTo(v.Type()) { + v.Set(ancestor) + return true + } + return false +} + +func (s *structstack) root() reflect.Value { + if len(s.stack) > 0 { + return s.stack[0] + } + return reflect.ValueOf(nil) +} + +func (s *structstack) ancestor(generation int) reflect.Value { + if len(s.stack) > generation { + return s.stack[len(s.stack)-generation-1] + } + return reflect.ValueOf(nil) +} diff --git a/rune/vendor/github.com/go-restruct/restruct/tag.go b/rune/vendor/github.com/go-restruct/restruct/tag.go new file mode 100644 index 0000000000000000000000000000000000000000..92ee33b4ca78aa5f32babcfcab480ed04a8007c5 --- /dev/null +++ b/rune/vendor/github.com/go-restruct/restruct/tag.go @@ -0,0 +1,290 @@ +package restruct + +import ( + "encoding/binary" + "errors" + "fmt" + "reflect" + "strconv" + "strings" + "unicode" + "unicode/utf8" +) + +func lower(ch rune) rune { + return ('a' - 'A') | ch +} + +func isdecimal(ch rune) bool { + return '0' <= ch && ch <= '9' +} + +func ishex(ch rune) bool { + return '0' <= ch && ch <= '9' || 'a' <= lower(ch) && lower(ch) <= 'f' +} + +func isletter(c rune) bool { + return 'a' <= lower(c) && lower(c) <= 'z' || c == '_' || c >= utf8.RuneSelf && unicode.IsLetter(c) +} + +func isdigit(c rune) bool { + return isdecimal(c) +} + +func isident(c rune) bool { + return isletter(c) || isdigit(c) +} + +func isint(c rune) bool { + return isdigit(c) || ishex(c) || lower(c) == 'x' +} + +// tagOptions represents a parsed struct tag. +type tagOptions struct { + Ignore bool + Type reflect.Type + SizeOf string + SizeFrom string + Skip int + Order binary.ByteOrder + BitSize uint8 + VariantBoolFlag bool + InvertedBoolFlag bool + RootFlag bool + ParentFlag bool + DefaultFlag bool + + IfExpr string + SizeExpr string + BitsExpr string + InExpr string + OutExpr string + WhileExpr string + SwitchExpr string + CaseExpr string +} + +func (opts *tagOptions) parse(tag string) error { + // Empty tag + if len(tag) == 0 { + return nil + } else if tag == "-" { + opts.Ignore = true + return nil + } + + tag += "\x00" + + accept := func(v string) bool { + if strings.HasPrefix(tag, v) { + tag = tag[len(v):] + return true + } + return false + } + + acceptIdent := func() (string, error) { + var ( + i int + r rune + ) + for i, r = range tag { + if r == ',' || r == 0 { + break + } + if i == 0 && !isletter(r) || !isident(r) { + return "", fmt.Errorf("invalid identifier character %c", r) + } + } + result := tag[:i] + tag = tag[i:] + return result, nil + } + + acceptInt := func() (int, error) { + var ( + i int + r rune + ) + for i, r = range tag { + if r == ',' || r == 0 { + break + } + if !isint(r) { + return 0, fmt.Errorf("invalid integer character %c", r) + } + } + result := tag[:i] + tag = tag[i:] + d, err := strconv.ParseInt(result, 0, 64) + return int(d), err + } + + acceptExpr := func() (string, error) { + stack := []byte{0} + + current := func() byte { return stack[len(stack)-1] } + push := func(r byte) { stack = append(stack, r) } + pop := func() { stack = stack[:len(stack)-1] } + + var i int + expr: + for i = 0; i < len(tag); i++ { + switch tag[i] { + case ',': + if len(stack) == 1 { + break expr + } + case '(': + push(')') + case '[': + push(']') + case '{': + push('}') + case '"', '\'': + term := tag[i] + i++ + lit: + for { + if i >= len(tag) { + return "", errors.New("unexpected eof in literal") + } + switch tag[i] { + case term: + break lit + case '\\': + i++ + } + i++ + } + case current(): + pop() + if len(stack) == 0 { + break expr + } + default: + if tag[i] == 0 { + return "", errors.New("unexpected eof in expr") + } + } + } + result := tag[:i] + tag = tag[i:] + return result, nil + } + + var err error + for { + switch { + case accept("lsb"), accept("little"): + opts.Order = binary.LittleEndian + case accept("msb"), accept("big"), accept("network"): + opts.Order = binary.BigEndian + case accept("variantbool"): + opts.VariantBoolFlag = true + case accept("invertedbool"): + opts.InvertedBoolFlag = true + case accept("root"): + opts.RootFlag = true + case accept("parent"): + opts.ParentFlag = true + case accept("default"): + opts.DefaultFlag = true + case accept("sizeof="): + if opts.SizeOf, err = acceptIdent(); err != nil { + return fmt.Errorf("sizeof: %v", err) + } + case accept("sizefrom="): + if opts.SizeFrom, err = acceptIdent(); err != nil { + return fmt.Errorf("sizefrom: %v", err) + } + case accept("skip="): + if opts.Skip, err = acceptInt(); err != nil { + return fmt.Errorf("skip: %v", err) + } + case accept("if="): + if opts.IfExpr, err = acceptExpr(); err != nil { + return fmt.Errorf("if: %v", err) + } + case accept("size="): + if opts.SizeExpr, err = acceptExpr(); err != nil { + return fmt.Errorf("size: %v", err) + } + case accept("bits="): + if opts.BitsExpr, err = acceptExpr(); err != nil { + return fmt.Errorf("bits: %v", err) + } + case accept("in="): + if opts.InExpr, err = acceptExpr(); err != nil { + return fmt.Errorf("in: %v", err) + } + case accept("out="): + if opts.OutExpr, err = acceptExpr(); err != nil { + return fmt.Errorf("out: %v", err) + } + case accept("while="): + if opts.WhileExpr, err = acceptExpr(); err != nil { + return fmt.Errorf("while: %v", err) + } + case accept("switch="): + if opts.SwitchExpr, err = acceptExpr(); err != nil { + return fmt.Errorf("switch: %v", err) + } + case accept("case="): + if opts.CaseExpr, err = acceptExpr(); err != nil { + return fmt.Errorf("case: %v", err) + } + case accept("-"): + return errors.New("extra options on ignored field") + default: + typeexpr, err := acceptExpr() + if err != nil { + return fmt.Errorf("struct type: %v", err) + } + parts := strings.SplitN(typeexpr, ":", 2) + opts.Type, err = parseType(parts[0]) + if err != nil { + return fmt.Errorf("struct type: %v", err) + } + if len(parts) < 2 { + break + } + if !validBitType(opts.Type) { + return fmt.Errorf("struct type bits specified on non-bitwise type %s", opts.Type) + } + bits, err := strconv.ParseUint(parts[1], 0, 8) + if err != nil { + return errors.New("struct type bits: invalid integer syntax") + } + opts.BitSize = uint8(bits) + if opts.BitSize >= uint8(opts.Type.Bits()) || opts.BitSize == 0 { + return fmt.Errorf("bit size %d out of range (%d to %d)", opts.BitSize, 1, opts.Type.Bits()-1) + } + } + if accept("\x00") { + return nil + } + if !accept(",") { + return errors.New("tag: expected comma") + } + } +} + +// mustParseTag calls ParseTag but panics if there is an error, to help make +// sure programming errors surface quickly. +func mustParseTag(tag string) tagOptions { + opt, err := parseTag(tag) + if err != nil { + panic(err) + } + return opt +} + +// parseTag parses a struct tag into a TagOptions structure. +func parseTag(tag string) (tagOptions, error) { + opts := tagOptions{} + if err := opts.parse(tag); err != nil { + return tagOptions{}, err + } + return opts, nil +} diff --git a/rune/vendor/github.com/go-restruct/restruct/typestr.go b/rune/vendor/github.com/go-restruct/restruct/typestr.go new file mode 100644 index 0000000000000000000000000000000000000000..4dcc3a146bdd2e55e8943d50692255a0eaa2be01 --- /dev/null +++ b/rune/vendor/github.com/go-restruct/restruct/typestr.go @@ -0,0 +1,107 @@ +package restruct + +import ( + "fmt" + "go/ast" + "go/parser" + "go/token" + "reflect" + "strconv" + + "github.com/pkg/errors" +) + +// typeMap maps identifiers to reflect.Types. +var typeMap = map[string]reflect.Type{ + "bool": reflect.TypeOf(bool(false)), + + "uint8": reflect.TypeOf(uint8(0)), + "uint16": reflect.TypeOf(uint16(0)), + "uint32": reflect.TypeOf(uint32(0)), + "uint64": reflect.TypeOf(uint64(0)), + + "int8": reflect.TypeOf(int8(0)), + "int16": reflect.TypeOf(int16(0)), + "int32": reflect.TypeOf(int32(0)), + "int64": reflect.TypeOf(int64(0)), + + "float32": reflect.TypeOf(float32(0)), + "float64": reflect.TypeOf(float64(0)), + + "complex64": reflect.TypeOf(complex64(0)), + "complex128": reflect.TypeOf(complex128(0)), + + "byte": reflect.TypeOf(uint8(0)), + "rune": reflect.TypeOf(int32(0)), + + "uint": reflect.TypeOf(uint(0)), + "int": reflect.TypeOf(int(0)), + "uintptr": reflect.TypeOf(uintptr(0)), + "string": reflect.SliceOf(reflect.TypeOf(uint8(0))), +} + +// typeOfExpr gets a type corresponding to an expression. +func typeOfExpr(expr ast.Expr) (reflect.Type, error) { + switch expr := expr.(type) { + default: + return nil, fmt.Errorf("unexpected expression: %T", expr) + case *ast.ArrayType: + switch expr.Len { + case ast.Expr(nil): + // Slice + sub, err := typeOfExpr(expr.Elt) + if err != nil { + return nil, err + } + return reflect.SliceOf(sub), nil + default: + // Parse length expression + lexpr, ok := expr.Len.(*ast.BasicLit) + if !ok { + return nil, fmt.Errorf("invalid array size expression") + } + if lexpr.Kind != token.INT { + return nil, fmt.Errorf("invalid array size type") + } + len, err := strconv.Atoi(lexpr.Value) + if err != nil { + return nil, err + } + + // Parse elem type expression + sub, err := typeOfExpr(expr.Elt) + if err != nil { + return nil, err + } + return reflect.ArrayOf(len, sub), nil + } + case *ast.Ident: + // Primitive types + typ, ok := typeMap[expr.Name] + if !ok { + return nil, fmt.Errorf("unknown type %s", expr.Name) + } + return typ, nil + case *ast.StarExpr: + // Pointer + sub, err := typeOfExpr(expr.X) + if err != nil { + return nil, err + } + return reflect.PtrTo(sub), nil + case *ast.ChanType: + return nil, fmt.Errorf("channel type not allowed") + case *ast.MapType: + return nil, fmt.Errorf("map type not allowed") + } +} + +// parseType parses a Golang type string and returns a reflect.Type. +func parseType(typ string) (reflect.Type, error) { + expr, err := parser.ParseExpr(typ) + if err != nil { + return nil, errors.Wrap(err, "parsing error") + } + + return typeOfExpr(expr) +} diff --git a/rune/vendor/modules.txt b/rune/vendor/modules.txt index 2f70f7aede37cdd3e92eba049c9aec8d3e6b8142..0edf052cabfe1f1c9659d6810d1733fcdff8450c 100644 --- a/rune/vendor/modules.txt +++ b/rune/vendor/modules.txt @@ -23,6 +23,10 @@ github.com/cyphar/filepath-securejoin # github.com/docker/go-units v0.4.0 ## explicit github.com/docker/go-units +# github.com/go-restruct/restruct v0.0.0-20191227155143-5734170a48a1 +## explicit +github.com/go-restruct/restruct +github.com/go-restruct/restruct/expr # github.com/godbus/dbus/v5 v5.0.3 ## explicit github.com/godbus/dbus/v5 diff --git a/runectl/gen-token.go b/runectl/gen-token.go index b3b7a9fd23bb855d886e196251fec592999d4e9a..8c874c5244043d7ae88217b16b888327429821b2 100644 --- a/runectl/gen-token.go +++ b/runectl/gen-token.go @@ -1,28 +1,17 @@ package main // import "github.com/inclavare-containers/runectl" import ( - "bytes" - "encoding/binary" - "encoding/hex" "fmt" - "github.com/go-restruct/restruct" - "github.com/golang/protobuf/proto" - pb "github.com/inclavare-containers/runectl/proto" "github.com/opencontainers/runc/libenclave/intelsgx" + "github.com/sirupsen/logrus" "github.com/urfave/cli" "io" "io/ioutil" - "log" - "net" "os" "path/filepath" "strings" ) -const ( - aesmd_socket = "/var/run/aesmd/aesm.socket" -) - var generateTokenCommand = cli.Command{ Name: "gen-token", Usage: "retrieve a token from aesmd", @@ -67,169 +56,21 @@ For example, generate the token file according to the given signature file: return fmt.Errorf("signature file %s not match SIGSTRUCT", sigPath) } - buf := make([]byte, intelsgx.SigStructLength) - if _, err = io.ReadFull(sf, buf); err != nil { - return fmt.Errorf("signature file %s read failed", sigPath) - } - - sig := &intelsgx.SigStruct{} - if err := restruct.Unpack(buf, binary.LittleEndian, &sig); err != nil { - log.Println(err) - return err - } - - mrenclave := sig.EnclaveHash[:] - modulus := sig.Modulus[:] - attributes := sig.Attributes[:] - if context.GlobalBool("verbose") { - fmt.Println("SIGSTRUCT:") - _ = sig.Header[:] - fmt.Printf(" Enclave Vendor: %#08x\n", - sig.Vendor) - fmt.Printf(" Enclave Build Date: %d-%d-%d\n", - sig.BuildYear, sig.BuildMonth, sig.BuildDay) - fmt.Printf(" Software Defined: %#08x\n", - sig.SwDefined) - fmt.Printf(" ISV assigned Product Family ID: 0x%v\n", - hex.EncodeToString(sig.ISVFamilyId[:])) - fmt.Printf(" ISV assigned Produdct ID: %#04x\n", - sig.ISVProdId) - fmt.Printf(" ISV assigned Extended Product ID: 0x%v\n", - hex.EncodeToString(sig.ISVExtProdId[:])) - fmt.Printf(" ISV assigned SVN: %d\n", sig.ISVSvn) - fmt.Printf(" Enclave Attributes: 0x%v\n", - hex.EncodeToString(attributes)) - fmt.Printf(" Enclave Attributes Mask: 0x%v\n", - hex.EncodeToString(sig.AttributesMask[:])) - fmt.Printf(" Enclave Misc Select: %#08x\n", - sig.MiscSelect) - fmt.Printf(" Enclave Misc Mask: %#08x\n", - sig.MiscMask) - fmt.Printf(" Enclave Hash: 0x%v\n", - hex.EncodeToString(mrenclave)) - fmt.Printf(" Modulus: 0x%v...\n", - hex.EncodeToString(modulus[:32])) - fmt.Printf(" Exponent: %d\n", - sig.Exponent) - fmt.Printf(" Signature: 0x%v...\n", - hex.EncodeToString(sig.Signature[:32])) - fmt.Printf(" Q1: 0x%v...\n", - hex.EncodeToString(sig.Q1[:32])) - fmt.Printf(" Q2: 0x%v...\n", - hex.EncodeToString(sig.Q2[:32])) - } - - var raddr *net.UnixAddr - raddr, err = net.ResolveUnixAddr("unix", aesmd_socket) - if err != nil { - return err - } - - var conn *net.UnixConn - conn, err = net.DialUnix("unix", nil, raddr) - if err != nil { - return err - } - - defer conn.Close() - - req := pb.GetTokenRequestMessage{} - req.Req = &pb.GetTokenRequest{ - Enclavehash: mrenclave, - Modulus: modulus, - Attributes: attributes, - Timeout: 10000, - } - - var rdata []byte - rdata, err = proto.Marshal(&req) - if err != nil { - return err - } - - msgSize := uint32(len(rdata)) - byteBuf := bytes.NewBuffer([]byte{}) - binary.Write(byteBuf, binary.LittleEndian, &msgSize) - if _, err = conn.Write(byteBuf.Bytes()); err != nil { - return err - } - - if _, err = conn.Write(rdata); err != nil { - return err - } - - rdata = append(rdata[:4]) - if _, err = conn.Read(rdata); err != nil { - return err + logrus.SetLevel(logrus.DebugLevel) } - byteBuf = bytes.NewBuffer(rdata) - if err = binary.Read(byteBuf, binary.LittleEndian, &msgSize); err != nil { - return err + buf := make([]byte, intelsgx.SigStructLength) + if _, err = io.ReadFull(sf, buf); err != nil { + return fmt.Errorf("signature file %s read failed", sigPath) } - rdata = make([]byte, msgSize) - var msgSizeRead int - msgSizeRead, err = conn.Read(rdata) + tok, err := intelsgx.GetToken(buf) if err != nil { + logrus.Print(err) return err } - if msgSizeRead != int(msgSize) { - return fmt.Errorf("invalid response size (returned %d, expected %d)", - msgSizeRead, msgSize) - } - - resp := pb.GetTokenResponseMessage{} - resp.Resp = &pb.GetTokenResponse{} - if err := proto.Unmarshal(rdata, &resp); err != nil { - return err - } - - if resp.Resp.GetError() != 0 { - return fmt.Errorf("failed to get EINITTOKEN (error code = %d)", - resp.Resp.GetError()) - } - - token := resp.Resp.GetToken() - if len(token) != intelsgx.EinittokenLength { - return fmt.Errorf("invalid length of token: (returned %d, expected %d)", - len(resp.Resp.GetToken()), intelsgx.EinittokenLength) - } - - tok := &intelsgx.Einittoken{} - if err := restruct.Unpack(token, binary.LittleEndian, &tok); err != nil { - log.Println(err) - return err - } - - if context.GlobalBool("verbose") { - fmt.Printf("EINITTOKEN:\n") - fmt.Printf(" Valid: %d\n", - tok.Valid) - fmt.Printf(" Enclave Attributes: 0x%v\n", - hex.EncodeToString(tok.Attributes[:])) - fmt.Printf(" Enclave Hash: 0x%v\n", - hex.EncodeToString(tok.MrEnclave[:])) - fmt.Printf(" Enclave Signer: 0x%v\n", - hex.EncodeToString(tok.MrSigner[:])) - fmt.Printf(" Launch Enclave's CPU SVN : 0x%v\n", - hex.EncodeToString(tok.CpuSvnLe[:])) - fmt.Printf(" Launch Enclave's ISV assigned Product ID: %#04x\n", - tok.ISVProdIdLe) - fmt.Printf(" Launch Enclave's ISV assigned SVN: %d\n", - tok.ISVSvnLe) - fmt.Printf(" Launch Enclave's Masked Misc Select: %#08x\n", - tok.MaskedMiscSelectLe) - fmt.Printf(" Launch Enclave's Masked Attributes: 0x%v\n", - hex.EncodeToString(tok.MaskedAttributesLe[:])) - fmt.Printf(" Key ID: 0x%v\n", - hex.EncodeToString(tok.KeyId[:])) - fmt.Printf(" MAC: 0x%v\n", - hex.EncodeToString(tok.Mac[:])) - } - tokenPath := context.String("token") if tokenPath == "" { tokenPath = filepath.Dir(sigPath) @@ -251,7 +92,7 @@ For example, generate the token file according to the given signature file: tokenPath += ".token" } - if err := ioutil.WriteFile(tokenPath, resp.Resp.GetToken(), sfi.Mode().Perm()); err != nil { + if err := ioutil.WriteFile(tokenPath, tok, sfi.Mode().Perm()); err != nil { return err } diff --git a/runectl/vendor/github.com/opencontainers/runc/libenclave/intelsgx/aesmd.go b/runectl/vendor/github.com/opencontainers/runc/libenclave/intelsgx/aesmd.go new file mode 100644 index 0000000000000000000000000000000000000000..0696771fa2ad783290ef5ab18a21c17c19b7ac5a --- /dev/null +++ b/runectl/vendor/github.com/opencontainers/runc/libenclave/intelsgx/aesmd.go @@ -0,0 +1,183 @@ +package intelsgx // import "github.com/opencontainers/runc/libenclave/intelsgx" + +import ( + "bytes" + "encoding/binary" + "encoding/hex" + "fmt" + "github.com/go-restruct/restruct" + "github.com/golang/protobuf/proto" + pb "github.com/opencontainers/runc/libenclave/intelsgx/proto" + "github.com/sirupsen/logrus" + "net" +) + +const ( + aesmdSocket = "/var/run/aesmd/aesm.socket" +) + +func dialAesmd() (*net.UnixConn, error) { + addr, err := net.ResolveUnixAddr("unix", aesmdSocket) + if err != nil { + return nil, err + } + + conn, err := net.DialUnix("unix", nil, addr) + if err != nil { + return nil, err + } + + return conn, nil +} + +func GetToken(sig []byte) ([]byte, error) { + if len(sig) != SigStructLength { + return nil, fmt.Errorf("signature not match SIGSTRUCT") + } + + s := &SigStruct{} + if err := restruct.Unpack(sig, binary.LittleEndian, &s); err != nil { + return nil, err + } + + mrenclave := s.EnclaveHash[:] + modulus := s.Modulus[:] + attributes := s.Attributes[:] + + logrus.Debugf("SIGSTRUCT:") + _ = s.Header[:] + logrus.Debugf(" Enclave Vendor: %#08x\n", + s.Vendor) + logrus.Debugf(" Enclave Build Date: %d-%d-%d\n", + s.BuildYear, s.BuildMonth, s.BuildDay) + logrus.Debugf(" Software Defined: %#08x\n", + s.SwDefined) + logrus.Debugf(" ISV assigned Product Family ID: 0x%v\n", + hex.EncodeToString(s.ISVFamilyId[:])) + logrus.Debugf(" ISV assigned Produdct ID: %#04x\n", + s.ISVProdId) + logrus.Debugf(" ISV assigned Extended Product ID: 0x%v\n", + hex.EncodeToString(s.ISVExtProdId[:])) + logrus.Debugf(" ISV assigned SVN: %d\n", s.ISVSvn) + logrus.Debugf(" Enclave Attributes: 0x%v\n", + hex.EncodeToString(attributes)) + logrus.Debugf(" Enclave Attributes Mask: 0x%v\n", + hex.EncodeToString(s.AttributesMask[:])) + logrus.Debugf(" Enclave Misc Select: %#08x\n", + s.MiscSelect) + logrus.Debugf(" Enclave Misc Mask: %#08x\n", + s.MiscMask) + logrus.Debugf(" Enclave Hash: 0x%v\n", + hex.EncodeToString(mrenclave)) + logrus.Debugf(" Modulus: 0x%v...\n", + hex.EncodeToString(modulus[:32])) + logrus.Debugf(" Exponent: %d\n", + s.Exponent) + logrus.Debugf(" Signature: 0x%v...\n", + hex.EncodeToString(s.Signature[:32])) + logrus.Debugf(" Q1: 0x%v...\n", + hex.EncodeToString(s.Q1[:32])) + logrus.Debugf(" Q2: 0x%v...\n", + hex.EncodeToString(s.Q2[:32])) + + conn, err := dialAesmd() + if err != nil { + return nil, err + } + defer conn.Close() + + req := pb.GetTokenRequestMessage{} + req.Req = &pb.GetTokenRequest{ + Enclavehash: mrenclave, + Modulus: modulus, + Attributes: attributes, + Timeout: 10000, + } + + var rdata []byte + rdata, err = proto.Marshal(&req) + if err != nil { + return nil, err + } + + msgSize := uint32(len(rdata)) + byteBuf := bytes.NewBuffer([]byte{}) + binary.Write(byteBuf, binary.LittleEndian, &msgSize) + if _, err = conn.Write(byteBuf.Bytes()); err != nil { + return nil, err + } + + if _, err = conn.Write(rdata); err != nil { + return nil, err + } + + rdata = append(rdata[:4]) + if _, err = conn.Read(rdata); err != nil { + return nil, err + } + + byteBuf = bytes.NewBuffer(rdata) + if err = binary.Read(byteBuf, binary.LittleEndian, &msgSize); err != nil { + return nil, err + } + + rdata = make([]byte, msgSize) + var msgSizeRead int + msgSizeRead, err = conn.Read(rdata) + if err != nil { + return nil, err + } + + if msgSizeRead != int(msgSize) { + return nil, fmt.Errorf("invalid response size (returned %d, expected %d)", + msgSizeRead, msgSize) + } + + resp := pb.GetTokenResponseMessage{} + resp.Resp = &pb.GetTokenResponse{} + if err := proto.Unmarshal(rdata, &resp); err != nil { + return nil, err + } + + if resp.Resp.GetError() != 0 { + return nil, fmt.Errorf("failed to get EINITTOKEN (error code = %d)", + resp.Resp.GetError()) + } + + token := resp.Resp.GetToken() + if len(token) != EinittokenLength { + return nil, fmt.Errorf("invalid length of token: (returned %d, expected %d)", + len(resp.Resp.GetToken()), EinittokenLength) + } + + tok := &Einittoken{} + if err := restruct.Unpack(token, binary.LittleEndian, &tok); err != nil { + return nil, err + } + + logrus.Debugf("EINITTOKEN:\n") + logrus.Debugf(" Valid: %d\n", + tok.Valid) + logrus.Debugf(" Enclave Attributes: 0x%v\n", + hex.EncodeToString(tok.Attributes[:])) + logrus.Debugf(" Enclave Hash: 0x%v\n", + hex.EncodeToString(tok.MrEnclave[:])) + logrus.Debugf(" Enclave Signer: 0x%v\n", + hex.EncodeToString(tok.MrSigner[:])) + logrus.Debugf(" Launch Enclave's CPU SVN : 0x%v\n", + hex.EncodeToString(tok.CpuSvnLe[:])) + logrus.Debugf(" Launch Enclave's ISV assigned Product ID: %#04x\n", + tok.ISVProdIdLe) + logrus.Debugf(" Launch Enclave's ISV assigned SVN: %d\n", + tok.ISVSvnLe) + logrus.Debugf(" Launch Enclave's Masked Misc Select: %#08x\n", + tok.MaskedMiscSelectLe) + logrus.Debugf(" Launch Enclave's Masked Attributes: 0x%v\n", + hex.EncodeToString(tok.MaskedAttributesLe[:])) + logrus.Debugf(" Key ID: 0x%v\n", + hex.EncodeToString(tok.KeyId[:])) + logrus.Debugf(" MAC: 0x%v\n", + hex.EncodeToString(tok.Mac[:])) + + return resp.Resp.GetToken(), nil +}