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, LT, Lit, Mult, New1, Over, Put, Reg, Repeat, Sub, 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()) }), 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()) }), If: r("if", func(f FE, _ XT) { doif(f) }), IfElse: r("if-else", func(f FE, _ XT) { doifelse(f) }), Leave: r("leave", func(f FE, _ XT) { f.RPop() }), Lit: r("lit", func(f FE, _ XT) { f.Push(f.Literal()) }), LT: r("<", func(f FE, _ XT) { f.Push(f.PopI() > f.PopI()) }), Mult: r("*", func(f FE, _ XT) { f.Push(f.PopI() * f.PopI()) }), New1: r("new1", func(f FE, _ XT) { f.Push(f.NewVar()) }), Over: r("over", func(f FE, _ XT) { f.Push(f.Peek(1)) }), Put: r("!", func(f FE, _ XT) { f.Pop().(FPtr).Set(f.Pop()) }), Reg: r("reg", func(f FE, _ XT) { doreg(f) }), Repeat: r("repeat", func(f FE, _ XT) { f.Reset() }), Sub: r("-", func(f FE, _ XT) { a := f.PopI() f.Push(f.PopI() - a) }), Swap: r("swap", func(f FE, _ XT) { doswap(f) }), /*Append: r("append", func(f FE, _ XT) { item := f.Pop() f.Peek(0).(FPtr).Append(item) }),*/ } 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 doswap(f FE) { a := f.Pop() b := f.Pop() f.Push(a) f.Push(b) } func doreg(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))) })) }