102 lines
2.7 KiB
Go
102 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.TypeBoolean:
|
|
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.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)
|
|
}
|