Compare commits

...

3 commits

Author SHA1 Message Date
E Sequeira
fe792a9369 value semantics for bools 2022-07-20 16:20:02 +01:00
E Sequeira
9515d2f2c0 fix comment 2022-07-20 10:17:49 +01:00
E Sequeira
e302d643a1 faster BinaryOp 2022-07-20 10:17:49 +01:00
34 changed files with 881 additions and 819 deletions

View file

@ -153,7 +153,7 @@ func builtinIsInt(args ...Object) (Object, error) {
if len(args) != 1 { if len(args) != 1 {
return nil, ErrWrongNumArguments return nil, ErrWrongNumArguments
} }
if _, ok := args[0].(*Int); ok { if _, ok := args[0].(Int); ok {
return TrueValue, nil return TrueValue, nil
} }
return FalseValue, nil return FalseValue, nil
@ -163,7 +163,7 @@ func builtinIsFloat(args ...Object) (Object, error) {
if len(args) != 1 { if len(args) != 1 {
return nil, ErrWrongNumArguments return nil, ErrWrongNumArguments
} }
if _, ok := args[0].(*Float); ok { if _, ok := args[0].(Float); ok {
return TrueValue, nil return TrueValue, nil
} }
return FalseValue, nil return FalseValue, nil
@ -173,7 +173,7 @@ func builtinIsBool(args ...Object) (Object, error) {
if len(args) != 1 { if len(args) != 1 {
return nil, ErrWrongNumArguments return nil, ErrWrongNumArguments
} }
if _, ok := args[0].(*Bool); ok { if _, ok := args[0].(Bool); ok {
return TrueValue, nil return TrueValue, nil
} }
return FalseValue, nil return FalseValue, nil
@ -183,7 +183,7 @@ func builtinIsChar(args ...Object) (Object, error) {
if len(args) != 1 { if len(args) != 1 {
return nil, ErrWrongNumArguments return nil, ErrWrongNumArguments
} }
if _, ok := args[0].(*Char); ok { if _, ok := args[0].(Char); ok {
return TrueValue, nil return TrueValue, nil
} }
return FalseValue, nil return FalseValue, nil
@ -307,17 +307,17 @@ func builtinLen(args ...Object) (Object, error) {
} }
switch arg := args[0].(type) { switch arg := args[0].(type) {
case *Array: case *Array:
return &Int{Value: int64(len(arg.Value))}, nil return Int{Value: int64(len(arg.Value))}, nil
case *ImmutableArray: case *ImmutableArray:
return &Int{Value: int64(len(arg.Value))}, nil return Int{Value: int64(len(arg.Value))}, nil
case *String: case *String:
return &Int{Value: int64(len(arg.Value))}, nil return Int{Value: int64(len(arg.Value))}, nil
case *Bytes: case *Bytes:
return &Int{Value: int64(len(arg.Value))}, nil return Int{Value: int64(len(arg.Value))}, nil
case *Map: case *Map:
return &Int{Value: int64(len(arg.Value))}, nil return Int{Value: int64(len(arg.Value))}, nil
case *ImmutableMap: case *ImmutableMap:
return &Int{Value: int64(len(arg.Value))}, nil return Int{Value: int64(len(arg.Value))}, nil
default: default:
return nil, ErrInvalidArgumentType{ return nil, ErrInvalidArgumentType{
Name: "first", Name: "first",
@ -333,10 +333,11 @@ func builtinRange(args ...Object) (Object, error) {
if numArgs < 2 || numArgs > 3 { if numArgs < 2 || numArgs > 3 {
return nil, ErrWrongNumArguments return nil, ErrWrongNumArguments
} }
var start, stop, step *Int var start, stop Int
step := Int{Value: 1}
for i, arg := range args { for i, arg := range args {
v, ok := args[i].(*Int) v, ok := args[i].(Int)
if !ok { if !ok {
var name string var name string
switch i { switch i {
@ -367,10 +368,6 @@ func builtinRange(args ...Object) (Object, error) {
} }
} }
if step == nil {
step = &Int{Value: int64(1)}
}
return buildRange(start.Value, stop.Value, step.Value), nil return buildRange(start.Value, stop.Value, step.Value), nil
} }
@ -378,13 +375,13 @@ func buildRange(start, stop, step int64) *Array {
array := &Array{} array := &Array{}
if start <= stop { if start <= stop {
for i := start; i < stop; i += step { for i := start; i < stop; i += step {
array.Value = append(array.Value, &Int{ array.Value = append(array.Value, Int{
Value: i, Value: i,
}) })
} }
} else { } else {
for i := start; i > stop; i -= step { for i := start; i > stop; i -= step {
array.Value = append(array.Value, &Int{ array.Value = append(array.Value, Int{
Value: i, Value: i,
}) })
} }
@ -449,12 +446,12 @@ func builtinInt(args ...Object) (Object, error) {
if !(argsLen == 1 || argsLen == 2) { if !(argsLen == 1 || argsLen == 2) {
return nil, ErrWrongNumArguments return nil, ErrWrongNumArguments
} }
if _, ok := args[0].(*Int); ok { if _, ok := args[0].(Int); ok {
return args[0], nil return args[0], nil
} }
v, ok := ToInt64(args[0]) v, ok := ToInt64(args[0])
if ok { if ok {
return &Int{Value: v}, nil return Int{Value: v}, nil
} }
if argsLen == 2 { if argsLen == 2 {
return args[1], nil return args[1], nil
@ -467,12 +464,12 @@ func builtinFloat(args ...Object) (Object, error) {
if !(argsLen == 1 || argsLen == 2) { if !(argsLen == 1 || argsLen == 2) {
return nil, ErrWrongNumArguments return nil, ErrWrongNumArguments
} }
if _, ok := args[0].(*Float); ok { if _, ok := args[0].(Float); ok {
return args[0], nil return args[0], nil
} }
v, ok := ToFloat64(args[0]) v, ok := ToFloat64(args[0])
if ok { if ok {
return &Float{Value: v}, nil return Float{Value: v}, nil
} }
if argsLen == 2 { if argsLen == 2 {
return args[1], nil return args[1], nil
@ -484,7 +481,7 @@ func builtinBool(args ...Object) (Object, error) {
if len(args) != 1 { if len(args) != 1 {
return nil, ErrWrongNumArguments return nil, ErrWrongNumArguments
} }
if _, ok := args[0].(*Bool); ok { if _, ok := args[0].(Bool); ok {
return args[0], nil return args[0], nil
} }
v, ok := ToBool(args[0]) v, ok := ToBool(args[0])
@ -502,12 +499,12 @@ func builtinChar(args ...Object) (Object, error) {
if !(argsLen == 1 || argsLen == 2) { if !(argsLen == 1 || argsLen == 2) {
return nil, ErrWrongNumArguments return nil, ErrWrongNumArguments
} }
if _, ok := args[0].(*Char); ok { if _, ok := args[0].(Char); ok {
return args[0], nil return args[0], nil
} }
v, ok := ToRune(args[0]) v, ok := ToRune(args[0])
if ok { if ok {
return &Char{Value: v}, nil return Char{Value: v}, nil
} }
if argsLen == 2 { if argsLen == 2 {
return args[1], nil return args[1], nil
@ -522,7 +519,7 @@ func builtinBytes(args ...Object) (Object, error) {
} }
// bytes(N) => create a new bytes with given size N // bytes(N) => create a new bytes with given size N
if n, ok := args[0].(*Int); ok { if n, ok := args[0].(Int); ok {
if n.Value > int64(MaxBytesLen) { if n.Value > int64(MaxBytesLen) {
return nil, ErrBytesLimit return nil, ErrBytesLimit
} }
@ -627,7 +624,7 @@ func builtinSplice(args ...Object) (Object, error) {
var startIdx int var startIdx int
if argsLen > 1 { if argsLen > 1 {
arg1, ok := args[1].(*Int) arg1, ok := args[1].(Int)
if !ok { if !ok {
return nil, ErrInvalidArgumentType{ return nil, ErrInvalidArgumentType{
Name: "second", Name: "second",
@ -643,7 +640,7 @@ func builtinSplice(args ...Object) (Object, error) {
delCount := len(array.Value) delCount := len(array.Value)
if argsLen > 2 { if argsLen > 2 {
arg2, ok := args[2].(*Int) arg2, ok := args[2].(Int)
if !ok { if !ok {
return nil, ErrInvalidArgumentType{ return nil, ErrInvalidArgumentType{
Name: "third", Name: "third",

View file

@ -52,7 +52,7 @@ func Test_builtinDelete(t *testing.T) {
}, },
{name: "nil-map-nonstr-key", {name: "nil-map-nonstr-key",
args: args{[]tengo.Object{ args: args{[]tengo.Object{
&tengo.Map{}, &tengo.Int{}}}, wantErr: true, &tengo.Map{}, tengo.Int{}}}, wantErr: true,
wantedErr: tengo.ErrInvalidArgumentType{ wantedErr: tengo.ErrInvalidArgumentType{
Name: "second", Expected: "string", Found: "int"}, Name: "second", Expected: "string", Found: "int"},
}, },
@ -88,12 +88,12 @@ func Test_builtinDelete(t *testing.T) {
[]tengo.Object{ []tengo.Object{
&tengo.Map{Value: map[string]tengo.Object{ &tengo.Map{Value: map[string]tengo.Object{
"key1": &tengo.String{Value: "value1"}, "key1": &tengo.String{Value: "value1"},
"key2": &tengo.Int{Value: 10}, "key2": tengo.Int{Value: 10},
}}, }},
&tengo.String{Value: "key1"}}}, &tengo.String{Value: "key1"}}},
want: tengo.UndefinedValue, want: tengo.UndefinedValue,
target: &tengo.Map{Value: map[string]tengo.Object{ target: &tengo.Map{Value: map[string]tengo.Object{
"key2": &tengo.Int{Value: 10}}}, "key2": tengo.Int{Value: 10}}},
}, },
} }
for _, tt := range tests { for _, tt := range tests {
@ -166,12 +166,12 @@ func Test_builtinSplice(t *testing.T) {
Name: "second", Expected: "int", Found: "string"}, Name: "second", Expected: "int", Found: "string"},
}, },
{name: "negative index", {name: "negative index",
args: []tengo.Object{&tengo.Array{}, &tengo.Int{Value: -1}}, args: []tengo.Object{&tengo.Array{}, tengo.Int{Value: -1}},
wantErr: true, wantErr: true,
wantedErr: tengo.ErrIndexOutOfBounds}, wantedErr: tengo.ErrIndexOutOfBounds},
{name: "non int count", {name: "non int count",
args: []tengo.Object{ args: []tengo.Object{
&tengo.Array{}, &tengo.Int{Value: 0}, &tengo.Array{}, tengo.Int{Value: 0},
&tengo.String{Value: ""}}, &tengo.String{Value: ""}},
wantErr: true, wantErr: true,
wantedErr: tengo.ErrInvalidArgumentType{ wantedErr: tengo.ErrInvalidArgumentType{
@ -180,153 +180,153 @@ func Test_builtinSplice(t *testing.T) {
{name: "negative count", {name: "negative count",
args: []tengo.Object{ args: []tengo.Object{
&tengo.Array{Value: []tengo.Object{ &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 0}, tengo.Int{Value: 0},
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}}}, tengo.Int{Value: 2}}},
&tengo.Int{Value: 0}, tengo.Int{Value: 0},
&tengo.Int{Value: -1}}, tengo.Int{Value: -1}},
wantErr: true, wantErr: true,
wantedErr: tengo.ErrIndexOutOfBounds, wantedErr: tengo.ErrIndexOutOfBounds,
}, },
{name: "insert with zero count", {name: "insert with zero count",
args: []tengo.Object{ args: []tengo.Object{
&tengo.Array{Value: []tengo.Object{ &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 0}, tengo.Int{Value: 0},
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}}}, tengo.Int{Value: 2}}},
&tengo.Int{Value: 0}, tengo.Int{Value: 0},
&tengo.Int{Value: 0}, tengo.Int{Value: 0},
&tengo.String{Value: "b"}}, &tengo.String{Value: "b"}},
deleted: &tengo.Array{Value: []tengo.Object{}}, deleted: &tengo.Array{Value: []tengo.Object{}},
Array: &tengo.Array{Value: []tengo.Object{ Array: &tengo.Array{Value: []tengo.Object{
&tengo.String{Value: "b"}, &tengo.String{Value: "b"},
&tengo.Int{Value: 0}, tengo.Int{Value: 0},
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}}}, tengo.Int{Value: 2}}},
}, },
{name: "insert", {name: "insert",
args: []tengo.Object{ args: []tengo.Object{
&tengo.Array{Value: []tengo.Object{ &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 0}, tengo.Int{Value: 0},
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}}}, tengo.Int{Value: 2}}},
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 0}, tengo.Int{Value: 0},
&tengo.String{Value: "c"}, &tengo.String{Value: "c"},
&tengo.String{Value: "d"}}, &tengo.String{Value: "d"}},
deleted: &tengo.Array{Value: []tengo.Object{}}, deleted: &tengo.Array{Value: []tengo.Object{}},
Array: &tengo.Array{Value: []tengo.Object{ Array: &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 0}, tengo.Int{Value: 0},
&tengo.String{Value: "c"}, &tengo.String{Value: "c"},
&tengo.String{Value: "d"}, &tengo.String{Value: "d"},
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}}}, tengo.Int{Value: 2}}},
}, },
{name: "insert with zero count", {name: "insert with zero count",
args: []tengo.Object{ args: []tengo.Object{
&tengo.Array{Value: []tengo.Object{ &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 0}, tengo.Int{Value: 0},
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}}}, tengo.Int{Value: 2}}},
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 0}, tengo.Int{Value: 0},
&tengo.String{Value: "c"}, &tengo.String{Value: "c"},
&tengo.String{Value: "d"}}, &tengo.String{Value: "d"}},
deleted: &tengo.Array{Value: []tengo.Object{}}, deleted: &tengo.Array{Value: []tengo.Object{}},
Array: &tengo.Array{Value: []tengo.Object{ Array: &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 0}, tengo.Int{Value: 0},
&tengo.String{Value: "c"}, &tengo.String{Value: "c"},
&tengo.String{Value: "d"}, &tengo.String{Value: "d"},
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}}}, tengo.Int{Value: 2}}},
}, },
{name: "insert with delete", {name: "insert with delete",
args: []tengo.Object{ args: []tengo.Object{
&tengo.Array{Value: []tengo.Object{ &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 0}, tengo.Int{Value: 0},
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}}}, tengo.Int{Value: 2}}},
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.String{Value: "c"}, &tengo.String{Value: "c"},
&tengo.String{Value: "d"}}, &tengo.String{Value: "d"}},
deleted: &tengo.Array{ deleted: &tengo.Array{
Value: []tengo.Object{&tengo.Int{Value: 1}}}, Value: []tengo.Object{tengo.Int{Value: 1}}},
Array: &tengo.Array{Value: []tengo.Object{ Array: &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 0}, tengo.Int{Value: 0},
&tengo.String{Value: "c"}, &tengo.String{Value: "c"},
&tengo.String{Value: "d"}, &tengo.String{Value: "d"},
&tengo.Int{Value: 2}}}, tengo.Int{Value: 2}}},
}, },
{name: "insert with delete multi", {name: "insert with delete multi",
args: []tengo.Object{ args: []tengo.Object{
&tengo.Array{Value: []tengo.Object{ &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 0}, tengo.Int{Value: 0},
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}}}, tengo.Int{Value: 2}}},
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}, tengo.Int{Value: 2},
&tengo.String{Value: "c"}, &tengo.String{Value: "c"},
&tengo.String{Value: "d"}}, &tengo.String{Value: "d"}},
deleted: &tengo.Array{Value: []tengo.Object{ deleted: &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}}}, tengo.Int{Value: 2}}},
Array: &tengo.Array{ Array: &tengo.Array{
Value: []tengo.Object{ Value: []tengo.Object{
&tengo.Int{Value: 0}, tengo.Int{Value: 0},
&tengo.String{Value: "c"}, &tengo.String{Value: "c"},
&tengo.String{Value: "d"}}}, &tengo.String{Value: "d"}}},
}, },
{name: "delete all with positive count", {name: "delete all with positive count",
args: []tengo.Object{ args: []tengo.Object{
&tengo.Array{Value: []tengo.Object{ &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 0}, tengo.Int{Value: 0},
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}}}, tengo.Int{Value: 2}}},
&tengo.Int{Value: 0}, tengo.Int{Value: 0},
&tengo.Int{Value: 3}}, tengo.Int{Value: 3}},
deleted: &tengo.Array{Value: []tengo.Object{ deleted: &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 0}, tengo.Int{Value: 0},
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}}}, tengo.Int{Value: 2}}},
Array: &tengo.Array{Value: []tengo.Object{}}, Array: &tengo.Array{Value: []tengo.Object{}},
}, },
{name: "delete all with big count", {name: "delete all with big count",
args: []tengo.Object{ args: []tengo.Object{
&tengo.Array{Value: []tengo.Object{ &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 0}, tengo.Int{Value: 0},
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}}}, tengo.Int{Value: 2}}},
&tengo.Int{Value: 0}, tengo.Int{Value: 0},
&tengo.Int{Value: 5}}, tengo.Int{Value: 5}},
deleted: &tengo.Array{Value: []tengo.Object{ deleted: &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 0}, tengo.Int{Value: 0},
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}}}, tengo.Int{Value: 2}}},
Array: &tengo.Array{Value: []tengo.Object{}}, Array: &tengo.Array{Value: []tengo.Object{}},
}, },
{name: "nothing2", {name: "nothing2",
args: []tengo.Object{ args: []tengo.Object{
&tengo.Array{Value: []tengo.Object{ &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 0}, tengo.Int{Value: 0},
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}}}}, tengo.Int{Value: 2}}}},
Array: &tengo.Array{Value: []tengo.Object{}}, Array: &tengo.Array{Value: []tengo.Object{}},
deleted: &tengo.Array{Value: []tengo.Object{ deleted: &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 0}, tengo.Int{Value: 0},
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}}}, tengo.Int{Value: 2}}},
}, },
{name: "pop without count", {name: "pop without count",
args: []tengo.Object{ args: []tengo.Object{
&tengo.Array{Value: []tengo.Object{ &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 0}, tengo.Int{Value: 0},
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}}}, tengo.Int{Value: 2}}},
&tengo.Int{Value: 2}}, tengo.Int{Value: 2}},
deleted: &tengo.Array{Value: []tengo.Object{&tengo.Int{Value: 2}}}, deleted: &tengo.Array{Value: []tengo.Object{tengo.Int{Value: 2}}},
Array: &tengo.Array{Value: []tengo.Object{ Array: &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 0}, &tengo.Int{Value: 1}}}, tengo.Int{Value: 0}, tengo.Int{Value: 1}}},
}, },
} }
for _, tt := range tests { for _, tt := range tests {
@ -388,36 +388,36 @@ func Test_builtinRange(t *testing.T) {
Name: "start", Expected: "int", Found: "string"}, Name: "start", Expected: "int", Found: "string"},
}, },
{name: "invalid stop", {name: "invalid stop",
args: []tengo.Object{&tengo.Int{}, &tengo.String{}}, args: []tengo.Object{tengo.Int{}, &tengo.String{}},
wantErr: true, wantErr: true,
wantedErr: tengo.ErrInvalidArgumentType{ wantedErr: tengo.ErrInvalidArgumentType{
Name: "stop", Expected: "int", Found: "string"}, Name: "stop", Expected: "int", Found: "string"},
}, },
{name: "invalid step", {name: "invalid step",
args: []tengo.Object{&tengo.Int{}, &tengo.Int{}, &tengo.String{}}, args: []tengo.Object{tengo.Int{}, tengo.Int{}, &tengo.String{}},
wantErr: true, wantErr: true,
wantedErr: tengo.ErrInvalidArgumentType{ wantedErr: tengo.ErrInvalidArgumentType{
Name: "step", Expected: "int", Found: "string"}, Name: "step", Expected: "int", Found: "string"},
}, },
{name: "zero step", {name: "zero step",
args: []tengo.Object{&tengo.Int{}, &tengo.Int{}, &tengo.Int{}}, //must greate than 0 args: []tengo.Object{tengo.Int{}, tengo.Int{}, tengo.Int{}}, //must greate than 0
wantErr: true, wantErr: true,
wantedErr: tengo.ErrInvalidRangeStep, wantedErr: tengo.ErrInvalidRangeStep,
}, },
{name: "negative step", {name: "negative step",
args: []tengo.Object{&tengo.Int{}, &tengo.Int{}, intObject(-2)}, //must greate than 0 args: []tengo.Object{tengo.Int{}, tengo.Int{}, intObject(-2)}, //must greate than 0
wantErr: true, wantErr: true,
wantedErr: tengo.ErrInvalidRangeStep, wantedErr: tengo.ErrInvalidRangeStep,
}, },
{name: "same bound", {name: "same bound",
args: []tengo.Object{&tengo.Int{}, &tengo.Int{}}, args: []tengo.Object{tengo.Int{}, tengo.Int{}},
wantErr: false, wantErr: false,
result: &tengo.Array{ result: &tengo.Array{
Value: nil, Value: nil,
}, },
}, },
{name: "positive range", {name: "positive range",
args: []tengo.Object{&tengo.Int{}, &tengo.Int{Value: 5}}, args: []tengo.Object{tengo.Int{}, tengo.Int{Value: 5}},
wantErr: false, wantErr: false,
result: &tengo.Array{ result: &tengo.Array{
Value: []tengo.Object{ Value: []tengo.Object{
@ -430,7 +430,7 @@ func Test_builtinRange(t *testing.T) {
}, },
}, },
{name: "negative range", {name: "negative range",
args: []tengo.Object{&tengo.Int{}, &tengo.Int{Value: -5}}, args: []tengo.Object{tengo.Int{}, tengo.Int{Value: -5}},
wantErr: false, wantErr: false,
result: &tengo.Array{ result: &tengo.Array{
Value: []tengo.Object{ Value: []tengo.Object{
@ -444,7 +444,7 @@ func Test_builtinRange(t *testing.T) {
}, },
{name: "positive with step", {name: "positive with step",
args: []tengo.Object{&tengo.Int{}, &tengo.Int{Value: 5}, &tengo.Int{Value: 2}}, args: []tengo.Object{tengo.Int{}, tengo.Int{Value: 5}, tengo.Int{Value: 2}},
wantErr: false, wantErr: false,
result: &tengo.Array{ result: &tengo.Array{
Value: []tengo.Object{ Value: []tengo.Object{
@ -456,7 +456,7 @@ func Test_builtinRange(t *testing.T) {
}, },
{name: "negative with step", {name: "negative with step",
args: []tengo.Object{&tengo.Int{}, &tengo.Int{Value: -10}, &tengo.Int{Value: 2}}, args: []tengo.Object{tengo.Int{}, tengo.Int{Value: -10}, tengo.Int{Value: 2}},
wantErr: false, wantErr: false,
result: &tengo.Array{ result: &tengo.Array{
Value: []tengo.Object{ Value: []tengo.Object{
@ -470,7 +470,7 @@ func Test_builtinRange(t *testing.T) {
}, },
{name: "large range", {name: "large range",
args: []tengo.Object{intObject(-10), intObject(10), &tengo.Int{Value: 3}}, args: []tengo.Object{intObject(-10), intObject(10), tengo.Int{Value: 3}},
wantErr: false, wantErr: false,
result: &tengo.Array{ result: &tengo.Array{
Value: []tengo.Object{ Value: []tengo.Object{

View file

@ -4,7 +4,6 @@ import (
"encoding/gob" "encoding/gob"
"fmt" "fmt"
"io" "io"
"reflect"
"github.com/d5/tengo/v2/parser" "github.com/d5/tengo/v2/parser"
) )
@ -56,7 +55,7 @@ func (b *Bytecode) FormatConstants() (output []string) {
} }
default: default:
output = append(output, fmt.Sprintf("[% 3d] %s (%s|%p)", output = append(output, fmt.Sprintf("[% 3d] %s (%s|%p)",
cidx, cn, reflect.TypeOf(cn).Elem().Name(), &cn)) cidx, cn, cn.TypeName(), &cn))
} }
} }
return return
@ -126,7 +125,7 @@ func (b *Bytecode) RemoveDuplicates() {
indexMap[curIdx] = newIdx indexMap[curIdx] = newIdx
deduped = append(deduped, c) deduped = append(deduped, c)
} }
case *Int: case Int:
if newIdx, ok := ints[c.Value]; ok { if newIdx, ok := ints[c.Value]; ok {
indexMap[curIdx] = newIdx indexMap[curIdx] = newIdx
} else { } else {
@ -144,7 +143,7 @@ func (b *Bytecode) RemoveDuplicates() {
indexMap[curIdx] = newIdx indexMap[curIdx] = newIdx
deduped = append(deduped, c) deduped = append(deduped, c)
} }
case *Float: case Float:
if newIdx, ok := floats[c.Value]; ok { if newIdx, ok := floats[c.Value]; ok {
indexMap[curIdx] = newIdx indexMap[curIdx] = newIdx
} else { } else {
@ -153,7 +152,7 @@ func (b *Bytecode) RemoveDuplicates() {
indexMap[curIdx] = newIdx indexMap[curIdx] = newIdx
deduped = append(deduped, c) deduped = append(deduped, c)
} }
case *Char: case Char:
if newIdx, ok := chars[c.Value]; ok { if newIdx, ok := chars[c.Value]; ok {
indexMap[curIdx] = newIdx indexMap[curIdx] = newIdx
} else { } else {
@ -188,7 +187,7 @@ func fixDecodedObject(
modules *ModuleMap, modules *ModuleMap,
) (Object, error) { ) (Object, error) {
switch o := o.(type) { switch o := o.(type) {
case *Bool: case Bool:
if o.IsFalsy() { if o.IsFalsy() {
return FalseValue, nil return FalseValue, nil
} }
@ -281,15 +280,15 @@ func init() {
gob.Register(&parser.SourceFileSet{}) gob.Register(&parser.SourceFileSet{})
gob.Register(&parser.SourceFile{}) gob.Register(&parser.SourceFile{})
gob.Register(&Array{}) gob.Register(&Array{})
gob.Register(&Bool{}) gob.Register(Bool{})
gob.Register(&Bytes{}) gob.Register(&Bytes{})
gob.Register(&Char{}) gob.Register(Char{})
gob.Register(&CompiledFunction{}) gob.Register(&CompiledFunction{})
gob.Register(&Error{}) gob.Register(&Error{})
gob.Register(&Float{}) gob.Register(Float{})
gob.Register(&ImmutableArray{}) gob.Register(&ImmutableArray{})
gob.Register(&ImmutableMap{}) gob.Register(&ImmutableMap{})
gob.Register(&Int{}) gob.Register(Int{})
gob.Register(&Map{}) gob.Register(&Map{})
gob.Register(&String{}) gob.Register(&String{})
gob.Register(&Time{}) gob.Register(&Time{})

View file

@ -20,15 +20,15 @@ func TestBytecode(t *testing.T) {
testBytecodeSerialization(t, bytecode( testBytecodeSerialization(t, bytecode(
concatInsts(), objectsArray( concatInsts(), objectsArray(
&tengo.Char{Value: 'y'}, tengo.Char{Value: 'y'},
&tengo.Float{Value: 93.11}, tengo.Float{Value: 93.11},
compiledFunction(1, 0, compiledFunction(1, 0,
tengo.MakeInstruction(parser.OpConstant, 3), tengo.MakeInstruction(parser.OpConstant, 3),
tengo.MakeInstruction(parser.OpSetLocal, 0), tengo.MakeInstruction(parser.OpSetLocal, 0),
tengo.MakeInstruction(parser.OpGetGlobal, 0), tengo.MakeInstruction(parser.OpGetGlobal, 0),
tengo.MakeInstruction(parser.OpGetFree, 0)), tengo.MakeInstruction(parser.OpGetFree, 0)),
&tengo.Float{Value: 39.2}, tengo.Float{Value: 39.2},
&tengo.Int{Value: 192}, tengo.Int{Value: 192},
&tengo.String{Value: "bar"}))) &tengo.String{Value: "bar"})))
testBytecodeSerialization(t, bytecodeFileSet( testBytecodeSerialization(t, bytecodeFileSet(
@ -38,17 +38,17 @@ func TestBytecode(t *testing.T) {
tengo.MakeInstruction(parser.OpConstant, 6), tengo.MakeInstruction(parser.OpConstant, 6),
tengo.MakeInstruction(parser.OpPop)), tengo.MakeInstruction(parser.OpPop)),
objectsArray( objectsArray(
&tengo.Int{Value: 55}, tengo.Int{Value: 55},
&tengo.Int{Value: 66}, tengo.Int{Value: 66},
&tengo.Int{Value: 77}, tengo.Int{Value: 77},
&tengo.Int{Value: 88}, tengo.Int{Value: 88},
&tengo.ImmutableMap{ &tengo.ImmutableMap{
Value: map[string]tengo.Object{ Value: map[string]tengo.Object{
"array": &tengo.ImmutableArray{ "array": &tengo.ImmutableArray{
Value: []tengo.Object{ Value: []tengo.Object{
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}, tengo.Int{Value: 2},
&tengo.Int{Value: 3}, tengo.Int{Value: 3},
tengo.TrueValue, tengo.TrueValue,
tengo.FalseValue, tengo.FalseValue,
tengo.UndefinedValue, tengo.UndefinedValue,
@ -57,16 +57,16 @@ func TestBytecode(t *testing.T) {
"true": tengo.TrueValue, "true": tengo.TrueValue,
"false": tengo.FalseValue, "false": tengo.FalseValue,
"bytes": &tengo.Bytes{Value: make([]byte, 16)}, "bytes": &tengo.Bytes{Value: make([]byte, 16)},
"char": &tengo.Char{Value: 'Y'}, "char": tengo.Char{Value: 'Y'},
"error": &tengo.Error{Value: &tengo.String{ "error": &tengo.Error{Value: &tengo.String{
Value: "some error", Value: "some error",
}}, }},
"float": &tengo.Float{Value: -19.84}, "float": tengo.Float{Value: -19.84},
"immutable_array": &tengo.ImmutableArray{ "immutable_array": &tengo.ImmutableArray{
Value: []tengo.Object{ Value: []tengo.Object{
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}, tengo.Int{Value: 2},
&tengo.Int{Value: 3}, tengo.Int{Value: 3},
tengo.TrueValue, tengo.TrueValue,
tengo.FalseValue, tengo.FalseValue,
tengo.UndefinedValue, tengo.UndefinedValue,
@ -74,20 +74,20 @@ func TestBytecode(t *testing.T) {
}, },
"immutable_map": &tengo.ImmutableMap{ "immutable_map": &tengo.ImmutableMap{
Value: map[string]tengo.Object{ Value: map[string]tengo.Object{
"a": &tengo.Int{Value: 1}, "a": tengo.Int{Value: 1},
"b": &tengo.Int{Value: 2}, "b": tengo.Int{Value: 2},
"c": &tengo.Int{Value: 3}, "c": tengo.Int{Value: 3},
"d": tengo.TrueValue, "d": tengo.TrueValue,
"e": tengo.FalseValue, "e": tengo.FalseValue,
"f": tengo.UndefinedValue, "f": tengo.UndefinedValue,
}, },
}, },
"int": &tengo.Int{Value: 91}, "int": tengo.Int{Value: 91},
"map": &tengo.Map{ "map": &tengo.Map{
Value: map[string]tengo.Object{ Value: map[string]tengo.Object{
"a": &tengo.Int{Value: 1}, "a": tengo.Int{Value: 1},
"b": &tengo.Int{Value: 2}, "b": tengo.Int{Value: 2},
"c": &tengo.Int{Value: 3}, "c": tengo.Int{Value: 3},
"d": tengo.TrueValue, "d": tengo.TrueValue,
"e": tengo.FalseValue, "e": tengo.FalseValue,
"f": tengo.UndefinedValue, "f": tengo.UndefinedValue,
@ -130,27 +130,27 @@ func TestBytecode_RemoveDuplicates(t *testing.T) {
testBytecodeRemoveDuplicates(t, testBytecodeRemoveDuplicates(t,
bytecode( bytecode(
concatInsts(), objectsArray( concatInsts(), objectsArray(
&tengo.Char{Value: 'y'}, tengo.Char{Value: 'y'},
&tengo.Float{Value: 93.11}, tengo.Float{Value: 93.11},
compiledFunction(1, 0, compiledFunction(1, 0,
tengo.MakeInstruction(parser.OpConstant, 3), tengo.MakeInstruction(parser.OpConstant, 3),
tengo.MakeInstruction(parser.OpSetLocal, 0), tengo.MakeInstruction(parser.OpSetLocal, 0),
tengo.MakeInstruction(parser.OpGetGlobal, 0), tengo.MakeInstruction(parser.OpGetGlobal, 0),
tengo.MakeInstruction(parser.OpGetFree, 0)), tengo.MakeInstruction(parser.OpGetFree, 0)),
&tengo.Float{Value: 39.2}, tengo.Float{Value: 39.2},
&tengo.Int{Value: 192}, tengo.Int{Value: 192},
&tengo.String{Value: "bar"})), &tengo.String{Value: "bar"})),
bytecode( bytecode(
concatInsts(), objectsArray( concatInsts(), objectsArray(
&tengo.Char{Value: 'y'}, tengo.Char{Value: 'y'},
&tengo.Float{Value: 93.11}, tengo.Float{Value: 93.11},
compiledFunction(1, 0, compiledFunction(1, 0,
tengo.MakeInstruction(parser.OpConstant, 3), tengo.MakeInstruction(parser.OpConstant, 3),
tengo.MakeInstruction(parser.OpSetLocal, 0), tengo.MakeInstruction(parser.OpSetLocal, 0),
tengo.MakeInstruction(parser.OpGetGlobal, 0), tengo.MakeInstruction(parser.OpGetGlobal, 0),
tengo.MakeInstruction(parser.OpGetFree, 0)), tengo.MakeInstruction(parser.OpGetFree, 0)),
&tengo.Float{Value: 39.2}, tengo.Float{Value: 39.2},
&tengo.Int{Value: 192}, tengo.Int{Value: 192},
&tengo.String{Value: "bar"}))) &tengo.String{Value: "bar"})))
testBytecodeRemoveDuplicates(t, testBytecodeRemoveDuplicates(t,
@ -167,9 +167,9 @@ func TestBytecode_RemoveDuplicates(t *testing.T) {
tengo.MakeInstruction(parser.OpConstant, 8), tengo.MakeInstruction(parser.OpConstant, 8),
tengo.MakeInstruction(parser.OpClosure, 4, 1)), tengo.MakeInstruction(parser.OpClosure, 4, 1)),
objectsArray( objectsArray(
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Float{Value: 2.0}, tengo.Float{Value: 2.0},
&tengo.Char{Value: '3'}, tengo.Char{Value: '3'},
&tengo.String{Value: "four"}, &tengo.String{Value: "four"},
compiledFunction(1, 0, compiledFunction(1, 0,
tengo.MakeInstruction(parser.OpConstant, 3), tengo.MakeInstruction(parser.OpConstant, 3),
@ -177,9 +177,9 @@ func TestBytecode_RemoveDuplicates(t *testing.T) {
tengo.MakeInstruction(parser.OpSetLocal, 0), tengo.MakeInstruction(parser.OpSetLocal, 0),
tengo.MakeInstruction(parser.OpGetGlobal, 0), tengo.MakeInstruction(parser.OpGetGlobal, 0),
tengo.MakeInstruction(parser.OpGetFree, 0)), tengo.MakeInstruction(parser.OpGetFree, 0)),
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Float{Value: 2.0}, tengo.Float{Value: 2.0},
&tengo.Char{Value: '3'}, tengo.Char{Value: '3'},
&tengo.String{Value: "four"})), &tengo.String{Value: "four"})),
bytecode( bytecode(
concatInsts( concatInsts(
@ -194,9 +194,9 @@ func TestBytecode_RemoveDuplicates(t *testing.T) {
tengo.MakeInstruction(parser.OpConstant, 3), tengo.MakeInstruction(parser.OpConstant, 3),
tengo.MakeInstruction(parser.OpClosure, 4, 1)), tengo.MakeInstruction(parser.OpClosure, 4, 1)),
objectsArray( objectsArray(
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Float{Value: 2.0}, tengo.Float{Value: 2.0},
&tengo.Char{Value: '3'}, tengo.Char{Value: '3'},
&tengo.String{Value: "four"}, &tengo.String{Value: "four"},
compiledFunction(1, 0, compiledFunction(1, 0,
tengo.MakeInstruction(parser.OpConstant, 3), tengo.MakeInstruction(parser.OpConstant, 3),
@ -214,11 +214,11 @@ func TestBytecode_RemoveDuplicates(t *testing.T) {
tengo.MakeInstruction(parser.OpConstant, 3), tengo.MakeInstruction(parser.OpConstant, 3),
tengo.MakeInstruction(parser.OpConstant, 4)), tengo.MakeInstruction(parser.OpConstant, 4)),
objectsArray( objectsArray(
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}, tengo.Int{Value: 2},
&tengo.Int{Value: 3}, tengo.Int{Value: 3},
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 3})), tengo.Int{Value: 3})),
bytecode( bytecode(
concatInsts( concatInsts(
tengo.MakeInstruction(parser.OpConstant, 0), tengo.MakeInstruction(parser.OpConstant, 0),
@ -227,19 +227,19 @@ func TestBytecode_RemoveDuplicates(t *testing.T) {
tengo.MakeInstruction(parser.OpConstant, 0), tengo.MakeInstruction(parser.OpConstant, 0),
tengo.MakeInstruction(parser.OpConstant, 2)), tengo.MakeInstruction(parser.OpConstant, 2)),
objectsArray( objectsArray(
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}, tengo.Int{Value: 2},
&tengo.Int{Value: 3}))) tengo.Int{Value: 3})))
} }
func TestBytecode_CountObjects(t *testing.T) { func TestBytecode_CountObjects(t *testing.T) {
b := bytecode( b := bytecode(
concatInsts(), concatInsts(),
objectsArray( objectsArray(
&tengo.Int{Value: 55}, tengo.Int{Value: 55},
&tengo.Int{Value: 66}, tengo.Int{Value: 66},
&tengo.Int{Value: 77}, tengo.Int{Value: 77},
&tengo.Int{Value: 88}, tengo.Int{Value: 88},
compiledFunction(1, 0, compiledFunction(1, 0,
tengo.MakeInstruction(parser.OpConstant, 3), tengo.MakeInstruction(parser.OpConstant, 3),
tengo.MakeInstruction(parser.OpReturn, 1)), tengo.MakeInstruction(parser.OpReturn, 1)),

View file

@ -36,9 +36,9 @@ fib := func(x) {
panic(err) panic(err)
} }
if nativeResult != int(result.(*tengo.Int).Value) { if nativeResult != int(result.(tengo.Int).Value) {
panic(fmt.Errorf("wrong result: %d != %d", nativeResult, panic(fmt.Errorf("wrong result: %d != %d", nativeResult,
int(result.(*tengo.Int).Value))) int(result.(tengo.Int).Value)))
} }
fmt.Println("-------------------------------------") fmt.Println("-------------------------------------")
@ -73,9 +73,9 @@ fib := func(x, s) {
panic(err) panic(err)
} }
if nativeResult != int(result.(*tengo.Int).Value) { if nativeResult != int(result.(tengo.Int).Value) {
panic(fmt.Errorf("wrong result: %d != %d", nativeResult, panic(fmt.Errorf("wrong result: %d != %d", nativeResult,
int(result.(*tengo.Int).Value))) int(result.(tengo.Int).Value)))
} }
fmt.Println("-------------------------------------") fmt.Println("-------------------------------------")
@ -110,9 +110,9 @@ fib := func(x, a, b) {
panic(err) panic(err)
} }
if nativeResult != int(result.(*tengo.Int).Value) { if nativeResult != int(result.(tengo.Int).Value) {
panic(fmt.Errorf("wrong result: %d != %d", nativeResult, panic(fmt.Errorf("wrong result: %d != %d", nativeResult,
int(result.(*tengo.Int).Value))) int(result.(tengo.Int).Value)))
} }
fmt.Println("-------------------------------------") fmt.Println("-------------------------------------")

View file

@ -204,10 +204,10 @@ func (c *Compiler) Compile(node parser.Node) error {
} }
case *parser.IntLit: case *parser.IntLit:
c.emit(node, parser.OpConstant, c.emit(node, parser.OpConstant,
c.addConstant(&Int{Value: node.Value})) c.addConstant(Int{Value: node.Value}))
case *parser.FloatLit: case *parser.FloatLit:
c.emit(node, parser.OpConstant, c.emit(node, parser.OpConstant,
c.addConstant(&Float{Value: node.Value})) c.addConstant(Float{Value: node.Value}))
case *parser.BoolLit: case *parser.BoolLit:
if node.Value { if node.Value {
c.emit(node, parser.OpTrue) c.emit(node, parser.OpTrue)
@ -222,7 +222,7 @@ func (c *Compiler) Compile(node parser.Node) error {
c.addConstant(&String{Value: node.Value})) c.addConstant(&String{Value: node.Value}))
case *parser.CharLit: case *parser.CharLit:
c.emit(node, parser.OpConstant, c.emit(node, parser.OpConstant,
c.addConstant(&Char{Value: node.Value})) c.addConstant(Char{Value: node.Value}))
case *parser.UndefinedLit: case *parser.UndefinedLit:
c.emit(node, parser.OpNull) c.emit(node, parser.OpNull)
case *parser.UnaryExpr: case *parser.UnaryExpr:

View file

@ -1458,8 +1458,8 @@ func objectsArray(o ...tengo.Object) []tengo.Object {
return o return o
} }
func intObject(v int64) *tengo.Int { func intObject(v int64) tengo.Int {
return &tengo.Int{Value: v} return tengo.Int{Value: v}
} }
func stringObject(v string) *tengo.String { func stringObject(v string) *tengo.String {

View file

@ -227,14 +227,14 @@ for more details on these runtime types.
Users can easily extend and add their own types by implementing the same Users can easily extend and add their own types by implementing the same
[Object](https://godoc.org/github.com/d5/tengo#Object) interface and the [Object](https://godoc.org/github.com/d5/tengo#Object) interface and the
default `ObjectImpl` implementation. Tengo runtime will treat them in the default `PtrObjectImpl` or `ObjectImpl` implementation. Tengo runtime will treat them in the
same way as its runtime types with no performance overhead. same way as its runtime types with no performance overhead.
Here's an example user type implementation, `StringArray`: Here's an example user type implementation, `StringArray`:
```golang ```golang
type StringArray struct { type StringArray struct {
tengo.ObjectImpl tengo.PtrObjectImpl
Value []string Value []string
} }
@ -309,7 +309,7 @@ It can also implement `IndexGet` and `IndexSet`:
```golang ```golang
func (o *StringArray) IndexGet(index tengo.Object) (tengo.Object, error) { func (o *StringArray) IndexGet(index tengo.Object) (tengo.Object, error) {
intIdx, ok := index.(*tengo.Int) intIdx, ok := index.(tengo.Int)
if ok { if ok {
if intIdx.Value >= 0 && intIdx.Value < int64(len(o.Value)) { if intIdx.Value >= 0 && intIdx.Value < int64(len(o.Value)) {
return &tengo.String{Value: o.Value[intIdx.Value]}, nil return &tengo.String{Value: o.Value[intIdx.Value]}, nil
@ -322,7 +322,7 @@ func (o *StringArray) IndexGet(index tengo.Object) (tengo.Object, error) {
if ok { if ok {
for vidx, str := range o.Value { for vidx, str := range o.Value {
if strIdx.Value == str { if strIdx.Value == str {
return &tengo.Int{Value: int64(vidx)}, nil return tengo.Int{Value: int64(vidx)}, nil
} }
} }
@ -338,7 +338,7 @@ func (o *StringArray) IndexSet(index, value tengo.Object) error {
return tengo.ErrInvalidIndexValueType return tengo.ErrInvalidIndexValueType
} }
intIdx, ok := index.(*tengo.Int) intIdx, ok := index.(tengo.Int)
if ok { if ok {
if intIdx.Value >= 0 && intIdx.Value < int64(len(o.Value)) { if intIdx.Value >= 0 && intIdx.Value < int64(len(o.Value)) {
o.Value[intIdx.Value] = strVal o.Value[intIdx.Value] = strVal
@ -375,7 +375,7 @@ func (o *StringArray) Call(args ...tengo.Object) (ret tengo.Object, err error) {
for i, v := range o.Value { for i, v := range o.Value {
if v == s1 { if v == s1 {
return &tengo.Int{Value: int64(i)}, nil return tengo.Int{Value: int64(i)}, nil
} }
} }
@ -409,7 +409,7 @@ func (o *StringArray) Iterate() tengo.Iterator {
} }
type StringArrayIterator struct { type StringArrayIterator struct {
tengo.ObjectImpl tengo.PtrObjectImpl
strArr *StringArray strArr *StringArray
idx int idx int
} }
@ -424,17 +424,16 @@ func (i *StringArrayIterator) Next() bool {
} }
func (i *StringArrayIterator) Key() tengo.Object { func (i *StringArrayIterator) Key() tengo.Object {
return &tengo.Int{Value: int64(i.idx - 1)} return tengo.Int{Value: int64(i.idx - 1)}
} }
func (i *StringArrayIterator) Value() tengo.Object { func (i *StringArrayIterator) Value() tengo.Object {
return &tengo.String{Value: i.strArr.Value[i.idx-1]} return &tengo.String{Value: i.strArr.Value[i.idx-1]}
} }
``` ```
### PtrObjectImpl and ObjectImpl
### ObjectImpl PtrObjectImpl and ObjectImpl represent a default Object Implementation. To defined a new value
type, one can embed PtrObjectImpl or ObjectImpl in their type declarations to avoid implementing
ObjectImpl represents a default Object Implementation. To defined a new value
type, one can embed ObjectImpl in their type declarations to avoid implementing
all non-significant methods. TypeName() and String() methods still need to be all non-significant methods. TypeName() and String() methods still need to be
implemented. implemented.

View file

@ -39,7 +39,7 @@ func NewGoProxy(ctx context.Context) *GoProxy {
// GoProxy is a builtin tengo module to register tengo functions and run them. // GoProxy is a builtin tengo module to register tengo functions and run them.
type GoProxy struct { type GoProxy struct {
tengo.ObjectImpl tengo.PtrObjectImpl
ctx context.Context ctx context.Context
moduleMap map[string]tengo.Object moduleMap map[string]tengo.Object
callbacks map[string]tengo.Object callbacks map[string]tengo.Object
@ -145,7 +145,7 @@ func (mod *GoProxy) args(args ...tengo.Object) (tengo.Object, error) {
} }
return tengo.UndefinedValue, nil return tengo.UndefinedValue, nil
}}, }},
"num_params": &tengo.Int{Value: int64(compiledFunc.NumParameters)}, "num_params": tengo.Int{Value: int64(compiledFunc.NumParameters)},
"callable": compiledFunc, "callable": compiledFunc,
"params": &tengo.Array{Value: params}, "params": &tengo.Array{Value: params},
}, },
@ -243,8 +243,8 @@ func main() {
fmt.Println("Calling tengo sum function") fmt.Println("Calling tengo sum function")
i1, i2 := rand.Int63n(100), rand.Int63n(100) i1, i2 := rand.Int63n(100), rand.Int63n(100)
callChan <- &CallArgs{Func: "sum", callChan <- &CallArgs{Func: "sum",
Params: []tengo.Object{&tengo.Int{Value: i1}, Params: []tengo.Object{tengo.Int{Value: i1},
&tengo.Int{Value: i2}}, tengo.Int{Value: i2}},
Result: result, Result: result,
} }
v := <-result v := <-result
@ -253,8 +253,8 @@ func main() {
fmt.Println("Calling tengo multiply function") fmt.Println("Calling tengo multiply function")
i1, i2 = rand.Int63n(20), rand.Int63n(20) i1, i2 = rand.Int63n(20), rand.Int63n(20)
callChan <- &CallArgs{Func: "multiply", callChan <- &CallArgs{Func: "multiply",
Params: []tengo.Object{&tengo.Int{Value: i1}, Params: []tengo.Object{tengo.Int{Value: i1},
&tengo.Int{Value: i2}}, tengo.Int{Value: i2}},
Result: result, Result: result,
} }
v = <-result v = <-result

View file

@ -951,11 +951,11 @@ func (p *pp) printArg(arg Object, verb rune) {
// Some types can be done without reflection. // Some types can be done without reflection.
switch f := arg.(type) { switch f := arg.(type) {
case *Bool: case Bool:
p.fmtBool(!f.IsFalsy(), verb) p.fmtBool(!f.IsFalsy(), verb)
case *Float: case Float:
p.fmtFloat(f.Value, 64, verb) p.fmtFloat(f.Value, 64, verb)
case *Int: case Int:
p.fmtInteger(uint64(f.Value), signed, verb) p.fmtInteger(uint64(f.Value), signed, verb)
case *String: case *String:
p.fmtString(f.Value, verb) p.fmtString(f.Value, verb)

View file

@ -16,7 +16,7 @@ type Iterator interface {
// ArrayIterator is an iterator for an array. // ArrayIterator is an iterator for an array.
type ArrayIterator struct { type ArrayIterator struct {
ObjectImpl PtrObjectImpl
v []Object v []Object
i int i int
l int l int
@ -55,7 +55,7 @@ func (i *ArrayIterator) Next() bool {
// Key returns the key or index value of the current element. // Key returns the key or index value of the current element.
func (i *ArrayIterator) Key() Object { func (i *ArrayIterator) Key() Object {
return &Int{Value: int64(i.i - 1)} return Int{Value: int64(i.i - 1)}
} }
// Value returns the value of the current element. // Value returns the value of the current element.
@ -65,7 +65,7 @@ func (i *ArrayIterator) Value() Object {
// BytesIterator represents an iterator for a string. // BytesIterator represents an iterator for a string.
type BytesIterator struct { type BytesIterator struct {
ObjectImpl PtrObjectImpl
v []byte v []byte
i int i int
l int l int
@ -99,17 +99,17 @@ func (i *BytesIterator) Next() bool {
// Key returns the key or index value of the current element. // Key returns the key or index value of the current element.
func (i *BytesIterator) Key() Object { func (i *BytesIterator) Key() Object {
return &Int{Value: int64(i.i - 1)} return Int{Value: int64(i.i - 1)}
} }
// Value returns the value of the current element. // Value returns the value of the current element.
func (i *BytesIterator) Value() Object { func (i *BytesIterator) Value() Object {
return &Int{Value: int64(i.v[i.i-1])} return Int{Value: int64(i.v[i.i-1])}
} }
// MapIterator represents an iterator for the map. // MapIterator represents an iterator for the map.
type MapIterator struct { type MapIterator struct {
ObjectImpl PtrObjectImpl
v map[string]Object v map[string]Object
k []string k []string
i int i int
@ -161,7 +161,7 @@ func (i *MapIterator) Value() Object {
// StringIterator represents an iterator for a string. // StringIterator represents an iterator for a string.
type StringIterator struct { type StringIterator struct {
ObjectImpl PtrObjectImpl
v []rune v []rune
i int i int
l int l int
@ -200,10 +200,10 @@ func (i *StringIterator) Next() bool {
// Key returns the key or index value of the current element. // Key returns the key or index value of the current element.
func (i *StringIterator) Key() Object { func (i *StringIterator) Key() Object {
return &Int{Value: int64(i.i - 1)} return Int{Value: int64(i.i - 1)}
} }
// Value returns the value of the current element. // Value returns the value of the current element.
func (i *StringIterator) Value() Object { func (i *StringIterator) Value() Object {
return &Char{Value: i.v[i.i-1]} return Char{Value: i.v[i.i-1]}
} }

View file

@ -14,10 +14,10 @@ import (
var ( var (
// TrueValue represents a true value. // TrueValue represents a true value.
TrueValue Object = &Bool{value: true} TrueValue Object = Bool{value: true}
// FalseValue represents a false value. // FalseValue represents a false value.
FalseValue Object = &Bool{value: false} FalseValue Object = Bool{value: false}
// UndefinedValue represents an undefined value. // UndefinedValue represents an undefined value.
UndefinedValue Object = &Undefined{} UndefinedValue Object = &Undefined{}
@ -87,70 +87,139 @@ type ObjectImpl struct {
} }
// TypeName returns the name of the type. // TypeName returns the name of the type.
func (o *ObjectImpl) TypeName() string { func (o ObjectImpl) TypeName() string {
panic(ErrNotImplemented) panic(ErrNotImplemented)
} }
func (o *ObjectImpl) String() string { func (o ObjectImpl) String() string {
panic(ErrNotImplemented) panic(ErrNotImplemented)
} }
// BinaryOp returns another object that is the result of a given binary // BinaryOp returns another object that is the result of a given binary
// operator and a right-hand side object. // operator and a right-hand side object.
func (o *ObjectImpl) BinaryOp(_ token.Token, _ Object) (Object, error) { func (o ObjectImpl) BinaryOp(_ token.Token, _ Object) (Object, error) {
return nil, ErrInvalidOperator return nil, ErrInvalidOperator
} }
// Copy returns a copy of the type. // Copy returns a copy of the type.
func (o *ObjectImpl) Copy() Object { func (o ObjectImpl) Copy() Object {
return nil return nil
} }
// IsFalsy returns true if the value of the type is falsy. // IsFalsy returns true if the value of the type is falsy.
func (o *ObjectImpl) IsFalsy() bool { func (o ObjectImpl) IsFalsy() bool {
return false return false
} }
// Equals returns true if the value of the type is equal to the value of // Equals returns true if the value of the type is equal to the value of
// another object. // another object.
func (o *ObjectImpl) Equals(x Object) bool { func (o ObjectImpl) Equals(x Object) bool {
return o == x return o == x
} }
// IndexGet returns an element at a given index. // IndexGet returns an element at a given index.
func (o *ObjectImpl) IndexGet(_ Object) (res Object, err error) { func (o ObjectImpl) IndexGet(_ Object) (res Object, err error) {
return nil, ErrNotIndexable return nil, ErrNotIndexable
} }
// IndexSet sets an element at a given index. // IndexSet sets an element at a given index.
func (o *ObjectImpl) IndexSet(_, _ Object) (err error) { func (o ObjectImpl) IndexSet(_, _ Object) (err error) {
return ErrNotIndexAssignable return ErrNotIndexAssignable
} }
// Iterate returns an iterator. // Iterate returns an iterator.
func (o *ObjectImpl) Iterate() Iterator { func (o ObjectImpl) Iterate() Iterator {
return nil return nil
} }
// CanIterate returns whether the Object can be Iterated. // CanIterate returns whether the Object can be Iterated.
func (o *ObjectImpl) CanIterate() bool { func (o ObjectImpl) CanIterate() bool {
return false return false
} }
// Call takes an arbitrary number of arguments and returns a return value // Call takes an arbitrary number of arguments and returns a return value
// and/or an error. // and/or an error.
func (o *ObjectImpl) Call(_ ...Object) (ret Object, err error) { func (o ObjectImpl) Call(_ ...Object) (ret Object, err error) {
return nil, nil return nil, nil
} }
// CanCall returns whether the Object can be Called. // CanCall returns whether the Object can be Called.
func (o *ObjectImpl) CanCall() bool { func (o ObjectImpl) CanCall() bool {
return false
}
// PtrObjectImpl represents a default Object Implementation. To defined a new
// value type, one can embed PtrObjectImpl in their type declarations to avoid
// implementing all non-significant methods. TypeName() and String() methods
// still need to be implemented.
type PtrObjectImpl struct {
}
// TypeName returns the name of the type.
func (o *PtrObjectImpl) TypeName() string {
panic(ErrNotImplemented)
}
func (o *PtrObjectImpl) String() string {
panic(ErrNotImplemented)
}
// BinaryOp returns another object that is the result of a given binary
// operator and a right-hand side object.
func (o *PtrObjectImpl) BinaryOp(_ token.Token, _ Object) (Object, error) {
return nil, ErrInvalidOperator
}
// Copy returns a copy of the type.
func (o *PtrObjectImpl) Copy() Object {
return nil
}
// IsFalsy returns true if the value of the type is falsy.
func (o *PtrObjectImpl) IsFalsy() bool {
return false
}
// Equals returns true if the value of the type is equal to the value of
// another object.
func (o *PtrObjectImpl) Equals(x Object) bool {
return o == x
}
// IndexGet returns an element at a given index.
func (o *PtrObjectImpl) IndexGet(_ Object) (res Object, err error) {
return nil, ErrNotIndexable
}
// IndexSet sets an element at a given index.
func (o *PtrObjectImpl) IndexSet(_, _ Object) (err error) {
return ErrNotIndexAssignable
}
// Iterate returns an iterator.
func (o *PtrObjectImpl) Iterate() Iterator {
return nil
}
// CanIterate returns whether the Object can be Iterated.
func (o *PtrObjectImpl) CanIterate() bool {
return false
}
// Call takes an arbitrary number of arguments and returns a return value
// and/or an error.
func (o *PtrObjectImpl) Call(_ ...Object) (ret Object, err error) {
return nil, nil
}
// CanCall returns whether the Object can be Called.
func (o *PtrObjectImpl) CanCall() bool {
return false return false
} }
// Array represents an array of objects. // Array represents an array of objects.
type Array struct { type Array struct {
ObjectImpl PtrObjectImpl
Value []Object Value []Object
} }
@ -221,7 +290,7 @@ func (o *Array) Equals(x Object) bool {
// IndexGet returns an element at a given index. // IndexGet returns an element at a given index.
func (o *Array) IndexGet(index Object) (res Object, err error) { func (o *Array) IndexGet(index Object) (res Object, err error) {
intIdx, ok := index.(*Int) intIdx, ok := index.(Int)
if !ok { if !ok {
err = ErrInvalidIndexType err = ErrInvalidIndexType
return return
@ -272,7 +341,7 @@ type Bool struct {
value bool value bool
} }
func (o *Bool) String() string { func (o Bool) String() string {
if o.value { if o.value {
return "true" return "true"
} }
@ -281,23 +350,23 @@ func (o *Bool) String() string {
} }
// TypeName returns the name of the type. // TypeName returns the name of the type.
func (o *Bool) TypeName() string { func (o Bool) TypeName() string {
return "bool" return "bool"
} }
// Copy returns a copy of the type. // Copy returns a copy of the type.
func (o *Bool) Copy() Object { func (o Bool) Copy() Object {
return o return o
} }
// IsFalsy returns true if the value of the type is falsy. // IsFalsy returns true if the value of the type is falsy.
func (o *Bool) IsFalsy() bool { func (o Bool) IsFalsy() bool {
return !o.value return !o.value
} }
// Equals returns true if the value of the type is equal to the value of // Equals returns true if the value of the type is equal to the value of
// another object. // another object.
func (o *Bool) Equals(x Object) bool { func (o Bool) Equals(x Object) bool {
return o == x return o == x
} }
@ -308,7 +377,7 @@ func (o *Bool) GobDecode(b []byte) (err error) {
} }
// GobEncode encodes bool values into bytes. // GobEncode encodes bool values into bytes.
func (o *Bool) GobEncode() (b []byte, err error) { func (o Bool) GobEncode() (b []byte, err error) {
if o.value { if o.value {
b = []byte{1} b = []byte{1}
} else { } else {
@ -319,7 +388,7 @@ func (o *Bool) GobEncode() (b []byte, err error) {
// BuiltinFunction represents a builtin function. // BuiltinFunction represents a builtin function.
type BuiltinFunction struct { type BuiltinFunction struct {
ObjectImpl PtrObjectImpl
Name string Name string
Value CallableFunc Value CallableFunc
} }
@ -376,7 +445,7 @@ func (m *BuiltinModule) AsImmutableMap(moduleName string) *ImmutableMap {
// Bytes represents a byte array. // Bytes represents a byte array.
type Bytes struct { type Bytes struct {
ObjectImpl PtrObjectImpl
Value []byte Value []byte
} }
@ -427,7 +496,7 @@ func (o *Bytes) Equals(x Object) bool {
// IndexGet returns an element (as Int) at a given index. // IndexGet returns an element (as Int) at a given index.
func (o *Bytes) IndexGet(index Object) (res Object, err error) { func (o *Bytes) IndexGet(index Object) (res Object, err error) {
intIdx, ok := index.(*Int) intIdx, ok := index.(Int)
if !ok { if !ok {
err = ErrInvalidIndexType err = ErrInvalidIndexType
return return
@ -437,7 +506,7 @@ func (o *Bytes) IndexGet(index Object) (res Object, err error) {
res = UndefinedValue res = UndefinedValue
return return
} }
res = &Int{Value: int64(o.Value[idxVal])} res = Int{Value: int64(o.Value[idxVal])}
return return
} }
@ -460,33 +529,33 @@ type Char struct {
Value rune Value rune
} }
func (o *Char) String() string { func (o Char) String() string {
return string(o.Value) return string(o.Value)
} }
// TypeName returns the name of the type. // TypeName returns the name of the type.
func (o *Char) TypeName() string { func (o Char) TypeName() string {
return "char" return "char"
} }
// BinaryOp returns another object that is the result of a given binary // BinaryOp returns another object that is the result of a given binary
// operator and a right-hand side object. // operator and a right-hand side object.
func (o *Char) BinaryOp(op token.Token, rhs Object) (Object, error) { func (o Char) BinaryOp(op token.Token, rhs Object) (Object, error) {
switch rhs := rhs.(type) { switch rhs := rhs.(type) {
case *Char: case Char:
switch op { switch op {
case token.Add: case token.Add:
r := o.Value + rhs.Value r := o.Value + rhs.Value
if r == o.Value { if r == o.Value {
return o, nil return o, nil
} }
return &Char{Value: r}, nil return Char{Value: r}, nil
case token.Sub: case token.Sub:
r := o.Value - rhs.Value r := o.Value - rhs.Value
if r == o.Value { if r == o.Value {
return o, nil return o, nil
} }
return &Char{Value: r}, nil return Char{Value: r}, nil
case token.Less: case token.Less:
if o.Value < rhs.Value { if o.Value < rhs.Value {
return TrueValue, nil return TrueValue, nil
@ -508,20 +577,20 @@ func (o *Char) BinaryOp(op token.Token, rhs Object) (Object, error) {
} }
return FalseValue, nil return FalseValue, nil
} }
case *Int: case Int:
switch op { switch op {
case token.Add: case token.Add:
r := o.Value + rune(rhs.Value) r := o.Value + rune(rhs.Value)
if r == o.Value { if r == o.Value {
return o, nil return o, nil
} }
return &Char{Value: r}, nil return Char{Value: r}, nil
case token.Sub: case token.Sub:
r := o.Value - rune(rhs.Value) r := o.Value - rune(rhs.Value)
if r == o.Value { if r == o.Value {
return o, nil return o, nil
} }
return &Char{Value: r}, nil return Char{Value: r}, nil
case token.Less: case token.Less:
if int64(o.Value) < rhs.Value { if int64(o.Value) < rhs.Value {
return TrueValue, nil return TrueValue, nil
@ -548,19 +617,19 @@ func (o *Char) BinaryOp(op token.Token, rhs Object) (Object, error) {
} }
// Copy returns a copy of the type. // Copy returns a copy of the type.
func (o *Char) Copy() Object { func (o Char) Copy() Object {
return &Char{Value: o.Value} return Char{Value: o.Value}
} }
// IsFalsy returns true if the value of the type is falsy. // IsFalsy returns true if the value of the type is falsy.
func (o *Char) IsFalsy() bool { func (o Char) IsFalsy() bool {
return o.Value == 0 return o.Value == 0
} }
// Equals returns true if the value of the type is equal to the value of // Equals returns true if the value of the type is equal to the value of
// another object. // another object.
func (o *Char) Equals(x Object) bool { func (o Char) Equals(x Object) bool {
t, ok := x.(*Char) t, ok := x.(Char)
if !ok { if !ok {
return false return false
} }
@ -569,7 +638,7 @@ func (o *Char) Equals(x Object) bool {
// CompiledFunction represents a compiled function. // CompiledFunction represents a compiled function.
type CompiledFunction struct { type CompiledFunction struct {
ObjectImpl PtrObjectImpl
Instructions []byte Instructions []byte
NumLocals int // number of local variables (including function parameters) NumLocals int // number of local variables (including function parameters)
NumParameters int NumParameters int
@ -622,7 +691,7 @@ func (o *CompiledFunction) CanCall() bool {
// Error represents an error value. // Error represents an error value.
type Error struct { type Error struct {
ObjectImpl PtrObjectImpl
Value Object Value Object
} }
@ -670,45 +739,45 @@ type Float struct {
Value float64 Value float64
} }
func (o *Float) String() string { func (o Float) String() string {
return strconv.FormatFloat(o.Value, 'f', -1, 64) return strconv.FormatFloat(o.Value, 'f', -1, 64)
} }
// TypeName returns the name of the type. // TypeName returns the name of the type.
func (o *Float) TypeName() string { func (o Float) TypeName() string {
return "float" return "float"
} }
// BinaryOp returns another object that is the result of a given binary // BinaryOp returns another object that is the result of a given binary
// operator and a right-hand side object. // operator and a right-hand side object.
func (o *Float) BinaryOp(op token.Token, rhs Object) (Object, error) { func (o Float) BinaryOp(op token.Token, rhs Object) (Object, error) {
switch rhs := rhs.(type) { switch rhs := rhs.(type) {
case *Float: case Float:
switch op { switch op {
case token.Add: case token.Add:
r := o.Value + rhs.Value r := o.Value + rhs.Value
if r == o.Value { if r == o.Value {
return o, nil return o, nil
} }
return &Float{Value: r}, nil return Float{Value: r}, nil
case token.Sub: case token.Sub:
r := o.Value - rhs.Value r := o.Value - rhs.Value
if r == o.Value { if r == o.Value {
return o, nil return o, nil
} }
return &Float{Value: r}, nil return Float{Value: r}, nil
case token.Mul: case token.Mul:
r := o.Value * rhs.Value r := o.Value * rhs.Value
if r == o.Value { if r == o.Value {
return o, nil return o, nil
} }
return &Float{Value: r}, nil return Float{Value: r}, nil
case token.Quo: case token.Quo:
r := o.Value / rhs.Value r := o.Value / rhs.Value
if r == o.Value { if r == o.Value {
return o, nil return o, nil
} }
return &Float{Value: r}, nil return Float{Value: r}, nil
case token.Less: case token.Less:
if o.Value < rhs.Value { if o.Value < rhs.Value {
return TrueValue, nil return TrueValue, nil
@ -730,32 +799,32 @@ func (o *Float) BinaryOp(op token.Token, rhs Object) (Object, error) {
} }
return FalseValue, nil return FalseValue, nil
} }
case *Int: case Int:
switch op { switch op {
case token.Add: case token.Add:
r := o.Value + float64(rhs.Value) r := o.Value + float64(rhs.Value)
if r == o.Value { if r == o.Value {
return o, nil return o, nil
} }
return &Float{Value: r}, nil return Float{Value: r}, nil
case token.Sub: case token.Sub:
r := o.Value - float64(rhs.Value) r := o.Value - float64(rhs.Value)
if r == o.Value { if r == o.Value {
return o, nil return o, nil
} }
return &Float{Value: r}, nil return Float{Value: r}, nil
case token.Mul: case token.Mul:
r := o.Value * float64(rhs.Value) r := o.Value * float64(rhs.Value)
if r == o.Value { if r == o.Value {
return o, nil return o, nil
} }
return &Float{Value: r}, nil return Float{Value: r}, nil
case token.Quo: case token.Quo:
r := o.Value / float64(rhs.Value) r := o.Value / float64(rhs.Value)
if r == o.Value { if r == o.Value {
return o, nil return o, nil
} }
return &Float{Value: r}, nil return Float{Value: r}, nil
case token.Less: case token.Less:
if o.Value < float64(rhs.Value) { if o.Value < float64(rhs.Value) {
return TrueValue, nil return TrueValue, nil
@ -782,19 +851,19 @@ func (o *Float) BinaryOp(op token.Token, rhs Object) (Object, error) {
} }
// Copy returns a copy of the type. // Copy returns a copy of the type.
func (o *Float) Copy() Object { func (o Float) Copy() Object {
return &Float{Value: o.Value} return Float{Value: o.Value}
} }
// IsFalsy returns true if the value of the type is falsy. // IsFalsy returns true if the value of the type is falsy.
func (o *Float) IsFalsy() bool { func (o Float) IsFalsy() bool {
return math.IsNaN(o.Value) return math.IsNaN(o.Value)
} }
// Equals returns true if the value of the type is equal to the value of // Equals returns true if the value of the type is equal to the value of
// another object. // another object.
func (o *Float) Equals(x Object) bool { func (o Float) Equals(x Object) bool {
t, ok := x.(*Float) t, ok := x.(Float)
if !ok { if !ok {
return false return false
} }
@ -803,7 +872,7 @@ func (o *Float) Equals(x Object) bool {
// ImmutableArray represents an immutable array of objects. // ImmutableArray represents an immutable array of objects.
type ImmutableArray struct { type ImmutableArray struct {
ObjectImpl PtrObjectImpl
Value []Object Value []Object
} }
@ -871,7 +940,7 @@ func (o *ImmutableArray) Equals(x Object) bool {
// IndexGet returns an element at a given index. // IndexGet returns an element at a given index.
func (o *ImmutableArray) IndexGet(index Object) (res Object, err error) { func (o *ImmutableArray) IndexGet(index Object) (res Object, err error) {
intIdx, ok := index.(*Int) intIdx, ok := index.(Int)
if !ok { if !ok {
err = ErrInvalidIndexType err = ErrInvalidIndexType
return return
@ -900,7 +969,7 @@ func (o *ImmutableArray) CanIterate() bool {
// ImmutableMap represents an immutable map object. // ImmutableMap represents an immutable map object.
type ImmutableMap struct { type ImmutableMap struct {
ObjectImpl PtrObjectImpl
Value map[string]Object Value map[string]Object
} }
@ -993,87 +1062,87 @@ type Int struct {
Value int64 Value int64
} }
func (o *Int) String() string { func (o Int) String() string {
return strconv.FormatInt(o.Value, 10) return strconv.FormatInt(o.Value, 10)
} }
// TypeName returns the name of the type. // TypeName returns the name of the type.
func (o *Int) TypeName() string { func (o Int) TypeName() string {
return "int" return "int"
} }
// BinaryOp returns another object that is the result of a given binary // BinaryOp returns another object that is the result of a given binary
// operator and a right-hand side object. // operator and a right-hand side object.
func (o *Int) BinaryOp(op token.Token, rhs Object) (Object, error) { func (o Int) BinaryOp(op token.Token, rhs Object) (Object, error) {
switch rhs := rhs.(type) { switch rhs := rhs.(type) {
case *Int: case Int:
switch op { switch op {
case token.Add: case token.Add:
r := o.Value + rhs.Value r := o.Value + rhs.Value
if r == o.Value { if r == o.Value {
return o, nil return o, nil
} }
return &Int{Value: r}, nil return Int{Value: r}, nil
case token.Sub: case token.Sub:
r := o.Value - rhs.Value r := o.Value - rhs.Value
if r == o.Value { if r == o.Value {
return o, nil return o, nil
} }
return &Int{Value: r}, nil return Int{Value: r}, nil
case token.Mul: case token.Mul:
r := o.Value * rhs.Value r := o.Value * rhs.Value
if r == o.Value { if r == o.Value {
return o, nil return o, nil
} }
return &Int{Value: r}, nil return Int{Value: r}, nil
case token.Quo: case token.Quo:
r := o.Value / rhs.Value r := o.Value / rhs.Value
if r == o.Value { if r == o.Value {
return o, nil return o, nil
} }
return &Int{Value: r}, nil return Int{Value: r}, nil
case token.Rem: case token.Rem:
r := o.Value % rhs.Value r := o.Value % rhs.Value
if r == o.Value { if r == o.Value {
return o, nil return o, nil
} }
return &Int{Value: r}, nil return Int{Value: r}, nil
case token.And: case token.And:
r := o.Value & rhs.Value r := o.Value & rhs.Value
if r == o.Value { if r == o.Value {
return o, nil return o, nil
} }
return &Int{Value: r}, nil return Int{Value: r}, nil
case token.Or: case token.Or:
r := o.Value | rhs.Value r := o.Value | rhs.Value
if r == o.Value { if r == o.Value {
return o, nil return o, nil
} }
return &Int{Value: r}, nil return Int{Value: r}, nil
case token.Xor: case token.Xor:
r := o.Value ^ rhs.Value r := o.Value ^ rhs.Value
if r == o.Value { if r == o.Value {
return o, nil return o, nil
} }
return &Int{Value: r}, nil return Int{Value: r}, nil
case token.AndNot: case token.AndNot:
r := o.Value &^ rhs.Value r := o.Value &^ rhs.Value
if r == o.Value { if r == o.Value {
return o, nil return o, nil
} }
return &Int{Value: r}, nil return Int{Value: r}, nil
case token.Shl: case token.Shl:
r := o.Value << uint64(rhs.Value) r := o.Value << uint64(rhs.Value)
if r == o.Value { if r == o.Value {
return o, nil return o, nil
} }
return &Int{Value: r}, nil return Int{Value: r}, nil
case token.Shr: case token.Shr:
r := o.Value >> uint64(rhs.Value) r := o.Value >> uint64(rhs.Value)
if r == o.Value { if r == o.Value {
return o, nil return o, nil
} }
return &Int{Value: r}, nil return Int{Value: r}, nil
case token.Less: case token.Less:
if o.Value < rhs.Value { if o.Value < rhs.Value {
return TrueValue, nil return TrueValue, nil
@ -1095,16 +1164,16 @@ func (o *Int) BinaryOp(op token.Token, rhs Object) (Object, error) {
} }
return FalseValue, nil return FalseValue, nil
} }
case *Float: case Float:
switch op { switch op {
case token.Add: case token.Add:
return &Float{Value: float64(o.Value) + rhs.Value}, nil return Float{Value: float64(o.Value) + rhs.Value}, nil
case token.Sub: case token.Sub:
return &Float{Value: float64(o.Value) - rhs.Value}, nil return Float{Value: float64(o.Value) - rhs.Value}, nil
case token.Mul: case token.Mul:
return &Float{Value: float64(o.Value) * rhs.Value}, nil return Float{Value: float64(o.Value) * rhs.Value}, nil
case token.Quo: case token.Quo:
return &Float{Value: float64(o.Value) / rhs.Value}, nil return Float{Value: float64(o.Value) / rhs.Value}, nil
case token.Less: case token.Less:
if float64(o.Value) < rhs.Value { if float64(o.Value) < rhs.Value {
return TrueValue, nil return TrueValue, nil
@ -1126,12 +1195,12 @@ func (o *Int) BinaryOp(op token.Token, rhs Object) (Object, error) {
} }
return FalseValue, nil return FalseValue, nil
} }
case *Char: case Char:
switch op { switch op {
case token.Add: case token.Add:
return &Char{Value: rune(o.Value) + rhs.Value}, nil return Char{Value: rune(o.Value) + rhs.Value}, nil
case token.Sub: case token.Sub:
return &Char{Value: rune(o.Value) - rhs.Value}, nil return Char{Value: rune(o.Value) - rhs.Value}, nil
case token.Less: case token.Less:
if o.Value < int64(rhs.Value) { if o.Value < int64(rhs.Value) {
return TrueValue, nil return TrueValue, nil
@ -1158,19 +1227,19 @@ func (o *Int) BinaryOp(op token.Token, rhs Object) (Object, error) {
} }
// Copy returns a copy of the type. // Copy returns a copy of the type.
func (o *Int) Copy() Object { func (o Int) Copy() Object {
return &Int{Value: o.Value} return Int{Value: o.Value}
} }
// IsFalsy returns true if the value of the type is falsy. // IsFalsy returns true if the value of the type is falsy.
func (o *Int) IsFalsy() bool { func (o Int) IsFalsy() bool {
return o.Value == 0 return o.Value == 0
} }
// Equals returns true if the value of the type is equal to the value of // Equals returns true if the value of the type is equal to the value of
// another object. // another object.
func (o *Int) Equals(x Object) bool { func (o Int) Equals(x Object) bool {
t, ok := x.(*Int) t, ok := x.(Int)
if !ok { if !ok {
return false return false
} }
@ -1179,7 +1248,7 @@ func (o *Int) Equals(x Object) bool {
// Map represents a map of objects. // Map represents a map of objects.
type Map struct { type Map struct {
ObjectImpl PtrObjectImpl
Value map[string]Object Value map[string]Object
} }
@ -1279,7 +1348,7 @@ func (o *Map) CanIterate() bool {
// ObjectPtr represents a free variable. // ObjectPtr represents a free variable.
type ObjectPtr struct { type ObjectPtr struct {
ObjectImpl PtrObjectImpl
Value *Object Value *Object
} }
@ -1310,7 +1379,7 @@ func (o *ObjectPtr) Equals(x Object) bool {
// String represents a string value. // String represents a string value.
type String struct { type String struct {
ObjectImpl PtrObjectImpl
Value string Value string
runeStr []rune runeStr []rune
} }
@ -1400,7 +1469,7 @@ func (o *String) Equals(x Object) bool {
// IndexGet returns a character at a given index. // IndexGet returns a character at a given index.
func (o *String) IndexGet(index Object) (res Object, err error) { func (o *String) IndexGet(index Object) (res Object, err error) {
intIdx, ok := index.(*Int) intIdx, ok := index.(Int)
if !ok { if !ok {
err = ErrInvalidIndexType err = ErrInvalidIndexType
return return
@ -1413,7 +1482,7 @@ func (o *String) IndexGet(index Object) (res Object, err error) {
res = UndefinedValue res = UndefinedValue
return return
} }
res = &Char{Value: o.runeStr[idxVal]} res = Char{Value: o.runeStr[idxVal]}
return return
} }
@ -1435,7 +1504,7 @@ func (o *String) CanIterate() bool {
// Time represents a time value. // Time represents a time value.
type Time struct { type Time struct {
ObjectImpl PtrObjectImpl
Value time.Time Value time.Time
} }
@ -1452,7 +1521,7 @@ func (o *Time) TypeName() string {
// operator and a right-hand side object. // operator and a right-hand side object.
func (o *Time) BinaryOp(op token.Token, rhs Object) (Object, error) { func (o *Time) BinaryOp(op token.Token, rhs Object) (Object, error) {
switch rhs := rhs.(type) { switch rhs := rhs.(type) {
case *Int: case Int:
switch op { switch op {
case token.Add: // time + int => time case token.Add: // time + int => time
if rhs.Value == 0 { if rhs.Value == 0 {
@ -1468,7 +1537,7 @@ func (o *Time) BinaryOp(op token.Token, rhs Object) (Object, error) {
case *Time: case *Time:
switch op { switch op {
case token.Sub: // time - time => int (duration) case token.Sub: // time - time => int (duration)
return &Int{Value: int64(o.Value.Sub(rhs.Value))}, nil return Int{Value: int64(o.Value.Sub(rhs.Value))}, nil
case token.Less: // time < time => bool case token.Less: // time < time => bool
if o.Value.Before(rhs.Value) { if o.Value.Before(rhs.Value) {
return TrueValue, nil return TrueValue, nil
@ -1516,7 +1585,7 @@ func (o *Time) Equals(x Object) bool {
// Undefined represents an undefined value. // Undefined represents an undefined value.
type Undefined struct { type Undefined struct {
ObjectImpl PtrObjectImpl
} }
// TypeName returns the name of the type. // TypeName returns the name of the type.
@ -1576,7 +1645,7 @@ func (o *Undefined) Value() Object {
// UserFunction represents a user function. // UserFunction represents a user function.
type UserFunction struct { type UserFunction struct {
ObjectImpl PtrObjectImpl
Name string Name string
Value CallableFunc Value CallableFunc
} }

View file

@ -9,15 +9,15 @@ import (
) )
func TestObject_TypeName(t *testing.T) { func TestObject_TypeName(t *testing.T) {
var o tengo.Object = &tengo.Int{} var o tengo.Object = tengo.Int{}
require.Equal(t, "int", o.TypeName()) require.Equal(t, "int", o.TypeName())
o = &tengo.Float{} o = tengo.Float{}
require.Equal(t, "float", o.TypeName()) require.Equal(t, "float", o.TypeName())
o = &tengo.Char{} o = tengo.Char{}
require.Equal(t, "char", o.TypeName()) require.Equal(t, "char", o.TypeName())
o = &tengo.String{} o = &tengo.String{}
require.Equal(t, "string", o.TypeName()) require.Equal(t, "string", o.TypeName())
o = &tengo.Bool{} o = tengo.Bool{}
require.Equal(t, "bool", o.TypeName()) require.Equal(t, "bool", o.TypeName())
o = &tengo.Array{} o = &tengo.Array{}
require.Equal(t, "array", o.TypeName()) require.Equal(t, "array", o.TypeName())
@ -44,17 +44,17 @@ func TestObject_TypeName(t *testing.T) {
} }
func TestObject_IsFalsy(t *testing.T) { func TestObject_IsFalsy(t *testing.T) {
var o tengo.Object = &tengo.Int{Value: 0} var o tengo.Object = tengo.Int{Value: 0}
require.True(t, o.IsFalsy()) require.True(t, o.IsFalsy())
o = &tengo.Int{Value: 1} o = tengo.Int{Value: 1}
require.False(t, o.IsFalsy()) require.False(t, o.IsFalsy())
o = &tengo.Float{Value: 0} o = tengo.Float{Value: 0}
require.False(t, o.IsFalsy()) require.False(t, o.IsFalsy())
o = &tengo.Float{Value: 1} o = tengo.Float{Value: 1}
require.False(t, o.IsFalsy()) require.False(t, o.IsFalsy())
o = &tengo.Char{Value: ' '} o = tengo.Char{Value: ' '}
require.False(t, o.IsFalsy()) require.False(t, o.IsFalsy())
o = &tengo.Char{Value: 'T'} o = tengo.Char{Value: 'T'}
require.False(t, o.IsFalsy()) require.False(t, o.IsFalsy())
o = &tengo.String{Value: ""} o = &tengo.String{Value: ""}
require.True(t, o.IsFalsy()) require.True(t, o.IsFalsy())
@ -89,17 +89,17 @@ func TestObject_IsFalsy(t *testing.T) {
} }
func TestObject_String(t *testing.T) { func TestObject_String(t *testing.T) {
var o tengo.Object = &tengo.Int{Value: 0} var o tengo.Object = tengo.Int{Value: 0}
require.Equal(t, "0", o.String()) require.Equal(t, "0", o.String())
o = &tengo.Int{Value: 1} o = tengo.Int{Value: 1}
require.Equal(t, "1", o.String()) require.Equal(t, "1", o.String())
o = &tengo.Float{Value: 0} o = tengo.Float{Value: 0}
require.Equal(t, "0", o.String()) require.Equal(t, "0", o.String())
o = &tengo.Float{Value: 1} o = tengo.Float{Value: 1}
require.Equal(t, "1", o.String()) require.Equal(t, "1", o.String())
o = &tengo.Char{Value: ' '} o = tengo.Char{Value: ' '}
require.Equal(t, " ", o.String()) require.Equal(t, " ", o.String())
o = &tengo.Char{Value: 'T'} o = tengo.Char{Value: 'T'}
require.Equal(t, "T", o.String()) require.Equal(t, "T", o.String())
o = &tengo.String{Value: ""} o = &tengo.String{Value: ""}
require.Equal(t, `""`, o.String()) require.Equal(t, `""`, o.String())
@ -128,10 +128,10 @@ func TestObject_String(t *testing.T) {
} }
func TestObject_BinaryOp(t *testing.T) { func TestObject_BinaryOp(t *testing.T) {
var o tengo.Object = &tengo.Char{} var o tengo.Object = tengo.Char{}
_, err := o.BinaryOp(token.Add, tengo.UndefinedValue) _, err := o.BinaryOp(token.Add, tengo.UndefinedValue)
require.Error(t, err) require.Error(t, err)
o = &tengo.Bool{} o = tengo.Bool{}
_, err = o.BinaryOp(token.Add, tengo.UndefinedValue) _, err = o.BinaryOp(token.Add, tengo.UndefinedValue)
require.Error(t, err) require.Error(t, err)
o = &tengo.Map{} o = &tengo.Map{}
@ -172,45 +172,45 @@ func TestArray_BinaryOp(t *testing.T) {
&tengo.Array{Value: []tengo.Object{}}) &tengo.Array{Value: []tengo.Object{}})
testBinaryOp(t, &tengo.Array{Value: nil}, token.Add, testBinaryOp(t, &tengo.Array{Value: nil}, token.Add,
&tengo.Array{Value: []tengo.Object{ &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
}}, &tengo.Array{Value: []tengo.Object{ }}, &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
}}) }})
testBinaryOp(t, &tengo.Array{Value: nil}, token.Add, testBinaryOp(t, &tengo.Array{Value: nil}, token.Add,
&tengo.Array{Value: []tengo.Object{ &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}, tengo.Int{Value: 2},
&tengo.Int{Value: 3}, tengo.Int{Value: 3},
}}, &tengo.Array{Value: []tengo.Object{ }}, &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}, tengo.Int{Value: 2},
&tengo.Int{Value: 3}, tengo.Int{Value: 3},
}}) }})
testBinaryOp(t, &tengo.Array{Value: []tengo.Object{ testBinaryOp(t, &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}, tengo.Int{Value: 2},
&tengo.Int{Value: 3}, tengo.Int{Value: 3},
}}, token.Add, &tengo.Array{Value: nil}, }}, token.Add, &tengo.Array{Value: nil},
&tengo.Array{Value: []tengo.Object{ &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}, tengo.Int{Value: 2},
&tengo.Int{Value: 3}, tengo.Int{Value: 3},
}}) }})
testBinaryOp(t, &tengo.Array{Value: []tengo.Object{ testBinaryOp(t, &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}, tengo.Int{Value: 2},
&tengo.Int{Value: 3}, tengo.Int{Value: 3},
}}, token.Add, &tengo.Array{Value: []tengo.Object{ }}, token.Add, &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 4}, tengo.Int{Value: 4},
&tengo.Int{Value: 5}, tengo.Int{Value: 5},
&tengo.Int{Value: 6}, tengo.Int{Value: 6},
}}, &tengo.Array{Value: []tengo.Object{ }}, &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}, tengo.Int{Value: 2},
&tengo.Int{Value: 3}, tengo.Int{Value: 3},
&tengo.Int{Value: 4}, tengo.Int{Value: 4},
&tengo.Int{Value: 5}, tengo.Int{Value: 5},
&tengo.Int{Value: 6}, tengo.Int{Value: 6},
}}) }})
} }
@ -229,24 +229,24 @@ func TestFloat_BinaryOp(t *testing.T) {
// float + float // float + float
for l := float64(-2); l <= 2.1; l += 0.4 { for l := float64(-2); l <= 2.1; l += 0.4 {
for r := float64(-2); r <= 2.1; r += 0.4 { for r := float64(-2); r <= 2.1; r += 0.4 {
testBinaryOp(t, &tengo.Float{Value: l}, token.Add, testBinaryOp(t, tengo.Float{Value: l}, token.Add,
&tengo.Float{Value: r}, &tengo.Float{Value: l + r}) tengo.Float{Value: r}, tengo.Float{Value: l + r})
} }
} }
// float - float // float - float
for l := float64(-2); l <= 2.1; l += 0.4 { for l := float64(-2); l <= 2.1; l += 0.4 {
for r := float64(-2); r <= 2.1; r += 0.4 { for r := float64(-2); r <= 2.1; r += 0.4 {
testBinaryOp(t, &tengo.Float{Value: l}, token.Sub, testBinaryOp(t, tengo.Float{Value: l}, token.Sub,
&tengo.Float{Value: r}, &tengo.Float{Value: l - r}) tengo.Float{Value: r}, tengo.Float{Value: l - r})
} }
} }
// float * float // float * float
for l := float64(-2); l <= 2.1; l += 0.4 { for l := float64(-2); l <= 2.1; l += 0.4 {
for r := float64(-2); r <= 2.1; r += 0.4 { for r := float64(-2); r <= 2.1; r += 0.4 {
testBinaryOp(t, &tengo.Float{Value: l}, token.Mul, testBinaryOp(t, tengo.Float{Value: l}, token.Mul,
&tengo.Float{Value: r}, &tengo.Float{Value: l * r}) tengo.Float{Value: r}, tengo.Float{Value: l * r})
} }
} }
@ -254,8 +254,8 @@ func TestFloat_BinaryOp(t *testing.T) {
for l := float64(-2); l <= 2.1; l += 0.4 { for l := float64(-2); l <= 2.1; l += 0.4 {
for r := float64(-2); r <= 2.1; r += 0.4 { for r := float64(-2); r <= 2.1; r += 0.4 {
if r != 0 { if r != 0 {
testBinaryOp(t, &tengo.Float{Value: l}, token.Quo, testBinaryOp(t, tengo.Float{Value: l}, token.Quo,
&tengo.Float{Value: r}, &tengo.Float{Value: l / r}) tengo.Float{Value: r}, tengo.Float{Value: l / r})
} }
} }
} }
@ -263,56 +263,56 @@ func TestFloat_BinaryOp(t *testing.T) {
// float < float // float < float
for l := float64(-2); l <= 2.1; l += 0.4 { for l := float64(-2); l <= 2.1; l += 0.4 {
for r := float64(-2); r <= 2.1; r += 0.4 { for r := float64(-2); r <= 2.1; r += 0.4 {
testBinaryOp(t, &tengo.Float{Value: l}, token.Less, testBinaryOp(t, tengo.Float{Value: l}, token.Less,
&tengo.Float{Value: r}, boolValue(l < r)) tengo.Float{Value: r}, boolValue(l < r))
} }
} }
// float > float // float > float
for l := float64(-2); l <= 2.1; l += 0.4 { for l := float64(-2); l <= 2.1; l += 0.4 {
for r := float64(-2); r <= 2.1; r += 0.4 { for r := float64(-2); r <= 2.1; r += 0.4 {
testBinaryOp(t, &tengo.Float{Value: l}, token.Greater, testBinaryOp(t, tengo.Float{Value: l}, token.Greater,
&tengo.Float{Value: r}, boolValue(l > r)) tengo.Float{Value: r}, boolValue(l > r))
} }
} }
// float <= float // float <= float
for l := float64(-2); l <= 2.1; l += 0.4 { for l := float64(-2); l <= 2.1; l += 0.4 {
for r := float64(-2); r <= 2.1; r += 0.4 { for r := float64(-2); r <= 2.1; r += 0.4 {
testBinaryOp(t, &tengo.Float{Value: l}, token.LessEq, testBinaryOp(t, tengo.Float{Value: l}, token.LessEq,
&tengo.Float{Value: r}, boolValue(l <= r)) tengo.Float{Value: r}, boolValue(l <= r))
} }
} }
// float >= float // float >= float
for l := float64(-2); l <= 2.1; l += 0.4 { for l := float64(-2); l <= 2.1; l += 0.4 {
for r := float64(-2); r <= 2.1; r += 0.4 { for r := float64(-2); r <= 2.1; r += 0.4 {
testBinaryOp(t, &tengo.Float{Value: l}, token.GreaterEq, testBinaryOp(t, tengo.Float{Value: l}, token.GreaterEq,
&tengo.Float{Value: r}, boolValue(l >= r)) tengo.Float{Value: r}, boolValue(l >= r))
} }
} }
// float + int // float + int
for l := float64(-2); l <= 2.1; l += 0.4 { for l := float64(-2); l <= 2.1; l += 0.4 {
for r := int64(-2); r <= 2; r++ { for r := int64(-2); r <= 2; r++ {
testBinaryOp(t, &tengo.Float{Value: l}, token.Add, testBinaryOp(t, tengo.Float{Value: l}, token.Add,
&tengo.Int{Value: r}, &tengo.Float{Value: l + float64(r)}) tengo.Int{Value: r}, tengo.Float{Value: l + float64(r)})
} }
} }
// float - int // float - int
for l := float64(-2); l <= 2.1; l += 0.4 { for l := float64(-2); l <= 2.1; l += 0.4 {
for r := int64(-2); r <= 2; r++ { for r := int64(-2); r <= 2; r++ {
testBinaryOp(t, &tengo.Float{Value: l}, token.Sub, testBinaryOp(t, tengo.Float{Value: l}, token.Sub,
&tengo.Int{Value: r}, &tengo.Float{Value: l - float64(r)}) tengo.Int{Value: r}, tengo.Float{Value: l - float64(r)})
} }
} }
// float * int // float * int
for l := float64(-2); l <= 2.1; l += 0.4 { for l := float64(-2); l <= 2.1; l += 0.4 {
for r := int64(-2); r <= 2; r++ { for r := int64(-2); r <= 2; r++ {
testBinaryOp(t, &tengo.Float{Value: l}, token.Mul, testBinaryOp(t, tengo.Float{Value: l}, token.Mul,
&tengo.Int{Value: r}, &tengo.Float{Value: l * float64(r)}) tengo.Int{Value: r}, tengo.Float{Value: l * float64(r)})
} }
} }
@ -320,9 +320,9 @@ func TestFloat_BinaryOp(t *testing.T) {
for l := float64(-2); l <= 2.1; l += 0.4 { for l := float64(-2); l <= 2.1; l += 0.4 {
for r := int64(-2); r <= 2; r++ { for r := int64(-2); r <= 2; r++ {
if r != 0 { if r != 0 {
testBinaryOp(t, &tengo.Float{Value: l}, token.Quo, testBinaryOp(t, tengo.Float{Value: l}, token.Quo,
&tengo.Int{Value: r}, tengo.Int{Value: r},
&tengo.Float{Value: l / float64(r)}) tengo.Float{Value: l / float64(r)})
} }
} }
} }
@ -330,32 +330,32 @@ func TestFloat_BinaryOp(t *testing.T) {
// float < int // float < int
for l := float64(-2); l <= 2.1; l += 0.4 { for l := float64(-2); l <= 2.1; l += 0.4 {
for r := int64(-2); r <= 2; r++ { for r := int64(-2); r <= 2; r++ {
testBinaryOp(t, &tengo.Float{Value: l}, token.Less, testBinaryOp(t, tengo.Float{Value: l}, token.Less,
&tengo.Int{Value: r}, boolValue(l < float64(r))) tengo.Int{Value: r}, boolValue(l < float64(r)))
} }
} }
// float > int // float > int
for l := float64(-2); l <= 2.1; l += 0.4 { for l := float64(-2); l <= 2.1; l += 0.4 {
for r := int64(-2); r <= 2; r++ { for r := int64(-2); r <= 2; r++ {
testBinaryOp(t, &tengo.Float{Value: l}, token.Greater, testBinaryOp(t, tengo.Float{Value: l}, token.Greater,
&tengo.Int{Value: r}, boolValue(l > float64(r))) tengo.Int{Value: r}, boolValue(l > float64(r)))
} }
} }
// float <= int // float <= int
for l := float64(-2); l <= 2.1; l += 0.4 { for l := float64(-2); l <= 2.1; l += 0.4 {
for r := int64(-2); r <= 2; r++ { for r := int64(-2); r <= 2; r++ {
testBinaryOp(t, &tengo.Float{Value: l}, token.LessEq, testBinaryOp(t, tengo.Float{Value: l}, token.LessEq,
&tengo.Int{Value: r}, boolValue(l <= float64(r))) tengo.Int{Value: r}, boolValue(l <= float64(r)))
} }
} }
// float >= int // float >= int
for l := float64(-2); l <= 2.1; l += 0.4 { for l := float64(-2); l <= 2.1; l += 0.4 {
for r := int64(-2); r <= 2; r++ { for r := int64(-2); r <= 2; r++ {
testBinaryOp(t, &tengo.Float{Value: l}, token.GreaterEq, testBinaryOp(t, tengo.Float{Value: l}, token.GreaterEq,
&tengo.Int{Value: r}, boolValue(l >= float64(r))) tengo.Int{Value: r}, boolValue(l >= float64(r)))
} }
} }
} }
@ -364,24 +364,24 @@ func TestInt_BinaryOp(t *testing.T) {
// int + int // int + int
for l := int64(-2); l <= 2; l++ { for l := int64(-2); l <= 2; l++ {
for r := int64(-2); r <= 2; r++ { for r := int64(-2); r <= 2; r++ {
testBinaryOp(t, &tengo.Int{Value: l}, token.Add, testBinaryOp(t, tengo.Int{Value: l}, token.Add,
&tengo.Int{Value: r}, &tengo.Int{Value: l + r}) tengo.Int{Value: r}, tengo.Int{Value: l + r})
} }
} }
// int - int // int - int
for l := int64(-2); l <= 2; l++ { for l := int64(-2); l <= 2; l++ {
for r := int64(-2); r <= 2; r++ { for r := int64(-2); r <= 2; r++ {
testBinaryOp(t, &tengo.Int{Value: l}, token.Sub, testBinaryOp(t, tengo.Int{Value: l}, token.Sub,
&tengo.Int{Value: r}, &tengo.Int{Value: l - r}) tengo.Int{Value: r}, tengo.Int{Value: l - r})
} }
} }
// int * int // int * int
for l := int64(-2); l <= 2; l++ { for l := int64(-2); l <= 2; l++ {
for r := int64(-2); r <= 2; r++ { for r := int64(-2); r <= 2; r++ {
testBinaryOp(t, &tengo.Int{Value: l}, token.Mul, testBinaryOp(t, tengo.Int{Value: l}, token.Mul,
&tengo.Int{Value: r}, &tengo.Int{Value: l * r}) tengo.Int{Value: r}, tengo.Int{Value: l * r})
} }
} }
@ -389,8 +389,8 @@ func TestInt_BinaryOp(t *testing.T) {
for l := int64(-2); l <= 2; l++ { for l := int64(-2); l <= 2; l++ {
for r := int64(-2); r <= 2; r++ { for r := int64(-2); r <= 2; r++ {
if r != 0 { if r != 0 {
testBinaryOp(t, &tengo.Int{Value: l}, token.Quo, testBinaryOp(t, tengo.Int{Value: l}, token.Quo,
&tengo.Int{Value: r}, &tengo.Int{Value: l / r}) tengo.Int{Value: r}, tengo.Int{Value: l / r})
} }
} }
} }
@ -399,243 +399,243 @@ func TestInt_BinaryOp(t *testing.T) {
for l := int64(-4); l <= 4; l++ { for l := int64(-4); l <= 4; l++ {
for r := -int64(-4); r <= 4; r++ { for r := -int64(-4); r <= 4; r++ {
if r == 0 { if r == 0 {
testBinaryOp(t, &tengo.Int{Value: l}, token.Rem, testBinaryOp(t, tengo.Int{Value: l}, token.Rem,
&tengo.Int{Value: r}, &tengo.Int{Value: l % r}) tengo.Int{Value: r}, tengo.Int{Value: l % r})
} }
} }
} }
// int & int // int & int
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 0}, token.And, &tengo.Int{Value: 0}, tengo.Int{Value: 0}, token.And, tengo.Int{Value: 0},
&tengo.Int{Value: int64(0)}) tengo.Int{Value: int64(0)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 1}, token.And, &tengo.Int{Value: 0}, tengo.Int{Value: 1}, token.And, tengo.Int{Value: 0},
&tengo.Int{Value: int64(1) & int64(0)}) tengo.Int{Value: int64(1) & int64(0)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 0}, token.And, &tengo.Int{Value: 1}, tengo.Int{Value: 0}, token.And, tengo.Int{Value: 1},
&tengo.Int{Value: int64(0) & int64(1)}) tengo.Int{Value: int64(0) & int64(1)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 1}, token.And, &tengo.Int{Value: 1}, tengo.Int{Value: 1}, token.And, tengo.Int{Value: 1},
&tengo.Int{Value: int64(1)}) tengo.Int{Value: int64(1)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 0}, token.And, &tengo.Int{Value: int64(0xffffffff)}, tengo.Int{Value: 0}, token.And, tengo.Int{Value: int64(0xffffffff)},
&tengo.Int{Value: int64(0) & int64(0xffffffff)}) tengo.Int{Value: int64(0) & int64(0xffffffff)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 1}, token.And, &tengo.Int{Value: int64(0xffffffff)}, tengo.Int{Value: 1}, token.And, tengo.Int{Value: int64(0xffffffff)},
&tengo.Int{Value: int64(1) & int64(0xffffffff)}) tengo.Int{Value: int64(1) & int64(0xffffffff)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: int64(0xffffffff)}, token.And, tengo.Int{Value: int64(0xffffffff)}, token.And,
&tengo.Int{Value: int64(0xffffffff)}, tengo.Int{Value: int64(0xffffffff)},
&tengo.Int{Value: int64(0xffffffff)}) tengo.Int{Value: int64(0xffffffff)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 1984}, token.And, tengo.Int{Value: 1984}, token.And,
&tengo.Int{Value: int64(0xffffffff)}, tengo.Int{Value: int64(0xffffffff)},
&tengo.Int{Value: int64(1984) & int64(0xffffffff)}) tengo.Int{Value: int64(1984) & int64(0xffffffff)})
testBinaryOp(t, &tengo.Int{Value: -1984}, token.And, testBinaryOp(t, tengo.Int{Value: -1984}, token.And,
&tengo.Int{Value: int64(0xffffffff)}, tengo.Int{Value: int64(0xffffffff)},
&tengo.Int{Value: int64(-1984) & int64(0xffffffff)}) tengo.Int{Value: int64(-1984) & int64(0xffffffff)})
// int | int // int | int
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 0}, token.Or, &tengo.Int{Value: 0}, tengo.Int{Value: 0}, token.Or, tengo.Int{Value: 0},
&tengo.Int{Value: int64(0)}) tengo.Int{Value: int64(0)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 1}, token.Or, &tengo.Int{Value: 0}, tengo.Int{Value: 1}, token.Or, tengo.Int{Value: 0},
&tengo.Int{Value: int64(1) | int64(0)}) tengo.Int{Value: int64(1) | int64(0)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 0}, token.Or, &tengo.Int{Value: 1}, tengo.Int{Value: 0}, token.Or, tengo.Int{Value: 1},
&tengo.Int{Value: int64(0) | int64(1)}) tengo.Int{Value: int64(0) | int64(1)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 1}, token.Or, &tengo.Int{Value: 1}, tengo.Int{Value: 1}, token.Or, tengo.Int{Value: 1},
&tengo.Int{Value: int64(1)}) tengo.Int{Value: int64(1)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 0}, token.Or, &tengo.Int{Value: int64(0xffffffff)}, tengo.Int{Value: 0}, token.Or, tengo.Int{Value: int64(0xffffffff)},
&tengo.Int{Value: int64(0) | int64(0xffffffff)}) tengo.Int{Value: int64(0) | int64(0xffffffff)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 1}, token.Or, &tengo.Int{Value: int64(0xffffffff)}, tengo.Int{Value: 1}, token.Or, tengo.Int{Value: int64(0xffffffff)},
&tengo.Int{Value: int64(1) | int64(0xffffffff)}) tengo.Int{Value: int64(1) | int64(0xffffffff)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: int64(0xffffffff)}, token.Or, tengo.Int{Value: int64(0xffffffff)}, token.Or,
&tengo.Int{Value: int64(0xffffffff)}, tengo.Int{Value: int64(0xffffffff)},
&tengo.Int{Value: int64(0xffffffff)}) tengo.Int{Value: int64(0xffffffff)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 1984}, token.Or, tengo.Int{Value: 1984}, token.Or,
&tengo.Int{Value: int64(0xffffffff)}, tengo.Int{Value: int64(0xffffffff)},
&tengo.Int{Value: int64(1984) | int64(0xffffffff)}) tengo.Int{Value: int64(1984) | int64(0xffffffff)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: -1984}, token.Or, tengo.Int{Value: -1984}, token.Or,
&tengo.Int{Value: int64(0xffffffff)}, tengo.Int{Value: int64(0xffffffff)},
&tengo.Int{Value: int64(-1984) | int64(0xffffffff)}) tengo.Int{Value: int64(-1984) | int64(0xffffffff)})
// int ^ int // int ^ int
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 0}, token.Xor, &tengo.Int{Value: 0}, tengo.Int{Value: 0}, token.Xor, tengo.Int{Value: 0},
&tengo.Int{Value: int64(0)}) tengo.Int{Value: int64(0)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 1}, token.Xor, &tengo.Int{Value: 0}, tengo.Int{Value: 1}, token.Xor, tengo.Int{Value: 0},
&tengo.Int{Value: int64(1) ^ int64(0)}) tengo.Int{Value: int64(1) ^ int64(0)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 0}, token.Xor, &tengo.Int{Value: 1}, tengo.Int{Value: 0}, token.Xor, tengo.Int{Value: 1},
&tengo.Int{Value: int64(0) ^ int64(1)}) tengo.Int{Value: int64(0) ^ int64(1)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 1}, token.Xor, &tengo.Int{Value: 1}, tengo.Int{Value: 1}, token.Xor, tengo.Int{Value: 1},
&tengo.Int{Value: int64(0)}) tengo.Int{Value: int64(0)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 0}, token.Xor, &tengo.Int{Value: int64(0xffffffff)}, tengo.Int{Value: 0}, token.Xor, tengo.Int{Value: int64(0xffffffff)},
&tengo.Int{Value: int64(0) ^ int64(0xffffffff)}) tengo.Int{Value: int64(0) ^ int64(0xffffffff)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 1}, token.Xor, &tengo.Int{Value: int64(0xffffffff)}, tengo.Int{Value: 1}, token.Xor, tengo.Int{Value: int64(0xffffffff)},
&tengo.Int{Value: int64(1) ^ int64(0xffffffff)}) tengo.Int{Value: int64(1) ^ int64(0xffffffff)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: int64(0xffffffff)}, token.Xor, tengo.Int{Value: int64(0xffffffff)}, token.Xor,
&tengo.Int{Value: int64(0xffffffff)}, tengo.Int{Value: int64(0xffffffff)},
&tengo.Int{Value: int64(0)}) tengo.Int{Value: int64(0)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 1984}, token.Xor, tengo.Int{Value: 1984}, token.Xor,
&tengo.Int{Value: int64(0xffffffff)}, tengo.Int{Value: int64(0xffffffff)},
&tengo.Int{Value: int64(1984) ^ int64(0xffffffff)}) tengo.Int{Value: int64(1984) ^ int64(0xffffffff)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: -1984}, token.Xor, tengo.Int{Value: -1984}, token.Xor,
&tengo.Int{Value: int64(0xffffffff)}, tengo.Int{Value: int64(0xffffffff)},
&tengo.Int{Value: int64(-1984) ^ int64(0xffffffff)}) tengo.Int{Value: int64(-1984) ^ int64(0xffffffff)})
// int &^ int // int &^ int
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 0}, token.AndNot, &tengo.Int{Value: 0}, tengo.Int{Value: 0}, token.AndNot, tengo.Int{Value: 0},
&tengo.Int{Value: int64(0)}) tengo.Int{Value: int64(0)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 1}, token.AndNot, &tengo.Int{Value: 0}, tengo.Int{Value: 1}, token.AndNot, tengo.Int{Value: 0},
&tengo.Int{Value: int64(1) &^ int64(0)}) tengo.Int{Value: int64(1) &^ int64(0)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 0}, token.AndNot, tengo.Int{Value: 0}, token.AndNot,
&tengo.Int{Value: 1}, &tengo.Int{Value: int64(0) &^ int64(1)}) tengo.Int{Value: 1}, tengo.Int{Value: int64(0) &^ int64(1)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 1}, token.AndNot, &tengo.Int{Value: 1}, tengo.Int{Value: 1}, token.AndNot, tengo.Int{Value: 1},
&tengo.Int{Value: int64(0)}) tengo.Int{Value: int64(0)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 0}, token.AndNot, tengo.Int{Value: 0}, token.AndNot,
&tengo.Int{Value: int64(0xffffffff)}, tengo.Int{Value: int64(0xffffffff)},
&tengo.Int{Value: int64(0) &^ int64(0xffffffff)}) tengo.Int{Value: int64(0) &^ int64(0xffffffff)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 1}, token.AndNot, tengo.Int{Value: 1}, token.AndNot,
&tengo.Int{Value: int64(0xffffffff)}, tengo.Int{Value: int64(0xffffffff)},
&tengo.Int{Value: int64(1) &^ int64(0xffffffff)}) tengo.Int{Value: int64(1) &^ int64(0xffffffff)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: int64(0xffffffff)}, token.AndNot, tengo.Int{Value: int64(0xffffffff)}, token.AndNot,
&tengo.Int{Value: int64(0xffffffff)}, tengo.Int{Value: int64(0xffffffff)},
&tengo.Int{Value: int64(0)}) tengo.Int{Value: int64(0)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 1984}, token.AndNot, tengo.Int{Value: 1984}, token.AndNot,
&tengo.Int{Value: int64(0xffffffff)}, tengo.Int{Value: int64(0xffffffff)},
&tengo.Int{Value: int64(1984) &^ int64(0xffffffff)}) tengo.Int{Value: int64(1984) &^ int64(0xffffffff)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: -1984}, token.AndNot, tengo.Int{Value: -1984}, token.AndNot,
&tengo.Int{Value: int64(0xffffffff)}, tengo.Int{Value: int64(0xffffffff)},
&tengo.Int{Value: int64(-1984) &^ int64(0xffffffff)}) tengo.Int{Value: int64(-1984) &^ int64(0xffffffff)})
// int << int // int << int
for s := int64(0); s < 64; s++ { for s := int64(0); s < 64; s++ {
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 0}, token.Shl, &tengo.Int{Value: s}, tengo.Int{Value: 0}, token.Shl, tengo.Int{Value: s},
&tengo.Int{Value: int64(0) << uint(s)}) tengo.Int{Value: int64(0) << uint(s)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 1}, token.Shl, &tengo.Int{Value: s}, tengo.Int{Value: 1}, token.Shl, tengo.Int{Value: s},
&tengo.Int{Value: int64(1) << uint(s)}) tengo.Int{Value: int64(1) << uint(s)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 2}, token.Shl, &tengo.Int{Value: s}, tengo.Int{Value: 2}, token.Shl, tengo.Int{Value: s},
&tengo.Int{Value: int64(2) << uint(s)}) tengo.Int{Value: int64(2) << uint(s)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: -1}, token.Shl, &tengo.Int{Value: s}, tengo.Int{Value: -1}, token.Shl, tengo.Int{Value: s},
&tengo.Int{Value: int64(-1) << uint(s)}) tengo.Int{Value: int64(-1) << uint(s)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: -2}, token.Shl, &tengo.Int{Value: s}, tengo.Int{Value: -2}, token.Shl, tengo.Int{Value: s},
&tengo.Int{Value: int64(-2) << uint(s)}) tengo.Int{Value: int64(-2) << uint(s)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: int64(0xffffffff)}, token.Shl, tengo.Int{Value: int64(0xffffffff)}, token.Shl,
&tengo.Int{Value: s}, tengo.Int{Value: s},
&tengo.Int{Value: int64(0xffffffff) << uint(s)}) tengo.Int{Value: int64(0xffffffff) << uint(s)})
} }
// int >> int // int >> int
for s := int64(0); s < 64; s++ { for s := int64(0); s < 64; s++ {
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 0}, token.Shr, &tengo.Int{Value: s}, tengo.Int{Value: 0}, token.Shr, tengo.Int{Value: s},
&tengo.Int{Value: int64(0) >> uint(s)}) tengo.Int{Value: int64(0) >> uint(s)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 1}, token.Shr, &tengo.Int{Value: s}, tengo.Int{Value: 1}, token.Shr, tengo.Int{Value: s},
&tengo.Int{Value: int64(1) >> uint(s)}) tengo.Int{Value: int64(1) >> uint(s)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: 2}, token.Shr, &tengo.Int{Value: s}, tengo.Int{Value: 2}, token.Shr, tengo.Int{Value: s},
&tengo.Int{Value: int64(2) >> uint(s)}) tengo.Int{Value: int64(2) >> uint(s)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: -1}, token.Shr, &tengo.Int{Value: s}, tengo.Int{Value: -1}, token.Shr, tengo.Int{Value: s},
&tengo.Int{Value: int64(-1) >> uint(s)}) tengo.Int{Value: int64(-1) >> uint(s)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: -2}, token.Shr, &tengo.Int{Value: s}, tengo.Int{Value: -2}, token.Shr, tengo.Int{Value: s},
&tengo.Int{Value: int64(-2) >> uint(s)}) tengo.Int{Value: int64(-2) >> uint(s)})
testBinaryOp(t, testBinaryOp(t,
&tengo.Int{Value: int64(0xffffffff)}, token.Shr, tengo.Int{Value: int64(0xffffffff)}, token.Shr,
&tengo.Int{Value: s}, tengo.Int{Value: s},
&tengo.Int{Value: int64(0xffffffff) >> uint(s)}) tengo.Int{Value: int64(0xffffffff) >> uint(s)})
} }
// int < int // int < int
for l := int64(-2); l <= 2; l++ { for l := int64(-2); l <= 2; l++ {
for r := int64(-2); r <= 2; r++ { for r := int64(-2); r <= 2; r++ {
testBinaryOp(t, &tengo.Int{Value: l}, token.Less, testBinaryOp(t, tengo.Int{Value: l}, token.Less,
&tengo.Int{Value: r}, boolValue(l < r)) tengo.Int{Value: r}, boolValue(l < r))
} }
} }
// int > int // int > int
for l := int64(-2); l <= 2; l++ { for l := int64(-2); l <= 2; l++ {
for r := int64(-2); r <= 2; r++ { for r := int64(-2); r <= 2; r++ {
testBinaryOp(t, &tengo.Int{Value: l}, token.Greater, testBinaryOp(t, tengo.Int{Value: l}, token.Greater,
&tengo.Int{Value: r}, boolValue(l > r)) tengo.Int{Value: r}, boolValue(l > r))
} }
} }
// int <= int // int <= int
for l := int64(-2); l <= 2; l++ { for l := int64(-2); l <= 2; l++ {
for r := int64(-2); r <= 2; r++ { for r := int64(-2); r <= 2; r++ {
testBinaryOp(t, &tengo.Int{Value: l}, token.LessEq, testBinaryOp(t, tengo.Int{Value: l}, token.LessEq,
&tengo.Int{Value: r}, boolValue(l <= r)) tengo.Int{Value: r}, boolValue(l <= r))
} }
} }
// int >= int // int >= int
for l := int64(-2); l <= 2; l++ { for l := int64(-2); l <= 2; l++ {
for r := int64(-2); r <= 2; r++ { for r := int64(-2); r <= 2; r++ {
testBinaryOp(t, &tengo.Int{Value: l}, token.GreaterEq, testBinaryOp(t, tengo.Int{Value: l}, token.GreaterEq,
&tengo.Int{Value: r}, boolValue(l >= r)) tengo.Int{Value: r}, boolValue(l >= r))
} }
} }
// int + float // int + float
for l := int64(-2); l <= 2; l++ { for l := int64(-2); l <= 2; l++ {
for r := float64(-2); r <= 2.1; r += 0.5 { for r := float64(-2); r <= 2.1; r += 0.5 {
testBinaryOp(t, &tengo.Int{Value: l}, token.Add, testBinaryOp(t, tengo.Int{Value: l}, token.Add,
&tengo.Float{Value: r}, tengo.Float{Value: r},
&tengo.Float{Value: float64(l) + r}) tengo.Float{Value: float64(l) + r})
} }
} }
// int - float // int - float
for l := int64(-2); l <= 2; l++ { for l := int64(-2); l <= 2; l++ {
for r := float64(-2); r <= 2.1; r += 0.5 { for r := float64(-2); r <= 2.1; r += 0.5 {
testBinaryOp(t, &tengo.Int{Value: l}, token.Sub, testBinaryOp(t, tengo.Int{Value: l}, token.Sub,
&tengo.Float{Value: r}, tengo.Float{Value: r},
&tengo.Float{Value: float64(l) - r}) tengo.Float{Value: float64(l) - r})
} }
} }
// int * float // int * float
for l := int64(-2); l <= 2; l++ { for l := int64(-2); l <= 2; l++ {
for r := float64(-2); r <= 2.1; r += 0.5 { for r := float64(-2); r <= 2.1; r += 0.5 {
testBinaryOp(t, &tengo.Int{Value: l}, token.Mul, testBinaryOp(t, tengo.Int{Value: l}, token.Mul,
&tengo.Float{Value: r}, tengo.Float{Value: r},
&tengo.Float{Value: float64(l) * r}) tengo.Float{Value: float64(l) * r})
} }
} }
@ -643,9 +643,9 @@ func TestInt_BinaryOp(t *testing.T) {
for l := int64(-2); l <= 2; l++ { for l := int64(-2); l <= 2; l++ {
for r := float64(-2); r <= 2.1; r += 0.5 { for r := float64(-2); r <= 2.1; r += 0.5 {
if r != 0 { if r != 0 {
testBinaryOp(t, &tengo.Int{Value: l}, token.Quo, testBinaryOp(t, tengo.Int{Value: l}, token.Quo,
&tengo.Float{Value: r}, tengo.Float{Value: r},
&tengo.Float{Value: float64(l) / r}) tengo.Float{Value: float64(l) / r})
} }
} }
} }
@ -653,39 +653,39 @@ func TestInt_BinaryOp(t *testing.T) {
// int < float // int < float
for l := int64(-2); l <= 2; l++ { for l := int64(-2); l <= 2; l++ {
for r := float64(-2); r <= 2.1; r += 0.5 { for r := float64(-2); r <= 2.1; r += 0.5 {
testBinaryOp(t, &tengo.Int{Value: l}, token.Less, testBinaryOp(t, tengo.Int{Value: l}, token.Less,
&tengo.Float{Value: r}, boolValue(float64(l) < r)) tengo.Float{Value: r}, boolValue(float64(l) < r))
} }
} }
// int > float // int > float
for l := int64(-2); l <= 2; l++ { for l := int64(-2); l <= 2; l++ {
for r := float64(-2); r <= 2.1; r += 0.5 { for r := float64(-2); r <= 2.1; r += 0.5 {
testBinaryOp(t, &tengo.Int{Value: l}, token.Greater, testBinaryOp(t, tengo.Int{Value: l}, token.Greater,
&tengo.Float{Value: r}, boolValue(float64(l) > r)) tengo.Float{Value: r}, boolValue(float64(l) > r))
} }
} }
// int <= float // int <= float
for l := int64(-2); l <= 2; l++ { for l := int64(-2); l <= 2; l++ {
for r := float64(-2); r <= 2.1; r += 0.5 { for r := float64(-2); r <= 2.1; r += 0.5 {
testBinaryOp(t, &tengo.Int{Value: l}, token.LessEq, testBinaryOp(t, tengo.Int{Value: l}, token.LessEq,
&tengo.Float{Value: r}, boolValue(float64(l) <= r)) tengo.Float{Value: r}, boolValue(float64(l) <= r))
} }
} }
// int >= float // int >= float
for l := int64(-2); l <= 2; l++ { for l := int64(-2); l <= 2; l++ {
for r := float64(-2); r <= 2.1; r += 0.5 { for r := float64(-2); r <= 2.1; r += 0.5 {
testBinaryOp(t, &tengo.Int{Value: l}, token.GreaterEq, testBinaryOp(t, tengo.Int{Value: l}, token.GreaterEq,
&tengo.Float{Value: r}, boolValue(float64(l) >= r)) tengo.Float{Value: r}, boolValue(float64(l) >= r))
} }
} }
} }
func TestMap_Index(t *testing.T) { func TestMap_Index(t *testing.T) {
m := &tengo.Map{Value: make(map[string]tengo.Object)} m := &tengo.Map{Value: make(map[string]tengo.Object)}
k := &tengo.Int{Value: 1} k := tengo.Int{Value: 1}
v := &tengo.String{Value: "abcdef"} v := &tengo.String{Value: "abcdef"}
err := m.IndexSet(k, v) err := m.IndexSet(k, v)
@ -709,7 +709,7 @@ func TestString_BinaryOp(t *testing.T) {
rc := []rune(rstr)[r] rc := []rune(rstr)[r]
testBinaryOp(t, &tengo.String{Value: ls}, token.Add, testBinaryOp(t, &tengo.String{Value: ls}, token.Add,
&tengo.Char{Value: rc}, tengo.Char{Value: rc},
&tengo.String{Value: ls + string(rc)}) &tengo.String{Value: ls + string(rc)})
} }
} }

View file

@ -134,15 +134,15 @@ func Equal(
} }
case []tengo.Object: case []tengo.Object:
equalObjectSlice(t, expected, actual.([]tengo.Object), msg...) equalObjectSlice(t, expected, actual.([]tengo.Object), msg...)
case *tengo.Int: case tengo.Int:
Equal(t, expected.Value, actual.(*tengo.Int).Value, msg...) Equal(t, expected.Value, actual.(tengo.Int).Value, msg...)
case *tengo.Float: case tengo.Float:
Equal(t, expected.Value, actual.(*tengo.Float).Value, msg...) Equal(t, expected.Value, actual.(tengo.Float).Value, msg...)
case *tengo.String: case *tengo.String:
Equal(t, expected.Value, actual.(*tengo.String).Value, msg...) Equal(t, expected.Value, actual.(*tengo.String).Value, msg...)
case *tengo.Char: case tengo.Char:
Equal(t, expected.Value, actual.(*tengo.Char).Value, msg...) Equal(t, expected.Value, actual.(tengo.Char).Value, msg...)
case *tengo.Bool: case tengo.Bool:
if expected != actual { if expected != actual {
failExpectedActual(t, expected, actual, msg...) failExpectedActual(t, expected, actual, msg...)
} }

View file

@ -24,12 +24,12 @@ func TestScript_Add(t *testing.T) {
func(args ...tengo.Object) (ret tengo.Object, err error) { func(args ...tengo.Object) (ret tengo.Object, err error) {
if len(args) > 0 { if len(args) > 0 {
switch arg := args[0].(type) { switch arg := args[0].(type) {
case *tengo.Int: case tengo.Int:
return &tengo.Int{Value: arg.Value + 1}, nil return tengo.Int{Value: arg.Value + 1}, nil
} }
} }
return &tengo.Int{Value: 0}, nil return tengo.Int{Value: 0}, nil
})) }))
c, err := s.Compile() c, err := s.Compile()
require.NoError(t, err) require.NoError(t, err)
@ -177,7 +177,7 @@ e := mod1.double(s)
err error, err error,
) { ) {
arg0, _ := tengo.ToInt64(args[0]) arg0, _ := tengo.ToInt64(args[0])
ret = &tengo.Int{Value: arg0 * 2} ret = tengo.Int{Value: arg0 * 2}
return return
}, },
}, },
@ -227,7 +227,7 @@ e := mod1.double(s)
} }
type Counter struct { type Counter struct {
tengo.ObjectImpl tengo.PtrObjectImpl
value int64 value int64
} }
@ -251,7 +251,7 @@ func (o *Counter) BinaryOp(
case token.Sub: case token.Sub:
return &Counter{value: o.value - rhs.value}, nil return &Counter{value: o.value - rhs.value}, nil
} }
case *tengo.Int: case tengo.Int:
switch op { switch op {
case token.Add: case token.Add:
return &Counter{value: o.value + rhs.Value}, nil return &Counter{value: o.value + rhs.Value}, nil
@ -280,7 +280,7 @@ func (o *Counter) Copy() tengo.Object {
} }
func (o *Counter) Call(_ ...tengo.Object) (tengo.Object, error) { func (o *Counter) Call(_ ...tengo.Object) (tengo.Object, error) {
return &tengo.Int{Value: o.value}, nil return tengo.Int{Value: o.value}, nil
} }
func (o *Counter) CanCall() bool { func (o *Counter) CanCall() bool {

View file

@ -24,7 +24,7 @@ func FuncARI(fn func() int) tengo.CallableFunc {
if len(args) != 0 { if len(args) != 0 {
return nil, tengo.ErrWrongNumArguments return nil, tengo.ErrWrongNumArguments
} }
return &tengo.Int{Value: int64(fn())}, nil return tengo.Int{Value: int64(fn())}, nil
} }
} }
@ -35,7 +35,7 @@ func FuncARI64(fn func() int64) tengo.CallableFunc {
if len(args) != 0 { if len(args) != 0 {
return nil, tengo.ErrWrongNumArguments return nil, tengo.ErrWrongNumArguments
} }
return &tengo.Int{Value: fn()}, nil return tengo.Int{Value: fn()}, nil
} }
} }
@ -55,7 +55,7 @@ func FuncAI64RI64(fn func(int64) int64) tengo.CallableFunc {
Found: args[0].TypeName(), Found: args[0].TypeName(),
} }
} }
return &tengo.Int{Value: fn(i1)}, nil return tengo.Int{Value: fn(i1)}, nil
} }
} }
@ -163,7 +163,7 @@ func FuncARF(fn func() float64) tengo.CallableFunc {
if len(args) != 0 { if len(args) != 0 {
return nil, tengo.ErrWrongNumArguments return nil, tengo.ErrWrongNumArguments
} }
return &tengo.Float{Value: fn()}, nil return tengo.Float{Value: fn()}, nil
} }
} }
@ -198,7 +198,7 @@ func FuncARIsE(fn func() ([]int, error)) tengo.CallableFunc {
} }
arr := &tengo.Array{} arr := &tengo.Array{}
for _, v := range res { for _, v := range res {
arr.Value = append(arr.Value, &tengo.Int{Value: int64(v)}) arr.Value = append(arr.Value, tengo.Int{Value: int64(v)})
} }
return arr, nil return arr, nil
} }
@ -222,7 +222,7 @@ func FuncAIRIs(fn func(int) []int) tengo.CallableFunc {
res := fn(i1) res := fn(i1)
arr := &tengo.Array{} arr := &tengo.Array{}
for _, v := range res { for _, v := range res {
arr.Value = append(arr.Value, &tengo.Int{Value: int64(v)}) arr.Value = append(arr.Value, tengo.Int{Value: int64(v)})
} }
return arr, nil return arr, nil
} }
@ -243,7 +243,7 @@ func FuncAFRF(fn func(float64) float64) tengo.CallableFunc {
Found: args[0].TypeName(), Found: args[0].TypeName(),
} }
} }
return &tengo.Float{Value: fn(f1)}, nil return tengo.Float{Value: fn(f1)}, nil
} }
} }
@ -281,7 +281,7 @@ func FuncAIRF(fn func(int) float64) tengo.CallableFunc {
Found: args[0].TypeName(), Found: args[0].TypeName(),
} }
} }
return &tengo.Float{Value: fn(i1)}, nil return tengo.Float{Value: fn(i1)}, nil
} }
} }
@ -300,7 +300,7 @@ func FuncAFRI(fn func(float64) int) tengo.CallableFunc {
Found: args[0].TypeName(), Found: args[0].TypeName(),
} }
} }
return &tengo.Int{Value: int64(fn(f1))}, nil return tengo.Int{Value: int64(fn(f1))}, nil
} }
} }
@ -327,7 +327,7 @@ func FuncAFFRF(fn func(float64, float64) float64) tengo.CallableFunc {
Found: args[1].TypeName(), Found: args[1].TypeName(),
} }
} }
return &tengo.Float{Value: fn(f1, f2)}, nil return tengo.Float{Value: fn(f1, f2)}, nil
} }
} }
@ -354,7 +354,7 @@ func FuncAIFRF(fn func(int, float64) float64) tengo.CallableFunc {
Found: args[1].TypeName(), Found: args[1].TypeName(),
} }
} }
return &tengo.Float{Value: fn(i1, f2)}, nil return tengo.Float{Value: fn(i1, f2)}, nil
} }
} }
@ -381,7 +381,7 @@ func FuncAFIRF(fn func(float64, int) float64) tengo.CallableFunc {
Found: args[1].TypeName(), Found: args[1].TypeName(),
} }
} }
return &tengo.Float{Value: fn(f1, i2)}, nil return tengo.Float{Value: fn(f1, i2)}, nil
} }
} }
@ -662,7 +662,7 @@ func FuncASSRI(fn func(string, string) int) tengo.CallableFunc {
Found: args[0].TypeName(), Found: args[0].TypeName(),
} }
} }
return &tengo.Int{Value: int64(fn(s1, s2))}, nil return tengo.Int{Value: int64(fn(s1, s2))}, nil
} }
} }
@ -922,7 +922,7 @@ func FuncAYRIE(fn func([]byte) (int, error)) tengo.CallableFunc {
if err != nil { if err != nil {
return wrapError(err), nil return wrapError(err), nil
} }
return &tengo.Int{Value: int64(res)}, nil return tengo.Int{Value: int64(res)}, nil
} }
} }
@ -965,7 +965,7 @@ func FuncASRIE(fn func(string) (int, error)) tengo.CallableFunc {
if err != nil { if err != nil {
return wrapError(err), nil return wrapError(err), nil
} }
return &tengo.Int{Value: int64(res)}, nil return tengo.Int{Value: int64(res)}, nil
} }
} }

View file

@ -13,7 +13,7 @@ import (
func TestFuncAIR(t *testing.T) { func TestFuncAIR(t *testing.T) {
uf := stdlib.FuncAIR(func(int) {}) uf := stdlib.FuncAIR(func(int) {})
ret, err := funcCall(uf, &tengo.Int{Value: 10}) ret, err := funcCall(uf, tengo.Int{Value: 10})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, tengo.UndefinedValue, ret) require.Equal(t, tengo.UndefinedValue, ret)
_, err = funcCall(uf) _, err = funcCall(uf)
@ -33,7 +33,7 @@ func TestFuncARI(t *testing.T) {
uf := stdlib.FuncARI(func() int { return 10 }) uf := stdlib.FuncARI(func() int { return 10 })
ret, err := funcCall(uf) ret, err := funcCall(uf)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, &tengo.Int{Value: 10}, ret) require.Equal(t, tengo.Int{Value: 10}, ret)
_, err = funcCall(uf, tengo.TrueValue) _, err = funcCall(uf, tengo.TrueValue)
require.Equal(t, tengo.ErrWrongNumArguments, err) require.Equal(t, tengo.ErrWrongNumArguments, err)
} }
@ -59,8 +59,8 @@ func TestFuncARIsE(t *testing.T) {
}) })
ret, err := funcCall(uf) ret, err := funcCall(uf)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, array(&tengo.Int{Value: 1}, require.Equal(t, array(tengo.Int{Value: 1},
&tengo.Int{Value: 2}, &tengo.Int{Value: 3}), ret) tengo.Int{Value: 2}, tengo.Int{Value: 3}), ret)
uf = stdlib.FuncARIsE(func() ([]int, error) { uf = stdlib.FuncARIsE(func() ([]int, error) {
return nil, errors.New("some error") return nil, errors.New("some error")
}) })
@ -146,13 +146,13 @@ func TestFuncASRSs(t *testing.T) {
func TestFuncASI64RE(t *testing.T) { func TestFuncASI64RE(t *testing.T) {
uf := stdlib.FuncASI64RE(func(a string, b int64) error { return nil }) uf := stdlib.FuncASI64RE(func(a string, b int64) error { return nil })
ret, err := funcCall(uf, &tengo.String{Value: "foo"}, &tengo.Int{Value: 5}) ret, err := funcCall(uf, &tengo.String{Value: "foo"}, tengo.Int{Value: 5})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, tengo.TrueValue, ret) require.Equal(t, tengo.TrueValue, ret)
uf = stdlib.FuncASI64RE(func(a string, b int64) error { uf = stdlib.FuncASI64RE(func(a string, b int64) error {
return errors.New("some error") return errors.New("some error")
}) })
ret, err = funcCall(uf, &tengo.String{Value: "foo"}, &tengo.Int{Value: 5}) ret, err = funcCall(uf, &tengo.String{Value: "foo"}, tengo.Int{Value: 5})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, require.Equal(t,
&tengo.Error{Value: &tengo.String{Value: "some error"}}, ret) &tengo.Error{Value: &tengo.String{Value: "some error"}}, ret)
@ -162,13 +162,13 @@ func TestFuncASI64RE(t *testing.T) {
func TestFuncAIIRE(t *testing.T) { func TestFuncAIIRE(t *testing.T) {
uf := stdlib.FuncAIIRE(func(a, b int) error { return nil }) uf := stdlib.FuncAIIRE(func(a, b int) error { return nil })
ret, err := funcCall(uf, &tengo.Int{Value: 5}, &tengo.Int{Value: 7}) ret, err := funcCall(uf, tengo.Int{Value: 5}, tengo.Int{Value: 7})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, tengo.TrueValue, ret) require.Equal(t, tengo.TrueValue, ret)
uf = stdlib.FuncAIIRE(func(a, b int) error { uf = stdlib.FuncAIIRE(func(a, b int) error {
return errors.New("some error") return errors.New("some error")
}) })
ret, err = funcCall(uf, &tengo.Int{Value: 5}, &tengo.Int{Value: 7}) ret, err = funcCall(uf, tengo.Int{Value: 5}, tengo.Int{Value: 7})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, require.Equal(t,
&tengo.Error{Value: &tengo.String{Value: "some error"}}, ret) &tengo.Error{Value: &tengo.String{Value: "some error"}}, ret)
@ -178,15 +178,15 @@ func TestFuncAIIRE(t *testing.T) {
func TestFuncASIIRE(t *testing.T) { func TestFuncASIIRE(t *testing.T) {
uf := stdlib.FuncASIIRE(func(a string, b, c int) error { return nil }) uf := stdlib.FuncASIIRE(func(a string, b, c int) error { return nil })
ret, err := funcCall(uf, &tengo.String{Value: "foo"}, &tengo.Int{Value: 5}, ret, err := funcCall(uf, &tengo.String{Value: "foo"}, tengo.Int{Value: 5},
&tengo.Int{Value: 7}) tengo.Int{Value: 7})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, tengo.TrueValue, ret) require.Equal(t, tengo.TrueValue, ret)
uf = stdlib.FuncASIIRE(func(a string, b, c int) error { uf = stdlib.FuncASIIRE(func(a string, b, c int) error {
return errors.New("some error") return errors.New("some error")
}) })
ret, err = funcCall(uf, &tengo.String{Value: "foo"}, &tengo.Int{Value: 5}, ret, err = funcCall(uf, &tengo.String{Value: "foo"}, tengo.Int{Value: 5},
&tengo.Int{Value: 7}) tengo.Int{Value: 7})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, require.Equal(t,
&tengo.Error{Value: &tengo.String{Value: "some error"}}, ret) &tengo.Error{Value: &tengo.String{Value: "some error"}}, ret)
@ -244,16 +244,16 @@ func TestFuncARF(t *testing.T) {
uf := stdlib.FuncARF(func() float64 { return 10.0 }) uf := stdlib.FuncARF(func() float64 { return 10.0 })
ret, err := funcCall(uf) ret, err := funcCall(uf)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, &tengo.Float{Value: 10.0}, ret) require.Equal(t, tengo.Float{Value: 10.0}, ret)
_, err = funcCall(uf, tengo.TrueValue) _, err = funcCall(uf, tengo.TrueValue)
require.Equal(t, tengo.ErrWrongNumArguments, err) require.Equal(t, tengo.ErrWrongNumArguments, err)
} }
func TestFuncAFRF(t *testing.T) { func TestFuncAFRF(t *testing.T) {
uf := stdlib.FuncAFRF(func(a float64) float64 { return a }) uf := stdlib.FuncAFRF(func(a float64) float64 { return a })
ret, err := funcCall(uf, &tengo.Float{Value: 10.0}) ret, err := funcCall(uf, tengo.Float{Value: 10.0})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, &tengo.Float{Value: 10.0}, ret) require.Equal(t, tengo.Float{Value: 10.0}, ret)
_, err = funcCall(uf) _, err = funcCall(uf)
require.Equal(t, tengo.ErrWrongNumArguments, err) require.Equal(t, tengo.ErrWrongNumArguments, err)
_, err = funcCall(uf, tengo.TrueValue, tengo.TrueValue) _, err = funcCall(uf, tengo.TrueValue, tengo.TrueValue)
@ -264,9 +264,9 @@ func TestFuncAIRF(t *testing.T) {
uf := stdlib.FuncAIRF(func(a int) float64 { uf := stdlib.FuncAIRF(func(a int) float64 {
return float64(a) return float64(a)
}) })
ret, err := funcCall(uf, &tengo.Int{Value: 10.0}) ret, err := funcCall(uf, tengo.Int{Value: 10.0})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, &tengo.Float{Value: 10.0}, ret) require.Equal(t, tengo.Float{Value: 10.0}, ret)
_, err = funcCall(uf) _, err = funcCall(uf)
require.Equal(t, tengo.ErrWrongNumArguments, err) require.Equal(t, tengo.ErrWrongNumArguments, err)
_, err = funcCall(uf, tengo.TrueValue, tengo.TrueValue) _, err = funcCall(uf, tengo.TrueValue, tengo.TrueValue)
@ -277,9 +277,9 @@ func TestFuncAFRI(t *testing.T) {
uf := stdlib.FuncAFRI(func(a float64) int { uf := stdlib.FuncAFRI(func(a float64) int {
return int(a) return int(a)
}) })
ret, err := funcCall(uf, &tengo.Float{Value: 10.5}) ret, err := funcCall(uf, tengo.Float{Value: 10.5})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, &tengo.Int{Value: 10}, ret) require.Equal(t, tengo.Int{Value: 10}, ret)
_, err = funcCall(uf) _, err = funcCall(uf)
require.Equal(t, tengo.ErrWrongNumArguments, err) require.Equal(t, tengo.ErrWrongNumArguments, err)
_, err = funcCall(uf, tengo.TrueValue, tengo.TrueValue) _, err = funcCall(uf, tengo.TrueValue, tengo.TrueValue)
@ -290,7 +290,7 @@ func TestFuncAFRB(t *testing.T) {
uf := stdlib.FuncAFRB(func(a float64) bool { uf := stdlib.FuncAFRB(func(a float64) bool {
return a > 0.0 return a > 0.0
}) })
ret, err := funcCall(uf, &tengo.Float{Value: 0.1}) ret, err := funcCall(uf, tengo.Float{Value: 0.1})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, tengo.TrueValue, ret) require.Equal(t, tengo.TrueValue, ret)
_, err = funcCall(uf) _, err = funcCall(uf)
@ -303,10 +303,10 @@ func TestFuncAFFRF(t *testing.T) {
uf := stdlib.FuncAFFRF(func(a, b float64) float64 { uf := stdlib.FuncAFFRF(func(a, b float64) float64 {
return a + b return a + b
}) })
ret, err := funcCall(uf, &tengo.Float{Value: 10.0}, ret, err := funcCall(uf, tengo.Float{Value: 10.0},
&tengo.Float{Value: 20.0}) tengo.Float{Value: 20.0})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, &tengo.Float{Value: 30.0}, ret) require.Equal(t, tengo.Float{Value: 30.0}, ret)
_, err = funcCall(uf) _, err = funcCall(uf)
require.Equal(t, tengo.ErrWrongNumArguments, err) require.Equal(t, tengo.ErrWrongNumArguments, err)
_, err = funcCall(uf, tengo.TrueValue) _, err = funcCall(uf, tengo.TrueValue)
@ -317,7 +317,7 @@ func TestFuncASIRS(t *testing.T) {
uf := stdlib.FuncASIRS(func(a string, b int) string { uf := stdlib.FuncASIRS(func(a string, b int) string {
return strings.Repeat(a, b) return strings.Repeat(a, b)
}) })
ret, err := funcCall(uf, &tengo.String{Value: "ab"}, &tengo.Int{Value: 2}) ret, err := funcCall(uf, &tengo.String{Value: "ab"}, tengo.Int{Value: 2})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, &tengo.String{Value: "abab"}, ret) require.Equal(t, &tengo.String{Value: "abab"}, ret)
_, err = funcCall(uf) _, err = funcCall(uf)
@ -330,9 +330,9 @@ func TestFuncAIFRF(t *testing.T) {
uf := stdlib.FuncAIFRF(func(a int, b float64) float64 { uf := stdlib.FuncAIFRF(func(a int, b float64) float64 {
return float64(a) + b return float64(a) + b
}) })
ret, err := funcCall(uf, &tengo.Int{Value: 10}, &tengo.Float{Value: 20.0}) ret, err := funcCall(uf, tengo.Int{Value: 10}, tengo.Float{Value: 20.0})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, &tengo.Float{Value: 30.0}, ret) require.Equal(t, tengo.Float{Value: 30.0}, ret)
_, err = funcCall(uf) _, err = funcCall(uf)
require.Equal(t, tengo.ErrWrongNumArguments, err) require.Equal(t, tengo.ErrWrongNumArguments, err)
_, err = funcCall(uf, tengo.TrueValue) _, err = funcCall(uf, tengo.TrueValue)
@ -343,9 +343,9 @@ func TestFuncAFIRF(t *testing.T) {
uf := stdlib.FuncAFIRF(func(a float64, b int) float64 { uf := stdlib.FuncAFIRF(func(a float64, b int) float64 {
return a + float64(b) return a + float64(b)
}) })
ret, err := funcCall(uf, &tengo.Float{Value: 10.0}, &tengo.Int{Value: 20}) ret, err := funcCall(uf, tengo.Float{Value: 10.0}, tengo.Int{Value: 20})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, &tengo.Float{Value: 30.0}, ret) require.Equal(t, tengo.Float{Value: 30.0}, ret)
_, err = funcCall(uf) _, err = funcCall(uf)
require.Equal(t, tengo.ErrWrongNumArguments, err) require.Equal(t, tengo.ErrWrongNumArguments, err)
_, err = funcCall(uf, tengo.TrueValue) _, err = funcCall(uf, tengo.TrueValue)
@ -356,7 +356,7 @@ func TestFuncAFIRB(t *testing.T) {
uf := stdlib.FuncAFIRB(func(a float64, b int) bool { uf := stdlib.FuncAFIRB(func(a float64, b int) bool {
return a < float64(b) return a < float64(b)
}) })
ret, err := funcCall(uf, &tengo.Float{Value: 10.0}, &tengo.Int{Value: 20}) ret, err := funcCall(uf, tengo.Float{Value: 10.0}, tengo.Int{Value: 20})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, tengo.TrueValue, ret) require.Equal(t, tengo.TrueValue, ret)
_, err = funcCall(uf) _, err = funcCall(uf)
@ -369,14 +369,14 @@ func TestFuncAIRSsE(t *testing.T) {
uf := stdlib.FuncAIRSsE(func(a int) ([]string, error) { uf := stdlib.FuncAIRSsE(func(a int) ([]string, error) {
return []string{"foo", "bar"}, nil return []string{"foo", "bar"}, nil
}) })
ret, err := funcCall(uf, &tengo.Int{Value: 10}) ret, err := funcCall(uf, tengo.Int{Value: 10})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, array(&tengo.String{Value: "foo"}, require.Equal(t, array(&tengo.String{Value: "foo"},
&tengo.String{Value: "bar"}), ret) &tengo.String{Value: "bar"}), ret)
uf = stdlib.FuncAIRSsE(func(a int) ([]string, error) { uf = stdlib.FuncAIRSsE(func(a int) ([]string, error) {
return nil, errors.New("some error") return nil, errors.New("some error")
}) })
ret, err = funcCall(uf, &tengo.Int{Value: 10}) ret, err = funcCall(uf, tengo.Int{Value: 10})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, require.Equal(t,
&tengo.Error{Value: &tengo.String{Value: "some error"}}, ret) &tengo.Error{Value: &tengo.String{Value: "some error"}}, ret)
@ -402,7 +402,7 @@ func TestFuncASSIRSs(t *testing.T) {
return []string{a, b, strconv.Itoa(c)} return []string{a, b, strconv.Itoa(c)}
}) })
ret, err := funcCall(uf, &tengo.String{Value: "foo"}, ret, err := funcCall(uf, &tengo.String{Value: "foo"},
&tengo.String{Value: "bar"}, &tengo.Int{Value: 5}) &tengo.String{Value: "bar"}, tengo.Int{Value: 5})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, array(&tengo.String{Value: "foo"}, require.Equal(t, array(&tengo.String{Value: "foo"},
&tengo.String{Value: "bar"}, &tengo.String{Value: "5"}), ret) &tengo.String{Value: "bar"}, &tengo.String{Value: "5"}), ret)
@ -441,7 +441,7 @@ func TestFuncASRIE(t *testing.T) {
uf := stdlib.FuncASRIE(func(a string) (int, error) { return 5, nil }) uf := stdlib.FuncASRIE(func(a string) (int, error) { return 5, nil })
ret, err := funcCall(uf, &tengo.String{Value: "foo"}) ret, err := funcCall(uf, &tengo.String{Value: "foo"})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, &tengo.Int{Value: 5}, ret) require.Equal(t, tengo.Int{Value: 5}, ret)
uf = stdlib.FuncASRIE(func(a string) (int, error) { uf = stdlib.FuncASRIE(func(a string) (int, error) {
return 0, errors.New("some error") return 0, errors.New("some error")
}) })
@ -457,7 +457,7 @@ func TestFuncAYRIE(t *testing.T) {
uf := stdlib.FuncAYRIE(func(a []byte) (int, error) { return 5, nil }) uf := stdlib.FuncAYRIE(func(a []byte) (int, error) { return 5, nil })
ret, err := funcCall(uf, &tengo.Bytes{Value: []byte("foo")}) ret, err := funcCall(uf, &tengo.Bytes{Value: []byte("foo")})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, &tengo.Int{Value: 5}, ret) require.Equal(t, tengo.Int{Value: 5}, ret)
uf = stdlib.FuncAYRIE(func(a []byte) (int, error) { uf = stdlib.FuncAYRIE(func(a []byte) (int, error) {
return 0, errors.New("some error") return 0, errors.New("some error")
}) })
@ -474,7 +474,7 @@ func TestFuncASSRI(t *testing.T) {
ret, err := funcCall(uf, ret, err := funcCall(uf,
&tengo.String{Value: "foo"}, &tengo.String{Value: "bar"}) &tengo.String{Value: "foo"}, &tengo.String{Value: "bar"})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, &tengo.Int{Value: 6}, ret) require.Equal(t, tengo.Int{Value: 6}, ret)
_, err = funcCall(uf, &tengo.String{Value: "foo"}) _, err = funcCall(uf, &tengo.String{Value: "foo"})
require.Equal(t, tengo.ErrWrongNumArguments, err) require.Equal(t, tengo.ErrWrongNumArguments, err)
} }
@ -501,7 +501,7 @@ func TestFuncASSRB(t *testing.T) {
func TestFuncAIRS(t *testing.T) { func TestFuncAIRS(t *testing.T) {
uf := stdlib.FuncAIRS(func(a int) string { return strconv.Itoa(a) }) uf := stdlib.FuncAIRS(func(a int) string { return strconv.Itoa(a) })
ret, err := funcCall(uf, &tengo.Int{Value: 55}) ret, err := funcCall(uf, tengo.Int{Value: 55})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, &tengo.String{Value: "55"}, ret) require.Equal(t, &tengo.String{Value: "55"}, ret)
_, err = funcCall(uf) _, err = funcCall(uf)
@ -510,16 +510,16 @@ func TestFuncAIRS(t *testing.T) {
func TestFuncAIRIs(t *testing.T) { func TestFuncAIRIs(t *testing.T) {
uf := stdlib.FuncAIRIs(func(a int) []int { return []int{a, a} }) uf := stdlib.FuncAIRIs(func(a int) []int { return []int{a, a} })
ret, err := funcCall(uf, &tengo.Int{Value: 55}) ret, err := funcCall(uf, tengo.Int{Value: 55})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, array(&tengo.Int{Value: 55}, &tengo.Int{Value: 55}), ret) require.Equal(t, array(tengo.Int{Value: 55}, tengo.Int{Value: 55}), ret)
_, err = funcCall(uf) _, err = funcCall(uf)
require.Equal(t, tengo.ErrWrongNumArguments, err) require.Equal(t, tengo.ErrWrongNumArguments, err)
} }
func TestFuncAI64R(t *testing.T) { func TestFuncAI64R(t *testing.T) {
uf := stdlib.FuncAIR(func(a int) {}) uf := stdlib.FuncAIR(func(a int) {})
ret, err := funcCall(uf, &tengo.Int{Value: 55}) ret, err := funcCall(uf, tengo.Int{Value: 55})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, tengo.UndefinedValue, ret) require.Equal(t, tengo.UndefinedValue, ret)
_, err = funcCall(uf) _, err = funcCall(uf)
@ -530,8 +530,8 @@ func TestFuncARI64(t *testing.T) {
uf := stdlib.FuncARI64(func() int64 { return 55 }) uf := stdlib.FuncARI64(func() int64 { return 55 })
ret, err := funcCall(uf) ret, err := funcCall(uf)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, &tengo.Int{Value: 55}, ret) require.Equal(t, tengo.Int{Value: 55}, ret)
_, err = funcCall(uf, &tengo.Int{Value: 55}) _, err = funcCall(uf, tengo.Int{Value: 55})
require.Equal(t, tengo.ErrWrongNumArguments, err) require.Equal(t, tengo.ErrWrongNumArguments, err)
} }
@ -550,9 +550,9 @@ func TestFuncASsSRS(t *testing.T) {
func TestFuncAI64RI64(t *testing.T) { func TestFuncAI64RI64(t *testing.T) {
uf := stdlib.FuncAI64RI64(func(a int64) int64 { return a * 2 }) uf := stdlib.FuncAI64RI64(func(a int64) int64 { return a * 2 })
ret, err := funcCall(uf, &tengo.Int{Value: 55}) ret, err := funcCall(uf, tengo.Int{Value: 55})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, &tengo.Int{Value: 110}, ret) require.Equal(t, tengo.Int{Value: 110}, ret)
_, err = funcCall(uf) _, err = funcCall(uf)
require.Equal(t, tengo.ErrWrongNumArguments, err) require.Equal(t, tengo.ErrWrongNumArguments, err)
} }

View file

@ -211,7 +211,7 @@ func (d *decodeState) literal() (tengo.Object, error) {
panic(phasePanicMsg) panic(phasePanicMsg)
} }
n, _ := strconv.ParseFloat(string(item), 10) n, _ := strconv.ParseFloat(string(item), 10)
return &tengo.Float{Value: n}, nil return tengo.Float{Value: n}, nil
} }
} }

View file

@ -193,7 +193,7 @@ func Encode(o tengo.Object) ([]byte, error) {
idx++ idx++
} }
b = append(b, '}') b = append(b, '}')
case *tengo.Bool: case tengo.Bool:
if o.IsFalsy() { if o.IsFalsy() {
b = strconv.AppendBool(b, false) b = strconv.AppendBool(b, false)
} else { } else {
@ -206,9 +206,9 @@ func Encode(o tengo.Object) ([]byte, error) {
base64.StdEncoding.Encode(dst, o.Value) base64.StdEncoding.Encode(dst, o.Value)
b = append(b, dst...) b = append(b, dst...)
b = append(b, '"') b = append(b, '"')
case *tengo.Char: case tengo.Char:
b = strconv.AppendInt(b, int64(o.Value), 10) b = strconv.AppendInt(b, int64(o.Value), 10)
case *tengo.Float: case tengo.Float:
var y []byte var y []byte
f := o.Value f := o.Value
@ -236,7 +236,7 @@ func Encode(o tengo.Object) ([]byte, error) {
} }
b = append(b, y...) b = append(b, y...)
case *tengo.Int: case tengo.Int:
b = strconv.AppendInt(b, o.Value, 10) b = strconv.AppendInt(b, o.Value, 10)
case *tengo.String: case *tengo.String:
// string encoding bug is fixed with newly introduced function // string encoding bug is fixed with newly introduced function

View file

@ -7,17 +7,17 @@ import (
) )
var mathModule = map[string]tengo.Object{ var mathModule = map[string]tengo.Object{
"e": &tengo.Float{Value: math.E}, "e": tengo.Float{Value: math.E},
"pi": &tengo.Float{Value: math.Pi}, "pi": tengo.Float{Value: math.Pi},
"phi": &tengo.Float{Value: math.Phi}, "phi": tengo.Float{Value: math.Phi},
"sqrt2": &tengo.Float{Value: math.Sqrt2}, "sqrt2": tengo.Float{Value: math.Sqrt2},
"sqrtE": &tengo.Float{Value: math.SqrtE}, "sqrtE": tengo.Float{Value: math.SqrtE},
"sqrtPi": &tengo.Float{Value: math.SqrtPi}, "sqrtPi": tengo.Float{Value: math.SqrtPi},
"sqrtPhi": &tengo.Float{Value: math.SqrtPhi}, "sqrtPhi": tengo.Float{Value: math.SqrtPhi},
"ln2": &tengo.Float{Value: math.Ln2}, "ln2": tengo.Float{Value: math.Ln2},
"log2E": &tengo.Float{Value: math.Log2E}, "log2E": tengo.Float{Value: math.Log2E},
"ln10": &tengo.Float{Value: math.Ln10}, "ln10": tengo.Float{Value: math.Ln10},
"log10E": &tengo.Float{Value: math.Log10E}, "log10E": tengo.Float{Value: math.Log10E},
"abs": &tengo.UserFunction{ "abs": &tengo.UserFunction{
Name: "abs", Name: "abs",
Value: FuncAFRF(math.Abs), Value: FuncAFRF(math.Abs),

View file

@ -11,34 +11,34 @@ import (
) )
var osModule = map[string]tengo.Object{ var osModule = map[string]tengo.Object{
"o_rdonly": &tengo.Int{Value: int64(os.O_RDONLY)}, "o_rdonly": tengo.Int{Value: int64(os.O_RDONLY)},
"o_wronly": &tengo.Int{Value: int64(os.O_WRONLY)}, "o_wronly": tengo.Int{Value: int64(os.O_WRONLY)},
"o_rdwr": &tengo.Int{Value: int64(os.O_RDWR)}, "o_rdwr": tengo.Int{Value: int64(os.O_RDWR)},
"o_append": &tengo.Int{Value: int64(os.O_APPEND)}, "o_append": tengo.Int{Value: int64(os.O_APPEND)},
"o_create": &tengo.Int{Value: int64(os.O_CREATE)}, "o_create": tengo.Int{Value: int64(os.O_CREATE)},
"o_excl": &tengo.Int{Value: int64(os.O_EXCL)}, "o_excl": tengo.Int{Value: int64(os.O_EXCL)},
"o_sync": &tengo.Int{Value: int64(os.O_SYNC)}, "o_sync": tengo.Int{Value: int64(os.O_SYNC)},
"o_trunc": &tengo.Int{Value: int64(os.O_TRUNC)}, "o_trunc": tengo.Int{Value: int64(os.O_TRUNC)},
"mode_dir": &tengo.Int{Value: int64(os.ModeDir)}, "mode_dir": tengo.Int{Value: int64(os.ModeDir)},
"mode_append": &tengo.Int{Value: int64(os.ModeAppend)}, "mode_append": tengo.Int{Value: int64(os.ModeAppend)},
"mode_exclusive": &tengo.Int{Value: int64(os.ModeExclusive)}, "mode_exclusive": tengo.Int{Value: int64(os.ModeExclusive)},
"mode_temporary": &tengo.Int{Value: int64(os.ModeTemporary)}, "mode_temporary": tengo.Int{Value: int64(os.ModeTemporary)},
"mode_symlink": &tengo.Int{Value: int64(os.ModeSymlink)}, "mode_symlink": tengo.Int{Value: int64(os.ModeSymlink)},
"mode_device": &tengo.Int{Value: int64(os.ModeDevice)}, "mode_device": tengo.Int{Value: int64(os.ModeDevice)},
"mode_named_pipe": &tengo.Int{Value: int64(os.ModeNamedPipe)}, "mode_named_pipe": tengo.Int{Value: int64(os.ModeNamedPipe)},
"mode_socket": &tengo.Int{Value: int64(os.ModeSocket)}, "mode_socket": tengo.Int{Value: int64(os.ModeSocket)},
"mode_setuid": &tengo.Int{Value: int64(os.ModeSetuid)}, "mode_setuid": tengo.Int{Value: int64(os.ModeSetuid)},
"mode_setgui": &tengo.Int{Value: int64(os.ModeSetgid)}, "mode_setgui": tengo.Int{Value: int64(os.ModeSetgid)},
"mode_char_device": &tengo.Int{Value: int64(os.ModeCharDevice)}, "mode_char_device": tengo.Int{Value: int64(os.ModeCharDevice)},
"mode_sticky": &tengo.Int{Value: int64(os.ModeSticky)}, "mode_sticky": tengo.Int{Value: int64(os.ModeSticky)},
"mode_type": &tengo.Int{Value: int64(os.ModeType)}, "mode_type": tengo.Int{Value: int64(os.ModeType)},
"mode_perm": &tengo.Int{Value: int64(os.ModePerm)}, "mode_perm": tengo.Int{Value: int64(os.ModePerm)},
"path_separator": &tengo.Char{Value: os.PathSeparator}, "path_separator": tengo.Char{Value: os.PathSeparator},
"path_list_separator": &tengo.Char{Value: os.PathListSeparator}, "path_list_separator": tengo.Char{Value: os.PathListSeparator},
"dev_null": &tengo.String{Value: os.DevNull}, "dev_null": &tengo.String{Value: os.DevNull},
"seek_set": &tengo.Int{Value: int64(io.SeekStart)}, "seek_set": tengo.Int{Value: int64(io.SeekStart)},
"seek_cur": &tengo.Int{Value: int64(io.SeekCurrent)}, "seek_cur": tengo.Int{Value: int64(io.SeekCurrent)},
"seek_end": &tengo.Int{Value: int64(io.SeekEnd)}, "seek_end": tengo.Int{Value: int64(io.SeekEnd)},
"args": &tengo.UserFunction{ "args": &tengo.UserFunction{
Name: "args", Name: "args",
Value: osArgs, Value: osArgs,
@ -242,8 +242,8 @@ func osStat(args ...tengo.Object) (ret tengo.Object, err error) {
Value: map[string]tengo.Object{ Value: map[string]tengo.Object{
"name": &tengo.String{Value: stat.Name()}, "name": &tengo.String{Value: stat.Name()},
"mtime": &tengo.Time{Value: stat.ModTime()}, "mtime": &tengo.Time{Value: stat.ModTime()},
"size": &tengo.Int{Value: stat.Size()}, "size": tengo.Int{Value: stat.Size()},
"mode": &tengo.Int{Value: int64(stat.Mode())}, "mode": tengo.Int{Value: int64(stat.Mode())},
}, },
} }
if stat.IsDir() { if stat.IsDir() {

View file

@ -99,7 +99,7 @@ func makeOSFile(file *os.File) *tengo.ImmutableMap {
if err != nil { if err != nil {
return wrapError(err), nil return wrapError(err), nil
} }
return &tengo.Int{Value: res}, nil return tengo.Int{Value: res}, nil
}, },
}, },
// stat() => imap(fileinfo)/error // stat() => imap(fileinfo)/error

View file

@ -50,8 +50,8 @@ func TestFileStatFile(t *testing.T) {
Value: map[string]tengo.Object{ Value: map[string]tengo.Object{
"name": &tengo.String{Value: stat.Name()}, "name": &tengo.String{Value: stat.Name()},
"mtime": &tengo.Time{Value: stat.ModTime()}, "mtime": &tengo.Time{Value: stat.ModTime()},
"size": &tengo.Int{Value: stat.Size()}, "size": tengo.Int{Value: stat.Size()},
"mode": &tengo.Int{Value: int64(stat.Mode())}, "mode": tengo.Int{Value: int64(stat.Mode())},
"directory": tengo.FalseValue, "directory": tengo.FalseValue,
}, },
}) })
@ -69,8 +69,8 @@ func TestFileStatDir(t *testing.T) {
Value: map[string]tengo.Object{ Value: map[string]tengo.Object{
"name": &tengo.String{Value: stat.Name()}, "name": &tengo.String{Value: stat.Name()},
"mtime": &tengo.Time{Value: stat.ModTime()}, "mtime": &tengo.Time{Value: stat.ModTime()},
"size": &tengo.Int{Value: stat.Size()}, "size": tengo.Int{Value: stat.Size()},
"mode": &tengo.Int{Value: int64(stat.Mode())}, "mode": tengo.Int{Value: int64(stat.Mode())},
"directory": tengo.TrueValue, "directory": tengo.TrueValue,
}, },
}) })

View file

@ -54,7 +54,7 @@ var randModule = map[string]tengo.Object{
ret = wrapError(err) ret = wrapError(err)
return return
} }
return &tengo.Int{Value: int64(res)}, nil return tengo.Int{Value: int64(res)}, nil
}, },
}, },
"rand": &tengo.UserFunction{ "rand": &tengo.UserFunction{
@ -130,7 +130,7 @@ func randRand(r *rand.Rand) *tengo.ImmutableMap {
ret = wrapError(err) ret = wrapError(err)
return return
} }
return &tengo.Int{Value: int64(res)}, nil return tengo.Int{Value: int64(res)}, nil
}, },
}, },
}, },

View file

@ -172,20 +172,20 @@ func object(v interface{}) tengo.Object {
case string: case string:
return &tengo.String{Value: v} return &tengo.String{Value: v}
case int64: case int64:
return &tengo.Int{Value: v} return tengo.Int{Value: v}
case int: // for convenience case int: // for convenience
return &tengo.Int{Value: int64(v)} return tengo.Int{Value: int64(v)}
case bool: case bool:
if v { if v {
return tengo.TrueValue return tengo.TrueValue
} }
return tengo.FalseValue return tengo.FalseValue
case rune: case rune:
return &tengo.Char{Value: v} return tengo.Char{Value: v}
case byte: // for convenience case byte: // for convenience
return &tengo.Char{Value: rune(v)} return tengo.Char{Value: rune(v)}
case float64: case float64:
return &tengo.Float{Value: v} return tengo.Float{Value: v}
case []byte: case []byte:
return &tengo.Bytes{Value: v} return &tengo.Bytes{Value: v}
case MAP: case MAP:
@ -221,7 +221,7 @@ func object(v interface{}) tengo.Object {
case []int: case []int:
var objs []tengo.Object var objs []tengo.Object
for _, e := range v { for _, e := range v {
objs = append(objs, &tengo.Int{Value: int64(e)}) objs = append(objs, tengo.Int{Value: int64(e)})
} }
return &tengo.Array{Value: objs} return &tengo.Array{Value: objs}

View file

@ -287,8 +287,8 @@ func textREFind(args ...tengo.Object) (ret tengo.Object, err error) {
arr.Value = append(arr.Value, arr.Value = append(arr.Value,
&tengo.ImmutableMap{Value: map[string]tengo.Object{ &tengo.ImmutableMap{Value: map[string]tengo.Object{
"text": &tengo.String{Value: s2[m[i]:m[i+1]]}, "text": &tengo.String{Value: s2[m[i]:m[i+1]]},
"begin": &tengo.Int{Value: int64(m[i])}, "begin": tengo.Int{Value: int64(m[i])},
"end": &tengo.Int{Value: int64(m[i+1])}, "end": tengo.Int{Value: int64(m[i+1])},
}}) }})
} }
@ -319,8 +319,8 @@ func textREFind(args ...tengo.Object) (ret tengo.Object, err error) {
subMatch.Value = append(subMatch.Value, subMatch.Value = append(subMatch.Value,
&tengo.ImmutableMap{Value: map[string]tengo.Object{ &tengo.ImmutableMap{Value: map[string]tengo.Object{
"text": &tengo.String{Value: s2[m[i]:m[i+1]]}, "text": &tengo.String{Value: s2[m[i]:m[i+1]]},
"begin": &tengo.Int{Value: int64(m[i])}, "begin": tengo.Int{Value: int64(m[i])},
"end": &tengo.Int{Value: int64(m[i+1])}, "end": tengo.Int{Value: int64(m[i+1])},
}}) }})
} }
@ -806,7 +806,7 @@ func textFormatBool(args ...tengo.Object) (ret tengo.Object, err error) {
return return
} }
b1, ok := args[0].(*tengo.Bool) b1, ok := args[0].(tengo.Bool)
if !ok { if !ok {
err = tengo.ErrInvalidArgumentType{ err = tengo.ErrInvalidArgumentType{
Name: "first", Name: "first",
@ -831,7 +831,7 @@ func textFormatFloat(args ...tengo.Object) (ret tengo.Object, err error) {
return return
} }
f1, ok := args[0].(*tengo.Float) f1, ok := args[0].(tengo.Float)
if !ok { if !ok {
err = tengo.ErrInvalidArgumentType{ err = tengo.ErrInvalidArgumentType{
Name: "first", Name: "first",
@ -882,7 +882,7 @@ func textFormatInt(args ...tengo.Object) (ret tengo.Object, err error) {
return return
} }
i1, ok := args[0].(*tengo.Int) i1, ok := args[0].(tengo.Int)
if !ok { if !ok {
err = tengo.ErrInvalidArgumentType{ err = tengo.ErrInvalidArgumentType{
Name: "first", Name: "first",
@ -970,7 +970,7 @@ func textParseFloat(args ...tengo.Object) (ret tengo.Object, err error) {
return return
} }
ret = &tengo.Float{Value: parsed} ret = tengo.Float{Value: parsed}
return return
} }
@ -1017,7 +1017,7 @@ func textParseInt(args ...tengo.Object) (ret tengo.Object, err error) {
return return
} }
ret = &tengo.Int{Value: parsed} ret = tengo.Int{Value: parsed}
return return
} }

View file

@ -78,10 +78,10 @@ func makeTextRegexp(re *regexp.Regexp) *tengo.ImmutableMap {
"text": &tengo.String{ "text": &tengo.String{
Value: s1[m[i]:m[i+1]], Value: s1[m[i]:m[i+1]],
}, },
"begin": &tengo.Int{ "begin": tengo.Int{
Value: int64(m[i]), Value: int64(m[i]),
}, },
"end": &tengo.Int{ "end": tengo.Int{
Value: int64(m[i+1]), Value: int64(m[i+1]),
}, },
}}) }})
@ -117,10 +117,10 @@ func makeTextRegexp(re *regexp.Regexp) *tengo.ImmutableMap {
"text": &tengo.String{ "text": &tengo.String{
Value: s1[m[i]:m[i+1]], Value: s1[m[i]:m[i+1]],
}, },
"begin": &tengo.Int{ "begin": tengo.Int{
Value: int64(m[i]), Value: int64(m[i]),
}, },
"end": &tengo.Int{ "end": tengo.Int{
Value: int64(m[i+1]), Value: int64(m[i+1]),
}, },
}}) }})

View file

@ -22,24 +22,24 @@ var timesModule = map[string]tengo.Object{
"format_stamp_milli": &tengo.String{Value: time.StampMilli}, "format_stamp_milli": &tengo.String{Value: time.StampMilli},
"format_stamp_micro": &tengo.String{Value: time.StampMicro}, "format_stamp_micro": &tengo.String{Value: time.StampMicro},
"format_stamp_nano": &tengo.String{Value: time.StampNano}, "format_stamp_nano": &tengo.String{Value: time.StampNano},
"nanosecond": &tengo.Int{Value: int64(time.Nanosecond)}, "nanosecond": tengo.Int{Value: int64(time.Nanosecond)},
"microsecond": &tengo.Int{Value: int64(time.Microsecond)}, "microsecond": tengo.Int{Value: int64(time.Microsecond)},
"millisecond": &tengo.Int{Value: int64(time.Millisecond)}, "millisecond": tengo.Int{Value: int64(time.Millisecond)},
"second": &tengo.Int{Value: int64(time.Second)}, "second": tengo.Int{Value: int64(time.Second)},
"minute": &tengo.Int{Value: int64(time.Minute)}, "minute": tengo.Int{Value: int64(time.Minute)},
"hour": &tengo.Int{Value: int64(time.Hour)}, "hour": tengo.Int{Value: int64(time.Hour)},
"january": &tengo.Int{Value: int64(time.January)}, "january": tengo.Int{Value: int64(time.January)},
"february": &tengo.Int{Value: int64(time.February)}, "february": tengo.Int{Value: int64(time.February)},
"march": &tengo.Int{Value: int64(time.March)}, "march": tengo.Int{Value: int64(time.March)},
"april": &tengo.Int{Value: int64(time.April)}, "april": tengo.Int{Value: int64(time.April)},
"may": &tengo.Int{Value: int64(time.May)}, "may": tengo.Int{Value: int64(time.May)},
"june": &tengo.Int{Value: int64(time.June)}, "june": tengo.Int{Value: int64(time.June)},
"july": &tengo.Int{Value: int64(time.July)}, "july": tengo.Int{Value: int64(time.July)},
"august": &tengo.Int{Value: int64(time.August)}, "august": tengo.Int{Value: int64(time.August)},
"september": &tengo.Int{Value: int64(time.September)}, "september": tengo.Int{Value: int64(time.September)},
"october": &tengo.Int{Value: int64(time.October)}, "october": tengo.Int{Value: int64(time.October)},
"november": &tengo.Int{Value: int64(time.November)}, "november": tengo.Int{Value: int64(time.November)},
"december": &tengo.Int{Value: int64(time.December)}, "december": tengo.Int{Value: int64(time.December)},
"sleep": &tengo.UserFunction{ "sleep": &tengo.UserFunction{
Name: "sleep", Name: "sleep",
Value: timesSleep, Value: timesSleep,
@ -229,7 +229,7 @@ func timesParseDuration(args ...tengo.Object) (
return return
} }
ret = &tengo.Int{Value: int64(dur)} ret = tengo.Int{Value: int64(dur)}
return return
} }
@ -253,7 +253,7 @@ func timesSince(args ...tengo.Object) (
return return
} }
ret = &tengo.Int{Value: int64(time.Since(t1))} ret = tengo.Int{Value: int64(time.Since(t1))}
return return
} }
@ -277,7 +277,7 @@ func timesUntil(args ...tengo.Object) (
return return
} }
ret = &tengo.Int{Value: int64(time.Until(t1))} ret = tengo.Int{Value: int64(time.Until(t1))}
return return
} }
@ -301,7 +301,7 @@ func timesDurationHours(args ...tengo.Object) (
return return
} }
ret = &tengo.Float{Value: time.Duration(i1).Hours()} ret = tengo.Float{Value: time.Duration(i1).Hours()}
return return
} }
@ -325,7 +325,7 @@ func timesDurationMinutes(args ...tengo.Object) (
return return
} }
ret = &tengo.Float{Value: time.Duration(i1).Minutes()} ret = tengo.Float{Value: time.Duration(i1).Minutes()}
return return
} }
@ -349,7 +349,7 @@ func timesDurationNanoseconds(args ...tengo.Object) (
return return
} }
ret = &tengo.Int{Value: time.Duration(i1).Nanoseconds()} ret = tengo.Int{Value: time.Duration(i1).Nanoseconds()}
return return
} }
@ -373,7 +373,7 @@ func timesDurationSeconds(args ...tengo.Object) (
return return
} }
ret = &tengo.Float{Value: time.Duration(i1).Seconds()} ret = tengo.Float{Value: time.Duration(i1).Seconds()}
return return
} }
@ -643,7 +643,7 @@ func timesSub(args ...tengo.Object) (ret tengo.Object, err error) {
return return
} }
ret = &tengo.Int{Value: int64(t1.Sub(t2))} ret = tengo.Int{Value: int64(t1.Sub(t2))}
return return
} }
@ -785,7 +785,7 @@ func timesTimeYear(args ...tengo.Object) (ret tengo.Object, err error) {
return return
} }
ret = &tengo.Int{Value: int64(t1.Year())} ret = tengo.Int{Value: int64(t1.Year())}
return return
} }
@ -806,7 +806,7 @@ func timesTimeMonth(args ...tengo.Object) (ret tengo.Object, err error) {
return return
} }
ret = &tengo.Int{Value: int64(t1.Month())} ret = tengo.Int{Value: int64(t1.Month())}
return return
} }
@ -827,7 +827,7 @@ func timesTimeDay(args ...tengo.Object) (ret tengo.Object, err error) {
return return
} }
ret = &tengo.Int{Value: int64(t1.Day())} ret = tengo.Int{Value: int64(t1.Day())}
return return
} }
@ -848,7 +848,7 @@ func timesTimeWeekday(args ...tengo.Object) (ret tengo.Object, err error) {
return return
} }
ret = &tengo.Int{Value: int64(t1.Weekday())} ret = tengo.Int{Value: int64(t1.Weekday())}
return return
} }
@ -869,7 +869,7 @@ func timesTimeHour(args ...tengo.Object) (ret tengo.Object, err error) {
return return
} }
ret = &tengo.Int{Value: int64(t1.Hour())} ret = tengo.Int{Value: int64(t1.Hour())}
return return
} }
@ -890,7 +890,7 @@ func timesTimeMinute(args ...tengo.Object) (ret tengo.Object, err error) {
return return
} }
ret = &tengo.Int{Value: int64(t1.Minute())} ret = tengo.Int{Value: int64(t1.Minute())}
return return
} }
@ -911,7 +911,7 @@ func timesTimeSecond(args ...tengo.Object) (ret tengo.Object, err error) {
return return
} }
ret = &tengo.Int{Value: int64(t1.Second())} ret = tengo.Int{Value: int64(t1.Second())}
return return
} }
@ -935,7 +935,7 @@ func timesTimeNanosecond(args ...tengo.Object) (
return return
} }
ret = &tengo.Int{Value: int64(t1.Nanosecond())} ret = tengo.Int{Value: int64(t1.Nanosecond())}
return return
} }
@ -956,7 +956,7 @@ func timesTimeUnix(args ...tengo.Object) (ret tengo.Object, err error) {
return return
} }
ret = &tengo.Int{Value: t1.Unix()} ret = tengo.Int{Value: t1.Unix()}
return return
} }
@ -980,7 +980,7 @@ func timesTimeUnixNano(args ...tengo.Object) (
return return
} }
ret = &tengo.Int{Value: t1.UnixNano()} ret = tengo.Int{Value: t1.UnixNano()}
return return
} }

View file

@ -16,10 +16,10 @@ func TestTimes(t *testing.T) {
require.True(t, module(t, "times"). require.True(t, module(t, "times").
call("since", time.Now().Add(-time.Hour)). call("since", time.Now().Add(-time.Hour)).
o.(*tengo.Int).Value > 3600000000000) o.(tengo.Int).Value > 3600000000000)
require.True(t, module(t, "times"). require.True(t, module(t, "times").
call("until", time.Now().Add(time.Hour)). call("until", time.Now().Add(time.Hour)).
o.(*tengo.Int).Value < 3600000000000) o.(tengo.Int).Value < 3600000000000)
module(t, "times").call("parse_duration", "1ns").expect(1) module(t, "times").call("parse_duration", "1ns").expect(1)
module(t, "times").call("parse_duration", "1ms").expect(1000000) module(t, "times").call("parse_duration", "1ms").expect(1000000)

View file

@ -79,16 +79,16 @@ func ToString(o Object) (v string, ok bool) {
// ToInt will try to convert object o to int value. // ToInt will try to convert object o to int value.
func ToInt(o Object) (v int, ok bool) { func ToInt(o Object) (v int, ok bool) {
switch o := o.(type) { switch o := o.(type) {
case *Int: case Int:
v = int(o.Value) v = int(o.Value)
ok = true ok = true
case *Float: case Float:
v = int(o.Value) v = int(o.Value)
ok = true ok = true
case *Char: case Char:
v = int(o.Value) v = int(o.Value)
ok = true ok = true
case *Bool: case Bool:
if o == TrueValue { if o == TrueValue {
v = 1 v = 1
} }
@ -106,16 +106,16 @@ func ToInt(o Object) (v int, ok bool) {
// ToInt64 will try to convert object o to int64 value. // ToInt64 will try to convert object o to int64 value.
func ToInt64(o Object) (v int64, ok bool) { func ToInt64(o Object) (v int64, ok bool) {
switch o := o.(type) { switch o := o.(type) {
case *Int: case Int:
v = o.Value v = o.Value
ok = true ok = true
case *Float: case Float:
v = int64(o.Value) v = int64(o.Value)
ok = true ok = true
case *Char: case Char:
v = int64(o.Value) v = int64(o.Value)
ok = true ok = true
case *Bool: case Bool:
if o == TrueValue { if o == TrueValue {
v = 1 v = 1
} }
@ -133,10 +133,10 @@ func ToInt64(o Object) (v int64, ok bool) {
// ToFloat64 will try to convert object o to float64 value. // ToFloat64 will try to convert object o to float64 value.
func ToFloat64(o Object) (v float64, ok bool) { func ToFloat64(o Object) (v float64, ok bool) {
switch o := o.(type) { switch o := o.(type) {
case *Int: case Int:
v = float64(o.Value) v = float64(o.Value)
ok = true ok = true
case *Float: case Float:
v = o.Value v = o.Value
ok = true ok = true
case *String: case *String:
@ -159,10 +159,10 @@ func ToBool(o Object) (v bool, ok bool) {
// ToRune will try to convert object o to rune value. // ToRune will try to convert object o to rune value.
func ToRune(o Object) (v rune, ok bool) { func ToRune(o Object) (v rune, ok bool) {
switch o := o.(type) { switch o := o.(type) {
case *Int: case Int:
v = rune(o.Value) v = rune(o.Value)
ok = true ok = true
case *Char: case Char:
v = o.Value v = o.Value
ok = true ok = true
} }
@ -188,7 +188,7 @@ func ToTime(o Object) (v time.Time, ok bool) {
case *Time: case *Time:
v = o.Value v = o.Value
ok = true ok = true
case *Int: case Int:
v = time.Unix(o.Value, 0) v = time.Unix(o.Value, 0)
ok = true ok = true
} }
@ -198,15 +198,15 @@ func ToTime(o Object) (v time.Time, ok bool) {
// ToInterface attempts to convert an object o to an interface{} value // ToInterface attempts to convert an object o to an interface{} value
func ToInterface(o Object) (res interface{}) { func ToInterface(o Object) (res interface{}) {
switch o := o.(type) { switch o := o.(type) {
case *Int: case Int:
res = o.Value res = o.Value
case *String: case *String:
res = o.Value res = o.Value
case *Float: case Float:
res = o.Value res = o.Value
case *Bool: case Bool:
res = o == TrueValue res = o == TrueValue
case *Char: case Char:
res = o.Value res = o.Value
case *Bytes: case *Bytes:
res = o.Value res = o.Value
@ -253,20 +253,20 @@ func FromInterface(v interface{}) (Object, error) {
} }
return &String{Value: v}, nil return &String{Value: v}, nil
case int64: case int64:
return &Int{Value: v}, nil return Int{Value: v}, nil
case int: case int:
return &Int{Value: int64(v)}, nil return Int{Value: int64(v)}, nil
case bool: case bool:
if v { if v {
return TrueValue, nil return TrueValue, nil
} }
return FalseValue, nil return FalseValue, nil
case rune: case rune:
return &Char{Value: v}, nil return Char{Value: v}, nil
case byte: case byte:
return &Char{Value: rune(v)}, nil return Char{Value: rune(v)}, nil
case float64: case float64:
return &Float{Value: v}, nil return Float{Value: v}, nil
case []byte: case []byte:
if len(v) > MaxBytesLen { if len(v) > MaxBytesLen {
return nil, ErrBytesLimit return nil, ErrBytesLimit

View file

@ -59,49 +59,49 @@ func TestMakeInstruction(t *testing.T) {
func TestNumObjects(t *testing.T) { func TestNumObjects(t *testing.T) {
testCountObjects(t, &tengo.Array{}, 1) testCountObjects(t, &tengo.Array{}, 1)
testCountObjects(t, &tengo.Array{Value: []tengo.Object{ testCountObjects(t, &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}, tengo.Int{Value: 2},
&tengo.Array{Value: []tengo.Object{ &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 3}, tengo.Int{Value: 3},
&tengo.Int{Value: 4}, tengo.Int{Value: 4},
&tengo.Int{Value: 5}, tengo.Int{Value: 5},
}}, }},
}}, 7) }}, 7)
testCountObjects(t, tengo.TrueValue, 1) testCountObjects(t, tengo.TrueValue, 1)
testCountObjects(t, tengo.FalseValue, 1) testCountObjects(t, tengo.FalseValue, 1)
testCountObjects(t, &tengo.BuiltinFunction{}, 1) testCountObjects(t, &tengo.BuiltinFunction{}, 1)
testCountObjects(t, &tengo.Bytes{Value: []byte("foobar")}, 1) testCountObjects(t, &tengo.Bytes{Value: []byte("foobar")}, 1)
testCountObjects(t, &tengo.Char{Value: '가'}, 1) testCountObjects(t, tengo.Char{Value: '가'}, 1)
testCountObjects(t, &tengo.CompiledFunction{}, 1) testCountObjects(t, &tengo.CompiledFunction{}, 1)
testCountObjects(t, &tengo.Error{Value: &tengo.Int{Value: 5}}, 2) testCountObjects(t, &tengo.Error{Value: tengo.Int{Value: 5}}, 2)
testCountObjects(t, &tengo.Float{Value: 19.84}, 1) testCountObjects(t, tengo.Float{Value: 19.84}, 1)
testCountObjects(t, &tengo.ImmutableArray{Value: []tengo.Object{ testCountObjects(t, &tengo.ImmutableArray{Value: []tengo.Object{
&tengo.Int{Value: 1}, tengo.Int{Value: 1},
&tengo.Int{Value: 2}, tengo.Int{Value: 2},
&tengo.ImmutableArray{Value: []tengo.Object{ &tengo.ImmutableArray{Value: []tengo.Object{
&tengo.Int{Value: 3}, tengo.Int{Value: 3},
&tengo.Int{Value: 4}, tengo.Int{Value: 4},
&tengo.Int{Value: 5}, tengo.Int{Value: 5},
}}, }},
}}, 7) }}, 7)
testCountObjects(t, &tengo.ImmutableMap{ testCountObjects(t, &tengo.ImmutableMap{
Value: map[string]tengo.Object{ Value: map[string]tengo.Object{
"k1": &tengo.Int{Value: 1}, "k1": tengo.Int{Value: 1},
"k2": &tengo.Int{Value: 2}, "k2": tengo.Int{Value: 2},
"k3": &tengo.Array{Value: []tengo.Object{ "k3": &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 3}, tengo.Int{Value: 3},
&tengo.Int{Value: 4}, tengo.Int{Value: 4},
&tengo.Int{Value: 5}, tengo.Int{Value: 5},
}}, }},
}}, 7) }}, 7)
testCountObjects(t, &tengo.Int{Value: 1984}, 1) testCountObjects(t, tengo.Int{Value: 1984}, 1)
testCountObjects(t, &tengo.Map{Value: map[string]tengo.Object{ testCountObjects(t, &tengo.Map{Value: map[string]tengo.Object{
"k1": &tengo.Int{Value: 1}, "k1": tengo.Int{Value: 1},
"k2": &tengo.Int{Value: 2}, "k2": tengo.Int{Value: 2},
"k3": &tengo.Array{Value: []tengo.Object{ "k3": &tengo.Array{Value: []tengo.Object{
&tengo.Int{Value: 3}, tengo.Int{Value: 3},
&tengo.Int{Value: 4}, tengo.Int{Value: 4},
&tengo.Int{Value: 5}, tengo.Int{Value: 5},
}}, }},
}}, 7) }}, 7)
testCountObjects(t, &tengo.String{Value: "foo bar"}, 1) testCountObjects(t, &tengo.String{Value: "foo bar"}, 1)

View file

@ -33,7 +33,7 @@ func TestVariable(t *testing.T) {
CharValue: rune(1), CharValue: rune(1),
BoolValue: true, BoolValue: true,
StringValue: "1", StringValue: "1",
Object: &tengo.Int{Value: 1}, Object: tengo.Int{Value: 1},
}, },
{ {
Name: "b", Name: "b",

27
vm.go
View file

@ -175,8 +175,8 @@ func (v *VM) run() {
v.sp-- v.sp--
switch x := operand.(type) { switch x := operand.(type) {
case *Int: case Int:
var res Object = &Int{Value: ^x.Value} var res Object = Int{Value: ^x.Value}
v.allocs-- v.allocs--
if v.allocs == 0 { if v.allocs == 0 {
v.err = ErrObjectAllocLimit v.err = ErrObjectAllocLimit
@ -194,8 +194,8 @@ func (v *VM) run() {
v.sp-- v.sp--
switch x := operand.(type) { switch x := operand.(type) {
case *Int: case Int:
var res Object = &Int{Value: -x.Value} var res Object = Int{Value: -x.Value}
v.allocs-- v.allocs--
if v.allocs == 0 { if v.allocs == 0 {
v.err = ErrObjectAllocLimit v.err = ErrObjectAllocLimit
@ -203,8 +203,8 @@ func (v *VM) run() {
} }
v.stack[v.sp] = res v.stack[v.sp] = res
v.sp++ v.sp++
case *Float: case Float:
var res Object = &Float{Value: -x.Value} var res Object = Float{Value: -x.Value}
v.allocs-- v.allocs--
if v.allocs == 0 { if v.allocs == 0 {
v.err = ErrObjectAllocLimit v.err = ErrObjectAllocLimit
@ -275,7 +275,7 @@ func (v *VM) run() {
v.ip += 2 v.ip += 2
numElements := int(v.curInsts[v.ip]) | int(v.curInsts[v.ip-1])<<8 numElements := int(v.curInsts[v.ip]) | int(v.curInsts[v.ip-1])<<8
var elements []Object elements := make([]Object, 0, numElements)
for i := v.sp - numElements; i < v.sp; i++ { for i := v.sp - numElements; i < v.sp; i++ {
elements = append(elements, v.stack[i]) elements = append(elements, v.stack[i])
} }
@ -376,7 +376,7 @@ func (v *VM) run() {
var lowIdx int64 var lowIdx int64
if low != UndefinedValue { if low != UndefinedValue {
if low, ok := low.(*Int); ok { if low, ok := low.(Int); ok {
lowIdx = low.Value lowIdx = low.Value
} else { } else {
v.err = fmt.Errorf("invalid slice index type: %s", v.err = fmt.Errorf("invalid slice index type: %s",
@ -391,7 +391,7 @@ func (v *VM) run() {
var highIdx int64 var highIdx int64
if high == UndefinedValue { if high == UndefinedValue {
highIdx = numElements highIdx = numElements
} else if high, ok := high.(*Int); ok { } else if high, ok := high.(Int); ok {
highIdx = high.Value highIdx = high.Value
} else { } else {
v.err = fmt.Errorf("invalid slice index type: %s", v.err = fmt.Errorf("invalid slice index type: %s",
@ -428,7 +428,7 @@ func (v *VM) run() {
var highIdx int64 var highIdx int64
if high == UndefinedValue { if high == UndefinedValue {
highIdx = numElements highIdx = numElements
} else if high, ok := high.(*Int); ok { } else if high, ok := high.(Int); ok {
highIdx = high.Value highIdx = high.Value
} else { } else {
v.err = fmt.Errorf("invalid slice index type: %s", v.err = fmt.Errorf("invalid slice index type: %s",
@ -465,7 +465,7 @@ func (v *VM) run() {
var highIdx int64 var highIdx int64
if high == UndefinedValue { if high == UndefinedValue {
highIdx = numElements highIdx = numElements
} else if high, ok := high.(*Int); ok { } else if high, ok := high.(Int); ok {
highIdx = high.Value highIdx = high.Value
} else { } else {
v.err = fmt.Errorf("invalid slice index type: %s", v.err = fmt.Errorf("invalid slice index type: %s",
@ -502,7 +502,7 @@ func (v *VM) run() {
var highIdx int64 var highIdx int64
if high == UndefinedValue { if high == UndefinedValue {
highIdx = numElements highIdx = numElements
} else if high, ok := high.(*Int); ok { } else if high, ok := high.(Int); ok {
highIdx = high.Value highIdx = high.Value
} else { } else {
v.err = fmt.Errorf("invalid slice index type: %s", v.err = fmt.Errorf("invalid slice index type: %s",
@ -628,8 +628,7 @@ func (v *VM) run() {
v.framesIndex++ v.framesIndex++
v.sp = v.sp - numArgs + callee.NumLocals v.sp = v.sp - numArgs + callee.NumLocals
} else { } else {
var args []Object args := v.stack[v.sp-numArgs : v.sp]
args = append(args, v.stack[v.sp-numArgs:v.sp]...)
ret, e := value.Call(args...) ret, e := value.Call(args...)
v.sp -= numArgs + 1 v.sp -= numArgs + 1

View file

@ -5,7 +5,6 @@ import (
"fmt" "fmt"
"math" "math"
"math/rand" "math/rand"
"reflect"
_runtime "runtime" _runtime "runtime"
"strings" "strings"
"testing" "testing"
@ -2094,7 +2093,7 @@ func TestIncDec(t *testing.T) {
} }
type StringDict struct { type StringDict struct {
tengo.ObjectImpl tengo.PtrObjectImpl
Value map[string]string Value map[string]string
} }
@ -2136,7 +2135,7 @@ func (o *StringDict) IndexSet(index, value tengo.Object) error {
} }
type StringCircle struct { type StringCircle struct {
tengo.ObjectImpl tengo.PtrObjectImpl
Value []string Value []string
} }
@ -2149,7 +2148,7 @@ func (o *StringCircle) String() string {
} }
func (o *StringCircle) IndexGet(index tengo.Object) (tengo.Object, error) { func (o *StringCircle) IndexGet(index tengo.Object) (tengo.Object, error) {
intIdx, ok := index.(*tengo.Int) intIdx, ok := index.(tengo.Int)
if !ok { if !ok {
return nil, tengo.ErrInvalidIndexType return nil, tengo.ErrInvalidIndexType
} }
@ -2163,7 +2162,7 @@ func (o *StringCircle) IndexGet(index tengo.Object) (tengo.Object, error) {
} }
func (o *StringCircle) IndexSet(index, value tengo.Object) error { func (o *StringCircle) IndexSet(index, value tengo.Object) error {
intIdx, ok := index.(*tengo.Int) intIdx, ok := index.(tengo.Int)
if !ok { if !ok {
return tengo.ErrInvalidIndexType return tengo.ErrInvalidIndexType
} }
@ -2184,7 +2183,7 @@ func (o *StringCircle) IndexSet(index, value tengo.Object) error {
} }
type StringArray struct { type StringArray struct {
tengo.ObjectImpl tengo.PtrObjectImpl
Value []string Value []string
} }
@ -2242,7 +2241,7 @@ func (o *StringArray) TypeName() string {
} }
func (o *StringArray) IndexGet(index tengo.Object) (tengo.Object, error) { func (o *StringArray) IndexGet(index tengo.Object) (tengo.Object, error) {
intIdx, ok := index.(*tengo.Int) intIdx, ok := index.(tengo.Int)
if ok { if ok {
if intIdx.Value >= 0 && intIdx.Value < int64(len(o.Value)) { if intIdx.Value >= 0 && intIdx.Value < int64(len(o.Value)) {
return &tengo.String{Value: o.Value[intIdx.Value]}, nil return &tengo.String{Value: o.Value[intIdx.Value]}, nil
@ -2255,7 +2254,7 @@ func (o *StringArray) IndexGet(index tengo.Object) (tengo.Object, error) {
if ok { if ok {
for vidx, str := range o.Value { for vidx, str := range o.Value {
if strIdx.Value == str { if strIdx.Value == str {
return &tengo.Int{Value: int64(vidx)}, nil return tengo.Int{Value: int64(vidx)}, nil
} }
} }
@ -2271,7 +2270,7 @@ func (o *StringArray) IndexSet(index, value tengo.Object) error {
return tengo.ErrInvalidIndexValueType return tengo.ErrInvalidIndexValueType
} }
intIdx, ok := index.(*tengo.Int) intIdx, ok := index.(tengo.Int)
if ok { if ok {
if intIdx.Value >= 0 && intIdx.Value < int64(len(o.Value)) { if intIdx.Value >= 0 && intIdx.Value < int64(len(o.Value)) {
o.Value[intIdx.Value] = strVal o.Value[intIdx.Value] = strVal
@ -2302,7 +2301,7 @@ func (o *StringArray) Call(
for i, v := range o.Value { for i, v := range o.Value {
if v == s1 { if v == s1 {
return &tengo.Int{Value: int64(i)}, nil return tengo.Int{Value: int64(i)}, nil
} }
} }
@ -2423,7 +2422,7 @@ func TestInteger(t *testing.T) {
} }
type StringArrayIterator struct { type StringArrayIterator struct {
tengo.ObjectImpl tengo.PtrObjectImpl
strArr *StringArray strArr *StringArray
idx int idx int
} }
@ -2442,7 +2441,7 @@ func (i *StringArrayIterator) Next() bool {
} }
func (i *StringArrayIterator) Key() tengo.Object { func (i *StringArrayIterator) Key() tengo.Object {
return &tengo.Int{Value: int64(i.idx - 1)} return tengo.Int{Value: int64(i.idx - 1)}
} }
func (i *StringArrayIterator) Value() tengo.Object { func (i *StringArrayIterator) Value() tengo.Object {
@ -2573,7 +2572,7 @@ func TestBuiltin(t *testing.T) {
Name: "abs", Name: "abs",
Value: func(a ...tengo.Object) (tengo.Object, error) { Value: func(a ...tengo.Object) (tengo.Object, error) {
v, _ := tengo.ToFloat64(a[0]) v, _ := tengo.ToFloat64(a[0])
return &tengo.Float{Value: math.Abs(v)}, nil return tengo.Float{Value: math.Abs(v)}, nil
}, },
}, },
}, },
@ -2779,7 +2778,7 @@ func TestModuleBlockScopes(t *testing.T) {
Name: "abs", Name: "abs",
Value: func(a ...tengo.Object) (tengo.Object, error) { Value: func(a ...tengo.Object) (tengo.Object, error) {
v, _ := tengo.ToInt64(a[0]) v, _ := tengo.ToInt64(a[0])
return &tengo.Int{Value: rand.Int63n(v)}, nil return tengo.Int{Value: rand.Int63n(v)}, nil
}, },
}, },
}, },
@ -3873,7 +3872,7 @@ func formatGlobals(globals []tengo.Object) (formatted []string) {
return return
} }
formatted = append(formatted, fmt.Sprintf("[% 3d] %s (%s|%p)", formatted = append(formatted, fmt.Sprintf("[% 3d] %s (%s|%p)",
idx, global.String(), reflect.TypeOf(global).Elem().Name(), global)) idx, global.String(), global.TypeName(), global))
} }
return return
} }
@ -3899,20 +3898,20 @@ func toObject(v interface{}) tengo.Object {
case string: case string:
return &tengo.String{Value: v} return &tengo.String{Value: v}
case int64: case int64:
return &tengo.Int{Value: v} return tengo.Int{Value: v}
case int: // for convenience case int: // for convenience
return &tengo.Int{Value: int64(v)} return tengo.Int{Value: int64(v)}
case bool: case bool:
if v { if v {
return tengo.TrueValue return tengo.TrueValue
} }
return tengo.FalseValue return tengo.FalseValue
case rune: case rune:
return &tengo.Char{Value: v} return tengo.Char{Value: v}
case byte: // for convenience case byte: // for convenience
return &tengo.Char{Value: rune(v)} return tengo.Char{Value: rune(v)}
case float64: case float64:
return &tengo.Float{Value: v} return tengo.Float{Value: v}
case []byte: case []byte:
return &tengo.Bytes{Value: v} return &tengo.Bytes{Value: v}
case MAP: case MAP:
@ -3950,14 +3949,14 @@ func toObject(v interface{}) tengo.Object {
func objectZeroCopy(o tengo.Object) tengo.Object { func objectZeroCopy(o tengo.Object) tengo.Object {
switch o.(type) { switch o.(type) {
case *tengo.Int: case tengo.Int:
return &tengo.Int{} return tengo.Int{}
case *tengo.Float: case tengo.Float:
return &tengo.Float{} return tengo.Float{}
case *tengo.Bool: case tengo.Bool:
return &tengo.Bool{} return tengo.Bool{}
case *tengo.Char: case tengo.Char:
return &tengo.Char{} return tengo.Char{}
case *tengo.String: case *tengo.String:
return &tengo.String{} return &tengo.String{}
case *tengo.Array: case *tengo.Array: