diff options
author | Wim <wim@42.be> | 2020-01-09 21:52:19 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-01-09 21:52:19 +0100 |
commit | 9d84d6dd643c4017074e81465671cd9b25f9539a (patch) | |
tree | 8a767f91d655a6cf21d476e4fb7aa6fd8a952df8 /vendor/github.com/d5/tengo/v2/stdlib | |
parent | 0f708daf2d14dcca261ef98cc698a1b1f2a6aa74 (diff) | |
download | matterbridge-msglm-9d84d6dd643c4017074e81465671cd9b25f9539a.tar.gz matterbridge-msglm-9d84d6dd643c4017074e81465671cd9b25f9539a.tar.bz2 matterbridge-msglm-9d84d6dd643c4017074e81465671cd9b25f9539a.zip |
Update to tengo v2 (#976)
Diffstat (limited to 'vendor/github.com/d5/tengo/v2/stdlib')
22 files changed, 6313 insertions, 0 deletions
diff --git a/vendor/github.com/d5/tengo/v2/stdlib/base64.go b/vendor/github.com/d5/tengo/v2/stdlib/base64.go new file mode 100644 index 00000000..b4c5b56e --- /dev/null +++ b/vendor/github.com/d5/tengo/v2/stdlib/base64.go @@ -0,0 +1,34 @@ +package stdlib + +import ( + "encoding/base64" + + "github.com/d5/tengo/v2" +) + +var base64Module = map[string]tengo.Object{ + "encode": &tengo.UserFunction{ + Value: FuncAYRS(base64.StdEncoding.EncodeToString), + }, + "decode": &tengo.UserFunction{ + Value: FuncASRYE(base64.StdEncoding.DecodeString), + }, + "raw_encode": &tengo.UserFunction{ + Value: FuncAYRS(base64.RawStdEncoding.EncodeToString), + }, + "raw_decode": &tengo.UserFunction{ + Value: FuncASRYE(base64.RawStdEncoding.DecodeString), + }, + "url_encode": &tengo.UserFunction{ + Value: FuncAYRS(base64.URLEncoding.EncodeToString), + }, + "url_decode": &tengo.UserFunction{ + Value: FuncASRYE(base64.URLEncoding.DecodeString), + }, + "raw_url_encode": &tengo.UserFunction{ + Value: FuncAYRS(base64.RawURLEncoding.EncodeToString), + }, + "raw_url_decode": &tengo.UserFunction{ + Value: FuncASRYE(base64.RawURLEncoding.DecodeString), + }, +} diff --git a/vendor/github.com/d5/tengo/v2/stdlib/builtin_modules.go b/vendor/github.com/d5/tengo/v2/stdlib/builtin_modules.go new file mode 100644 index 00000000..cf0e9621 --- /dev/null +++ b/vendor/github.com/d5/tengo/v2/stdlib/builtin_modules.go @@ -0,0 +1,18 @@ +package stdlib + +import ( + "github.com/d5/tengo/v2" +) + +// BuiltinModules are builtin type standard library modules. +var BuiltinModules = map[string]map[string]tengo.Object{ + "math": mathModule, + "os": osModule, + "text": textModule, + "times": timesModule, + "rand": randModule, + "fmt": fmtModule, + "json": jsonModule, + "base64": base64Module, + "hex": hexModule, +} diff --git a/vendor/github.com/d5/tengo/v2/stdlib/errors.go b/vendor/github.com/d5/tengo/v2/stdlib/errors.go new file mode 100644 index 00000000..ad83c6f8 --- /dev/null +++ b/vendor/github.com/d5/tengo/v2/stdlib/errors.go @@ -0,0 +1,12 @@ +package stdlib + +import ( + "github.com/d5/tengo/v2" +) + +func wrapError(err error) tengo.Object { + if err == nil { + return tengo.TrueValue + } + return &tengo.Error{Value: &tengo.String{Value: err.Error()}} +} diff --git a/vendor/github.com/d5/tengo/v2/stdlib/fmt.go b/vendor/github.com/d5/tengo/v2/stdlib/fmt.go new file mode 100644 index 00000000..9945277f --- /dev/null +++ b/vendor/github.com/d5/tengo/v2/stdlib/fmt.go @@ -0,0 +1,101 @@ +package stdlib + +import ( + "fmt" + + "github.com/d5/tengo/v2" +) + +var fmtModule = map[string]tengo.Object{ + "print": &tengo.UserFunction{Name: "print", Value: fmtPrint}, + "printf": &tengo.UserFunction{Name: "printf", Value: fmtPrintf}, + "println": &tengo.UserFunction{Name: "println", Value: fmtPrintln}, + "sprintf": &tengo.UserFunction{Name: "sprintf", Value: fmtSprintf}, +} + +func fmtPrint(args ...tengo.Object) (ret tengo.Object, err error) { + printArgs, err := getPrintArgs(args...) + if err != nil { + return nil, err + } + _, _ = fmt.Print(printArgs...) + return nil, nil +} + +func fmtPrintf(args ...tengo.Object) (ret tengo.Object, err error) { + numArgs := len(args) + if numArgs == 0 { + return nil, tengo.ErrWrongNumArguments + } + + format, ok := args[0].(*tengo.String) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "format", + Expected: "string", + Found: args[0].TypeName(), + } + } + if numArgs == 1 { + fmt.Print(format) + return nil, nil + } + + s, err := tengo.Format(format.Value, args[1:]...) + if err != nil { + return nil, err + } + fmt.Print(s) + return nil, nil +} + +func fmtPrintln(args ...tengo.Object) (ret tengo.Object, err error) { + printArgs, err := getPrintArgs(args...) + if err != nil { + return nil, err + } + printArgs = append(printArgs, "\n") + _, _ = fmt.Print(printArgs...) + return nil, nil +} + +func fmtSprintf(args ...tengo.Object) (ret tengo.Object, err error) { + numArgs := len(args) + if numArgs == 0 { + return nil, tengo.ErrWrongNumArguments + } + + format, ok := args[0].(*tengo.String) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "format", + Expected: "string", + Found: args[0].TypeName(), + } + } + if numArgs == 1 { + // okay to return 'format' directly as String is immutable + return format, nil + } + s, err := tengo.Format(format.Value, args[1:]...) + if err != nil { + return nil, err + } + return &tengo.String{Value: s}, nil +} + +func getPrintArgs(args ...tengo.Object) ([]interface{}, error) { + var printArgs []interface{} + l := 0 + for _, arg := range args { + s, _ := tengo.ToString(arg) + slen := len(s) + // make sure length does not exceed the limit + if l+slen > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + l += slen + printArgs = append(printArgs, s) + } + return printArgs, nil +} diff --git a/vendor/github.com/d5/tengo/v2/stdlib/func_typedefs.go b/vendor/github.com/d5/tengo/v2/stdlib/func_typedefs.go new file mode 100644 index 00000000..fdac933c --- /dev/null +++ b/vendor/github.com/d5/tengo/v2/stdlib/func_typedefs.go @@ -0,0 +1,1049 @@ +package stdlib + +import ( + "fmt" + + "github.com/d5/tengo/v2" +) + +// FuncAR transform a function of 'func()' signature into CallableFunc type. +func FuncAR(fn func()) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 0 { + return nil, tengo.ErrWrongNumArguments + } + fn() + return tengo.UndefinedValue, nil + } +} + +// FuncARI transform a function of 'func() int' signature into CallableFunc +// type. +func FuncARI(fn func() int) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 0 { + return nil, tengo.ErrWrongNumArguments + } + return &tengo.Int{Value: int64(fn())}, nil + } +} + +// FuncARI64 transform a function of 'func() int64' signature into CallableFunc +// type. +func FuncARI64(fn func() int64) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 0 { + return nil, tengo.ErrWrongNumArguments + } + return &tengo.Int{Value: fn()}, nil + } +} + +// FuncAI64RI64 transform a function of 'func(int64) int64' signature into +// CallableFunc type. +func FuncAI64RI64(fn func(int64) int64) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + + i1, ok := tengo.ToInt64(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "int(compatible)", + Found: args[0].TypeName(), + } + } + return &tengo.Int{Value: fn(i1)}, nil + } +} + +// FuncAI64R transform a function of 'func(int64)' signature into CallableFunc +// type. +func FuncAI64R(fn func(int64)) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + + i1, ok := tengo.ToInt64(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "int(compatible)", + Found: args[0].TypeName(), + } + } + fn(i1) + return tengo.UndefinedValue, nil + } +} + +// FuncARB transform a function of 'func() bool' signature into CallableFunc +// type. +func FuncARB(fn func() bool) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 0 { + return nil, tengo.ErrWrongNumArguments + } + if fn() { + return tengo.TrueValue, nil + } + return tengo.FalseValue, nil + } +} + +// FuncARE transform a function of 'func() error' signature into CallableFunc +// type. +func FuncARE(fn func() error) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 0 { + return nil, tengo.ErrWrongNumArguments + } + return wrapError(fn()), nil + } +} + +// FuncARS transform a function of 'func() string' signature into CallableFunc +// type. +func FuncARS(fn func() string) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 0 { + return nil, tengo.ErrWrongNumArguments + } + s := fn() + if len(s) > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + return &tengo.String{Value: s}, nil + } +} + +// FuncARSE transform a function of 'func() (string, error)' signature into +// CallableFunc type. +func FuncARSE(fn func() (string, error)) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 0 { + return nil, tengo.ErrWrongNumArguments + } + res, err := fn() + if err != nil { + return wrapError(err), nil + } + if len(res) > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + return &tengo.String{Value: res}, nil + } +} + +// FuncARYE transform a function of 'func() ([]byte, error)' signature into +// CallableFunc type. +func FuncARYE(fn func() ([]byte, error)) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 0 { + return nil, tengo.ErrWrongNumArguments + } + res, err := fn() + if err != nil { + return wrapError(err), nil + } + if len(res) > tengo.MaxBytesLen { + return nil, tengo.ErrBytesLimit + } + return &tengo.Bytes{Value: res}, nil + } +} + +// FuncARF transform a function of 'func() float64' signature into CallableFunc +// type. +func FuncARF(fn func() float64) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 0 { + return nil, tengo.ErrWrongNumArguments + } + return &tengo.Float{Value: fn()}, nil + } +} + +// FuncARSs transform a function of 'func() []string' signature into +// CallableFunc type. +func FuncARSs(fn func() []string) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 0 { + return nil, tengo.ErrWrongNumArguments + } + arr := &tengo.Array{} + for _, elem := range fn() { + if len(elem) > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + arr.Value = append(arr.Value, &tengo.String{Value: elem}) + } + return arr, nil + } +} + +// FuncARIsE transform a function of 'func() ([]int, error)' signature into +// CallableFunc type. +func FuncARIsE(fn func() ([]int, error)) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 0 { + return nil, tengo.ErrWrongNumArguments + } + res, err := fn() + if err != nil { + return wrapError(err), nil + } + arr := &tengo.Array{} + for _, v := range res { + arr.Value = append(arr.Value, &tengo.Int{Value: int64(v)}) + } + return arr, nil + } +} + +// FuncAIRIs transform a function of 'func(int) []int' signature into +// CallableFunc type. +func FuncAIRIs(fn func(int) []int) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + i1, ok := tengo.ToInt(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "int(compatible)", + Found: args[0].TypeName(), + } + } + res := fn(i1) + arr := &tengo.Array{} + for _, v := range res { + arr.Value = append(arr.Value, &tengo.Int{Value: int64(v)}) + } + return arr, nil + } +} + +// FuncAFRF transform a function of 'func(float64) float64' signature into +// CallableFunc type. +func FuncAFRF(fn func(float64) float64) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + f1, ok := tengo.ToFloat64(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "float(compatible)", + Found: args[0].TypeName(), + } + } + return &tengo.Float{Value: fn(f1)}, nil + } +} + +// FuncAIR transform a function of 'func(int)' signature into CallableFunc type. +func FuncAIR(fn func(int)) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + i1, ok := tengo.ToInt(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "int(compatible)", + Found: args[0].TypeName(), + } + } + fn(i1) + return tengo.UndefinedValue, nil + } +} + +// FuncAIRF transform a function of 'func(int) float64' signature into +// CallableFunc type. +func FuncAIRF(fn func(int) float64) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + i1, ok := tengo.ToInt(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "int(compatible)", + Found: args[0].TypeName(), + } + } + return &tengo.Float{Value: fn(i1)}, nil + } +} + +// FuncAFRI transform a function of 'func(float64) int' signature into +// CallableFunc type. +func FuncAFRI(fn func(float64) int) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + f1, ok := tengo.ToFloat64(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "float(compatible)", + Found: args[0].TypeName(), + } + } + return &tengo.Int{Value: int64(fn(f1))}, nil + } +} + +// FuncAFFRF transform a function of 'func(float64, float64) float64' signature +// into CallableFunc type. +func FuncAFFRF(fn func(float64, float64) float64) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 2 { + return nil, tengo.ErrWrongNumArguments + } + f1, ok := tengo.ToFloat64(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "float(compatible)", + Found: args[0].TypeName(), + } + } + f2, ok := tengo.ToFloat64(args[1]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "float(compatible)", + Found: args[1].TypeName(), + } + } + return &tengo.Float{Value: fn(f1, f2)}, nil + } +} + +// FuncAIFRF transform a function of 'func(int, float64) float64' signature +// into CallableFunc type. +func FuncAIFRF(fn func(int, float64) float64) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 2 { + return nil, tengo.ErrWrongNumArguments + } + i1, ok := tengo.ToInt(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "int(compatible)", + Found: args[0].TypeName(), + } + } + f2, ok := tengo.ToFloat64(args[1]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "float(compatible)", + Found: args[1].TypeName(), + } + } + return &tengo.Float{Value: fn(i1, f2)}, nil + } +} + +// FuncAFIRF transform a function of 'func(float64, int) float64' signature +// into CallableFunc type. +func FuncAFIRF(fn func(float64, int) float64) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 2 { + return nil, tengo.ErrWrongNumArguments + } + f1, ok := tengo.ToFloat64(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "float(compatible)", + Found: args[0].TypeName(), + } + } + i2, ok := tengo.ToInt(args[1]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + } + return &tengo.Float{Value: fn(f1, i2)}, nil + } +} + +// FuncAFIRB transform a function of 'func(float64, int) bool' signature +// into CallableFunc type. +func FuncAFIRB(fn func(float64, int) bool) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 2 { + return nil, tengo.ErrWrongNumArguments + } + f1, ok := tengo.ToFloat64(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "float(compatible)", + Found: args[0].TypeName(), + } + } + i2, ok := tengo.ToInt(args[1]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + } + if fn(f1, i2) { + return tengo.TrueValue, nil + } + return tengo.FalseValue, nil + } +} + +// FuncAFRB transform a function of 'func(float64) bool' signature +// into CallableFunc type. +func FuncAFRB(fn func(float64) bool) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + f1, ok := tengo.ToFloat64(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "float(compatible)", + Found: args[0].TypeName(), + } + } + if fn(f1) { + return tengo.TrueValue, nil + } + return tengo.FalseValue, nil + } +} + +// FuncASRS transform a function of 'func(string) string' signature into +// CallableFunc type. User function will return 'true' if underlying native +// function returns nil. +func FuncASRS(fn func(string) string) tengo.CallableFunc { + return func(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + s := fn(s1) + if len(s) > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + return &tengo.String{Value: s}, nil + } +} + +// FuncASRSs transform a function of 'func(string) []string' signature into +// CallableFunc type. +func FuncASRSs(fn func(string) []string) tengo.CallableFunc { + return func(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + res := fn(s1) + arr := &tengo.Array{} + for _, elem := range res { + if len(elem) > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + arr.Value = append(arr.Value, &tengo.String{Value: elem}) + } + return arr, nil + } +} + +// FuncASRSE transform a function of 'func(string) (string, error)' signature +// into CallableFunc type. User function will return 'true' if underlying +// native function returns nil. +func FuncASRSE(fn func(string) (string, error)) tengo.CallableFunc { + return func(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + res, err := fn(s1) + if err != nil { + return wrapError(err), nil + } + if len(res) > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + return &tengo.String{Value: res}, nil + } +} + +// FuncASRE transform a function of 'func(string) error' signature into +// CallableFunc type. User function will return 'true' if underlying native +// function returns nil. +func FuncASRE(fn func(string) error) tengo.CallableFunc { + return func(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + return wrapError(fn(s1)), nil + } +} + +// FuncASSRE transform a function of 'func(string, string) error' signature +// into CallableFunc type. User function will return 'true' if underlying +// native function returns nil. +func FuncASSRE(fn func(string, string) error) tengo.CallableFunc { + return func(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 2 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + s2, ok := tengo.ToString(args[1]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "string(compatible)", + Found: args[1].TypeName(), + } + } + return wrapError(fn(s1, s2)), nil + } +} + +// FuncASSRSs transform a function of 'func(string, string) []string' +// signature into CallableFunc type. +func FuncASSRSs(fn func(string, string) []string) tengo.CallableFunc { + return func(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 2 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + s2, ok := tengo.ToString(args[1]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[1].TypeName(), + } + } + arr := &tengo.Array{} + for _, res := range fn(s1, s2) { + if len(res) > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + arr.Value = append(arr.Value, &tengo.String{Value: res}) + } + return arr, nil + } +} + +// FuncASSIRSs transform a function of 'func(string, string, int) []string' +// signature into CallableFunc type. +func FuncASSIRSs(fn func(string, string, int) []string) tengo.CallableFunc { + return func(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 3 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + s2, ok := tengo.ToString(args[1]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "string(compatible)", + Found: args[1].TypeName(), + } + } + i3, ok := tengo.ToInt(args[2]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "third", + Expected: "int(compatible)", + Found: args[2].TypeName(), + } + } + arr := &tengo.Array{} + for _, res := range fn(s1, s2, i3) { + if len(res) > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + arr.Value = append(arr.Value, &tengo.String{Value: res}) + } + return arr, nil + } +} + +// FuncASSRI transform a function of 'func(string, string) int' signature into +// CallableFunc type. +func FuncASSRI(fn func(string, string) int) tengo.CallableFunc { + return func(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 2 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + s2, ok := tengo.ToString(args[1]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + return &tengo.Int{Value: int64(fn(s1, s2))}, nil + } +} + +// FuncASSRS transform a function of 'func(string, string) string' signature +// into CallableFunc type. +func FuncASSRS(fn func(string, string) string) tengo.CallableFunc { + return func(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 2 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + s2, ok := tengo.ToString(args[1]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "string(compatible)", + Found: args[1].TypeName(), + } + } + s := fn(s1, s2) + if len(s) > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + return &tengo.String{Value: s}, nil + } +} + +// FuncASSRB transform a function of 'func(string, string) bool' signature +// into CallableFunc type. +func FuncASSRB(fn func(string, string) bool) tengo.CallableFunc { + return func(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 2 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + s2, ok := tengo.ToString(args[1]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "string(compatible)", + Found: args[1].TypeName(), + } + } + if fn(s1, s2) { + return tengo.TrueValue, nil + } + return tengo.FalseValue, nil + } +} + +// FuncASsSRS transform a function of 'func([]string, string) string' signature +// into CallableFunc type. +func FuncASsSRS(fn func([]string, string) string) tengo.CallableFunc { + return func(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 2 { + return nil, tengo.ErrWrongNumArguments + } + var ss1 []string + switch arg0 := args[0].(type) { + case *tengo.Array: + for idx, a := range arg0.Value { + as, ok := tengo.ToString(a) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: fmt.Sprintf("first[%d]", idx), + Expected: "string(compatible)", + Found: a.TypeName(), + } + } + ss1 = append(ss1, as) + } + case *tengo.ImmutableArray: + for idx, a := range arg0.Value { + as, ok := tengo.ToString(a) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: fmt.Sprintf("first[%d]", idx), + Expected: "string(compatible)", + Found: a.TypeName(), + } + } + ss1 = append(ss1, as) + } + default: + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "array", + Found: args[0].TypeName(), + } + } + s2, ok := tengo.ToString(args[1]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "string(compatible)", + Found: args[1].TypeName(), + } + } + s := fn(ss1, s2) + if len(s) > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + return &tengo.String{Value: s}, nil + } +} + +// FuncASI64RE transform a function of 'func(string, int64) error' signature +// into CallableFunc type. +func FuncASI64RE(fn func(string, int64) error) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 2 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + i2, ok := tengo.ToInt64(args[1]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + } + return wrapError(fn(s1, i2)), nil + } +} + +// FuncAIIRE transform a function of 'func(int, int) error' signature +// into CallableFunc type. +func FuncAIIRE(fn func(int, int) error) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 2 { + return nil, tengo.ErrWrongNumArguments + } + i1, ok := tengo.ToInt(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "int(compatible)", + Found: args[0].TypeName(), + } + } + i2, ok := tengo.ToInt(args[1]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + } + return wrapError(fn(i1, i2)), nil + } +} + +// FuncASIRS transform a function of 'func(string, int) string' signature +// into CallableFunc type. +func FuncASIRS(fn func(string, int) string) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 2 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + i2, ok := tengo.ToInt(args[1]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + } + s := fn(s1, i2) + if len(s) > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + return &tengo.String{Value: s}, nil + } +} + +// FuncASIIRE transform a function of 'func(string, int, int) error' signature +// into CallableFunc type. +func FuncASIIRE(fn func(string, int, int) error) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 3 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + i2, ok := tengo.ToInt(args[1]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + } + i3, ok := tengo.ToInt(args[2]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "third", + Expected: "int(compatible)", + Found: args[2].TypeName(), + } + } + return wrapError(fn(s1, i2, i3)), nil + } +} + +// FuncAYRIE transform a function of 'func([]byte) (int, error)' signature +// into CallableFunc type. +func FuncAYRIE(fn func([]byte) (int, error)) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + y1, ok := tengo.ToByteSlice(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "bytes(compatible)", + Found: args[0].TypeName(), + } + } + res, err := fn(y1) + if err != nil { + return wrapError(err), nil + } + return &tengo.Int{Value: int64(res)}, nil + } +} + +// FuncAYRS transform a function of 'func([]byte) string' signature into +// CallableFunc type. +func FuncAYRS(fn func([]byte) string) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + y1, ok := tengo.ToByteSlice(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "bytes(compatible)", + Found: args[0].TypeName(), + } + } + res := fn(y1) + return &tengo.String{Value: res}, nil + } +} + +// FuncASRIE transform a function of 'func(string) (int, error)' signature +// into CallableFunc type. +func FuncASRIE(fn func(string) (int, error)) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + res, err := fn(s1) + if err != nil { + return wrapError(err), nil + } + return &tengo.Int{Value: int64(res)}, nil + } +} + +// FuncASRYE transform a function of 'func(string) ([]byte, error)' signature +// into CallableFunc type. +func FuncASRYE(fn func(string) ([]byte, error)) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + res, err := fn(s1) + if err != nil { + return wrapError(err), nil + } + if len(res) > tengo.MaxBytesLen { + return nil, tengo.ErrBytesLimit + } + return &tengo.Bytes{Value: res}, nil + } +} + +// FuncAIRSsE transform a function of 'func(int) ([]string, error)' signature +// into CallableFunc type. +func FuncAIRSsE(fn func(int) ([]string, error)) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + i1, ok := tengo.ToInt(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "int(compatible)", + Found: args[0].TypeName(), + } + } + res, err := fn(i1) + if err != nil { + return wrapError(err), nil + } + arr := &tengo.Array{} + for _, r := range res { + if len(r) > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + arr.Value = append(arr.Value, &tengo.String{Value: r}) + } + return arr, nil + } +} + +// FuncAIRS transform a function of 'func(int) string' signature into +// CallableFunc type. +func FuncAIRS(fn func(int) string) tengo.CallableFunc { + return func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + i1, ok := tengo.ToInt(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "int(compatible)", + Found: args[0].TypeName(), + } + } + s := fn(i1) + if len(s) > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + return &tengo.String{Value: s}, nil + } +} diff --git a/vendor/github.com/d5/tengo/v2/stdlib/hex.go b/vendor/github.com/d5/tengo/v2/stdlib/hex.go new file mode 100644 index 00000000..981da696 --- /dev/null +++ b/vendor/github.com/d5/tengo/v2/stdlib/hex.go @@ -0,0 +1,12 @@ +package stdlib + +import ( + "encoding/hex" + + "github.com/d5/tengo/v2" +) + +var hexModule = map[string]tengo.Object{ + "encode": &tengo.UserFunction{Value: FuncAYRS(hex.EncodeToString)}, + "decode": &tengo.UserFunction{Value: FuncASRYE(hex.DecodeString)}, +} diff --git a/vendor/github.com/d5/tengo/v2/stdlib/json.go b/vendor/github.com/d5/tengo/v2/stdlib/json.go new file mode 100644 index 00000000..be2185db --- /dev/null +++ b/vendor/github.com/d5/tengo/v2/stdlib/json.go @@ -0,0 +1,146 @@ +package stdlib + +import ( + "bytes" + gojson "encoding/json" + + "github.com/d5/tengo/v2" + "github.com/d5/tengo/v2/stdlib/json" +) + +var jsonModule = map[string]tengo.Object{ + "decode": &tengo.UserFunction{ + Name: "decode", + Value: jsonDecode, + }, + "encode": &tengo.UserFunction{ + Name: "encode", + Value: jsonEncode, + }, + "indent": &tengo.UserFunction{ + Name: "encode", + Value: jsonIndent, + }, + "html_escape": &tengo.UserFunction{ + Name: "html_escape", + Value: jsonHTMLEscape, + }, +} + +func jsonDecode(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + + switch o := args[0].(type) { + case *tengo.Bytes: + v, err := json.Decode(o.Value) + if err != nil { + return &tengo.Error{ + Value: &tengo.String{Value: err.Error()}, + }, nil + } + return v, nil + case *tengo.String: + v, err := json.Decode([]byte(o.Value)) + if err != nil { + return &tengo.Error{ + Value: &tengo.String{Value: err.Error()}, + }, nil + } + return v, nil + default: + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "bytes/string", + Found: args[0].TypeName(), + } + } +} + +func jsonEncode(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + + b, err := json.Encode(args[0]) + if err != nil { + return &tengo.Error{Value: &tengo.String{Value: err.Error()}}, nil + } + + return &tengo.Bytes{Value: b}, nil +} + +func jsonIndent(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 3 { + return nil, tengo.ErrWrongNumArguments + } + + prefix, ok := tengo.ToString(args[1]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "prefix", + Expected: "string(compatible)", + Found: args[1].TypeName(), + } + } + + indent, ok := tengo.ToString(args[2]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "indent", + Expected: "string(compatible)", + Found: args[2].TypeName(), + } + } + + switch o := args[0].(type) { + case *tengo.Bytes: + var dst bytes.Buffer + err := gojson.Indent(&dst, o.Value, prefix, indent) + if err != nil { + return &tengo.Error{ + Value: &tengo.String{Value: err.Error()}, + }, nil + } + return &tengo.Bytes{Value: dst.Bytes()}, nil + case *tengo.String: + var dst bytes.Buffer + err := gojson.Indent(&dst, []byte(o.Value), prefix, indent) + if err != nil { + return &tengo.Error{ + Value: &tengo.String{Value: err.Error()}, + }, nil + } + return &tengo.Bytes{Value: dst.Bytes()}, nil + default: + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "bytes/string", + Found: args[0].TypeName(), + } + } +} + +func jsonHTMLEscape(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + + switch o := args[0].(type) { + case *tengo.Bytes: + var dst bytes.Buffer + gojson.HTMLEscape(&dst, o.Value) + return &tengo.Bytes{Value: dst.Bytes()}, nil + case *tengo.String: + var dst bytes.Buffer + gojson.HTMLEscape(&dst, []byte(o.Value)) + return &tengo.Bytes{Value: dst.Bytes()}, nil + default: + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "bytes/string", + Found: args[0].TypeName(), + } + } +} diff --git a/vendor/github.com/d5/tengo/v2/stdlib/json/decode.go b/vendor/github.com/d5/tengo/v2/stdlib/json/decode.go new file mode 100644 index 00000000..6d468ef0 --- /dev/null +++ b/vendor/github.com/d5/tengo/v2/stdlib/json/decode.go @@ -0,0 +1,358 @@ +// A modified version of Go's JSON implementation. + +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package json + +import ( + "strconv" + "unicode" + "unicode/utf16" + "unicode/utf8" + + "github.com/d5/tengo/v2" +) + +// Decode parses the JSON-encoded data and returns the result object. +func Decode(data []byte) (tengo.Object, error) { + var d decodeState + err := checkValid(data, &d.scan) + if err != nil { + return nil, err + } + d.init(data) + d.scan.reset() + d.scanWhile(scanSkipSpace) + return d.value() +} + +// decodeState represents the state while decoding a JSON value. +type decodeState struct { + data []byte + off int // next read offset in data + opcode int // last read result + scan scanner +} + +// readIndex returns the position of the last byte read. +func (d *decodeState) readIndex() int { + return d.off - 1 +} + +const phasePanicMsg = "JSON decoder out of sync - data changing underfoot?" + +func (d *decodeState) init(data []byte) *decodeState { + d.data = data + d.off = 0 + return d +} + +// scanNext processes the byte at d.data[d.off]. +func (d *decodeState) scanNext() { + if d.off < len(d.data) { + d.opcode = d.scan.step(&d.scan, d.data[d.off]) + d.off++ + } else { + d.opcode = d.scan.eof() + d.off = len(d.data) + 1 // mark processed EOF with len+1 + } +} + +// scanWhile processes bytes in d.data[d.off:] until it +// receives a scan code not equal to op. +func (d *decodeState) scanWhile(op int) { + s, data, i := &d.scan, d.data, d.off + for i < len(data) { + newOp := s.step(s, data[i]) + i++ + if newOp != op { + d.opcode = newOp + d.off = i + return + } + } + + d.off = len(data) + 1 // mark processed EOF with len+1 + d.opcode = d.scan.eof() +} + +func (d *decodeState) value() (tengo.Object, error) { + switch d.opcode { + default: + panic(phasePanicMsg) + case scanBeginArray: + o, err := d.array() + if err != nil { + return nil, err + } + d.scanNext() + return o, nil + case scanBeginObject: + o, err := d.object() + if err != nil { + return nil, err + } + d.scanNext() + return o, nil + case scanBeginLiteral: + return d.literal() + } +} + +func (d *decodeState) array() (tengo.Object, error) { + var arr []tengo.Object + for { + // Look ahead for ] - can only happen on first iteration. + d.scanWhile(scanSkipSpace) + if d.opcode == scanEndArray { + break + } + o, err := d.value() + if err != nil { + return nil, err + } + arr = append(arr, o) + + // Next token must be , or ]. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode == scanEndArray { + break + } + if d.opcode != scanArrayValue { + panic(phasePanicMsg) + } + } + return &tengo.Array{Value: arr}, nil +} + +func (d *decodeState) object() (tengo.Object, error) { + m := make(map[string]tengo.Object) + for { + // Read opening " of string key or closing }. + d.scanWhile(scanSkipSpace) + if d.opcode == scanEndObject { + // closing } - can only happen on first iteration. + break + } + if d.opcode != scanBeginLiteral { + panic(phasePanicMsg) + } + + // Read string key. + start := d.readIndex() + d.scanWhile(scanContinue) + item := d.data[start:d.readIndex()] + key, ok := unquote(item) + if !ok { + panic(phasePanicMsg) + } + + // Read : before value. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode != scanObjectKey { + panic(phasePanicMsg) + } + d.scanWhile(scanSkipSpace) + + // Read value. + o, err := d.value() + if err != nil { + return nil, err + } + + m[key] = o + + // Next token must be , or }. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode == scanEndObject { + break + } + if d.opcode != scanObjectValue { + panic(phasePanicMsg) + } + } + return &tengo.Map{Value: m}, nil +} + +func (d *decodeState) literal() (tengo.Object, error) { + // All bytes inside literal return scanContinue op code. + start := d.readIndex() + d.scanWhile(scanContinue) + + item := d.data[start:d.readIndex()] + + switch c := item[0]; c { + case 'n': // null + return tengo.UndefinedValue, nil + + case 't', 'f': // true, false + if c == 't' { + return tengo.TrueValue, nil + } + return tengo.FalseValue, nil + + case '"': // string + s, ok := unquote(item) + if !ok { + panic(phasePanicMsg) + } + return &tengo.String{Value: s}, nil + + default: // number + if c != '-' && (c < '0' || c > '9') { + panic(phasePanicMsg) + } + n, _ := strconv.ParseFloat(string(item), 10) + return &tengo.Float{Value: n}, nil + } +} + +// getu4 decodes \uXXXX from the beginning of s, returning the hex value, +// or it returns -1. +func getu4(s []byte) rune { + if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { + return -1 + } + var r rune + for _, c := range s[2:6] { + switch { + case '0' <= c && c <= '9': + c = c - '0' + case 'a' <= c && c <= 'f': + c = c - 'a' + 10 + case 'A' <= c && c <= 'F': + c = c - 'A' + 10 + default: + return -1 + } + r = r*16 + rune(c) + } + return r +} + +// unquote converts a quoted JSON string literal s into an actual string t. +// The rules are different than for Go, so cannot use strconv.Unquote. +func unquote(s []byte) (t string, ok bool) { + s, ok = unquoteBytes(s) + t = string(s) + return +} + +func unquoteBytes(s []byte) (t []byte, ok bool) { + if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { + return + } + s = s[1 : len(s)-1] + + // Check for unusual characters. If there are none, then no unquoting is + // needed, so return a slice of the original bytes. + r := 0 + for r < len(s) { + c := s[r] + if c == '\\' || c == '"' || c < ' ' { + break + } + if c < utf8.RuneSelf { + r++ + continue + } + rr, size := utf8.DecodeRune(s[r:]) + if rr == utf8.RuneError && size == 1 { + break + } + r += size + } + if r == len(s) { + return s, true + } + + b := make([]byte, len(s)+2*utf8.UTFMax) + w := copy(b, s[0:r]) + for r < len(s) { + // Out of room? Can only happen if s is full of + // malformed UTF-8 and we're replacing each + // byte with RuneError. + if w >= len(b)-2*utf8.UTFMax { + nb := make([]byte, (len(b)+utf8.UTFMax)*2) + copy(nb, b[0:w]) + b = nb + } + switch c := s[r]; { + case c == '\\': + r++ + if r >= len(s) { + return + } + switch s[r] { + default: + return + case '"', '\\', '/', '\'': + b[w] = s[r] + r++ + w++ + case 'b': + b[w] = '\b' + r++ + w++ + case 'f': + b[w] = '\f' + r++ + w++ + case 'n': + b[w] = '\n' + r++ + w++ + case 'r': + b[w] = '\r' + r++ + w++ + case 't': + b[w] = '\t' + r++ + w++ + case 'u': + r-- + rr := getu4(s[r:]) + if rr < 0 { + return + } + r += 6 + if utf16.IsSurrogate(rr) { + rr1 := getu4(s[r:]) + dec := utf16.DecodeRune(rr, rr1) + if dec != unicode.ReplacementChar { + // A valid pair; consume. + r += 6 + w += utf8.EncodeRune(b[w:], dec) + break + } + // Invalid surrogate; fall back to replacement rune. + rr = unicode.ReplacementChar + } + w += utf8.EncodeRune(b[w:], rr) + } + // Quote, control characters are invalid. + case c == '"', c < ' ': + return + // ASCII + case c < utf8.RuneSelf: + b[w] = c + r++ + w++ + // Coerce to well-formed UTF-8. + default: + rr, size := utf8.DecodeRune(s[r:]) + r += size + w += utf8.EncodeRune(b[w:], rr) + } + } + return b[0:w], true +} diff --git a/vendor/github.com/d5/tengo/v2/stdlib/json/encode.go b/vendor/github.com/d5/tengo/v2/stdlib/json/encode.go new file mode 100644 index 00000000..ab7ca6ff --- /dev/null +++ b/vendor/github.com/d5/tengo/v2/stdlib/json/encode.go @@ -0,0 +1,146 @@ +// A modified version of Go's JSON implementation. + +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package json + +import ( + "encoding/base64" + "errors" + "math" + "strconv" + + "github.com/d5/tengo/v2" +) + +// Encode returns the JSON encoding of the object. +func Encode(o tengo.Object) ([]byte, error) { + var b []byte + + switch o := o.(type) { + case *tengo.Array: + b = append(b, '[') + len1 := len(o.Value) - 1 + for idx, elem := range o.Value { + eb, err := Encode(elem) + if err != nil { + return nil, err + } + b = append(b, eb...) + if idx < len1 { + b = append(b, ',') + } + } + b = append(b, ']') + case *tengo.ImmutableArray: + b = append(b, '[') + len1 := len(o.Value) - 1 + for idx, elem := range o.Value { + eb, err := Encode(elem) + if err != nil { + return nil, err + } + b = append(b, eb...) + if idx < len1 { + b = append(b, ',') + } + } + b = append(b, ']') + case *tengo.Map: + b = append(b, '{') + len1 := len(o.Value) - 1 + idx := 0 + for key, value := range o.Value { + b = strconv.AppendQuote(b, key) + b = append(b, ':') + eb, err := Encode(value) + if err != nil { + return nil, err + } + b = append(b, eb...) + if idx < len1 { + b = append(b, ',') + } + idx++ + } + b = append(b, '}') + case *tengo.ImmutableMap: + b = append(b, '{') + len1 := len(o.Value) - 1 + idx := 0 + for key, value := range o.Value { + b = strconv.AppendQuote(b, key) + b = append(b, ':') + eb, err := Encode(value) + if err != nil { + return nil, err + } + b = append(b, eb...) + if idx < len1 { + b = append(b, ',') + } + idx++ + } + b = append(b, '}') + case *tengo.Bool: + if o.IsFalsy() { + b = strconv.AppendBool(b, false) + } else { + b = strconv.AppendBool(b, true) + } + case *tengo.Bytes: + b = append(b, '"') + encodedLen := base64.StdEncoding.EncodedLen(len(o.Value)) + dst := make([]byte, encodedLen) + base64.StdEncoding.Encode(dst, o.Value) + b = append(b, dst...) + b = append(b, '"') + case *tengo.Char: + b = strconv.AppendInt(b, int64(o.Value), 10) + case *tengo.Float: + var y []byte + + f := o.Value + if math.IsInf(f, 0) || math.IsNaN(f) { + return nil, errors.New("unsupported float value") + } + + // Convert as if by ES6 number to string conversion. + // This matches most other JSON generators. + abs := math.Abs(f) + fmt := byte('f') + if abs != 0 { + if abs < 1e-6 || abs >= 1e21 { + fmt = 'e' + } + } + y = strconv.AppendFloat(y, f, fmt, -1, 64) + if fmt == 'e' { + // clean up e-09 to e-9 + n := len(y) + if n >= 4 && y[n-4] == 'e' && y[n-3] == '-' && y[n-2] == '0' { + y[n-2] = y[n-1] + y = y[:n-1] + } + } + + b = append(b, y...) + case *tengo.Int: + b = strconv.AppendInt(b, o.Value, 10) + case *tengo.String: + b = strconv.AppendQuote(b, o.Value) + case *tengo.Time: + y, err := o.Value.MarshalJSON() + if err != nil { + return nil, err + } + b = append(b, y...) + case *tengo.Undefined: + b = append(b, "null"...) + default: + // unknown type: ignore + } + return b, nil +} diff --git a/vendor/github.com/d5/tengo/v2/stdlib/json/scanner.go b/vendor/github.com/d5/tengo/v2/stdlib/json/scanner.go new file mode 100644 index 00000000..aed15cf5 --- /dev/null +++ b/vendor/github.com/d5/tengo/v2/stdlib/json/scanner.go @@ -0,0 +1,562 @@ +// A modified version of Go's JSON implementation. + +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package json + +import "strconv" + +func checkValid(data []byte, scan *scanner) error { + scan.reset() + for _, c := range data { + scan.bytes++ + if scan.step(scan, c) == scanError { + return scan.err + } + } + if scan.eof() == scanError { + return scan.err + } + return nil +} + +// A SyntaxError is a description of a JSON syntax error. +type SyntaxError struct { + msg string // description of error + Offset int64 // error occurred after reading Offset bytes +} + +func (e *SyntaxError) Error() string { return e.msg } + +// A scanner is a JSON scanning state machine. +// Callers call scan.reset() and then pass bytes in one at a time +// by calling scan.step(&scan, c) for each byte. +// The return value, referred to as an opcode, tells the +// caller about significant parsing events like beginning +// and ending literals, objects, and arrays, so that the +// caller can follow along if it wishes. +// The return value scanEnd indicates that a single top-level +// JSON value has been completed, *before* the byte that +// just got passed in. (The indication must be delayed in order +// to recognize the end of numbers: is 123 a whole value or +// the beginning of 12345e+6?). +type scanner struct { + // The step is a func to be called to execute the next transition. + // Also tried using an integer constant and a single func + // with a switch, but using the func directly was 10% faster + // on a 64-bit Mac Mini, and it's nicer to read. + step func(*scanner, byte) int + + // Reached end of top-level value. + endTop bool + + // Stack of what we're in the middle of - array values, object keys, object values. + parseState []int + + // Error that happened, if any. + err error + + // total bytes consumed, updated by decoder.Decode + bytes int64 +} + +// These values are returned by the state transition functions +// assigned to scanner.state and the method scanner.eof. +// They give details about the current state of the scan that +// callers might be interested to know about. +// It is okay to ignore the return value of any particular +// call to scanner.state: if one call returns scanError, +// every subsequent call will return scanError too. +const ( + // Continue. + scanContinue = iota // uninteresting byte + scanBeginLiteral // end implied by next result != scanContinue + scanBeginObject // begin object + scanObjectKey // just finished object key (string) + scanObjectValue // just finished non-last object value + scanEndObject // end object (implies scanObjectValue if possible) + scanBeginArray // begin array + scanArrayValue // just finished array value + scanEndArray // end array (implies scanArrayValue if possible) + scanSkipSpace // space byte; can skip; known to be last "continue" result + + // Stop. + scanEnd // top-level value ended *before* this byte; known to be first "stop" result + scanError // hit an error, scanner.err. +) + +// These values are stored in the parseState stack. +// They give the current state of a composite value +// being scanned. If the parser is inside a nested value +// the parseState describes the nested state, outermost at entry 0. +const ( + parseObjectKey = iota // parsing object key (before colon) + parseObjectValue // parsing object value (after colon) + parseArrayValue // parsing array value +) + +// reset prepares the scanner for use. +// It must be called before calling s.step. +func (s *scanner) reset() { + s.step = stateBeginValue + s.parseState = s.parseState[0:0] + s.err = nil + s.endTop = false +} + +// eof tells the scanner that the end of input has been reached. +// It returns a scan status just as s.step does. +func (s *scanner) eof() int { + if s.err != nil { + return scanError + } + if s.endTop { + return scanEnd + } + s.step(s, ' ') + if s.endTop { + return scanEnd + } + if s.err == nil { + s.err = &SyntaxError{"unexpected end of JSON input", s.bytes} + } + return scanError +} + +// pushParseState pushes a new parse state p onto the parse stack. +func (s *scanner) pushParseState(p int) { + s.parseState = append(s.parseState, p) +} + +// popParseState pops a parse state (already obtained) off the stack +// and updates s.step accordingly. +func (s *scanner) popParseState() { + n := len(s.parseState) - 1 + s.parseState = s.parseState[0:n] + if n == 0 { + s.step = stateEndTop + s.endTop = true + } else { + s.step = stateEndValue + } +} + +func isSpace(c byte) bool { + return c == ' ' || c == '\t' || c == '\r' || c == '\n' +} + +// stateBeginValueOrEmpty is the state after reading `[`. +func stateBeginValueOrEmpty(s *scanner, c byte) int { + if c <= ' ' && isSpace(c) { + return scanSkipSpace + } + if c == ']' { + return stateEndValue(s, c) + } + return stateBeginValue(s, c) +} + +// stateBeginValue is the state at the beginning of the input. +func stateBeginValue(s *scanner, c byte) int { + if c <= ' ' && isSpace(c) { + return scanSkipSpace + } + switch c { + case '{': + s.step = stateBeginStringOrEmpty + s.pushParseState(parseObjectKey) + return scanBeginObject + case '[': + s.step = stateBeginValueOrEmpty + s.pushParseState(parseArrayValue) + return scanBeginArray + case '"': + s.step = stateInString + return scanBeginLiteral + case '-': + s.step = stateNeg + return scanBeginLiteral + case '0': // beginning of 0.123 + s.step = state0 + return scanBeginLiteral + case 't': // beginning of true + s.step = stateT + return scanBeginLiteral + case 'f': // beginning of false + s.step = stateF + return scanBeginLiteral + case 'n': // beginning of null + s.step = stateN + return scanBeginLiteral + } + if '1' <= c && c <= '9' { // beginning of 1234.5 + s.step = state1 + return scanBeginLiteral + } + return s.error(c, "looking for beginning of value") +} + +// stateBeginStringOrEmpty is the state after reading `{`. +func stateBeginStringOrEmpty(s *scanner, c byte) int { + if c <= ' ' && isSpace(c) { + return scanSkipSpace + } + if c == '}' { + n := len(s.parseState) + s.parseState[n-1] = parseObjectValue + return stateEndValue(s, c) + } + return stateBeginString(s, c) +} + +// stateBeginString is the state after reading `{"key": value,`. +func stateBeginString(s *scanner, c byte) int { + if c <= ' ' && isSpace(c) { + return scanSkipSpace + } + if c == '"' { + s.step = stateInString + return scanBeginLiteral + } + return s.error(c, "looking for beginning of object key string") +} + +// stateEndValue is the state after completing a value, +// such as after reading `{}` or `true` or `["x"`. +func stateEndValue(s *scanner, c byte) int { + n := len(s.parseState) + if n == 0 { + // Completed top-level before the current byte. + s.step = stateEndTop + s.endTop = true + return stateEndTop(s, c) + } + if c <= ' ' && isSpace(c) { + s.step = stateEndValue + return scanSkipSpace + } + ps := s.parseState[n-1] + switch ps { + case parseObjectKey: + if c == ':' { + s.parseState[n-1] = parseObjectValue + s.step = stateBeginValue + return scanObjectKey + } + return s.error(c, "after object key") + case parseObjectValue: + if c == ',' { + s.parseState[n-1] = parseObjectKey + s.step = stateBeginString + return scanObjectValue + } + if c == '}' { + s.popParseState() + return scanEndObject + } + return s.error(c, "after object key:value pair") + case parseArrayValue: + if c == ',' { + s.step = stateBeginValue + return scanArrayValue + } + if c == ']' { + s.popParseState() + return scanEndArray + } + return s.error(c, "after array element") + } + return s.error(c, "") +} + +// stateEndTop is the state after finishing the top-level value, +// such as after reading `{}` or `[1,2,3]`. +// Only space characters should be seen now. +func stateEndTop(s *scanner, c byte) int { + if !isSpace(c) { + // Complain about non-space byte on next call. + s.error(c, "after top-level value") + } + return scanEnd +} + +// stateInString is the state after reading `"`. +func stateInString(s *scanner, c byte) int { + if c == '"' { + s.step = stateEndValue + return scanContinue + } + if c == '\\' { + s.step = stateInStringEsc + return scanContinue + } + if c < 0x20 { + return s.error(c, "in string literal") + } + return scanContinue +} + +// stateInStringEsc is the state after reading `"\` during a quoted string. +func stateInStringEsc(s *scanner, c byte) int { + switch c { + case 'b', 'f', 'n', 'r', 't', '\\', '/', '"': + s.step = stateInString + return scanContinue + case 'u': + s.step = stateInStringEscU + return scanContinue + } + return s.error(c, "in string escape code") +} + +// stateInStringEscU is the state after reading `"\u` during a quoted string. +func stateInStringEscU(s *scanner, c byte) int { + if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { + s.step = stateInStringEscU1 + return scanContinue + } + // numbers + return s.error(c, "in \\u hexadecimal character escape") +} + +// stateInStringEscU1 is the state after reading `"\u1` during a quoted string. +func stateInStringEscU1(s *scanner, c byte) int { + if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { + s.step = stateInStringEscU12 + return scanContinue + } + // numbers + return s.error(c, "in \\u hexadecimal character escape") +} + +// stateInStringEscU12 is the state after reading `"\u12` during a quoted string. +func stateInStringEscU12(s *scanner, c byte) int { + if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { + s.step = stateInStringEscU123 + return scanContinue + } + // numbers + return s.error(c, "in \\u hexadecimal character escape") +} + +// stateInStringEscU123 is the state after reading `"\u123` during a quoted string. +func stateInStringEscU123(s *scanner, c byte) int { + if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' { + s.step = stateInString + return scanContinue + } + // numbers + return s.error(c, "in \\u hexadecimal character escape") +} + +// stateNeg is the state after reading `-` during a number. +func stateNeg(s *scanner, c byte) int { + if c == '0' { + s.step = state0 + return scanContinue + } + if '1' <= c && c <= '9' { + s.step = state1 + return scanContinue + } + return s.error(c, "in numeric literal") +} + +// state1 is the state after reading a non-zero integer during a number, +// such as after reading `1` or `100` but not `0`. +func state1(s *scanner, c byte) int { + if '0' <= c && c <= '9' { + s.step = state1 + return scanContinue + } + return state0(s, c) +} + +// state0 is the state after reading `0` during a number. +func state0(s *scanner, c byte) int { + if c == '.' { + s.step = stateDot + return scanContinue + } + if c == 'e' || c == 'E' { + s.step = stateE + return scanContinue + } + return stateEndValue(s, c) +} + +// stateDot is the state after reading the integer and decimal point in a number, +// such as after reading `1.`. +func stateDot(s *scanner, c byte) int { + if '0' <= c && c <= '9' { + s.step = stateDot0 + return scanContinue + } + return s.error(c, "after decimal point in numeric literal") +} + +// stateDot0 is the state after reading the integer, decimal point, and subsequent +// digits of a number, such as after reading `3.14`. +func stateDot0(s *scanner, c byte) int { + if '0' <= c && c <= '9' { + return scanContinue + } + if c == 'e' || c == 'E' { + s.step = stateE + return scanContinue + } + return stateEndValue(s, c) +} + +// stateE is the state after reading the mantissa and e in a number, +// such as after reading `314e` or `0.314e`. +func stateE(s *scanner, c byte) int { + if c == '+' || c == '-' { + s.step = stateESign + return scanContinue + } + return stateESign(s, c) +} + +// stateESign is the state after reading the mantissa, e, and sign in a number, +// such as after reading `314e-` or `0.314e+`. +func stateESign(s *scanner, c byte) int { + if '0' <= c && c <= '9' { + s.step = stateE0 + return scanContinue + } + return s.error(c, "in exponent of numeric literal") +} + +// stateE0 is the state after reading the mantissa, e, optional sign, +// and at least one digit of the exponent in a number, +// such as after reading `314e-2` or `0.314e+1` or `3.14e0`. +func stateE0(s *scanner, c byte) int { + if '0' <= c && c <= '9' { + return scanContinue + } + return stateEndValue(s, c) +} + +// stateT is the state after reading `t`. +func stateT(s *scanner, c byte) int { + if c == 'r' { + s.step = stateTr + return scanContinue + } + return s.error(c, "in literal true (expecting 'r')") +} + +// stateTr is the state after reading `tr`. +func stateTr(s *scanner, c byte) int { + if c == 'u' { + s.step = stateTru + return scanContinue + } + return s.error(c, "in literal true (expecting 'u')") +} + +// stateTru is the state after reading `tru`. +func stateTru(s *scanner, c byte) int { + if c == 'e' { + s.step = stateEndValue + return scanContinue + } + return s.error(c, "in literal true (expecting 'e')") +} + +// stateF is the state after reading `f`. +func stateF(s *scanner, c byte) int { + if c == 'a' { + s.step = stateFa + return scanContinue + } + return s.error(c, "in literal false (expecting 'a')") +} + +// stateFa is the state after reading `fa`. +func stateFa(s *scanner, c byte) int { + if c == 'l' { + s.step = stateFal + return scanContinue + } + return s.error(c, "in literal false (expecting 'l')") +} + +// stateFal is the state after reading `fal`. +func stateFal(s *scanner, c byte) int { + if c == 's' { + s.step = stateFals + return scanContinue + } + return s.error(c, "in literal false (expecting 's')") +} + +// stateFals is the state after reading `fals`. +func stateFals(s *scanner, c byte) int { + if c == 'e' { + s.step = stateEndValue + return scanContinue + } + return s.error(c, "in literal false (expecting 'e')") +} + +// stateN is the state after reading `n`. +func stateN(s *scanner, c byte) int { + if c == 'u' { + s.step = stateNu + return scanContinue + } + return s.error(c, "in literal null (expecting 'u')") +} + +// stateNu is the state after reading `nu`. +func stateNu(s *scanner, c byte) int { + if c == 'l' { + s.step = stateNul + return scanContinue + } + return s.error(c, "in literal null (expecting 'l')") +} + +// stateNul is the state after reading `nul`. +func stateNul(s *scanner, c byte) int { + if c == 'l' { + s.step = stateEndValue + return scanContinue + } + return s.error(c, "in literal null (expecting 'l')") +} + +// stateError is the state after reaching a syntax error, +// such as after reading `[1}` or `5.1.2`. +func stateError(_ *scanner, _ byte) int { + return scanError +} + +// error records an error and switches to the error state. +func (s *scanner) error(c byte, context string) int { + s.step = stateError + s.err = &SyntaxError{ + msg: "invalid character " + quoteChar(c) + " " + context, + Offset: s.bytes, + } + return scanError +} + +// quoteChar formats c as a quoted character literal +func quoteChar(c byte) string { + // special cases - different from quoted strings + if c == '\'' { + return `'\''` + } + if c == '"' { + return `'"'` + } + + // use quoted string with different quotation marks + s := strconv.Quote(string(c)) + return "'" + s[1:len(s)-1] + "'" +} diff --git a/vendor/github.com/d5/tengo/v2/stdlib/math.go b/vendor/github.com/d5/tengo/v2/stdlib/math.go new file mode 100644 index 00000000..633ea09f --- /dev/null +++ b/vendor/github.com/d5/tengo/v2/stdlib/math.go @@ -0,0 +1,233 @@ +package stdlib + +import ( + "math" + + "github.com/d5/tengo/v2" +) + +var mathModule = map[string]tengo.Object{ + "e": &tengo.Float{Value: math.E}, + "pi": &tengo.Float{Value: math.Pi}, + "phi": &tengo.Float{Value: math.Phi}, + "sqrt2": &tengo.Float{Value: math.Sqrt2}, + "sqrtE": &tengo.Float{Value: math.SqrtE}, + "sqrtPi": &tengo.Float{Value: math.SqrtPi}, + "sqrtPhi": &tengo.Float{Value: math.SqrtPhi}, + "ln2": &tengo.Float{Value: math.Ln2}, + "log2E": &tengo.Float{Value: math.Log2E}, + "ln10": &tengo.Float{Value: math.Ln10}, + "log10E": &tengo.Float{Value: math.Log10E}, + "abs": &tengo.UserFunction{ + Name: "abs", + Value: FuncAFRF(math.Abs), + }, + "acos": &tengo.UserFunction{ + Name: "acos", + Value: FuncAFRF(math.Acos), + }, + "acosh": &tengo.UserFunction{ + Name: "acosh", + Value: FuncAFRF(math.Acosh), + }, + "asin": &tengo.UserFunction{ + Name: "asin", + Value: FuncAFRF(math.Asin), + }, + "asinh": &tengo.UserFunction{ + Name: "asinh", + Value: FuncAFRF(math.Asinh), + }, + "atan": &tengo.UserFunction{ + Name: "atan", + Value: FuncAFRF(math.Atan), + }, + "atan2": &tengo.UserFunction{ + Name: "atan2", + Value: FuncAFFRF(math.Atan2), + }, + "atanh": &tengo.UserFunction{ + Name: "atanh", + Value: FuncAFRF(math.Atanh), + }, + "cbrt": &tengo.UserFunction{ + Name: "cbrt", + Value: FuncAFRF(math.Cbrt), + }, + "ceil": &tengo.UserFunction{ + Name: "ceil", + Value: FuncAFRF(math.Ceil), + }, + "copysign": &tengo.UserFunction{ + Name: "copysign", + Value: FuncAFFRF(math.Copysign), + }, + "cos": &tengo.UserFunction{ + Name: "cos", + Value: FuncAFRF(math.Cos), + }, + "cosh": &tengo.UserFunction{ + Name: "cosh", + Value: FuncAFRF(math.Cosh), + }, + "dim": &tengo.UserFunction{ + Name: "dim", + Value: FuncAFFRF(math.Dim), + }, + "erf": &tengo.UserFunction{ + Name: "erf", + Value: FuncAFRF(math.Erf), + }, + "erfc": &tengo.UserFunction{ + Name: "erfc", + Value: FuncAFRF(math.Erfc), + }, + "exp": &tengo.UserFunction{ + Name: "exp", + Value: FuncAFRF(math.Exp), + }, + "exp2": &tengo.UserFunction{ + Name: "exp2", + Value: FuncAFRF(math.Exp2), + }, + "expm1": &tengo.UserFunction{ + Name: "expm1", + Value: FuncAFRF(math.Expm1), + }, + "floor": &tengo.UserFunction{ + Name: "floor", + Value: FuncAFRF(math.Floor), + }, + "gamma": &tengo.UserFunction{ + Name: "gamma", + Value: FuncAFRF(math.Gamma), + }, + "hypot": &tengo.UserFunction{ + Name: "hypot", + Value: FuncAFFRF(math.Hypot), + }, + "ilogb": &tengo.UserFunction{ + Name: "ilogb", + Value: FuncAFRI(math.Ilogb), + }, + "inf": &tengo.UserFunction{ + Name: "inf", + Value: FuncAIRF(math.Inf), + }, + "is_inf": &tengo.UserFunction{ + Name: "is_inf", + Value: FuncAFIRB(math.IsInf), + }, + "is_nan": &tengo.UserFunction{ + Name: "is_nan", + Value: FuncAFRB(math.IsNaN), + }, + "j0": &tengo.UserFunction{ + Name: "j0", + Value: FuncAFRF(math.J0), + }, + "j1": &tengo.UserFunction{ + Name: "j1", + Value: FuncAFRF(math.J1), + }, + "jn": &tengo.UserFunction{ + Name: "jn", + Value: FuncAIFRF(math.Jn), + }, + "ldexp": &tengo.UserFunction{ + Name: "ldexp", + Value: FuncAFIRF(math.Ldexp), + }, + "log": &tengo.UserFunction{ + Name: "log", + Value: FuncAFRF(math.Log), + }, + "log10": &tengo.UserFunction{ + Name: "log10", + Value: FuncAFRF(math.Log10), + }, + "log1p": &tengo.UserFunction{ + Name: "log1p", + Value: FuncAFRF(math.Log1p), + }, + "log2": &tengo.UserFunction{ + Name: "log2", + Value: FuncAFRF(math.Log2), + }, + "logb": &tengo.UserFunction{ + Name: "logb", + Value: FuncAFRF(math.Logb), + }, + "max": &tengo.UserFunction{ + Name: "max", + Value: FuncAFFRF(math.Max), + }, + "min": &tengo.UserFunction{ + Name: "min", + Value: FuncAFFRF(math.Min), + }, + "mod": &tengo.UserFunction{ + Name: "mod", + Value: FuncAFFRF(math.Mod), + }, + "nan": &tengo.UserFunction{ + Name: "nan", + Value: FuncARF(math.NaN), + }, + "nextafter": &tengo.UserFunction{ + Name: "nextafter", + Value: FuncAFFRF(math.Nextafter), + }, + "pow": &tengo.UserFunction{ + Name: "pow", + Value: FuncAFFRF(math.Pow), + }, + "pow10": &tengo.UserFunction{ + Name: "pow10", + Value: FuncAIRF(math.Pow10), + }, + "remainder": &tengo.UserFunction{ + Name: "remainder", + Value: FuncAFFRF(math.Remainder), + }, + "signbit": &tengo.UserFunction{ + Name: "signbit", + Value: FuncAFRB(math.Signbit), + }, + "sin": &tengo.UserFunction{ + Name: "sin", + Value: FuncAFRF(math.Sin), + }, + "sinh": &tengo.UserFunction{ + Name: "sinh", + Value: FuncAFRF(math.Sinh), + }, + "sqrt": &tengo.UserFunction{ + Name: "sqrt", + Value: FuncAFRF(math.Sqrt), + }, + "tan": &tengo.UserFunction{ + Name: "tan", + Value: FuncAFRF(math.Tan), + }, + "tanh": &tengo.UserFunction{ + Name: "tanh", + Value: FuncAFRF(math.Tanh), + }, + "trunc": &tengo.UserFunction{ + Name: "trunc", + Value: FuncAFRF(math.Trunc), + }, + "y0": &tengo.UserFunction{ + Name: "y0", + Value: FuncAFRF(math.Y0), + }, + "y1": &tengo.UserFunction{ + Name: "y1", + Value: FuncAFRF(math.Y1), + }, + "yn": &tengo.UserFunction{ + Name: "yn", + Value: FuncAIFRF(math.Yn), + }, +} diff --git a/vendor/github.com/d5/tengo/v2/stdlib/os.go b/vendor/github.com/d5/tengo/v2/stdlib/os.go new file mode 100644 index 00000000..576bc94b --- /dev/null +++ b/vendor/github.com/d5/tengo/v2/stdlib/os.go @@ -0,0 +1,564 @@ +package stdlib + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "os/exec" + + "github.com/d5/tengo/v2" +) + +var osModule = map[string]tengo.Object{ + "o_rdonly": &tengo.Int{Value: int64(os.O_RDONLY)}, + "o_wronly": &tengo.Int{Value: int64(os.O_WRONLY)}, + "o_rdwr": &tengo.Int{Value: int64(os.O_RDWR)}, + "o_append": &tengo.Int{Value: int64(os.O_APPEND)}, + "o_create": &tengo.Int{Value: int64(os.O_CREATE)}, + "o_excl": &tengo.Int{Value: int64(os.O_EXCL)}, + "o_sync": &tengo.Int{Value: int64(os.O_SYNC)}, + "o_trunc": &tengo.Int{Value: int64(os.O_TRUNC)}, + "mode_dir": &tengo.Int{Value: int64(os.ModeDir)}, + "mode_append": &tengo.Int{Value: int64(os.ModeAppend)}, + "mode_exclusive": &tengo.Int{Value: int64(os.ModeExclusive)}, + "mode_temporary": &tengo.Int{Value: int64(os.ModeTemporary)}, + "mode_symlink": &tengo.Int{Value: int64(os.ModeSymlink)}, + "mode_device": &tengo.Int{Value: int64(os.ModeDevice)}, + "mode_named_pipe": &tengo.Int{Value: int64(os.ModeNamedPipe)}, + "mode_socket": &tengo.Int{Value: int64(os.ModeSocket)}, + "mode_setuid": &tengo.Int{Value: int64(os.ModeSetuid)}, + "mode_setgui": &tengo.Int{Value: int64(os.ModeSetgid)}, + "mode_char_device": &tengo.Int{Value: int64(os.ModeCharDevice)}, + "mode_sticky": &tengo.Int{Value: int64(os.ModeSticky)}, + "mode_type": &tengo.Int{Value: int64(os.ModeType)}, + "mode_perm": &tengo.Int{Value: int64(os.ModePerm)}, + "path_separator": &tengo.Char{Value: os.PathSeparator}, + "path_list_separator": &tengo.Char{Value: os.PathListSeparator}, + "dev_null": &tengo.String{Value: os.DevNull}, + "seek_set": &tengo.Int{Value: int64(io.SeekStart)}, + "seek_cur": &tengo.Int{Value: int64(io.SeekCurrent)}, + "seek_end": &tengo.Int{Value: int64(io.SeekEnd)}, + "args": &tengo.UserFunction{ + Name: "args", + Value: osArgs, + }, // args() => array(string) + "chdir": &tengo.UserFunction{ + Name: "chdir", + Value: FuncASRE(os.Chdir), + }, // chdir(dir string) => error + "chmod": osFuncASFmRE("chmod", os.Chmod), // chmod(name string, mode int) => error + "chown": &tengo.UserFunction{ + Name: "chown", + Value: FuncASIIRE(os.Chown), + }, // chown(name string, uid int, gid int) => error + "clearenv": &tengo.UserFunction{ + Name: "clearenv", + Value: FuncAR(os.Clearenv), + }, // clearenv() + "environ": &tengo.UserFunction{ + Name: "environ", + Value: FuncARSs(os.Environ), + }, // environ() => array(string) + "exit": &tengo.UserFunction{ + Name: "exit", + Value: FuncAIR(os.Exit), + }, // exit(code int) + "expand_env": &tengo.UserFunction{ + Name: "expand_env", + Value: osExpandEnv, + }, // expand_env(s string) => string + "getegid": &tengo.UserFunction{ + Name: "getegid", + Value: FuncARI(os.Getegid), + }, // getegid() => int + "getenv": &tengo.UserFunction{ + Name: "getenv", + Value: FuncASRS(os.Getenv), + }, // getenv(s string) => string + "geteuid": &tengo.UserFunction{ + Name: "geteuid", + Value: FuncARI(os.Geteuid), + }, // geteuid() => int + "getgid": &tengo.UserFunction{ + Name: "getgid", + Value: FuncARI(os.Getgid), + }, // getgid() => int + "getgroups": &tengo.UserFunction{ + Name: "getgroups", + Value: FuncARIsE(os.Getgroups), + }, // getgroups() => array(string)/error + "getpagesize": &tengo.UserFunction{ + Name: "getpagesize", + Value: FuncARI(os.Getpagesize), + }, // getpagesize() => int + "getpid": &tengo.UserFunction{ + Name: "getpid", + Value: FuncARI(os.Getpid), + }, // getpid() => int + "getppid": &tengo.UserFunction{ + Name: "getppid", + Value: FuncARI(os.Getppid), + }, // getppid() => int + "getuid": &tengo.UserFunction{ + Name: "getuid", + Value: FuncARI(os.Getuid), + }, // getuid() => int + "getwd": &tengo.UserFunction{ + Name: "getwd", + Value: FuncARSE(os.Getwd), + }, // getwd() => string/error + "hostname": &tengo.UserFunction{ + Name: "hostname", + Value: FuncARSE(os.Hostname), + }, // hostname() => string/error + "lchown": &tengo.UserFunction{ + Name: "lchown", + Value: FuncASIIRE(os.Lchown), + }, // lchown(name string, uid int, gid int) => error + "link": &tengo.UserFunction{ + Name: "link", + Value: FuncASSRE(os.Link), + }, // link(oldname string, newname string) => error + "lookup_env": &tengo.UserFunction{ + Name: "lookup_env", + Value: osLookupEnv, + }, // lookup_env(key string) => string/false + "mkdir": osFuncASFmRE("mkdir", os.Mkdir), // mkdir(name string, perm int) => error + "mkdir_all": osFuncASFmRE("mkdir_all", os.MkdirAll), // mkdir_all(name string, perm int) => error + "readlink": &tengo.UserFunction{ + Name: "readlink", + Value: FuncASRSE(os.Readlink), + }, // readlink(name string) => string/error + "remove": &tengo.UserFunction{ + Name: "remove", + Value: FuncASRE(os.Remove), + }, // remove(name string) => error + "remove_all": &tengo.UserFunction{ + Name: "remove_all", + Value: FuncASRE(os.RemoveAll), + }, // remove_all(name string) => error + "rename": &tengo.UserFunction{ + Name: "rename", + Value: FuncASSRE(os.Rename), + }, // rename(oldpath string, newpath string) => error + "setenv": &tengo.UserFunction{ + Name: "setenv", + Value: FuncASSRE(os.Setenv), + }, // setenv(key string, value string) => error + "symlink": &tengo.UserFunction{ + Name: "symlink", + Value: FuncASSRE(os.Symlink), + }, // symlink(oldname string newname string) => error + "temp_dir": &tengo.UserFunction{ + Name: "temp_dir", + Value: FuncARS(os.TempDir), + }, // temp_dir() => string + "truncate": &tengo.UserFunction{ + Name: "truncate", + Value: FuncASI64RE(os.Truncate), + }, // truncate(name string, size int) => error + "unsetenv": &tengo.UserFunction{ + Name: "unsetenv", + Value: FuncASRE(os.Unsetenv), + }, // unsetenv(key string) => error + "create": &tengo.UserFunction{ + Name: "create", + Value: osCreate, + }, // create(name string) => imap(file)/error + "open": &tengo.UserFunction{ + Name: "open", + Value: osOpen, + }, // open(name string) => imap(file)/error + "open_file": &tengo.UserFunction{ + Name: "open_file", + Value: osOpenFile, + }, // open_file(name string, flag int, perm int) => imap(file)/error + "find_process": &tengo.UserFunction{ + Name: "find_process", + Value: osFindProcess, + }, // find_process(pid int) => imap(process)/error + "start_process": &tengo.UserFunction{ + Name: "start_process", + Value: osStartProcess, + }, // start_process(name string, argv array(string), dir string, env array(string)) => imap(process)/error + "exec_look_path": &tengo.UserFunction{ + Name: "exec_look_path", + Value: FuncASRSE(exec.LookPath), + }, // exec_look_path(file) => string/error + "exec": &tengo.UserFunction{ + Name: "exec", + Value: osExec, + }, // exec(name, args...) => command + "stat": &tengo.UserFunction{ + Name: "stat", + Value: osStat, + }, // stat(name) => imap(fileinfo)/error + "read_file": &tengo.UserFunction{ + Name: "read_file", + Value: osReadFile, + }, // readfile(name) => array(byte)/error +} + +func osReadFile(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + fname, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + bytes, err := ioutil.ReadFile(fname) + if err != nil { + return wrapError(err), nil + } + if len(bytes) > tengo.MaxBytesLen { + return nil, tengo.ErrBytesLimit + } + return &tengo.Bytes{Value: bytes}, nil +} + +func osStat(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + fname, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + stat, err := os.Stat(fname) + if err != nil { + return wrapError(err), nil + } + fstat := &tengo.ImmutableMap{ + Value: map[string]tengo.Object{ + "name": &tengo.String{Value: stat.Name()}, + "mtime": &tengo.Time{Value: stat.ModTime()}, + "size": &tengo.Int{Value: stat.Size()}, + "mode": &tengo.Int{Value: int64(stat.Mode())}, + }, + } + if stat.IsDir() { + fstat.Value["directory"] = tengo.TrueValue + } else { + fstat.Value["directory"] = tengo.FalseValue + } + return fstat, nil +} + +func osCreate(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + res, err := os.Create(s1) + if err != nil { + return wrapError(err), nil + } + return makeOSFile(res), nil +} + +func osOpen(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + res, err := os.Open(s1) + if err != nil { + return wrapError(err), nil + } + return makeOSFile(res), nil +} + +func osOpenFile(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 3 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + i2, ok := tengo.ToInt(args[1]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + } + i3, ok := tengo.ToInt(args[2]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "third", + Expected: "int(compatible)", + Found: args[2].TypeName(), + } + } + res, err := os.OpenFile(s1, i2, os.FileMode(i3)) + if err != nil { + return wrapError(err), nil + } + return makeOSFile(res), nil +} + +func osArgs(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 0 { + return nil, tengo.ErrWrongNumArguments + } + arr := &tengo.Array{} + for _, osArg := range os.Args { + if len(osArg) > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + arr.Value = append(arr.Value, &tengo.String{Value: osArg}) + } + return arr, nil +} + +func osFuncASFmRE( + name string, + fn func(string, os.FileMode) error, +) *tengo.UserFunction { + return &tengo.UserFunction{ + Name: name, + Value: func(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 2 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + i2, ok := tengo.ToInt64(args[1]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + } + return wrapError(fn(s1, os.FileMode(i2))), nil + }, + } +} + +func osLookupEnv(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + res, ok := os.LookupEnv(s1) + if !ok { + return tengo.FalseValue, nil + } + if len(res) > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + return &tengo.String{Value: res}, nil +} + +func osExpandEnv(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + var vlen int + var failed bool + s := os.Expand(s1, func(k string) string { + if failed { + return "" + } + v := os.Getenv(k) + + // this does not count the other texts that are not being replaced + // but the code checks the final length at the end + vlen += len(v) + if vlen > tengo.MaxStringLen { + failed = true + return "" + } + return v + }) + if failed || len(s) > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + return &tengo.String{Value: s}, nil +} + +func osExec(args ...tengo.Object) (tengo.Object, error) { + if len(args) == 0 { + return nil, tengo.ErrWrongNumArguments + } + name, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + var execArgs []string + for idx, arg := range args[1:] { + execArg, ok := tengo.ToString(arg) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: fmt.Sprintf("args[%d]", idx), + Expected: "string(compatible)", + Found: args[1+idx].TypeName(), + } + } + execArgs = append(execArgs, execArg) + } + return makeOSExecCommand(exec.Command(name, execArgs...)), nil +} + +func osFindProcess(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + i1, ok := tengo.ToInt(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "int(compatible)", + Found: args[0].TypeName(), + } + } + proc, err := os.FindProcess(i1) + if err != nil { + return wrapError(err), nil + } + return makeOSProcess(proc), nil +} + +func osStartProcess(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 4 { + return nil, tengo.ErrWrongNumArguments + } + name, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + var argv []string + var err error + switch arg1 := args[1].(type) { + case *tengo.Array: + argv, err = stringArray(arg1.Value, "second") + if err != nil { + return nil, err + } + case *tengo.ImmutableArray: + argv, err = stringArray(arg1.Value, "second") + if err != nil { + return nil, err + } + default: + return nil, tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "array", + Found: arg1.TypeName(), + } + } + + dir, ok := tengo.ToString(args[2]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "third", + Expected: "string(compatible)", + Found: args[2].TypeName(), + } + } + + var env []string + switch arg3 := args[3].(type) { + case *tengo.Array: + env, err = stringArray(arg3.Value, "fourth") + if err != nil { + return nil, err + } + case *tengo.ImmutableArray: + env, err = stringArray(arg3.Value, "fourth") + if err != nil { + return nil, err + } + default: + return nil, tengo.ErrInvalidArgumentType{ + Name: "fourth", + Expected: "array", + Found: arg3.TypeName(), + } + } + + proc, err := os.StartProcess(name, argv, &os.ProcAttr{ + Dir: dir, + Env: env, + }) + if err != nil { + return wrapError(err), nil + } + return makeOSProcess(proc), nil +} + +func stringArray(arr []tengo.Object, argName string) ([]string, error) { + var sarr []string + for idx, elem := range arr { + str, ok := elem.(*tengo.String) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: fmt.Sprintf("%s[%d]", argName, idx), + Expected: "string", + Found: elem.TypeName(), + } + } + sarr = append(sarr, str.Value) + } + return sarr, nil +} diff --git a/vendor/github.com/d5/tengo/v2/stdlib/os_exec.go b/vendor/github.com/d5/tengo/v2/stdlib/os_exec.go new file mode 100644 index 00000000..7ee5c1cd --- /dev/null +++ b/vendor/github.com/d5/tengo/v2/stdlib/os_exec.go @@ -0,0 +1,119 @@ +package stdlib + +import ( + "os/exec" + + "github.com/d5/tengo/v2" +) + +func makeOSExecCommand(cmd *exec.Cmd) *tengo.ImmutableMap { + return &tengo.ImmutableMap{ + Value: map[string]tengo.Object{ + // combined_output() => bytes/error + "combined_output": &tengo.UserFunction{ + Name: "combined_output", + Value: FuncARYE(cmd.CombinedOutput), + }, + // output() => bytes/error + "output": &tengo.UserFunction{ + Name: "output", + Value: FuncARYE(cmd.Output), + }, // + // run() => error + "run": &tengo.UserFunction{ + Name: "run", + Value: FuncARE(cmd.Run), + }, // + // start() => error + "start": &tengo.UserFunction{ + Name: "start", + Value: FuncARE(cmd.Start), + }, // + // wait() => error + "wait": &tengo.UserFunction{ + Name: "wait", + Value: FuncARE(cmd.Wait), + }, // + // set_path(path string) + "set_path": &tengo.UserFunction{ + Name: "set_path", + Value: func(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + cmd.Path = s1 + return tengo.UndefinedValue, nil + }, + }, + // set_dir(dir string) + "set_dir": &tengo.UserFunction{ + Name: "set_dir", + Value: func(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + cmd.Dir = s1 + return tengo.UndefinedValue, nil + }, + }, + // set_env(env array(string)) + "set_env": &tengo.UserFunction{ + Name: "set_env", + Value: func(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + + var env []string + var err error + switch arg0 := args[0].(type) { + case *tengo.Array: + env, err = stringArray(arg0.Value, "first") + if err != nil { + return nil, err + } + case *tengo.ImmutableArray: + env, err = stringArray(arg0.Value, "first") + if err != nil { + return nil, err + } + default: + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "array", + Found: arg0.TypeName(), + } + } + cmd.Env = env + return tengo.UndefinedValue, nil + }, + }, + // process() => imap(process) + "process": &tengo.UserFunction{ + Name: "process", + Value: func(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 0 { + return nil, tengo.ErrWrongNumArguments + } + return makeOSProcess(cmd.Process), nil + }, + }, + }, + } +} diff --git a/vendor/github.com/d5/tengo/v2/stdlib/os_file.go b/vendor/github.com/d5/tengo/v2/stdlib/os_file.go new file mode 100644 index 00000000..4f59b4c4 --- /dev/null +++ b/vendor/github.com/d5/tengo/v2/stdlib/os_file.go @@ -0,0 +1,117 @@ +package stdlib + +import ( + "os" + + "github.com/d5/tengo/v2" +) + +func makeOSFile(file *os.File) *tengo.ImmutableMap { + return &tengo.ImmutableMap{ + Value: map[string]tengo.Object{ + // chdir() => true/error + "chdir": &tengo.UserFunction{ + Name: "chdir", + Value: FuncARE(file.Chdir), + }, // + // chown(uid int, gid int) => true/error + "chown": &tengo.UserFunction{ + Name: "chown", + Value: FuncAIIRE(file.Chown), + }, // + // close() => error + "close": &tengo.UserFunction{ + Name: "close", + Value: FuncARE(file.Close), + }, // + // name() => string + "name": &tengo.UserFunction{ + Name: "name", + Value: FuncARS(file.Name), + }, // + // readdirnames(n int) => array(string)/error + "readdirnames": &tengo.UserFunction{ + Name: "readdirnames", + Value: FuncAIRSsE(file.Readdirnames), + }, // + // sync() => error + "sync": &tengo.UserFunction{ + Name: "sync", + Value: FuncARE(file.Sync), + }, // + // write(bytes) => int/error + "write": &tengo.UserFunction{ + Name: "write", + Value: FuncAYRIE(file.Write), + }, // + // write(string) => int/error + "write_string": &tengo.UserFunction{ + Name: "write_string", + Value: FuncASRIE(file.WriteString), + }, // + // read(bytes) => int/error + "read": &tengo.UserFunction{ + Name: "read", + Value: FuncAYRIE(file.Read), + }, // + // chmod(mode int) => error + "chmod": &tengo.UserFunction{ + Name: "chmod", + Value: func(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + i1, ok := tengo.ToInt64(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "int(compatible)", + Found: args[0].TypeName(), + } + } + return wrapError(file.Chmod(os.FileMode(i1))), nil + }, + }, + // seek(offset int, whence int) => int/error + "seek": &tengo.UserFunction{ + Name: "seek", + Value: func(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 2 { + return nil, tengo.ErrWrongNumArguments + } + i1, ok := tengo.ToInt64(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "int(compatible)", + Found: args[0].TypeName(), + } + } + i2, ok := tengo.ToInt(args[1]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + } + res, err := file.Seek(i1, i2) + if err != nil { + return wrapError(err), nil + } + return &tengo.Int{Value: res}, nil + }, + }, + // stat() => imap(fileinfo)/error + "stat": &tengo.UserFunction{ + Name: "stat", + Value: func(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 0 { + return nil, tengo.ErrWrongNumArguments + } + return osStat(&tengo.String{Value: file.Name()}) + }, + }, + }, + } +} diff --git a/vendor/github.com/d5/tengo/v2/stdlib/os_process.go b/vendor/github.com/d5/tengo/v2/stdlib/os_process.go new file mode 100644 index 00000000..7fcf27a4 --- /dev/null +++ b/vendor/github.com/d5/tengo/v2/stdlib/os_process.go @@ -0,0 +1,76 @@ +package stdlib + +import ( + "os" + "syscall" + + "github.com/d5/tengo/v2" +) + +func makeOSProcessState(state *os.ProcessState) *tengo.ImmutableMap { + return &tengo.ImmutableMap{ + Value: map[string]tengo.Object{ + "exited": &tengo.UserFunction{ + Name: "exited", + Value: FuncARB(state.Exited), + }, + "pid": &tengo.UserFunction{ + Name: "pid", + Value: FuncARI(state.Pid), + }, + "string": &tengo.UserFunction{ + Name: "string", + Value: FuncARS(state.String), + }, + "success": &tengo.UserFunction{ + Name: "success", + Value: FuncARB(state.Success), + }, + }, + } +} + +func makeOSProcess(proc *os.Process) *tengo.ImmutableMap { + return &tengo.ImmutableMap{ + Value: map[string]tengo.Object{ + "kill": &tengo.UserFunction{ + Name: "kill", + Value: FuncARE(proc.Kill), + }, + "release": &tengo.UserFunction{ + Name: "release", + Value: FuncARE(proc.Release), + }, + "signal": &tengo.UserFunction{ + Name: "signal", + Value: func(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + i1, ok := tengo.ToInt64(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "int(compatible)", + Found: args[0].TypeName(), + } + } + return wrapError(proc.Signal(syscall.Signal(i1))), nil + }, + }, + "wait": &tengo.UserFunction{ + Name: "wait", + Value: func(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 0 { + return nil, tengo.ErrWrongNumArguments + } + state, err := proc.Wait() + if err != nil { + return wrapError(err), nil + } + return makeOSProcessState(state), nil + }, + }, + }, + } +} diff --git a/vendor/github.com/d5/tengo/v2/stdlib/rand.go b/vendor/github.com/d5/tengo/v2/stdlib/rand.go new file mode 100644 index 00000000..5d21e1df --- /dev/null +++ b/vendor/github.com/d5/tengo/v2/stdlib/rand.go @@ -0,0 +1,138 @@ +package stdlib + +import ( + "math/rand" + + "github.com/d5/tengo/v2" +) + +var randModule = map[string]tengo.Object{ + "int": &tengo.UserFunction{ + Name: "int", + Value: FuncARI64(rand.Int63), + }, + "float": &tengo.UserFunction{ + Name: "float", + Value: FuncARF(rand.Float64), + }, + "intn": &tengo.UserFunction{ + Name: "intn", + Value: FuncAI64RI64(rand.Int63n), + }, + "exp_float": &tengo.UserFunction{ + Name: "exp_float", + Value: FuncARF(rand.ExpFloat64), + }, + "norm_float": &tengo.UserFunction{ + Name: "norm_float", + Value: FuncARF(rand.NormFloat64), + }, + "perm": &tengo.UserFunction{ + Name: "perm", + Value: FuncAIRIs(rand.Perm), + }, + "seed": &tengo.UserFunction{ + Name: "seed", + Value: FuncAI64R(rand.Seed), + }, + "read": &tengo.UserFunction{ + Name: "read", + Value: func(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + y1, ok := args[0].(*tengo.Bytes) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "bytes", + Found: args[0].TypeName(), + } + } + res, err := rand.Read(y1.Value) + if err != nil { + ret = wrapError(err) + return + } + return &tengo.Int{Value: int64(res)}, nil + }, + }, + "rand": &tengo.UserFunction{ + Name: "rand", + Value: func(args ...tengo.Object) (tengo.Object, error) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + i1, ok := tengo.ToInt64(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "int(compatible)", + Found: args[0].TypeName(), + } + } + src := rand.NewSource(i1) + return randRand(rand.New(src)), nil + }, + }, +} + +func randRand(r *rand.Rand) *tengo.ImmutableMap { + return &tengo.ImmutableMap{ + Value: map[string]tengo.Object{ + "int": &tengo.UserFunction{ + Name: "int", + Value: FuncARI64(r.Int63), + }, + "float": &tengo.UserFunction{ + Name: "float", + Value: FuncARF(r.Float64), + }, + "intn": &tengo.UserFunction{ + Name: "intn", + Value: FuncAI64RI64(r.Int63n), + }, + "exp_float": &tengo.UserFunction{ + Name: "exp_float", + Value: FuncARF(r.ExpFloat64), + }, + "norm_float": &tengo.UserFunction{ + Name: "norm_float", + Value: FuncARF(r.NormFloat64), + }, + "perm": &tengo.UserFunction{ + Name: "perm", + Value: FuncAIRIs(r.Perm), + }, + "seed": &tengo.UserFunction{ + Name: "seed", + Value: FuncAI64R(r.Seed), + }, + "read": &tengo.UserFunction{ + Name: "read", + Value: func(args ...tengo.Object) ( + ret tengo.Object, + err error, + ) { + if len(args) != 1 { + return nil, tengo.ErrWrongNumArguments + } + y1, ok := args[0].(*tengo.Bytes) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "bytes", + Found: args[0].TypeName(), + } + } + res, err := r.Read(y1.Value) + if err != nil { + ret = wrapError(err) + return + } + return &tengo.Int{Value: int64(res)}, nil + }, + }, + }, + } +} diff --git a/vendor/github.com/d5/tengo/v2/stdlib/source_modules.go b/vendor/github.com/d5/tengo/v2/stdlib/source_modules.go new file mode 100644 index 00000000..ca69d7d1 --- /dev/null +++ b/vendor/github.com/d5/tengo/v2/stdlib/source_modules.go @@ -0,0 +1,8 @@ +// Code generated using gensrcmods.go; DO NOT EDIT. + +package stdlib + +// SourceModules are source type standard library modules. +var SourceModules = map[string]string{ + "enum": "is_enumerable := func(x) {\n return is_array(x) || is_map(x) || is_immutable_array(x) || is_immutable_map(x)\n}\n\nis_array_like := func(x) {\n return is_array(x) || is_immutable_array(x)\n}\n\nexport {\n // all returns true if the given function `fn` evaluates to a truthy value on\n // all of the items in `x`. It returns undefined if `x` is not enumerable.\n all: func(x, fn) {\n if !is_enumerable(x) { return undefined }\n\n for k, v in x {\n if !fn(k, v) { return false }\n }\n\n return true\n },\n // any returns true if the given function `fn` evaluates to a truthy value on\n // any of the items in `x`. It returns undefined if `x` is not enumerable.\n any: func(x, fn) {\n if !is_enumerable(x) { return undefined }\n\n for k, v in x {\n if fn(k, v) { return true }\n }\n\n return false\n },\n // chunk returns an array of elements split into groups the length of size.\n // If `x` can't be split evenly, the final chunk will be the remaining elements.\n // It returns undefined if `x` is not array.\n chunk: func(x, size) {\n if !is_array_like(x) || !size { return undefined }\n\n numElements := len(x)\n if !numElements { return [] }\n\n res := []\n idx := 0\n for idx < numElements {\n res = append(res, x[idx:idx+size])\n idx += size\n }\n\n return res\n },\n // at returns an element at the given index (if `x` is array) or\n // key (if `x` is map). It returns undefined if `x` is not enumerable.\n at: func(x, key) {\n if !is_enumerable(x) { return undefined }\n\n if is_array_like(x) {\n if !is_int(key) { return undefined }\n } else {\n if !is_string(key) { return undefined }\n }\n\n return x[key]\n },\n // each iterates over elements of `x` and invokes `fn` for each element. `fn` is\n // invoked with two arguments: `key` and `value`. `key` is an int index\n // if `x` is array. `key` is a string key if `x` is map. It does not iterate\n // and returns undefined if `x` is not enumerable.\n each: func(x, fn) {\n if !is_enumerable(x) { return undefined }\n\n for k, v in x {\n fn(k, v)\n }\n },\n // filter iterates over elements of `x`, returning an array of all elements `fn`\n // returns truthy for. `fn` is invoked with two arguments: `key` and `value`.\n // `key` is an int index if `x` is array. `key` is a string key if `x` is map.\n // It returns undefined if `x` is not enumerable.\n filter: func(x, fn) {\n if !is_array_like(x) { return undefined }\n\n dst := []\n for k, v in x {\n if fn(k, v) { dst = append(dst, v) }\n }\n\n return dst\n },\n // find iterates over elements of `x`, returning value of the first element `fn`\n // returns truthy for. `fn` is invoked with two arguments: `key` and `value`.\n // `key` is an int index if `x` is array. `key` is a string key if `x` is map.\n // It returns undefined if `x` is not enumerable.\n find: func(x, fn) {\n if !is_enumerable(x) { return undefined }\n\n for k, v in x {\n if fn(k, v) { return v }\n }\n },\n // find_key iterates over elements of `x`, returning key or index of the first\n // element `fn` returns truthy for. `fn` is invoked with two arguments: `key`\n // and `value`. `key` is an int index if `x` is array. `key` is a string key if\n // `x` is map. It returns undefined if `x` is not enumerable.\n find_key: func(x, fn) {\n if !is_enumerable(x) { return undefined }\n\n for k, v in x {\n if fn(k, v) { return k }\n }\n },\n // map creates an array of values by running each element in `x` through `fn`.\n // `fn` is invoked with two arguments: `key` and `value`. `key` is an int index\n // if `x` is array. `key` is a string key if `x` is map. It returns undefined\n // if `x` is not enumerable.\n map: func(x, fn) {\n if !is_enumerable(x) { return undefined }\n\n dst := []\n for k, v in x {\n dst = append(dst, fn(k, v))\n }\n\n return dst\n },\n // key returns the first argument.\n key: func(k, _) { return k },\n // value returns the second argument.\n value: func(_, v) { return v }\n}\n", +} diff --git a/vendor/github.com/d5/tengo/v2/stdlib/srcmod_enum.tengo b/vendor/github.com/d5/tengo/v2/stdlib/srcmod_enum.tengo new file mode 100644 index 00000000..7a5ea637 --- /dev/null +++ b/vendor/github.com/d5/tengo/v2/stdlib/srcmod_enum.tengo @@ -0,0 +1,128 @@ +is_enumerable := func(x) { + return is_array(x) || is_map(x) || is_immutable_array(x) || is_immutable_map(x) +} + +is_array_like := func(x) { + return is_array(x) || is_immutable_array(x) +} + +export { + // all returns true if the given function `fn` evaluates to a truthy value on + // all of the items in `x`. It returns undefined if `x` is not enumerable. + all: func(x, fn) { + if !is_enumerable(x) { return undefined } + + for k, v in x { + if !fn(k, v) { return false } + } + + return true + }, + // any returns true if the given function `fn` evaluates to a truthy value on + // any of the items in `x`. It returns undefined if `x` is not enumerable. + any: func(x, fn) { + if !is_enumerable(x) { return undefined } + + for k, v in x { + if fn(k, v) { return true } + } + + return false + }, + // chunk returns an array of elements split into groups the length of size. + // If `x` can't be split evenly, the final chunk will be the remaining elements. + // It returns undefined if `x` is not array. + chunk: func(x, size) { + if !is_array_like(x) || !size { return undefined } + + numElements := len(x) + if !numElements { return [] } + + res := [] + idx := 0 + for idx < numElements { + res = append(res, x[idx:idx+size]) + idx += size + } + + return res + }, + // at returns an element at the given index (if `x` is array) or + // key (if `x` is map). It returns undefined if `x` is not enumerable. + at: func(x, key) { + if !is_enumerable(x) { return undefined } + + if is_array_like(x) { + if !is_int(key) { return undefined } + } else { + if !is_string(key) { return undefined } + } + + return x[key] + }, + // each iterates over elements of `x` and invokes `fn` for each element. `fn` is + // invoked with two arguments: `key` and `value`. `key` is an int index + // if `x` is array. `key` is a string key if `x` is map. It does not iterate + // and returns undefined if `x` is not enumerable. + each: func(x, fn) { + if !is_enumerable(x) { return undefined } + + for k, v in x { + fn(k, v) + } + }, + // filter iterates over elements of `x`, returning an array of all elements `fn` + // returns truthy for. `fn` is invoked with two arguments: `key` and `value`. + // `key` is an int index if `x` is array. `key` is a string key if `x` is map. + // It returns undefined if `x` is not enumerable. + filter: func(x, fn) { + if !is_array_like(x) { return undefined } + + dst := [] + for k, v in x { + if fn(k, v) { dst = append(dst, v) } + } + + return dst + }, + // find iterates over elements of `x`, returning value of the first element `fn` + // returns truthy for. `fn` is invoked with two arguments: `key` and `value`. + // `key` is an int index if `x` is array. `key` is a string key if `x` is map. + // It returns undefined if `x` is not enumerable. + find: func(x, fn) { + if !is_enumerable(x) { return undefined } + + for k, v in x { + if fn(k, v) { return v } + } + }, + // find_key iterates over elements of `x`, returning key or index of the first + // element `fn` returns truthy for. `fn` is invoked with two arguments: `key` + // and `value`. `key` is an int index if `x` is array. `key` is a string key if + // `x` is map. It returns undefined if `x` is not enumerable. + find_key: func(x, fn) { + if !is_enumerable(x) { return undefined } + + for k, v in x { + if fn(k, v) { return k } + } + }, + // map creates an array of values by running each element in `x` through `fn`. + // `fn` is invoked with two arguments: `key` and `value`. `key` is an int index + // if `x` is array. `key` is a string key if `x` is map. It returns undefined + // if `x` is not enumerable. + map: func(x, fn) { + if !is_enumerable(x) { return undefined } + + dst := [] + for k, v in x { + dst = append(dst, fn(k, v)) + } + + return dst + }, + // key returns the first argument. + key: func(k, _) { return k }, + // value returns the second argument. + value: func(_, v) { return v } +} diff --git a/vendor/github.com/d5/tengo/v2/stdlib/stdlib.go b/vendor/github.com/d5/tengo/v2/stdlib/stdlib.go new file mode 100644 index 00000000..16c369a0 --- /dev/null +++ b/vendor/github.com/d5/tengo/v2/stdlib/stdlib.go @@ -0,0 +1,34 @@ +package stdlib + +//go:generate go run gensrcmods.go + +import ( + "github.com/d5/tengo/v2" +) + +// AllModuleNames returns a list of all default module names. +func AllModuleNames() []string { + var names []string + for name := range BuiltinModules { + names = append(names, name) + } + for name := range SourceModules { + names = append(names, name) + } + return names +} + +// GetModuleMap returns the module map that includes all modules +// for the given module names. +func GetModuleMap(names ...string) *tengo.ModuleMap { + modules := tengo.NewModuleMap() + for _, name := range names { + if mod := BuiltinModules[name]; mod != nil { + modules.AddBuiltinModule(name, mod) + } + if mod := SourceModules[name]; mod != "" { + modules.AddSourceModule(name, []byte(mod)) + } + } + return modules +} diff --git a/vendor/github.com/d5/tengo/v2/stdlib/text.go b/vendor/github.com/d5/tengo/v2/stdlib/text.go new file mode 100644 index 00000000..d7d5d1da --- /dev/null +++ b/vendor/github.com/d5/tengo/v2/stdlib/text.go @@ -0,0 +1,1072 @@ +package stdlib + +import ( + "fmt" + "regexp" + "strconv" + "strings" + "unicode/utf8" + + "github.com/d5/tengo/v2" +) + +var textModule = map[string]tengo.Object{ + "re_match": &tengo.UserFunction{ + Name: "re_match", + Value: textREMatch, + }, // re_match(pattern, text) => bool/error + "re_find": &tengo.UserFunction{ + Name: "re_find", + Value: textREFind, + }, // re_find(pattern, text, count) => [[{text:,begin:,end:}]]/undefined + "re_replace": &tengo.UserFunction{ + Name: "re_replace", + Value: textREReplace, + }, // re_replace(pattern, text, repl) => string/error + "re_split": &tengo.UserFunction{ + Name: "re_split", + Value: textRESplit, + }, // re_split(pattern, text, count) => [string]/error + "re_compile": &tengo.UserFunction{ + Name: "re_compile", + Value: textRECompile, + }, // re_compile(pattern) => Regexp/error + "compare": &tengo.UserFunction{ + Name: "compare", + Value: FuncASSRI(strings.Compare), + }, // compare(a, b) => int + "contains": &tengo.UserFunction{ + Name: "contains", + Value: FuncASSRB(strings.Contains), + }, // contains(s, substr) => bool + "contains_any": &tengo.UserFunction{ + Name: "contains_any", + Value: FuncASSRB(strings.ContainsAny), + }, // contains_any(s, chars) => bool + "count": &tengo.UserFunction{ + Name: "count", + Value: FuncASSRI(strings.Count), + }, // count(s, substr) => int + "equal_fold": &tengo.UserFunction{ + Name: "equal_fold", + Value: FuncASSRB(strings.EqualFold), + }, // "equal_fold(s, t) => bool + "fields": &tengo.UserFunction{ + Name: "fields", + Value: FuncASRSs(strings.Fields), + }, // fields(s) => [string] + "has_prefix": &tengo.UserFunction{ + Name: "has_prefix", + Value: FuncASSRB(strings.HasPrefix), + }, // has_prefix(s, prefix) => bool + "has_suffix": &tengo.UserFunction{ + Name: "has_suffix", + Value: FuncASSRB(strings.HasSuffix), + }, // has_suffix(s, suffix) => bool + "index": &tengo.UserFunction{ + Name: "index", + Value: FuncASSRI(strings.Index), + }, // index(s, substr) => int + "index_any": &tengo.UserFunction{ + Name: "index_any", + Value: FuncASSRI(strings.IndexAny), + }, // index_any(s, chars) => int + "join": &tengo.UserFunction{ + Name: "join", + Value: textJoin, + }, // join(arr, sep) => string + "last_index": &tengo.UserFunction{ + Name: "last_index", + Value: FuncASSRI(strings.LastIndex), + }, // last_index(s, substr) => int + "last_index_any": &tengo.UserFunction{ + Name: "last_index_any", + Value: FuncASSRI(strings.LastIndexAny), + }, // last_index_any(s, chars) => int + "repeat": &tengo.UserFunction{ + Name: "repeat", + Value: textRepeat, + }, // repeat(s, count) => string + "replace": &tengo.UserFunction{ + Name: "replace", + Value: textReplace, + }, // replace(s, old, new, n) => string + "substr": &tengo.UserFunction{ + Name: "substr", + Value: textSubstring, + }, // substr(s, lower, upper) => string + "split": &tengo.UserFunction{ + Name: "split", + Value: FuncASSRSs(strings.Split), + }, // split(s, sep) => [string] + "split_after": &tengo.UserFunction{ + Name: "split_after", + Value: FuncASSRSs(strings.SplitAfter), + }, // split_after(s, sep) => [string] + "split_after_n": &tengo.UserFunction{ + Name: "split_after_n", + Value: FuncASSIRSs(strings.SplitAfterN), + }, // split_after_n(s, sep, n) => [string] + "split_n": &tengo.UserFunction{ + Name: "split_n", + Value: FuncASSIRSs(strings.SplitN), + }, // split_n(s, sep, n) => [string] + "title": &tengo.UserFunction{ + Name: "title", + Value: FuncASRS(strings.Title), + }, // title(s) => string + "to_lower": &tengo.UserFunction{ + Name: "to_lower", + Value: FuncASRS(strings.ToLower), + }, // to_lower(s) => string + "to_title": &tengo.UserFunction{ + Name: "to_title", + Value: FuncASRS(strings.ToTitle), + }, // to_title(s) => string + "to_upper": &tengo.UserFunction{ + Name: "to_upper", + Value: FuncASRS(strings.ToUpper), + }, // to_upper(s) => string + "pad_left": &tengo.UserFunction{ + Name: "pad_left", + Value: textPadLeft, + }, // pad_left(s, pad_len, pad_with) => string + "pad_right": &tengo.UserFunction{ + Name: "pad_right", + Value: textPadRight, + }, // pad_right(s, pad_len, pad_with) => string + "trim": &tengo.UserFunction{ + Name: "trim", + Value: FuncASSRS(strings.Trim), + }, // trim(s, cutset) => string + "trim_left": &tengo.UserFunction{ + Name: "trim_left", + Value: FuncASSRS(strings.TrimLeft), + }, // trim_left(s, cutset) => string + "trim_prefix": &tengo.UserFunction{ + Name: "trim_prefix", + Value: FuncASSRS(strings.TrimPrefix), + }, // trim_prefix(s, prefix) => string + "trim_right": &tengo.UserFunction{ + Name: "trim_right", + Value: FuncASSRS(strings.TrimRight), + }, // trim_right(s, cutset) => string + "trim_space": &tengo.UserFunction{ + Name: "trim_space", + Value: FuncASRS(strings.TrimSpace), + }, // trim_space(s) => string + "trim_suffix": &tengo.UserFunction{ + Name: "trim_suffix", + Value: FuncASSRS(strings.TrimSuffix), + }, // trim_suffix(s, suffix) => string + "atoi": &tengo.UserFunction{ + Name: "atoi", + Value: FuncASRIE(strconv.Atoi), + }, // atoi(str) => int/error + "format_bool": &tengo.UserFunction{ + Name: "format_bool", + Value: textFormatBool, + }, // format_bool(b) => string + "format_float": &tengo.UserFunction{ + Name: "format_float", + Value: textFormatFloat, + }, // format_float(f, fmt, prec, bits) => string + "format_int": &tengo.UserFunction{ + Name: "format_int", + Value: textFormatInt, + }, // format_int(i, base) => string + "itoa": &tengo.UserFunction{ + Name: "itoa", + Value: FuncAIRS(strconv.Itoa), + }, // itoa(i) => string + "parse_bool": &tengo.UserFunction{ + Name: "parse_bool", + Value: textParseBool, + }, // parse_bool(str) => bool/error + "parse_float": &tengo.UserFunction{ + Name: "parse_float", + Value: textParseFloat, + }, // parse_float(str, bits) => float/error + "parse_int": &tengo.UserFunction{ + Name: "parse_int", + Value: textParseInt, + }, // parse_int(str, base, bits) => int/error + "quote": &tengo.UserFunction{ + Name: "quote", + Value: FuncASRS(strconv.Quote), + }, // quote(str) => string + "unquote": &tengo.UserFunction{ + Name: "unquote", + Value: FuncASRSE(strconv.Unquote), + }, // unquote(str) => string/error +} + +func textREMatch(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 2 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := tengo.ToString(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + return + } + + s2, ok := tengo.ToString(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "string(compatible)", + Found: args[1].TypeName(), + } + return + } + + matched, err := regexp.MatchString(s1, s2) + if err != nil { + ret = wrapError(err) + return + } + + if matched { + ret = tengo.TrueValue + } else { + ret = tengo.FalseValue + } + + return +} + +func textREFind(args ...tengo.Object) (ret tengo.Object, err error) { + numArgs := len(args) + if numArgs != 2 && numArgs != 3 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := tengo.ToString(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + return + } + + re, err := regexp.Compile(s1) + if err != nil { + ret = wrapError(err) + return + } + + s2, ok := tengo.ToString(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "string(compatible)", + Found: args[1].TypeName(), + } + return + } + + if numArgs < 3 { + m := re.FindStringSubmatchIndex(s2) + if m == nil { + ret = tengo.UndefinedValue + return + } + + arr := &tengo.Array{} + for i := 0; i < len(m); i += 2 { + arr.Value = append(arr.Value, + &tengo.ImmutableMap{Value: map[string]tengo.Object{ + "text": &tengo.String{Value: s2[m[i]:m[i+1]]}, + "begin": &tengo.Int{Value: int64(m[i])}, + "end": &tengo.Int{Value: int64(m[i+1])}, + }}) + } + + ret = &tengo.Array{Value: []tengo.Object{arr}} + + return + } + + i3, ok := tengo.ToInt(args[2]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "third", + Expected: "int(compatible)", + Found: args[2].TypeName(), + } + return + } + m := re.FindAllStringSubmatchIndex(s2, i3) + if m == nil { + ret = tengo.UndefinedValue + return + } + + arr := &tengo.Array{} + for _, m := range m { + subMatch := &tengo.Array{} + for i := 0; i < len(m); i += 2 { + subMatch.Value = append(subMatch.Value, + &tengo.ImmutableMap{Value: map[string]tengo.Object{ + "text": &tengo.String{Value: s2[m[i]:m[i+1]]}, + "begin": &tengo.Int{Value: int64(m[i])}, + "end": &tengo.Int{Value: int64(m[i+1])}, + }}) + } + + arr.Value = append(arr.Value, subMatch) + } + + ret = arr + + return +} + +func textREReplace(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 3 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := tengo.ToString(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + return + } + + s2, ok := tengo.ToString(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "string(compatible)", + Found: args[1].TypeName(), + } + return + } + + s3, ok := tengo.ToString(args[2]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "third", + Expected: "string(compatible)", + Found: args[2].TypeName(), + } + return + } + + re, err := regexp.Compile(s1) + if err != nil { + ret = wrapError(err) + } else { + s, ok := doTextRegexpReplace(re, s2, s3) + if !ok { + return nil, tengo.ErrStringLimit + } + + ret = &tengo.String{Value: s} + } + + return +} + +func textRESplit(args ...tengo.Object) (ret tengo.Object, err error) { + numArgs := len(args) + if numArgs != 2 && numArgs != 3 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := tengo.ToString(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + return + } + + s2, ok := tengo.ToString(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "string(compatible)", + Found: args[1].TypeName(), + } + return + } + + var i3 = -1 + if numArgs > 2 { + i3, ok = tengo.ToInt(args[2]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "third", + Expected: "int(compatible)", + Found: args[2].TypeName(), + } + return + } + } + + re, err := regexp.Compile(s1) + if err != nil { + ret = wrapError(err) + return + } + + arr := &tengo.Array{} + for _, s := range re.Split(s2, i3) { + arr.Value = append(arr.Value, &tengo.String{Value: s}) + } + + ret = arr + + return +} + +func textRECompile(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := tengo.ToString(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + return + } + + re, err := regexp.Compile(s1) + if err != nil { + ret = wrapError(err) + } else { + ret = makeTextRegexp(re) + } + + return +} + +func textReplace(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 4 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := tengo.ToString(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + return + } + + s2, ok := tengo.ToString(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "string(compatible)", + Found: args[1].TypeName(), + } + return + } + + s3, ok := tengo.ToString(args[2]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "third", + Expected: "string(compatible)", + Found: args[2].TypeName(), + } + return + } + + i4, ok := tengo.ToInt(args[3]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "fourth", + Expected: "int(compatible)", + Found: args[3].TypeName(), + } + return + } + + s, ok := doTextReplace(s1, s2, s3, i4) + if !ok { + err = tengo.ErrStringLimit + return + } + + ret = &tengo.String{Value: s} + + return +} + +func textSubstring(args ...tengo.Object) (ret tengo.Object, err error) { + argslen := len(args) + if argslen != 2 && argslen != 3 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := tengo.ToString(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + return + } + + i2, ok := tengo.ToInt(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + return + } + + strlen := len(s1) + i3 := strlen + if argslen == 3 { + i3, ok = tengo.ToInt(args[2]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "third", + Expected: "int(compatible)", + Found: args[2].TypeName(), + } + return + } + } + + if i2 > i3 { + err = tengo.ErrInvalidIndexType + return + } + + if i2 < 0 { + i2 = 0 + } else if i2 > strlen { + i2 = strlen + } + + if i3 < 0 { + i3 = 0 + } else if i3 > strlen { + i3 = strlen + } + + ret = &tengo.String{Value: s1[i2:i3]} + + return +} + +func textPadLeft(args ...tengo.Object) (ret tengo.Object, err error) { + argslen := len(args) + if argslen != 2 && argslen != 3 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := tengo.ToString(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + return + } + + i2, ok := tengo.ToInt(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + return + } + + if i2 > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + + sLen := len(s1) + if sLen >= i2 { + ret = &tengo.String{Value: s1} + return + } + + s3 := " " + if argslen == 3 { + s3, ok = tengo.ToString(args[2]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "third", + Expected: "string(compatible)", + Found: args[2].TypeName(), + } + return + } + } + + padStrLen := len(s3) + if padStrLen == 0 { + ret = &tengo.String{Value: s1} + return + } + + padCount := ((i2 - padStrLen) / padStrLen) + 1 + retStr := strings.Repeat(s3, padCount) + s1 + ret = &tengo.String{Value: retStr[len(retStr)-i2:]} + + return +} + +func textPadRight(args ...tengo.Object) (ret tengo.Object, err error) { + argslen := len(args) + if argslen != 2 && argslen != 3 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := tengo.ToString(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + return + } + + i2, ok := tengo.ToInt(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + return + } + + if i2 > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + + sLen := len(s1) + if sLen >= i2 { + ret = &tengo.String{Value: s1} + return + } + + s3 := " " + if argslen == 3 { + s3, ok = tengo.ToString(args[2]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "third", + Expected: "string(compatible)", + Found: args[2].TypeName(), + } + return + } + } + + padStrLen := len(s3) + if padStrLen == 0 { + ret = &tengo.String{Value: s1} + return + } + + padCount := ((i2 - padStrLen) / padStrLen) + 1 + retStr := s1 + strings.Repeat(s3, padCount) + ret = &tengo.String{Value: retStr[:i2]} + + return +} + +func textRepeat(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 2 { + return nil, tengo.ErrWrongNumArguments + } + + s1, ok := tengo.ToString(args[0]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + } + + i2, ok := tengo.ToInt(args[1]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + } + + if len(s1)*i2 > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + + return &tengo.String{Value: strings.Repeat(s1, i2)}, nil +} + +func textJoin(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 2 { + return nil, tengo.ErrWrongNumArguments + } + + var slen int + var ss1 []string + switch arg0 := args[0].(type) { + case *tengo.Array: + for idx, a := range arg0.Value { + as, ok := tengo.ToString(a) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: fmt.Sprintf("first[%d]", idx), + Expected: "string(compatible)", + Found: a.TypeName(), + } + } + slen += len(as) + ss1 = append(ss1, as) + } + case *tengo.ImmutableArray: + for idx, a := range arg0.Value { + as, ok := tengo.ToString(a) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: fmt.Sprintf("first[%d]", idx), + Expected: "string(compatible)", + Found: a.TypeName(), + } + } + slen += len(as) + ss1 = append(ss1, as) + } + default: + return nil, tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "array", + Found: args[0].TypeName(), + } + } + + s2, ok := tengo.ToString(args[1]) + if !ok { + return nil, tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "string(compatible)", + Found: args[1].TypeName(), + } + } + + // make sure output length does not exceed the limit + if slen+len(s2)*(len(ss1)-1) > tengo.MaxStringLen { + return nil, tengo.ErrStringLimit + } + + return &tengo.String{Value: strings.Join(ss1, s2)}, nil +} + +func textFormatBool(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + b1, ok := args[0].(*tengo.Bool) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "bool", + Found: args[0].TypeName(), + } + return + } + + if b1 == tengo.TrueValue { + ret = &tengo.String{Value: "true"} + } else { + ret = &tengo.String{Value: "false"} + } + + return +} + +func textFormatFloat(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 4 { + err = tengo.ErrWrongNumArguments + return + } + + f1, ok := args[0].(*tengo.Float) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "float", + Found: args[0].TypeName(), + } + return + } + + s2, ok := tengo.ToString(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "string(compatible)", + Found: args[1].TypeName(), + } + return + } + + i3, ok := tengo.ToInt(args[2]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "third", + Expected: "int(compatible)", + Found: args[2].TypeName(), + } + return + } + + i4, ok := tengo.ToInt(args[3]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "fourth", + Expected: "int(compatible)", + Found: args[3].TypeName(), + } + return + } + + ret = &tengo.String{Value: strconv.FormatFloat(f1.Value, s2[0], i3, i4)} + + return +} + +func textFormatInt(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 2 { + err = tengo.ErrWrongNumArguments + return + } + + i1, ok := args[0].(*tengo.Int) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "int", + Found: args[0].TypeName(), + } + return + } + + i2, ok := tengo.ToInt(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + return + } + + ret = &tengo.String{Value: strconv.FormatInt(i1.Value, i2)} + + return +} + +func textParseBool(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := args[0].(*tengo.String) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string", + Found: args[0].TypeName(), + } + return + } + + parsed, err := strconv.ParseBool(s1.Value) + if err != nil { + ret = wrapError(err) + return + } + + if parsed { + ret = tengo.TrueValue + } else { + ret = tengo.FalseValue + } + + return +} + +func textParseFloat(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 2 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := args[0].(*tengo.String) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string", + Found: args[0].TypeName(), + } + return + } + + i2, ok := tengo.ToInt(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + return + } + + parsed, err := strconv.ParseFloat(s1.Value, i2) + if err != nil { + ret = wrapError(err) + return + } + + ret = &tengo.Float{Value: parsed} + + return +} + +func textParseInt(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 3 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := args[0].(*tengo.String) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string", + Found: args[0].TypeName(), + } + return + } + + i2, ok := tengo.ToInt(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + return + } + + i3, ok := tengo.ToInt(args[2]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "third", + Expected: "int(compatible)", + Found: args[2].TypeName(), + } + return + } + + parsed, err := strconv.ParseInt(s1.Value, i2, i3) + if err != nil { + ret = wrapError(err) + return + } + + ret = &tengo.Int{Value: parsed} + + return +} + +// Modified implementation of strings.Replace +// to limit the maximum length of output string. +func doTextReplace(s, old, new string, n int) (string, bool) { + if old == new || n == 0 { + return s, true // avoid allocation + } + + // Compute number of replacements. + if m := strings.Count(s, old); m == 0 { + return s, true // avoid allocation + } else if n < 0 || m < n { + n = m + } + + // Apply replacements to buffer. + t := make([]byte, len(s)+n*(len(new)-len(old))) + w := 0 + start := 0 + for i := 0; i < n; i++ { + j := start + if len(old) == 0 { + if i > 0 { + _, wid := utf8.DecodeRuneInString(s[start:]) + j += wid + } + } else { + j += strings.Index(s[start:], old) + } + + ssj := s[start:j] + if w+len(ssj)+len(new) > tengo.MaxStringLen { + return "", false + } + + w += copy(t[w:], ssj) + w += copy(t[w:], new) + start = j + len(old) + } + + ss := s[start:] + if w+len(ss) > tengo.MaxStringLen { + return "", false + } + + w += copy(t[w:], ss) + + return string(t[0:w]), true +} diff --git a/vendor/github.com/d5/tengo/v2/stdlib/text_regexp.go b/vendor/github.com/d5/tengo/v2/stdlib/text_regexp.go new file mode 100644 index 00000000..1a7ecf07 --- /dev/null +++ b/vendor/github.com/d5/tengo/v2/stdlib/text_regexp.go @@ -0,0 +1,251 @@ +package stdlib + +import ( + "regexp" + + "github.com/d5/tengo/v2" +) + +func makeTextRegexp(re *regexp.Regexp) *tengo.ImmutableMap { + return &tengo.ImmutableMap{ + Value: map[string]tengo.Object{ + // match(text) => bool + "match": &tengo.UserFunction{ + Value: func(args ...tengo.Object) ( + ret tengo.Object, + err error, + ) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := tengo.ToString(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + return + } + + if re.MatchString(s1) { + ret = tengo.TrueValue + } else { + ret = tengo.FalseValue + } + + return + }, + }, + + // find(text) => array(array({text:,begin:,end:}))/undefined + // find(text, maxCount) => array(array({text:,begin:,end:}))/undefined + "find": &tengo.UserFunction{ + Value: func(args ...tengo.Object) ( + ret tengo.Object, + err error, + ) { + numArgs := len(args) + if numArgs != 1 && numArgs != 2 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := tengo.ToString(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + return + } + + if numArgs == 1 { + m := re.FindStringSubmatchIndex(s1) + if m == nil { + ret = tengo.UndefinedValue + return + } + + arr := &tengo.Array{} + for i := 0; i < len(m); i += 2 { + arr.Value = append(arr.Value, + &tengo.ImmutableMap{ + Value: map[string]tengo.Object{ + "text": &tengo.String{ + Value: s1[m[i]:m[i+1]], + }, + "begin": &tengo.Int{ + Value: int64(m[i]), + }, + "end": &tengo.Int{ + Value: int64(m[i+1]), + }, + }}) + } + + ret = &tengo.Array{Value: []tengo.Object{arr}} + + return + } + + i2, ok := tengo.ToInt(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + return + } + m := re.FindAllStringSubmatchIndex(s1, i2) + if m == nil { + ret = tengo.UndefinedValue + return + } + + arr := &tengo.Array{} + for _, m := range m { + subMatch := &tengo.Array{} + for i := 0; i < len(m); i += 2 { + subMatch.Value = append(subMatch.Value, + &tengo.ImmutableMap{ + Value: map[string]tengo.Object{ + "text": &tengo.String{ + Value: s1[m[i]:m[i+1]], + }, + "begin": &tengo.Int{ + Value: int64(m[i]), + }, + "end": &tengo.Int{ + Value: int64(m[i+1]), + }, + }}) + } + + arr.Value = append(arr.Value, subMatch) + } + + ret = arr + + return + }, + }, + + // replace(src, repl) => string + "replace": &tengo.UserFunction{ + Value: func(args ...tengo.Object) ( + ret tengo.Object, + err error, + ) { + if len(args) != 2 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := tengo.ToString(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + return + } + + s2, ok := tengo.ToString(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "string(compatible)", + Found: args[1].TypeName(), + } + return + } + + s, ok := doTextRegexpReplace(re, s1, s2) + if !ok { + return nil, tengo.ErrStringLimit + } + + ret = &tengo.String{Value: s} + + return + }, + }, + + // split(text) => array(string) + // split(text, maxCount) => array(string) + "split": &tengo.UserFunction{ + Value: func(args ...tengo.Object) ( + ret tengo.Object, + err error, + ) { + numArgs := len(args) + if numArgs != 1 && numArgs != 2 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := tengo.ToString(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + return + } + + var i2 = -1 + if numArgs > 1 { + i2, ok = tengo.ToInt(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + return + } + } + + arr := &tengo.Array{} + for _, s := range re.Split(s1, i2) { + arr.Value = append(arr.Value, + &tengo.String{Value: s}) + } + + ret = arr + + return + }, + }, + }, + } +} + +// Size-limit checking implementation of regexp.ReplaceAllString. +func doTextRegexpReplace(re *regexp.Regexp, src, repl string) (string, bool) { + idx := 0 + out := "" + for _, m := range re.FindAllStringSubmatchIndex(src, -1) { + var exp []byte + exp = re.ExpandString(exp, repl, src, m) + if len(out)+m[0]-idx+len(exp) > tengo.MaxStringLen { + return "", false + } + out += src[idx:m[0]] + string(exp) + idx = m[1] + } + if idx < len(src) { + if len(out)+len(src)-idx > tengo.MaxStringLen { + return "", false + } + out += src[idx:] + } + return out, true +} diff --git a/vendor/github.com/d5/tengo/v2/stdlib/times.go b/vendor/github.com/d5/tengo/v2/stdlib/times.go new file mode 100644 index 00000000..0b6f7bd4 --- /dev/null +++ b/vendor/github.com/d5/tengo/v2/stdlib/times.go @@ -0,0 +1,1135 @@ +package stdlib + +import ( + "time" + + "github.com/d5/tengo/v2" +) + +var timesModule = map[string]tengo.Object{ + "format_ansic": &tengo.String{Value: time.ANSIC}, + "format_unix_date": &tengo.String{Value: time.UnixDate}, + "format_ruby_date": &tengo.String{Value: time.RubyDate}, + "format_rfc822": &tengo.String{Value: time.RFC822}, + "format_rfc822z": &tengo.String{Value: time.RFC822Z}, + "format_rfc850": &tengo.String{Value: time.RFC850}, + "format_rfc1123": &tengo.String{Value: time.RFC1123}, + "format_rfc1123z": &tengo.String{Value: time.RFC1123Z}, + "format_rfc3339": &tengo.String{Value: time.RFC3339}, + "format_rfc3339_nano": &tengo.String{Value: time.RFC3339Nano}, + "format_kitchen": &tengo.String{Value: time.Kitchen}, + "format_stamp": &tengo.String{Value: time.Stamp}, + "format_stamp_milli": &tengo.String{Value: time.StampMilli}, + "format_stamp_micro": &tengo.String{Value: time.StampMicro}, + "format_stamp_nano": &tengo.String{Value: time.StampNano}, + "nanosecond": &tengo.Int{Value: int64(time.Nanosecond)}, + "microsecond": &tengo.Int{Value: int64(time.Microsecond)}, + "millisecond": &tengo.Int{Value: int64(time.Millisecond)}, + "second": &tengo.Int{Value: int64(time.Second)}, + "minute": &tengo.Int{Value: int64(time.Minute)}, + "hour": &tengo.Int{Value: int64(time.Hour)}, + "january": &tengo.Int{Value: int64(time.January)}, + "february": &tengo.Int{Value: int64(time.February)}, + "march": &tengo.Int{Value: int64(time.March)}, + "april": &tengo.Int{Value: int64(time.April)}, + "may": &tengo.Int{Value: int64(time.May)}, + "june": &tengo.Int{Value: int64(time.June)}, + "july": &tengo.Int{Value: int64(time.July)}, + "august": &tengo.Int{Value: int64(time.August)}, + "september": &tengo.Int{Value: int64(time.September)}, + "october": &tengo.Int{Value: int64(time.October)}, + "november": &tengo.Int{Value: int64(time.November)}, + "december": &tengo.Int{Value: int64(time.December)}, + "sleep": &tengo.UserFunction{ + Name: "sleep", + Value: timesSleep, + }, // sleep(int) + "parse_duration": &tengo.UserFunction{ + Name: "parse_duration", + Value: timesParseDuration, + }, // parse_duration(str) => int + "since": &tengo.UserFunction{ + Name: "since", + Value: timesSince, + }, // since(time) => int + "until": &tengo.UserFunction{ + Name: "until", + Value: timesUntil, + }, // until(time) => int + "duration_hours": &tengo.UserFunction{ + Name: "duration_hours", + Value: timesDurationHours, + }, // duration_hours(int) => float + "duration_minutes": &tengo.UserFunction{ + Name: "duration_minutes", + Value: timesDurationMinutes, + }, // duration_minutes(int) => float + "duration_nanoseconds": &tengo.UserFunction{ + Name: "duration_nanoseconds", + Value: timesDurationNanoseconds, + }, // duration_nanoseconds(int) => int + "duration_seconds": &tengo.UserFunction{ + Name: "duration_seconds", + Value: timesDurationSeconds, + }, // duration_seconds(int) => float + "duration_string": &tengo.UserFunction{ + Name: "duration_string", + Value: timesDurationString, + }, // duration_string(int) => string + "month_string": &tengo.UserFunction{ + Name: "month_string", + Value: timesMonthString, + }, // month_string(int) => string + "date": &tengo.UserFunction{ + Name: "date", + Value: timesDate, + }, // date(year, month, day, hour, min, sec, nsec) => time + "now": &tengo.UserFunction{ + Name: "now", + Value: timesNow, + }, // now() => time + "parse": &tengo.UserFunction{ + Name: "parse", + Value: timesParse, + }, // parse(format, str) => time + "unix": &tengo.UserFunction{ + Name: "unix", + Value: timesUnix, + }, // unix(sec, nsec) => time + "add": &tengo.UserFunction{ + Name: "add", + Value: timesAdd, + }, // add(time, int) => time + "add_date": &tengo.UserFunction{ + Name: "add_date", + Value: timesAddDate, + }, // add_date(time, years, months, days) => time + "sub": &tengo.UserFunction{ + Name: "sub", + Value: timesSub, + }, // sub(t time, u time) => int + "after": &tengo.UserFunction{ + Name: "after", + Value: timesAfter, + }, // after(t time, u time) => bool + "before": &tengo.UserFunction{ + Name: "before", + Value: timesBefore, + }, // before(t time, u time) => bool + "time_year": &tengo.UserFunction{ + Name: "time_year", + Value: timesTimeYear, + }, // time_year(time) => int + "time_month": &tengo.UserFunction{ + Name: "time_month", + Value: timesTimeMonth, + }, // time_month(time) => int + "time_day": &tengo.UserFunction{ + Name: "time_day", + Value: timesTimeDay, + }, // time_day(time) => int + "time_weekday": &tengo.UserFunction{ + Name: "time_weekday", + Value: timesTimeWeekday, + }, // time_weekday(time) => int + "time_hour": &tengo.UserFunction{ + Name: "time_hour", + Value: timesTimeHour, + }, // time_hour(time) => int + "time_minute": &tengo.UserFunction{ + Name: "time_minute", + Value: timesTimeMinute, + }, // time_minute(time) => int + "time_second": &tengo.UserFunction{ + Name: "time_second", + Value: timesTimeSecond, + }, // time_second(time) => int + "time_nanosecond": &tengo.UserFunction{ + Name: "time_nanosecond", + Value: timesTimeNanosecond, + }, // time_nanosecond(time) => int + "time_unix": &tengo.UserFunction{ + Name: "time_unix", + Value: timesTimeUnix, + }, // time_unix(time) => int + "time_unix_nano": &tengo.UserFunction{ + Name: "time_unix_nano", + Value: timesTimeUnixNano, + }, // time_unix_nano(time) => int + "time_format": &tengo.UserFunction{ + Name: "time_format", + Value: timesTimeFormat, + }, // time_format(time, format) => string + "time_location": &tengo.UserFunction{ + Name: "time_location", + Value: timesTimeLocation, + }, // time_location(time) => string + "time_string": &tengo.UserFunction{ + Name: "time_string", + Value: timesTimeString, + }, // time_string(time) => string + "is_zero": &tengo.UserFunction{ + Name: "is_zero", + Value: timesIsZero, + }, // is_zero(time) => bool + "to_local": &tengo.UserFunction{ + Name: "to_local", + Value: timesToLocal, + }, // to_local(time) => time + "to_utc": &tengo.UserFunction{ + Name: "to_utc", + Value: timesToUTC, + }, // to_utc(time) => time +} + +func timesSleep(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + i1, ok := tengo.ToInt64(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "int(compatible)", + Found: args[0].TypeName(), + } + return + } + + time.Sleep(time.Duration(i1)) + ret = tengo.UndefinedValue + + return +} + +func timesParseDuration(args ...tengo.Object) ( + ret tengo.Object, + err error, +) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := tengo.ToString(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + return + } + + dur, err := time.ParseDuration(s1) + if err != nil { + ret = wrapError(err) + return + } + + ret = &tengo.Int{Value: int64(dur)} + + return +} + +func timesSince(args ...tengo.Object) ( + ret tengo.Object, + err error, +) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + t1, ok := tengo.ToTime(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "time(compatible)", + Found: args[0].TypeName(), + } + return + } + + ret = &tengo.Int{Value: int64(time.Since(t1))} + + return +} + +func timesUntil(args ...tengo.Object) ( + ret tengo.Object, + err error, +) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + t1, ok := tengo.ToTime(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "time(compatible)", + Found: args[0].TypeName(), + } + return + } + + ret = &tengo.Int{Value: int64(time.Until(t1))} + + return +} + +func timesDurationHours(args ...tengo.Object) ( + ret tengo.Object, + err error, +) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + i1, ok := tengo.ToInt64(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "int(compatible)", + Found: args[0].TypeName(), + } + return + } + + ret = &tengo.Float{Value: time.Duration(i1).Hours()} + + return +} + +func timesDurationMinutes(args ...tengo.Object) ( + ret tengo.Object, + err error, +) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + i1, ok := tengo.ToInt64(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "int(compatible)", + Found: args[0].TypeName(), + } + return + } + + ret = &tengo.Float{Value: time.Duration(i1).Minutes()} + + return +} + +func timesDurationNanoseconds(args ...tengo.Object) ( + ret tengo.Object, + err error, +) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + i1, ok := tengo.ToInt64(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "int(compatible)", + Found: args[0].TypeName(), + } + return + } + + ret = &tengo.Int{Value: time.Duration(i1).Nanoseconds()} + + return +} + +func timesDurationSeconds(args ...tengo.Object) ( + ret tengo.Object, + err error, +) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + i1, ok := tengo.ToInt64(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "int(compatible)", + Found: args[0].TypeName(), + } + return + } + + ret = &tengo.Float{Value: time.Duration(i1).Seconds()} + + return +} + +func timesDurationString(args ...tengo.Object) ( + ret tengo.Object, + err error, +) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + i1, ok := tengo.ToInt64(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "int(compatible)", + Found: args[0].TypeName(), + } + return + } + + ret = &tengo.String{Value: time.Duration(i1).String()} + + return +} + +func timesMonthString(args ...tengo.Object) ( + ret tengo.Object, + err error, +) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + i1, ok := tengo.ToInt64(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "int(compatible)", + Found: args[0].TypeName(), + } + return + } + + ret = &tengo.String{Value: time.Month(i1).String()} + + return +} + +func timesDate(args ...tengo.Object) ( + ret tengo.Object, + err error, +) { + if len(args) != 7 { + err = tengo.ErrWrongNumArguments + return + } + + i1, ok := tengo.ToInt(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "int(compatible)", + Found: args[0].TypeName(), + } + return + } + i2, ok := tengo.ToInt(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + return + } + i3, ok := tengo.ToInt(args[2]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "third", + Expected: "int(compatible)", + Found: args[2].TypeName(), + } + return + } + i4, ok := tengo.ToInt(args[3]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "fourth", + Expected: "int(compatible)", + Found: args[3].TypeName(), + } + return + } + i5, ok := tengo.ToInt(args[4]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "fifth", + Expected: "int(compatible)", + Found: args[4].TypeName(), + } + return + } + i6, ok := tengo.ToInt(args[5]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "sixth", + Expected: "int(compatible)", + Found: args[5].TypeName(), + } + return + } + i7, ok := tengo.ToInt(args[6]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "seventh", + Expected: "int(compatible)", + Found: args[6].TypeName(), + } + return + } + + ret = &tengo.Time{ + Value: time.Date(i1, + time.Month(i2), i3, i4, i5, i6, i7, time.Now().Location()), + } + + return +} + +func timesNow(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 0 { + err = tengo.ErrWrongNumArguments + return + } + + ret = &tengo.Time{Value: time.Now()} + + return +} + +func timesParse(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 2 { + err = tengo.ErrWrongNumArguments + return + } + + s1, ok := tengo.ToString(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "string(compatible)", + Found: args[0].TypeName(), + } + return + } + + s2, ok := tengo.ToString(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "string(compatible)", + Found: args[1].TypeName(), + } + return + } + + parsed, err := time.Parse(s1, s2) + if err != nil { + ret = wrapError(err) + return + } + + ret = &tengo.Time{Value: parsed} + + return +} + +func timesUnix(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 2 { + err = tengo.ErrWrongNumArguments + return + } + + i1, ok := tengo.ToInt64(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "int(compatible)", + Found: args[0].TypeName(), + } + return + } + + i2, ok := tengo.ToInt64(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + return + } + + ret = &tengo.Time{Value: time.Unix(i1, i2)} + + return +} + +func timesAdd(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 2 { + err = tengo.ErrWrongNumArguments + return + } + + t1, ok := tengo.ToTime(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "time(compatible)", + Found: args[0].TypeName(), + } + return + } + + i2, ok := tengo.ToInt64(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + return + } + + ret = &tengo.Time{Value: t1.Add(time.Duration(i2))} + + return +} + +func timesSub(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 2 { + err = tengo.ErrWrongNumArguments + return + } + + t1, ok := tengo.ToTime(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "time(compatible)", + Found: args[0].TypeName(), + } + return + } + + t2, ok := tengo.ToTime(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "time(compatible)", + Found: args[1].TypeName(), + } + return + } + + ret = &tengo.Int{Value: int64(t1.Sub(t2))} + + return +} + +func timesAddDate(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 4 { + err = tengo.ErrWrongNumArguments + return + } + + t1, ok := tengo.ToTime(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "time(compatible)", + Found: args[0].TypeName(), + } + return + } + + i2, ok := tengo.ToInt(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "int(compatible)", + Found: args[1].TypeName(), + } + return + } + + i3, ok := tengo.ToInt(args[2]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "third", + Expected: "int(compatible)", + Found: args[2].TypeName(), + } + return + } + + i4, ok := tengo.ToInt(args[3]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "fourth", + Expected: "int(compatible)", + Found: args[3].TypeName(), + } + return + } + + ret = &tengo.Time{Value: t1.AddDate(i2, i3, i4)} + + return +} + +func timesAfter(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 2 { + err = tengo.ErrWrongNumArguments + return + } + + t1, ok := tengo.ToTime(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "time(compatible)", + Found: args[0].TypeName(), + } + return + } + + t2, ok := tengo.ToTime(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "time(compatible)", + Found: args[1].TypeName(), + } + return + } + + if t1.After(t2) { + ret = tengo.TrueValue + } else { + ret = tengo.FalseValue + } + + return +} + +func timesBefore(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 2 { + err = tengo.ErrWrongNumArguments + return + } + + t1, ok := tengo.ToTime(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "time(compatible)", + Found: args[0].TypeName(), + } + return + } + + t2, ok := tengo.ToTime(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "time(compatible)", + Found: args[0].TypeName(), + } + return + } + + if t1.Before(t2) { + ret = tengo.TrueValue + } else { + ret = tengo.FalseValue + } + + return +} + +func timesTimeYear(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + t1, ok := tengo.ToTime(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "time(compatible)", + Found: args[0].TypeName(), + } + return + } + + ret = &tengo.Int{Value: int64(t1.Year())} + + return +} + +func timesTimeMonth(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + t1, ok := tengo.ToTime(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "time(compatible)", + Found: args[0].TypeName(), + } + return + } + + ret = &tengo.Int{Value: int64(t1.Month())} + + return +} + +func timesTimeDay(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + t1, ok := tengo.ToTime(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "time(compatible)", + Found: args[0].TypeName(), + } + return + } + + ret = &tengo.Int{Value: int64(t1.Day())} + + return +} + +func timesTimeWeekday(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + t1, ok := tengo.ToTime(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "time(compatible)", + Found: args[0].TypeName(), + } + return + } + + ret = &tengo.Int{Value: int64(t1.Weekday())} + + return +} + +func timesTimeHour(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + t1, ok := tengo.ToTime(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "time(compatible)", + Found: args[0].TypeName(), + } + return + } + + ret = &tengo.Int{Value: int64(t1.Hour())} + + return +} + +func timesTimeMinute(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + t1, ok := tengo.ToTime(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "time(compatible)", + Found: args[0].TypeName(), + } + return + } + + ret = &tengo.Int{Value: int64(t1.Minute())} + + return +} + +func timesTimeSecond(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + t1, ok := tengo.ToTime(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "time(compatible)", + Found: args[0].TypeName(), + } + return + } + + ret = &tengo.Int{Value: int64(t1.Second())} + + return +} + +func timesTimeNanosecond(args ...tengo.Object) ( + ret tengo.Object, + err error, +) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + t1, ok := tengo.ToTime(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "time(compatible)", + Found: args[0].TypeName(), + } + return + } + + ret = &tengo.Int{Value: int64(t1.Nanosecond())} + + return +} + +func timesTimeUnix(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + t1, ok := tengo.ToTime(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "time(compatible)", + Found: args[0].TypeName(), + } + return + } + + ret = &tengo.Int{Value: t1.Unix()} + + return +} + +func timesTimeUnixNano(args ...tengo.Object) ( + ret tengo.Object, + err error, +) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + t1, ok := tengo.ToTime(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "time(compatible)", + Found: args[0].TypeName(), + } + return + } + + ret = &tengo.Int{Value: t1.UnixNano()} + + return +} + +func timesTimeFormat(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 2 { + err = tengo.ErrWrongNumArguments + return + } + + t1, ok := tengo.ToTime(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "time(compatible)", + Found: args[0].TypeName(), + } + return + } + + s2, ok := tengo.ToString(args[1]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "second", + Expected: "string(compatible)", + Found: args[1].TypeName(), + } + return + } + + s := t1.Format(s2) + if len(s) > tengo.MaxStringLen { + + return nil, tengo.ErrStringLimit + } + + ret = &tengo.String{Value: s} + + return +} + +func timesIsZero(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + t1, ok := tengo.ToTime(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "time(compatible)", + Found: args[0].TypeName(), + } + return + } + + if t1.IsZero() { + ret = tengo.TrueValue + } else { + ret = tengo.FalseValue + } + + return +} + +func timesToLocal(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + t1, ok := tengo.ToTime(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "time(compatible)", + Found: args[0].TypeName(), + } + return + } + + ret = &tengo.Time{Value: t1.Local()} + + return +} + +func timesToUTC(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + t1, ok := tengo.ToTime(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "time(compatible)", + Found: args[0].TypeName(), + } + return + } + + ret = &tengo.Time{Value: t1.UTC()} + + return +} + +func timesTimeLocation(args ...tengo.Object) ( + ret tengo.Object, + err error, +) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + t1, ok := tengo.ToTime(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "time(compatible)", + Found: args[0].TypeName(), + } + return + } + + ret = &tengo.String{Value: t1.Location().String()} + + return +} + +func timesTimeString(args ...tengo.Object) (ret tengo.Object, err error) { + if len(args) != 1 { + err = tengo.ErrWrongNumArguments + return + } + + t1, ok := tengo.ToTime(args[0]) + if !ok { + err = tengo.ErrInvalidArgumentType{ + Name: "first", + Expected: "time(compatible)", + Found: args[0].TypeName(), + } + return + } + + ret = &tengo.String{Value: t1.String()} + + return +} |