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