2023-03-31 11:52:04 +02:00
package state
import (
2023-03-31 13:56:11 +02:00
"fmt"
2023-03-31 14:06:59 +02:00
"log"
2023-04-10 10:05:48 +02:00
"strings"
2023-03-31 11:52:04 +02:00
)
2023-04-12 09:42:37 +02:00
type IndexError struct {
}
func ( err * IndexError ) Error ( ) string {
return fmt . Sprintf ( "already at first index" )
}
2023-03-31 23:35:13 +02:00
// State holds the command stack, error condition of a unique execution session.
//
// It also holds cached values for all results of executed symbols.
//
// Cached values are linked to the command stack level it which they were loaded. When they go out of scope they are freed.
//
// Values must be mapped to a level in order to be available for retrieval and count towards size
//
// It can hold a single argument, which is freed once it is read
//
// Symbols are loaded with individual size limitations. The limitations apply if a load symbol is updated. Symbols may be added with a 0-value for limits, called a "sink." If mapped, the sink will consume all net remaining size allowance unused by other symbols. Only one sink may be mapped per level.
//
// Symbol keys do not count towards cache size limitations.
2023-04-01 09:36:26 +02:00
//
2023-04-01 23:19:12 +02:00
// 8 first flags are reserved.
2023-03-31 11:52:04 +02:00
type State struct {
2023-04-13 00:42:36 +02:00
Code [ ] byte // Pending bytecode to execute
ExecPath [ ] string // Command symbols stack
BitSize uint32 // size of (32-bit capacity) bit flag byte array
SizeIdx uint16
2023-04-13 01:38:33 +02:00
Flags [ ] byte // Error state
2023-04-13 11:33:24 +02:00
Moves uint32 // Number of times navigation has been performed
2023-04-01 23:19:12 +02:00
input [ ] byte // Last input
2023-03-31 11:52:04 +02:00
}
2023-04-08 17:09:10 +02:00
// number of bytes necessary to represent a bitfield of the given size.
2023-04-13 00:42:36 +02:00
func toByteSize ( BitSize uint32 ) uint8 {
if BitSize == 0 {
2023-04-01 09:36:26 +02:00
return 0
}
2023-04-13 00:42:36 +02:00
n := BitSize % 8
2023-03-31 11:52:04 +02:00
if n > 0 {
2023-04-13 00:42:36 +02:00
BitSize += ( 8 - n )
2023-03-31 11:52:04 +02:00
}
2023-04-13 00:42:36 +02:00
return uint8 ( BitSize / 8 )
2023-04-01 09:36:26 +02:00
}
2023-03-31 11:52:04 +02:00
2023-04-01 09:36:26 +02:00
// Retrieve the state of a state flag
func getFlag ( bitIndex uint32 , bitField [ ] byte ) bool {
byteIndex := bitIndex / 8
localBitIndex := bitIndex % 8
b := bitField [ byteIndex ]
return ( b & ( 1 << localBitIndex ) ) > 0
}
2023-04-13 00:42:36 +02:00
// NewState creates a new State object with BitSize number of error condition states in ADDITION to the 8 builtin flags.
func NewState ( BitSize uint32 ) State {
2023-03-31 16:24:29 +02:00
st := State {
2023-04-13 00:42:36 +02:00
BitSize : BitSize + 8 ,
2023-03-31 11:52:04 +02:00
}
2023-04-13 00:42:36 +02:00
byteSize := toByteSize ( BitSize + 8 )
2023-04-01 09:36:26 +02:00
if byteSize > 0 {
2023-04-13 01:38:33 +02:00
st . Flags = make ( [ ] byte , byteSize )
2023-04-01 09:36:26 +02:00
} else {
2023-04-13 01:38:33 +02:00
st . Flags = [ ] byte { }
2023-04-01 09:36:26 +02:00
}
2023-03-31 16:24:29 +02:00
return st
2023-03-31 11:52:04 +02:00
}
2023-04-01 00:25:05 +02:00
// SetFlag sets the flag at the given bit field index
2023-04-01 00:17:44 +02:00
//
// Returns true if bit state was changed.
//
// Fails if bitindex is out of range.
func ( st * State ) SetFlag ( bitIndex uint32 ) ( bool , error ) {
2023-04-13 00:42:36 +02:00
if bitIndex + 1 > st . BitSize {
return false , fmt . Errorf ( "bit index %v is out of range of bitfield size %v" , bitIndex , st . BitSize )
2023-04-01 00:17:44 +02:00
}
2023-04-13 01:38:33 +02:00
r := getFlag ( bitIndex , st . Flags )
2023-04-01 00:17:44 +02:00
if r {
return false , nil
}
byteIndex := bitIndex / 8
localBitIndex := bitIndex % 8
2023-04-13 01:38:33 +02:00
b := st . Flags [ byteIndex ]
st . Flags [ byteIndex ] = b | ( 1 << localBitIndex )
2023-04-01 00:17:44 +02:00
return true , nil
}
// ResetFlag resets the flag at the given bit field index.
//
// Returns true if bit state was changed.
//
// Fails if bitindex is out of range.
func ( st * State ) ResetFlag ( bitIndex uint32 ) ( bool , error ) {
2023-04-13 00:42:36 +02:00
if bitIndex + 1 > st . BitSize {
return false , fmt . Errorf ( "bit index %v is out of range of bitfield size %v" , bitIndex , st . BitSize )
2023-04-01 00:17:44 +02:00
}
2023-04-13 01:38:33 +02:00
r := getFlag ( bitIndex , st . Flags )
2023-04-01 00:17:44 +02:00
if ! r {
return false , nil
}
byteIndex := bitIndex / 8
localBitIndex := bitIndex % 8
2023-04-13 01:38:33 +02:00
b := st . Flags [ byteIndex ]
st . Flags [ byteIndex ] = b & ( ^ ( 1 << localBitIndex ) )
2023-04-01 00:17:44 +02:00
return true , nil
}
2023-04-13 10:16:17 +02:00
// ResetBaseFlags restes all builtin flags not writeable by client.
func ( st * State ) ResetBaseFlags ( ) {
st . Flags [ 0 ] = 0
}
2023-04-01 00:17:44 +02:00
// GetFlag returns the state of the flag at the given bit field index.
//
// Fails if bit field index is out of range.
func ( st * State ) GetFlag ( bitIndex uint32 ) ( bool , error ) {
2023-04-13 00:42:36 +02:00
if bitIndex + 1 > st . BitSize {
return false , fmt . Errorf ( "bit index %v is out of range of bitfield size %v" , bitIndex , st . BitSize )
2023-04-01 00:17:44 +02:00
}
2023-04-13 01:38:33 +02:00
return getFlag ( bitIndex , st . Flags ) , nil
2023-04-01 09:36:26 +02:00
}
// FlagBitSize reports the amount of bits available in the bit field index.
func ( st * State ) FlagBitSize ( ) uint32 {
2023-04-13 00:42:36 +02:00
return st . BitSize
2023-04-01 09:36:26 +02:00
}
2023-04-01 10:03:03 +02:00
// FlagBitSize reports the amount of bits available in the bit field index.
func ( st * State ) FlagByteSize ( ) uint8 {
2023-04-13 01:38:33 +02:00
return uint8 ( len ( st . Flags ) )
2023-04-01 10:03:03 +02:00
}
2023-04-06 11:08:40 +02:00
// MatchFlag matches the current state of the given flag.
//
// The flag is specified given its bit index in the bit field.
//
// If invertMatch is set, a positive result will be returned if the flag is not set.
func ( st * State ) MatchFlag ( sig uint32 , invertMatch bool ) ( bool , error ) {
r , err := st . GetFlag ( sig )
if err != nil {
return false , err
}
if invertMatch {
if ! r {
return true , nil
}
} else if r {
return true , nil
}
return false , nil
}
2023-04-01 09:36:26 +02:00
// GetIndex scans a byte slice in same order as in storage, and returns the index of the first set bit.
//
// If the given byte slice is too small for the bit field bitsize, the check will terminate at end-of-data without error.
func ( st * State ) GetIndex ( flags [ ] byte ) bool {
var globalIndex uint32
2023-04-13 00:42:36 +02:00
if st . BitSize == 0 {
2023-04-01 09:36:26 +02:00
return false
}
if len ( flags ) == 0 {
return false
}
var byteIndex uint8
var localIndex uint8
l := uint8 ( len ( flags ) )
var i uint32
2023-04-13 00:42:36 +02:00
for i = 0 ; i < st . BitSize ; i ++ {
2023-04-01 09:36:26 +02:00
testVal := flags [ byteIndex ] & ( 1 << localIndex )
2023-04-13 01:38:33 +02:00
if ( testVal & st . Flags [ byteIndex ] ) > 0 {
2023-04-01 09:36:26 +02:00
return true
}
globalIndex += 1
if globalIndex % 8 == 0 {
byteIndex += 1
localIndex = 0
if byteIndex > ( l - 1 ) {
return false
}
} else {
localIndex += 1
}
}
return false
2023-04-01 00:17:44 +02:00
}
2023-03-31 23:35:13 +02:00
// Where returns the current active rendering symbol.
2023-04-08 12:31:05 +02:00
func ( st * State ) Where ( ) ( string , uint16 ) {
2023-04-13 00:42:36 +02:00
if len ( st . ExecPath ) == 0 {
2023-04-07 12:31:30 +02:00
return "" , 0
2023-03-31 23:35:13 +02:00
}
2023-04-13 00:42:36 +02:00
l := len ( st . ExecPath )
return st . ExecPath [ l - 1 ] , st . SizeIdx
2023-03-31 23:35:13 +02:00
}
2023-04-08 09:54:55 +02:00
// Next moves to the next sink page index.
2023-04-08 12:31:05 +02:00
func ( st * State ) Next ( ) ( uint16 , error ) {
2023-04-13 00:42:36 +02:00
if len ( st . ExecPath ) == 0 {
2023-04-08 10:31:32 +02:00
return 0 , fmt . Errorf ( "state root node not yet defined" )
}
2023-04-13 00:42:36 +02:00
st . SizeIdx += 1
2023-04-08 12:31:05 +02:00
s , idx := st . Where ( )
log . Printf ( "next page for %s: %v" , s , idx )
2023-04-13 11:33:24 +02:00
st . Moves += 1
2023-04-13 00:42:36 +02:00
return st . SizeIdx , nil
2023-04-08 09:54:55 +02:00
}
// Previous moves to the next sink page index.
//
// Fails if try to move beyond index 0.
func ( st * State ) Previous ( ) ( uint16 , error ) {
2023-04-13 00:42:36 +02:00
if len ( st . ExecPath ) == 0 {
2023-04-08 10:31:32 +02:00
return 0 , fmt . Errorf ( "state root node not yet defined" )
}
2023-04-13 00:42:36 +02:00
if st . SizeIdx == 0 {
2023-04-12 09:42:37 +02:00
return 0 , & IndexError { } // ("already at first index")
2023-04-08 09:54:55 +02:00
}
2023-04-13 00:42:36 +02:00
st . SizeIdx -= 1
2023-04-08 12:31:05 +02:00
s , idx := st . Where ( )
log . Printf ( "previous page for %s: %v" , s , idx )
2023-04-13 11:33:24 +02:00
st . Moves += 1
2023-04-13 00:42:36 +02:00
return st . SizeIdx , nil
2023-04-08 09:54:55 +02:00
}
// Sides informs the caller which index page options will currently succeed.
//
// Two values are returned, for the "next" and "previous" options in that order. A false value means the option is not available in the current state.
func ( st * State ) Sides ( ) ( bool , bool ) {
2023-04-13 00:42:36 +02:00
if len ( st . ExecPath ) == 0 {
2023-04-08 10:31:32 +02:00
return false , false
}
2023-04-08 09:54:55 +02:00
next := true
2023-04-13 00:42:36 +02:00
log . Printf ( "sides %v" , st . SizeIdx )
if st . SizeIdx == 0 {
2023-04-08 09:54:55 +02:00
return next , false
}
return next , true
}
2023-04-08 10:31:32 +02:00
// Top returns true if currently at topmode node.
//
// Fails if first Down() was never called.
func ( st * State ) Top ( ) ( bool , error ) {
2023-04-13 00:42:36 +02:00
if len ( st . ExecPath ) == 0 {
2023-04-08 10:31:32 +02:00
return false , fmt . Errorf ( "state root node not yet defined" )
}
2023-04-13 00:42:36 +02:00
return len ( st . ExecPath ) == 1 , nil
2023-04-08 10:31:32 +02:00
}
2023-03-31 23:35:13 +02:00
// Down adds the given symbol to the command stack.
//
// Clears mapping and sink.
2023-04-08 17:09:10 +02:00
func ( st * State ) Down ( input string ) error {
2023-04-13 00:42:36 +02:00
st . ExecPath = append ( st . ExecPath , input )
st . SizeIdx = 0
2023-04-13 11:33:24 +02:00
st . Moves += 1
2023-04-08 17:09:10 +02:00
return nil
2023-03-31 22:18:54 +02:00
}
2023-03-31 23:35:13 +02:00
// Up removes the latest symbol to the command stack, and make the previous symbol current.
//
// Frees all symbols and associated values loaded at the previous stack level. Cache capacity is increased by the corresponding amount.
//
// Clears mapping and sink.
//
// Fails if called at top frame.
2023-04-08 09:14:14 +02:00
func ( st * State ) Up ( ) ( string , error ) {
2023-04-13 00:42:36 +02:00
l := len ( st . ExecPath )
2023-04-08 17:09:10 +02:00
if l == 0 {
2023-04-08 09:14:14 +02:00
return "" , fmt . Errorf ( "exit called beyond top frame" )
2023-03-31 22:18:54 +02:00
}
2023-04-13 00:42:36 +02:00
log . Printf ( "execpath before %v" , st . ExecPath )
st . ExecPath = st . ExecPath [ : l - 1 ]
2023-04-08 09:14:14 +02:00
sym := ""
2023-04-13 00:42:36 +02:00
if len ( st . ExecPath ) > 0 {
sym = st . ExecPath [ len ( st . ExecPath ) - 1 ]
2023-04-08 09:14:14 +02:00
}
2023-04-13 00:42:36 +02:00
st . SizeIdx = 0
log . Printf ( "execpath after %v" , st . ExecPath )
2023-04-13 11:33:24 +02:00
st . Moves += 1
2023-04-08 09:14:14 +02:00
return sym , nil
2023-03-31 11:59:55 +02:00
}
2023-03-31 23:35:13 +02:00
// Depth returns the current call stack depth.
2023-03-31 15:04:08 +02:00
func ( st * State ) Depth ( ) uint8 {
2023-04-13 00:42:36 +02:00
return uint8 ( len ( st . ExecPath ) - 1 )
2023-04-06 16:21:26 +02:00
}
2023-04-01 15:47:03 +02:00
// Appendcode adds the given bytecode to the end of the existing code.
func ( st * State ) AppendCode ( b [ ] byte ) error {
2023-04-13 00:42:36 +02:00
st . Code = append ( st . Code , b ... )
2023-04-02 10:07:53 +02:00
log . Printf ( "code changed to 0x%x" , b )
2023-04-01 15:47:03 +02:00
return nil
}
// SetCode replaces the current bytecode with the given bytecode.
func ( st * State ) SetCode ( b [ ] byte ) {
2023-04-02 10:07:53 +02:00
log . Printf ( "code set to 0x%x" , b )
2023-04-13 00:42:36 +02:00
st . Code = b
2023-04-01 15:47:03 +02:00
}
2023-04-01 23:19:12 +02:00
// Get the remaning cached bytecode
2023-04-01 15:47:03 +02:00
func ( st * State ) GetCode ( ) ( [ ] byte , error ) {
2023-04-13 00:42:36 +02:00
b := st . Code
st . Code = [ ] byte { }
2023-04-01 15:47:03 +02:00
return b , nil
}
2023-04-01 23:19:12 +02:00
// GetInput gets the most recent client input.
func ( st * State ) GetInput ( ) ( [ ] byte , error ) {
if st . input == nil {
return nil , fmt . Errorf ( "no input has been set" )
}
return st . input , nil
}
// SetInput is used to record the latest client input.
func ( st * State ) SetInput ( input [ ] byte ) error {
l := len ( input )
if l > 255 {
return fmt . Errorf ( "input size %v too large (limit %v)" , l , 255 )
}
st . input = input
return nil
}
2023-04-10 16:26:18 +02:00
func ( st * State ) Reset ( ) error {
return nil
2023-04-09 10:44:32 +02:00
}
2023-04-10 10:05:48 +02:00
func ( st State ) String ( ) string {
2023-04-13 11:33:24 +02:00
return fmt . Sprintf ( "moves %v idx %v path: %s" , st . Moves , st . SizeIdx , strings . Join ( st . ExecPath , "/" ) )
2023-04-10 10:05:48 +02:00
}