work in progress: add some 'Forge' (Forth by Go) functionality
This commit is contained in:
		
							parent
							
								
									3f16eb44ca
								
							
						
					
					
						commit
						ec6172f07e
					
				
					 4 changed files with 141 additions and 0 deletions
				
			
		
							
								
								
									
										2
									
								
								forge/forge.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								forge/forge.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
// Package forge implements sort of a stack-based interpreter.
 | 
			
		||||
package forge
 | 
			
		||||
							
								
								
									
										53
									
								
								forge/stack/stack.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								forge/stack/stack.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,53 @@
 | 
			
		|||
// package stack provides a generic first-in / first-out stack.
 | 
			
		||||
package stack
 | 
			
		||||
 | 
			
		||||
// stack interface
 | 
			
		||||
 | 
			
		||||
type Stack[V any] interface {
 | 
			
		||||
	Depth() int
 | 
			
		||||
	Push(V)
 | 
			
		||||
	Pop() V
 | 
			
		||||
	Peek(int) V
 | 
			
		||||
	Replace(int, V)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// simple slice implementation
 | 
			
		||||
 | 
			
		||||
type stack[V any] struct {
 | 
			
		||||
	tos  int
 | 
			
		||||
	data []V
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewStack[V any]() *stack[V] {
 | 
			
		||||
	return &stack[V]{
 | 
			
		||||
		tos:  -1,
 | 
			
		||||
		data: make([]V, 0, 5),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (st *stack[V]) Depth() int {
 | 
			
		||||
	return st.tos + 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (st *stack[V]) Push(v V) {
 | 
			
		||||
	st.tos += 1
 | 
			
		||||
	if st.tos >= len(st.data) {
 | 
			
		||||
		st.data = append(st.data, v)
 | 
			
		||||
	} else {
 | 
			
		||||
		st.data[st.tos] = v
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (st *stack[V]) Pop() V {
 | 
			
		||||
	v := st.data[st.tos]
 | 
			
		||||
	st.tos -= 1
 | 
			
		||||
	return v
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (st *stack[V]) Peek(i int) V {
 | 
			
		||||
	return st.data[st.tos-i]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (st *stack[V]) Replace(i int, v V) {
 | 
			
		||||
	st.data[st.tos-i] = v
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										42
									
								
								forge/voc/voc.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								forge/voc/voc.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,42 @@
 | 
			
		|||
// Package voc implements a generic vocabulary. Vocabularies may be nested
 | 
			
		||||
// and are searched upwards using the parent vocabulary until this is nil.
 | 
			
		||||
// Individual entries contain slices of values; the last item in a
 | 
			
		||||
// slice is the current value.
 | 
			
		||||
package voc
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"git.sr.ht/~cco/go-scopes/lib/funky"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type VocData[V any] map[string][]V
 | 
			
		||||
 | 
			
		||||
type Vocabulary[V any] struct {
 | 
			
		||||
	parent *Vocabulary[V]
 | 
			
		||||
	data   VocData[V]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewVoc[V any](parent *Vocabulary[V]) *Vocabulary[V] {
 | 
			
		||||
	return &Vocabulary[V]{
 | 
			
		||||
		parent: parent,
 | 
			
		||||
		data:   VocData[V]{},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
func (voc *Vocabulary[V]) Register(name string, it V) {
 | 
			
		||||
	vi, ok := voc.data[name]
 | 
			
		||||
	if ok {
 | 
			
		||||
		voc.data[name] = append(vi, it)
 | 
			
		||||
	} else {
 | 
			
		||||
		voc.data[name] = []V{it}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (voc *Vocabulary[V]) Lookup(name string) funky.Maybe[V] {
 | 
			
		||||
	vi, ok := voc.data[name]
 | 
			
		||||
	if ok {
 | 
			
		||||
		return funky.Just(vi[len(vi)-1])
 | 
			
		||||
	}
 | 
			
		||||
	if voc.parent != nil {
 | 
			
		||||
		return voc.parent.Lookup(name)
 | 
			
		||||
	}
 | 
			
		||||
	return funky.Nothing[V]()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										44
									
								
								tests/forge_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								tests/forge_test.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,44 @@
 | 
			
		|||
package scopes_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	tbase "testing"
 | 
			
		||||
 | 
			
		||||
	"git.sr.ht/~cco/go-scopes/forge/stack"
 | 
			
		||||
	"git.sr.ht/~cco/go-scopes/forge/voc"
 | 
			
		||||
	"git.sr.ht/~cco/go-scopes/testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestForge(tb *tbase.T) {
 | 
			
		||||
	t := testing.SetUp(tb)
 | 
			
		||||
	t.Run("stack", StackTest)
 | 
			
		||||
	t.Run("voc", VocTest)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func StackTest(t *testing.T) {
 | 
			
		||||
	var st stack.Stack[int] = stack.NewStack[int]()
 | 
			
		||||
	st.Push(3)
 | 
			
		||||
	st.Push(4)
 | 
			
		||||
	t.AssertEqual(st.Depth(), 2)
 | 
			
		||||
	st.Push(5)
 | 
			
		||||
	t.AssertEqual(st.Peek(0), 5)
 | 
			
		||||
	st.Replace(1, 99)
 | 
			
		||||
	st.Push(6)
 | 
			
		||||
	t.AssertEqual(st.Peek(2), 99)
 | 
			
		||||
	st.Push(7)
 | 
			
		||||
	st.Push(8)
 | 
			
		||||
	st.Push(9)
 | 
			
		||||
	t.AssertEqual(st.Peek(2), 7)
 | 
			
		||||
	st.Pop()
 | 
			
		||||
	t.AssertEqual(st.Pop(), 8)
 | 
			
		||||
	t.AssertEqual(st.Peek(st.Depth()-1), 3)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func VocTest(t *testing.T) {
 | 
			
		||||
	v1 := voc.NewVoc[int](nil)
 | 
			
		||||
	v1.Register("one", 1)
 | 
			
		||||
	m := v1.Lookup("one")
 | 
			
		||||
	t.AssertEqual(m.IsNothing(), false)
 | 
			
		||||
	t.AssertEqual(m.Value(), 1)
 | 
			
		||||
	m = v1.Lookup("two")
 | 
			
		||||
	t.AssertEqual(m.IsNothing(), true)
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		
		Reference in a new issue