commit 5c5e36cdfafa75e56adcc397daa9f8aaefc1b427
parent d84720d59571a038b3c2f956c53572a1bd088356
Author: lash <dev@holbrook.no>
Date: Fri, 31 Mar 2023 21:08:06 +0100
Enfore single sink for map level
Diffstat:
5 files changed, 67 insertions(+), 18 deletions(-)
diff --git a/draft.txt b/draft.txt
@@ -138,7 +138,7 @@ Compiler must croak if:
should generate warnings if sink cannot render a single enrry (of list)
MAP <symbol> <maxsize> <minsize>
-SINK <symbol>
+SINK <symbol> <maxsize>
---
diff --git a/go/state/state.go b/go/state/state.go
@@ -14,7 +14,8 @@ type State struct {
ExecPath []string
Arg *string
sizes map[string]uint16
- idx uint16
+ sink *string
+ //sizeIdx uint16
}
func NewState(bitSize uint64) State {
@@ -66,6 +67,7 @@ func(st *State) Down(input string) {
st.CacheMap = make(map[string]string)
st.sizes = make(map[string]uint16)
st.ExecPath = append(st.ExecPath, input)
+ st.sink = nil
}
func(st *State) Add(key string, value string, sizeHint uint16) error {
@@ -119,12 +121,19 @@ func(st *State) Update(key string, value string) error {
return nil
}
-func(st *State) Map(k string) error {
+func(st *State) Map(key string) error {
m, err := st.Get()
if err != nil {
return err
}
- st.CacheMap[k] = m[k]
+ l := st.sizes[key]
+ if l == 0 {
+ if st.sink != nil {
+ return fmt.Errorf("sink already set to symbol '%v'", *st.sink)
+ }
+ st.sink = &key
+ }
+ st.CacheMap[key] = m[key]
return nil
}
@@ -161,6 +170,7 @@ func(st *State) Up() error {
}
st.Cache = st.Cache[:l]
st.ExecPath = st.ExecPath[:l]
+ st.sink = nil
return nil
}
@@ -177,6 +187,7 @@ func(st *State) Check(key string) bool {
return st.frameOf(key) == -1
}
+// Returns size used by values, and remaining size available
func(st *State) Size() (uint32, uint32) {
var l int
var c uint16
@@ -184,7 +195,8 @@ func(st *State) Size() (uint32, uint32) {
l += len(v)
c += st.sizes[k]
}
- return uint32(l), uint32(c)
+ r := uint32(l)
+ return r, uint32(c)-r
}
// return 0-indexed frame number where key is defined. -1 if not defined
diff --git a/go/state/state_test.go b/go/state/state_test.go
@@ -130,7 +130,7 @@ func TestStateCurrentSize(t *testing.T) {
if err != nil {
t.Error(err)
}
- err = st.Add("baz", "inkypinkyblinkyclyde", 40)
+ err = st.Add("baz", "inkypinkyblinkyclyde", 51)
if err != nil {
t.Error(err)
}
@@ -142,7 +142,51 @@ func TestStateCurrentSize(t *testing.T) {
if l != 25 {
t.Errorf("expected actual length 25, got %v", l)
}
- if c != 50 {
+ if c != 36 {
t.Errorf("expected actual length 50, got %v", c)
}
}
+
+func TestStateMapSink(t *testing.T) {
+ st := NewState(17)
+ st.Down("one")
+ err := st.Add("foo", "bar", 0)
+ if err != nil {
+ t.Error(err)
+ }
+ st.Down("two")
+ err = st.Add("bar", "xyzzy", 6)
+ if err != nil {
+ t.Error(err)
+ }
+ err = st.Add("baz", "bazbaz", 18)
+ if err != nil {
+ t.Error(err)
+ }
+ err = st.Add("xyzzy", "plugh", 0)
+ if err != nil {
+ t.Error(err)
+ }
+ err = st.Map("foo")
+ if err != nil {
+ t.Error(err)
+ }
+ err = st.Map("xyzzy")
+ if err == nil {
+ t.Errorf("Expected fail on duplicate sink")
+ }
+ err = st.Map("baz")
+ if err != nil {
+ t.Error(err)
+ }
+ st.Down("three")
+ err = st.Map("foo")
+ if err != nil {
+ t.Error(err)
+ }
+ st.Up()
+ err = st.Map("foo")
+ if err != nil {
+ t.Error(err)
+ }
+}
diff --git a/go/vm/vm.go b/go/vm/vm.go
@@ -11,7 +11,7 @@ import (
"git.defalsify.org/festive/state"
)
-type Runner func(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, []byte, error)
+//type Runner func(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, []byte, error)
func argFromBytes(input []byte) (string, []byte, error) {
if len(input) == 0 {
@@ -76,9 +76,6 @@ func Run(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Co
case MAP:
st, instruction, err = RunMap(instruction[2:], st, rs, ctx)
break
- case SINK:
- st, instruction, err = RunSink(instruction[2:], st, rs, ctx)
- break
case MOVE:
st, instruction, err = RunMove(instruction[2:], st, rs, ctx)
break
@@ -100,12 +97,8 @@ func RunMap(instruction []byte, st state.State, rs resource.Fetcher, ctx context
if err != nil {
return st, instruction, err
}
- st.Map(head)
- return st, tail, nil
-}
-
-func RunSink(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, []byte, error) {
- return st, nil, nil
+ err = st.Map(head)
+ return st, tail, err
}
func RunCatch(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, []byte, error) {
diff --git a/go/vm/vm_test.go b/go/vm/vm_test.go
@@ -259,7 +259,7 @@ func TestRunArgInstructions(t *testing.T) {
b = append(b, rt.ToBytes()...)
bi := NewLine([]byte{}, LOAD, []string{"one"}, nil, []uint8{0})
- bi = NewLine(bi, LOAD, []string{"two"}, nil, []uint8{0})
+ bi = NewLine(bi, LOAD, []string{"two"}, nil, []uint8{3})
bi = NewLine(bi, MAP, []string{"one"}, nil, nil)
bi = NewLine(bi, MAP, []string{"two"}, nil, nil)
var err error