diff options
author | Wim <wim@42.be> | 2019-02-23 16:39:44 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-02-23 16:39:44 +0100 |
commit | 1bb39eba8717f62336cc98c5bb7cfbef194f3626 (patch) | |
tree | 0437ae89473b8e25ad1c9597e1049a23a7933f6a /vendor/github.com/d5/tengo/objects | |
parent | 3190703dc8618896c932a23d8ca155fbbf6fab13 (diff) | |
download | matterbridge-msglm-1bb39eba8717f62336cc98c5bb7cfbef194f3626.tar.gz matterbridge-msglm-1bb39eba8717f62336cc98c5bb7cfbef194f3626.tar.bz2 matterbridge-msglm-1bb39eba8717f62336cc98c5bb7cfbef194f3626.zip |
Add scripting (tengo) support for every incoming message (#731)
TengoModifyMessage allows you to specify the location of a tengo (https://github.com/d5/tengo/) script.
This script will receive every incoming message and can be used to modify the Username and the Text of that message.
The script will have the following global variables:
to modify: msgUsername and msgText
to read: msgChannel and msgAccount
The script is reloaded on every message, so you can modify the script on the fly.
Example script can be found in https://github.com/42wim/matterbridge/tree/master/gateway/bench.tengo
and https://github.com/42wim/matterbridge/tree/master/contrib/example.tengo
The example below will check if the text contains blah and if so, it'll replace the text and the username of that message.
text := import("text")
if text.re_match("blah",msgText) {
msgText="replaced by this"
msgUsername="fakeuser"
}
More information about tengo on: https://github.com/d5/tengo/blob/master/docs/tutorial.md and
https://github.com/d5/tengo/blob/master/docs/stdlib.md
Diffstat (limited to 'vendor/github.com/d5/tengo/objects')
42 files changed, 2862 insertions, 0 deletions
diff --git a/vendor/github.com/d5/tengo/objects/array.go b/vendor/github.com/d5/tengo/objects/array.go new file mode 100644 index 00000000..1e917c59 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/array.go @@ -0,0 +1,130 @@ +package objects + +import ( + "fmt" + "strings" + + "github.com/d5/tengo/compiler/token" +) + +// Array represents an array of objects. +type Array struct { + Value []Object +} + +// TypeName returns the name of the type. +func (o *Array) TypeName() string { + return "array" +} + +func (o *Array) String() string { + var elements []string + for _, e := range o.Value { + elements = append(elements, e.String()) + } + + return fmt.Sprintf("[%s]", strings.Join(elements, ", ")) +} + +// BinaryOp returns another object that is the result of +// a given binary operator and a right-hand side object. +func (o *Array) BinaryOp(op token.Token, rhs Object) (Object, error) { + if rhs, ok := rhs.(*Array); ok { + switch op { + case token.Add: + if len(rhs.Value) == 0 { + return o, nil + } + return &Array{Value: append(o.Value, rhs.Value...)}, nil + } + } + + return nil, ErrInvalidOperator +} + +// Copy returns a copy of the type. +func (o *Array) Copy() Object { + var c []Object + for _, elem := range o.Value { + c = append(c, elem.Copy()) + } + + return &Array{Value: c} +} + +// IsFalsy returns true if the value of the type is falsy. +func (o *Array) IsFalsy() bool { + return len(o.Value) == 0 +} + +// Equals returns true if the value of the type +// is equal to the value of another object. +func (o *Array) Equals(x Object) bool { + var xVal []Object + switch x := x.(type) { + case *Array: + xVal = x.Value + case *ImmutableArray: + xVal = x.Value + default: + return false + } + + if len(o.Value) != len(xVal) { + return false + } + + for i, e := range o.Value { + if !e.Equals(xVal[i]) { + return false + } + } + + return true +} + +// IndexGet returns an element at a given index. +func (o *Array) IndexGet(index Object) (res Object, err error) { + intIdx, ok := index.(*Int) + if !ok { + err = ErrInvalidIndexType + return + } + + idxVal := int(intIdx.Value) + + if idxVal < 0 || idxVal >= len(o.Value) { + res = UndefinedValue + return + } + + res = o.Value[idxVal] + + return +} + +// IndexSet sets an element at a given index. +func (o *Array) IndexSet(index, value Object) (err error) { + intIdx, ok := ToInt(index) + if !ok { + err = ErrInvalidIndexType + return + } + + if intIdx < 0 || intIdx >= len(o.Value) { + err = ErrIndexOutOfBounds + return + } + + o.Value[intIdx] = value + + return nil +} + +// Iterate creates an array iterator. +func (o *Array) Iterate() Iterator { + return &ArrayIterator{ + v: o.Value, + l: len(o.Value), + } +} diff --git a/vendor/github.com/d5/tengo/objects/array_iterator.go b/vendor/github.com/d5/tengo/objects/array_iterator.go new file mode 100644 index 00000000..204faa41 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/array_iterator.go @@ -0,0 +1,57 @@ +package objects + +import "github.com/d5/tengo/compiler/token" + +// ArrayIterator is an iterator for an array. +type ArrayIterator struct { + v []Object + i int + l int +} + +// TypeName returns the name of the type. +func (i *ArrayIterator) TypeName() string { + return "array-iterator" +} + +func (i *ArrayIterator) String() string { + return "<array-iterator>" +} + +// BinaryOp returns another object that is the result of +// a given binary operator and a right-hand side object. +func (i *ArrayIterator) BinaryOp(op token.Token, rhs Object) (Object, error) { + return nil, ErrInvalidOperator +} + +// IsFalsy returns true if the value of the type is falsy. +func (i *ArrayIterator) IsFalsy() bool { + return true +} + +// Equals returns true if the value of the type +// is equal to the value of another object. +func (i *ArrayIterator) Equals(Object) bool { + return false +} + +// Copy returns a copy of the type. +func (i *ArrayIterator) Copy() Object { + return &ArrayIterator{v: i.v, i: i.i, l: i.l} +} + +// Next returns true if there are more elements to iterate. +func (i *ArrayIterator) Next() bool { + i.i++ + return i.i <= i.l +} + +// Key returns the key or index value of the current element. +func (i *ArrayIterator) Key() Object { + return &Int{Value: int64(i.i - 1)} +} + +// Value returns the value of the current element. +func (i *ArrayIterator) Value() Object { + return i.v[i.i-1] +} diff --git a/vendor/github.com/d5/tengo/objects/bool.go b/vendor/github.com/d5/tengo/objects/bool.go new file mode 100644 index 00000000..ac9949e4 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/bool.go @@ -0,0 +1,64 @@ +package objects + +import ( + "github.com/d5/tengo/compiler/token" +) + +// Bool represents a boolean value. +type Bool struct { + // this is intentionally non-public to force using objects.TrueValue and FalseValue always + value bool +} + +func (o *Bool) String() string { + if o.value { + return "true" + } + + return "false" +} + +// TypeName returns the name of the type. +func (o *Bool) TypeName() string { + return "bool" +} + +// BinaryOp returns another object that is the result of +// a given binary operator and a right-hand side object. +func (o *Bool) BinaryOp(op token.Token, rhs Object) (Object, error) { + return nil, ErrInvalidOperator +} + +// Copy returns a copy of the type. +func (o *Bool) Copy() Object { + return o +} + +// IsFalsy returns true if the value of the type is falsy. +func (o *Bool) IsFalsy() bool { + return !o.value +} + +// Equals returns true if the value of the type +// is equal to the value of another object. +func (o *Bool) Equals(x Object) bool { + return o == x +} + +// GobDecode decodes bool value from input bytes. +func (o *Bool) GobDecode(b []byte) (err error) { + o.value = b[0] == 1 + + return +} + +// GobEncode encodes bool values into bytes. +func (o *Bool) GobEncode() (b []byte, err error) { + if o.value { + b = []byte{1} + } else { + b = []byte{0} + } + + return +} diff --git a/vendor/github.com/d5/tengo/objects/break.go b/vendor/github.com/d5/tengo/objects/break.go new file mode 100644 index 00000000..cd473a87 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/break.go @@ -0,0 +1,37 @@ +package objects + +import "github.com/d5/tengo/compiler/token" + +// Break represents a break statement. +type Break struct{} + +// TypeName returns the name of the type. +func (o *Break) TypeName() string { + return "break" +} + +func (o *Break) String() string { + return "<break>" +} + +// BinaryOp returns another object that is the result of +// a given binary operator and a right-hand side object. +func (o *Break) BinaryOp(op token.Token, rhs Object) (Object, error) { + return nil, ErrInvalidOperator +} + +// Copy returns a copy of the type. +func (o *Break) Copy() Object { + return &Break{} +} + +// IsFalsy returns true if the value of the type is falsy. +func (o *Break) IsFalsy() bool { + return false +} + +// Equals returns true if the value of the type +// is equal to the value of another object. +func (o *Break) Equals(x Object) bool { + return false +} diff --git a/vendor/github.com/d5/tengo/objects/builtin_append.go b/vendor/github.com/d5/tengo/objects/builtin_append.go new file mode 100644 index 00000000..9fb14b82 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/builtin_append.go @@ -0,0 +1,21 @@ +package objects + +// append(arr, items...) +func builtinAppend(args ...Object) (Object, error) { + if len(args) < 2 { + return nil, ErrWrongNumArguments + } + + switch arg := args[0].(type) { + case *Array: + return &Array{Value: append(arg.Value, args[1:]...)}, nil + case *ImmutableArray: + return &Array{Value: append(arg.Value, args[1:]...)}, nil + default: + return nil, ErrInvalidArgumentType{ + Name: "first", + Expected: "array", + Found: arg.TypeName(), + } + } +} diff --git a/vendor/github.com/d5/tengo/objects/builtin_convert.go b/vendor/github.com/d5/tengo/objects/builtin_convert.go new file mode 100644 index 00000000..7d9a8733 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/builtin_convert.go @@ -0,0 +1,155 @@ +package objects + +func builtinString(args ...Object) (Object, error) { + argsLen := len(args) + if !(argsLen == 1 || argsLen == 2) { + return nil, ErrWrongNumArguments + } + + if _, ok := args[0].(*String); ok { + return args[0], nil + } + + v, ok := ToString(args[0]) + if ok { + return &String{Value: v}, nil + } + + if argsLen == 2 { + return args[1], nil + } + + return UndefinedValue, nil +} + +func builtinInt(args ...Object) (Object, error) { + argsLen := len(args) + if !(argsLen == 1 || argsLen == 2) { + return nil, ErrWrongNumArguments + } + + if _, ok := args[0].(*Int); ok { + return args[0], nil + } + + v, ok := ToInt64(args[0]) + if ok { + return &Int{Value: v}, nil + } + + if argsLen == 2 { + return args[1], nil + } + + return UndefinedValue, nil +} + +func builtinFloat(args ...Object) (Object, error) { + argsLen := len(args) + if !(argsLen == 1 || argsLen == 2) { + return nil, ErrWrongNumArguments + } + + if _, ok := args[0].(*Float); ok { + return args[0], nil + } + + v, ok := ToFloat64(args[0]) + if ok { + return &Float{Value: v}, nil + } + + if argsLen == 2 { + return args[1], nil + } + + return UndefinedValue, nil +} + +func builtinBool(args ...Object) (Object, error) { + if len(args) != 1 { + return nil, ErrWrongNumArguments + } + + if _, ok := args[0].(*Bool); ok { + return args[0], nil + } + + v, ok := ToBool(args[0]) + if ok { + if v { + return TrueValue, nil + } + + return FalseValue, nil + } + + return UndefinedValue, nil +} + +func builtinChar(args ...Object) (Object, error) { + argsLen := len(args) + if !(argsLen == 1 || argsLen == 2) { + return nil, ErrWrongNumArguments + } + + if _, ok := args[0].(*Char); ok { + return args[0], nil + } + + v, ok := ToRune(args[0]) + if ok { + return &Char{Value: v}, nil + } + + if argsLen == 2 { + return args[1], nil + } + + return UndefinedValue, nil +} + +func builtinBytes(args ...Object) (Object, error) { + argsLen := len(args) + if !(argsLen == 1 || argsLen == 2) { + return nil, ErrWrongNumArguments + } + + // bytes(N) => create a new bytes with given size N + if n, ok := args[0].(*Int); ok { + return &Bytes{Value: make([]byte, int(n.Value))}, nil + } + + v, ok := ToByteSlice(args[0]) + if ok { + return &Bytes{Value: v}, nil + } + + if argsLen == 2 { + return args[1], nil + } + + return UndefinedValue, nil +} + +func builtinTime(args ...Object) (Object, error) { + argsLen := len(args) + if !(argsLen == 1 || argsLen == 2) { + return nil, ErrWrongNumArguments + } + + if _, ok := args[0].(*Time); ok { + return args[0], nil + } + + v, ok := ToTime(args[0]) + if ok { + return &Time{Value: v}, nil + } + + if argsLen == 2 { + return args[1], nil + } + + return UndefinedValue, nil +} diff --git a/vendor/github.com/d5/tengo/objects/builtin_copy.go b/vendor/github.com/d5/tengo/objects/builtin_copy.go new file mode 100644 index 00000000..4b254b2b --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/builtin_copy.go @@ -0,0 +1,9 @@ +package objects + +func builtinCopy(args ...Object) (Object, error) { + if len(args) != 1 { + return nil, ErrWrongNumArguments + } + + return args[0].Copy(), nil +} diff --git a/vendor/github.com/d5/tengo/objects/builtin_function.go b/vendor/github.com/d5/tengo/objects/builtin_function.go new file mode 100644 index 00000000..1d021617 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/builtin_function.go @@ -0,0 +1,47 @@ +package objects + +import ( + "github.com/d5/tengo/compiler/token" +) + +// BuiltinFunction represents a builtin function. +type BuiltinFunction struct { + Name string + Value CallableFunc +} + +// TypeName returns the name of the type. +func (o *BuiltinFunction) TypeName() string { + return "builtin-function:" + o.Name +} + +func (o *BuiltinFunction) String() string { + return "<builtin-function>" +} + +// BinaryOp returns another object that is the result of +// a given binary operator and a right-hand side object. +func (o *BuiltinFunction) BinaryOp(op token.Token, rhs Object) (Object, error) { + return nil, ErrInvalidOperator +} + +// Copy returns a copy of the type. +func (o *BuiltinFunction) Copy() Object { + return &BuiltinFunction{Value: o.Value} +} + +// IsFalsy returns true if the value of the type is falsy. +func (o *BuiltinFunction) IsFalsy() bool { + return false +} + +// Equals returns true if the value of the type +// is equal to the value of another object. +func (o *BuiltinFunction) Equals(x Object) bool { + return false +} + +// Call executes a builtin function. +func (o *BuiltinFunction) Call(args ...Object) (Object, error) { + return o.Value(args...) +} diff --git a/vendor/github.com/d5/tengo/objects/builtin_json.go b/vendor/github.com/d5/tengo/objects/builtin_json.go new file mode 100644 index 00000000..c0810f7d --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/builtin_json.go @@ -0,0 +1,54 @@ +package objects + +import ( + "encoding/json" +) + +// to_json(v object) => bytes +func builtinToJSON(args ...Object) (Object, error) { + if len(args) != 1 { + return nil, ErrWrongNumArguments + } + + res, err := json.Marshal(objectToInterface(args[0])) + if err != nil { + return &Error{Value: &String{Value: err.Error()}}, nil + } + + return &Bytes{Value: res}, nil +} + +// from_json(data string/bytes) => object +func builtinFromJSON(args ...Object) (Object, error) { + if len(args) != 1 { + return nil, ErrWrongNumArguments + } + + var target interface{} + + switch o := args[0].(type) { + case *Bytes: + err := json.Unmarshal(o.Value, &target) + if err != nil { + return &Error{Value: &String{Value: err.Error()}}, nil + } + case *String: + err := json.Unmarshal([]byte(o.Value), &target) + if err != nil { + return &Error{Value: &String{Value: err.Error()}}, nil + } + default: + return nil, ErrInvalidArgumentType{ + Name: "first", + Expected: "bytes/string", + Found: args[0].TypeName(), + } + } + + res, err := FromInterface(target) + if err != nil { + return nil, err + } + + return res, nil +} diff --git a/vendor/github.com/d5/tengo/objects/builtin_len.go b/vendor/github.com/d5/tengo/objects/builtin_len.go new file mode 100644 index 00000000..39fbedd8 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/builtin_len.go @@ -0,0 +1,29 @@ +package objects + +// len(obj object) => int +func builtinLen(args ...Object) (Object, error) { + if len(args) != 1 { + return nil, ErrWrongNumArguments + } + + switch arg := args[0].(type) { + case *Array: + return &Int{Value: int64(len(arg.Value))}, nil + case *ImmutableArray: + return &Int{Value: int64(len(arg.Value))}, nil + case *String: + return &Int{Value: int64(len(arg.Value))}, nil + case *Bytes: + return &Int{Value: int64(len(arg.Value))}, nil + case *Map: + return &Int{Value: int64(len(arg.Value))}, nil + case *ImmutableMap: + return &Int{Value: int64(len(arg.Value))}, nil + default: + return nil, ErrInvalidArgumentType{ + Name: "first", + Expected: "array/string/bytes/map", + Found: arg.TypeName(), + } + } +} diff --git a/vendor/github.com/d5/tengo/objects/builtin_print.go b/vendor/github.com/d5/tengo/objects/builtin_print.go new file mode 100644 index 00000000..c5fe36db --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/builtin_print.go @@ -0,0 +1,75 @@ +package objects + +import ( + "fmt" +) + +// print(args...) +func builtinPrint(args ...Object) (Object, error) { + for _, arg := range args { + if str, ok := arg.(*String); ok { + fmt.Println(str.Value) + } else { + fmt.Println(arg.String()) + } + } + + return nil, nil +} + +// printf("format", args...) +func builtinPrintf(args ...Object) (Object, error) { + numArgs := len(args) + if numArgs == 0 { + return nil, ErrWrongNumArguments + } + + format, ok := args[0].(*String) + if !ok { + return nil, ErrInvalidArgumentType{ + Name: "format", + Expected: "string", + Found: args[0].TypeName(), + } + } + if numArgs == 1 { + fmt.Print(format) + return nil, nil + } + + formatArgs := make([]interface{}, numArgs-1, numArgs-1) + for idx, arg := range args[1:] { + formatArgs[idx] = objectToInterface(arg) + } + + fmt.Printf(format.Value, formatArgs...) + + return nil, nil +} + +// sprintf("format", args...) +func builtinSprintf(args ...Object) (Object, error) { + numArgs := len(args) + if numArgs == 0 { + return nil, ErrWrongNumArguments + } + + format, ok := args[0].(*String) + if !ok { + return nil, ErrInvalidArgumentType{ + Name: "format", + Expected: "string", + Found: args[0].TypeName(), + } + } + if numArgs == 1 { + return format, nil // okay to return 'format' directly as String is immutable + } + + formatArgs := make([]interface{}, numArgs-1, numArgs-1) + for idx, arg := range args[1:] { + formatArgs[idx] = objectToInterface(arg) + } + + return &String{Value: fmt.Sprintf(format.Value, formatArgs...)}, nil +} diff --git a/vendor/github.com/d5/tengo/objects/builtin_type.go b/vendor/github.com/d5/tengo/objects/builtin_type.go new file mode 100644 index 00000000..376c26bb --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/builtin_type.go @@ -0,0 +1,9 @@ +package objects + +func builtinTypeName(args ...Object) (Object, error) { + if len(args) != 1 { + return nil, ErrWrongNumArguments + } + + return &String{Value: args[0].TypeName()}, nil +} diff --git a/vendor/github.com/d5/tengo/objects/builtin_type_checks.go b/vendor/github.com/d5/tengo/objects/builtin_type_checks.go new file mode 100644 index 00000000..960f7828 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/builtin_type_checks.go @@ -0,0 +1,183 @@ +package objects + +func builtinIsString(args ...Object) (Object, error) { + if len(args) != 1 { + return nil, ErrWrongNumArguments + } + + if _, ok := args[0].(*String); ok { + return TrueValue, nil + } + + return FalseValue, nil +} + +func builtinIsInt(args ...Object) (Object, error) { + if len(args) != 1 { + return nil, ErrWrongNumArguments + } + + if _, ok := args[0].(*Int); ok { + return TrueValue, nil + } + + return FalseValue, nil +} + +func builtinIsFloat(args ...Object) (Object, error) { + if len(args) != 1 { + return nil, ErrWrongNumArguments + } + + if _, ok := args[0].(*Float); ok { + return TrueValue, nil + } + + return FalseValue, nil +} + +func builtinIsBool(args ...Object) (Object, error) { + if len(args) != 1 { + return nil, ErrWrongNumArguments + } + + if _, ok := args[0].(*Bool); ok { + return TrueValue, nil + } + + return FalseValue, nil +} + +func builtinIsChar(args ...Object) (Object, error) { + if len(args) != 1 { + return nil, ErrWrongNumArguments + } + + if _, ok := args[0].(*Char); ok { + return TrueValue, nil + } + + return FalseValue, nil +} + +func builtinIsBytes(args ...Object) (Object, error) { + if len(args) != 1 { + return nil, ErrWrongNumArguments + } + + if _, ok := args[0].(*Bytes); ok { + return TrueValue, nil + } + + return FalseValue, nil +} + +func builtinIsArray(args ...Object) (Object, error) { + if len(args) != 1 { + return nil, ErrWrongNumArguments + } + + if _, ok := args[0].(*Array); ok { + return TrueValue, nil + } + + return FalseValue, nil +} + +func builtinIsImmutableArray(args ...Object) (Object, error) { + if len(args) != 1 { + return nil, ErrWrongNumArguments + } + + if _, ok := args[0].(*ImmutableArray); ok { + return TrueValue, nil + } + + return FalseValue, nil +} + +func builtinIsMap(args ...Object) (Object, error) { + if len(args) != 1 { + return nil, ErrWrongNumArguments + } + + if _, ok := args[0].(*Map); ok { + return TrueValue, nil + } + + return FalseValue, nil +} + +func builtinIsImmutableMap(args ...Object) (Object, error) { + if len(args) != 1 { + return nil, ErrWrongNumArguments + } + + if _, ok := args[0].(*ImmutableMap); ok { + return TrueValue, nil + } + + return FalseValue, nil +} + +func builtinIsTime(args ...Object) (Object, error) { + if len(args) != 1 { + return nil, ErrWrongNumArguments + } + + if _, ok := args[0].(*Time); ok { + return TrueValue, nil + } + + return FalseValue, nil +} + +func builtinIsError(args ...Object) (Object, error) { + if len(args) != 1 { + return nil, ErrWrongNumArguments + } + + if _, ok := args[0].(*Error); ok { + return TrueValue, nil + } + + return FalseValue, nil +} + +func builtinIsUndefined(args ...Object) (Object, error) { + if len(args) != 1 { + return nil, ErrWrongNumArguments + } + + if args[0] == UndefinedValue { + return TrueValue, nil + } + + return FalseValue, nil +} + +func builtinIsFunction(args ...Object) (Object, error) { + if len(args) != 1 { + return nil, ErrWrongNumArguments + } + + switch args[0].(type) { + case *CompiledFunction, *Closure: + return TrueValue, nil + } + + return FalseValue, nil +} + +func builtinIsCallable(args ...Object) (Object, error) { + if len(args) != 1 { + return nil, ErrWrongNumArguments + } + + switch args[0].(type) { + case *CompiledFunction, *Closure, Callable: // BuiltinFunction is Callable + return TrueValue, nil + } + + return FalseValue, nil +} diff --git a/vendor/github.com/d5/tengo/objects/builtins.go b/vendor/github.com/d5/tengo/objects/builtins.go new file mode 100644 index 00000000..67553932 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/builtins.go @@ -0,0 +1,135 @@ +package objects + +// NamedBuiltinFunc is a named builtin function. +type NamedBuiltinFunc struct { + Name string + Func CallableFunc +} + +// Builtins contains all default builtin functions. +var Builtins = []NamedBuiltinFunc{ + { + Name: "print", + Func: builtinPrint, + }, + { + Name: "printf", + Func: builtinPrintf, + }, + { + Name: "sprintf", + Func: builtinSprintf, + }, + { + Name: "len", + Func: builtinLen, + }, + { + Name: "copy", + Func: builtinCopy, + }, + { + Name: "append", + Func: builtinAppend, + }, + { + Name: "string", + Func: builtinString, + }, + { + Name: "int", + Func: builtinInt, + }, + { + Name: "bool", + Func: builtinBool, + }, + { + Name: "float", + Func: builtinFloat, + }, + { + Name: "char", + Func: builtinChar, + }, + { + Name: "bytes", + Func: builtinBytes, + }, + { + Name: "time", + Func: builtinTime, + }, + { + Name: "is_int", + Func: builtinIsInt, + }, + { + Name: "is_float", + Func: builtinIsFloat, + }, + { + Name: "is_string", + Func: builtinIsString, + }, + { + Name: "is_bool", + Func: builtinIsBool, + }, + { + Name: "is_char", + Func: builtinIsChar, + }, + { + Name: "is_bytes", + Func: builtinIsBytes, + }, + { + Name: "is_array", + Func: builtinIsArray, + }, + { + Name: "is_immutable_array", + Func: builtinIsImmutableArray, + }, + { + Name: "is_map", + Func: builtinIsMap, + }, + { + Name: "is_immutable_map", + Func: builtinIsImmutableMap, + }, + { + Name: "is_time", + Func: builtinIsTime, + }, + { + Name: "is_error", + Func: builtinIsError, + }, + { + Name: "is_undefined", + Func: builtinIsUndefined, + }, + { + Name: "is_function", + Func: builtinIsFunction, + }, + { + Name: "is_callable", + Func: builtinIsCallable, + }, + { + Name: "to_json", + Func: builtinToJSON, + }, + { + Name: "from_json", + Func: builtinFromJSON, + }, + { + Name: "type_name", + Func: builtinTypeName, + }, +} diff --git a/vendor/github.com/d5/tengo/objects/bytes.go b/vendor/github.com/d5/tengo/objects/bytes.go new file mode 100644 index 00000000..7d8d6694 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/bytes.go @@ -0,0 +1,76 @@ +package objects + +import ( + "bytes" + + "github.com/d5/tengo/compiler/token" +) + +// Bytes represents a byte array. +type Bytes struct { + Value []byte +} + +func (o *Bytes) String() string { + return string(o.Value) +} + +// TypeName returns the name of the type. +func (o *Bytes) TypeName() string { + return "bytes" +} + +// BinaryOp returns another object that is the result of +// a given binary operator and a right-hand side object. +func (o *Bytes) BinaryOp(op token.Token, rhs Object) (Object, error) { + switch op { + case token.Add: + switch rhs := rhs.(type) { + case *Bytes: + return &Bytes{Value: append(o.Value, rhs.Value...)}, nil + } + } + + return nil, ErrInvalidOperator +} + +// Copy returns a copy of the type. +func (o *Bytes) Copy() Object { + return &Bytes{Value: append([]byte{}, o.Value...)} +} + +// IsFalsy returns true if the value of the type is falsy. +func (o *Bytes) IsFalsy() bool { + return len(o.Value) == 0 +} + +// Equals returns true if the value of the type +// is equal to the value of another object. +func (o *Bytes) Equals(x Object) bool { + t, ok := x.(*Bytes) + if !ok { + return false + } + + return bytes.Compare(o.Value, t.Value) == 0 +} + +// IndexGet returns an element (as Int) at a given index. +func (o *Bytes) IndexGet(index Object) (res Object, err error) { + intIdx, ok := index.(*Int) + if !ok { + err = ErrInvalidIndexType + return + } + + idxVal := int(intIdx.Value) + + if idxVal < 0 || idxVal >= len(o.Value) { + res = UndefinedValue + return + } + + res = &Int{Value: int64(o.Value[idxVal])} + + return +} diff --git a/vendor/github.com/d5/tengo/objects/callable.go b/vendor/github.com/d5/tengo/objects/callable.go new file mode 100644 index 00000000..a066e1b9 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/callable.go @@ -0,0 +1,9 @@ +package objects + +// Callable represents an object that can be called like a function. +type Callable interface { + // Call should take an arbitrary number of arguments + // and returns a return value and/or an error, + // which the VM will consider as a run-time error. + Call(args ...Object) (ret Object, err error) +} diff --git a/vendor/github.com/d5/tengo/objects/callable_func.go b/vendor/github.com/d5/tengo/objects/callable_func.go new file mode 100644 index 00000000..cf9b43aa --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/callable_func.go @@ -0,0 +1,4 @@ +package objects + +// CallableFunc is a function signature for the callable functions. +type CallableFunc func(args ...Object) (ret Object, err error) diff --git a/vendor/github.com/d5/tengo/objects/char.go b/vendor/github.com/d5/tengo/objects/char.go new file mode 100644 index 00000000..4458bd12 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/char.go @@ -0,0 +1,119 @@ +package objects + +import ( + "github.com/d5/tengo/compiler/token" +) + +// Char represents a character value. +type Char struct { + Value rune +} + +func (o *Char) String() string { + return string(o.Value) +} + +// TypeName returns the name of the type. +func (o *Char) TypeName() string { + return "char" +} + +// BinaryOp returns another object that is the result of +// a given binary operator and a right-hand side object. +func (o *Char) BinaryOp(op token.Token, rhs Object) (Object, error) { + switch rhs := rhs.(type) { + case *Char: + switch op { + case token.Add: + r := o.Value + rhs.Value + if r == o.Value { + return o, nil + } + return &Char{Value: r}, nil + case token.Sub: + r := o.Value - rhs.Value + if r == o.Value { + return o, nil + } + return &Char{Value: r}, nil + case token.Less: + if o.Value < rhs.Value { + return TrueValue, nil + } + return FalseValue, nil + case token.Greater: + if o.Value > rhs.Value { + return TrueValue, nil + } + return FalseValue, nil + case token.LessEq: + if o.Value <= rhs.Value { + return TrueValue, nil + } + return FalseValue, nil + case token.GreaterEq: + if o.Value >= rhs.Value { + return TrueValue, nil + } + return FalseValue, nil + } + case *Int: + switch op { + case token.Add: + r := o.Value + rune(rhs.Value) + if r == o.Value { + return o, nil + } + return &Char{Value: r}, nil + case token.Sub: + r := o.Value - rune(rhs.Value) + if r == o.Value { + return o, nil + } + return &Char{Value: r}, nil + case token.Less: + if int64(o.Value) < rhs.Value { + return TrueValue, nil + } + return FalseValue, nil + case token.Greater: + if int64(o.Value) > rhs.Value { + return TrueValue, nil + } + return FalseValue, nil + case token.LessEq: + if int64(o.Value) <= rhs.Value { + return TrueValue, nil + } + return FalseValue, nil + case token.GreaterEq: + if int64(o.Value) >= rhs.Value { + return TrueValue, nil + } + return FalseValue, nil + } + } + + return nil, ErrInvalidOperator +} + +// Copy returns a copy of the type. +func (o *Char) Copy() Object { + return &Char{Value: o.Value} +} + +// IsFalsy returns true if the value of the type is falsy. +func (o *Char) IsFalsy() bool { + return o.Value == 0 +} + +// Equals returns true if the value of the type +// is equal to the value of another object. +func (o *Char) Equals(x Object) bool { + t, ok := x.(*Char) + if !ok { + return false + } + + return o.Value == t.Value +} diff --git a/vendor/github.com/d5/tengo/objects/closure.go b/vendor/github.com/d5/tengo/objects/closure.go new file mode 100644 index 00000000..d4915a52 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/closure.go @@ -0,0 +1,45 @@ +package objects + +import ( + "github.com/d5/tengo/compiler/token" +) + +// Closure represents a function closure. +type Closure struct { + Fn *CompiledFunction + Free []*Object +} + +// TypeName returns the name of the type. +func (o *Closure) TypeName() string { + return "closure" +} + +func (o *Closure) String() string { + return "<closure>" +} + +// BinaryOp returns another object that is the result of +// a given binary operator and a right-hand side object. +func (o *Closure) BinaryOp(op token.Token, rhs Object) (Object, error) { + return nil, ErrInvalidOperator +} + +// Copy returns a copy of the type. +func (o *Closure) Copy() Object { + return &Closure{ + Fn: o.Fn.Copy().(*CompiledFunction), + Free: append([]*Object{}, o.Free...), // DO NOT Copy() of elements; these are variable pointers + } +} + +// IsFalsy returns true if the value of the type is falsy. +func (o *Closure) IsFalsy() bool { + return false +} + +// Equals returns true if the value of the type +// is equal to the value of another object. +func (o *Closure) Equals(x Object) bool { + return false +} diff --git a/vendor/github.com/d5/tengo/objects/compiled_function.go b/vendor/github.com/d5/tengo/objects/compiled_function.go new file mode 100644 index 00000000..d20f2375 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/compiled_function.go @@ -0,0 +1,49 @@ +package objects + +import ( + "github.com/d5/tengo/compiler/source" + "github.com/d5/tengo/compiler/token" +) + +// CompiledFunction represents a compiled function. +type CompiledFunction struct { + Instructions []byte + NumLocals int // number of local variables (including function parameters) + NumParameters int + SourceMap map[int]source.Pos +} + +// TypeName returns the name of the type. +func (o *CompiledFunction) TypeName() string { + return "compiled-function" +} + +func (o *CompiledFunction) String() string { + return "<compiled-function>" +} + +// BinaryOp returns another object that is the result of +// a given binary operator and a right-hand side object. +func (o *CompiledFunction) BinaryOp(op token.Token, rhs Object) (Object, error) { + return nil, ErrInvalidOperator +} + +// Copy returns a copy of the type. +func (o *CompiledFunction) Copy() Object { + return &CompiledFunction{ + Instructions: append([]byte{}, o.Instructions...), + NumLocals: o.NumLocals, + NumParameters: o.NumParameters, + } +} + +// IsFalsy returns true if the value of the type is falsy. +func (o *CompiledFunction) IsFalsy() bool { + return false +} + +// Equals returns true if the value of the type +// is equal to the value of another object. +func (o *CompiledFunction) Equals(x Object) bool { + return false +} diff --git a/vendor/github.com/d5/tengo/objects/continue.go b/vendor/github.com/d5/tengo/objects/continue.go new file mode 100644 index 00000000..8094e686 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/continue.go @@ -0,0 +1,38 @@ +package objects + +import "github.com/d5/tengo/compiler/token" + +// Continue represents a continue statement. +type Continue struct { +} + +// TypeName returns the name of the type. +func (o *Continue) TypeName() string { + return "continue" +} + +func (o *Continue) String() string { + return "<continue>" +} + +// BinaryOp returns another object that is the result of +// a given binary operator and a right-hand side object. +func (o *Continue) BinaryOp(op token.Token, rhs Object) (Object, error) { + return nil, ErrInvalidOperator +} + +// Copy returns a copy of the type. +func (o *Continue) Copy() Object { + return &Continue{} +} + +// IsFalsy returns true if the value of the type is falsy. +func (o *Continue) IsFalsy() bool { + return false +} + +// Equals returns true if the value of the type +// is equal to the value of another object. +func (o *Continue) Equals(x Object) bool { + return false +} diff --git a/vendor/github.com/d5/tengo/objects/conversion.go b/vendor/github.com/d5/tengo/objects/conversion.go new file mode 100644 index 00000000..3c17546f --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/conversion.go @@ -0,0 +1,249 @@ +package objects + +import ( + "fmt" + "strconv" + "time" +) + +// ToString will try to convert object o to string value. +func ToString(o Object) (v string, ok bool) { + if o == UndefinedValue { + //ok = false + return + } + + ok = true + + if str, isStr := o.(*String); isStr { + v = str.Value + } else { + v = o.String() + } + + return +} + +// ToInt will try to convert object o to int value. +func ToInt(o Object) (v int, ok bool) { + switch o := o.(type) { + case *Int: + v = int(o.Value) + ok = true + case *Float: + v = int(o.Value) + ok = true + case *Char: + v = int(o.Value) + ok = true + case *Bool: + if o == TrueValue { + v = 1 + } + ok = true + case *String: + c, err := strconv.ParseInt(o.Value, 10, 64) + if err == nil { + v = int(c) + ok = true + } + } + + //ok = false + return +} + +// ToInt64 will try to convert object o to int64 value. +func ToInt64(o Object) (v int64, ok bool) { + switch o := o.(type) { + case *Int: + v = o.Value + ok = true + case *Float: + v = int64(o.Value) + ok = true + case *Char: + v = int64(o.Value) + ok = true + case *Bool: + if o == TrueValue { + v = 1 + } + ok = true + case *String: + c, err := strconv.ParseInt(o.Value, 10, 64) + if err == nil { + v = c + ok = true + } + } + + //ok = false + return +} + +// ToFloat64 will try to convert object o to float64 value. +func ToFloat64(o Object) (v float64, ok bool) { + switch o := o.(type) { + case *Int: + v = float64(o.Value) + ok = true + case *Float: + v = o.Value + ok = true + case *String: + c, err := strconv.ParseFloat(o.Value, 64) + if err == nil { + v = c + ok = true + } + } + + //ok = false + return +} + +// ToBool will try to convert object o to bool value. +func ToBool(o Object) (v bool, ok bool) { + ok = true + v = !o.IsFalsy() + + return +} + +// ToRune will try to convert object o to rune value. +func ToRune(o Object) (v rune, ok bool) { + switch o := o.(type) { + case *Int: + v = rune(o.Value) + ok = true + case *Char: + v = rune(o.Value) + ok = true + } + + //ok = false + return +} + +// ToByteSlice will try to convert object o to []byte value. +func ToByteSlice(o Object) (v []byte, ok bool) { + switch o := o.(type) { + case *Bytes: + v = o.Value + ok = true + case *String: + v = []byte(o.Value) + ok = true + } + + //ok = false + return +} + +// ToTime will try to convert object o to time.Time value. +func ToTime(o Object) (v time.Time, ok bool) { + switch o := o.(type) { + case *Time: + v = o.Value + ok = true + case *Int: + v = time.Unix(o.Value, 0) + ok = true + } + + //ok = false + return +} + +// objectToInterface attempts to convert an object o to an interface{} value +func objectToInterface(o Object) (res interface{}) { + switch o := o.(type) { + case *Int: + res = o.Value + case *String: + res = o.Value + case *Float: + res = o.Value + case *Bool: + res = o == TrueValue + case *Char: + res = o.Value + case *Bytes: + res = o.Value + case *Array: + res = make([]interface{}, len(o.Value)) + for i, val := range o.Value { + res.([]interface{})[i] = objectToInterface(val) + } + case *Map: + res = make(map[string]interface{}) + for key, v := range o.Value { + res.(map[string]interface{})[key] = objectToInterface(v) + } + case Object: + return o + } + + return +} + +// FromInterface will attempt to convert an interface{} v to a Tengo Object +func FromInterface(v interface{}) (Object, error) { + switch v := v.(type) { + case nil: + return UndefinedValue, nil + case string: + return &String{Value: v}, nil + case int64: + return &Int{Value: v}, nil + case int: + return &Int{Value: int64(v)}, nil + case bool: + if v { + return TrueValue, nil + } + return FalseValue, nil + case rune: + return &Char{Value: v}, nil + case byte: + return &Char{Value: rune(v)}, nil + case float64: + return &Float{Value: v}, nil + case []byte: + return &Bytes{Value: v}, nil + case error: + return &Error{Value: &String{Value: v.Error()}}, nil + case map[string]Object: + return &Map{Value: v}, nil + case map[string]interface{}: + kv := make(map[string]Object) + for vk, vv := range v { + vo, err := FromInterface(vv) + if err != nil { + return nil, err + } + kv[vk] = vo + } + return &Map{Value: kv}, nil + case []Object: + return &Array{Value: v}, nil + case []interface{}: + arr := make([]Object, len(v), len(v)) + for i, e := range v { + vo, err := FromInterface(e) + if err != nil { + return nil, err + } + + arr[i] = vo + } + return &Array{Value: arr}, nil + case time.Time: + return &Time{Value: v}, nil + case Object: + return v, nil + } + + return nil, fmt.Errorf("cannot convert to object: %T", v) +} diff --git a/vendor/github.com/d5/tengo/objects/error.go b/vendor/github.com/d5/tengo/objects/error.go new file mode 100644 index 00000000..be21de03 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/error.go @@ -0,0 +1,47 @@ +package objects + +import ( + "fmt" + + "github.com/d5/tengo/compiler/token" +) + +// Error represents a string value. +type Error struct { + Value Object +} + +// TypeName returns the name of the type. +func (o *Error) TypeName() string { + return "error" +} + +func (o *Error) String() string { + if o.Value != nil { + return fmt.Sprintf("error: %s", o.Value.String()) + } + + return "error" +} + +// BinaryOp returns another object that is the result of +// a given binary operator and a right-hand side object. +func (o *Error) BinaryOp(op token.Token, rhs Object) (Object, error) { + return nil, ErrInvalidOperator +} + +// IsFalsy returns true if the value of the type is falsy. +func (o *Error) IsFalsy() bool { + return true // error is always false. +} + +// Copy returns a copy of the type. +func (o *Error) Copy() Object { + return &Error{Value: o.Value.Copy()} +} + +// Equals returns true if the value of the type +// is equal to the value of another object. +func (o *Error) Equals(x Object) bool { + return o == x // pointer equality +} diff --git a/vendor/github.com/d5/tengo/objects/errors.go b/vendor/github.com/d5/tengo/objects/errors.go new file mode 100644 index 00000000..e4012314 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/errors.go @@ -0,0 +1,32 @@ +package objects + +import ( + "errors" + "fmt" +) + +// ErrIndexOutOfBounds is an error where a given index is out of the bounds. +var ErrIndexOutOfBounds = errors.New("index out of bounds") + +// ErrInvalidIndexType represents an invalid index type. +var ErrInvalidIndexType = errors.New("invalid index type") + +// ErrInvalidIndexValueType represents an invalid index value type. +var ErrInvalidIndexValueType = errors.New("invalid index value type") + +// ErrInvalidOperator represents an error for invalid operator usage. +var ErrInvalidOperator = errors.New("invalid operator") + +// ErrWrongNumArguments represents a wrong number of arguments error. +var ErrWrongNumArguments = errors.New("wrong number of arguments") + +// ErrInvalidArgumentType represents an invalid argument value type error. +type ErrInvalidArgumentType struct { + Name string + Expected string + Found string +} + +func (e ErrInvalidArgumentType) Error() string { + return fmt.Sprintf("invalid type for argument '%s': expected %s, found %s", e.Name, e.Expected, e.Found) +} diff --git a/vendor/github.com/d5/tengo/objects/float.go b/vendor/github.com/d5/tengo/objects/float.go new file mode 100644 index 00000000..65997303 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/float.go @@ -0,0 +1,146 @@ +package objects + +import ( + "math" + "strconv" + + "github.com/d5/tengo/compiler/token" +) + +// Float represents a floating point number value. +type Float struct { + Value float64 +} + +func (o *Float) String() string { + return strconv.FormatFloat(o.Value, 'f', -1, 64) +} + +// TypeName returns the name of the type. +func (o *Float) TypeName() string { + return "float" +} + +// BinaryOp returns another object that is the result of +// a given binary operator and a right-hand side object. +func (o *Float) BinaryOp(op token.Token, rhs Object) (Object, error) { + switch rhs := rhs.(type) { + case *Float: + switch op { + case token.Add: + r := o.Value + rhs.Value + if r == o.Value { + return o, nil + } + return &Float{Value: r}, nil + case token.Sub: + r := o.Value - rhs.Value + if r == o.Value { + return o, nil + } + return &Float{Value: r}, nil + case token.Mul: + r := o.Value * rhs.Value + if r == o.Value { + return o, nil + } + return &Float{Value: r}, nil + case token.Quo: + r := o.Value / rhs.Value + if r == o.Value { + return o, nil + } + return &Float{Value: r}, nil + case token.Less: + if o.Value < rhs.Value { + return TrueValue, nil + } + return FalseValue, nil + case token.Greater: + if o.Value > rhs.Value { + return TrueValue, nil + } + return FalseValue, nil + case token.LessEq: + if o.Value <= rhs.Value { + return TrueValue, nil + } + return FalseValue, nil + case token.GreaterEq: + if o.Value >= rhs.Value { + return TrueValue, nil + } + return FalseValue, nil + } + case *Int: + switch op { + case token.Add: + r := o.Value + float64(rhs.Value) + if r == o.Value { + return o, nil + } + return &Float{Value: r}, nil + case token.Sub: + r := o.Value - float64(rhs.Value) + if r == o.Value { + return o, nil + } + return &Float{Value: r}, nil + case token.Mul: + r := o.Value * float64(rhs.Value) + if r == o.Value { + return o, nil + } + return &Float{Value: r}, nil + case token.Quo: + r := o.Value / float64(rhs.Value) + if r == o.Value { + return o, nil + } + return &Float{Value: r}, nil + case token.Less: + if o.Value < float64(rhs.Value) { + return TrueValue, nil + } + return FalseValue, nil + case token.Greater: + if o.Value > float64(rhs.Value) { + return TrueValue, nil + } + return FalseValue, nil + case token.LessEq: + if o.Value <= float64(rhs.Value) { + return TrueValue, nil + } + return FalseValue, nil + case token.GreaterEq: + if o.Value >= float64(rhs.Value) { + return TrueValue, nil + } + return FalseValue, nil + } + } + + return nil, ErrInvalidOperator +} + +// Copy returns a copy of the type. +func (o *Float) Copy() Object { + return &Float{Value: o.Value} +} + +// IsFalsy returns true if the value of the type is falsy. +func (o *Float) IsFalsy() bool { + return math.IsNaN(o.Value) +} + +// Equals returns true if the value of the type +// is equal to the value of another object. +func (o *Float) Equals(x Object) bool { + t, ok := x.(*Float) + if !ok { + return false + } + + return o.Value == t.Value +} diff --git a/vendor/github.com/d5/tengo/objects/immautable_array.go b/vendor/github.com/d5/tengo/objects/immautable_array.go new file mode 100644 index 00000000..f3621e29 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/immautable_array.go @@ -0,0 +1,109 @@ +package objects + +import ( + "fmt" + "strings" + + "github.com/d5/tengo/compiler/token" +) + +// ImmutableArray represents an immutable array of objects. +type ImmutableArray struct { + Value []Object +} + +// TypeName returns the name of the type. +func (o *ImmutableArray) TypeName() string { + return "immutable-array" +} + +func (o *ImmutableArray) String() string { + var elements []string + for _, e := range o.Value { + elements = append(elements, e.String()) + } + + return fmt.Sprintf("[%s]", strings.Join(elements, ", ")) +} + +// BinaryOp returns another object that is the result of +// a given binary operator and a right-hand side object. +func (o *ImmutableArray) BinaryOp(op token.Token, rhs Object) (Object, error) { + if rhs, ok := rhs.(*ImmutableArray); ok { + switch op { + case token.Add: + return &Array{Value: append(o.Value, rhs.Value...)}, nil + } + } + + return nil, ErrInvalidOperator +} + +// Copy returns a copy of the type. +func (o *ImmutableArray) Copy() Object { + var c []Object + for _, elem := range o.Value { + c = append(c, elem.Copy()) + } + + return &Array{Value: c} +} + +// IsFalsy returns true if the value of the type is falsy. +func (o *ImmutableArray) IsFalsy() bool { + return len(o.Value) == 0 +} + +// Equals returns true if the value of the type +// is equal to the value of another object. +func (o *ImmutableArray) Equals(x Object) bool { + var xVal []Object + switch x := x.(type) { + case *Array: + xVal = x.Value + case *ImmutableArray: + xVal = x.Value + default: + return false + } + + if len(o.Value) != len(xVal) { + return false + } + + for i, e := range o.Value { + if !e.Equals(xVal[i]) { + return false + } + } + + return true +} + +// IndexGet returns an element at a given index. +func (o *ImmutableArray) IndexGet(index Object) (res Object, err error) { + intIdx, ok := index.(*Int) + if !ok { + err = ErrInvalidIndexType + return + } + + idxVal := int(intIdx.Value) + + if idxVal < 0 || idxVal >= len(o.Value) { + res = UndefinedValue + return + } + + res = o.Value[idxVal] + + return +} + +// Iterate creates an array iterator. +func (o *ImmutableArray) Iterate() Iterator { + return &ArrayIterator{ + v: o.Value, + l: len(o.Value), + } +} diff --git a/vendor/github.com/d5/tengo/objects/immutable_map.go b/vendor/github.com/d5/tengo/objects/immutable_map.go new file mode 100644 index 00000000..8f58701b --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/immutable_map.go @@ -0,0 +1,105 @@ +package objects + +import ( + "fmt" + "strings" + + "github.com/d5/tengo/compiler/token" +) + +// ImmutableMap represents an immutable map object. +type ImmutableMap struct { + Value map[string]Object +} + +// TypeName returns the name of the type. +func (o *ImmutableMap) TypeName() string { + return "immutable-map" +} + +func (o *ImmutableMap) String() string { + var pairs []string + for k, v := range o.Value { + pairs = append(pairs, fmt.Sprintf("%s: %s", k, v.String())) + } + + return fmt.Sprintf("{%s}", strings.Join(pairs, ", ")) +} + +// BinaryOp returns another object that is the result of +// a given binary operator and a right-hand side object. +func (o *ImmutableMap) BinaryOp(op token.Token, rhs Object) (Object, error) { + return nil, ErrInvalidOperator +} + +// Copy returns a copy of the type. +func (o *ImmutableMap) Copy() Object { + c := make(map[string]Object) + for k, v := range o.Value { + c[k] = v.Copy() + } + + return &Map{Value: c} +} + +// IsFalsy returns true if the value of the type is falsy. +func (o *ImmutableMap) IsFalsy() bool { + return len(o.Value) == 0 +} + +// IndexGet returns the value for the given key. +func (o *ImmutableMap) IndexGet(index Object) (res Object, err error) { + strIdx, ok := ToString(index) + if !ok { + err = ErrInvalidIndexType + return + } + + val, ok := o.Value[strIdx] + if !ok { + val = UndefinedValue + } + + return val, nil +} + +// Equals returns true if the value of the type +// is equal to the value of another object. +func (o *ImmutableMap) Equals(x Object) bool { + var xVal map[string]Object + switch x := x.(type) { + case *Map: + xVal = x.Value + case *ImmutableMap: + xVal = x.Value + default: + return false + } + + if len(o.Value) != len(xVal) { + return false + } + + for k, v := range o.Value { + tv := xVal[k] + if !v.Equals(tv) { + return false + } + } + + return true +} + +// Iterate creates an immutable map iterator. +func (o *ImmutableMap) Iterate() Iterator { + var keys []string + for k := range o.Value { + keys = append(keys, k) + } + + return &MapIterator{ + v: o.Value, + k: keys, + l: len(keys), + } +} diff --git a/vendor/github.com/d5/tengo/objects/index_assignable.go b/vendor/github.com/d5/tengo/objects/index_assignable.go new file mode 100644 index 00000000..a1c6cbff --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/index_assignable.go @@ -0,0 +1,9 @@ +package objects + +// IndexAssignable is an object that can take an index and a value +// on the left-hand side of the assignment statement. +type IndexAssignable interface { + // IndexSet should take an index Object and a value Object. + // If an error is returned, it will be treated as a run-time error. + IndexSet(index, value Object) error +} diff --git a/vendor/github.com/d5/tengo/objects/indexable.go b/vendor/github.com/d5/tengo/objects/indexable.go new file mode 100644 index 00000000..bbc81633 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/indexable.go @@ -0,0 +1,9 @@ +package objects + +// Indexable is an object that can take an index and return an object. +type Indexable interface { + // IndexGet should take an index Object and return a result Object or an error. + // If error is returned, the runtime will treat it as a run-time error and ignore returned value. + // If nil is returned as value, it will be converted to Undefined value by the runtime. + IndexGet(index Object) (value Object, err error) +} diff --git a/vendor/github.com/d5/tengo/objects/int.go b/vendor/github.com/d5/tengo/objects/int.go new file mode 100644 index 00000000..e902c93a --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/int.go @@ -0,0 +1,198 @@ +package objects + +import ( + "strconv" + + "github.com/d5/tengo/compiler/token" +) + +// Int represents an integer value. +type Int struct { + Value int64 +} + +func (o *Int) String() string { + return strconv.FormatInt(o.Value, 10) +} + +// TypeName returns the name of the type. +func (o *Int) TypeName() string { + return "int" +} + +// BinaryOp returns another object that is the result of +// a given binary operator and a right-hand side object. +func (o *Int) BinaryOp(op token.Token, rhs Object) (Object, error) { + switch rhs := rhs.(type) { + case *Int: + switch op { + case token.Add: + r := o.Value + rhs.Value + if r == o.Value { + return o, nil + } + return &Int{Value: r}, nil + case token.Sub: + r := o.Value - rhs.Value + if r == o.Value { + return o, nil + } + return &Int{Value: r}, nil + case token.Mul: + r := o.Value * rhs.Value + if r == o.Value { + return o, nil + } + return &Int{Value: r}, nil + case token.Quo: + r := o.Value / rhs.Value + if r == o.Value { + return o, nil + } + return &Int{Value: r}, nil + case token.Rem: + r := o.Value % rhs.Value + if r == o.Value { + return o, nil + } + return &Int{Value: r}, nil + case token.And: + r := o.Value & rhs.Value + if r == o.Value { + return o, nil + } + return &Int{Value: r}, nil + case token.Or: + r := o.Value | rhs.Value + if r == o.Value { + return o, nil + } + return &Int{Value: r}, nil + case token.Xor: + r := o.Value ^ rhs.Value + if r == o.Value { + return o, nil + } + return &Int{Value: r}, nil + case token.AndNot: + r := o.Value &^ rhs.Value + if r == o.Value { + return o, nil + } + return &Int{Value: r}, nil + case token.Shl: + r := o.Value << uint64(rhs.Value) + if r == o.Value { + return o, nil + } + return &Int{Value: r}, nil + case token.Shr: + r := o.Value >> uint64(rhs.Value) + if r == o.Value { + return o, nil + } + return &Int{Value: r}, nil + case token.Less: + if o.Value < rhs.Value { + return TrueValue, nil + } + return FalseValue, nil + case token.Greater: + if o.Value > rhs.Value { + return TrueValue, nil + } + return FalseValue, nil + case token.LessEq: + if o.Value <= rhs.Value { + return TrueValue, nil + } + return FalseValue, nil + case token.GreaterEq: + if o.Value >= rhs.Value { + return TrueValue, nil + } + return FalseValue, nil + } + case *Float: + switch op { + case token.Add: + return &Float{float64(o.Value) + rhs.Value}, nil + case token.Sub: + return &Float{float64(o.Value) - rhs.Value}, nil + case token.Mul: + return &Float{float64(o.Value) * rhs.Value}, nil + case token.Quo: + return &Float{float64(o.Value) / rhs.Value}, nil + case token.Less: + if float64(o.Value) < rhs.Value { + return TrueValue, nil + } + return FalseValue, nil + case token.Greater: + if float64(o.Value) > rhs.Value { + return TrueValue, nil + } + return FalseValue, nil + case token.LessEq: + if float64(o.Value) <= rhs.Value { + return TrueValue, nil + } + return FalseValue, nil + case token.GreaterEq: + if float64(o.Value) >= rhs.Value { + return TrueValue, nil + } + return FalseValue, nil + } + case *Char: + switch op { + case token.Add: + return &Char{rune(o.Value) + rhs.Value}, nil + case token.Sub: + return &Char{rune(o.Value) - rhs.Value}, nil + case token.Less: + if o.Value < int64(rhs.Value) { + return TrueValue, nil + } + return FalseValue, nil + case token.Greater: + if o.Value > int64(rhs.Value) { + return TrueValue, nil + } + return FalseValue, nil + case token.LessEq: + if o.Value <= int64(rhs.Value) { + return TrueValue, nil + } + return FalseValue, nil + case token.GreaterEq: + if o.Value >= int64(rhs.Value) { + return TrueValue, nil + } + return FalseValue, nil + } + } + + return nil, ErrInvalidOperator +} + +// Copy returns a copy of the type. +func (o *Int) Copy() Object { + return &Int{Value: o.Value} +} + +// IsFalsy returns true if the value of the type is falsy. +func (o *Int) IsFalsy() bool { + return o.Value == 0 +} + +// Equals returns true if the value of the type +// is equal to the value of another object. +func (o *Int) Equals(x Object) bool { + t, ok := x.(*Int) + if !ok { + return false + } + + return o.Value == t.Value +} diff --git a/vendor/github.com/d5/tengo/objects/iterable.go b/vendor/github.com/d5/tengo/objects/iterable.go new file mode 100644 index 00000000..e431d3d7 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/iterable.go @@ -0,0 +1,7 @@ +package objects + +// Iterable represents an object that has iterator. +type Iterable interface { + // Iterate should return an Iterator for the type. + Iterate() Iterator +} diff --git a/vendor/github.com/d5/tengo/objects/iterator.go b/vendor/github.com/d5/tengo/objects/iterator.go new file mode 100644 index 00000000..01522ba5 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/iterator.go @@ -0,0 +1,15 @@ +package objects + +// Iterator represents an iterator for underlying data type. +type Iterator interface { + Object + + // Next returns true if there are more elements to iterate. + Next() bool + + // Key returns the key or index value of the current element. + Key() Object + + // Value returns the value of the current element. + Value() Object +} diff --git a/vendor/github.com/d5/tengo/objects/map.go b/vendor/github.com/d5/tengo/objects/map.go new file mode 100644 index 00000000..c42ffe93 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/map.go @@ -0,0 +1,118 @@ +package objects + +import ( + "fmt" + "strings" + + "github.com/d5/tengo/compiler/token" +) + +// Map represents a map of objects. +type Map struct { + Value map[string]Object +} + +// TypeName returns the name of the type. +func (o *Map) TypeName() string { + return "map" +} + +func (o *Map) String() string { + var pairs []string + for k, v := range o.Value { + pairs = append(pairs, fmt.Sprintf("%s: %s", k, v.String())) + } + + return fmt.Sprintf("{%s}", strings.Join(pairs, ", ")) +} + +// BinaryOp returns another object that is the result of +// a given binary operator and a right-hand side object. +func (o *Map) BinaryOp(op token.Token, rhs Object) (Object, error) { + return nil, ErrInvalidOperator +} + +// Copy returns a copy of the type. +func (o *Map) Copy() Object { + c := make(map[string]Object) + for k, v := range o.Value { + c[k] = v.Copy() + } + + return &Map{Value: c} +} + +// IsFalsy returns true if the value of the type is falsy. +func (o *Map) IsFalsy() bool { + return len(o.Value) == 0 +} + +// Equals returns true if the value of the type +// is equal to the value of another object. +func (o *Map) Equals(x Object) bool { + var xVal map[string]Object + switch x := x.(type) { + case *Map: + xVal = x.Value + case *ImmutableMap: + xVal = x.Value + default: + return false + } + + if len(o.Value) != len(xVal) { + return false + } + + for k, v := range o.Value { + tv := xVal[k] + if !v.Equals(tv) { + return false + } + } + + return true +} + +// IndexGet returns the value for the given key. +func (o *Map) IndexGet(index Object) (res Object, err error) { + strIdx, ok := index.(*String) + if !ok { + err = ErrInvalidIndexType + return + } + + val, ok := o.Value[strIdx.Value] + if !ok { + val = UndefinedValue + } + + return val, nil +} + +// IndexSet sets the value for the given key. +func (o *Map) IndexSet(index, value Object) (err error) { + strIdx, ok := ToString(index) + if !ok { + err = ErrInvalidIndexType + return + } + + o.Value[strIdx] = value + + return nil +} + +// Iterate creates a map iterator. +func (o *Map) Iterate() Iterator { + var keys []string + for k := range o.Value { + keys = append(keys, k) + } + + return &MapIterator{ + v: o.Value, + k: keys, + l: len(keys), + } +} diff --git a/vendor/github.com/d5/tengo/objects/map_iterator.go b/vendor/github.com/d5/tengo/objects/map_iterator.go new file mode 100644 index 00000000..d60dd0e1 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/map_iterator.go @@ -0,0 +1,62 @@ +package objects + +import "github.com/d5/tengo/compiler/token" + +// MapIterator represents an iterator for the map. +type MapIterator struct { + v map[string]Object + k []string + i int + l int +} + +// TypeName returns the name of the type. +func (i *MapIterator) TypeName() string { + return "map-iterator" +} + +func (i *MapIterator) String() string { + return "<map-iterator>" +} + +// BinaryOp returns another object that is the result of +// a given binary operator and a right-hand side object. +func (i *MapIterator) BinaryOp(op token.Token, rhs Object) (Object, error) { + return nil, ErrInvalidOperator +} + +// IsFalsy returns true if the value of the type is falsy. +func (i *MapIterator) IsFalsy() bool { + return true +} + +// Equals returns true if the value of the type +// is equal to the value of another object. +func (i *MapIterator) Equals(Object) bool { + return false +} + +// Copy returns a copy of the type. +func (i *MapIterator) Copy() Object { + return &MapIterator{v: i.v, k: i.k, i: i.i, l: i.l} +} + +// Next returns true if there are more elements to iterate. +func (i *MapIterator) Next() bool { + i.i++ + return i.i <= i.l +} + +// Key returns the key or index value of the current element. +func (i *MapIterator) Key() Object { + k := i.k[i.i-1] + + return &String{Value: k} +} + +// Value returns the value of the current element. +func (i *MapIterator) Value() Object { + k := i.k[i.i-1] + + return i.v[k] +} diff --git a/vendor/github.com/d5/tengo/objects/object.go b/vendor/github.com/d5/tengo/objects/object.go new file mode 100644 index 00000000..4c5aa7ae --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/object.go @@ -0,0 +1,30 @@ +package objects + +import "github.com/d5/tengo/compiler/token" + +// Object represents an object in the VM. +type Object interface { + // TypeName should return the name of the type. + TypeName() string + + // String should return a string representation of the type's value. + String() string + + // BinaryOp should return another object that is the result of + // a given binary operator and a right-hand side object. + // If BinaryOp returns an error, the VM will treat it as a run-time error. + BinaryOp(op token.Token, rhs Object) (Object, error) + + // IsFalsy should return true if the value of the type + // should be considered as falsy. + IsFalsy() bool + + // Equals should return true if the value of the type + // should be considered as equal to the value of another object. + Equals(another Object) bool + + // Copy should return a copy of the type (and its value). + // Copy function will be used for copy() builtin function + // which is expected to deep-copy the values generally. + Copy() Object +} diff --git a/vendor/github.com/d5/tengo/objects/objects.go b/vendor/github.com/d5/tengo/objects/objects.go new file mode 100644 index 00000000..f3878b11 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/objects.go @@ -0,0 +1,12 @@ +package objects + +var ( + // TrueValue represents a true value. + TrueValue Object = &Bool{value: true} + + // FalseValue represents a false value. + FalseValue Object = &Bool{value: false} + + // UndefinedValue represents an undefined value. + UndefinedValue Object = &Undefined{} +) diff --git a/vendor/github.com/d5/tengo/objects/return_value.go b/vendor/github.com/d5/tengo/objects/return_value.go new file mode 100644 index 00000000..f7ef1dc4 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/return_value.go @@ -0,0 +1,39 @@ +package objects + +import "github.com/d5/tengo/compiler/token" + +// ReturnValue represents a value that is being returned. +type ReturnValue struct { + Value Object +} + +// TypeName returns the name of the type. +func (o *ReturnValue) TypeName() string { + return "return-value" +} + +func (o *ReturnValue) String() string { + return "<return-value>" +} + +// BinaryOp returns another object that is the result of +// a given binary operator and a right-hand side object. +func (o *ReturnValue) BinaryOp(op token.Token, rhs Object) (Object, error) { + return nil, ErrInvalidOperator +} + +// Copy returns a copy of the type. +func (o *ReturnValue) Copy() Object { + return &ReturnValue{Value: o.Copy()} +} + +// IsFalsy returns true if the value of the type is falsy. +func (o *ReturnValue) IsFalsy() bool { + return false +} + +// Equals returns true if the value of the type +// is equal to the value of another object. +func (o *ReturnValue) Equals(x Object) bool { + return false +} diff --git a/vendor/github.com/d5/tengo/objects/string.go b/vendor/github.com/d5/tengo/objects/string.go new file mode 100644 index 00000000..6a53b44d --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/string.go @@ -0,0 +1,95 @@ +package objects + +import ( + "strconv" + + "github.com/d5/tengo/compiler/token" +) + +// String represents a string value. +type String struct { + Value string + runeStr []rune +} + +// TypeName returns the name of the type. +func (o *String) TypeName() string { + return "string" +} + +func (o *String) String() string { + return strconv.Quote(o.Value) +} + +// BinaryOp returns another object that is the result of +// a given binary operator and a right-hand side object. +func (o *String) BinaryOp(op token.Token, rhs Object) (Object, error) { + switch op { + case token.Add: + switch rhs := rhs.(type) { + case *String: + return &String{Value: o.Value + rhs.Value}, nil + default: + return &String{Value: o.Value + rhs.String()}, nil + } + } + + return nil, ErrInvalidOperator +} + +// IsFalsy returns true if the value of the type is falsy. +func (o *String) IsFalsy() bool { + return len(o.Value) == 0 +} + +// Copy returns a copy of the type. +func (o *String) Copy() Object { + return &String{Value: o.Value} +} + +// Equals returns true if the value of the type +// is equal to the value of another object. +func (o *String) Equals(x Object) bool { + t, ok := x.(*String) + if !ok { + return false + } + + return o.Value == t.Value +} + +// IndexGet returns a character at a given index. +func (o *String) IndexGet(index Object) (res Object, err error) { + intIdx, ok := index.(*Int) + if !ok { + err = ErrInvalidIndexType + return + } + + idxVal := int(intIdx.Value) + + if o.runeStr == nil { + o.runeStr = []rune(o.Value) + } + + if idxVal < 0 || idxVal >= len(o.runeStr) { + res = UndefinedValue + return + } + + res = &Char{Value: o.runeStr[idxVal]} + + return +} + +// Iterate creates a string iterator. +func (o *String) Iterate() Iterator { + if o.runeStr == nil { + o.runeStr = []rune(o.Value) + } + + return &StringIterator{ + v: o.runeStr, + l: len(o.runeStr), + } +} diff --git a/vendor/github.com/d5/tengo/objects/string_iterator.go b/vendor/github.com/d5/tengo/objects/string_iterator.go new file mode 100644 index 00000000..8bc95eb5 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/string_iterator.go @@ -0,0 +1,57 @@ +package objects + +import "github.com/d5/tengo/compiler/token" + +// StringIterator represents an iterator for a string. +type StringIterator struct { + v []rune + i int + l int +} + +// TypeName returns the name of the type. +func (i *StringIterator) TypeName() string { + return "string-iterator" +} + +func (i *StringIterator) String() string { + return "<string-iterator>" +} + +// BinaryOp returns another object that is the result of +// a given binary operator and a right-hand side object. +func (i *StringIterator) BinaryOp(op token.Token, rhs Object) (Object, error) { + return nil, ErrInvalidOperator +} + +// IsFalsy returns true if the value of the type is falsy. +func (i *StringIterator) IsFalsy() bool { + return true +} + +// Equals returns true if the value of the type +// is equal to the value of another object. +func (i *StringIterator) Equals(Object) bool { + return false +} + +// Copy returns a copy of the type. +func (i *StringIterator) Copy() Object { + return &StringIterator{v: i.v, i: i.i, l: i.l} +} + +// Next returns true if there are more elements to iterate. +func (i *StringIterator) Next() bool { + i.i++ + return i.i <= i.l +} + +// Key returns the key or index value of the current element. +func (i *StringIterator) Key() Object { + return &Int{Value: int64(i.i - 1)} +} + +// Value returns the value of the current element. +func (i *StringIterator) Value() Object { + return &Char{Value: i.v[i.i-1]} +} diff --git a/vendor/github.com/d5/tengo/objects/time.go b/vendor/github.com/d5/tengo/objects/time.go new file mode 100644 index 00000000..4e783cc8 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/time.go @@ -0,0 +1,89 @@ +package objects + +import ( + "time" + + "github.com/d5/tengo/compiler/token" +) + +// Time represents a time value. +type Time struct { + Value time.Time +} + +func (o *Time) String() string { + return o.Value.String() +} + +// TypeName returns the name of the type. +func (o *Time) TypeName() string { + return "time" +} + +// BinaryOp returns another object that is the result of +// a given binary operator and a right-hand side object. +func (o *Time) BinaryOp(op token.Token, rhs Object) (Object, error) { + switch rhs := rhs.(type) { + case *Int: + switch op { + case token.Add: // time + int => time + if rhs.Value == 0 { + return o, nil + } + return &Time{Value: o.Value.Add(time.Duration(rhs.Value))}, nil + case token.Sub: // time - int => time + if rhs.Value == 0 { + return o, nil + } + return &Time{Value: o.Value.Add(time.Duration(-rhs.Value))}, nil + } + case *Time: + switch op { + case token.Sub: // time - time => int (duration) + return &Int{Value: int64(o.Value.Sub(rhs.Value))}, nil + case token.Less: // time < time => bool + if o.Value.Before(rhs.Value) { + return TrueValue, nil + } + return FalseValue, nil + case token.Greater: + if o.Value.After(rhs.Value) { + return TrueValue, nil + } + return FalseValue, nil + case token.LessEq: + if o.Value.Equal(rhs.Value) || o.Value.Before(rhs.Value) { + return TrueValue, nil + } + return FalseValue, nil + case token.GreaterEq: + if o.Value.Equal(rhs.Value) || o.Value.After(rhs.Value) { + return TrueValue, nil + } + return FalseValue, nil + } + } + + return nil, ErrInvalidOperator +} + +// Copy returns a copy of the type. +func (o *Time) Copy() Object { + return &Time{Value: o.Value} +} + +// IsFalsy returns true if the value of the type is falsy. +func (o *Time) IsFalsy() bool { + return o.Value.IsZero() +} + +// Equals returns true if the value of the type +// is equal to the value of another object. +func (o *Time) Equals(x Object) bool { + t, ok := x.(*Time) + if !ok { + return false + } + + return o.Value.Equal(t.Value) +} diff --git a/vendor/github.com/d5/tengo/objects/undefined.go b/vendor/github.com/d5/tengo/objects/undefined.go new file mode 100644 index 00000000..79a380f5 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/undefined.go @@ -0,0 +1,42 @@ +package objects + +import "github.com/d5/tengo/compiler/token" + +// Undefined represents an undefined value. +type Undefined struct{} + +// TypeName returns the name of the type. +func (o *Undefined) TypeName() string { + return "undefined" +} + +func (o *Undefined) String() string { + return "<undefined>" +} + +// BinaryOp returns another object that is the result of +// a given binary operator and a right-hand side object. +func (o *Undefined) BinaryOp(op token.Token, rhs Object) (Object, error) { + return nil, ErrInvalidOperator +} + +// Copy returns a copy of the type. +func (o *Undefined) Copy() Object { + return o +} + +// IsFalsy returns true if the value of the type is falsy. +func (o *Undefined) IsFalsy() bool { + return true +} + +// Equals returns true if the value of the type +// is equal to the value of another object. +func (o *Undefined) Equals(x Object) bool { + return o == x +} + +// IndexGet returns an element at a given index. +func (o *Undefined) IndexGet(index Object) (Object, error) { + return UndefinedValue, nil +} diff --git a/vendor/github.com/d5/tengo/objects/user_function.go b/vendor/github.com/d5/tengo/objects/user_function.go new file mode 100644 index 00000000..1d9bb4f7 --- /dev/null +++ b/vendor/github.com/d5/tengo/objects/user_function.go @@ -0,0 +1,47 @@ +package objects + +import ( + "github.com/d5/tengo/compiler/token" +) + +// UserFunction represents a user function. +type UserFunction struct { + Name string + Value CallableFunc +} + +// TypeName returns the name of the type. +func (o *UserFunction) TypeName() string { + return "user-function:" + o.Name +} + +func (o *UserFunction) String() string { + return "<user-function>" +} + +// BinaryOp returns another object that is the result of +// a given binary operator and a right-hand side object. +func (o *UserFunction) BinaryOp(op token.Token, rhs Object) (Object, error) { + return nil, ErrInvalidOperator +} + +// Copy returns a copy of the type. +func (o *UserFunction) Copy() Object { + return &UserFunction{Value: o.Value} +} + +// IsFalsy returns true if the value of the type is falsy. +func (o *UserFunction) IsFalsy() bool { + return false +} + +// Equals returns true if the value of the type +// is equal to the value of another object. +func (o *UserFunction) Equals(x Object) bool { + return false +} + +// Call invokes a user function. +func (o *UserFunction) Call(args ...Object) (Object, error) { + return o.Value(args...) +} |