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 }