tests, abstracting output for PRINT and EMIT
This commit is contained in:
		
							
								
								
									
										22
									
								
								builtins.go
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								builtins.go
									
									
									
									
									
								
							@@ -1,6 +1,10 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import "fmt"
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Builtins is a handy holder for our various default words
 | 
			
		||||
type Builtins struct{}
 | 
			
		||||
@@ -228,14 +232,17 @@ func (b *Builtins) Div(s *Stack) func() error {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Print pops the stack and outputs it to stdout
 | 
			
		||||
func (b *Builtins) Print(s *Stack) func() error {
 | 
			
		||||
// Print pops the stack and outputs it to the writer with a trailing space (defaults to stdout)
 | 
			
		||||
func (b *Builtins) Print(out io.Writer, s *Stack) func() error {
 | 
			
		||||
	if out == nil {
 | 
			
		||||
		out = os.Stdout
 | 
			
		||||
	}
 | 
			
		||||
	return func() error {
 | 
			
		||||
		tos, err := s.Pop()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		fmt.Print(tos, " ")
 | 
			
		||||
		fmt.Fprint(out, tos, " ")
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -333,13 +340,16 @@ func (b *Builtins) Flags(c Context) func() error {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Emit outputs the UTF-8 rune for the int on the top of the stack
 | 
			
		||||
func (b *Builtins) Emit(s *Stack) func() error {
 | 
			
		||||
func (b *Builtins) Emit(out io.Writer, s *Stack) func() error {
 | 
			
		||||
	if out == nil {
 | 
			
		||||
		out = os.Stdout
 | 
			
		||||
	}
 | 
			
		||||
	return func() error {
 | 
			
		||||
		tos, err := s.Pop()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		fmt.Print(string(rune(tos)) + " ")
 | 
			
		||||
		fmt.Fprint(out, string(rune(tos))+" ")
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										331
									
								
								builtins_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										331
									
								
								builtins_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,331 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestAdd(t *testing.T) {
 | 
			
		||||
	s := Stack{
 | 
			
		||||
		values: []int{1, 2},
 | 
			
		||||
	}
 | 
			
		||||
	b := Builtins{}
 | 
			
		||||
	err := b.Add(&s)()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if len(s.values) != 1 {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if s.values[0] != 3 {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSub(t *testing.T) {
 | 
			
		||||
	s := Stack{
 | 
			
		||||
		values: []int{1, 2},
 | 
			
		||||
	}
 | 
			
		||||
	b := Builtins{}
 | 
			
		||||
	err := b.Sub(&s)()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if len(s.values) != 1 {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if s.values[0] != 1 {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestMul(t *testing.T) {
 | 
			
		||||
	b := Builtins{}
 | 
			
		||||
	s := Stack{
 | 
			
		||||
		values: []int{4, 2},
 | 
			
		||||
	}
 | 
			
		||||
	err := b.Mul(&s)()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if len(s.values) != 1 {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if s.values[0] != 8 {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	s = Stack{
 | 
			
		||||
		values: []int{-4, 2},
 | 
			
		||||
	}
 | 
			
		||||
	err = b.Mul(&s)()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if len(s.values) != 1 {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if s.values[0] != -8 {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDiv(t *testing.T) {
 | 
			
		||||
	b := Builtins{}
 | 
			
		||||
	s := Stack{
 | 
			
		||||
		values: []int{2, 4},
 | 
			
		||||
	}
 | 
			
		||||
	err := b.Div(&s)()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Log(err)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if len(s.values) != 1 {
 | 
			
		||||
		t.Log(s.values)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if s.values[0] != 2 {
 | 
			
		||||
		t.Log(s.values[0])
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	s = Stack{
 | 
			
		||||
		values: []int{2, -4},
 | 
			
		||||
	}
 | 
			
		||||
	err = b.Div(&s)()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Log(err)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if len(s.values) != 1 {
 | 
			
		||||
		t.Log(s.values)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if s.values[0] != -2 {
 | 
			
		||||
		t.Log(s.values[0])
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestPrint(t *testing.T) {
 | 
			
		||||
	b := Builtins{}
 | 
			
		||||
	s := Stack{
 | 
			
		||||
		values: []int{200},
 | 
			
		||||
	}
 | 
			
		||||
	out := new(bytes.Buffer)
 | 
			
		||||
	err := b.Print(out, &s)()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Log(err)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if len(s.values) != 0 {
 | 
			
		||||
		t.Log(s.values)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if string(out.Bytes()) != "200 " {
 | 
			
		||||
		t.Log(string(out.Bytes()), out.Bytes())
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDup(t *testing.T) {
 | 
			
		||||
	b := Builtins{}
 | 
			
		||||
	s := Stack{
 | 
			
		||||
		values: []int{200},
 | 
			
		||||
	}
 | 
			
		||||
	err := b.Dup(&s)()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Log(err)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if len(s.values) != 2 {
 | 
			
		||||
		t.Log(s.values)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if s.values[0] != s.values[1] {
 | 
			
		||||
		t.Log(s.values)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSwap(t *testing.T) {
 | 
			
		||||
	b := Builtins{}
 | 
			
		||||
	s := Stack{
 | 
			
		||||
		values: []int{200, 100},
 | 
			
		||||
	}
 | 
			
		||||
	err := b.Swap(&s)()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Log(err)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if len(s.values) != 2 {
 | 
			
		||||
		t.Log(s.values)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if s.values[0] != 100 || s.values[1] != 200 {
 | 
			
		||||
		t.Log(s.values)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestOver(t *testing.T) {
 | 
			
		||||
	b := Builtins{}
 | 
			
		||||
	s := Stack{
 | 
			
		||||
		values: []int{200, 100},
 | 
			
		||||
	}
 | 
			
		||||
	err := b.Over(&s)()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Log(err)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if len(s.values) != 3 {
 | 
			
		||||
		t.Log(s.values)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if s.values[0] != 100 || s.values[1] != 200 || s.values[2] != 100 {
 | 
			
		||||
		t.Log(s.values)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDrop(t *testing.T) {
 | 
			
		||||
	b := Builtins{}
 | 
			
		||||
	s := Stack{
 | 
			
		||||
		values: []int{200, 100},
 | 
			
		||||
	}
 | 
			
		||||
	err := b.Drop(&s)()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Log(err)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if len(s.values) != 1 {
 | 
			
		||||
		t.Log(s.values)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if s.values[0] != 100 {
 | 
			
		||||
		t.Log(s.values)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRot(t *testing.T) {
 | 
			
		||||
	b := Builtins{}
 | 
			
		||||
	s := Stack{
 | 
			
		||||
		values: []int{100, 200, 300},
 | 
			
		||||
	}
 | 
			
		||||
	err := b.Rot(&s)()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Log(err)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if len(s.values) != 3 {
 | 
			
		||||
		t.Log(s.values)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if s.values[0] != 300 || s.values[1] != 100 || s.values[2] != 200 {
 | 
			
		||||
		t.Log(s.values)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestEmit(t *testing.T) {
 | 
			
		||||
	b := Builtins{}
 | 
			
		||||
	s := Stack{
 | 
			
		||||
		values: []int{42},
 | 
			
		||||
	}
 | 
			
		||||
	out := new(bytes.Buffer)
 | 
			
		||||
	err := b.Emit(out, &s)()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Log(err)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if len(s.values) != 0 {
 | 
			
		||||
		t.Log(s.values)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if string(out.Bytes()) != "* " {
 | 
			
		||||
		t.Log(string(out.Bytes()), out.Bytes())
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestToR(t *testing.T) {
 | 
			
		||||
	b := Builtins{}
 | 
			
		||||
	s := Stack{
 | 
			
		||||
		values: []int{200, 100},
 | 
			
		||||
	}
 | 
			
		||||
	r := Stack{
 | 
			
		||||
		values: []int{},
 | 
			
		||||
	}
 | 
			
		||||
	err := b.ToR(&s, &r)()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Log(err)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if len(s.values) != 1 {
 | 
			
		||||
		t.Log(s.values)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if len(r.values) != 1 {
 | 
			
		||||
		t.Log(r.values)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if s.values[0] != 100 || r.values[0] != 200 {
 | 
			
		||||
		t.Log(s.values, r.values)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRFrom(t *testing.T) {
 | 
			
		||||
	b := Builtins{}
 | 
			
		||||
	s := Stack{
 | 
			
		||||
		values: []int{},
 | 
			
		||||
	}
 | 
			
		||||
	r := Stack{
 | 
			
		||||
		values: []int{200, 100},
 | 
			
		||||
	}
 | 
			
		||||
	err := b.RFrom(&s, &r)()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Log(err)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if len(s.values) != 1 {
 | 
			
		||||
		t.Log(s.values)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if len(r.values) != 1 {
 | 
			
		||||
		t.Log(r.values)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if s.values[0] != 200 || r.values[0] != 100 {
 | 
			
		||||
		t.Log(s.values, r.values)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRFetch(t *testing.T) {
 | 
			
		||||
	b := Builtins{}
 | 
			
		||||
	s := Stack{
 | 
			
		||||
		values: []int{},
 | 
			
		||||
	}
 | 
			
		||||
	r := Stack{
 | 
			
		||||
		values: []int{200, 100},
 | 
			
		||||
	}
 | 
			
		||||
	err := b.RFetch(&s, &r)()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Log(err)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if len(s.values) != 1 {
 | 
			
		||||
		t.Log(s.values)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if len(r.values) != 2 {
 | 
			
		||||
		t.Log(r.values)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if s.values[0] != 200 || r.values[0] != 200 || r.values[1] != 100 {
 | 
			
		||||
		t.Log(s.values, r.values)
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								eval.go
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								eval.go
									
									
									
									
									
								
							@@ -35,12 +35,10 @@ func (c *Context) Eval(line string) error {
 | 
			
		||||
				c.Flags.SetFlag("Immediate", w.Immediate)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if !c.Flags.GetFlag("Immediate") && !c.Flags.GetFlag("Comment") {
 | 
			
		||||
				c.Words = append(c.Words, sword)
 | 
			
		||||
				word = []byte{}
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			if !c.Flags.GetFlag("Immediate") && c.Flags.GetFlag("Comment") {
 | 
			
		||||
			if !c.Flags.GetFlag("Immediate") {
 | 
			
		||||
				if !c.Flags.GetFlag("Comment") {
 | 
			
		||||
					c.Words = append(c.Words, sword)
 | 
			
		||||
				}
 | 
			
		||||
				word = []byte{}
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
@@ -76,6 +74,7 @@ func (c *Context) Eval(line string) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Exec wraps the branched execution of words (either built-in or user-defined)
 | 
			
		||||
func (c *Context) Exec(w Word) error {
 | 
			
		||||
	if w.Impl != nil {
 | 
			
		||||
		// we have an implementation for that word. Run it.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								flags.go
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								flags.go
									
									
									
									
									
								
							@@ -3,10 +3,12 @@ package main
 | 
			
		||||
// Flags is a simple map of strings to boolean flag fields
 | 
			
		||||
type Flags map[string]bool
 | 
			
		||||
 | 
			
		||||
// GetFlag returns a boolean for the given flag
 | 
			
		||||
func (f Flags) GetFlag(s string) bool {
 | 
			
		||||
	return f[s]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetFlag overwrites the existing boolean for the flag
 | 
			
		||||
func (f Flags) SetFlag(s string, b bool) {
 | 
			
		||||
	f[s] = b
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								main.go
									
									
									
									
									
								
							@@ -38,8 +38,8 @@ func main() {
 | 
			
		||||
	dict.AddWord("*", b.Mul(&stack), nil, false)
 | 
			
		||||
	dict.AddWord("/", b.Div(&stack), nil, false)
 | 
			
		||||
	// output
 | 
			
		||||
	dict.AddWord(".", b.Print(&stack), nil, false)
 | 
			
		||||
	dict.AddWord("EMIT", b.Emit(&stack), nil, false)
 | 
			
		||||
	dict.AddWord(".", b.Print(os.Stdout, &stack), nil, false)
 | 
			
		||||
	dict.AddWord("EMIT", b.Emit(os.Stdout, &stack), nil, false)
 | 
			
		||||
	dict.AddWord("CR", nil, []string{"10", "EMIT"}, false) // emit a newline
 | 
			
		||||
	// logic
 | 
			
		||||
	dict.AddWord("=", b.Eq(&stack), nil, false)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user