Refuse a calc over digits(0) or a repeat of 0, name an option's wrong kind as JSON does, type the name scope kinds, and compile only from a jsonvalue.Value
This commit is contained in:
@@ -36,6 +36,9 @@ var builtins = withTransforms(map[string]builtin{
|
||||
"nanoid": {arity: 1, checkArgs: countArg, prep: chars(nanoidAlphabet)},
|
||||
"hex": {arity: 1, checkArgs: countArg, prep: chars(hexDigits)},
|
||||
"digits": {arity: 1, checkArgs: countArg, prep: chars("0123456789"), prints: datatype.String, proveNumber: func(token string, prints datatype.DataType, a []string) proven.Facts {
|
||||
if atoi(a[0]) == 0 {
|
||||
return proven.Unproven("{" + token + "} prints nothing, which is no number")
|
||||
}
|
||||
return proven.Printing(token, prints, proven.Bounded(0, math.Pow(10, float64(atoi(a[0])))-1, true))
|
||||
}},
|
||||
"upper": {arity: 1, checkArgs: countArg, prep: chars("ABCDEFGHIJKLMNOPQRSTUVWXYZ")},
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
package datafiles
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
@@ -11,6 +9,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/larvit/fejkdata/internal/grammar"
|
||||
"github.com/larvit/fejkdata/internal/jsonvalue"
|
||||
)
|
||||
|
||||
// Source is one tree to load: an fs.FS and the directory in it to start from. label
|
||||
@@ -35,7 +34,7 @@ func FS(fsys fs.FS, base string) Source { return Source{fsys: fsys, base: base}
|
||||
type Category struct {
|
||||
Folders []string
|
||||
Name string
|
||||
JSON any
|
||||
JSON jsonvalue.Value
|
||||
rows *rowsFiles
|
||||
}
|
||||
|
||||
@@ -142,7 +141,7 @@ func (s Source) compileFile(dir []string, file string, rows *rowsFiles, compile
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("%s: %w", s.labelled(full), err)
|
||||
}
|
||||
raw, err := DecodeJSON(b)
|
||||
raw, err := jsonvalue.Decode(b)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("%s: %w", s.labelled(full), err)
|
||||
}
|
||||
@@ -179,14 +178,3 @@ func (r *rowsFiles) read(name string) (string, error) {
|
||||
}
|
||||
return string(b), nil
|
||||
}
|
||||
|
||||
// DecodeJSON decodes one JSON value, keeping each number as the json.Number it is written as.
|
||||
func DecodeJSON(b []byte) (any, error) {
|
||||
var v any
|
||||
if !json.Valid(b) {
|
||||
return nil, json.Unmarshal(b, &v)
|
||||
}
|
||||
dec := json.NewDecoder(bytes.NewReader(b))
|
||||
dec.UseNumber()
|
||||
return v, dec.Decode(&v)
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ func walk(t *testing.T, src Source) ([]handed, error) {
|
||||
t.Helper()
|
||||
var got []handed
|
||||
err := src.Walk(func(c Category) error {
|
||||
got = append(got, handed{c.Folders, c.Name, c.JSON})
|
||||
got = append(got, handed{c.Folders, c.Name, c.JSON.Any()})
|
||||
return nil
|
||||
})
|
||||
return got, err
|
||||
@@ -133,7 +133,7 @@ func TestLoadHandsOneCategoryAndItsRows(t *testing.T) {
|
||||
var got handed
|
||||
var rows string
|
||||
err := src.Load([]string{"sub"}, "t", func(c Category) error {
|
||||
got = handed{c.Folders, c.Name, c.JSON}
|
||||
got = handed{c.Folders, c.Name, c.JSON.Any()}
|
||||
var err error
|
||||
rows, err = c.ReadRows("t.tsv")
|
||||
return err
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// Package jsonvalue holds a decoded JSON value whose numbers keep the text they are written in.
|
||||
package jsonvalue
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Value is a JSON value that only Decode, String and Object make, so a template never compiles
|
||||
// from a value encoding/json decoded with its numbers as float64.
|
||||
type Value struct{ v any }
|
||||
|
||||
// Decode decodes one JSON value, keeping each number as the json.Number it is written as.
|
||||
func Decode(b []byte) (Value, error) {
|
||||
var v any
|
||||
if !json.Valid(b) {
|
||||
return Value{}, json.Unmarshal(b, &v)
|
||||
}
|
||||
dec := json.NewDecoder(bytes.NewReader(b))
|
||||
dec.UseNumber()
|
||||
err := dec.Decode(&v)
|
||||
return Value{v}, err
|
||||
}
|
||||
|
||||
// String is the JSON string s.
|
||||
func String(s string) Value { return Value{s} }
|
||||
|
||||
// Object is the JSON object holding fields.
|
||||
func Object(fields map[string]Value) Value {
|
||||
m := make(map[string]any, len(fields))
|
||||
for k, f := range fields {
|
||||
m[k] = f.v
|
||||
}
|
||||
return Value{m}
|
||||
}
|
||||
|
||||
// Any is the value as encoding/json decodes it: a map[string]any, []any, string, json.Number,
|
||||
// bool or nil.
|
||||
func (v Value) Any() any { return v.v }
|
||||
Reference in New Issue
Block a user