go-toml/cmd/toml-test-decoder/main.go

104 lines
2.7 KiB
Go

// Command toml-test-decoder satisfies BurntSushi's toml-test interface for testing
// TOML decoders. Namely, it accepts TOML on stdin and outputs JSON on stdout.
// See: https://github.com/BurntSushi/toml-test
package main
import (
"flag"
"fmt"
"log"
"os"
"path"
"sort"
"strings"
"time"
"git.makaay.nl/mauricem/go-toml/ast"
"git.makaay.nl/mauricem/go-toml/parse"
)
func init() {
log.SetFlags(0)
flag.Usage = usage
flag.Parse()
}
func usage() {
log.Printf("Usage: %s < toml-file\n", path.Base(os.Args[0]))
flag.PrintDefaults()
os.Exit(1)
}
func main() {
if flag.NArg() != 0 {
flag.Usage()
}
toml, err := parse.Run(os.Stdin)
if err != nil {
log.Fatalf("Error decoding TOML: %s", err)
} else {
sushi := makeSushi(ast.NewValue(ast.TypeTable, toml))
fmt.Println(sushi)
}
}
func makeSushi(value *ast.Value) string {
switch value.Type {
case ast.TypeString:
return renderValue("string", value.Data[0].(string))
case ast.TypeInteger:
return renderValue("integer", fmt.Sprintf("%d", value.Data[0].(int64)))
case ast.TypeFloat:
return renderValue("float", fmt.Sprintf("%v", value.Data[0].(float64)))
case ast.TypeBool:
return renderValue("bool", fmt.Sprintf("%t", value.Data[0].(bool)))
case ast.TypeOffsetDateTime:
return renderValue("datetime", value.Data[0].(time.Time).Format(time.RFC3339Nano))
case ast.TypeLocalDateTime:
return renderValue("local_datetime", value.Data[0].(time.Time).Format("2006-01-02 15:04:05.999999999"))
case ast.TypeLocalDate:
return renderValue("local_date", value.Data[0].(time.Time).Format("2006-01-02"))
case ast.TypeLocalTime:
return renderValue("local_time", value.Data[0].(time.Time).Format("15:04:05.999999999"))
case ast.TypeArrayOfTables:
fallthrough
case ast.TypeArray:
values := make([]string, len(value.Data))
isArrayOfTables := false
for i, value := range value.Data {
isArrayOfTables = value.(*ast.Value).Type == ast.TypeTable
values[i] = makeSushi(value.(*ast.Value))
}
if isArrayOfTables {
return fmt.Sprintf("[%s]", strings.Join(values, ", "))
} else {
return fmt.Sprintf(`{"type": "array", "value": [%s]}`, strings.Join(values, ", "))
}
case ast.TypeImplicitTable:
fallthrough
case ast.TypeTable:
pairs := value.Data[0].(ast.Table)
keys := make([]string, len(pairs))
i := 0
for k := range pairs {
keys[i] = k
i++
}
sort.Strings(keys)
values := make([]string, len(pairs))
for i, k := range keys {
values[i] = fmt.Sprintf("%q: %s", k, makeSushi(pairs[k]))
}
return fmt.Sprintf("{%s}", strings.Join(values, ", "))
default:
panic(fmt.Sprintf("Unhandled data type: %s", value.Type))
}
}
func renderValue(t string, v string) string {
return fmt.Sprintf("{%q: %q, %q: %q}", "type", t, "value", v)
}