diff --git a/internal/builtins/len.go b/internal/builtins/len.go index 65fd41a..89a4215 100644 --- a/internal/builtins/len.go +++ b/internal/builtins/len.go @@ -14,8 +14,14 @@ func Len(args ...object.Object) object.Object { return newError(err.Error()) } - if size, ok := args[0].(object.Sizeable); ok { - return object.Integer{Value: int64(size.Len())} + switch obj := args[0].(type) { + case object.String: + return object.Integer{Value: int64(obj.Len())} + case *object.Array: + return object.Integer{Value: int64(obj.Len())} + case *object.Hash: + return object.Integer{Value: int64(obj.Len())} + default: + return newError("TypeError: object of type '%s' has no len()", args[0].Type()) } - return newError("TypeError: object of type '%s' has no len()", args[0].Type()) } diff --git a/internal/object/array.go b/internal/object/array.go index e8c24e1..9d7ad92 100644 --- a/internal/object/array.go +++ b/internal/object/array.go @@ -70,31 +70,33 @@ func (ao *Array) Less(i, j int) bool { return false } -func (ao *Array) Add(other Object) (Object, error) { - if other.Type() != ao.Type() { - return nil, NewBinaryOpError(ao, other, "+") +func (a *Array) Add(other Object) (Object, error) { + switch obj := other.(type) { + case *Array: + var elements []Object + elements = append(elements, a.Elements...) + elements = append(elements, obj.Elements...) + + return &Array{Elements: elements}, nil + default: + return nil, NewBinaryOpError(a, other, "+") } - - var elements []Object - elements = append(elements, ao.Elements...) - elements = append(elements, other.(*Array).Elements...) - - return &Array{Elements: elements}, nil - } -func (ao *Array) Mul(other Object) (Object, error) { - if other.Type() != IntegerType { - return nil, NewBinaryOpError(ao, other, "*") +func (a *Array) Mul(other Object) (Object, error) { + switch obj := other.(type) { + case Integer: + var elements []Object + N := int(obj.Value) + for i := 0; i < N; i++ { + elements = append(elements, a.Elements...) + } + + return &Array{Elements: elements}, nil + default: + return nil, NewBinaryOpError(a, other, "*") } - var elements []Object - N := int(other.(Integer).Value) - for i := 0; i < N; i++ { - elements = append(elements, ao.Elements...) - } - - return &Array{Elements: elements}, nil } func (ao *Array) Get(index Object) (Object, error) { diff --git a/internal/object/int.go b/internal/object/int.go index 291c188..2720028 100644 --- a/internal/object/int.go +++ b/internal/object/int.go @@ -45,51 +45,61 @@ func (i Integer) Sub(other Object) (Object, error) { } func (i Integer) Mul(other Object) (Object, error) { - switch other.Type() { - case IntegerType: - return Integer{i.Value * other.(Integer).Value}, nil - case StringType: - return other.(Mul).Mul(i) - case ArrayType: - return other.(Mul).Mul(i) + switch obj := other.(type) { + case Integer: + return Integer{i.Value * obj.Value}, nil + case String: + return obj.Mul(i) + case *Array: + return obj.Mul(i) default: return nil, NewBinaryOpError(i, other, "*") } } func (i Integer) Div(other Object) (Object, error) { - if !AssertTypes(other, IntegerType) { + switch obj := other.(type) { + case Integer: + return Integer{i.Value / obj.Value}, nil + default: return nil, NewBinaryOpError(i, other, "/") } - return Integer{i.Value / other.(Integer).Value}, nil } func (i Integer) Mod(other Object) (Object, error) { - if !AssertTypes(other, IntegerType) { + switch obj := other.(type) { + case Integer: + return Integer{i.Value % obj.Value}, nil + default: return nil, NewBinaryOpError(i, other, "%") } - return Integer{i.Value % other.(Integer).Value}, nil } func (i Integer) BitwiseOr(other Object) (Object, error) { - if !AssertTypes(other, IntegerType) { + switch obj := other.(type) { + case Integer: + return Integer{i.Value | obj.Value}, nil + default: return nil, NewBinaryOpError(i, other, "|") } - return Integer{i.Value | other.(Integer).Value}, nil } func (i Integer) BitwiseXor(other Object) (Object, error) { - if !AssertTypes(other, IntegerType) { + switch obj := other.(type) { + case Integer: + return Integer{i.Value ^ obj.Value}, nil + default: return nil, NewBinaryOpError(i, other, "^") } - return Integer{i.Value ^ other.(Integer).Value}, nil } func (i Integer) BitwiseAnd(other Object) (Object, error) { - if !AssertTypes(other, IntegerType) { + switch obj := other.(type) { + case Integer: + return Integer{i.Value & obj.Value}, nil + default: return nil, NewBinaryOpError(i, other, "") } - return Integer{i.Value & other.(Integer).Value}, nil } func (i Integer) BitwiseNot() Object { @@ -97,17 +107,21 @@ func (i Integer) BitwiseNot() Object { } func (i Integer) LeftShift(other Object) (Object, error) { - if !AssertTypes(other, IntegerType) { + switch obj := other.(type) { + case Integer: + return Integer{i.Value << obj.Value}, nil + default: return nil, NewBinaryOpError(i, other, "<<") } - return Integer{i.Value << other.(Integer).Value}, nil } func (i Integer) RightShift(other Object) (Object, error) { - if !AssertTypes(other, IntegerType) { + switch obj := other.(type) { + case Integer: + return Integer{i.Value >> obj.Value}, nil + default: return nil, NewBinaryOpError(i, other, ">>") } - return Integer{i.Value >> other.(Integer).Value}, nil } func (i Integer) LogicalNot() Object { diff --git a/internal/object/object.go b/internal/object/object.go index 3208106..1ee0abb 100644 --- a/internal/object/object.go +++ b/internal/object/object.go @@ -54,91 +54,6 @@ func (t Type) String() string { } } -// Add is the interface for binary addition -type Add interface { - Add(other Object) (Object, error) -} - -// Sub is the interface for binary subtraction -type Sub interface { - Sub(other Object) (Object, error) -} - -// Mul is the interface for binary multiplication -type Mul interface { - Mul(other Object) (Object, error) -} - -// Div is the interface for binary division -type Div interface { - Div(other Object) (Object, error) -} - -// Mod is the interface for binary modulo -type Mod interface { - Mod(other Object) (Object, error) -} - -// LogicalOr is the interface for logical or -type LogicalOr interface { - LogicalOr(other Object) (Object, error) -} - -// LogicalAnd is the interface for logical and -type LogicalAnd interface { - LogicalAnd(other Object) (Object, error) -} - -// BitwiseOr is the interface for bitwise or -type BitwiseOr interface { - BitwiseOr(other Object) (Object, error) -} - -// BitwiseAnd is the interface for bitwise and -type BitwiseAnd interface { - BitwiseAnd(other Object) (Object, error) -} - -// BitwiseXor is the interface for bitwise xor -type BitwiseXor interface { - BitwiseXor(other Object) (Object, error) -} - -// BitwiseNot is the interface for bitwise not -type BitwiseNot interface { - BitwiseNot() Object -} - -// LeftShift is the interface for bitwise left shift -type LeftShift interface { - LeftShift(other Object) (Object, error) -} - -// RightShift is the interface for bitwise right shift -type RightShift interface { - RightShift(other Object) (Object, error) -} - -// LogicalNot is the interface for logical not -type LogicalNot interface { - LogicalNot() Object -} - -// Negate is the interface for unary negation -type Negate interface { - Negate() Object -} - -// Setter is the interface for assigning a value to an index -type Setter interface { - Set(index, value Object) error -} - -// Getter is the interface for getting a value from an index -type Getter interface { - Get(index Object) (Object, error) -} - // Comparable is the interface for comparing two Object and their underlying // values. It is the responsibility of the caller (left) to check for types. // Returns `true` iif the types and values are identical, `false` otherwise. @@ -146,13 +61,6 @@ type Comparable interface { Compare(other Object) int } -// Sizeable is the interface for returning the size of an Object. -// Object(s) that have a valid size must implement this interface and the -// Len() method. -type Sizeable interface { - Len() int -} - // Immutable is the interface for all immutable objects which must implement // the Clone() method used by binding names to values. type Immutable interface { diff --git a/internal/object/str.go b/internal/object/str.go index 6809e82..1faccca 100644 --- a/internal/object/str.go +++ b/internal/object/str.go @@ -35,17 +35,21 @@ func (s String) String() string { } func (s String) Add(other Object) (Object, error) { - if !AssertTypes(other, StringType) { + switch obj := other.(type) { + case String: + return String{s.Value + obj.Value}, nil + default: return nil, NewBinaryOpError(s, other, "+") } - return String{s.Value + other.(String).Value}, nil } func (s String) Mul(other Object) (Object, error) { - if !AssertTypes(other, IntegerType) { + switch obj := other.(type) { + case Integer: + return String{strings.Repeat(s.Value, int(obj.Value))}, nil + default: return nil, NewBinaryOpError(s, other, "*") } - return String{strings.Repeat(s.Value, int(other.(Integer).Value))}, nil } func (s String) Get(index Object) (Object, error) { diff --git a/internal/vm/vm.go b/internal/vm/vm.go index 9ba86ee..bea2809 100644 --- a/internal/vm/vm.go +++ b/internal/vm/vm.go @@ -206,29 +206,6 @@ func (vm *VM) pop() object.Object { return o } -func (vm *VM) executeLoadBuiltin() error { - builtinIndex := vm.currentFrame().ReadUint8() - builtin := builtins.BuiltinsIndex[builtinIndex] - return vm.push(builtin) -} - -func (vm *VM) executeConstant() error { - constIndex := vm.currentFrame().ReadUint16() - return vm.push(vm.state.Constants[constIndex]) -} - -func (vm *VM) executeAssignGlobal() error { - globalIndex := vm.currentFrame().ReadUint16() - vm.state.Globals[globalIndex] = vm.pop() - return vm.push(object.NULL) -} - -func (vm *VM) executeAssignLocal() error { - localIndex := vm.currentFrame().ReadUint8() - vm.stack[vm.currentFrame().basePointer+int(localIndex)] = vm.pop() - return vm.push(object.NULL) -} - func (vm *VM) executeSetGlobal() error { globalIndex := vm.currentFrame().ReadUint16() @@ -242,11 +219,6 @@ func (vm *VM) executeSetGlobal() error { return vm.push(object.NULL) } -func (vm *VM) executeGetGlobal() error { - globalIndex := vm.currentFrame().ReadUint16() - return vm.push(vm.state.Globals[globalIndex]) -} - func (vm *VM) executeSetLocal() error { localIndex := vm.currentFrame().ReadUint8() @@ -260,38 +232,6 @@ func (vm *VM) executeSetLocal() error { return vm.push(object.NULL) } -func (vm *VM) executeGetLocal() error { - localIndex := vm.currentFrame().ReadUint8() - return vm.push(vm.stack[vm.currentFrame().basePointer+int(localIndex)]) -} - -func (vm *VM) executeGetFree() error { - freeIndex := vm.currentFrame().ReadUint8() - return vm.push(vm.currentFrame().GetFree(freeIndex)) -} - -func (vm *VM) executeLoadModule() error { - name := vm.pop() - return vm.loadModule(name) -} - -func (vm *VM) executeCurrentClosure() error { - currentClosure := vm.currentFrame().cl - return vm.push(currentClosure) -} - -func (vm *VM) executeTrue() error { - return vm.push(object.TRUE) -} - -func (vm *VM) executeFalse() error { - return vm.push(object.FALSE) -} - -func (vm *VM) executeNull() error { - return vm.push(object.NULL) -} - func (vm *VM) buildHash(startIndex, endIndex int) (object.Object, error) { hashedPairs := make(map[object.HashKey]object.HashPair) @@ -342,200 +282,238 @@ func (vm *VM) executeMakeArray() error { return vm.push(hash) } -func (vm *VM) executeClosure() error { - constIndex := vm.currentFrame().ReadUint16() - numFree := vm.currentFrame().ReadUint8() - return vm.pushClosure(int(constIndex), int(numFree)) -} - func (vm *VM) executeAdd() error { right := vm.pop() left := vm.pop() - if obj, ok := left.(object.Add); ok { + switch obj := left.(type) { + case object.Integer: val, err := obj.Add(right) if err != nil { return err } return vm.push(val) + case object.String: + val, err := obj.Add(right) + if err != nil { + return err + } + return vm.push(val) + case *object.Array: + val, err := obj.Add(right) + if err != nil { + return err + } + return vm.push(val) + case *object.Hash: + val, err := obj.Add(right) + if err != nil { + return err + } + return vm.push(val) + default: + return object.NewBinaryOpError(left, right, "+") } - - return object.NewBinaryOpError(left, right, "+") } func (vm *VM) executeSub() error { right := vm.pop() left := vm.pop() - if obj, ok := left.(object.Sub); ok { + switch obj := left.(type) { + case object.Integer: val, err := obj.Sub(right) if err != nil { return err } return vm.push(val) + default: + return fmt.Errorf("unsupported types for unary operation: -%s", left.Type()) } - - return object.NewBinaryOpError(left, right, "+") } func (vm *VM) executeMul() error { right := vm.pop() left := vm.pop() - if obj, ok := left.(object.Mul); ok { + switch obj := left.(type) { + case *object.Array: val, err := obj.Mul(right) if err != nil { return err } return vm.push(val) + case object.Integer: + val, err := obj.Mul(right) + if err != nil { + return err + } + return vm.push(val) + case object.String: + val, err := obj.Mul(right) + if err != nil { + return err + } + return vm.push(val) + default: + return object.NewBinaryOpError(left, right, "*") } - - return object.NewBinaryOpError(left, right, "*") } func (vm *VM) executeDiv() error { right := vm.pop() left := vm.pop() - if obj, ok := left.(object.Div); ok { + switch obj := left.(type) { + case object.Integer: val, err := obj.Div(right) if err != nil { return err } return vm.push(val) + default: + return object.NewBinaryOpError(left, right, "/") } - return object.NewBinaryOpError(left, right, "+") } func (vm *VM) executeMod() error { right := vm.pop() left := vm.pop() - if obj, ok := left.(object.Mod); ok { + switch obj := left.(type) { + case object.Integer: val, err := obj.Mod(right) if err != nil { return err } return vm.push(val) + default: + return object.NewBinaryOpError(left, right, "%") } - - return object.NewBinaryOpError(left, right, "%") } func (vm *VM) executeOr() error { right := vm.pop() left := vm.pop() - if obj, ok := left.(object.LogicalOr); ok { + switch obj := left.(type) { + case object.Boolean: val, err := obj.LogicalOr(right) if err != nil { return err } return vm.push(val) + default: + return object.NewBinaryOpError(left, right, "||") } - - return object.NewBinaryOpError(left, right, "||") } func (vm *VM) executeAnd() error { right := vm.pop() left := vm.pop() - if obj, ok := left.(object.LogicalAnd); ok { + switch obj := left.(type) { + case object.Boolean: val, err := obj.LogicalAnd(right) if err != nil { return err } return vm.push(val) + default: + return object.NewBinaryOpError(left, right, "&&") } - - return object.NewBinaryOpError(left, right, "&&") } func (vm *VM) executeBitwiseOr() error { right := vm.pop() left := vm.pop() - if obj, ok := left.(object.BitwiseOr); ok { + switch obj := left.(type) { + case object.Integer: val, err := obj.BitwiseOr(right) if err != nil { return err } return vm.push(val) + default: + return object.NewBinaryOpError(left, right, "|") } - - return object.NewBinaryOpError(left, right, "|") } func (vm *VM) executeBitwiseXor() error { right := vm.pop() left := vm.pop() - if obj, ok := left.(object.BitwiseXor); ok { + switch obj := left.(type) { + case object.Integer: val, err := obj.BitwiseXor(right) if err != nil { return err } return vm.push(val) + default: + return object.NewBinaryOpError(left, right, "^") } - - return object.NewBinaryOpError(left, right, "^") } func (vm *VM) executeBitwiseAnd() error { right := vm.pop() left := vm.pop() - if obj, ok := left.(object.BitwiseAnd); ok { + switch obj := left.(type) { + case object.Integer: val, err := obj.BitwiseAnd(right) if err != nil { return err } return vm.push(val) + default: + return object.NewBinaryOpError(left, right, "&") } - - return object.NewBinaryOpError(left, right, "&") } func (vm *VM) executeBitwiseNot() error { left := vm.pop() - if obj, ok := left.(object.BitwiseNot); ok { + switch obj := left.(type) { + case object.Integer: return vm.push(obj.BitwiseNot()) + default: + return fmt.Errorf("unsupported types for unary operation: ~%s", left.Type()) } - - return fmt.Errorf("unsupported types for unary operation: ~%s", left.Type()) } func (vm *VM) executeLeftShift() error { right := vm.pop() left := vm.pop() - if obj, ok := left.(object.LeftShift); ok { + switch obj := left.(type) { + case object.Integer: val, err := obj.LeftShift(right) if err != nil { return err } return vm.push(val) + default: + return object.NewBinaryOpError(left, right, "<<") } - - return object.NewBinaryOpError(left, right, "<<") } func (vm *VM) executeRightShift() error { right := vm.pop() left := vm.pop() - if obj, ok := left.(object.RightShift); ok { + switch obj := left.(type) { + case object.Integer: val, err := obj.RightShift(right) if err != nil { return err } return vm.push(val) + default: + return object.NewBinaryOpError(left, right, ">>") } - - return object.NewBinaryOpError(left, right, ">>") } func (vm *VM) executeEqual() error { @@ -601,21 +579,27 @@ func (vm *VM) executeGreaterThanOrEqual() error { func (vm *VM) executeNot() error { left := vm.pop() - if obj, ok := left.(object.LogicalNot); ok { + switch obj := left.(type) { + case object.Boolean: return vm.push(obj.LogicalNot()) + case object.Integer: + return vm.push(obj.LogicalNot()) + case object.Null: + return vm.push(obj.LogicalNot()) + default: + return fmt.Errorf("unsupported types for unary operation: !%s", left.Type()) } - - return fmt.Errorf("unsupported types for unary operation: !%s", left.Type()) } func (vm *VM) executeMinus() error { left := vm.pop() - if obj, ok := left.(object.Negate); ok { + switch obj := left.(type) { + case object.Integer: return vm.push(obj.Negate()) + default: + return fmt.Errorf("unsupported types for unary operation: -%s", left.Type()) } - - return fmt.Errorf("unsupported types for unary operation: -%s", left.Type()) } func (vm *VM) executeSetItem() error { @@ -623,36 +607,62 @@ func (vm *VM) executeSetItem() error { index := vm.pop() left := vm.pop() - if obj, ok := left.(object.Setter); ok { + switch obj := left.(type) { + case *object.Array: err := obj.Set(index, right) if err != nil { return err } return vm.push(object.NULL) + case *object.Hash: + err := obj.Set(index, right) + if err != nil { + return err + } + return vm.push(object.NULL) + default: + return fmt.Errorf( + "set item operation not supported: left=%s index=%s", + left.Type(), index.Type(), + ) } - - return fmt.Errorf( - "set item operation not supported: left=%s index=%s", - left.Type(), index.Type(), - ) } func (vm *VM) executeGetItem() error { index := vm.pop() left := vm.pop() - if obj, ok := left.(object.Getter); ok { + switch obj := left.(type) { + case object.String: val, err := obj.Get(index) if err != nil { return err } return vm.push(val) + case *object.Array: + val, err := obj.Get(index) + if err != nil { + return err + } + return vm.push(val) + case *object.Hash: + val, err := obj.Get(index) + if err != nil { + return err + } + return vm.push(val) + case object.Module: + val, err := obj.Get(index) + if err != nil { + return err + } + return vm.push(val) + default: + return fmt.Errorf( + "get item operation not supported: left=%s index=%s", + left.Type(), index.Type(), + ) } - - return fmt.Errorf( - "index operator not supported: left=%s index=%s", - left.Type(), index.Type(), - ) } func (vm *VM) executeCall() error { @@ -672,34 +682,6 @@ func (vm *VM) executeCall() error { } } -func (vm *VM) executeReturn() error { - returnValue := vm.pop() - - frame := vm.popFrame() - vm.sp = frame.basePointer - 1 - - return vm.push(returnValue) -} - -func (vm *VM) executeJumpIfFalse() error { - pos := int(vm.currentFrame().ReadUint16()) - if !isTruthy(vm.pop()) { - vm.currentFrame().SetIP(pos) - } - return nil -} - -func (vm *VM) executeJump() error { - pos := int(vm.currentFrame().ReadUint16()) - vm.currentFrame().SetIP(pos) - return nil -} - -func (vm *VM) executePop() error { - vm.pop() - return nil -} - func (vm *VM) callClosure(cl *object.Closure, numArgs int) error { if numArgs != cl.Fn.NumParameters { return fmt.Errorf("wrong number of arguments: want=%d, got=%d", cl.Fn.NumParameters, numArgs) @@ -732,18 +714,10 @@ func (vm *VM) callBuiltin(builtin object.Builtin, numArgs int) error { vm.sp = vm.sp - numArgs - 1 if result != nil { - err := vm.push(result) - if err != nil { - return err - } - } else { - err := vm.push(object.NULL) - if err != nil { - return err - } + return vm.push(result) } - return nil + return vm.push(object.NULL) } func (vm *VM) pushClosure(constIndex, numFree int) error { @@ -830,37 +804,47 @@ func (vm *VM) Run() (err error) { switch op { case code.OpConstant: - err = vm.executeConstant() + constIndex := vm.currentFrame().ReadUint16() + err = vm.push(vm.state.Constants[constIndex]) case code.OpPop: - err = vm.executePop() + vm.pop() case code.OpTrue: - err = vm.executeTrue() + err = vm.push(object.TRUE) case code.OpFalse: - err = vm.executeFalse() + err = vm.push(object.FALSE) case code.OpJump: - err = vm.executeJump() + pos := int(vm.currentFrame().ReadUint16()) + vm.currentFrame().SetIP(pos) case code.OpJumpNotTruthy: - err = vm.executeJumpIfFalse() + pos := int(vm.currentFrame().ReadUint16()) + if !isTruthy(vm.pop()) { + vm.currentFrame().SetIP(pos) + } case code.OpNull: - err = vm.executeNull() + err = vm.push(object.NULL) case code.OpSetGlobal: err = vm.executeSetGlobal() case code.OpAssignGlobal: - err = vm.executeAssignGlobal() + globalIndex := vm.currentFrame().ReadUint16() + vm.state.Globals[globalIndex] = vm.pop() + err = vm.push(object.NULL) case code.OpAssignLocal: - err = vm.executeAssignLocal() + localIndex := vm.currentFrame().ReadUint8() + vm.stack[vm.currentFrame().basePointer+int(localIndex)] = vm.pop() + err = vm.push(object.NULL) case code.OpGetGlobal: - err = vm.executeGetGlobal() + globalIndex := vm.currentFrame().ReadUint16() + err = vm.push(vm.state.Globals[globalIndex]) case code.OpArray: err = vm.executeMakeArray() @@ -878,28 +862,39 @@ func (vm *VM) Run() (err error) { err = vm.executeCall() case code.OpReturn: - err = vm.executeReturn() + returnValue := vm.pop() + frame := vm.popFrame() + vm.sp = frame.basePointer - 1 + err = vm.push(returnValue) case code.OpSetLocal: err = vm.executeSetLocal() case code.OpGetLocal: - err = vm.executeGetLocal() + localIndex := vm.currentFrame().ReadUint8() + err = vm.push(vm.stack[vm.currentFrame().basePointer+int(localIndex)]) case code.OpGetBuiltin: - err = vm.executeLoadBuiltin() + builtinIndex := vm.currentFrame().ReadUint8() + builtin := builtins.BuiltinsIndex[builtinIndex] + err = vm.push(builtin) case code.OpClosure: - err = vm.executeClosure() + constIndex := vm.currentFrame().ReadUint16() + numFree := vm.currentFrame().ReadUint8() + err = vm.pushClosure(int(constIndex), int(numFree)) case code.OpGetFree: - err = vm.executeGetFree() + freeIndex := vm.currentFrame().ReadUint8() + err = vm.push(vm.currentFrame().GetFree(freeIndex)) case code.OpCurrentClosure: - err = vm.executeCurrentClosure() + currentClosure := vm.currentFrame().cl + err = vm.push(currentClosure) case code.OpLoadModule: - err = vm.executeLoadModule() + name := vm.pop() + err = vm.loadModule(name) case code.OpAdd: err = vm.executeAdd()