Skip to content

Commit

Permalink
Add primitive type conversion. (#240)
Browse files Browse the repository at this point in the history
The convert operator now supports converting from primitive types into
String, Number, Binary and Bool. This can helps comparing primitive values
to other concrete types, for instance checking for greater than or
boolean truth.
  • Loading branch information
kairichard authored and td5r committed Dec 8, 2019
1 parent 2b6c249 commit 9c96c84
Showing 1 changed file with 134 additions and 37 deletions.
171 changes: 134 additions & 37 deletions pkg/elem/data_convert.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,53 @@
package elem

import (
"encoding/binary"
"fmt"
"math"
"strconv"
"strings"

"github.com/Bitspark/slang/pkg/core"
"github.com/google/uuid"
)

func numberToBinary(value float64) core.Binary {
bits := math.Float64bits(value)
bytes := make(core.Binary, 8)
binary.LittleEndian.PutUint64(bytes, bits)
return bytes
}

func numberToString(value float64) string {
return strconv.FormatFloat(value, 'f', -1, 64)
}

func stringToNumber(value string) float64 {
result, _ := strconv.ParseFloat(value, 64)
return result
}

func boolToNumber(value bool) float64 {
if value {
return 1.0
} else {
return 0.0
}
}

func binaryToNumber(value core.Binary) float64 {
bits := binary.LittleEndian.Uint64(value)
return math.Float64frombits(bits)
}

func binaryToBool(value core.Binary) bool {
return stringToBool(string(value))
}

func stringToBool(value string) bool {
result, _ := strconv.ParseBool(value)
return result
}

var dataConvertId = uuid.MustParse("d1191456-3583-4eaf-8ec1-e486c3818c60")
var dataConvertCfg = &builtinConfig{
blueprint: core.Blueprint{
Expand Down Expand Up @@ -44,67 +83,125 @@ var dataConvertCfg = &builtinConfig{
continue
}

if in.Type() == out.Type() {
out.Push(i)
continue
}

switch in.Type() {
case core.TYPE_NUMBER:
item := i.(float64)
value := i.(float64)
switch out.Type() {
case core.TYPE_STRING:
out.Push(strconv.FormatFloat(item, 'f', -1, 64))
case core.TYPE_STRING: // number -> string
out.Push(numberToString(value))
case core.TYPE_BINARY: // number -> binary
out.Push(numberToBinary(value))
case core.TYPE_BOOLEAN: // number -> bool
out.Push(value != 0.0)
default:
panic("not supported yet")
}
case core.TYPE_BOOLEAN:
item := i.(bool)
value := i.(bool)
switch out.Type() {
case core.TYPE_STRING:
out.Push(fmt.Sprintf("%v", item))
case core.TYPE_BINARY:
out.Push(core.Binary(fmt.Sprintf("%v", item)))
case core.TYPE_STRING: // bool -> string
out.Push(strconv.FormatBool(value))
case core.TYPE_BINARY: // bool -> binary
out.Push(core.Binary(strconv.FormatBool(value)))
case core.TYPE_NUMBER: // bool -> number
out.Push(boolToNumber(value))
default:
panic("not supported yet")
}
case core.TYPE_STRING:
item := i.(string)
value := i.(string)
switch out.Type() {
case core.TYPE_STRING:
out.Push(item)
case core.TYPE_BINARY:
out.Push(core.Binary(item))
case core.TYPE_NUMBER:
item = strings.Trim(item, " ")
floatItem := 0.0
if strings.Contains(item, ":") {
items := strings.Split(item, ":")
factor := 1.0
for i := len(items) - 1; i >= 0; i-- {
part, _ := strconv.ParseFloat(items[i], 64)
floatItem += factor * part
factor *= 60
}
} else {
floatItem, _ = strconv.ParseFloat(item, 64)
}
out.Push(floatItem)
case core.TYPE_BINARY: // string -> binary
out.Push(core.Binary(value))
case core.TYPE_NUMBER: // string -> number
out.Push(stringToNumber(value))
case core.TYPE_BOOLEAN: // string -> bool
out.Push(stringToBool(value))
default:
panic("not supported yet")
}
case core.TYPE_BINARY:
item := i.(core.Binary)
value := i.(core.Binary)
switch out.Type() {
case core.TYPE_STRING:
out.Push(string(item))
case core.TYPE_BINARY:
out.Push(item)
case core.TYPE_STRING: // binary -> string
out.Push(string(value))
case core.TYPE_NUMBER: // binary -> number
out.Push(binaryToNumber(value))
case core.TYPE_BOOLEAN: // binary -> bool
out.Push(binaryToBool(value))
default:
panic("not supported yet")
}
case core.TYPE_STREAM:
item := i.([]interface{})
value := i.([]interface{})
switch out.Type() {
case core.TYPE_STRING: // stream -> string
out.Push(fmt.Sprintf("%v", value))
case core.TYPE_BINARY: // stream -> binary
out.Push(core.Binary(fmt.Sprintf("%v", value)))
default:
panic("not supported yet")
}
case core.TYPE_PRIMITIVE:
switch out.Type() {
case core.TYPE_STRING:
out.Push(fmt.Sprintf("%v", item))
switch value := i.(type) {
case float64: // number -> string
out.Push(numberToString(value))
case string: // string -> string
out.Push(value)
case bool: // bool -> string
out.Push(strconv.FormatBool(value))
case core.Binary: // binary -> string
out.Push(string(value))
default:
panic("not supported yet")
}
case core.TYPE_NUMBER:
switch value := i.(type) {
case float64: // number -> number
out.Push(value)
case string: // string -> number
out.Push(stringToNumber(value))
case bool: // bool -> number
out.Push(boolToNumber(value))
case core.Binary: // binary -> number
out.Push(binaryToNumber(value))
default:
panic("not supported yet")
}
case core.TYPE_BOOLEAN:
switch value := i.(type) {
case float64: // number -> bool
out.Push(value != 0.0)
case string: // string -> bool
out.Push(stringToBool(value))
case bool: // bool -> bool
out.Push(value)
case core.Binary: // binary -> bool
out.Push(binaryToBool(value))
default:
panic("not supported yet")
}
case core.TYPE_BINARY:
out.Push(core.Binary(fmt.Sprintf("%v", item)))
switch value := i.(type) {
case float64: // number -> binary
out.Push(numberToBinary(value))
case string: // string -> binary
out.Push(core.Binary(value))
case bool: // bool -> binary
stringBool := strconv.FormatBool(value)
out.Push(core.Binary(stringBool))
case core.Binary: // binary -> binary
out.Push(value)
default:
panic("not supported yet")
}
default:
panic("not supported yet")
}
Expand Down

0 comments on commit 9c96c84

Please sign in to comment.