126 lines
2 KiB
Go
126 lines
2 KiB
Go
// Package forge implements sort of a stack-based interpreter.
|
|
package forge
|
|
|
|
import (
|
|
"io"
|
|
"os"
|
|
|
|
"git.sr.ht/~cco/go-scopes/common/ptr"
|
|
"git.sr.ht/~cco/go-scopes/common/stack"
|
|
"git.sr.ht/~cco/go-scopes/common/voc"
|
|
)
|
|
|
|
type DataItem interface{}
|
|
|
|
type Ptr = ptr.Ptr[DataItem]
|
|
type Stack = stack.Stack[DataItem]
|
|
type Voc = voc.Vocabulary[XT]
|
|
|
|
type Callable func(*ForgeEnv, XT)
|
|
|
|
type Item struct {
|
|
name string
|
|
immediate bool
|
|
fct Callable
|
|
body Ptr
|
|
}
|
|
|
|
type XT = *Item
|
|
|
|
type ForgeEnv struct {
|
|
ds, rs Stack
|
|
cp, ip, dp Ptr
|
|
voc *Voc
|
|
latestXT XT
|
|
cstate bool
|
|
output io.Writer
|
|
}
|
|
|
|
func NewVoc(parent *Voc) *Voc {
|
|
return voc.NewVoc[XT](parent)
|
|
}
|
|
|
|
func NewFE() *ForgeEnv {
|
|
return newFE(NewVoc(nil))
|
|
}
|
|
|
|
func (f *ForgeEnv) ChildFE() *ForgeEnv {
|
|
return newFE(NewVoc(f.voc))
|
|
}
|
|
|
|
func newFE(voc *Voc) *ForgeEnv {
|
|
return &ForgeEnv{
|
|
ds: stack.NewStack[DataItem](),
|
|
rs: stack.NewStack[DataItem](),
|
|
ip: ptr.NewSlice[DataItem](),
|
|
voc: voc,
|
|
output: os.Stdout,
|
|
}
|
|
}
|
|
|
|
// basic functions and methods
|
|
|
|
func Register(voc *Voc, name string, fct Callable) *Item {
|
|
it := Item{
|
|
name: name,
|
|
fct: fct,
|
|
}
|
|
voc.Register(name, &it)
|
|
return &it
|
|
}
|
|
|
|
func (it *Item) IsImmediate() bool {
|
|
return it.immediate
|
|
}
|
|
|
|
func (it *Item) Immediate() {
|
|
it.immediate = true
|
|
}
|
|
|
|
func (it *Item) Body() Ptr {
|
|
if it.body == nil {
|
|
it.body = ptr.NewSlice[DataItem]()
|
|
}
|
|
return it.body
|
|
}
|
|
|
|
func (it *Item) Name() string {
|
|
return it.name
|
|
}
|
|
|
|
// ForgeEnv methods
|
|
|
|
func (f *ForgeEnv) Voc() *Voc {
|
|
return f.voc
|
|
}
|
|
|
|
func (f *ForgeEnv) IP() Ptr {
|
|
return f.ip
|
|
}
|
|
|
|
func (f *ForgeEnv) Exec(items ...DataItem) {
|
|
f.ip = ptr.NewSlice[DataItem](items...)
|
|
for f.ip.Next() != nil {
|
|
it := f.ip.Value().(XT)
|
|
it.fct(f, it)
|
|
}
|
|
}
|
|
|
|
func (f *ForgeEnv) Push(it DataItem) {
|
|
f.ds.Push(it)
|
|
}
|
|
|
|
func (f *ForgeEnv) Pop() DataItem {
|
|
return f.ds.Pop()
|
|
}
|
|
|
|
// dummy stuff for testing
|
|
|
|
var builtins = struct{ add, sub XT }{}
|
|
|
|
var work = struct{ square XT }{}
|
|
|
|
func init() {
|
|
builtins.add = &Item{}
|
|
builtins.sub = &Item{}
|
|
}
|