package selsl import "fmt" type Slots map[string]Object func (s Slots) Set(name string, inst Object) Slots { s[name] = inst return s } func (s Slots) Get(name string) Object { res, ok := s[name] if !ok { return Nil } return res } /* func (s Slots) Clone() Slots { clone := Slots{} for k, v := range s { clone[k] = v.Clone() } return clone } */ // Constants for special object slot names const ( ParentSlot = "*parent" SelfSlot = "*self" MeSlot = "*me" ArgsSlot = "*args" ) // IsReturner is a marker interface for types that cause // a return. type IsReturner interface{ IsReturn() } // Breaker is a marker interface for a type that cases // a break in flow. type IsBreaker interface{ IsBreak() } // A Thrower is a marker interface for a type that causes // a throw. type IsThrower interface{ IsThrow() } // Type is the type of an object. It is simply a string. type Type string // A message can be send to an object. It is also an object. type Message struct { Name string Args []Object Env Object Actor } func (m Message) String() string { return "message: " + m.Name } func (Message) Type() Type { return Type("message") } func (m Message) Value(env Object) Object { return m } func (m Message) Send(Message) Object { return m } // Object is the interface for all objects in SELSL. type Object interface { // String stringifies the value of the object. String() string // Type returns the name of the type in lower case. Type() Type // Value evaluates the object in a context. Value(env Object) Object // Send sends a message to the object. Send(msg Message) Object } type NilObject struct{} func (NilObject) String() string { return "nil" } func (NilObject) Value(env Object) Object { return nil } func (NilObject) Type() Type { return Type("nil") } func (NilObject) Send(Message) Object { return Nil } var Nil Object = NilObject{} func ParentOf(val Object) Object { return val.Send(Message{Name: ParentSlot}) } /* type Environment struct { Instance } func NewEnvironment(parent, me, to Object, args ...Object) *Environment { name := "_env" if parent != nil { name = parent.Name() + "_env" } res := &Environment{Instance{name: name, slots: Slots{}}} res.Set(ParentSlot, parent) res.Set(SelfSlot, to) res.Set(ArgsSlot, List(args)) res.Set(MeSlot, me) return res } func SendInEnv(to Object, message string, env Object) Object { lookup := to value := lookup.Slots().Get(message) for value == Nil { lookup = ParentOf(lookup) if lookup == Nil || lookup == nil { panic("Object does not support message " + message) } value = lookup.Slots().Get(message) } return value.Value(env) } func Send(to Object, message string, me, here Object, args ...Object) Object { env := NewEnvironment(here, me, to, args...) return SendInEnv(to, message, env) } */ // Instance is a concrete implementation of Object // which can be embedded into Go structs to help them // become Objects themselves. type Instance struct { // the type of the instance, used in Type() kind Type // Slots, used to store members slots Slots } // String stringifies the value of the instance. func (i Instance) String() string { res := string(i.kind) + " { " for k, v := range i.slots { res += "\n" + k + ":" + v.String() } res += " } " return res } func (i Instance) Type() Type { return Type(i.kind) } func (i Instance) Value(env Object) Object { return i } func (i Instance) Send(message Message) Object { value := i.slots.Get(message.Name) if value == nil || value == Nil { // XXX should return an error in stead. return Nil } return value.Value(message.Env) } func (i *Instance) Set(name string, inst Object) *Instance { i.slots.Set(name, inst) return i } func NewInstance(kind string) *Instance { return &Instance{kind: Type(kind), slots: Slots{}} } // A primitive is a function implemented in Go that // on evaluation as an Object calls that function // with the given environment type Primitive func(env Object) Object func (p Primitive) Type() Type { return Type("primitive") } func (p Primitive) Send(m Message) Object { return p.Value(m) } func (p Primitive) Value(env Object) Object { return p(env) } func Self(o Object) Object { return o.Send(Message{Name: SelfSlot}) } func Me(o Object) Object { return o.Send(Message{Name: MeSlot}) } func Args(o Object) List { list := o.Send(Message{Name: ArgsSlot}) if list == Nil { return List{} } return list.(List) } func Unary(unary func(target Object) Object) Primitive { return func(env Object) Object { return unary(Self(env)) } } func Nullary(nullary func() Object) Primitive { return func(env Object) Object { return nullary() } } type String string func (s String) String() string { return string(s) } func (s String) Type() Type { return Type("string") } func (p String) Send(m Message) Object { // XXX implement string methods here return Nil } func (s String) Value(env Object) Object { return s } type List []Object func (l List) Type() Type { return Type("list") } func (l List) String() string { res := fmt.Sprintf("list: ") sep := "" for _, o := range l { res = fmt.Sprintf("%s %s %s", res, sep, o.String()) sep = "and" } res += ";" return res } func (l List) Send(m Message) Object { // XXX implement list methods here return Nil } func (l List) Value(env Object) Object { return l } type Error struct { *Instance Error error } func (e Error) String() string { return fmt.Sprintf("error `%s`", e.Error) } func (e Error) Value(env Object) Object { return e } func NewErrorBasic(err error) Error { return Error{Instance: NewInstance("error"), Error: err} } func NewError(err string) Error { return NewErrorBasic(fmt.Errorf("%s", err)) } type Int struct { *Instance Int int64 } func NewInt(i int64) Int { return Int{Instance: NewInstance("int"), Int: i} } func (i Int) String() string { return fmt.Sprintf("%d", i.Int) } func (i Int) Value(env Object) Object { return i } type Statement struct { *Instance Command Object Param List } func (s Statement) String() string { return fmt.Sprintf("%s %s.", s.Command.String(), s.Param.String()) } /* func (s Statement) Value(env Object) Object { cenv := env cenv.Slots().Set(ArgsSlot, s.Param) return SendInEnv(env, s.Command.Name(), cenv) }*/ var _ Object = Error{} var _ Object = String("") var _ Object = Int{} var _ Object = List{}