diff --git a/object.go b/object.go index 3c3df44..025d437 100644 --- a/object.go +++ b/object.go @@ -48,8 +48,6 @@ func ObjectGetProperty(obj Object, name string) (Value, bool) { if vValue, ok := vValueI.(Value); ok { return vValue, true } else { - // TODO: this could be useful in value.go to autosense a type into its gal.Value equivalent! - // It'd make it easier to write a Function. switch vValueIType := vValueI.(type) { case int: return NewNumberFromInt(int64(vValueIType)), true diff --git a/tree_builder.go b/tree_builder.go index 84c519c..41ea25f 100644 --- a/tree_builder.go +++ b/tree_builder.go @@ -188,7 +188,7 @@ func extractPart(expr string) (string, exprType, int, error) { } // allow to continue so we can check alphanumerical operator names such as "And", "Or", etc // TODO: before we try for alphanum operators, we will need to check if we have a defined constant - // e.g. Phi (golden ratio), etc user-defined or built-in + // e.g. Phi (golden ratio), etc user-defined or built-in (True, False) case err != nil: return "", unknownType, 0, err default: @@ -210,7 +210,7 @@ func extractPart(expr string) (string, exprType, int, error) { } // read part - number - // TODO: complex numbers are not supported - could be "native" or via function or perhaps even a MultiValue? + // TODO: complex numbers are not supported - could be "native" or via function or perhaps even a specialised MultiValue? s, l, err := readNumber(expr[pos:]) if err != nil { return "", unknownType, 0, err @@ -231,7 +231,7 @@ func readString(expr string) (string, int, error) { if r == '"' && (escapes == 0 || escapes&1 == 0) { break } - // TODO: perhaps we should collapse the `\`, here? + // TODO: perhaps we should collapse the `\`'s, here? escapes = 0 } diff --git a/value.go b/value.go index 92ba46f..b1ec4ba 100644 --- a/value.go +++ b/value.go @@ -25,14 +25,54 @@ type Evaler interface { Eval() Value } -// TODO: we may also want to create ToString() and ToBool() +func ToValue(value any) Value { + v, _ := toValue(value) + return v +} +func toValue(value any) (Value, bool) { + switch typedValue := value.(type) { + case int: + return NewNumberFromInt(int64(typedValue)), true + case int32: + return NewNumberFromInt(int64(typedValue)), true + case int64: + return NewNumberFromInt(typedValue), true + case uint: + return NewNumberFromInt(int64(typedValue)), true + case uint32: + return NewNumberFromInt(int64(typedValue)), true + case uint64: + n, err := NewNumberFromString(fmt.Sprintf("%d", typedValue)) + if err != nil { + return NewUndefinedWithReasonf("value '%d' cannot be converted to a Number", typedValue), false + } + return n, true + case float32: // this will commonly suffer from floating point issues + return NewNumberFromFloat(float64(typedValue)), true + case float64: + return NewNumberFromFloat(typedValue), true + case string: + return NewString(typedValue), true + case bool: + return NewBool(typedValue), true + default: + return NewUndefinedWithReasonf("type '%T', does not resolve to a gal.Value", typedValue), false + } +} + func ToNumber(val Value) Number { - // TODO: we could also try to convert Bool to Number since we could add NewNumberFromBool() to deal with Bool's return val.(Numberer).Number() // may panic } +func ToString(val Value) String { + return val.AsString() +} + +func ToBool(val Value) Bool { + return val.(Booler).Bool() // may panic +} + // MultiValue is a container of zero or more Value's. -// TODO: impose a minimum of 1 value? // For the time being, it is only usable and useful with functions. // Functions can accept a MultiValue, and also return a MultiValue. // This allows a function to effectively return multiple values as a MultiValue. @@ -57,12 +97,17 @@ func (MultiValue) kind() entryKind { // Equal satisfies the external Equaler interface such as in testify assertions and the cmp package // Note that the current implementation defines equality as values matching and in order they appear. func (m MultiValue) Equal(other MultiValue) bool { + if m.Size() != other.Size() { + return false + } + for i := range m.values { // TODO: add test to confirm this is correct! if m.values[i].NotEqualTo(other.values[i]) == False { return false } } + return true } @@ -488,6 +533,13 @@ func (n Number) String() string { return n.value.String() } +func (n Number) Bool() Bool { + if n.value.IsZero() { + return False + } + return True +} + func (n Number) AsString() String { return NewString(n.String()) } @@ -574,6 +626,13 @@ func (b Bool) String() string { return "False" } +func (b Bool) Number() Number { + if b.value { + return NewNumberFromInt(1) + } + return NewNumberFromInt(0) +} + func (b Bool) AsString() String { return NewString(b.String()) }