Skip to content

Commit

Permalink
some methods of array are mutable
Browse files Browse the repository at this point in the history
  • Loading branch information
gravataLonga committed Jul 1, 2022
1 parent 0a41d36 commit 6257940
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 23 deletions.
44 changes: 44 additions & 0 deletions evaluator/array_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,14 @@ func TestArrayMethod(t *testing.T) {
`[1, true, 1.1, "hello", function() {return 1;}()].join(",")`,
`[1,true,1.1,hello,1]`,
},
{
`var a = [1, 2]; a.join(";");`,
`[1;2]`,
},
{
`var a = [1, 2]; a.join(";"); a`,
object.Array{Elements: []object.Object{&object.Integer{Value: 1}, &object.Integer{Value: 2}}},
},
{
`[1].push(2)`,
object.Array{Elements: []object.Object{&object.Integer{Value: 1}, &object.Integer{Value: 2}}},
Expand All @@ -228,6 +236,18 @@ func TestArrayMethod(t *testing.T) {
`[1].push(2, 3)`,
object.Array{Elements: []object.Object{&object.Integer{Value: 1}, &object.Integer{Value: 2}, &object.Integer{Value: 3}}},
},
{
`var a = [1]; a.push(2, 3); a`,
object.Array{Elements: []object.Object{&object.Integer{Value: 1}, &object.Integer{Value: 2}, &object.Integer{Value: 3}}},
},
{
`var a = [1, 2]; a.pop(); a;`,
object.Array{Elements: []object.Object{&object.Integer{Value: 1}}},
},
{
`var a = [1, 2]; a.pop();`,
2,
},
{
`[1, 2].pop()`,
2,
Expand All @@ -240,6 +260,14 @@ func TestArrayMethod(t *testing.T) {
`[1, 2].shift()`,
1,
},
{
`var a = [1, 2]; a.shift()`,
1,
},
{
`var a = [1, 2]; a.shift(); a`,
object.Array{Elements: []object.Object{&object.Integer{Value: 2}}},
},
{
`[].shift()`,
nil,
Expand All @@ -248,18 +276,34 @@ func TestArrayMethod(t *testing.T) {
`[1, 2, 3].slice(1)`,
object.Array{Elements: []object.Object{&object.Integer{Value: 2}, &object.Integer{Value: 3}}},
},
{
`var a = [1, 2, 3]; a.slice(1)`,
object.Array{Elements: []object.Object{&object.Integer{Value: 2}, &object.Integer{Value: 3}}},
},
{
`[1, 2, 3].slice(4)`,
object.Array{Elements: []object.Object{}},
},
{
`var a = [1, 2, 3]; a.slice(4)`,
object.Array{Elements: []object.Object{}},
},
{
`[1, 2, 3].slice(1, 1)`,
object.Array{Elements: []object.Object{&object.Integer{Value: 2}}},
},
{
`var a = [1, 2, 3]; a.slice(1, 1)`,
object.Array{Elements: []object.Object{&object.Integer{Value: 2}}},
},
{
`[1, 2, 3].slice(1, 2)`,
object.Array{Elements: []object.Object{&object.Integer{Value: 2}, &object.Integer{Value: 3}}},
},
{
`var a = [1, 2, 3]; a.slice(1, 2)`,
object.Array{Elements: []object.Object{&object.Integer{Value: 2}, &object.Integer{Value: 3}}},
},
}

for _, tt := range tests {
Expand Down
8 changes: 6 additions & 2 deletions evaluator/integer_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package evaluator

import (
"fmt"
"ninja/object"
"testing"
)
Expand Down Expand Up @@ -119,9 +120,12 @@ func TestIntegerMethod(t *testing.T) {
}

for _, tt := range tests {
evaluated := testEval(tt.input, t)
t.Run(fmt.Sprintf("TestIntegerMethod_%s", tt.input), func(t *testing.T) {
evaluated := testEval(tt.input, t)

testObjectLiteral(t, evaluated, tt.expected)
})

testObjectLiteral(t, evaluated, tt.expected)
}
}

Expand Down
2 changes: 1 addition & 1 deletion evaluator/object_call.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,5 @@ func evalObjectCallExpression(node *ast.ObjectCall, env *object.Environment) obj
return args[0]
}

return callable.Call(method.Value, args...)
return callable.Call(node, method.Value, env, args...)
}
47 changes: 34 additions & 13 deletions object/array.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package object

import (
"bytes"
"ninja/ast"
"strconv"
"strings"
)
Expand All @@ -23,7 +24,7 @@ func (ao *Array) Inspect() string {
return out.String()
}

func (s *Array) Call(method string, args ...Object) Object {
func (s *Array) Call(objectCall *ast.ObjectCall, method string, env *Environment, args ...Object) Object {
switch method {
case "type":
if len(args) > 0 {
Expand All @@ -34,11 +35,30 @@ func (s *Array) Call(method string, args ...Object) Object {
case "join":
return arrayJoin(s.Elements, args...)
case "push":
return arrayPush(s.Elements, args...)
result := arrayPush(s.Elements, args...)

ident, ok := objectCall.Object.(*ast.Identifier)
if ok {
env.Set(ident.Value, result)
}

return result
case "pop":
return arrayPop(s.Elements, args...)
popValue, newArray := arrayPop(s.Elements, args...)

ident, ok := objectCall.Object.(*ast.Identifier)
if ok {
env.Set(ident.Value, newArray)
}
return popValue
case "shift":
return arrayShift(s.Elements, args...)
shiftValue, newArray := arrayShift(s.Elements, args...)

ident, ok := objectCall.Object.(*ast.Identifier)
if ok {
env.Set(ident.Value, newArray)
}
return shiftValue
case "slice":
return arraySlice(s.Elements, args...)
}
Expand Down Expand Up @@ -79,7 +99,7 @@ func arrayJoin(elements []Object, args ...Object) Object {
}
case *Array:
v, _ := el.(*Array)
joinObject := v.Call("join", args...)
joinObject := v.Call(nil, "join", nil, args...)
strJoinObject, ok := joinObject.(*String)
if !ok {
return NewErrorFormat("Unable to join array")
Expand Down Expand Up @@ -112,26 +132,27 @@ func arrayPush(elements []Object, args ...Object) Object {
return arr
}

func arrayPop(elements []Object, args ...Object) Object {
func arrayPop(elements []Object, args ...Object) (popValue Object, newArray Object) {
if len(args) > 0 {
return NewErrorFormat("array.pop expect exactly 0 argument. Got: %d", len(args))
return NewErrorFormat("array.pop expect exactly 0 argument. Got: %d", len(args)), nil
}

if len(elements) <= 0 {
return NULL
return NULL, &Array{}
}
return elements[len(elements)-1]

return elements[len(elements)-1], &Array{Elements: elements[0 : len(elements)-1]}
}

func arrayShift(elements []Object, args ...Object) Object {
func arrayShift(elements []Object, args ...Object) (shiftValue Object, newArray Object) {
if len(args) > 0 {
return NewErrorFormat("array.shift expect exactly 0 argument. Got: %d", len(args))
return NewErrorFormat("array.shift expect exactly 0 argument. Got: %d", len(args)), nil
}

if len(elements) <= 0 {
return NULL
return NULL, &Array{}
}
return elements[0]
return elements[0], &Array{Elements: elements[1:]}
}

func arraySlice(elements []Object, args ...Object) Object {
Expand Down
7 changes: 5 additions & 2 deletions object/boolean.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package object

import "fmt"
import (
"fmt"
"ninja/ast"
)

var (
TRUE = &Boolean{Value: true}
Expand All @@ -24,7 +27,7 @@ func (b *Boolean) HashKey() HashKey {
return HashKey{Type: b.Type(), Value: value}
}

func (s *Boolean) Call(method string, args ...Object) Object {
func (s *Boolean) Call(objectCall *ast.ObjectCall, method string, env *Environment, args ...Object) Object {
switch method {
case "type":
if len(args) > 0 {
Expand Down
3 changes: 2 additions & 1 deletion object/float.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"hash/fnv"
"math"
"ninja/ast"
"strconv"
)

Expand All @@ -28,7 +29,7 @@ func (f *Float) HashKey() HashKey {
return HashKey{Type: f.Type(), Value: f.hashKeyCache}
}

func (f *Float) Call(method string, args ...Object) Object {
func (f *Float) Call(objectCall *ast.ObjectCall, method string, env *Environment, args ...Object) Object {
switch method {
case "type":
if len(args) > 0 {
Expand Down
3 changes: 2 additions & 1 deletion object/hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package object
import (
"bytes"
"fmt"
"ninja/ast"
"strings"
)

Expand Down Expand Up @@ -32,7 +33,7 @@ func (h *Hash) Inspect() string {
return out.String()
}

func (s *Hash) Call(method string, args ...Object) Object {
func (s *Hash) Call(objectCall *ast.ObjectCall, method string, env *Environment, args ...Object) Object {
switch method {
case "type":
if len(args) > 0 {
Expand Down
3 changes: 2 additions & 1 deletion object/int.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package object

import (
"fmt"
"ninja/ast"
"strconv"
)

Expand All @@ -16,7 +17,7 @@ func (i *Integer) HashKey() HashKey {
return HashKey{Type: i.Type(), Value: uint64(i.Value)}
}

func (s *Integer) Call(method string, args ...Object) Object {
func (s *Integer) Call(objectCall *ast.ObjectCall, method string, env *Environment, args ...Object) Object {
switch method {
case "type":
if len(args) > 0 {
Expand Down
3 changes: 2 additions & 1 deletion object/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package object

import (
"bytes"
"ninja/ast"
"strings"
)

Expand All @@ -14,7 +15,7 @@ type Object interface {

// CallableMethod is use for calling method in data type.
type CallableMethod interface {
Call(method string, args ...Object) Object
Call(objectCall *ast.ObjectCall, method string, env *Environment, args ...Object) Object
}

// HashKey hold "key" on Hash
Expand Down
3 changes: 2 additions & 1 deletion object/string.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package object

import (
"hash/fnv"
"ninja/ast"
"strconv"
"strings"
)
Expand All @@ -24,7 +25,7 @@ func (s *String) HashKey() HashKey {
return HashKey{Type: s.Type(), Value: s.hashKeyCached}
}

func (s *String) Call(method string, args ...Object) Object {
func (s *String) Call(objectCall *ast.ObjectCall, method string, env *Environment, args ...Object) Object {
switch method {
case "type":
if len(args) > 0 {
Expand Down

0 comments on commit 6257940

Please sign in to comment.