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