Add tons of builtin helpers and array operations.
This commit is contained in:
29
vm/vm.go
29
vm/vm.go
@@ -527,8 +527,29 @@ func (vm *VM) executeBinaryOperation(op code.Opcode) error {
|
||||
|
||||
switch {
|
||||
|
||||
// {"a": 1} + {"b": 2}
|
||||
case op == code.OpAdd && left.Type() == object.HASH_OBJ && right.Type() == object.HASH_OBJ:
|
||||
leftVal := left.(*object.Hash).Pairs
|
||||
rightVal := right.(*object.Hash).Pairs
|
||||
pairs := make(map[object.HashKey]object.HashPair)
|
||||
for k, v := range leftVal {
|
||||
pairs[k] = v
|
||||
}
|
||||
for k, v := range rightVal {
|
||||
pairs[k] = v
|
||||
}
|
||||
return vm.push(&object.Hash{Pairs: pairs})
|
||||
|
||||
// [1] + [2]
|
||||
case op == code.OpAdd && left.Type() == object.ARRAY_OBJ && right.Type() == object.ARRAY_OBJ:
|
||||
leftVal := left.(*object.Array).Elements
|
||||
rightVal := right.(*object.Array).Elements
|
||||
elements := make([]object.Object, len(leftVal)+len(rightVal))
|
||||
elements = append(leftVal, rightVal...)
|
||||
return vm.push(&object.Array{Elements: elements})
|
||||
|
||||
// [1] * 3
|
||||
case left.Type() == object.ARRAY_OBJ && right.Type() == object.INTEGER_OBJ:
|
||||
case op == code.OpMul && left.Type() == object.ARRAY_OBJ && right.Type() == object.INTEGER_OBJ:
|
||||
leftVal := left.(*object.Array).Elements
|
||||
rightVal := int(right.(*object.Integer).Value)
|
||||
elements := leftVal
|
||||
@@ -537,7 +558,7 @@ func (vm *VM) executeBinaryOperation(op code.Opcode) error {
|
||||
}
|
||||
return vm.push(&object.Array{Elements: elements})
|
||||
// 3 * [1]
|
||||
case left.Type() == object.INTEGER_OBJ && right.Type() == object.ARRAY_OBJ:
|
||||
case op == code.OpMul && left.Type() == object.INTEGER_OBJ && right.Type() == object.ARRAY_OBJ:
|
||||
leftVal := int(left.(*object.Integer).Value)
|
||||
rightVal := right.(*object.Array).Elements
|
||||
elements := rightVal
|
||||
@@ -547,12 +568,12 @@ func (vm *VM) executeBinaryOperation(op code.Opcode) error {
|
||||
return vm.push(&object.Array{Elements: elements})
|
||||
|
||||
// " " * 4
|
||||
case left.Type() == object.STRING_OBJ && right.Type() == object.INTEGER_OBJ:
|
||||
case op == code.OpMul && left.Type() == object.STRING_OBJ && right.Type() == object.INTEGER_OBJ:
|
||||
leftVal := left.(*object.String).Value
|
||||
rightVal := right.(*object.Integer).Value
|
||||
return vm.push(&object.String{Value: strings.Repeat(leftVal, int(rightVal))})
|
||||
// 4 * " "
|
||||
case left.Type() == object.INTEGER_OBJ && right.Type() == object.STRING_OBJ:
|
||||
case op == code.OpMul && left.Type() == object.INTEGER_OBJ && right.Type() == object.STRING_OBJ:
|
||||
leftVal := left.(*object.Integer).Value
|
||||
rightVal := right.(*object.String).Value
|
||||
return vm.push(&object.String{Value: strings.Repeat(rightVal, int(leftVal))})
|
||||
|
||||
@@ -354,6 +354,16 @@ func TestArrayDuplication(t *testing.T) {
|
||||
runVmTests(t, tests)
|
||||
}
|
||||
|
||||
func TestArrayMerging(t *testing.T) {
|
||||
tests := []vmTestCase{
|
||||
{"[] + [1]", []int{1}},
|
||||
{"[1] + [2]", []int{1, 2}},
|
||||
{"[1, 2] + [3, 4]", []int{1, 2, 3, 4}},
|
||||
}
|
||||
|
||||
runVmTests(t, tests)
|
||||
}
|
||||
|
||||
func TestHashLiterals(t *testing.T) {
|
||||
tests := []vmTestCase{
|
||||
{
|
||||
@@ -378,6 +388,26 @@ func TestHashLiterals(t *testing.T) {
|
||||
runVmTests(t, tests)
|
||||
}
|
||||
|
||||
func TestHashMerging(t *testing.T) {
|
||||
tests := []vmTestCase{
|
||||
{
|
||||
`{} + {"a": 1}`,
|
||||
map[object.HashKey]int64{
|
||||
(&object.String{Value: "a"}).HashKey(): 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
`{"a": 1} + {"b": 2}`,
|
||||
map[object.HashKey]int64{
|
||||
(&object.String{Value: "a"}).HashKey(): 1,
|
||||
(&object.String{Value: "b"}).HashKey(): 2,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
runVmTests(t, tests)
|
||||
}
|
||||
|
||||
func TestSelectorExpressions(t *testing.T) {
|
||||
tests := []vmTestCase{
|
||||
{`{"foo": 5}.foo`, 5},
|
||||
@@ -677,7 +707,7 @@ func TestBuiltinFunctions(t *testing.T) {
|
||||
{
|
||||
`len(1)`,
|
||||
&object.Error{
|
||||
Message: "argument to `len` not supported, got INTEGER",
|
||||
Message: "argument to `len` not supported, got int",
|
||||
},
|
||||
},
|
||||
{`len("one", "two")`,
|
||||
@@ -692,14 +722,14 @@ func TestBuiltinFunctions(t *testing.T) {
|
||||
{`first([])`, Null},
|
||||
{`first(1)`,
|
||||
&object.Error{
|
||||
Message: "argument to `first` must be ARRAY, got INTEGER",
|
||||
Message: "argument to `first` must be array, got int",
|
||||
},
|
||||
},
|
||||
{`last([1, 2, 3])`, 3},
|
||||
{`last([])`, Null},
|
||||
{`last(1)`,
|
||||
&object.Error{
|
||||
Message: "argument to `last` must be ARRAY, got INTEGER",
|
||||
Message: "argument to `last` must be array, got int",
|
||||
},
|
||||
},
|
||||
{`rest([1, 2, 3])`, []int{2, 3}},
|
||||
@@ -707,7 +737,7 @@ func TestBuiltinFunctions(t *testing.T) {
|
||||
{`push([], 1)`, []int{1}},
|
||||
{`push(1, 1)`,
|
||||
&object.Error{
|
||||
Message: "argument to `push` must be ARRAY, got INTEGER",
|
||||
Message: "argument to `push` must be array, got int",
|
||||
},
|
||||
},
|
||||
{`input()`, ""},
|
||||
|
||||
Reference in New Issue
Block a user