wip chunker i gotta go faste bye
This commit is contained in:
parent
57deaa3670
commit
c96643250c
|
@ -1 +0,0 @@
|
|||
package asld
|
|
@ -0,0 +1,5 @@
|
|||
package consts
|
||||
|
||||
const (
|
||||
PkgTag = "ld"
|
||||
)
|
|
@ -0,0 +1,223 @@
|
|||
package chunk
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"sectorinf.com/emilis/flabk/pkg/coll"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNoMatch = errors.New("no matching")
|
||||
ErrMapMemberNotString = errors.New("map member not a string")
|
||||
ErrUnexpectedSymbol = errors.New("unexpected symbol")
|
||||
)
|
||||
|
||||
type Chunk struct {
|
||||
vector coll.Vector[byte]
|
||||
posLeft int
|
||||
posRight int
|
||||
// todo global pos impl
|
||||
globLeft int
|
||||
globRight int
|
||||
}
|
||||
|
||||
// Match finds the matching closer to the symbol at the left position and sets the
|
||||
// right position to this index
|
||||
func (c Chunk) Match() (Chunk, error) {
|
||||
s, ok := matchers[c.vector[c.posLeft]]
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("Match called on %c with no matcher defined", c.vector[c.posLeft]))
|
||||
}
|
||||
if s.StartFromRight {
|
||||
for c.posRight > 0 {
|
||||
if c.vector[c.posRight] == s.MatchByte {
|
||||
return c, nil
|
||||
}
|
||||
c.posRight--
|
||||
c.globRight--
|
||||
}
|
||||
} else {
|
||||
for index := c.posLeft + 1; index < len(c.vector); index++ {
|
||||
if c.vector[index] == s.MatchByte {
|
||||
c.posRight = index
|
||||
c.globRight += (c.posLeft + 1) - index
|
||||
return c, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return c, fmt.Errorf("%w %c", ErrNoMatch, c.vector[c.posLeft])
|
||||
}
|
||||
|
||||
func (c Chunk) Copy() Chunk {
|
||||
return c
|
||||
}
|
||||
|
||||
func (c Chunk) Left() byte {
|
||||
return c.vector[c.posLeft]
|
||||
}
|
||||
|
||||
// Sub returns an inclusive subchunk of [left;right]
|
||||
func (c Chunk) Sub() Chunk {
|
||||
return New(c.vector[c.posLeft : c.posRight+1])
|
||||
}
|
||||
|
||||
// CookieCutter returns a subchunk of (left;right)
|
||||
func (c Chunk) CookieCutter() Chunk {
|
||||
return New(c.vector[c.posLeft+1 : c.posRight])
|
||||
}
|
||||
|
||||
func (c Chunk) AtSpace() bool {
|
||||
r, _ := utf8.DecodeRune(c.vector[c.posLeft:])
|
||||
return unicode.IsSpace(r)
|
||||
}
|
||||
|
||||
func (c Chunk) Seek() Chunk {
|
||||
for c.posLeft < len(c.vector) && c.AtSpace() {
|
||||
c.posLeft++
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func (c Chunk) ValueEnd() (Chunk, error) {
|
||||
switch c.vector[c.posLeft] {
|
||||
case '"', '{', '[':
|
||||
return c.Match()
|
||||
default:
|
||||
for index := c.posLeft; index <= c.posRight; index++ {
|
||||
if c.vector[index] == ',' {
|
||||
return New(c.vector[c.posLeft:index]), nil
|
||||
}
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Skip skips the current left position and then Seeks
|
||||
func (c Chunk) Skip() Chunk {
|
||||
if c.posLeft+1 < len(c.vector) {
|
||||
c.posLeft++
|
||||
}
|
||||
return c.Seek()
|
||||
}
|
||||
|
||||
type MatchRule struct {
|
||||
MatchByte byte
|
||||
StartFromRight bool
|
||||
}
|
||||
|
||||
var (
|
||||
matchers = map[byte]MatchRule{
|
||||
'{': {
|
||||
MatchByte: '}',
|
||||
StartFromRight: true,
|
||||
},
|
||||
'[': {
|
||||
MatchByte: ']',
|
||||
StartFromRight: true,
|
||||
},
|
||||
'"': {
|
||||
MatchByte: '"',
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func New(v []byte) Chunk {
|
||||
posRight := len(v) - 1
|
||||
if len(v) == 0 {
|
||||
posRight = 0
|
||||
}
|
||||
return Chunk{
|
||||
vector: coll.Vector[byte](v),
|
||||
posLeft: 0,
|
||||
posRight: posRight,
|
||||
}
|
||||
}
|
||||
|
||||
func (c Chunk) Child(left, right int) Chunk {
|
||||
sub := c.vector[left:right]
|
||||
return Chunk{
|
||||
vector: sub,
|
||||
posLeft: 0,
|
||||
posRight: len(sub),
|
||||
globLeft: (c.globLeft - c.posLeft) + left,
|
||||
globRight: (c.globRight - c.posRight) + right,
|
||||
}
|
||||
}
|
||||
|
||||
type ParseFunc[T any] func(T) (T, error)
|
||||
|
||||
func Parse[T any](c Chunk) ParseFunc[T] {
|
||||
switch c.vector[c.posLeft] {
|
||||
case '{':
|
||||
return ParseMap[T](c.CookieCutter())
|
||||
default:
|
||||
panic("not implemented")
|
||||
}
|
||||
// return can be:
|
||||
// * {}
|
||||
// * []
|
||||
// * ""
|
||||
// * 123
|
||||
// * true
|
||||
// * false
|
||||
// * null
|
||||
}
|
||||
|
||||
type Row struct {
|
||||
Name string
|
||||
Value Chunk
|
||||
}
|
||||
|
||||
func (c Chunk) String() string {
|
||||
return string(c.vector[c.posLeft : c.posRight+1])
|
||||
}
|
||||
|
||||
func (c Chunk) Row() (Row, error) {
|
||||
c = c.Seek()
|
||||
if c.vector[c.posLeft] != '"' {
|
||||
return Row{}, fmt.Errorf("%w: %c", ErrMapMemberNotString, c.vector[c.posLeft])
|
||||
}
|
||||
name, err := c.Match()
|
||||
if err != nil {
|
||||
return Row{}, fmt.Errorf("match: %w", err)
|
||||
}
|
||||
postName := c.Copy()
|
||||
postName.posLeft = name.posRight
|
||||
postName = postName.Skip()
|
||||
// Next we must get a :
|
||||
if postName.vector[postName.posLeft] != ':' {
|
||||
return Row{}, fmt.Errorf("%w '%c', expected ':'", ErrUnexpectedSymbol, postName.vector[postName.posLeft])
|
||||
}
|
||||
value, err := postName.Skip().ValueEnd()
|
||||
if err != nil {
|
||||
return Row{}, fmt.Errorf("value: %w", err)
|
||||
}
|
||||
|
||||
return Row{
|
||||
Name: name.String(),
|
||||
Value: value,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c Chunk) After(v Chunk) Chunk {
|
||||
c.posLeft = v.posLeft
|
||||
return c
|
||||
}
|
||||
|
||||
func ParseMap[T any](c Chunk) ParseFunc[T] {
|
||||
return func(t T) (T, error) {
|
||||
// mapper := parse.GetMap(t)
|
||||
// for {
|
||||
// row, err := c.Row()
|
||||
// if err != nil {
|
||||
// return t, err
|
||||
// }
|
||||
|
||||
// }
|
||||
panic("todo")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package chunk_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"sectorinf.com/emilis/flabk/pkg/ld/internal/parse/chunk"
|
||||
)
|
||||
|
||||
func TestSpace(t *testing.T) {
|
||||
that := require.New(t)
|
||||
ch := chunk.New([]byte(" hello world"))
|
||||
that.True(ch.AtSpace())
|
||||
}
|
||||
|
||||
func TestParseMap(t *testing.T) {
|
||||
type Hello struct {
|
||||
Hello string
|
||||
}
|
||||
ch := chunk.New([]byte(`"Hello": "world"`))
|
||||
h, err := chunk.ParseMap[Hello](ch)(Hello{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(h)
|
||||
}
|
||||
|
||||
func TestChild(t *testing.T) {
|
||||
type Hello struct {
|
||||
Hello string
|
||||
}
|
||||
ch := chunk.New([]byte(`"Hello": "world"`))
|
||||
child := ch.Child(5, 10)
|
||||
|
||||
fmt.Println(child)
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package parse
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"sectorinf.com/emilis/flabk/pkg/ld/internal/consts"
|
||||
)
|
||||
|
||||
type LazyMapFunc func(name string, value string)
|
||||
|
||||
func GetMap(v any) LazyMapFunc {
|
||||
val := reflect.ValueOf(v)
|
||||
// typ := reflect.TypeOf(v)
|
||||
switch val.Kind() {
|
||||
case reflect.Map:
|
||||
return func(name string, value string) {
|
||||
// val.SetMapIndex(reflect.ValueOf(name), value)
|
||||
}
|
||||
case reflect.Struct:
|
||||
// fields := GetStructFields(val, typ)
|
||||
return func(name, value string) {
|
||||
// val, ok := fields[name]
|
||||
// if ok {
|
||||
// val.Set(value)
|
||||
// }
|
||||
}
|
||||
default:
|
||||
panic("wrong")
|
||||
}
|
||||
}
|
||||
|
||||
func ParseAsValue(v string, valType reflect.Type) (any, error) {
|
||||
// Might not be necessary to trim
|
||||
v = strings.TrimSpace(v)
|
||||
switch valType.Kind() {
|
||||
case reflect.String:
|
||||
return v[1 : len(v)-1], nil
|
||||
case reflect.Bool:
|
||||
b, err := strconv.ParseBool(strings.ToLower(v))
|
||||
if err != nil {
|
||||
fmt.Errorf("boolean: %w", err)
|
||||
}
|
||||
return b, nil
|
||||
case reflect.Struct, reflect.Map:
|
||||
panic("todo")
|
||||
default:
|
||||
panic("todo")
|
||||
}
|
||||
}
|
||||
|
||||
func GetStructFields(val reflect.Value, typ reflect.Type) map[string]reflect.Value {
|
||||
total := val.NumField()
|
||||
out := map[string]reflect.Value{}
|
||||
for index := 0; index < total; index++ {
|
||||
cName := StructName(typ.Field(index))
|
||||
if cName != "-" {
|
||||
out[cName] = val.Field(index)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func StructName(v reflect.StructField) string {
|
||||
tag := v.Tag.Get(consts.PkgTag)
|
||||
if tag != "" {
|
||||
return tag
|
||||
}
|
||||
// Default to field name
|
||||
return v.Name
|
||||
}
|
|
@ -1,4 +1,8 @@
|
|||
// // Package asld handles JSON-LD for asflab
|
||||
// //
|
||||
// // This will not go well
|
||||
package asld
|
||||
package ld
|
||||
|
||||
const (
|
||||
pkgTag = "ld"
|
||||
)
|
|
@ -0,0 +1 @@
|
|||
package ld
|
|
@ -1,4 +1,4 @@
|
|||
package asld_test
|
||||
package ld_test
|
||||
|
||||
// import (
|
||||
// "encoding/json"
|
Loading…
Reference in New Issue