gopp/tengo.go

137 lines
2.8 KiB
Go

package pp
import (
"github.com/d5/tengo/v2"
"github.com/d5/tengo/v2/stdlib"
"fmt"
"context"
)
type Tengo struct {
head string
modules *tengo.ModuleMap
}
func NewTengo() *Tengo {
evaler := &Tengo{}
evaler.modules = stdlib.GetModuleMap(stdlib.AllModuleNames()...)
return evaler
}
func (pp *Tengo) Tags() [2]string {
return [2]string{
"<?",
"?>",
}
}
// Simple Evaler implementation for the Tengo language
func (pp *Tengo) Eval(filePath string, codes []string) ([]string, error) {
const retHead = `
__ret_one__ := ""
printf := func(format, ...vals) {
__ret_one__ += sprintf(format, vals...)
}
print := func(...vals) {
__ret_one__ += sprint(vals...)
}
println := func(...vals) {
__ret_one__ += sprintln(vals...)
}
`
const retSeparator = `
__Separate(__ret_one__)
__ret_one__ = ""
`
rets := []string{}
fullCode := retHead + "\n" + pp.head
for _, code := range codes {
fullCode += "\n" + code + retSeparator + "\n"
}
script := tengo.NewScript([]byte(fullCode))
script.SetImports(pp.modules)
script.EnableFileImport(true)
script.SetImportDir(".")
err := script.Add("sprintf", &tengo.UserFunction{
Value: func(args ...tengo.Object) (tengo.Object, error){
if len(args) < 1 {
return nil, tengo.ErrWrongNumArguments
}
format, ok := tengo.ToString(args[0])
if !ok {
return nil, tengo.ErrInvalidArgumentType{
Expected: "string",
}
}
gargs := make([]any, len(args) - 1)
for i := range gargs {
gargs[i] = tengo.ToInterface(args[i+1])
//fmt.Printf("shit: %q\n", gargs[i])
}
str := fmt.Sprintf(format, gargs...)
return tengo.FromInterface(str)
},
},
)
if err != nil {
return nil, err
}
err = script.Add("sprint", &tengo.UserFunction{
Value: func(args ...tengo.Object) (tengo.Object, error){
gargs := make([]any, len(args))
for i := range gargs {
gargs[i] = tengo.ToInterface(args[i])
}
str := fmt.Sprint(gargs...)
return tengo.FromInterface(str)
},
},
)
if err != nil {
return nil, err
}
err = script.Add("sprintln", &tengo.UserFunction{
Value: func(args ...tengo.Object) (tengo.Object, error){
gargs := make([]any, len(args))
for i := range gargs {
gargs[i] = tengo.ToInterface(args[i])
}
str := fmt.Sprintln(gargs...)
return tengo.FromInterface(str)
},
},
)
if err != nil {
return nil, err
}
err = script.Add("__Separate", &tengo.UserFunction{
Value: func(args ...tengo.Object) (tengo.Object, error){
if len(args) < 1 {
return nil, tengo.ErrWrongNumArguments
}
str, ok := tengo.ToString(args[0])
if !ok {
return nil, tengo.ErrInvalidArgumentType{
}
}
rets = append(rets, str)
return nil, nil
},
},
)
if err != nil {
return nil, err
}
_, err = script.RunContext(context.Background())
if err != nil {
return nil, err
}
return rets, nil
}