├── .github └── workflows │ └── go.yml ├── .gitignore ├── CONTRIBUTORS.md ├── LICENSE.md ├── README.md ├── arrayof.go ├── decoder.go ├── encoder.go ├── expr.go ├── expr ├── ast.go ├── ast_test.go ├── env.go ├── env_test.go ├── eval.go ├── eval_test.go ├── lex.go ├── lex_test.go ├── package.go ├── package_test.go ├── parse.go ├── parse_test.go ├── tokenkind_string.go ├── type.go ├── value.go └── value_test.go ├── expr_18.go ├── expr_19.go ├── field.go ├── field_test.go ├── formats └── png │ └── png.go ├── formats_test.go ├── go.mod ├── go.sum ├── packing.go ├── packing_test.go ├── structstack.go ├── structstack_test.go ├── tag.go ├── tag_test.go ├── testdata ├── pnggrad8rgb.json └── pnggrad8rgb.png ├── typestr.go └── typestr_test.go /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | name: Build 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | matrix: 16 | go-version: ["1.11", "1.18"] 17 | 18 | steps: 19 | - name: Set up Go 20 | uses: actions/setup-go@v2 21 | with: 22 | go-version: ${{ matrix.go-version }} 23 | 24 | - name: Check out code into the Go module directory 25 | uses: actions/checkout@v2 26 | 27 | - name: Get dependencies 28 | run: go get -v -t -d ./... 29 | 30 | - name: Build (Smoke test) 31 | run: go build -v ./... 32 | 33 | - name: Test 34 | run: go test -v -race -coverprofile=coverage.out -covermode=atomic ./... 35 | 36 | - name: Upload coverage 37 | if: matrix.go-version == '1.18' 38 | uses: codecov/codecov-action@v2 39 | 40 | lint: 41 | name: Lint 42 | runs-on: ubuntu-latest 43 | steps: 44 | - uses: actions/checkout@v2 45 | - name: Lint 46 | uses: golangci/golangci-lint-action@v2 47 | with: 48 | version: v1.45 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | coverage.out 2 | -------------------------------------------------------------------------------- /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | 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). 2 | 3 | * [Dave Cheney](https://github.com/davecheney) 4 | * [John Chadwick](https://github.com/jchv) 5 | * [jlojosnegros](https://github.com/jlojosnegros) 6 | 7 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright © 2015, John Chadwick 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any purpose 6 | with or without fee is hereby granted, provided that the above copyright notice 7 | and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 10 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 11 | FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 12 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 13 | OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 14 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 15 | THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # restruct [![Go](https://github.com/jchv/cleansheets/actions/workflows/go.yml/badge.svg)](https://github.com/jchv/cleansheets/actions/workflows/go.yml) [![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) 2 | `restruct` is a library for reading and writing binary data in Go. Similar to 3 | lunixbochs `struc` and `encoding/binary`, this library reads data based on the 4 | layout of structures and, like `struc`, based on what is contained in struct 5 | tags. 6 | 7 | To install Restruct, use the following command: 8 | 9 | ``` 10 | go get github.com/go-restruct/restruct 11 | ``` 12 | 13 | `restruct` aims to provide a clean, flexible, robust implementation of struct 14 | packing. In the future, through fast-path optimizations and code generation, it 15 | also aims to be quick, but it is currently very slow. 16 | 17 | `restruct` currently requires Go 1.7+. 18 | 19 | ## Status 20 | 21 | * As of writing, coverage is hovering around 95%, but more thorough testing 22 | is always useful and desirable. 23 | * Unpacking and packing are fully functional. 24 | * More optimizations are probably possible. 25 | 26 | ## Example 27 | 28 | ```go 29 | package main 30 | 31 | import ( 32 | "encoding/binary" 33 | "io/ioutil" 34 | "os" 35 | 36 | "github.com/go-restruct/restruct" 37 | ) 38 | 39 | type Record struct { 40 | Message string `struct:"[128]byte"` 41 | } 42 | 43 | type Container struct { 44 | Version int `struct:"int32"` 45 | NumRecord int `struct:"int32,sizeof=Records"` 46 | Records []Record 47 | } 48 | 49 | func main() { 50 | var c Container 51 | 52 | file, _ := os.Open("records") 53 | defer file.Close() 54 | data, _ := ioutil.ReadAll(file) 55 | 56 | restruct.Unpack(data, binary.LittleEndian, &c) 57 | } 58 | ``` 59 | -------------------------------------------------------------------------------- /arrayof.go: -------------------------------------------------------------------------------- 1 | package restruct 2 | 3 | // RegisterArrayType is deprecated; it is now a noop. 4 | func RegisterArrayType(array interface{}) { 5 | } 6 | -------------------------------------------------------------------------------- /decoder.go: -------------------------------------------------------------------------------- 1 | package restruct 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "math" 7 | "reflect" 8 | "strings" 9 | ) 10 | 11 | // Unpacker is a type capable of unpacking a binary representation of itself 12 | // into a native representation. The Unpack function is expected to consume 13 | // a number of bytes from the buffer, then return a slice of the remaining 14 | // bytes in the buffer. You may use a pointer receiver even if the type is 15 | // used by value. 16 | type Unpacker interface { 17 | Unpack(buf []byte, order binary.ByteOrder) ([]byte, error) 18 | } 19 | 20 | type decoder struct { 21 | structstack 22 | order binary.ByteOrder 23 | sfields []field 24 | bitCounter uint8 25 | bitSize int 26 | } 27 | 28 | func putBit(buf []byte, bitSize int, bit int, val byte) { 29 | bit = bitSize - 1 - bit 30 | buf[len(buf)-bit/8-1] |= (val) << (uint(bit) % 8) 31 | } 32 | 33 | func (d *decoder) readBit() byte { 34 | value := (d.buf[0] >> uint(7-d.bitCounter)) & 1 35 | d.bitCounter++ 36 | if d.bitCounter >= 8 { 37 | d.buf = d.buf[1:] 38 | d.bitCounter -= 8 39 | } 40 | return value 41 | } 42 | 43 | func (d *decoder) readBits(f field, outBuf []byte) { 44 | var decodedBits int 45 | 46 | // Determine encoded size in bits. 47 | if d.bitSize == 0 { 48 | decodedBits = 8 * len(outBuf) 49 | } else { 50 | decodedBits = int(d.bitSize) 51 | 52 | // HACK: Go's generic endianness abstraction is not great if you are 53 | // working with bits directly. Here we hardcode a case for little endian 54 | // because there is no other obvious way to deal with it. 55 | // 56 | // Crop output buffer to relevant bytes only. 57 | if d.order == binary.LittleEndian { 58 | outBuf = outBuf[:(decodedBits+7)/8] 59 | } else { 60 | outBuf = outBuf[len(outBuf)-(decodedBits+7)/8:] 61 | } 62 | } 63 | 64 | if d.bitCounter == 0 && decodedBits%8 == 0 { 65 | // Fast path: we are fully byte-aligned. 66 | copy(outBuf, d.buf) 67 | d.buf = d.buf[len(outBuf):] 68 | } else { 69 | // Slow path: work bit-by-bit. 70 | // TODO: This needs to be optimized in a way that can be easily 71 | // understood; the previous optimized version was simply too hard to 72 | // reason about. 73 | for i := 0; i < decodedBits; i++ { 74 | putBit(outBuf, decodedBits, i, d.readBit()) 75 | } 76 | } 77 | } 78 | 79 | func (d *decoder) extend8(val uint8, signed bool) uint8 { 80 | if signed && d.bitSize != 0 && val&1< 8 { 156 | d.bitCounter -= 8 157 | count += 8 158 | } 159 | d.buf = d.buf[count/8:] 160 | } 161 | 162 | func (d *decoder) skip(f field, v reflect.Value) { 163 | d.skipBits(d.fieldbits(f, v)) 164 | } 165 | 166 | func (d *decoder) unpacker(v reflect.Value) (Unpacker, bool) { 167 | if s, ok := v.Interface().(Unpacker); ok { 168 | return s, true 169 | } 170 | 171 | if !v.CanAddr() { 172 | return nil, false 173 | } 174 | 175 | if s, ok := v.Addr().Interface().(Unpacker); ok { 176 | return s, true 177 | } 178 | 179 | return nil, false 180 | } 181 | 182 | func (d *decoder) setUint(f field, v reflect.Value, x uint64) { 183 | switch v.Kind() { 184 | case reflect.Bool: 185 | b := x != 0 186 | if f.Flags&InvertedBoolFlag == InvertedBoolFlag { 187 | b = !b 188 | } 189 | v.SetBool(b) 190 | default: 191 | v.SetUint(x) 192 | } 193 | } 194 | 195 | func (d *decoder) setInt(f field, v reflect.Value, x int64) { 196 | switch v.Kind() { 197 | case reflect.Bool: 198 | b := x != 0 199 | if f.Flags&InvertedBoolFlag == InvertedBoolFlag { 200 | b = !b 201 | } 202 | v.SetBool(b) 203 | default: 204 | v.SetInt(x) 205 | } 206 | } 207 | 208 | func (d *decoder) switc(f field, v reflect.Value, on interface{}) { 209 | var def *switchcase 210 | 211 | if v.Kind() != reflect.Struct { 212 | panic(fmt.Errorf("%s: only switches on structs are valid", f.Name)) 213 | } 214 | 215 | sfields := cachedFieldsFromStruct(f.BinaryType) 216 | l := len(sfields) 217 | 218 | // Zero out values for decoding. 219 | for i := 0; i < l; i++ { 220 | v := v.Field(f.Index) 221 | v.Set(reflect.Zero(v.Type())) 222 | } 223 | 224 | for i := 0; i < l; i++ { 225 | f := sfields[i] 226 | v := v.Field(f.Index) 227 | 228 | if f.Flags&DefaultFlag != 0 { 229 | if def != nil { 230 | panic(fmt.Errorf("%s: only one default case is allowed", f.Name)) 231 | } 232 | def = &switchcase{f, v} 233 | continue 234 | } 235 | 236 | if f.CaseExpr == nil { 237 | panic(fmt.Errorf("%s: only cases are valid inside switches", f.Name)) 238 | } 239 | 240 | if d.evalExpr(f.CaseExpr) == on { 241 | d.read(f, v) 242 | return 243 | } 244 | } 245 | 246 | if def != nil { 247 | d.read(def.f, def.v) 248 | } 249 | } 250 | 251 | func (d *decoder) read(f field, v reflect.Value) { 252 | if f.Flags&RootFlag == RootFlag { 253 | d.setancestor(f, v, d.root()) 254 | return 255 | } 256 | 257 | if f.Flags&ParentFlag == ParentFlag { 258 | for i := 1; i < len(d.stack); i++ { 259 | if d.setancestor(f, v, d.ancestor(i)) { 260 | break 261 | } 262 | } 263 | return 264 | } 265 | 266 | if f.SwitchExpr != nil { 267 | d.switc(f, v, d.evalExpr(f.SwitchExpr)) 268 | return 269 | } 270 | 271 | struc := d.ancestor(0) 272 | 273 | if f.Name != "_" { 274 | if s, ok := d.unpacker(v); ok { 275 | var err error 276 | d.buf, err = s.Unpack(d.buf, d.order) 277 | if err != nil { 278 | panic(err) 279 | } 280 | return 281 | } 282 | } else { 283 | d.skipBits(d.fieldbits(f, v)) 284 | return 285 | } 286 | 287 | if !d.evalIf(f) { 288 | return 289 | } 290 | 291 | sfields := d.sfields 292 | order := d.order 293 | 294 | if f.Order != nil { 295 | d.order = f.Order 296 | defer func() { d.order = order }() 297 | } 298 | 299 | if f.Skip != 0 { 300 | d.skipBits(f.Skip * 8) 301 | } 302 | 303 | d.bitSize = d.evalBits(f) 304 | alen := d.evalSize(f) 305 | 306 | if alen == 0 && f.SIndex != -1 { 307 | sv := struc.Field(f.SIndex) 308 | l := len(sfields) 309 | for i := 0; i < l; i++ { 310 | if sfields[i].Index != f.SIndex { 311 | continue 312 | } 313 | sf := sfields[i] 314 | // Must use different codepath for signed/unsigned. 315 | switch sf.BinaryType.Kind() { 316 | case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 317 | alen = int(sv.Int()) 318 | case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 319 | alen = int(sv.Uint()) 320 | default: 321 | panic(fmt.Errorf("unsupported size type %s: %s", sf.BinaryType.String(), sf.Name)) 322 | } 323 | break 324 | } 325 | } 326 | 327 | switch f.BinaryType.Kind() { 328 | case reflect.Array: 329 | l := f.BinaryType.Len() 330 | 331 | // If the underlying value is a slice, initialize it. 332 | if f.NativeType.Kind() == reflect.Slice { 333 | v.Set(reflect.MakeSlice(reflect.SliceOf(f.NativeType.Elem()), l, l)) 334 | } 335 | 336 | switch f.NativeType.Kind() { 337 | case reflect.String: 338 | // When using strings, treat as C string. 339 | str := string(d.readBytes(d.fieldbytes(f, v))) 340 | nul := strings.IndexByte(str, 0) 341 | if nul != -1 { 342 | str = str[0:nul] 343 | } 344 | v.SetString(str) 345 | case reflect.Slice, reflect.Array: 346 | ef := f.Elem() 347 | for i := 0; i < l; i++ { 348 | d.read(ef, v.Index(i)) 349 | } 350 | default: 351 | panic(fmt.Errorf("invalid array cast type: %s", f.NativeType.String())) 352 | } 353 | 354 | case reflect.Struct: 355 | d.push(v) 356 | d.sfields = cachedFieldsFromStruct(f.BinaryType) 357 | l := len(d.sfields) 358 | for i := 0; i < l; i++ { 359 | f := d.sfields[i] 360 | v := v.Field(f.Index) 361 | if v.CanSet() { 362 | d.read(f, v) 363 | } else { 364 | d.skip(f, v) 365 | } 366 | } 367 | d.sfields = sfields 368 | d.pop(v) 369 | 370 | case reflect.Ptr: 371 | v.Set(reflect.New(v.Type().Elem())) 372 | d.read(f.Elem(), v.Elem()) 373 | 374 | case reflect.Slice, reflect.String: 375 | fixed := func() { 376 | switch f.NativeType.Elem().Kind() { 377 | case reflect.Uint8: 378 | v.SetBytes(d.readBytes(d.fieldbytes(f, v))) 379 | default: 380 | ef := f.Elem() 381 | for i := 0; i < alen; i++ { 382 | d.read(ef, v.Index(i)) 383 | } 384 | } 385 | } 386 | switch f.NativeType.Kind() { 387 | case reflect.String: 388 | v.SetString(string(d.readBytes(alen))) 389 | case reflect.Array: 390 | if f.WhileExpr != nil { 391 | i := 0 392 | ef := f.Elem() 393 | for d.evalWhile(f) { 394 | d.read(ef, v.Index(i)) 395 | i++ 396 | } 397 | } else { 398 | fixed() 399 | } 400 | case reflect.Slice: 401 | if f.WhileExpr != nil { 402 | switch f.NativeType.Kind() { 403 | case reflect.Slice: 404 | ef := f.Elem() 405 | for d.evalWhile(f) { 406 | nv := reflect.New(ef.NativeType).Elem() 407 | d.read(ef, nv) 408 | v.Set(reflect.Append(v, nv)) 409 | } 410 | } 411 | } else { 412 | v.Set(reflect.MakeSlice(f.NativeType, alen, alen)) 413 | fixed() 414 | } 415 | default: 416 | panic(fmt.Errorf("invalid array cast type: %s", f.NativeType.String())) 417 | } 418 | 419 | case reflect.Int8: 420 | d.setInt(f, v, int64(d.readS8(f))) 421 | case reflect.Int16: 422 | d.setInt(f, v, int64(d.readS16(f))) 423 | case reflect.Int32: 424 | d.setInt(f, v, int64(d.readS32(f))) 425 | case reflect.Int64: 426 | d.setInt(f, v, d.readS64(f)) 427 | 428 | case reflect.Uint8, reflect.Bool: 429 | d.setUint(f, v, uint64(d.readU8(f))) 430 | case reflect.Uint16: 431 | d.setUint(f, v, uint64(d.readU16(f))) 432 | case reflect.Uint32: 433 | d.setUint(f, v, uint64(d.readU32(f))) 434 | case reflect.Uint64: 435 | d.setUint(f, v, d.readU64(f)) 436 | 437 | case reflect.Float32: 438 | v.SetFloat(float64(math.Float32frombits(d.read32(f, false)))) 439 | case reflect.Float64: 440 | v.SetFloat(math.Float64frombits(d.read64(f, false))) 441 | 442 | case reflect.Complex64: 443 | v.SetComplex(complex( 444 | float64(math.Float32frombits(d.read32(f, false))), 445 | float64(math.Float32frombits(d.read32(f, false))), 446 | )) 447 | case reflect.Complex128: 448 | v.SetComplex(complex( 449 | math.Float64frombits(d.read64(f, false)), 450 | math.Float64frombits(d.read64(f, false)), 451 | )) 452 | } 453 | 454 | if f.InExpr != nil { 455 | v.Set(reflect.ValueOf(d.evalExpr(f.InExpr))) 456 | } 457 | } 458 | -------------------------------------------------------------------------------- /encoder.go: -------------------------------------------------------------------------------- 1 | package restruct 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "math" 7 | "reflect" 8 | ) 9 | 10 | // Packer is a type capable of packing a native value into a binary 11 | // representation. The Pack function is expected to overwrite a number of 12 | // bytes in buf then return a slice of the remaining buffer. Note that you 13 | // must also implement SizeOf, and returning an incorrect SizeOf will cause 14 | // the encoder to crash. The SizeOf should be equal to the number of bytes 15 | // consumed from the buffer slice in Pack. You may use a pointer receiver even 16 | // if the type is used by value. 17 | type Packer interface { 18 | Sizer 19 | Pack(buf []byte, order binary.ByteOrder) ([]byte, error) 20 | } 21 | 22 | type encoder struct { 23 | structstack 24 | order binary.ByteOrder 25 | sfields []field 26 | bitCounter int 27 | bitSize int 28 | } 29 | 30 | func getBit(buf []byte, bitSize int, bit int) byte { 31 | bit = bitSize - 1 - bit 32 | return (buf[len(buf)-bit/8-1] >> (uint(bit) % 8)) & 1 33 | } 34 | 35 | func (e *encoder) writeBit(value byte) { 36 | e.buf[0] |= (value & 1) << uint(7-e.bitCounter) 37 | e.bitCounter++ 38 | if e.bitCounter >= 8 { 39 | e.buf = e.buf[1:] 40 | e.bitCounter -= 8 41 | } 42 | } 43 | 44 | func (e *encoder) writeBits(f field, inBuf []byte) { 45 | var encodedBits int 46 | 47 | // Determine encoded size in bits. 48 | if e.bitSize == 0 { 49 | encodedBits = 8 * len(inBuf) 50 | } else { 51 | encodedBits = int(e.bitSize) 52 | 53 | // HACK: Go's generic endianness abstraction is not great if you are 54 | // working with bits directly. Here we hardcode a case for little endian 55 | // because there is no other obvious way to deal with it. 56 | // 57 | // Crop input buffer to relevant bytes only. 58 | if e.order == binary.LittleEndian { 59 | inBuf = inBuf[:(encodedBits+7)/8] 60 | } else { 61 | inBuf = inBuf[len(inBuf)-(encodedBits+7)/8:] 62 | } 63 | } 64 | 65 | if e.bitCounter == 0 && encodedBits%8 == 0 { 66 | // Fast path: we are fully byte-aligned. 67 | copy(e.buf, inBuf) 68 | e.buf = e.buf[len(inBuf):] 69 | } else { 70 | // Slow path: work bit-by-bit. 71 | // TODO: This needs to be optimized in a way that can be easily 72 | // understood; the previous optimized version was simply too hard to 73 | // reason about. 74 | for i := 0; i < encodedBits; i++ { 75 | e.writeBit(getBit(inBuf, encodedBits, i)) 76 | } 77 | } 78 | } 79 | 80 | func (e *encoder) write8(f field, x uint8) { 81 | b := make([]byte, 1) 82 | b[0] = x 83 | e.writeBits(f, b) 84 | } 85 | 86 | func (e *encoder) write16(f field, x uint16) { 87 | b := make([]byte, 2) 88 | e.order.PutUint16(b, x) 89 | e.writeBits(f, b) 90 | } 91 | 92 | func (e *encoder) write32(f field, x uint32) { 93 | b := make([]byte, 4) 94 | e.order.PutUint32(b, x) 95 | e.writeBits(f, b) 96 | } 97 | 98 | func (e *encoder) write64(f field, x uint64) { 99 | b := make([]byte, 8) 100 | e.order.PutUint64(b, x) 101 | e.writeBits(f, b) 102 | } 103 | 104 | func (e *encoder) writeS8(f field, x int8) { e.write8(f, uint8(x)) } 105 | 106 | func (e *encoder) writeS16(f field, x int16) { e.write16(f, uint16(x)) } 107 | 108 | func (e *encoder) writeS32(f field, x int32) { e.write32(f, uint32(x)) } 109 | 110 | func (e *encoder) writeS64(f field, x int64) { e.write64(f, uint64(x)) } 111 | 112 | func (e *encoder) skipBits(count int) { 113 | e.bitCounter += count % 8 114 | if e.bitCounter > 8 { 115 | e.bitCounter -= 8 116 | count += 8 117 | } 118 | e.buf = e.buf[count/8:] 119 | } 120 | 121 | func (e *encoder) skip(f field, v reflect.Value) { 122 | e.skipBits(e.fieldbits(f, v)) 123 | } 124 | 125 | func (e *encoder) packer(v reflect.Value) (Packer, bool) { 126 | if s, ok := v.Interface().(Packer); ok { 127 | return s, true 128 | } 129 | 130 | if !v.CanAddr() { 131 | return nil, false 132 | } 133 | 134 | if s, ok := v.Addr().Interface().(Packer); ok { 135 | return s, true 136 | } 137 | 138 | return nil, false 139 | } 140 | 141 | func (e *encoder) intFromField(f field, v reflect.Value) int64 { 142 | switch v.Kind() { 143 | case reflect.Bool: 144 | b := v.Bool() 145 | if f.Flags&InvertedBoolFlag == InvertedBoolFlag { 146 | b = !b 147 | } 148 | if b { 149 | if f.Flags&VariantBoolFlag == VariantBoolFlag { 150 | return -1 151 | } 152 | return 1 153 | } 154 | return 0 155 | default: 156 | return v.Int() 157 | } 158 | } 159 | 160 | func (e *encoder) uintFromField(f field, v reflect.Value) uint64 { 161 | switch v.Kind() { 162 | case reflect.Bool: 163 | b := v.Bool() 164 | if f.Flags&InvertedBoolFlag == InvertedBoolFlag { 165 | b = !b 166 | } 167 | if b { 168 | if f.Flags&VariantBoolFlag == VariantBoolFlag { 169 | return ^uint64(0) 170 | } 171 | return 1 172 | } 173 | return 0 174 | default: 175 | return v.Uint() 176 | } 177 | } 178 | 179 | func (e *encoder) switc(f field, v reflect.Value, on interface{}) { 180 | var def *switchcase 181 | 182 | if v.Kind() != reflect.Struct { 183 | panic(fmt.Errorf("%s: only switches on structs are valid", f.Name)) 184 | } 185 | 186 | sfields := cachedFieldsFromStruct(f.BinaryType) 187 | l := len(sfields) 188 | 189 | for i := 0; i < l; i++ { 190 | f := sfields[i] 191 | v := v.Field(f.Index) 192 | 193 | if f.Flags&DefaultFlag != 0 { 194 | if def != nil { 195 | panic(fmt.Errorf("%s: only one default case is allowed", f.Name)) 196 | } 197 | def = &switchcase{f, v} 198 | continue 199 | } 200 | 201 | if f.CaseExpr == nil { 202 | panic(fmt.Errorf("%s: only cases are valid inside switches", f.Name)) 203 | } 204 | 205 | if e.evalExpr(f.CaseExpr) == on { 206 | e.write(f, v) 207 | return 208 | } 209 | } 210 | 211 | if def != nil { 212 | e.write(def.f, def.v) 213 | } 214 | } 215 | 216 | func (e *encoder) write(f field, v reflect.Value) { 217 | if f.Flags&RootFlag == RootFlag { 218 | e.setancestor(f, v, e.root()) 219 | return 220 | } 221 | 222 | if f.Flags&ParentFlag == ParentFlag { 223 | for i := 1; i < len(e.stack); i++ { 224 | if e.setancestor(f, v, e.ancestor(i)) { 225 | break 226 | } 227 | } 228 | return 229 | } 230 | 231 | if f.SwitchExpr != nil { 232 | e.switc(f, v, e.evalExpr(f.SwitchExpr)) 233 | return 234 | } 235 | 236 | struc := e.ancestor(0) 237 | 238 | if f.Name != "_" { 239 | if s, ok := e.packer(v); ok { 240 | var err error 241 | e.buf, err = s.Pack(e.buf, e.order) 242 | if err != nil { 243 | panic(err) 244 | } 245 | return 246 | } 247 | } else { 248 | e.skipBits(e.fieldbits(f, v)) 249 | return 250 | } 251 | 252 | if !e.evalIf(f) { 253 | return 254 | } 255 | 256 | sfields := e.sfields 257 | order := e.order 258 | 259 | if f.Order != nil { 260 | e.order = f.Order 261 | defer func() { e.order = order }() 262 | } 263 | 264 | if f.Skip != 0 { 265 | e.skipBits(f.Skip * 8) 266 | } 267 | 268 | e.bitSize = e.evalBits(f) 269 | 270 | // If this is a sizeof field, pull the current slice length into it. 271 | if f.TIndex != -1 { 272 | sv := struc.Field(f.TIndex) 273 | 274 | switch f.BinaryType.Kind() { 275 | case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 276 | v.SetInt(int64(sv.Len())) 277 | case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 278 | v.SetUint(uint64(sv.Len())) 279 | default: 280 | panic(fmt.Errorf("unsupported size type %s: %s", f.BinaryType.String(), f.Name)) 281 | } 282 | } 283 | 284 | ov := v 285 | if f.OutExpr != nil { 286 | ov = reflect.ValueOf(e.evalExpr(f.OutExpr)) 287 | } 288 | 289 | switch f.BinaryType.Kind() { 290 | case reflect.Ptr: 291 | // Skip if pointer is nil. 292 | if v.IsNil() { 293 | return 294 | } 295 | 296 | e.write(f.Elem(), v.Elem()) 297 | 298 | case reflect.Array, reflect.Slice, reflect.String: 299 | switch f.NativeType.Kind() { 300 | case reflect.Slice, reflect.String: 301 | if f.SizeExpr != nil { 302 | if l := e.evalSize(f); l != ov.Len() { 303 | panic(fmt.Errorf("length does not match size expression (%d != %d)", ov.Len(), l)) 304 | } 305 | } 306 | fallthrough 307 | case reflect.Array: 308 | ef := f.Elem() 309 | len := ov.Len() 310 | cap := len 311 | if f.BinaryType.Kind() == reflect.Array { 312 | cap = f.BinaryType.Len() 313 | } 314 | for i := 0; i < len; i++ { 315 | e.write(ef, ov.Index(i)) 316 | } 317 | for i := len; i < cap; i++ { 318 | e.write(ef, reflect.New(f.BinaryType.Elem()).Elem()) 319 | } 320 | default: 321 | panic(fmt.Errorf("invalid array cast type: %s", f.NativeType.String())) 322 | } 323 | 324 | case reflect.Struct: 325 | e.push(ov) 326 | e.sfields = cachedFieldsFromStruct(f.BinaryType) 327 | l := len(e.sfields) 328 | for i := 0; i < l; i++ { 329 | sf := e.sfields[i] 330 | sv := ov.Field(sf.Index) 331 | if sv.CanSet() { 332 | e.write(sf, sv) 333 | } else { 334 | e.skip(sf, sv) 335 | } 336 | } 337 | e.sfields = sfields 338 | e.pop(ov) 339 | 340 | case reflect.Int8: 341 | e.writeS8(f, int8(e.intFromField(f, ov))) 342 | case reflect.Int16: 343 | e.writeS16(f, int16(e.intFromField(f, ov))) 344 | case reflect.Int32: 345 | e.writeS32(f, int32(e.intFromField(f, ov))) 346 | case reflect.Int64: 347 | e.writeS64(f, int64(e.intFromField(f, ov))) 348 | 349 | case reflect.Uint8, reflect.Bool: 350 | e.write8(f, uint8(e.uintFromField(f, ov))) 351 | case reflect.Uint16: 352 | e.write16(f, uint16(e.uintFromField(f, ov))) 353 | case reflect.Uint32: 354 | e.write32(f, uint32(e.uintFromField(f, ov))) 355 | case reflect.Uint64: 356 | e.write64(f, uint64(e.uintFromField(f, ov))) 357 | 358 | case reflect.Float32: 359 | e.write32(f, math.Float32bits(float32(ov.Float()))) 360 | case reflect.Float64: 361 | e.write64(f, math.Float64bits(float64(ov.Float()))) 362 | 363 | case reflect.Complex64: 364 | x := ov.Complex() 365 | e.write32(f, math.Float32bits(float32(real(x)))) 366 | e.write32(f, math.Float32bits(float32(imag(x)))) 367 | case reflect.Complex128: 368 | x := ov.Complex() 369 | e.write64(f, math.Float64bits(float64(real(x)))) 370 | e.write64(f, math.Float64bits(float64(imag(x)))) 371 | } 372 | } 373 | -------------------------------------------------------------------------------- /expr.go: -------------------------------------------------------------------------------- 1 | package restruct 2 | 3 | import ( 4 | "github.com/go-restruct/restruct/expr" 5 | ) 6 | 7 | var ( 8 | expressionsEnabled = false 9 | stdLibResolver = expr.NewMapResolver(exprStdLib) 10 | ) 11 | 12 | // EnableExprBeta enables you to use restruct expr while it is still in beta. 13 | // Use at your own risk. Functionality may change in unforeseen, incompatible 14 | // ways at any time. 15 | func EnableExprBeta() { 16 | expressionsEnabled = true 17 | } 18 | -------------------------------------------------------------------------------- /expr/ast.go: -------------------------------------------------------------------------------- 1 | package expr 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | ) 7 | 8 | type node interface { 9 | source() string 10 | } 11 | 12 | type unaryop int 13 | 14 | const ( 15 | unaryplus unaryop = iota 16 | unarynegate 17 | unarynot 18 | unarybitnot 19 | unaryderef 20 | unaryref 21 | ) 22 | 23 | type binaryop int 24 | 25 | const ( 26 | binarylogicalor binaryop = iota 27 | binarylogicaland 28 | binaryequal 29 | binarynotequal 30 | binarylesser 31 | binarylesserequal 32 | binarygreater 33 | binarygreaterequal 34 | binaryadd 35 | binarysub 36 | binaryor 37 | binaryxor 38 | binarymul 39 | binarydiv 40 | binaryrem 41 | binarylsh 42 | binaryrsh 43 | binaryand 44 | binaryandnot 45 | binarymember 46 | binarycall 47 | binarysubscript 48 | binarygroup 49 | ) 50 | 51 | // Identifier node. 52 | type identnode struct { 53 | pos int 54 | ident string 55 | } 56 | 57 | func newidentnode(t token) identnode { 58 | return identnode{t.pos, t.sval} 59 | } 60 | 61 | func (n identnode) source() string { 62 | return n.ident 63 | } 64 | 65 | // Integer literal node. 66 | type intnode struct { 67 | pos int 68 | uval uint64 69 | ival int64 70 | sign bool 71 | } 72 | 73 | func newintnode(t token) intnode { 74 | return intnode{pos: t.pos, uval: t.uval, ival: t.ival, sign: t.sign} 75 | } 76 | 77 | func (n intnode) source() string { 78 | if n.sign { 79 | return strconv.FormatInt(n.ival, 10) 80 | } 81 | return strconv.FormatUint(n.uval, 10) 82 | } 83 | 84 | // Float literal node. 85 | type floatnode struct { 86 | pos int 87 | fval float64 88 | } 89 | 90 | func newfloatnode(t token) floatnode { 91 | return floatnode{pos: t.pos, fval: t.fval} 92 | } 93 | 94 | func (n floatnode) source() string { 95 | return strconv.FormatFloat(n.fval, 'f', -1, 64) 96 | } 97 | 98 | // Bool literal node. 99 | type boolnode struct { 100 | pos int 101 | val bool 102 | } 103 | 104 | func newboolnode(t token) boolnode { 105 | return boolnode{t.pos, t.bval} 106 | } 107 | 108 | func (n boolnode) source() string { 109 | if n.val { 110 | return "true" 111 | } 112 | return "false" 113 | } 114 | 115 | // String literal node. 116 | type strnode struct { 117 | pos int 118 | val string 119 | } 120 | 121 | func newstrnode(t token) strnode { 122 | return strnode{t.pos, t.sval} 123 | } 124 | 125 | func (n strnode) source() string { 126 | return fmt.Sprintf("%q", n.val) 127 | } 128 | 129 | // Rune literal node. 130 | type runenode struct { 131 | pos int 132 | val rune 133 | } 134 | 135 | func newrunenode(t token) runenode { 136 | return runenode{t.pos, rune(t.ival)} 137 | } 138 | 139 | func (n runenode) source() string { 140 | return fmt.Sprintf("%q", n.val) 141 | } 142 | 143 | // Nil node. 144 | type nilnode struct { 145 | pos int 146 | } 147 | 148 | func newnilnode(t token) nilnode { 149 | return nilnode{t.pos} 150 | } 151 | 152 | func (nilnode) source() string { 153 | return "nil" 154 | } 155 | 156 | // Unary expression node. 157 | type unaryexpr struct { 158 | op unaryop 159 | n node 160 | } 161 | 162 | func (n unaryexpr) source() string { 163 | operand := n.n.source() 164 | switch n.op { 165 | case unaryplus: 166 | return "+" + operand 167 | case unarynegate: 168 | return "-" + operand 169 | case unarynot: 170 | return "!" + operand 171 | case unarybitnot: 172 | return "^" + operand 173 | case unaryderef: 174 | return "*" + operand 175 | case unaryref: 176 | return "&" + operand 177 | } 178 | panic("invalid unary expr?") 179 | } 180 | 181 | // Binary expression node. 182 | type binaryexpr struct { 183 | op binaryop 184 | a, b node 185 | } 186 | 187 | func (n binaryexpr) source() string { 188 | a, b := n.a.source(), n.b.source() 189 | switch n.op { 190 | case binarylogicalor: 191 | return a + " || " + b 192 | case binarylogicaland: 193 | return a + " && " + b 194 | case binaryequal: 195 | return a + " == " + b 196 | case binarynotequal: 197 | return a + " != " + b 198 | case binarylesser: 199 | return a + " < " + b 200 | case binarylesserequal: 201 | return a + " <= " + b 202 | case binarygreater: 203 | return a + " > " + b 204 | case binarygreaterequal: 205 | return a + " >= " + b 206 | case binaryadd: 207 | return a + " + " + b 208 | case binarysub: 209 | return a + " - " + b 210 | case binaryor: 211 | return a + " | " + b 212 | case binaryxor: 213 | return a + " ^ " + b 214 | case binarymul: 215 | return a + " * " + b 216 | case binarydiv: 217 | return a + " / " + b 218 | case binaryrem: 219 | return a + " % " + b 220 | case binarylsh: 221 | return a + " << " + b 222 | case binaryrsh: 223 | return a + " >> " + b 224 | case binaryand: 225 | return a + " & " + b 226 | case binaryandnot: 227 | return a + " &^ " + b 228 | case binarymember: 229 | return a + "." + b 230 | case binarycall: 231 | return a + "(" + b + ")" 232 | case binarysubscript: 233 | return a + "[" + b + "]" 234 | case binarygroup: 235 | return a + ", " + b 236 | } 237 | panic("invalid binary expr?") 238 | } 239 | 240 | // Ternary expression node. 241 | type ternaryexpr struct { 242 | a, b, c node 243 | } 244 | 245 | func (n ternaryexpr) source() string { 246 | return n.a.source() + " ? " + n.b.source() + " : " + n.c.source() 247 | } 248 | -------------------------------------------------------------------------------- /expr/ast_test.go: -------------------------------------------------------------------------------- 1 | package expr 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestSource(t *testing.T) { 10 | tests := []struct { 11 | input node 12 | output string 13 | }{ 14 | { 15 | binaryexpr{ 16 | binaryadd, 17 | identnode{0, "a"}, 18 | binaryexpr{ 19 | binarymul, 20 | identnode{4, "b"}, 21 | identnode{8, "c"}, 22 | }, 23 | }, 24 | "a + b * c", 25 | }, 26 | { 27 | ternaryexpr{ 28 | binaryexpr{ 29 | binaryequal, 30 | identnode{0, "a"}, 31 | intnode{5, 1, 1, false}, 32 | }, 33 | binaryexpr{ 34 | binaryadd, 35 | identnode{9, "b"}, 36 | intnode{13, 1, 1, false}, 37 | }, 38 | binaryexpr{ 39 | binarymul, 40 | identnode{17, "c"}, 41 | intnode{21, 1, 1, false}, 42 | }, 43 | }, 44 | "a == 1 ? b + 1 : c * 1", 45 | }, 46 | { 47 | binaryexpr{ 48 | binarycall, 49 | identnode{0, "a"}, 50 | binaryexpr{ 51 | binarygroup, 52 | identnode{2, "b"}, 53 | identnode{5, "c"}, 54 | }, 55 | }, 56 | "a(b, c)", 57 | }, 58 | } 59 | 60 | for _, test := range tests { 61 | assert.Equal(t, test.output, test.input.source()) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /expr/env.go: -------------------------------------------------------------------------------- 1 | package expr 2 | 3 | import "reflect" 4 | 5 | // Assertions. 6 | var ( 7 | _ = TypeResolver(&TypeResolverAdapter{}) 8 | _ = TypeResolver(&MetaTypeResolver{}) 9 | _ = Resolver(&MetaResolver{}) 10 | _ = TypeResolver(&StructTypeResolver{}) 11 | _ = Resolver(&StructResolver{}) 12 | _ = TypeResolver(&MapTypeResolver{}) 13 | _ = Resolver(&MapResolver{}) 14 | ) 15 | 16 | // TypeResolver resolves types. 17 | type TypeResolver interface { 18 | TypeResolve(ident string) Type 19 | } 20 | 21 | // Resolver resolves runtime values. 22 | type Resolver interface { 23 | Resolve(ident string) Value 24 | } 25 | 26 | // TypeResolverAdapter adapts a runtime resolver to a type resolver by taking 27 | // types of values retrieve from Resolve. 28 | type TypeResolverAdapter struct { 29 | Resolver 30 | } 31 | 32 | // NewTypeResolverAdapter creates a new TypeResolverAdapter from a resolver. 33 | func NewTypeResolverAdapter(r Resolver) *TypeResolverAdapter { 34 | return &TypeResolverAdapter{r} 35 | } 36 | 37 | // TypeResolve implements TypeResolver. 38 | func (r *TypeResolverAdapter) TypeResolve(ident string) Type { 39 | if v := r.Resolve(ident); v != nil { 40 | return v.Type() 41 | } 42 | return nil 43 | } 44 | 45 | // MetaTypeResolver runs multiple type resolvers serially. 46 | type MetaTypeResolver struct { 47 | resolvers []TypeResolver 48 | } 49 | 50 | // NewMetaTypeResolver creates a new meta type resolver. 51 | func NewMetaTypeResolver() *MetaTypeResolver { 52 | return &MetaTypeResolver{} 53 | } 54 | 55 | // AddResolver adds a new resolver below other resolvers. 56 | func (r *MetaTypeResolver) AddResolver(n TypeResolver) { 57 | r.resolvers = append(r.resolvers, n) 58 | } 59 | 60 | // TypeResolve implements TypeResolver. 61 | func (r *MetaTypeResolver) TypeResolve(ident string) Type { 62 | for _, resolver := range r.resolvers { 63 | if t := resolver.TypeResolve(ident); t != nil { 64 | return t 65 | } 66 | } 67 | return nil 68 | } 69 | 70 | // MetaResolver runs multiple resolvers serially. 71 | type MetaResolver struct { 72 | resolvers []Resolver 73 | } 74 | 75 | // NewMetaResolver creates a new meta resolver. 76 | func NewMetaResolver() *MetaResolver { 77 | return &MetaResolver{} 78 | } 79 | 80 | // AddResolver adds a new resolver below other resolvers. 81 | func (r *MetaResolver) AddResolver(n Resolver) { 82 | r.resolvers = append(r.resolvers, n) 83 | } 84 | 85 | // Resolve implements Resolver. 86 | func (r *MetaResolver) Resolve(ident string) Value { 87 | for _, resolver := range r.resolvers { 88 | if t := resolver.Resolve(ident); t != nil { 89 | return t 90 | } 91 | } 92 | return nil 93 | } 94 | 95 | // StructTypeResolver resolves types of struct fields. 96 | type StructTypeResolver struct { 97 | struc *StructType 98 | } 99 | 100 | // NewStructTypeResolver creates a new struct type resolver. 101 | func NewStructTypeResolver(s interface{}) *StructTypeResolver { 102 | return &StructTypeResolver{TypeOf(s).(*StructType)} 103 | } 104 | 105 | // TypeResolve implements TypeResolver. 106 | func (r *StructTypeResolver) TypeResolve(ident string) Type { 107 | if f, ok := r.struc.FieldByName(ident); ok { 108 | return f.Type 109 | } 110 | return nil 111 | } 112 | 113 | // StructResolver resolves struct fields. 114 | type StructResolver struct { 115 | struc reflect.Value 116 | } 117 | 118 | // NewStructResolver creates a new struct resolver. 119 | func NewStructResolver(s reflect.Value) *StructResolver { 120 | return &StructResolver{s} 121 | } 122 | 123 | // Resolve implements Resolver. 124 | func (r *StructResolver) Resolve(ident string) Value { 125 | if sv := r.struc.FieldByName(ident); sv.IsValid() { 126 | return ValueOf(sv.Interface()) 127 | } 128 | return nil 129 | } 130 | 131 | // MapTypeResolver resolves map keys. 132 | type MapTypeResolver struct { 133 | m map[string]Type 134 | } 135 | 136 | // NewMapTypeResolver creates a new struct resolver. 137 | func NewMapTypeResolver(m map[string]Type) *MapTypeResolver { 138 | return &MapTypeResolver{m} 139 | } 140 | 141 | // TypeResolve implements TypeResolver. 142 | func (r *MapTypeResolver) TypeResolve(ident string) Type { 143 | if t, ok := r.m[ident]; ok { 144 | return t 145 | } 146 | return nil 147 | } 148 | 149 | // MapResolver resolves map keys. 150 | type MapResolver struct { 151 | m map[string]Value 152 | } 153 | 154 | // NewMapResolver creates a new struct resolver. 155 | func NewMapResolver(m map[string]Value) *MapResolver { 156 | return &MapResolver{m} 157 | } 158 | 159 | // Resolve implements Resolver. 160 | func (r *MapResolver) Resolve(ident string) Value { 161 | if v, ok := r.m[ident]; ok { 162 | return v 163 | } 164 | return nil 165 | } 166 | -------------------------------------------------------------------------------- /expr/env_test.go: -------------------------------------------------------------------------------- 1 | package expr 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestStructResolver(t *testing.T) { 11 | v := struct { 12 | A int 13 | B int32 14 | }{ 15 | A: 1, 16 | B: 2, 17 | } 18 | resolver := NewStructResolver(reflect.ValueOf(v)) 19 | typeResolver := NewStructTypeResolver(v) 20 | assert.Equal(t, 1, resolver.Resolve("A").RawValue()) 21 | assert.Equal(t, int32(2), resolver.Resolve("B").RawValue()) 22 | assert.Equal(t, nil, resolver.Resolve("C")) 23 | assert.Equal(t, Int, typeResolver.TypeResolve("A").Kind()) 24 | assert.Equal(t, Int32, typeResolver.TypeResolve("B").Kind()) 25 | assert.Equal(t, nil, typeResolver.TypeResolve("C")) 26 | } 27 | 28 | func TestMapResolver(t *testing.T) { 29 | resolver := NewMapResolver(map[string]Value{ 30 | "A": ValueOf(1), 31 | "B": ValueOf(int32(2)), 32 | }) 33 | typeResolver := NewMapTypeResolver(map[string]Type{ 34 | "A": TypeOf(1), 35 | "B": TypeOf(int32(2)), 36 | }) 37 | assert.Equal(t, 1, resolver.Resolve("A").RawValue()) 38 | assert.Equal(t, int32(2), resolver.Resolve("B").RawValue()) 39 | assert.Equal(t, nil, resolver.Resolve("C")) 40 | assert.Equal(t, Int, typeResolver.TypeResolve("A").Kind()) 41 | assert.Equal(t, Int32, typeResolver.TypeResolve("B").Kind()) 42 | assert.Equal(t, nil, typeResolver.TypeResolve("C")) 43 | } 44 | 45 | func TestTypeResolverAdapter(t *testing.T) { 46 | typeResolver := NewTypeResolverAdapter(NewMapResolver(map[string]Value{ 47 | "A": ValueOf(1), 48 | "B": ValueOf(int32(2)), 49 | })) 50 | assert.Equal(t, Int, typeResolver.TypeResolve("A").Kind()) 51 | assert.Equal(t, Int32, typeResolver.TypeResolve("B").Kind()) 52 | assert.Equal(t, nil, typeResolver.TypeResolve("C")) 53 | } 54 | 55 | func TestMetaResolver(t *testing.T) { 56 | v := struct{ A int }{A: 1} 57 | resolver := NewMetaResolver() 58 | typeResolver := NewMetaTypeResolver() 59 | resolver.AddResolver(NewStructResolver(reflect.ValueOf(v))) 60 | resolver.AddResolver(NewMapResolver(map[string]Value{"B": ValueOf(int32(2))})) 61 | typeResolver.AddResolver(NewStructTypeResolver(v)) 62 | typeResolver.AddResolver(NewMapTypeResolver(map[string]Type{"B": TypeOf(int32(2))})) 63 | assert.Equal(t, 1, resolver.Resolve("A").RawValue()) 64 | assert.Equal(t, int32(2), resolver.Resolve("B").RawValue()) 65 | assert.Equal(t, nil, resolver.Resolve("C")) 66 | assert.Equal(t, Int, typeResolver.TypeResolve("A").Kind()) 67 | assert.Equal(t, Int32, typeResolver.TypeResolve("B").Kind()) 68 | assert.Equal(t, nil, typeResolver.TypeResolve("C")) 69 | } 70 | -------------------------------------------------------------------------------- /expr/eval.go: -------------------------------------------------------------------------------- 1 | package expr 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // EvalProgram returns the result of executing the program with the given resolver. 8 | func EvalProgram(resolver Resolver, program *Program) (v interface{}, err error) { 9 | defer func() { 10 | if r := recover(); r != nil { 11 | if rerr, ok := r.(error); ok { 12 | err = rerr 13 | } else { 14 | panic(r) 15 | } 16 | } 17 | }() 18 | 19 | v = evalnode(resolver, program.root).RawValue() 20 | return 21 | } 22 | 23 | // Eval returns the result of evaluating the provided expression. 24 | func Eval(resolver Resolver, expr string) (interface{}, error) { 25 | return EvalProgram(resolver, ParseString(expr)) 26 | } 27 | 28 | func evalnode(resolver Resolver, node node) Value { 29 | switch n := node.(type) { 30 | case identnode: 31 | v := resolver.Resolve(n.ident) 32 | if v == nil { 33 | panic(fmt.Errorf("unresolved name %s", n.ident)) 34 | } 35 | return v 36 | case intnode: 37 | if n.sign { 38 | return literalintval(n.ival) 39 | } 40 | return literaluintval(n.uval) 41 | case floatnode: 42 | return literalfloatval(n.fval) 43 | case boolnode: 44 | return literalboolval(n.val) 45 | case strnode: 46 | return literalstrval(n.val) 47 | case runenode: 48 | return literalintval(int64(n.val)) 49 | case nilnode: 50 | return literalnilval() 51 | case unaryexpr: 52 | return evalunary(resolver, n) 53 | case binaryexpr: 54 | return evalbinary(resolver, n) 55 | case ternaryexpr: 56 | return evalternary(resolver, n) 57 | default: 58 | panic("invalid node") 59 | } 60 | } 61 | 62 | func evalunary(resolver Resolver, node unaryexpr) Value { 63 | n := evalnode(resolver, node.n) 64 | switch node.op { 65 | case unaryplus: 66 | return n 67 | case unarynegate: 68 | return n.Negate() 69 | case unarynot: 70 | return n.Not() 71 | case unarybitnot: 72 | return n.BitNot() 73 | case unaryderef: 74 | return n.Deref() 75 | case unaryref: 76 | return n.Ref() 77 | default: 78 | panic("invalid unary expression") 79 | } 80 | } 81 | 82 | func flattengroup(n node) []node { 83 | if n, ok := n.(binaryexpr); ok { 84 | if n.op == binarygroup { 85 | return append(flattengroup(n.a), flattengroup(n.b)...) 86 | } 87 | } 88 | return []node{n} 89 | } 90 | 91 | func evalbinary(resolver Resolver, node binaryexpr) Value { 92 | a := evalnode(resolver, node.a) 93 | switch node.op { 94 | case binarymember: 95 | if id, ok := node.b.(identnode); ok { 96 | return a.Dot(id.ident) 97 | } 98 | panic(fmt.Errorf("expected ident node, got %T", node.b)) 99 | case binarycall: 100 | in := []Value{} 101 | for _, n := range flattengroup(node.b) { 102 | in = append(in, evalnode(resolver, n)) 103 | } 104 | return a.Call(in) 105 | case binarygroup: 106 | return evalnode(resolver, node.b) 107 | } 108 | 109 | b := evalnode(resolver, node.b) 110 | switch node.op { 111 | case binarylogicalor: 112 | return a.LogicalOr(b) 113 | case binarylogicaland: 114 | return a.LogicalAnd(b) 115 | case binaryequal: 116 | return a.Equal(b) 117 | case binarynotequal: 118 | return a.NotEqual(b) 119 | case binarylesser: 120 | return a.Lesser(b) 121 | case binarylesserequal: 122 | return a.LesserEqual(b) 123 | case binarygreater: 124 | return a.Greater(b) 125 | case binarygreaterequal: 126 | return a.GreaterEqual(b) 127 | case binaryadd: 128 | return a.Add(b) 129 | case binarysub: 130 | return a.Sub(b) 131 | case binaryor: 132 | return a.Or(b) 133 | case binaryxor: 134 | return a.Xor(b) 135 | case binarymul: 136 | return a.Mul(b) 137 | case binarydiv: 138 | return a.Div(b) 139 | case binaryrem: 140 | return a.Rem(b) 141 | case binarylsh: 142 | return a.Lsh(b) 143 | case binaryrsh: 144 | return a.Rsh(b) 145 | case binaryand: 146 | return a.And(b) 147 | case binaryandnot: 148 | return a.AndNot(b) 149 | case binarysubscript: 150 | return a.Index(b) 151 | default: 152 | panic("invalid binary expression") 153 | } 154 | } 155 | 156 | func evalternary(resolver Resolver, node ternaryexpr) Value { 157 | a := evalnode(resolver, node.a).Value().Interface() 158 | cond, ok := a.(bool) 159 | if !ok { 160 | panic(fmt.Errorf("unexpected type %T for ternary", cond)) 161 | } 162 | if cond { 163 | return evalnode(resolver, node.b) 164 | } 165 | return evalnode(resolver, node.c) 166 | } 167 | -------------------------------------------------------------------------------- /expr/eval_test.go: -------------------------------------------------------------------------------- 1 | package expr 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | type TestStruct1 struct { 11 | A int 12 | B float64 13 | } 14 | 15 | func TestEvalSimple(t *testing.T) { 16 | tests := []struct { 17 | struc interface{} 18 | expr string 19 | result interface{} 20 | }{ 21 | { 22 | TestStruct1{A: 42}, 23 | "A", 24 | 42, 25 | }, 26 | { 27 | TestStruct1{A: 42}, 28 | "A * 2", 29 | 84, 30 | }, 31 | { 32 | TestStruct1{B: 10.5}, 33 | "B * 2", 34 | 21.0, 35 | }, 36 | { 37 | TestStruct1{B: 10.5}, 38 | "-(B * 2)", 39 | -21.0, 40 | }, 41 | { 42 | TestStruct1{A: 0xf0}, 43 | "^0xf0 | A", 44 | -1, 45 | }, 46 | { 47 | TestStruct1{}, 48 | "2 << 2", 49 | 8, 50 | }, 51 | { 52 | TestStruct1{}, 53 | "true", 54 | true, 55 | }, 56 | { 57 | TestStruct1{}, 58 | "false", 59 | false, 60 | }, 61 | { 62 | TestStruct1{}, 63 | "true ? 1.0 : 0.0", 64 | 1.0, 65 | }, 66 | { 67 | TestStruct1{}, 68 | "false ? 1.0 : 0.0", 69 | 0.0, 70 | }, 71 | { 72 | TestStruct1{}, 73 | `"string value!"`, 74 | "string value!", 75 | }, 76 | { 77 | TestStruct1{}, 78 | `"equal" == "equal"`, 79 | true, 80 | }, 81 | { 82 | TestStruct1{}, 83 | `"equal" == "not equal"`, 84 | false, 85 | }, 86 | { 87 | TestStruct1{}, 88 | `"equal" != "not equal"`, 89 | true, 90 | }, 91 | { 92 | TestStruct1{}, 93 | `"equal" != "equal"`, 94 | false, 95 | }, 96 | { 97 | TestStruct1{}, 98 | `"equal"[1] == 'q'`, 99 | true, 100 | }, 101 | } 102 | 103 | for _, test := range tests { 104 | resolver := NewStructResolver(reflect.ValueOf(test.struc)) 105 | result, err := Eval(resolver, test.expr) 106 | assert.Nil(t, err) 107 | assert.Equal(t, test.result, result) 108 | } 109 | } 110 | 111 | func TestError(t *testing.T) { 112 | tests := []struct { 113 | struc interface{} 114 | expr string 115 | err string 116 | }{ 117 | { 118 | TestStruct1{A: 42}, 119 | "!A", 120 | "invalid operation: operator ! not defined for 42 (int)", 121 | }, 122 | { 123 | TestStruct1{}, 124 | "!42", 125 | "invalid operation: operator ! not defined for 42 (untyped int constant)", 126 | }, 127 | { 128 | TestStruct1{A: 1, B: 1.0}, 129 | "A == B", 130 | "cannot convert int to float64", 131 | }, 132 | { 133 | TestStruct1{A: 1, B: 1.0}, 134 | "A == true", 135 | "cannot convert int to untyped bool constant", 136 | }, 137 | { 138 | TestStruct1{A: 1, B: 1.0}, 139 | "A > true", 140 | "cannot convert int to untyped bool constant", 141 | }, 142 | } 143 | 144 | for _, test := range tests { 145 | resolver := NewStructResolver(reflect.ValueOf(test.struc)) 146 | _, err := Eval(resolver, test.expr) 147 | assert.EqualError(t, err, test.err) 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /expr/lex.go: -------------------------------------------------------------------------------- 1 | package expr 2 | 3 | //go:generate stringer -type=tokenkind 4 | 5 | import ( 6 | "fmt" 7 | "io" 8 | "strconv" 9 | "unicode" 10 | "unicode/utf8" 11 | ) 12 | 13 | func lower(ch rune) rune { 14 | return ('a' - 'A') | ch 15 | } 16 | 17 | func isdecimal(ch rune) bool { 18 | return '0' <= ch && ch <= '9' 19 | } 20 | 21 | func isoctal(ch rune) bool { 22 | return '0' <= ch && ch <= '7' 23 | } 24 | 25 | func ishex(ch rune) bool { 26 | return '0' <= ch && ch <= '9' || 'a' <= lower(ch) && lower(ch) <= 'f' 27 | } 28 | 29 | func isletter(c rune) bool { 30 | return 'a' <= lower(c) && lower(c) <= 'z' || c == '_' || c >= utf8.RuneSelf && unicode.IsLetter(c) 31 | } 32 | 33 | func isdigit(c rune) bool { 34 | return isdecimal(c) || c >= utf8.RuneSelf && unicode.IsDigit(c) 35 | } 36 | 37 | func isnumber(c rune) bool { 38 | return isdigit(c) || ishex(c) || c == '.' || lower(c) == 'x' 39 | } 40 | 41 | func isident(c rune) bool { 42 | return isletter(c) || isdigit(c) 43 | } 44 | 45 | func iswhitespace(c rune) bool { 46 | return c == ' ' || c == '\t' 47 | } 48 | 49 | // tokenkind is an enumeration of different kinds of tokens. 50 | type tokenkind int 51 | 52 | // This is a definition of all possible token kinds. 53 | const ( 54 | niltoken tokenkind = iota 55 | errtoken 56 | eoftoken 57 | 58 | identtoken 59 | inttoken 60 | floattoken 61 | booltoken 62 | strtoken 63 | runetoken 64 | 65 | addtoken 66 | subtoken 67 | multoken 68 | quotoken 69 | remtoken 70 | 71 | andtoken 72 | nottoken 73 | ortoken 74 | xortoken 75 | shltoken 76 | shrtoken 77 | andnottoken 78 | 79 | logicalandtoken 80 | logicalortoken 81 | 82 | equaltoken 83 | lessertoken 84 | greatertoken 85 | notequaltoken 86 | lesserequaltoken 87 | greaterequaltoken 88 | 89 | leftparentoken 90 | leftbrackettoken 91 | commatoken 92 | periodtoken 93 | 94 | rightparentoken 95 | rightbrackettoken 96 | colontoken 97 | ternarytoken 98 | 99 | boolkeyword 100 | bytekeyword 101 | float32keyword 102 | float64keyword 103 | intkeyword 104 | int8keyword 105 | int16keyword 106 | int32keyword 107 | int64keyword 108 | uintkeyword 109 | uint8keyword 110 | uint16keyword 111 | uint32keyword 112 | uint64keyword 113 | uintptrkeyword 114 | nilkeyword 115 | ) 116 | 117 | var keywordmap = map[string]tokenkind{ 118 | "bool": boolkeyword, 119 | "byte": bytekeyword, 120 | "float32": float32keyword, 121 | "float64": float64keyword, 122 | "int": intkeyword, 123 | "int8": int8keyword, 124 | "int16": int16keyword, 125 | "int32": int32keyword, 126 | "int64": int64keyword, 127 | "uint": uintkeyword, 128 | "uint8": uint8keyword, 129 | "uint16": uint16keyword, 130 | "uint32": uint32keyword, 131 | "uint64": uint64keyword, 132 | "uintptr": uintptrkeyword, 133 | "nil": nilkeyword, 134 | } 135 | 136 | const eof = utf8.MaxRune + 0x0001 137 | 138 | // token contains information for a single lexical token. 139 | type token struct { 140 | kind tokenkind 141 | pos int 142 | 143 | sval string 144 | ival int64 145 | uval uint64 146 | fval float64 147 | bval bool 148 | sign bool 149 | eval error 150 | } 151 | 152 | // scanner scans lexical tokens from the expression. 153 | type scanner struct { 154 | r io.RuneScanner 155 | p int 156 | eof bool 157 | } 158 | 159 | func newscanner(r io.RuneScanner) *scanner { 160 | return &scanner{r: r} 161 | } 162 | 163 | func (s *scanner) readrune() rune { 164 | if s.eof { 165 | return eof 166 | } 167 | c, _, err := s.r.ReadRune() 168 | if err == io.EOF { 169 | s.eof = true 170 | return eof 171 | } else if err != nil { 172 | panic(err) 173 | } 174 | s.p++ 175 | return c 176 | } 177 | 178 | func (s *scanner) unreadrune() { 179 | if s.eof { 180 | return 181 | } 182 | if err := s.r.UnreadRune(); err != nil { 183 | panic(err) 184 | } 185 | s.p-- 186 | } 187 | 188 | func (s *scanner) skipws() { 189 | for { 190 | c := s.readrune() 191 | if !iswhitespace(c) { 192 | s.unreadrune() 193 | return 194 | } 195 | } 196 | } 197 | 198 | func (s *scanner) accept(c rune) bool { 199 | if s.readrune() == c { 200 | return true 201 | } 202 | s.unreadrune() 203 | return false 204 | } 205 | 206 | func (s *scanner) expect(c rune) { 207 | r := s.readrune() 208 | if r != c { 209 | panic(fmt.Errorf("expected %c", r)) 210 | } 211 | } 212 | 213 | func (s *scanner) peekmatch(f func(rune) bool) bool { 214 | c := s.readrune() 215 | s.unreadrune() 216 | return f(c) 217 | } 218 | 219 | func (s *scanner) acceptfn(f func(rune) bool) (rune, bool) { 220 | r := s.readrune() 221 | if f(r) { 222 | return r, true 223 | } 224 | s.unreadrune() 225 | return r, false 226 | } 227 | 228 | func (s *scanner) expectfn(f func(rune) bool) rune { 229 | r, ok := s.acceptfn(f) 230 | if !ok { 231 | panic(fmt.Errorf("unexpected %c", r)) 232 | } 233 | return r 234 | } 235 | 236 | func (s *scanner) tokensym(k tokenkind, src string) token { 237 | return token{kind: k, sval: src} 238 | } 239 | 240 | func (s *scanner) errsymf(format string, a ...interface{}) token { 241 | return token{kind: errtoken, eval: fmt.Errorf(format, a...)} 242 | } 243 | 244 | func (s *scanner) scanident() token { 245 | t := token{kind: identtoken} 246 | if r, ok := s.acceptfn(isletter); ok { 247 | t.sval = string(r) 248 | } else { 249 | return s.errsymf("unexpected ident start token: %c", r) 250 | } 251 | for { 252 | if r, ok := s.acceptfn(isident); ok { 253 | t.sval += string(r) 254 | continue 255 | } 256 | break 257 | } 258 | // Handle boolean constant. 259 | if t.sval == "true" { 260 | t.kind = booltoken 261 | t.bval = true 262 | } 263 | if t.sval == "false" { 264 | t.kind = booltoken 265 | t.bval = false 266 | } 267 | // Handle keywords. 268 | if k, ok := keywordmap[t.sval]; ok { 269 | t.kind = k 270 | } 271 | return t 272 | } 273 | 274 | func (s *scanner) scannumber(t token) token { 275 | if r, ok := s.acceptfn(isnumber); ok { 276 | t.sval += string(r) 277 | } else { 278 | return s.errsymf("unexpected int start token: %c", r) 279 | } 280 | for { 281 | if r, ok := s.acceptfn(isnumber); ok { 282 | t.sval += string(r) 283 | continue 284 | } 285 | break 286 | } 287 | var err error 288 | if t.uval, err = strconv.ParseUint(t.sval, 0, 64); err == nil { 289 | t.ival = int64(t.uval) 290 | t.fval = float64(t.ival) 291 | t.kind = inttoken 292 | t.sign = false 293 | } else if t.ival, err = strconv.ParseInt(t.sval, 0, 64); err == nil { 294 | t.uval = uint64(t.ival) 295 | t.fval = float64(t.ival) 296 | t.kind = inttoken 297 | t.sign = true 298 | } else if t.fval, err = strconv.ParseFloat(t.sval, 64); err == nil { 299 | t.ival = int64(t.fval) 300 | t.uval = uint64(t.fval) 301 | t.kind = floattoken 302 | } else { 303 | return token{kind: errtoken, eval: err} 304 | } 305 | return t 306 | } 307 | 308 | func runebytes(r rune) []byte { 309 | runebuf := [4]byte{} 310 | l := utf8.EncodeRune(runebuf[:], rune(r)) 311 | return runebuf[:l] 312 | } 313 | 314 | func (s *scanner) scanescape(quote byte) []byte { 315 | switch { 316 | case s.accept('a'): 317 | return []byte{'\a'} 318 | case s.accept('b'): 319 | return []byte{'\b'} 320 | case s.accept('f'): 321 | return []byte{'\f'} 322 | case s.accept('n'): 323 | return []byte{'\n'} 324 | case s.accept('r'): 325 | return []byte{'\r'} 326 | case s.accept('t'): 327 | return []byte{'\t'} 328 | case s.accept('v'): 329 | return []byte{'\v'} 330 | case s.accept('\\'): 331 | return []byte{'\\'} 332 | case s.accept(rune(quote)): 333 | return []byte{quote} 334 | case s.peekmatch(isoctal): 335 | octal := string([]rune{s.expectfn(isoctal), s.expectfn(isoctal), s.expectfn(isoctal)}) 336 | code, err := strconv.ParseUint(octal, 8, 8) 337 | if err != nil { 338 | panic(err) 339 | } 340 | return []byte{byte(code)} 341 | case s.accept('x'): 342 | hex := string([]rune{s.expectfn(ishex), s.expectfn(ishex)}) 343 | code, err := strconv.ParseUint(hex, 16, 8) 344 | if err != nil { 345 | panic(err) 346 | } 347 | return []byte{byte(code)} 348 | case s.accept('u'): 349 | hex := string([]rune{ 350 | s.expectfn(ishex), s.expectfn(ishex), s.expectfn(ishex), s.expectfn(ishex), 351 | }) 352 | code, err := strconv.ParseUint(hex, 16, 16) 353 | if err != nil { 354 | panic(err) 355 | } 356 | return runebytes(rune(code)) 357 | case s.accept('U'): 358 | hex := string([]rune{ 359 | s.expectfn(ishex), s.expectfn(ishex), s.expectfn(ishex), s.expectfn(ishex), 360 | s.expectfn(ishex), s.expectfn(ishex), s.expectfn(ishex), s.expectfn(ishex), 361 | }) 362 | code, err := strconv.ParseUint(hex, 16, 32) 363 | if err != nil { 364 | panic(err) 365 | } 366 | return runebytes(rune(code)) 367 | default: 368 | panic(fmt.Errorf("unexpected escape code %c", s.readrune())) 369 | } 370 | } 371 | 372 | func (s *scanner) scanstring(quote byte) token { 373 | str := []byte{} 374 | for { 375 | switch { 376 | case s.accept(rune(quote)): 377 | return token{kind: strtoken, sval: string(str)} 378 | case s.accept('\\'): 379 | str = append(str, s.scanescape(quote)...) 380 | default: 381 | str = append(str, runebytes(s.readrune())...) 382 | } 383 | } 384 | } 385 | 386 | func (s *scanner) scanrune() token { 387 | defer s.expect('\'') 388 | switch { 389 | case s.accept('\\'): 390 | r := []rune(string(s.scanescape('\''))) 391 | return token{kind: runetoken, ival: int64(r[0])} 392 | default: 393 | return token{kind: runetoken, ival: int64(s.readrune())} 394 | } 395 | } 396 | 397 | func (s *scanner) scan() (t token) { 398 | defer func() { 399 | if r := recover(); r != nil { 400 | if err, ok := r.(error); ok { 401 | t = token{kind: errtoken, pos: s.p, eval: err} 402 | } else { 403 | panic(r) 404 | } 405 | } 406 | }() 407 | 408 | s.skipws() 409 | 410 | p := s.p 411 | 412 | defer func() { 413 | t.pos = p 414 | }() 415 | 416 | switch { 417 | case s.accept(eof): 418 | p = s.p 419 | return token{kind: eoftoken} 420 | case s.peekmatch(isletter): 421 | return s.scanident() 422 | case s.peekmatch(isdigit): 423 | return s.scannumber(token{}) 424 | case s.accept('"'): 425 | return s.scanstring('"') 426 | case s.accept('\''): 427 | return s.scanrune() 428 | case s.accept('$'): 429 | s.expect('\'') 430 | return s.scanstring('\'') 431 | case s.accept('+'): 432 | return s.tokensym(addtoken, "+") 433 | case s.accept('-'): 434 | switch { 435 | default: 436 | return s.tokensym(subtoken, "-") 437 | case s.peekmatch(isdigit): 438 | return s.scannumber(token{sval: "-"}) 439 | } 440 | case s.accept('*'): 441 | return s.tokensym(multoken, "*") 442 | case s.accept('/'): 443 | return s.tokensym(quotoken, "/") 444 | case s.accept('%'): 445 | return s.tokensym(remtoken, "%") 446 | case s.accept('&'): 447 | switch { 448 | default: 449 | return s.tokensym(andtoken, "&") 450 | case s.accept('&'): 451 | return s.tokensym(logicalandtoken, "&&") 452 | case s.accept('^'): 453 | return s.tokensym(andnottoken, "&^") 454 | } 455 | case s.accept('|'): 456 | switch { 457 | default: 458 | return s.tokensym(ortoken, "|") 459 | case s.accept('|'): 460 | return s.tokensym(logicalortoken, "||") 461 | } 462 | case s.accept('^'): 463 | switch { 464 | default: 465 | return s.tokensym(xortoken, "^") 466 | } 467 | case s.accept('<'): 468 | switch { 469 | default: 470 | return s.tokensym(lessertoken, "<") 471 | case s.accept('='): 472 | return s.tokensym(lesserequaltoken, "<=") 473 | case s.accept('<'): 474 | return s.tokensym(shltoken, "<<") 475 | } 476 | case s.accept('>'): 477 | switch { 478 | default: 479 | return s.tokensym(greatertoken, ">") 480 | case s.accept('='): 481 | return s.tokensym(greaterequaltoken, ">=") 482 | case s.accept('>'): 483 | return s.tokensym(shrtoken, ">>") 484 | } 485 | case s.accept('='): 486 | switch { 487 | case s.accept('='): 488 | return s.tokensym(equaltoken, "==") 489 | default: 490 | return s.errsymf("unexpected rune %c", s.readrune()) 491 | } 492 | case s.accept('!'): 493 | switch { 494 | case s.accept('='): 495 | return s.tokensym(notequaltoken, "!=") 496 | default: 497 | return s.tokensym(nottoken, "!") 498 | } 499 | case s.accept('('): 500 | return s.tokensym(leftparentoken, "(") 501 | case s.accept('['): 502 | return s.tokensym(leftbrackettoken, "[") 503 | case s.accept(','): 504 | return s.tokensym(commatoken, ",") 505 | case s.accept('.'): 506 | switch { 507 | default: 508 | return s.tokensym(periodtoken, ".") 509 | case s.peekmatch(isdigit): 510 | return s.scannumber(token{sval: "."}) 511 | } 512 | case s.accept(')'): 513 | return s.tokensym(rightparentoken, ")") 514 | case s.accept(']'): 515 | return s.tokensym(rightbrackettoken, "]") 516 | case s.accept(':'): 517 | return s.tokensym(colontoken, ":") 518 | case s.accept('?'): 519 | return s.tokensym(ternarytoken, "?") 520 | default: 521 | return s.errsymf("unexpected rune %c", s.readrune()) 522 | } 523 | } 524 | -------------------------------------------------------------------------------- /expr/lex_test.go: -------------------------------------------------------------------------------- 1 | package expr 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestScanValid(t *testing.T) { 11 | tests := []struct { 12 | input string 13 | expected []token 14 | }{ 15 | { 16 | input: "a + b - c * d / e ^ f | g & h &^ i % k", 17 | expected: []token{ 18 | {kind: identtoken, sval: "a", pos: 0}, 19 | {kind: addtoken, sval: "+", pos: 2}, 20 | {kind: identtoken, sval: "b", pos: 4}, 21 | {kind: subtoken, sval: "-", pos: 6}, 22 | {kind: identtoken, sval: "c", pos: 8}, 23 | {kind: multoken, sval: "*", pos: 10}, 24 | {kind: identtoken, sval: "d", pos: 12}, 25 | {kind: quotoken, sval: "/", pos: 14}, 26 | {kind: identtoken, sval: "e", pos: 16}, 27 | {kind: xortoken, sval: "^", pos: 18}, 28 | {kind: identtoken, sval: "f", pos: 20}, 29 | {kind: ortoken, sval: "|", pos: 22}, 30 | {kind: identtoken, sval: "g", pos: 24}, 31 | {kind: andtoken, sval: "&", pos: 26}, 32 | {kind: identtoken, sval: "h", pos: 28}, 33 | {kind: andnottoken, sval: "&^", pos: 30}, 34 | {kind: identtoken, sval: "i", pos: 33}, 35 | {kind: remtoken, sval: "%", pos: 35}, 36 | {kind: identtoken, sval: "k", pos: 37}, 37 | {kind: eoftoken, pos: 38}, 38 | }, 39 | }, 40 | { 41 | input: "l > m < n >= o <= p == q != r >> s << t || u && v", 42 | expected: []token{ 43 | {kind: identtoken, sval: "l", pos: 0}, 44 | {kind: greatertoken, sval: ">", pos: 2}, 45 | {kind: identtoken, sval: "m", pos: 4}, 46 | {kind: lessertoken, sval: "<", pos: 6}, 47 | {kind: identtoken, sval: "n", pos: 8}, 48 | {kind: greaterequaltoken, sval: ">=", pos: 10}, 49 | {kind: identtoken, sval: "o", pos: 13}, 50 | {kind: lesserequaltoken, sval: "<=", pos: 15}, 51 | {kind: identtoken, sval: "p", pos: 18}, 52 | {kind: equaltoken, sval: "==", pos: 20}, 53 | {kind: identtoken, sval: "q", pos: 23}, 54 | {kind: notequaltoken, sval: "!=", pos: 25}, 55 | {kind: identtoken, sval: "r", pos: 28}, 56 | {kind: shrtoken, sval: ">>", pos: 30}, 57 | {kind: identtoken, sval: "s", pos: 33}, 58 | {kind: shltoken, sval: "<<", pos: 35}, 59 | {kind: identtoken, sval: "t", pos: 38}, 60 | {kind: logicalortoken, sval: "||", pos: 40}, 61 | {kind: identtoken, sval: "u", pos: 43}, 62 | {kind: logicalandtoken, sval: "&&", pos: 45}, 63 | {kind: identtoken, sval: "v", pos: 48}, 64 | {kind: eoftoken, pos: 49}, 65 | }, 66 | }, 67 | { 68 | input: "(A + Test) % C[0]", 69 | expected: []token{ 70 | {kind: leftparentoken, pos: 0, sval: "("}, 71 | {kind: identtoken, pos: 1, sval: "A"}, 72 | {kind: addtoken, pos: 3, sval: "+"}, 73 | {kind: identtoken, pos: 5, sval: "Test"}, 74 | {kind: rightparentoken, pos: 9, sval: ")"}, 75 | {kind: remtoken, pos: 11, sval: "%"}, 76 | {kind: identtoken, pos: 13, sval: "C"}, 77 | {kind: leftbrackettoken, pos: 14, sval: "["}, 78 | {kind: inttoken, pos: 15, sval: "0"}, 79 | {kind: rightbrackettoken, pos: 16, sval: "]"}, 80 | {kind: eoftoken, pos: 17}, 81 | }, 82 | }, 83 | { 84 | input: "0x80000000 + 0.1", 85 | expected: []token{ 86 | {kind: inttoken, pos: 0, sval: "0x80000000", ival: 0x80000000, uval: 0x80000000, fval: 0x80000000}, 87 | {kind: addtoken, pos: 11, sval: "+"}, 88 | {kind: floattoken, pos: 13, sval: "0.1", ival: 0, uval: 0, fval: 0.1}, 89 | {kind: eoftoken, pos: 16}, 90 | }, 91 | }, 92 | { 93 | input: "0x80000000 + 0.1", 94 | expected: []token{ 95 | {kind: inttoken, pos: 0, sval: "0x80000000", ival: 0x80000000, uval: 0x80000000, fval: 0x80000000}, 96 | {kind: addtoken, pos: 11, sval: "+"}, 97 | {kind: floattoken, pos: 13, sval: "0.1", ival: 0, uval: 0, fval: 0.1}, 98 | {kind: eoftoken, pos: 16}, 99 | }, 100 | }, 101 | { 102 | input: "-0x80000000 - -0.1", 103 | expected: []token{ 104 | {kind: inttoken, pos: 0, sval: "-0x80000000", ival: -0x80000000, uval: 0xFFFFFFFF80000000, fval: -0x80000000, sign: true}, 105 | {kind: subtoken, pos: 12, sval: "-"}, 106 | {kind: floattoken, pos: 14, sval: "-0.1", ival: 0, uval: 0, fval: -0.1}, 107 | {kind: eoftoken, pos: 18}, 108 | }, 109 | }, 110 | { 111 | input: `"a b c" + " d e f"`, 112 | expected: []token{ 113 | {kind: strtoken, pos: 0, sval: "a b c"}, 114 | {kind: addtoken, pos: 8, sval: "+"}, 115 | {kind: strtoken, pos: 10, sval: " d e f"}, 116 | {kind: eoftoken, pos: 18}, 117 | }, 118 | }, 119 | { 120 | input: `'a' + 0`, 121 | expected: []token{ 122 | {kind: runetoken, pos: 0, ival: 'a'}, 123 | {kind: addtoken, pos: 4, sval: "+"}, 124 | {kind: inttoken, pos: 6, sval: "0", ival: 0, uval: 0, fval: 0}, 125 | {kind: eoftoken, pos: 7}, 126 | }, 127 | }, 128 | { 129 | input: `"aä本\t\000\007\377\x07\xff\u12e4\U00101234\""`, 130 | expected: []token{ 131 | {kind: strtoken, pos: 0, sval: "aä本\t\000\007\377\x07\xff\u12e4\U00101234\""}, 132 | {kind: eoftoken, pos: 45}, 133 | }, 134 | }, 135 | } 136 | 137 | for _, test := range tests { 138 | t.Run(test.input, func(t *testing.T) { 139 | actual := []token{} 140 | s := newscanner(bytes.NewBufferString(test.input)) 141 | for { 142 | t := s.scan() 143 | actual = append(actual, t) 144 | if t.kind == eoftoken || t.kind == errtoken { 145 | break 146 | } 147 | if len(actual) > 500 { 148 | panic("Maximum test token limit exceeded.") 149 | } 150 | } 151 | assert.Equal(t, test.expected, actual) 152 | }) 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /expr/package.go: -------------------------------------------------------------------------------- 1 | package expr 2 | 3 | // Package represents a package value. 4 | type Package struct { 5 | types map[string]Type 6 | symbols map[string]Value 7 | } 8 | 9 | // NewPackage creates a new package. 10 | func NewPackage(symbols map[string]Value) Package { 11 | pkg := Package{symbols: symbols, types: map[string]Type{}} 12 | for key := range symbols { 13 | pkg.types[key] = pkg.symbols[key].Type() 14 | } 15 | return pkg 16 | } 17 | 18 | // Symbol returns a symbol, or nil if the symbol doesn't exist. 19 | func (p Package) Symbol(ident string) Value { 20 | if symbol, ok := p.symbols[ident]; ok { 21 | return symbol 22 | } 23 | return nil 24 | } 25 | 26 | // Type returns the type for this package. 27 | func (p Package) Type() Type { 28 | return NewPackageType(p.types) 29 | } 30 | -------------------------------------------------------------------------------- /expr/package_test.go: -------------------------------------------------------------------------------- 1 | package expr 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestPackage(t *testing.T) { 10 | pkg := NewPackage(map[string]Value{ 11 | "A": ValueOf(1), 12 | "B": ValueOf(int32(2)), 13 | }) 14 | assert.Equal(t, 1, pkg.Symbol("A").RawValue()) 15 | assert.Equal(t, int32(2), pkg.Symbol("B").RawValue()) 16 | assert.Equal(t, nil, pkg.Symbol("C")) 17 | assert.Equal(t, Int, pkg.Type().(*PackageType).Symbol("A").Kind()) 18 | assert.Equal(t, Int32, pkg.Type().(*PackageType).Symbol("B").Kind()) 19 | assert.Equal(t, nil, pkg.Type().(*PackageType).Symbol("C")) 20 | } 21 | -------------------------------------------------------------------------------- /expr/parse.go: -------------------------------------------------------------------------------- 1 | package expr 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | ) 8 | 9 | // Program represents a parsed expression. 10 | type Program struct { 11 | root node 12 | } 13 | 14 | // Parse parses an expression into a program. 15 | func Parse(r io.RuneScanner) *Program { 16 | return &Program{newparser(newscanner(r)).parse()} 17 | } 18 | 19 | // ParseString parses an expression from a string. 20 | func ParseString(s string) *Program { 21 | return Parse(bytes.NewBufferString(s)) 22 | } 23 | 24 | type parser struct { 25 | s *scanner 26 | 27 | a bool 28 | t token 29 | } 30 | 31 | func newparser(s *scanner) *parser { 32 | return &parser{s: s} 33 | } 34 | 35 | func (p *parser) readtoken() *token { 36 | if !p.a { 37 | p.a = true 38 | p.t = p.s.scan() 39 | } 40 | return &p.t 41 | } 42 | 43 | func (p *parser) consume() { 44 | p.a = false 45 | } 46 | 47 | func (p *parser) accept(k tokenkind) bool { 48 | if p.readtoken().kind == k { 49 | p.consume() 50 | return true 51 | } 52 | return false 53 | } 54 | 55 | func (p *parser) expect(k tokenkind) { 56 | if p.readtoken().kind != k { 57 | panic(fmt.Errorf("expected %s token, got %s", k, p.t.kind)) 58 | } 59 | p.consume() 60 | } 61 | 62 | // This parser is strongly based on byuu's modified recursive-descent algorithm 63 | // (particularly the 'depth' parameter.) 64 | // https://github.com/byuu/bsnes/blob/master/nall/string/eval/parser.hpp 65 | func (p *parser) parseexpr(depth int) node { 66 | var n node 67 | 68 | unary := func(op unaryop, depth int) { 69 | n = unaryexpr{op: op, n: p.parseexpr(depth)} 70 | } 71 | 72 | binary := func(op binaryop, depth int) { 73 | if n == nil { 74 | panic("unexpected binary op") 75 | } 76 | n = binaryexpr{op: op, a: n, b: p.parseexpr(depth)} 77 | } 78 | 79 | ternary := func(depth int) { 80 | t := ternaryexpr{} 81 | t.a = n 82 | t.b = p.parseexpr(depth) 83 | p.expect(colontoken) 84 | t.c = p.parseexpr(depth) 85 | n = t 86 | } 87 | 88 | switch { 89 | case p.accept(identtoken): 90 | n = newidentnode(p.t) 91 | case p.accept(inttoken): 92 | n = newintnode(p.t) 93 | case p.accept(floattoken): 94 | n = newfloatnode(p.t) 95 | case p.accept(booltoken): 96 | n = newboolnode(p.t) 97 | case p.accept(strtoken): 98 | n = newstrnode(p.t) 99 | case p.accept(runetoken): 100 | n = newrunenode(p.t) 101 | case p.accept(nilkeyword): 102 | n = newnilnode(p.t) 103 | case p.accept(leftparentoken): 104 | n = p.parseexpr(1) 105 | default: 106 | } 107 | 108 | for { 109 | if depth >= 8 { 110 | break 111 | } 112 | if n != nil && p.accept(periodtoken) { 113 | binary(binarymember, 8) 114 | continue 115 | } 116 | if n != nil && p.accept(leftparentoken) { 117 | binary(binarycall, 1) 118 | continue 119 | } 120 | if n != nil && p.accept(leftbrackettoken) { 121 | binary(binarysubscript, 1) 122 | continue 123 | } 124 | if n == nil && p.accept(addtoken) { 125 | unary(unaryplus, 7) 126 | } 127 | if n == nil && p.accept(subtoken) { 128 | unary(unarynegate, 7) 129 | } 130 | if n == nil && p.accept(nottoken) { 131 | unary(unarynot, 7) 132 | } 133 | if n == nil && p.accept(xortoken) { 134 | unary(unarybitnot, 7) 135 | } 136 | if n == nil && p.accept(multoken) { 137 | unary(unaryderef, 7) 138 | } 139 | if n == nil && p.accept(andtoken) { 140 | unary(unaryref, 7) 141 | } 142 | if depth >= 7 { 143 | break 144 | } 145 | if p.accept(multoken) { 146 | binary(binarymul, 7) 147 | continue 148 | } 149 | if p.accept(quotoken) { 150 | binary(binarydiv, 7) 151 | continue 152 | } 153 | if p.accept(remtoken) { 154 | binary(binaryrem, 7) 155 | continue 156 | } 157 | if p.accept(shltoken) { 158 | binary(binarylsh, 7) 159 | continue 160 | } 161 | if p.accept(shrtoken) { 162 | binary(binaryrsh, 7) 163 | continue 164 | } 165 | if p.accept(andtoken) { 166 | binary(binaryand, 7) 167 | continue 168 | } 169 | if depth >= 6 { 170 | break 171 | } 172 | if p.accept(addtoken) { 173 | binary(binaryadd, 6) 174 | continue 175 | } 176 | if p.accept(subtoken) { 177 | binary(binarysub, 6) 178 | continue 179 | } 180 | if p.accept(ortoken) { 181 | binary(binaryor, 6) 182 | continue 183 | } 184 | if p.accept(xortoken) { 185 | binary(binaryxor, 6) 186 | continue 187 | } 188 | if depth >= 5 { 189 | break 190 | } 191 | if p.accept(equaltoken) { 192 | binary(binaryequal, 5) 193 | continue 194 | } 195 | if p.accept(notequaltoken) { 196 | binary(binarynotequal, 5) 197 | continue 198 | } 199 | if p.accept(lessertoken) { 200 | binary(binarylesser, 5) 201 | continue 202 | } 203 | if p.accept(lesserequaltoken) { 204 | binary(binarylesserequal, 5) 205 | continue 206 | } 207 | if p.accept(greatertoken) { 208 | binary(binarygreater, 5) 209 | continue 210 | } 211 | if p.accept(greaterequaltoken) { 212 | binary(binarygreaterequal, 5) 213 | continue 214 | } 215 | if depth >= 4 { 216 | break 217 | } 218 | if p.accept(logicalandtoken) { 219 | binary(binarylogicaland, 4) 220 | continue 221 | } 222 | if depth >= 3 { 223 | break 224 | } 225 | if p.accept(logicalortoken) { 226 | binary(binarylogicalor, 3) 227 | continue 228 | } 229 | if p.accept(ternarytoken) { 230 | ternary(3) 231 | continue 232 | } 233 | if depth >= 2 { 234 | break 235 | } 236 | if p.accept(commatoken) { 237 | binary(binarygroup, 2) 238 | continue 239 | } 240 | if depth >= 1 && (p.accept(rightparentoken) || p.accept(rightbrackettoken)) { 241 | break 242 | } 243 | p.expect(eoftoken) 244 | break 245 | } 246 | return n 247 | } 248 | 249 | func (p *parser) parse() node { 250 | return p.parseexpr(0) 251 | } 252 | -------------------------------------------------------------------------------- /expr/parse_test.go: -------------------------------------------------------------------------------- 1 | package expr 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestParseBasic(t *testing.T) { 11 | tests := []struct { 12 | input string 13 | output node 14 | }{ 15 | { 16 | "a + b * c", 17 | binaryexpr{ 18 | binaryadd, 19 | identnode{0, "a"}, 20 | binaryexpr{ 21 | binarymul, 22 | identnode{4, "b"}, 23 | identnode{8, "c"}, 24 | }, 25 | }, 26 | }, 27 | { 28 | "a * b + c", 29 | binaryexpr{ 30 | binaryadd, 31 | binaryexpr{ 32 | binarymul, 33 | identnode{0, "a"}, 34 | identnode{4, "b"}, 35 | }, 36 | identnode{8, "c"}, 37 | }, 38 | }, 39 | { 40 | "a * (b + c)", 41 | binaryexpr{ 42 | binarymul, 43 | identnode{0, "a"}, 44 | binaryexpr{ 45 | binaryadd, 46 | identnode{5, "b"}, 47 | identnode{9, "c"}, 48 | }, 49 | }, 50 | }, 51 | { 52 | "a ? b : c", 53 | ternaryexpr{ 54 | identnode{0, "a"}, 55 | identnode{4, "b"}, 56 | identnode{8, "c"}, 57 | }, 58 | }, 59 | { 60 | "a == 1 ? b + 1 : c * 1", 61 | ternaryexpr{ 62 | binaryexpr{ 63 | binaryequal, 64 | identnode{0, "a"}, 65 | intnode{5, 1, 1, false}, 66 | }, 67 | binaryexpr{ 68 | binaryadd, 69 | identnode{9, "b"}, 70 | intnode{13, 1, 1, false}, 71 | }, 72 | binaryexpr{ 73 | binarymul, 74 | identnode{17, "c"}, 75 | intnode{21, 1, 1, false}, 76 | }, 77 | }, 78 | }, 79 | { 80 | "a(b, c)", 81 | binaryexpr{ 82 | binarycall, 83 | identnode{0, "a"}, 84 | binaryexpr{ 85 | binarygroup, 86 | identnode{2, "b"}, 87 | identnode{5, "c"}, 88 | }, 89 | }, 90 | }, 91 | { 92 | "a[1]", 93 | binaryexpr{ 94 | binarysubscript, 95 | identnode{0, "a"}, 96 | intnode{2, 1, 1, false}, 97 | }, 98 | }, 99 | } 100 | 101 | for _, test := range tests { 102 | p := newparser(newscanner(bytes.NewBufferString(test.input))) 103 | assert.Equal(t, test.output, p.parse()) 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /expr/tokenkind_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=tokenkind"; DO NOT EDIT. 2 | 3 | package expr 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[niltoken-0] 12 | _ = x[errtoken-1] 13 | _ = x[eoftoken-2] 14 | _ = x[identtoken-3] 15 | _ = x[inttoken-4] 16 | _ = x[floattoken-5] 17 | _ = x[booltoken-6] 18 | _ = x[strtoken-7] 19 | _ = x[runetoken-8] 20 | _ = x[addtoken-9] 21 | _ = x[subtoken-10] 22 | _ = x[multoken-11] 23 | _ = x[quotoken-12] 24 | _ = x[remtoken-13] 25 | _ = x[andtoken-14] 26 | _ = x[nottoken-15] 27 | _ = x[ortoken-16] 28 | _ = x[xortoken-17] 29 | _ = x[shltoken-18] 30 | _ = x[shrtoken-19] 31 | _ = x[andnottoken-20] 32 | _ = x[logicalandtoken-21] 33 | _ = x[logicalortoken-22] 34 | _ = x[equaltoken-23] 35 | _ = x[lessertoken-24] 36 | _ = x[greatertoken-25] 37 | _ = x[notequaltoken-26] 38 | _ = x[lesserequaltoken-27] 39 | _ = x[greaterequaltoken-28] 40 | _ = x[leftparentoken-29] 41 | _ = x[leftbrackettoken-30] 42 | _ = x[commatoken-31] 43 | _ = x[periodtoken-32] 44 | _ = x[rightparentoken-33] 45 | _ = x[rightbrackettoken-34] 46 | _ = x[colontoken-35] 47 | _ = x[ternarytoken-36] 48 | _ = x[boolkeyword-37] 49 | _ = x[bytekeyword-38] 50 | _ = x[float32keyword-39] 51 | _ = x[float64keyword-40] 52 | _ = x[intkeyword-41] 53 | _ = x[int8keyword-42] 54 | _ = x[int16keyword-43] 55 | _ = x[int32keyword-44] 56 | _ = x[int64keyword-45] 57 | _ = x[uintkeyword-46] 58 | _ = x[uint8keyword-47] 59 | _ = x[uint16keyword-48] 60 | _ = x[uint32keyword-49] 61 | _ = x[uint64keyword-50] 62 | _ = x[uintptrkeyword-51] 63 | _ = x[nilkeyword-52] 64 | } 65 | 66 | const _tokenkind_name = "niltokenerrtokeneoftokenidenttokeninttokenfloattokenbooltokenstrtokenrunetokenaddtokensubtokenmultokenquotokenremtokenandtokennottokenortokenxortokenshltokenshrtokenandnottokenlogicalandtokenlogicalortokenequaltokenlessertokengreatertokennotequaltokenlesserequaltokengreaterequaltokenleftparentokenleftbrackettokencommatokenperiodtokenrightparentokenrightbrackettokencolontokenternarytokenboolkeywordbytekeywordfloat32keywordfloat64keywordintkeywordint8keywordint16keywordint32keywordint64keyworduintkeyworduint8keyworduint16keyworduint32keyworduint64keyworduintptrkeywordnilkeyword" 67 | 68 | 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} 69 | 70 | func (i tokenkind) String() string { 71 | if i < 0 || i >= tokenkind(len(_tokenkind_index)-1) { 72 | return "tokenkind(" + strconv.FormatInt(int64(i), 10) + ")" 73 | } 74 | return _tokenkind_name[_tokenkind_index[i]:_tokenkind_index[i+1]] 75 | } 76 | -------------------------------------------------------------------------------- /expr/type.go: -------------------------------------------------------------------------------- 1 | package expr 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "sync" 8 | ) 9 | 10 | var ( 11 | primType = map[reflect.Kind]Type{ 12 | reflect.Bool: NewPrimitiveType(Bool), 13 | reflect.Int: NewPrimitiveType(Int), 14 | reflect.Int8: NewPrimitiveType(Int8), 15 | reflect.Int16: NewPrimitiveType(Int16), 16 | reflect.Int32: NewPrimitiveType(Int32), 17 | reflect.Int64: NewPrimitiveType(Int64), 18 | reflect.Uint: NewPrimitiveType(Uint), 19 | reflect.Uint8: NewPrimitiveType(Uint8), 20 | reflect.Uint16: NewPrimitiveType(Uint16), 21 | reflect.Uint32: NewPrimitiveType(Uint32), 22 | reflect.Uint64: NewPrimitiveType(Uint64), 23 | reflect.Uintptr: NewPrimitiveType(Uintptr), 24 | reflect.Float32: NewPrimitiveType(Float32), 25 | reflect.Float64: NewPrimitiveType(Float64), 26 | reflect.String: NewPrimitiveType(String), 27 | } 28 | 29 | primRType = map[Kind]reflect.Type{ 30 | Bool: reflect.TypeOf(bool(false)), 31 | Int: reflect.TypeOf(int(0)), 32 | Int8: reflect.TypeOf(int8(0)), 33 | Int16: reflect.TypeOf(int16(0)), 34 | Int32: reflect.TypeOf(int32(0)), 35 | Int64: reflect.TypeOf(int64(0)), 36 | Uint: reflect.TypeOf(uint(0)), 37 | Uint8: reflect.TypeOf(uint8(0)), 38 | Uint16: reflect.TypeOf(uint16(0)), 39 | Uint32: reflect.TypeOf(uint32(0)), 40 | Uint64: reflect.TypeOf(uint64(0)), 41 | Uintptr: reflect.TypeOf(uintptr(0)), 42 | Float32: reflect.TypeOf(float32(0)), 43 | Float64: reflect.TypeOf(float64(0)), 44 | String: reflect.TypeOf(string("")), 45 | } 46 | 47 | // ErrInvalidKind occurs when you call an inappropriate method for a given kind. 48 | ErrInvalidKind = errors.New("invalid kind") 49 | 50 | // ErrNotRepresentable occurs when a type is encountered that is not supported by the language. 51 | ErrNotRepresentable = errors.New("type cannot be represented") 52 | 53 | // ErrUntypedNil occurs when an untyped nil is used inappropriately. 54 | ErrUntypedNil = errors.New("untyped nil value") 55 | ) 56 | 57 | // NoSuchFieldError is returned when an unknown field is accessed. 58 | type NoSuchFieldError struct { 59 | field string 60 | } 61 | 62 | func (err NoSuchFieldError) Error() string { 63 | return fmt.Sprintf("no such field: %s", err.field) 64 | } 65 | 66 | // Kind is the most basic type descriptor. 67 | type Kind int 68 | 69 | // Enumeration of valid kinds of types. 70 | const ( 71 | Invalid Kind = iota 72 | 73 | // Primitives 74 | Bool 75 | Int 76 | Int8 77 | Int16 78 | Int32 79 | Int64 80 | Uint 81 | Uint8 82 | Uint16 83 | Uint32 84 | Uint64 85 | Uintptr 86 | Float32 87 | Float64 88 | String 89 | 90 | // Untyped constants 91 | UntypedBool 92 | UntypedInt 93 | UntypedFloat 94 | UntypedNil 95 | 96 | // Composite types 97 | Array 98 | Slice 99 | Struct 100 | Map 101 | Ptr 102 | Func 103 | Pkg 104 | ) 105 | 106 | // Type is the representation of an expr type. 107 | type Type interface { 108 | Kind() Kind 109 | String() string 110 | } 111 | 112 | // PrimitiveType is the type of primitives. 113 | type PrimitiveType struct { 114 | kind Kind 115 | } 116 | 117 | // NewPrimitiveType returns a new primitive type. 118 | func NewPrimitiveType(k Kind) Type { 119 | if k < Bool || k > String { 120 | panic("not a primitive kind") 121 | } 122 | return &PrimitiveType{kind: k} 123 | } 124 | 125 | // String implements Type. 126 | func (t PrimitiveType) String() string { 127 | switch t.kind { 128 | case Bool: 129 | return "bool" 130 | case Int: 131 | return "int" 132 | case Int8: 133 | return "int8" 134 | case Int16: 135 | return "int16" 136 | case Int32: 137 | return "int32" 138 | case Int64: 139 | return "int64" 140 | case Uint: 141 | return "uint" 142 | case Uint8: 143 | return "uint8" 144 | case Uint16: 145 | return "uint16" 146 | case Uint32: 147 | return "uint32" 148 | case Uint64: 149 | return "uint64" 150 | case Uintptr: 151 | return "uintptr" 152 | case Float32: 153 | return "float32" 154 | case Float64: 155 | return "float64" 156 | case String: 157 | return "string" 158 | default: 159 | return "" 160 | } 161 | } 162 | 163 | // Kind implements Type. 164 | func (t PrimitiveType) Kind() Kind { 165 | return t.kind 166 | } 167 | 168 | // littype is the type of literals. 169 | type littype struct { 170 | kind Kind 171 | } 172 | 173 | // NewLiteralType returns a new primitive type. 174 | func NewLiteralType(k Kind) Type { 175 | if k < UntypedBool || k > UntypedNil { 176 | panic("not a primitive kind") 177 | } 178 | return &littype{kind: k} 179 | } 180 | 181 | // String implements Type. 182 | func (t littype) String() string { 183 | switch t.kind { 184 | case UntypedBool: 185 | return "untyped bool constant" 186 | case UntypedInt: 187 | return "untyped int constant" 188 | case UntypedFloat: 189 | return "untyped float constant" 190 | case UntypedNil: 191 | return "untyped nil value" 192 | default: 193 | return "" 194 | } 195 | } 196 | 197 | func (t littype) Kind() Kind { return t.kind } 198 | 199 | // PackageType is the type of a package. 200 | type PackageType struct { 201 | symbols map[string]Type 202 | } 203 | 204 | // NewPackageType returns a new package with the given symbols. 205 | func NewPackageType(symbols map[string]Type) *PackageType { 206 | return &PackageType{symbols} 207 | } 208 | 209 | // String implements Type. 210 | func (PackageType) String() string { 211 | return "package" 212 | } 213 | 214 | // Kind implements Type. 215 | func (PackageType) Kind() Kind { 216 | return Pkg 217 | } 218 | 219 | // Symbol returns a symbol by the given name, or nil if none could be found. 220 | func (t PackageType) Symbol(ident string) Type { 221 | if s, ok := t.symbols[ident]; ok { 222 | return s 223 | } 224 | return nil 225 | } 226 | 227 | // ArrayType is the type of array-like values. 228 | type ArrayType struct { 229 | count int 230 | elem Type 231 | } 232 | 233 | // NewArrayType returns a new array type. 234 | func NewArrayType(count int, elem Type) *ArrayType { 235 | return &ArrayType{count: count, elem: elem} 236 | } 237 | 238 | // String implements Type. 239 | func (t ArrayType) String() string { 240 | return fmt.Sprintf("[%d]%s", t.count, t.elem.String()) 241 | } 242 | 243 | // Kind implements Type. 244 | func (ArrayType) Kind() Kind { 245 | return Array 246 | } 247 | 248 | // Elem is the type of element in the array. 249 | func (t ArrayType) Elem() Type { 250 | return t.elem 251 | } 252 | 253 | // Len is the length of the array. 254 | func (t ArrayType) Len() int { 255 | return t.count 256 | } 257 | 258 | // SliceType is the type of array-like values. 259 | type SliceType struct { 260 | elem Type 261 | } 262 | 263 | // NewSliceType returns a new array type. 264 | func NewSliceType(elem Type) *SliceType { 265 | return &SliceType{elem: elem} 266 | } 267 | 268 | // String implements Type. 269 | func (t SliceType) String() string { 270 | return "[]" + t.elem.String() 271 | } 272 | 273 | // Kind implements Type. 274 | func (SliceType) Kind() Kind { 275 | return Slice 276 | } 277 | 278 | // Elem is the type of element in the slice. 279 | func (t SliceType) Elem() Type { 280 | return t.elem 281 | } 282 | 283 | // MapType is the type of maps. 284 | type MapType struct { 285 | key, val Type 286 | } 287 | 288 | // NewMapType returns a new map type. 289 | func NewMapType(key Type, val Type) Type { 290 | return MapType{key: key, val: val} 291 | } 292 | 293 | // String implements Type. 294 | func (t MapType) String() string { 295 | return "map[" + t.key.String() + "]" + t.val.String() 296 | } 297 | 298 | // Kind implements Type. 299 | func (MapType) Kind() Kind { 300 | return Map 301 | } 302 | 303 | // Key is the type of the map's keys. 304 | func (t MapType) Key() Type { 305 | return t.key 306 | } 307 | 308 | // Value is the type of the map's values. 309 | func (t MapType) Value() Type { 310 | return t.val 311 | } 312 | 313 | // Field represents a struct field. 314 | type Field struct { 315 | Name string 316 | Type Type 317 | } 318 | 319 | // StructType is the type of struct values. 320 | type StructType struct { 321 | fields []Field 322 | fieldMap map[string]Field 323 | } 324 | 325 | // NewStructType returns a new struct type. 326 | func NewStructType(fields []Field) *StructType { 327 | fieldMap := map[string]Field{} 328 | for _, field := range fields { 329 | fieldMap[field.Name] = field 330 | } 331 | return &StructType{fields: fields, fieldMap: fieldMap} 332 | } 333 | 334 | // String implements Type. 335 | func (t StructType) String() string { 336 | return "struct" 337 | } 338 | 339 | // Kind implements Type. 340 | func (StructType) Kind() Kind { 341 | return Struct 342 | } 343 | 344 | // NumFields returns the number of fields in the struct. 345 | func (t StructType) NumFields() int { 346 | return len(t.fields) 347 | } 348 | 349 | // Field returns the nth field in the struct. 350 | func (t StructType) Field(i int) Field { 351 | return t.fields[i] 352 | } 353 | 354 | // FieldByName returns the field with the given name. 355 | func (t StructType) FieldByName(name string) (Field, bool) { 356 | f, ok := t.fieldMap[name] 357 | return f, ok 358 | } 359 | 360 | // PtrType is the type of pointers. 361 | type PtrType struct { 362 | elem Type 363 | } 364 | 365 | // NewPtrType returns a new pointer type. 366 | func NewPtrType(elem Type) *PtrType { 367 | return &PtrType{elem: elem} 368 | } 369 | 370 | // String implements Type. 371 | func (t PtrType) String() string { 372 | return "*" + t.elem.String() 373 | } 374 | 375 | // Kind implements Type. 376 | func (PtrType) Kind() Kind { 377 | return Ptr 378 | } 379 | 380 | // Elem returns the element being pointed to by the pointer. 381 | func (t PtrType) Elem() Type { 382 | return t.elem 383 | } 384 | 385 | // FuncType is the type of function values. 386 | type FuncType struct { 387 | in []Type 388 | out []Type 389 | variadic bool 390 | } 391 | 392 | // NewFuncType returns a new function type. 393 | func NewFuncType(in []Type, out []Type, variadic bool) *FuncType { 394 | return &FuncType{in: in, out: out, variadic: variadic} 395 | } 396 | 397 | // String implements Type. 398 | func (t FuncType) String() string { 399 | return "func" 400 | } 401 | 402 | // Kind implements Type. 403 | func (FuncType) Kind() Kind { 404 | return Func 405 | } 406 | 407 | // NumIn returns the number of input parameters. 408 | func (t FuncType) NumIn() int { 409 | return len(t.in) 410 | } 411 | 412 | // In gets the nth input parameter. 413 | func (t FuncType) In(i int) Type { 414 | return t.in[i] 415 | } 416 | 417 | // IsVariadic returns true for variadic functions. 418 | func (t FuncType) IsVariadic() bool { 419 | return t.variadic 420 | } 421 | 422 | // NumOut returns the number of output parameters. 423 | func (t FuncType) NumOut() int { 424 | return len(t.out) 425 | } 426 | 427 | // Out gets the nth output parameter. 428 | func (t FuncType) Out(i int) Type { 429 | return t.out[i] 430 | } 431 | 432 | // TypeEqual returns true if the two types are equal. 433 | func TypeEqual(a, b Type) bool { 434 | // TODO: this could be a bit more precise. 435 | return reflect.DeepEqual(a, b) 436 | } 437 | 438 | // toreflecttype converts an expr type into a runtime type. 439 | func toreflecttype(t Type) reflect.Type { 440 | switch t := t.(type) { 441 | case *PrimitiveType: 442 | return primRType[t.Kind()] 443 | case *ArrayType: 444 | return reflect.ArrayOf(t.Len(), toreflecttype(t.Elem())) 445 | case *SliceType: 446 | return reflect.SliceOf(toreflecttype(t.Elem())) 447 | case *StructType: 448 | fields := make([]reflect.StructField, 0, t.NumFields()) 449 | for i := 0; i < t.NumFields(); i++ { 450 | field := t.Field(i) 451 | fields = append(fields, reflect.StructField{ 452 | Name: field.Name, 453 | Type: toreflecttype(field.Type), 454 | }) 455 | } 456 | return reflect.StructOf(fields) 457 | case *MapType: 458 | return reflect.MapOf(toreflecttype(t.Key()), toreflecttype(t.Value())) 459 | case *PtrType: 460 | return reflect.PtrTo(toreflecttype(t.Elem())) 461 | case *FuncType: 462 | nin := t.NumIn() 463 | in := make([]reflect.Type, 0, nin) 464 | for i := 0; i < nin; i++ { 465 | in = append(in, toreflecttype(t.In(i))) 466 | } 467 | nout := t.NumOut() 468 | out := make([]reflect.Type, 0, nout) 469 | for i := 0; i < nout; i++ { 470 | out = append(out, toreflecttype(t.Out(i))) 471 | } 472 | return reflect.FuncOf(in, out, t.IsVariadic()) 473 | default: 474 | panic(ErrNotRepresentable) 475 | } 476 | } 477 | 478 | var typemap = map[reflect.Type]Type{} 479 | var typemutex = sync.Mutex{} 480 | 481 | func savetype(reflect reflect.Type, expr Type) Type { 482 | typemutex.Lock() 483 | defer typemutex.Unlock() 484 | 485 | typemap[reflect] = expr 486 | return expr 487 | } 488 | 489 | func loadtype(reflect reflect.Type) (Type, bool) { 490 | typemutex.Lock() 491 | defer typemutex.Unlock() 492 | 493 | if expr, ok := typemap[reflect]; ok { 494 | return expr, true 495 | } 496 | return nil, false 497 | } 498 | 499 | // fromreflecttype converts a runtime type into an expr type. 500 | func fromreflecttype(t reflect.Type) Type { 501 | if et, ok := loadtype(t); ok { 502 | return et 503 | } 504 | 505 | switch t.Kind() { 506 | case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, 507 | reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, 508 | reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64, 509 | reflect.String: 510 | return primType[t.Kind()] 511 | case reflect.Array: 512 | return NewArrayType(t.Len(), fromreflecttype(t.Elem())) 513 | case reflect.Func: 514 | nin := t.NumIn() 515 | in := make([]Type, 0, nin) 516 | for i := 0; i < nin; i++ { 517 | in = append(in, fromreflecttype(t.In(i))) 518 | } 519 | nout := t.NumOut() 520 | out := make([]Type, 0, nout) 521 | for i := 0; i < nout; i++ { 522 | out = append(out, fromreflecttype(t.Out(i))) 523 | } 524 | return NewFuncType(in, out, t.IsVariadic()) 525 | case reflect.Map: 526 | return NewMapType(fromreflecttype(t.Key()), fromreflecttype(t.Elem())) 527 | case reflect.Ptr: 528 | et := &PtrType{} 529 | savetype(t, et) 530 | *et = *NewPtrType(fromreflecttype(t.Elem())) 531 | return et 532 | case reflect.Slice: 533 | et := &SliceType{} 534 | savetype(t, et) 535 | *et = *NewSliceType(fromreflecttype(t.Elem())) 536 | return et 537 | case reflect.Struct: 538 | fields := make([]Field, 0, t.NumField()) 539 | for i := 0; i < t.NumField(); i++ { 540 | field := t.Field(i) 541 | fields = append(fields, Field{ 542 | Name: field.Name, 543 | Type: fromreflecttype(field.Type), 544 | }) 545 | } 546 | return NewStructType(fields) 547 | default: 548 | panic(ErrNotRepresentable) 549 | } 550 | } 551 | 552 | func assignable(from Type, to Type) bool { 553 | if TypeEqual(from, to) { 554 | return true 555 | } 556 | 557 | switch from.Kind() { 558 | case UntypedNil: 559 | switch to.Kind() { 560 | case Ptr, Func, Slice, Map: 561 | return true 562 | } 563 | 564 | case UntypedBool: 565 | switch to.Kind() { 566 | case Bool: 567 | return true 568 | } 569 | 570 | case UntypedInt: 571 | // TODO: Range and overflow checks. 572 | switch to.Kind() { 573 | case Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: 574 | return true 575 | case Float32, Float64: 576 | return true 577 | } 578 | 579 | case UntypedFloat: 580 | switch to.Kind() { 581 | case Float32, Float64: 582 | return true 583 | } 584 | } 585 | return false 586 | } 587 | 588 | // TypeOf returns the type of a runtime value. 589 | func TypeOf(i interface{}) Type { 590 | if pkg, ok := i.(Package); ok { 591 | return pkg.Type() 592 | } 593 | 594 | return fromreflecttype(reflect.TypeOf(i)) 595 | } 596 | -------------------------------------------------------------------------------- /expr/value.go: -------------------------------------------------------------------------------- 1 | package expr 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | // InvalidOpError is returned when an attempt is made to perform an operation 9 | // on a type that is not supported. 10 | type InvalidOpError struct { 11 | Op string 12 | V Value 13 | } 14 | 15 | func (e InvalidOpError) Error() string { 16 | return fmt.Sprintf("invalid operation: operator %s not defined for %v (%s)", e.Op, e.V.Value(), e.V.Type()) 17 | } 18 | 19 | // ConversionError is returned when an invalid type conversion is attempted. 20 | type ConversionError struct { 21 | From Type 22 | To Type 23 | } 24 | 25 | func (e ConversionError) Error() string { 26 | return fmt.Sprintf("cannot convert %s to %s", e.From, e.To) 27 | } 28 | 29 | // ReferenceError is returned when it is not possible to take the address of a 30 | // value. 31 | type ReferenceError struct{} 32 | 33 | func (e ReferenceError) Error() string { 34 | return "could not take reference of value" 35 | } 36 | 37 | // Value represents a value at runtime. 38 | type Value interface { 39 | Type() Type 40 | Value() reflect.Value 41 | RawValue() interface{} 42 | 43 | Negate() Value 44 | Not() Value 45 | BitNot() Value 46 | Deref() Value 47 | Ref() Value 48 | Dot(ident string) Value 49 | 50 | LogicalOr(rhs Value) Value 51 | LogicalAnd(rhs Value) Value 52 | Equal(rhs Value) Value 53 | NotEqual(rhs Value) Value 54 | Lesser(rhs Value) Value 55 | LesserEqual(rhs Value) Value 56 | Greater(rhs Value) Value 57 | GreaterEqual(rhs Value) Value 58 | Add(rhs Value) Value 59 | Sub(rhs Value) Value 60 | Or(rhs Value) Value 61 | Xor(rhs Value) Value 62 | Mul(rhs Value) Value 63 | Div(rhs Value) Value 64 | Rem(rhs Value) Value 65 | Lsh(rhs Value) Value 66 | Rsh(rhs Value) Value 67 | And(rhs Value) Value 68 | AndNot(rhs Value) Value 69 | Index(rhs Value) Value 70 | Call(in []Value) Value 71 | } 72 | 73 | type val struct { 74 | v reflect.Value 75 | t Type 76 | } 77 | 78 | func promote(from Value, to Type) Value { 79 | if TypeEqual(from.Type(), to) { 80 | return from 81 | } 82 | 83 | ftype := from.Type() 84 | switch ftype.Kind() { 85 | case UntypedBool: 86 | switch to.Kind() { 87 | case Bool: 88 | return val{from.Value(), to} 89 | default: 90 | panic(ConversionError{From: ftype, To: to}) 91 | } 92 | case UntypedFloat: 93 | switch to.Kind() { 94 | case Float32: 95 | return val{reflect.ValueOf(float32(reflect.ValueOf(from.Value).Float())), to} 96 | case Float64: 97 | return val{reflect.ValueOf(float64(reflect.ValueOf(from.Value).Float())), to} 98 | default: 99 | panic(ConversionError{From: ftype, To: to}) 100 | } 101 | case UntypedInt: 102 | ival, uval, fval := int64(0), uint64(0), float64(0) 103 | switch n := from.RawValue().(type) { 104 | case int64: 105 | ival = int64(n) 106 | uval = uint64(n) 107 | fval = float64(n) 108 | case uint64: 109 | ival = int64(n) 110 | uval = uint64(n) 111 | fval = float64(n) 112 | } 113 | switch to.Kind() { 114 | case Int: 115 | return val{reflect.ValueOf(int(ival)), to} 116 | case Int8: 117 | return val{reflect.ValueOf(int8(ival)), to} 118 | case Int16: 119 | return val{reflect.ValueOf(int16(ival)), to} 120 | case Int32: 121 | return val{reflect.ValueOf(int32(ival)), to} 122 | case Int64: 123 | return val{reflect.ValueOf(int64(ival)), to} 124 | case Uint: 125 | return val{reflect.ValueOf(uint(uval)), to} 126 | case Uint8: 127 | return val{reflect.ValueOf(uint8(uval)), to} 128 | case Uint16: 129 | return val{reflect.ValueOf(uint16(uval)), to} 130 | case Uint32: 131 | return val{reflect.ValueOf(uint32(uval)), to} 132 | case Uint64: 133 | return val{reflect.ValueOf(uint64(uval)), to} 134 | case Uintptr: 135 | return val{reflect.ValueOf(uintptr(uval)), to} 136 | case Float32: 137 | return val{reflect.ValueOf(float32(fval)), to} 138 | case Float64: 139 | return val{reflect.ValueOf(float64(fval)), to} 140 | default: 141 | panic(ConversionError{From: ftype, To: to}) 142 | } 143 | case UntypedNil: 144 | return val{reflect.Zero(toreflecttype(to)), to} 145 | default: 146 | panic(ConversionError{From: ftype, To: to}) 147 | } 148 | } 149 | 150 | func coerce1(v Value) Value { 151 | if v.Type().Kind() == UntypedInt { 152 | switch n := v.RawValue().(type) { 153 | case uint64: 154 | return val{reflect.ValueOf(int(n)), NewPrimitiveType(Int)} 155 | case int64: 156 | return val{reflect.ValueOf(int(n)), NewPrimitiveType(Int)} 157 | } 158 | } 159 | return v 160 | } 161 | 162 | func coerce(lhs Value, rhs Value) (Value, Value) { 163 | if TypeEqual(lhs.Type(), rhs.Type()) { 164 | return coerce1(lhs), coerce1(rhs) 165 | } else if assignable(lhs.Type(), rhs.Type()) { 166 | return promote(lhs, rhs.Type()), rhs 167 | } else if assignable(rhs.Type(), lhs.Type()) { 168 | return lhs, promote(rhs, lhs.Type()) 169 | } 170 | panic(ConversionError{From: lhs.Type(), To: rhs.Type()}) 171 | } 172 | 173 | func (v val) Type() Type { 174 | return v.t 175 | } 176 | 177 | func (v val) Value() reflect.Value { 178 | return v.v 179 | } 180 | 181 | func (v val) RawValue() interface{} { 182 | return v.v.Interface() 183 | } 184 | 185 | func (v val) Negate() Value { 186 | switch n := v.RawValue().(type) { 187 | case int: 188 | return val{reflect.ValueOf(-n), v.t} 189 | case int8: 190 | return val{reflect.ValueOf(-n), v.t} 191 | case int16: 192 | return val{reflect.ValueOf(-n), v.t} 193 | case int32: 194 | return val{reflect.ValueOf(-n), v.t} 195 | case int64: 196 | return val{reflect.ValueOf(-n), v.t} 197 | case uint: 198 | return val{reflect.ValueOf(-n), v.t} 199 | case uint8: 200 | return val{reflect.ValueOf(-n), v.t} 201 | case uint16: 202 | return val{reflect.ValueOf(-n), v.t} 203 | case uint32: 204 | return val{reflect.ValueOf(-n), v.t} 205 | case uint64: 206 | return val{reflect.ValueOf(-n), v.t} 207 | case uintptr: 208 | return val{reflect.ValueOf(-n), v.t} 209 | case float32: 210 | return val{reflect.ValueOf(-n), v.t} 211 | case float64: 212 | return val{reflect.ValueOf(-n), v.t} 213 | default: 214 | panic(InvalidOpError{Op: "-", V: v}) 215 | } 216 | } 217 | 218 | func (v val) Not() Value { 219 | switch n := v.RawValue().(type) { 220 | case bool: 221 | return val{reflect.ValueOf(!n), v.t} 222 | default: 223 | panic(InvalidOpError{Op: "!", V: v}) 224 | } 225 | } 226 | 227 | func (v val) BitNot() Value { 228 | switch n := v.RawValue().(type) { 229 | case int: 230 | return val{reflect.ValueOf(^n), v.t} 231 | case int8: 232 | return val{reflect.ValueOf(^n), v.t} 233 | case int16: 234 | return val{reflect.ValueOf(^n), v.t} 235 | case int32: 236 | return val{reflect.ValueOf(^n), v.t} 237 | case int64: 238 | return val{reflect.ValueOf(^n), v.t} 239 | case uint: 240 | return val{reflect.ValueOf(^n), v.t} 241 | case uint8: 242 | return val{reflect.ValueOf(^n), v.t} 243 | case uint16: 244 | return val{reflect.ValueOf(^n), v.t} 245 | case uint32: 246 | return val{reflect.ValueOf(^n), v.t} 247 | case uint64: 248 | return val{reflect.ValueOf(^n), v.t} 249 | case uintptr: 250 | return val{reflect.ValueOf(^n), v.t} 251 | default: 252 | panic(InvalidOpError{Op: "^", V: v}) 253 | } 254 | } 255 | 256 | func (v val) Deref() Value { 257 | ptrtype, ok := v.t.(*PtrType) 258 | if !ok { 259 | panic(InvalidOpError{Op: "*", V: v}) 260 | } 261 | return val{v.v.Elem(), ptrtype.Elem()} 262 | } 263 | 264 | func (v val) Ref() Value { 265 | if !v.v.CanAddr() { 266 | panic(ReferenceError{}) 267 | } 268 | return val{v.v.Addr(), NewPtrType(v.t)} 269 | } 270 | 271 | func (v val) Dot(ident string) Value { 272 | switch v.t.(type) { 273 | case *PackageType: 274 | if sv := v.RawValue().(Package).Symbol(ident); sv != nil { 275 | return sv 276 | } 277 | case *StructType: 278 | if sv := v.v.FieldByName(ident); sv.IsValid() { 279 | return val{sv, TypeOf(sv.Interface())} 280 | } 281 | case *PtrType: 282 | return v.Deref().Dot(ident) 283 | } 284 | panic(InvalidOpError{Op: ".", V: v}) 285 | } 286 | 287 | func (v val) LogicalOr(rhs Value) Value { 288 | lv, ok := v.RawValue().(bool) 289 | if !ok { 290 | panic(InvalidOpError{Op: "||", V: v}) 291 | } 292 | 293 | rv, ok := rhs.RawValue().(bool) 294 | if !ok { 295 | panic(InvalidOpError{Op: "||", V: rhs}) 296 | } 297 | 298 | return val{reflect.ValueOf(lv || rv), NewPrimitiveType(Bool)} 299 | } 300 | 301 | func (v val) LogicalAnd(rhs Value) Value { 302 | lv, ok := v.RawValue().(bool) 303 | if !ok { 304 | panic(InvalidOpError{Op: "&&", V: v}) 305 | } 306 | 307 | rv, ok := rhs.RawValue().(bool) 308 | if !ok { 309 | panic(InvalidOpError{Op: "&&", V: rhs}) 310 | } 311 | 312 | return val{reflect.ValueOf(lv && rv), NewPrimitiveType(Bool)} 313 | } 314 | 315 | func (v val) Equal(rhs Value) Value { 316 | l, r := coerce(v, rhs) 317 | return val{reflect.ValueOf(l.RawValue() == r.RawValue()), NewPrimitiveType(Bool)} 318 | } 319 | 320 | func (v val) NotEqual(rhs Value) Value { 321 | l, r := coerce(v, rhs) 322 | return val{reflect.ValueOf(l.RawValue() != r.RawValue()), NewPrimitiveType(Bool)} 323 | } 324 | 325 | func (v val) Lesser(rhs Value) Value { 326 | l, r := coerce(v, rhs) 327 | switch lv := l.RawValue().(type) { 328 | case int: 329 | return val{reflect.ValueOf(lv < r.RawValue().(int)), NewPrimitiveType(Bool)} 330 | case int8: 331 | return val{reflect.ValueOf(lv < r.RawValue().(int8)), NewPrimitiveType(Bool)} 332 | case int16: 333 | return val{reflect.ValueOf(lv < r.RawValue().(int16)), NewPrimitiveType(Bool)} 334 | case int32: 335 | return val{reflect.ValueOf(lv < r.RawValue().(int32)), NewPrimitiveType(Bool)} 336 | case int64: 337 | return val{reflect.ValueOf(lv < r.RawValue().(int64)), NewPrimitiveType(Bool)} 338 | case uint: 339 | return val{reflect.ValueOf(lv < r.RawValue().(uint)), NewPrimitiveType(Bool)} 340 | case uint8: 341 | return val{reflect.ValueOf(lv < r.RawValue().(uint8)), NewPrimitiveType(Bool)} 342 | case uint16: 343 | return val{reflect.ValueOf(lv < r.RawValue().(uint16)), NewPrimitiveType(Bool)} 344 | case uint32: 345 | return val{reflect.ValueOf(lv < r.RawValue().(uint32)), NewPrimitiveType(Bool)} 346 | case uint64: 347 | return val{reflect.ValueOf(lv < r.RawValue().(uint64)), NewPrimitiveType(Bool)} 348 | case uintptr: 349 | return val{reflect.ValueOf(lv < r.RawValue().(uintptr)), NewPrimitiveType(Bool)} 350 | case float32: 351 | return val{reflect.ValueOf(lv < r.RawValue().(float32)), NewPrimitiveType(Bool)} 352 | case float64: 353 | return val{reflect.ValueOf(lv < r.RawValue().(float64)), NewPrimitiveType(Bool)} 354 | default: 355 | panic(InvalidOpError{Op: "<", V: l}) 356 | } 357 | } 358 | 359 | func (v val) LesserEqual(rhs Value) Value { 360 | l, r := coerce(v, rhs) 361 | switch lv := l.RawValue().(type) { 362 | case int: 363 | return val{reflect.ValueOf(lv <= r.RawValue().(int)), NewPrimitiveType(Bool)} 364 | case int8: 365 | return val{reflect.ValueOf(lv <= r.RawValue().(int8)), NewPrimitiveType(Bool)} 366 | case int16: 367 | return val{reflect.ValueOf(lv <= r.RawValue().(int16)), NewPrimitiveType(Bool)} 368 | case int32: 369 | return val{reflect.ValueOf(lv <= r.RawValue().(int32)), NewPrimitiveType(Bool)} 370 | case int64: 371 | return val{reflect.ValueOf(lv <= r.RawValue().(int64)), NewPrimitiveType(Bool)} 372 | case uint: 373 | return val{reflect.ValueOf(lv <= r.RawValue().(uint)), NewPrimitiveType(Bool)} 374 | case uint8: 375 | return val{reflect.ValueOf(lv <= r.RawValue().(uint8)), NewPrimitiveType(Bool)} 376 | case uint16: 377 | return val{reflect.ValueOf(lv <= r.RawValue().(uint16)), NewPrimitiveType(Bool)} 378 | case uint32: 379 | return val{reflect.ValueOf(lv <= r.RawValue().(uint32)), NewPrimitiveType(Bool)} 380 | case uint64: 381 | return val{reflect.ValueOf(lv <= r.RawValue().(uint64)), NewPrimitiveType(Bool)} 382 | case uintptr: 383 | return val{reflect.ValueOf(lv <= r.RawValue().(uintptr)), NewPrimitiveType(Bool)} 384 | case float32: 385 | return val{reflect.ValueOf(lv <= r.RawValue().(float32)), NewPrimitiveType(Bool)} 386 | case float64: 387 | return val{reflect.ValueOf(lv <= r.RawValue().(float64)), NewPrimitiveType(Bool)} 388 | default: 389 | panic(InvalidOpError{Op: "<=", V: l}) 390 | } 391 | } 392 | 393 | func (v val) Greater(rhs Value) Value { 394 | l, r := coerce(v, rhs) 395 | switch lv := l.RawValue().(type) { 396 | case int: 397 | return val{reflect.ValueOf(lv > r.RawValue().(int)), NewPrimitiveType(Bool)} 398 | case int8: 399 | return val{reflect.ValueOf(lv > r.RawValue().(int8)), NewPrimitiveType(Bool)} 400 | case int16: 401 | return val{reflect.ValueOf(lv > r.RawValue().(int16)), NewPrimitiveType(Bool)} 402 | case int32: 403 | return val{reflect.ValueOf(lv > r.RawValue().(int32)), NewPrimitiveType(Bool)} 404 | case int64: 405 | return val{reflect.ValueOf(lv > r.RawValue().(int64)), NewPrimitiveType(Bool)} 406 | case uint: 407 | return val{reflect.ValueOf(lv > r.RawValue().(uint)), NewPrimitiveType(Bool)} 408 | case uint8: 409 | return val{reflect.ValueOf(lv > r.RawValue().(uint8)), NewPrimitiveType(Bool)} 410 | case uint16: 411 | return val{reflect.ValueOf(lv > r.RawValue().(uint16)), NewPrimitiveType(Bool)} 412 | case uint32: 413 | return val{reflect.ValueOf(lv > r.RawValue().(uint32)), NewPrimitiveType(Bool)} 414 | case uint64: 415 | return val{reflect.ValueOf(lv > r.RawValue().(uint64)), NewPrimitiveType(Bool)} 416 | case uintptr: 417 | return val{reflect.ValueOf(lv > r.RawValue().(uintptr)), NewPrimitiveType(Bool)} 418 | case float32: 419 | return val{reflect.ValueOf(lv > r.RawValue().(float32)), NewPrimitiveType(Bool)} 420 | case float64: 421 | return val{reflect.ValueOf(lv > r.RawValue().(float64)), NewPrimitiveType(Bool)} 422 | default: 423 | panic(InvalidOpError{Op: ">", V: l}) 424 | } 425 | } 426 | 427 | func (v val) GreaterEqual(rhs Value) Value { 428 | l, r := coerce(v, rhs) 429 | switch lv := l.RawValue().(type) { 430 | case int: 431 | return val{reflect.ValueOf(lv >= r.RawValue().(int)), NewPrimitiveType(Bool)} 432 | case int8: 433 | return val{reflect.ValueOf(lv >= r.RawValue().(int8)), NewPrimitiveType(Bool)} 434 | case int16: 435 | return val{reflect.ValueOf(lv >= r.RawValue().(int16)), NewPrimitiveType(Bool)} 436 | case int32: 437 | return val{reflect.ValueOf(lv >= r.RawValue().(int32)), NewPrimitiveType(Bool)} 438 | case int64: 439 | return val{reflect.ValueOf(lv >= r.RawValue().(int64)), NewPrimitiveType(Bool)} 440 | case uint: 441 | return val{reflect.ValueOf(lv >= r.RawValue().(uint)), NewPrimitiveType(Bool)} 442 | case uint8: 443 | return val{reflect.ValueOf(lv >= r.RawValue().(uint8)), NewPrimitiveType(Bool)} 444 | case uint16: 445 | return val{reflect.ValueOf(lv >= r.RawValue().(uint16)), NewPrimitiveType(Bool)} 446 | case uint32: 447 | return val{reflect.ValueOf(lv >= r.RawValue().(uint32)), NewPrimitiveType(Bool)} 448 | case uint64: 449 | return val{reflect.ValueOf(lv >= r.RawValue().(uint64)), NewPrimitiveType(Bool)} 450 | case uintptr: 451 | return val{reflect.ValueOf(lv >= r.RawValue().(uintptr)), NewPrimitiveType(Bool)} 452 | case float32: 453 | return val{reflect.ValueOf(lv >= r.RawValue().(float32)), NewPrimitiveType(Bool)} 454 | case float64: 455 | return val{reflect.ValueOf(lv >= r.RawValue().(float64)), NewPrimitiveType(Bool)} 456 | default: 457 | panic(InvalidOpError{Op: ">=", V: l}) 458 | } 459 | } 460 | 461 | func (v val) Add(rhs Value) Value { 462 | l, r := coerce(v, rhs) 463 | switch lv := l.RawValue().(type) { 464 | case int: 465 | return val{reflect.ValueOf(lv + r.RawValue().(int)), NewPrimitiveType(Int)} 466 | case int8: 467 | return val{reflect.ValueOf(lv + r.RawValue().(int8)), NewPrimitiveType(Int8)} 468 | case int16: 469 | return val{reflect.ValueOf(lv + r.RawValue().(int16)), NewPrimitiveType(Int16)} 470 | case int32: 471 | return val{reflect.ValueOf(lv + r.RawValue().(int32)), NewPrimitiveType(Int32)} 472 | case int64: 473 | return val{reflect.ValueOf(lv + r.RawValue().(int64)), NewPrimitiveType(Int64)} 474 | case uint: 475 | return val{reflect.ValueOf(lv + r.RawValue().(uint)), NewPrimitiveType(Uint)} 476 | case uint8: 477 | return val{reflect.ValueOf(lv + r.RawValue().(uint8)), NewPrimitiveType(Uint8)} 478 | case uint16: 479 | return val{reflect.ValueOf(lv + r.RawValue().(uint16)), NewPrimitiveType(Uint16)} 480 | case uint32: 481 | return val{reflect.ValueOf(lv + r.RawValue().(uint32)), NewPrimitiveType(Uint32)} 482 | case uint64: 483 | return val{reflect.ValueOf(lv + r.RawValue().(uint64)), NewPrimitiveType(Uint64)} 484 | case uintptr: 485 | return val{reflect.ValueOf(lv + r.RawValue().(uintptr)), NewPrimitiveType(Uintptr)} 486 | case float32: 487 | return val{reflect.ValueOf(lv + r.RawValue().(float32)), NewPrimitiveType(Float32)} 488 | case float64: 489 | return val{reflect.ValueOf(lv + r.RawValue().(float64)), NewPrimitiveType(Float64)} 490 | case string: 491 | return val{reflect.ValueOf(lv + r.RawValue().(string)), NewPrimitiveType(String)} 492 | default: 493 | panic(InvalidOpError{Op: "+", V: l}) 494 | } 495 | } 496 | 497 | func (v val) Sub(rhs Value) Value { 498 | l, r := coerce(v, rhs) 499 | switch lv := l.RawValue().(type) { 500 | case int: 501 | return val{reflect.ValueOf(lv - r.RawValue().(int)), NewPrimitiveType(Int)} 502 | case int8: 503 | return val{reflect.ValueOf(lv - r.RawValue().(int8)), NewPrimitiveType(Int8)} 504 | case int16: 505 | return val{reflect.ValueOf(lv - r.RawValue().(int16)), NewPrimitiveType(Int16)} 506 | case int32: 507 | return val{reflect.ValueOf(lv - r.RawValue().(int32)), NewPrimitiveType(Int32)} 508 | case int64: 509 | return val{reflect.ValueOf(lv - r.RawValue().(int64)), NewPrimitiveType(Int64)} 510 | case uint: 511 | return val{reflect.ValueOf(lv - r.RawValue().(uint)), NewPrimitiveType(Uint)} 512 | case uint8: 513 | return val{reflect.ValueOf(lv - r.RawValue().(uint8)), NewPrimitiveType(Uint8)} 514 | case uint16: 515 | return val{reflect.ValueOf(lv - r.RawValue().(uint16)), NewPrimitiveType(Uint16)} 516 | case uint32: 517 | return val{reflect.ValueOf(lv - r.RawValue().(uint32)), NewPrimitiveType(Uint32)} 518 | case uint64: 519 | return val{reflect.ValueOf(lv - r.RawValue().(uint64)), NewPrimitiveType(Uint64)} 520 | case uintptr: 521 | return val{reflect.ValueOf(lv - r.RawValue().(uintptr)), NewPrimitiveType(Uintptr)} 522 | case float32: 523 | return val{reflect.ValueOf(lv - r.RawValue().(float32)), NewPrimitiveType(Float32)} 524 | case float64: 525 | return val{reflect.ValueOf(lv - r.RawValue().(float64)), NewPrimitiveType(Float64)} 526 | default: 527 | panic(InvalidOpError{Op: "-", V: l}) 528 | } 529 | } 530 | 531 | func (v val) Or(rhs Value) Value { 532 | l, r := coerce(v, rhs) 533 | switch lv := l.RawValue().(type) { 534 | case int: 535 | return val{reflect.ValueOf(lv | r.RawValue().(int)), NewPrimitiveType(Int)} 536 | case int8: 537 | return val{reflect.ValueOf(lv | r.RawValue().(int8)), NewPrimitiveType(Int8)} 538 | case int16: 539 | return val{reflect.ValueOf(lv | r.RawValue().(int16)), NewPrimitiveType(Int16)} 540 | case int32: 541 | return val{reflect.ValueOf(lv | r.RawValue().(int32)), NewPrimitiveType(Int32)} 542 | case int64: 543 | return val{reflect.ValueOf(lv | r.RawValue().(int64)), NewPrimitiveType(Int64)} 544 | case uint: 545 | return val{reflect.ValueOf(lv | r.RawValue().(uint)), NewPrimitiveType(Uint)} 546 | case uint8: 547 | return val{reflect.ValueOf(lv | r.RawValue().(uint8)), NewPrimitiveType(Uint8)} 548 | case uint16: 549 | return val{reflect.ValueOf(lv | r.RawValue().(uint16)), NewPrimitiveType(Uint16)} 550 | case uint32: 551 | return val{reflect.ValueOf(lv | r.RawValue().(uint32)), NewPrimitiveType(Uint32)} 552 | case uint64: 553 | return val{reflect.ValueOf(lv | r.RawValue().(uint64)), NewPrimitiveType(Uint64)} 554 | case uintptr: 555 | return val{reflect.ValueOf(lv | r.RawValue().(uintptr)), NewPrimitiveType(Uintptr)} 556 | default: 557 | panic(InvalidOpError{Op: "|", V: l}) 558 | } 559 | } 560 | 561 | func (v val) Xor(rhs Value) Value { 562 | l, r := coerce(v, rhs) 563 | switch lv := l.RawValue().(type) { 564 | case int: 565 | return val{reflect.ValueOf(lv ^ r.RawValue().(int)), NewPrimitiveType(Int)} 566 | case int8: 567 | return val{reflect.ValueOf(lv ^ r.RawValue().(int8)), NewPrimitiveType(Int8)} 568 | case int16: 569 | return val{reflect.ValueOf(lv ^ r.RawValue().(int16)), NewPrimitiveType(Int16)} 570 | case int32: 571 | return val{reflect.ValueOf(lv ^ r.RawValue().(int32)), NewPrimitiveType(Int32)} 572 | case int64: 573 | return val{reflect.ValueOf(lv ^ r.RawValue().(int64)), NewPrimitiveType(Int64)} 574 | case uint: 575 | return val{reflect.ValueOf(lv ^ r.RawValue().(uint)), NewPrimitiveType(Uint)} 576 | case uint8: 577 | return val{reflect.ValueOf(lv ^ r.RawValue().(uint8)), NewPrimitiveType(Uint8)} 578 | case uint16: 579 | return val{reflect.ValueOf(lv ^ r.RawValue().(uint16)), NewPrimitiveType(Uint16)} 580 | case uint32: 581 | return val{reflect.ValueOf(lv ^ r.RawValue().(uint32)), NewPrimitiveType(Uint32)} 582 | case uint64: 583 | return val{reflect.ValueOf(lv ^ r.RawValue().(uint64)), NewPrimitiveType(Uint64)} 584 | case uintptr: 585 | return val{reflect.ValueOf(lv ^ r.RawValue().(uintptr)), NewPrimitiveType(Uintptr)} 586 | default: 587 | panic(InvalidOpError{Op: "^", V: l}) 588 | } 589 | } 590 | 591 | func (v val) Mul(rhs Value) Value { 592 | l, r := coerce(v, rhs) 593 | switch lv := l.RawValue().(type) { 594 | case int: 595 | return val{reflect.ValueOf(lv * r.RawValue().(int)), NewPrimitiveType(Int)} 596 | case int8: 597 | return val{reflect.ValueOf(lv * r.RawValue().(int8)), NewPrimitiveType(Int8)} 598 | case int16: 599 | return val{reflect.ValueOf(lv * r.RawValue().(int16)), NewPrimitiveType(Int16)} 600 | case int32: 601 | return val{reflect.ValueOf(lv * r.RawValue().(int32)), NewPrimitiveType(Int32)} 602 | case int64: 603 | return val{reflect.ValueOf(lv * r.RawValue().(int64)), NewPrimitiveType(Int64)} 604 | case uint: 605 | return val{reflect.ValueOf(lv * r.RawValue().(uint)), NewPrimitiveType(Uint)} 606 | case uint8: 607 | return val{reflect.ValueOf(lv * r.RawValue().(uint8)), NewPrimitiveType(Uint8)} 608 | case uint16: 609 | return val{reflect.ValueOf(lv * r.RawValue().(uint16)), NewPrimitiveType(Uint16)} 610 | case uint32: 611 | return val{reflect.ValueOf(lv * r.RawValue().(uint32)), NewPrimitiveType(Uint32)} 612 | case uint64: 613 | return val{reflect.ValueOf(lv * r.RawValue().(uint64)), NewPrimitiveType(Uint64)} 614 | case uintptr: 615 | return val{reflect.ValueOf(lv * r.RawValue().(uintptr)), NewPrimitiveType(Uintptr)} 616 | case float32: 617 | return val{reflect.ValueOf(lv * r.RawValue().(float32)), NewPrimitiveType(Float32)} 618 | case float64: 619 | return val{reflect.ValueOf(lv * r.RawValue().(float64)), NewPrimitiveType(Float64)} 620 | default: 621 | panic(InvalidOpError{Op: "*", V: l}) 622 | } 623 | } 624 | 625 | func (v val) Div(rhs Value) Value { 626 | l, r := coerce(v, rhs) 627 | switch lv := l.RawValue().(type) { 628 | case int: 629 | return val{reflect.ValueOf(lv / r.RawValue().(int)), NewPrimitiveType(Int)} 630 | case int8: 631 | return val{reflect.ValueOf(lv / r.RawValue().(int8)), NewPrimitiveType(Int8)} 632 | case int16: 633 | return val{reflect.ValueOf(lv / r.RawValue().(int16)), NewPrimitiveType(Int16)} 634 | case int32: 635 | return val{reflect.ValueOf(lv / r.RawValue().(int32)), NewPrimitiveType(Int32)} 636 | case int64: 637 | return val{reflect.ValueOf(lv / r.RawValue().(int64)), NewPrimitiveType(Int64)} 638 | case uint: 639 | return val{reflect.ValueOf(lv / r.RawValue().(uint)), NewPrimitiveType(Uint)} 640 | case uint8: 641 | return val{reflect.ValueOf(lv / r.RawValue().(uint8)), NewPrimitiveType(Uint8)} 642 | case uint16: 643 | return val{reflect.ValueOf(lv / r.RawValue().(uint16)), NewPrimitiveType(Uint16)} 644 | case uint32: 645 | return val{reflect.ValueOf(lv / r.RawValue().(uint32)), NewPrimitiveType(Uint32)} 646 | case uint64: 647 | return val{reflect.ValueOf(lv / r.RawValue().(uint64)), NewPrimitiveType(Uint64)} 648 | case uintptr: 649 | return val{reflect.ValueOf(lv / r.RawValue().(uintptr)), NewPrimitiveType(Uintptr)} 650 | case float32: 651 | return val{reflect.ValueOf(lv / r.RawValue().(float32)), NewPrimitiveType(Float32)} 652 | case float64: 653 | return val{reflect.ValueOf(lv / r.RawValue().(float64)), NewPrimitiveType(Float64)} 654 | default: 655 | panic(InvalidOpError{Op: "/", V: l}) 656 | } 657 | } 658 | 659 | func (v val) Rem(rhs Value) Value { 660 | l, r := coerce(v, rhs) 661 | switch lv := l.RawValue().(type) { 662 | case int: 663 | return val{reflect.ValueOf(lv % r.RawValue().(int)), NewPrimitiveType(Int)} 664 | case int8: 665 | return val{reflect.ValueOf(lv % r.RawValue().(int8)), NewPrimitiveType(Int8)} 666 | case int16: 667 | return val{reflect.ValueOf(lv % r.RawValue().(int16)), NewPrimitiveType(Int16)} 668 | case int32: 669 | return val{reflect.ValueOf(lv % r.RawValue().(int32)), NewPrimitiveType(Int32)} 670 | case int64: 671 | return val{reflect.ValueOf(lv % r.RawValue().(int64)), NewPrimitiveType(Int64)} 672 | case uint: 673 | return val{reflect.ValueOf(lv % r.RawValue().(uint)), NewPrimitiveType(Uint)} 674 | case uint8: 675 | return val{reflect.ValueOf(lv % r.RawValue().(uint8)), NewPrimitiveType(Uint8)} 676 | case uint16: 677 | return val{reflect.ValueOf(lv % r.RawValue().(uint16)), NewPrimitiveType(Uint16)} 678 | case uint32: 679 | return val{reflect.ValueOf(lv % r.RawValue().(uint32)), NewPrimitiveType(Uint32)} 680 | case uint64: 681 | return val{reflect.ValueOf(lv % r.RawValue().(uint64)), NewPrimitiveType(Uint64)} 682 | case uintptr: 683 | return val{reflect.ValueOf(lv % r.RawValue().(uintptr)), NewPrimitiveType(Uintptr)} 684 | default: 685 | panic(InvalidOpError{Op: "%", V: l}) 686 | } 687 | } 688 | 689 | func (v val) Lsh(rhs Value) Value { 690 | l := coerce1(v) 691 | shift := uint64(0) 692 | 693 | switch rv := rhs.RawValue().(type) { 694 | case uint: 695 | shift = uint64(rv) 696 | case uint8: 697 | shift = uint64(rv) 698 | case uint16: 699 | shift = uint64(rv) 700 | case uint32: 701 | shift = uint64(rv) 702 | case uint64: 703 | shift = uint64(rv) 704 | case uintptr: 705 | shift = uint64(rv) 706 | default: 707 | panic(InvalidOpError{Op: "<<", V: rhs}) 708 | } 709 | 710 | switch lv := l.RawValue().(type) { 711 | case int: 712 | return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Int)} 713 | case int8: 714 | return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Int8)} 715 | case int16: 716 | return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Int16)} 717 | case int32: 718 | return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Int32)} 719 | case int64: 720 | return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Int64)} 721 | case uint: 722 | return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Uint)} 723 | case uint8: 724 | return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Uint8)} 725 | case uint16: 726 | return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Uint16)} 727 | case uint32: 728 | return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Uint32)} 729 | case uint64: 730 | return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Uint64)} 731 | case uintptr: 732 | return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Uintptr)} 733 | default: 734 | panic(InvalidOpError{Op: "<<", V: l}) 735 | } 736 | } 737 | 738 | func (v val) Rsh(rhs Value) Value { 739 | l := coerce1(v) 740 | shift := uint64(0) 741 | 742 | switch rv := rhs.RawValue().(type) { 743 | case uint: 744 | shift = uint64(rv) 745 | case uint8: 746 | shift = uint64(rv) 747 | case uint16: 748 | shift = uint64(rv) 749 | case uint32: 750 | shift = uint64(rv) 751 | case uint64: 752 | shift = uint64(rv) 753 | case uintptr: 754 | shift = uint64(rv) 755 | default: 756 | panic(InvalidOpError{Op: ">>", V: rhs}) 757 | } 758 | 759 | switch lv := l.RawValue().(type) { 760 | case int: 761 | return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Int)} 762 | case int8: 763 | return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Int8)} 764 | case int16: 765 | return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Int16)} 766 | case int32: 767 | return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Int32)} 768 | case int64: 769 | return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Int64)} 770 | case uint: 771 | return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Uint)} 772 | case uint8: 773 | return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Uint8)} 774 | case uint16: 775 | return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Uint16)} 776 | case uint32: 777 | return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Uint32)} 778 | case uint64: 779 | return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Uint64)} 780 | case uintptr: 781 | return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Uintptr)} 782 | default: 783 | panic(InvalidOpError{Op: ">>", V: l}) 784 | } 785 | } 786 | 787 | func (v val) And(rhs Value) Value { 788 | l, r := coerce(v, rhs) 789 | switch lv := l.RawValue().(type) { 790 | case int: 791 | return val{reflect.ValueOf(lv & r.RawValue().(int)), NewPrimitiveType(Int)} 792 | case int8: 793 | return val{reflect.ValueOf(lv & r.RawValue().(int8)), NewPrimitiveType(Int8)} 794 | case int16: 795 | return val{reflect.ValueOf(lv & r.RawValue().(int16)), NewPrimitiveType(Int16)} 796 | case int32: 797 | return val{reflect.ValueOf(lv & r.RawValue().(int32)), NewPrimitiveType(Int32)} 798 | case int64: 799 | return val{reflect.ValueOf(lv & r.RawValue().(int64)), NewPrimitiveType(Int64)} 800 | case uint: 801 | return val{reflect.ValueOf(lv & r.RawValue().(uint)), NewPrimitiveType(Uint)} 802 | case uint8: 803 | return val{reflect.ValueOf(lv & r.RawValue().(uint8)), NewPrimitiveType(Uint8)} 804 | case uint16: 805 | return val{reflect.ValueOf(lv & r.RawValue().(uint16)), NewPrimitiveType(Uint16)} 806 | case uint32: 807 | return val{reflect.ValueOf(lv & r.RawValue().(uint32)), NewPrimitiveType(Uint32)} 808 | case uint64: 809 | return val{reflect.ValueOf(lv & r.RawValue().(uint64)), NewPrimitiveType(Uint64)} 810 | case uintptr: 811 | return val{reflect.ValueOf(lv & r.RawValue().(uintptr)), NewPrimitiveType(Uintptr)} 812 | default: 813 | panic(InvalidOpError{Op: "&", V: l}) 814 | } 815 | } 816 | 817 | func (v val) AndNot(rhs Value) Value { 818 | l, r := coerce(v, rhs) 819 | switch lv := l.RawValue().(type) { 820 | case int: 821 | return val{reflect.ValueOf(lv &^ r.RawValue().(int)), NewPrimitiveType(Int)} 822 | case int8: 823 | return val{reflect.ValueOf(lv &^ r.RawValue().(int8)), NewPrimitiveType(Int8)} 824 | case int16: 825 | return val{reflect.ValueOf(lv &^ r.RawValue().(int16)), NewPrimitiveType(Int16)} 826 | case int32: 827 | return val{reflect.ValueOf(lv &^ r.RawValue().(int32)), NewPrimitiveType(Int32)} 828 | case int64: 829 | return val{reflect.ValueOf(lv &^ r.RawValue().(int64)), NewPrimitiveType(Int64)} 830 | case uint: 831 | return val{reflect.ValueOf(lv &^ r.RawValue().(uint)), NewPrimitiveType(Uint)} 832 | case uint8: 833 | return val{reflect.ValueOf(lv &^ r.RawValue().(uint8)), NewPrimitiveType(Uint8)} 834 | case uint16: 835 | return val{reflect.ValueOf(lv &^ r.RawValue().(uint16)), NewPrimitiveType(Uint16)} 836 | case uint32: 837 | return val{reflect.ValueOf(lv &^ r.RawValue().(uint32)), NewPrimitiveType(Uint32)} 838 | case uint64: 839 | return val{reflect.ValueOf(lv &^ r.RawValue().(uint64)), NewPrimitiveType(Uint64)} 840 | case uintptr: 841 | return val{reflect.ValueOf(lv &^ r.RawValue().(uintptr)), NewPrimitiveType(Uintptr)} 842 | default: 843 | panic(InvalidOpError{Op: "&^", V: l}) 844 | } 845 | } 846 | 847 | func (v val) Index(rhs Value) Value { 848 | if v.t.Kind() == String { 849 | index := promote(rhs, NewPrimitiveType(Int)).RawValue().(int) 850 | return val{reflect.ValueOf(v.RawValue().(string)[index]), NewPrimitiveType(Uint8)} 851 | } 852 | switch t := v.t.(type) { 853 | case *ArrayType: 854 | return val{v.v.Index(promote(rhs, NewPrimitiveType(Int)).RawValue().(int)), t.Elem()} 855 | case *SliceType: 856 | return val{v.v.Index(promote(rhs, NewPrimitiveType(Int)).RawValue().(int)), t.Elem()} 857 | case *MapType: 858 | return val{v.v.MapIndex(promote(rhs, t.Key()).Value()), t.Value()} 859 | default: 860 | panic(InvalidOpError{Op: "[]", V: v}) 861 | } 862 | } 863 | 864 | func (v val) Call(in []Value) Value { 865 | ft, ok := v.t.(*FuncType) 866 | if !ok { 867 | panic("Call invoked on non-function") 868 | } 869 | if len(in) != ft.NumIn() { 870 | panic("invalid number of arguments to function") 871 | } 872 | inconv := []reflect.Value{} 873 | for i, n := range in { 874 | inconv = append(inconv, promote(n, ft.In(i)).Value()) 875 | } 876 | out := v.v.Call(inconv) 877 | if len(out) != 1 { 878 | panic("only functions returning 1 value are supported") 879 | } 880 | return val{out[0], ft.Out(0)} 881 | } 882 | 883 | // ValueOf returns a Value for the given runtime value. 884 | func ValueOf(i interface{}) Value { 885 | return val{reflect.ValueOf(i), TypeOf(i)} 886 | } 887 | 888 | func literalboolval(v bool) Value { 889 | return val{reflect.ValueOf(v), NewLiteralType(UntypedBool)} 890 | } 891 | 892 | func literalstrval(v string) Value { 893 | return val{reflect.ValueOf(v), NewPrimitiveType(String)} 894 | } 895 | 896 | func literalintval(v int64) Value { 897 | return val{reflect.ValueOf(v), NewLiteralType(UntypedInt)} 898 | } 899 | 900 | func literaluintval(v uint64) Value { 901 | return val{reflect.ValueOf(v), NewLiteralType(UntypedInt)} 902 | } 903 | 904 | func literalfloatval(v float64) Value { 905 | return val{reflect.ValueOf(v), NewLiteralType(UntypedFloat)} 906 | } 907 | 908 | func literalnilval() Value { 909 | return val{reflect.ValueOf(interface{}(nil)), NewLiteralType(UntypedNil)} 910 | } 911 | -------------------------------------------------------------------------------- /expr/value_test.go: -------------------------------------------------------------------------------- 1 | package expr 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestValueBasicCompare(t *testing.T) { 10 | assert.Equal(t, ValueOf(true).RawValue(), ValueOf(int(10)).Add(ValueOf(int(20))).Equal(ValueOf(int(30))).RawValue()) 11 | assert.Equal(t, ValueOf(true).RawValue(), ValueOf(int8(10)).Add(ValueOf(int8(20))).Equal(ValueOf(int8(30))).RawValue()) 12 | assert.Equal(t, ValueOf(true).RawValue(), ValueOf(int16(10)).Add(ValueOf(int16(20))).Equal(ValueOf(int16(30))).RawValue()) 13 | assert.Equal(t, ValueOf(true).RawValue(), ValueOf(int32(10)).Add(ValueOf(int32(20))).Equal(ValueOf(int32(30))).RawValue()) 14 | assert.Equal(t, ValueOf(true).RawValue(), ValueOf(int64(10)).Add(ValueOf(int64(20))).Equal(ValueOf(int64(30))).RawValue()) 15 | assert.Equal(t, ValueOf(true).RawValue(), ValueOf(uint(10)).Add(ValueOf(uint(20))).Equal(ValueOf(uint(30))).RawValue()) 16 | assert.Equal(t, ValueOf(true).RawValue(), ValueOf(uint8(10)).Add(ValueOf(uint8(20))).Equal(ValueOf(uint8(30))).RawValue()) 17 | assert.Equal(t, ValueOf(true).RawValue(), ValueOf(uint16(10)).Add(ValueOf(uint16(20))).Equal(ValueOf(uint16(30))).RawValue()) 18 | assert.Equal(t, ValueOf(true).RawValue(), ValueOf(uint32(10)).Add(ValueOf(uint32(20))).Equal(ValueOf(uint32(30))).RawValue()) 19 | assert.Equal(t, ValueOf(true).RawValue(), ValueOf(uint64(10)).Add(ValueOf(uint64(20))).Equal(ValueOf(uint64(30))).RawValue()) 20 | assert.Equal(t, ValueOf(true).RawValue(), ValueOf(uintptr(10)).Add(ValueOf(uintptr(20))).Equal(ValueOf(uintptr(30))).RawValue()) 21 | assert.Equal(t, ValueOf(true).RawValue(), ValueOf(float32(10)).Add(ValueOf(float32(20))).Equal(ValueOf(float32(30))).RawValue()) 22 | assert.Equal(t, ValueOf(true).RawValue(), ValueOf(float64(10)).Add(ValueOf(float64(20))).Equal(ValueOf(float64(30))).RawValue()) 23 | 24 | assert.Equal(t, ValueOf(false).RawValue(), ValueOf(int(15)).Add(ValueOf(int(20))).Equal(ValueOf(int(30))).RawValue()) 25 | assert.Equal(t, ValueOf(false).RawValue(), ValueOf(int8(15)).Add(ValueOf(int8(20))).Equal(ValueOf(int8(30))).RawValue()) 26 | assert.Equal(t, ValueOf(false).RawValue(), ValueOf(int16(15)).Add(ValueOf(int16(20))).Equal(ValueOf(int16(30))).RawValue()) 27 | assert.Equal(t, ValueOf(false).RawValue(), ValueOf(int32(15)).Add(ValueOf(int32(20))).Equal(ValueOf(int32(30))).RawValue()) 28 | assert.Equal(t, ValueOf(false).RawValue(), ValueOf(int64(15)).Add(ValueOf(int64(20))).Equal(ValueOf(int64(30))).RawValue()) 29 | assert.Equal(t, ValueOf(false).RawValue(), ValueOf(uint(15)).Add(ValueOf(uint(20))).Equal(ValueOf(uint(30))).RawValue()) 30 | assert.Equal(t, ValueOf(false).RawValue(), ValueOf(uint8(15)).Add(ValueOf(uint8(20))).Equal(ValueOf(uint8(30))).RawValue()) 31 | assert.Equal(t, ValueOf(false).RawValue(), ValueOf(uint16(15)).Add(ValueOf(uint16(20))).Equal(ValueOf(uint16(30))).RawValue()) 32 | assert.Equal(t, ValueOf(false).RawValue(), ValueOf(uint32(15)).Add(ValueOf(uint32(20))).Equal(ValueOf(uint32(30))).RawValue()) 33 | assert.Equal(t, ValueOf(false).RawValue(), ValueOf(uint64(15)).Add(ValueOf(uint64(20))).Equal(ValueOf(uint64(30))).RawValue()) 34 | assert.Equal(t, ValueOf(false).RawValue(), ValueOf(uintptr(15)).Add(ValueOf(uintptr(20))).Equal(ValueOf(uintptr(30))).RawValue()) 35 | assert.Equal(t, ValueOf(false).RawValue(), ValueOf(float32(15)).Add(ValueOf(float32(20))).Equal(ValueOf(float32(30))).RawValue()) 36 | assert.Equal(t, ValueOf(false).RawValue(), ValueOf(float64(15)).Add(ValueOf(float64(20))).Equal(ValueOf(float64(30))).RawValue()) 37 | 38 | assert.Equal(t, ValueOf(false).RawValue(), ValueOf(int(10)).Add(ValueOf(int(20))).NotEqual(ValueOf(int(30))).RawValue()) 39 | assert.Equal(t, ValueOf(false).RawValue(), ValueOf(int8(10)).Add(ValueOf(int8(20))).NotEqual(ValueOf(int8(30))).RawValue()) 40 | assert.Equal(t, ValueOf(false).RawValue(), ValueOf(int16(10)).Add(ValueOf(int16(20))).NotEqual(ValueOf(int16(30))).RawValue()) 41 | assert.Equal(t, ValueOf(false).RawValue(), ValueOf(int32(10)).Add(ValueOf(int32(20))).NotEqual(ValueOf(int32(30))).RawValue()) 42 | assert.Equal(t, ValueOf(false).RawValue(), ValueOf(int64(10)).Add(ValueOf(int64(20))).NotEqual(ValueOf(int64(30))).RawValue()) 43 | assert.Equal(t, ValueOf(false).RawValue(), ValueOf(uint(10)).Add(ValueOf(uint(20))).NotEqual(ValueOf(uint(30))).RawValue()) 44 | assert.Equal(t, ValueOf(false).RawValue(), ValueOf(uint8(10)).Add(ValueOf(uint8(20))).NotEqual(ValueOf(uint8(30))).RawValue()) 45 | assert.Equal(t, ValueOf(false).RawValue(), ValueOf(uint16(10)).Add(ValueOf(uint16(20))).NotEqual(ValueOf(uint16(30))).RawValue()) 46 | assert.Equal(t, ValueOf(false).RawValue(), ValueOf(uint32(10)).Add(ValueOf(uint32(20))).NotEqual(ValueOf(uint32(30))).RawValue()) 47 | assert.Equal(t, ValueOf(false).RawValue(), ValueOf(uint64(10)).Add(ValueOf(uint64(20))).NotEqual(ValueOf(uint64(30))).RawValue()) 48 | assert.Equal(t, ValueOf(false).RawValue(), ValueOf(uintptr(10)).Add(ValueOf(uintptr(20))).NotEqual(ValueOf(uintptr(30))).RawValue()) 49 | assert.Equal(t, ValueOf(false).RawValue(), ValueOf(float32(10)).Add(ValueOf(float32(20))).NotEqual(ValueOf(float32(30))).RawValue()) 50 | assert.Equal(t, ValueOf(false).RawValue(), ValueOf(float64(10)).Add(ValueOf(float64(20))).NotEqual(ValueOf(float64(30))).RawValue()) 51 | 52 | assert.Equal(t, ValueOf(true).RawValue(), ValueOf(int(15)).Add(ValueOf(int(20))).NotEqual(ValueOf(int(30))).RawValue()) 53 | assert.Equal(t, ValueOf(true).RawValue(), ValueOf(int8(15)).Add(ValueOf(int8(20))).NotEqual(ValueOf(int8(30))).RawValue()) 54 | assert.Equal(t, ValueOf(true).RawValue(), ValueOf(int16(15)).Add(ValueOf(int16(20))).NotEqual(ValueOf(int16(30))).RawValue()) 55 | assert.Equal(t, ValueOf(true).RawValue(), ValueOf(int32(15)).Add(ValueOf(int32(20))).NotEqual(ValueOf(int32(30))).RawValue()) 56 | assert.Equal(t, ValueOf(true).RawValue(), ValueOf(int64(15)).Add(ValueOf(int64(20))).NotEqual(ValueOf(int64(30))).RawValue()) 57 | assert.Equal(t, ValueOf(true).RawValue(), ValueOf(uint(15)).Add(ValueOf(uint(20))).NotEqual(ValueOf(uint(30))).RawValue()) 58 | assert.Equal(t, ValueOf(true).RawValue(), ValueOf(uint8(15)).Add(ValueOf(uint8(20))).NotEqual(ValueOf(uint8(30))).RawValue()) 59 | assert.Equal(t, ValueOf(true).RawValue(), ValueOf(uint16(15)).Add(ValueOf(uint16(20))).NotEqual(ValueOf(uint16(30))).RawValue()) 60 | assert.Equal(t, ValueOf(true).RawValue(), ValueOf(uint32(15)).Add(ValueOf(uint32(20))).NotEqual(ValueOf(uint32(30))).RawValue()) 61 | assert.Equal(t, ValueOf(true).RawValue(), ValueOf(uint64(15)).Add(ValueOf(uint64(20))).NotEqual(ValueOf(uint64(30))).RawValue()) 62 | assert.Equal(t, ValueOf(true).RawValue(), ValueOf(uintptr(15)).Add(ValueOf(uintptr(20))).NotEqual(ValueOf(uintptr(30))).RawValue()) 63 | assert.Equal(t, ValueOf(true).RawValue(), ValueOf(float32(15)).Add(ValueOf(float32(20))).NotEqual(ValueOf(float32(30))).RawValue()) 64 | assert.Equal(t, ValueOf(true).RawValue(), ValueOf(float64(15)).Add(ValueOf(float64(20))).NotEqual(ValueOf(float64(30))).RawValue()) 65 | } 66 | 67 | func TestCoerceUntyped(t *testing.T) { 68 | assert.Equal(t, ValueOf(true).RawValue(), literalintval(10).Add(ValueOf(int(20))).Equal(ValueOf(int(30))).RawValue()) 69 | assert.Equal(t, ValueOf(true).RawValue(), literalintval(10).Add(ValueOf(int8(20))).Equal(ValueOf(int8(30))).RawValue()) 70 | assert.Equal(t, ValueOf(true).RawValue(), literalintval(10).Add(ValueOf(int16(20))).Equal(ValueOf(int16(30))).RawValue()) 71 | assert.Equal(t, ValueOf(true).RawValue(), literalintval(10).Add(ValueOf(int32(20))).Equal(ValueOf(int32(30))).RawValue()) 72 | assert.Equal(t, ValueOf(true).RawValue(), literalintval(10).Add(ValueOf(int64(20))).Equal(ValueOf(int64(30))).RawValue()) 73 | assert.Equal(t, ValueOf(true).RawValue(), literalintval(10).Add(ValueOf(uint(20))).Equal(ValueOf(uint(30))).RawValue()) 74 | assert.Equal(t, ValueOf(true).RawValue(), literalintval(10).Add(ValueOf(uint8(20))).Equal(ValueOf(uint8(30))).RawValue()) 75 | assert.Equal(t, ValueOf(true).RawValue(), literalintval(10).Add(ValueOf(uint16(20))).Equal(ValueOf(uint16(30))).RawValue()) 76 | assert.Equal(t, ValueOf(true).RawValue(), literalintval(10).Add(ValueOf(uint32(20))).Equal(ValueOf(uint32(30))).RawValue()) 77 | assert.Equal(t, ValueOf(true).RawValue(), literalintval(10).Add(ValueOf(uint64(20))).Equal(ValueOf(uint64(30))).RawValue()) 78 | assert.Equal(t, ValueOf(true).RawValue(), literalintval(10).Add(ValueOf(uintptr(20))).Equal(ValueOf(uintptr(30))).RawValue()) 79 | assert.Equal(t, ValueOf(true).RawValue(), literalintval(10).Add(ValueOf(float32(20))).Equal(ValueOf(float32(30))).RawValue()) 80 | assert.Equal(t, ValueOf(true).RawValue(), literalintval(10).Add(ValueOf(float64(20))).Equal(ValueOf(float64(30))).RawValue()) 81 | 82 | assert.Equal(t, ValueOf(true).RawValue(), literaluintval(10).Add(ValueOf(int(20))).Equal(ValueOf(int(30))).RawValue()) 83 | assert.Equal(t, ValueOf(true).RawValue(), literaluintval(10).Add(ValueOf(int8(20))).Equal(ValueOf(int8(30))).RawValue()) 84 | assert.Equal(t, ValueOf(true).RawValue(), literaluintval(10).Add(ValueOf(int16(20))).Equal(ValueOf(int16(30))).RawValue()) 85 | assert.Equal(t, ValueOf(true).RawValue(), literaluintval(10).Add(ValueOf(int32(20))).Equal(ValueOf(int32(30))).RawValue()) 86 | assert.Equal(t, ValueOf(true).RawValue(), literaluintval(10).Add(ValueOf(int64(20))).Equal(ValueOf(int64(30))).RawValue()) 87 | assert.Equal(t, ValueOf(true).RawValue(), literaluintval(10).Add(ValueOf(uint(20))).Equal(ValueOf(uint(30))).RawValue()) 88 | assert.Equal(t, ValueOf(true).RawValue(), literaluintval(10).Add(ValueOf(uint8(20))).Equal(ValueOf(uint8(30))).RawValue()) 89 | assert.Equal(t, ValueOf(true).RawValue(), literaluintval(10).Add(ValueOf(uint16(20))).Equal(ValueOf(uint16(30))).RawValue()) 90 | assert.Equal(t, ValueOf(true).RawValue(), literaluintval(10).Add(ValueOf(uint32(20))).Equal(ValueOf(uint32(30))).RawValue()) 91 | assert.Equal(t, ValueOf(true).RawValue(), literaluintval(10).Add(ValueOf(uint64(20))).Equal(ValueOf(uint64(30))).RawValue()) 92 | assert.Equal(t, ValueOf(true).RawValue(), literaluintval(10).Add(ValueOf(uintptr(20))).Equal(ValueOf(uintptr(30))).RawValue()) 93 | assert.Equal(t, ValueOf(true).RawValue(), literaluintval(10).Add(ValueOf(float32(20))).Equal(ValueOf(float32(30))).RawValue()) 94 | assert.Equal(t, ValueOf(true).RawValue(), literaluintval(10).Add(ValueOf(float64(20))).Equal(ValueOf(float64(30))).RawValue()) 95 | } 96 | 97 | func TestUnaryOps(t *testing.T) { 98 | i := 35 99 | s := struct{ I int }{I: 35} 100 | assert.Equal(t, ValueOf(-15).RawValue(), ValueOf(15).Negate().RawValue()) 101 | assert.Equal(t, ValueOf(!true).RawValue(), ValueOf(true).Not().RawValue()) 102 | assert.Equal(t, ValueOf(!false).RawValue(), ValueOf(false).Not().RawValue()) 103 | assert.Equal(t, ValueOf(^25).RawValue(), ValueOf(25).BitNot().RawValue()) 104 | assert.Equal(t, ValueOf(35).RawValue(), ValueOf(&i).Deref().RawValue()) 105 | assert.Equal(t, ValueOf(35).RawValue(), ValueOf(&s).Dot("I").Ref().Deref().RawValue()) 106 | } 107 | -------------------------------------------------------------------------------- /expr_18.go: -------------------------------------------------------------------------------- 1 | // +build !go1.9 2 | 3 | package restruct 4 | 5 | import ( 6 | "github.com/go-restruct/restruct/expr" 7 | ) 8 | 9 | var exprStdLib = map[string]expr.Value{} 10 | -------------------------------------------------------------------------------- /expr_19.go: -------------------------------------------------------------------------------- 1 | // +build go1.9 2 | 3 | package restruct 4 | 5 | import ( 6 | "math/bits" 7 | 8 | "github.com/go-restruct/restruct/expr" 9 | ) 10 | 11 | var exprStdLib = map[string]expr.Value{ 12 | "bits": expr.ValueOf(expr.NewPackage(map[string]expr.Value{ 13 | "LeadingZeros": expr.ValueOf(bits.LeadingZeros), 14 | "LeadingZeros8": expr.ValueOf(bits.LeadingZeros8), 15 | "LeadingZeros16": expr.ValueOf(bits.LeadingZeros16), 16 | "LeadingZeros32": expr.ValueOf(bits.LeadingZeros32), 17 | "LeadingZeros64": expr.ValueOf(bits.LeadingZeros64), 18 | 19 | "Len": expr.ValueOf(bits.Len), 20 | "Len8": expr.ValueOf(bits.Len8), 21 | "Len16": expr.ValueOf(bits.Len16), 22 | "Len32": expr.ValueOf(bits.Len32), 23 | "Len64": expr.ValueOf(bits.Len64), 24 | 25 | "OnesCount": expr.ValueOf(bits.OnesCount), 26 | "OnesCount8": expr.ValueOf(bits.OnesCount8), 27 | "OnesCount16": expr.ValueOf(bits.OnesCount16), 28 | "OnesCount32": expr.ValueOf(bits.OnesCount32), 29 | "OnesCount64": expr.ValueOf(bits.OnesCount64), 30 | 31 | "Reverse": expr.ValueOf(bits.Reverse), 32 | "Reverse8": expr.ValueOf(bits.Reverse8), 33 | "Reverse16": expr.ValueOf(bits.Reverse16), 34 | "Reverse32": expr.ValueOf(bits.Reverse32), 35 | "Reverse64": expr.ValueOf(bits.Reverse64), 36 | 37 | "ReverseBytes": expr.ValueOf(bits.ReverseBytes), 38 | "ReverseBytes16": expr.ValueOf(bits.ReverseBytes16), 39 | "ReverseBytes32": expr.ValueOf(bits.ReverseBytes32), 40 | "ReverseBytes64": expr.ValueOf(bits.ReverseBytes64), 41 | 42 | "RotateLeft": expr.ValueOf(bits.RotateLeft), 43 | "RotateLeft8": expr.ValueOf(bits.RotateLeft8), 44 | "RotateLeft16": expr.ValueOf(bits.RotateLeft16), 45 | "RotateLeft32": expr.ValueOf(bits.RotateLeft32), 46 | "RotateLeft64": expr.ValueOf(bits.RotateLeft64), 47 | 48 | "TrailingZeros": expr.ValueOf(bits.TrailingZeros), 49 | "TrailingZeros8": expr.ValueOf(bits.TrailingZeros8), 50 | "TrailingZeros16": expr.ValueOf(bits.TrailingZeros16), 51 | "TrailingZeros32": expr.ValueOf(bits.TrailingZeros32), 52 | "TrailingZeros64": expr.ValueOf(bits.TrailingZeros64), 53 | })), 54 | } 55 | -------------------------------------------------------------------------------- /field.go: -------------------------------------------------------------------------------- 1 | package restruct 2 | 3 | import ( 4 | "encoding/binary" 5 | "errors" 6 | "fmt" 7 | "reflect" 8 | "sync" 9 | 10 | "github.com/go-restruct/restruct/expr" 11 | ) 12 | 13 | // ErrInvalidSize is returned when sizefrom is used on an invalid type. 14 | var ErrInvalidSize = errors.New("size specified on fixed size type") 15 | 16 | // ErrInvalidSizeOf is returned when sizefrom is used on an invalid type. 17 | var ErrInvalidSizeOf = errors.New("sizeof specified on fixed size type") 18 | 19 | // ErrInvalidSizeFrom is returned when sizefrom is used on an invalid type. 20 | var ErrInvalidSizeFrom = errors.New("sizefrom specified on fixed size type") 21 | 22 | // ErrInvalidBits is returned when bits is used on an invalid type. 23 | var ErrInvalidBits = errors.New("bits specified on non-bitwise type") 24 | 25 | // FieldFlags is a type for flags that can be applied to fields individually. 26 | type FieldFlags uint64 27 | 28 | const ( 29 | // VariantBoolFlag causes the true value of a boolean to be ~0 instead of 30 | // just 1 (all bits are set.) This emulates the behavior of VARIANT_BOOL. 31 | VariantBoolFlag FieldFlags = 1 << iota 32 | 33 | // InvertedBoolFlag causes the true and false states of a boolean to be 34 | // flipped in binary. 35 | InvertedBoolFlag 36 | 37 | // RootFlag is set when the field points to the root struct. 38 | RootFlag 39 | 40 | // ParentFlag is set when the field points to the parent struct. 41 | ParentFlag 42 | 43 | // DefaultFlag is set when the field is designated as a switch case default. 44 | DefaultFlag 45 | ) 46 | 47 | // Sizer is a type which has a defined size in binary. The SizeOf function 48 | // returns how many bytes the type will consume in memory. This is used during 49 | // encoding for allocation and therefore must equal the exact number of bytes 50 | // the encoded form needs. You may use a pointer receiver even if the type is 51 | // used by value. 52 | type Sizer interface { 53 | SizeOf() int 54 | } 55 | 56 | // BitSizer is an interface for types that need to specify their own size in 57 | // bit-level granularity. It has the same effect as Sizer. 58 | type BitSizer interface { 59 | BitSize() int 60 | } 61 | 62 | // field represents a structure field, similar to reflect.StructField. 63 | type field struct { 64 | Name string 65 | Index int 66 | BinaryType reflect.Type 67 | NativeType reflect.Type 68 | Order binary.ByteOrder 69 | SIndex int // Index of size field for a slice/string. 70 | TIndex int // Index of target of sizeof field. 71 | Skip int 72 | Trivial bool 73 | BitSize uint8 74 | Flags FieldFlags 75 | IsRoot bool 76 | IsParent bool 77 | 78 | IfExpr *expr.Program 79 | SizeExpr *expr.Program 80 | BitsExpr *expr.Program 81 | InExpr *expr.Program 82 | OutExpr *expr.Program 83 | WhileExpr *expr.Program 84 | SwitchExpr *expr.Program 85 | CaseExpr *expr.Program 86 | } 87 | 88 | // fields represents a structure. 89 | type fields []field 90 | 91 | var fieldCache = map[reflect.Type][]field{} 92 | var cacheMutex = sync.RWMutex{} 93 | 94 | // Elem constructs a transient field representing an element of an array, slice, 95 | // or pointer. 96 | func (f *field) Elem() field { 97 | // Special cases for string types, grumble grumble. 98 | t := f.BinaryType 99 | if t.Kind() == reflect.String { 100 | t = reflect.TypeOf([]byte{}) 101 | } 102 | 103 | dt := f.NativeType 104 | if dt.Kind() == reflect.String { 105 | dt = reflect.TypeOf([]byte{}) 106 | } 107 | 108 | return field{ 109 | Name: "*" + f.Name, 110 | Index: -1, 111 | BinaryType: t.Elem(), 112 | NativeType: dt.Elem(), 113 | Order: f.Order, 114 | TIndex: -1, 115 | SIndex: -1, 116 | Skip: 0, 117 | Trivial: isTypeTrivial(t.Elem()), 118 | } 119 | } 120 | 121 | // fieldFromType returns a field from a reflected type. 122 | func fieldFromType(typ reflect.Type) field { 123 | return field{ 124 | Index: -1, 125 | BinaryType: typ, 126 | NativeType: typ, 127 | Order: nil, 128 | TIndex: -1, 129 | SIndex: -1, 130 | Skip: 0, 131 | Trivial: isTypeTrivial(typ), 132 | } 133 | } 134 | 135 | func validBitType(typ reflect.Type) bool { 136 | switch typ.Kind() { 137 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, 138 | reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, 139 | reflect.Uint32, reflect.Uint64, reflect.Float32, 140 | reflect.Complex64, reflect.Complex128: 141 | return true 142 | default: 143 | return false 144 | } 145 | } 146 | 147 | func validSizeType(typ reflect.Type) bool { 148 | switch typ.Kind() { 149 | case reflect.Slice, reflect.String: 150 | return true 151 | default: 152 | return false 153 | } 154 | } 155 | 156 | func parseExpr(sources ...string) *expr.Program { 157 | for _, s := range sources { 158 | if s != "" { 159 | return expr.ParseString(s) 160 | } 161 | } 162 | return nil 163 | } 164 | 165 | // fieldsFromStruct returns a slice of fields for binary packing and unpacking. 166 | func fieldsFromStruct(typ reflect.Type) (result fields) { 167 | if typ.Kind() != reflect.Struct { 168 | panic(fmt.Errorf("tried to get fields from non-struct type %s", typ.Kind().String())) 169 | } 170 | 171 | count := typ.NumField() 172 | 173 | sizeOfMap := map[string]int{} 174 | 175 | for i := 0; i < count; i++ { 176 | val := typ.Field(i) 177 | 178 | // Skip unexported names (except _) 179 | if val.PkgPath != "" && val.Name != "_" { 180 | continue 181 | } 182 | 183 | // Parse struct tag 184 | opts := mustParseTag(val.Tag.Get("struct")) 185 | if opts.Ignore { 186 | continue 187 | } 188 | 189 | if opts.RootFlag { 190 | result = append(result, field{ 191 | Name: val.Name, 192 | Index: i, 193 | Flags: RootFlag, 194 | }) 195 | continue 196 | } 197 | 198 | if opts.ParentFlag { 199 | result = append(result, field{ 200 | Name: val.Name, 201 | Index: i, 202 | Flags: ParentFlag, 203 | }) 204 | continue 205 | } 206 | 207 | // Derive type 208 | ftyp := val.Type 209 | if opts.Type != nil { 210 | ftyp = opts.Type 211 | } 212 | 213 | // SizeOf 214 | sindex := -1 215 | tindex := -1 216 | if j, ok := sizeOfMap[val.Name]; ok { 217 | if !validSizeType(val.Type) { 218 | panic(ErrInvalidSizeOf) 219 | } 220 | sindex = j 221 | result[sindex].TIndex = i 222 | delete(sizeOfMap, val.Name) 223 | } else if opts.SizeOf != "" { 224 | sizeOfMap[opts.SizeOf] = i 225 | } 226 | 227 | // SizeFrom 228 | if opts.SizeFrom != "" { 229 | if !validSizeType(val.Type) { 230 | panic(ErrInvalidSizeFrom) 231 | } 232 | for j := 0; j < i; j++ { 233 | val := result[j] 234 | if opts.SizeFrom == val.Name { 235 | sindex = j 236 | result[sindex].TIndex = i 237 | } 238 | } 239 | if sindex == -1 { 240 | panic(fmt.Errorf("couldn't find SizeFrom field %s", opts.SizeFrom)) 241 | } 242 | } 243 | 244 | // Expr 245 | ifExpr := parseExpr(opts.IfExpr, val.Tag.Get("struct-if")) 246 | sizeExpr := parseExpr(opts.SizeExpr, val.Tag.Get("struct-size")) 247 | bitsExpr := parseExpr(opts.BitsExpr, val.Tag.Get("struct-bits")) 248 | inExpr := parseExpr(opts.InExpr, val.Tag.Get("struct-in")) 249 | outExpr := parseExpr(opts.OutExpr, val.Tag.Get("struct-out")) 250 | whileExpr := parseExpr(opts.WhileExpr, val.Tag.Get("struct-while")) 251 | switchExpr := parseExpr(opts.SwitchExpr, val.Tag.Get("struct-switch")) 252 | caseExpr := parseExpr(opts.CaseExpr, val.Tag.Get("struct-case")) 253 | if sizeExpr != nil && !validSizeType(val.Type) { 254 | panic(ErrInvalidSize) 255 | } 256 | if bitsExpr != nil && !validBitType(ftyp) { 257 | panic(ErrInvalidBits) 258 | } 259 | 260 | // Flags 261 | flags := FieldFlags(0) 262 | if opts.VariantBoolFlag { 263 | flags |= VariantBoolFlag 264 | } 265 | if opts.InvertedBoolFlag { 266 | flags |= InvertedBoolFlag 267 | } 268 | if opts.DefaultFlag { 269 | flags |= DefaultFlag 270 | } 271 | 272 | result = append(result, field{ 273 | Name: val.Name, 274 | Index: i, 275 | BinaryType: ftyp, 276 | NativeType: val.Type, 277 | Order: opts.Order, 278 | SIndex: sindex, 279 | TIndex: tindex, 280 | Skip: opts.Skip, 281 | Trivial: isTypeTrivial(ftyp), 282 | BitSize: opts.BitSize, 283 | Flags: flags, 284 | IfExpr: ifExpr, 285 | SizeExpr: sizeExpr, 286 | BitsExpr: bitsExpr, 287 | InExpr: inExpr, 288 | OutExpr: outExpr, 289 | WhileExpr: whileExpr, 290 | SwitchExpr: switchExpr, 291 | CaseExpr: caseExpr, 292 | }) 293 | } 294 | 295 | for fieldName := range sizeOfMap { 296 | panic(fmt.Errorf("couldn't find SizeOf field %s", fieldName)) 297 | } 298 | 299 | return 300 | } 301 | 302 | func cachedFieldsFromStruct(typ reflect.Type) (result fields) { 303 | cacheMutex.RLock() 304 | result, ok := fieldCache[typ] 305 | cacheMutex.RUnlock() 306 | 307 | if ok { 308 | return 309 | } 310 | 311 | result = fieldsFromStruct(typ) 312 | 313 | cacheMutex.Lock() 314 | fieldCache[typ] = result 315 | cacheMutex.Unlock() 316 | 317 | return 318 | } 319 | 320 | // isTypeTrivial determines if a given type is constant-size. 321 | func isTypeTrivial(typ reflect.Type) bool { 322 | if typ == nil { 323 | return false 324 | } 325 | switch typ.Kind() { 326 | case reflect.Bool, 327 | reflect.Int, 328 | reflect.Int8, 329 | reflect.Int16, 330 | reflect.Int32, 331 | reflect.Int64, 332 | reflect.Uint, 333 | reflect.Uint8, 334 | reflect.Uint16, 335 | reflect.Uint32, 336 | reflect.Uint64, 337 | reflect.Uintptr, 338 | reflect.Float32, 339 | reflect.Float64, 340 | reflect.Complex64, 341 | reflect.Complex128: 342 | return true 343 | case reflect.Array, reflect.Ptr: 344 | return isTypeTrivial(typ.Elem()) 345 | case reflect.Struct: 346 | for _, field := range cachedFieldsFromStruct(typ) { 347 | if !isTypeTrivial(field.BinaryType) { 348 | return false 349 | } 350 | } 351 | return true 352 | default: 353 | return false 354 | } 355 | } 356 | 357 | func (f *field) sizer(v reflect.Value) (Sizer, bool) { 358 | if s, ok := v.Interface().(Sizer); ok { 359 | return s, true 360 | } 361 | 362 | if !v.CanAddr() { 363 | return nil, false 364 | } 365 | 366 | if s, ok := v.Addr().Interface().(Sizer); ok { 367 | return s, true 368 | } 369 | 370 | return nil, false 371 | } 372 | 373 | func (f *field) bitSizer(v reflect.Value) (BitSizer, bool) { 374 | if s, ok := v.Interface().(BitSizer); ok { 375 | return s, true 376 | } 377 | 378 | if !v.CanAddr() { 379 | return nil, false 380 | } 381 | 382 | if s, ok := v.Addr().Interface().(BitSizer); ok { 383 | return s, true 384 | } 385 | 386 | return nil, false 387 | } 388 | 389 | func (f *field) bitSizeUsingInterface(val reflect.Value) (int, bool) { 390 | if s, ok := f.bitSizer(val); ok { 391 | return s.BitSize(), true 392 | } 393 | 394 | if s, ok := f.sizer(val); ok { 395 | return s.SizeOf() * 8, true 396 | } 397 | 398 | return 0, false 399 | } 400 | -------------------------------------------------------------------------------- /field_test.go: -------------------------------------------------------------------------------- 1 | package restruct 2 | 3 | import ( 4 | "encoding/binary" 5 | "reflect" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | var intType = reflect.TypeOf(int(0)) 12 | var boolType = reflect.TypeOf(false) 13 | var strType = reflect.TypeOf(string("")) 14 | 15 | func TestFieldsFromStruct(t *testing.T) { 16 | tests := []struct { 17 | input interface{} 18 | fields fields 19 | }{ 20 | { 21 | struct { 22 | Simple int 23 | }{}, 24 | fields{ 25 | field{ 26 | Name: "Simple", 27 | Index: 0, 28 | BinaryType: intType, 29 | NativeType: intType, 30 | Order: nil, 31 | SIndex: -1, 32 | TIndex: -1, 33 | Skip: 0, 34 | Trivial: true, 35 | BitSize: 0, 36 | Flags: 0, 37 | }, 38 | }, 39 | }, 40 | { 41 | struct { 42 | Before int 43 | During string `struct:"-"` 44 | After bool 45 | }{}, 46 | fields{ 47 | field{ 48 | Name: "Before", 49 | Index: 0, 50 | BinaryType: intType, 51 | NativeType: intType, 52 | Order: nil, 53 | SIndex: -1, 54 | TIndex: -1, 55 | Skip: 0, 56 | Trivial: true, 57 | BitSize: 0, 58 | Flags: 0, 59 | }, 60 | field{ 61 | Name: "After", 62 | Index: 2, 63 | BinaryType: boolType, 64 | NativeType: boolType, 65 | Order: nil, 66 | SIndex: -1, 67 | TIndex: -1, 68 | Skip: 0, 69 | Trivial: true, 70 | BitSize: 0, 71 | Flags: 0, 72 | }, 73 | }, 74 | }, 75 | { 76 | struct { 77 | VariantBool bool `struct:"variantbool"` 78 | InvertedBool bool `struct:"invertedbool"` 79 | InvertedVariantBool bool `struct:"variantbool,invertedbool"` 80 | }{}, 81 | fields{ 82 | field{ 83 | Name: "VariantBool", 84 | Index: 0, 85 | BinaryType: boolType, 86 | NativeType: boolType, 87 | Order: nil, 88 | SIndex: -1, 89 | TIndex: -1, 90 | Skip: 0, 91 | Trivial: true, 92 | BitSize: 0, 93 | Flags: VariantBoolFlag, 94 | }, 95 | field{ 96 | Name: "InvertedBool", 97 | Index: 1, 98 | BinaryType: boolType, 99 | NativeType: boolType, 100 | Order: nil, 101 | SIndex: -1, 102 | TIndex: -1, 103 | Skip: 0, 104 | Trivial: true, 105 | BitSize: 0, 106 | Flags: InvertedBoolFlag, 107 | }, 108 | field{ 109 | Name: "InvertedVariantBool", 110 | Index: 2, 111 | BinaryType: boolType, 112 | NativeType: boolType, 113 | Order: nil, 114 | SIndex: -1, 115 | TIndex: -1, 116 | Skip: 0, 117 | Trivial: true, 118 | BitSize: 0, 119 | Flags: VariantBoolFlag | InvertedBoolFlag, 120 | }, 121 | }, 122 | }, 123 | { 124 | struct { 125 | FixedStr string `struct:"[64]byte,skip=4"` 126 | LSBInt int `struct:"uint32,little"` 127 | }{}, 128 | fields{ 129 | field{ 130 | Name: "FixedStr", 131 | Index: 0, 132 | BinaryType: reflect.TypeOf([64]byte{}), 133 | NativeType: strType, 134 | Order: nil, 135 | SIndex: -1, 136 | TIndex: -1, 137 | Skip: 4, 138 | Trivial: true, 139 | BitSize: 0, 140 | Flags: 0, 141 | }, 142 | field{ 143 | Name: "LSBInt", 144 | Index: 1, 145 | BinaryType: reflect.TypeOf(uint32(0)), 146 | NativeType: intType, 147 | Order: binary.LittleEndian, 148 | SIndex: -1, 149 | TIndex: -1, 150 | Skip: 0, 151 | Trivial: true, 152 | BitSize: 0, 153 | Flags: 0, 154 | }, 155 | }, 156 | }, 157 | { 158 | struct { 159 | NumColors int32 `struct:"sizeof=Colors"` 160 | Colors [][4]uint8 161 | }{}, 162 | fields{ 163 | field{ 164 | Name: "NumColors", 165 | Index: 0, 166 | BinaryType: reflect.TypeOf(int32(0)), 167 | NativeType: reflect.TypeOf(int32(0)), 168 | SIndex: -1, 169 | TIndex: 1, 170 | Skip: 0, 171 | Trivial: true, 172 | }, 173 | field{ 174 | Name: "Colors", 175 | Index: 1, 176 | BinaryType: reflect.TypeOf([][4]uint8{}), 177 | NativeType: reflect.TypeOf([][4]uint8{}), 178 | SIndex: 0, 179 | TIndex: -1, 180 | Skip: 0, 181 | Trivial: false, 182 | }, 183 | }, 184 | }, 185 | { 186 | struct { 187 | NumColors int32 188 | Colors [][4]uint8 `struct:"sizefrom=NumColors"` 189 | }{}, 190 | fields{ 191 | field{ 192 | Name: "NumColors", 193 | Index: 0, 194 | BinaryType: reflect.TypeOf(int32(0)), 195 | NativeType: reflect.TypeOf(int32(0)), 196 | SIndex: -1, 197 | TIndex: 1, 198 | Skip: 0, 199 | Trivial: true, 200 | }, 201 | field{ 202 | Name: "Colors", 203 | Index: 1, 204 | BinaryType: reflect.TypeOf([][4]uint8{}), 205 | NativeType: reflect.TypeOf([][4]uint8{}), 206 | SIndex: 0, 207 | TIndex: -1, 208 | Skip: 0, 209 | Trivial: false, 210 | }, 211 | }, 212 | }, 213 | } 214 | 215 | for _, test := range tests { 216 | fields := fieldsFromStruct(reflect.TypeOf(test.input)) 217 | assert.Equal(t, test.fields, fields) 218 | } 219 | } 220 | 221 | func TestFieldsFromNonStructPanics(t *testing.T) { 222 | defer func() { 223 | if r := recover(); r == nil { 224 | t.Error("Non-struct did not panic.") 225 | } 226 | }() 227 | fieldsFromStruct(reflect.TypeOf(0)) 228 | } 229 | 230 | func TestFieldsFromBrokenSizeOf(t *testing.T) { 231 | defer func() { 232 | r := recover() 233 | if r == nil { 234 | t.Error("Broken struct did not panic.") 235 | } 236 | assert.Equal(t, "couldn't find SizeOf field Nonexistant", r.(error).Error()) 237 | }() 238 | 239 | badSize := struct { 240 | Test int64 `struct:"sizeof=Nonexistant"` 241 | }{} 242 | fieldsFromStruct(reflect.TypeOf(badSize)) 243 | } 244 | 245 | func TestFieldsFromBrokenSizeFrom(t *testing.T) { 246 | defer func() { 247 | r := recover() 248 | if r == nil { 249 | t.Error("Broken struct did not panic.") 250 | } 251 | assert.Equal(t, "couldn't find SizeFrom field Nonexistant", r.(error).Error()) 252 | }() 253 | 254 | badSize := struct { 255 | Test string `struct:"sizefrom=Nonexistant"` 256 | }{} 257 | fieldsFromStruct(reflect.TypeOf(badSize)) 258 | } 259 | 260 | func TestIsTypeTrivial(t *testing.T) { 261 | tests := []struct { 262 | input interface{} 263 | trivial bool 264 | }{ 265 | {int8(0), true}, 266 | {int16(0), true}, 267 | {int32(0), true}, 268 | {int64(0), true}, 269 | {[0]int8{}, true}, 270 | {[]int8{}, false}, 271 | {struct{}{}, true}, 272 | {struct{ int8 }{}, true}, 273 | {struct{ A []int8 }{[]int8{}}, false}, 274 | {struct{ A [0]int8 }{[0]int8{}}, true}, 275 | {(*interface{})(nil), false}, 276 | } 277 | 278 | for _, test := range tests { 279 | assert.Equal(t, test.trivial, isTypeTrivial(reflect.TypeOf(test.input))) 280 | } 281 | } 282 | 283 | func BenchmarkFieldsFromStruct(b *testing.B) { 284 | for i := 0; i < b.N; i++ { 285 | fieldsFromStruct(reflect.TypeOf(TestStruct{})) 286 | } 287 | } 288 | -------------------------------------------------------------------------------- /formats/png/png.go: -------------------------------------------------------------------------------- 1 | // Package png implements some of the PNG format using Restruct. 2 | package png 3 | 4 | // ColorType is used to specify the color format of a PNG. 5 | type ColorType byte 6 | 7 | // Enumeration of valid ColorTypes. 8 | const ( 9 | ColorGreyscale ColorType = 0 10 | ColorTrueColor ColorType = 2 11 | ColorIndexed ColorType = 3 12 | ColorGreyscaleAlpha ColorType = 4 13 | ColorTrueColorAlpha ColorType = 6 14 | ) 15 | 16 | // File contains the data of an image. 17 | type File struct { 18 | Magic [8]byte 19 | Header Chunk 20 | Chunks []Chunk `struct-while:"!_eof"` 21 | } 22 | 23 | // Chunk contains the data of a single chunk. 24 | type Chunk struct { 25 | Len uint32 26 | Type string `struct:"[4]byte"` 27 | Data struct { 28 | IHDR *ChunkIHDR `struct-case:"$'IHDR'" json:",omitempty"` 29 | IDAT *ChunkIDAT `struct-case:"$'IDAT'" json:",omitempty"` 30 | IEND *ChunkIEND `struct-case:"$'IEND'" json:",omitempty"` 31 | Raw *ChunkRaw `struct:"default" json:",omitempty"` 32 | } `struct-switch:"Type"` 33 | CRC uint32 34 | } 35 | 36 | // ChunkIHDR contains the body of a IHDR chunk. 37 | type ChunkIHDR struct { 38 | Width uint32 39 | Height uint32 40 | BitDepth byte 41 | ColorType ColorType 42 | CompressionMethod byte 43 | FilterMethod byte 44 | InterlaceMethod byte 45 | } 46 | 47 | // ChunkIDAT contains the body of a IDAT chunk. 48 | type ChunkIDAT struct { 49 | Parent *Chunk `struct:"parent" json:"-"` 50 | Data []byte `struct-size:"Parent.Len"` 51 | } 52 | 53 | // ChunkRaw contains the body of an unrecognized chunk. 54 | type ChunkRaw struct { 55 | Parent *Chunk `struct:"parent" json:"-"` 56 | Data []byte `struct-size:"Parent.Len"` 57 | } 58 | 59 | // ChunkIEND contains the body of a IEND chunk. 60 | type ChunkIEND struct { 61 | } 62 | 63 | // ChunkPLTE contains the body of a PLTE chunk. 64 | type ChunkPLTE struct { 65 | } 66 | -------------------------------------------------------------------------------- /formats_test.go: -------------------------------------------------------------------------------- 1 | package restruct 2 | 3 | import ( 4 | "encoding/binary" 5 | "encoding/json" 6 | "io/ioutil" 7 | "reflect" 8 | "testing" 9 | 10 | "github.com/go-restruct/restruct/formats/png" 11 | "github.com/stretchr/testify/assert" 12 | ) 13 | 14 | func readfile(fn string) []byte { 15 | if d, err := ioutil.ReadFile(fn); err == nil { 16 | return d 17 | } else { 18 | panic(err) 19 | } 20 | } 21 | 22 | func TestPNGGrad8RGB(t *testing.T) { 23 | EnableExprBeta() 24 | 25 | tests := []struct { 26 | format interface{} 27 | expectdata []byte 28 | expectjson []byte 29 | }{ 30 | { 31 | format: png.File{}, 32 | expectdata: readfile("testdata/pnggrad8rgb.png"), 33 | expectjson: readfile("testdata/pnggrad8rgb.json"), 34 | }, 35 | } 36 | 37 | for _, test := range tests { 38 | f := reflect.New(reflect.TypeOf(test.format)).Interface() 39 | assert.Nil(t, json.Unmarshal(test.expectjson, f)) 40 | data, err := Pack(binary.BigEndian, f) 41 | assert.Nil(t, err) 42 | assert.Equal(t, test.expectdata, data) 43 | 44 | f = reflect.New(reflect.TypeOf(test.format)).Interface() 45 | assert.Nil(t, Unpack(test.expectdata, binary.BigEndian, f)) 46 | data, err = json.Marshal(f) 47 | assert.Nil(t, err) 48 | assert.JSONEq(t, string(test.expectjson), string(data)) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-restruct/restruct 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/pkg/errors v0.8.1 7 | github.com/stretchr/testify v1.4.0 8 | ) 9 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 4 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 5 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 6 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 7 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 8 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 9 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 10 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 11 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= 12 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 13 | -------------------------------------------------------------------------------- /packing.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package restruct implements packing and unpacking of raw binary formats. 3 | 4 | Structures can be created with struct tags annotating the on-disk or in-memory 5 | layout of the structure, using the "struct" struct tag, like so: 6 | 7 | struct { 8 | Length int `struct:"int32,sizeof=Packets"` 9 | Packets []struct{ 10 | Source string `struct:"[16]byte"` 11 | Timestamp int `struct:"int32,big"` 12 | Data [256]byte `struct:"skip=8"` 13 | } 14 | } 15 | 16 | To unpack data in memory to this structure, simply use Unpack with a byte slice: 17 | 18 | msg := Message{} 19 | restruct.Unpack(data, binary.LittleEndian, &msg) 20 | */ 21 | package restruct 22 | 23 | import ( 24 | "encoding/binary" 25 | "reflect" 26 | ) 27 | 28 | func fieldFromIntf(v interface{}) (field, reflect.Value) { 29 | val := reflect.ValueOf(v) 30 | if val.Kind() == reflect.Ptr { 31 | val = val.Elem() 32 | } 33 | f := fieldFromType(val.Type()) 34 | return f, val 35 | } 36 | 37 | /* 38 | Unpack reads data from a byteslice into a value. 39 | 40 | Two types of values are directly supported here: Unpackers and structs. You can 41 | pass them by value or by pointer, although it is an error if Restruct is 42 | unable to set a value because it is unaddressable. 43 | 44 | For structs, each field will be read sequentially based on a straightforward 45 | interpretation of the type. For example, an int32 will be read as a 32-bit 46 | signed integer, taking 4 bytes of memory. Structures and arrays are laid out 47 | flat with no padding or metadata. 48 | 49 | Unexported fields are ignored, except for fields named _ - those fields will 50 | be treated purely as padding. Padding will not be preserved through packing 51 | and unpacking. 52 | 53 | The behavior of deserialization can be customized using struct tags. The 54 | following struct tag syntax is supported: 55 | 56 | `struct:"[flags...]"` 57 | 58 | Flags are comma-separated keys. The following are available: 59 | 60 | type A bare type name, e.g. int32 or []string. For integer 61 | types, it is possible to specify the number of bits, 62 | allowing the definition of bitfields, by appending a 63 | colon followed by the number of bits. For example, 64 | uint32:20 would specify a field that is 20 bits long. 65 | 66 | sizeof=[Field] Specifies that the field should be treated as a count of 67 | the number of elements in Field. 68 | 69 | sizefrom=[Field] Specifies that the field should determine the number of 70 | elements in itself by reading the counter in Field. 71 | 72 | skip=[Count] Skips Count bytes before the field. You can use this to 73 | e.g. emulate C structure alignment. 74 | 75 | big,msb Specifies big endian byte order. When applied to 76 | structs, this will apply to all fields under the struct. 77 | 78 | little,lsb Specifies little endian byte order. When applied to 79 | structs, this will apply to all fields under the struct. 80 | 81 | variantbool Specifies that the boolean `true` value should be 82 | encoded as -1 instead of 1. 83 | 84 | invertedbool Specifies that the `true` and `false` encodings for 85 | boolean should be swapped. 86 | */ 87 | func Unpack(data []byte, order binary.ByteOrder, v interface{}) (err error) { 88 | defer func() { 89 | if r := recover(); r != nil { 90 | var ok bool 91 | if err, ok = r.(error); !ok { 92 | panic(err) 93 | } 94 | } 95 | }() 96 | 97 | f, val := fieldFromIntf(v) 98 | ss := structstack{allowexpr: expressionsEnabled, buf: data} 99 | d := decoder{structstack: ss, order: order} 100 | d.read(f, val) 101 | 102 | return 103 | } 104 | 105 | /* 106 | SizeOf returns the binary encoded size of the given value, in bytes. 107 | */ 108 | func SizeOf(v interface{}) (size int, err error) { 109 | defer func() { 110 | if r := recover(); r != nil { 111 | err = r.(error) 112 | } 113 | }() 114 | 115 | ss := structstack{allowexpr: expressionsEnabled} 116 | f, val := fieldFromIntf(v) 117 | return ss.fieldbytes(f, val), nil 118 | } 119 | 120 | /* 121 | BitSize returns the binary encoded size of the given value, in bits. 122 | */ 123 | func BitSize(v interface{}) (size int, err error) { 124 | defer func() { 125 | if r := recover(); r != nil { 126 | err = r.(error) 127 | } 128 | }() 129 | 130 | ss := structstack{allowexpr: expressionsEnabled} 131 | f, val := fieldFromIntf(v) 132 | return ss.fieldbits(f, val), nil 133 | } 134 | 135 | /* 136 | Pack writes data from a datastructure into a byteslice. 137 | 138 | Two types of values are directly supported here: Packers and structs. You can 139 | pass them by value or by pointer. 140 | 141 | Each structure is serialized in the same way it would be deserialized with 142 | Unpack. See Unpack documentation for the struct tag format. 143 | */ 144 | func Pack(order binary.ByteOrder, v interface{}) (data []byte, err error) { 145 | defer func() { 146 | if r := recover(); r != nil { 147 | data = nil 148 | err = r.(error) 149 | } 150 | }() 151 | 152 | ss := structstack{allowexpr: expressionsEnabled, buf: []byte{}} 153 | 154 | f, val := fieldFromIntf(v) 155 | data = make([]byte, ss.fieldbytes(f, val)) 156 | 157 | ss.buf = data 158 | e := encoder{structstack: ss, order: order} 159 | e.write(f, val) 160 | 161 | return 162 | } 163 | -------------------------------------------------------------------------------- /packing_test.go: -------------------------------------------------------------------------------- 1 | package restruct 2 | 3 | import ( 4 | "encoding/binary" 5 | "errors" 6 | "reflect" 7 | "testing" 8 | 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestUnpack(t *testing.T) { 13 | tests := []struct { 14 | data []byte 15 | bitsize int 16 | value interface{} 17 | }{ 18 | { 19 | data: []byte{ 20 | 0x12, 0x34, 0x56, 0x78, 21 | }, 22 | bitsize: 32, 23 | value: struct { 24 | Dd uint32 25 | }{ 26 | Dd: 0x12345678, 27 | }, 28 | }, 29 | { 30 | data: []byte{ 31 | 0x55, 0x55, 32 | }, 33 | bitsize: 16, 34 | value: struct { 35 | A uint8 `struct:"uint8:3"` 36 | B uint8 `struct:"uint8:2"` 37 | C uint8 `struct:"uint8"` 38 | D uint8 `struct:"uint8:3"` 39 | }{ 40 | A: 0x02, 41 | B: 0x02, 42 | C: 0xAA, 43 | D: 0x05, 44 | }, 45 | }, 46 | { 47 | data: []byte{ 48 | 0x55, 0x55, 49 | }, 50 | bitsize: 16, 51 | value: struct { 52 | A int8 `struct:"int8:3"` 53 | B int8 `struct:"int8:2,big"` 54 | C int8 `struct:"int8"` 55 | D int8 `struct:"int8:3"` 56 | }{ 57 | A: 0x02, 58 | B: 0x02, 59 | C: -0x56, 60 | D: -0x03, 61 | }, 62 | }, 63 | { 64 | data: []byte{ 65 | 0xFF, 0xFF, 66 | }, 67 | bitsize: 16, 68 | value: struct { 69 | A int8 `struct:"int8:3"` 70 | B int8 `struct:"int8:2"` 71 | C int8 `struct:"int8"` 72 | D int8 `struct:"int8:3"` 73 | }{ 74 | A: -1, 75 | B: -1, 76 | C: -1, 77 | D: -1, 78 | }, 79 | }, 80 | { 81 | data: []byte{ 82 | 0xFF, 0xFF, 0xFF, 0xFF, 83 | }, 84 | bitsize: 32, 85 | value: struct { 86 | A int32 `struct:"int32:24"` 87 | B int8 `struct:"int16:8"` 88 | }{A: -1, B: -1}, 89 | }, 90 | { 91 | data: []byte{ 92 | 0xFF, 0xFF, 0xFF, 0xFF, 93 | 0xFF, 0xFF, 0xFF, 0xFF, 94 | }, 95 | bitsize: 64, 96 | value: struct { 97 | A int64 `struct:"int64:49"` 98 | B int64 `struct:"int64:15"` 99 | }{A: -1, B: -1}, 100 | }, 101 | { 102 | data: []byte{ 103 | 0x00, 0x00, 0x00, 0x00, 104 | 0x00, 0x00, 0x80, 0x01, 105 | }, 106 | bitsize: 64, 107 | value: struct { 108 | A int64 `struct:"int64:49"` 109 | B int64 `struct:"int64:15"` 110 | }{A: 1, B: 1}, 111 | }, 112 | { 113 | data: []byte{ 114 | 0x0F, 0x0F, 0x0F, 0x0F, 115 | 0x0F, 0x0F, 0x0F, 0x0F, 116 | }, 117 | bitsize: 64, 118 | value: struct { 119 | A int64 `struct:"int64:49"` 120 | B int64 `struct:"int64:15"` 121 | }{ 122 | A: 0x00001E1E1E1E1E1E, 123 | B: 0x0000000000000F0F, 124 | }, 125 | }, 126 | { 127 | data: []byte{ 128 | 0xAA, 0xBB, 0xCC, 0xDD, 129 | 0xEE, 0xFF, 0x00, 0x11, 130 | }, 131 | bitsize: 64, 132 | value: struct { 133 | A uint64 `struct:"uint64:48,little"` 134 | B uint64 `struct:"uint16,little"` 135 | }{ 136 | A: 0x0000FFEEDDCCBBAA, 137 | B: 0x0000000000001100, 138 | }, 139 | }, 140 | { 141 | data: []byte{ 142 | 0xAA, 0xBB, 0xCC, 0xDD, 143 | 0xEE, 0xFF, 0x00, 0x11, 144 | }, 145 | bitsize: 64, 146 | value: struct { 147 | A int64 `struct:"int64:48,little"` 148 | B int64 `struct:"int16,little"` 149 | }{ 150 | A: -0x0000001122334456, 151 | B: 0x0000000000001100, 152 | }, 153 | }, 154 | { 155 | data: []byte{ 156 | 0x00, 0x00, 0x00, 0x01, 157 | 0x00, 0x00, 0x00, 0x02, 158 | 0x03, 0x00, 0x00, 0x00, 159 | }, 160 | bitsize: 96, 161 | value: struct { 162 | DefaultOrder uint32 163 | BigEndian uint32 `struct:"big"` 164 | LittleEndian uint32 `struct:"little"` 165 | }{ 166 | DefaultOrder: 1, 167 | BigEndian: 2, 168 | LittleEndian: 3, 169 | }, 170 | }, 171 | { 172 | data: []byte{ 173 | 0x00, 0x00, 0x00, 0x01, 174 | 0x00, 0x00, 0x00, 0x02, 175 | 0x03, 0x00, 0x00, 0x00, 176 | }, 177 | bitsize: 96, 178 | value: struct { 179 | DefaultOrder uint32 180 | BigSub struct { 181 | BigEndian uint32 182 | } `struct:"big"` 183 | LittleSub struct { 184 | LittleEndian uint32 185 | } `struct:"little"` 186 | }{ 187 | DefaultOrder: 1, 188 | BigSub: struct{ BigEndian uint32 }{2}, 189 | LittleSub: struct{ LittleEndian uint32 }{3}, 190 | }, 191 | }, 192 | { 193 | data: []byte{ 194 | 0x00, 0x00, 0x00, 0x02, 195 | 0x00, 0x00, 0x00, 0x01, 196 | 0x00, 0x00, 0x00, 0x02, 197 | 0x00, 0x00, 0x00, 0x03, 198 | 0x00, 0x00, 0x00, 0x04, 199 | }, 200 | bitsize: 160, 201 | value: struct { 202 | NumStructs int32 `struct:"sizeof=Structs"` 203 | Structs []struct{ V1, V2 uint32 } 204 | }{ 205 | NumStructs: 2, 206 | Structs: []struct{ V1, V2 uint32 }{ 207 | {V1: 1, V2: 2}, 208 | {V1: 3, V2: 4}, 209 | }, 210 | }, 211 | }, 212 | { 213 | data: []byte{ 214 | 0x3e, 0x00, 0x00, 0x00, 215 | 0x3f, 0x80, 0x00, 0x00, 216 | }, 217 | bitsize: 64, 218 | value: struct { 219 | C64 complex64 220 | }{ 221 | C64: complex(0.125, 1.0), 222 | }, 223 | }, 224 | { 225 | data: []byte{ 226 | 0x00, 0x00, 0x00, 0x00, 227 | 0x00, 0x00, 0x00, 0x02, 228 | 229 | 0x3f, 0x8c, 0xcc, 0xcd, 230 | 0x3f, 0x99, 0x99, 0x9a, 231 | 0x3f, 0xa6, 0x66, 0x66, 232 | 0x3f, 0xb3, 0x33, 0x33, 233 | 234 | 0x3f, 0xc0, 0x00, 0x00, 235 | 0x00, 0x00, 0x00, 0x00, 236 | 237 | 0x3e, 0x00, 0x00, 0x00, 238 | 0x3f, 0x80, 0x00, 0x00, 239 | 240 | 0x3f, 0xc0, 0x00, 0x00, 241 | 0x00, 0x00, 0x00, 0x00, 242 | 0x3f, 0xf0, 0x00, 0x00, 243 | 0x00, 0x00, 0x00, 0x00, 244 | 245 | 0x3e, 0x00, 0x00, 0x00, 246 | 0x3f, 0x80, 0x00, 0x00, 247 | 248 | 0xfc, 0xfd, 0xfe, 0xff, 249 | 0x00, 0x01, 0x02, 0x03, 250 | 251 | 0xff, 0xfe, 0xfd, 0xfc, 252 | 0xfb, 0xfa, 0xf9, 0xf8, 253 | 254 | 0xff, 0xfe, 255 | 256 | 0xff, 0xff, 0xff, 0xff, 257 | 0xff, 0xff, 0xff, 0x00, 258 | 259 | 0x00, 0x00, 0x00, 0x00, 260 | 0x00, 0x00, 0x00, 0x00, 261 | 262 | 0xe3, 0x82, 0x84, 0xe3, 263 | 0x81, 0xa3, 0xe3, 0x81, 264 | 0x9f, 0xef, 0xbc, 0x81, 265 | }, 266 | bitsize: 880, 267 | value: struct { 268 | NumStructs uint32 `struct:"uint64,sizeof=Structs"` 269 | Structs []struct{ V1, V2 float32 } 270 | Float64 float64 271 | Complex64 complex64 272 | Complex128 complex128 273 | Complex complex128 `struct:"complex64"` 274 | SomeInt8s [8]int8 275 | SomeUint8s [8]uint8 276 | AUint16 uint16 277 | AnInt64 int64 278 | _ [8]byte 279 | Message string `struct:"[12]byte"` 280 | }{ 281 | NumStructs: 2, 282 | Structs: []struct{ V1, V2 float32 }{ 283 | {V1: 1.1, V2: 1.2}, 284 | {V1: 1.3, V2: 1.4}, 285 | }, 286 | Float64: 0.125, 287 | Complex64: complex(0.125, 1.0), 288 | Complex128: complex(0.125, 1.0), 289 | Complex: complex(0.125, 1.0), 290 | SomeInt8s: [8]int8{-4, -3, -2, -1, 0, 1, 2, 3}, 291 | SomeUint8s: [8]uint8{0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8}, 292 | AUint16: 0xfffe, 293 | AnInt64: -256, 294 | Message: "やった!", 295 | }, 296 | }, 297 | { 298 | data: []byte{ 299 | 0x00, 0x00, 0x00, 0x04, 300 | 0xf0, 0x9f, 0x91, 0x8c, 301 | }, 302 | bitsize: 64, 303 | value: struct { 304 | StrLen uint32 `struct:"uint32,sizeof=String"` 305 | String string 306 | }{ 307 | StrLen: 4, 308 | String: "👌", 309 | }, 310 | }, 311 | { 312 | data: []byte{ 313 | 0x00, 0x00, 0x00, 0x04, 314 | 0x00, 0x00, 0x00, 0x00, 315 | 0xf0, 0x9f, 0x91, 0x8c, 316 | }, 317 | bitsize: 96, 318 | value: struct { 319 | StrLen uint32 `struct:"uint32,sizeof=String"` 320 | String string `struct:"skip=4"` 321 | }{ 322 | StrLen: 4, 323 | String: "👌", 324 | }, 325 | }, 326 | { 327 | data: []byte{ 328 | 0xf0, 0x9f, 0x91, 0x8c, 329 | }, 330 | bitsize: 32, 331 | value: struct { 332 | String string `struct:"[4]byte"` 333 | }{ 334 | String: "👌", 335 | }, 336 | }, 337 | { 338 | data: []byte{ 339 | 0xf0, 0x9f, 0x91, 0x8c, 0x00, 0x00, 0x00, 0x01, 340 | }, 341 | bitsize: 64, 342 | value: struct { 343 | String string `struct:"[7]byte"` 344 | Value byte 345 | }{ 346 | String: "👌", 347 | Value: 1, 348 | }, 349 | }, 350 | { 351 | data: []byte{ 352 | 0x00, 0x02, 0x00, 353 | 0x00, 0x00, 354 | 0x00, 0x22, 0x18, 355 | 0x00, 0x28, 0x12, 356 | }, 357 | bitsize: 88, 358 | value: struct { 359 | Length int32 `struct:"int16,sizeof=Slice,little,skip=1"` 360 | Slice []struct { 361 | Test int16 `struct:"skip=1"` 362 | } `struct:"skip=2,lsb"` 363 | }{ 364 | Length: 2, 365 | Slice: []struct { 366 | Test int16 `struct:"skip=1"` 367 | }{ 368 | {Test: 0x1822}, 369 | {Test: 0x1228}, 370 | }, 371 | }, 372 | }, 373 | { 374 | data: []byte{ 375 | 0x00, 0x01, 376 | 0x00, 0x02, 377 | 0x00, 0x03, 378 | }, 379 | bitsize: 48, 380 | value: struct { 381 | Ints []uint16 `struct:"[3]uint16"` 382 | }{ 383 | Ints: []uint16{1, 2, 3}, 384 | }, 385 | }, 386 | { 387 | data: []byte{ 388 | 0x00, 0x00, 0x00, 0x01, 389 | 0x00, 0x00, 0x00, 0x03, 390 | }, 391 | bitsize: 64, 392 | value: struct { 393 | Size int `struct:"int32,sizeof=Array"` 394 | Array []int32 395 | }{ 396 | Size: 1, 397 | Array: []int32{3}, 398 | }, 399 | }, 400 | { 401 | data: []byte{ 402 | 0x00, 0x00, 0x00, 0x03, 403 | }, 404 | bitsize: 32, 405 | value: struct { 406 | Array [1]int `struct:"[1]int32"` 407 | }{ 408 | Array: [1]int{3}, 409 | }, 410 | }, 411 | { 412 | data: []byte{ 413 | 0x00, 0x00, 0x00, 0x01, 414 | 0x00, 0x00, 0x00, 0x03, 415 | }, 416 | bitsize: 64, 417 | value: struct { 418 | Size int `struct:"int32,sizeof=Array"` 419 | Array []int `struct:"[]int32"` 420 | }{ 421 | Size: 1, 422 | Array: []int{3}, 423 | }, 424 | }, 425 | { 426 | data: []byte{ 427 | 0x00, 0x00, 0x00, 0x03, 428 | }, 429 | bitsize: 32, 430 | value: struct { 431 | Array []int `struct:"[1]int32"` 432 | }{ 433 | Array: []int{3}, 434 | }, 435 | }, 436 | { 437 | data: []byte{ 438 | 0x00, 0x00, 0x00, 0x01, 439 | 0x00, 0x00, 0x00, 0x03, 440 | }, 441 | bitsize: 64, 442 | value: struct { 443 | _ struct{} 444 | Size int `struct:"int32"` 445 | _ struct{} 446 | Array []int32 `struct:"sizefrom=Size"` 447 | _ struct{} 448 | }{ 449 | Size: 1, 450 | Array: []int32{3}, 451 | }, 452 | }, 453 | { 454 | data: []byte{ 455 | 0x00, 0x00, 0x00, 0x01, 456 | 0x00, 0x00, 0x00, 0x03, 457 | 0x00, 0x00, 0x00, 0x04, 458 | }, 459 | bitsize: 96, 460 | value: struct { 461 | _ struct{} 462 | Size int `struct:"int32"` 463 | _ struct{} 464 | Array1 []int32 `struct:"sizefrom=Size"` 465 | Array2 []int32 `struct:"sizefrom=Size"` 466 | _ struct{} 467 | }{ 468 | Size: 1, 469 | Array1: []int32{3}, 470 | Array2: []int32{4}, 471 | }, 472 | }, 473 | { 474 | data: []byte{ 475 | 0xff, 0xff, 0xff, 0xff, 476 | 0xff, 0xff, 0xff, 0xff, 477 | }, 478 | bitsize: 64, 479 | value: struct { 480 | A uint64 `struct:"uint64:12"` 481 | B uint64 `struct:"uint64:12"` 482 | C uint64 `struct:"uint64:30"` 483 | D uint64 `struct:"uint64:1"` 484 | E uint64 `struct:"uint64:5"` 485 | F uint64 `struct:"uint64:1"` 486 | G uint64 `struct:"uint64:3"` 487 | }{ 488 | A: 0xfff, 489 | B: 0xfff, 490 | C: 0x3fffffff, 491 | D: 0x1, 492 | E: 0x1f, 493 | F: 0x1, 494 | G: 0x7, 495 | }, 496 | }, 497 | { 498 | data: []byte{ 499 | // nonvariant/variant 8-bit 500 | // false, false, true, true 501 | 0x00, 0x00, 0x01, 0xFF, 502 | 503 | // nonvariant/variant 8-bit inverted 504 | // false, false, true, true 505 | 0x01, 0xFF, 0x00, 0x00, 506 | 507 | // nonvariant/variant 32-bit 508 | // false, false, true, true 509 | 0x00, 0x00, 0x00, 0x00, 510 | 0x00, 0x00, 0x00, 0x00, 511 | 0x00, 0x00, 0x00, 0x01, 512 | 0xFF, 0xFF, 0xFF, 0xFF, 513 | 514 | // nonvariant/variant 32-bit inverted 515 | // false, false, true, true 516 | 0x00, 0x00, 0x00, 0x01, 517 | 0xFF, 0xFF, 0xFF, 0xFF, 518 | 0x00, 0x00, 0x00, 0x00, 519 | 0x00, 0x00, 0x00, 0x00, 520 | }, 521 | bitsize: 320, 522 | value: struct { 523 | NonVariant8BitFalse bool `struct:"bool"` 524 | Variant8BitFalse bool `struct:"bool,variantbool"` 525 | NonVariant8BitTrue bool `struct:"bool"` 526 | Variant8BitTrue bool `struct:"bool,variantbool"` 527 | NonVariant8BitFalseInverted bool `struct:"bool,invertedbool"` 528 | Variant8BitFalseInverted bool `struct:"bool,invertedbool,variantbool"` 529 | NonVariant8BitTrueInverted bool `struct:"bool,invertedbool"` 530 | Variant8BitTrueInverted bool `struct:"bool,invertedbool,variantbool"` 531 | NonVariant32BitFalse bool `struct:"int32"` 532 | Variant32BitFalse bool `struct:"uint32,variantbool"` 533 | NonVariant32BitTrue bool `struct:"uint32"` 534 | Variant32BitTrue bool `struct:"int32,variantbool"` 535 | NonVariant32BitFalseInverted bool `struct:"uint32,invertedbool"` 536 | Variant32BitFalseInverted bool `struct:"int32,invertedbool,variantbool"` 537 | NonVariant32BitTrueInverted bool `struct:"int32,invertedbool"` 538 | Variant32BitTrueInverted bool `struct:"uint32,invertedbool,variantbool"` 539 | }{ 540 | NonVariant8BitFalse: false, 541 | Variant8BitFalse: false, 542 | NonVariant8BitTrue: true, 543 | Variant8BitTrue: true, 544 | NonVariant8BitFalseInverted: false, 545 | Variant8BitFalseInverted: false, 546 | NonVariant8BitTrueInverted: true, 547 | Variant8BitTrueInverted: true, 548 | NonVariant32BitFalse: false, 549 | Variant32BitFalse: false, 550 | NonVariant32BitTrue: true, 551 | Variant32BitTrue: true, 552 | NonVariant32BitFalseInverted: false, 553 | Variant32BitFalseInverted: false, 554 | NonVariant32BitTrueInverted: true, 555 | Variant32BitTrueInverted: true, 556 | }, 557 | }, 558 | { 559 | data: []byte{0x80}, 560 | bitsize: 1, 561 | value: struct { 562 | Bit bool `struct:"uint8:1"` 563 | }{ 564 | Bit: true, 565 | }, 566 | }, 567 | { 568 | data: []byte{0x08, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F}, 569 | bitsize: 80, 570 | value: struct { 571 | Count uint8 `struct:"uint8,sizeof=List"` 572 | List []struct { 573 | A bool `struct:"uint8:1,variantbool"` 574 | B uint8 `struct:"uint8:4"` 575 | C uint8 `struct:"uint8:4"` 576 | } 577 | }{ 578 | Count: 8, 579 | List: []struct { 580 | A bool `struct:"uint8:1,variantbool"` 581 | B uint8 `struct:"uint8:4"` 582 | C uint8 `struct:"uint8:4"` 583 | }{ 584 | {A: false, B: 1, C: 14}, 585 | {A: false, B: 3, C: 12}, 586 | {A: false, B: 7, C: 8}, 587 | {A: false, B: 15, C: 0}, 588 | {A: true, B: 14, C: 1}, 589 | {A: true, B: 12, C: 3}, 590 | {A: true, B: 8, C: 7}, 591 | {A: true, B: 0, C: 15}, 592 | }, 593 | }, 594 | }, 595 | } 596 | 597 | for _, test := range tests { 598 | v := reflect.New(reflect.TypeOf(test.value)) 599 | 600 | // Test unpacking 601 | err := Unpack(test.data, binary.BigEndian, v.Interface()) 602 | assert.Nil(t, err) 603 | assert.Equal(t, test.value, v.Elem().Interface()) 604 | 605 | // Test packing 606 | data, err := Pack(binary.BigEndian, v.Interface()) 607 | assert.Nil(t, err) 608 | assert.Equal(t, test.data, data) 609 | 610 | // Test sizing 611 | size, err := SizeOf(v.Interface()) 612 | assert.Nil(t, err) 613 | assert.Equal(t, len(test.data), size) 614 | 615 | // Test bit sizing 616 | bits, err := BitSize(v.Interface()) 617 | assert.Nil(t, err) 618 | assert.Equal(t, test.bitsize, bits) 619 | } 620 | } 621 | 622 | func TestUnpackBrokenSizeOf(t *testing.T) { 623 | data := []byte{ 624 | 0x00, 0x02, 0x00, 625 | 0x00, 0x00, 626 | 0x00, 0x22, 0x18, 627 | 0x00, 0x28, 0x12, 628 | } 629 | 630 | s := struct { 631 | Length string `struct:"sizeof=Slice,skip=1"` 632 | Slice []struct { 633 | Test int16 `struct:"skip=1"` 634 | } `struct:"skip=2,lsb"` 635 | }{ 636 | Length: "no", 637 | Slice: []struct { 638 | Test int16 `struct:"skip=1"` 639 | }{ 640 | {Test: 0x1822}, 641 | {Test: 0x1228}, 642 | }, 643 | } 644 | 645 | // Test unpacking 646 | err := Unpack(data, binary.BigEndian, &s) 647 | assert.NotNil(t, err) 648 | assert.Equal(t, "unsupported size type string: Length", err.Error()) 649 | 650 | // Test packing 651 | _, err = Pack(binary.BigEndian, &s) 652 | assert.NotNil(t, err) 653 | assert.Equal(t, "unsupported size type string: Length", err.Error()) 654 | 655 | // Test unpacking sizeof to array fails. 656 | s2 := struct { 657 | Length int32 `struct:"sizeof=Array,skip=1"` 658 | Array [2]int16 `struct:"skip=2,lsb"` 659 | }{ 660 | Length: 2, 661 | Array: [2]int16{ 662 | 0x1822, 663 | 0x1228, 664 | }, 665 | } 666 | 667 | err = Unpack(data, binary.BigEndian, &s2) 668 | assert.NotNil(t, err) 669 | assert.Equal(t, "sizeof specified on fixed size type", err.Error()) 670 | } 671 | 672 | func TestUnpackBrokenArray(t *testing.T) { 673 | data := []byte{ 674 | 0x02, 0x00, 675 | } 676 | 677 | s := struct { 678 | Length int16 `struct:"[2]uint8"` 679 | }{ 680 | Length: 2, 681 | } 682 | 683 | // Test unpacking 684 | err := Unpack(data, binary.BigEndian, &s) 685 | assert.NotNil(t, err) 686 | assert.Equal(t, "invalid array cast type: int16", err.Error()) 687 | 688 | // Test packing 689 | _, err = Pack(binary.BigEndian, &s) 690 | assert.NotNil(t, err) 691 | assert.Equal(t, "invalid array cast type: int16", err.Error()) 692 | 693 | s2 := struct { 694 | Length int16 `struct:"[]uint8"` 695 | }{ 696 | Length: 2, 697 | } 698 | 699 | // Test unpacking 700 | err = Unpack(data, binary.BigEndian, &s2) 701 | assert.NotNil(t, err) 702 | assert.Equal(t, "invalid array cast type: int16", err.Error()) 703 | 704 | // Test packing 705 | _, err = Pack(binary.BigEndian, &s2) 706 | assert.NotNil(t, err) 707 | assert.Equal(t, "invalid array cast type: int16", err.Error()) 708 | } 709 | 710 | func TestUnpackFastPath(t *testing.T) { 711 | v := struct { 712 | Size uint8 `struct:"sizeof=Data"` 713 | Data []byte 714 | }{} 715 | assert.Nil(t, Unpack([]byte("\x04Data"), binary.LittleEndian, &v)) 716 | assert.Equal(t, 4, int(v.Size)) 717 | assert.Equal(t, "Data", string(v.Data)) 718 | } 719 | 720 | func BenchmarkFastPath(b *testing.B) { 721 | v := struct { 722 | Size uint8 `struct:"sizeof=Data"` 723 | Data []byte 724 | }{} 725 | data := []byte(" @?>=<;:9876543210/.-,+*)('&%$#\"! ") 726 | for i := 0; i < b.N; i++ { 727 | _ = Unpack(data, binary.LittleEndian, &v) 728 | } 729 | } 730 | 731 | // Test custom packing 732 | type CString string 733 | 734 | func (s *CString) SizeOf() int { 735 | return len(*s) + 1 736 | } 737 | 738 | func (s *CString) Unpack(buf []byte, order binary.ByteOrder) ([]byte, error) { 739 | for i, l := 0, len(buf); i < l; i++ { 740 | if buf[i] == 0 { 741 | *s = CString(buf[:i]) 742 | return buf[i+1:], nil 743 | } 744 | } 745 | return []byte{}, errors.New("unterminated string") 746 | } 747 | 748 | func (s *CString) Pack(buf []byte, order binary.ByteOrder) ([]byte, error) { 749 | l := len(*s) 750 | for i := 0; i < l; i++ { 751 | buf[i] = (*s)[i] 752 | } 753 | buf[l] = 0 754 | return buf[l+1:], nil 755 | } 756 | 757 | func TestCustomPacking(t *testing.T) { 758 | x := CString("Test string! テスト。") 759 | b, err := Pack(binary.LittleEndian, &x) 760 | assert.Nil(t, err) 761 | assert.Equal(t, []byte{ 762 | 0x54, 0x65, 0x73, 0x74, 0x20, 0x73, 0x74, 0x72, 763 | 0x69, 0x6e, 0x67, 0x21, 0x20, 0xe3, 0x83, 0x86, 764 | 0xe3, 0x82, 0xb9, 0xe3, 0x83, 0x88, 0xe3, 0x80, 765 | 0x82, 0x0, 766 | }, b) 767 | 768 | y := CString("") 769 | err = Unpack(b, binary.LittleEndian, &y) 770 | assert.Nil(t, err) 771 | assert.Equal(t, "Test string! テスト。", string(y)) 772 | } 773 | 774 | // Test custom packing with non-pointer receiver 775 | type Custom struct { 776 | A *int 777 | } 778 | 779 | func (s Custom) SizeOf() int { 780 | return 4 781 | } 782 | 783 | func (s Custom) Unpack(buf []byte, order binary.ByteOrder) ([]byte, error) { 784 | *s.A = int(order.Uint32(buf[0:4])) 785 | return buf[4:], nil 786 | } 787 | 788 | func (s Custom) Pack(buf []byte, order binary.ByteOrder) ([]byte, error) { 789 | order.PutUint32(buf[0:4], uint32(*s.A)) 790 | return buf[4:], nil 791 | } 792 | 793 | func TestCustomPackingNonPointer(t *testing.T) { 794 | c := Custom{new(int)} 795 | *c.A = 32 796 | 797 | b, err := Pack(binary.LittleEndian, c) 798 | assert.Nil(t, err) 799 | assert.Equal(t, []byte{0x20, 0x00, 0x00, 0x00}, b) 800 | 801 | d := Custom{new(int)} 802 | err = Unpack(b, binary.LittleEndian, d) 803 | assert.Nil(t, err) 804 | assert.Equal(t, 32, *d.A) 805 | } 806 | 807 | func TestSizeExpr(t *testing.T) { 808 | EnableExprBeta() 809 | 810 | type sizeStruct struct { 811 | Len byte 812 | Data []byte `struct:"size=Len*2"` 813 | } 814 | 815 | expectStruct := sizeStruct{ 816 | 2, []byte{0, 1, 2, 3}, 817 | } 818 | expectData := []byte{2, 0, 1, 2, 3} 819 | 820 | var actualStruct sizeStruct 821 | err := Unpack(expectData, binary.LittleEndian, &actualStruct) 822 | assert.Nil(t, err) 823 | assert.Equal(t, expectStruct, actualStruct) 824 | 825 | actualData, err := Pack(binary.LittleEndian, &expectStruct) 826 | assert.Nil(t, err) 827 | assert.Equal(t, expectData, actualData) 828 | } 829 | 830 | func TestBitsExpr(t *testing.T) { 831 | EnableExprBeta() 832 | 833 | type dynamicBits struct { 834 | BitLen byte 835 | Int uint64 `struct:"bits=BitLen"` 836 | } 837 | 838 | expectStruct := dynamicBits{5, 0x1f} 839 | expectData := []byte{5, 0xf8} 840 | 841 | var actualStruct dynamicBits 842 | err := Unpack(expectData, binary.BigEndian, &actualStruct) 843 | assert.Nil(t, err) 844 | assert.Equal(t, expectStruct, actualStruct) 845 | 846 | actualData, err := Pack(binary.BigEndian, &expectStruct) 847 | assert.Nil(t, err) 848 | assert.Equal(t, expectData, actualData) 849 | } 850 | 851 | func TestIfExpr(t *testing.T) { 852 | EnableExprBeta() 853 | 854 | type ifExpr struct { 855 | HasByte bool 856 | Byte byte `struct:"if=HasByte"` 857 | } 858 | 859 | { 860 | expectStruct := ifExpr{false, 0} 861 | expectData := []byte{0} 862 | 863 | var actualStruct ifExpr 864 | err := Unpack(expectData, binary.BigEndian, &actualStruct) 865 | assert.Nil(t, err) 866 | assert.Equal(t, expectStruct, actualStruct) 867 | 868 | actualData, err := Pack(binary.BigEndian, &expectStruct) 869 | assert.Nil(t, err) 870 | assert.Equal(t, expectData, actualData) 871 | } 872 | 873 | { 874 | expectStruct := ifExpr{true, 255} 875 | expectData := []byte{1, 255} 876 | 877 | var actualStruct ifExpr 878 | err := Unpack(expectData, binary.BigEndian, &actualStruct) 879 | assert.Nil(t, err) 880 | assert.Equal(t, expectStruct, actualStruct) 881 | 882 | actualData, err := Pack(binary.BigEndian, &expectStruct) 883 | assert.Nil(t, err) 884 | assert.Equal(t, expectData, actualData) 885 | } 886 | } 887 | 888 | func TestInOutExpr(t *testing.T) { 889 | EnableExprBeta() 890 | 891 | type inoutStruct struct { 892 | Value byte `struct:"in=Value/2,out=Value*2"` 893 | } 894 | 895 | expectStruct := inoutStruct{20} 896 | expectData := []byte{40} 897 | 898 | var actualStruct inoutStruct 899 | err := Unpack(expectData, binary.LittleEndian, &actualStruct) 900 | assert.Nil(t, err) 901 | assert.Equal(t, expectStruct, actualStruct) 902 | 903 | actualData, err := Pack(binary.LittleEndian, &expectStruct) 904 | assert.Nil(t, err) 905 | assert.Equal(t, expectData, actualData) 906 | } 907 | -------------------------------------------------------------------------------- /structstack.go: -------------------------------------------------------------------------------- 1 | package restruct 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | 7 | "github.com/go-restruct/restruct/expr" 8 | ) 9 | 10 | type switchcase struct { 11 | f field 12 | v reflect.Value 13 | } 14 | 15 | type structstack struct { 16 | buf []byte 17 | stack []reflect.Value 18 | allowexpr bool 19 | } 20 | 21 | func (s *structstack) Resolve(ident string) expr.Value { 22 | switch ident { 23 | case "_eof": 24 | return expr.ValueOf(len(s.buf) == 0) 25 | default: 26 | if t := stdLibResolver.Resolve(ident); t != nil { 27 | return t 28 | } 29 | if len(s.stack) > 0 { 30 | if sv := s.stack[len(s.stack)-1].FieldByName(ident); sv.IsValid() { 31 | return expr.ValueOf(sv.Interface()) 32 | } 33 | } 34 | return nil 35 | } 36 | } 37 | 38 | func (s *structstack) evalBits(f field) int { 39 | bits := 0 40 | if f.BitSize != 0 { 41 | bits = int(f.BitSize) 42 | } 43 | if f.BitsExpr != nil { 44 | bits = reflect.ValueOf(s.evalExpr(f.BitsExpr)).Convert(reflect.TypeOf(int(0))).Interface().(int) 45 | } 46 | return bits 47 | } 48 | 49 | func (s *structstack) evalSize(f field) int { 50 | size := 0 51 | if f.SizeExpr != nil { 52 | size = reflect.ValueOf(s.evalExpr(f.SizeExpr)).Convert(reflect.TypeOf(int(0))).Interface().(int) 53 | } 54 | return size 55 | } 56 | 57 | func (s *structstack) evalIf(f field) bool { 58 | if f.IfExpr == nil { 59 | return true 60 | } 61 | if b, ok := s.evalExpr(f.IfExpr).(bool); ok { 62 | return b 63 | } 64 | panic("expected bool value for if expr") 65 | } 66 | 67 | func (s *structstack) evalWhile(f field) bool { 68 | if b, ok := s.evalExpr(f.WhileExpr).(bool); ok { 69 | return b 70 | } 71 | panic("expected bool value for while expr") 72 | } 73 | 74 | func (s *structstack) switcbits(f field, v reflect.Value, on interface{}) (size int) { 75 | var def *switchcase 76 | 77 | if v.Kind() != reflect.Struct { 78 | panic(fmt.Errorf("%s: only switches on structs are valid", f.Name)) 79 | } 80 | 81 | sfields := cachedFieldsFromStruct(f.BinaryType) 82 | l := len(sfields) 83 | 84 | for i := 0; i < l; i++ { 85 | f := sfields[i] 86 | v := v.Field(f.Index) 87 | 88 | if f.Flags&DefaultFlag != 0 { 89 | if def != nil { 90 | panic(fmt.Errorf("%s: only one default case is allowed", f.Name)) 91 | } 92 | def = &switchcase{f, v} 93 | continue 94 | } 95 | 96 | if f.CaseExpr == nil { 97 | panic(fmt.Errorf("%s: only cases are valid inside switches", f.Name)) 98 | } 99 | 100 | if s.evalExpr(f.CaseExpr) == on { 101 | return s.fieldbits(f, v) 102 | } 103 | } 104 | 105 | if def != nil { 106 | return s.fieldbits(def.f, def.v) 107 | } 108 | 109 | return 0 110 | } 111 | 112 | // fieldbits determines the encoded size of a field in bits. 113 | func (s *structstack) fieldbits(f field, val reflect.Value) (size int) { 114 | skipBits := f.Skip * 8 115 | 116 | if f.Flags&RootFlag == RootFlag { 117 | s.setancestor(f, val, s.root()) 118 | return 0 119 | } 120 | 121 | if f.Flags&ParentFlag == ParentFlag { 122 | for i := 1; i < len(s.stack); i++ { 123 | if s.setancestor(f, val, s.ancestor(i)) { 124 | break 125 | } 126 | } 127 | return 0 128 | } 129 | 130 | if f.SwitchExpr != nil { 131 | return s.switcbits(f, val, s.evalExpr(f.SwitchExpr)) 132 | } 133 | 134 | if f.Name != "_" { 135 | if s, ok := f.bitSizeUsingInterface(val); ok { 136 | return s 137 | } 138 | } else { 139 | // Non-trivial, unnamed fields do not make sense. You can't set a field 140 | // with no name, so the elements can't possibly differ. 141 | // N.B.: Though skip will still work, use struct{} instead for skip. 142 | if !isTypeTrivial(val.Type()) { 143 | return skipBits 144 | } 145 | } 146 | 147 | if !s.evalIf(f) { 148 | return 0 149 | } 150 | 151 | if b := s.evalBits(f); b != 0 { 152 | return b 153 | } 154 | 155 | alen := 1 156 | switch f.BinaryType.Kind() { 157 | case reflect.Int8, reflect.Uint8, reflect.Bool: 158 | return 8 + skipBits 159 | case reflect.Int16, reflect.Uint16: 160 | return 16 + skipBits 161 | case reflect.Int, reflect.Int32, 162 | reflect.Uint, reflect.Uint32, 163 | reflect.Float32: 164 | return 32 + skipBits 165 | case reflect.Int64, reflect.Uint64, 166 | reflect.Float64, reflect.Complex64: 167 | return 64 + skipBits 168 | case reflect.Complex128: 169 | return 128 + skipBits 170 | case reflect.Slice, reflect.String: 171 | switch f.NativeType.Kind() { 172 | case reflect.Slice, reflect.String, reflect.Array, reflect.Ptr: 173 | alen = val.Len() 174 | default: 175 | return 0 176 | } 177 | fallthrough 178 | case reflect.Array, reflect.Ptr: 179 | size += skipBits 180 | 181 | // If array type, get length from type. 182 | if f.BinaryType.Kind() == reflect.Array { 183 | alen = f.BinaryType.Len() 184 | } 185 | 186 | // Optimization: if the array/slice is empty, bail now. 187 | if alen == 0 { 188 | return size 189 | } 190 | 191 | switch f.NativeType.Kind() { 192 | case reflect.Ptr: 193 | return s.fieldbits(f.Elem(), val.Elem()) 194 | case reflect.Slice, reflect.String, reflect.Array: 195 | // Optimization: if the element type is trivial, we can derive the 196 | // length from a single element. 197 | elem := f.Elem() 198 | if elem.Trivial { 199 | size += s.fieldbits(elem, reflect.Zero(elem.BinaryType)) * alen 200 | } else { 201 | for i := 0; i < alen; i++ { 202 | size += s.fieldbits(elem, val.Index(i)) 203 | } 204 | } 205 | } 206 | return size 207 | case reflect.Struct: 208 | size += skipBits 209 | s.push(val) 210 | for _, field := range cachedFieldsFromStruct(f.BinaryType) { 211 | if field.BitSize != 0 { 212 | size += int(field.BitSize) 213 | } else { 214 | size += s.fieldbits(field, val.Field(field.Index)) 215 | } 216 | } 217 | s.pop(val) 218 | return size 219 | default: 220 | return 0 221 | } 222 | } 223 | 224 | // fieldbytes returns the effective size in bytes, for the few cases where 225 | // byte sizes are needed. 226 | func (s *structstack) fieldbytes(f field, val reflect.Value) (size int) { 227 | return (s.fieldbits(f, val) + 7) / 8 228 | } 229 | 230 | func (s *structstack) fieldsbits(fields fields, val reflect.Value) (size int) { 231 | for _, field := range fields { 232 | size += s.fieldbits(field, val.Field(field.Index)) 233 | } 234 | return 235 | } 236 | 237 | func (s *structstack) evalExpr(program *expr.Program) interface{} { 238 | if !s.allowexpr { 239 | panic("call restruct.EnableExprBeta() to eanble expressions beta") 240 | } 241 | v, err := expr.EvalProgram(s, program) 242 | if err != nil { 243 | panic(err) 244 | } 245 | return v 246 | } 247 | 248 | func (s *structstack) push(v reflect.Value) { 249 | s.stack = append(s.stack, v) 250 | } 251 | 252 | func (s *structstack) pop(v reflect.Value) { 253 | var p reflect.Value 254 | s.stack, p = s.stack[:len(s.stack)-1], s.stack[len(s.stack)-1] 255 | if p != v { 256 | panic("struct stack misaligned") 257 | } 258 | } 259 | 260 | func (s *structstack) setancestor(f field, v reflect.Value, ancestor reflect.Value) bool { 261 | if ancestor.Kind() != reflect.Ptr { 262 | if !ancestor.CanAddr() { 263 | return false 264 | } 265 | ancestor = ancestor.Addr() 266 | } 267 | if ancestor.Type().AssignableTo(v.Type()) { 268 | v.Set(ancestor) 269 | return true 270 | } 271 | return false 272 | } 273 | 274 | func (s *structstack) root() reflect.Value { 275 | if len(s.stack) > 0 { 276 | return s.stack[0] 277 | } 278 | return reflect.ValueOf(nil) 279 | } 280 | 281 | func (s *structstack) ancestor(generation int) reflect.Value { 282 | if len(s.stack) > generation { 283 | return s.stack[len(s.stack)-generation-1] 284 | } 285 | return reflect.ValueOf(nil) 286 | } 287 | -------------------------------------------------------------------------------- /structstack_test.go: -------------------------------------------------------------------------------- 1 | package restruct 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | type TestElem struct { 11 | Test1 int64 12 | Test2 int8 13 | } 14 | 15 | type TestStruct struct { 16 | Sub [10]struct { 17 | Sub2 struct { 18 | Size int `struct:"uint32,sizeof=Elems"` 19 | Elems []TestElem 20 | } `struct:"skip=4"` 21 | } `struct:"skip=2"` 22 | Numbers [128]int64 23 | Numbers2 []float64 `struct:"[256]float32"` 24 | } 25 | 26 | func TestSizeOf(t *testing.T) { 27 | tests := []struct { 28 | input interface{} 29 | size int 30 | }{ 31 | {int8(0), 8}, 32 | {int16(0), 16}, 33 | {int32(0), 32}, 34 | {int64(0), 64}, 35 | {uint8(0), 8}, 36 | {uint16(0), 16}, 37 | {uint32(0), 32}, 38 | {uint64(0), 64}, 39 | {float32(0), 32}, 40 | {float64(0), 64}, 41 | {complex64(0), 64}, 42 | {complex128(0), 128}, 43 | {[0]int8{}, 0}, 44 | {[1]int8{1}, 8}, 45 | {[]int8{1, 2}, 16}, 46 | {[]int32{1, 2}, 64}, 47 | {[2][3]int8{}, 48}, 48 | {struct{}{}, 0}, 49 | {struct{ A int8 }{}, 8}, 50 | {struct{ A []int8 }{[]int8{}}, 0}, 51 | {struct{ A [0]int8 }{[0]int8{}}, 0}, 52 | {struct{ A []int8 }{[]int8{1}}, 8}, 53 | {struct{ A [1]int8 }{[1]int8{1}}, 8}, 54 | {TestStruct{}, 17040}, 55 | {interface{}(struct{}{}), 0}, 56 | {struct{ Test interface{} }{}, 0}, 57 | 58 | // Unexported fields test 59 | {struct{ a int8 }{}, 0}, 60 | {struct{ a []int8 }{[]int8{}}, 0}, 61 | {struct{ a [0]int8 }{[0]int8{}}, 0}, 62 | {struct{ a []int8 }{[]int8{1}}, 0}, 63 | {struct{ a [1]int8 }{[1]int8{1}}, 0}, 64 | 65 | // Trivial unnamed fields test 66 | {struct{ _ [1]int8 }{}, 8}, 67 | {struct { 68 | _ [1]int8 `struct:"skip=4"` 69 | }{}, 40}, 70 | 71 | // Non-trivial unnamed fields test 72 | {struct{ _ []interface{} }{}, 0}, 73 | {struct{ _ [1]interface{} }{}, 0}, 74 | {struct { 75 | _ [1]interface{} `struct:"skip=4"` 76 | }{}, 32}, 77 | {struct { 78 | _ [4]struct { 79 | _ [4]struct{} `struct:"skip=4"` 80 | } `struct:"skip=4"` 81 | }{}, 160}, 82 | {struct{ T string }{"yeehaw"}, 48}, 83 | 84 | // Byte-misaligned structures 85 | {[10]struct { 86 | _ int8 `struct:"uint8:1"` 87 | }{}, 10}, 88 | {[4]struct { 89 | _ bool `struct:"uint8:1,variantbool"` 90 | _ int8 `struct:"uint8:4"` 91 | _ int8 `struct:"uint8:4"` 92 | }{}, 36}, 93 | } 94 | 95 | ss := structstack{} 96 | for _, test := range tests { 97 | field := fieldFromType(reflect.TypeOf(test.input)) 98 | assert.Equal(t, test.size, ss.fieldbits(field, reflect.ValueOf(test.input)), 99 | "bad size for input: %#v", test.input) 100 | } 101 | } 102 | 103 | var ( 104 | simpleFields = fieldsFromStruct(reflect.TypeOf(TestElem{})) 105 | complexFields = fieldsFromStruct(reflect.TypeOf(TestStruct{})) 106 | ) 107 | 108 | func TestSizeOfFields(t *testing.T) { 109 | ss := structstack{} 110 | assert.Equal(t, 72, ss.fieldsbits(simpleFields, reflect.ValueOf(TestElem{}))) 111 | assert.Equal(t, 17040, ss.fieldsbits(complexFields, reflect.ValueOf(TestStruct{}))) 112 | } 113 | 114 | func BenchmarkSizeOfSimple(b *testing.B) { 115 | ss := structstack{} 116 | for i := 0; i < b.N; i++ { 117 | ss.fieldsbits(simpleFields, reflect.ValueOf(TestElem{})) 118 | } 119 | } 120 | 121 | func BenchmarkSizeOfComplex(b *testing.B) { 122 | ss := structstack{} 123 | for i := 0; i < b.N; i++ { 124 | ss.fieldsbits(complexFields, reflect.ValueOf(TestStruct{})) 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /tag.go: -------------------------------------------------------------------------------- 1 | package restruct 2 | 3 | import ( 4 | "encoding/binary" 5 | "errors" 6 | "fmt" 7 | "reflect" 8 | "strconv" 9 | "strings" 10 | "unicode" 11 | "unicode/utf8" 12 | ) 13 | 14 | func lower(ch rune) rune { 15 | return ('a' - 'A') | ch 16 | } 17 | 18 | func isdecimal(ch rune) bool { 19 | return '0' <= ch && ch <= '9' 20 | } 21 | 22 | func ishex(ch rune) bool { 23 | return '0' <= ch && ch <= '9' || 'a' <= lower(ch) && lower(ch) <= 'f' 24 | } 25 | 26 | func isletter(c rune) bool { 27 | return 'a' <= lower(c) && lower(c) <= 'z' || c == '_' || c >= utf8.RuneSelf && unicode.IsLetter(c) 28 | } 29 | 30 | func isdigit(c rune) bool { 31 | return isdecimal(c) 32 | } 33 | 34 | func isident(c rune) bool { 35 | return isletter(c) || isdigit(c) 36 | } 37 | 38 | func isint(c rune) bool { 39 | return isdigit(c) || ishex(c) || lower(c) == 'x' 40 | } 41 | 42 | // tagOptions represents a parsed struct tag. 43 | type tagOptions struct { 44 | Ignore bool 45 | Type reflect.Type 46 | SizeOf string 47 | SizeFrom string 48 | Skip int 49 | Order binary.ByteOrder 50 | BitSize uint8 51 | VariantBoolFlag bool 52 | InvertedBoolFlag bool 53 | RootFlag bool 54 | ParentFlag bool 55 | DefaultFlag bool 56 | 57 | IfExpr string 58 | SizeExpr string 59 | BitsExpr string 60 | InExpr string 61 | OutExpr string 62 | WhileExpr string 63 | SwitchExpr string 64 | CaseExpr string 65 | } 66 | 67 | func (opts *tagOptions) parse(tag string) error { 68 | // Empty tag 69 | if len(tag) == 0 { 70 | return nil 71 | } else if tag == "-" { 72 | opts.Ignore = true 73 | return nil 74 | } 75 | 76 | tag += "\x00" 77 | 78 | accept := func(v string) bool { 79 | if strings.HasPrefix(tag, v) { 80 | tag = tag[len(v):] 81 | return true 82 | } 83 | return false 84 | } 85 | 86 | acceptIdent := func() (string, error) { 87 | var ( 88 | i int 89 | r rune 90 | ) 91 | for i, r = range tag { 92 | if r == ',' || r == 0 { 93 | break 94 | } 95 | if i == 0 && !isletter(r) || !isident(r) { 96 | return "", fmt.Errorf("invalid identifier character %c", r) 97 | } 98 | } 99 | result := tag[:i] 100 | tag = tag[i:] 101 | return result, nil 102 | } 103 | 104 | acceptInt := func() (int, error) { 105 | var ( 106 | i int 107 | r rune 108 | ) 109 | for i, r = range tag { 110 | if r == ',' || r == 0 { 111 | break 112 | } 113 | if !isint(r) { 114 | return 0, fmt.Errorf("invalid integer character %c", r) 115 | } 116 | } 117 | result := tag[:i] 118 | tag = tag[i:] 119 | d, err := strconv.ParseInt(result, 0, 64) 120 | return int(d), err 121 | } 122 | 123 | acceptExpr := func() (string, error) { 124 | stack := []byte{0} 125 | 126 | current := func() byte { return stack[len(stack)-1] } 127 | push := func(r byte) { stack = append(stack, r) } 128 | pop := func() { stack = stack[:len(stack)-1] } 129 | 130 | var i int 131 | expr: 132 | for i = 0; i < len(tag); i++ { 133 | switch tag[i] { 134 | case ',': 135 | if len(stack) == 1 { 136 | break expr 137 | } 138 | case '(': 139 | push(')') 140 | case '[': 141 | push(']') 142 | case '{': 143 | push('}') 144 | case '"', '\'': 145 | term := tag[i] 146 | i++ 147 | lit: 148 | for { 149 | if i >= len(tag) { 150 | return "", errors.New("unexpected eof in literal") 151 | } 152 | switch tag[i] { 153 | case term: 154 | break lit 155 | case '\\': 156 | i++ 157 | } 158 | i++ 159 | } 160 | case current(): 161 | pop() 162 | if len(stack) == 0 { 163 | break expr 164 | } 165 | default: 166 | if tag[i] == 0 { 167 | return "", errors.New("unexpected eof in expr") 168 | } 169 | } 170 | } 171 | result := tag[:i] 172 | tag = tag[i:] 173 | return result, nil 174 | } 175 | 176 | var err error 177 | for { 178 | switch { 179 | case accept("lsb"), accept("little"): 180 | opts.Order = binary.LittleEndian 181 | case accept("msb"), accept("big"), accept("network"): 182 | opts.Order = binary.BigEndian 183 | case accept("variantbool"): 184 | opts.VariantBoolFlag = true 185 | case accept("invertedbool"): 186 | opts.InvertedBoolFlag = true 187 | case accept("root"): 188 | opts.RootFlag = true 189 | case accept("parent"): 190 | opts.ParentFlag = true 191 | case accept("default"): 192 | opts.DefaultFlag = true 193 | case accept("sizeof="): 194 | if opts.SizeOf, err = acceptIdent(); err != nil { 195 | return fmt.Errorf("sizeof: %v", err) 196 | } 197 | case accept("sizefrom="): 198 | if opts.SizeFrom, err = acceptIdent(); err != nil { 199 | return fmt.Errorf("sizefrom: %v", err) 200 | } 201 | case accept("skip="): 202 | if opts.Skip, err = acceptInt(); err != nil { 203 | return fmt.Errorf("skip: %v", err) 204 | } 205 | case accept("if="): 206 | if opts.IfExpr, err = acceptExpr(); err != nil { 207 | return fmt.Errorf("if: %v", err) 208 | } 209 | case accept("size="): 210 | if opts.SizeExpr, err = acceptExpr(); err != nil { 211 | return fmt.Errorf("size: %v", err) 212 | } 213 | case accept("bits="): 214 | if opts.BitsExpr, err = acceptExpr(); err != nil { 215 | return fmt.Errorf("bits: %v", err) 216 | } 217 | case accept("in="): 218 | if opts.InExpr, err = acceptExpr(); err != nil { 219 | return fmt.Errorf("in: %v", err) 220 | } 221 | case accept("out="): 222 | if opts.OutExpr, err = acceptExpr(); err != nil { 223 | return fmt.Errorf("out: %v", err) 224 | } 225 | case accept("while="): 226 | if opts.WhileExpr, err = acceptExpr(); err != nil { 227 | return fmt.Errorf("while: %v", err) 228 | } 229 | case accept("switch="): 230 | if opts.SwitchExpr, err = acceptExpr(); err != nil { 231 | return fmt.Errorf("switch: %v", err) 232 | } 233 | case accept("case="): 234 | if opts.CaseExpr, err = acceptExpr(); err != nil { 235 | return fmt.Errorf("case: %v", err) 236 | } 237 | case accept("-"): 238 | return errors.New("extra options on ignored field") 239 | default: 240 | typeexpr, err := acceptExpr() 241 | if err != nil { 242 | return fmt.Errorf("struct type: %v", err) 243 | } 244 | parts := strings.SplitN(typeexpr, ":", 2) 245 | opts.Type, err = parseType(parts[0]) 246 | if err != nil { 247 | return fmt.Errorf("struct type: %v", err) 248 | } 249 | if len(parts) < 2 { 250 | break 251 | } 252 | if !validBitType(opts.Type) { 253 | return fmt.Errorf("struct type bits specified on non-bitwise type %s", opts.Type) 254 | } 255 | bits, err := strconv.ParseUint(parts[1], 0, 8) 256 | if err != nil { 257 | return errors.New("struct type bits: invalid integer syntax") 258 | } 259 | opts.BitSize = uint8(bits) 260 | if opts.BitSize >= uint8(opts.Type.Bits()) || opts.BitSize == 0 { 261 | return fmt.Errorf("bit size %d out of range (%d to %d)", opts.BitSize, 1, opts.Type.Bits()-1) 262 | } 263 | } 264 | if accept("\x00") { 265 | return nil 266 | } 267 | if !accept(",") { 268 | return errors.New("tag: expected comma") 269 | } 270 | } 271 | } 272 | 273 | // mustParseTag calls ParseTag but panics if there is an error, to help make 274 | // sure programming errors surface quickly. 275 | func mustParseTag(tag string) tagOptions { 276 | opt, err := parseTag(tag) 277 | if err != nil { 278 | panic(err) 279 | } 280 | return opt 281 | } 282 | 283 | // parseTag parses a struct tag into a TagOptions structure. 284 | func parseTag(tag string) (tagOptions, error) { 285 | opts := tagOptions{} 286 | if err := opts.parse(tag); err != nil { 287 | return tagOptions{}, err 288 | } 289 | return opts, nil 290 | } 291 | -------------------------------------------------------------------------------- /tag_test.go: -------------------------------------------------------------------------------- 1 | package restruct 2 | 3 | import ( 4 | "encoding/binary" 5 | "reflect" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestParseTag(t *testing.T) { 12 | tests := []struct { 13 | input string 14 | opts tagOptions 15 | errstr string 16 | }{ 17 | // Blank 18 | {"", tagOptions{}, ""}, 19 | 20 | // Gibberish 21 | {"!#%,1245^#df,little,&~@~@~@~@", tagOptions{}, "parsing error"}, 22 | {"&paREZysLu&@,83D9I!,9OsQ56BLD", tagOptions{}, "parsing error"}, 23 | {"B7~,H0IDSxDlJ,#xa$kgDEL%Ts,88", tagOptions{}, "parsing error"}, 24 | {"fio&eQ8xwbhAWR*!CRlL2XBDG$45s", tagOptions{}, "parsing error"}, 25 | {"IcPyRJ#EV@a4QAb9wENk4Zq9MpX$p", tagOptions{}, "parsing error"}, 26 | 27 | // Conflicting byte order 28 | {"little,big", tagOptions{Order: binary.BigEndian}, ""}, 29 | {"big,little", tagOptions{Order: binary.LittleEndian}, ""}, 30 | 31 | // Byte order 32 | {"msb", tagOptions{Order: binary.BigEndian}, ""}, 33 | {"lsb", tagOptions{Order: binary.LittleEndian}, ""}, 34 | {"network", tagOptions{Order: binary.BigEndian}, ""}, 35 | {"big little", tagOptions{}, "tag: expected comma"}, 36 | 37 | // Ignore 38 | {"-", tagOptions{Ignore: true}, ""}, 39 | {"-,test", tagOptions{}, "extra options on ignored field"}, 40 | 41 | // Bad types 42 | {"invalid", tagOptions{}, "unknown type invalid"}, 43 | {"chan int8", tagOptions{}, "channel type not allowed"}, 44 | {"map[byte]byte", tagOptions{}, "map type not allowed"}, 45 | {`map[`, tagOptions{}, "struct type: unexpected eof in expr"}, 46 | {`map[]`, tagOptions{}, "struct type: parsing error"}, 47 | 48 | // Types 49 | {"uint8", tagOptions{Type: reflect.TypeOf(uint8(0))}, ""}, 50 | {"uint16", tagOptions{Type: reflect.TypeOf(uint16(0))}, ""}, 51 | {"uint32", tagOptions{Type: reflect.TypeOf(uint32(0))}, ""}, 52 | {"int8", tagOptions{Type: reflect.TypeOf(int8(0))}, ""}, 53 | {"int16", tagOptions{Type: reflect.TypeOf(int16(0))}, ""}, 54 | {"int32", tagOptions{Type: reflect.TypeOf(int32(0))}, ""}, 55 | 56 | // Bitfields 57 | {"uint8:3", tagOptions{Type: reflect.TypeOf(uint8(0)), BitSize: 3}, ""}, 58 | {"uint16:15", tagOptions{Type: reflect.TypeOf(uint16(0)), BitSize: 15}, ""}, 59 | {"uint32:31", tagOptions{Type: reflect.TypeOf(uint32(0)), BitSize: 31}, ""}, 60 | {"uint64:63", tagOptions{Type: reflect.TypeOf(uint64(0)), BitSize: 63}, ""}, 61 | {"uint8:1", tagOptions{Type: reflect.TypeOf(uint8(0)), BitSize: 1}, ""}, 62 | {"uint16:1", tagOptions{Type: reflect.TypeOf(uint16(0)), BitSize: 1}, ""}, 63 | {"uint32:1", tagOptions{Type: reflect.TypeOf(uint32(0)), BitSize: 1}, ""}, 64 | {"uint64:1", tagOptions{Type: reflect.TypeOf(uint64(0)), BitSize: 1}, ""}, 65 | {"[]uint8:1", tagOptions{}, "struct type bits specified on non-bitwise type []uint8"}, 66 | 67 | // Wrong bitfields 68 | {"uint8:0", tagOptions{}, "bit size 0 out of range (1 to 7)"}, 69 | {"uint16:0", tagOptions{}, "bit size 0 out of range (1 to 15)"}, 70 | {"uint32:0", tagOptions{}, "bit size 0 out of range (1 to 31)"}, 71 | {"uint64:0", tagOptions{}, "bit size 0 out of range (1 to 63)"}, 72 | {"int8:0", tagOptions{}, "bit size 0 out of range (1 to 7)"}, 73 | {"int16:0", tagOptions{}, "bit size 0 out of range (1 to 15)"}, 74 | {"int32:0", tagOptions{}, "bit size 0 out of range (1 to 31)"}, 75 | {"int64:0", tagOptions{}, "bit size 0 out of range (1 to 63)"}, 76 | 77 | {"uint8:8", tagOptions{BitSize: 0}, "bit size 8 out of range (1 to 7)"}, 78 | {"uint16:16", tagOptions{BitSize: 0}, "bit size 16 out of range (1 to 15)"}, 79 | {"uint32:32", tagOptions{BitSize: 0}, "bit size 32 out of range (1 to 31)"}, 80 | {"uint64:64", tagOptions{BitSize: 0}, "bit size 64 out of range (1 to 63)"}, 81 | {"int8:8", tagOptions{BitSize: 0}, "bit size 8 out of range (1 to 7)"}, 82 | {"int16:16", tagOptions{BitSize: 0}, "bit size 16 out of range (1 to 15)"}, 83 | {"int32:32", tagOptions{BitSize: 0}, "bit size 32 out of range (1 to 31)"}, 84 | {"int64:64", tagOptions{BitSize: 0}, "bit size 64 out of range (1 to 63)"}, 85 | 86 | {"uint8:XX", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, 87 | {"uint16:XX", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, 88 | {"uint32:XX", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, 89 | {"uint64:XX", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, 90 | {"int8:XX", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, 91 | {"int16:XX", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, 92 | {"int32:XX", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, 93 | {"int64:XX", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, 94 | 95 | {"uint8:X:X", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, 96 | {"uint16:X:X", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, 97 | {"uint32:X:X", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, 98 | {"uint64:X:X", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, 99 | {"int8:X:X", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, 100 | {"int16:X:X", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, 101 | {"int32:X:X", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, 102 | {"int64:X:X", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, 103 | 104 | // Sizeof 105 | {"sizefrom=OtherField", tagOptions{SizeFrom: "OtherField"}, ""}, 106 | {"sizefrom=日本", tagOptions{SizeFrom: "日本"}, ""}, 107 | {"sizefrom=日本,variantbool", tagOptions{SizeFrom: "日本", VariantBoolFlag: true}, ""}, 108 | {"sizefrom=0", tagOptions{}, "sizefrom: invalid identifier character 0"}, 109 | 110 | // Sizeof 111 | {"sizeof=OtherField", tagOptions{SizeOf: "OtherField"}, ""}, 112 | {"sizeof=日本", tagOptions{SizeOf: "日本"}, ""}, 113 | {"sizeof=日本,variantbool", tagOptions{SizeOf: "日本", VariantBoolFlag: true}, ""}, 114 | {"sizeof=0", tagOptions{}, "sizeof: invalid identifier character 0"}, 115 | 116 | // Skip 117 | {"skip=4", tagOptions{Skip: 4}, ""}, 118 | {"skip=字", tagOptions{}, "skip: invalid integer character 字"}, 119 | 120 | // Expressions 121 | {"if=true", tagOptions{IfExpr: "true"}, ""}, 122 | {"if=call(0,1)", tagOptions{IfExpr: "call(0,1)"}, ""}, 123 | {`if=call(")Test)"),sizeof=Test`, tagOptions{IfExpr: `call(")Test)")`, SizeOf: "Test"}, ""}, 124 | {"size=4", tagOptions{SizeExpr: "4"}, ""}, 125 | {"size={,", tagOptions{}, "size: unexpected eof in expr"}, 126 | {"bits=4", tagOptions{BitsExpr: "4"}, ""}, 127 | {"bits={,", tagOptions{}, "bits: unexpected eof in expr"}, 128 | {"in=42", tagOptions{InExpr: "42"}, ""}, 129 | {"out=struct{}{}", tagOptions{OutExpr: "struct{}{}"}, ""}, 130 | {"out=struct{}{},variantbool", tagOptions{OutExpr: "struct{}{}", VariantBoolFlag: true}, ""}, 131 | {"while=true", tagOptions{WhileExpr: "true"}, ""}, 132 | {`if="`, tagOptions{}, "if: unexpected eof in literal"}, 133 | {`while="\"`, tagOptions{}, "while: unexpected eof in literal"}, 134 | {`in="\"\"""`, tagOptions{}, "in: unexpected eof in literal"}, 135 | {`out="\"test`, tagOptions{}, "out: unexpected eof in literal"}, 136 | 137 | // Root 138 | {"root", tagOptions{RootFlag: true}, ""}, 139 | 140 | // Parent 141 | {"parent", tagOptions{ParentFlag: true}, ""}, 142 | 143 | // Composite 144 | {"uint16,little,sizeof=test,skip=5", 145 | tagOptions{ 146 | Type: reflect.TypeOf(uint16(0)), 147 | Order: binary.LittleEndian, 148 | SizeOf: "test", 149 | Skip: 5, 150 | }, 151 | "", 152 | }, 153 | } 154 | 155 | for _, test := range tests { 156 | opts, err := parseTag(test.input) 157 | assert.Equal(t, test.opts, opts) 158 | if err != nil { 159 | assert.NotEmpty(t, test.errstr) 160 | assert.Contains(t, err.Error(), test.errstr) 161 | } 162 | } 163 | } 164 | 165 | func TestMustParseTagPanicsOnError(t *testing.T) { 166 | defer func() { 167 | if r := recover(); r == nil { 168 | t.Error("Invalid tag did not panic.") 169 | } 170 | }() 171 | mustParseTag("???") 172 | } 173 | 174 | func TestMustParseTagReturnsOnSuccess(t *testing.T) { 175 | defer func() { 176 | if r := recover(); r != nil { 177 | t.Error("Valid tag panicked.") 178 | } 179 | }() 180 | mustParseTag("[128]byte,little,sizeof=Test") 181 | } 182 | -------------------------------------------------------------------------------- /testdata/pnggrad8rgb.json: -------------------------------------------------------------------------------- 1 | { 2 | "Magic": [ 3 | 137, 4 | 80, 5 | 78, 6 | 71, 7 | 13, 8 | 10, 9 | 26, 10 | 10 11 | ], 12 | "Header": { 13 | "Len": 13, 14 | "Type": "IHDR", 15 | "Data": { 16 | "IHDR": { 17 | "Width": 300, 18 | "Height": 300, 19 | "BitDepth": 8, 20 | "ColorType": 2, 21 | "CompressionMethod": 0, 22 | "FilterMethod": 0, 23 | "InterlaceMethod": 0 24 | } 25 | }, 26 | "CRC": 4129233186 27 | }, 28 | "Chunks": [ 29 | { 30 | "Len": 919, 31 | "Type": "IDAT", 32 | "Data": { 33 | "IDAT": { 34 | "Data": "eJzt2TGKw0AURMEe4/tfWYqdCRy8QFVstCBw8miYf7Zru87v37bz6J/zrW99++e3nwGp7079E+DdRAgxEUJMhBATIcS8jkLMEkJMhBATIcRECDERQkyEEHOigJglhJgIISZCiIkQYiKEmAgh5kQBMUsIMRFCTIQQEyHERAgxr6MQs4QQEyHERAgxEUJMhBATIcScKCBmCSEmQoiJEGIihJgIISZCiDlRQMwSQkyEEBMhxEQIMRFCzOsoxCwhxEQIMRFCTIQQEyHERAgxJwqIWUKIiRBiIoSYCCEmQoiJEGJOFBCzhBATIcRECDERQkyEEPM6CjFLCDERQkyEEBMhxEQIMRFCzIkCYpYQYiKEmAghJkKIiRBiIoSYEwXELCHERAgxEUJMhBATIcS8jkLMEkJMhBATIcRECDERQkyEEHOigJglhJgIISZCiIkQYiKEmAgh5kQBMUsIMRFCTIQQEyHERAgxr6MQs4QQEyHERAgxEUJMhBATIcScKCBmCSEmQoiJEGIihJgIISZCiDlRQMwSQkyEEBMhxEQIMRFCzOsoxCwhxEQIMRFCTIQQEyHERAgxJwqIWUKIiRBiIoSYCCEmQoiJEGJOFBCzhBATIcRECDERQkyEEPM6CjFLCDERQkyEEBMhxEQIMRFCzIkCYpYQYiKEmAghJkKIiRBiIoSYEwXELCHERAgxEUJMhBATIcS8jkLMEkJMhBATIcRECDERQkyEEHOigJglhJgIISZCiIkQYiKEmAgh5kQBMUsIMRFCTIQQEyHERAgxr6MQs4QQEyHERAgxEUJMhBATIcScKCBmCSEmQoiJEGIihJgIISZCiDlRQMwSQkyEEBMhxEQIMRFCzOsoxCwhxEQIMRFCTIQQEyHERAgxJwqIWUKIiRBiIoSYCCEmQoiJEGJOFBCzhBATIcRECDERQkyEEPM6CjFLCDERQkyEEBMhxEQIMRFCzIkCYpYQYiKEmAghJkKIiRBiIoSYEwXELCHERAgxEUJMhBATIcS8jkLMEkJMhBATIcRECDERQkyEEHOigJglhJgIISZCiIkQYiKEmAgh5kQBMUsIMRFCTIQQEyHERAgxr6MQs4QQEyHERAgxEUJMhBATIcScKCBmCSEmQoiJEGIihJgIISZCiDlRQMwSQkyEEBMhxEQIMRFCzOsoxCwhxEQIMRFCTIQQEyHERAgxJwqIWUKIiRBiIoSYCCEmQojdB7QFXw==" 35 | } 36 | }, 37 | "CRC": 566973649 38 | }, 39 | { 40 | "Len": 0, 41 | "Type": "IEND", 42 | "Data": { 43 | "IEND": {} 44 | }, 45 | "CRC": 2923585666 46 | } 47 | ] 48 | } -------------------------------------------------------------------------------- /testdata/pnggrad8rgb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/go-restruct/restruct/1bb20937bae4323212206089007dfebc305d90d1/testdata/pnggrad8rgb.png -------------------------------------------------------------------------------- /typestr.go: -------------------------------------------------------------------------------- 1 | package restruct 2 | 3 | import ( 4 | "fmt" 5 | "go/ast" 6 | "go/parser" 7 | "go/token" 8 | "reflect" 9 | "strconv" 10 | 11 | "github.com/pkg/errors" 12 | ) 13 | 14 | // typeMap maps identifiers to reflect.Types. 15 | var typeMap = map[string]reflect.Type{ 16 | "bool": reflect.TypeOf(bool(false)), 17 | 18 | "uint8": reflect.TypeOf(uint8(0)), 19 | "uint16": reflect.TypeOf(uint16(0)), 20 | "uint32": reflect.TypeOf(uint32(0)), 21 | "uint64": reflect.TypeOf(uint64(0)), 22 | 23 | "int8": reflect.TypeOf(int8(0)), 24 | "int16": reflect.TypeOf(int16(0)), 25 | "int32": reflect.TypeOf(int32(0)), 26 | "int64": reflect.TypeOf(int64(0)), 27 | 28 | "float32": reflect.TypeOf(float32(0)), 29 | "float64": reflect.TypeOf(float64(0)), 30 | 31 | "complex64": reflect.TypeOf(complex64(0)), 32 | "complex128": reflect.TypeOf(complex128(0)), 33 | 34 | "byte": reflect.TypeOf(uint8(0)), 35 | "rune": reflect.TypeOf(int32(0)), 36 | 37 | "uint": reflect.TypeOf(uint(0)), 38 | "int": reflect.TypeOf(int(0)), 39 | "uintptr": reflect.TypeOf(uintptr(0)), 40 | "string": reflect.SliceOf(reflect.TypeOf(uint8(0))), 41 | } 42 | 43 | // typeOfExpr gets a type corresponding to an expression. 44 | func typeOfExpr(expr ast.Expr) (reflect.Type, error) { 45 | switch expr := expr.(type) { 46 | default: 47 | return nil, fmt.Errorf("unexpected expression: %T", expr) 48 | case *ast.ArrayType: 49 | switch expr.Len { 50 | case ast.Expr(nil): 51 | // Slice 52 | sub, err := typeOfExpr(expr.Elt) 53 | if err != nil { 54 | return nil, err 55 | } 56 | return reflect.SliceOf(sub), nil 57 | default: 58 | // Parse length expression 59 | lexpr, ok := expr.Len.(*ast.BasicLit) 60 | if !ok { 61 | return nil, fmt.Errorf("invalid array size expression") 62 | } 63 | if lexpr.Kind != token.INT { 64 | return nil, fmt.Errorf("invalid array size type") 65 | } 66 | len, err := strconv.Atoi(lexpr.Value) 67 | if err != nil { 68 | return nil, err 69 | } 70 | 71 | // Parse elem type expression 72 | sub, err := typeOfExpr(expr.Elt) 73 | if err != nil { 74 | return nil, err 75 | } 76 | return reflect.ArrayOf(len, sub), nil 77 | } 78 | case *ast.Ident: 79 | // Primitive types 80 | typ, ok := typeMap[expr.Name] 81 | if !ok { 82 | return nil, fmt.Errorf("unknown type %s", expr.Name) 83 | } 84 | return typ, nil 85 | case *ast.StarExpr: 86 | // Pointer 87 | sub, err := typeOfExpr(expr.X) 88 | if err != nil { 89 | return nil, err 90 | } 91 | return reflect.PtrTo(sub), nil 92 | case *ast.ChanType: 93 | return nil, fmt.Errorf("channel type not allowed") 94 | case *ast.MapType: 95 | return nil, fmt.Errorf("map type not allowed") 96 | } 97 | } 98 | 99 | // parseType parses a Golang type string and returns a reflect.Type. 100 | func parseType(typ string) (reflect.Type, error) { 101 | expr, err := parser.ParseExpr(typ) 102 | if err != nil { 103 | return nil, errors.Wrap(err, "parsing error") 104 | } 105 | 106 | return typeOfExpr(expr) 107 | } 108 | -------------------------------------------------------------------------------- /typestr_test.go: -------------------------------------------------------------------------------- 1 | package restruct 2 | 3 | import ( 4 | "go/ast" 5 | "go/token" 6 | "reflect" 7 | "testing" 8 | 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestParseType(t *testing.T) { 13 | RegisterArrayType([5]*float32{}) 14 | 15 | tests := []struct { 16 | input string 17 | typ reflect.Type 18 | errstr string 19 | }{ 20 | // Bad code 21 | {"", nil, "parsing error"}, 22 | {"Invalid", nil, "unknown type Invalid"}, 23 | {"[][435w5[43]]]**//!!!!!!!", nil, "parsing error"}, 24 | {"日本語ですか?", nil, "parsing error"}, 25 | 26 | // Containers 27 | {"float32", reflect.TypeOf(float32(0)), ""}, 28 | {"*float32", reflect.TypeOf((*float32)(nil)), ""}, 29 | {"[5]*float32", reflect.TypeOf([5]*float32{}), ""}, 30 | {"[5]*invalid", nil, "unknown type invalid"}, 31 | {"[][][]*float32", reflect.TypeOf([][][]*float32{}), ""}, 32 | {"[][][]*invalid", nil, "unknown type invalid"}, 33 | 34 | // Types 35 | {"bool", reflect.TypeOf(false), ""}, 36 | 37 | {"uint8", reflect.TypeOf(uint8(0)), ""}, 38 | {"uint16", reflect.TypeOf(uint16(0)), ""}, 39 | {"uint32", reflect.TypeOf(uint32(0)), ""}, 40 | {"uint64", reflect.TypeOf(uint64(0)), ""}, 41 | 42 | {"int8", reflect.TypeOf(int8(0)), ""}, 43 | {"int16", reflect.TypeOf(int16(0)), ""}, 44 | {"int32", reflect.TypeOf(int32(0)), ""}, 45 | {"int64", reflect.TypeOf(int64(0)), ""}, 46 | 47 | {"complex64", reflect.TypeOf(complex64(0)), ""}, 48 | {"complex128", reflect.TypeOf(complex128(0)), ""}, 49 | 50 | {"byte", reflect.TypeOf(byte(0)), ""}, 51 | {"rune", reflect.TypeOf(rune(0)), ""}, 52 | 53 | {"uint", reflect.TypeOf(uint(0)), ""}, 54 | {"int", reflect.TypeOf(int(0)), ""}, 55 | {"uintptr", reflect.TypeOf(uintptr(0)), ""}, 56 | {"string", reflect.TypeOf([]byte{}), ""}, 57 | 58 | // Illegal types 59 | {"chan int", nil, "channel type not allowed"}, 60 | {"*chan int", nil, "channel type not allowed"}, 61 | {"map[string]string", nil, "map type not allowed"}, 62 | {"map[interface{}]interface{}", nil, "map type not allowed"}, 63 | 64 | // Disallowed expressions 65 | {"i + 1", nil, "unexpected expression: *ast.BinaryExpr"}, 66 | {"i()", nil, "unexpected expression: *ast.CallExpr"}, 67 | } 68 | 69 | for _, test := range tests { 70 | typ, err := parseType(test.input) 71 | if typ != nil { 72 | assert.Equal(t, test.typ.String(), typ.String()) 73 | } 74 | if err != nil { 75 | assert.Contains(t, err.Error(), test.errstr) 76 | } 77 | } 78 | } 79 | 80 | func TestBadAst(t *testing.T) { 81 | // typeOfExpr should gracefully handle broken AST structures. Let's 82 | // construct some. 83 | 84 | // Array with bad length descriptor. 85 | // [Bad]int32 86 | badArr := ast.ArrayType{ 87 | Len: ast.NewIdent("Bad"), 88 | Elt: ast.NewIdent("int32"), 89 | } 90 | typ, err := typeOfExpr(&badArr) 91 | assert.Equal(t, typ, nil) 92 | assert.Equal(t, err.Error(), "invalid array size expression") 93 | 94 | // Array with bad length descriptor. 95 | // ["How about that!"]int32 96 | badArr = ast.ArrayType{ 97 | Len: &ast.BasicLit{Kind: token.STRING, Value: `"How about that!"`}, 98 | Elt: ast.NewIdent("int32"), 99 | } 100 | typ, err = typeOfExpr(&badArr) 101 | assert.Equal(t, typ, nil) 102 | assert.Equal(t, err.Error(), "invalid array size type") 103 | 104 | // Array with bad length descriptor. 105 | // [10ii0]int32 106 | badArr = ast.ArrayType{ 107 | Len: &ast.BasicLit{Kind: token.INT, Value: "10ii0"}, 108 | Elt: ast.NewIdent("int32"), 109 | } 110 | typ, err = typeOfExpr(&badArr) 111 | assert.Equal(t, typ, nil) 112 | assert.NotNil(t, err) 113 | } 114 | --------------------------------------------------------------------------------