From 5c5e36cdfafa75e56adcc397daa9f8aaefc1b427 Mon Sep 17 00:00:00 2001 From: lash Date: Fri, 31 Mar 2023 21:08:06 +0100 Subject: [PATCH] Enfore single sink for map level --- draft.txt | 2 +- go/state/state.go | 20 ++++++++++++++---- go/state/state_test.go | 48 ++++++++++++++++++++++++++++++++++++++++-- go/vm/vm.go | 13 +++--------- go/vm/vm_test.go | 2 +- 5 files changed, 67 insertions(+), 18 deletions(-) diff --git a/draft.txt b/draft.txt index 9669e0b..f994f12 100644 --- 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 -SINK +SINK --- diff --git a/go/state/state.go b/go/state/state.go index c8c9087..ff1a074 100644 --- 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 index 8697a9c..d393264 100644 --- 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 index 917d60c..4bc1f00 100644 --- 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 index 4dab858..e16fc08 100644 --- 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