From 1eb5e35fa3d736eb60f05ea8cccfd7e4165b9223 Mon Sep 17 00:00:00 2001 From: surdeus Date: Mon, 26 Feb 2024 23:04:47 +0500 Subject: [PATCH] feat: added interface to implement making possible to use other interpreter implementations and also for the standard Tengo implementation added way to import scripts. --- eval.go | 6 ++ main.go | 131 ++------------------------------------------ tengo.go | 137 ++++++++++++++++++++++++++++++++++++++++++++++ tests/index.md.pp | 15 ++++- tests/shit.tengo | 6 ++ tests/somefile | 1 + tool.go | 4 +- 7 files changed, 171 insertions(+), 129 deletions(-) create mode 100644 eval.go create mode 100644 tengo.go create mode 100644 tests/shit.tengo create mode 100644 tests/somefile diff --git a/eval.go b/eval.go new file mode 100644 index 0000000..3421bcf --- /dev/null +++ b/eval.go @@ -0,0 +1,6 @@ +package pp + +type Evaler interface { + Tags() [2]string + Eval(string, []string) ([]string, error) +} diff --git a/main.go b/main.go index 65d99cf..8747af4 100644 --- a/main.go +++ b/main.go @@ -1,144 +1,25 @@ package pp import ( - "github.com/d5/tengo/v2" - "github.com/d5/tengo/v2/stdlib" - "context" "strings" "fmt" ) type Preprocessor struct { - // The string will be inserted in the - // beginning of processed files. - head string - + evaler Evaler tags [2]string - modules *tengo.ModuleMap -} - -// Evaluate the expression and return the value -// it would print. -func (pp *Preprocessor) Eval(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) - 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 } // Get the new preprocessor with default options. -func NewPp() *Preprocessor { +func NewPp(evaler Evaler) *Preprocessor { pp := &Preprocessor{ - tags: [2]string{ - "", - }, - modules: stdlib.GetModuleMap(stdlib.AllModuleNames()...), + tags: evaler.Tags(), } + pp.evaler = evaler return pp } -func (pp *Preprocessor) Process(data string) (string, error) { +func (pp *Preprocessor) Process(filePath string, data string) (string, error) { var b strings.Builder last := 0 texts := []string{} @@ -171,7 +52,7 @@ func (pp *Preprocessor) Process(data string) (string, error) { data = data[1:] }*/ } - codeRets, err := pp.Eval(codes) + codeRets, err := pp.evaler.Eval(filePath, codes) if err != nil { return "", err } diff --git a/tengo.go b/tengo.go new file mode 100644 index 0000000..eb4a3ae --- /dev/null +++ b/tengo.go @@ -0,0 +1,137 @@ +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 +} diff --git a/tests/index.md.pp b/tests/index.md.pp index c1694a2..782f5c2 100644 --- a/tests/index.md.pp +++ b/tests/index.md.pp @@ -1,9 +1,20 @@ # The index testing 1 + 1 = cock ## The shit after -checking +checking + +## File contents + + + diff --git a/tests/shit.tengo b/tests/shit.tengo new file mode 100644 index 0000000..7dd37a8 --- /dev/null +++ b/tests/shit.tengo @@ -0,0 +1,6 @@ +some_func := func() { + return "THE RET VALUE OF SOME FUNC" +} +export({ + some_func: some_func +}) diff --git a/tests/somefile b/tests/somefile new file mode 100644 index 0000000..550ac0c --- /dev/null +++ b/tests/somefile @@ -0,0 +1 @@ +content of some file diff --git a/tool.go b/tool.go index 1c206e9..2c9d42e 100644 --- a/tool.go +++ b/tool.go @@ -9,7 +9,7 @@ import ( ) var Tool = mtool.T("pp").Func(func(flags *mtool.Flags){ - pp := NewPp() + pp := NewPp(NewTengo()) filePaths := flags.Parse() for _, filePath := range filePaths { pth := filepath.FromSlash(filePath) @@ -18,7 +18,7 @@ var Tool = mtool.T("pp").Func(func(flags *mtool.Flags){ log.Println("read error:", err) continue } - str, err := pp.Process(string(bts)) + str, err := pp.Process(pth, string(bts)) if err != nil { log.Println("pp error:", err) continue