go-scopes/forge/builtins/builtins.go

92 lines
2.4 KiB
Go

package builtins
import (
"git.sr.ht/~cco/go-scopes/forge"
)
type FE = forge.FE
type XT = forge.XT
type FPtr = forge.FPtr
type builtins struct {
Add, Body, Code, Comp, Drop, Dup, Get, If, IfElse, Leave, Lit, Mult,
New1, Put, Reg, Repeat, Swap,
Var1 XT
}
func Get(f FE) *builtins {
if v, ok := f.Voc().Lookup("builtins"); ok {
return v.(*builtins)
}
b := setup(f)
f.Voc().Register("builtins", b)
return b
}
func setup(f FE) *builtins {
voc := f.Voc()
r := func(name string, fct forge.Callable) XT {
return forge.Register(voc, forge.GoFunc(name, fct))
}
b := builtins{
Add: r("+", func(f FE, _ XT) { f.Push(f.PopI() + f.PopI()) }),
/*Append: r("append", func(f FE, _ XT) {
item := f.Pop()
f.Peek(0).(FPtr).Append(item)
}),*/
Body: r("body", func(f FE, _ XT) { f.Push(f.Pop().(XT).Code().New().Next()) }),
Code: r("code", func(f FE, _ XT) { f.Push(f.Code()) }),
Comp: r("comp", func(f FE, _ XT) { f.LatestXT().Code().Append(f.Pop()) }),
Drop: r("drop", func(f FE, _ XT) { f.Pop() }),
Dup: r("dup", func(f FE, _ XT) { f.Push(f.Peek(0)) }),
Get: r("@", func(f FE, _ XT) { f.Push(f.Pop().(FPtr).Value()) }),
Leave: r("leave", func(f FE, _ XT) { f.RPop() }),
Lit: r("lit", func(f FE, _ XT) { f.Push(f.Literal()) }),
Mult: r("*", func(f FE, _ XT) { f.Push(f.PopI() * f.PopI()) }),
New1: r("new1", func(f FE, _ XT) { f.Push(f.NewVar()) }),
Put: r("!", func(f FE, _ XT) { f.Pop().(FPtr).Set(f.Pop()) }),
Reg: r("reg", func(f FE, _ XT) { reg(f) }),
Repeat: r("repeat", func(f FE, _ XT) { f.Reset() }),
Swap: r("swap", func(f FE, _ XT) {
a := f.Pop()
b := f.Pop()
f.Push(a)
f.Push(b)
}),
}
rf := func(name string, code ...forge.FItem) XT {
return forge.Register(voc, forge.FCode(name, f.Code(code...)))
}
b.Var1 = rf("var1", b.Code, b.Swap, b.Reg, b.New1, b.Comp)
return &b
}
func doif(f FE) {
ifBranch := f.Literal().(FPtr)
if f.Pop().(bool) {
f.Call(ifBranch)
}
}
func doifelse(f FE) {
ifBranch := f.Literal().(FPtr)
elseBranch := f.Literal().(FPtr)
if f.Pop().(bool) {
f.Call(ifBranch)
} else {
f.Call(elseBranch)
}
}
func reg(f FE) {
f.Register(forge.FCode(f.Pop().(string), f.Pop().(FPtr)))
}
func create(f FE, _ XT) {
name := f.Pop().(string)
does := forge.AnonCode(f.Pop().(FPtr))
f.Register(forge.GoFunc(name, func(f FE, _ XT) {
f.Register(forge.FCode(f.Pop().(string),
f.Code(f.NewVar(), does)))
}))
}