Browse Source

Move to a SELF like object model.

Beoran 2 years ago
parent
commit
4eda761cb6
5 changed files with 358 additions and 176 deletions
  1. 1 1
      README
  2. 323 0
      selsl/object.go
  3. 34 0
      selsl/object_test.go
  4. 0 164
      selsl/value.go
  5. 0 11
      selsl/value_test.go

+ 1 - 1
README

@@ -74,7 +74,7 @@ Set hp of me as add 1 with divide hp of me by 2 end end
 
 Create a red door as a door.
 
-open red door
+open red door with green key
 
 cast cure light at smart bob
 

+ 323 - 0
selsl/object.go

@@ -0,0 +1,323 @@
+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) 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"
+)
+
+// Effect is the effect an object has on return from a Run
+type Effect int
+
+// Constants for effects
+const (
+	EffectNone   Effect = 0
+	EffectBreak  Effect = 1
+	EffectReturn Effect = 2
+	EffectThrow  Effect = 4
+)
+
+// Object is the interface for all objects in SELSL.
+type Object interface {
+	Name() string
+	Slots() Slots
+	Run(env Object) Object
+	Effect() Effect
+	Clone() Object
+}
+
+var Nil Object = NewInstance("nil")
+
+func ParentOf(val Object) Object {
+	res, ok := val.Slots()[ParentSlot]
+	if ok {
+		return res
+	}
+	return Nil
+}
+
+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 Send(to Object, message string, me, here Object, args ...Object) Object {
+	env := NewEnvironment(here, me, to, args...)
+	lookup := to
+	value, ok := lookup.Slots()[message]
+	for !ok || value == nil {
+		lookup = ParentOf(lookup)
+		if lookup == Nil || lookup == nil {
+			panic("Object does not support message " + message)
+		}
+		value, ok = lookup.Slots()[message]
+	}
+	return value.Run(env)
+}
+
+type Instance struct {
+	name  string
+	slots Slots
+}
+
+func (i Instance) Name() string {
+	return i.name
+}
+
+func (i Instance) Slots() Slots {
+	return i.slots
+}
+
+func (i Instance) Effect() Effect {
+	return EffectNone
+}
+
+func (i Instance) Run(env Object) Object {
+	return i
+}
+
+func (i *Instance) Set(name string, inst Object) *Instance {
+	i.slots.Set(name, inst)
+	return i
+}
+
+func (i Instance) DeepCopy() Instance {
+	return Instance{name: i.name + "", slots: i.slots.Clone()}
+}
+
+func (i Instance) Clone() Object {
+	return i.DeepCopy()
+}
+
+func NewInstance(name string) *Instance {
+	return &Instance{name: name, slots: Slots{}}
+}
+
+type Primitive func(env Object) Object
+
+func (p Primitive) Name() string {
+	return "primitive"
+}
+
+func (p Primitive) Slots() Slots {
+	emptySlots := Slots{}
+	return emptySlots
+}
+
+func (p Primitive) Effect() Effect {
+	return EffectNone
+}
+
+func (p Primitive) Run(env Object) Object {
+	return p(env)
+}
+
+func (p Primitive) Clone() Object {
+	return p
+}
+
+func Self(o Object) Object {
+	return o.Slots()[SelfSlot]
+}
+
+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) Name() string {
+	return string(s)
+}
+
+var StringType Object = NewInstance("String").
+	Set(ParentSlot, RootType)
+
+var StringSlots Slots = Slots{}.Set(ParentSlot, StringType)
+
+func (s String) Slots() Slots {
+	return StringSlots
+}
+
+func (s String) Effect() Effect {
+	return EffectNone
+}
+
+func (s String) Run(env Object) Object {
+	return s
+}
+
+func (s String) Clone() Object {
+	return String(s + "")
+}
+
+func NameOf(o Object) Object {
+	return String(o.Name())
+}
+
+func NameString(o Object) func() Object {
+	return func() Object {
+		return NameOf(o)
+	}
+}
+
+var RootType Object = NewInstance("Type").Set("name", Unary(NameOf))
+
+type List []Object
+
+func (l List) Name() string {
+	res := fmt.Sprintf("list: ")
+	sep := ""
+	for _, o := range l {
+		res = fmt.Sprintf("%s %s %s", res, sep, o.Name())
+		sep = "and"
+	}
+	res += ";"
+	return res
+}
+
+var ListType Object = NewInstance("List").
+	Set(ParentSlot, RootType)
+
+var ListSlots Slots = Slots{}.Set(ParentSlot, ListType)
+
+func (l List) Slots() Slots {
+	return ListSlots
+}
+
+func (l List) Effect() Effect {
+	return EffectNone
+}
+
+func (l List) Run(env Object) Object {
+	return l
+}
+
+func (l List) DeepCopy() List {
+	res := List{}
+	for _, o := range l {
+		res = append(res, o.Clone())
+	}
+	return res
+}
+
+func (l List) Clone() Object {
+	return l.DeepCopy()
+}
+
+/*
+var RootType Object = NewInstance("Type").Slot("string")
+var InstanceType Type = NewType("Instance", &RootType, nil)
+var ErrorType Type = NewType("Error", &InstanceType, nil)
+var StringType Type = NewType("String", &InstanceType, nil)
+var IntType Type = NewType("Int", &InstanceType, nil)
+var ListType Type = NewType("List", &InstanceType, nil)
+var MethodType Type = NewType("Method", &InstanceType, nil)
+
+
+type Error struct {
+	Instance
+	Object error
+}
+
+func (s Error) String() string {
+	return fmt.Sprintf("%s", s.Object)
+}
+
+func NewError(name string, Slots Slots, Object error) Error {
+	return Error{Instance: NewInstance(name, ErrorType, Slots),
+		Object: Object}
+}
+
+
+type Int struct {
+	Instance
+	Object int64
+}
+
+func NewInt(name string, Slots Slots, Object int64) Int {
+	return Int{Instance: NewInstance(name, IntType, Slots),
+		Object: Object}
+}
+
+func (i Int) String() string {
+	return fmt.Sprintf("%d", i.Object)
+}
+
+type List struct {
+	Instance
+	Object []Object
+}
+
+func NewList(name string, Slots Slots, Object ...Object) List {
+	return List{Instance: NewInstance(name, ListType, Slots),
+		Object: Object}
+}
+
+func (l List) String() string {
+	return fmt.Sprintf("[%v]", l.Object)
+}
+
+type Method struct {
+	Instance
+	Signature List
+	Object    func(env Object, self Object, args ...Object) List
+}
+
+func NewMethod(name string, Slots Slots, signature List,
+	Object func(env Object, self Object, args ...Object) List) Method {
+	return Method{Instance: NewInstance(name, MethodType, Slots),
+		Signature: signature, Object: Object}
+}
+
+func (m Method) String() string {
+	return fmt.Sprintf("Method: %s", m.Name())
+}
+
+var _ Object = RootType
+var _ Object = InstanceType
+var _ Object = Error{}
+var _ Object = String{}
+var _ Object = Int{}
+var _ Object = List{}
+var _ Object = Method{}
+*/

+ 34 - 0
selsl/object_test.go

@@ -0,0 +1,34 @@
+package selsl
+
+import "testing"
+
+func TestRootType(t *testing.T) {
+	name := Send(RootType, "name", nil, nil)
+	nameString := string(name.(String))
+	if nameString != "Type" {
+		t.Errorf("Root type name wrong: %v", name)
+	}
+	t.Logf("Name root type: %s", nameString)
+}
+
+func TestStringType(t *testing.T) {
+	raw := "banana"
+	str := String(raw)
+	name := Send(str, "name", nil, nil)
+	nameString := string(name.(String))
+	if nameString != raw {
+		t.Errorf("String type name wrong: %v", name)
+	}
+	t.Logf("Name string type: %s", nameString)
+}
+
+func TestListType(t *testing.T) {
+	raw := [ "apple", "banana", "pear" ]
+	list :=  List{ String(raw[0]),
+				String(raw[1]),
+				String(raw[2]) }
+	clone := list.Clone()
+	clone[1] = String("cumquat")
+
+}
+

+ 0 - 164
selsl/value.go

@@ -1,164 +0,0 @@
-package selsl
-
-import "fmt"
-
-type Members map[string][]Value
-
-type Value interface {
-	Name() string
-	// Proto/type of the value.
-	Type() Type
-	String() string
-	Members() Members
-}
-
-// A type is modeled by it's name as a string
-type Type struct {
-	name    string
-	meta    *Type // type of the type
-	members Members
-}
-
-func (t Type) String() string {
-	return fmt.Sprintf(":type %s;", t.name)
-}
-
-func (t Type) Name() string {
-	return t.name
-}
-
-func (t Type) Members() Members {
-	return t.members
-}
-
-// Type returns the metatype of a type.
-func (t Type) Type() Type {
-	// turtles all the way down.
-	if t.meta == nil || t.meta.meta == nil {
-		return RootType
-	}
-	return *t.meta
-}
-
-func (t Type) Match(v Value) bool {
-	t2 := v.Type()
-	return t.Name() == t2.Name()
-}
-
-func NewType(name string, meta *Type, members Members) Type {
-	return Type{name: name, meta: meta, members: members}
-}
-
-var RootType Type = NewType("Type", nil, nil)
-var ObjectType Type = NewType("Object", &RootType, nil)
-var ErrorType Type = NewType("Error", &ObjectType, nil)
-var StringType Type = NewType("String", &ObjectType, nil)
-var IntType Type = NewType("Int", &ObjectType, nil)
-var ListType Type = NewType("List", &ObjectType, nil)
-var MethodType Type = NewType("Method", &ObjectType, nil)
-
-type Object struct {
-	name    string
-	typ     Type
-	members Members
-}
-
-func (o Object) String() string {
-	return fmt.Sprintf("%s: %s", o.typ, o.name)
-}
-
-func (o Object) Name() string {
-	return o.name
-}
-
-func (o Object) Members() Members {
-	return o.members
-}
-
-func (o Object) Type() Type {
-	return o.typ
-}
-
-func NewObject(name string, typ Type, members Members) Object {
-	return Object{name: name, typ: typ, members: members}
-}
-
-type Error struct {
-	Object
-	Value error
-}
-
-func (s Error) String() string {
-	return fmt.Sprintf("%s", s.Value)
-}
-
-func NewError(name string, members Members, value error) Error {
-	return Error{Object: NewObject(name, ErrorType, members),
-		Value: value}
-}
-
-type String struct {
-	Object
-	Value string
-}
-
-func (s String) String() string {
-	return s.Value
-}
-
-func NewString(name string, members Members, value string) String {
-	return String{Object: NewObject(name, StringType, members),
-		Value: value}
-}
-
-type Int struct {
-	Object
-	Value int64
-}
-
-func NewInt(name string, members Members, value int64) Int {
-	return Int{Object: NewObject(name, IntType, members),
-		Value: value}
-}
-
-func (i Int) String() string {
-	return fmt.Sprintf("%d", i.Value)
-}
-
-type List struct {
-	Object
-	Value []Value
-}
-
-func NewList(name string, members Members, value ...Value) List {
-	return List{Object: NewObject(name, ListType, members),
-		Value: value}
-}
-
-func (l List) String() string {
-	return fmt.Sprintf("[%v]", l.Value)
-}
-
-type Method struct {
-	Object
-	Signature List
-	Value     func(env Value, self Value, args ...Value) List
-}
-
-func NewMethod(name string, members Members, signature List,
-	value func(env Value, self Value, args ...Value) List) Method {
-	return Method{Object: NewObject(name, MethodType, members),
-		Signature: signature, Value: value}
-}
-
-func (m Method) String() string {
-	return fmt.Sprintf("Method: %s", m.Name())
-}
-
-var _ Value = RootType
-var _ Value = ObjectType
-var _ Value = Error{}
-var _ Value = String{}
-var _ Value = Int{}
-var _ Value = List{}
-var _ Value = Method{}

+ 0 - 11
selsl/value_test.go

@@ -1,11 +0,0 @@
-package selsl
-
-import "testing"
-
-func TestRootType(t *testing.T) {
-	meta := RootType.Type()
-	if meta.Name() != "Type" {
-		t.Errorf("Root type not rooted: %v", meta.Name())
-	}
-	t.Logf("Root of root type: %s", meta)
-}