From 552e9c01c56d2ab7943bc27d407e47d1e6c7b20e Mon Sep 17 00:00:00 2001 From: Daniel Kang Date: Thu, 17 Jan 2019 16:52:07 -0800 Subject: [PATCH] separate objects conversion functions --- objects/builtin_convert.go | 95 +++++++++++--------------- objects/conversion.go | 132 +++++++++++++++++++++++++++++++++++++ objects/errors.go | 3 + 3 files changed, 174 insertions(+), 56 deletions(-) create mode 100644 objects/conversion.go diff --git a/objects/builtin_convert.go b/objects/builtin_convert.go index 618691d..f8fdd8a 100644 --- a/objects/builtin_convert.go +++ b/objects/builtin_convert.go @@ -1,22 +1,20 @@ package objects -import ( - "strconv" -) - func builtinString(args ...Object) (Object, error) { if len(args) != 1 { return nil, ErrWrongNumArguments } - switch arg := args[0].(type) { - case *String: - return arg, nil - case *Undefined: - return UndefinedValue, nil - default: - return &String{Value: arg.String()}, nil + if _, ok := args[0].(*String); ok { + return args[0], nil } + + v, ok := ToString(args[0]) + if ok { + return &String{Value: v}, nil + } + + return UndefinedValue, nil } func builtinInt(args ...Object) (Object, error) { @@ -24,23 +22,13 @@ func builtinInt(args ...Object) (Object, error) { return nil, ErrWrongNumArguments } - switch arg := args[0].(type) { - case *Int: - return arg, nil - case *Float: - return &Int{Value: int64(arg.Value)}, nil - case *Char: - return &Int{Value: int64(arg.Value)}, nil - case *Bool: - if arg.Value { - return &Int{Value: 1}, nil - } - return &Int{Value: 0}, nil - case *String: - n, err := strconv.ParseInt(arg.Value, 10, 64) - if err == nil { - return &Int{Value: n}, nil - } + if _, ok := args[0].(*Int); ok { + return args[0], nil + } + + v, ok := ToInt64(args[0]) + if ok { + return &Int{Value: v}, nil } return UndefinedValue, nil @@ -51,16 +39,13 @@ func builtinFloat(args ...Object) (Object, error) { return nil, ErrWrongNumArguments } - switch arg := args[0].(type) { - case *Float: - return arg, nil - case *Int: - return &Float{Value: float64(arg.Value)}, nil - case *String: - f, err := strconv.ParseFloat(arg.Value, 64) - if err == nil { - return &Float{Value: f}, nil - } + if _, ok := args[0].(*Float); ok { + return args[0], nil + } + + v, ok := ToFloat64(args[0]) + if ok { + return &Float{Value: v}, nil } return UndefinedValue, nil @@ -71,12 +56,16 @@ func builtinBool(args ...Object) (Object, error) { return nil, ErrWrongNumArguments } - switch arg := args[0].(type) { - case *Bool: - return arg, nil - default: - return &Bool{Value: !arg.IsFalsy()}, nil + if _, ok := args[0].(*Bool); ok { + return args[0], nil } + + v, ok := ToBool(args[0]) + if ok { + return &Bool{Value: v}, nil + } + + return UndefinedValue, nil } func builtinChar(args ...Object) (Object, error) { @@ -84,19 +73,13 @@ func builtinChar(args ...Object) (Object, error) { return nil, ErrWrongNumArguments } - switch arg := args[0].(type) { - case *Char: - return arg, nil - case *Int: - return &Char{Value: rune(arg.Value)}, nil - case *String: - rs := []rune(arg.Value) - switch len(rs) { - case 0: - return &Char{}, nil - case 1: - return &Char{Value: rs[0]}, nil - } + if _, ok := args[0].(*Char); ok { + return args[0], nil + } + + v, ok := ToRune(args[0]) + if ok { + return &Char{Value: v}, nil } return UndefinedValue, nil diff --git a/objects/conversion.go b/objects/conversion.go new file mode 100644 index 0000000..064aa69 --- /dev/null +++ b/objects/conversion.go @@ -0,0 +1,132 @@ +package objects + +import ( + "strconv" +) + +// ToString will try to convert object o to string value. +func ToString(o Object) (v string, ok bool) { + if _, isUndefined := o.(*Undefined); isUndefined { + //ok = false + return + } + + ok = true + + if str, isStr := o.(*String); isStr { + v = str.Value + } else { + v = o.String() + } + + return +} + +// ToInt will try to convert object o to int value. +func ToInt(o Object) (v int, ok bool) { + switch o := o.(type) { + case *Int: + v = int(o.Value) + ok = true + case *Float: + v = int(o.Value) + ok = true + case *Char: + v = int(o.Value) + ok = true + case *Bool: + if o.Value { + v = 1 + } + ok = true + case *String: + c, err := strconv.ParseInt(o.Value, 10, 64) + if err == nil { + v = int(c) + ok = true + } + } + + //ok = false + return +} + +// ToInt64 will try to convert object o to int64 value. +func ToInt64(o Object) (v int64, ok bool) { + switch o := o.(type) { + case *Int: + v = o.Value + ok = true + case *Float: + v = int64(o.Value) + ok = true + case *Char: + v = int64(o.Value) + ok = true + case *Bool: + if o.Value { + v = 1 + } + ok = true + case *String: + c, err := strconv.ParseInt(o.Value, 10, 64) + if err == nil { + v = c + ok = true + } + } + + //ok = false + return +} + +// ToFloat64 will try to convert object o to float64 value. +func ToFloat64(o Object) (v float64, ok bool) { + switch o := o.(type) { + case *Int: + v = float64(o.Value) + ok = true + case *Float: + v = o.Value + ok = true + case *String: + c, err := strconv.ParseFloat(o.Value, 64) + if err == nil { + v = c + ok = true + } + } + + //ok = false + return +} + +// ToBool will try to convert object o to bool value. +func ToBool(o Object) (v bool, ok bool) { + ok = true + v = !o.IsFalsy() + + return +} + +// ToRune will try to convert object o to rune value. +func ToRune(o Object) (v rune, ok bool) { + switch o := o.(type) { + case *Int: + v = rune(o.Value) + ok = true + case *Char: + v = rune(o.Value) + ok = true + case *String: + rs := []rune(o.Value) + switch len(rs) { + case 1: + v = rs[0] + ok = true + } + } + + //ok = false + return +} diff --git a/objects/errors.go b/objects/errors.go index 78d6a40..a0f9038 100644 --- a/objects/errors.go +++ b/objects/errors.go @@ -7,3 +7,6 @@ var ErrInvalidOperator = errors.New("invalid operator") // ErrWrongNumArguments represents a wrong number of arguments error. var ErrWrongNumArguments = errors.New("wrong number of arguments") + +// ErrInvalidTypeConversion represents an invalid type conversion error. +var ErrInvalidTypeConversion = errors.New("invalid type conversion")