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

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)
}

847
vendor/github.com/glycerine/zygomys/zygo/vm.go generated vendored Normal file
View File

@@ -0,0 +1,847 @@
package zygo
import (
"errors"
"fmt"
)
type Instruction interface {
InstrString() string
Execute(env *Zlisp) error
}
type JumpInstr struct {
addpc int
where string
}
var OutOfBounds error = errors.New("jump out of bounds")
func (j JumpInstr) InstrString() string {
return fmt.Sprintf("jump %d %s", j.addpc, j.where)
}
func (j JumpInstr) Execute(env *Zlisp) error {
newpc := env.pc + j.addpc
if newpc < 0 || newpc > env.CurrentFunctionSize() {
return OutOfBounds
}
env.pc = newpc
return nil
}
type GotoInstr struct {
location int
}
func (g GotoInstr) InstrString() string {
return fmt.Sprintf("goto %d", g.location)
}
func (g GotoInstr) Execute(env *Zlisp) error {
if g.location < 0 || g.location > env.CurrentFunctionSize() {
return OutOfBounds
}
env.pc = g.location
return nil
}
type BranchInstr struct {
direction bool
location int
}
func (b BranchInstr) InstrString() string {
var format string
if b.direction {
format = "br %d"
} else {
format = "brn %d"
}
return fmt.Sprintf(format, b.location)
}
func (b BranchInstr) Execute(env *Zlisp) error {
expr, err := env.datastack.PopExpr()
if err != nil {
return err
}
if b.direction == IsTruthy(expr) {
return JumpInstr{addpc: b.location}.Execute(env)
}
env.pc++
return nil
}
type PushInstr struct {
expr Sexp
}
func (p PushInstr) InstrString() string {
return "push " + p.expr.SexpString(nil)
}
func (p PushInstr) Execute(env *Zlisp) error {
env.datastack.PushExpr(p.expr)
env.pc++
return nil
}
type PopInstr int
func (p PopInstr) InstrString() string {
return "pop"
}
func (p PopInstr) Execute(env *Zlisp) error {
_, err := env.datastack.PopExpr()
env.pc++
return err
}
type DupInstr int
func (d DupInstr) InstrString() string {
return "dup"
}
func (d DupInstr) Execute(env *Zlisp) error {
expr, err := env.datastack.GetExpr(0)
if err != nil {
return err
}
env.datastack.PushExpr(expr)
env.pc++
return nil
}
type EnvToStackInstr struct {
sym *SexpSymbol
}
func (g EnvToStackInstr) InstrString() string {
return fmt.Sprintf("envToStack %s", g.sym.name)
}
func (g EnvToStackInstr) Execute(env *Zlisp) error {
VPrintf("in EnvToStackInstr\n")
defer VPrintf("leaving EnvToStackInstr env.pc =%v\n", env.pc)
macxpr, isMacro := env.macros[g.sym.number]
if isMacro {
if macxpr.orig != nil {
return fmt.Errorf("'%s' is a macro, with definition: %s\n", g.sym.name, macxpr.orig.SexpString(nil))
}
return fmt.Errorf("'%s' is a builtin macro.\n", g.sym.name)
}
var expr Sexp
var err error
expr, err, _ = env.LexicalLookupSymbol(g.sym, nil)
if err != nil {
return err
}
env.datastack.PushExpr(expr)
env.pc++
return nil
}
type PopStackPutEnvInstr struct {
sym *SexpSymbol
}
func (p PopStackPutEnvInstr) InstrString() string {
return fmt.Sprintf("popStackPutEnv %s", p.sym.name)
}
func (p PopStackPutEnvInstr) Execute(env *Zlisp) error {
expr, err := env.datastack.PopExpr()
if err != nil {
return err
}
env.pc++
return env.LexicalBindSymbol(p.sym, expr)
}
// Update takes top of datastack and
// assigns it to sym when sym is found
// already in the current scope or
// up the stack. Used
// to implement (set v 10) when v is
// not in the local scope.
//
type UpdateInstr struct {
sym *SexpSymbol
}
func (p UpdateInstr) InstrString() string {
return fmt.Sprintf("putup %s", p.sym.name)
}
func (p UpdateInstr) Execute(env *Zlisp) error {
expr, err := env.datastack.PopExpr()
if err != nil {
return err
}
env.pc++
if p.sym.isSigil {
Q("UpdateInstr: ignoring sigil symbol '%s'", p.sym.SexpString(nil))
return nil
}
if p.sym.isDot {
Q("UpdateInstr: dot symbol '%s' being updated with dotGetSetHelper()",
p.sym.SexpString(nil))
_, err := dotGetSetHelper(env, p.sym.name, &expr)
return err
}
// if found up the stack, we will (set) expr
_, err, _ = env.LexicalLookupSymbol(p.sym, &expr)
if err != nil {
// not found up the stack, so treat like (def)
// instead of (set)
return env.LexicalBindSymbol(p.sym, expr)
}
//return scope.UpdateSymbolInScope(p.sym, expr) // LexicalLookupSymbol now takes a setVal pointer which does this automatically
return err
}
type CallInstr struct {
sym *SexpSymbol
nargs int
}
func (c CallInstr) InstrString() string {
return fmt.Sprintf("call %s %d", c.sym.name, c.nargs)
}
func (c CallInstr) Execute(env *Zlisp) error {
f, ok := env.builtins[c.sym.number]
if ok {
_, err := env.CallUserFunction(f, c.sym.name, c.nargs)
return err
}
var funcobj, indirectFuncName Sexp
var err error
funcobj, err, _ = env.LexicalLookupSymbol(c.sym, nil)
if err != nil {
return err
}
//P("\n in CallInstr, after looking up c.sym='%s', got funcobj='%v'. datastack is:\n", c.sym.name, funcobj.SexpString(nil))
//env.datastack.PrintStack()
switch f := funcobj.(type) {
case *SexpSymbol:
// is it a dot-symbol call?
//P("\n in CallInstr, found symbol\n")
if c.sym.isDot {
//P("\n in CallInstr, found symbol, c.sym.isDot is true\n")
dotSymRef, dotLookupErr := dotGetSetHelper(env, c.sym.name, nil)
// cannot error out yet, we might be assigning to a new field,
// not already set.
if dotLookupErr != nil {
return dotLookupErr
}
// are we a value request (no further args), or a fuction/method call?
//P("\n in CallInstr, found dot-symbol\n")
// now always be a function call here, allowing zero-argument calls.
indirectFuncName = dotSymRef
} else {
// not isDot
// allow symbols to refer to dot-symbols, that then we call
indirectFuncName, err = dotGetSetHelper(env, f.name, nil)
if err != nil {
return fmt.Errorf("'%s' refers to symbol '%s', but '%s' could not be resolved: '%s'.",
c.sym.name, f.name, f.name, err)
}
// allow symbols to refer to functions that we then call
/*
indirectFuncName, err, _ = env.LexicalLookupSymbol(f, nil)
if err != nil {
return fmt.Errorf("'%s' refers to symbol '%s', but '%s' could not be resolved: '%s'.",
c.sym.name, f.name, f.name, err)
}
*/
//P("\n in CallInstr, found symbol, c.sym.isDot is false. f of type %T/val = %v. indirectFuncName = '%v'\n", f, f.SexpString(nil), indirectFuncName.SexpString(nil))
}
//P("in CallInstr, reached switch on indirectFuncName.(type)")
switch g := indirectFuncName.(type) {
case *SexpFunction:
if !g.user {
return env.CallFunction(g, c.nargs)
}
_, err := env.CallUserFunction(g, f.name, c.nargs)
return err
default:
if err != nil {
return fmt.Errorf("symbol '%s' refers to '%s' which does not refer to a function.", c.sym.name, f.name)
}
}
case *SexpFunction:
if !f.user {
return env.CallFunction(f, c.nargs)
}
_, err := env.CallUserFunction(f, c.sym.name, c.nargs)
return err
case *RegisteredType:
if f.Constructor == nil {
env.pc++
res, err := baseConstruct(env, f, c.nargs)
if err != nil {
return err
}
env.datastack.PushExpr(res)
return nil
}
//P("call instruction for RegisteredType!")
_, err := env.CallUserFunction(f.Constructor, c.sym.name, c.nargs)
return err
}
return fmt.Errorf("%s is not a function", c.sym.name)
}
type DispatchInstr struct {
nargs int
}
func (d DispatchInstr) InstrString() string {
return fmt.Sprintf("dispatch %d", d.nargs)
}
func (d DispatchInstr) Execute(env *Zlisp) error {
funcobj, err := env.datastack.PopExpr()
if err != nil {
return err
}
switch f := funcobj.(type) {
case *SexpFunction:
if !f.user {
return env.CallFunction(f, d.nargs)
}
_, err := env.CallUserFunction(f, f.name, d.nargs)
return err
}
// allow ([] int64) to express slice of int64.
switch arr := funcobj.(type) {
case *SexpArray:
if len(arr.Val) == 0 {
_, err := env.CallUserFunction(sxSliceOf, funcobj.SexpString(nil), d.nargs)
return err
}
// call along with the array as an argument so we know the size of the
// array / matrix / tensor to make. The 2nd argument will be the dimension array.
env.datastack.PushExpr(arr)
_, err := env.CallUserFunction(sxArrayOf, funcobj.SexpString(nil), d.nargs+1)
return err
}
return fmt.Errorf("unbalanced parenthesis in the input? : not a function on top of datastack: '%T/%#v'", funcobj, funcobj)
}
type ReturnInstr struct {
err error
}
func (r ReturnInstr) Execute(env *Zlisp) error {
if r.err != nil {
return r.err
}
return env.ReturnFromFunction()
}
func (r ReturnInstr) InstrString() string {
if r.err == nil {
return "ret"
}
return "ret \"" + r.err.Error() + "\""
}
type AddScopeInstr struct {
Name string
}
func (a AddScopeInstr) InstrString() string {
return "add scope " + a.Name
}
func (a AddScopeInstr) Execute(env *Zlisp) error {
sc := env.NewNamedScope(fmt.Sprintf("scope Name: '%s'",
a.Name))
env.linearstack.Push(sc)
env.pc++
return nil
}
type AddFuncScopeInstr struct {
Name string
Helper *AddFuncScopeHelper // we need a pointer we can update later once we know MyFunction
}
type AddFuncScopeHelper struct {
MyFunction *SexpFunction
}
func (a AddFuncScopeInstr) InstrString() string {
return "add func scope " + a.Name
}
func (a AddFuncScopeInstr) Execute(env *Zlisp) error {
sc := env.NewNamedScope(fmt.Sprintf("%s at pc=%v",
env.curfunc.name, env.pc))
sc.IsFunction = true
sc.MyFunction = a.Helper.MyFunction
env.linearstack.Push(sc)
env.pc++
return nil
}
type RemoveScopeInstr struct{}
func (a RemoveScopeInstr) InstrString() string {
return "rem runtime scope"
}
func (a RemoveScopeInstr) Execute(env *Zlisp) error {
env.pc++
return env.linearstack.PopScope()
}
type ExplodeInstr int
func (e ExplodeInstr) InstrString() string {
return "explode"
}
func (e ExplodeInstr) Execute(env *Zlisp) error {
expr, err := env.datastack.PopExpr()
if err != nil {
return err
}
arr, err := ListToArray(expr)
if err != nil {
return err
}
for _, val := range arr {
env.datastack.PushExpr(val)
}
env.pc++
return nil
}
type SquashInstr int
func (s SquashInstr) InstrString() string {
return "squash"
}
func (s SquashInstr) Execute(env *Zlisp) error {
var list Sexp = SexpNull
for {
expr, err := env.datastack.PopExpr()
if err != nil {
return err
}
if expr == SexpMarker {
break
}
list = Cons(expr, list)
}
env.datastack.PushExpr(list)
env.pc++
return nil
}
// bind these symbols to the SexpPair list found at
// datastack top.
type BindlistInstr struct {
syms []*SexpSymbol
}
func (b BindlistInstr) InstrString() string {
joined := ""
for _, s := range b.syms {
joined += s.name + " "
}
return fmt.Sprintf("bindlist %s", joined)
}
func (b BindlistInstr) Execute(env *Zlisp) error {
expr, err := env.datastack.PopExpr()
if err != nil {
return err
}
arr, err := ListToArray(expr)
if err != nil {
return err
}
nsym := len(b.syms)
narr := len(arr)
if narr < nsym {
return fmt.Errorf("bindlist failing: %d targets but only %d sources", nsym, narr)
}
for i, bindThisSym := range b.syms {
env.LexicalBindSymbol(bindThisSym, arr[i])
}
env.pc++
return nil
}
type VectorizeInstr int
func (s VectorizeInstr) InstrString() string {
return fmt.Sprintf("vectorize %v", int(s))
}
func (s VectorizeInstr) Execute(env *Zlisp) error {
vec := make([]Sexp, 0)
env.pc++
for {
expr, err := env.datastack.PopExpr()
if err != nil {
return err
}
if expr == SexpMarker {
break
}
vec = append([]Sexp{expr}, vec...)
}
env.datastack.PushExpr(&SexpArray{Val: vec, Env: env})
return nil
}
type HashizeInstr struct {
HashLen int
TypeName string
}
func (s HashizeInstr) InstrString() string {
return "hashize"
}
func (s HashizeInstr) Execute(env *Zlisp) error {
a := make([]Sexp, 0)
for {
expr, err := env.datastack.PopExpr()
if err != nil {
return err
}
if expr == SexpMarker {
break
}
a = append(a, expr)
}
hash, err := MakeHash(a, s.TypeName, env)
if err != nil {
return err
}
env.datastack.PushExpr(hash)
env.pc++
return nil
}
type LabelInstr struct {
label string
}
func (s LabelInstr) InstrString() string {
return fmt.Sprintf("label %s", s.label)
}
func (s LabelInstr) Execute(env *Zlisp) error {
env.pc++
return nil
}
type BreakInstr struct {
loop *Loop
pos int
}
func (s BreakInstr) InstrString() string {
if s.pos == 0 {
return fmt.Sprintf("break %s", s.loop.stmtname.name)
}
return fmt.Sprintf("break %s (loop is at %d)", s.loop.stmtname.name, s.pos)
}
func (s *BreakInstr) Execute(env *Zlisp) error {
if s.pos == 0 {
pos, err := env.FindLoop(s.loop)
if err != nil {
return err
}
s.pos = pos
}
env.pc = s.pos + s.loop.breakOffset
return nil
}
type ContinueInstr struct {
loop *Loop
pos int
}
func (s ContinueInstr) InstrString() string {
if s.pos == 0 {
return fmt.Sprintf("continue %s", s.loop.stmtname.name)
}
return fmt.Sprintf("continue %s (loop is at pos %d)", s.loop.stmtname.name, s.pos)
}
func (s *ContinueInstr) Execute(env *Zlisp) error {
VPrintf("\n executing ContinueInstr with loop: '%#v'\n", s.loop)
if s.pos == 0 {
pos, err := env.FindLoop(s.loop)
if err != nil {
return err
}
s.pos = pos
}
env.pc = s.pos + s.loop.continueOffset
VPrintf("\n more detail ContinueInstr pos=%d, setting pc = %d\n", s.pos, env.pc)
return nil
}
type LoopStartInstr struct {
loop *Loop
}
func (s LoopStartInstr) InstrString() string {
return fmt.Sprintf("loopstart %s", s.loop.stmtname.name)
}
func (s LoopStartInstr) Execute(env *Zlisp) error {
env.pc++
return nil
}
// stack cleanup discipline instructions let us
// ensure the stack gets reset to a previous
// known good level. The sym designates
// how far down to clean up, in a unique and
// distinguishable gensym-ed manner.
// create a stack mark
type PushStackmarkInstr struct {
sym *SexpSymbol
}
func (s PushStackmarkInstr) InstrString() string {
return fmt.Sprintf("push-stack-mark %s", s.sym.name)
}
func (s PushStackmarkInstr) Execute(env *Zlisp) error {
env.datastack.PushExpr(&SexpStackmark{sym: s.sym})
env.pc++
return nil
}
// cleanup until our stackmark, but leave it in place
type PopUntilStackmarkInstr struct {
sym *SexpSymbol
}
func (s PopUntilStackmarkInstr) InstrString() string {
return fmt.Sprintf("pop-until-stack-mark %s", s.sym.name)
}
func (s PopUntilStackmarkInstr) Execute(env *Zlisp) error {
env.pc++
toploop:
for {
expr, err := env.datastack.PopExpr()
if err != nil {
P("alert: did not find SexpStackmark '%s'", s.sym.name)
return err
}
switch m := expr.(type) {
case *SexpStackmark:
if m.sym.number == s.sym.number {
env.datastack.PushExpr(m)
break toploop
}
}
}
return nil
}
// erase everything up-to-and-including our mark
type ClearStackmarkInstr struct {
sym *SexpSymbol
}
func (s ClearStackmarkInstr) InstrString() string {
return fmt.Sprintf("clear-stack-mark %s", s.sym.name)
}
func (s ClearStackmarkInstr) Execute(env *Zlisp) error {
toploop:
for {
expr, err := env.datastack.PopExpr()
if err != nil {
return err
}
switch m := expr.(type) {
case *SexpStackmark:
if m.sym.number == s.sym.number {
break toploop
}
}
}
env.pc++
return nil
}
type DebugInstr struct {
diagnostic string
}
func (g DebugInstr) InstrString() string {
return fmt.Sprintf("debug %s", g.diagnostic)
}
func (g DebugInstr) Execute(env *Zlisp) error {
switch g.diagnostic {
case "showScopes":
err := env.ShowStackStackAndScopeStack()
if err != nil {
return err
}
default:
panic(fmt.Errorf("unknown diagnostic %v", g.diagnostic))
}
env.pc++
return nil
}
// when a defn or fn executes, capture the creation env.
type CreateClosureInstr struct {
sfun *SexpFunction
}
func (a CreateClosureInstr) InstrString() string {
return "create closure " + a.sfun.SexpString(nil)
}
func (a CreateClosureInstr) Execute(env *Zlisp) error {
env.pc++
cls := NewClosing(a.sfun.name, env)
myInvok := a.sfun.Copy()
myInvok.SetClosing(cls)
if env.curfunc != nil {
a.sfun.parent = env.curfunc
myInvok.parent = env.curfunc
//P("myInvok is copy of a.sfun '%s' with parent = %s", a.sfun.name, myInvok.parent.name)
}
ps8 := NewPrintStateWithIndent(8)
shown, err := myInvok.ShowClosing(env, ps8,
fmt.Sprintf("closedOverScopes of '%s'", myInvok.name))
if err != nil {
return err
}
VPrintf("+++ CreateClosure: assign to '%s' the stack:\n\n%s\n\n",
myInvok.SexpString(nil), shown)
top := cls.TopScope()
VPrintf("222 CreateClosure: top of NewClosing Scope has addr %p and is\n",
top)
top.Show(env, ps8, fmt.Sprintf("top of NewClosing at %p", top))
env.datastack.PushExpr(myInvok)
return nil
}
type AssignInstr struct {
}
func (a AssignInstr) InstrString() string {
return "assign stack top to stack top -1"
}
func (a AssignInstr) Execute(env *Zlisp) error {
env.pc++
rhs, err := env.datastack.PopExpr()
if err != nil {
return err
}
lhs, err := env.datastack.PopExpr()
if err != nil {
return err
}
switch x := lhs.(type) {
case *SexpSymbol:
return env.LexicalBindSymbol(x, rhs)
case Selector:
Q("AssignInstr: I see lhs is Selector")
err := x.AssignToSelection(env, rhs)
return err
case *SexpArray:
switch rhsArray := rhs.(type) {
case *SexpArray:
//Q("AssignInstr: lhs is SexpArray '%v', *and* rhs is SexpArray ='%v'",
// x.SexpString(nil), rhsArray.SexpString(nil))
nRhs := len(rhsArray.Val)
nLhs := len(x.Val)
if nRhs != nLhs {
return fmt.Errorf("assignment count mismatch %v != %v", nLhs, nRhs)
}
for i := range x.Val {
switch sym := x.Val[i].(type) {
case *SexpSymbol:
err = env.LexicalBindSymbol(sym, rhsArray.Val[i])
if err != nil {
return err
}
default:
return fmt.Errorf("assignment error: left-hand-side element %v needs to be a symbol but"+
" we found %T", i, x.Val[i])
}
}
return nil
default:
return fmt.Errorf("AssignInstr: don't know how to assign rhs %T `%v` to lhs %T `%v`",
rhs, rhs.SexpString(nil), lhs, lhs.SexpString(nil))
}
}
return fmt.Errorf("AssignInstr: don't know how to assign to lhs %T", lhs)
}
// PopScopeTransferToDataStackInstr is used to wrap up a package
// and put it on the data stack as a value.
type PopScopeTransferToDataStackInstr struct {
PackageName string
}
func (a PopScopeTransferToDataStackInstr) InstrString() string {
return "pop scope transfer to data stack as package " + a.PackageName
}
func (a PopScopeTransferToDataStackInstr) Execute(env *Zlisp) error {
env.pc++
stackClone := env.linearstack.Clone()
stackClone.IsPackage = true // always/only used for packages.
stackClone.PackageName = a.PackageName
//P("PopScopeTransferToDataStackInstr: scope is '%v'", stackClone.SexpString(nil))
env.linearstack.PopScope()
env.datastack.PushExpr(stackClone)
return nil
}

42
vendor/github.com/glycerine/zygomys/zygo/vprint.go generated vendored Normal file
View File

@@ -0,0 +1,42 @@
package zygo
import (
"fmt"
"time"
)
var Verbose bool // set to true to debug
var Working bool // currently under investigation
var V = VPrintf
var W = WPrintf
var Q = func(quietly_ignored ...interface{}) {} // quiet
// P is a shortcut for a call to fmt.Printf that implicitly starts
// and ends its message with a newline.
func P(format string, stuff ...interface{}) {
fmt.Printf("\n "+format+"\n", stuff...)
}
// get timestamp for logging purposes
func ts() string {
return time.Now().Format("2006-01-02 15:04:05.999 -0700 MST")
}
// time-stamped printf
func TSPrintf(format string, a ...interface{}) {
fmt.Printf("%s ", ts())
fmt.Printf(format, a...)
}
func VPrintf(format string, a ...interface{}) {
if Verbose {
TSPrintf(format, a...)
}
}
func WPrintf(format string, a ...interface{}) {
if Working {
TSPrintf(format, a...)
}
}