Skip to content

Commit

Permalink
assignment operators seem to work; arithmetic operators sometimes work
Browse files Browse the repository at this point in the history
  • Loading branch information
zephyrtronium committed Sep 28, 2018
1 parent 44644fc commit eb01e30
Show file tree
Hide file tree
Showing 9 changed files with 629 additions and 176 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2014 Branden J Brown
Copyright (c) 2014, 2018 Branden J Brown

This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.

Expand Down
1 change: 0 additions & 1 deletion control.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ type StopStatus int

const (
// I have resisted the urge to name this DontStopBelieving.
// Unfortunately, I have just realized it is now a rape joke.
NoStop StopStatus = iota
ReturnStop
BreakStop
Expand Down
2 changes: 1 addition & 1 deletion io/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (

func main() {
vm := iolang.NewVM()
// iolang.Debugvm = vm
iolang.Debugvm = vm
iolang.SetSlot(vm.Lobby, "ps1", vm.NewString("io> "))
iolang.SetSlot(vm.Lobby, "ps2", vm.NewString("... "))
iolang.SetSlot(vm.Lobby, "isRunning", vm.True)
Expand Down
130 changes: 94 additions & 36 deletions message.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,34 @@ const (
StringSym
)

// IdentMessage creates a message of a given identifier. Additional messages
// may be passed as arguments.
func (vm *VM) IdentMessage(s string, args ...*Message) *Message {
return &Message{
Object: Object{Slots: vm.DefaultSlots["Message"], Protos: []Interface{vm.BaseObject}},
Symbol: Symbol{Kind: IdentSym, Text: s},
Args: args,
}
}

// StringMessage creates message carrying a string value.
func (vm *VM) StringMessage(s string) *Message {
return &Message{
Object: Object{Slots: vm.DefaultSlots["Message"], Protos: []Interface{vm.BaseObject}},
Symbol: Symbol{Kind: StringSym, String: s},
Memo: vm.NewString(s),
}
}

// NumberMessage creates a message carrying a numeric value.
func (vm *VM) NumberMessage(v float64) *Message {
return &Message{
Object: Object{Slots: vm.DefaultSlots["Message"], Protos: []Interface{vm.BaseObject}},
Symbol: Symbol{Kind: NumSym, Num: v},
Memo: vm.NewNumber(v),
}
}

func (m *Message) AssertArgCount(name string, n int) error {
if len(m.Args) != n {
return fmt.Errorf("%s must have %d arguments", name, n)
Expand All @@ -39,7 +67,7 @@ func (m *Message) AssertArgCount(name string, n int) error {
}

func (m *Message) ArgAt(n int) *Message {
if n >= len(m.Args) {
if n >= len(m.Args) || n < 0 {
return nil
}
return m.Args[n]
Expand Down Expand Up @@ -88,11 +116,20 @@ func (m *Message) EvalArgAt(vm *VM, locals Interface, n int) Interface {
return m.ArgAt(n).Eval(vm, locals)
}

// Evaluate a message in the context of the given VM. A nil message evaluates
// to vm.Nil.
// Evaluate a message in the context of the given VM. This is a proxy to Send
// using locals as the target.
func (m *Message) Eval(vm *VM, locals Interface) (result Interface) {
return m.Send(vm, locals, locals)
}

// Send evaluates a message in the context of the given VM, targeting an
// object. If target is nil, it becomes the locals. A nil Message evaluates to
// vm.Nil.
func (m *Message) Send(vm *VM, locals, target Interface) (result Interface) {
result = vm.Nil
target := locals
if target == nil {
target = locals
}
for m != nil {
if m.Memo != nil {
result = m.Memo
Expand All @@ -103,6 +140,7 @@ func (m *Message) Eval(vm *VM, locals Interface) (result Interface) {
// fmt.Println("ident:", m.Symbol.Text)
if newtarget, proto := GetSlot(target, m.Symbol.Text); proto != nil {
// We have the slot.
// fmt.Println("we have the slot")
switch a := newtarget.(type) {
case Stop:
a.Result = result
Expand All @@ -112,6 +150,7 @@ func (m *Message) Eval(vm *VM, locals Interface) (result Interface) {
default:
result = newtarget
}
// fmt.Println("target goes from", vm.AsString(target), "to", vm.AsString(newtarget))
target = newtarget
} else if forward, fp := GetSlot(target, "forward"); fp != nil {
// fmt.Println("forwarding", m.Symbol.Text)
Expand All @@ -135,6 +174,7 @@ func (m *Message) Eval(vm *VM, locals Interface) (result Interface) {
panic(fmt.Sprintf("iolang: invalid Symbol: %#v", m.Symbol))
}
}
// fmt.Println("evaluated")
if result == nil {
// No message should evaluate to something that is not an Io
// object, so we want to convert nil to vm.Nil.
Expand All @@ -143,17 +183,33 @@ func (m *Message) Eval(vm *VM, locals Interface) (result Interface) {
if m.Symbol.Kind != SemiSym {
target = result
}
// fmt.Println("m goes from", m.Name(), "to", m.Next.Name())
m = m.Next
}
return result
}

// InsertAfter links another message to follow this one.
func (m *Message) InsertAfter(other *Message) {
if m.Next != nil {
m.Next.Prev = other
}
if other != nil {
other.Next = m.Next
other.Prev = m
}
m.Next = other
}

func (m *Message) Name() string {
if m == nil {
return "<nil message>"
}
switch m.Symbol.Kind {
case SemiSym, IdentSym:
return m.Symbol.Text
case NumSym:
return fmt.Sprintf("%d", m.Symbol.Num)
return fmt.Sprintf("%g", m.Symbol.Num)
case StringSym:
return m.Symbol.String
default:
Expand All @@ -162,48 +218,50 @@ func (m *Message) Name() string {
}

func (m *Message) String() string {
return "message"
return "message-" + m.Name()
}

func (m *Message) stringRecurse(vm *VM, b *bytes.Buffer) {
if m == nil {
b.WriteString("<nil>")
return
}
if m.Memo != nil {
if msg, ok := m.Memo.(*Message); ok {
b.WriteString("<message(")
msg.stringRecurse(vm, b)
b.WriteString(")>")
for m != nil {
if m.Memo != nil {
if msg, ok := m.Memo.(*Message); ok {
b.WriteString("<message(")
msg.stringRecurse(vm, b)
b.WriteString(")>")
} else {
b.WriteString(vm.AsString(m.Memo))
}
} else {
b.WriteString(vm.AsString(m.Memo))
}
} else {
switch m.Symbol.Kind {
case SemiSym:
b.WriteString("; ")
case IdentSym:
b.WriteString(m.Symbol.Text)
if len(m.Args) > 0 {
b.WriteByte('(')
m.Args[0].stringRecurse(vm, b)
for _, arg := range m.Args[1:] {
b.WriteString(", ")
arg.stringRecurse(vm, b)
switch m.Symbol.Kind {
case SemiSym:
b.WriteString("; ")
case IdentSym:
b.WriteString(m.Symbol.Text)
if len(m.Args) > 0 {
b.WriteByte('(')
m.Args[0].stringRecurse(vm, b)
for _, arg := range m.Args[1:] {
b.WriteString(", ")
arg.stringRecurse(vm, b)
}
b.WriteByte(')')
}
b.WriteByte(')')
case NumSym:
fmt.Fprint(b, m.Symbol.Num)
case StringSym:
fmt.Fprintf(b, "%q", m.Symbol.String)
default:
panic("iolang: unknown symbol kind")
}
case NumSym:
fmt.Fprint(b, m.Symbol.Num)
case StringSym:
fmt.Fprintf(b, "%q", m.Symbol.String)
default:
panic("iolang: unknown symbol kind")
}
}
if m.Next != nil {
b.WriteByte(' ')
m.Next.stringRecurse(vm, b)
if m.Next != nil {
b.WriteByte(' ')
}
m = m.Next
}
}

Expand Down
29 changes: 27 additions & 2 deletions number.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,11 @@ func (n *Number) String() string {

func (vm *VM) initNumber() {
slots := Slots{
"*": vm.NewCFunction(NumberMul, "NumberMul(v)"),
"+": vm.NewCFunction(NumberAdd, "NumberAdd(v)"),
"/": vm.NewCFunction(NumberDiv, "NumberDiv(v)"),
"abs": vm.NewCFunction(NumberAbs, "NumberAbs()"),
"acos": vm.NewCFunction(NumberAcos, "NumberAcos()"),
"add": vm.NewCFunction(NumberAdd, "NumberAdd(v)"),
"asBinary": vm.NewCFunction(NumberAsBinary, "NumberAsBinary()"),
"asCharacter": vm.NewCFunction(NumberAsCharacter, "NumberAsCharacter()"),
"asHex": vm.NewCFunction(NumberAsHex, "NumberAsHex()"),
Expand Down Expand Up @@ -136,7 +138,6 @@ func (vm *VM) initNumber() {
vm.MemoizeNumber(math.MaxInt64)
vm.MemoizeNumber(math.Inf(1))
vm.MemoizeNumber(math.Inf(-1))
slots["+"] = slots["add"]
slots["%"] = slots["mod"]
slots["&"] = slots["bitwiseAnd"]
slots["|"] = slots["bitwiseOr"]
Expand Down Expand Up @@ -306,6 +307,14 @@ func NumberCubed(vm *VM, target, locals Interface, msg *Message) Interface {
return vm.NewNumber(x * x * x)
}

func NumberDiv(vm *VM, target, locals Interface, msg *Message) Interface {
arg, err := msg.NumberArgAt(vm, locals, 0)
if err != nil {
return vm.IoError(err)
}
return vm.NewNumber(target.(*Number).Value / arg.Value)
}

func NumberExp(vm *VM, target, locals Interface, msg *Message) Interface {
return vm.NewNumber(math.Exp(target.(*Number).Value))
}
Expand Down Expand Up @@ -431,6 +440,14 @@ func NumberNegate(vm *VM, target, locals Interface, msg *Message) Interface {
return vm.NewNumber(-target.(*Number).Value)
}

func NumberMul(vm *VM, target, locals Interface, msg *Message) Interface {
arg, err := msg.NumberArgAt(vm, locals, 0)
if err != nil {
return vm.IoError(err)
}
return vm.NewNumber(target.(*Number).Value * arg.Value)
}

func NumberPow(vm *VM, target, locals Interface, msg *Message) Interface {
arg, err := msg.NumberArgAt(vm, locals, 0)
if err != nil {
Expand Down Expand Up @@ -482,6 +499,14 @@ func NumberSquared(vm *VM, target, locals Interface, msg *Message) Interface {
return vm.NewNumber(x * x)
}

func NumberSub(vm *VM, target, locals Interface, msg *Message) Interface {
arg, err := msg.NumberArgAt(vm, locals, 0)
if err != nil {
return vm.IoError(err)
}
return vm.NewNumber(target.(*Number).Value - arg.Value)
}

func NumberTan(vm *VM, target, locals Interface, msg *Message) Interface {
return vm.NewNumber(math.Tan(target.(*Number).Value))
}
Expand Down
3 changes: 2 additions & 1 deletion object.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ func GetSlot(o Interface, slot string) (value, proto Interface) {
return getSlotRecurse(o, slot, make(map[*Object]struct{}, len(o.SP().Protos)+1))
}

// var Debugvm *VM
var Debugvm *VM
var _ = Debugvm

func getSlotRecurse(o Interface, slot string, checked map[*Object]struct{}) (Interface, Interface) {
obj := o.SP()
Expand Down
Loading

0 comments on commit eb01e30

Please sign in to comment.