Add arg handling, invalid arg handling

This commit is contained in:
lash 2023-03-31 19:24:30 +01:00
parent 9f9ef86b9e
commit 78261239b2
Signed by untrusted user who does not match committer: lash
GPG Key ID: 21D2E7BB88C2A746
5 changed files with 123 additions and 32 deletions

View File

@ -7,20 +7,17 @@ import (
type Router struct {
selectors []string
symbols map[string]string
navigable bool
}
func NewRouter() Router {
return Router{
symbols: make(map[string]string),
navigable: true,
}
}
func NewStaticRouter(symbol string) Router {
return Router{
symbols: map[string]string{"_": symbol},
navigable: false,
}
}
@ -32,6 +29,9 @@ func(r *Router) Add(selector string, symbol string) error {
if (l > 255) {
return fmt.Errorf("selector too long (is %v, max 255)", l)
}
if selector[0] == '_' {
return fmt.Errorf("Invalid selector prefix '_'")
}
l = len(symbol)
if (l > 255) {
return fmt.Errorf("symbol too long (is %v, max 255)", l)

View File

@ -34,6 +34,14 @@ func NewState(bitSize uint64) State {
return st
}
func(st State) Where() string {
if len(st.ExecPath) == 0 {
return ""
}
l := len(st.ExecPath)
return st.ExecPath[l-1]
}
func(st State) WithCacheSize(cacheSize uint32) State {
st.CacheSize = cacheSize
return st

View File

@ -1,13 +1,35 @@
package vm
import (
"encoding/binary"
)
const VERSION = 0
const (
CATCH = iota
BACK = iota
CATCH
CROAK
LOAD
RELOAD
MAP
SINK
MOVE
_MAX
)
func NewLine(instructionList []byte, instruction uint16, args []string, post []byte, szPost []uint8) []byte {
b := []byte{0x00, 0x00}
binary.BigEndian.PutUint16(b, instruction)
for _, arg := range args {
b = append(b, uint8(len(arg)))
b = append(b, []byte(arg)...)
}
if post != nil {
b = append(b, uint8(len(post)))
b = append(b, post...)
}
if szPost != nil {
b = append(b, szPost...)
}
return append(instructionList, b...)
}

View File

@ -13,19 +13,39 @@ import (
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 {
return "", input, fmt.Errorf("zero length input")
}
sz := input[0]
out := input[1:1+sz]
return string(out), input[1+sz:], nil
}
func Apply(input []byte, instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, []byte, error) {
var err error
arg, input, err := argFromBytes(input)
if err != nil {
return st, input, err
}
rt := router.FromBytes(input)
sym := rt.Get(arg)
if sym == "" {
sym = rt.Default()
st.PutArg(arg)
}
if sym == "" {
instruction = NewLine([]byte{}, MOVE, []string{"_catch"}, nil , nil)
} else {
instruction = NewLine(instruction, MOVE, []string{sym}, nil, nil)
}
st, instruction, err = Run(instruction, st, rs, ctx)
if err != nil {
return st, instruction, err
}
rt := router.FromBytes(instruction)
sym := rt.Get(string(input))
if sym == "" {
sym = rt.Default()
st.PutArg(string(input))
}
return st, instruction, nil
}
@ -56,6 +76,9 @@ func Run(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Co
case SINK:
st, instruction, err = RunSink(instruction[2:], st, rs, ctx)
break
case MOVE:
st, instruction, err = RunMove(instruction[2:], st, rs, ctx)
break
default:
err = fmt.Errorf("Unhandled state: %v", op)
}
@ -88,8 +111,9 @@ func RunCatch(instruction []byte, st state.State, rs resource.Fetcher, ctx conte
if err != nil {
return st, instruction, err
}
_ = tail
st.Add(head, r, uint32(len(r)))
return st, tail, nil
return st, []byte{}, nil
}
func RunCroak(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, []byte, error) {
@ -98,8 +122,9 @@ func RunCroak(instruction []byte, st state.State, rs resource.Fetcher, ctx conte
return st, instruction, err
}
_ = head
_ = tail
st.Reset()
return st, tail, nil
return st, []byte{}, nil
}
func RunLoad(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, []byte, error) {
@ -135,7 +160,12 @@ func RunReload(instruction []byte, st state.State, rs resource.Fetcher, ctx cont
}
func RunMove(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, []byte, error) {
return st, nil, nil
head, tail, err := instructionSplit(instruction)
if err != nil {
return st, instruction, err
}
st.Down(head)
return st, tail, nil
}
func refresh(key string, sym []byte, rs resource.Fetcher, ctx context.Context) (string, error) {

View File

@ -3,13 +3,13 @@ package vm
import (
"bytes"
"context"
"encoding/binary"
"fmt"
"log"
"testing"
"text/template"
"git.defalsify.org/festive/resource"
"git.defalsify.org/festive/router"
"git.defalsify.org/festive/state"
)
@ -159,8 +159,8 @@ func TestRunMultiple(t *testing.T) {
st := state.NewState(5)
rs := TestResource{}
b := []byte{}
b = NewTestOp(b, LOAD, []string{"one"}, nil, []uint8{0})
b = NewTestOp(b, LOAD, []string{"two"}, nil, []uint8{42})
b = NewLine(b, LOAD, []string{"one"}, nil, []uint8{0})
b = NewLine(b, LOAD, []string{"two"}, nil, []uint8{42})
st, _, err := Run(b, st, &rs, context.TODO())
if err != nil {
t.Error(err)
@ -171,8 +171,8 @@ func TestRunReload(t *testing.T) {
st := state.NewState(5)
rs := TestResource{}
b := []byte{}
b = NewTestOp(b, LOAD, []string{"dyn"}, nil, []uint8{0})
b = NewTestOp(b, MAP, []string{"dyn"}, nil, nil)
b = NewLine(b, LOAD, []string{"dyn"}, nil, []uint8{0})
b = NewLine(b, MAP, []string{"dyn"}, nil, nil)
st, _, err := Run(b, st, &rs, context.TODO())
if err != nil {
t.Error(err)
@ -186,7 +186,7 @@ func TestRunReload(t *testing.T) {
}
dynVal = "baz"
b = []byte{}
b = NewTestOp(b, RELOAD, []string{"dyn"}, nil, nil)
b = NewLine(b, RELOAD, []string{"dyn"}, nil, nil)
st, _, err = Run(b, st, &rs, context.TODO())
if err != nil {
t.Error(err)
@ -202,19 +202,50 @@ func TestRunReload(t *testing.T) {
}
func NewTestOp(instructionList []byte, instruction uint16, args []string, post []byte, szPost []uint8) []byte {
b := []byte{0x00, 0x00}
binary.BigEndian.PutUint16(b, instruction)
for _, arg := range args {
b = append(b, uint8(len(arg)))
b = append(b, []byte(arg)...)
func TestRunArg(t *testing.T) {
st := state.NewState(5)
rt := router.NewRouter()
rt.Add("foo", "bar")
rt.Add("baz", "xyzzy")
b := []byte{0x03}
b = append(b, []byte("baz")...)
b = append(b, rt.ToBytes()...)
var err error
st, b, err = Apply(b, []byte{}, st, nil, context.TODO())
if err != nil {
t.Error(err)
}
if post != nil {
b = append(b, uint8(len(post)))
b = append(b, post...)
l := len(b)
if l != 0 {
t.Errorf("expected empty remainder, got length %v: %v", l, b)
}
if szPost != nil {
b = append(b, szPost...)
r := st.Where()
if r != "xyzzy" {
t.Errorf("expected where-state baz, got %v", r)
}
return append(instructionList, b...)
}
func TestRunArgInvalid(t *testing.T) {
st := state.NewState(5)
rt := router.NewRouter()
rt.Add("foo", "bar")
rt.Add("baz", "xyzzy")
b := []byte{0x03}
b = append(b, []byte("bar")...)
b = append(b, rt.ToBytes()...)
var err error
st, b, err = Apply(b, []byte{}, st, nil, context.TODO())
if err != nil {
t.Error(err)
}
l := len(b)
if l != 0 {
t.Errorf("expected empty remainder, got length %v: %v", l, b)
}
r := st.Where()
if r != "_catch" {
t.Errorf("expected where-state _catch, got %v", r)
}
}