feat: scaffold interpres project with TOML parser and CI
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
// Command interpres-decode reads a TOML document from standard input and writes
|
||||
// the toml-test "tagged JSON" representation to standard output.
|
||||
//
|
||||
// It exits non-zero on a parse error, which is how the toml-test harness checks
|
||||
// that invalid documents are rejected. Run the official suite against it with:
|
||||
//
|
||||
// toml-test ./interpres-decode
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"codeberg.org/petrbalvin/interpres"
|
||||
)
|
||||
|
||||
func main() {
|
||||
data, err := io.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "read stdin:", err)
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
tree, err := interpres.Parse(data)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
enc.SetEscapeHTML(false)
|
||||
if err := enc.Encode(tag(tree)); err != nil {
|
||||
fmt.Fprintln(os.Stderr, "encode:", err)
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
|
||||
// tag converts an interpres value into its toml-test tagged-JSON form. Tables
|
||||
// become JSON objects and arrays become JSON arrays; scalars are wrapped in a
|
||||
// {"type", "value"} object.
|
||||
func tag(v any) any {
|
||||
switch x := v.(type) {
|
||||
case map[string]any:
|
||||
out := make(map[string]any, len(x))
|
||||
for k, val := range x {
|
||||
out[k] = tag(val)
|
||||
}
|
||||
return out
|
||||
case []any:
|
||||
out := make([]any, len(x))
|
||||
for i, e := range x {
|
||||
out[i] = tag(e)
|
||||
}
|
||||
return out
|
||||
case []map[string]any:
|
||||
out := make([]any, len(x))
|
||||
for i, e := range x {
|
||||
out[i] = tag(e)
|
||||
}
|
||||
return out
|
||||
case string:
|
||||
return tagged("string", x)
|
||||
case bool:
|
||||
return tagged("bool", strconv.FormatBool(x))
|
||||
case int64:
|
||||
return tagged("integer", strconv.FormatInt(x, 10))
|
||||
case float64:
|
||||
return tagged("float", formatFloat(x))
|
||||
case time.Time:
|
||||
return tagged("datetime", x.Format(time.RFC3339Nano))
|
||||
case interpres.LocalDateTime:
|
||||
return tagged("datetime-local", x.Format("2006-01-02T15:04:05.999999999"))
|
||||
case interpres.LocalDate:
|
||||
return tagged("date-local", x.Format("2006-01-02"))
|
||||
case interpres.LocalTime:
|
||||
return tagged("time-local", x.Format("15:04:05.999999999"))
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "unsupported value type %T\n", v)
|
||||
os.Exit(2)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func tagged(typ, value string) map[string]string {
|
||||
return map[string]string{"type": typ, "value": value}
|
||||
}
|
||||
|
||||
func formatFloat(f float64) string {
|
||||
switch {
|
||||
case math.IsInf(f, 1):
|
||||
return "inf"
|
||||
case math.IsInf(f, -1):
|
||||
return "-inf"
|
||||
case math.IsNaN(f):
|
||||
return "nan"
|
||||
default:
|
||||
return strconv.FormatFloat(f, 'g', -1, 64)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user