This commit is contained in:
2024-05-14 12:10:58 +02:00
parent a9bb79b01c
commit 59911aebb9
645 changed files with 263320 additions and 0 deletions

23
vendor/github.com/glycerine/blake2b/README generated vendored Normal file
View File

@@ -0,0 +1,23 @@
Go implementation of BLAKE2b collision-resistant cryptographic hash function
created by Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn, and
Christian Winnerlein (https://blake2.net).
INSTALLATION
$ go get github.com/dchest/blake2b
DOCUMENTATION
See http://godoc.org/github.com/dchest/blake2b
PUBLIC DOMAIN DEDICATION
Written in 2012 by Dmitry Chestnykh.
To the extent possible under law, the author have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
http://creativecommons.org/publicdomain/zero/1.0/

299
vendor/github.com/glycerine/blake2b/blake2b.go generated vendored Normal file
View File

@@ -0,0 +1,299 @@
// Written in 2012 by Dmitry Chestnykh.
//
// To the extent possible under law, the author have dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
// http://creativecommons.org/publicdomain/zero/1.0/
// Package blake2b implements BLAKE2b cryptographic hash function.
package blake2b
import (
"encoding/binary"
"errors"
"hash"
)
const (
BlockSize = 128 // block size of algorithm
Size = 64 // maximum digest size
SaltSize = 16 // maximum salt size
PersonSize = 16 // maximum personalization string size
KeySize = 64 // maximum size of key
)
type digest struct {
h [8]uint64 // current chain value
t [2]uint64 // message bytes counter
f [2]uint64 // finalization flags
x [BlockSize]byte // buffer for data not yet compressed
nx int // number of bytes in buffer
ih [8]uint64 // initial chain value (after config)
paddedKey [BlockSize]byte // copy of key, padded with zeros
isKeyed bool // indicates whether hash was keyed
size uint8 // digest size in bytes
isLastNode bool // indicates processing of the last node in tree hashing
}
// Initialization values.
var iv = [8]uint64{
0x6a09e667f3bcc908, 0xbb67ae8584caa73b,
0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
0x510e527fade682d1, 0x9b05688c2b3e6c1f,
0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
}
// Config is used to configure hash function parameters and keying.
// All parameters are optional.
type Config struct {
Size uint8 // digest size (if zero, default size of 64 bytes is used)
Key []byte // key for prefix-MAC
Salt []byte // salt (if < 16 bytes, padded with zeros)
Person []byte // personalization (if < 16 bytes, padded with zeros)
Tree *Tree // parameters for tree hashing
}
// Tree represents parameters for tree hashing.
type Tree struct {
Fanout uint8 // fanout
MaxDepth uint8 // maximal depth
LeafSize uint32 // leaf maximal byte length (0 for unlimited)
NodeOffset uint64 // node offset (0 for first, leftmost or leaf)
NodeDepth uint8 // node depth (0 for leaves)
InnerHashSize uint8 // inner hash byte length
IsLastNode bool // indicates processing of the last node of layer
}
var (
defaultConfig = &Config{Size: Size}
config256 = &Config{Size: 32}
)
func verifyConfig(c *Config) error {
if c.Size > Size {
return errors.New("digest size is too large")
}
if len(c.Key) > KeySize {
return errors.New("key is too large")
}
if len(c.Salt) > SaltSize {
// Smaller salt is okay: it will be padded with zeros.
return errors.New("salt is too large")
}
if len(c.Person) > PersonSize {
// Smaller personalization is okay: it will be padded with zeros.
return errors.New("personalization is too large")
}
if c.Tree != nil {
if c.Tree.Fanout == 1 {
return errors.New("fanout of 1 is not allowed in tree mode")
}
if c.Tree.MaxDepth < 2 {
return errors.New("incorrect tree depth")
}
if c.Tree.InnerHashSize < 1 || c.Tree.InnerHashSize > Size {
return errors.New("incorrect tree inner hash size")
}
}
return nil
}
// New returns a new hash.Hash configured with the given Config.
// Config can be nil, in which case the default one is used, calculating 64-byte digest.
// Returns non-nil error if Config contains invalid parameters.
func New(c *Config) (hash.Hash, error) {
if c == nil {
c = defaultConfig
} else {
if c.Size == 0 {
// Set default size if it's zero.
c.Size = Size
}
if err := verifyConfig(c); err != nil {
return nil, err
}
}
d := new(digest)
d.initialize(c)
return d, nil
}
// initialize initializes digest with the given
// config, which must be non-nil and verified.
func (d *digest) initialize(c *Config) {
// Create parameter block.
var p [BlockSize]byte
p[0] = c.Size
p[1] = uint8(len(c.Key))
if c.Salt != nil {
copy(p[32:], c.Salt)
}
if c.Person != nil {
copy(p[48:], c.Person)
}
if c.Tree != nil {
p[2] = c.Tree.Fanout
p[3] = c.Tree.MaxDepth
binary.LittleEndian.PutUint32(p[4:], c.Tree.LeafSize)
binary.LittleEndian.PutUint64(p[8:], c.Tree.NodeOffset)
p[16] = c.Tree.NodeDepth
p[17] = c.Tree.InnerHashSize
} else {
p[2] = 1
p[3] = 1
}
// Initialize.
d.size = c.Size
for i := 0; i < 8; i++ {
d.h[i] = iv[i] ^ binary.LittleEndian.Uint64(p[i*8:])
}
if c.Tree != nil && c.Tree.IsLastNode {
d.isLastNode = true
}
// Process key.
if c.Key != nil {
copy(d.paddedKey[:], c.Key)
d.Write(d.paddedKey[:])
d.isKeyed = true
}
// Save a copy of initialized state.
copy(d.ih[:], d.h[:])
}
// New512 returns a new hash.Hash computing the BLAKE2b 64-byte checksum.
func New512() hash.Hash {
d := new(digest)
d.initialize(defaultConfig)
return d
}
// New256 returns a new hash.Hash computing the BLAKE2b 32-byte checksum.
func New256() hash.Hash {
d := new(digest)
d.initialize(config256)
return d
}
// NewMAC returns a new hash.Hash computing BLAKE2b prefix-
// Message Authentication Code of the given size in bytes
// (up to 64) with the given key (up to 64 bytes in length).
func NewMAC(outBytes uint8, key []byte) hash.Hash {
d, err := New(&Config{Size: outBytes, Key: key})
if err != nil {
panic(err.Error())
}
return d
}
// Reset resets the state of digest to the initial state
// after configuration and keying.
func (d *digest) Reset() {
copy(d.h[:], d.ih[:])
d.t[0] = 0
d.t[1] = 0
d.f[0] = 0
d.f[1] = 0
d.nx = 0
if d.isKeyed {
d.Write(d.paddedKey[:])
}
}
// Size returns the digest size in bytes.
func (d *digest) Size() int { return int(d.size) }
// BlockSize returns the algorithm block size in bytes.
func (d *digest) BlockSize() int { return BlockSize }
func (d *digest) Write(p []byte) (nn int, err error) {
nn = len(p)
left := BlockSize - d.nx
if len(p) > left {
// Process buffer.
copy(d.x[d.nx:], p[:left])
p = p[left:]
blocks(d, d.x[:])
d.nx = 0
}
// Process full blocks except for the last one.
if len(p) > BlockSize {
n := len(p) &^ (BlockSize - 1)
if n == len(p) {
n -= BlockSize
}
blocks(d, p[:n])
p = p[n:]
}
// Fill buffer.
d.nx += copy(d.x[d.nx:], p)
return
}
// Sum returns the calculated checksum.
func (d0 *digest) Sum(in []byte) []byte {
// Make a copy of d0 so that caller can keep writing and summing.
d := *d0
hash := d.checkSum()
return append(in, hash[:d.size]...)
}
func (d *digest) checkSum() [Size]byte {
// Do not create unnecessary copies of the key.
if d.isKeyed {
for i := 0; i < len(d.paddedKey); i++ {
d.paddedKey[i] = 0
}
}
dec := BlockSize - uint64(d.nx)
if d.t[0] < dec {
d.t[1]--
}
d.t[0] -= dec
// Pad buffer with zeros.
for i := d.nx; i < len(d.x); i++ {
d.x[i] = 0
}
// Set last block flag.
d.f[0] = 0xffffffffffffffff
if d.isLastNode {
d.f[1] = 0xffffffffffffffff
}
// Compress last block.
blocks(d, d.x[:])
var out [Size]byte
j := 0
for _, s := range d.h[:(d.size-1)/8+1] {
out[j+0] = byte(s >> 0)
out[j+1] = byte(s >> 8)
out[j+2] = byte(s >> 16)
out[j+3] = byte(s >> 24)
out[j+4] = byte(s >> 32)
out[j+5] = byte(s >> 40)
out[j+6] = byte(s >> 48)
out[j+7] = byte(s >> 56)
j += 8
}
return out
}
// Sum512 returns a 64-byte BLAKE2b hash of data.
func Sum512(data []byte) [64]byte {
var d digest
d.initialize(defaultConfig)
d.Write(data)
return d.checkSum()
}
// Sum256 returns a 32-byte BLAKE2b hash of data.
func Sum256(data []byte) (out [32]byte) {
var d digest
d.initialize(config256)
d.Write(data)
sum := d.checkSum()
copy(out[:], sum[:32])
return
}

1420
vendor/github.com/glycerine/blake2b/block.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

25
vendor/github.com/glycerine/greenpack/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,25 @@
MIT License
Portions Copyright (c) 2016 Jason E. Aten
Portions Copyright (c) 2014 Philip Hofer
Portions Copyright (c) 2009 The Go Authors (license at http://golang.org) where indicated
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the
following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,24 @@
// +build linux,!appengine
package msgp
import (
"os"
"syscall"
)
func adviseRead(mem []byte) {
syscall.Madvise(mem, syscall.MADV_SEQUENTIAL|syscall.MADV_WILLNEED)
}
func adviseWrite(mem []byte) {
syscall.Madvise(mem, syscall.MADV_SEQUENTIAL)
}
func fallocate(f *os.File, sz int64) error {
err := syscall.Fallocate(int(f.Fd()), 0, 0, sz)
if err == syscall.ENOTSUP {
return f.Truncate(sz)
}
return err
}

View File

@@ -0,0 +1,17 @@
// +build !linux appengine
package msgp
import (
"os"
)
// TODO: darwin, BSD support
func adviseRead(mem []byte) {}
func adviseWrite(mem []byte) {}
func fallocate(f *os.File, sz int64) error {
return f.Truncate(sz)
}

View File

@@ -0,0 +1,15 @@
// +build appengine
package msgp
// let's just assume appengine
// uses 64-bit hardware...
const smallint = false
func UnsafeString(b []byte) string {
return string(b)
}
func UnsafeBytes(s string) []byte {
return []byte(s)
}

39
vendor/github.com/glycerine/greenpack/msgp/circular.go generated vendored Normal file
View File

@@ -0,0 +1,39 @@
package msgp
type timer interface {
StartTimer()
StopTimer()
}
// EndlessReader is an io.Reader
// that loops over the same data
// endlessly. It is used for benchmarking.
type EndlessReader struct {
tb timer
data []byte
offset int
}
// NewEndlessReader returns a new endless reader
func NewEndlessReader(b []byte, tb timer) *EndlessReader {
return &EndlessReader{tb: tb, data: b, offset: 0}
}
// Read implements io.Reader. In practice, it
// always returns (len(p), nil), although it
// fills the supplied slice while the benchmark
// timer is stopped.
func (c *EndlessReader) Read(p []byte) (int, error) {
c.tb.StopTimer()
var n int
l := len(p)
m := len(c.data)
for n < l {
nn := copy(p[n:], c.data[c.offset:])
n += nn
c.offset += nn
c.offset %= m
}
c.tb.StartTimer()
return n, nil
}

37
vendor/github.com/glycerine/greenpack/msgp/clue.go generated vendored Normal file
View File

@@ -0,0 +1,37 @@
package msgp
import (
"fmt"
"strconv"
"strings"
)
func Clue2Field(name string, clue string, zid int64) string {
if zid >= 0 {
return fmt.Sprintf("%s_zid%02d_%s", name, zid, clue)
}
// handle the missing zid, and don't write -1 as the zid.
return fmt.Sprintf("%s__%s", name, clue)
}
func Field2Clue(fieldname string) (name string, clue string, zid int64, err error) {
parts := strings.Split(fieldname, "_")
n := len(parts)
if n < 3 {
err = fmt.Errorf("too few underscore (expect at least two) in fieldname '%s'", fieldname)
return
}
clue = parts[n-1]
if strings.HasPrefix(parts[n-2], "zid") {
tmp, err2 := strconv.Atoi(parts[n-2][3:])
if err2 == nil {
zid = int64(tmp)
} else {
err = fmt.Errorf("problem parsing out _zid field in fieldname '%s': '%v'", fieldname, err2)
return
}
}
used := len(parts[n-1]) + len(parts[n-2]) + 2
name = fieldname[:len(fieldname)-used]
return
}

146
vendor/github.com/glycerine/greenpack/msgp/dedup.go generated vendored Normal file
View File

@@ -0,0 +1,146 @@
package msgp
import (
"fmt"
"reflect"
)
var _ = fmt.Printf
// Methods for deduplicating repeated occurances of the same pointer.
//
// When writing, we track the sequence of pointers written.
// When we see a duplicate pointer, we write the special
// extension "duplicate" value along with the pointer's
// occurance order in the serialization.
//
// As we read back, we keep a count that increments for every
// pointer we read, and we save a map from the count to the pointer.
// When we encounter a value that is the special value indicating reuse, then
// we refer back to the pointer k (k being found within the special extension value)
// and we plug in the k-th pointer instead.
// writer then reader methods
// ===============================
// ===============================
// Writer methods
// ===============================
// ===============================
func (mw *Writer) DedupReset() {
mw.ptrWrit = make(map[interface{}]int)
mw.ptrCountNext = 0
}
// diagnostic
func (mw *Writer) DedupPointerCount() int {
return len(mw.ptrWrit)
}
// upon writing each pointer, first check if it is a duplicate;
// i.e. appears more than once, pointing to the same object.
func (mw *Writer) DedupWriteIsDup(v interface{}) (res bool, err error) {
defer func() {
// This recover allows test 911 (_generated/gen_test.go:67) to run green.
// It turns indexing by []byte msgp.Raw into a no-op. Which it
// should be.
if recover() != nil {
return
}
}()
if v == nil || reflect.ValueOf(v).IsNil() {
return false, nil
}
k, dup := mw.ptrWrit[v]
if !dup {
mw.ptrWrit[v] = mw.ptrCountNext
//fmt.Printf("\n\n $$$ NOT dup write %p -> k=%v / %#v\n\n", v, mw.ptrCountNext, v)
mw.ptrCountNext++
return false, nil
} else {
//fmt.Printf("\n\n $$$ DUP write %p -> k=%v / %#v\n\n", v, k, v)
}
return true, mw.DedupWriteExt(k)
}
// write DedupExtension with k integer count
// of the pointer that is duplicated here. k is
// runtime appearance order.
func (mw *Writer) DedupWriteExt(k int) error {
var by [8]byte
kby := AppendInt(by[:0], k)
ext := RawExtension{
Data: kby,
Type: DedupExtension,
}
return mw.WriteExtension(&ext)
}
// =============================
// =============================
// Reader side
// =============================
// =============================
func (m *Reader) DedupReadExt() (int, error) {
ext := RawExtension{
Type: DedupExtension,
}
err := m.ReadExtension(&ext)
if err != nil {
return -1, err
}
var nbs NilBitsStack
k, _, err := nbs.ReadIntBytes(ext.Data)
if err != nil {
return -1, err
}
return k, nil
}
func (r *Reader) DedupReset() {
r.dedupPointers = r.dedupPointers[:0]
}
func (r *Reader) DedupPtr(k int) interface{} {
if k >= 0 && k < len(r.dedupPointers) {
return r.dedupPointers[k]
}
panic(fmt.Sprintf("Reader.DedupPtr requested for k=%v but that was out of range! (avail=%v)", k, len(r.dedupPointers)))
return nil
}
func (m *Reader) DedupIndexEachPtr(ptr interface{}) {
//fmt.Printf("\n DedupIndexEachPtr called for ptr=%p/%T/val='%#v'\n", ptr, ptr, ptr)
if ptr == nil {
return
}
va := reflect.ValueOf(ptr)
if va.IsNil() {
return
}
m.dedupPointers = append(m.dedupPointers, ptr)
//fmt.Printf("\n\n *** Reader.DedupIndexEachPtr stored ptr '%#v', as sequence k=%v\n\n", ptr, len(m.dedupPointers)-1)
}
func (m *Reader) DedupReadIsDup(field, typeTarget string) (iface interface{}, res bool) {
//fmt.Printf("\n+++ Reader.DedupReadIsDup(field:'%s', type:'%s') starting.\n", field, typeTarget)
//defer func() {
// fmt.Printf("\n^^^ Reader.DedupReadIsDup() returning res=%v\n", res)
//}()
typ, err := m.peekExtensionType()
if err != nil {
return nil, false
}
if typ != DedupExtension {
return nil, false
}
k, err := m.DedupReadExt()
if err != nil {
return nil, false
}
ptr := m.DedupPtr(k)
//fmt.Printf("\n m.DedupReadIsDup() substituting, ptr= %p b/c read k=%v\n", ptr, k)
return ptr, true
}

142
vendor/github.com/glycerine/greenpack/msgp/defs.go generated vendored Normal file
View File

@@ -0,0 +1,142 @@
// This package is the support library for the greenpack code generator (http://github.com/glycerine/greenpack).
//
// This package defines the utilites used by the greenpack code generator for encoding and decoding MessagePack
// from []byte and io.Reader/io.Writer types. Much of this package is devoted to helping the greenpack code
// generator implement the Marshaler/Unmarshaler and Encodable/Decodable interfaces.
//
// This package defines four "families" of functions:
// - AppendXxxx() appends an object to a []byte in MessagePack encoding.
// - ReadXxxxBytes() reads an object from a []byte and returns the remaining bytes.
// - (*Writer).WriteXxxx() writes an object to the buffered *Writer type.
// - (*Reader).ReadXxxx() reads an object from a buffered *Reader type.
//
// Once a type has satisfied the `Encodable` and `Decodable` interfaces,
// it can be written and read from arbitrary `io.Writer`s and `io.Reader`s using
// msgp.Encode(io.Writer, msgp.Encodable)
// and
// msgp.Decode(io.Reader, msgp.Decodable)
//
// There are also methods for converting MessagePack to JSON without
// an explicit de-serialization step.
//
// For additional tips, tricks, and gotchas, please visit
// the wiki at http://github.com/glycerine/greenpack
package msgp
const last4 = 0x0f
const first4 = 0xf0
const last5 = 0x1f
const first3 = 0xe0
const last7 = 0x7f
func isfixint(b byte) bool {
return b>>7 == 0
}
func isnfixint(b byte) bool {
return b&first3 == mnfixint
}
func isfixmap(b byte) bool {
return b&first4 == mfixmap
}
func isfixarray(b byte) bool {
return b&first4 == mfixarray
}
func isfixstr(b byte) bool {
return b&first3 == mfixstr
}
func wfixint(u uint8) byte {
return u & last7
}
func rfixint(b byte) uint8 {
return b
}
func wnfixint(i int8) byte {
return byte(i) | mnfixint
}
func rnfixint(b byte) int8 {
return int8(b)
}
func rfixmap(b byte) uint8 {
return b & last4
}
func wfixmap(u uint8) byte {
return mfixmap | (u & last4)
}
func rfixstr(b byte) uint8 {
return b & last5
}
func wfixstr(u uint8) byte {
return (u & last5) | mfixstr
}
func rfixarray(b byte) uint8 {
return (b & last4)
}
func wfixarray(u uint8) byte {
return (u & last4) | mfixarray
}
// These are all the byte
// prefixes defined by the
// msgpack standard
const (
// 0XXXXXXX
mfixint uint8 = 0x00
// 111XXXXX
mnfixint uint8 = 0xe0
// 1000XXXX
mfixmap uint8 = 0x80
// 1001XXXX
mfixarray uint8 = 0x90
// 101XXXXX
mfixstr uint8 = 0xa0
mnil uint8 = 0xc0
mfalse uint8 = 0xc2
mtrue uint8 = 0xc3
mbin8 uint8 = 0xc4
mbin16 uint8 = 0xc5
mbin32 uint8 = 0xc6
mext8 uint8 = 0xc7
mext16 uint8 = 0xc8
mext32 uint8 = 0xc9
mfloat32 uint8 = 0xca
mfloat64 uint8 = 0xcb
muint8 uint8 = 0xcc
muint16 uint8 = 0xcd
muint32 uint8 = 0xce
muint64 uint8 = 0xcf
mint8 uint8 = 0xd0
mint16 uint8 = 0xd1
mint32 uint8 = 0xd2
mint64 uint8 = 0xd3
mfixext1 uint8 = 0xd4
mfixext2 uint8 = 0xd5
mfixext4 uint8 = 0xd6
mfixext8 uint8 = 0xd7
mfixext16 uint8 = 0xd8
mstr8 uint8 = 0xd9
mstr16 uint8 = 0xda
mstr32 uint8 = 0xdb
marray16 uint8 = 0xdc
marray32 uint8 = 0xdd
mmap16 uint8 = 0xde
mmap32 uint8 = 0xdf
)

245
vendor/github.com/glycerine/greenpack/msgp/edit.go generated vendored Normal file
View File

@@ -0,0 +1,245 @@
package msgp
import (
"math"
)
// Locate returns a []byte pointing to the field
// in a messagepack map with the provided key. (The returned []byte
// points to a sub-slice of 'raw'; Locate does no allocations.) If the
// key doesn't exist in the map, a zero-length []byte will be returned.
func Locate(key string, raw []byte) []byte {
s, n := locate(raw, key)
return raw[s:n]
}
// Replace takes a key ("key") in a messagepack map ("raw")
// and replaces its value with the one provided and returns
// the new []byte. The returned []byte may point to the same
// memory as "raw". Replace makes no effort to evaluate the validity
// of the contents of 'val'. It may use up to the full capacity of 'raw.'
// Replace returns 'nil' if the field doesn't exist or if the object in 'raw'
// is not a map.
func Replace(key string, raw []byte, val []byte) []byte {
start, end := locate(raw, key)
if start == end {
return nil
}
return replace(raw, start, end, val, true)
}
// CopyReplace works similarly to Replace except that the returned
// byte slice does not point to the same memory as 'raw'. CopyReplace
// returns 'nil' if the field doesn't exist or 'raw' isn't a map.
func CopyReplace(key string, raw []byte, val []byte) []byte {
start, end := locate(raw, key)
if start == end {
return nil
}
return replace(raw, start, end, val, false)
}
// Remove removes a key-value pair from 'raw'. It returns
// 'raw' unchanged if the key didn't exist.
func Remove(key string, raw []byte) []byte {
start, end := locateKV(raw, key)
if start == end {
return raw
}
raw = raw[:start+copy(raw[start:], raw[end:])]
return resizeMap(raw, -1)
}
// HasKey returns whether the map in 'raw' has
// a field with key 'key'
func HasKey(key string, raw []byte) bool {
var nbs *NilBitsStack
sz, bts, err := nbs.ReadMapHeaderBytes(raw)
if err != nil {
return false
}
var field []byte
for i := uint32(0); i < sz; i++ {
field, bts, err = nbs.ReadStringZC(bts)
if err != nil {
return false
}
if UnsafeString(field) == key {
return true
}
}
return false
}
func replace(raw []byte, start int, end int, val []byte, inplace bool) []byte {
ll := end - start // length of segment to replace
lv := len(val)
if inplace {
extra := lv - ll
// fastest case: we're doing
// a 1:1 replacement
if extra == 0 {
copy(raw[start:], val)
return raw
} else if extra < 0 {
// 'val' smaller than replaced value
// copy in place and shift back
x := copy(raw[start:], val)
y := copy(raw[start+x:], raw[end:])
return raw[:start+x+y]
} else if extra < cap(raw)-len(raw) {
// 'val' less than (cap-len) extra bytes
// copy in place and shift forward
raw = raw[0 : len(raw)+extra]
// shift end forward
copy(raw[end+extra:], raw[end:])
copy(raw[start:], val)
return raw
}
}
// we have to allocate new space
out := make([]byte, len(raw)+len(val)-ll)
x := copy(out, raw[:start])
y := copy(out[x:], val)
copy(out[x+y:], raw[end:])
return out
}
// locate does a naive O(n) search for the map key; returns start, end
// (returns 0,0 on error)
func locate(raw []byte, key string) (start int, end int) {
var (
sz uint32
bts []byte
field []byte
err error
)
var nbs *NilBitsStack
sz, bts, err = nbs.ReadMapHeaderBytes(raw)
if err != nil {
return
}
// loop and locate field
for i := uint32(0); i < sz; i++ {
field, bts, err = nbs.ReadStringZC(bts)
if err != nil {
return 0, 0
}
if UnsafeString(field) == key {
// start location
l := len(raw)
start = l - len(bts)
bts, err = Skip(bts)
if err != nil {
return 0, 0
}
end = l - len(bts)
return
}
bts, err = Skip(bts)
if err != nil {
return 0, 0
}
}
return 0, 0
}
// locate key AND value
func locateKV(raw []byte, key string) (start int, end int) {
var nbs *NilBitsStack
var (
sz uint32
bts []byte
field []byte
err error
)
sz, bts, err = nbs.ReadMapHeaderBytes(raw)
if err != nil {
return 0, 0
}
for i := uint32(0); i < sz; i++ {
tmp := len(bts)
field, bts, err = nbs.ReadStringZC(bts)
if err != nil {
return 0, 0
}
if UnsafeString(field) == key {
start = len(raw) - tmp
bts, err = Skip(bts)
if err != nil {
return 0, 0
}
end = len(raw) - len(bts)
return
}
bts, err = Skip(bts)
if err != nil {
return 0, 0
}
}
return 0, 0
}
// delta is delta on map size
func resizeMap(raw []byte, delta int64) []byte {
var sz int64
switch raw[0] {
case mmap16:
sz = int64(big.Uint16(raw[1:]))
if sz+delta <= math.MaxUint16 {
big.PutUint16(raw[1:], uint16(sz+delta))
return raw
}
if cap(raw)-len(raw) >= 2 {
raw = raw[0 : len(raw)+2]
copy(raw[5:], raw[3:])
big.PutUint32(raw[1:], uint32(sz+delta))
return raw
}
n := make([]byte, 0, len(raw)+5)
n = AppendMapHeader(n, uint32(sz+delta))
return append(n, raw[3:]...)
case mmap32:
sz = int64(big.Uint32(raw[1:]))
big.PutUint32(raw[1:], uint32(sz+delta))
return raw
default:
sz = int64(rfixmap(raw[0]))
if sz+delta < 16 {
raw[0] = wfixmap(uint8(sz + delta))
return raw
} else if sz+delta <= math.MaxUint16 {
if cap(raw)-len(raw) >= 2 {
raw = raw[0 : len(raw)+2]
copy(raw[3:], raw[1:])
raw[0] = mmap16
big.PutUint16(raw[1:], uint16(sz+delta))
return raw
}
n := make([]byte, 0, len(raw)+5)
n = AppendMapHeader(n, uint32(sz+delta))
return append(n, raw[1:]...)
}
if cap(raw)-len(raw) >= 4 {
raw = raw[0 : len(raw)+4]
copy(raw[5:], raw[1:])
raw[0] = mmap32
big.PutUint32(raw[1:], uint32(sz+delta))
return raw
}
n := make([]byte, 0, len(raw)+5)
n = AppendMapHeader(n, uint32(sz+delta))
return append(n, raw[1:]...)
}
}

99
vendor/github.com/glycerine/greenpack/msgp/elsize.go generated vendored Normal file
View File

@@ -0,0 +1,99 @@
package msgp
// size of every object on the wire,
// plus type information. gives us
// constant-time type information
// for traversing composite objects.
//
var sizes = [256]bytespec{
mnil: {size: 1, extra: constsize, typ: NilType},
mfalse: {size: 1, extra: constsize, typ: BoolType},
mtrue: {size: 1, extra: constsize, typ: BoolType},
mbin8: {size: 2, extra: extra8, typ: BinType},
mbin16: {size: 3, extra: extra16, typ: BinType},
mbin32: {size: 5, extra: extra32, typ: BinType},
mext8: {size: 3, extra: extra8, typ: ExtensionType},
mext16: {size: 4, extra: extra16, typ: ExtensionType},
mext32: {size: 6, extra: extra32, typ: ExtensionType},
mfloat32: {size: 5, extra: constsize, typ: Float32Type},
mfloat64: {size: 9, extra: constsize, typ: Float64Type},
muint8: {size: 2, extra: constsize, typ: UintType},
muint16: {size: 3, extra: constsize, typ: UintType},
muint32: {size: 5, extra: constsize, typ: UintType},
muint64: {size: 9, extra: constsize, typ: UintType},
mint8: {size: 2, extra: constsize, typ: IntType},
mint16: {size: 3, extra: constsize, typ: IntType},
mint32: {size: 5, extra: constsize, typ: IntType},
mint64: {size: 9, extra: constsize, typ: IntType},
mfixext1: {size: 3, extra: constsize, typ: ExtensionType},
mfixext2: {size: 4, extra: constsize, typ: ExtensionType},
mfixext4: {size: 6, extra: constsize, typ: ExtensionType},
mfixext8: {size: 10, extra: constsize, typ: ExtensionType},
mfixext16: {size: 18, extra: constsize, typ: ExtensionType},
mstr8: {size: 2, extra: extra8, typ: StrType},
mstr16: {size: 3, extra: extra16, typ: StrType},
mstr32: {size: 5, extra: extra32, typ: StrType},
marray16: {size: 3, extra: array16v, typ: ArrayType},
marray32: {size: 5, extra: array32v, typ: ArrayType},
mmap16: {size: 3, extra: map16v, typ: MapType},
mmap32: {size: 5, extra: map32v, typ: MapType},
}
func init() {
// set up fixed fields
// fixint
for i := mfixint; i < 0x80; i++ {
sizes[i] = bytespec{size: 1, extra: constsize, typ: IntType}
}
// nfixint
for i := uint16(mnfixint); i < 0x100; i++ {
sizes[uint8(i)] = bytespec{size: 1, extra: constsize, typ: IntType}
}
// fixstr gets constsize,
// since the prefix yields the size
for i := mfixstr; i < 0xc0; i++ {
sizes[i] = bytespec{size: 1 + rfixstr(i), extra: constsize, typ: StrType}
}
// fixmap
for i := mfixmap; i < 0x90; i++ {
sizes[i] = bytespec{size: 1, extra: varmode(2 * rfixmap(i)), typ: MapType}
}
// fixarray
for i := mfixarray; i < 0xa0; i++ {
sizes[i] = bytespec{size: 1, extra: varmode(rfixarray(i)), typ: ArrayType}
}
}
// a valid bytespsec has
// non-zero 'size' and
// non-zero 'typ'
type bytespec struct {
size uint8 // prefix size information
extra varmode // extra size information
typ Type // type
_ byte // makes bytespec 4 bytes (yes, this matters)
}
// size mode
// if positive, # elements for composites
type varmode int8
const (
constsize varmode = 0 // constant size (size bytes + uint8(varmode) objects)
extra8 = -1 // has uint8(p[1]) extra bytes
extra16 = -2 // has be16(p[1:]) extra bytes
extra32 = -3 // has be32(p[1:]) extra bytes
map16v = -4 // use map16
map32v = -5 // use map32
array16v = -6 // use array16
array32v = -7 // use array32
)
func getType(v byte) Type {
return sizes[v].typ
}

142
vendor/github.com/glycerine/greenpack/msgp/errors.go generated vendored Normal file
View File

@@ -0,0 +1,142 @@
package msgp
import (
"fmt"
"reflect"
)
var (
// ErrShortBytes is returned when the
// slice being decoded is too short to
// contain the contents of the message
ErrShortBytes error = errShort{}
// this error is only returned
// if we reach code that should
// be unreachable
fatal error = errFatal{}
)
// Error is the interface satisfied
// by all of the errors that originate
// from this package.
type Error interface {
error
// Resumable returns whether
// or not the error means that
// the stream of data is malformed
// and the information is unrecoverable.
Resumable() bool
}
type errShort struct{}
func (e errShort) Error() string { return "msgp: too few bytes left to read object" }
func (e errShort) Resumable() bool { return false }
type errFatal struct{}
func (f errFatal) Error() string { return "msgp: fatal decoding error (unreachable code)" }
func (f errFatal) Resumable() bool { return false }
// ArrayError is an error returned
// when decoding a fix-sized array
// of the wrong size
type ArrayError struct {
Wanted uint32
Got uint32
}
// Error implements the error interface
func (a ArrayError) Error() string {
return fmt.Sprintf("msgp: wanted array of size %d; got %d", a.Wanted, a.Got)
}
// Resumable is always 'true' for ArrayErrors
func (a ArrayError) Resumable() bool { return true }
// IntOverflow is returned when a call
// would downcast an integer to a type
// with too few bits to hold its value.
type IntOverflow struct {
Value int64 // the value of the integer
FailedBitsize int // the bit size that the int64 could not fit into
}
// Error implements the error interface
func (i IntOverflow) Error() string {
return fmt.Sprintf("msgp: %d overflows int%d", i.Value, i.FailedBitsize)
}
// Resumable is always 'true' for overflows
func (i IntOverflow) Resumable() bool { return true }
// UintOverflow is returned when a call
// would downcast an unsigned integer to a type
// with too few bits to hold its value
type UintOverflow struct {
Value uint64 // value of the uint
FailedBitsize int // the bit size that couldn't fit the value
}
// Error implements the error interface
func (u UintOverflow) Error() string {
return fmt.Sprintf("msgp: %d overflows uint%d", u.Value, u.FailedBitsize)
}
// Resumable is always 'true' for overflows
func (u UintOverflow) Resumable() bool { return true }
// A TypeError is returned when a particular
// decoding method is unsuitable for decoding
// a particular MessagePack value.
type TypeError struct {
Method Type // Type expected by method
Encoded Type // Type actually encoded
}
// Error implements the error interface
func (t TypeError) Error() string {
return fmt.Sprintf("msgp: attempted to decode type %q with method for %q", t.Encoded, t.Method)
}
// Resumable returns 'true' for TypeErrors
func (t TypeError) Resumable() bool { return true }
// returns either InvalidPrefixError or
// TypeError depending on whether or not
// the prefix is recognized
func badPrefix(want Type, lead byte) error {
t := sizes[lead].typ
if t == InvalidType {
return InvalidPrefixError(lead)
}
return TypeError{Method: want, Encoded: t}
}
// InvalidPrefixError is returned when a bad encoding
// uses a prefix that is not recognized in the MessagePack standard.
// This kind of error is unrecoverable.
type InvalidPrefixError byte
// Error implements the error interface
func (i InvalidPrefixError) Error() string {
return fmt.Sprintf("msgp: unrecognized type prefix 0x%x", byte(i))
}
// Resumable returns 'false' for InvalidPrefixErrors
func (i InvalidPrefixError) Resumable() bool { return false }
// ErrUnsupportedType is returned
// when a bad argument is supplied
// to a function that takes `interface{}`.
type ErrUnsupportedType struct {
T reflect.Type
}
// Error implements error
func (e *ErrUnsupportedType) Error() string { return fmt.Sprintf("msgp: type %q not supported(4)", e.T) }
// Resumable returns 'true' for ErrUnsupportedType
func (e *ErrUnsupportedType) Resumable() bool { return true }

559
vendor/github.com/glycerine/greenpack/msgp/extension.go generated vendored Normal file
View File

@@ -0,0 +1,559 @@
package msgp
import (
"fmt"
"math"
)
const (
// Complex64Extension is the extension number used for complex64
Complex64Extension = 3
// Complex128Extension is the extension number used for complex128
Complex128Extension = 4
// TimeExtension is the extension number used for time.Time
TimeExtension = 5
// DedupExtension allows us to avoid cycles and avoid excess
// space consumption for graphs that are not strictly trees.
DedupExtension = 6
// DurationExtension is used for time.Duration
DurationExtension = 7
)
// our extensions live here
var extensionReg = make(map[int8]func() Extension)
// RegisterExtension registers extensions so that they
// can be initialized and returned by methods that
// decode `interface{}` values. This should only
// be called during initialization. f() should return
// a newly-initialized zero value of the extension. Keep in
// mind that extensions 3, 4, and 5 are reserved for
// complex64, complex128, and time.Time, respectively,
// and that MessagePack reserves extension types from -127 to -1.
//
// For example, if you wanted to register a user-defined struct:
//
// msgp.RegisterExtension(10, func() msgp.Extension { &MyExtension{} })
//
// RegisterExtension will panic if you call it multiple times
// with the same 'typ' argument, or if you use a reserved
// type (3, 4, 5, 6, 7).
func RegisterExtension(typ int8, f func() Extension) {
switch typ {
case Complex64Extension, Complex128Extension, TimeExtension, DedupExtension, DurationExtension:
panic(fmt.Sprint("msgp: forbidden extension type:", typ))
}
if _, ok := extensionReg[typ]; ok {
panic(fmt.Sprint("msgp: RegisterExtension() called with typ", typ, "more than once"))
}
extensionReg[typ] = f
}
// ExtensionTypeError is an error type returned
// when there is a mis-match between an extension type
// and the type encoded on the wire
type ExtensionTypeError struct {
Got int8
Want int8
}
// Error implements the error interface
func (e ExtensionTypeError) Error() string {
return fmt.Sprintf("msgp: error decoding extension: wanted type %d; got type %d", e.Want, e.Got)
}
// Resumable returns 'true' for ExtensionTypeErrors
func (e ExtensionTypeError) Resumable() bool { return true }
func errExt(got int8, wanted int8) error {
return ExtensionTypeError{Got: got, Want: wanted}
}
// Extension is the interface fulfilled
// by types that want to define their
// own binary encoding.
type Extension interface {
// ExtensionType should return
// a int8 that identifies the concrete
// type of the extension. (Types <0 are
// officially reserved by the MessagePack
// specifications.)
ExtensionType() int8
// Len should return the length
// of the data to be encoded
Len() int
// MarshalBinaryTo should copy
// the data into the supplied slice,
// assuming that the slice has length Len()
MarshalBinaryTo([]byte) error
UnmarshalBinary([]byte) error
}
// RawExtension implements the Extension interface
type RawExtension struct {
Data []byte
Type int8
}
// ExtensionType implements Extension.ExtensionType, and returns r.Type
func (r *RawExtension) ExtensionType() int8 { return r.Type }
// Len implements Extension.Len, and returns len(r.Data)
func (r *RawExtension) Len() int { return len(r.Data) }
// MarshalBinaryTo implements Extension.MarshalBinaryTo,
// and returns a copy of r.Data
func (r *RawExtension) MarshalBinaryTo(d []byte) error {
copy(d, r.Data)
return nil
}
// UnmarshalBinary implements Extension.UnmarshalBinary,
// and sets r.Data to the contents of the provided slice
func (r *RawExtension) UnmarshalBinary(b []byte) error {
if cap(r.Data) >= len(b) {
r.Data = r.Data[0:len(b)]
} else {
r.Data = make([]byte, len(b))
}
copy(r.Data, b)
return nil
}
// WriteExtension writes an extension type to the writer
func (mw *Writer) WriteExtension(e Extension) error {
l := e.Len()
var err error
switch l {
case 0:
o, err := mw.require(3)
if err != nil {
return err
}
mw.buf[o] = mext8
mw.buf[o+1] = 0
mw.buf[o+2] = byte(e.ExtensionType())
case 1:
o, err := mw.require(2)
if err != nil {
return err
}
mw.buf[o] = mfixext1
mw.buf[o+1] = byte(e.ExtensionType())
case 2:
o, err := mw.require(2)
if err != nil {
return err
}
mw.buf[o] = mfixext2
mw.buf[o+1] = byte(e.ExtensionType())
case 4:
o, err := mw.require(2)
if err != nil {
return err
}
mw.buf[o] = mfixext4
mw.buf[o+1] = byte(e.ExtensionType())
case 8:
o, err := mw.require(2)
if err != nil {
return err
}
mw.buf[o] = mfixext8
mw.buf[o+1] = byte(e.ExtensionType())
case 16:
o, err := mw.require(2)
if err != nil {
return err
}
mw.buf[o] = mfixext16
mw.buf[o+1] = byte(e.ExtensionType())
default:
switch {
case l < math.MaxUint8:
o, err := mw.require(3)
if err != nil {
return err
}
mw.buf[o] = mext8
mw.buf[o+1] = byte(uint8(l))
mw.buf[o+2] = byte(e.ExtensionType())
case l < math.MaxUint16:
o, err := mw.require(4)
if err != nil {
return err
}
mw.buf[o] = mext16
big.PutUint16(mw.buf[o+1:], uint16(l))
mw.buf[o+3] = byte(e.ExtensionType())
default:
o, err := mw.require(6)
if err != nil {
return err
}
mw.buf[o] = mext32
big.PutUint32(mw.buf[o+1:], uint32(l))
mw.buf[o+5] = byte(e.ExtensionType())
}
}
// we can only write directly to the
// buffer if we're sure that it
// fits the object
if l <= mw.bufsize() {
o, err := mw.require(l)
if err != nil {
return err
}
return e.MarshalBinaryTo(mw.buf[o:])
}
// here we create a new buffer
// just large enough for the body
// and save it as the write buffer
err = mw.flush()
if err != nil {
return err
}
buf := make([]byte, l)
err = e.MarshalBinaryTo(buf)
if err != nil {
return err
}
mw.buf = buf
mw.wloc = l
return nil
}
// peek at the extension type, assuming the next
// kind to be read is Extension
func (m *Reader) peekExtensionType() (int8, error) {
p, err := m.R.Peek(2)
if err != nil {
return 0, err
}
spec := sizes[p[0]]
if spec.typ != ExtensionType {
return 0, badPrefix(ExtensionType, p[0])
}
if spec.extra == constsize {
return int8(p[1]), nil
}
size := spec.size
p, err = m.R.Peek(int(size))
if err != nil {
return 0, err
}
return int8(p[size-1]), nil
}
// peekExtension peeks at the extension encoding type
// (must guarantee at least 1 byte in 'b')
func peekExtension(b []byte) (int8, error) {
spec := sizes[b[0]]
size := spec.size
if spec.typ != ExtensionType {
return 0, badPrefix(ExtensionType, b[0])
}
if len(b) < int(size) {
return 0, ErrShortBytes
}
// for fixed extensions,
// the type information is in
// the second byte
if spec.extra == constsize {
return int8(b[1]), nil
}
// otherwise, it's in the last
// part of the prefix
return int8(b[size-1]), nil
}
// ReadExtension reads the next object from the reader
// as an extension. ReadExtension will fail if the next
// object in the stream is not an extension, or if
// e.Type() is not the same as the wire type.
func (m *Reader) ReadExtension(e Extension) (err error) {
var p []byte
p, err = m.R.Peek(2)
if err != nil {
return
}
lead := p[0]
var read int
var off int
switch lead {
case mfixext1:
if int8(p[1]) != e.ExtensionType() {
err = errExt(int8(p[1]), e.ExtensionType())
return
}
p, err = m.R.Peek(3)
if err != nil {
return
}
err = e.UnmarshalBinary(p[2:])
if err == nil {
_, err = m.R.Skip(3)
}
return
case mfixext2:
if int8(p[1]) != e.ExtensionType() {
err = errExt(int8(p[1]), e.ExtensionType())
return
}
p, err = m.R.Peek(4)
if err != nil {
return
}
err = e.UnmarshalBinary(p[2:])
if err == nil {
_, err = m.R.Skip(4)
}
return
case mfixext4:
if int8(p[1]) != e.ExtensionType() {
err = errExt(int8(p[1]), e.ExtensionType())
return
}
p, err = m.R.Peek(6)
if err != nil {
return
}
err = e.UnmarshalBinary(p[2:])
if err == nil {
_, err = m.R.Skip(6)
}
return
case mfixext8:
if int8(p[1]) != e.ExtensionType() {
err = errExt(int8(p[1]), e.ExtensionType())
return
}
p, err = m.R.Peek(10)
if err != nil {
return
}
err = e.UnmarshalBinary(p[2:])
if err == nil {
_, err = m.R.Skip(10)
}
return
case mfixext16:
if int8(p[1]) != e.ExtensionType() {
err = errExt(int8(p[1]), e.ExtensionType())
return
}
p, err = m.R.Peek(18)
if err != nil {
return
}
err = e.UnmarshalBinary(p[2:])
if err == nil {
_, err = m.R.Skip(18)
}
return
case mext8:
p, err = m.R.Peek(3)
if err != nil {
return
}
if int8(p[2]) != e.ExtensionType() {
err = errExt(int8(p[2]), e.ExtensionType())
return
}
read = int(uint8(p[1]))
off = 3
case mext16:
p, err = m.R.Peek(4)
if err != nil {
return
}
if int8(p[3]) != e.ExtensionType() {
err = errExt(int8(p[3]), e.ExtensionType())
return
}
read = int(big.Uint16(p[1:]))
off = 4
case mext32:
p, err = m.R.Peek(6)
if err != nil {
return
}
if int8(p[5]) != e.ExtensionType() {
err = errExt(int8(p[5]), e.ExtensionType())
return
}
read = int(big.Uint32(p[1:]))
off = 6
default:
err = badPrefix(ExtensionType, lead)
return
}
p, err = m.R.Peek(read + off)
if err != nil {
return
}
err = e.UnmarshalBinary(p[off:])
if err == nil {
_, err = m.R.Skip(read + off)
}
return
}
// AppendExtension appends a MessagePack extension to the provided slice
func AppendExtension(b []byte, e Extension) ([]byte, error) {
l := e.Len()
var o []byte
var n int
switch l {
case 0:
o, n = ensure(b, 3)
o[n] = mext8
o[n+1] = 0
o[n+2] = byte(e.ExtensionType())
return o[:n+3], nil
case 1:
o, n = ensure(b, 3)
o[n] = mfixext1
o[n+1] = byte(e.ExtensionType())
n += 2
case 2:
o, n = ensure(b, 4)
o[n] = mfixext2
o[n+1] = byte(e.ExtensionType())
n += 2
case 4:
o, n = ensure(b, 6)
o[n] = mfixext4
o[n+1] = byte(e.ExtensionType())
n += 2
case 8:
o, n = ensure(b, 10)
o[n] = mfixext8
o[n+1] = byte(e.ExtensionType())
n += 2
case 16:
o, n = ensure(b, 18)
o[n] = mfixext16
o[n+1] = byte(e.ExtensionType())
n += 2
}
switch {
case l < math.MaxUint8:
o, n = ensure(b, l+3)
o[n] = mext8
o[n+1] = byte(uint8(l))
o[n+2] = byte(e.ExtensionType())
n += 3
case l < math.MaxUint16:
o, n = ensure(b, l+4)
o[n] = mext16
big.PutUint16(o[n+1:], uint16(l))
o[n+3] = byte(e.ExtensionType())
n += 4
default:
o, n = ensure(b, l+6)
o[n] = mext32
big.PutUint32(o[n+1:], uint32(l))
o[n+5] = byte(e.ExtensionType())
n += 6
}
return o, e.MarshalBinaryTo(o[n:])
}
// ReadExtensionBytes reads an extension from 'b' into 'e'
// and returns any remaining bytes.
// Possible errors:
// - ErrShortBytes ('b' not long enough)
// - ExtensionTypeErorr{} (wire type not the same as e.Type())
// - TypeErorr{} (next object not an extension)
// - InvalidPrefixError
// - An umarshal error returned from e.UnmarshalBinary
func (nbs *NilBitsStack) ReadExtensionBytes(b []byte, e Extension) ([]byte, error) {
if nbs != nil && nbs.AlwaysNil {
return b, nil
}
l := len(b)
if l < 3 {
return b, ErrShortBytes
}
lead := b[0]
var (
sz int // size of 'data'
off int // offset of 'data'
typ int8
)
switch lead {
case mfixext1:
typ = int8(b[1])
sz = 1
off = 2
case mfixext2:
typ = int8(b[1])
sz = 2
off = 2
case mfixext4:
typ = int8(b[1])
sz = 4
off = 2
case mfixext8:
typ = int8(b[1])
sz = 8
off = 2
case mfixext16:
typ = int8(b[1])
sz = 16
off = 2
case mext8:
sz = int(uint8(b[1]))
typ = int8(b[2])
off = 3
if sz == 0 {
return b[3:], e.UnmarshalBinary(b[3:3])
}
case mext16:
if l < 4 {
return b, ErrShortBytes
}
sz = int(big.Uint16(b[1:]))
typ = int8(b[3])
off = 4
case mext32:
if l < 6 {
return b, ErrShortBytes
}
sz = int(big.Uint32(b[1:]))
typ = int8(b[5])
off = 6
default:
return b, badPrefix(ExtensionType, lead)
}
if typ != e.ExtensionType() {
return b, errExt(typ, e.ExtensionType())
}
// the data of the extension starts
// at 'off' and is 'sz' bytes long
if len(b[off:]) < sz {
return b, ErrShortBytes
}
tot := off + sz
return b[tot:], e.UnmarshalBinary(b[off:tot])
}

91
vendor/github.com/glycerine/greenpack/msgp/file.go generated vendored Normal file
View File

@@ -0,0 +1,91 @@
// +build linux,!appengine darwin dragonfly freebsd netbsd openbsd
package msgp
import (
"os"
"syscall"
)
// ReadFile reads a file into 'dst' using
// a read-only memory mapping. Consequently,
// the file must be mmap-able, and the
// Unmarshaler should never write to
// the source memory. (Methods generated
// by the msgp tool obey that constraint, but
// user-defined implementations may not.)
//
// Reading and writing through file mappings
// is only efficient for large files; small
// files are best read and written using
// the ordinary streaming interfaces.
//
func ReadFile(dst Unmarshaler, file *os.File) error {
stat, err := file.Stat()
if err != nil {
return err
}
data, err := syscall.Mmap(int(file.Fd()), 0, int(stat.Size()), syscall.PROT_READ, syscall.MAP_SHARED)
if err != nil {
return err
}
adviseRead(data)
_, err = dst.UnmarshalMsg(data)
uerr := syscall.Munmap(data)
if err == nil {
err = uerr
}
return err
}
// MarshalSizer is the combination
// of the Marshaler and Sizer
// interfaces.
type MarshalSizer interface {
Marshaler
Sizer
}
// WriteFile writes a file from 'src' using
// memory mapping. It overwrites the entire
// contents of the previous file.
// The mapping size is calculated
// using the `Msgsize()` method
// of 'src', so it must produce a result
// equal to or greater than the actual encoded
// size of the object. Otherwise,
// a fault (SIGBUS) will occur.
//
// Reading and writing through file mappings
// is only efficient for large files; small
// files are best read and written using
// the ordinary streaming interfaces.
//
// NOTE: The performance of this call
// is highly OS- and filesystem-dependent.
// Users should take care to test that this
// performs as expected in a production environment.
// (Linux users should run a kernel and filesystem
// that support fallocate(2) for the best results.)
func WriteFile(src MarshalSizer, file *os.File) error {
sz := src.Msgsize()
err := fallocate(file, int64(sz))
if err != nil {
return err
}
data, err := syscall.Mmap(int(file.Fd()), 0, sz, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
if err != nil {
return err
}
adviseWrite(data)
chunk := data[:0]
chunk, err = src.MarshalMsg(chunk)
if err != nil {
return err
}
uerr := syscall.Munmap(data)
if uerr != nil {
return uerr
}
return file.Truncate(int64(len(chunk)))
}

View File

@@ -0,0 +1,47 @@
// +build windows appengine
package msgp
import (
"io/ioutil"
"os"
)
// MarshalSizer is the combination
// of the Marshaler and Sizer
// interfaces.
type MarshalSizer interface {
Marshaler
Sizer
}
func ReadFile(dst Unmarshaler, file *os.File) error {
if u, ok := dst.(Decodable); ok {
return u.DecodeMsg(NewReader(file))
}
data, err := ioutil.ReadAll(file)
if err != nil {
return err
}
_, err = dst.UnmarshalMsg(data)
return err
}
func WriteFile(src MarshalSizer, file *os.File) error {
if e, ok := src.(Encodable); ok {
w := NewWriter(file)
err := e.EncodeMsg(w)
if err == nil {
err = w.Flush()
}
return err
}
raw, err := src.MarshalMsg(nil)
if err != nil {
return err
}
_, err = file.Write(raw)
return err
}

174
vendor/github.com/glycerine/greenpack/msgp/integers.go generated vendored Normal file
View File

@@ -0,0 +1,174 @@
package msgp
/* ----------------------------------
integer encoding utilities
(inline-able)
TODO(tinylib): there are faster,
albeit non-portable solutions
to the code below. implement
byteswap?
---------------------------------- */
func putMint64(b []byte, i int64) {
b[0] = mint64
b[1] = byte(i >> 56)
b[2] = byte(i >> 48)
b[3] = byte(i >> 40)
b[4] = byte(i >> 32)
b[5] = byte(i >> 24)
b[6] = byte(i >> 16)
b[7] = byte(i >> 8)
b[8] = byte(i)
}
func getMint64(b []byte) int64 {
return (int64(b[1]) << 56) | (int64(b[2]) << 48) |
(int64(b[3]) << 40) | (int64(b[4]) << 32) |
(int64(b[5]) << 24) | (int64(b[6]) << 16) |
(int64(b[7]) << 8) | (int64(b[8]))
}
func putMint32(b []byte, i int32) {
b[0] = mint32
b[1] = byte(i >> 24)
b[2] = byte(i >> 16)
b[3] = byte(i >> 8)
b[4] = byte(i)
}
func getMint32(b []byte) int32 {
return (int32(b[1]) << 24) | (int32(b[2]) << 16) | (int32(b[3]) << 8) | (int32(b[4]))
}
func putMint16(b []byte, i int16) {
b[0] = mint16
b[1] = byte(i >> 8)
b[2] = byte(i)
}
func getMint16(b []byte) (i int16) {
return (int16(b[1]) << 8) | int16(b[2])
}
func putMint8(b []byte, i int8) {
b[0] = mint8
b[1] = byte(i)
}
func getMint8(b []byte) (i int8) {
return int8(b[1])
}
func putMuint64(b []byte, u uint64) {
b[0] = muint64
b[1] = byte(u >> 56)
b[2] = byte(u >> 48)
b[3] = byte(u >> 40)
b[4] = byte(u >> 32)
b[5] = byte(u >> 24)
b[6] = byte(u >> 16)
b[7] = byte(u >> 8)
b[8] = byte(u)
}
func getMuint64(b []byte) uint64 {
return (uint64(b[1]) << 56) | (uint64(b[2]) << 48) |
(uint64(b[3]) << 40) | (uint64(b[4]) << 32) |
(uint64(b[5]) << 24) | (uint64(b[6]) << 16) |
(uint64(b[7]) << 8) | (uint64(b[8]))
}
func putMuint32(b []byte, u uint32) {
b[0] = muint32
b[1] = byte(u >> 24)
b[2] = byte(u >> 16)
b[3] = byte(u >> 8)
b[4] = byte(u)
}
func getMuint32(b []byte) uint32 {
return (uint32(b[1]) << 24) | (uint32(b[2]) << 16) | (uint32(b[3]) << 8) | (uint32(b[4]))
}
func putMuint16(b []byte, u uint16) {
b[0] = muint16
b[1] = byte(u >> 8)
b[2] = byte(u)
}
func getMuint16(b []byte) uint16 {
return (uint16(b[1]) << 8) | uint16(b[2])
}
func putMuint8(b []byte, u uint8) {
b[0] = muint8
b[1] = byte(u)
}
func getMuint8(b []byte) uint8 {
return uint8(b[1])
}
func getUnix(b []byte) (sec int64, nsec int32) {
sec = (int64(b[0]) << 56) | (int64(b[1]) << 48) |
(int64(b[2]) << 40) | (int64(b[3]) << 32) |
(int64(b[4]) << 24) | (int64(b[5]) << 16) |
(int64(b[6]) << 8) | (int64(b[7]))
nsec = (int32(b[8]) << 24) | (int32(b[9]) << 16) | (int32(b[10]) << 8) | (int32(b[11]))
return
}
func putUnix(b []byte, sec int64, nsec int32) {
b[0] = byte(sec >> 56)
b[1] = byte(sec >> 48)
b[2] = byte(sec >> 40)
b[3] = byte(sec >> 32)
b[4] = byte(sec >> 24)
b[5] = byte(sec >> 16)
b[6] = byte(sec >> 8)
b[7] = byte(sec)
b[8] = byte(nsec >> 24)
b[9] = byte(nsec >> 16)
b[10] = byte(nsec >> 8)
b[11] = byte(nsec)
}
/* -----------------------------
prefix utilities
----------------------------- */
// write prefix and uint8
func prefixu8(b []byte, pre byte, sz uint8) {
b[0] = pre
b[1] = byte(sz)
}
// write prefix and big-endian uint16
func prefixu16(b []byte, pre byte, sz uint16) {
b[0] = pre
b[1] = byte(sz >> 8)
b[2] = byte(sz)
}
// write prefix and big-endian uint32
func prefixu32(b []byte, pre byte, sz uint32) {
b[0] = pre
b[1] = byte(sz >> 24)
b[2] = byte(sz >> 16)
b[3] = byte(sz >> 8)
b[4] = byte(sz)
}
func prefixu64(b []byte, pre byte, sz uint64) {
b[0] = pre
b[1] = byte(sz >> 56)
b[2] = byte(sz >> 48)
b[3] = byte(sz >> 40)
b[4] = byte(sz >> 32)
b[5] = byte(sz >> 24)
b[6] = byte(sz >> 16)
b[7] = byte(sz >> 8)
b[8] = byte(sz)
}

555
vendor/github.com/glycerine/greenpack/msgp/json.go generated vendored Normal file
View File

@@ -0,0 +1,555 @@
package msgp
import (
"bufio"
"encoding/base64"
"encoding/json"
"io"
"strconv"
"unicode/utf8"
)
var (
null = []byte("null")
hex = []byte("0123456789abcdef")
)
var defuns [_maxtype]func(jsWriter, *Reader) (int, error)
// note: there is an initialization loop if
// this isn't set up during init()
func init() {
// since none of these functions are inline-able,
// there is not much of a penalty to the indirect
// call. however, this is best expressed as a jump-table...
defuns = [_maxtype]func(jsWriter, *Reader) (int, error){
StrType: rwString,
BinType: rwBytes,
MapType: rwMap,
ArrayType: rwArray,
Float64Type: rwFloat64,
Float32Type: rwFloat32,
BoolType: rwBool,
IntType: rwInt,
UintType: rwUint,
NilType: rwNil,
ExtensionType: rwExtension,
Complex64Type: rwExtension,
Complex128Type: rwExtension,
TimeType: rwTime,
DurationType: rwDuration,
}
}
// this is the interface
// used to write json
type jsWriter interface {
io.Writer
io.ByteWriter
WriteString(string) (int, error)
}
// CopyToJSON reads MessagePack from 'src' and copies it
// as JSON to 'dst' until EOF.
func CopyToJSON(dst io.Writer, src io.Reader) (n int64, err error) {
r := NewReader(src)
n, err = r.WriteToJSON(dst)
freeR(r)
return
}
// WriteToJSON translates MessagePack from 'r' and writes it as
// JSON to 'w' until the underlying reader returns io.EOF. It returns
// the number of bytes written, and an error if it stopped before EOF.
func (r *Reader) WriteToJSON(w io.Writer) (n int64, err error) {
var j jsWriter
var bf *bufio.Writer
if jsw, ok := w.(jsWriter); ok {
j = jsw
} else {
bf = bufio.NewWriter(w)
j = bf
}
var nn int
for err == nil {
nn, err = rwNext(j, r)
n += int64(nn)
}
if err != io.EOF {
if bf != nil {
bf.Flush()
}
return
}
err = nil
if bf != nil {
err = bf.Flush()
}
return
}
func rwNext(w jsWriter, src *Reader) (int, error) {
t, err := src.NextType()
if err != nil {
return 0, err
}
return defuns[t](w, src)
}
func rwMap(dst jsWriter, src *Reader) (n int, err error) {
var comma bool
var sz uint32
var field []byte
sz, err = src.ReadMapHeader()
if err != nil {
return
}
if sz == 0 {
return dst.WriteString("{}")
}
err = dst.WriteByte('{')
if err != nil {
return
}
n++
var nn int
for i := uint32(0); i < sz; i++ {
if comma {
err = dst.WriteByte(',')
if err != nil {
return
}
n++
}
field, err = src.ReadMapKeyPtr()
if err != nil {
return
}
nn, err = rwquoted(dst, field)
n += nn
if err != nil {
return
}
err = dst.WriteByte(':')
if err != nil {
return
}
n++
nn, err = rwNext(dst, src)
n += nn
if err != nil {
return
}
if !comma {
comma = true
}
}
err = dst.WriteByte('}')
if err != nil {
return
}
n++
return
}
func rwArray(dst jsWriter, src *Reader) (n int, err error) {
err = dst.WriteByte('[')
if err != nil {
return
}
var sz uint32
var nn int
sz, err = src.ReadArrayHeader()
if err != nil {
return
}
comma := false
for i := uint32(0); i < sz; i++ {
if comma {
err = dst.WriteByte(',')
if err != nil {
return
}
n++
}
nn, err = rwNext(dst, src)
n += nn
if err != nil {
return
}
comma = true
}
err = dst.WriteByte(']')
if err != nil {
return
}
n++
return
}
func rwNil(dst jsWriter, src *Reader) (int, error) {
err := src.ReadNil()
if err != nil {
return 0, err
}
return dst.Write(null)
}
func rwFloat32(dst jsWriter, src *Reader) (int, error) {
f, err := src.ReadFloat32()
if err != nil {
return 0, err
}
src.scratch = strconv.AppendFloat(src.scratch[:0], float64(f), 'f', -1, 64)
return dst.Write(src.scratch)
}
func rwFloat64(dst jsWriter, src *Reader) (int, error) {
f, err := src.ReadFloat64()
if err != nil {
return 0, err
}
src.scratch = strconv.AppendFloat(src.scratch[:0], f, 'f', -1, 32)
return dst.Write(src.scratch)
}
func rwInt(dst jsWriter, src *Reader) (int, error) {
i, err := src.ReadInt64()
if err != nil {
return 0, err
}
src.scratch = strconv.AppendInt(src.scratch[:0], i, 10)
return dst.Write(src.scratch)
}
func rwUint(dst jsWriter, src *Reader) (int, error) {
u, err := src.ReadUint64()
if err != nil {
return 0, err
}
src.scratch = strconv.AppendUint(src.scratch[:0], u, 10)
return dst.Write(src.scratch)
}
func rwBool(dst jsWriter, src *Reader) (int, error) {
b, err := src.ReadBool()
if err != nil {
return 0, err
}
if b {
return dst.WriteString("true")
}
return dst.WriteString("false")
}
func rwTime(dst jsWriter, src *Reader) (int, error) {
t, err := src.ReadTime()
if err != nil {
return 0, err
}
bts, err := t.MarshalJSON()
if err != nil {
return 0, err
}
return dst.Write(bts)
}
func rwDuration(dst jsWriter, src *Reader) (int, error) {
dur, err := src.ReadDuration()
if err != nil {
return 0, err
}
bts, err := durationMarshalJSON(dur)
if err != nil {
return 0, err
}
return dst.Write(bts)
}
func rwExtension(dst jsWriter, src *Reader) (n int, err error) {
et, err := src.peekExtensionType()
if err != nil {
return 0, err
}
// registered extensions can override
// the JSON encoding
if j, ok := extensionReg[et]; ok {
var bts []byte
e := j()
err = src.ReadExtension(e)
if err != nil {
return
}
bts, err = json.Marshal(e)
if err != nil {
return
}
return dst.Write(bts)
}
e := RawExtension{}
e.Type = et
err = src.ReadExtension(&e)
if err != nil {
return
}
var nn int
err = dst.WriteByte('{')
if err != nil {
return
}
n++
nn, err = dst.WriteString(`"type:"`)
n += nn
if err != nil {
return
}
src.scratch = strconv.AppendInt(src.scratch[0:0], int64(e.Type), 10)
nn, err = dst.Write(src.scratch)
n += nn
if err != nil {
return
}
nn, err = dst.WriteString(`,"data":"`)
n += nn
if err != nil {
return
}
enc := base64.NewEncoder(base64.StdEncoding, dst)
nn, err = enc.Write(e.Data)
n += nn
if err != nil {
return
}
err = enc.Close()
if err != nil {
return
}
nn, err = dst.WriteString(`"}`)
n += nn
return
}
func rwString(dst jsWriter, src *Reader) (n int, err error) {
var p []byte
p, err = src.R.Peek(1)
if err != nil {
return
}
lead := p[0]
var read int
if isfixstr(lead) {
read = int(rfixstr(lead))
src.R.Skip(1)
goto write
}
switch lead {
case mstr8:
p, err = src.R.Next(2)
if err != nil {
return
}
read = int(uint8(p[1]))
case mstr16:
p, err = src.R.Next(3)
if err != nil {
return
}
read = int(big.Uint16(p[1:]))
case mstr32:
p, err = src.R.Next(5)
if err != nil {
return
}
read = int(big.Uint32(p[1:]))
default:
err = badPrefix(StrType, lead)
return
}
write:
p, err = src.R.Next(read)
if err != nil {
return
}
n, err = rwquoted(dst, p)
return
}
func rwBytes(dst jsWriter, src *Reader) (n int, err error) {
var nn int
err = dst.WriteByte('"')
if err != nil {
return
}
n++
src.scratch, err = src.ReadBytes(src.scratch[:0])
if err != nil {
return
}
enc := base64.NewEncoder(base64.StdEncoding, dst)
nn, err = enc.Write(src.scratch)
n += nn
if err != nil {
return
}
err = enc.Close()
if err != nil {
return
}
err = dst.WriteByte('"')
if err != nil {
return
}
n++
return
}
// Below (c) The Go Authors, 2009-2014
// Subject to the BSD-style license found at http://golang.org
//
// see: encoding/json/encode.go:(*encodeState).stringbytes()
func rwquoted(dst jsWriter, s []byte) (n int, err error) {
var nn int
err = dst.WriteByte('"')
if err != nil {
return
}
n++
start := 0
for i := 0; i < len(s); {
if b := s[i]; b < utf8.RuneSelf {
if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' && b != '&' {
i++
continue
}
if start < i {
nn, err = dst.Write(s[start:i])
n += nn
if err != nil {
return
}
}
switch b {
case '\\', '"':
err = dst.WriteByte('\\')
if err != nil {
return
}
n++
err = dst.WriteByte(b)
if err != nil {
return
}
n++
case '\n':
err = dst.WriteByte('\\')
if err != nil {
return
}
n++
err = dst.WriteByte('n')
if err != nil {
return
}
n++
case '\r':
err = dst.WriteByte('\\')
if err != nil {
return
}
n++
err = dst.WriteByte('r')
if err != nil {
return
}
n++
default:
nn, err = dst.WriteString(`\u00`)
n += nn
if err != nil {
return
}
err = dst.WriteByte(hex[b>>4])
if err != nil {
return
}
n++
err = dst.WriteByte(hex[b&0xF])
if err != nil {
return
}
n++
}
i++
start = i
continue
}
c, size := utf8.DecodeRune(s[i:])
if c == utf8.RuneError && size == 1 {
if start < i {
nn, err = dst.Write(s[start:i])
n += nn
if err != nil {
return
}
nn, err = dst.WriteString(`\ufffd`)
n += nn
if err != nil {
return
}
i += size
start = i
continue
}
}
if c == '\u2028' || c == '\u2029' {
if start < i {
nn, err = dst.Write(s[start:i])
n += nn
if err != nil {
return
}
nn, err = dst.WriteString(`\u202`)
n += nn
if err != nil {
return
}
err = dst.WriteByte(hex[c&0xF])
if err != nil {
return
}
n++
}
}
i += size
}
if start < len(s) {
nn, err = dst.Write(s[start:])
n += nn
if err != nil {
return
}
}
err = dst.WriteByte('"')
if err != nil {
return
}
n++
return
}

View File

@@ -0,0 +1,416 @@
package msgp
import (
"bufio"
"bytes"
"encoding/base64"
"encoding/json"
"io"
"strconv"
"time"
)
var unfuns [_maxtype]func(jsWriter, []byte, []byte) ([]byte, []byte, error)
func init() {
// NOTE(pmh): this is best expressed as a jump table,
// but gc doesn't do that yet. revisit post-go1.5.
unfuns = [_maxtype]func(jsWriter, []byte, []byte) ([]byte, []byte, error){
StrType: rwStringBytes,
BinType: rwBytesBytes,
MapType: rwMapBytes,
ArrayType: rwArrayBytes,
Float64Type: rwFloat64Bytes,
Float32Type: rwFloat32Bytes,
BoolType: rwBoolBytes,
IntType: rwIntBytes,
UintType: rwUintBytes,
NilType: rwNullBytes,
ExtensionType: rwExtensionBytes,
Complex64Type: rwExtensionBytes,
Complex128Type: rwExtensionBytes,
TimeType: rwTimeBytes,
}
}
// UnmarshalAsJSON takes raw messagepack and writes
// it as JSON to 'w'. If an error is returned, the
// bytes not translated will also be returned. If
// no errors are encountered, the length of the returned
// slice will be zero.
func UnmarshalAsJSON(w io.Writer, msg []byte) ([]byte, error) {
var (
scratch []byte
cast bool
dst jsWriter
err error
)
if jsw, ok := w.(jsWriter); ok {
dst = jsw
cast = true
} else {
dst = bufio.NewWriterSize(w, 512)
}
for len(msg) > 0 && err == nil {
msg, scratch, err = writeNext(dst, msg, scratch)
}
if !cast && err == nil {
err = dst.(*bufio.Writer).Flush()
}
return msg, err
}
func writeNext(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
if len(msg) < 1 {
return msg, scratch, ErrShortBytes
}
t := getType(msg[0])
if t == InvalidType {
return msg, scratch, InvalidPrefixError(msg[0])
}
if t == ExtensionType {
et, err := peekExtension(msg)
if err != nil {
return nil, scratch, err
}
if et == TimeExtension {
t = TimeType
} else if et == DurationExtension {
t = DurationType
}
}
return unfuns[t](w, msg, scratch)
}
func rwArrayBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
var nbs *NilBitsStack
sz, msg, err := nbs.ReadArrayHeaderBytes(msg)
if err != nil {
return msg, scratch, err
}
err = w.WriteByte('[')
if err != nil {
return msg, scratch, err
}
for i := uint32(0); i < sz; i++ {
if i != 0 {
err = w.WriteByte(',')
if err != nil {
return msg, scratch, err
}
}
msg, scratch, err = writeNext(w, msg, scratch)
if err != nil {
return msg, scratch, err
}
}
err = w.WriteByte(']')
return msg, scratch, err
}
func rwMapBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
var nbs *NilBitsStack
sz, msg, err := nbs.ReadMapHeaderBytes(msg)
if err != nil {
return msg, scratch, err
}
err = w.WriteByte('{')
if err != nil {
return msg, scratch, err
}
for i := uint32(0); i < sz; i++ {
if i != 0 {
err = w.WriteByte(',')
if err != nil {
return msg, scratch, err
}
}
msg, scratch, err = rwMapKeyBytes(w, msg, scratch)
if err != nil {
return msg, scratch, err
}
err = w.WriteByte(':')
if err != nil {
return msg, scratch, err
}
msg, scratch, err = writeNext(w, msg, scratch)
if err != nil {
return msg, scratch, err
}
}
err = w.WriteByte('}')
return msg, scratch, err
}
func rwMapKeyBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
msg, scratch, err := rwStringBytes(w, msg, scratch)
if err != nil {
if tperr, ok := err.(TypeError); ok && tperr.Encoded == BinType {
return rwBytesBytes(w, msg, scratch)
}
}
return msg, scratch, err
}
func rwStringBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
var nbs *NilBitsStack
str, msg, err := nbs.ReadStringZC(msg)
if err != nil {
return msg, scratch, err
}
_, err = rwquoted(w, str)
return msg, scratch, err
}
func rwBytesBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
var nbs *NilBitsStack
bts, msg, err := nbs.ReadBytesZC(msg)
if err != nil {
return msg, scratch, err
}
l := base64.StdEncoding.EncodedLen(len(bts))
if cap(scratch) >= l {
scratch = scratch[0:l]
} else {
scratch = make([]byte, l)
}
base64.StdEncoding.Encode(scratch, bts)
err = w.WriteByte('"')
if err != nil {
return msg, scratch, err
}
_, err = w.Write(scratch)
if err != nil {
return msg, scratch, err
}
err = w.WriteByte('"')
return msg, scratch, err
}
func rwNullBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
var nbs *NilBitsStack
msg, err := nbs.ReadNilBytes(msg)
if err != nil {
return msg, scratch, err
}
_, err = w.Write(null)
return msg, scratch, err
}
func rwBoolBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
var nbs *NilBitsStack
b, msg, err := nbs.ReadBoolBytes(msg)
if err != nil {
return msg, scratch, err
}
if b {
_, err = w.WriteString("true")
return msg, scratch, err
}
_, err = w.WriteString("false")
return msg, scratch, err
}
func rwIntBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
var nbs *NilBitsStack
i, msg, err := nbs.ReadInt64Bytes(msg)
if err != nil {
return msg, scratch, err
}
scratch = strconv.AppendInt(scratch[0:0], i, 10)
_, err = w.Write(scratch)
return msg, scratch, err
}
func rwUintBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
var nbs *NilBitsStack
u, msg, err := nbs.ReadUint64Bytes(msg)
if err != nil {
return msg, scratch, err
}
scratch = strconv.AppendUint(scratch[0:0], u, 10)
_, err = w.Write(scratch)
return msg, scratch, err
}
func rwFloatBytes(w jsWriter, msg []byte, f64 bool, scratch []byte) ([]byte, []byte, error) {
var nbs *NilBitsStack
var f float64
var err error
var sz int
if f64 {
sz = 64
f, msg, err = nbs.ReadFloat64Bytes(msg)
} else {
sz = 32
var v float32
v, msg, err = nbs.ReadFloat32Bytes(msg)
f = float64(v)
}
if err != nil {
return msg, scratch, err
}
scratch = strconv.AppendFloat(scratch, f, 'f', -1, sz)
_, err = w.Write(scratch)
return msg, scratch, err
}
func rwFloat32Bytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
var nbs *NilBitsStack
var f float32
var err error
f, msg, err = nbs.ReadFloat32Bytes(msg)
if err != nil {
return msg, scratch, err
}
scratch = strconv.AppendFloat(scratch[:0], float64(f), 'f', -1, 32)
_, err = w.Write(scratch)
return msg, scratch, err
}
func rwFloat64Bytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
var nbs *NilBitsStack
var f float64
var err error
f, msg, err = nbs.ReadFloat64Bytes(msg)
if err != nil {
return msg, scratch, err
}
scratch = strconv.AppendFloat(scratch[:0], f, 'f', -1, 64)
_, err = w.Write(scratch)
return msg, scratch, err
}
func rwTimeBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
var nbs *NilBitsStack
var t time.Time
var err error
t, msg, err = nbs.ReadTimeBytes(msg)
if err != nil {
return msg, scratch, err
}
bts, err := t.MarshalJSON()
if err != nil {
return msg, scratch, err
}
_, err = w.Write(bts)
return msg, scratch, err
}
func rwExtensionBytes(w jsWriter, msg []byte, scratch []byte) ([]byte, []byte, error) {
var nbs *NilBitsStack
var err error
var et int8
et, err = peekExtension(msg)
if err != nil {
return msg, scratch, err
}
// if it's time.Time
if et == TimeExtension {
var tm time.Time
tm, msg, err = nbs.ReadTimeBytes(msg)
if err != nil {
return msg, scratch, err
}
bts, err := tm.MarshalJSON()
if err != nil {
return msg, scratch, err
}
_, err = w.Write(bts)
return msg, scratch, err
} else if et == DurationExtension {
var dur time.Duration
dur, msg, err = nbs.ReadDurationBytes(msg)
if err != nil {
return msg, scratch, err
}
_, err := w.WriteString(`{"time.Duration":`)
if err != nil {
return msg, scratch, err
}
scratch = strconv.AppendInt(scratch[0:0], int64(dur), 10)
_, err = w.Write(scratch)
if err != nil {
return msg, scratch, err
}
_, err = w.WriteString(`}`)
return msg, scratch, err
}
// if the extension is registered,
// use its canonical JSON form
if f, ok := extensionReg[et]; ok {
e := f()
msg, err = nbs.ReadExtensionBytes(msg, e)
if err != nil {
return msg, scratch, err
}
bts, err := json.Marshal(e)
if err != nil {
return msg, scratch, err
}
_, err = w.Write(bts)
return msg, scratch, err
}
// otherwise, write `{"type": <num>, "data": "<base64data>"}`
r := RawExtension{}
r.Type = et
msg, err = nbs.ReadExtensionBytes(msg, &r)
if err != nil {
return msg, scratch, err
}
scratch, err = writeExt(w, r, scratch)
return msg, scratch, err
}
func durationMarshalJSON(dur time.Duration) ([]byte, error) {
var w bytes.Buffer
_, err := w.WriteString(`{"time.Duration":`)
if err != nil {
return nil, err
}
scratch := make([]byte, 32)
scratch = strconv.AppendInt(scratch[0:0], int64(dur), 10)
_, err = w.Write(scratch)
if err != nil {
return nil, err
}
_, err = w.WriteString(`}`)
return w.Bytes(), err
}
func writeExt(w jsWriter, r RawExtension, scratch []byte) ([]byte, error) {
_, err := w.WriteString(`{"type":`)
if err != nil {
return scratch, err
}
scratch = strconv.AppendInt(scratch[0:0], int64(r.Type), 10)
_, err = w.Write(scratch)
if err != nil {
return scratch, err
}
_, err = w.WriteString(`,"data":"`)
if err != nil {
return scratch, err
}
l := base64.StdEncoding.EncodedLen(len(r.Data))
if cap(scratch) >= l {
scratch = scratch[0:l]
} else {
scratch = make([]byte, l)
}
base64.StdEncoding.Encode(scratch, r.Data)
_, err = w.Write(scratch)
if err != nil {
return scratch, err
}
_, err = w.WriteString(`"}`)
return scratch, err
}

126
vendor/github.com/glycerine/greenpack/msgp/nilbits.go generated vendored Normal file
View File

@@ -0,0 +1,126 @@
package msgp
import (
"fmt"
//"runtime/debug"
)
const MaxNestedStructPointerDepth = 8
// NilBitsStack is a helper for Unmarshal
// methods to track where we are when
// deserializing from empty/nil/missing
// fields.
type NilBitsStack struct {
// simulate getting nils on the wire
AlwaysNil bool
LifoAlwaysNil int // this lifo always had false in it, so change it to a count.
LifoBts [MaxNestedStructPointerDepth][]byte // caps our static tree depth at 8, but avoids all memory allocation during the decode hotpath.
// UnsafeZeroCopy will make strings point to the
// original msgpack buffers. This is unsafe because
// if the buffer changes the string will change/be
// invalid/not protected against re-use. But for
// processing and disposing of single messages, one-at-at-time,
// without re-using any part of a message (or making a copy of strings explicitly with copy()
// if you must) then we can avoid all allocations for strings.
UnsafeZeroCopy bool
}
func (r *NilBitsStack) Init(cfg *RuntimeConfig) {
if cfg != nil {
r.UnsafeZeroCopy = cfg.UnsafeZeroCopy
}
}
func (r *NilBitsStack) IsNil(bts []byte) bool {
if r.AlwaysNil {
return true
}
if len(bts) != 0 && bts[0] == mnil {
return true
}
return false
}
// OnlyNilSlice is a slice that contains
// only the msgpack nil (0xc0) bytes.
var OnlyNilSlice = []byte{mnil}
// AlwaysNilString returns a string representation
// of the internal state of the NilBitsStack for
// debugging purposes.
func (r *NilBitsStack) AlwaysNilString() string {
s := "bottom: "
for i := 0; i > r.LifoAlwaysNil; i++ {
s += "T"
}
/* for _, v := range r.LifoAlwaysNil {
if v {
s += "T"
} else {
s += "f"
}
}
*/
return s
}
// PushAlwaysNil will set r.AlwaysNil to true
// and store bts on the internal stack.
func (r *NilBitsStack) PushAlwaysNil(bts []byte) []byte {
//fmt.Printf("PushAlwaysNil(), pre we are '%v'. Called from: stack is '%v'\n", r.AlwaysNilString(), string(debug.Stack()))
// save current state
if r.LifoAlwaysNil == MaxNestedStructPointerDepth {
panic(fmt.Sprintf("we hit our maximum nested struct-inside-struct depth! you must recompile msgp with github.com/glycerine/greenpack/msgp/nilbits.go: MaxNestedStructPointerDepth set to greater than the current value of %v, and then regenerate your msgp Unmarshaling code.", MaxNestedStructPointerDepth))
}
r.LifoBts[r.LifoAlwaysNil] = bts
r.LifoAlwaysNil++
// set reader r to always return nils
r.AlwaysNil = true
return OnlyNilSlice
}
// PopAlwaysNil pops the last []byte off the internal
// stack and returns it. If the stack is empty
// we panic.
func (r *NilBitsStack) PopAlwaysNil() (bts []byte) {
//fmt.Printf("my NilBitsTack.PopAlwaysNil() called!! ... stack is '%v'\n", string(debug.Stack()))
// defer func() {
// fmt.Printf("len of bts returned by PopAlwaysNil: %v, and debug string: '%v'\n",
// len(bts), r.AlwaysNilString())
// }()
n := r.LifoAlwaysNil
if n == 0 {
panic("PopAlwaysNil called on empty lifo")
}
if n < 0 {
panic("PopAlwaysNil called on illegal-less-thab-empty lifo")
}
bts = r.LifoBts[n-1]
r.LifoAlwaysNil--
if r.LifoAlwaysNil == 0 {
r.AlwaysNil = false
}
return bts
}
func ShowFound(found []bool) string {
s := "["
for i := range found {
if found[i] {
s += "1,"
} else {
s += "0,"
}
}
s += "]"
return s
}

268
vendor/github.com/glycerine/greenpack/msgp/number.go generated vendored Normal file
View File

@@ -0,0 +1,268 @@
package msgp
import (
"math"
"strconv"
)
// The portable parts of the Number implementation
// Number can be
// an int64, uint64, float32,
// or float64 internally.
// It can decode itself
// from any of the native
// messagepack number types.
// The zero-value of Number
// is Int(0). Using the equality
// operator with Number compares
// both the type and the value
// of the number.
type Number struct {
// internally, this
// is just a tagged union.
// the raw bits of the number
// are stored the same way regardless.
bits uint64
typ Type
}
// AsInt sets the number to an int64.
func (n *Number) AsInt(i int64) {
// we always store int(0)
// as {0, InvalidType} in
// order to preserve
// the behavior of the == operator
if i == 0 {
n.typ = InvalidType
n.bits = 0
return
}
n.typ = IntType
n.bits = uint64(i)
}
// AsUint sets the number to a uint64.
func (n *Number) AsUint(u uint64) {
n.typ = UintType
n.bits = u
}
// AsFloat32 sets the value of the number
// to a float32.
func (n *Number) AsFloat32(f float32) {
n.typ = Float32Type
n.bits = uint64(math.Float32bits(f))
}
// AsFloat64 sets the value of the
// number to a float64.
func (n *Number) AsFloat64(f float64) {
n.typ = Float64Type
n.bits = math.Float64bits(f)
}
// Int casts the number as an int64, and
// returns whether or not that was the
// underlying type.
func (n *Number) Int() (int64, bool) {
return int64(n.bits), n.typ == IntType || n.typ == InvalidType
}
// Uint casts the number as a uint64, and returns
// whether or not that was the underlying type.
func (n *Number) Uint() (uint64, bool) {
return n.bits, n.typ == UintType
}
// Float casts the number to a float64, and
// returns whether or not that was the underlying
// type (either a float64 or a float32).
func (n *Number) Float() (float64, bool) {
switch n.typ {
case Float32Type:
return float64(math.Float32frombits(uint32(n.bits))), true
case Float64Type:
return math.Float64frombits(n.bits), true
default:
return 0.0, false
}
}
// Type will return one of:
// Float64Type, Float32Type, UintType, or IntType.
func (n *Number) Type() Type {
if n.typ == InvalidType {
return IntType
}
return n.typ
}
// DecodeMsg implements msgp.Decodable
func (n *Number) DecodeMsg(r *Reader) error {
typ, err := r.NextType()
if err != nil {
return err
}
switch typ {
case Float32Type:
f, err := r.ReadFloat32()
if err != nil {
return err
}
n.AsFloat32(f)
return nil
case Float64Type:
f, err := r.ReadFloat64()
if err != nil {
return err
}
n.AsFloat64(f)
return nil
case IntType:
i, err := r.ReadInt64()
if err != nil {
return err
}
n.AsInt(i)
return nil
case UintType:
u, err := r.ReadUint64()
if err != nil {
return err
}
n.AsUint(u)
return nil
default:
return TypeError{Encoded: typ, Method: IntType}
}
}
// UnmarshalMsg implements msgp.Unmarshaler
func (n *Number) UnmarshalMsg(b []byte) ([]byte, error) {
var nbs *NilBitsStack
typ := NextType(b)
switch typ {
case IntType:
i, o, err := nbs.ReadInt64Bytes(b)
if err != nil {
return b, err
}
n.AsInt(i)
return o, nil
case UintType:
u, o, err := nbs.ReadUint64Bytes(b)
if err != nil {
return b, err
}
n.AsUint(u)
return o, nil
case Float64Type:
f, o, err := nbs.ReadFloat64Bytes(b)
if err != nil {
return b, err
}
n.AsFloat64(f)
return o, nil
case Float32Type:
f, o, err := nbs.ReadFloat32Bytes(b)
if err != nil {
return b, err
}
n.AsFloat32(f)
return o, nil
default:
return b, TypeError{Method: IntType, Encoded: typ}
}
}
// MarshalMsg implements msgp.Marshaler
func (n *Number) MarshalMsg(b []byte) ([]byte, error) {
switch n.typ {
case IntType:
return AppendInt64(b, int64(n.bits)), nil
case UintType:
return AppendUint64(b, uint64(n.bits)), nil
case Float64Type:
return AppendFloat64(b, math.Float64frombits(n.bits)), nil
case Float32Type:
return AppendFloat32(b, math.Float32frombits(uint32(n.bits))), nil
default:
return AppendInt64(b, 0), nil
}
}
// EncodeMsg implements msgp.Encodable
func (n *Number) EncodeMsg(w *Writer) error {
switch n.typ {
case IntType:
return w.WriteInt64(int64(n.bits))
case UintType:
return w.WriteUint64(n.bits)
case Float64Type:
return w.WriteFloat64(math.Float64frombits(n.bits))
case Float32Type:
return w.WriteFloat32(math.Float32frombits(uint32(n.bits)))
default:
return w.WriteInt64(0)
}
}
// Msgsize implements msgp.Sizer
func (n *Number) Msgsize() int {
switch n.typ {
case Float32Type:
return Float32Size
case Float64Type:
return Float64Size
case IntType:
return Int64Size
case UintType:
return Uint64Size
default:
return 1 // fixint(0)
}
}
// MarshalJSON implements json.Marshaler
func (n *Number) MarshalJSON() ([]byte, error) {
t := n.Type()
if t == InvalidType {
return []byte{'0'}, nil
}
out := make([]byte, 0, 32)
switch t {
case Float32Type, Float64Type:
f, _ := n.Float()
return strconv.AppendFloat(out, f, 'f', -1, 64), nil
case IntType:
i, _ := n.Int()
return strconv.AppendInt(out, i, 10), nil
case UintType:
u, _ := n.Uint()
return strconv.AppendUint(out, u, 10), nil
default:
panic("(*Number).typ is invalid")
}
}
// String implements fmt.Stringer
func (n *Number) String() string {
switch n.typ {
case InvalidType:
return "0"
case Float32Type, Float64Type:
f, _ := n.Float()
return strconv.FormatFloat(f, 'f', -1, 64)
case IntType:
i, _ := n.Int()
return strconv.FormatInt(i, 10)
case UintType:
u, _ := n.Uint()
return strconv.FormatUint(u, 10)
default:
panic("(*Number).typ is invalid")
}
}

1597
vendor/github.com/glycerine/greenpack/msgp/read.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

1483
vendor/github.com/glycerine/greenpack/msgp/read_bytes.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,13 @@
package msgp
type RuntimeConfig struct {
// UnsafeZeroCopy will make strings point to the
// original msgpack buffers. This is unsafe because
// if the buffer changes the string will change/be
// invalid/not protected against re-use. But for
// processing and disposing of single messages, one-at-at-time,
// without re-using any part of a message (or making a copy of strings explicitly with copy()
// if you must) then we can avoid all allocations for strings.
UnsafeZeroCopy bool
}

39
vendor/github.com/glycerine/greenpack/msgp/size.go generated vendored Normal file
View File

@@ -0,0 +1,39 @@
package msgp
// The sizes provided
// are the worst-case
// encoded sizes for
// each type. For variable-
// length types ([]byte, string),
// the total encoded size is
// the prefix size plus the
// length of the object.
const (
Int64Size = 9
IntSize = Int64Size
UintSize = Int64Size
Int8Size = 2
Int16Size = 3
Int32Size = 5
Uint8Size = 2
ByteSize = Uint8Size
Uint16Size = 3
Uint32Size = 5
Uint64Size = Int64Size
Float64Size = 9
Float32Size = 5
Complex64Size = 10
Complex128Size = 18
TimeSize = 15
DurationSize = 12
BoolSize = 1
NilSize = 1
MapHeaderSize = 5
ArrayHeaderSize = 5
BytesPrefixSize = 5
StringPrefixSize = 5
ExtensionPrefixSize = 6
)

40
vendor/github.com/glycerine/greenpack/msgp/unsafe.go generated vendored Normal file
View File

@@ -0,0 +1,40 @@
// +build !appengine
package msgp
import (
"reflect"
"unsafe"
)
// NOTE:
// all of the definition in this file
// should be repeated in appengine.go,
// but without using unsafe
const (
// spec says int and uint are always
// the same size, but that int/uint
// size may not be machine word size
smallint = unsafe.Sizeof(int(0)) == 4
)
// UnsafeString returns the byte slice as a volatile string
// THIS SHOULD ONLY BE USED BY THE CODE GENERATOR.
// THIS IS EVIL CODE.
// YOU HAVE BEEN WARNED.
func UnsafeString(b []byte) string {
return *(*string)(unsafe.Pointer(&reflect.StringHeader{Data: uintptr(unsafe.Pointer(&b[0])), Len: len(b)}))
}
// UnsafeBytes returns the string as a byte slice
// THIS SHOULD ONLY BE USED BY THE CODE GENERATOR.
// THIS IS EVIL CODE.
// YOU HAVE BEEN WARNED.
func UnsafeBytes(s string) []byte {
return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
Len: len(s),
Cap: len(s),
Data: (*(*reflect.StringHeader)(unsafe.Pointer(&s))).Data,
}))
}

869
vendor/github.com/glycerine/greenpack/msgp/write.go generated vendored Normal file
View File

@@ -0,0 +1,869 @@
package msgp
import (
"errors"
"fmt"
"io"
"math"
"reflect"
"sync"
"time"
)
// Sizer is an interface implemented
// by types that can estimate their
// size when MessagePack encoded.
// This interface is optional, but
// encoding/marshaling implementations
// may use this as a way to pre-allocate
// memory for serialization.
type Sizer interface {
Msgsize() int
}
var (
// Nowhere is an io.Writer to nowhere
Nowhere io.Writer = nwhere{}
btsType = reflect.TypeOf(([]byte)(nil))
writerPool = sync.Pool{
New: func() interface{} {
return &Writer{
buf: make([]byte, 2048),
ptrWrit: make(map[interface{}]int),
}
},
}
)
func popWriter(w io.Writer) *Writer {
wr := writerPool.Get().(*Writer)
wr.Reset(w)
wr.DedupReset()
return wr
}
func pushWriter(wr *Writer) {
wr.w = nil
wr.wloc = 0
writerPool.Put(wr)
}
// freeW frees a writer for use
// by other processes. It is not necessary
// to call freeW on a writer. However, maintaining
// a reference to a *Writer after calling freeW on
// it will cause undefined behavior.
func freeW(w *Writer) { pushWriter(w) }
// Require ensures that cap(old)-len(old) >= extra.
func Require(old []byte, extra int) []byte {
l := len(old)
c := cap(old)
r := l + extra
if c >= r {
return old
} else if l == 0 {
return make([]byte, 0, extra)
}
// the new size is the greater
// of double the old capacity
// and the sum of the old length
// and the number of new bytes
// necessary.
c <<= 1
if c < r {
c = r
}
n := make([]byte, l, c)
copy(n, old)
return n
}
// nowhere writer
type nwhere struct{}
func (n nwhere) Write(p []byte) (int, error) { return len(p), nil }
// Marshaler is the interface implemented
// by types that know how to marshal themselves
// as MessagePack. MarshalMsg appends the marshalled
// form of the object to the provided
// byte slice, returning the extended
// slice and any errors encountered.
type Marshaler interface {
MarshalMsg([]byte) ([]byte, error)
}
// Encodable is the interface implemented
// by types that know how to write themselves
// as MessagePack using a *msgp.Writer.
type Encodable interface {
EncodeMsg(*Writer) error
}
// Writer is a buffered writer
// that can be used to write
// MessagePack objects to an io.Writer.
// You must call *Writer.Flush() in order
// to flush all of the buffered data
// to the underlying writer.
type Writer struct {
w io.Writer
buf []byte
wloc int
ptrWrit map[interface{}]int
ptrCountNext int
}
// NewWriter returns a new *Writer.
func NewWriter(w io.Writer) *Writer {
if wr, ok := w.(*Writer); ok {
return wr
}
return popWriter(w)
}
// NewWriterSize returns a writer with a custom buffer size.
func NewWriterSize(w io.Writer, sz int) *Writer {
// we must be able to require() 18
// contiguous bytes, so that is the
// practical minimum buffer size
if sz < 18 {
sz = 18
}
return &Writer{
w: w,
buf: make([]byte, sz),
}
}
// Encode encodes an Encodable to an io.Writer.
func Encode(w io.Writer, e Encodable) error {
wr := NewWriter(w)
err := e.EncodeMsg(wr)
if err == nil {
err = wr.Flush()
}
freeW(wr)
return err
}
func (mw *Writer) flush() error {
if mw.wloc == 0 {
return nil
}
n, err := mw.w.Write(mw.buf[:mw.wloc])
if err != nil {
if n > 0 {
mw.wloc = copy(mw.buf, mw.buf[n:mw.wloc])
}
return err
}
mw.wloc = 0
return nil
}
// Flush flushes all of the buffered
// data to the underlying writer.
func (mw *Writer) Flush() error { return mw.flush() }
// Buffered returns the number bytes in the write buffer
func (mw *Writer) Buffered() int { return len(mw.buf) - mw.wloc }
func (mw *Writer) avail() int { return len(mw.buf) - mw.wloc }
func (mw *Writer) bufsize() int { return len(mw.buf) }
// NOTE: this should only be called with
// a number that is guaranteed to be less than
// len(mw.buf). typically, it is called with a constant.
//
// NOTE: this is a hot code path
func (mw *Writer) require(n int) (int, error) {
c := len(mw.buf)
wl := mw.wloc
if c-wl < n {
if err := mw.flush(); err != nil {
return 0, err
}
wl = mw.wloc
}
mw.wloc += n
return wl, nil
}
func (mw *Writer) Append(b ...byte) error {
if mw.avail() < len(b) {
err := mw.flush()
if err != nil {
return err
}
}
mw.wloc += copy(mw.buf[mw.wloc:], b)
return nil
}
// push one byte onto the buffer
//
// NOTE: this is a hot code path
func (mw *Writer) push(b byte) error {
if mw.wloc == len(mw.buf) {
if err := mw.flush(); err != nil {
return err
}
}
mw.buf[mw.wloc] = b
mw.wloc++
return nil
}
func (mw *Writer) prefix8(b byte, u uint8) error {
const need = 2
if len(mw.buf)-mw.wloc < need {
if err := mw.flush(); err != nil {
return err
}
}
prefixu8(mw.buf[mw.wloc:], b, u)
mw.wloc += need
return nil
}
func (mw *Writer) prefix16(b byte, u uint16) error {
const need = 3
if len(mw.buf)-mw.wloc < need {
if err := mw.flush(); err != nil {
return err
}
}
prefixu16(mw.buf[mw.wloc:], b, u)
mw.wloc += need
return nil
}
func (mw *Writer) prefix32(b byte, u uint32) error {
const need = 5
if len(mw.buf)-mw.wloc < need {
if err := mw.flush(); err != nil {
return err
}
}
prefixu32(mw.buf[mw.wloc:], b, u)
mw.wloc += need
return nil
}
func (mw *Writer) prefix64(b byte, u uint64) error {
const need = 9
if len(mw.buf)-mw.wloc < need {
if err := mw.flush(); err != nil {
return err
}
}
prefixu64(mw.buf[mw.wloc:], b, u)
mw.wloc += need
return nil
}
// Write implements io.Writer, and writes
// data directly to the buffer.
func (mw *Writer) Write(p []byte) (int, error) {
l := len(p)
if mw.avail() < l {
if err := mw.flush(); err != nil {
return 0, err
}
if l > len(mw.buf) {
return mw.w.Write(p)
}
}
mw.wloc += copy(mw.buf[mw.wloc:], p)
return l, nil
}
// implements io.WriteString
func (mw *Writer) writeString(s string) error {
l := len(s)
if mw.avail() < l {
if err := mw.flush(); err != nil {
return err
}
if l > len(mw.buf) {
_, err := io.WriteString(mw.w, s)
return err
}
}
mw.wloc += copy(mw.buf[mw.wloc:], s)
return nil
}
// Reset changes the underlying writer used by the Writer
func (mw *Writer) Reset(w io.Writer) {
mw.buf = mw.buf[:cap(mw.buf)]
mw.w = w
mw.wloc = 0
}
// WriteMapHeader writes a map header of the given
// size to the writer
func (mw *Writer) WriteMapHeader(sz uint32) error {
switch {
case sz <= 15:
return mw.push(wfixmap(uint8(sz)))
case sz <= math.MaxUint16:
return mw.prefix16(mmap16, uint16(sz))
default:
return mw.prefix32(mmap32, sz)
}
}
// WriteArrayHeader writes an array header of the
// given size to the writer
func (mw *Writer) WriteArrayHeader(sz uint32) error {
switch {
case sz <= 15:
return mw.push(wfixarray(uint8(sz)))
case sz <= math.MaxUint16:
return mw.prefix16(marray16, uint16(sz))
default:
return mw.prefix32(marray32, sz)
}
}
// WriteNil writes a nil byte to the buffer
func (mw *Writer) WriteNil() error {
return mw.push(mnil)
}
// WriteFloat64 writes a float64 to the writer
func (mw *Writer) WriteFloat64(f float64) error {
return mw.prefix64(mfloat64, math.Float64bits(f))
}
// WriteFloat32 writes a float32 to the writer
func (mw *Writer) WriteFloat32(f float32) error {
return mw.prefix32(mfloat32, math.Float32bits(f))
}
// WriteInt64 writes an int64 to the writer
func (mw *Writer) WriteInt64(i int64) error {
if i >= 0 {
switch {
case i <= math.MaxInt8:
return mw.push(wfixint(uint8(i)))
case i <= math.MaxInt16:
return mw.prefix16(mint16, uint16(i))
case i <= math.MaxInt32:
return mw.prefix32(mint32, uint32(i))
default:
return mw.prefix64(mint64, uint64(i))
}
}
switch {
case i >= -32:
return mw.push(wnfixint(int8(i)))
case i >= math.MinInt8:
return mw.prefix8(mint8, uint8(i))
case i >= math.MinInt16:
return mw.prefix16(mint16, uint16(i))
case i >= math.MinInt32:
return mw.prefix32(mint32, uint32(i))
default:
return mw.prefix64(mint64, uint64(i))
}
}
// WriteInt8 writes an int8 to the writer
func (mw *Writer) WriteInt8(i int8) error { return mw.WriteInt64(int64(i)) }
// WriteInt16 writes an int16 to the writer
func (mw *Writer) WriteInt16(i int16) error { return mw.WriteInt64(int64(i)) }
// WriteInt32 writes an int32 to the writer
func (mw *Writer) WriteInt32(i int32) error { return mw.WriteInt64(int64(i)) }
// WriteInt writes an int to the writer
func (mw *Writer) WriteInt(i int) error { return mw.WriteInt64(int64(i)) }
// WriteUint64 writes a uint64 to the writer
func (mw *Writer) WriteUint64(u uint64) error {
switch {
case u <= (1<<7)-1:
return mw.push(wfixint(uint8(u)))
case u <= math.MaxUint8:
return mw.prefix8(muint8, uint8(u))
case u <= math.MaxUint16:
return mw.prefix16(muint16, uint16(u))
case u <= math.MaxUint32:
return mw.prefix32(muint32, uint32(u))
default:
return mw.prefix64(muint64, u)
}
}
// WriteByte is analogous to WriteUint8
func (mw *Writer) WriteByte(u byte) error { return mw.WriteUint8(uint8(u)) }
// WriteUint8 writes a uint8 to the writer
func (mw *Writer) WriteUint8(u uint8) error { return mw.WriteUint64(uint64(u)) }
// WriteUint16 writes a uint16 to the writer
func (mw *Writer) WriteUint16(u uint16) error { return mw.WriteUint64(uint64(u)) }
// WriteUint32 writes a uint32 to the writer
func (mw *Writer) WriteUint32(u uint32) error { return mw.WriteUint64(uint64(u)) }
// WriteUint writes a uint to the writer
func (mw *Writer) WriteUint(u uint) error { return mw.WriteUint64(uint64(u)) }
// WriteBytes writes binary as 'bin' to the writer
func (mw *Writer) WriteBytes(b []byte) error {
sz := uint32(len(b))
var err error
switch {
case sz <= math.MaxUint8:
err = mw.prefix8(mbin8, uint8(sz))
case sz <= math.MaxUint16:
err = mw.prefix16(mbin16, uint16(sz))
default:
err = mw.prefix32(mbin32, sz)
}
if err != nil {
return err
}
_, err = mw.Write(b)
return err
}
// WriteBytesHeader writes just the size header
// of a MessagePack 'bin' object. The user is responsible
// for then writing 'sz' more bytes into the stream.
func (mw *Writer) WriteBytesHeader(sz uint32) error {
switch {
case sz <= math.MaxUint8:
return mw.prefix8(mbin8, uint8(sz))
case sz <= math.MaxUint16:
return mw.prefix16(mbin16, uint16(sz))
default:
return mw.prefix32(mbin32, sz)
}
}
// WriteBool writes a bool to the writer
func (mw *Writer) WriteBool(b bool) error {
if b {
return mw.push(mtrue)
}
return mw.push(mfalse)
}
// WriteString writes a messagepack string to the writer.
// (This is NOT an implementation of io.StringWriter)
func (mw *Writer) WriteString(s string) error {
sz := uint32(len(s))
var err error
switch {
case sz <= 31:
err = mw.push(wfixstr(uint8(sz)))
case sz <= math.MaxUint8:
err = mw.prefix8(mstr8, uint8(sz))
case sz <= math.MaxUint16:
err = mw.prefix16(mstr16, uint16(sz))
default:
err = mw.prefix32(mstr32, sz)
}
if err != nil {
return err
}
return mw.writeString(s)
}
// WriteStringHeader writes just the string size
// header of a MessagePack 'str' object. The user
// is responsible for writing 'sz' more valid UTF-8
// bytes to the stream.
func (mw *Writer) WriteStringHeader(sz uint32) error {
switch {
case sz <= 31:
return mw.push(wfixstr(uint8(sz)))
case sz <= math.MaxUint8:
return mw.prefix8(mstr8, uint8(sz))
case sz <= math.MaxUint16:
return mw.prefix16(mstr16, uint16(sz))
default:
return mw.prefix32(mstr32, sz)
}
}
// WriteStringFromBytes writes a 'str' object
// from a []byte.
func (mw *Writer) WriteStringFromBytes(str []byte) error {
sz := uint32(len(str))
var err error
switch {
case sz <= 31:
err = mw.push(wfixstr(uint8(sz)))
case sz <= math.MaxUint8:
err = mw.prefix8(mstr8, uint8(sz))
case sz <= math.MaxUint16:
err = mw.prefix16(mstr16, uint16(sz))
default:
err = mw.prefix32(mstr32, sz)
}
if err != nil {
return err
}
_, err = mw.Write(str)
return err
}
// WriteComplex64 writes a complex64 to the writer
func (mw *Writer) WriteComplex64(f complex64) error {
o, err := mw.require(10)
if err != nil {
return err
}
mw.buf[o] = mfixext8
mw.buf[o+1] = Complex64Extension
big.PutUint32(mw.buf[o+2:], math.Float32bits(real(f)))
big.PutUint32(mw.buf[o+6:], math.Float32bits(imag(f)))
return nil
}
// WriteComplex128 writes a complex128 to the writer
func (mw *Writer) WriteComplex128(f complex128) error {
o, err := mw.require(18)
if err != nil {
return err
}
mw.buf[o] = mfixext16
mw.buf[o+1] = Complex128Extension
big.PutUint64(mw.buf[o+2:], math.Float64bits(real(f)))
big.PutUint64(mw.buf[o+10:], math.Float64bits(imag(f)))
return nil
}
// WriteMapStrStr writes a map[string]string to the writer
func (mw *Writer) WriteMapStrStr(mp map[string]string) (err error) {
err = mw.WriteMapHeader(uint32(len(mp)))
if err != nil {
return
}
for key, val := range mp {
err = mw.WriteString(key)
if err != nil {
return
}
err = mw.WriteString(val)
if err != nil {
return
}
}
return nil
}
// WriteMapStrIntf writes a map[string]interface to the writer
func (mw *Writer) WriteMapStrIntf(mp map[string]interface{}) (err error) {
err = mw.WriteMapHeader(uint32(len(mp)))
if err != nil {
return
}
for key, val := range mp {
err = mw.WriteString(key)
if err != nil {
return
}
err = mw.WriteIntf(val)
if err != nil {
return
}
}
return
}
// WriteTime writes a time.Time object to the wire.
//
// Time is encoded as Unix time, which means that
// location (time zone) data is removed from the object.
// The encoded object itself is 12 bytes: 8 bytes for
// a big-endian 64-bit integer denoting seconds
// elapsed since "zero" Unix time, followed by 4 bytes
// for a big-endian 32-bit signed integer denoting
// the nanosecond offset of the time. This encoding
// is intended to ease portability across languages.
// (Note that this is *not* the standard time.Time
// binary encoding, because its implementation relies
// heavily on the internal representation used by the
// time package.)
func (mw *Writer) WriteTime(t time.Time) error {
t = t.UTC().Truncate(0) // strip out monotone clock
o, err := mw.require(15)
if err != nil {
return err
}
mw.buf[o] = mext8
mw.buf[o+1] = 12
mw.buf[o+2] = TimeExtension
putUnix(mw.buf[o+3:], t.Unix(), int32(t.Nanosecond()))
return nil
}
// WriteDuration writes a time.Duration object to the wire.
//
// Duration is encoded as int64.
func (mw *Writer) WriteDuration(dur time.Duration) error {
o, err := mw.require(12)
if err != nil {
return err
}
mw.buf[o] = mext8
mw.buf[o+1] = 9
mw.buf[o+2] = DurationExtension
putMint64(mw.buf[o+3:], int64(dur))
return nil
}
// WriteIntf writes the concrete type of 'v'.
// WriteIntf will error if 'v' is not one of the following:
// - A bool, float, string, []byte, int, uint, or complex
// - A map of supported types (with string keys)
// - An array or slice of supported types
// - A pointer to a supported type
// - A type that satisfies the msgp.Encodable interface
// - A type that satisfies the msgp.Extension interface
func (mw *Writer) WriteIntf(v interface{}) error {
if v == nil {
return mw.WriteNil()
}
switch v := v.(type) {
// preferred interfaces
case Encodable:
return v.EncodeMsg(mw)
case Extension:
return mw.WriteExtension(v)
// concrete types
case bool:
return mw.WriteBool(v)
case float32:
return mw.WriteFloat32(v)
case float64:
return mw.WriteFloat64(v)
case complex64:
return mw.WriteComplex64(v)
case complex128:
return mw.WriteComplex128(v)
case uint8:
return mw.WriteUint8(v)
case uint16:
return mw.WriteUint16(v)
case uint32:
return mw.WriteUint32(v)
case uint64:
return mw.WriteUint64(v)
case uint:
return mw.WriteUint(v)
case int8:
return mw.WriteInt8(v)
case int16:
return mw.WriteInt16(v)
case int32:
return mw.WriteInt32(v)
case int64:
return mw.WriteInt64(v)
case int:
return mw.WriteInt(v)
case string:
return mw.WriteString(v)
case []byte:
return mw.WriteBytes(v)
case map[string]string:
return mw.WriteMapStrStr(v)
case map[string]interface{}:
return mw.WriteMapStrIntf(v)
case time.Time:
return mw.WriteTime(v)
case time.Duration:
return mw.WriteDuration(v)
}
val := reflect.ValueOf(v)
if !isSupported(val.Kind()) || !val.IsValid() {
return fmt.Errorf("msgp: type %s not supported(1)", val)
}
switch val.Kind() {
case reflect.Ptr:
if val.IsNil() {
return mw.WriteNil()
}
return mw.WriteIntf(val.Elem().Interface())
case reflect.Slice:
return mw.writeSlice(val)
case reflect.Map:
return mw.writeMap(val)
}
return &ErrUnsupportedType{val.Type()}
}
func (mw *Writer) writeMap(v reflect.Value) (err error) {
if v.Elem().Kind() != reflect.String {
return errors.New("msgp: map keys must be strings")
}
ks := v.MapKeys()
err = mw.WriteMapHeader(uint32(len(ks)))
if err != nil {
return
}
for _, key := range ks {
val := v.MapIndex(key)
err = mw.WriteString(key.String())
if err != nil {
return
}
err = mw.WriteIntf(val.Interface())
if err != nil {
return
}
}
return
}
func (mw *Writer) writeSlice(v reflect.Value) (err error) {
// is []byte
if v.Type().ConvertibleTo(btsType) {
return mw.WriteBytes(v.Bytes())
}
sz := uint32(v.Len())
err = mw.WriteArrayHeader(sz)
if err != nil {
return
}
for i := uint32(0); i < sz; i++ {
err = mw.WriteIntf(v.Index(int(i)).Interface())
if err != nil {
return
}
}
return
}
func (mw *Writer) writeStruct(v reflect.Value) error {
if enc, ok := v.Interface().(Encodable); ok {
return enc.EncodeMsg(mw)
}
return fmt.Errorf("msgp: unsupported type: %s", v.Type())
}
func (mw *Writer) writeVal(v reflect.Value) error {
if !isSupported(v.Kind()) {
return fmt.Errorf("msgp: msgp/enc: type %q not supported(2)", v.Type())
}
// shortcut for nil values
if v.IsNil() {
return mw.WriteNil()
}
switch v.Kind() {
case reflect.Bool:
return mw.WriteBool(v.Bool())
case reflect.Float32, reflect.Float64:
return mw.WriteFloat64(v.Float())
case reflect.Complex64, reflect.Complex128:
return mw.WriteComplex128(v.Complex())
case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int8:
return mw.WriteInt64(v.Int())
case reflect.Interface, reflect.Ptr:
if v.IsNil() {
mw.WriteNil()
}
return mw.writeVal(v.Elem())
case reflect.Map:
return mw.writeMap(v)
case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint8:
return mw.WriteUint64(v.Uint())
case reflect.String:
return mw.WriteString(v.String())
case reflect.Slice, reflect.Array:
return mw.writeSlice(v)
case reflect.Struct:
return mw.writeStruct(v)
}
return fmt.Errorf("msgp: msgp/enc: type %q not supported(3)", v.Type())
}
// is the reflect.Kind encodable?
func isSupported(k reflect.Kind) bool {
switch k {
case reflect.Func, reflect.Chan, reflect.Invalid, reflect.UnsafePointer:
return false
default:
return true
}
}
// GuessSize guesses the size of the underlying
// value of 'i'. If the underlying value is not
// a simple builtin (or []byte), GuessSize defaults
// to 512.
func GuessSize(i interface{}) int {
if i == nil {
return NilSize
}
switch i := i.(type) {
case Sizer:
return i.Msgsize()
case Extension:
return ExtensionPrefixSize + i.Len()
case float64:
return Float64Size
case float32:
return Float32Size
case uint8, uint16, uint32, uint64, uint:
return UintSize
case int8, int16, int32, int64, int:
return IntSize
case []byte:
return BytesPrefixSize + len(i)
case string:
return StringPrefixSize + len(i)
case complex64:
return Complex64Size
case complex128:
return Complex128Size
case bool:
return BoolSize
case map[string]interface{}:
s := MapHeaderSize
for key, val := range i {
s += StringPrefixSize + len(key) + GuessSize(val)
}
return s
case map[string]string:
s := MapHeaderSize
for key, val := range i {
s += 2*StringPrefixSize + len(key) + len(val)
}
return s
default:
return 512
}
}

View File

@@ -0,0 +1,464 @@
package msgp
import (
"math"
"reflect"
"time"
)
// ensure 'sz' extra bytes in 'b' btw len(b) and cap(b)
func ensure(b []byte, sz int) ([]byte, int) {
l := len(b)
c := cap(b)
if c-l < sz {
o := make([]byte, (2*c)+sz) // exponential growth
n := copy(o, b)
return o[:n+sz], n
}
return b[:l+sz], l
}
// AppendMapHeader appends a map header with the
// given size to the slice
func AppendMapHeader(b []byte, sz uint32) []byte {
switch {
case sz <= 15:
return append(b, wfixmap(uint8(sz)))
case sz <= math.MaxUint16:
o, n := ensure(b, 3)
prefixu16(o[n:], mmap16, uint16(sz))
return o
default:
o, n := ensure(b, 5)
prefixu32(o[n:], mmap32, sz)
return o
}
}
// AppendArrayHeader appends an array header with
// the given size to the slice
func AppendArrayHeader(b []byte, sz uint32) []byte {
switch {
case sz <= 15:
return append(b, wfixarray(uint8(sz)))
case sz <= math.MaxUint16:
o, n := ensure(b, 3)
prefixu16(o[n:], marray16, uint16(sz))
return o
default:
o, n := ensure(b, 5)
prefixu32(o[n:], marray32, sz)
return o
}
}
// AppendNil appends a 'nil' byte to the slice
func AppendNil(b []byte) []byte { return append(b, mnil) }
// AppendFloat64 appends a float64 to the slice
func AppendFloat64(b []byte, f float64) []byte {
o, n := ensure(b, Float64Size)
prefixu64(o[n:], mfloat64, math.Float64bits(f))
return o
}
// AppendFloat32 appends a float32 to the slice
func AppendFloat32(b []byte, f float32) []byte {
o, n := ensure(b, Float32Size)
prefixu32(o[n:], mfloat32, math.Float32bits(f))
return o
}
// AppendInt64 appends an int64 to the slice
func AppendInt64(b []byte, i int64) []byte {
if i >= 0 {
switch {
case i <= math.MaxInt8:
return append(b, wfixint(uint8(i)))
case i <= math.MaxInt16:
o, n := ensure(b, 3)
putMint16(o[n:], int16(i))
return o
case i <= math.MaxInt32:
o, n := ensure(b, 5)
putMint32(o[n:], int32(i))
return o
default:
o, n := ensure(b, 9)
putMint64(o[n:], i)
return o
}
}
switch {
case i >= -32:
return append(b, wnfixint(int8(i)))
case i >= math.MinInt8:
o, n := ensure(b, 2)
putMint8(o[n:], int8(i))
return o
case i >= math.MinInt16:
o, n := ensure(b, 3)
putMint16(o[n:], int16(i))
return o
case i >= math.MinInt32:
o, n := ensure(b, 5)
putMint32(o[n:], int32(i))
return o
default:
o, n := ensure(b, 9)
putMint64(o[n:], i)
return o
}
}
// AppendInt appends an int to the slice
func AppendInt(b []byte, i int) []byte { return AppendInt64(b, int64(i)) }
// AppendInt8 appends an int8 to the slice
func AppendInt8(b []byte, i int8) []byte { return AppendInt64(b, int64(i)) }
// AppendInt16 appends an int16 to the slice
func AppendInt16(b []byte, i int16) []byte { return AppendInt64(b, int64(i)) }
// AppendInt32 appends an int32 to the slice
func AppendInt32(b []byte, i int32) []byte { return AppendInt64(b, int64(i)) }
// AppendUint64 appends a uint64 to the slice
func AppendUint64(b []byte, u uint64) []byte {
switch {
case u <= (1<<7)-1:
return append(b, wfixint(uint8(u)))
case u <= math.MaxUint8:
o, n := ensure(b, 2)
putMuint8(o[n:], uint8(u))
return o
case u <= math.MaxUint16:
o, n := ensure(b, 3)
putMuint16(o[n:], uint16(u))
return o
case u <= math.MaxUint32:
o, n := ensure(b, 5)
putMuint32(o[n:], uint32(u))
return o
default:
o, n := ensure(b, 9)
putMuint64(o[n:], u)
return o
}
}
// AppendUint appends a uint to the slice
func AppendUint(b []byte, u uint) []byte { return AppendUint64(b, uint64(u)) }
// AppendUint8 appends a uint8 to the slice
func AppendUint8(b []byte, u uint8) []byte { return AppendUint64(b, uint64(u)) }
// AppendByte is analogous to AppendUint8
func AppendByte(b []byte, u byte) []byte { return AppendUint8(b, uint8(u)) }
// AppendUint16 appends a uint16 to the slice
func AppendUint16(b []byte, u uint16) []byte { return AppendUint64(b, uint64(u)) }
// AppendUint32 appends a uint32 to the slice
func AppendUint32(b []byte, u uint32) []byte { return AppendUint64(b, uint64(u)) }
// AppendBytes appends bytes to the slice as MessagePack 'bin' data
func AppendBytes(b []byte, bts []byte) []byte {
sz := len(bts)
var o []byte
var n int
switch {
case sz <= math.MaxUint8:
o, n = ensure(b, 2+sz)
prefixu8(o[n:], mbin8, uint8(sz))
n += 2
case sz <= math.MaxUint16:
o, n = ensure(b, 3+sz)
prefixu16(o[n:], mbin16, uint16(sz))
n += 3
default:
o, n = ensure(b, 5+sz)
prefixu32(o[n:], mbin32, uint32(sz))
n += 5
}
return o[:n+copy(o[n:], bts)]
}
// AppendBool appends a bool to the slice
func AppendBool(b []byte, t bool) []byte {
if t {
return append(b, mtrue)
}
return append(b, mfalse)
}
// AppendString appends a string as a MessagePack 'str' to the slice
func AppendString(b []byte, s string) []byte {
sz := len(s)
var n int
var o []byte
switch {
case sz <= 31:
o, n = ensure(b, 1+sz)
o[n] = wfixstr(uint8(sz))
n++
case sz <= math.MaxUint8:
o, n = ensure(b, 2+sz)
prefixu8(o[n:], mstr8, uint8(sz))
n += 2
case sz <= math.MaxUint16:
o, n = ensure(b, 3+sz)
prefixu16(o[n:], mstr16, uint16(sz))
n += 3
default:
o, n = ensure(b, 5+sz)
prefixu32(o[n:], mstr32, uint32(sz))
n += 5
}
return o[:n+copy(o[n:], s)]
}
// AppendStringFromBytes appends a []byte
// as a MessagePack 'str' to the slice 'b.'
func AppendStringFromBytes(b []byte, str []byte) []byte {
sz := len(str)
var n int
var o []byte
switch {
case sz <= 31:
o, n = ensure(b, 1+sz)
o[n] = wfixstr(uint8(sz))
n++
case sz <= math.MaxUint8:
o, n = ensure(b, 2+sz)
prefixu8(o[n:], mstr8, uint8(sz))
n += 2
case sz <= math.MaxUint16:
o, n = ensure(b, 3+sz)
prefixu16(o[n:], mstr16, uint16(sz))
n += 3
default:
o, n = ensure(b, 5+sz)
prefixu32(o[n:], mstr32, uint32(sz))
n += 5
}
return o[:n+copy(o[n:], str)]
}
// AppendComplex64 appends a complex64 to the slice as a MessagePack extension
func AppendComplex64(b []byte, c complex64) []byte {
o, n := ensure(b, Complex64Size)
o[n] = mfixext8
o[n+1] = Complex64Extension
big.PutUint32(o[n+2:], math.Float32bits(real(c)))
big.PutUint32(o[n+6:], math.Float32bits(imag(c)))
return o
}
// AppendComplex128 appends a complex128 to the slice as a MessagePack extension
func AppendComplex128(b []byte, c complex128) []byte {
o, n := ensure(b, Complex128Size)
o[n] = mfixext16
o[n+1] = Complex128Extension
big.PutUint64(o[n+2:], math.Float64bits(real(c)))
big.PutUint64(o[n+10:], math.Float64bits(imag(c)))
return o
}
// AppendTime appends a time.Time to the slice as a MessagePack extension
func AppendTime(b []byte, t time.Time) []byte {
o, n := ensure(b, TimeSize)
t = t.UTC()
o[n] = mext8
o[n+1] = 12
o[n+2] = TimeExtension
putUnix(o[n+3:], t.Unix(), int32(t.Nanosecond()))
return o
}
// AppendDuration appends a time.Duration to the slice as a MessagePack extension
func AppendDuration(b []byte, dur time.Duration) []byte {
o, n := ensure(b, DurationSize)
o[n] = mext8
o[n+1] = 9
o[n+2] = DurationExtension
putMint64(o[n+3:], int64(dur))
return o
}
// AppendMapStrStr appends a map[string]string to the slice
// as a MessagePack map with 'str'-type keys and values
func AppendMapStrStr(b []byte, m map[string]string) []byte {
sz := uint32(len(m))
b = AppendMapHeader(b, sz)
for key, val := range m {
b = AppendString(b, key)
b = AppendString(b, val)
}
return b
}
// AppendMapStrIntf appends a map[string]interface{} to the slice
// as a MessagePack map with 'str'-type keys.
func AppendMapStrIntf(b []byte, m map[string]interface{}) ([]byte, error) {
sz := uint32(len(m))
b = AppendMapHeader(b, sz)
var err error
for key, val := range m {
b = AppendString(b, key)
b, err = AppendIntf(b, val)
if err != nil {
return b, err
}
}
return b, nil
}
// AppendMapStrSomething appends a map[string]* to the slice
// as a MessagePack map with 'str'-type keys. * must be
// serializable by AppendIntf().
func AppendMapStrSomething(b []byte, m reflect.Value) ([]byte, error) {
keys := m.MapKeys()
sz := uint32(len(keys))
if sz == 0 {
b = AppendMapHeader(b, sz)
return b, nil
}
var err error
for i, key := range keys {
if i == 0 {
if key.Type().Kind() != reflect.String {
return b, &ErrUnsupportedType{T: m.Type()}
}
// lazy because we try hard not to write
// half a value to b and then error out.
b = AppendMapHeader(b, sz)
}
b = AppendString(b, key.String())
val := m.MapIndex(key)
b, err = AppendIntf(b, val.Interface())
if err != nil {
return b, err
}
}
return b, nil
}
// AppendIntf appends the concrete type of 'i' to the
// provided []byte. 'i' must be one of the following:
// - 'nil'
// - A bool, float, string, []byte, int, uint, or complex
// - A map[string]interface{} or map[string]string
// - A []T, where T is another supported type
// - A *T, where T is another supported type
// - A type that satisfieds the msgp.Marshaler interface
// - A type that satisfies the msgp.Extension interface
func AppendIntf(b []byte, i interface{}) ([]byte, error) {
if i == nil {
return AppendNil(b), nil
}
// all the concrete types
// for which we have methods
switch i := i.(type) {
case Marshaler:
return i.MarshalMsg(b)
case Extension:
return AppendExtension(b, i)
case bool:
return AppendBool(b, i), nil
case float32:
return AppendFloat32(b, i), nil
case float64:
return AppendFloat64(b, i), nil
case complex64:
return AppendComplex64(b, i), nil
case complex128:
return AppendComplex128(b, i), nil
case string:
return AppendString(b, i), nil
case []byte:
return AppendBytes(b, i), nil
case int8:
return AppendInt8(b, i), nil
case int16:
return AppendInt16(b, i), nil
case int32:
return AppendInt32(b, i), nil
case int64:
return AppendInt64(b, i), nil
case int:
return AppendInt64(b, int64(i)), nil
case uint:
return AppendUint64(b, uint64(i)), nil
case uint8:
return AppendUint8(b, i), nil
case uint16:
return AppendUint16(b, i), nil
case uint32:
return AppendUint32(b, i), nil
case uint64:
return AppendUint64(b, i), nil
case time.Time:
return AppendTime(b, i), nil
case time.Duration:
return AppendDuration(b, i), nil
case map[string]interface{}:
return AppendMapStrIntf(b, i)
case map[string]string:
return AppendMapStrStr(b, i), nil
case []interface{}:
b = AppendArrayHeader(b, uint32(len(i)))
var err error
for _, k := range i {
b, err = AppendIntf(b, k)
if err != nil {
return b, err
}
}
return b, nil
}
var err error
v := reflect.ValueOf(i)
switch v.Kind() {
case reflect.Array, reflect.Slice:
l := v.Len()
b = AppendArrayHeader(b, uint32(l))
for i := 0; i < l; i++ {
b, err = AppendIntf(b, v.Index(i).Interface())
if err != nil {
return b, err
}
}
return b, nil
case reflect.Ptr:
if v.IsNil() {
return AppendNil(b), err
}
b, err = AppendIntf(b, v.Elem().Interface())
return b, err
case reflect.Map:
return AppendMapStrSomething(b, v)
default:
return b, &ErrUnsupportedType{T: v.Type()}
}
}
// AppendNegativeOneAndString is a helper for runtime struct id
func AppendNegativeOneAndStringAsBytes(b []byte, str []byte) []byte {
o := AppendInt64(b, -1)
return AppendStringFromBytes(o, str)
}

21
vendor/github.com/glycerine/liner/COPYING generated vendored Normal file
View File

@@ -0,0 +1,21 @@
Copyright © 2012 Peter Harris
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

100
vendor/github.com/glycerine/liner/README.md generated vendored Normal file
View File

@@ -0,0 +1,100 @@
Liner
=====
Liner is a command line editor with history. It was inspired by linenoise;
everything Unix-like is a VT100 (or is trying very hard to be). If your
terminal is not pretending to be a VT100, change it. Liner also support
Windows.
Liner is released under the X11 license (which is similar to the new BSD
license).
Line Editing
------------
The following line editing commands are supported on platforms and terminals
that Liner supports:
Keystroke | Action
--------- | ------
Ctrl-A, Home | Move cursor to beginning of line
Ctrl-E, End | Move cursor to end of line
Ctrl-B, Left | Move cursor one character left
Ctrl-F, Right| Move cursor one character right
Ctrl-Left, Alt-B | Move cursor to previous word
Ctrl-Right, Alt-F | Move cursor to next word
Ctrl-D, Del | (if line is *not* empty) Delete character under cursor
Ctrl-D | (if line *is* empty) End of File - usually quits application
Ctrl-C | Reset input (create new empty prompt)
Ctrl-L | Clear screen (line is unmodified)
Ctrl-T | Transpose previous character with current character
Ctrl-H, BackSpace | Delete character before cursor
Ctrl-W | Delete word leading up to cursor
Ctrl-K | Delete from cursor to end of line
Ctrl-U | Delete from start of line to cursor
Ctrl-P, Up | Previous match from history
Ctrl-N, Down | Next match from history
Ctrl-R | Reverse Search history (Ctrl-S forward, Ctrl-G cancel)
Ctrl-Y | Paste from Yank buffer (Alt-Y to paste next yank instead)
Tab | Next completion
Shift-Tab | (after Tab) Previous completion
Getting started
-----------------
```go
package main
import (
"log"
"os"
"path/filepath"
"strings"
"github.com/peterh/liner"
)
var (
history_fn = filepath.Join(os.TempDir(), ".liner_example_history")
names = []string{"john", "james", "mary", "nancy"}
)
func main() {
line := liner.NewLiner()
defer line.Close()
line.SetCtrlCAborts(true)
line.SetCompleter(func(line string) (c []string) {
for _, n := range names {
if strings.HasPrefix(n, strings.ToLower(line)) {
c = append(c, n)
}
}
return
})
if f, err := os.Open(history_fn); err == nil {
line.ReadHistory(f)
f.Close()
}
if name, err := line.Prompt("What is your name? "); err == nil {
log.Print("Got: ", name)
line.AppendHistory(name)
} else if err == liner.ErrPromptAborted {
log.Print("Aborted")
} else {
log.Print("Error reading line: ", err)
}
if f, err := os.Create(history_fn); err != nil {
log.Print("Error writing history file: ", err)
} else {
line.WriteHistory(f)
f.Close()
}
}
```
For documentation, see http://godoc.org/github.com/peterh/liner

39
vendor/github.com/glycerine/liner/bsdinput.go generated vendored Normal file
View File

@@ -0,0 +1,39 @@
// +build openbsd freebsd netbsd
package liner
import "syscall"
const (
getTermios = syscall.TIOCGETA
setTermios = syscall.TIOCSETA
)
const (
// Input flags
inpck = 0x010
istrip = 0x020
icrnl = 0x100
ixon = 0x200
// Output flags
opost = 0x1
// Control flags
cs8 = 0x300
// Local flags
isig = 0x080
icanon = 0x100
iexten = 0x400
)
type termios struct {
Iflag uint32
Oflag uint32
Cflag uint32
Lflag uint32
Cc [20]byte
Ispeed int32
Ospeed int32
}

226
vendor/github.com/glycerine/liner/common.go generated vendored Normal file
View File

@@ -0,0 +1,226 @@
/*
Package liner implements a simple command line editor, inspired by linenoise
(https://github.com/antirez/linenoise/). This package supports WIN32 in
addition to the xterm codes supported by everything else.
*/
package liner
import (
"bufio"
"container/ring"
"errors"
"fmt"
"io"
"strings"
"sync"
"unicode/utf8"
)
type commonState struct {
terminalSupported bool
outputRedirected bool
inputRedirected bool
history []string
historyMutex sync.RWMutex
completer WordCompleter
columns int
killRing *ring.Ring
ctrlCAborts bool
r *bufio.Reader
tabStyle TabStyle
multiLineMode bool
cursorRows int
maxRows int
}
// TabStyle is used to select how tab completions are displayed.
type TabStyle int
// Two tab styles are currently available:
//
// TabCircular cycles through each completion item and displays it directly on
// the prompt
//
// TabPrints prints the list of completion items to the screen after a second
// tab key is pressed. This behaves similar to GNU readline and BASH (which
// uses readline)
const (
TabCircular TabStyle = iota
TabPrints
)
// ErrPromptAborted is returned from Prompt or PasswordPrompt when the user presses Ctrl-C
// if SetCtrlCAborts(true) has been called on the State
var ErrPromptAborted = errors.New("prompt aborted")
// ErrNotTerminalOutput is returned from Prompt or PasswordPrompt if the
// platform is normally supported, but stdout has been redirected
var ErrNotTerminalOutput = errors.New("standard output is not a terminal")
// Max elements to save on the killring
const KillRingMax = 60
// HistoryLimit is the maximum number of entries saved in the scrollback history.
const HistoryLimit = 1000
// ReadHistory reads scrollback history from r. Returns the number of lines
// read, and any read error (except io.EOF).
func (s *State) ReadHistory(r io.Reader) (num int, err error) {
s.historyMutex.Lock()
defer s.historyMutex.Unlock()
in := bufio.NewReader(r)
num = 0
for {
line, part, err := in.ReadLine()
if err == io.EOF {
break
}
if err != nil {
return num, err
}
if part {
return num, fmt.Errorf("line %d is too long", num+1)
}
if !utf8.Valid(line) {
return num, fmt.Errorf("invalid string at line %d", num+1)
}
num++
s.history = append(s.history, string(line))
if len(s.history) > HistoryLimit {
s.history = s.history[1:]
}
}
return num, nil
}
// WriteHistory writes scrollback history to w. Returns the number of lines
// successfully written, and any write error.
//
// Unlike the rest of liner's API, WriteHistory is safe to call
// from another goroutine while Prompt is in progress.
// This exception is to facilitate the saving of the history buffer
// during an unexpected exit (for example, due to Ctrl-C being invoked)
func (s *State) WriteHistory(w io.Writer) (num int, err error) {
s.historyMutex.RLock()
defer s.historyMutex.RUnlock()
for _, item := range s.history {
_, err := fmt.Fprintln(w, item)
if err != nil {
return num, err
}
num++
}
return num, nil
}
// AppendHistory appends an entry to the scrollback history. AppendHistory
// should be called iff Prompt returns a valid command.
func (s *State) AppendHistory(item string) {
s.historyMutex.Lock()
defer s.historyMutex.Unlock()
if len(s.history) > 0 {
if item == s.history[len(s.history)-1] {
return
}
}
s.history = append(s.history, item)
if len(s.history) > HistoryLimit {
s.history = s.history[1:]
}
}
// Returns the history lines starting with prefix
func (s *State) getHistoryByPrefix(prefix string) (ph []string) {
for _, h := range s.history {
if strings.HasPrefix(h, prefix) {
ph = append(ph, h)
}
}
return
}
// Returns the history lines matching the inteligent search
func (s *State) getHistoryByPattern(pattern string) (ph []string, pos []int) {
if pattern == "" {
return
}
for _, h := range s.history {
if i := strings.Index(h, pattern); i >= 0 {
ph = append(ph, h)
pos = append(pos, i)
}
}
return
}
// Completer takes the currently edited line content at the left of the cursor
// and returns a list of completion candidates.
// If the line is "Hello, wo!!!" and the cursor is before the first '!', "Hello, wo" is passed
// to the completer which may return {"Hello, world", "Hello, Word"} to have "Hello, world!!!".
type Completer func(line string) []string
// WordCompleter takes the currently edited line with the cursor position and
// returns the completion candidates for the partial word to be completed.
// If the line is "Hello, wo!!!" and the cursor is before the first '!', ("Hello, wo!!!", 9) is passed
// to the completer which may returns ("Hello, ", {"world", "Word"}, "!!!") to have "Hello, world!!!".
type WordCompleter func(line string, pos int) (head string, completions []string, tail string)
// SetCompleter sets the completion function that Liner will call to
// fetch completion candidates when the user presses tab.
func (s *State) SetCompleter(f Completer) {
if f == nil {
s.completer = nil
return
}
s.completer = func(line string, pos int) (string, []string, string) {
return "", f(string([]rune(line)[:pos])), string([]rune(line)[pos:])
}
}
// SetWordCompleter sets the completion function that Liner will call to
// fetch completion candidates when the user presses tab.
func (s *State) SetWordCompleter(f WordCompleter) {
s.completer = f
}
// SetTabCompletionStyle sets the behvavior when the Tab key is pressed
// for auto-completion. TabCircular is the default behavior and cycles
// through the list of candidates at the prompt. TabPrints will print
// the available completion candidates to the screen similar to BASH
// and GNU Readline
func (s *State) SetTabCompletionStyle(tabStyle TabStyle) {
s.tabStyle = tabStyle
}
// ModeApplier is the interface that wraps a representation of the terminal
// mode. ApplyMode sets the terminal to this mode.
type ModeApplier interface {
ApplyMode() error
}
// SetCtrlCAborts sets whether Prompt on a supported terminal will return an
// ErrPromptAborted when Ctrl-C is pressed. The default is false (will not
// return when Ctrl-C is pressed). Unsupported terminals typically raise SIGINT
// (and Prompt does not return) regardless of the value passed to SetCtrlCAborts.
func (s *State) SetCtrlCAborts(aborts bool) {
s.ctrlCAborts = aborts
}
// SetMultiLineMode sets whether line is auto-wrapped. The default is false (single line).
func (s *State) SetMultiLineMode(mlmode bool) {
s.multiLineMode = mlmode
}
func (s *State) promptUnsupported(p string) (string, error) {
if !s.inputRedirected || !s.terminalSupported {
fmt.Print(p)
}
linebuf, _, err := s.r.ReadLine()
if err != nil {
return "", err
}
return string(linebuf), nil
}

57
vendor/github.com/glycerine/liner/fallbackinput.go generated vendored Normal file
View File

@@ -0,0 +1,57 @@
// +build !windows,!linux,!darwin,!openbsd,!freebsd,!netbsd
package liner
import (
"bufio"
"errors"
"os"
)
// State represents an open terminal
type State struct {
commonState
}
// Prompt displays p, and then waits for user input. Prompt does not support
// line editing on this operating system.
func (s *State) Prompt(p string) (string, error) {
return s.promptUnsupported(p)
}
// PasswordPrompt is not supported in this OS.
func (s *State) PasswordPrompt(p string) (string, error) {
return "", errors.New("liner: function not supported in this terminal")
}
// NewLiner initializes a new *State
//
// Note that this operating system uses a fallback mode without line
// editing. Patches welcome.
func NewLiner() *State {
var s State
s.r = bufio.NewReader(os.Stdin)
return &s
}
// Close returns the terminal to its previous mode
func (s *State) Close() error {
return nil
}
// TerminalSupported returns false because line editing is not
// supported on this platform.
func TerminalSupported() bool {
return false
}
type noopMode struct{}
func (n noopMode) ApplyMode() error {
return nil
}
// TerminalMode returns a noop InputModeSetter on this platform.
func TerminalMode() (ModeApplier, error) {
return noopMode{}, nil
}

368
vendor/github.com/glycerine/liner/input.go generated vendored Normal file
View File

@@ -0,0 +1,368 @@
// +build linux darwin openbsd freebsd netbsd
package liner
import (
"bufio"
"errors"
"os"
"os/signal"
"strconv"
"strings"
"syscall"
"time"
)
type nexter struct {
r rune
err error
}
// State represents an open terminal
type State struct {
commonState
origMode termios
defaultMode termios
next <-chan nexter
winch chan os.Signal
pending []rune
useCHA bool
}
// NewLiner initializes a new *State, and sets the terminal into raw mode. To
// restore the terminal to its previous state, call State.Close().
//
// Note if you are still using Go 1.0: NewLiner handles SIGWINCH, so it will
// leak a channel every time you call it. Therefore, it is recommened that you
// upgrade to a newer release of Go, or ensure that NewLiner is only called
// once.
func NewLiner() *State {
var s State
s.r = bufio.NewReader(os.Stdin)
s.terminalSupported = TerminalSupported()
if m, err := TerminalMode(); err == nil {
s.origMode = *m.(*termios)
} else {
s.inputRedirected = true
}
if _, err := getMode(syscall.Stdout); err != 0 {
s.outputRedirected = true
}
if s.inputRedirected && s.outputRedirected {
s.terminalSupported = false
}
if s.terminalSupported && !s.inputRedirected && !s.outputRedirected {
mode := s.origMode
mode.Iflag &^= icrnl | inpck | istrip | ixon
mode.Cflag |= cs8
mode.Lflag &^= syscall.ECHO | icanon | iexten
mode.ApplyMode()
winch := make(chan os.Signal, 1)
signal.Notify(winch, syscall.SIGWINCH)
s.winch = winch
s.checkOutput()
}
if !s.outputRedirected {
s.getColumns()
s.outputRedirected = s.columns <= 0
}
return &s
}
var errTimedOut = errors.New("timeout")
func (s *State) startPrompt() {
if s.terminalSupported {
if m, err := TerminalMode(); err == nil {
s.defaultMode = *m.(*termios)
mode := s.defaultMode
mode.Lflag &^= isig
mode.ApplyMode()
}
}
s.restartPrompt()
}
func (s *State) restartPrompt() {
next := make(chan nexter)
go func() {
for {
var n nexter
n.r, _, n.err = s.r.ReadRune()
next <- n
// Shut down nexter loop when an end condition has been reached
if n.err != nil || n.r == '\n' || n.r == '\r' || n.r == ctrlC || n.r == ctrlD {
close(next)
return
}
}
}()
s.next = next
}
func (s *State) stopPrompt() {
if s.terminalSupported {
s.defaultMode.ApplyMode()
}
}
func (s *State) nextPending(timeout <-chan time.Time) (rune, error) {
select {
case thing, ok := <-s.next:
if !ok {
return 0, errors.New("liner: internal error")
}
if thing.err != nil {
return 0, thing.err
}
s.pending = append(s.pending, thing.r)
return thing.r, nil
case <-timeout:
rv := s.pending[0]
s.pending = s.pending[1:]
return rv, errTimedOut
}
// not reached
return 0, nil
}
func (s *State) readNext() (interface{}, error) {
if len(s.pending) > 0 {
rv := s.pending[0]
s.pending = s.pending[1:]
return rv, nil
}
var r rune
select {
case thing, ok := <-s.next:
if !ok {
return 0, errors.New("liner: internal error")
}
if thing.err != nil {
return nil, thing.err
}
r = thing.r
case <-s.winch:
s.getColumns()
return winch, nil
}
if r != esc {
return r, nil
}
s.pending = append(s.pending, r)
// Wait at most 50 ms for the rest of the escape sequence
// If nothing else arrives, it was an actual press of the esc key
timeout := time.After(50 * time.Millisecond)
flag, err := s.nextPending(timeout)
if err != nil {
if err == errTimedOut {
return flag, nil
}
return unknown, err
}
switch flag {
case '[':
code, err := s.nextPending(timeout)
if err != nil {
if err == errTimedOut {
return code, nil
}
return unknown, err
}
switch code {
case 'A':
s.pending = s.pending[:0] // escape code complete
return up, nil
case 'B':
s.pending = s.pending[:0] // escape code complete
return down, nil
case 'C':
s.pending = s.pending[:0] // escape code complete
return right, nil
case 'D':
s.pending = s.pending[:0] // escape code complete
return left, nil
case 'F':
s.pending = s.pending[:0] // escape code complete
return end, nil
case 'H':
s.pending = s.pending[:0] // escape code complete
return home, nil
case 'Z':
s.pending = s.pending[:0] // escape code complete
return shiftTab, nil
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
num := []rune{code}
for {
code, err := s.nextPending(timeout)
if err != nil {
if err == errTimedOut {
return code, nil
}
return nil, err
}
switch code {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
num = append(num, code)
case ';':
// Modifier code to follow
// This only supports Ctrl-left and Ctrl-right for now
x, _ := strconv.ParseInt(string(num), 10, 32)
if x != 1 {
// Can't be left or right
rv := s.pending[0]
s.pending = s.pending[1:]
return rv, nil
}
num = num[:0]
for {
code, err = s.nextPending(timeout)
if err != nil {
if err == errTimedOut {
rv := s.pending[0]
s.pending = s.pending[1:]
return rv, nil
}
return nil, err
}
switch code {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
num = append(num, code)
case 'C', 'D':
// right, left
mod, _ := strconv.ParseInt(string(num), 10, 32)
if mod != 5 {
// Not bare Ctrl
rv := s.pending[0]
s.pending = s.pending[1:]
return rv, nil
}
s.pending = s.pending[:0] // escape code complete
if code == 'C' {
return wordRight, nil
}
return wordLeft, nil
default:
// Not left or right
rv := s.pending[0]
s.pending = s.pending[1:]
return rv, nil
}
}
case '~':
s.pending = s.pending[:0] // escape code complete
x, _ := strconv.ParseInt(string(num), 10, 32)
switch x {
case 2:
return insert, nil
case 3:
return del, nil
case 5:
return pageUp, nil
case 6:
return pageDown, nil
case 7:
return home, nil
case 8:
return end, nil
case 15:
return f5, nil
case 17:
return f6, nil
case 18:
return f7, nil
case 19:
return f8, nil
case 20:
return f9, nil
case 21:
return f10, nil
case 23:
return f11, nil
case 24:
return f12, nil
default:
return unknown, nil
}
default:
// unrecognized escape code
rv := s.pending[0]
s.pending = s.pending[1:]
return rv, nil
}
}
}
case 'O':
code, err := s.nextPending(timeout)
if err != nil {
if err == errTimedOut {
return code, nil
}
return nil, err
}
s.pending = s.pending[:0] // escape code complete
switch code {
case 'c':
return wordRight, nil
case 'd':
return wordLeft, nil
case 'H':
return home, nil
case 'F':
return end, nil
case 'P':
return f1, nil
case 'Q':
return f2, nil
case 'R':
return f3, nil
case 'S':
return f4, nil
default:
return unknown, nil
}
case 'b':
s.pending = s.pending[:0] // escape code complete
return altB, nil
case 'f':
s.pending = s.pending[:0] // escape code complete
return altF, nil
case 'y':
s.pending = s.pending[:0] // escape code complete
return altY, nil
default:
rv := s.pending[0]
s.pending = s.pending[1:]
return rv, nil
}
// not reached
return r, nil
}
// Close returns the terminal to its previous mode
func (s *State) Close() error {
stopSignal(s.winch)
if !s.inputRedirected {
s.origMode.ApplyMode()
}
return nil
}
// TerminalSupported returns true if the current terminal supports
// line editing features, and false if liner will use the 'dumb'
// fallback for input.
// Note that TerminalSupported does not check all factors that may
// cause liner to not fully support the terminal (such as stdin redirection)
func TerminalSupported() bool {
bad := map[string]bool{"": true, "dumb": true, "cons25": true}
return !bad[strings.ToLower(os.Getenv("TERM"))]
}

39
vendor/github.com/glycerine/liner/input_darwin.go generated vendored Normal file
View File

@@ -0,0 +1,39 @@
// +build darwin
package liner
import "syscall"
const (
getTermios = syscall.TIOCGETA
setTermios = syscall.TIOCSETA
)
const (
// Input flags
inpck = 0x010
istrip = 0x020
icrnl = 0x100
ixon = 0x200
// Output flags
opost = 0x1
// Control flags
cs8 = 0x300
// Local flags
isig = 0x080
icanon = 0x100
iexten = 0x400
)
type termios struct {
Iflag uintptr
Oflag uintptr
Cflag uintptr
Lflag uintptr
Cc [20]byte
Ispeed uintptr
Ospeed uintptr
}

26
vendor/github.com/glycerine/liner/input_linux.go generated vendored Normal file
View File

@@ -0,0 +1,26 @@
// +build linux
package liner
import "syscall"
const (
getTermios = syscall.TCGETS
setTermios = syscall.TCSETS
)
const (
icrnl = syscall.ICRNL
inpck = syscall.INPCK
istrip = syscall.ISTRIP
ixon = syscall.IXON
opost = syscall.OPOST
cs8 = syscall.CS8
isig = syscall.ISIG
icanon = syscall.ICANON
iexten = syscall.IEXTEN
)
type termios struct {
syscall.Termios
}

321
vendor/github.com/glycerine/liner/input_windows.go generated vendored Normal file
View File

@@ -0,0 +1,321 @@
package liner
import (
"bufio"
"os"
"syscall"
"unsafe"
)
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procGetStdHandle = kernel32.NewProc("GetStdHandle")
procReadConsoleInput = kernel32.NewProc("ReadConsoleInputW")
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition")
procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
)
// These names are from the Win32 api, so they use underscores (contrary to
// what golint suggests)
const (
std_input_handle = uint32(-10 & 0xFFFFFFFF)
std_output_handle = uint32(-11 & 0xFFFFFFFF)
std_error_handle = uint32(-12 & 0xFFFFFFFF)
invalid_handle_value = ^uintptr(0)
)
type inputMode uint32
// State represents an open terminal
type State struct {
commonState
handle syscall.Handle
hOut syscall.Handle
origMode inputMode
defaultMode inputMode
key interface{}
repeat uint16
}
const (
enableEchoInput = 0x4
enableInsertMode = 0x20
enableLineInput = 0x2
enableMouseInput = 0x10
enableProcessedInput = 0x1
enableQuickEditMode = 0x40
enableWindowInput = 0x8
)
// NewLiner initializes a new *State, and sets the terminal into raw mode. To
// restore the terminal to its previous state, call State.Close().
func NewLiner() *State {
var s State
hIn, _, _ := procGetStdHandle.Call(uintptr(std_input_handle))
s.handle = syscall.Handle(hIn)
hOut, _, _ := procGetStdHandle.Call(uintptr(std_output_handle))
s.hOut = syscall.Handle(hOut)
s.terminalSupported = true
if m, err := TerminalMode(); err == nil {
s.origMode = m.(inputMode)
mode := s.origMode
mode &^= enableEchoInput
mode &^= enableInsertMode
mode &^= enableLineInput
mode &^= enableMouseInput
mode |= enableWindowInput
mode.ApplyMode()
} else {
s.inputRedirected = true
s.r = bufio.NewReader(os.Stdin)
}
s.getColumns()
s.outputRedirected = s.columns <= 0
return &s
}
// These names are from the Win32 api, so they use underscores (contrary to
// what golint suggests)
const (
focus_event = 0x0010
key_event = 0x0001
menu_event = 0x0008
mouse_event = 0x0002
window_buffer_size_event = 0x0004
)
type input_record struct {
eventType uint16
pad uint16
blob [16]byte
}
type key_event_record struct {
KeyDown int32
RepeatCount uint16
VirtualKeyCode uint16
VirtualScanCode uint16
Char int16
ControlKeyState uint32
}
// These names are from the Win32 api, so they use underscores (contrary to
// what golint suggests)
const (
vk_tab = 0x09
vk_prior = 0x21
vk_next = 0x22
vk_end = 0x23
vk_home = 0x24
vk_left = 0x25
vk_up = 0x26
vk_right = 0x27
vk_down = 0x28
vk_insert = 0x2d
vk_delete = 0x2e
vk_f1 = 0x70
vk_f2 = 0x71
vk_f3 = 0x72
vk_f4 = 0x73
vk_f5 = 0x74
vk_f6 = 0x75
vk_f7 = 0x76
vk_f8 = 0x77
vk_f9 = 0x78
vk_f10 = 0x79
vk_f11 = 0x7a
vk_f12 = 0x7b
bKey = 0x42
fKey = 0x46
yKey = 0x59
)
const (
shiftPressed = 0x0010
leftAltPressed = 0x0002
leftCtrlPressed = 0x0008
rightAltPressed = 0x0001
rightCtrlPressed = 0x0004
modKeys = shiftPressed | leftAltPressed | rightAltPressed | leftCtrlPressed | rightCtrlPressed
)
func (s *State) readNext() (interface{}, error) {
if s.repeat > 0 {
s.repeat--
return s.key, nil
}
var input input_record
pbuf := uintptr(unsafe.Pointer(&input))
var rv uint32
prv := uintptr(unsafe.Pointer(&rv))
for {
ok, _, err := procReadConsoleInput.Call(uintptr(s.handle), pbuf, 1, prv)
if ok == 0 {
return nil, err
}
if input.eventType == window_buffer_size_event {
xy := (*coord)(unsafe.Pointer(&input.blob[0]))
s.columns = int(xy.x)
return winch, nil
}
if input.eventType != key_event {
continue
}
ke := (*key_event_record)(unsafe.Pointer(&input.blob[0]))
if ke.KeyDown == 0 {
continue
}
if ke.VirtualKeyCode == vk_tab && ke.ControlKeyState&modKeys == shiftPressed {
s.key = shiftTab
} else if ke.VirtualKeyCode == bKey && (ke.ControlKeyState&modKeys == leftAltPressed ||
ke.ControlKeyState&modKeys == rightAltPressed) {
s.key = altB
} else if ke.VirtualKeyCode == fKey && (ke.ControlKeyState&modKeys == leftAltPressed ||
ke.ControlKeyState&modKeys == rightAltPressed) {
s.key = altF
} else if ke.VirtualKeyCode == yKey && (ke.ControlKeyState&modKeys == leftAltPressed ||
ke.ControlKeyState&modKeys == rightAltPressed) {
s.key = altY
} else if ke.Char > 0 {
s.key = rune(ke.Char)
} else {
switch ke.VirtualKeyCode {
case vk_prior:
s.key = pageUp
case vk_next:
s.key = pageDown
case vk_end:
s.key = end
case vk_home:
s.key = home
case vk_left:
s.key = left
if ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) != 0 {
if ke.ControlKeyState&modKeys == ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) {
s.key = wordLeft
}
}
case vk_right:
s.key = right
if ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) != 0 {
if ke.ControlKeyState&modKeys == ke.ControlKeyState&(leftCtrlPressed|rightCtrlPressed) {
s.key = wordRight
}
}
case vk_up:
s.key = up
case vk_down:
s.key = down
case vk_insert:
s.key = insert
case vk_delete:
s.key = del
case vk_f1:
s.key = f1
case vk_f2:
s.key = f2
case vk_f3:
s.key = f3
case vk_f4:
s.key = f4
case vk_f5:
s.key = f5
case vk_f6:
s.key = f6
case vk_f7:
s.key = f7
case vk_f8:
s.key = f8
case vk_f9:
s.key = f9
case vk_f10:
s.key = f10
case vk_f11:
s.key = f11
case vk_f12:
s.key = f12
default:
// Eat modifier keys
// TODO: return Action(Unknown) if the key isn't a
// modifier.
continue
}
}
if ke.RepeatCount > 1 {
s.repeat = ke.RepeatCount - 1
}
return s.key, nil
}
return unknown, nil
}
// Close returns the terminal to its previous mode
func (s *State) Close() error {
s.origMode.ApplyMode()
return nil
}
func (s *State) startPrompt() {
if m, err := TerminalMode(); err == nil {
s.defaultMode = m.(inputMode)
mode := s.defaultMode
mode &^= enableProcessedInput
mode.ApplyMode()
}
}
func (s *State) restartPrompt() {
}
func (s *State) stopPrompt() {
s.defaultMode.ApplyMode()
}
// TerminalSupported returns true because line editing is always
// supported on Windows.
func TerminalSupported() bool {
return true
}
func (mode inputMode) ApplyMode() error {
hIn, _, err := procGetStdHandle.Call(uintptr(std_input_handle))
if hIn == invalid_handle_value || hIn == 0 {
return err
}
ok, _, err := procSetConsoleMode.Call(hIn, uintptr(mode))
if ok != 0 {
err = nil
}
return err
}
// TerminalMode returns the current terminal input mode as an InputModeSetter.
//
// This function is provided for convenience, and should
// not be necessary for most users of liner.
func TerminalMode() (ModeApplier, error) {
var mode inputMode
hIn, _, err := procGetStdHandle.Call(uintptr(std_input_handle))
if hIn == invalid_handle_value || hIn == 0 {
return nil, err
}
ok, _, err := procGetConsoleMode.Call(hIn, uintptr(unsafe.Pointer(&mode)))
if ok != 0 {
err = nil
}
return mode, err
}

1007
vendor/github.com/glycerine/liner/line.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

75
vendor/github.com/glycerine/liner/output.go generated vendored Normal file
View File

@@ -0,0 +1,75 @@
// +build linux darwin openbsd freebsd netbsd
package liner
import (
"fmt"
"os"
"strings"
"syscall"
"unsafe"
)
func (s *State) cursorPos(x int) {
if s.useCHA {
// 'G' is "Cursor Character Absolute (CHA)"
fmt.Printf("\x1b[%dG", x+1)
} else {
// 'C' is "Cursor Forward (CUF)"
fmt.Print("\r")
if x > 0 {
fmt.Printf("\x1b[%dC", x)
}
}
}
func (s *State) eraseLine() {
fmt.Print("\x1b[0K")
}
func (s *State) eraseScreen() {
fmt.Print("\x1b[H\x1b[2J")
}
func (s *State) moveUp(lines int) {
fmt.Printf("\x1b[%dA", lines)
}
func (s *State) moveDown(lines int) {
fmt.Printf("\x1b[%dB", lines)
}
func (s *State) emitNewLine() {
fmt.Print("\n")
}
type winSize struct {
row, col uint16
xpixel, ypixel uint16
}
func (s *State) getColumns() {
var ws winSize
ok, _, _ := syscall.Syscall(syscall.SYS_IOCTL, uintptr(syscall.Stdout),
syscall.TIOCGWINSZ, uintptr(unsafe.Pointer(&ws)))
if ok < 0 {
s.columns = 80
}
s.columns = int(ws.col)
}
func (s *State) checkOutput() {
// xterm is known to support CHA
if strings.Contains(strings.ToLower(os.Getenv("TERM")), "xterm") {
s.useCHA = true
return
}
// The test for functional ANSI CHA is unreliable (eg the Windows
// telnet command does not support reading the cursor position with
// an ANSI DSR request, despite setting TERM=ansi)
// Assume CHA isn't supported (which should be safe, although it
// does result in occasional visible cursor jitter)
s.useCHA = false
}

72
vendor/github.com/glycerine/liner/output_windows.go generated vendored Normal file
View File

@@ -0,0 +1,72 @@
package liner
import (
"unsafe"
)
type coord struct {
x, y int16
}
type smallRect struct {
left, top, right, bottom int16
}
type consoleScreenBufferInfo struct {
dwSize coord
dwCursorPosition coord
wAttributes int16
srWindow smallRect
dwMaximumWindowSize coord
}
func (s *State) cursorPos(x int) {
var sbi consoleScreenBufferInfo
procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi)))
procSetConsoleCursorPosition.Call(uintptr(s.hOut),
uintptr(int(x)&0xFFFF|int(sbi.dwCursorPosition.y)<<16))
}
func (s *State) eraseLine() {
var sbi consoleScreenBufferInfo
procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi)))
var numWritten uint32
procFillConsoleOutputCharacter.Call(uintptr(s.hOut), uintptr(' '),
uintptr(sbi.dwSize.x-sbi.dwCursorPosition.x),
uintptr(int(sbi.dwCursorPosition.x)&0xFFFF|int(sbi.dwCursorPosition.y)<<16),
uintptr(unsafe.Pointer(&numWritten)))
}
func (s *State) eraseScreen() {
var sbi consoleScreenBufferInfo
procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi)))
var numWritten uint32
procFillConsoleOutputCharacter.Call(uintptr(s.hOut), uintptr(' '),
uintptr(sbi.dwSize.x)*uintptr(sbi.dwSize.y),
0,
uintptr(unsafe.Pointer(&numWritten)))
procSetConsoleCursorPosition.Call(uintptr(s.hOut), 0)
}
func (s *State) moveUp(lines int) {
var sbi consoleScreenBufferInfo
procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi)))
procSetConsoleCursorPosition.Call(uintptr(s.hOut),
uintptr(int(sbi.dwCursorPosition.x)&0xFFFF|(int(sbi.dwCursorPosition.y)-lines)<<16))
}
func (s *State) moveDown(lines int) {
var sbi consoleScreenBufferInfo
procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi)))
procSetConsoleCursorPosition.Call(uintptr(s.hOut),
uintptr(int(sbi.dwCursorPosition.x)&0xFFFF|(int(sbi.dwCursorPosition.y)+lines)<<16))
}
func (s *State) emitNewLine() {
// windows doesn't need to omit a new line
}
func (s *State) getColumns() {
var sbi consoleScreenBufferInfo
procGetConsoleScreenBufferInfo.Call(uintptr(s.hOut), uintptr(unsafe.Pointer(&sbi)))
s.columns = int(sbi.dwSize.x)
}

12
vendor/github.com/glycerine/liner/signal.go generated vendored Normal file
View File

@@ -0,0 +1,12 @@
// +build go1.1,!windows
package liner
import (
"os"
"os/signal"
)
func stopSignal(c chan<- os.Signal) {
signal.Stop(c)
}

11
vendor/github.com/glycerine/liner/signal_legacy.go generated vendored Normal file
View File

@@ -0,0 +1,11 @@
// +build !go1.1,!windows
package liner
import (
"os"
)
func stopSignal(c chan<- os.Signal) {
// signal.Stop does not exist before Go 1.1
}

37
vendor/github.com/glycerine/liner/unixmode.go generated vendored Normal file
View File

@@ -0,0 +1,37 @@
// +build linux darwin freebsd openbsd netbsd
package liner
import (
"syscall"
"unsafe"
)
func (mode *termios) ApplyMode() error {
_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(syscall.Stdin), setTermios, uintptr(unsafe.Pointer(mode)))
if errno != 0 {
return errno
}
return nil
}
// TerminalMode returns the current terminal input mode as an InputModeSetter.
//
// This function is provided for convenience, and should
// not be necessary for most users of liner.
func TerminalMode() (ModeApplier, error) {
mode, errno := getMode(syscall.Stdin)
if errno != 0 {
return nil, errno
}
return mode, nil
}
func getMode(handle int) (*termios, syscall.Errno) {
var mode termios
_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(handle), getTermios, uintptr(unsafe.Pointer(&mode)))
return &mode, errno
}

79
vendor/github.com/glycerine/liner/width.go generated vendored Normal file
View File

@@ -0,0 +1,79 @@
package liner
import "unicode"
// These character classes are mostly zero width (when combined).
// A few might not be, depending on the user's font. Fixing this
// is non-trivial, given that some terminals don't support
// ANSI DSR/CPR
var zeroWidth = []*unicode.RangeTable{
unicode.Mn,
unicode.Me,
unicode.Cc,
unicode.Cf,
}
var doubleWidth = []*unicode.RangeTable{
unicode.Han,
unicode.Hangul,
unicode.Hiragana,
unicode.Katakana,
}
// countGlyphs considers zero-width characters to be zero glyphs wide,
// and members of Chinese, Japanese, and Korean scripts to be 2 glyphs wide.
func countGlyphs(s []rune) int {
n := 0
for _, r := range s {
switch {
case unicode.IsOneOf(zeroWidth, r):
case unicode.IsOneOf(doubleWidth, r):
n += 2
default:
n++
}
}
return n
}
func countMultiLineGlyphs(s []rune, columns int, start int) int {
n := start
for _, r := range s {
switch {
case unicode.IsOneOf(zeroWidth, r):
case unicode.IsOneOf(doubleWidth, r):
n += 2
// no room for a 2-glyphs-wide char in the ending
// so skip a column and display it at the beginning
if n%columns == 1 {
n++
}
default:
n++
}
}
return n
}
func getPrefixGlyphs(s []rune, num int) []rune {
p := 0
for n := 0; n < num && p < len(s); p++ {
if !unicode.IsOneOf(zeroWidth, s[p]) {
n++
}
}
for p < len(s) && unicode.IsOneOf(zeroWidth, s[p]) {
p++
}
return s[:p]
}
func getSuffixGlyphs(s []rune, num int) []rune {
p := len(s)
for n := 0; n < num && p > 0; p-- {
if !unicode.IsOneOf(zeroWidth, s[p-1]) {
n++
}
}
return s[p:]
}

22
vendor/github.com/glycerine/zygomys/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,22 @@
Copyright (c) 2016, The zygomys authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

21
vendor/github.com/glycerine/zygomys/zygo/address.go generated vendored Normal file
View File

@@ -0,0 +1,21 @@
package zygo
type Address struct {
function *SexpFunction
position int
}
func (a Address) IsStackElem() {}
func (stack *Stack) PushAddr(function *SexpFunction, pc int) {
stack.Push(Address{function, pc})
}
func (stack *Stack) PopAddr() (*SexpFunction, int, error) {
elem, err := stack.Pop()
if err != nil {
return MissingFunction, 0, err
}
addr := elem.(Address)
return addr.function, addr.position, nil
}

221
vendor/github.com/glycerine/zygomys/zygo/arrayutils.go generated vendored Normal file
View File

@@ -0,0 +1,221 @@
package zygo
import "fmt"
func MapArray(env *Zlisp, fun *SexpFunction, arr *SexpArray) (Sexp, error) {
result := make([]Sexp, len(arr.Val))
var err error
var firstTyp *RegisteredType
for i := range arr.Val {
result[i], err = env.Apply(fun, arr.Val[i:i+1])
if err != nil {
return &SexpArray{Val: result, Typ: firstTyp, Env: env}, err
}
if firstTyp == nil {
firstTyp = result[i].Type()
}
}
return &SexpArray{Val: result, Typ: firstTyp, Env: env}, nil
}
func ConcatArray(arr *SexpArray, rest []Sexp) (Sexp, error) {
if arr == nil {
return SexpNull, fmt.Errorf("ConcatArray called with nil arr")
}
var res SexpArray
res.Val = arr.Val
for i, x := range rest {
switch t := x.(type) {
case *SexpArray:
res.Val = append(res.Val, t.Val...)
default:
return &res, fmt.Errorf("ConcatArray error: %d-th argument "+
"(0-based) is not an array", i)
}
}
return &res, nil
}
// (arrayidx ar [0 1])
func ArrayIndexFunction(env *Zlisp, name string, args []Sexp) (Sexp, error) {
Q("in ArrayIndexFunction, args = '%#v'", args)
narg := len(args)
if narg != 2 {
return SexpNull, WrongNargs
}
var err error
args, err = env.ResolveDotSym(args)
if err != nil {
return SexpNull, err
}
var ar *SexpArray
switch ar2 := args[0].(type) {
case *SexpArraySelector:
x, err := ar2.RHS(env)
if err != nil {
return SexpNull, err
}
switch xArr := x.(type) {
case *SexpArray:
ar = xArr
case *SexpHash:
return HashIndexFunction(env, name, []Sexp{xArr, args[1]})
default:
return SexpNull, fmt.Errorf("bad (arrayidx ar index) call: ar as arrayidx, but that did not resolve to an array, instead '%s'/type %T", x.SexpString(nil), x)
}
case *SexpArray:
ar = ar2
case *SexpHash:
return HashIndexFunction(env, name, args)
case *SexpHashSelector:
Q("ArrayIndexFunction sees args[0] is a hashSelector")
return HashIndexFunction(env, name, args)
default:
return SexpNull, fmt.Errorf("bad (arrayidx ar index) call: ar was not an array, instead '%s'/type %T",
args[0].SexpString(nil), args[0])
}
var idx *SexpArray
switch idx2 := args[1].(type) {
case *SexpArray:
idx = idx2
default:
return SexpNull, fmt.Errorf("bad (arrayidx ar index) call: index was not an array, instead '%s'/type %T",
args[1].SexpString(nil), args[1])
}
ret := SexpArraySelector{
Select: idx,
Container: ar,
}
return &ret, nil
}
// IndexBy subsets one array (possibly multidimensional) by another.
// e.g. if arr is [a b c] and idx is [0], we'll return a.
func (arr *SexpArray) IndexBy(idx *SexpArray) (Sexp, error) {
nIdx := len(idx.Val)
nTarget := arr.NumDim()
if nIdx > nTarget {
return SexpNull, fmt.Errorf("bad (arrayidx ar index) call: index requested %d dimensions, only have %d",
nIdx, nTarget)
}
if len(idx.Val) == 0 {
return SexpNull, fmt.Errorf("bad (arrayidx ar index) call: no index supplied")
}
if len(idx.Val) != 1 {
return SexpNull, fmt.Errorf("bad (arrayidx ar index) call: we only support a single index value atm")
}
i := 0
myInt, isInt := idx.Val[i].(*SexpInt)
if !isInt {
return SexpNull, fmt.Errorf("bad (arrayidx ar index) call: index with non-integer '%v'",
idx.Val[i].SexpString(nil))
}
k := myInt.Val
pos := k % int64(len(arr.Val))
if k < 0 {
mk := -k
mod := mk % int64(len(arr.Val))
pos = int64(len(arr.Val)) - mod
}
//Q("return pos %v", pos)
return arr.Val[pos], nil
}
func (arr *SexpArray) NumDim() int {
return 1
}
// SexpSelector: select a subset of an array:
// can be multidimensional index/slice
// and hence know its container and its position(s),
// and thus be able to read and write that position as
// need be.
type SexpArraySelector struct {
Select *SexpArray
Container *SexpArray
}
func (si *SexpArraySelector) SexpString(ps *PrintState) string {
Q("in SexpArraySelector.SexpString(), si.Container.Env = %p", si.Container.Env)
rhs, err := si.RHS(si.Container.Env)
if err != nil {
return fmt.Sprintf("(arraySelector %v %v)", si.Container.SexpString(ps), si.Select.SexpString(ps))
}
Q("in SexpArraySelector.SexpString(), rhs = %v", rhs.SexpString(ps))
Q("in SexpArraySelector.SexpString(), si.Container = %v", si.Container.SexpString(ps))
Q("in SexpArraySelector.SexpString(), si.Select = %v", si.Select.SexpString(ps))
return fmt.Sprintf("%v /*(arraySelector %v %v)*/", rhs.SexpString(ps), si.Container.SexpString(ps), si.Select.SexpString(ps))
}
// Type returns the type of the value.
func (si *SexpArraySelector) Type() *RegisteredType {
return GoStructRegistry.Lookup("arraySelector")
}
// RHS applies the selector to the contain and returns
// the value obtained.
func (x *SexpArraySelector) RHS(env *Zlisp) (Sexp, error) {
if len(x.Select.Val) != 1 {
return SexpNull, fmt.Errorf("SexpArraySelector: only " +
"size 1 selectors implemented")
}
var i int64
switch asInt := x.Select.Val[0].(type) {
case *SexpInt:
i = asInt.Val
default:
return SexpNull, fmt.Errorf("SexpArraySelector: int "+
"selector required; we saw %T", x.Select.Val[0])
}
if i < 0 {
return SexpNull, fmt.Errorf("SexpArraySelector: negative "+
"indexes not supported; we saw %v", i)
}
if i >= int64(len(x.Container.Val)) {
return SexpNull, fmt.Errorf("SexpArraySelector: index "+
"%v is out-of-bounds; length is %v", i, len(x.Container.Val))
}
ret := x.Container.Val[i]
Q("arraySelector returning ret = %#v", ret)
return ret, nil
}
// Selector stores indexing information that isn't
// yet materialized for getting or setting.
//
type Selector interface {
// RHS (right-hand-side) is used to dereference
// the pointer-like Selector, yielding a value suitable for the
// right-hand-side of an assignment statement.
//
RHS(env *Zlisp) (Sexp, error)
// AssignToSelection sets the selection to rhs
// The selected elements are the left-hand-side of the
// assignment *lhs = rhs
AssignToSelection(env *Zlisp, rhs Sexp) error
}
func (x *SexpArraySelector) AssignToSelection(env *Zlisp, rhs Sexp) error {
_, err := x.RHS(x.Container.Env) // check for errors
if err != nil {
return err
}
x.Container.Val[x.Select.Val[0].(*SexpInt).Val] = rhs
return nil
}
func (env *Zlisp) NewSexpArray(arr []Sexp) *SexpArray {
return &SexpArray{Val: arr, Env: env}
}

View File

@@ -0,0 +1 @@
package zygo

26
vendor/github.com/glycerine/zygomys/zygo/blake2.go generated vendored Normal file
View File

@@ -0,0 +1,26 @@
package zygo
import (
"encoding/binary"
"github.com/glycerine/blake2b"
)
// Blake2bUint64 returns an 8 byte BLAKE2b cryptographic
// hash of the raw.
//
// we're using the pure go: https://github.com/dchest/blake2b
//
// but the C-wrapped refence may be helpful as well --
//
// reference: https://godoc.org/github.com/codahale/blake2
// reference: https://blake2.net/
// reference: https://tools.ietf.org/html/rfc7693
//
func Blake2bUint64(raw []byte) uint64 {
cfg := &blake2b.Config{Size: 8}
h, err := blake2b.New(cfg)
panicOn(err)
h.Write(raw)
by := h.Sum(nil)
return binary.LittleEndian.Uint64(by[:8])
}

128
vendor/github.com/glycerine/zygomys/zygo/bsave.go generated vendored Normal file
View File

@@ -0,0 +1,128 @@
package zygo
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"os"
"github.com/glycerine/greenpack/msgp"
)
// (bsave value path) writes value as greenpack to file.
//
// (greenpack value) writes value as greenpack to SexpRaw in memory.
//
// bsave converts to binary with (togo) then saves the binary to file.
func WriteShadowGreenpackToFileFunction(env *Zlisp, name string, args []Sexp) (Sexp, error) {
narg := len(args)
if narg < 1 || narg > 2 {
return SexpNull, WrongNargs
}
// check arg[0]
var asHash *SexpHash
switch x := args[0].(type) {
default:
return SexpNull, fmt.Errorf("%s error: top value must be a hash or defmap; we see '%T'", name, args[0])
case *SexpHash:
// okay, good
asHash = x
}
switch name {
case "bsave":
if narg != 2 {
return SexpNull, WrongNargs
}
case "greenpack":
if narg != 1 {
return SexpNull, WrongNargs
}
var buf bytes.Buffer
_, err := toGreenpackHelper(env, asHash, &buf, "memory")
if err != nil {
return SexpNull, err
}
return &SexpRaw{Val: buf.Bytes()}, nil
}
// check arg[1]
var fn string
switch fna := args[1].(type) {
case *SexpStr:
fn = fna.S
default:
return SexpNull, fmt.Errorf("error: %s requires a string (SexpStr) path to write to as the second argument. we got type %T / value = %v", name, args[1], args[1])
}
// don't overwrite existing file
if FileExists(fn) {
return SexpNull, fmt.Errorf("error: %s refusing to write to existing file '%s'",
name, fn)
}
f, err := os.Create(fn)
if err != nil {
return SexpNull, fmt.Errorf("error: %s sees error trying to create file '%s': '%v'", name, fn, err)
}
defer f.Close()
_, err = toGreenpackHelper(env, asHash, f, fn)
return SexpNull, err
}
func toGreenpackHelper(env *Zlisp, asHash *SexpHash, f io.Writer, fn string) (Sexp, error) {
// create shadow structs
_, err := ToGoFunction(env, "togo", []Sexp{asHash})
if err != nil {
return SexpNull, fmt.Errorf("ToGo call sees error: '%v'", err)
}
if asHash.GoShadowStruct == nil {
return SexpNull, fmt.Errorf("GoShadowStruct was nil, on attempt to write to '%s'", fn)
}
enc, ok := interface{}(asHash.GoShadowStruct).(msgp.Encodable)
if !ok {
return SexpNull, fmt.Errorf("error: GoShadowStruct was not greenpack Encodable -- run `go generate` or add greenpack to the source file for type '%T'. on attempt to save to '%s'", asHash.GoShadowStruct, fn)
}
w := msgp.NewWriter(f)
err = msgp.Encode(w, enc)
if err != nil {
return SexpNull, fmt.Errorf("error: greenpack encoding to file '%s' of type '%T' sees error '%v'", fn, asHash.GoShadowStruct, err)
}
err = w.Flush()
return SexpNull, err
}
func ReadGreenpackFromFileFunction(env *Zlisp, name string, args []Sexp) (Sexp, error) {
narg := len(args)
if narg != 1 {
return SexpNull, WrongNargs
}
var fn string
switch fna := args[0].(type) {
case *SexpStr:
fn = fna.S
default:
return SexpNull, fmt.Errorf("%s requires a string path to read. we got type %T / value = %v", name, args[0], args[0])
}
if !FileExists(string(fn)) {
return SexpNull, fmt.Errorf("file '%s' does not exist", fn)
}
f, err := os.Open(fn)
if err != nil {
return SexpNull, err
}
defer f.Close()
by, err := ioutil.ReadAll(f)
if err != nil {
return SexpNull, err
}
return MsgpackToSexp(by, env)
}

879
vendor/github.com/glycerine/zygomys/zygo/builders.go generated vendored Normal file
View File

@@ -0,0 +1,879 @@
package zygo
import (
"fmt"
"reflect"
"strings"
"time"
)
// package.go: declare package, structs, function types
// A builder is a special kind of function. Like
// a macro it receives the un-evaluated tree
// of symbols from its caller. A builder
// can therefore be used to build new types
// and declarations new functions/methods.
//
// Like a function, a builder is called at
// run/evaluation time, not at definition time.
//
// Since it receives an un-evaluated tree of
// symbols, a builder must manually evaluate
// any arguments it wishes to find bindings for.
//
// The primary use here is to be able to define
// packages, structs, interfaces, functions,
// methods, and type aliases.
//
func (env *Zlisp) ImportPackageBuilder() {
env.AddBuilder("infixExpand", InfixBuilder)
env.AddBuilder("infix", InfixBuilder)
env.AddBuilder(":", ColonAccessBuilder)
env.AddBuilder("sys", SystemBuilder)
env.AddBuilder("struct", StructBuilder)
env.AddBuilder("func", FuncBuilder)
env.AddBuilder("method", FuncBuilder)
env.AddBuilder("interface", InterfaceBuilder)
//env.AddBuilder("package", PackageBuilder)
//env.AddBuilder("import", ImportBuilder)
env.AddBuilder("var", VarBuilder)
env.AddBuilder("expectError", ExpectErrorBuilder)
env.AddBuilder("comma", CommaBuilder)
// env.AddBuilder("&", AddressOfBuilder)
env.AddBuilder("import", ImportPackageBuilder)
env.AddFunction("sliceOf", SliceOfFunction)
env.AddFunction("ptr", PointerToFunction)
}
var sxSliceOf *SexpFunction = MakeUserFunction("sliceOf", SliceOfFunction)
var sxArrayOf *SexpFunction = MakeUserFunction("arrayOf", ArrayOfFunction)
type SexpUserVarDefn struct {
Name string
}
type RecordDefn struct {
Name string
Fields []*SexpField
FieldType map[string]*RegisteredType
}
func NewRecordDefn() *RecordDefn {
return &RecordDefn{
FieldType: make(map[string]*RegisteredType),
}
}
func (r *RecordDefn) SetName(name string) {
r.Name = name
}
func (r *RecordDefn) SetFields(flds []*SexpField) {
r.Fields = flds
for _, f := range flds {
g := (*SexpHash)(f)
rt, err := g.HashGet(nil, f.KeyOrder[0])
panicOn(err)
r.FieldType[g.KeyOrder[0].(*SexpSymbol).name] = rt.(*RegisteredType)
}
}
func (p *RecordDefn) Type() *RegisteredType {
rt := GoStructRegistry.Registry[p.Name]
//Q("RecordDefn) Type() sees rt = %v", rt)
return rt
}
// pretty print a struct
func (p *RecordDefn) SexpString(ps *PrintState) string {
Q("RecordDefn::SexpString() called!")
if len(p.Fields) == 0 {
return fmt.Sprintf("(struct %s)", p.Name)
}
s := fmt.Sprintf("(struct %s [\n", p.Name)
w := make([][]int, len(p.Fields))
maxnfield := 0
for i, f := range p.Fields {
w[i] = f.FieldWidths()
Q("w[i=%v] = %v", i, w[i])
maxnfield = maxi(maxnfield, len(w[i]))
}
biggestCol := make([]int, maxnfield)
Q("\n")
for j := 0; j < maxnfield; j++ {
for i := range p.Fields {
Q("i= %v, j=%v, len(w[i])=%v check=%v", i, j, len(w[i]), len(w[i]) < j)
if j < len(w[i]) {
biggestCol[j] = maxi(biggestCol[j], w[i][j]+1)
}
}
}
Q("RecordDefn::SexpString(): maxnfield = %v, out of %v", maxnfield, len(p.Fields))
Q("RecordDefn::SexpString(): biggestCol = %#v", biggestCol)
// computing padding
// x
// xx xx
// xxxxxxx x
// xxx x x x
//
// becomes
//
// x
// xx xx
// xxxxxxx
// xxx x x x
Q("pad = %#v", biggestCol)
for _, f := range p.Fields {
s += " " + f.AlignString(biggestCol) + "\n"
}
s += " ])\n"
return s
}
func maxi(a, b int) int {
if a > b {
return a
}
return b
}
type SexpField SexpHash
func (r SexpField) Type() *RegisteredType {
return r.GoStructFactory
}
// compute key and value widths to assist alignment
func (f *SexpField) FieldWidths() []int {
hash := (*SexpHash)(f)
wide := []int{}
for _, key := range hash.KeyOrder {
val, err := hash.HashGet(nil, key)
str := ""
if err == nil {
switch s := key.(type) {
case *SexpStr:
str += s.S + ":"
case *SexpSymbol:
str += s.name + ":"
default:
str += key.SexpString(nil) + ":"
}
wide = append(wide, len(str))
wide = append(wide, len(val.SexpString(nil))+1)
} else {
panic(err)
}
}
return wide
}
func (f *SexpField) AlignString(pad []int) string {
hash := (*SexpHash)(f)
str := " (" + hash.TypeName + " "
spc := " "
for i, key := range hash.KeyOrder {
val, err := hash.HashGet(nil, key)
r := ""
if err == nil {
switch s := key.(type) {
case *SexpStr:
r += s.S + ":"
case *SexpSymbol:
r += s.name + ":"
default:
r += key.SexpString(nil) + ":"
}
xtra := pad[i*2] - len(r)
if xtra < 0 {
panic(fmt.Sprintf("xtra = %d, pad[i=%v]=%v, len(r)=%v (r=%v)", xtra, i, pad[i], len(r), r))
}
leftpad := strings.Repeat(" ", xtra)
vs := val.SexpString(nil)
rightpad := strings.Repeat(" ", pad[(i*2)+1]-len(vs))
if i == 0 {
spc = " "
} else {
spc = ""
}
r = leftpad + r + spc + vs + rightpad
} else {
panic(err)
}
str += r
}
if len(hash.Map) > 0 {
return str[:len(str)-1] + ")"
}
return str + ")"
}
func (f *SexpField) SexpString(ps *PrintState) string {
hash := (*SexpHash)(f)
str := " (" + hash.TypeName + " "
for i, key := range hash.KeyOrder {
val, err := hash.HashGet(nil, key)
if err == nil {
switch s := key.(type) {
case *SexpStr:
str += s.S + ":"
case *SexpSymbol:
str += s.name + ":"
default:
str += key.SexpString(nil) + ":"
}
if i > 0 {
str += val.SexpString(nil) + " "
} else {
str += val.SexpString(nil) + " "
}
} else {
panic(err)
}
}
if len(hash.Map) > 0 {
return str[:len(str)-1] + ")"
}
return str + ")"
}
func StructBuilder(env *Zlisp, name string,
args []Sexp) (Sexp, error) {
n := len(args)
if n < 1 {
return SexpNull, fmt.Errorf("struct name is missing. use: " +
"(struct struct-name ...)\n")
}
Q("in struct builder, name = '%s', args = ", name)
for i := range args {
Q("args[%v] = '%s' of type %T", i, args[i].SexpString(nil), args[i])
}
var symN *SexpSymbol
switch b := args[0].(type) {
case *SexpSymbol:
symN = b
case *SexpPair:
sy, isQuo := isQuotedSymbol(b)
if isQuo {
symN = sy.(*SexpSymbol)
} else {
return SexpNull, fmt.Errorf("bad struct name: symbol required")
}
default:
return SexpNull, fmt.Errorf("bad struct name: symbol required")
}
Q("good: have struct name '%v'", symN)
env.datastack.PushExpr(SexpNull)
structName := symN.name
{
// begin enable recursion -- add ourselves to the env early, then
// update later, so that structs can refer to themselves.
udsR := NewRecordDefn()
udsR.SetName(structName)
rtR := NewRegisteredType(func(env *Zlisp, h *SexpHash) (interface{}, error) {
return udsR, nil
})
rtR.UserStructDefn = udsR
rtR.DisplayAs = structName
GoStructRegistry.RegisterUserdef(rtR, false, structName)
// overwrite any existing definition, deliberately ignore any error,
// as there may not be a prior definition present at all.
env.linearstack.DeleteSymbolFromTopOfStackScope(symN)
err := env.LexicalBindSymbol(symN, rtR)
if err != nil {
return SexpNull, fmt.Errorf("struct builder could not bind symbol '%s': '%v'",
structName, err)
}
// end enable recursion
}
var xar []Sexp
var flat []*SexpField
if n > 2 {
return SexpNull, fmt.Errorf("bad struct declaration: more than two arguments." +
"prototype is (struct name [(field ...)*] )")
}
if n == 2 {
Q("in case n == 2")
switch ar := args[1].(type) {
default:
return SexpNull, fmt.Errorf("bad struct declaration '%v': second argument "+
"must be a slice of fields."+
" prototype is (struct name [(field ...)*] )", structName)
case *SexpArray:
arr := ar.Val
if len(arr) == 0 {
// allow this
} else {
// dup to avoid messing with the stack on eval:
//dup := env.Duplicate()
for i, ele := range arr {
Q("about to eval i=%v", i)
//ev, err := dup.EvalExpressions([]Sexp{ele})
ev, err := EvalFunction(env, "evalStructBuilder", []Sexp{ele})
Q("done with eval i=%v. ev=%v", i, ev.SexpString(nil))
if err != nil {
return SexpNull, fmt.Errorf("bad struct declaration '%v': bad "+
"field at array entry %v; error was '%v'", structName, i, err)
}
Q("checking for isHash at i=%v", i)
asHash, isHash := ev.(*SexpField)
if !isHash {
Q("was not hash, instead was %T", ev)
return SexpNull, fmt.Errorf("bad struct declaration '%v': bad "+
"field array at entry %v; a (field ...) is required. Instead saw '%T'/with value = '%v'",
structName, i, ev, ev.SexpString(nil))
}
Q("good eval i=%v, ev=%#v / %v", i, ev, ev.SexpString(nil))
ko := asHash.KeyOrder
if len(ko) == 0 {
return SexpNull, fmt.Errorf("bad struct declaration '%v': bad "+
"field array at entry %v; field had no name",
structName, i)
}
Q("ko = '%#v'", ko)
first := ko[0]
Q("first = '%#v'", first)
xar = append(xar, first)
xar = append(xar, ev)
flat = append(flat, ev.(*SexpField))
}
Q("no err from EvalExpressions, got xar = '%#v'", xar)
}
}
} // end n == 2
uds := NewRecordDefn()
uds.SetName(structName)
uds.SetFields(flat)
Q("good: made typeDefnHash: '%s'", uds.SexpString(nil))
rt := NewRegisteredType(func(env *Zlisp, h *SexpHash) (interface{}, error) {
return uds, nil
})
rt.UserStructDefn = uds
rt.DisplayAs = structName
GoStructRegistry.RegisterUserdef(rt, false, structName)
Q("good: registered new userdefined struct '%s'", structName)
// replace our recursive-reference-enabling symbol with the real one.
err := env.linearstack.DeleteSymbolFromTopOfStackScope(symN)
if err != nil {
return SexpNull, fmt.Errorf("internal error: should have already had symbol '%s' "+
"bound, but DeleteSymbolFromTopOfStackScope returned error: '%v'",
symN.name, err)
}
err = env.LexicalBindSymbol(symN, rt)
if err != nil {
return SexpNull, fmt.Errorf("late: struct builder could not bind symbol '%s': '%v'",
structName, err)
}
Q("good: bound symbol '%s' to RegisteredType '%s'", symN.SexpString(nil), rt.SexpString(nil))
return rt, nil
}
func InterfaceBuilder(env *Zlisp, name string,
args []Sexp) (Sexp, error) {
nargs := len(args)
switch {
case nargs < 1:
return SexpNull, fmt.Errorf("interface name is missing. use: " +
"(interface interface-name [...])\n")
case nargs == 1:
return SexpNull, fmt.Errorf("interface array of methods missing. use: " +
"(interface interface-name [...])\n")
case nargs > 2:
return SexpNull, WrongNargs
}
// P("in interface builder, past arg check")
var iname string
var symN *SexpSymbol
switch sy := args[0].(type) {
case *SexpSymbol:
symN = sy
iname = sy.name
default:
return SexpNull, fmt.Errorf("interface name must be a symbol; we got %T", args[0])
}
// sanity check the name
builtin, builtTyp := env.IsBuiltinSym(symN)
if builtin {
return SexpNull,
fmt.Errorf("already have %s '%s', refusing to overwrite with interface",
builtTyp, symN.name)
}
if env.HasMacro(symN) {
return SexpNull, fmt.Errorf("Already have macro named '%s': refusing"+
" to define interface of same name.", symN.name)
}
// end sanity check the name
var arrMeth *SexpArray
switch ar := args[1].(type) {
case *SexpArray:
arrMeth = ar
default:
return SexpNull, fmt.Errorf("interface method vector expected after name; we got %T", args[1])
}
// P("in interface builder, args = ")
// for i := range args {
// P("args[%v] = '%s'", i, args[i].SexpString(nil))
// }
methods := make([]*SexpFunction, 0)
methodSlice := arrMeth.Val
if len(methodSlice) > 0 {
//dup := env.Duplicate()
for i := range methodSlice {
//ev, err := dup.EvalExpressions([]Sexp{methodSlice[i]})
ev, err := EvalFunction(env, "evalInterface", []Sexp{methodSlice[i]})
if err != nil {
return SexpNull, fmt.Errorf("error parsing the %v-th method in interface definition: '%v'", i, err)
}
me, gotFunc := ev.(*SexpFunction)
if !gotFunc {
return SexpNull,
fmt.Errorf("error parsing the %v-th method in interface: was not function but rather %T",
i, ev)
}
methods = append(methods, me)
}
}
decl := &SexpInterfaceDecl{
name: iname,
methods: methods,
}
return decl, nil
}
func SliceOfFunction(env *Zlisp, name string,
args []Sexp) (Sexp, error) {
if len(args) != 1 {
return SexpNull, fmt.Errorf("argument x to (%s x) is missing. use: "+
"(%s a-regtype)\n", name, name)
}
Q("in SliceOfFunction")
var rt *RegisteredType
switch arg := args[0].(type) {
case *RegisteredType:
rt = arg
case *SexpHash:
rt = arg.GoStructFactory
default:
return SexpNull, fmt.Errorf("argument tx in (%s x) was not regtype, "+
"instead type %T displaying as '%v' ",
name, arg, arg.SexpString(nil))
}
Q("sliceOf arg = '%s' with type %T", args[0].SexpString(nil), args[0])
sliceRt := GoStructRegistry.GetOrCreateSliceType(rt)
Q("in SliceOfFunction: returning sliceRt = '%#v'", sliceRt)
return sliceRt, nil
}
func PointerToFunction(env *Zlisp, name string,
args []Sexp) (Sexp, error) {
if len(args) != 1 {
return SexpNull, fmt.Errorf("argument to pointer-to is missing. use: "+
"(%s a-regtype)\n", name)
}
//P("in PointerToFunction(): args[0] = '%#v'", args[0])
var rt *RegisteredType
switch arg := args[0].(type) {
case *RegisteredType:
rt = arg
case *SexpHash:
rt = arg.GoStructFactory
case *SexpPointer:
// dereference operation, rather than type declaration
//P("dereference operation on *SexpPointer detected, returning target")
if arg == nil || arg.Target == nil {
return SexpNull, fmt.Errorf("illegal to dereference nil pointer")
}
return arg.Target, nil
case *SexpReflect:
Q("dereference operation on SexpReflect detected")
// TODO what goes here?
return SexpNull, fmt.Errorf("illegal to dereference nil pointer")
case *SexpSymbol:
if arg.isDot {
// (* h.a) dereferencing a dot symbol
resolved, err := dotGetSetHelper(env, arg.name, nil)
if err != nil {
return nil, err
}
return resolved, nil
} else {
panic("TODO: what goes here, for (* sym) where sym is a regular symbol")
}
default:
return SexpNull, fmt.Errorf("argument x in (%s x) was not regtype or SexpPointer, "+
"instead type %T displaying as '%v' ",
name, arg, arg.SexpString(nil))
}
Q("pointer-to arg = '%s' with type %T", args[0].SexpString(nil), args[0])
ptrRt := GoStructRegistry.GetOrCreatePointerType(rt)
return ptrRt, nil
}
func StructConstructorFunction(env *Zlisp, name string, args []Sexp) (Sexp, error) {
Q("in struct ctor, name = '%s', args = %#v", name, args)
return MakeHash(args, name, env)
}
func BaseTypeConstructorFunction(env *Zlisp, name string, args []Sexp) (Sexp, error) {
Q("in base type ctor, args = '%#v'", args)
if len(args) < 1 {
return SexpNull, WrongNargs
}
Q("in base ctor, name = '%s', args = %#v", name, args)
return SexpNull, nil
}
func baseConstruct(env *Zlisp, f *RegisteredType, nargs int) (Sexp, error) {
if nargs > 1 {
return SexpNull, fmt.Errorf("%d is too many arguments for a base type constructor", nargs)
}
v, err := f.Factory(env, nil)
if err != nil {
return SexpNull, err
}
Q("see call to baseConstruct, v = %v/type=%T", v, v)
if nargs == 0 {
switch v.(type) {
case *int, *uint8, *uint16, *uint32, *uint64, *int8, *int16, *int32, *int64:
return &SexpInt{}, nil
case *float32, *float64:
return &SexpFloat{}, nil
case *string:
return &SexpStr{S: ""}, nil
case *bool:
return &SexpBool{Val: false}, nil
case *time.Time:
return &SexpTime{}, nil
default:
return SexpNull, fmt.Errorf("unhandled no-arg case in baseConstruct, v has type=%T", v)
}
}
// get our one argument
args, err := env.datastack.PopExpressions(1)
if err != nil {
return SexpNull, err
}
arg := args[0]
switch v.(type) {
case *int, *uint8, *uint16, *uint32, *uint64, *int8, *int16, *int32, *int64:
myint, ok := arg.(*SexpInt)
if !ok {
return SexpNull, fmt.Errorf("cannot convert %T to int", arg)
}
return myint, nil
case *float32, *float64:
myfloat, ok := arg.(*SexpFloat)
if !ok {
return SexpNull, fmt.Errorf("cannot convert %T to float", arg)
}
return myfloat, nil
case *string:
mystring, ok := arg.(*SexpStr)
if !ok {
return SexpNull, fmt.Errorf("cannot convert %T to string", arg)
}
return mystring, nil
case *bool:
mybool, ok := arg.(*SexpBool)
if !ok {
return SexpNull, fmt.Errorf("cannot convert %T to bool", arg)
}
return mybool, nil
default:
return SexpNull, fmt.Errorf("unhandled case in baseConstruct, arg = %#v/type=%T", arg, arg)
}
//return SexpNull, fmt.Errorf("unhandled no-arg case in baseConstruct, v has type=%T", v)
}
// generate fixed size array
func ArrayOfFunction(env *Zlisp, name string,
args []Sexp) (Sexp, error) {
if len(args) != 2 {
return SexpNull, fmt.Errorf("insufficient arguments to ([size] regtype) array constructor. use: " +
"([size...] a-regtype)\n")
}
sz := 0
Q("args = %#v in ArrayOfFunction", args)
switch ar := args[1].(type) {
case *SexpArray:
if len(ar.Val) == 0 {
return SexpNull, fmt.Errorf("at least one size must be specified in array constructor; e.g. ([size ...] regtype)")
}
asInt, isInt := ar.Val[0].(*SexpInt)
if !isInt {
return SexpNull, fmt.Errorf("size must be an int (not %T) in array constructor; e.g. ([size ...] regtype)", ar.Val[0])
}
sz = int(asInt.Val)
// TODO: implement multiple dimensional arrays (matrixes etc).
default:
return SexpNull, fmt.Errorf("at least one size must be specified in array constructor; e.g. ([size ...] regtype)")
}
var rt *RegisteredType
switch arg := args[0].(type) {
case *RegisteredType:
rt = arg
case *SexpHash:
rt = arg.GoStructFactory
default:
return SexpNull, fmt.Errorf("argument tx in (%s x) was not regtype, "+
"instead type %T displaying as '%v' ",
name, arg, arg.SexpString(nil))
}
//Q("arrayOf arg = '%s' with type %T", args[0].SexpString(nil), args[0])
derivedType := reflect.ArrayOf(sz, rt.TypeCache)
arrayRt := NewRegisteredType(func(env *Zlisp, h *SexpHash) (interface{}, error) {
return reflect.New(derivedType), nil
})
arrayRt.DisplayAs = fmt.Sprintf("(%s %s)", name, rt.DisplayAs)
arrayName := "arrayOf" + rt.RegisteredName
GoStructRegistry.RegisterUserdef(arrayRt, false, arrayName)
return arrayRt, nil
}
func VarBuilder(env *Zlisp, name string,
args []Sexp) (Sexp, error) {
n := len(args)
if n != 2 {
return SexpNull, fmt.Errorf("var name/type missing. use: " +
"(var name regtype)\n")
}
Q("in var builder, name = '%s', args = ", name)
for i := range args {
Q("args[%v] = '%s' of type %T", i, args[i].SexpString(nil), args[i])
}
var symN *SexpSymbol
switch b := args[0].(type) {
case *SexpSymbol:
symN = b
case *SexpPair:
sy, isQuo := isQuotedSymbol(b)
if isQuo {
symN = sy.(*SexpSymbol)
} else {
return SexpNull, fmt.Errorf("bad var name: symbol required")
}
default:
return SexpNull, fmt.Errorf("bad var name: symbol required")
}
Q("good: have var name '%v'", symN)
//dup := env.Duplicate()
Q("about to eval args[1]=%v", args[1])
//ev, err := dup.EvalExpressions(args[1:2])
ev, err := EvalFunction(env, "evalVar", args[1:2])
Q("done with eval, ev=%v / type %T", ev.SexpString(nil), ev)
if err != nil {
return SexpNull, fmt.Errorf("bad var declaration, problem with type '%v': %v", args[1].SexpString(nil), err)
}
var rt *RegisteredType
switch myrt := ev.(type) {
case *RegisteredType:
rt = myrt
default:
return SexpNull, fmt.Errorf("bad var declaration, type '%v' is unknown", rt.SexpString(nil))
}
val, err := rt.Factory(env, nil)
if err != nil {
return SexpNull, fmt.Errorf("var declaration error: could not make type '%s': %v",
rt.SexpString(nil), err)
}
var valSexp Sexp
Q("val is of type %T", val)
switch v := val.(type) {
case Sexp:
valSexp = v
case reflect.Value:
Q("v is of type %T", v.Interface())
switch rd := v.Interface().(type) {
case ***RecordDefn:
Q("we have RecordDefn rd = %#v", *rd)
}
valSexp = &SexpReflect{Val: reflect.ValueOf(v)}
default:
valSexp = &SexpReflect{Val: reflect.ValueOf(v)}
}
Q("var decl: valSexp is '%v'", valSexp.SexpString(nil))
err = env.LexicalBindSymbol(symN, valSexp)
if err != nil {
return SexpNull, fmt.Errorf("var declaration error: could not bind symbol '%s': %v",
symN.name, err)
}
Q("good: var decl bound symbol '%s' to '%s' of type '%s'", symN.SexpString(nil), valSexp.SexpString(nil), rt.SexpString(nil))
env.datastack.PushExpr(valSexp)
return SexpNull, nil
}
func ExpectErrorBuilder(env *Zlisp, name string, args []Sexp) (Sexp, error) {
narg := len(args)
if narg != 2 {
return SexpNull, WrongNargs
}
dup := env.Duplicate()
es, err := dup.EvalExpressions(args[0:1])
if err != nil {
return SexpNull, fmt.Errorf("error evaluating the error string to expect: %s", err)
}
var expectedError *SexpStr
switch e := es.(type) {
case *SexpStr:
expectedError = e
default:
return SexpNull, fmt.Errorf("first arg to expectError must be the string of the error to expect")
}
Q("expectedError = %v", expectedError)
ev, err := dup.EvalExpressions(args[1:2])
Q("done with eval, ev=%v / type %T. err = %v", ev.SexpString(nil), ev, err)
if err != nil {
if err.Error() == expectedError.S {
return SexpNull, nil
}
return SexpNull, fmt.Errorf("expectError expected '%s' but saw '%s'", expectedError.S, err)
}
if expectedError.S == "" {
return SexpNull, nil
}
return SexpNull, fmt.Errorf("expectError expected '%s' but got no error", expectedError.S)
}
func ColonAccessBuilder(env *Zlisp, name string, args []Sexp) (Sexp, error) {
if len(args) < 1 || len(args) > 3 {
return SexpNull, WrongNargs
}
////Q("ColonAccessBuilder, args = %#v", args)
name = "hget"
//dup := env.Duplicate()
//collec, err := dup.EvalExpressions(args[1:2])
collec, err := EvalFunction(env, "evalColonAccess", args[1:2])
if err != nil {
return SexpNull, err
}
swapped := args
swapped[1] = swapped[0]
swapped[0] = collec
if len(args) == 3 {
// have default, needs eval too
//defaul, err := dup.EvalExpressions(args[2:3])
defaul, err := EvalFunction(env, "evalColonDefault", args[2:3])
if err != nil {
return SexpNull, err
}
swapped[2] = defaul
}
switch sx := collec.(type) {
case *SexpHash:
return HashAccessFunction(env, name, swapped)
case *SexpArray:
return ArrayAccessFunction(env, name, swapped)
case *SexpArraySelector:
Q("*SexpSelector seen in : operator form.")
return sx.RHS(env)
}
return SexpNull, fmt.Errorf("second argument to ':' function must be hash or array")
}
// CommaBuilder turns expressions on the LHS and RHS like {a,b,c = 1,2,3}
// into arrays (set [a b c] [1 2 3])
func CommaBuilder(env *Zlisp, name string, args []Sexp) (Sexp, error) {
n := len(args)
if n < 1 {
return SexpNull, nil
}
res := make([]Sexp, 0)
for i := range args {
commaHelper(args[i], &res)
}
return &SexpArray{Val: res}, nil
}
func commaHelper(a Sexp, res *[]Sexp) {
//Q("top of commaHelper with a = '%s'", a.SexpString(nil))
switch x := a.(type) {
case *SexpPair:
sy, isQuo := isQuotedSymbol(x)
if isQuo {
symN := sy.(*SexpSymbol)
//Q("have quoted symbol symN=%v", symN.SexpString(nil))
*res = append(*res, symN)
return
}
ar, err := ListToArray(x)
if err != nil || len(ar) < 1 {
return
}
switch sym := ar[0].(type) {
case *SexpSymbol:
if sym.name == "comma" {
//Q("have recursive comma")
over := ar[1:]
for i := range over {
commaHelper(over[i], res)
}
} else {
//Q("have symbol sym = '%v'", sym.SexpString(nil))
*res = append(*res, a)
}
default:
*res = append(*res, a)
}
default:
*res = append(*res, a)
}
}

209
vendor/github.com/glycerine/zygomys/zygo/callgo.go generated vendored Normal file
View File

@@ -0,0 +1,209 @@
package zygo
import (
"fmt"
"reflect"
"runtime"
)
// call Go methods
// Using reflection, invoke a Go method on a struct or interface.
// args[0] is a hash with an an attached GoStruct
// args[1] is a hash representing a method call on that struct.
// The returned Sexp is a hash that represents the result of that call.
func CallGoMethodFunction(env *Zlisp, name string, args []Sexp) (Sexp, error) {
Q("_method user func running!\n")
// protect against bad calls/bad reflection
var wasPanic bool
var recovered interface{}
tr := make([]byte, 16384)
trace := &tr
sx, err := func() (Sexp, error) {
defer func() {
recovered = recover()
if recovered != nil {
wasPanic = true
nbyte := runtime.Stack(*trace, false)
*trace = (*trace)[:nbyte]
}
}()
narg := len(args)
if narg < 2 {
return SexpNull, WrongNargs
}
obj, isHash := args[0].(*SexpHash)
if !isHash {
return SexpNull, fmt.Errorf("_method error: first argument must be a hash or defmap (a record) with an attached GoObject")
}
var methodname string
switch m := args[1].(type) {
case *SexpSymbol:
methodname = m.name
case *SexpStr:
methodname = m.S
default:
return SexpNull, fmt.Errorf("_method error: second argument must be a method name in symbol or string form (got %T)", args[1])
}
// get the method list, verify the method exists and get its type
if obj.NumMethod == -1 {
err := obj.SetMethodList(env)
if err != nil {
return SexpNull, fmt.Errorf("could not get method list for object: %s", err)
}
}
var method reflect.Method
found := false
for _, me := range obj.GoMethods {
if me.Name == methodname {
method = me
found = true
break
}
}
if !found {
return SexpNull, fmt.Errorf("no such method '%s' on %s. choices are: %s",
methodname, obj.TypeName,
(obj.GoMethSx).SexpString(nil))
}
// INVAR: var method holds our call target
// try always expecting this to be already done... test crashes
//P("in CallGoMethod '%s' obj.GoShadowStructVa = '%#v'", methodname, obj.GoShadowStructVa)
if obj.GoShadowStructVa.Kind() == reflect.Invalid {
// ready the struct... but only because there isn't already a shadow struct there!!
if !obj.ShadowSet {
_, err := ToGoFunction(env, "togo", []Sexp{obj})
if err != nil {
return SexpNull, fmt.Errorf("error converting object to Go struct: '%s'", err)
}
}
}
inputVa := []reflect.Value{(obj.GoShadowStructVa)}
// prep args.
needed := method.Type.NumIn() - 1 // one for the receiver
avail := narg - 2
if needed != avail {
// TODO: support varargs eventually
return SexpNull, fmt.Errorf("method %s needs %d arguments, but we have %d", method.Name, needed, avail)
}
var va reflect.Value
for i := 2; i < narg; i++ {
typ := method.Type.In(i - 1)
pdepth := PointerDepth(typ)
// we only handle 0 and 1 for now
Q("pdepth = %v\n", pdepth)
switch pdepth {
case 0:
va = reflect.New(typ)
case 1:
// handle the common single pointer to struct case
va = reflect.New(typ.Elem())
default:
return SexpNull, fmt.Errorf("error converting %d-th argument to "+
"Go: we don't handle double pointers", i-2)
}
Q("converting to go '%#v' into -> %#v\n", args[i], va.Interface())
iface, err := SexpToGoStructs(args[i], va.Interface(), env, nil)
if err != nil {
return SexpNull, fmt.Errorf("error converting %d-th "+
"argument to Go: '%s'", i-2, err)
}
switch pdepth {
case 0:
inputVa = append(inputVa, reflect.ValueOf(iface).Elem())
case 1:
inputVa = append(inputVa, reflect.ValueOf(iface))
}
Q("\n allocated new %T/val=%#v /i=%#v\n", va, va, va.Interface())
}
//P("_method: about to .Call by reflection!\n")
out := method.Func.Call(inputVa)
var iout []interface{}
for _, o := range out {
iout = append(iout, o.Interface())
}
Q("done with _method call, iout = %#v\n", iout)
Q("done with _method call, iout[0] = %#v\n", iout[0])
nout := len(out)
r := make([]Sexp, 0)
for i := 0; i < nout; i++ {
f := out[i].Interface()
switch e := f.(type) {
case nil:
r = append(r, SexpNull)
case int64:
r = append(r, &SexpInt{Val: e})
case int:
r = append(r, &SexpInt{Val: int64(e)})
case error:
r = append(r, &SexpError{e})
case string:
r = append(r, &SexpStr{S: e})
case float64:
r = append(r, &SexpFloat{Val: e})
case []byte:
r = append(r, &SexpRaw{Val: e})
case rune:
r = append(r, &SexpChar{Val: e})
default:
// go through the type registry
found := false
for hashName, factory := range GoStructRegistry.Registry {
st, err := factory.Factory(env, nil)
if err != nil {
return SexpNull, fmt.Errorf("MakeHash '%s' problem on Factory call: %s",
hashName, err)
}
Q("got st from Factory, checking if types match")
if reflect.ValueOf(st).Type() == out[i].Type() {
Q("types match")
retHash, err := MakeHash([]Sexp{}, factory.RegisteredName, env)
if err != nil {
return SexpNull, fmt.Errorf("MakeHash '%s' problem: %s",
hashName, err)
}
Q("filling from shadow")
err = retHash.FillHashFromShadow(env, f)
if err != nil {
return SexpNull, err
}
r = append(r, retHash)
found = true
break
}
}
if !found {
r = append(r, &SexpReflect{Val: out[i]})
}
}
}
return env.NewSexpArray(r), nil
}()
if wasPanic {
return SexpNull, fmt.Errorf("\n recovered from panic "+
"during CallGo. panic on = '%v'\n"+
"stack trace:\n%s\n", recovered, string(*trace))
}
return sx, err
}
// detect if inteface is holding anything
func NilOrHoldsNil(iface interface{}) bool {
if iface == nil {
return true
}
return reflect.ValueOf(iface).IsNil()
}

54
vendor/github.com/glycerine/zygomys/zygo/cfg.go generated vendored Normal file
View File

@@ -0,0 +1,54 @@
package zygo
import (
"flag"
)
// configure a glisp repl
type ZlispConfig struct {
CpuProfile string
MemProfile string
ExitOnFailure bool
CountFuncCalls bool
Flags *flag.FlagSet
ExtensionsVersion string
Command string
Sandboxed bool
Quiet bool
Trace bool
LoadDemoStructs bool
AfterScriptDontExit bool
// liner bombs under emacs, avoid it with this flag.
NoLiner bool
Prompt string // default "zygo> "
}
func NewZlispConfig(cmdname string) *ZlispConfig {
return &ZlispConfig{
Flags: flag.NewFlagSet(cmdname, flag.ExitOnError),
}
}
// call DefineFlags before myflags.Parse()
func (c *ZlispConfig) DefineFlags() {
c.Flags.StringVar(&c.CpuProfile, "cpuprofile", "", "write cpu profile to file")
c.Flags.StringVar(&c.MemProfile, "memprofile", "", "write mem profile to file")
c.Flags.BoolVar(&c.ExitOnFailure, "exitonfail", false, "exit on failure instead of starting repl")
c.Flags.BoolVar(&c.CountFuncCalls, "countcalls", false, "count how many times each function is run")
c.Flags.StringVar(&c.Command, "c", "", "expressions to evaluate")
c.Flags.BoolVar(&c.AfterScriptDontExit, "i", false, "after running the command line script, remain interactive rather than exiting")
c.Flags.BoolVar(&c.Sandboxed, "sandbox", false, "run sandboxed; disallow system/external interaction functions")
c.Flags.BoolVar(&c.Quiet, "quiet", false, "start repl without printing the version/mode/help banner")
c.Flags.BoolVar(&c.Trace, "trace", false, "trace execution (warning: very verbose and slow)")
c.Flags.BoolVar(&c.LoadDemoStructs, "demo", false, "load the demo structs: Event, Snoopy, Hornet, Weather and friends.")
}
// call c.ValidateConfig() after myflags.Parse()
func (c *ZlispConfig) ValidateConfig() error {
if c.Prompt == "" {
c.Prompt = "zygo> "
}
return nil
}

70
vendor/github.com/glycerine/zygomys/zygo/channels.go generated vendored Normal file
View File

@@ -0,0 +1,70 @@
package zygo
import (
"errors"
"fmt"
)
type SexpChannel struct {
Val chan Sexp
Typ *RegisteredType
}
func (ch *SexpChannel) SexpString(ps *PrintState) string {
return "[chan]"
}
func (ch *SexpChannel) Type() *RegisteredType {
return ch.Typ // TODO what should this be?
}
func MakeChanFunction(env *Zlisp, name string,
args []Sexp) (Sexp, error) {
if len(args) > 1 {
return SexpNull, WrongNargs
}
size := 0
if len(args) == 1 {
switch t := args[0].(type) {
case *SexpInt:
size = int(t.Val)
default:
return SexpNull, errors.New(
fmt.Sprintf("argument to %s must be int", name))
}
}
return &SexpChannel{Val: make(chan Sexp, size)}, nil
}
func ChanTxFunction(env *Zlisp, name string,
args []Sexp) (Sexp, error) {
if len(args) < 1 {
return SexpNull, WrongNargs
}
var channel chan Sexp
switch t := args[0].(type) {
case *SexpChannel:
channel = chan Sexp(t.Val)
default:
return SexpNull, errors.New(
fmt.Sprintf("argument 0 of %s must be channel", name))
}
if name == "send" {
if len(args) != 2 {
return SexpNull, WrongNargs
}
channel <- args[1]
return SexpNull, nil
}
return <-channel, nil
}
func (env *Zlisp) ImportChannels() {
env.AddFunction("makeChan", MakeChanFunction)
env.AddFunction("send", ChanTxFunction)
env.AddFunction("<!", ChanTxFunction)
}

93
vendor/github.com/glycerine/zygomys/zygo/check.go generated vendored Normal file
View File

@@ -0,0 +1,93 @@
package zygo
import (
"fmt"
)
// FunctionCallNameTypeCheck type checks a function call.
func (env *Zlisp) FunctionCallNameTypeCheck(f *SexpFunction, nargs *int) error {
if f.inputTypes != nil {
Q("FunctionCallNameTypeCheck sees inputTypes: '%v'", f.inputTypes.SexpString(nil))
} else {
return nil // no type checking requested
}
if f.varargs {
return nil // name/type checking for vargarg not currently implemented.
}
// our call arguments prepared -- will be pushed to the datastack
finalArgs := make([]Sexp, f.inputTypes.NumKeys)
// pop everything off the stack, will push finalArgs later
exprs, err := env.datastack.PopExpressions(*nargs)
if err != nil {
return err
}
// map the named submitted args, for fast lookup by name
submittedByName := make(map[string]Sexp)
// prep submittedByName
for i := 0; i < *nargs; i++ {
switch sym := exprs[i].(type) {
case *SexpSymbol:
if sym.colonTail {
Q("in env.CallFunction, have symbol.colonTail: exprs[%v]='%#v'", i, sym)
typ, err := f.inputTypes.HashGet(env, sym)
if err != nil {
return fmt.Errorf("%s takes no argument '%s'", f.name, sym.name)
}
if i == (*nargs)-1 {
return fmt.Errorf("named parameter '%s' not followed by value", sym.name)
}
val := exprs[i+1]
i++
_, already := submittedByName[sym.name]
if already {
return fmt.Errorf("duplicate named parameter '%s'", sym.name)
}
submittedByName[sym.name] = val
valtyp := val.Type()
if typ != nil && typ != valtyp {
return fmt.Errorf("type mismatch for parameter '%s': expected '%s', got '%s'",
sym.name, typ.SexpString(nil), valtyp.SexpString(nil))
}
} else {
Q("in env.CallFunction, exprs[%v]='%v'/type=%T", i, exprs[i].SexpString(nil), exprs[i])
}
default:
Q("in env.CallFunction, exprs[%v]='%v'/type=%T", i, exprs[i].SexpString(nil), exprs[i])
}
}
// simplify name matching for now with this rule: all by name, or none.
haveByName := len(submittedByName)
if haveByName > 0 {
if haveByName != f.inputTypes.NumKeys {
return fmt.Errorf("named arguments count %v != expected %v", haveByName, f.inputTypes.NumKeys)
}
// prep finalArgs in the order dictated
for i, key := range f.inputTypes.KeyOrder {
switch sy := key.(type) {
case *SexpSymbol:
// search for sy.name in our submittedByName args
a, found := submittedByName[sy.name]
if found {
Q("%s call: matching %v-th argument named '%s': passing value '%s'",
f.name, i, sy.name, a.SexpString(nil))
finalArgs[i] = a
}
default:
return fmt.Errorf("unsupported argument-name type %T", key)
}
}
} else {
// not using named parameters, restore the arguments to the stack as they were.
finalArgs = exprs
}
*nargs = len(finalArgs)
return env.datastack.PushExpressions(finalArgs)
}

45
vendor/github.com/glycerine/zygomys/zygo/closing.go generated vendored Normal file
View File

@@ -0,0 +1,45 @@
package zygo
// where we store our closure-supporing stack pointers
type Closing struct {
Stack *Stack
Name string
env *Zlisp
}
func NewClosing(name string, env *Zlisp) *Closing {
stk := env.linearstack.Clone()
// be super strict: only store up to our
// enclosing function definition, because after
// that, the definition time of that function
// should be what we use.
return &Closing{
Stack: stk,
Name: name,
env: env}
}
func NewEmptyClosing(name string, env *Zlisp) *Closing {
return &Closing{
Stack: env.NewStack(0),
Name: name,
env: env}
}
func (c *Closing) IsStackElem() {}
func (c *Closing) LookupSymbolUntilFunction(sym *SexpSymbol, setVal *Sexp, maximumFuncToSearch int, checkCaptures bool) (Sexp, error, *Scope) {
return c.Stack.LookupSymbolUntilFunction(sym, setVal, maximumFuncToSearch, checkCaptures)
}
func (c *Closing) LookupSymbol(sym *SexpSymbol, setVal *Sexp) (Sexp, error, *Scope) {
return c.Stack.LookupSymbol(sym, setVal)
}
func (c *Closing) Show(env *Zlisp, ps *PrintState, label string) (string, error) {
return c.Stack.Show(env, ps, label)
}
func (c *Closing) TopScope() *Scope {
return c.Stack.GetTop().(*Scope)
}

105
vendor/github.com/glycerine/zygomys/zygo/comment.go generated vendored Normal file
View File

@@ -0,0 +1,105 @@
package zygo
type SexpComment struct {
Comment string
Block bool
}
func (p *SexpComment) SexpString(ps *PrintState) string {
return p.Comment
}
func (p *SexpComment) Type() *RegisteredType {
return GoStructRegistry.Registry["comment"]
}
// Filters return true to keep, false to drop.
type Filter func(x Sexp) bool
func RemoveCommentsFilter(x Sexp) bool {
switch x.(type) {
case *SexpComment:
//P("RemoveCommentsFilter called on x= %T/val=%v. return false", x, x)
return false
default:
//P("RemoveCommentsFilter called on x= %T/val=%v. return true", x, x)
return true
}
}
// detect SexpEnd values and return false on them to filter them out.
func RemoveEndsFilter(x Sexp) bool {
switch n := x.(type) {
case *SexpSentinel:
if n.Val == SexpEnd.Val {
return false
}
}
return true
}
// detect SexpComma values and return false on them to filter them out.
func RemoveCommasFilter(x Sexp) bool {
switch x.(type) {
case *SexpComma:
return false
}
return true
}
func (env *Zlisp) FilterAny(x Sexp, f Filter) (filtered Sexp, keep bool) {
switch ele := x.(type) {
case *SexpArray:
res := &SexpArray{Val: env.FilterArray(ele.Val, f), Typ: ele.Typ, IsFuncDeclTypeArray: ele.IsFuncDeclTypeArray, Env: env}
return res, true
case *SexpPair:
return env.FilterList(ele, f), true
case *SexpHash:
return env.FilterHash(ele, f), true
default:
keep = f(x)
if keep {
return x, true
}
return SexpNull, false
}
}
func (env *Zlisp) FilterArray(x []Sexp, f Filter) []Sexp {
//P("FilterArray: before: %d in size", len(x))
//for i := range x {
//P("x[i=%d] = %v", i, x[i].SexpString())
//}
res := []Sexp{}
for i := range x {
filtered, keep := env.FilterAny(x[i], f)
if keep {
res = append(res, filtered)
}
}
//P("FilterArray: after: %d in size", len(res))
//for i := range res {
//P("x[i=%d] = %v", i, res[i].SexpString())
//}
return res
}
func (env *Zlisp) FilterHash(h *SexpHash, f Filter) *SexpHash {
// should not actually need this, since hashes
// don't yet exist in parsed symbols. (they are
// still lists).
//P("in FilterHash")
return h
}
func (env *Zlisp) FilterList(h *SexpPair, f Filter) Sexp {
//P("in FilterList")
arr, err := ListToArray(h)
res := []Sexp{}
if err == NotAList {
// don't filter pair lists
return h
}
res = env.FilterArray(arr, f)
return MakeList(res)
}

323
vendor/github.com/glycerine/zygomys/zygo/comparisons.go generated vendored Normal file
View File

@@ -0,0 +1,323 @@
package zygo
import (
"bytes"
"errors"
"fmt"
"math"
"reflect"
)
func IsNaNFunction(env *Zlisp, name string, args []Sexp) (Sexp, error) {
if len(args) != 1 {
return SexpNull, WrongNargs
}
var err error
a := args[0]
if sel, isSel := a.(Selector); isSel {
a, err = sel.RHS(env)
if err != nil {
return SexpNull, err
}
}
switch at := a.(type) {
case *SexpFloat:
if math.IsNaN(at.Val) {
return &SexpBool{Val: true}, nil
}
}
return &SexpBool{Val: false}, nil
}
func signumFloat(f float64) int {
if f > 0 {
return 1
}
if f < 0 {
return -1
}
return 0
}
func signumInt(i int64) int {
if i > 0 {
return 1
}
if i < 0 {
return -1
}
return 0
}
func compareFloat(f *SexpFloat, expr Sexp) (int, error) {
switch e := expr.(type) {
case *SexpInt:
if math.IsNaN(f.Val) {
return 2, nil
}
return signumFloat(f.Val - float64(e.Val)), nil
case *SexpFloat:
nanCount := 0
if math.IsNaN(f.Val) {
nanCount++
}
if math.IsNaN(e.Val) {
nanCount++
}
if nanCount > 0 {
return 1 + nanCount, nil
}
return signumFloat(f.Val - e.Val), nil
case *SexpChar:
if math.IsNaN(f.Val) {
return 2, nil
}
return signumFloat(f.Val - float64(e.Val)), nil
}
errmsg := fmt.Sprintf("err 91: cannot compare %T to %T", f, expr)
return 0, errors.New(errmsg)
}
func compareInt(i *SexpInt, expr Sexp) (int, error) {
switch e := expr.(type) {
case *SexpInt:
return signumInt(i.Val - e.Val), nil
case *SexpFloat:
return signumFloat(float64(i.Val) - e.Val), nil
case *SexpChar:
return signumInt(i.Val - int64(e.Val)), nil
case *SexpReflect:
r := reflect.Value(e.Val)
ifa := r.Interface()
switch z := ifa.(type) {
case *int64:
return signumInt(i.Val - *z), nil
}
P("compareInt(): ifa = %v/%T", ifa, ifa)
P("compareInt(): r.Elem() = %v/%T", r.Elem(), r.Elem())
P("compareInt(): r.Elem().Interface() = %v/%T", r.Elem().Interface(), r.Elem().Interface())
P("compareInt(): r.Elem().Type() = %v/%T", r.Elem().Type(), r.Elem().Type())
P("compareInt(): r.Elem().Type().Name() = %v/%T", r.Elem().Type().Name(), r.Elem().Type().Name())
}
errmsg := fmt.Sprintf("err 92: cannot compare %T to %T", i, expr)
return 0, errors.New(errmsg)
}
func compareChar(c *SexpChar, expr Sexp) (int, error) {
switch e := expr.(type) {
case *SexpInt:
return signumInt(int64(c.Val) - e.Val), nil
case *SexpFloat:
return signumFloat(float64(c.Val) - e.Val), nil
case *SexpChar:
return signumInt(int64(c.Val) - int64(e.Val)), nil
}
errmsg := fmt.Sprintf("err 93: cannot compare %T to %T", c, expr)
return 0, errors.New(errmsg)
}
func compareString(s *SexpStr, expr Sexp) (int, error) {
switch e := expr.(type) {
case *SexpStr:
return bytes.Compare([]byte(s.S), []byte(e.S)), nil
case *SexpReflect:
r := reflect.Value(e.Val)
ifa := r.Interface()
switch z := ifa.(type) {
case *string:
return bytes.Compare([]byte(s.S), []byte(*z)), nil
}
}
errmsg := fmt.Sprintf("err 94: cannot compare %T to %T", s, expr)
return 0, errors.New(errmsg)
}
func (env *Zlisp) compareSymbol(sym *SexpSymbol, expr Sexp) (int, error) {
switch e := expr.(type) {
case *SexpSymbol:
return signumInt(int64(sym.number - e.number)), nil
}
errmsg := fmt.Sprintf("err 95: cannot compare %T to %T", sym, expr)
return 0, errors.New(errmsg)
}
func (env *Zlisp) comparePair(a *SexpPair, b Sexp) (int, error) {
var bp *SexpPair
switch t := b.(type) {
case *SexpPair:
bp = t
default:
errmsg := fmt.Sprintf("err 96: cannot compare %T to %T", a, b)
return 0, errors.New(errmsg)
}
res, err := env.Compare(a.Head, bp.Head)
if err != nil {
return 0, err
}
if res != 0 {
return res, nil
}
return env.Compare(a.Tail, bp.Tail)
}
func (env *Zlisp) compareArray(a *SexpArray, b Sexp) (int, error) {
var ba *SexpArray
switch t := b.(type) {
case *SexpArray:
ba = t
default:
errmsg := fmt.Sprintf("err 97: cannot compare %T to %T", a, b)
return 0, errors.New(errmsg)
}
var length int
if len(a.Val) < len(ba.Val) {
length = len(a.Val)
} else {
length = len(ba.Val)
}
for i := 0; i < length; i++ {
res, err := env.Compare(a.Val[i], ba.Val[i])
if err != nil {
return 0, err
}
if res != 0 {
return res, nil
}
}
return signumInt(int64(len(a.Val) - len(ba.Val))), nil
}
func compareBool(a *SexpBool, b Sexp) (int, error) {
var bb *SexpBool
switch bt := b.(type) {
case *SexpBool:
bb = bt
default:
errmsg := fmt.Sprintf("err 98: cannot compare %T to %T", a, b)
return 0, errors.New(errmsg)
}
// true > false
if a.Val && bb.Val {
return 0, nil
}
if a.Val {
return 1, nil
}
if bb.Val {
return -1, nil
}
return 0, nil
}
func comparePointers(a *SexpPointer, bs Sexp) (int, error) {
var b *SexpPointer
switch bt := bs.(type) {
case *SexpPointer:
b = bt
default:
return 0, fmt.Errorf("err 99: cannot compare %T to %T", a, bs)
}
if a.Target == b.Target {
return 0, nil
}
return 1, nil
}
func (env *Zlisp) Compare(a Sexp, b Sexp) (int, error) {
var err error
if sel, isSel := a.(Selector); isSel {
a, err = sel.RHS(env)
if err != nil {
return 0, err
}
}
if sel, isSel := b.(Selector); isSel {
b, err = sel.RHS(env)
if err != nil {
return 0, err
}
}
switch at := a.(type) {
case *SexpInt:
return compareInt(at, b)
case *SexpUint64:
return compareUint64(at, b)
case *SexpChar:
return compareChar(at, b)
case *SexpFloat:
return compareFloat(at, b)
case *SexpBool:
return compareBool(at, b)
case *SexpStr:
return compareString(at, b)
case *SexpSymbol:
return env.compareSymbol(at, b)
case *SexpPair:
return env.comparePair(at, b)
case *SexpArray:
return env.compareArray(at, b)
case *SexpHash:
return compareHash(at, b)
case *RegisteredType:
return compareRegisteredTypes(at, b)
case *SexpPointer:
return comparePointers(at, b)
case *SexpSentinel:
if at == SexpNull && b == SexpNull {
return 0, nil
} else {
return -1, nil
}
case *SexpTime:
switch bt := b.(type) {
case *SexpTime:
if bt.Tm.Unix() == at.Tm.Unix() {
return 0, nil
}
return -1, nil
}
case *SexpReflect:
r := reflect.Value(at.Val)
ifa := r.Interface()
//P("Compare(): ifa = %v/%t", ifa, ifa)
//P("Compare(): r.Elem() = %v/%T", r.Elem(), r.Elem())
switch z := ifa.(type) {
case *int64:
return compareInt(&SexpInt{Val: *z}, b)
case *string:
return compareString(&SexpStr{S: *z}, b)
}
}
errmsg := fmt.Sprintf("err 100: cannot compare %T to %T", a, b)
return 0, errors.New(errmsg)
}
// only compare uint64 to uint64
func compareUint64(i *SexpUint64, expr Sexp) (int, error) {
switch e := expr.(type) {
case *SexpUint64:
return signumUint64(i.Val - e.Val), nil
}
errmsg := fmt.Sprintf("err 101: cannot compare %T to %T", i, expr)
return 0, errors.New(errmsg)
}
func signumUint64(i uint64) int {
if i > 0 {
return 1
}
if i < 0 {
return -1
}
return 0
}

46
vendor/github.com/glycerine/zygomys/zygo/coroutines.go generated vendored Normal file
View File

@@ -0,0 +1,46 @@
package zygo
import (
"errors"
)
type SexpGoroutine struct {
env *Zlisp
}
func (goro *SexpGoroutine) SexpString(ps *PrintState) string {
return "[coroutine]"
}
func (goro *SexpGoroutine) Type() *RegisteredType {
return nil // TODO what goes here
}
func StartGoroutineFunction(env *Zlisp, name string,
args []Sexp) (Sexp, error) {
switch t := args[0].(type) {
case *SexpGoroutine:
go t.env.Run()
default:
return SexpNull, errors.New("not a goroutine")
}
return SexpNull, nil
}
func CreateGoroutineMacro(env *Zlisp, name string,
args []Sexp) (Sexp, error) {
goroenv := env.Duplicate()
err := goroenv.LoadExpressions(args)
if err != nil {
return SexpNull, nil
}
goro := &SexpGoroutine{goroenv}
// (apply StartGoroutineFunction [goro])
return MakeList([]Sexp{env.MakeSymbol("apply"),
MakeUserFunction("__start", StartGoroutineFunction),
&SexpArray{Val: []Sexp{goro}, Env: env}}), nil
}
func (env *Zlisp) ImportGoroutines() {
env.AddMacro("go", CreateGoroutineMacro)
}

75
vendor/github.com/glycerine/zygomys/zygo/datastack.go generated vendored Normal file
View File

@@ -0,0 +1,75 @@
package zygo
import (
"errors"
"fmt"
)
type DataStackElem struct {
expr Sexp
}
func (d DataStackElem) IsStackElem() {}
func (stack *Stack) PushExpr(expr Sexp) {
stack.Push(DataStackElem{expr})
}
func (stack *Stack) PushExpressions(expr []Sexp) error {
for _, x := range expr {
stack.Push(DataStackElem{x})
}
return nil
}
func (stack *Stack) PopExpr() (Sexp, error) {
elem, err := stack.Pop()
if err != nil {
return nil, err
}
return elem.(DataStackElem).expr, nil
}
func (stack *Stack) GetExpressions(n int) ([]Sexp, error) {
stack_start := stack.tos - n + 1
if stack_start < 0 {
return nil, errors.New("not enough items on stack")
}
arr := make([]Sexp, n)
for i := 0; i < n; i++ {
arr[i] = stack.elements[stack_start+i].(DataStackElem).expr
}
return arr, nil
}
func (stack *Stack) PopExpressions(n int) ([]Sexp, error) {
origSz := stack.Size()
expressions, err := stack.GetExpressions(n)
if err != nil {
return nil, err
}
stack.TruncateToSize(origSz - n)
return expressions, nil
}
func (stack *Stack) GetExpr(n int) (Sexp, error) {
elem, err := stack.Get(n)
if err != nil {
return nil, err
}
return elem.(DataStackElem).expr, nil
}
func (stack *Stack) PrintStack() {
for i := 0; i <= stack.tos; i++ {
expr := stack.elements[i].(DataStackElem).expr
fmt.Println("\t" + expr.SexpString(nil))
}
}
func (stack *Stack) PrintScopeStack() {
for i := 0; i <= stack.tos; i++ {
scop := stack.elements[i].(*Scope)
scop.Show(stack.env, NewPrintStateWithIndent(4), "")
}
}

View File

@@ -0,0 +1,149 @@
package zygo
import (
"fmt"
"time"
)
//go:generate msgp
//msgp:ignore Plane Wings Snoopy Hornet Hellcat SetOfPlanes
// the pointer wasn't getting followed.
type NestOuter struct {
Inner *NestInner `msg:"inner" json:"inner" zid:"0"`
}
type NestInner struct {
Hello string `msg:"hello" json:"hello" zid:"0"`
}
type Event struct {
Id int `json:"id" msg:"id"`
User Person `json:"user" msg:"user"`
Flight string `json:"flight" msg:"flight"`
Pilot []string `json:"pilot" msg:"pilot"`
Cancelled bool `json:"cancelled" msg:"cancelled"`
}
type Person struct {
First string `json:"first" msg:"first"`
Last string `json:"last" msg:"last"`
}
func (ev *Event) DisplayEvent(from string) {
fmt.Printf("%s %#v", from, ev)
}
type Wings struct {
SpanCm int
}
type SetOfPlanes struct {
Flyers []Flyer `json:"flyers" msg:"flyers"`
}
// the interface Flyer confounds the msgp msgpack code generator,
// so put the msgp:ignore Plane above
type Plane struct {
Wings
ID int `json:"id" msg:"id"`
Speed int `json:"speed" msg:"speed"`
Chld Flyer `json:"chld" msg:"chld"`
Friends []Flyer `json:"friends"`
}
type Snoopy struct {
Plane `json:"plane" msg:"plane"`
Cry string `json:"cry" msg:"cry"`
Pack []int `json:"pack"`
Carrying []Flyer `json:"carrying"`
}
type Hornet struct {
Plane `json:"plane" msg:"plane"`
Mass float64
Nickname string
}
type Hellcat struct {
Plane `json:"plane" msg:"plane"`
}
func (p *Snoopy) Fly(w *Weather) (s string, err error) {
w.Type = "VERY " + w.Type // side-effect, for demo purposes
s = fmt.Sprintf("Snoopy sees weather '%s', cries '%s'", w.Type, p.Cry)
fmt.Println(s)
for _, flyer := range p.Friends {
flyer.Fly(w)
}
return
}
func (p *Snoopy) GetCry() string {
return p.Cry
}
func (p *Snoopy) EchoWeather(w *Weather) *Weather {
return w
}
func (p *Snoopy) Sideeffect() {
fmt.Printf("Sideeffect() called! p = %p\n", p)
}
func (b *Hornet) Fly(w *Weather) (s string, err error) {
fmt.Printf("Hornet.Fly() called. I see weather %v\n", w.Type)
return
}
func (b *Hellcat) Fly(w *Weather) (s string, err error) {
fmt.Printf("Hellcat.Fly() called. I see weather %v\n", w.Type)
return
}
type Flyer interface {
Fly(w *Weather) (s string, err error)
}
type Weather struct {
Time time.Time `json:"time" msg:"time"`
Size int64 `json:"size" msg:"size"`
Type string `json:"type" msg:"type"`
Details []byte `json:"details" msg:"details"`
}
func (w *Weather) IsSunny() bool {
return w.Type == "sunny"
}
func (env *Zlisp) ImportDemoData() {
env.AddFunction("nestouter", DemoNestInnerOuterFunction)
env.AddFunction("nestinner", DemoNestInnerOuterFunction)
rt := &RegisteredType{GenDefMap: true, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return &NestOuter{}, nil
}}
GoStructRegistry.RegisterUserdef(rt, true, "nestouter", "NestOuter")
rt = &RegisteredType{GenDefMap: true, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return &NestInner{}, nil
}}
GoStructRegistry.RegisterUserdef(rt, true, "nestinner", "NestInner")
}
// constructor
func DemoNestInnerOuterFunction(env *Zlisp, name string, args []Sexp) (Sexp, error) {
n := len(args)
switch n {
case 0:
return SexpNull, WrongNargs
default:
// many parameters, treat as key:value pairs in the hash/record.
return ConstructorFunction(env, "msgmap", append([]Sexp{&SexpStr{S: name}}, MakeList(args)))
}
}

View File

@@ -0,0 +1,845 @@
package zygo
// NOTE: THIS FILE WAS PRODUCED BY THE
// MSGP CODE GENERATION TOOL (github.com/tinylib/msgp)
// DO NOT EDIT
import (
"github.com/tinylib/msgp/msgp"
)
// DecodeMsg implements msgp.Decodable
func (z *Event) DecodeMsg(dc *msgp.Reader) (err error) {
var field []byte
_ = field
var zb0001 uint32
zb0001, err = dc.ReadMapHeader()
if err != nil {
return
}
for zb0001 > 0 {
zb0001--
field, err = dc.ReadMapKeyPtr()
if err != nil {
return
}
switch msgp.UnsafeString(field) {
case "id":
z.Id, err = dc.ReadInt()
if err != nil {
return
}
case "user":
var zb0002 uint32
zb0002, err = dc.ReadMapHeader()
if err != nil {
return
}
for zb0002 > 0 {
zb0002--
field, err = dc.ReadMapKeyPtr()
if err != nil {
return
}
switch msgp.UnsafeString(field) {
case "first":
z.User.First, err = dc.ReadString()
if err != nil {
return
}
case "last":
z.User.Last, err = dc.ReadString()
if err != nil {
return
}
default:
err = dc.Skip()
if err != nil {
return
}
}
}
case "flight":
z.Flight, err = dc.ReadString()
if err != nil {
return
}
case "pilot":
var zb0003 uint32
zb0003, err = dc.ReadArrayHeader()
if err != nil {
return
}
if cap(z.Pilot) >= int(zb0003) {
z.Pilot = (z.Pilot)[:zb0003]
} else {
z.Pilot = make([]string, zb0003)
}
for za0001 := range z.Pilot {
z.Pilot[za0001], err = dc.ReadString()
if err != nil {
return
}
}
case "cancelled":
z.Cancelled, err = dc.ReadBool()
if err != nil {
return
}
default:
err = dc.Skip()
if err != nil {
return
}
}
}
return
}
// EncodeMsg implements msgp.Encodable
func (z *Event) EncodeMsg(en *msgp.Writer) (err error) {
// map header, size 5
// write "id"
err = en.Append(0x85, 0xa2, 0x69, 0x64)
if err != nil {
return
}
err = en.WriteInt(z.Id)
if err != nil {
return
}
// write "user"
// map header, size 2
// write "first"
err = en.Append(0xa4, 0x75, 0x73, 0x65, 0x72, 0x82, 0xa5, 0x66, 0x69, 0x72, 0x73, 0x74)
if err != nil {
return
}
err = en.WriteString(z.User.First)
if err != nil {
return
}
// write "last"
err = en.Append(0xa4, 0x6c, 0x61, 0x73, 0x74)
if err != nil {
return
}
err = en.WriteString(z.User.Last)
if err != nil {
return
}
// write "flight"
err = en.Append(0xa6, 0x66, 0x6c, 0x69, 0x67, 0x68, 0x74)
if err != nil {
return
}
err = en.WriteString(z.Flight)
if err != nil {
return
}
// write "pilot"
err = en.Append(0xa5, 0x70, 0x69, 0x6c, 0x6f, 0x74)
if err != nil {
return
}
err = en.WriteArrayHeader(uint32(len(z.Pilot)))
if err != nil {
return
}
for za0001 := range z.Pilot {
err = en.WriteString(z.Pilot[za0001])
if err != nil {
return
}
}
// write "cancelled"
err = en.Append(0xa9, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, 0x64)
if err != nil {
return
}
err = en.WriteBool(z.Cancelled)
if err != nil {
return
}
return
}
// MarshalMsg implements msgp.Marshaler
func (z *Event) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
// map header, size 5
// string "id"
o = append(o, 0x85, 0xa2, 0x69, 0x64)
o = msgp.AppendInt(o, z.Id)
// string "user"
// map header, size 2
// string "first"
o = append(o, 0xa4, 0x75, 0x73, 0x65, 0x72, 0x82, 0xa5, 0x66, 0x69, 0x72, 0x73, 0x74)
o = msgp.AppendString(o, z.User.First)
// string "last"
o = append(o, 0xa4, 0x6c, 0x61, 0x73, 0x74)
o = msgp.AppendString(o, z.User.Last)
// string "flight"
o = append(o, 0xa6, 0x66, 0x6c, 0x69, 0x67, 0x68, 0x74)
o = msgp.AppendString(o, z.Flight)
// string "pilot"
o = append(o, 0xa5, 0x70, 0x69, 0x6c, 0x6f, 0x74)
o = msgp.AppendArrayHeader(o, uint32(len(z.Pilot)))
for za0001 := range z.Pilot {
o = msgp.AppendString(o, z.Pilot[za0001])
}
// string "cancelled"
o = append(o, 0xa9, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, 0x64)
o = msgp.AppendBool(o, z.Cancelled)
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *Event) UnmarshalMsg(bts []byte) (o []byte, err error) {
var field []byte
_ = field
var zb0001 uint32
zb0001, bts, err = msgp.ReadMapHeaderBytes(bts)
if err != nil {
return
}
for zb0001 > 0 {
zb0001--
field, bts, err = msgp.ReadMapKeyZC(bts)
if err != nil {
return
}
switch msgp.UnsafeString(field) {
case "id":
z.Id, bts, err = msgp.ReadIntBytes(bts)
if err != nil {
return
}
case "user":
var zb0002 uint32
zb0002, bts, err = msgp.ReadMapHeaderBytes(bts)
if err != nil {
return
}
for zb0002 > 0 {
zb0002--
field, bts, err = msgp.ReadMapKeyZC(bts)
if err != nil {
return
}
switch msgp.UnsafeString(field) {
case "first":
z.User.First, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
return
}
case "last":
z.User.Last, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
return
}
default:
bts, err = msgp.Skip(bts)
if err != nil {
return
}
}
}
case "flight":
z.Flight, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
return
}
case "pilot":
var zb0003 uint32
zb0003, bts, err = msgp.ReadArrayHeaderBytes(bts)
if err != nil {
return
}
if cap(z.Pilot) >= int(zb0003) {
z.Pilot = (z.Pilot)[:zb0003]
} else {
z.Pilot = make([]string, zb0003)
}
for za0001 := range z.Pilot {
z.Pilot[za0001], bts, err = msgp.ReadStringBytes(bts)
if err != nil {
return
}
}
case "cancelled":
z.Cancelled, bts, err = msgp.ReadBoolBytes(bts)
if err != nil {
return
}
default:
bts, err = msgp.Skip(bts)
if err != nil {
return
}
}
}
o = bts
return
}
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
func (z *Event) Msgsize() (s int) {
s = 1 + 3 + msgp.IntSize + 5 + 1 + 6 + msgp.StringPrefixSize + len(z.User.First) + 5 + msgp.StringPrefixSize + len(z.User.Last) + 7 + msgp.StringPrefixSize + len(z.Flight) + 6 + msgp.ArrayHeaderSize
for za0001 := range z.Pilot {
s += msgp.StringPrefixSize + len(z.Pilot[za0001])
}
s += 10 + msgp.BoolSize
return
}
// DecodeMsg implements msgp.Decodable
func (z *NestInner) DecodeMsg(dc *msgp.Reader) (err error) {
var field []byte
_ = field
var zb0001 uint32
zb0001, err = dc.ReadMapHeader()
if err != nil {
return
}
for zb0001 > 0 {
zb0001--
field, err = dc.ReadMapKeyPtr()
if err != nil {
return
}
switch msgp.UnsafeString(field) {
case "hello":
z.Hello, err = dc.ReadString()
if err != nil {
return
}
default:
err = dc.Skip()
if err != nil {
return
}
}
}
return
}
// EncodeMsg implements msgp.Encodable
func (z NestInner) EncodeMsg(en *msgp.Writer) (err error) {
// map header, size 1
// write "hello"
err = en.Append(0x81, 0xa5, 0x68, 0x65, 0x6c, 0x6c, 0x6f)
if err != nil {
return
}
err = en.WriteString(z.Hello)
if err != nil {
return
}
return
}
// MarshalMsg implements msgp.Marshaler
func (z NestInner) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
// map header, size 1
// string "hello"
o = append(o, 0x81, 0xa5, 0x68, 0x65, 0x6c, 0x6c, 0x6f)
o = msgp.AppendString(o, z.Hello)
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *NestInner) UnmarshalMsg(bts []byte) (o []byte, err error) {
var field []byte
_ = field
var zb0001 uint32
zb0001, bts, err = msgp.ReadMapHeaderBytes(bts)
if err != nil {
return
}
for zb0001 > 0 {
zb0001--
field, bts, err = msgp.ReadMapKeyZC(bts)
if err != nil {
return
}
switch msgp.UnsafeString(field) {
case "hello":
z.Hello, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
return
}
default:
bts, err = msgp.Skip(bts)
if err != nil {
return
}
}
}
o = bts
return
}
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
func (z NestInner) Msgsize() (s int) {
s = 1 + 6 + msgp.StringPrefixSize + len(z.Hello)
return
}
// DecodeMsg implements msgp.Decodable
func (z *NestOuter) DecodeMsg(dc *msgp.Reader) (err error) {
var field []byte
_ = field
var zb0001 uint32
zb0001, err = dc.ReadMapHeader()
if err != nil {
return
}
for zb0001 > 0 {
zb0001--
field, err = dc.ReadMapKeyPtr()
if err != nil {
return
}
switch msgp.UnsafeString(field) {
case "inner":
if dc.IsNil() {
err = dc.ReadNil()
if err != nil {
return
}
z.Inner = nil
} else {
if z.Inner == nil {
z.Inner = new(NestInner)
}
var zb0002 uint32
zb0002, err = dc.ReadMapHeader()
if err != nil {
return
}
for zb0002 > 0 {
zb0002--
field, err = dc.ReadMapKeyPtr()
if err != nil {
return
}
switch msgp.UnsafeString(field) {
case "hello":
z.Inner.Hello, err = dc.ReadString()
if err != nil {
return
}
default:
err = dc.Skip()
if err != nil {
return
}
}
}
}
default:
err = dc.Skip()
if err != nil {
return
}
}
}
return
}
// EncodeMsg implements msgp.Encodable
func (z *NestOuter) EncodeMsg(en *msgp.Writer) (err error) {
// map header, size 1
// write "inner"
err = en.Append(0x81, 0xa5, 0x69, 0x6e, 0x6e, 0x65, 0x72)
if err != nil {
return
}
if z.Inner == nil {
err = en.WriteNil()
if err != nil {
return
}
} else {
// map header, size 1
// write "hello"
err = en.Append(0x81, 0xa5, 0x68, 0x65, 0x6c, 0x6c, 0x6f)
if err != nil {
return
}
err = en.WriteString(z.Inner.Hello)
if err != nil {
return
}
}
return
}
// MarshalMsg implements msgp.Marshaler
func (z *NestOuter) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
// map header, size 1
// string "inner"
o = append(o, 0x81, 0xa5, 0x69, 0x6e, 0x6e, 0x65, 0x72)
if z.Inner == nil {
o = msgp.AppendNil(o)
} else {
// map header, size 1
// string "hello"
o = append(o, 0x81, 0xa5, 0x68, 0x65, 0x6c, 0x6c, 0x6f)
o = msgp.AppendString(o, z.Inner.Hello)
}
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *NestOuter) UnmarshalMsg(bts []byte) (o []byte, err error) {
var field []byte
_ = field
var zb0001 uint32
zb0001, bts, err = msgp.ReadMapHeaderBytes(bts)
if err != nil {
return
}
for zb0001 > 0 {
zb0001--
field, bts, err = msgp.ReadMapKeyZC(bts)
if err != nil {
return
}
switch msgp.UnsafeString(field) {
case "inner":
if msgp.IsNil(bts) {
bts, err = msgp.ReadNilBytes(bts)
if err != nil {
return
}
z.Inner = nil
} else {
if z.Inner == nil {
z.Inner = new(NestInner)
}
var zb0002 uint32
zb0002, bts, err = msgp.ReadMapHeaderBytes(bts)
if err != nil {
return
}
for zb0002 > 0 {
zb0002--
field, bts, err = msgp.ReadMapKeyZC(bts)
if err != nil {
return
}
switch msgp.UnsafeString(field) {
case "hello":
z.Inner.Hello, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
return
}
default:
bts, err = msgp.Skip(bts)
if err != nil {
return
}
}
}
}
default:
bts, err = msgp.Skip(bts)
if err != nil {
return
}
}
}
o = bts
return
}
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
func (z *NestOuter) Msgsize() (s int) {
s = 1 + 6
if z.Inner == nil {
s += msgp.NilSize
} else {
s += 1 + 6 + msgp.StringPrefixSize + len(z.Inner.Hello)
}
return
}
// DecodeMsg implements msgp.Decodable
func (z *Person) DecodeMsg(dc *msgp.Reader) (err error) {
var field []byte
_ = field
var zb0001 uint32
zb0001, err = dc.ReadMapHeader()
if err != nil {
return
}
for zb0001 > 0 {
zb0001--
field, err = dc.ReadMapKeyPtr()
if err != nil {
return
}
switch msgp.UnsafeString(field) {
case "first":
z.First, err = dc.ReadString()
if err != nil {
return
}
case "last":
z.Last, err = dc.ReadString()
if err != nil {
return
}
default:
err = dc.Skip()
if err != nil {
return
}
}
}
return
}
// EncodeMsg implements msgp.Encodable
func (z Person) EncodeMsg(en *msgp.Writer) (err error) {
// map header, size 2
// write "first"
err = en.Append(0x82, 0xa5, 0x66, 0x69, 0x72, 0x73, 0x74)
if err != nil {
return
}
err = en.WriteString(z.First)
if err != nil {
return
}
// write "last"
err = en.Append(0xa4, 0x6c, 0x61, 0x73, 0x74)
if err != nil {
return
}
err = en.WriteString(z.Last)
if err != nil {
return
}
return
}
// MarshalMsg implements msgp.Marshaler
func (z Person) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
// map header, size 2
// string "first"
o = append(o, 0x82, 0xa5, 0x66, 0x69, 0x72, 0x73, 0x74)
o = msgp.AppendString(o, z.First)
// string "last"
o = append(o, 0xa4, 0x6c, 0x61, 0x73, 0x74)
o = msgp.AppendString(o, z.Last)
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *Person) UnmarshalMsg(bts []byte) (o []byte, err error) {
var field []byte
_ = field
var zb0001 uint32
zb0001, bts, err = msgp.ReadMapHeaderBytes(bts)
if err != nil {
return
}
for zb0001 > 0 {
zb0001--
field, bts, err = msgp.ReadMapKeyZC(bts)
if err != nil {
return
}
switch msgp.UnsafeString(field) {
case "first":
z.First, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
return
}
case "last":
z.Last, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
return
}
default:
bts, err = msgp.Skip(bts)
if err != nil {
return
}
}
}
o = bts
return
}
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
func (z Person) Msgsize() (s int) {
s = 1 + 6 + msgp.StringPrefixSize + len(z.First) + 5 + msgp.StringPrefixSize + len(z.Last)
return
}
// DecodeMsg implements msgp.Decodable
func (z *Weather) DecodeMsg(dc *msgp.Reader) (err error) {
var field []byte
_ = field
var zb0001 uint32
zb0001, err = dc.ReadMapHeader()
if err != nil {
return
}
for zb0001 > 0 {
zb0001--
field, err = dc.ReadMapKeyPtr()
if err != nil {
return
}
switch msgp.UnsafeString(field) {
case "time":
z.Time, err = dc.ReadTime()
if err != nil {
return
}
case "size":
z.Size, err = dc.ReadInt64()
if err != nil {
return
}
case "type":
z.Type, err = dc.ReadString()
if err != nil {
return
}
case "details":
z.Details, err = dc.ReadBytes(z.Details)
if err != nil {
return
}
default:
err = dc.Skip()
if err != nil {
return
}
}
}
return
}
// EncodeMsg implements msgp.Encodable
func (z *Weather) EncodeMsg(en *msgp.Writer) (err error) {
// map header, size 4
// write "time"
err = en.Append(0x84, 0xa4, 0x74, 0x69, 0x6d, 0x65)
if err != nil {
return
}
err = en.WriteTime(z.Time)
if err != nil {
return
}
// write "size"
err = en.Append(0xa4, 0x73, 0x69, 0x7a, 0x65)
if err != nil {
return
}
err = en.WriteInt64(z.Size)
if err != nil {
return
}
// write "type"
err = en.Append(0xa4, 0x74, 0x79, 0x70, 0x65)
if err != nil {
return
}
err = en.WriteString(z.Type)
if err != nil {
return
}
// write "details"
err = en.Append(0xa7, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73)
if err != nil {
return
}
err = en.WriteBytes(z.Details)
if err != nil {
return
}
return
}
// MarshalMsg implements msgp.Marshaler
func (z *Weather) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
// map header, size 4
// string "time"
o = append(o, 0x84, 0xa4, 0x74, 0x69, 0x6d, 0x65)
o = msgp.AppendTime(o, z.Time)
// string "size"
o = append(o, 0xa4, 0x73, 0x69, 0x7a, 0x65)
o = msgp.AppendInt64(o, z.Size)
// string "type"
o = append(o, 0xa4, 0x74, 0x79, 0x70, 0x65)
o = msgp.AppendString(o, z.Type)
// string "details"
o = append(o, 0xa7, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73)
o = msgp.AppendBytes(o, z.Details)
return
}
// UnmarshalMsg implements msgp.Unmarshaler
func (z *Weather) UnmarshalMsg(bts []byte) (o []byte, err error) {
var field []byte
_ = field
var zb0001 uint32
zb0001, bts, err = msgp.ReadMapHeaderBytes(bts)
if err != nil {
return
}
for zb0001 > 0 {
zb0001--
field, bts, err = msgp.ReadMapKeyZC(bts)
if err != nil {
return
}
switch msgp.UnsafeString(field) {
case "time":
z.Time, bts, err = msgp.ReadTimeBytes(bts)
if err != nil {
return
}
case "size":
z.Size, bts, err = msgp.ReadInt64Bytes(bts)
if err != nil {
return
}
case "type":
z.Type, bts, err = msgp.ReadStringBytes(bts)
if err != nil {
return
}
case "details":
z.Details, bts, err = msgp.ReadBytesBytes(bts, z.Details)
if err != nil {
return
}
default:
bts, err = msgp.Skip(bts)
if err != nil {
return
}
}
}
o = bts
return
}
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
func (z *Weather) Msgsize() (s int) {
s = 1 + 5 + msgp.TimeSize + 5 + msgp.Int64Size + 5 + msgp.StringPrefixSize + len(z.Type) + 8 + msgp.BytesPrefixSize + len(z.Details)
return
}

8
vendor/github.com/glycerine/zygomys/zygo/doc.go generated vendored Normal file
View File

@@ -0,0 +1,8 @@
/*
This project does not use godoc. Instead there is extensive
and detailed description of the language features maintained
on the wiki. See the following link.
https://github.com/glycerine/zygomys/wiki
*/
package zygo

859
vendor/github.com/glycerine/zygomys/zygo/environment.go generated vendored Normal file
View File

@@ -0,0 +1,859 @@
package zygo
import (
"bufio"
"bytes"
"errors"
"fmt"
"io"
"os"
"runtime"
"strconv"
)
type PreHook func(*Zlisp, string, []Sexp)
type PostHook func(*Zlisp, string, Sexp)
type Zlisp struct {
parser *Parser
datastack *Stack
addrstack *Stack
// linearstack: push on scope enter, pop on scope exit. runtime dynamic.
linearstack *Stack
// loopstack: let break and continue find the nearest enclosing loop.
loopstack *Stack
symtable map[string]int
revsymtable map[int]string
builtins map[int]*SexpFunction
reserved map[int]bool
macros map[int]*SexpFunction
curfunc *SexpFunction
mainfunc *SexpFunction
pc int
nextsymbol int
before []PreHook
after []PostHook
debugExec bool
debugSymbolNotFound bool
showGlobalScope bool
baseTypeCtor *SexpFunction
infixOps map[string]*InfixOp
Pretty bool
booter Booter
// API use, since infix is already default at repl
WrapLoadExpressionsInInfix bool
}
// allow clients to establish a callback to
// happen after reinflating a Go struct. These
// structs need to be "booted" to be ready to go.
func (env *Zlisp) SetBooter(b Booter) {
env.booter = b
}
// Booter provides for registering a callback
// for any new Go struct created by the ToGoFunction (togo).
type Booter func(s interface{})
const CallStackSize = 25
const ScopeStackSize = 50
const DataStackSize = 100
const StackStackSize = 5
const LoopStackSize = 5
var ReservedWords = []string{"byte", "defbuild", "builder", "field", "and", "or", "cond", "quote", "def", "mdef", "fn", "defn", "begin", "let", "letseq", "assert", "defmac", "macexpand", "syntaxQuote", "include", "for", "set", "break", "continue", "newScope", "_ls", "int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", "float32", "float64", "complex64", "complex128", "bool", "string", "any", "break", "case", "chan", "const", "continue", "default", "else", "defer", "fallthrough", "for", "func", "go", "goto", "if", "import", "interface", "map", "package", "range", "return", "select", "struct", "switch", "type", "var", "append", "cap", "close", "complex", "copy", "delete", "imag", "len", "make", "new", "panic", "print", "println", "real", "recover", "null", "nil", "-", "+", "--", "++", "-=", "+=", ":=", "=", ">", "<", ">=", "<=", "send", "NaN", "nan"}
func NewZlisp() *Zlisp {
return NewZlispWithFuncs(AllBuiltinFunctions())
}
func (env *Zlisp) Stop() error {
return env.parser.Stop()
}
// NewZlispSandbox returns a new *Zlisp instance that does not allow the
// user to get to the outside world
func NewZlispSandbox() *Zlisp {
return NewZlispWithFuncs(SandboxSafeFunctions())
}
// NewZlispWithFuncs returns a new *Zlisp instance with access to only the given builtin functions
func NewZlispWithFuncs(funcs map[string]ZlispUserFunction) *Zlisp {
env := new(Zlisp)
env.baseTypeCtor = MakeUserFunction("__basetype_ctor", BaseTypeConstructorFunction)
env.parser = env.NewParser()
env.parser.Start()
env.datastack = env.NewStack(DataStackSize)
env.linearstack = env.NewStack(ScopeStackSize)
glob := env.NewNamedScope("global")
glob.IsGlobal = true
env.linearstack.Push(glob)
env.addrstack = env.NewStack(CallStackSize)
env.loopstack = env.NewStack(LoopStackSize)
env.builtins = make(map[int]*SexpFunction)
env.reserved = make(map[int]bool)
env.macros = make(map[int]*SexpFunction)
env.symtable = make(map[string]int)
env.revsymtable = make(map[int]string)
env.nextsymbol = 1
env.before = []PreHook{}
env.after = []PostHook{}
env.infixOps = make(map[string]*InfixOp)
env.AddGlobal("null", SexpNull)
env.AddGlobal("nil", SexpNull)
for key, function := range funcs {
sym := env.MakeSymbol(key)
env.builtins[sym.number] = MakeUserFunction(key, function)
env.AddFunction(key, function)
}
for _, word := range ReservedWords {
sym := env.MakeSymbol(word)
env.reserved[sym.number] = true
}
env.mainfunc = env.MakeFunction("__main", 0, false,
make([]Instruction, 0), nil)
env.curfunc = env.mainfunc
env.pc = 0
env.debugSymbolNotFound = false
//env.debugSymbolNotFound = true
//env.debugExec = true
env.InitInfixOps()
return env
}
func (env *Zlisp) Clone() *Zlisp {
dupenv := new(Zlisp)
dupenv.parser = env.parser
dupenv.baseTypeCtor = env.baseTypeCtor
dupenv.datastack = env.datastack.Clone()
dupenv.linearstack = env.linearstack.Clone()
dupenv.addrstack = env.addrstack.Clone()
dupenv.builtins = env.builtins
dupenv.reserved = env.reserved
dupenv.macros = env.macros
dupenv.symtable = env.symtable
dupenv.revsymtable = env.revsymtable
dupenv.nextsymbol = env.nextsymbol
dupenv.before = env.before
dupenv.after = env.after
dupenv.infixOps = env.infixOps
dupenv.linearstack.Push(env.linearstack.elements[0])
dupenv.mainfunc = env.MakeFunction("__main", 0, false,
make([]Instruction, 0), nil)
dupenv.curfunc = dupenv.mainfunc
dupenv.pc = 0
dupenv.debugExec = env.debugExec
dupenv.debugSymbolNotFound = env.debugSymbolNotFound
dupenv.showGlobalScope = env.showGlobalScope
return dupenv
}
func (env *Zlisp) Duplicate() *Zlisp {
dupenv := new(Zlisp)
dupenv.parser = env.parser
dupenv.baseTypeCtor = env.baseTypeCtor
dupenv.datastack = dupenv.NewStack(DataStackSize)
dupenv.linearstack = dupenv.NewStack(ScopeStackSize)
dupenv.addrstack = dupenv.NewStack(CallStackSize)
dupenv.builtins = env.builtins
dupenv.reserved = env.reserved
dupenv.macros = env.macros
dupenv.symtable = env.symtable
dupenv.revsymtable = env.revsymtable
dupenv.nextsymbol = env.nextsymbol
dupenv.before = env.before
dupenv.after = env.after
dupenv.infixOps = env.infixOps
dupenv.linearstack.Push(env.linearstack.elements[0])
dupenv.mainfunc = env.MakeFunction("__main", 0, false,
make([]Instruction, 0), nil)
dupenv.curfunc = dupenv.mainfunc
dupenv.pc = 0
dupenv.debugExec = env.debugExec
dupenv.debugSymbolNotFound = env.debugSymbolNotFound
dupenv.showGlobalScope = env.showGlobalScope
return dupenv
}
func (env *Zlisp) MakeDotSymbol(name string) *SexpSymbol {
x := env.MakeSymbol(name)
x.isDot = true
return x
}
func (env *Zlisp) DetectSigils(sym *SexpSymbol) {
if sym == nil {
return
}
if len(sym.name) == 0 {
return
}
switch sym.name[0] {
case '$':
sym.isSigil = true
sym.sigil = "$"
case '#':
sym.isSigil = true
sym.sigil = "#"
case '?':
sym.isSigil = true
sym.sigil = "?"
}
}
func (env *Zlisp) DumpSymTable() {
for kk, vv := range env.symtable {
fmt.Printf("symtable entry: kk: '%v' -> '%v'\n", kk, vv)
}
}
func (env *Zlisp) MakeSymbol(name string) *SexpSymbol {
if env == nil {
panic("internal problem: env.MakeSymbol called with nil env")
}
symnum, ok := env.symtable[name]
if ok {
symbol := &SexpSymbol{name: name, number: symnum}
env.DetectSigils(symbol)
return symbol
}
symbol := &SexpSymbol{name: name, number: env.nextsymbol}
env.symtable[name] = symbol.number
env.revsymtable[symbol.number] = name
env.nextsymbol++
env.DetectSigils(symbol)
return symbol
}
func (env *Zlisp) GenSymbol(prefix string) *SexpSymbol {
symname := prefix + strconv.Itoa(env.nextsymbol)
return env.MakeSymbol(symname)
}
func (env *Zlisp) CurrentFunctionSize() int {
if env.curfunc.user {
return 0
}
return len(env.curfunc.fun)
}
func (env *Zlisp) wrangleOptargs(fnargs, nargs int) error {
if nargs < fnargs {
return errors.New(
fmt.Sprintf("Expected >%d arguments, got %d",
fnargs, nargs))
}
if nargs > fnargs {
optargs, err := env.datastack.PopExpressions(nargs - fnargs)
if err != nil {
return err
}
env.datastack.PushExpr(MakeList(optargs))
} else {
env.datastack.PushExpr(SexpNull)
}
return nil
}
func (env *Zlisp) CallFunction(function *SexpFunction, nargs int) error {
for _, prehook := range env.before {
expressions, err := env.datastack.GetExpressions(nargs)
if err != nil {
return err
}
prehook(env, function.name, expressions)
}
// do name and type checking
err := env.FunctionCallNameTypeCheck(function, &nargs)
if err != nil {
return err
}
if function.varargs {
err := env.wrangleOptargs(function.nargs, nargs)
if err != nil {
return err
}
} else if nargs != function.nargs {
return errors.New(
fmt.Sprintf("%s expected %d arguments, got %d",
function.name, function.nargs, nargs))
}
if env.linearstack.IsEmpty() {
panic("where's the global scope?")
}
env.addrstack.PushAddr(env.curfunc, env.pc+1)
//P("DEBUG linearstack with this next:")
//env.showStackHelper(env.linearstack, "linearstack")
// this effectely *is* the call, because it sets the
// next instructions to happen once we exit.
env.curfunc = function
env.pc = 0
//Q("\n CallFunction starting with stack:\n")
//env.ShowStackStackAndScopeStack()
return nil
}
func (env *Zlisp) ReturnFromFunction() error {
for _, posthook := range env.after {
retval, err := env.datastack.GetExpr(0)
if err != nil {
return err
}
posthook(env, env.curfunc.name, retval)
}
var err error
env.curfunc, env.pc, err = env.addrstack.PopAddr()
return err
}
func (env *Zlisp) CallUserFunction(
function *SexpFunction, name string, nargs int) (nargReturned int, err error) {
Q("CallUserFunction calling name '%s' with nargs=%v", name, nargs)
for _, prehook := range env.before {
expressions, err := env.datastack.GetExpressions(nargs)
if err != nil {
return 0, err
}
prehook(env, function.name, expressions)
}
args, err := env.datastack.PopExpressions(nargs)
if err != nil {
return 0, errors.New(
fmt.Sprintf("Error calling '%s': %v", name, err))
}
env.addrstack.PushAddr(env.curfunc, env.pc+1)
env.curfunc = function
env.pc = -1
//P("DEBUG linearstack with this next, just before calling function.userfun:")
//env.showStackHelper(env.linearstack, "linearstack")
// protect against bad calls/bad reflection in usercalls
var wasPanic bool
var recovered interface{}
tr := make([]byte, 16384)
trace := &tr
res, err := func() (Sexp, error) {
defer func() {
recovered = recover()
if recovered != nil {
wasPanic = true
nbyte := runtime.Stack(*trace, false)
*trace = (*trace)[:nbyte]
}
}()
// the point we were getting to, before the panic protection:
return function.userfun(env, name, args)
}()
//P("DEBUG linearstack with this next, just *after* calling function.userfun:")
//env.showStackHelper(env.linearstack, "linearstack")
if wasPanic {
err = fmt.Errorf("CallUserFunction caught panic during call of "+
"'%s': '%v'\n stack trace:\n%v\n",
name, recovered, string(*trace))
}
if err != nil {
return 0, errors.New(
fmt.Sprintf("Error calling '%s': %v", name, err))
}
env.datastack.PushExpr(res)
for _, posthook := range env.after {
posthook(env, name, res)
}
env.curfunc, env.pc, _ = env.addrstack.PopAddr()
return len(args), nil
}
func (env *Zlisp) LoadExpressions(xs []Sexp) error {
expressions := xs
if env.WrapLoadExpressionsInInfix {
infixSym := env.MakeSymbol("infix")
expressions = []Sexp{MakeList([]Sexp{infixSym, &SexpArray{Val: xs, Env: env}})}
}
//P("expressions before RemoveCommentsFilter: '%s'", (&SexpArray{Val: expressions, Env: env}).SexpString(0))
expressions = env.FilterArray(expressions, RemoveCommentsFilter)
//P("expressions after RemoveCommentsFilter: '%s'", (&SexpArray{Val: expressions, Env: env}).SexpString(0))
expressions = env.FilterArray(expressions, RemoveEndsFilter)
gen := NewGenerator(env)
if !env.ReachedEnd() {
gen.AddInstruction(PopInstr(0))
}
err := gen.GenerateBegin(expressions)
if err != nil {
return err
}
env.mainfunc.fun = append(env.mainfunc.fun, gen.instructions...)
env.curfunc = env.mainfunc
return nil
}
func (env *Zlisp) ParseFile(file string) ([]Sexp, error) {
in, err := os.Open(file)
if err != nil {
return nil, err
}
var exp []Sexp
env.parser.Reset()
env.parser.NewInput(bufio.NewReader(in))
exp, err = env.parser.ParseTokens()
if err != nil {
return nil, fmt.Errorf("Error on line %d: %v\n", env.parser.lexer.Linenum(), err)
}
in.Close()
return exp, nil
}
func (env *Zlisp) LoadStream(stream io.RuneScanner) error {
env.parser.ResetAddNewInput(stream)
expressions, err := env.parser.ParseTokens()
if err != nil {
return fmt.Errorf("Error on line %d: %v\n", env.parser.lexer.Linenum(), err)
}
return env.LoadExpressions(expressions)
}
func (env *Zlisp) EvalString(str string) (Sexp, error) {
err := env.LoadString(str)
if err != nil {
return SexpNull, err
}
VPrintf("\n EvalString: LoadString() done, now to Run():\n")
return env.Run()
}
// for most things now (except the main repl), prefer EvalFunction() instead of EvalExpressions.
func (env *Zlisp) EvalExpressions(xs []Sexp) (Sexp, error) {
//P("inside EvalExpressions with env %p: xs[0] = %s", env, xs[0].SexpString(0))
err := env.LoadExpressions(xs)
if err != nil {
return SexpNull, err
}
return env.Run()
}
func (env *Zlisp) LoadFile(file io.Reader) error {
return env.LoadStream(bufio.NewReader(file))
}
func (env *Zlisp) LoadString(str string) error {
return env.LoadStream(bytes.NewBuffer([]byte(str)))
}
func (env *Zlisp) AddFunction(name string, function ZlispUserFunction) {
env.AddGlobal(name, MakeUserFunction(name, function))
}
func (env *Zlisp) AddBuilder(name string, function ZlispUserFunction) {
env.AddGlobal(name, MakeBuilderFunction(name, function))
}
func (env *Zlisp) AddGlobal(name string, obj Sexp) {
sym := env.MakeSymbol(name)
env.linearstack.elements[0].(*Scope).Map[sym.number] = obj
}
func (env *Zlisp) AddMacro(name string, function ZlispUserFunction) {
sym := env.MakeSymbol(name)
env.macros[sym.number] = MakeUserFunction(name, function)
}
func (env *Zlisp) HasMacro(sym *SexpSymbol) bool {
_, found := env.macros[sym.number]
return found
}
func (env *Zlisp) ImportEval() {
env.AddFunction("eval", EvalFunction)
}
func (env *Zlisp) DumpFunctionByName(name string) error {
obj, found := env.FindObject(name)
if !found {
return errors.New(fmt.Sprintf("%q not found", name))
}
var fun ZlispFunction
switch t := obj.(type) {
case *SexpFunction:
if !t.user {
fun = t.fun
} else {
return errors.New("not a glisp function")
}
default:
return errors.New("dump by name error: not a function")
}
DumpFunction(fun, -1)
return nil
}
// if pc is -1, don't show it.
func DumpFunction(fun ZlispFunction, pc int) {
blank := " "
extra := blank
for i, instr := range fun {
if i == pc {
extra = " PC-> "
} else {
extra = blank
}
fmt.Printf("%s %d: %s\n", extra, i, instr.InstrString())
}
if pc == len(fun) {
fmt.Printf(" PC just past end at %d -----\n\n", pc)
}
}
func (env *Zlisp) DumpEnvironment() {
fmt.Printf("PC: %d\n", env.pc)
fmt.Println("Instructions:")
if !env.curfunc.user {
DumpFunction(env.curfunc.fun, env.pc)
}
fmt.Printf("DataStack (%p): (length %d)\n", env.datastack, env.datastack.Size())
env.datastack.PrintStack()
fmt.Printf("Linear stack: (length %d)\n", env.linearstack.Size())
//env.linearstack.PrintScopeStack()
// instead of the above, try:
env.showStackHelper(env.linearstack, "linearstack")
}
func (env *Zlisp) ReachedEnd() bool {
return env.pc == env.CurrentFunctionSize()
}
func (env *Zlisp) GetStackTrace(err error) string {
str := fmt.Sprintf("error in %s:%d: %v\n",
env.curfunc.name, env.pc, err)
for !env.addrstack.IsEmpty() {
fun, pos, _ := env.addrstack.PopAddr()
str += fmt.Sprintf("in %s:%d\n", fun.name, pos)
}
return str
}
func (env *Zlisp) Clear() {
env.datastack.tos = -1
env.linearstack.tos = 0
env.addrstack.tos = -1
env.mainfunc = env.MakeFunction("__main", 0, false,
make([]Instruction, 0), nil)
env.curfunc = env.mainfunc
env.pc = 0
}
func (env *Zlisp) FindObject(name string) (Sexp, bool) {
sym := env.MakeSymbol(name)
obj, err, _ := env.linearstack.LookupSymbol(sym, nil)
if err != nil {
return SexpNull, false
}
return obj, true
}
func (env *Zlisp) Apply(fun *SexpFunction, args []Sexp) (Sexp, error) {
VPrintf("\n\n debug Apply not working on user funcs: fun = '%#v' and args = '%#v'\n\n", fun, args)
if fun.user {
return fun.userfun(env, fun.name, args)
}
env.pc = -2
for _, expr := range args {
env.datastack.PushExpr(expr)
}
//VPrintf("\nApply Calling '%s'\n", fun.SexpString())
err := env.CallFunction(fun, len(args))
if err != nil {
return SexpNull, err
}
return env.Run()
}
func (env *Zlisp) Run() (Sexp, error) {
for env.pc != -1 && !env.ReachedEnd() {
instr := env.curfunc.fun[env.pc]
if env.debugExec {
fmt.Printf("\n ====== in '%s', about to run: '%v'\n",
env.curfunc.name, instr.InstrString())
env.DumpEnvironment()
fmt.Printf("\n ====== in '%s', now running the above.\n",
env.curfunc.name)
}
err := instr.Execute(env)
if err == StackUnderFlowErr {
err = nil
}
if err != nil {
return SexpNull, err
}
if env.debugExec {
fmt.Printf("\n ****** in '%s', after running, stack is: \n",
env.curfunc.name)
env.DumpEnvironment()
fmt.Printf("\n ****** \n")
}
}
if env.datastack.IsEmpty() {
// this does fire.
//P("debug: *** detected empty datastack, adding a null")
env.datastack.PushExpr(SexpNull)
}
return env.datastack.PopExpr()
}
func (env *Zlisp) AddPreHook(fun PreHook) {
env.before = append(env.before, fun)
}
func (env *Zlisp) AddPostHook(fun PostHook) {
env.after = append(env.after, fun)
}
// scan the instruction stream to locate loop start
func (env *Zlisp) FindLoop(target *Loop) (int, error) {
if env.curfunc.user {
panic(fmt.Errorf("impossible in user-defined-function to find a loop '%s'", target.stmtname.name))
}
instruc := env.curfunc.fun
for i := range instruc {
switch loop := instruc[i].(type) {
case LoopStartInstr:
if loop.loop == target {
return i, nil
}
}
}
return -1, fmt.Errorf("could not find loop target '%s'", target.stmtname.name)
}
func (env *Zlisp) showStackHelper(stack *Stack, name string) {
note := ""
n := stack.Top()
if n < 0 {
note = "(empty)"
}
fmt.Printf(" ======== env(%p).%s is %v deep: %s\n", env, name, n+1, note)
s := ""
for i := 0; i <= n; i++ {
ele, err := stack.Get(n - i)
if err != nil {
panic(fmt.Errorf("env.%s access error on %v: %v",
name, i, err))
}
label := fmt.Sprintf("%s %v", name, i)
switch x := ele.(type) {
case *Stack:
s, _ = x.Show(env, nil, label)
case *Scope:
s, _ = x.Show(env, nil, label)
case Scope:
s, _ = x.Show(env, nil, label)
default:
panic(fmt.Errorf("unrecognized element on %s: %T/val=%v",
name, x, x))
}
fmt.Println(s)
}
}
func (env *Zlisp) dumpParentChain(curfunc *SexpFunction) {
cur := curfunc
par := cur.parent
for par != nil {
fmt.Printf(" parent chain: cur:%v -> parent:%v\n", cur.name, par.name)
fmt.Printf(" cur.closures = %s", ClosureToString(cur, env))
cur = par
par = par.parent
}
}
func (env *Zlisp) ShowStackStackAndScopeStack() error {
env.showStackHelper(env.linearstack, "linearstack")
fmt.Println(" --- done with env.linearstack, now here is env.curfunc --- ")
fmt.Println(ClosureToString(env.curfunc, env))
fmt.Println(" --- done with env.curfunc closure, now here is parent chain: --- ")
env.dumpParentChain(env.curfunc)
return nil
}
func (env *Zlisp) ShowGlobalStack() error {
prev := env.showGlobalScope
env.showGlobalScope = true
err := env.ShowStackStackAndScopeStack()
env.showGlobalScope = prev
return err
}
func (env *Zlisp) LexicalLookupSymbol(sym *SexpSymbol, setVal *Sexp) (Sexp, error, *Scope) {
// DotSymbols always evaluate to themselves
if sym.isDot || sym.isSigil || sym.colonTail {
return sym, nil, nil
}
//P("LexicalLookupSymbol('%s', with setVal: %v)\n", sym.name, setVal)
const maxFuncToScan = 1 // 1 or otherwise tests/{closure.zy, dynprob.zy, dynscope.zy} will fail.
exp, err, scope := env.linearstack.LookupSymbolUntilFunction(sym, setVal, maxFuncToScan, false)
switch err {
case nil:
//P("LexicalLookupSymbol('%s') found on env.linearstack(1, false) in scope '%s'\n", sym.name, scope.Name)
return exp, err, scope
case SymNotFound:
break
}
// check the parent function lexical captured scopes, if parent available.
if env.curfunc.parent != nil {
//P("checking non-nil parent...")
//exp, err, whichScope := env.curfunc.parent.ClosingLookupSymbol(sym, setVal)
exp, err, whichScope := env.curfunc.LookupSymbolInParentChainOfClosures(sym, setVal, env)
switch err {
case nil:
//P("LookupSymbolUntilFunction('%s') found in curfunc.parent.ClosingLookupSymbol() scope '%s'\n", sym.name, whichScope.Name)
return exp, err, whichScope
default:
//P("not found looking via env.curfunc.parent.ClosingLookupSymbol(sym='%s')", sym.name)
//env.ShowStackStackAndScopeStack()
}
} else {
//fmt.Printf(" *** env.curfunc has closure of: %s\n", ClosureToString(env.curfunc, env))
//exp, err, scope = env.curfunc.ClosingLookupSymbol(sym, setVal)
exp, err, scope = env.curfunc.ClosingLookupSymbolUntilFunc(sym, setVal, 1, false)
switch err {
case nil:
//P("LexicalLookupSymbol('%s') found in env.curfunc.ClosingLookupSymbolUnfilFunc(1, false) in scope '%s'\n", sym.name, scope.Name)
return exp, err, scope
}
}
// with checkCaptures true, as tests/package.zy needs this.
exp, err, scope = env.linearstack.LookupSymbolUntilFunction(sym, setVal, 2, true)
switch err {
case nil:
//P("LexicalLookupSymbol('%s') found in env.linearstack.LookupSymbolUtilFunction(2, true) in parent runtime scope '%s'\n", sym.name, scope.Name)
return exp, err, scope
case SymNotFound:
break
}
return SexpNull, fmt.Errorf("symbol `%s` not found", sym.name), nil
}
func (env *Zlisp) LexicalBindSymbol(sym *SexpSymbol, expr Sexp) error {
return env.linearstack.BindSymbol(sym, expr)
}
// _closdump : show the closed over env attached to an *SexpFunction
func DumpClosureEnvFunction(env *Zlisp, name string, args []Sexp) (Sexp, error) {
if len(args) != 1 {
return SexpNull, WrongNargs
}
switch f := args[0].(type) {
case *SexpFunction:
s := ClosureToString(f, env)
return &SexpStr{S: s}, nil
default:
return SexpNull, fmt.Errorf("_closdump needs an *SexpFunction to inspect")
}
}
func ClosureToString(f *SexpFunction, env *Zlisp) string {
s, err := f.ShowClosing(env, NewPrintState(),
fmt.Sprintf("closedOverScopes of '%s'", f.name))
if err != nil {
return err.Error()
}
return s
}
func (env *Zlisp) IsBuiltinSym(sym *SexpSymbol) (builtin bool, typ string) {
_, isBuiltin := env.builtins[sym.number]
if isBuiltin {
return true, "built-in function"
}
_, isBuiltin = env.macros[sym.number]
if isBuiltin {
return true, "macro"
}
_, isReserved := env.reserved[sym.number]
if isReserved {
return true, "reserved word"
}
return false, ""
}
func (env *Zlisp) ResolveDotSym(arg []Sexp) ([]Sexp, error) {
r := []Sexp{}
for i := range arg {
switch sym := arg[i].(type) {
case *SexpSymbol:
resolved, err := dotGetSetHelper(env, sym.name, nil)
if err != nil {
return nil, err
}
r = append(r, resolved)
default:
r = append(r, arg[i])
}
}
return r, nil
}

27
vendor/github.com/glycerine/zygomys/zygo/exists.go generated vendored Normal file
View File

@@ -0,0 +1,27 @@
package zygo
import (
"os"
)
func FileExists(name string) bool {
fi, err := os.Stat(name)
if err != nil {
return false
}
if fi.IsDir() {
return false
}
return true
}
func DirExists(name string) bool {
fi, err := os.Stat(name)
if err != nil {
return false
}
if fi.IsDir() {
return true
}
return false
}

694
vendor/github.com/glycerine/zygomys/zygo/expressions.go generated vendored Normal file
View File

@@ -0,0 +1,694 @@
package zygo
import (
"fmt"
"reflect"
"strconv"
"strings"
)
// all Sexp are typed, and have a zero value corresponding to
// the type of the Sexp.
// Sexp is the central interface for all
// S-expressions (Symbol expressions ala lisp).
type Sexp interface {
// SexpString: produce a string from our value.
// Single-line strings can ignore indent.
// Only multiline strings should follow every
// newline with at least indent worth of spaces.
SexpString(ps *PrintState) string
// Type returns the type of the value.
Type() *RegisteredType
}
type SexpPair struct {
Head Sexp
Tail Sexp
}
type SexpPointer struct {
ReflectTarget reflect.Value
Target Sexp
PointedToType *RegisteredType
MyType *RegisteredType
}
func NewSexpPointer(pointedTo Sexp) *SexpPointer {
pointedToType := pointedTo.Type()
var reftarg reflect.Value
Q("NewSexpPointer sees pointedTo of '%#v'", pointedTo)
switch e := pointedTo.(type) {
case *SexpReflect:
Q("SexpReflect.Val = '%#v'", e.Val)
reftarg = e.Val
default:
reftarg = reflect.ValueOf(pointedTo)
}
ptrRt := GoStructRegistry.GetOrCreatePointerType(pointedToType)
Q("pointer type is ptrRt = '%#v'", ptrRt)
p := &SexpPointer{
ReflectTarget: reftarg,
Target: pointedTo,
PointedToType: pointedToType,
MyType: ptrRt,
}
return p
}
func (p *SexpPointer) SexpString(ps *PrintState) string {
return fmt.Sprintf("%p", &p.Target)
//return fmt.Sprintf("(* %v) %p", p.PointedToType.RegisteredName, p.Target)
}
func (p *SexpPointer) Type() *RegisteredType {
return p.MyType
}
type SexpInt struct {
Val int64
Typ *RegisteredType
}
type SexpUint64 struct {
Val uint64
Typ *RegisteredType
}
type SexpBool struct {
Val bool
Typ *RegisteredType
}
type SexpFloat struct {
Val float64
Typ *RegisteredType
Scientific bool
}
type SexpChar struct {
Val rune
Typ *RegisteredType
}
type SexpStr struct {
S string
backtick bool
Typ *RegisteredType
}
func (r SexpStr) Type() *RegisteredType {
return GoStructRegistry.Registry["string"]
}
func (r *SexpInt) Type() *RegisteredType {
return GoStructRegistry.Registry["int64"]
}
func (r *SexpUint64) Type() *RegisteredType {
return GoStructRegistry.Registry["uint64"]
}
func (r *SexpFloat) Type() *RegisteredType {
return GoStructRegistry.Registry["float64"]
}
func (r *SexpBool) Type() *RegisteredType {
return GoStructRegistry.Registry["bool"]
}
func (r *SexpChar) Type() *RegisteredType {
return GoStructRegistry.Registry["int32"]
}
func (r *RegisteredType) Type() *RegisteredType {
return r
}
type SexpRaw struct {
Val []byte
Typ *RegisteredType
}
func (r *SexpRaw) Type() *RegisteredType {
return r.Typ
}
type SexpReflect struct {
Val reflect.Value
}
func (r *SexpReflect) Type() *RegisteredType {
k := reflectName(reflect.Value(r.Val))
Q("SexpReflect.Type() looking up type named '%s'", k)
ty, ok := GoStructRegistry.Registry[k]
if !ok {
Q("SexpReflect.Type(): type named '%s' not found", k)
return nil
}
Q("SexpReflect.Type(): type named '%s' found as regtype '%v'", k, ty.SexpString(nil))
return ty
}
type SexpError struct {
error
}
func (r *SexpError) Type() *RegisteredType {
return GoStructRegistry.Registry["error"]
}
func (r *SexpSentinel) Type() *RegisteredType {
return nil // TODO what should this be?
}
type SexpClosureEnv Scope
func (r *SexpClosureEnv) Type() *RegisteredType {
return nil // TODO what should this be?
}
func (c *SexpClosureEnv) SexpString(ps *PrintState) string {
scop := (*Scope)(c)
s, err := scop.Show(scop.env, ps, "")
if err != nil {
panic(err)
}
return s
}
type SexpSentinel struct {
Val int
}
// these are values now so that they also have addresses.
var SexpNull = &SexpSentinel{Val: 0}
var SexpEnd = &SexpSentinel{Val: 1}
var SexpMarker = &SexpSentinel{Val: 2}
type SexpSemicolon struct{}
type SexpComma struct{}
func (r *SexpSemicolon) Type() *RegisteredType {
return nil // TODO what should this be?
}
func (s *SexpSemicolon) SexpString(ps *PrintState) string {
return ";"
}
func (r *SexpComma) Type() *RegisteredType {
return nil // TODO what should this be?
}
func (s *SexpComma) SexpString(ps *PrintState) string {
return ","
}
func (sent *SexpSentinel) SexpString(ps *PrintState) string {
if sent == SexpNull {
return "nil"
}
if sent == SexpEnd {
return "End"
}
if sent == SexpMarker {
return "Marker"
}
return ""
}
func Cons(a Sexp, b Sexp) *SexpPair {
return &SexpPair{a, b}
}
func (pair *SexpPair) SexpString(ps *PrintState) string {
str := "("
for {
switch pair.Tail.(type) {
case *SexpPair:
str += pair.Head.SexpString(ps) + " "
pair = pair.Tail.(*SexpPair)
continue
}
break
}
str += pair.Head.SexpString(ps)
if pair.Tail == SexpNull {
str += ")"
} else {
str += " \\ " + pair.Tail.SexpString(ps) + ")"
}
return str
}
func (r *SexpPair) Type() *RegisteredType {
return nil // TODO what should this be?
}
type SexpArray struct {
Val []Sexp
Typ *RegisteredType
IsFuncDeclTypeArray bool
Infix bool
Env *Zlisp
}
func (r *SexpArray) Type() *RegisteredType {
if r.Typ == nil {
if len(r.Val) > 0 {
// take type from first element
ty := r.Val[0].Type()
if ty != nil {
r.Typ = GoStructRegistry.GetOrCreateSliceType(ty)
}
} else {
// empty array
r.Typ = GoStructRegistry.Lookup("[]")
//P("lookup [] returned type %#v", r.Typ)
}
}
return r.Typ
}
func (arr *SexpArray) SexpString(ps *PrintState) string {
indInner := ""
indent := ps.GetIndent()
innerPs := ps.AddIndent(4) // generates a fresh new PrintState
inner := indent + 4
//prettyEnd := ""
pretty := false
if arr != nil && arr.Env != nil && arr.Env.Pretty {
pretty = true
//prettyEnd = "\n"
indInner = strings.Repeat(" ", inner)
ps = innerPs
}
opn := "["
cls := "]"
if arr.Infix {
opn = "{"
cls = "}"
}
if pretty {
opn += "\n"
indInner = strings.Repeat(" ", inner)
}
if len(arr.Val) == 0 {
return opn + cls
}
ta := arr.IsFuncDeclTypeArray
str := opn
for i, sexp := range arr.Val {
str += indInner + sexp.SexpString(ps)
if ta && i%2 == 0 {
str += ":"
} else {
str += " "
}
}
m := len(str)
str = str[:m-1] + indInner + cls
return str
}
func (e *SexpError) SexpString(ps *PrintState) string {
return e.error.Error()
}
type EmbedPath struct {
ChildName string
ChildFieldNum int
}
func GetEmbedPath(e []EmbedPath) string {
r := ""
last := len(e) - 1
for i, s := range e {
r += s.ChildName
if i < last {
r += ":"
}
}
return r
}
type HashFieldDet struct {
FieldNum int
FieldType reflect.Type
StructField reflect.StructField
FieldName string
FieldJsonTag string
EmbedPath []EmbedPath // we are embedded if len(EmbedPath) > 0
}
type SexpHash struct {
TypeName string
Map map[int][]*SexpPair
KeyOrder []Sexp
GoStructFactory *RegisteredType
NumKeys int
GoMethods []reflect.Method
GoFields []reflect.StructField
GoMethSx SexpArray
GoFieldSx SexpArray
GoType reflect.Type
NumMethod int
GoShadowStruct interface{}
GoShadowStructVa reflect.Value
ShadowSet bool
// json tag name -> pointers to example values, as factories for SexpToGoStructs()
JsonTagMap map[string]*HashFieldDet
DetOrder []*HashFieldDet
// for using these as a scoping model
DefnEnv *SexpHash
SuperClass *SexpHash
ZMain SexpFunction
ZMethods map[string]*SexpFunction
Env *Zlisp
}
var MethodNotFound = fmt.Errorf("method not found")
func (h *SexpHash) RunZmethod(method string, args []Sexp) (Sexp, error) {
f, ok := (h.ZMethods)[method]
if !ok {
return SexpNull, MethodNotFound
}
panic(fmt.Errorf("not done calling %s", f.name))
//return SexpNull, nil
}
func CallZMethodOnRecordFunction(env *Zlisp, name string, args []Sexp) (Sexp, error) {
narg := len(args)
if narg < 2 {
return SexpNull, WrongNargs
}
var hash *SexpHash
switch h := args[0].(type) {
case *SexpHash:
hash = h
default:
return SexpNull, fmt.Errorf("can only _call on a record")
}
method := ""
switch s := args[1].(type) {
case *SexpSymbol:
method = s.name
case *SexpStr:
method = s.S
default:
return SexpNull, fmt.Errorf("can only _call with a " +
"symbol or string as the method name. example: (_call record method:)")
}
return hash.RunZmethod(method, args[2:])
}
func (h *SexpHash) SetMain(p *SexpFunction) {
h.BindSymbol(h.Env.MakeSymbol(".main"), p)
}
func (h *SexpHash) SetDefnEnv(p *SexpHash) {
h.DefnEnv = p
h.BindSymbol(h.Env.MakeSymbol(".parent"), p)
}
func (h *SexpHash) Lookup(env *Zlisp, key Sexp) (expr Sexp, err error) {
return h.HashGet(env, key)
}
func (h *SexpHash) BindSymbol(key *SexpSymbol, val Sexp) error {
return h.HashSet(key, val)
}
func (h *SexpHash) SetGoStructFactory(factory *RegisteredType) {
h.GoStructFactory = factory
}
var SexpIntSize = 64
var SexpFloatSize = 64
func (r *SexpReflect) SexpString(ps *PrintState) string {
Q("in SexpReflect.SexpString(indent); top; type = %T", r)
if reflect.Value(r.Val).Type().Kind() == reflect.Ptr {
iface := reflect.Value(r.Val).Interface()
switch iface.(type) {
case *string:
return fmt.Sprintf("`%v`", reflect.Value(r.Val).Elem().Interface())
default:
return fmt.Sprintf("%v", reflect.Value(r.Val).Elem().Interface())
}
}
iface := reflect.Value(r.Val).Interface()
Q("in SexpReflect.SexpString(indent); type = %T", iface)
switch iface.(type) {
default:
return fmt.Sprintf("%v", iface)
}
}
func (b *SexpBool) SexpString(ps *PrintState) string {
if bool(b.Val) {
return "true"
}
return "false"
}
func (i *SexpInt) SexpString(ps *PrintState) string {
return strconv.Itoa(int(i.Val))
}
func (i *SexpUint64) SexpString(ps *PrintState) string {
return strconv.FormatUint(i.Val, 10) + "ULL"
}
func (f *SexpFloat) SexpString(ps *PrintState) string {
if f.Scientific {
return strconv.FormatFloat(f.Val, 'e', -1, SexpFloatSize)
}
return strconv.FormatFloat(f.Val, 'f', -1, SexpFloatSize)
}
func (c *SexpChar) SexpString(ps *PrintState) string {
return strconv.QuoteRune(c.Val)
}
func (s *SexpStr) SexpString(ps *PrintState) string {
if s.backtick {
return "`" + s.S + "`"
}
return strconv.Quote(string(s.S))
}
func (r *SexpRaw) SexpString(ps *PrintState) string {
return fmt.Sprintf("%#v", []byte(r.Val))
}
type SexpSymbol struct {
name string
number int
isDot bool
isSigil bool
colonTail bool
sigil string
}
func (sym *SexpSymbol) RHS(env *Zlisp) (Sexp, error) {
if sym.isDot && env != nil {
return dotGetSetHelper(env, sym.name, nil)
}
return sym, nil
}
func (sym *SexpSymbol) AssignToSelection(env *Zlisp, rhs Sexp) error {
if sym.isDot && env != nil {
_, err := dotGetSetHelper(env, sym.name, &rhs)
return err
}
panic("not implemented yet")
}
func (sym *SexpSymbol) SexpString(ps *PrintState) string {
if sym.colonTail {
// return sym.name + ":"
}
return sym.name
}
func (r *SexpSymbol) Type() *RegisteredType {
return GoStructRegistry.Registry["symbol"]
}
func (sym SexpSymbol) Name() string {
return sym.name
}
func (sym SexpSymbol) Number() int {
return sym.number
}
// SexpInterfaceDecl
type SexpInterfaceDecl struct {
name string
methods []*SexpFunction
}
func (r *SexpInterfaceDecl) SexpString(ps *PrintState) string {
indent := ps.GetIndent()
space := strings.Repeat(" ", indent)
space4 := strings.Repeat(" ", indent+4)
s := space + "(interface " + r.name + " ["
if len(r.methods) > 0 {
s += "\n"
}
for i := range r.methods {
s += space4 + r.methods[i].SexpString(ps.AddIndent(4)) + "\n"
}
s += space + "])"
return s
}
func (r *SexpInterfaceDecl) Type() *RegisteredType {
// todo: how to register/what to register?
return GoStructRegistry.Registry[r.name]
}
// SexpFunction
type SexpFunction struct {
name string
user bool
nargs int
varargs bool
fun ZlispFunction
userfun ZlispUserFunction
orig Sexp
closingOverScopes *Closing
parent *SexpFunction
isBuilder bool // see defbuild; builders are builtins that receive un-evaluated expressions
inputTypes *SexpHash
returnTypes *SexpHash
hasBody bool // could just be declaration in an interface, without a body
}
func (sf *SexpFunction) Type() *RegisteredType {
return nil // TODO what goes here
}
func (sf *SexpFunction) Copy() *SexpFunction {
cp := *sf
return &cp
}
func (sf *SexpFunction) SetClosing(clos *Closing) {
ps4 := NewPrintStateWithIndent(4)
pre, err := sf.ShowClosing(clos.env, ps4, "prev")
_ = pre
panicOn(err)
newnew, err := sf.ShowClosing(clos.env, ps4, "newnew")
_ = newnew
panicOn(err)
//P("99999 for sfun = %p, in sfun.SetClosing(), prev value is %p = '%s'\n",
// sf, sf.closingOverScopes, pre)
//P("88888 in sfun.SetClosing(), new value is %p = '%s'\n", clos, newnew)
sf.closingOverScopes = clos
//P("in SetClosing() for '%s'/%p: my stack is: '%s'", sf.name, sf, clos.Stack.SexpString(nil))
}
func (sf *SexpFunction) ShowClosing(env *Zlisp, ps *PrintState, label string) (string, error) {
if sf.closingOverScopes == nil {
return sf.name + " has no captured scopes.", nil
}
return sf.closingOverScopes.Show(env, ps, label)
}
func (sf *SexpFunction) ClosingLookupSymbolUntilFunction(sym *SexpSymbol) (Sexp, error, *Scope) {
if sf.closingOverScopes != nil {
return sf.closingOverScopes.LookupSymbolUntilFunction(sym, nil, 1, false)
}
return SexpNull, SymNotFound, nil
}
func (sf *SexpFunction) ClosingLookupSymbol(sym *SexpSymbol, setVal *Sexp) (Sexp, error, *Scope) {
if sf.closingOverScopes != nil {
return sf.closingOverScopes.LookupSymbol(sym, setVal)
}
//P("sf.closingOverScopes was nil, no captured scopes. sf = '%v'", sf.SexpString(nil))
return SexpNull, SymNotFound, nil
}
// chase parent pointers up the chain and check each of their immediate closures.
func (sf *SexpFunction) LookupSymbolInParentChainOfClosures(sym *SexpSymbol, setVal *Sexp, env *Zlisp) (Sexp, error, *Scope) {
cur := sf
par := sf.parent
for par != nil {
//fmt.Printf(" parent chain: cur:%v -> parent:%v\n", cur.name, par.name)
//fmt.Printf(" cur.closures = %s", ClosureToString(cur, env))
exp, err, scope := cur.ClosingLookupSymbolUntilFunc(sym, setVal, 1, false)
if err == nil {
//P("LookupSymbolInParentChainOfClosures(sym='%s') found in scope '%s'\n", sym.name, scope.Name)
return exp, err, scope
}
cur = par
par = par.parent
}
return SexpNull, SymNotFound, nil
}
func (sf *SexpFunction) ClosingLookupSymbolUntilFunc(sym *SexpSymbol, setVal *Sexp, maximumFuncToSearch int, checkCaptures bool) (Sexp, error, *Scope) {
if sf.closingOverScopes != nil {
return sf.closingOverScopes.LookupSymbolUntilFunction(sym, setVal, maximumFuncToSearch, checkCaptures)
}
//P("sf.closingOverScopes was nil, no captured scopes. sf = '%v'", sf.SexpString(nil))
return SexpNull, SymNotFound, nil
}
func (sf *SexpFunction) SexpString(ps *PrintState) string {
if sf.orig == nil {
return "fn [" + sf.name + "]"
}
return sf.orig.SexpString(ps)
}
func IsTruthy(expr Sexp) bool {
switch e := expr.(type) {
case *SexpBool:
return e.Val
case *SexpInt:
return e.Val != 0
case *SexpUint64:
return e.Val != 0
case *SexpChar:
return e.Val != 0
case *SexpSentinel:
return e != SexpNull
}
return true
}
type SexpStackmark struct {
sym *SexpSymbol
}
func (r *SexpStackmark) Type() *RegisteredType {
return nil // TODO what should this be?
}
func (mark *SexpStackmark) SexpString(ps *PrintState) string {
return "stackmark " + mark.sym.name
}

295
vendor/github.com/glycerine/zygomys/zygo/func.go generated vendored Normal file
View File

@@ -0,0 +1,295 @@
package zygo
import (
"fmt"
)
func FuncBuilder(env *Zlisp, name string,
args []Sexp) (Sexp, error) {
useName := name
isMethod := false
if name == "method" {
isMethod = true
useName = "method [p: (* StructName)]"
}
use := "use: (" + useName + " funcName [inputs:type ...] [returns:type ...])"
n := len(args)
if n < 1 {
return SexpNull, fmt.Errorf("missing arguments. %s", use)
}
inputsLoc := 1
returnsLoc := 2
bodyLoc := 3
isAnon := false
var symN *SexpSymbol
switch b := args[0].(type) {
case *SexpSymbol:
symN = b
case *SexpPair:
sy, isQuo := isQuotedSymbol(b)
if isQuo {
symN = sy.(*SexpSymbol)
} else {
return SexpNull, fmt.Errorf("bad func name: symbol required")
}
case *SexpArray:
if isMethod {
ok := false
symN, ok = args[1].(*SexpSymbol)
if !ok {
return SexpNull, fmt.Errorf("bad method name: symbol required after receiver array")
}
inputsLoc++
returnsLoc++
bodyLoc++
} else {
// anonymous function
symN = env.GenSymbol("__anon")
isAnon = true
inputsLoc--
returnsLoc--
bodyLoc--
}
default:
return SexpNull, fmt.Errorf("bad func name: symbol required")
}
Q("good: have func name '%v'", symN.name)
funcName := symN.name
builtin, builtTyp := env.IsBuiltinSym(symN)
if builtin {
return SexpNull,
fmt.Errorf("already have %s '%s', refusing to overwrite with defn",
builtTyp, symN.name)
}
if env.HasMacro(symN) {
return SexpNull, fmt.Errorf("Already have macro named '%s': refusing"+
" to define function of same name.", symN.name)
}
if n < inputsLoc+1 {
return SexpNull, fmt.Errorf("func [inputs] array is missing. %s", use)
}
if n < returnsLoc+1 {
return SexpNull, fmt.Errorf("func [returns] array is missing. %s", use)
}
var inputs *SexpArray
switch ar := args[inputsLoc].(type) {
default:
return SexpNull, fmt.Errorf("bad func declaration '%v': "+
"expected array of input declarations after the name. %s", funcName, use)
case *SexpArray:
inputs = ar
inputs.IsFuncDeclTypeArray = true
}
var returns *SexpArray
switch ar := args[returnsLoc].(type) {
default:
return SexpNull, fmt.Errorf("bad func declaration '%v': third argument "+
"must be a array of return declarations. %s", funcName, use)
case *SexpArray:
returns = ar
returns.IsFuncDeclTypeArray = true
}
body := args[bodyLoc:]
Q("in func builder, args = ")
for i := range args {
Q("args[%v] = '%s'", i, args[i].SexpString(nil))
}
Q("in func builder, isAnon = %v", isAnon)
Q("in func builder, inputs = %v", inputs.SexpString(nil))
Q("in func builder, returns = %v", returns.SexpString(nil))
Q("in func builder, body = %v", (&SexpArray{Val: body, Env: env}).SexpString(nil))
inHash, err := GetFuncArgArray(inputs, env, "inputs")
if err != nil {
return SexpNull, fmt.Errorf("inputs array parsing error: %v", err)
}
Q("inHash = '%v'", inHash.SexpString(nil))
retHash, err := GetFuncArgArray(returns, env, "returns")
if err != nil {
return SexpNull, fmt.Errorf("returns array parsing error: %v", err)
}
Q("retHash = '%v'", retHash.SexpString(nil))
env.datastack.PushExpr(SexpNull)
Q("FuncBuilder() about to call buildSexpFun")
// ===================================
// ===================================
//
// from buildSexpFun, adapted
//
// todo: type checking the inputs and handling the returns as well
//
// ===================================
// ===================================
// sfun, err := buildSexpFun(env, symN.name, funcargs, body, orig)
//orig := &SexpArray{Val: args, Env: env}
origa := []Sexp{env.MakeSymbol("func")}
origa = append(origa, args...)
orig := MakeList(origa)
funcargs := inHash.KeyOrder
gen := NewGenerator(env)
gen.Tail = true
gen.funcname = funcName
afsHelper := &AddFuncScopeHelper{}
gen.AddInstruction(AddFuncScopeInstr{Name: "runtime " + gen.funcname, Helper: afsHelper})
argsyms := make([]*SexpSymbol, len(funcargs))
// copy
for i := range funcargs {
argsyms[i] = funcargs[i].(*SexpSymbol)
}
varargs := false
nargs := len(funcargs)
if len(argsyms) >= 2 && argsyms[len(argsyms)-2].name == "&" {
argsyms[len(argsyms)-2] = argsyms[len(argsyms)-1]
argsyms = argsyms[0 : len(argsyms)-1]
varargs = true
nargs = len(argsyms) - 1
}
VPrintf("\n in buildSexpFun(): DumpFunction just before %v args go onto stack\n",
len(argsyms))
if Working {
DumpFunction(ZlispFunction(gen.instructions), -1)
}
for i := len(argsyms) - 1; i >= 0; i-- {
gen.AddInstruction(PopStackPutEnvInstr{argsyms[i]})
}
err = gen.GenerateBegin(body)
if err != nil {
return MissingFunction, err
}
// minimal sanity check that we return the number of arguments
// on the stack that are declared
if len(body) == 0 {
for range retHash.KeyOrder {
gen.AddInstruction(PushInstr{expr: SexpNull})
}
}
gen.AddInstruction(RemoveScopeInstr{})
gen.AddInstruction(ReturnInstr{nil}) // nil is the error returned
newfunc := ZlispFunction(gen.instructions)
sfun := gen.env.MakeFunction(gen.funcname, nargs,
varargs, newfunc, orig)
sfun.inputTypes = inHash
sfun.returnTypes = retHash
// tell the function scope where their function is, to
// provide access to the captured-closure scopes at runtime.
afsHelper.MyFunction = sfun
clos := CreateClosureInstr{sfun}
notePc := env.pc
clos.Execute(env)
invok, err := env.datastack.PopExpr()
panicOn(err) // we just pushed in the clos.Execute(), so this should always be err == nil
env.pc = notePc
err = env.LexicalBindSymbol(symN, invok)
if err != nil {
return SexpNull, fmt.Errorf("internal error: could not bind symN:'%s' into env: %v", symN.name, err)
}
if len(body) > 0 {
invok.(*SexpFunction).hasBody = true
}
return invok, nil
}
func GetFuncArgArray(arr *SexpArray, env *Zlisp, where string) (*SexpHash, error) {
ar := arr.Val
n := len(ar)
hash, err := MakeHash([]Sexp{}, "hash", env)
panicOn(err)
if n == 0 {
return hash, nil
}
if n%2 != 0 {
return nil, fmt.Errorf("func definintion's %s array must have an even number of elements (each name:type pair counts as two)", where)
}
for i := 0; i < n; i += 2 {
name := ar[i]
typ := ar[i+1]
//P("name = %#v", name)
//P("typ = %#v", typ)
var symN *SexpSymbol
switch b := name.(type) {
case *SexpSymbol:
symN = b
case *SexpPair:
sy, isQuo := isQuotedSymbol(b)
if isQuo {
symN = sy.(*SexpSymbol)
} else {
return nil, fmt.Errorf("bad formal parameter name: symbol required in %s array, not a symbol: '%s'",
where, b.SexpString(nil))
}
}
var symTyp *SexpSymbol
switch b := typ.(type) {
case *SexpSymbol:
symTyp = b
case *SexpPair:
sy, isQuo := isQuotedSymbol(b)
if isQuo {
symTyp = sy.(*SexpSymbol)
} else {
return nil, fmt.Errorf("bad formal parameter type: type required in %s array, but found '%s'",
where, b.SexpString(nil))
}
}
//P("here is env.ShowGlobalStack():")
//env.ShowGlobalStack()
//P("symN = '%s'", symN.SexpString(nil))
//P("symTyp = '%s'", symTyp.SexpString(nil))
r, err, _ := env.LexicalLookupSymbol(symTyp, nil)
if err != nil {
return nil, fmt.Errorf("could not identify type %s: %v", symTyp.SexpString(nil), err)
}
switch rt := r.(type) {
case *RegisteredType:
// good, store it
hash.HashSet(symN, rt)
default:
return nil, fmt.Errorf("'%s' is not a known type", symTyp.SexpString(nil))
}
}
return hash, nil
}

1787
vendor/github.com/glycerine/zygomys/zygo/functions.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

1498
vendor/github.com/glycerine/zygomys/zygo/generator.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
package zygo
func init() { GITLASTTAG = "v5.1.1"; GITLASTCOMMIT = "acef8bb25d1cad8aebed3cedb59b481795ac9fa1" }

59
vendor/github.com/glycerine/zygomys/zygo/gob.go generated vendored Normal file
View File

@@ -0,0 +1,59 @@
package zygo
import (
"bytes"
"encoding/gob"
"fmt"
)
func GobEncodeFunction(env *Zlisp, name string, args []Sexp) (Sexp, error) {
if len(args) != 1 {
return SexpNull, WrongNargs
}
h, isHash := args[0].(*SexpHash)
if !isHash {
return SexpNull, fmt.Errorf("gob argument must be a hash or defmap")
}
// fill the go shadow struct
_, err := ToGoFunction(env, "togo", []Sexp{h})
if err != nil {
return SexpNull, fmt.Errorf("error converting object to Go struct: '%s'", err)
}
// serialize to gob
var gobBytes bytes.Buffer
enc := gob.NewEncoder(&gobBytes)
err = enc.Encode(h.GoShadowStruct)
if err != nil {
return SexpNull, fmt.Errorf("gob encode error: '%s'", err)
}
return &SexpRaw{Val: gobBytes.Bytes()}, nil
}
func GobDecodeFunction(env *Zlisp, name string, args []Sexp) (Sexp, error) {
if len(args) != 1 {
return SexpNull, WrongNargs
}
raw, isRaw := args[0].(*SexpRaw)
if !isRaw {
return SexpNull, fmt.Errorf("ungob argument must be raw []byte")
}
rawBuf := bytes.NewBuffer(raw.Val)
dec := gob.NewDecoder(rawBuf)
var iface interface{}
err := dec.Decode(iface)
if err != nil {
return SexpNull, fmt.Errorf("gob decode error: '%s'", err)
}
// TODO convert to hash
panic("not done yet!")
//return SexpNull, nil
}

472
vendor/github.com/glycerine/zygomys/zygo/gotypereg.go generated vendored Normal file
View File

@@ -0,0 +1,472 @@
package zygo
import (
"fmt"
"reflect"
"time"
)
// The Go Type Registry
// ====================
//
// simply decide upon a name, and add a maker
// function for that returns a pointer to your struct.
// The simply add to the init() function below.
//
// The env parameter to your MakeGoStructFunc()
// function is there is case you want to initialize
// your struct differently depending on the content
// of its context, but this is not commonly needed.
// Also, the factory method *must* support the
// env parameter being nil and still return a
// sensible, usable value. The factory will be called
// with env = nil during init() time.
//
// The repl will automatically do a (defmap record)
// for each record defined in the registry. e.g.
// for snoopy, hornet, hellcat, etc.
//
var GoStructRegistry GoStructRegistryType
// the registry type
type GoStructRegistryType struct {
// comprehensive
Registry map[string]*RegisteredType
// only init-time builtins
Builtin map[string]*RegisteredType
// later, user-defined types
Userdef map[string]*RegisteredType
}
// consistently ordered list of all registered types (created at init time).
var ListRegisteredTypes = []string{}
func (r *GoStructRegistryType) RegisterBuiltin(name string, e *RegisteredType) {
r.register(name, e, false)
e.IsUser = false
}
func (r *GoStructRegistryType) RegisterPointer(pointedToName string, pointedToType *RegisteredType) *RegisteredType {
newRT := &RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
p, err := pointedToType.Factory(env, h)
if err != nil {
return nil, err
}
return &p, nil
}}
r.register(fmt.Sprintf("(* %s)", pointedToName), newRT, false)
newRT.IsPointer = true
return newRT
}
func (r *GoStructRegistryType) register(name string, e *RegisteredType, isUser bool) {
if !e.initDone {
e.Init()
}
e.RegisteredName = name
e.Aliases[name] = true
e.Aliases[e.ReflectName] = true
_, found := r.Registry[name]
if !found {
ListRegisteredTypes = append(ListRegisteredTypes, name)
}
_, found2 := r.Registry[e.ReflectName]
if !found2 {
ListRegisteredTypes = append(ListRegisteredTypes, e.ReflectName)
}
if isUser {
r.Userdef[name] = e
} else {
r.Builtin[name] = e
}
r.Registry[name] = e
r.Registry[e.ReflectName] = e
}
func (e *RegisteredType) Init() {
e.Aliases = make(map[string]bool)
val, err := e.Factory(nil, nil)
panicOn(err)
if val != nil {
e.ValueCache = reflect.ValueOf(val)
e.TypeCache = e.ValueCache.Type()
e.PointerName = fmt.Sprintf("%T", val)
e.ReflectName = e.PointerName[1:] // todo: make this conditional on whether PointerName starts with '*'.
e.DisplayAs = e.ReflectName
}
e.initDone = true
}
func reflectName(val reflect.Value) string {
pointerName := fmt.Sprintf("%T", val.Interface())
reflectName := pointerName[1:]
return reflectName
}
func ifaceName(val interface{}) string {
pointerName := fmt.Sprintf("%T", val)
reflectName := pointerName[1:]
return reflectName
}
func (r *GoStructRegistryType) RegisterUserdef(
e *RegisteredType,
hasShadowStruct bool,
names ...string) {
for i, name := range names {
e0 := e
if i > 0 {
// make a copy of the RegisteredType for each name, so all names are kept.
// Otherwise we overwrite the DisplayAs below.
rt := *e
e0 = &rt
}
r.register(name, e0, true)
e0.IsUser = true
e0.hasShadowStruct = hasShadowStruct
e0.Constructor = MakeUserFunction("__struct_"+name, StructConstructorFunction)
if e0.DisplayAs == "" {
e0.DisplayAs = name
}
}
}
func (r *GoStructRegistryType) Lookup(name string) *RegisteredType {
return r.Registry[name]
}
// the type of all maker functions
type MakeGoStructFunc func(env *Zlisp, h *SexpHash) (interface{}, error)
var NullRT *RegisteredType
var PairRT *RegisteredType
var Int64RT *RegisteredType
var BoolRT *RegisteredType
var RuneRT *RegisteredType
var Float64RT *RegisteredType
var RawRT *RegisteredType
var ReflectRT *RegisteredType
var ErrorRT *RegisteredType
var SentinelRT *RegisteredType
var ClosureRT *RegisteredType
var ArraySelectorRT *RegisteredType
type RegisteredType struct {
initDone bool
hasShadowStruct bool
Constructor *SexpFunction
RegisteredName string
Factory MakeGoStructFunc
GenDefMap bool
ValueCache reflect.Value
TypeCache reflect.Type
PointerName string
ReflectName string
IsUser bool
Aliases map[string]bool
DisplayAs string
UserStructDefn *RecordDefn
IsPointer bool
}
func (p *RegisteredType) TypeCheckRecord(hash *SexpHash) error {
Q("in RegisteredType.TypeCheckRecord(hash = '%v')", hash.SexpString(nil))
if hash.TypeName == "field" {
Q("in RegisteredType.TypeCheckRecord, TypeName == field, skipping.")
return nil
}
if p.UserStructDefn != nil {
Q("in RegisteredType.TypeCheckRecord, type checking against '%#v'", p.UserStructDefn)
var err error
for _, key := range hash.KeyOrder {
obs, _ := hash.HashGet(nil, key)
err = hash.TypeCheckField(key, obs)
if err != nil {
return err
}
}
}
return nil
}
func (p *RegisteredType) SexpString(ps *PrintState) string {
if p == nil {
return "nil RegisteredType"
}
if p.UserStructDefn != nil {
return p.UserStructDefn.SexpString(ps)
}
return p.DisplayAs
}
func (p *RegisteredType) ShortName() string {
if p.UserStructDefn != nil {
return p.UserStructDefn.Name
}
return p.DisplayAs
}
func NewRegisteredType(f MakeGoStructFunc) *RegisteredType {
rt := &RegisteredType{Factory: f}
rt.Init()
return rt
}
// builtin known Go Structs
// NB these are used to test the functionality of the
// Go integration.
//
func init() {
GoStructRegistry = GoStructRegistryType{
Registry: make(map[string]*RegisteredType),
Builtin: make(map[string]*RegisteredType),
Userdef: make(map[string]*RegisteredType),
}
gsr := &GoStructRegistry
// add go builtin types
// ====================
// empty array
gsr.RegisterBuiltin("[]", &RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return &SexpArray{}, nil
}})
// scope, as used by the package operation
gsr.RegisterBuiltin("packageScope", &RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
pkg := env.NewScope()
pkg.Name = "prototype"
pkg.IsPackage = true
return pkg, nil
}})
gsr.RegisterBuiltin("packageScopeStack", &RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
pkg := env.NewStack(0)
pkg.Name = "prototypePackageScopeStack"
pkg.IsPackage = true
return pkg, nil
}})
gsr.RegisterBuiltin("arraySelector", &RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return &SexpArraySelector{}, nil
}})
gsr.RegisterBuiltin("hashSelector", &RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return &SexpHashSelector{}, nil
}})
gsr.RegisterBuiltin("comment",
&RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return SexpNull, nil
}})
gsr.RegisterBuiltin("byte",
&RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return new(byte), nil
}})
gsr.RegisterBuiltin("uint8",
&RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return new(byte), nil
}})
gsr.RegisterBuiltin("int",
&RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return new(int), nil
}})
gsr.RegisterBuiltin("uint16",
&RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return new(uint16), nil
}})
gsr.RegisterBuiltin("uint32",
&RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return new(uint32), nil
}})
gsr.RegisterBuiltin("uint64",
&RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return new(uint64), nil
}})
gsr.RegisterBuiltin("int8", &RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return new(int8), nil
}})
gsr.RegisterBuiltin("int16", &RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return new(int16), nil
}})
gsr.RegisterBuiltin("int32", &RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return new(int32), nil
}})
gsr.RegisterBuiltin("rune", &RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return new(int32), nil
}})
gsr.RegisterBuiltin("int64", &RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return new(int64), nil
}})
gsr.RegisterBuiltin("float32", &RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return new(float32), nil
}})
gsr.RegisterBuiltin("float64", &RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return new(float64), nil
}})
gsr.RegisterBuiltin("complex64", &RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return new(complex64), nil
}})
gsr.RegisterBuiltin("complex128", &RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return new(complex128), nil
}})
gsr.RegisterBuiltin("bool", &RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return new(bool), nil
}})
gsr.RegisterBuiltin("string", &RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return new(string), nil
}})
gsr.RegisterBuiltin("time.Time", &RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return new(time.Time), nil
}})
// add Sexp types
gsr.RegisterBuiltin("symbol", &RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return &SexpSymbol{}, nil
}})
/* either:
gsr.RegisterBuiltin("time.Time", &RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return new(time.Time), nil
}})
*/
// PairRT *RegisteredType
// RawRT *RegisteredType
// ReflectRT *RegisteredType
// ErrorRT *RegisteredType
gsr.RegisterBuiltin("error", &RegisteredType{GenDefMap: false, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
var err error
return &err, nil
}})
// SentinelRT *RegisteredType
// ClosureRT *RegisteredType
}
func TypeListFunction(env *Zlisp, name string, args []Sexp) (Sexp, error) {
narg := len(args)
if narg != 0 {
return SexpNull, WrongNargs
}
r := ListRegisteredTypes
s := make([]Sexp, len(r))
for i := range r {
s[i] = &SexpStr{S: r[i]}
}
return env.NewSexpArray(s), nil
}
func (env *Zlisp) ImportBaseTypes() {
for _, e := range GoStructRegistry.Builtin {
env.AddGlobal(e.RegisteredName, e)
}
for _, e := range GoStructRegistry.Userdef {
env.AddGlobal(e.RegisteredName, e)
}
}
func compareRegisteredTypes(a *RegisteredType, bs Sexp) (int, error) {
var b *RegisteredType
switch bt := bs.(type) {
case *RegisteredType:
b = bt
default:
return 0, fmt.Errorf("cannot compare %T to %T", a, bs)
}
if a == b {
// equal for sure
return 0, nil
}
return 1, nil
}
func (gsr *GoStructRegistryType) GetOrCreatePointerType(pointedToType *RegisteredType) *RegisteredType {
Q("pointedToType = %#v", pointedToType)
ptrName := "*" + pointedToType.RegisteredName
ptrRt := gsr.Lookup(ptrName)
if ptrRt != nil {
Q("type named '%v' already registered, reusing the pointer type", ptrName)
} else {
Q("registering new pointer type '%v'", ptrName)
derivedType := reflect.PtrTo(pointedToType.TypeCache)
ptrRt = NewRegisteredType(func(env *Zlisp, h *SexpHash) (interface{}, error) {
return reflect.New(derivedType), nil
})
ptrRt.DisplayAs = fmt.Sprintf("(* %s)", pointedToType.DisplayAs)
ptrRt.RegisteredName = ptrName
gsr.RegisterUserdef(ptrRt, false, ptrName)
}
return ptrRt
}
func (gsr *GoStructRegistryType) GetOrCreateSliceType(rt *RegisteredType) *RegisteredType {
//sliceName := "sliceOf" + rt.RegisteredName
sliceName := "[]" + rt.RegisteredName
sliceRt := gsr.Lookup(sliceName)
if sliceRt != nil {
Q("type named '%v' already registered, re-using the type", sliceName)
} else {
Q("registering new slice type '%v'", sliceName)
derivedType := reflect.SliceOf(rt.TypeCache)
sliceRt = NewRegisteredType(func(env *Zlisp, h *SexpHash) (interface{}, error) {
return reflect.MakeSlice(derivedType, 0, 0), nil
})
sliceRt.DisplayAs = fmt.Sprintf("(%s)", sliceName)
sliceRt.RegisteredName = sliceName
gsr.RegisterUserdef(sliceRt, false, sliceName)
}
return sliceRt
}
func RegisterDemoStructs() {
gsr := &GoStructRegistry
// demo and user defined structs
gsr.RegisterUserdef(&RegisteredType{GenDefMap: true, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return &Event{}, nil
}}, true, "eventdemo")
gsr.RegisterUserdef(&RegisteredType{GenDefMap: true, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return &Person{}, nil
}}, true, "persondemo")
gsr.RegisterUserdef(&RegisteredType{GenDefMap: true, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return &Snoopy{}, nil
}}, true, "snoopy")
gsr.RegisterUserdef(&RegisteredType{GenDefMap: true, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return &Hornet{}, nil
}}, true, "hornet")
gsr.RegisterUserdef(&RegisteredType{GenDefMap: true, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return &Hellcat{}, nil
}}, true, "hellcat")
gsr.RegisterUserdef(&RegisteredType{GenDefMap: true, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return &Weather{}, nil
}}, true, "weather")
gsr.RegisterUserdef(&RegisteredType{GenDefMap: true, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return &Plane{}, nil
}}, true, "plane")
gsr.RegisterUserdef(&RegisteredType{GenDefMap: true, Factory: func(env *Zlisp, h *SexpHash) (interface{}, error) {
return &SetOfPlanes{}, nil
}}, true, "setOfPlanes")
}

1155
vendor/github.com/glycerine/zygomys/zygo/hashutils.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

67
vendor/github.com/glycerine/zygomys/zygo/import.go generated vendored Normal file
View File

@@ -0,0 +1,67 @@
package zygo
import (
"fmt"
)
// import a package, analagous to Golang.
func ImportPackageBuilder(env *Zlisp, name string, args []Sexp) (Sexp, error) {
//P("starting ImportPackageBuilder")
n := len(args)
if n != 1 && n != 2 {
return SexpNull, WrongNargs
}
var path Sexp
var alias string
switch n {
case 1:
path = args[0]
case 2:
path = args[1]
//P("import debug: alias position at args[0] is '%#v'", args[0])
switch sy := args[0].(type) {
case *SexpSymbol:
//P("import debug: alias is symbol, ok: '%v'", sy.name)
alias = sy.name
default:
return SexpNull, fmt.Errorf("import error: alias was not a symbol name")
}
}
var pth string
switch x := path.(type) {
case *SexpStr:
pth = x.S
default:
return SexpNull, fmt.Errorf("import error: path argument must be string")
}
if !FileExists(pth) {
return SexpNull, fmt.Errorf("import error: path '%s' does not exist", pth)
}
pkg, err := SourceFileFunction(env, "source", []Sexp{path})
if err != nil {
return SexpNull, fmt.Errorf("import error: attempt to import path '%s' resulted in: '%s'", pth, err)
}
//P("pkg = '%#v'", pkg)
asPkg, isPkg := pkg.(*Stack)
if !isPkg || !asPkg.IsPackage {
return SexpNull, fmt.Errorf("import error: attempt to import path '%s' resulted value that was not a package, but rather '%T'", pth, pkg)
}
if n == 1 {
alias = asPkg.PackageName
}
//P("using alias = '%s'", alias)
// now set alias in the current env
err = env.LexicalBindSymbol(env.MakeSymbol(alias), asPkg)
if err != nil {
return SexpNull, err
}
return pkg, nil
}

1160
vendor/github.com/glycerine/zygomys/zygo/jsonmsgp.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

860
vendor/github.com/glycerine/zygomys/zygo/lexer.go generated vendored Normal file
View File

@@ -0,0 +1,860 @@
package zygo
import (
"bytes"
"errors"
"fmt"
"io"
"regexp"
"strconv"
"unicode/utf8"
)
type TokenType int
const (
TokenTypeEmpty TokenType = iota
TokenLParen
TokenRParen
TokenLSquare
TokenRSquare
TokenLCurly
TokenRCurly
TokenDot
TokenQuote
TokenBacktick
TokenTilde
TokenTildeAt
TokenSymbol
TokenBool
TokenDecimal
TokenHex
TokenOct
TokenBinary
TokenFloat
TokenChar
TokenString
TokenCaret
TokenColonOperator
TokenThreadingOperator
TokenBackslash
TokenDollar
TokenDotSymbol
TokenFreshAssign
TokenBeginBacktickString
TokenBacktickString
TokenComment
TokenBeginBlockComment
TokenEndBlockComment
TokenSemicolon
TokenSymbolColon
TokenComma
TokenUint64
TokenEnd
)
type Token struct {
typ TokenType
str string
}
var EndTk = Token{typ: TokenEnd}
func (t Token) String() string {
switch t.typ {
case TokenLParen:
return "("
case TokenRParen:
return ")"
case TokenLSquare:
return "["
case TokenRSquare:
return "]"
case TokenLCurly:
return "{"
case TokenRCurly:
return "}"
case TokenDot:
return t.str
case TokenQuote:
return "'"
case TokenBacktick:
return "`"
case TokenCaret:
return "^"
case TokenTilde:
return "~"
case TokenTildeAt:
return "~@"
case TokenHex:
return "0x" + t.str
case TokenOct:
return "0o" + t.str
case TokenBinary:
return "0b" + t.str
case TokenChar:
return strconv.Quote(t.str)
case TokenColonOperator:
return ":"
case TokenThreadingOperator:
return "->"
case TokenBackslash:
return "\\"
case TokenDollar:
return "$"
}
return t.str
}
type LexerState int
const (
LexerNormal LexerState = iota
LexerCommentLine //
LexerStrLit //
LexerStrEscaped //
LexerUnquote //
LexerBacktickString //
LexerFreshAssignOrColon
LexerFirstFwdSlash // could be start of // comment or /*
LexerCommentBlock
LexerCommentBlockAsterisk // could be end of block comment */
LexerBuiltinOperator
LexerRuneLit
LexerRuneEscaped
)
type Lexer struct {
parser *Parser
state LexerState
prevrune rune
tokens []Token
buffer *bytes.Buffer
prevToken Token
prevPrevToken Token
stream io.RuneScanner
next []io.RuneScanner
linenum int
priori int
priorRune [20]rune
}
func (lexer *Lexer) AppendToken(tok Token) {
lexer.tokens = append(lexer.tokens, tok)
lexer.prevPrevToken = lexer.prevToken
lexer.prevToken = tok
}
func (lexer *Lexer) PrependToken(tok Token) {
lexer.tokens = append([]Token{tok}, lexer.tokens...)
}
//helper
func (lexer *Lexer) twoback() rune {
pen := lexer.priori - 2
if pen < 0 {
pen = len(lexer.priorRune) + pen
}
pr := lexer.priorRune[pen]
return pr
}
func NewLexer(p *Parser) *Lexer {
return &Lexer{
parser: p,
tokens: make([]Token, 0, 10),
buffer: new(bytes.Buffer),
state: LexerNormal,
linenum: 1,
}
}
func (lexer *Lexer) Linenum() int {
return lexer.linenum
}
func (lex *Lexer) Reset() {
lex.stream = nil
lex.tokens = lex.tokens[:0]
lex.state = LexerNormal
lex.linenum = 1
lex.buffer.Reset()
}
func (lex *Lexer) EmptyToken() Token {
return Token{}
}
func (lex *Lexer) Token(typ TokenType, str string) Token {
t := Token{
typ: typ,
str: str,
}
return t
}
var (
BoolRegex = regexp.MustCompile("^(true|false)$")
Uint64Regex = regexp.MustCompile("^(0x|0o)?[0-9a-fA-F]+ULL$")
DecimalRegex = regexp.MustCompile("^-?[0-9]+$")
HexRegex = regexp.MustCompile("^0x[0-9a-fA-F]+$")
OctRegex = regexp.MustCompile("^0o[0-7]+$")
BinaryRegex = regexp.MustCompile("^0b[01]+$")
// SymbolRegex = regexp.MustCompile("^[^'#]+$")
// (Sigil) symbols can begin with #, $, ?, but
// sigils cannot appear later in any symbol.
// Symbols cannot contain whitespace nor `~`, `@`, `(`, `)`, `[`, `]`,
// `{`, `}`, `'`, `#`, `^`, `\`, `|`, `%`, `"`, `;`. They can optionally
// end in `:`.
// Nor, obviously, can symbols contain backticks, "`".
// Symbols cannot start with a number. DotSymbols cannot have a number
// as the first character after '.'
SymbolRegex = regexp.MustCompile(`^[#$?]?[^#$?':;\\~@\[\]{}\^|"()%0-9,&][^'#:;\\~@\[\]{}\^|"()%,&*\-]*[:]?$`)
// dot symbol examples: `.`, `.a`, `.a.b`, `.a.b.c`
// dot symbol non-examples: `.a.`, `..`
DotSymbolRegex = regexp.MustCompile(`^[.]$|^([.][^'#:;\\~@\[\]{}\^|"()%.0-9,][^'#:;\\~@\[\]{}\^|"()%.,*+\-]*)+$|^[^'#:;\\~@\[\]{}\^|"()%.0-9,][^'#:;\\~@\[\]{}\^|"()%.,*+\-]*([.][^'#:;\\~@\[\]{}\^|"()%.0-9,][^'#:;\\~@\[\]{}\^|"()%.,*+\-]*)+$`)
DotPartsRegex = regexp.MustCompile(`[.]?[^'#:;\\~@\[\]{}\^|"()%.0-9,][^'#:;\\~@\[\]{}\^|"()%.,]*`)
CharRegex = regexp.MustCompile("^'(\\\\?.|\n)'$")
FloatRegex = regexp.MustCompile("^-?([0-9]+\\.[0-9]*)$|-?(\\.[0-9]+)$|-?([0-9]+(\\.[0-9]*)?[eE]([-+]?[0-9]+))$")
ComplexRegex = regexp.MustCompile("^-?([0-9]+\\.[0-9]*)i?$|-?(\\.[0-9]+)i?$|-?([0-9]+(\\.[0-9]*)?[eE](-?[0-9]+))i?$")
BuiltinOpRegex = regexp.MustCompile(`^(\+\+|\-\-|\+=|\-=|=|==|:=|\+|\-|\*|<|>|<=|>=|<-|->|\*=|/=|\*\*|!|!=|<!)$`)
)
func StringToRunes(str string) []rune {
b := []byte(str)
runes := make([]rune, 0)
for len(b) > 0 {
r, size := utf8.DecodeRune(b)
runes = append(runes, r)
b = b[size:]
}
return runes
}
func EscapeChar(char rune) (rune, error) {
switch char {
case 'n':
return '\n', nil
case 'r':
return '\r', nil
case 'a':
return '\a', nil
case 't':
return '\t', nil
case '\\':
return '\\', nil
case '"':
return '"', nil
case '\'':
return '\'', nil
case '#':
return '#', nil
}
return ' ', errors.New("invalid escape sequence")
}
func DecodeChar(atom string) (string, error) {
runes := StringToRunes(atom)
n := len(runes)
runes = runes[:n-1]
runes = runes[1:]
if len(runes) == 2 {
char, err := EscapeChar(runes[1])
return string(char), err
}
if len(runes) == 1 {
return string(runes[0]), nil
}
return "", errors.New("not a char literal")
}
func (x *Lexer) DecodeAtom(atom string) (tk Token, err error) {
endColon := false
n := len(atom)
if atom[n-1] == ':' {
endColon = true
atom = atom[:n-1] // remove the colon
}
if atom == "&" {
return x.Token(TokenSymbol, "&"), nil
}
if atom == "\\" {
return x.Token(TokenBackslash, ""), nil
}
if BoolRegex.MatchString(atom) {
return x.Token(TokenBool, atom), nil
}
if Uint64Regex.MatchString(atom) {
return x.Token(TokenUint64, atom), nil
}
if DecimalRegex.MatchString(atom) {
return x.Token(TokenDecimal, atom), nil
}
if HexRegex.MatchString(atom) {
return x.Token(TokenHex, atom[2:]), nil
}
if OctRegex.MatchString(atom) {
return x.Token(TokenOct, atom[2:]), nil
}
if BinaryRegex.MatchString(atom) {
return x.Token(TokenBinary, atom[2:]), nil
}
if FloatRegex.MatchString(atom) {
return x.Token(TokenFloat, atom), nil
}
if atom == "NaN" || atom == "nan" {
return x.Token(TokenFloat, "NaN"), nil
}
if DotSymbolRegex.MatchString(atom) {
//Q("matched DotSymbolRegex '%v'", atom)
return x.Token(TokenDotSymbol, atom), nil
}
if BuiltinOpRegex.MatchString(atom) {
return x.Token(TokenSymbol, atom), nil
}
if atom == ":" {
return x.Token(TokenSymbol, atom), nil
} else if SymbolRegex.MatchString(atom) {
////Q("matched symbol regex, atom='%v'", atom)
if endColon {
////Q("matched symbol regex with colon, atom[:n-1]='%v'", atom[:n-1])
return x.Token(TokenSymbolColon, atom[:n-1]), nil
}
return x.Token(TokenSymbol, atom), nil
}
if CharRegex.MatchString(atom) {
char, err := DecodeChar(atom)
if err != nil {
return x.EmptyToken(), err
}
return x.Token(TokenChar, char), nil
}
if endColon {
return x.Token(TokenColonOperator, ":"), nil
}
return x.EmptyToken(), fmt.Errorf("Unrecognized atom: '%s'", atom)
}
func (lexer *Lexer) dumpBuffer() error {
n := lexer.buffer.Len()
if n <= 0 {
return nil
}
tok, err := lexer.DecodeAtom(lexer.buffer.String())
if err != nil {
return err
}
lexer.buffer.Reset()
lexer.AppendToken(tok)
return nil
}
// with block comments, we've got to tell
// the parser about them, so it can recognize
// when another line is needed to finish a
// block comment.
func (lexer *Lexer) dumpComment() {
str := lexer.buffer.String()
lexer.buffer.Reset()
lexer.AppendToken(lexer.Token(TokenComment, str))
}
func (lexer *Lexer) dumpString() {
str := lexer.buffer.String()
lexer.buffer.Reset()
lexer.AppendToken(lexer.Token(TokenString, str))
}
func (lexer *Lexer) dumpBacktickString() {
str := lexer.buffer.String()
lexer.buffer.Reset()
lexer.AppendToken(lexer.Token(TokenBacktickString, str))
}
func (x *Lexer) DecodeBrace(brace rune) Token {
switch brace {
case '(':
return x.Token(TokenLParen, "")
case ')':
return x.Token(TokenRParen, "")
case '[':
return x.Token(TokenLSquare, "")
case ']':
return x.Token(TokenRSquare, "")
case '{':
return x.Token(TokenLCurly, "")
case '}':
return x.Token(TokenRCurly, "")
}
return EndTk
}
func (lexer *Lexer) LexNextRune(r rune) error {
// a little look-back ring. To help with scientific
// notation recognition
lexer.priorRune[lexer.priori] = r
lexer.priori = (lexer.priori + 1) % len(lexer.priorRune)
top:
switch lexer.state {
case LexerCommentBlock:
//Q("lexer.state = LexerCommentBlock")
if r == '\n' {
_, err := lexer.buffer.WriteRune('\n')
if err != nil {
return err
}
lexer.dumpComment()
// stay in LexerCommentBlock
return nil
}
if r == '*' {
lexer.state = LexerCommentBlockAsterisk
return nil
}
case LexerCommentBlockAsterisk:
//Q("lexer.state = LexerCommentBlockAsterisk")
if r == '/' {
_, err := lexer.buffer.WriteString("*/")
if err != nil {
return err
}
lexer.dumpComment()
lexer.AppendToken(lexer.Token(TokenEndBlockComment, ""))
lexer.state = LexerNormal
return nil
}
_, err := lexer.buffer.WriteRune('*')
if err != nil {
return err
}
lexer.state = LexerCommentBlock
goto writeRuneToBuffer
case LexerFirstFwdSlash:
//Q("lexer.state = LexerFirstFwdSlash")
if r == '/' {
err := lexer.dumpBuffer()
if err != nil {
return err
}
lexer.state = LexerCommentLine
_, err = lexer.buffer.WriteString("//")
return err
}
if r == '*' {
err := lexer.dumpBuffer()
if err != nil {
return err
}
_, err = lexer.buffer.WriteString("/*")
if err != nil {
return err
}
lexer.state = LexerCommentBlock
lexer.AppendToken(lexer.Token(TokenBeginBlockComment, ""))
return nil
}
lexer.state = LexerBuiltinOperator
lexer.prevrune = '/'
err := lexer.dumpBuffer() // don't mix with token before the /
if err != nil {
return err
}
goto top // process the unknown rune r
case LexerCommentLine:
//Q("lexer.state = LexerCommentLine")
if r == '\n' {
//Q("lexer.state = LexerCommentLine sees end of line comment: '%s', going to LexerNormal", string(lexer.buffer.Bytes()))
lexer.dumpComment()
lexer.state = LexerNormal
return nil
}
case LexerBacktickString:
if r == '`' {
lexer.dumpBacktickString()
lexer.state = LexerNormal
return nil
}
lexer.buffer.WriteRune(r)
return nil
case LexerStrLit:
if r == '\\' {
lexer.state = LexerStrEscaped
return nil
}
if r == '"' {
lexer.dumpString()
lexer.state = LexerNormal
return nil
}
lexer.buffer.WriteRune(r)
return nil
case LexerStrEscaped:
char, err := EscapeChar(r)
if err != nil {
return err
}
lexer.buffer.WriteRune(char)
lexer.state = LexerStrLit
return nil
case LexerRuneLit:
if r == '\\' {
lexer.state = LexerRuneEscaped
return nil
}
if r == '\'' {
// closing single quote
lexer.buffer.WriteRune(r)
lexer.dumpBuffer()
lexer.state = LexerNormal
return nil
}
lexer.buffer.WriteRune(r)
return nil
case LexerRuneEscaped:
char, err := EscapeChar(r)
if err != nil {
return err
}
lexer.buffer.WriteRune(char)
lexer.state = LexerRuneLit
return nil
case LexerUnquote:
if r == '@' {
lexer.AppendToken(lexer.Token(TokenTildeAt, ""))
} else {
lexer.AppendToken(lexer.Token(TokenTilde, ""))
lexer.buffer.WriteRune(r)
}
lexer.state = LexerNormal
return nil
case LexerFreshAssignOrColon:
lexer.state = LexerNormal
// there was a ':' followed by either '=' or something other than '=',
// so proceed to process the normal ':' actions.
if lexer.buffer.Len() == 0 {
if r == '=' {
lexer.AppendToken(lexer.Token(TokenFreshAssign, ":="))
return nil
}
}
if r == '=' {
err := lexer.dumpBuffer()
if err != nil {
return err
}
lexer.AppendToken(lexer.Token(TokenFreshAssign, ":="))
return nil
} else {
// but still allow ':' to be a token terminator at the end of a word.
_, err := lexer.buffer.WriteRune(':')
if err != nil {
return err
}
err = lexer.dumpBuffer()
if err != nil {
return err
}
goto top // process the unknown rune r in Normal mode
}
case LexerBuiltinOperator:
//Q("in LexerBuiltinOperator")
lexer.state = LexerNormal
// three cases: negative number, one rune operator, two rune operator
first := string(lexer.prevrune)
atom := fmt.Sprintf("%c%c", lexer.prevrune, r)
//Q("in LexerBuiltinOperator, first='%s', atom='%s'", first, atom)
// are we a negative number -1 or -.1 rather than ->, --, -= operator?
if lexer.prevrune == '-' {
if FloatRegex.MatchString(atom) || DecimalRegex.MatchString(atom) {
//Q("'%s' is the beginning of a negative number", atom)
_, err := lexer.buffer.WriteString(atom)
if err != nil {
return err
}
return nil
} else {
//Q("atom was not matched by FloatRegex: '%s'", atom)
}
}
if BuiltinOpRegex.MatchString(atom) {
//Q("2 rune atom in builtin op '%s', first='%s'", atom, first)
// 2 rune op
lexer.AppendToken(lexer.Token(TokenSymbol, atom))
return nil
}
//Q("1 rune atom in builtin op '%s', first='%s'", atom, first)
lexer.AppendToken(lexer.Token(TokenSymbol, first))
goto top // still have to parse r in normal
case LexerNormal:
switch r {
case '+':
fallthrough
case '-':
// 1e-1, 1E+1, 1e1 are allowed, scientific notation for floats.
pr := lexer.twoback()
if pr == 'e' || pr == 'E' {
// scientific notation number?
s := lexer.buffer.String()
ns := len(s)
if ns > 1 {
sWithoutE := s[:ns-1]
if DecimalRegex.MatchString(sWithoutE) ||
FloatRegex.MatchString(sWithoutE) {
goto writeRuneToBuffer
}
}
}
fallthrough
case '*':
fallthrough
case '<':
fallthrough
case '>':
fallthrough
case '=':
fallthrough
case '!':
err := lexer.dumpBuffer()
if err != nil {
return err
}
lexer.state = LexerBuiltinOperator
lexer.prevrune = r
return nil
case '/':
lexer.state = LexerFirstFwdSlash
return nil
case '`':
if lexer.buffer.Len() > 0 {
return errors.New("Unexpected backtick")
}
lexer.state = LexerBacktickString
lexer.AppendToken(lexer.Token(TokenBeginBacktickString, ""))
return nil
case '"':
if lexer.buffer.Len() > 0 {
return errors.New("Unexpected quote")
}
lexer.state = LexerStrLit
return nil
case '\'':
if lexer.buffer.Len() > 0 {
return errors.New("Unexpected single quote")
}
lexer.buffer.WriteRune(r)
lexer.state = LexerRuneLit
return nil
case ';':
err := lexer.dumpBuffer()
if err != nil {
return err
}
lexer.AppendToken(lexer.Token(TokenSemicolon, ";"))
return nil
case ',':
err := lexer.dumpBuffer()
if err != nil {
return err
}
lexer.AppendToken(lexer.Token(TokenComma, ","))
return nil
// colon terminates a keyword symbol, e.g. in `mykey: "myvalue"`;
// mykey is the symbol.
// Exception: unless it is the := operator for fresh assigment.
case ':':
lexer.state = LexerFreshAssignOrColon
// won't know if it is ':' alone or ':=' for sure
// until we get the next rune
return nil
// likewise &
case '&':
err := lexer.dumpBuffer()
if err != nil {
return err
}
lexer.AppendToken(lexer.Token(TokenSymbol, "&"))
return nil
case '%': // replaces ' as our quote shorthand
if lexer.buffer.Len() > 0 {
return errors.New("Unexpected % quote")
}
lexer.AppendToken(lexer.Token(TokenQuote, ""))
return nil
// caret '^' replaces backtick '`' as the start of a macro template, so
// we can use `` as in Go for verbatim strings (strings with newlines, etc).
case '^':
if lexer.buffer.Len() > 0 {
return errors.New("Unexpected ^ caret")
}
lexer.AppendToken(lexer.Token(TokenCaret, ""))
return nil
case '~':
if lexer.buffer.Len() > 0 {
return errors.New("Unexpected tilde")
}
lexer.state = LexerUnquote
return nil
case '(':
fallthrough
case ')':
fallthrough
case '[':
fallthrough
case ']':
fallthrough
case '{':
fallthrough
case '}':
err := lexer.dumpBuffer()
if err != nil {
return err
}
lexer.AppendToken(lexer.DecodeBrace(r))
return nil
case '\n':
lexer.linenum++
fallthrough
case ' ':
fallthrough
case '\t':
fallthrough
case '\r':
err := lexer.dumpBuffer()
if err != nil {
return err
}
return nil
} // end switch r in LexerNormal state
} // end switch lexer.state
writeRuneToBuffer:
_, err := lexer.buffer.WriteRune(r)
if err != nil {
return err
}
return nil
}
func (lexer *Lexer) PeekNextToken() (tok Token, err error) {
/*
Q("\n in PeekNextToken()\n")
defer func() {
Q("\n done with PeekNextToken() -> returning tok='%v', err=%v. tok='%#v'. tok==EndTk? %v\n",
tok, err, tok, tok == EndTk)
}()
*/
if lexer.stream == nil {
if !lexer.PromoteNextStream() {
return EndTk, nil
}
}
for len(lexer.tokens) == 0 {
r, _, err := lexer.stream.ReadRune()
if err != nil {
if lexer.PromoteNextStream() {
continue
} else {
return EndTk, nil
}
}
err = lexer.LexNextRune(r)
if err != nil {
return EndTk, err
}
}
tok = lexer.tokens[0]
return tok, nil
}
func (lexer *Lexer) GetNextToken() (tok Token, err error) {
/*
Q("\n in GetNextToken()\n")
defer func() {
Q("\n done with GetNextToken() -> returning tok='%v', err=%v. lexer.buffer.String()='%s'\n",
tok, err, lexer.buffer.String())
}()
*/
tok, err = lexer.PeekNextToken()
if err != nil || tok.typ == TokenEnd {
return EndTk, err
}
lexer.tokens = lexer.tokens[1:]
return tok, nil
}
func (lex *Lexer) PromoteNextStream() (ok bool) {
/*
Q("entering PromoteNextStream()!\n")
defer func() {
Q("done with PromoteNextStream, promoted=%v\n", ok)
}()
*/
if len(lex.next) == 0 {
return false
}
//Q("Promoting next stream!\n")
lex.stream = lex.next[0]
lex.next = lex.next[1:]
return true
}
func (lex *Lexer) AddNextStream(s io.RuneScanner) {
// in case we still have input available,
// save new stuff for later
lex.next = append(lex.next, s)
if lex.stream == nil {
lex.PromoteNextStream()
} else {
_, _, err := lex.stream.ReadRune()
if err == nil {
lex.stream.UnreadRune()
// still have input available
return
} else {
lex.PromoteNextStream()
}
}
}

134
vendor/github.com/glycerine/zygomys/zygo/liner.go generated vendored Normal file
View File

@@ -0,0 +1,134 @@
package zygo
import (
"sort"
"strings"
"github.com/glycerine/liner"
)
// filled at init time based on BuiltinFunctions
var completion_keywords = []string{`(`}
var math_funcs = []string{`* `, `** `, `+ `, `- `, `-> `, `/ `, `< `, `<= `, `== `, `> `, `>= `, `\ `}
func init() {
// fill in our auto-complete keywords
sortme := []*SymtabE{}
for f, _ := range AllBuiltinFunctions() {
sortme = append(sortme, &SymtabE{Key: f})
}
sort.Sort(SymtabSorter(sortme))
for i := range sortme {
completion_keywords = append(completion_keywords, "("+sortme[i].Key)
}
for i := range math_funcs {
completion_keywords = append(completion_keywords, "("+math_funcs[i])
}
}
type Prompter struct {
prompt string
prompter *liner.State
origMode liner.ModeApplier
rawMode liner.ModeApplier
}
// complete phrases that start with '('
func MyWordCompleter(line string, pos int) (head string, c []string, tail string) {
beg := []rune(line[:pos])
end := line[pos:]
Q("\nline = '%s' pos=%v\n", line, pos)
Q("\nbeg = '%v'\nend = '%s'\n", string(beg), end)
// find most recent paren in beg
n := len(beg)
last := n - 1
var i int
var p int = -1
outer:
for i = last; i >= 0; i-- {
Q("\nbeg[i=%v] is '%v'\n", i, string(beg[i]))
switch beg[i] {
case ' ':
break outer
case '(':
p = i
Q("\n found paren at p = %v\n", i)
break outer
}
}
Q("p=%d\n", p)
prefix := string(beg)
extendme := ""
if p == 0 {
prefix = ""
extendme = string(beg)
} else if p > 0 {
prefix = string(beg[:p])
extendme = string(beg[p:])
}
Q("prefix = '%s'\nextendme = '%s'\n", prefix, extendme)
for _, n := range completion_keywords {
if strings.HasPrefix(n, strings.ToLower(extendme)) {
Q("n='%s' has prefix = '%s'\n", n, extendme)
c = append(c, n)
}
}
return prefix, c, end
}
func NewPrompter(prompt string) *Prompter {
origMode, err := liner.TerminalMode()
if err != nil {
panic(err)
}
p := &Prompter{
prompt: prompt,
prompter: liner.NewLiner(),
origMode: origMode,
}
rawMode, err := liner.TerminalMode()
if err != nil {
panic(err)
}
p.rawMode = rawMode
p.prompter.SetCtrlCAborts(false)
p.prompter.SetWordCompleter(liner.WordCompleter(MyWordCompleter))
return p
}
func (p *Prompter) Close() {
defer p.prompter.Close()
}
func (p *Prompter) Getline(prompt *string) (line string, err error) {
applyErr := p.rawMode.ApplyMode()
if applyErr != nil {
panic(applyErr)
}
defer func() {
applyErr := p.origMode.ApplyMode()
if applyErr != nil {
panic(applyErr)
}
}()
if prompt == nil {
line, err = p.prompter.Prompt(p.prompt)
} else {
line, err = p.prompter.Prompt(*prompt)
}
if err == nil {
p.prompter.AppendHistory(line)
return line, nil
}
return "", err
}

119
vendor/github.com/glycerine/zygomys/zygo/listutils.go generated vendored Normal file
View File

@@ -0,0 +1,119 @@
package zygo
import (
"errors"
"fmt"
)
var NotAList = errors.New("not a list")
func ListToArray(expr Sexp) ([]Sexp, error) {
if !IsList(expr) {
return nil, NotAList
}
arr := make([]Sexp, 0)
for expr != SexpNull {
list := expr.(*SexpPair)
arr = append(arr, list.Head)
expr = list.Tail
}
return arr, nil
}
func MakeList(expressions []Sexp) Sexp {
if len(expressions) == 0 {
return SexpNull
}
return Cons(expressions[0], MakeList(expressions[1:]))
}
func MapList(env *Zlisp, fun *SexpFunction, expr Sexp) (Sexp, error) {
if expr == SexpNull {
return SexpNull, nil
}
var list = &SexpPair{}
switch e := expr.(type) {
case *SexpPair:
list.Head = e.Head
list.Tail = e.Tail
default:
return SexpNull, NotAList
}
var err error
list.Head, err = env.Apply(fun, []Sexp{list.Head})
if err != nil {
return SexpNull, err
}
list.Tail, err = MapList(env, fun, list.Tail)
if err != nil {
return SexpNull, err
}
return list, nil
}
// O(n^2) for n total nodes in all lists. So this is
// not super efficient. We have to
// find the tail of each list in turn by
// linear search. Avoid lists if possible in favor
// of arrays.
func ConcatLists(a *SexpPair, bs []Sexp) (Sexp, error) {
result := a
for _, b := range bs {
res, err := ConcatTwoLists(result, b)
if err != nil {
return SexpNull, err
}
x, ok := res.(*SexpPair)
if !ok {
return SexpNull, NotAList
}
result = x
}
return result, nil
}
func ConcatTwoLists(a *SexpPair, b Sexp) (Sexp, error) {
if !IsList(b) {
return SexpNull, NotAList
}
if a.Tail == SexpNull {
return Cons(a.Head, b), nil
}
switch t := a.Tail.(type) {
case *SexpPair:
newtail, err := ConcatTwoLists(t, b)
if err != nil {
return SexpNull, err
}
return Cons(a.Head, newtail), nil
}
return SexpNull, NotAList
}
func ListLen(expr Sexp) (int, error) {
sz := 0
var list *SexpPair
ok := false
for expr != SexpNull {
list, ok = expr.(*SexpPair)
if !ok {
return 0, fmt.Errorf("ListLen() called on non-list")
}
sz++
expr = list.Tail
}
return sz, nil
}

1
vendor/github.com/glycerine/zygomys/zygo/makego.go generated vendored Normal file
View File

@@ -0,0 +1 @@
package zygo

43
vendor/github.com/glycerine/zygomys/zygo/msgpackmap.go generated vendored Normal file
View File

@@ -0,0 +1,43 @@
package zygo
import (
"errors"
"fmt"
)
func (env *Zlisp) ImportMsgpackMap() {
env.AddMacro("msgpack-map", MsgpackMapMacro)
env.AddFunction("declare-msgpack-map", DeclareMsgpackMapFunction)
}
// declare a new record type
func MsgpackMapMacro(env *Zlisp, name string,
args []Sexp) (Sexp, error) {
if len(args) < 1 {
return SexpNull, fmt.Errorf("struct-name is missing. use: " +
"(msgpack-map struct-name)\n")
}
return MakeList([]Sexp{
env.MakeSymbol("def"),
args[0],
MakeList([]Sexp{
env.MakeSymbol("quote"),
env.MakeSymbol("msgmap"),
&SexpStr{S: args[0].(*SexpSymbol).name},
}),
}), nil
}
func DeclareMsgpackMapFunction(env *Zlisp, name string, args []Sexp) (Sexp, error) {
if len(args) != 1 {
return SexpNull, WrongNargs
}
switch t := args[0].(type) {
case *SexpStr:
return t, nil
}
return SexpNull, errors.New("argument must be string: the name of the new msgpack-map constructor function to create")
}

View File

@@ -0,0 +1,246 @@
package zygo
import (
"errors"
"math"
)
type IntegerOp int
const (
ShiftLeft IntegerOp = iota
ShiftRightArith
ShiftRightLog
Modulo
BitAnd
BitOr
BitXor
)
var WrongType error = errors.New("operands have invalid type")
func IntegerDo(op IntegerOp, a, b Sexp) (Sexp, error) {
var ia *SexpInt
var ib *SexpInt
switch i := a.(type) {
case *SexpInt:
ia = i
case *SexpUint64:
return UintegerDo(op, i, b)
case *SexpChar:
ia = &SexpInt{Val: int64(i.Val)}
default:
return SexpNull, WrongType
}
switch i := b.(type) {
case *SexpInt:
ib = i
case *SexpUint64:
return UintegerDo(op, &SexpUint64{Val: uint64(ia.Val)}, b)
case *SexpChar:
ib = &SexpInt{Val: int64(i.Val)}
default:
return SexpNull, WrongType
}
switch op {
case ShiftLeft:
return &SexpInt{Val: ia.Val << uint(ib.Val)}, nil
case ShiftRightArith:
return &SexpInt{Val: ia.Val >> uint(ib.Val)}, nil
case ShiftRightLog:
return &SexpInt{Val: int64(uint(ia.Val) >> uint(ib.Val))}, nil
case Modulo:
return &SexpInt{Val: ia.Val % ib.Val}, nil
case BitAnd:
return &SexpInt{Val: ia.Val & ib.Val}, nil
case BitOr:
return &SexpInt{Val: ia.Val | ib.Val}, nil
case BitXor:
return &SexpInt{Val: ia.Val ^ ib.Val}, nil
}
return SexpNull, errors.New("unrecognized shift operation")
}
func UintegerDo(op IntegerOp, ia *SexpUint64, b Sexp) (Sexp, error) {
var ib *SexpUint64
switch i := b.(type) {
case *SexpUint64:
ib = i
case *SexpInt:
ib = &SexpUint64{Val: uint64(i.Val)}
case *SexpChar:
ib = &SexpUint64{Val: uint64(i.Val)}
default:
return SexpNull, WrongType
}
switch op {
case ShiftLeft:
return &SexpUint64{Val: ia.Val << ib.Val}, nil
case ShiftRightArith:
return &SexpUint64{Val: ia.Val >> ib.Val}, nil
case ShiftRightLog:
return &SexpUint64{Val: ia.Val >> ib.Val}, nil
case Modulo:
return &SexpUint64{Val: ia.Val % ib.Val}, nil
case BitAnd:
return &SexpUint64{Val: ia.Val & ib.Val}, nil
case BitOr:
return &SexpUint64{Val: ia.Val | ib.Val}, nil
case BitXor:
return &SexpUint64{Val: ia.Val ^ ib.Val}, nil
}
return SexpNull, errors.New("unrecognized shift operation")
}
type NumericOp int
const (
Add NumericOp = iota
Sub
Mult
Div
Pow
)
func NumericFloatDo(op NumericOp, a, b *SexpFloat) Sexp {
switch op {
case Add:
return &SexpFloat{Val: a.Val + b.Val}
case Sub:
return &SexpFloat{Val: a.Val - b.Val}
case Mult:
return &SexpFloat{Val: a.Val * b.Val}
case Div:
return &SexpFloat{Val: a.Val / b.Val}
case Pow:
return &SexpFloat{Val: math.Pow(float64(a.Val), float64(b.Val))}
}
return SexpNull
}
func NumericIntDo(op NumericOp, a, b *SexpInt) Sexp {
switch op {
case Add:
return &SexpInt{Val: a.Val + b.Val}
case Sub:
return &SexpInt{Val: a.Val - b.Val}
case Mult:
return &SexpInt{Val: a.Val * b.Val}
case Div:
if a.Val%b.Val == 0 {
return &SexpInt{Val: a.Val / b.Val}
} else {
return &SexpFloat{Val: float64(a.Val) / float64(b.Val)}
}
case Pow:
return &SexpInt{Val: int64(math.Pow(float64(a.Val), float64(b.Val)))}
}
return SexpNull
}
func NumericUint64Do(op NumericOp, a, b *SexpUint64) Sexp {
switch op {
case Add:
return &SexpUint64{Val: a.Val + b.Val}
case Sub:
return &SexpUint64{Val: a.Val - b.Val}
case Mult:
return &SexpUint64{Val: a.Val * b.Val}
case Div:
if a.Val%b.Val == 0 {
return &SexpUint64{Val: a.Val / b.Val}
} else {
return &SexpFloat{Val: float64(a.Val) / float64(b.Val)}
}
case Pow:
return &SexpUint64{Val: uint64(math.Pow(float64(a.Val), float64(b.Val)))}
}
return SexpNull
}
func NumericMatchFloat(op NumericOp, a *SexpFloat, b Sexp) (Sexp, error) {
var fb *SexpFloat
switch tb := b.(type) {
case *SexpFloat:
fb = tb
case *SexpInt:
fb = &SexpFloat{Val: float64(tb.Val)}
case *SexpUint64:
fb = &SexpFloat{Val: float64(tb.Val)}
case *SexpChar:
fb = &SexpFloat{Val: float64(tb.Val)}
default:
return SexpNull, WrongType
}
return NumericFloatDo(op, a, fb), nil
}
func NumericMatchInt(op NumericOp, a *SexpInt, b Sexp) (Sexp, error) {
switch tb := b.(type) {
case *SexpFloat:
return NumericFloatDo(op, &SexpFloat{Val: float64(a.Val)}, tb), nil
case *SexpInt:
return NumericIntDo(op, a, tb), nil
case *SexpUint64:
return NumericUint64Do(op, &SexpUint64{Val: uint64(a.Val)}, tb), nil
case *SexpChar:
return NumericIntDo(op, a, &SexpInt{Val: int64(tb.Val)}), nil
}
return SexpNull, WrongType
}
func NumericMatchUint64(op NumericOp, a *SexpUint64, b Sexp) (Sexp, error) {
switch tb := b.(type) {
case *SexpFloat:
return NumericFloatDo(op, &SexpFloat{Val: float64(a.Val)}, tb), nil
case *SexpInt:
return NumericUint64Do(op, a, &SexpUint64{Val: uint64(tb.Val)}), nil
case *SexpUint64:
return NumericUint64Do(op, a, tb), nil
case *SexpChar:
return NumericUint64Do(op, a, &SexpUint64{Val: uint64(tb.Val)}), nil
}
return SexpNull, WrongType
}
func NumericMatchChar(op NumericOp, a *SexpChar, b Sexp) (Sexp, error) {
var res Sexp
switch tb := b.(type) {
case *SexpFloat:
res = NumericFloatDo(op, &SexpFloat{Val: float64(a.Val)}, tb)
case *SexpInt:
res = NumericIntDo(op, &SexpInt{Val: int64(a.Val)}, tb)
case *SexpUint64:
return NumericUint64Do(op, &SexpUint64{Val: uint64(a.Val)}, tb), nil
case *SexpChar:
res = NumericIntDo(op, &SexpInt{Val: int64(a.Val)}, &SexpInt{Val: int64(tb.Val)})
default:
return SexpNull, WrongType
}
switch tres := res.(type) {
case *SexpFloat:
return tres, nil
case *SexpInt:
return &SexpChar{Val: rune(tres.Val)}, nil
}
return SexpNull, errors.New("unexpected result")
}
func NumericDo(op NumericOp, a, b Sexp) (Sexp, error) {
switch ta := a.(type) {
case *SexpFloat:
return NumericMatchFloat(op, ta, b)
case *SexpInt:
return NumericMatchInt(op, ta, b)
case *SexpUint64:
return NumericMatchUint64(op, ta, b)
case *SexpChar:
return NumericMatchChar(op, ta, b)
}
return SexpNull, WrongType
}

7
vendor/github.com/glycerine/zygomys/zygo/panicon.go generated vendored Normal file
View File

@@ -0,0 +1,7 @@
package zygo
func panicOn(err error) {
if err != nil {
panic(err)
}
}

650
vendor/github.com/glycerine/zygomys/zygo/parser.go generated vendored Normal file
View File

@@ -0,0 +1,650 @@
package zygo
import (
"errors"
"fmt"
"io"
"math"
"strconv"
"strings"
"sync"
)
var NaN float64
func init() {
NaN = math.NaN()
}
type Parser struct {
lexer *Lexer
env *Zlisp
Done chan bool
reqStop chan bool
AddInput chan io.RuneScanner
ReqReset chan io.RuneScanner
ParsedOutput chan []ParserReply
mut sync.Mutex
stopped bool
sendMe []ParserReply
FlagSendNeedInput bool
inBacktick bool
}
type ParserReply struct {
Expr []Sexp
Err error
}
func (env *Zlisp) NewParser() *Parser {
p := &Parser{
env: env,
Done: make(chan bool),
reqStop: make(chan bool),
ReqReset: make(chan io.RuneScanner),
AddInput: make(chan io.RuneScanner),
ParsedOutput: make(chan []ParserReply),
sendMe: make([]ParserReply, 0, 1),
}
p.lexer = NewLexer(p)
return p
}
func (p *Parser) Stop() error {
p.mut.Lock()
defer p.mut.Unlock()
if p.stopped {
return nil
}
p.stopped = true
close(p.reqStop)
<-p.Done
return nil
}
// Starts launches a background goroutine that runs an
// infinite parsing loop.
func (p *Parser) Start() {
go func() {
defer close(p.Done)
expressions := make([]Sexp, 0, SliceDefaultCap)
// maybe we already have input, be optimistic!
// no need to call p.GetMoreInput() before staring
// our loop.
for {
expr, err := p.ParseExpression(0)
if err != nil || expr == SexpEnd {
if err == ParserHaltRequested {
return
}
err = p.GetMoreInput(expressions, err)
if err == ParserHaltRequested {
return
}
// GetMoreInput will have delivered what we gave them. Reset since we
// don't own that memory any more.
expressions = make([]Sexp, 0, SliceDefaultCap)
} else {
// INVAR: err == nil && expr is not SexpEnd
expressions = append(expressions, expr)
}
}
}()
}
var ParserHaltRequested = fmt.Errorf("parser halt requested")
var ResetRequested = fmt.Errorf("parser reset requested")
var ErrMoreInputNeeded = fmt.Errorf("parser needs more input")
// This function should *return* when it has more input
// for the parser/lexer, which will call it when they get wedged.
//
// Listeners on p.ParsedOutput should know the Convention: sending
// a length 0 []ParserReply on p.ParsedOutput channel means: we need more
// input! They should send some in on p.AddInput channel; or request
// a reset and simultaneously give us new input with p.ReqReset channel.
func (p *Parser) GetMoreInput(deliverThese []Sexp, errorToReport error) error {
if len(deliverThese) == 0 && errorToReport == nil {
p.FlagSendNeedInput = true
} else {
p.sendMe = append(p.sendMe,
ParserReply{
Expr: deliverThese,
Err: errorToReport,
})
}
for {
select {
case <-p.reqStop:
return ParserHaltRequested
case input := <-p.AddInput:
p.lexer.AddNextStream(input)
p.FlagSendNeedInput = false
return nil
case input := <-p.ReqReset:
p.lexer.Reset()
p.lexer.AddNextStream(input)
p.FlagSendNeedInput = false
return ResetRequested
case p.HaveStuffToSend() <- p.sendMe:
p.sendMe = make([]ParserReply, 0, 1)
p.FlagSendNeedInput = false
}
}
}
func (p *Parser) HaveStuffToSend() chan []ParserReply {
if len(p.sendMe) > 0 || p.FlagSendNeedInput {
return p.ParsedOutput
}
return nil
}
func (p *Parser) Reset() {
select {
case p.ReqReset <- nil:
case <-p.reqStop:
}
}
func (p *Parser) NewInput(s io.RuneScanner) {
select {
case p.AddInput <- s:
case <-p.reqStop:
}
}
func (p *Parser) ResetAddNewInput(s io.RuneScanner) {
select {
case p.ReqReset <- s:
case <-p.reqStop:
}
}
var UnexpectedEnd error = errors.New("Unexpected end of input")
const SliceDefaultCap = 10
func (parser *Parser) ParseList(depth int) (sx Sexp, err error) {
lexer := parser.lexer
var tok Token
tokFilled:
for {
tok, err = lexer.PeekNextToken()
//Q("\n ParseList(depth=%d) got lexer.PeekNextToken() -> tok='%v' err='%v'\n", depth, tok, err)
if err != nil {
return SexpNull, err
}
if tok.typ != TokenEnd {
break tokFilled
}
// instead of returning UnexpectedEnd, we:
err = parser.GetMoreInput(nil, ErrMoreInputNeeded)
//Q("\n ParseList(depth=%d) got back from parser.GetMoreInput(): '%v'\n", depth, err)
switch err {
case ParserHaltRequested:
return SexpNull, err
case ResetRequested:
return SexpEnd, err
}
// have to still fill tok, so
// loop to the top to PeekNextToken
}
if tok.typ == TokenRParen {
_, _ = lexer.GetNextToken()
return SexpNull, nil
}
var start = &SexpPair{}
expr, err := parser.ParseExpression(depth + 1)
if err != nil {
return SexpNull, err
}
start.Head = expr
tok, err = lexer.PeekNextToken()
if err != nil {
return SexpNull, err
}
// backslash '\' replaces dot '.' in zygo
if tok.typ == TokenBackslash {
// eat up the backslash
_, _ = lexer.GetNextToken()
expr, err = parser.ParseExpression(depth + 1)
if err != nil {
return SexpNull, err
}
// eat up the end paren
tok, err = lexer.GetNextToken()
if err != nil {
return SexpNull, err
}
// make sure it was actually an end paren
if tok.typ != TokenRParen {
return SexpNull, errors.New("extra value in dotted pair")
}
start.Tail = expr
return start, nil
}
expr, err = parser.ParseList(depth + 1)
if err != nil {
return start, err
}
start.Tail = expr
return start, nil
}
func (parser *Parser) ParseArray(depth int) (Sexp, error) {
lexer := parser.lexer
arr := make([]Sexp, 0, SliceDefaultCap)
var tok Token
var err error
for {
getTok:
for {
tok, err = lexer.PeekNextToken()
if err != nil {
return SexpEnd, err
}
if tok.typ == TokenComma {
// pop off the ,
_, _ = lexer.GetNextToken()
continue getTok
}
if tok.typ != TokenEnd {
break getTok
} else {
//instead of return SexpEnd, UnexpectedEnd
// we ask for more, and then loop
err = parser.GetMoreInput(nil, ErrMoreInputNeeded)
switch err {
case ParserHaltRequested:
return SexpNull, err
case ResetRequested:
return SexpEnd, err
}
}
}
if tok.typ == TokenRSquare {
// pop off the ]
_, _ = lexer.GetNextToken()
break
}
expr, err := parser.ParseExpression(depth + 1)
if err != nil {
return SexpNull, err
}
arr = append(arr, expr)
}
return &SexpArray{Val: arr, Env: parser.env}, nil
}
func (parser *Parser) ParseExpression(depth int) (res Sexp, err error) {
defer func() {
if res != nil {
//Q("returning from ParseExpression at depth=%v with res='%s'\n", depth, res.SexpString(nil))
} else {
//Q("returning from ParseExpression at depth=%v, res = nil", depth)
}
}()
lexer := parser.lexer
env := parser.env
//getAnother:
tok, err := lexer.GetNextToken()
if err != nil {
return SexpEnd, err
}
switch tok.typ {
case TokenLParen:
exp, err := parser.ParseList(depth + 1)
return exp, err
case TokenLSquare:
exp, err := parser.ParseArray(depth + 1)
return exp, err
case TokenLCurly:
exp, err := parser.ParseInfix(depth + 1)
return exp, err
case TokenQuote:
expr, err := parser.ParseExpression(depth + 1)
if err != nil {
return SexpNull, err
}
return MakeList([]Sexp{env.MakeSymbol("quote"), expr}), nil
case TokenCaret:
// '^' is now our syntax-quote symbol, not TokenBacktick, to allow go-style `string literals`.
expr, err := parser.ParseExpression(depth + 1)
if err != nil {
return SexpNull, err
}
return MakeList([]Sexp{env.MakeSymbol("syntaxQuote"), expr}), nil
case TokenTilde:
expr, err := parser.ParseExpression(depth + 1)
if err != nil {
return SexpNull, err
}
return MakeList([]Sexp{env.MakeSymbol("unquote"), expr}), nil
case TokenTildeAt:
expr, err := parser.ParseExpression(depth + 1)
if err != nil {
return SexpNull, err
}
return MakeList([]Sexp{env.MakeSymbol("unquote-splicing"), expr}), nil
case TokenFreshAssign:
return env.MakeSymbol(tok.str), nil
case TokenColonOperator:
return env.MakeSymbol(tok.str), nil
case TokenDollar:
return env.MakeSymbol(tok.str), nil
case TokenBool:
return &SexpBool{Val: tok.str == "true"}, nil
case TokenUint64:
// truncate off the "ULL" suffix
inp := tok.str[:len(tok.str)-3]
// handle hex 0x and octacl 0o
n := len(inp)
base := 10
if n > 2 {
switch inp[:2] {
case "0o":
base = 8
inp = inp[2:]
case "0x":
base = 16
inp = inp[2:]
}
}
u, err := strconv.ParseUint(inp, base, 64)
//fmt.Printf("debug: parsed inp='%s' into u=%v\n", inp, u)
if err != nil {
return SexpNull, err
}
return &SexpUint64{Val: u}, nil
case TokenDecimal:
i, err := strconv.ParseInt(tok.str, 10, SexpIntSize)
if err != nil {
return SexpNull, err
}
return &SexpInt{Val: i}, nil
case TokenHex:
i, err := strconv.ParseInt(tok.str, 16, SexpIntSize)
if err != nil {
return SexpNull, err
}
return &SexpInt{Val: i}, nil
case TokenOct:
i, err := strconv.ParseInt(tok.str, 8, SexpIntSize)
if err != nil {
return SexpNull, err
}
return &SexpInt{Val: i}, nil
case TokenBinary:
i, err := strconv.ParseInt(tok.str, 2, SexpIntSize)
if err != nil {
return SexpNull, err
}
return &SexpInt{Val: i}, nil
case TokenChar:
return &SexpChar{Val: rune(tok.str[0])}, nil
case TokenString:
return &SexpStr{S: tok.str}, nil
case TokenBeginBacktickString:
parser.inBacktick = true
return parser.ParseBacktickString(&tok)
case TokenBacktickString:
parser.inBacktick = false
return &SexpStr{S: tok.str, backtick: true}, nil
case TokenFloat:
var f float64
if tok.str == "NaN" {
f = NaN
} else {
f, err = strconv.ParseFloat(tok.str, SexpFloatSize)
if err != nil {
return SexpNull, err
}
}
r := &SexpFloat{Val: f}
if strings.Contains(tok.str, "e") || strings.Contains(tok.str, "E") {
r.Scientific = true
}
return r, nil
case TokenEnd:
return SexpEnd, nil
case TokenSymbol:
return env.MakeSymbol(tok.str), nil
case TokenSymbolColon:
sym := env.MakeSymbol(tok.str)
sym.colonTail = true
return sym, nil
case TokenDot:
sym := env.MakeSymbol(tok.str)
sym.isDot = true
return sym, nil
case TokenDotSymbol:
sym := env.MakeSymbol(tok.str)
sym.isDot = true
return sym, nil
case TokenComment:
//Q("parser making SexpComment from '%s'", tok.str)
return &SexpComment{Comment: tok.str}, nil
// parser skips comments
//goto getAnother
case TokenBeginBlockComment:
// parser skips comments
return parser.ParseBlockComment(&tok)
//parser.ParseBlockComment(&tok)
//goto getAnother
case TokenComma:
return &SexpComma{}, nil
case TokenSemicolon:
return &SexpSemicolon{}, nil
}
return SexpNull, fmt.Errorf("Invalid syntax, don't know what to do with %v '%v'", tok.typ, tok)
}
// ParseTokens is the main service the Parser provides.
// Currently returns first error encountered, ignoring
// any expressions after that.
func (p *Parser) ParseTokens() ([]Sexp, error) {
select {
case out := <-p.ParsedOutput:
Q("ParseTokens got p.ParsedOutput out: '%#v'", out)
r := make([]Sexp, 0)
for _, k := range out {
r = append(r, k.Expr...)
Q("\n ParseTokens k.Expr = '%v'\n\n", (&SexpArray{Val: k.Expr, Env: p.env}).SexpString(nil))
if k.Err != nil {
return r, k.Err
}
}
return r, nil
case <-p.reqStop:
return nil, ErrShuttingDown
}
}
var ErrShuttingDown error = fmt.Errorf("lexer shutting down")
func (parser *Parser) ParseBlockComment(start *Token) (sx Sexp, err error) {
defer func() {
if sx != nil {
//Q("returning from ParseBlockComment with sx ='%v', err='%v'",
// sx.SexpString(), err)
}
}()
lexer := parser.lexer
var tok Token
var block = &SexpComment{Block: true, Comment: start.str}
for {
tokFilled:
for {
tok, err = lexer.PeekNextToken()
if err != nil {
return SexpNull, err
}
if tok.typ != TokenEnd {
break tokFilled
}
err = parser.GetMoreInput(nil, ErrMoreInputNeeded)
switch err {
case ParserHaltRequested:
return SexpNull, err
case ResetRequested:
return SexpEnd, err
}
// have to still fill tok, so
// loop to the top to PeekNextToken
}
// consume it
//cons, err := lexer.GetNextToken()
_, err := lexer.GetNextToken()
if err != nil {
return nil, err
}
//Q("parse block comment is consuming '%v'", cons)
switch tok.typ {
case TokenEndBlockComment:
block.Comment += tok.str
return block, nil
case TokenComment:
block.Comment += tok.str
default:
panic("internal error: inside a block comment, we should only see TokenComment and TokenEndBlockComment tokens")
}
}
//return block, nil
}
func (parser *Parser) ParseBacktickString(start *Token) (sx Sexp, err error) {
defer func() {
if sx != nil {
//Q("returning from ParseBlockComment with sx ='%v', err='%v'",
// sx.SexpString(), err)
}
}()
lexer := parser.lexer
var tok Token
for {
tokFilled:
for {
tok, err = lexer.PeekNextToken()
if err != nil {
return SexpNull, err
}
if tok.typ != TokenEnd {
break tokFilled
}
err = parser.GetMoreInput(nil, ErrMoreInputNeeded)
switch err {
case ParserHaltRequested:
return SexpNull, err
case ResetRequested:
return SexpEnd, err
}
// have to still fill tok, so
// loop to the top to PeekNextToken
}
// consume it
//cons, err := lexer.GetNextToken()
_, err := lexer.GetNextToken()
if err != nil {
return nil, err
}
//P("parse backtick string is consuming '%v'", cons)
switch tok.typ {
case TokenBacktickString:
return &SexpStr{S: tok.str, backtick: true}, nil
default:
panic("internal error: inside a backtick string, we should only see TokenBacktickString token")
}
}
}
func (parser *Parser) ParseInfix(depth int) (Sexp, error) {
lexer := parser.lexer
arr := make([]Sexp, 0, SliceDefaultCap)
var err error
var tok Token
for {
getTok:
for {
tok, err = lexer.PeekNextToken()
if err != nil {
return SexpEnd, err
}
if tok.typ != TokenEnd {
break getTok
} else {
//instead of return SexpEnd, UnexpectedEnd
// we ask for more, and then loop
err = parser.GetMoreInput(nil, ErrMoreInputNeeded)
switch err {
case ParserHaltRequested:
return SexpNull, err
case ResetRequested:
return SexpEnd, err
}
}
}
if tok.typ == TokenRCurly {
// pop off the }
_, _ = lexer.GetNextToken()
break
}
Q("debug: ParseInfix(depth=%v) calling ParseExpression", depth)
expr, err := parser.ParseExpression(depth + 1)
if err != nil {
return SexpNull, err
}
Q("debug2: ParseInfix(depth=%v) appending expr = '%v'", depth, expr.SexpString(nil))
arr = append(arr, expr)
}
var list SexpPair
list.Head = parser.env.MakeSymbol("infix")
list.Tail = SexpNull
if len(arr) > 0 {
list.Tail = Cons(&SexpArray{Val: arr, Infix: true, Env: parser.env}, SexpNull)
}
return &list, nil
//return &SexpArray{Val: arr, Infix: true, Env: env}, nil
}

670
vendor/github.com/glycerine/zygomys/zygo/pratt.go generated vendored Normal file
View File

@@ -0,0 +1,670 @@
package zygo
import (
"fmt"
"io"
)
// Pratt parsing. see http://javascript.crockford.com/tdop/tdop.html
// Also nice writeup: http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/
// precedence levels (smaller == lower priority,
// so smaller => goes towards top of tree)
//
// Borrowing from the tdop.html precedence list mostly:
//
// 0 non-binding operators like ;
// 10 assignment operators like = :=
// 20 ?
// 30 or and
// 40 relational operators like ==
// 50 + -
// 60 * /
// 65 **
// 70 unary operators like 'not'
// 80 . [ (
//
// InfixOp lets us attach led (MunchLeft) and nud (MunchRight)
// Pratt parsing methods, along with a binding power, to a symbol.
type InfixOp struct {
Sym *SexpSymbol
Bp int // binding power, aka precedence level.
MunchRight RightMuncher // aka nud
MunchLeft LeftMuncher // aka led
MunchStmt StmtMuncher // aka std. Used only at the beginning of a statement.
IsAssign bool
}
// Infix creates a new infix operator
func (env *Zlisp) Infix(op string, bp int) *InfixOp {
oper := env.MakeSymbol(op)
iop := &InfixOp{
Sym: oper,
Bp: bp,
MunchLeft: func(env *Zlisp, pr *Pratt, left Sexp) (Sexp, error) {
right, err := pr.Expression(env, bp)
if err != nil {
return SexpNull, err
}
list := MakeList([]Sexp{
oper, left, right,
})
Q("in Infix(), MunchLeft() call, pr.NextToken = %v. list returned = '%v'",
pr.NextToken.SexpString(nil), list.SexpString(nil))
return list, nil
},
}
env.infixOps[op] = iop
return iop
}
func (env *Zlisp) InfixF(op string, bp int, f func(env *Zlisp, op string, bp int) *InfixOp) *InfixOp {
return f(env, op, bp)
}
// Infix creates a new (right-associative) short-circuiting
// infix operator, used for `and` and `or` in infix processing.
func (env *Zlisp) Infixr(op string, bp int) *InfixOp {
oper := env.MakeSymbol(op)
iop := &InfixOp{
Sym: oper,
Bp: bp,
MunchLeft: func(env *Zlisp, pr *Pratt, left Sexp) (Sexp, error) {
right, err := pr.Expression(env, bp-1)
if err != nil {
return SexpNull, err
}
list := MakeList([]Sexp{
oper, left, right,
})
return list, nil
},
}
env.infixOps[op] = iop
return iop
}
// Prefix creates a new prefix operator, like `not`, for
// infix processing.
func (env *Zlisp) Prefix(op string, bp int) *InfixOp {
oper := env.MakeSymbol(op)
iop := &InfixOp{
Sym: oper,
Bp: bp,
MunchRight: func(env *Zlisp, pr *Pratt) (Sexp, error) {
right, err := pr.Expression(env, bp)
if err != nil {
return SexpNull, err
}
list := MakeList([]Sexp{
oper, right,
})
return list, nil
},
}
env.infixOps[op] = iop
return iop
}
// Assignment creates a new assignment operator for infix
// processing.
func (env *Zlisp) Assignment(op string, bp int) *InfixOp {
oper := env.MakeSymbol(op)
operSet := env.MakeSymbol("set")
iop := &InfixOp{
Sym: oper,
Bp: bp,
MunchLeft: func(env *Zlisp, pr *Pratt, left Sexp) (Sexp, error) {
// TODO: check that left is okay as an LVALUE.
right, err := pr.Expression(env, bp-1)
if err != nil {
return SexpNull, err
}
if op == "=" || op == ":=" {
oper = operSet
}
list := MakeList([]Sexp{
oper, left, right,
})
Q("assignment returning list: '%v'", list.SexpString(nil))
return list, nil
},
IsAssign: true,
}
env.infixOps[op] = iop
return iop
}
// PostfixAssign creates a new postfix assignment operator for infix
// processing.
func (env *Zlisp) PostfixAssign(op string, bp int) *InfixOp {
oper := env.MakeSymbol(op)
iop := &InfixOp{
Sym: oper,
Bp: bp,
MunchLeft: func(env *Zlisp, pr *Pratt, left Sexp) (Sexp, error) {
// TODO: check that left is okay as an LVALUE
list := MakeList([]Sexp{
oper, left,
})
Q("postfix assignment returning list: '%v'", list.SexpString(nil))
return list, nil
},
}
env.infixOps[op] = iop
return iop
}
func arrayOpMunchLeft(env *Zlisp, pr *Pratt, left Sexp) (Sexp, error) {
oper := env.MakeSymbol("arrayidx")
Q("pr.NextToken = '%v', left = %#v", pr.NextToken.SexpString(nil), left)
if len(pr.CnodeStack) > 0 {
Q("pr.CnodeStack[0] = '%v'", pr.CnodeStack[0])
}
right := pr.NextToken
Q("right = %#v", right)
list := MakeList([]Sexp{
oper, left, pr.CnodeStack[0],
})
return list, nil
}
func dotOpMunchLeft(env *Zlisp, pr *Pratt, left Sexp) (Sexp, error) {
//Q("dotOp MunchLeft, left = '%v'. NextToken='%v'. pr.CnodeStack[0]='%v'", left.SexpString(nil), pr.NextToken.SexpString(nil), pr.CnodeStack[0].SexpString(nil))
list := MakeList([]Sexp{
env.MakeSymbol("hashidx"), left, pr.CnodeStack[0],
})
return list, nil
}
func starOpMunchRight(env *Zlisp, pr *Pratt) (Sexp, error) {
right, err := pr.Expression(env, 70)
if err != nil {
return SexpNull, err
}
list := MakeList([]Sexp{
env.MakeSymbol("*"), right,
})
return list, nil
}
var arrayOp *InfixOp
// InitInfixOps establishes the env.infixOps definitions
// required for infix parsing using the Pratt parser.
func (env *Zlisp) InitInfixOps() {
env.Infix("+", 50)
env.Infix("-", 50)
star := env.Infix("*", 60)
star.MunchRight = starOpMunchRight
env.Infix("/", 60)
env.Infix("mod", 60)
env.Infixr("**", 65)
env.Infixr("and", 30)
env.Infixr("or", 30)
env.Prefix("not", 70)
env.Assignment("=", 10)
env.Assignment(":=", 10)
env.Assignment("+=", 10)
env.Assignment("-=", 10)
env.PostfixAssign("++", 10)
env.PostfixAssign("--", 10)
env.Infix("==", 40)
env.Infix("!=", 40)
env.Infix(">", 40)
env.Infix(">=", 40)
env.Infix("<", 40)
env.Infix("<=", 40)
// set the global arrayOp
arrayOp = &InfixOp{
Bp: 80,
MunchLeft: arrayOpMunchLeft,
}
dotOp := env.Infix(".", 80)
dotOp.MunchLeft = dotOpMunchLeft
ifOp := env.Prefix("if", 5)
//Q("ifOp = %#v", ifOp.SexpString(nil))
ifOp.MunchRight = func(env *Zlisp, pr *Pratt) (Sexp, error) {
Q("ifOp.MunchRight(): NextToken='%v'. pr.CnodeStack[0]='%v'", pr.NextToken.SexpString(nil), pr.CnodeStack[0].SexpString(nil))
right, err := pr.Expression(env, 5)
Q("ifOp.MunchRight: back from Expression-1st-call, err = %#v, right = '%v'", err, right.SexpString(nil))
if err != nil {
return SexpNull, err
}
Q("in ifOpMunchRight, got from p.Expression(env, 0) the right = '%v', err = %#v, pr.CnodeStack[0] = %#v, ifOp.Sym = '%v'", right.SexpString(nil), err, pr.CnodeStack[0], ifOp.Sym.SexpString(nil))
thenExpr, err := pr.Expression(env, 0)
Q("ifOp.MunchRight: back from Expression-2nd-call, err = %#v, thenExpr = '%v'", err, thenExpr.SexpString(nil))
if err != nil {
return SexpNull, err
}
Q("ifOp.MunchRight(), after Expression-2nd-call: . NextToken='%v'. pr.CnodeStack[0]='%v'", pr.NextToken.SexpString(nil), pr.CnodeStack[0].SexpString(nil))
var elseExpr Sexp = SexpNull
switch sym := pr.NextToken.(type) {
case *SexpSymbol:
if sym.name == "else" {
Q("detected else, advancing past it")
pr.Advance()
elseExpr, err = pr.Expression(env, 0)
Q("ifOp.MunchRight: back from Expression-3rd-call, err = %#v, elseExpr = '%v'", err, elseExpr.SexpString(nil))
if err != nil {
return SexpNull, err
}
}
}
list := MakeList([]Sexp{
env.MakeSymbol("cond"), right, thenExpr, elseExpr,
})
return list, nil
}
env.Infix("comma", 15)
}
type RightMuncher func(env *Zlisp, pr *Pratt) (Sexp, error)
type LeftMuncher func(env *Zlisp, pr *Pratt, left Sexp) (Sexp, error)
type StmtMuncher func(env *Zlisp, pr *Pratt) (Sexp, error)
func InfixBuilder(env *Zlisp, name string, args []Sexp) (Sexp, error) {
Q("InfixBuilder top, name='%s', len(args)==%v ", name, len(args))
if name != "infixExpand" && len(args) != 1 {
// let {} mean nil
return SexpNull, nil
}
var arr *SexpArray
Q("InfixBuilder after top, args[0] has type ='%T' ", args[0])
switch v := args[0].(type) {
case *SexpArray:
arr = v
case *SexpPair:
if name == "infixExpand" {
_, isSent := v.Tail.(*SexpSentinel)
if isSent {
// expansion of {} is nil
return SexpNull, nil
}
pair, isPair := v.Tail.(*SexpPair)
if !isPair {
return SexpNull, fmt.Errorf("infixExpand expects (infix []) as its argument; instead we saw '%T' [err 3]", v.Tail)
}
switch ar2 := pair.Head.(type) {
case *SexpArray:
Q("infixExpand, doing recursive call to InfixBuilder, ar2 = '%v'", ar2.SexpString(nil))
return InfixBuilder(env, name, []Sexp{ar2})
default:
return SexpNull, fmt.Errorf("infixExpand expects (infix []) as its argument; instead we saw '%T'", v.Tail)
}
}
return SexpNull, fmt.Errorf("InfixBuilder must receive an SexpArray")
default:
return SexpNull, fmt.Errorf("InfixBuilder must receive an SexpArray")
}
Q("InfixBuilder, name='%s', arr = ", name)
for i := range arr.Val {
Q("arr[%v] = '%v', of type %T", i, arr.Val[i].SexpString(nil), arr.Val[i])
}
pr := NewPratt(arr.Val)
xs := []Sexp{}
if name == "infixExpand" {
xs = append(xs, env.MakeSymbol("quote"))
}
for {
x, err := pr.Expression(env, 0)
if err != nil {
return SexpNull, err
}
if x == nil {
Q("x was nil")
} else {
Q("x back is not nil and is of type %T/val = '%v', err = %v", x, x.SexpString(nil), err)
}
_, isSemi := x.(*SexpSemicolon)
if !isSemi {
xs = append(xs, x)
}
Q("end of infix builder loop, pr.NextToken = '%v'", pr.NextToken.SexpString(nil))
if pr.IsEOF() {
break
}
_, nextIsSemi := pr.NextToken.(*SexpSemicolon)
if nextIsSemi {
pr.Advance() // skip over the semicolon
}
}
Q("infix builder loop done, here are my expressions:")
for i, ele := range xs {
Q("xs[%v] = %v", i, ele.SexpString(nil))
}
if name == "infixExpand" {
ret := MakeList(xs)
Q("infixExpand: returning ret = '%v'", ret.SexpString(nil))
return ret, nil
}
ev, err := EvalFunction(env, "infixEval", xs)
if err != nil {
return SexpNull, err
}
return ev, nil
}
type Pratt struct {
NextToken Sexp
CnodeStack []Sexp
AccumTree Sexp
Pos int
Stream []Sexp
}
func NewPratt(stream []Sexp) *Pratt {
p := &Pratt{
NextToken: SexpNull,
AccumTree: SexpNull,
CnodeStack: make([]Sexp, 0),
Stream: stream,
}
if len(stream) > 0 {
p.NextToken = stream[0]
}
return p
}
// Expression():
//
// From Douglas Crockford's article on Pratt parsing:
// "Top Down Operator Precedence"
// http://javascript.crockford.com/tdop/tdop.html
//
// The heart of Pratt's technique is the expression
// function. It takes a right binding power that
// controls how aggressively it binds to tokens on its right.
// expression calls the nud method of the token.
//
// The nud is used to process literals, variables,
// and prefix operators.
//
// Then as long as the right binding
// power is less than the left binding power of the next
// token, the led method is invoked on the following
// token. The led is used to process infix and
// suffix operators. This process can be recursive
// because the nud and led
// methods can call expression.
//
// In pseudo Java script:
//
// var expression = function (rbp) {
// var left;
// var t = token;
// advance();
// left = t.nud();
// while (rbp < token.lbp) {
// t = token;
// advance();
// left = t.led(left);
// }
// return left;
// }
//
// jea: Below is a working expression() parsing routine. Reproduces the
// original Pratt and Crockford formulation.
//
// AccumTree holds the accumulated parse tree at any point in time.
// "The parse Tree Up to this point, by consuming the tokens
// to the left" would be a better-but-too-long name.
//
// and AccumTree is the stuff to the left of the
// current operator in the parse stream.
//
// data flows from NextToken -> cnode -> (possibly on the stack of t
// recursive MunchLeft calls) -> into the AccumTree tree.
//
// better names: _left -> AccumTree (to be returned)
// t -> cnode; as it is the current token's qtree
// node to be processed. Once we grab this
// we always advance() past it
// before processing it, so that
// NextToken contains the
// following token.
//
//
// meaning of rbp parameter: if you hit a token with
// a NextToken.Lbp < rbp, then don't bother calling MunchLeft,
// stop and return what you have.
//
// better explanation: rbp = a lower bound on descendant nodes
// precedence level, so we can
// guarantee the precedence-hill-climbing property (small precedence
// at the top) in the resulting parse tree.
//
func (p *Pratt) Expression(env *Zlisp, rbp int) (ret Sexp, err error) {
defer func() {
if ret == nil {
Q("Expression is returning Sexp ret = nil")
} else {
Q("Expression is returning Sexp ret = '%v'", ret.SexpString(nil))
}
}()
cnode := p.NextToken
if cnode != nil {
Q("top of Expression, rbp = %v, cnode = '%v'", rbp, cnode.SexpString(nil))
} else {
Q("top of Expression, rbp = %v, cnode is nil", rbp)
}
if p.IsEOF() {
Q("Expression sees IsEOF, returning cnode = %v", cnode.SexpString(nil))
return cnode, nil
}
p.CnodeStack = append([]Sexp{p.NextToken}, p.CnodeStack...)
//p.ShowCnodeStack()
p.Advance()
var curOp *InfixOp
switch x := cnode.(type) {
case *SexpSymbol:
op, found := env.infixOps[x.name]
if found {
Q("Expression lookup of op.Sym=%v/op='%#v' succeeded", op.Sym.SexpString(nil), op)
curOp = op
} else {
Q("Expression lookup of x.name == '%v' failed", x.name)
}
case *SexpArray:
Q("in pratt parsing, got array x = '%v'", x.SexpString(nil))
}
if curOp != nil && curOp.MunchRight != nil {
// munch_right() of atoms returns this/itself, in which
// case: p.AccumTree = t; is the result.
Q("about to MunchRight on cnode = %v", cnode.SexpString(nil))
p.AccumTree, err = curOp.MunchRight(env, p)
if err != nil {
Q("Expression(%v) MunchRight saw err = %v", rbp, err)
return SexpNull, err
}
Q("after MunchRight on cnode = %v, p.AccumTree = '%v'",
cnode.SexpString(nil), p.AccumTree.SexpString(nil))
} else {
// do this, or have the default MunchRight return itself.
p.AccumTree = cnode
}
for !p.IsEOF() {
nextLbp, err := env.LeftBindingPower(p.NextToken)
if err != nil {
Q("env.LeftBindingPower('%s') saw err = %v",
p.NextToken.SexpString(nil), err)
return SexpNull, err
}
Q("nextLbp = %v, and rbp = %v, so rpb >= nextLbp == %v", nextLbp, rbp, rbp >= nextLbp)
if rbp >= nextLbp {
Q("found rbp >= nextLbp so breaking out of left-binding loop")
break
}
cnode = p.NextToken
curOp = nil
switch x := cnode.(type) {
case *SexpSymbol:
op, found := env.infixOps[x.name]
if found {
Q("assigning curOp <- cnode '%s'", x.name)
curOp = op
} else {
if x.isDot {
curOp = env.infixOps["."]
Q("assigning curOp <- dotInfixOp; then curOp = %#v", curOp)
}
}
case *SexpArray:
Q("assigning curOp <- arrayOp")
curOp = arrayOp
case *SexpComma:
curOp = env.infixOps["comma"]
Q("assigning curOp <- infixOps[`comma`]; then curOp = %#v", curOp)
case *SexpPair:
// sexp-call, treat like function call with rbp 80
Q("Expression sees an SexpPair")
// leaving curOp nil seems to work just fine here.
default:
panic(fmt.Errorf("how to handle cnode type = %#v", cnode))
}
Q("curOp = %#v", curOp)
p.CnodeStack[0] = p.NextToken
//_cnode_stack.front() = NextToken;
Q("in MunchLeft loop, before Advance, p.NextToken = %v",
p.NextToken.SexpString(nil))
p.Advance()
if p.Pos < len(p.Stream) {
Q("in MunchLeft loop, after Advance, p.NextToken = %v",
p.NextToken.SexpString(nil))
}
// if cnode->munch_left() returns this/itself, then
// the net effect is: p.AccumTree = cnode;
if curOp != nil && curOp.MunchLeft != nil {
Q("about to MunchLeft, cnode = %v, p.AccumTree = %v", cnode.SexpString(nil), p.AccumTree.SexpString(nil))
p.AccumTree, err = curOp.MunchLeft(env, p, p.AccumTree)
if err != nil {
Q("curOp.MunchLeft saw err = %v", err)
return SexpNull, err
}
} else {
Q("curOp has not MunchLeft, setting AccumTree <- cnode. here cnode = %v", cnode.SexpString(nil))
// do this, or have the default MunchLeft return itself.
p.AccumTree = cnode
}
} // end for !p.IsEOF()
p.CnodeStack = p.CnodeStack[1:]
//_cnode_stack.pop_front()
Q("at end of Expression(%v), returning p.AccumTree=%v, err=nil", rbp, p.AccumTree.SexpString(nil))
return p.AccumTree, nil
}
// Advance sets p.NextToken
func (p *Pratt) Advance() error {
p.Pos++
if p.Pos >= len(p.Stream) {
return io.EOF
}
p.NextToken = p.Stream[p.Pos]
Q("end of Advance, p.NextToken = '%v'", p.NextToken.SexpString(nil))
return nil
}
func (p *Pratt) IsEOF() bool {
if p.Pos >= len(p.Stream) {
return true
}
return false
}
func (env *Zlisp) LeftBindingPower(sx Sexp) (int, error) {
Q("LeftBindingPower: sx is '%v'", sx.SexpString(nil))
switch x := sx.(type) {
case *SexpInt:
return 0, nil
case *SexpBool:
return 0, nil
case *SexpStr:
return 0, nil
case *SexpSymbol:
op, found := env.infixOps[x.name]
if x.name == "if" {
// we don't want if to be doing any binding to the left,
// so we enforce that it has zero left-binding power. It
// gets a right-binding power of 5 since it is a prefix operator.
Q("LeftBindingPower: found if, return 0 left-binding-power")
return 0, nil
}
if found {
Q("LeftBindingPower: found op '%#v', returning op.Bp = %v", op, op.Bp)
return op.Bp, nil
}
if x.isDot {
Q("LeftBindingPower: dot symbol '%v', "+
"giving it binding-power 80", x.name)
return 80, nil
}
Q("LeftBindingPower: no entry in env.infixOps for operation '%s'",
x.name)
return 0, nil
case *SexpArray:
return 80, nil
case *SexpComma:
return 15, nil
case *SexpSemicolon:
return 0, nil
case *SexpComment:
return 0, nil
case *SexpPair:
if x.Head != nil {
switch sym := x.Head.(type) {
case *SexpSymbol:
if sym.name == "infix" {
Q("detected infix!!! -- setting binding power to 0")
return 0, nil
}
}
}
return 0, nil
}
return 0, fmt.Errorf("LeftBindingPower: unhandled sx :%#v", sx)
}
func (p *Pratt) ShowCnodeStack() {
if len(p.CnodeStack) == 0 {
fmt.Println("CnodeStack is: empty")
return
}
fmt.Println("CnodeStack is:")
for i := range p.CnodeStack {
fmt.Printf("CnodeStack[%v] = %v\n", i, p.CnodeStack[i].SexpString(nil))
}
}

100
vendor/github.com/glycerine/zygomys/zygo/printstate.go generated vendored Normal file
View File

@@ -0,0 +1,100 @@
package zygo
import (
"fmt"
)
// begin supporting SexpString structs
// PrintState threads the state of display through SexpString() and Show() calls,
// to give pretty-printing indentation and to avoid infinite looping on
// cyclic data structures.
type PrintState struct {
Indent int
Seen Seen
}
func (ps *PrintState) SetSeen(x interface{}, name string) {
if ps == nil {
panic("can't SetSeen on a nil PrintState")
}
ps.Seen[x] = struct{}{}
}
func (ps *PrintState) GetSeen(x interface{}) bool {
if ps == nil {
return false
}
_, ok := ps.Seen[x]
return ok
}
func (ps *PrintState) GetIndent() int {
if ps == nil {
return 0
}
return ps.Indent
}
func (ps *PrintState) AddIndent(addme int) *PrintState {
if ps == nil {
return &PrintState{
Indent: addme,
Seen: NewSeen(),
}
}
return &PrintState{
Indent: ps.Indent + addme,
Seen: ps.Seen,
}
}
func NewPrintState() *PrintState {
return &PrintState{
Seen: NewSeen(),
}
}
func NewPrintStateWithIndent(indent int) *PrintState {
return &PrintState{
Indent: indent,
Seen: NewSeen(),
}
}
func (ps *PrintState) Clear() {
ps.Indent = 0
ps.Seen = NewSeen()
}
func (ps *PrintState) Dump() {
fmt.Printf("ps Dump: ")
if ps == nil {
fmt.Printf("nil\n")
return
}
for k, v := range ps.Seen {
fmt.Printf("ps Dump: %p -- %v\n", k, v)
}
fmt.Printf("\n")
}
// Seen tracks if a value has already been displayed, to
// detect and avoid cycles.
//
/* Q: How to do garbage-collection safe graph traversal in a graph of Go objects?
A: "Instead of converting the pointer to a uintptr, just store the pointer
itself in a map[interface{}]bool. If you encounter the same pointer
again, you will get the same map entry. The GC must guarantee that
using pointers as map keys will work even if the pointers move."
- Ian Lance Taylor on golang-nuts (2016 June 20).
*/
type Seen map[interface{}]struct{}
func NewSeen() Seen {
return Seen(make(map[interface{}]struct{}))
}
// end supporting SexpString structs

59
vendor/github.com/glycerine/zygomys/zygo/ptrcheck.go generated vendored Normal file
View File

@@ -0,0 +1,59 @@
package zygo
import (
"reflect"
)
// true if target is type *T where T
// is a struct/string/int/other-non-pointer type.
func IsExactlySinglePointer(target interface{}) bool {
// va, isVa := target.(reflect.Value)
// if isVa {
// return IsExactlySinglePointerType(va.Type())
// }
typ := reflect.ValueOf(target).Type()
return IsExactlySinglePointerType(typ)
}
func IsExactlySinglePointerType(typ reflect.Type) bool {
kind := typ.Kind()
if kind != reflect.Ptr {
return false
}
typ2 := typ.Elem()
kind2 := typ2.Kind()
if kind2 == reflect.Ptr {
return false // two level pointer
}
return true
}
// true if target is of type **T where T is
// a struct/string/int/other-non-pointer type.
func IsExactlyDoublePointer(target interface{}) bool {
typ := reflect.ValueOf(target).Type()
kind := typ.Kind()
if kind != reflect.Ptr {
return false
}
typ2 := typ.Elem()
kind2 := typ2.Kind()
if kind2 != reflect.Ptr {
return false
}
if typ2.Elem().Kind() == reflect.Ptr {
return false // triple level pointer, not double.
}
return true
}
func PointerDepth(typ reflect.Type) int {
return pointerDepthHelper(typ, 0)
}
func pointerDepthHelper(typ reflect.Type, accum int) int {
kind := typ.Kind()
if kind != reflect.Ptr {
return accum
}
return pointerDepthHelper(typ.Elem(), accum+1)
}

17
vendor/github.com/glycerine/zygomys/zygo/random.go generated vendored Normal file
View File

@@ -0,0 +1,17 @@
package zygo
import (
"math/rand"
"time"
)
var defaultRand = rand.New(rand.NewSource(time.Now().Unix()))
func RandomFunction(env *Zlisp, name string,
args []Sexp) (Sexp, error) {
return &SexpFloat{Val: defaultRand.Float64()}, nil
}
func (env *Zlisp) ImportRandom() {
env.AddFunction("random", RandomFunction)
}

33
vendor/github.com/glycerine/zygomys/zygo/rawutils.go generated vendored Normal file
View File

@@ -0,0 +1,33 @@
package zygo
import (
"errors"
"fmt"
)
func MakeRaw(args []Sexp) (*SexpRaw, error) {
raw := make([]byte, 0)
for i := 0; i < len(args); i++ {
switch e := args[i].(type) {
case *SexpStr:
a := []byte(e.S)
raw = append(raw, a...)
default:
return &SexpRaw{},
fmt.Errorf("raw takes only string arguments. We see %T: '%v'", e, e)
}
}
return &SexpRaw{Val: raw}, nil
}
func RawToStringFunction(env *Zlisp, name string, args []Sexp) (Sexp, error) {
if len(args) != 1 {
return SexpNull, WrongNargs
}
switch t := args[0].(type) {
case *SexpRaw:
return &SexpStr{S: string(t.Val)}, nil
}
return SexpNull, errors.New("argument must be raw")
}

100
vendor/github.com/glycerine/zygomys/zygo/regexp.go generated vendored Normal file
View File

@@ -0,0 +1,100 @@
package zygo
import (
"errors"
"fmt"
"regexp"
)
type SexpRegexp regexp.Regexp
func (re *SexpRegexp) SexpString(ps *PrintState) string {
r := (*regexp.Regexp)(re)
return fmt.Sprintf(`(regexpCompile "%v")`, r.String())
}
func (r *SexpRegexp) Type() *RegisteredType {
return nil // TODO what should this be?
}
func regexpFindIndex(env *Zlisp,
needle *regexp.Regexp, haystack string) (Sexp, error) {
loc := needle.FindStringIndex(haystack)
arr := make([]Sexp, len(loc))
for i := range arr {
arr[i] = Sexp(&SexpInt{Val: int64(loc[i])})
}
return &SexpArray{Val: arr, Env: env}, nil
}
func RegexpFind(env *Zlisp, name string,
args []Sexp) (Sexp, error) {
if len(args) != 2 {
return SexpNull, WrongNargs
}
var haystack string
switch t := args[1].(type) {
case *SexpStr:
haystack = t.S
default:
return SexpNull,
errors.New(fmt.Sprintf("2nd argument of %v should be a string", name))
}
var needle *regexp.Regexp
switch t := args[0].(type) {
case *SexpRegexp:
needle = (*regexp.Regexp)(t)
default:
return SexpNull,
errors.New(fmt.Sprintf("1st argument of %v should be a compiled regular expression", name))
}
switch name {
case "regexpFind":
str := needle.FindString(haystack)
return &SexpStr{S: str}, nil
case "regexpFindIndex":
return regexpFindIndex(env, needle, haystack)
case "regexpMatch":
matches := needle.MatchString(haystack)
return &SexpBool{Val: matches}, nil
}
return SexpNull, errors.New("unknown function")
}
func RegexpCompile(env *Zlisp, name string,
args []Sexp) (Sexp, error) {
if len(args) < 1 {
return SexpNull, WrongNargs
}
var re string
switch t := args[0].(type) {
case *SexpStr:
re = t.S
default:
return SexpNull,
errors.New("argument of regexpCompile should be a string")
}
r, err := regexp.Compile(re)
if err != nil {
return SexpNull, errors.New(
fmt.Sprintf("error during regexpCompile: '%v'", err))
}
return Sexp((*SexpRegexp)(r)), nil
}
func (env *Zlisp) ImportRegex() {
env.AddFunction("regexpCompile", RegexpCompile)
env.AddFunction("regexpFindIndex", RegexpFind)
env.AddFunction("regexpFind", RegexpFind)
env.AddFunction("regexpMatch", RegexpFind)
}

515
vendor/github.com/glycerine/zygomys/zygo/repl.go generated vendored Normal file
View File

@@ -0,0 +1,515 @@
package zygo
import (
"bufio"
"bytes"
"encoding/gob"
"fmt"
"io"
"os"
"runtime/pprof"
"strconv"
"strings"
)
var precounts map[string]int
var postcounts map[string]int
func CountPreHook(env *Zlisp, name string, args []Sexp) {
precounts[name] += 1
}
func CountPostHook(env *Zlisp, name string, retval Sexp) {
postcounts[name] += 1
}
func getLine(reader *bufio.Reader) (string, error) {
line := make([]byte, 0)
for {
linepart, hasMore, err := reader.ReadLine()
if err != nil {
return "", err
}
line = append(line, linepart...)
if !hasMore {
break
}
}
return string(line), nil
}
// NB at the moment this doesn't track comment and strings state,
// so it will fail if unbalanced '(' are found in either.
func isBalanced(str string) bool {
parens := 0
squares := 0
for _, c := range str {
switch c {
case '(':
parens++
case ')':
parens--
case '[':
squares++
case ']':
squares--
}
}
return parens == 0 && squares == 0
}
var continuationPrompt = "... "
func (pr *Prompter) getExpressionOrig(reader *bufio.Reader) (readin string, err error) {
line, err := getLine(reader)
if err != nil {
return "", err
}
for !isBalanced(line) {
fmt.Printf(continuationPrompt)
nextline, err := getLine(reader)
if err != nil {
return "", err
}
line += "\n" + nextline
}
return line, nil
}
// liner reads Stdin only. If noLiner, then we read from reader.
func (pr *Prompter) getExpressionWithLiner(env *Zlisp, reader *bufio.Reader, noLiner bool) (readin string, xs []Sexp, err error) {
var line, nextline string
if noLiner {
fmt.Printf(pr.prompt)
line, err = getLine(reader)
} else {
line, err = pr.Getline(nil)
}
if err != nil {
return "", nil, err
}
err = UnexpectedEnd
var x []Sexp
// test parse, but don't load or generate bytecode
env.parser.ResetAddNewInput(bytes.NewBuffer([]byte(line + "\n")))
x, err = env.parser.ParseTokens()
//P("\n after ResetAddNewInput, err = %v. x = '%s'\n", err, SexpArray(x).SexpString())
if len(x) > 0 {
xs = append(xs, x...)
}
for err == ErrMoreInputNeeded || err == UnexpectedEnd || err == ResetRequested {
if noLiner {
fmt.Printf(continuationPrompt)
nextline, err = getLine(reader)
} else {
nextline, err = pr.Getline(&continuationPrompt)
}
if err != nil {
return "", nil, err
}
env.parser.NewInput(bytes.NewBuffer([]byte(nextline + "\n")))
x, err = env.parser.ParseTokens()
if len(x) > 0 {
for i := range x {
if x[i] == SexpEnd {
P("found an SexpEnd token, omitting it")
continue
}
xs = append(xs, x[i])
}
}
switch err {
case nil:
line += "\n" + nextline
Q("no problem parsing line '%s' into '%s', proceeding...\n", line, (&SexpArray{Val: x, Env: env}).SexpString(nil))
return line, xs, nil
case ResetRequested:
continue
case ErrMoreInputNeeded:
continue
default:
return "", nil, fmt.Errorf("Error on line %d: %v\n", env.parser.lexer.Linenum(), err)
}
}
return line, xs, nil
}
func processDumpCommand(env *Zlisp, args []string) {
if len(args) == 0 {
env.DumpEnvironment()
} else {
err := env.DumpFunctionByName(args[0])
if err != nil {
fmt.Println(err)
}
}
}
func Repl(env *Zlisp, cfg *ZlispConfig) {
var reader *bufio.Reader
if cfg.NoLiner {
// reader is used if one wishes to drop the liner library.
// Useful for not full terminal env, like under test.
reader = bufio.NewReader(os.Stdin)
}
if cfg.Trace {
// debug tracing
env.debugExec = true
}
if !cfg.Quiet {
if cfg.Sandboxed {
fmt.Printf("zygo [sandbox mode] version %s\n", Version())
} else {
fmt.Printf("zygo version %s\n", Version())
}
fmt.Printf("press tab (repeatedly) to get completion suggestions. Shift-tab goes back. Ctrl-d to exit.\n")
}
var pr *Prompter // can be nil if noLiner
if !cfg.NoLiner {
pr = NewPrompter(cfg.Prompt)
defer pr.Close()
} else {
pr = &Prompter{prompt: cfg.Prompt}
}
infixSym := env.MakeSymbol("infix")
for {
line, exprsInput, err := pr.getExpressionWithLiner(env, reader, cfg.NoLiner)
//Q("\n exprsInput(len=%d) = '%v'\n line = '%s'\n", len(exprsInput), (&SexpArray{Val: exprsInput}).SexpString(nil), line)
if err != nil {
fmt.Println(err)
if err == io.EOF {
os.Exit(0)
}
env.Clear()
continue
}
parts := strings.Split(strings.Trim(line, " "), " ")
//parts := strings.Split(line, " ")
if len(parts) == 0 {
continue
}
first := strings.Trim(parts[0], " ")
if first == ".quit" {
break
}
if first == ".cd" {
if len(parts) < 2 {
fmt.Printf("provide directory path to change to.\n")
continue
}
err := os.Chdir(parts[1])
if err != nil {
fmt.Printf("error: %s\n", err)
continue
}
pwd, err := os.Getwd()
if err == nil {
fmt.Printf("cur dir: %s\n", pwd)
} else {
fmt.Printf("error: %s\n", err)
}
continue
}
// allow & at the repl to take the address of an expression
if len(first) > 0 && first[0] == '&' {
//P("saw & at repl, first='%v', parts='%#v'. exprsInput = '%#v'", first, parts, exprsInput)
exprsInput = []Sexp{MakeList(exprsInput)}
}
// allow * at the repl to dereference a pointer and print
if len(first) > 0 && first[0] == '*' {
//P("saw * at repl, first='%v', parts='%#v'. exprsInput = '%#v'", first, parts, exprsInput)
exprsInput = []Sexp{MakeList(exprsInput)}
}
if first == ".dump" {
processDumpCommand(env, parts[1:])
continue
}
if first == ".gls" {
fmt.Printf("\nScopes:\n")
prev := env.showGlobalScope
env.showGlobalScope = true
err = env.ShowStackStackAndScopeStack()
env.showGlobalScope = prev
if err != nil {
fmt.Printf("%s\n", err)
}
continue
}
if first == ".ls" {
err := env.ShowStackStackAndScopeStack()
if err != nil {
fmt.Println(err)
}
continue
}
if first == ".verb" {
Verbose = !Verbose
fmt.Printf("verbose: %v.\n", Verbose)
continue
}
if first == ".debug" {
env.debugExec = true
fmt.Printf("instruction debugging on.\n")
continue
}
if first == ".undebug" {
env.debugExec = false
fmt.Printf("instruction debugging off.\n")
continue
}
var expr Sexp
n := len(exprsInput)
if n > 0 {
infixWrappedSexp := MakeList([]Sexp{infixSym, &SexpArray{Val: exprsInput, Env: env}})
expr, err = env.EvalExpressions([]Sexp{infixWrappedSexp})
} else {
line = env.ReplLineInfixWrap(line)
expr, err = env.EvalString(line + " ") // print standalone variables
}
switch err {
case nil:
case NoExpressionsFound:
env.Clear()
continue
default:
fmt.Print(env.GetStackTrace(err))
env.Clear()
continue
}
if expr != SexpNull {
// try to print strings more elegantly!
switch e := expr.(type) {
case *SexpStr:
if e.backtick {
fmt.Printf("`%s`\n", e.S)
} else {
fmt.Printf("%s\n", strconv.Quote(e.S))
}
default:
switch sym := expr.(type) {
case Selector:
Q("repl calling RHS() on Selector")
rhs, err := sym.RHS(env)
if err != nil {
Q("repl problem in call to RHS() on SexpSelector: '%v'", err)
fmt.Print(env.GetStackTrace(err))
env.Clear()
continue
} else {
Q("got back rhs of type %T", rhs)
fmt.Println(rhs.SexpString(nil))
continue
}
case *SexpSymbol:
if sym.isDot {
resolved, err := dotGetSetHelper(env, sym.name, nil)
if err != nil {
fmt.Print(env.GetStackTrace(err))
env.Clear()
continue
}
fmt.Println(resolved.SexpString(nil))
continue
}
}
fmt.Println(expr.SexpString(nil))
}
}
}
}
func runScript(env *Zlisp, fname string, cfg *ZlispConfig) {
file, err := os.Open(fname)
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
err = env.LoadFile(file)
if err != nil {
fmt.Println(err)
if cfg.ExitOnFailure {
os.Exit(-1)
}
return
}
_, err = env.Run()
if cfg.CountFuncCalls {
fmt.Println("Pre:")
for name, count := range precounts {
fmt.Printf("\t%s: %d\n", name, count)
}
fmt.Println("Post:")
for name, count := range postcounts {
fmt.Printf("\t%s: %d\n", name, count)
}
}
if err != nil {
fmt.Print(env.GetStackTrace(err))
if cfg.ExitOnFailure {
os.Exit(-1)
}
Repl(env, cfg)
}
}
func (env *Zlisp) StandardSetup() {
env.ImportBaseTypes()
env.ImportEval()
env.ImportTime()
env.ImportPackageBuilder()
env.ImportMsgpackMap()
defmap := `(defmac defmap [name] ^(defn ~name [& rest] (msgmap (quote ~name) rest)))`
_, err := env.EvalString(defmap)
panicOn(err)
// colonOp := `(defmac : [key hmap & def] ^(hget ~hmap (quote ~key) ~@def))`
// _, err = env.EvalString(colonOp)
// panicOn(err)
rangeMacro := `(defmac range [key value myhash & body]
^(let [n (len ~myhash)]
(for [(def i 0) (< i n) (def i (+ i 1))]
(begin
(mdef (quote ~key) (quote ~value) (hpair ~myhash i))
~@body))))`
_, err = env.EvalString(rangeMacro)
panicOn(err)
reqMacro := `(defmac req [a] ^(source (sym2str (quote ~a))))`
_, err = env.EvalString(reqMacro)
panicOn(err)
incrMacro := `(defmac ++ [a] ^(set ~a (+ ~a 1)))`
_, err = env.EvalString(incrMacro)
panicOn(err)
incrEqMacro := `(defmac += [a b] ^(set ~a (+ ~a ~b)))`
_, err = env.EvalString(incrEqMacro)
panicOn(err)
decrMacro := `(defmac -- [a] ^(set ~a (- ~a 1)))`
_, err = env.EvalString(decrMacro)
panicOn(err)
decrEqMacro := `(defmac -= [a b] ^(set ~a (- ~a ~b)))`
_, err = env.EvalString(decrEqMacro)
panicOn(err)
env.ImportChannels()
env.ImportGoroutines()
env.ImportRegex()
env.ImportRandom()
gob.Register(SexpHash{})
gob.Register(SexpArray{})
}
// like main() for a standalone repl, now in library
func ReplMain(cfg *ZlispConfig) {
var env *Zlisp
if cfg.LoadDemoStructs {
RegisterDemoStructs()
}
if cfg.Sandboxed {
env = NewZlispSandbox()
} else {
env = NewZlisp()
}
env.StandardSetup()
if cfg.LoadDemoStructs {
// avoid data conflicts by only loading these in demo mode.
env.ImportDemoData()
}
if cfg.CpuProfile != "" {
f, err := os.Create(cfg.CpuProfile)
if err != nil {
fmt.Println(err)
os.Exit(-1)
}
err = pprof.StartCPUProfile(f)
if err != nil {
fmt.Println(err)
os.Exit(-1)
}
defer pprof.StopCPUProfile()
}
precounts = make(map[string]int)
postcounts = make(map[string]int)
if cfg.CountFuncCalls {
env.AddPreHook(CountPreHook)
env.AddPostHook(CountPostHook)
}
if cfg.Command != "" {
_, err := env.EvalString(cfg.Command)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1)
}
os.Exit(0)
}
runRepl := true
args := cfg.Flags.Args()
if len(args) > 0 {
runRepl = false
runScript(env, args[0], cfg)
if cfg.AfterScriptDontExit {
runRepl = true
}
}
if runRepl {
Repl(env, cfg)
}
if cfg.MemProfile != "" {
f, err := os.Create(cfg.MemProfile)
if err != nil {
fmt.Println(err)
os.Exit(-1)
}
defer f.Close()
err = pprof.Lookup("heap").WriteTo(f, 1)
if err != nil {
fmt.Println(err)
os.Exit(-1)
}
}
}
func (env *Zlisp) ReplLineInfixWrap(line string) string {
return "{" + line + "}"
}

339
vendor/github.com/glycerine/zygomys/zygo/scopes.go generated vendored Normal file
View File

@@ -0,0 +1,339 @@
package zygo
import (
"errors"
"fmt"
"sort"
"strings"
)
// Scopes map names to values. Scope nesting avoids variable name collisions and
// allows namespace maintainance. Most scopes (inside loops, inside functions)
// are implicitly created. Packages are scopes that the user can manipulate
// explicitly.
type Scope struct {
Map map[int]Sexp
IsGlobal bool
Name string
PackageName string
Parent *Scope
IsFunction bool // if true, read-only.
MyFunction *SexpFunction // so we can query captured closure scopes.
IsPackage bool
env *Zlisp
}
// SexpString satisfies the Sexp interface, producing a string presentation of the value.
func (s *Scope) SexpString(ps *PrintState) string {
var label string
head := ""
if s.IsPackage {
head = "(package " + s.PackageName
} else {
label = "scope " + s.Name
if s.IsGlobal {
label += " (global)"
}
}
str, err := s.Show(s.env, ps, s.Name)
if err != nil {
return "(" + label + ")"
}
return head + " " + str + " )"
}
// Type() satisfies the Sexp interface, returning the type of the value.
func (s *Scope) Type() *RegisteredType {
return GoStructRegistry.Lookup("packageScope")
}
func (env *Zlisp) NewScope() *Scope {
return &Scope{
Map: make(map[int]Sexp),
env: env,
}
}
func (env *Zlisp) NewNamedScope(name string) *Scope {
return &Scope{
Map: make(map[int]Sexp),
Name: name,
env: env,
}
}
func (s *Scope) CloneScope() *Scope {
n := s.env.NewScope()
for k, v := range s.Map {
n.Map[k] = v
}
return n
}
func (s Scope) IsStackElem() {}
func (stack *Stack) PushScope() {
s := stack.env.NewScope()
if stack.Size() > 0 {
s.Parent = stack.GetTop().(*Scope)
}
stack.Push(s)
}
func (stack *Stack) PopScope() error {
_, err := stack.Pop()
return err
}
// dynamic scoping lookup. See env.LexicalLookupSymbol() for the lexically
// scoped equivalent.
// If setVal is not nil, and if we find the symbol, we set it in the scope
// where it was found. This is equivalent to scope.UpdateSymbolInScope.
//
func (stack *Stack) lookupSymbol(sym *SexpSymbol, minFrame int, setVal *Sexp) (Sexp, error, *Scope) {
if !stack.IsEmpty() {
for i := 0; i <= stack.tos-minFrame; i++ {
//P("lookupSymbol checking stack %v of %v", i, (stack.tos-minFrame)+1)
elem, err := stack.Get(i)
if err != nil {
//P("lookupSymbol bailing (early?) at i=%v on err='%v'", i, err)
return SexpNull, err, nil
}
switch scope := elem.(type) {
case (*Scope):
expr, ok := scope.Map[sym.number]
if ok {
//P("lookupSymbol at stack scope# i=%v, we found sym '%s' with value '%s'", i, sym.name, expr.SexpString(0))
if setVal != nil {
scope.Map[sym.number] = *setVal
}
return expr, nil, scope
}
}
}
}
//P("lookupSymbol finished stack scan without finding it")
if stack.env != nil && stack.env.debugSymbolNotFound {
stack.env.ShowStackStackAndScopeStack()
}
return SexpNull, fmt.Errorf("alas, symbol `%s` not found", sym.name), nil
}
func (stack *Stack) LookupSymbol(sym *SexpSymbol, setVal *Sexp) (Sexp, error, *Scope) {
return stack.lookupSymbol(sym, 0, setVal)
}
// LookupSymbolNonGlobal - closures use this to only find symbols below the global scope, to avoid copying globals it'll always be-able to ref
func (stack *Stack) LookupSymbolNonGlobal(sym *SexpSymbol) (Sexp, error, *Scope) {
return stack.lookupSymbol(sym, 1, nil)
}
var SymNotFound = errors.New("symbol not found")
// lookup symbols, but don't go beyond a function boundary -- a user-defined
// function boundary that is. We certainly have to go up beyond
// all built-in operators like '+' and '-', '*' and '/'.
func (stack *Stack) LookupSymbolUntilFunction(sym *SexpSymbol, setVal *Sexp, maximumFuncToSearch int, checkCaptures bool) (Sexp, error, *Scope) {
funcCount := 0
if !stack.IsEmpty() {
doneSearching:
for i := 0; i <= stack.tos; i++ {
elem, err := stack.Get(i)
if err != nil {
return SexpNull, err, nil
}
switch scope := elem.(type) {
case (*Scope):
VPrintf(" ...looking up in scope '%s'\n", scope.Name)
expr, ok := scope.Map[sym.number]
if ok {
if setVal != nil {
scope.UpdateSymbolInScope(sym, *setVal)
}
return expr, nil, scope
}
if scope.IsFunction {
funcCount++
//P(" ...scope '%s' was a function, halting up search and checking captured closures\n", scope.Name)
if checkCaptures {
// check the captured closure scope stack
exp, err, whichScope := scope.MyFunction.ClosingLookupSymbol(sym, setVal)
switch err {
case nil:
//P("LookupSymbolUntilFunction('%s') found in scope '%s'\n", sym.name, whichScope.Name)
return exp, err, whichScope
}
}
// no luck inside the captured closure scopes.
if funcCount >= maximumFuncToSearch {
break doneSearching
}
}
}
}
}
if stack != nil && stack.env != nil && stack.env.debugSymbolNotFound {
fmt.Printf("debugSymbolNotFound is true, here are scopes:\n")
stack.env.ShowStackStackAndScopeStack()
}
return SexpNull, SymNotFound, nil
}
func (stack *Stack) BindSymbol(sym *SexpSymbol, expr Sexp) error {
if stack.IsEmpty() {
panic("empty stack!!")
}
cur, already := stack.elements[stack.tos].(*Scope).Map[sym.number]
if already {
Q("BindSymbol already sees symbol %v, currently bound to '%v'", sym.name, cur.SexpString(nil))
lhsTy := cur.Type()
rhsTy := expr.Type()
if lhsTy == nil {
// for backcompat with closure.zy, just do the binding for now if the LHS isn't typed.
//return fmt.Errorf("left-hand-side had nil type")
// TODO: fix this? or require removal of previous symbol binding to avoid type errors?
stack.elements[stack.tos].(*Scope).Map[sym.number] = expr
return nil
}
if rhsTy == nil {
// meh, we need to be able to assign nil to stuff without freaking out,
// so force type match
rhsTy = lhsTy
//return fmt.Errorf("right-hand-side had nil type back from Type() call; val = '%s'/%T", expr.SexpString(nil), expr)
}
// both sides have type
Q("BindSymbol: both sides have type. rhs=%v, lhs=%v", rhsTy.SexpString(nil), lhsTy.SexpString(nil))
if lhsTy == rhsTy {
Q("BindSymbol: YES types match exactly. Good.")
stack.elements[stack.tos].(*Scope).Map[sym.number] = expr
return nil
}
if rhsTy.UserStructDefn != nil && rhsTy.UserStructDefn != lhsTy.UserStructDefn {
return fmt.Errorf("cannot assign %v to %v", rhsTy.ShortName(), lhsTy.ShortName())
}
if lhsTy.UserStructDefn != nil && lhsTy.UserStructDefn != rhsTy.UserStructDefn {
return fmt.Errorf("cannot assign %v to %v", rhsTy.ShortName(), lhsTy.ShortName())
}
// TODO: problem with this implementation is that it may narrow the possible
// types assignments to this variable. To fix we'll need to keep around the
// type of the symbol in the symbol table, separately from the value currently
// bound to it.
if lhsTy.TypeCache != nil && rhsTy.TypeCache != nil {
if rhsTy.TypeCache.AssignableTo(lhsTy.TypeCache) {
Q("BindSymbol: YES: rhsTy.TypeCache (%v) is AssigntableTo(lhsTy.TypeCache) (%v). Good.", rhsTy.TypeCache, lhsTy.TypeCache)
stack.elements[stack.tos].(*Scope).Map[sym.number] = expr
return nil
}
}
Q("BindSymbol: at end, defaulting to deny")
return fmt.Errorf("cannot assign %v to %v", rhsTy.ShortName(), lhsTy.ShortName())
} else {
Q("BindSymbol: new symbol %v", sym.name)
}
stack.elements[stack.tos].(*Scope).Map[sym.number] = expr
return nil
}
func (stack *Stack) DeleteSymbolFromTopOfStackScope(sym *SexpSymbol) error {
if stack.IsEmpty() {
panic("empty stack!!")
//return errors.New("no scope available")
}
_, present := stack.elements[stack.tos].(*Scope).Map[sym.number]
if !present {
return fmt.Errorf("symbol `%s` not found", sym.name)
}
delete(stack.elements[stack.tos].(*Scope).Map, sym.number)
return nil
}
// used to implement (set v 10)
func (scope *Scope) UpdateSymbolInScope(sym *SexpSymbol, expr Sexp) error {
_, found := scope.Map[sym.number]
if !found {
return fmt.Errorf("symbol `%s` not found", sym.name)
}
scope.Map[sym.number] = expr
return nil
}
func (scope *Scope) DeleteSymbolInScope(sym *SexpSymbol) error {
_, found := scope.Map[sym.number]
if !found {
return fmt.Errorf("symbol `%s` not found", sym.name)
}
delete(scope.Map, sym.number)
return nil
}
type SymtabE struct {
Key string
Val string
}
type SymtabSorter []*SymtabE
func (a SymtabSorter) Len() int { return len(a) }
func (a SymtabSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a SymtabSorter) Less(i, j int) bool { return a[i].Key < a[j].Key }
func (scop *Scope) Show(env *Zlisp, ps *PrintState, label string) (s string, err error) {
//P("scop %p Show() starting, PackageName: '%s' IsGlobal: %v", scop, scop.PackageName, scop.IsGlobal)
if ps == nil {
ps = NewPrintState()
}
if ps.GetSeen(scop) {
// This check is critical to prevent infinite looping in a cycle.
// Scopes like global are referenced by every package, and
// nested scopes refer to their paranets, so nesting
// two packages will loop forever without this check.
// debug version: return fmt.Sprintf("already-saw Scope %p with scop.PackageName='%s'\n", scop, scop.PackageName), nil
return "", nil
} else {
ps.SetSeen(scop, "Scope")
}
indent := ps.GetIndent()
rep := strings.Repeat(" ", indent)
rep4 := strings.Repeat(" ", indent+4)
s += fmt.Sprintf("%s %s %s (%p)\n", rep, label, scop.Name, scop)
if scop.IsGlobal && !env.showGlobalScope {
s += fmt.Sprintf("%s (global scope - omitting content for brevity)\n", rep4)
return
}
if len(scop.Map) == 0 {
s += fmt.Sprintf("%s empty-scope: no symbols\n", rep4)
return
}
sortme := []*SymtabE{}
for symbolNumber, val := range scop.Map {
symbolName := env.revsymtable[symbolNumber]
sortme = append(sortme, &SymtabE{Key: symbolName, Val: val.SexpString(ps)})
}
sort.Sort(SymtabSorter(sortme))
for i := range sortme {
s += fmt.Sprintf("%s %s -> %s\n", rep4,
sortme[i].Key, sortme[i].Val)
}
return
}
type Showable interface {
Show(env *Zlisp, ps *PrintState, label string) (string, error)
}

169
vendor/github.com/glycerine/zygomys/zygo/slurp.go generated vendored Normal file
View File

@@ -0,0 +1,169 @@
package zygo
import (
"bufio"
"fmt"
"io"
"os"
"strings"
)
// read new-line delimited text from a file into an array (slurpf "path-to-file")
func SlurpfileFunction(env *Zlisp, name string, args []Sexp) (Sexp, error) {
if len(args) != 1 {
return SexpNull, WrongNargs
}
var fn string
switch fna := args[0].(type) {
case *SexpStr:
fn = fna.S
default:
return SexpNull, fmt.Errorf("slurp requires a string path to read. we got type %T / value = %v", args[0], args[0])
}
if !FileExists(string(fn)) {
return SexpNull, fmt.Errorf("file '%s' does not exist", fn)
}
f, err := os.Open(fn)
if err != nil {
return SexpNull, err
}
defer f.Close()
a := make([]Sexp, 0)
bufIn := bufio.NewReader(f)
lineNum := int64(1)
for {
lastline, err := bufIn.ReadBytes('\n')
if err != nil && err != io.EOF {
return SexpNull, err
}
n := len(lastline)
if err == io.EOF && n == 0 {
break
}
if n > 0 {
if lastline[n-1] == '\n' {
a = append(a, &SexpStr{S: string(lastline[:n-1])})
} else {
a = append(a, &SexpStr{S: string(lastline)})
}
lineNum += 1
}
if err == io.EOF {
break
}
}
VPrintf("read %d lines\n", lineNum)
return env.NewSexpArray(a), nil
}
// (writef <content> path); (write path) is the macro version.
// (owritef <content> path): write an array of strings out to the named file,
// overwriting it in the process. (owrite) is the macro version.
// save is the same as write.
func WriteToFileFunction(env *Zlisp, name string, args []Sexp) (Sexp, error) {
if len(args) != 2 {
return SexpNull, WrongNargs
}
var fn string
switch fna := args[1].(type) {
case *SexpStr:
fn = fna.S
default:
return SexpNull, fmt.Errorf("owrite requires a string (SexpStr) path to write to as the second argument. we got type %T / value = %v", args[1], args[1])
}
if name == "write" || name == "writef" || name == "save" {
// don't overwrite existing file
if FileExists(fn) {
return SexpNull, fmt.Errorf("refusing to write to existing file '%s'",
fn)
}
}
// owrite / owritef overwrite indiscriminately.
f, err := os.Create(fn)
if err != nil {
return SexpNull, err
}
defer f.Close()
var slice []Sexp
switch sl := args[0].(type) {
case *SexpArray:
slice = sl.Val
for i := range slice {
s := slice[i].SexpString(nil)
if len(s) >= 2 && s[0] == '"' && s[len(s)-1] == '"' {
s = s[1 : len(s)-1]
} else if len(s) >= 2 && s[0] == '`' && s[len(s)-1] == '`' {
s = s[1 : len(s)-1]
}
_, err = fmt.Fprintf(f, "%s\n", s)
if err != nil {
return SexpNull, err
}
}
case *SexpRaw:
_, err = f.Write([]byte(sl.Val))
if err != nil {
return SexpNull, err
}
default:
s := sl.SexpString(nil)
if len(s) >= 2 && s[0] == '"' && s[len(s)-1] == '"' {
s = s[1 : len(s)-1]
} else if len(s) >= 2 && s[0] == '`' && s[len(s)-1] == '`' {
s = s[1 : len(s)-1]
}
_, err = fmt.Fprintf(f, "%s\n", s)
if err != nil {
return SexpNull, err
}
}
return SexpNull, nil
}
// SplitStringFunction splits a string based on an arbitrary delimiter
func SplitStringFunction(env *Zlisp, name string, args []Sexp) (Sexp, error) {
if len(args) != 2 {
return SexpNull, WrongNargs
}
// make sure the two args are strings
s1, ok := args[0].(*SexpStr)
if !ok {
return SexpNull, fmt.Errorf("split requires a string to split, got %T", args[0])
}
s2, ok := args[1].(*SexpStr)
if !ok {
return SexpNull, fmt.Errorf("split requires a string as a delimiter, got %T", args[1])
}
toSplit := s1.S
splitter := s2.S
s := strings.Split(toSplit, splitter)
split := make([]Sexp, len(s))
for i := range split {
split[i] = &SexpStr{S: s[i]}
}
return env.NewSexpArray(split), nil
}
// (nsplit "a\nb") -> ["a" "b"]
func SplitStringOnNewlinesFunction(env *Zlisp, name string, args []Sexp) (Sexp, error) {
if len(args) != 1 {
return SexpNull, WrongNargs
}
args = append(args, &SexpStr{S: "\n"})
return SplitStringFunction(env, name, args)
}

150
vendor/github.com/glycerine/zygomys/zygo/source.go generated vendored Normal file
View File

@@ -0,0 +1,150 @@
package zygo
import (
"bufio"
"errors"
"fmt"
"io"
"os"
)
// alternative. simpler, currently panics.
func SimpleSourceFunction(env *Zlisp, name string, args []Sexp) (Sexp, error) {
if len(args) != 1 {
return SexpNull, WrongNargs
}
src, isStr := args[0].(*SexpStr)
if !isStr {
return SexpNull, fmt.Errorf("-> error: first argument must be a string")
}
file := src.S
if !FileExists(file) {
return SexpNull, fmt.Errorf("path '%s' does not exist", file)
}
env2 := env.Duplicate()
f, err := os.Open(file)
if err != nil {
return SexpNull, err
}
defer f.Close()
err = env2.LoadFile(f)
if err != nil {
return SexpNull, err
}
_, err = env2.Run()
return SexpNull, err
}
// existing
// SourceExpressions, this should be called from a user func context
func (env *Zlisp) SourceExpressions(expressions []Sexp) error {
gen := NewGenerator(env)
err := gen.GenerateBegin(expressions)
if err != nil {
return err
}
//P("debug: in SourceExpressions, FROM expressions='%s'", (&SexpArray{Val: expressions, Env: env}).SexpString(0))
//P("debug: in SourceExpressions, gen=")
//DumpFunction(ZlispFunction(gen.instructions), -1)
curfunc := env.curfunc
curpc := env.pc
env.curfunc = env.MakeFunction("__source", 0, false,
gen.instructions, nil)
env.pc = 0
result, err := env.Run()
if err != nil {
return err
}
//P("end of SourceExpressions, result going onto datastack is: '%s'", result.SexpString(0))
env.datastack.PushExpr(result)
//P("debug done with Run in source, now stack is:")
//env.datastack.PrintStack()
env.pc = curpc
env.curfunc = curfunc
return nil
}
func (env *Zlisp) SourceStream(stream io.RuneScanner) error {
env.parser.ResetAddNewInput(stream)
expressions, err := env.parser.ParseTokens()
if err != nil {
return errors.New(fmt.Sprintf(
"Error parsing on line %d: %v\n", env.parser.lexer.Linenum(), err))
}
return env.SourceExpressions(expressions)
}
func (env *Zlisp) SourceFile(file *os.File) error {
return env.SourceStream(bufio.NewReader(file))
}
func SourceFileFunction(env *Zlisp, name string, args []Sexp) (Sexp, error) {
if len(args) < 1 {
return SexpNull, WrongNargs
}
for _, v := range args {
if err := env.sourceItem(v); err != nil {
return SexpNull, err
}
}
result, err := env.datastack.PopExpr()
if err != nil {
return SexpNull, err
}
return result, nil
}
// helper for SourceFileFunction recursion
func (env *Zlisp) sourceItem(item Sexp) error {
switch t := item.(type) {
case *SexpArray:
for _, v := range t.Val {
if err := env.sourceItem(v); err != nil {
return err
}
}
case *SexpPair:
expr := item
for expr != SexpNull {
list := expr.(*SexpPair)
if err := env.sourceItem(list.Head); err != nil {
return err
}
expr = list.Tail
}
case *SexpStr:
var f *os.File
var err error
if f, err = os.Open(t.S); err != nil {
return err
}
defer f.Close()
if err = env.SourceFile(f); err != nil {
return err
}
default:
return fmt.Errorf("source: Expected `string`, `list`, `array`. Instead found type %T val %v", item, item)
}
return nil
}

278
vendor/github.com/glycerine/zygomys/zygo/stack.go generated vendored Normal file
View File

@@ -0,0 +1,278 @@
package zygo
import (
"fmt"
"strings"
)
type StackElem interface {
IsStackElem()
}
type Stack struct {
tos int
elements []StackElem
env *Zlisp
Name string // type name
// package support:
PackageName string
IsPackage bool
}
func (s *Stack) SexpString(ps *PrintState) string {
if ps == nil {
ps = NewPrintState()
}
var label string
head := ""
if s.IsPackage {
head = "(package " + s.PackageName
} else {
label = "scope " + s.Name
}
str, err := s.Show(s.env, ps, s.Name)
if err != nil {
return "(" + label + ")"
}
return head + " " + str + " )"
}
// Type() satisfies the Sexp interface, returning the type of the value.
func (s *Stack) Type() *RegisteredType {
return GoStructRegistry.Lookup("packageScopeStack")
}
func (env *Zlisp) NewStack(size int) *Stack {
return &Stack{
tos: -1,
// elements: make([]StackElem, size),
elements: make([]StackElem, 0),
env: env,
}
}
func (stack *Stack) Clone() *Stack {
ret := &Stack{}
ret.tos = stack.tos
ret.env = stack.env
ret.elements = make([]StackElem, len(stack.elements))
for i := range stack.elements {
ret.elements[i] = stack.elements[i]
}
return ret
}
func (stack *Stack) Top() int {
return stack.tos
}
func (stack *Stack) PushAllTo(target *Stack) int {
if stack.tos < 0 {
return 0
}
for _, v := range stack.elements[0 : stack.tos+1] {
target.Push(v)
}
return stack.tos + 1
}
func (stack *Stack) IsEmpty() bool {
return stack.tos < 0
}
func (stack *Stack) Push(elem StackElem) {
// we have to lazily recover from errors here where the stack
// didn't get unwound...
n := len(stack.elements)
// n-1 is the last legal entry, which should be top of stack too.
switch {
case stack.tos == n-1:
// normal, 99% of the time.
stack.tos++
stack.elements = append(stack.elements, elem)
case stack.tos > n-1:
// really irretreivably problematic
panic(fmt.Sprintf("stack %p is really messed up! starting size=%v > "+
"len(stack.elements)=%v:\n here is stack: '%s'\n",
stack, stack.tos-1, n, stack.SexpString(nil)))
default:
// INVAR stack.tos < n-1
// We might get here if an error caused the last operation to abort,
// resulting in the call stack pop upon returning never happening.
// So we'll lazily cleanup now and carry on.
stack.TruncateToSize(stack.tos + 1)
stack.tos++
stack.elements = append(stack.elements, elem)
}
}
func (stack *Stack) GetTop() StackElem {
s, err := stack.Get(0)
if err != nil {
panic(err)
}
return s
}
func (stack *Stack) Size() int {
return stack.tos + 1
}
var StackUnderFlowErr = fmt.Errorf("invalid stack access: underflow")
func (stack *Stack) Get(n int) (StackElem, error) {
if stack.tos-n < 0 {
err := StackUnderFlowErr
return nil, err
}
return stack.elements[stack.tos-n], nil
}
func (stack *Stack) Pop() (StackElem, error) {
// always make a new array,
// so we can use for the closure stack-of-scopes.
elem, err := stack.Get(0)
if err != nil {
return nil, err
}
// invar n > 0
n := stack.Size()
if n == 0 {
return nil, fmt.Errorf("Stack.Pop() on emtpy stack")
}
el := make([]StackElem, n-1)
copy(el, stack.elements)
stack.elements = el
stack.tos--
return elem, nil
}
func (stack *Stack) IsStackElem() {}
func (stack *Stack) Show(env *Zlisp, ps *PrintState, label string) (string, error) {
//P("debug: Stack.Show starting with stack = %p, ps = %p, Package: '%s', IsPkg: %v", stack, ps, stack.PackageName, stack.IsPackage)
if ps.GetSeen(stack) {
return fmt.Sprintf("already-saw Stack %p in Show", stack), nil
} else {
ps.SetSeen(stack, "Stack in Show")
}
s := ""
rep := strings.Repeat(" ", ps.GetIndent())
s += fmt.Sprintf("%s %s\n", rep, label)
n := stack.Top()
for i := 0; i <= n; i++ {
ele, err := stack.Get(n - i)
if err != nil {
panic(fmt.Errorf("stack access error on %v: %v", i, err))
}
showme, canshow := ele.(Showable)
if canshow {
r, err := showme.Show(env, ps.AddIndent(4),
fmt.Sprintf("elem %v of %s:", i, label))
if err != nil {
return "", err
}
s += r
}
}
return s, nil
}
// set newsize to 0 to truncate everything
func (stack *Stack) TruncateToSize(newsize int) {
el := make([]StackElem, newsize)
copy(el, stack.elements)
stack.elements = el
stack.tos = newsize - 1
}
// nestedPathGetSet does a top-down lookup, as opposed to LexicalLookupSymbol which is bottom up
func (s *Stack) nestedPathGetSet(env *Zlisp, dotpaths []string, setVal *Sexp) (Sexp, error) {
if len(dotpaths) == 0 {
return SexpNull, fmt.Errorf("internal error: in nestedPathGetSet() dotpaths" +
" had zero length")
}
curStack := s
var ret Sexp = SexpNull
var err error
var scop *Scope
lenpath := len(dotpaths)
//P("\n in nestedPathGetSet, dotpaths=%#v\n", dotpaths)
for i := range dotpaths {
curSym := env.MakeSymbol(stripAnyDotPrefix(dotpaths[i]))
if !curStack.IsPackage {
return SexpNull, fmt.Errorf("error locating symbol '%s': current Stack is not a package", curSym.name)
}
ret, err, scop = curStack.LookupSymbol(curSym, nil)
if err != nil {
return SexpNull, fmt.Errorf("could not find symbol '%s' in current package '%v'",
curSym.name, curStack.PackageName)
}
if setVal != nil && i == lenpath-1 {
// check if private
err = errIfPrivate(curSym.name, curStack)
if err != nil {
return SexpNull, err
}
// assign now
scop.Map[curSym.number] = *setVal
// done with SET
return *setVal, nil
}
if i == lenpath-1 {
// final element
switch ret.(type) {
case *Stack:
// allow package within package to be inspected.
// done with GET
return ret, nil
default:
// don't allow private value within package to be inspected.
err = errIfPrivate(curSym.name, curStack)
if err != nil {
return SexpNull, err
}
}
// done with GET
return ret, nil
}
// invar: i < lenpath-1, so go deeper
switch x := ret.(type) {
case *SexpHash:
err = errIfPrivate(curSym.name, curStack)
if err != nil {
return SexpNull, err
}
//P("\n found hash in x at i=%d, looping to next i\n", i)
return x.nestedPathGetSet(env, dotpaths[1:], setVal)
case *Stack:
curStack = x
default:
return SexpNull, fmt.Errorf("not a record or scope: cannot get field '%s'"+
" out of type %T)", dotpaths[i+1][1:], x)
}
}
return ret, nil
}

63
vendor/github.com/glycerine/zygomys/zygo/strutils.go generated vendored Normal file
View File

@@ -0,0 +1,63 @@
package zygo
import (
"errors"
"fmt"
"strings"
)
func ConcatStr(str *SexpStr, rest []Sexp) (*SexpStr, error) {
res := &SexpStr{S: str.S}
for i, x := range rest {
switch t := x.(type) {
case *SexpStr:
res.S += t.S
case *SexpChar:
res.S += string(t.Val)
default:
return &SexpStr{}, fmt.Errorf("ConcatStr error: %d-th argument (0-based) is "+
"not a string (was %T)", i, t)
}
}
return res, nil
}
func AppendStr(str *SexpStr, expr Sexp) (*SexpStr, error) {
var chr *SexpChar
switch t := expr.(type) {
case *SexpChar:
chr = t
case *SexpStr:
return &SexpStr{S: str.S + t.S}, nil
default:
return &SexpStr{}, errors.New("second argument is not a char")
}
return &SexpStr{S: str.S + string(chr.Val)}, nil
}
func StringUtilFunction(env *Zlisp, name string, args []Sexp) (Sexp, error) {
if len(args) != 1 {
return SexpNull, WrongNargs
}
var s string
switch str := args[0].(type) {
case *SexpStr:
s = str.S
default:
return SexpNull, fmt.Errorf("string required, got %T", s)
}
switch name {
case "chomp":
n := len(s)
if n > 0 && s[n-1] == '\n' {
return &SexpStr{S: s[:n-1]}, nil
}
return &SexpStr{S: s}, nil
case "trim":
return &SexpStr{S: strings.TrimSpace(s)}, nil
}
return SexpNull, fmt.Errorf("unrecognized command '%s'", name)
}

125
vendor/github.com/glycerine/zygomys/zygo/system.go generated vendored Normal file
View File

@@ -0,0 +1,125 @@
package zygo
import (
"fmt"
"os"
"os/exec"
"runtime"
"strings"
)
var ShellCmd string = "/bin/bash"
func init() {
SetShellCmd()
}
// set ShellCmd as used by SystemFunction
func SetShellCmd() {
if runtime.GOOS == "windows" {
ShellCmd = os.Getenv("COMSPEC")
return
}
try := []string{"/usr/bin/bash"}
if !FileExists(ShellCmd) {
for i := range try {
b := try[i]
if FileExists(b) {
ShellCmd = b
return
}
}
}
}
// sys is a builder. shell out, return the combined output.
func SystemBuilder(env *Zlisp, name string, args []Sexp) (Sexp, error) {
//P("SystemBuilder called with args='%#v'", args)
return SystemFunction(env, name, args)
}
func SystemFunction(env *Zlisp, name string, args []Sexp) (Sexp, error) {
if len(args) == 0 {
return SexpNull, WrongNargs
}
flat, err := flattenToWordsHelper(args)
if err != nil {
return SexpNull, fmt.Errorf("flatten on '%#v' failed with error '%s'", args, err)
}
if len(flat) == 0 {
return SexpNull, WrongNargs
}
joined := strings.Join(flat, " ")
cmd := ShellCmd
var out []byte
if runtime.GOOS == "windows" {
out, err = exec.Command(cmd, "/c", joined).CombinedOutput()
} else {
out, err = exec.Command(cmd, "-c", joined).CombinedOutput()
}
if err != nil {
return SexpNull, fmt.Errorf("error from command: '%s'. Output:'%s'", err, string(Chomp(out)))
}
return &SexpStr{S: string(Chomp(out))}, nil
}
// given strings/lists of strings with possible whitespace
// flatten out to a array of SexpStr with no internal whitespace,
// suitable for passing along to (system) / exec.Command()
func FlattenToWordsFunction(env *Zlisp, name string, args []Sexp) (Sexp, error) {
if len(args) == 0 {
return SexpNull, WrongNargs
}
stringArgs, err := flattenToWordsHelper(args)
if err != nil {
return SexpNull, err
}
// Now convert to []Sexp{SexpStr}
res := make([]Sexp, len(stringArgs))
for i := range stringArgs {
res[i] = &SexpStr{S: stringArgs[i]}
}
return env.NewSexpArray(res), nil
}
func flattenToWordsHelper(args []Sexp) ([]string, error) {
stringArgs := []string{}
for i := range args {
switch c := args[i].(type) {
case *SexpStr:
many := strings.Split(c.S, " ")
stringArgs = append(stringArgs, many...)
case *SexpSymbol:
stringArgs = append(stringArgs, c.name)
case *SexpPair:
carry, err := ListToArray(c)
if err != nil {
return []string{}, fmt.Errorf("tried to convert list of strings to array but failed with error '%s'. Input was type %T / val = '%#v'", err, c, c)
}
moreWords, err := flattenToWordsHelper(carry)
if err != nil {
return []string{}, err
}
stringArgs = append(stringArgs, moreWords...)
default:
return []string{}, fmt.Errorf("arguments to system must be strings; instead we have %T / val = '%#v'", c, c)
}
} // end i over args
// INVAR: stringArgs has our flattened list.
return stringArgs, nil
}
func Chomp(by []byte) []byte {
if len(by) > 0 {
n := len(by)
if by[n-1] == '\n' {
return by[:n-1]
}
}
return by
}

111
vendor/github.com/glycerine/zygomys/zygo/time.go generated vendored Normal file
View File

@@ -0,0 +1,111 @@
package zygo
import (
"errors"
"fmt"
"time"
)
var UtcTz *time.Location
var NYC *time.Location
func init() {
var err error
UtcTz, err = time.LoadLocation("UTC")
panicOn(err)
NYC, err = time.LoadLocation("America/New_York")
panicOn(err)
}
type SexpTime struct {
Tm time.Time
}
func (r *SexpTime) Type() *RegisteredType {
return nil // TODO what should this be?
}
func (t *SexpTime) SexpString(ps *PrintState) string {
return t.Tm.String()
}
func NowFunction(env *Zlisp, name string,
args []Sexp) (Sexp, error) {
return &SexpTime{Tm: time.Now()}, nil
}
// string -> time.Time
func AsTmFunction(env *Zlisp, name string,
args []Sexp) (Sexp, error) {
if len(args) != 1 {
return SexpNull, WrongNargs
}
var str *SexpStr
switch t := args[0].(type) {
case *SexpStr:
str = t
default:
return SexpNull,
errors.New("argument of astm should be a string RFC3999Nano timestamp that we want to convert to time.Time")
}
tm, err := time.ParseInLocation(time.RFC3339Nano, str.S, NYC)
if err != nil {
return SexpNull, err
}
return &SexpTime{Tm: tm.In(NYC)}, nil
}
func TimeitFunction(env *Zlisp, name string,
args []Sexp) (Sexp, error) {
if len(args) != 1 {
return SexpNull, WrongNargs
}
var fun *SexpFunction
switch t := args[0].(type) {
case *SexpFunction:
fun = t
default:
return SexpNull,
errors.New("argument of timeit should be function")
}
starttime := time.Now()
elapsed := time.Since(starttime)
maxseconds := 10.0
var iterations int
for iterations = 0; iterations < 10000; iterations++ {
_, err := env.Apply(fun, []Sexp{})
if err != nil {
return SexpNull, err
}
elapsed = time.Since(starttime)
if elapsed.Seconds() > maxseconds {
break
}
}
fmt.Printf("ran %d iterations in %f seconds\n",
iterations, elapsed.Seconds())
fmt.Printf("average %f seconds per run\n",
elapsed.Seconds()/float64(iterations))
return SexpNull, nil
}
func MillisFunction(env *Zlisp, name string,
args []Sexp) (Sexp, error) {
millis := time.Now().UnixNano() / 1000000
return &SexpInt{Val: int64(millis)}, nil
}
func (env *Zlisp) ImportTime() {
env.AddFunction("now", NowFunction)
env.AddFunction("timeit", TimeitFunction)
env.AddFunction("astm", AsTmFunction)
env.AddFunction("millis", MillisFunction)
}

205
vendor/github.com/glycerine/zygomys/zygo/typeutils.go generated vendored Normal file
View File

@@ -0,0 +1,205 @@
package zygo
import (
"fmt"
"reflect"
)
func IsArray(expr Sexp) bool {
switch expr.(type) {
case *SexpArray:
return true
}
return false
}
func IsList(expr Sexp) bool {
if expr == SexpNull {
return true
}
switch list := expr.(type) {
case *SexpPair:
return IsList(list.Tail)
}
return false
}
func IsAssignmentList(expr Sexp, pos int) (bool, int) {
if expr == SexpNull {
return false, -1
}
switch list := expr.(type) {
case *SexpPair:
sym, isSym := list.Head.(*SexpSymbol)
if !isSym {
return IsAssignmentList(list.Tail, pos+1)
}
if sym.name == "=" || sym.name == ":=" {
return true, pos
}
return IsAssignmentList(list.Tail, pos+1)
}
return false, -1
}
func IsFloat(expr Sexp) bool {
switch expr.(type) {
case *SexpFloat:
return true
}
return false
}
func IsInt(expr Sexp) bool {
switch expr.(type) {
case *SexpInt:
return true
}
return false
}
func IsString(expr Sexp) bool {
switch expr.(type) {
case *SexpStr:
return true
}
return false
}
func IsChar(expr Sexp) bool {
switch expr.(type) {
case *SexpChar:
return true
}
return false
}
func IsNumber(expr Sexp) bool {
switch expr.(type) {
case *SexpFloat:
return true
case *SexpInt:
return true
case *SexpChar:
return true
}
return false
}
func IsSymbol(expr Sexp) bool {
switch expr.(type) {
case *SexpSymbol:
return true
}
return false
}
func IsHash(expr Sexp) bool {
switch expr.(type) {
case *SexpHash:
return true
}
return false
}
func IsZero(expr Sexp) bool {
switch e := expr.(type) {
case *SexpInt:
return int(e.Val) == 0
case *SexpChar:
return int(e.Val) == 0
case *SexpFloat:
return float64(e.Val) == 0.0
}
return false
}
func IsEmpty(expr Sexp) bool {
if expr == SexpNull {
return true
}
switch e := expr.(type) {
case *SexpArray:
return len(e.Val) == 0
case *SexpHash:
return HashIsEmpty(e)
}
return false
}
func IsFunc(expr Sexp) bool {
switch expr.(type) {
case *SexpFunction:
return true
}
return false
}
func TypeOf(expr Sexp) *SexpStr {
v := ""
switch e := expr.(type) {
case *SexpRaw:
v = "raw"
case *SexpBool:
v = "bool"
case *SexpArray:
v = "array"
case *SexpInt:
v = "int64"
case *SexpUint64:
v = "uint64"
case *SexpStr:
v = "string"
case *SexpChar:
v = "char"
case *SexpFloat:
v = "float64"
case *SexpHash:
v = e.TypeName
case *SexpPair:
v = "list"
case *SexpSymbol:
v = "symbol"
case *SexpFunction:
v = "func"
case *SexpSentinel:
v = "nil"
case *SexpTime:
v = "time.Time"
case *RegisteredType:
v = "regtype"
case *SexpPointer:
v = e.MyType.RegisteredName
case *SexpArraySelector:
v = "arraySelector"
case *SexpHashSelector:
v = "hashSelector"
case *SexpReflect:
rt := expr.Type()
if rt != nil {
return &SexpStr{S: rt.RegisteredName}
}
//v = reflect.Value(e).Type().Name()
//if v == "Ptr" {
// v = reflect.Value(e).Type().Elem().Kind().String()
//}
kind := reflect.Value(e.Val).Type().Kind()
if kind == reflect.Ptr {
v = reflect.Value(e.Val).Elem().Type().Name()
} else {
P("kind = %v", kind)
v = "reflect.Value"
}
case *Stack:
if e.IsPackage {
v = "package"
} else {
v = "stack"
}
default:
fmt.Printf("\n error: unknown type: %T in '%#v'\n", e, e)
}
return &SexpStr{S: v}
}

11
vendor/github.com/glycerine/zygomys/zygo/version.go generated vendored Normal file
View File

@@ -0,0 +1,11 @@
package zygo
import "fmt"
// version information. See Makefile and gitcommit.go for update/init.
var GITLASTTAG string
var GITLASTCOMMIT string
func Version() string {
return fmt.Sprintf("%s/%s", GITLASTTAG, GITLASTCOMMIT)
}

Some files were not shown because too many files have changed in this diff Show More