state.go (10884B)
1 package state 2 3 import ( 4 "fmt" 5 "strings" 6 7 "git.defalsify.org/vise.git/lang" 8 ) 9 10 const ( 11 INPUT_LIMIT = 255 12 ) 13 14 var ( 15 IndexError = fmt.Errorf("already at first index") 16 MaxLevel = 128 17 ) 18 19 // State holds the command stack, error condition of a unique execution session. 20 // 21 // It also holds cached values for all results of executed symbols. 22 // 23 // Cached values are linked to the command stack level it which they were loaded. When they go out of scope they are freed. 24 // 25 // It can hold a single argument, which is freed once it is read. 26 // 27 // Values must be mapped to a level in order to be available for retrieval and count towards size. 28 // 29 // 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. 30 // 31 // Symbol keys do not count towards cache size limitations. 32 // 33 // 8 first flags are reserved. 34 type State struct { 35 Code []byte // Pending bytecode to execute 36 ExecPath []string // Command symbols stack 37 BitSize uint32 // Size of (32-bit capacity) bit flag byte array 38 SizeIdx uint16 // Lateral page browse index in current frame 39 Flags []byte // Error state 40 Moves uint32 // Number of times navigation has been performed 41 Language *lang.Language // Language selector for rendering 42 input []byte // Last input 43 debug bool // Make string representation more human friendly 44 invalid bool 45 } 46 47 // number of bytes necessary to represent a bitfield of the given size. 48 func toByteSize(BitSize uint32) uint8 { 49 if BitSize == 0 { 50 return 0 51 } 52 n := BitSize % 8 53 if n > 0 { 54 BitSize += (8 - n) 55 } 56 return uint8(BitSize / 8) 57 } 58 59 // Invalidate marks a state as invalid. 60 // 61 // An invalid state should not be persisted or propagated 62 func(st *State) Invalidate() { 63 st.invalid = true 64 } 65 66 // Invalid returns true if state is invalid. 67 // 68 // An invalid state should not be persisted or propagated 69 func(st *State) Invalid() bool { 70 return st.invalid 71 } 72 73 //// Retrieve the state of a state flag 74 //func getFlag(bitIndex uint32, bitField []byte) bool { 75 // byteIndex := bitIndex / 8 76 // localBitIndex := bitIndex % 8 77 // b := bitField[byteIndex] 78 // return (b & (1 << localBitIndex)) > 0 79 //} 80 81 // NewState creates a new State object with BitSize number of error condition states in ADDITION to the 8 builtin flags. 82 func NewState(BitSize uint32) *State { 83 st := &State{ 84 BitSize: BitSize + 8, 85 } 86 byteSize := toByteSize(BitSize + 8) 87 if byteSize > 0 { 88 st.Flags = make([]byte, byteSize) 89 } else { 90 st.Flags = []byte{} 91 } 92 return st 93 } 94 95 // UseDebug enables rendering of registered string values of state flags in the string representation. 96 func(st *State) UseDebug() { 97 st.debug = true 98 } 99 100 // SetFlag sets the flag at the given bit field index 101 // 102 // Returns true if bit state was changed. 103 // 104 // Fails if bitindex is out of range. 105 func(st *State) SetFlag(bitIndex uint32) bool { 106 if bitIndex + 1 > st.BitSize { 107 panic(fmt.Sprintf("bit index %v is out of range of bitfield size %v", bitIndex, st.BitSize)) 108 } 109 r := getFlag(bitIndex, st.Flags) 110 if r { 111 return false 112 } 113 byteIndex := bitIndex / 8 114 localBitIndex := bitIndex % 8 115 b := st.Flags[byteIndex] 116 st.Flags[byteIndex] = b | (1 << localBitIndex) 117 return true 118 } 119 120 121 // ResetFlag resets the flag at the given bit field index. 122 // 123 // Returns true if bit state was changed. 124 // 125 // Fails if bitindex is out of range. 126 func(st *State) ResetFlag(bitIndex uint32) bool { 127 if bitIndex + 1 > st.BitSize { 128 panic(fmt.Sprintf("bit index %v is out of range of bitfield size %v", bitIndex, st.BitSize)) 129 } 130 r := getFlag(bitIndex, st.Flags) 131 if !r { 132 return false 133 } 134 byteIndex := bitIndex / 8 135 localBitIndex := bitIndex % 8 136 b := st.Flags[byteIndex] 137 st.Flags[byteIndex] = b & (^(1 << localBitIndex)) 138 return true 139 } 140 141 // GetFlag returns the state of the flag at the given bit field index. 142 // 143 // Fails if bit field index is out of range. 144 func(st *State) GetFlag(bitIndex uint32) bool { 145 if bitIndex + 1 > st.BitSize { 146 panic(fmt.Sprintf("bit index %v is out of range of bitfield size %v", bitIndex, st.BitSize)) 147 } 148 return getFlag(bitIndex, st.Flags) 149 } 150 151 // FlagBitSize reports the amount of bits available in the bit field index. 152 func(st *State) FlagBitSize() uint32 { 153 return st.BitSize 154 } 155 156 // FlagBitSize reports the amount of bits available in the bit field index. 157 func(st *State) FlagByteSize() uint8 { 158 return uint8(len(st.Flags)) 159 } 160 161 // MatchFlag matches the current state of the given flag. 162 // 163 // The flag is specified given its bit index in the bit field. 164 // 165 // If matchSet is set, a positive result will be returned if the flag is set. 166 func(st *State) MatchFlag(sig uint32, matchSet bool) bool { 167 r := st.GetFlag(sig) 168 return matchSet == r 169 } 170 171 // GetIndex scans a byte slice in same order as in storage, and returns the index of the first set bit. 172 // 173 // If the given byte slice is too small for the bit field bitsize, the check will terminate at end-of-data without error. 174 func(st *State) GetIndex(flags []byte) bool { 175 var globalIndex uint32 176 if st.BitSize == 0 { 177 return false 178 } 179 if len(flags) == 0 { 180 return false 181 } 182 var byteIndex uint8 183 var localIndex uint8 184 l := uint8(len(flags)) 185 var i uint32 186 for i = 0; i < st.BitSize; i++ { 187 testVal := flags[byteIndex] & (1 << localIndex) 188 if (testVal & st.Flags[byteIndex]) > 0 { 189 return true 190 } 191 globalIndex += 1 192 if globalIndex % 8 == 0 { 193 byteIndex += 1 194 localIndex = 0 195 if byteIndex > (l - 1) { 196 return false 197 } 198 } else { 199 localIndex += 1 200 } 201 } 202 return false 203 } 204 205 // Where returns the current active rendering symbol. 206 func(st *State) Where() (string, uint16) { 207 if len(st.ExecPath) == 0 { 208 return "", 0 209 } 210 l := len(st.ExecPath) 211 return st.ExecPath[l-1], st.SizeIdx 212 } 213 214 // Next moves to the next sink page index. 215 func(st *State) Next() (uint16, error) { 216 if len(st.ExecPath) == 0 { 217 return 0, fmt.Errorf("state root node not yet defined") 218 } 219 st.SizeIdx += 1 220 s, idx := st.Where() 221 logg.Debugf("next page", "location", s, "index", idx) 222 st.Moves += 1 223 return st.SizeIdx, nil 224 } 225 226 func(st *State) Same() { 227 st.Moves += 1 228 } 229 230 // Previous moves to the next sink page index. 231 // 232 // Fails if try to move beyond index 0. 233 func(st *State) Previous() (uint16, error) { 234 if len(st.ExecPath) == 0 { 235 return 0, fmt.Errorf("state root node not yet defined") 236 } 237 if st.SizeIdx == 0 { 238 return 0, IndexError 239 } 240 st.SizeIdx -= 1 241 s, idx := st.Where() 242 logg.Debugf("previous page", "location", s, "index", idx) 243 st.Moves += 1 244 return st.SizeIdx, nil 245 } 246 247 // Sides informs the caller which index page options will currently succeed. 248 // 249 // 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. 250 func(st *State) Sides() (bool, bool) { 251 if len(st.ExecPath) == 0 { 252 return false, false 253 } 254 next := true 255 logg.Tracef("sides", "index", st.SizeIdx) 256 if st.SizeIdx == 0 { 257 return next, false 258 } 259 return next, true 260 } 261 262 // Top returns true if currently at topmode node. 263 // 264 // Fails if first Down() was never called. 265 func(st *State) Top() (bool, error) { 266 if len(st.ExecPath) == 0 { 267 return false, fmt.Errorf("state root node not yet defined") 268 } 269 return len(st.ExecPath) == 1, nil 270 } 271 272 // Down adds the given symbol to the command stack. 273 // 274 // Clears mapping and sink. 275 func(st *State) Down(input string) error { 276 var n uint16 277 l := len(st.ExecPath) 278 if l > MaxLevel { 279 panic("maxlevel") 280 return fmt.Errorf("max levels exceeded (%d)", n) 281 } 282 if l > 0 { 283 if st.ExecPath[l-1] == input { 284 s := fmt.Sprintf("down into same node as previous: %v -> '%s'", st.ExecPath, input) 285 panic(s) 286 } 287 } 288 st.ExecPath = append(st.ExecPath, input) 289 st.SizeIdx = 0 290 st.Moves += 1 291 return nil 292 } 293 294 // Up removes the latest symbol to the command stack, and make the previous symbol current. 295 // 296 // Frees all symbols and associated values loaded at the previous stack level. Cache capacity is increased by the corresponding amount. 297 // 298 // Clears mapping and sink. 299 // 300 // Fails if called at top frame. 301 func(st *State) Up() (string, error) { 302 l := len(st.ExecPath) 303 if l == 0 { 304 return "", fmt.Errorf("exit called beyond top frame") 305 } 306 logg.Tracef("execpath before", "path", st.ExecPath) 307 st.ExecPath = st.ExecPath[:l-1] 308 sym := "" 309 if len(st.ExecPath) > 0 { 310 sym = st.ExecPath[len(st.ExecPath)-1] 311 } 312 st.SizeIdx = 0 313 logg.Tracef("execpath after", "path", st.ExecPath) 314 st.Moves += 1 315 return sym, nil 316 } 317 318 // Depth returns the current call stack depth. 319 func(st *State) Depth() int { 320 return len(st.ExecPath)-1 321 } 322 323 // Appendcode adds the given bytecode to the end of the existing code. 324 func(st *State) AppendCode(b []byte) error { 325 st.Code = append(st.Code, b...) 326 logg.Debugf("code changed (append)", "code", b) 327 return nil 328 } 329 330 // SetCode replaces the current bytecode with the given bytecode. 331 func(st *State) SetCode(b []byte) { 332 logg.Debugf("code changed (set)", "code", b) 333 st.Code = b 334 } 335 336 // Get the remaning cached bytecode 337 func(st *State) GetCode() ([]byte, error) { 338 b := st.Code 339 st.Code = []byte{} 340 return b, nil 341 } 342 343 // GetInput gets the most recent client input. 344 func(st *State) GetInput() ([]byte, error) { 345 if st.input == nil { 346 return nil, fmt.Errorf("no input has been set") 347 } 348 return st.input, nil 349 } 350 351 // SetInput is used to record the latest client input. 352 func(st *State) SetInput(input []byte) error { 353 l := len(input) 354 if l > INPUT_LIMIT { 355 return fmt.Errorf("input size %v too large (limit %v)", l, 255) 356 } 357 st.input = input 358 return nil 359 } 360 361 // Reset re-initializes the state to run from top node with accumulated client state. 362 func(st *State) Restart() error { 363 var err error 364 if len(st.ExecPath) == 0 { 365 return fmt.Errorf("Restart called but no root set") 366 } 367 st.resetBaseFlags() 368 st.Moves = 0 369 st.SizeIdx = 0 370 st.input = []byte{} 371 st.ExecPath = st.ExecPath[:1] 372 return err 373 } 374 375 // SetLanguage validates and sets language according to the given ISO639 language code. 376 func(st *State) SetLanguage(code string) error { 377 if code == "" { 378 st.Language = nil 379 } 380 l, err := lang.LanguageFromCode(code) 381 if err != nil { 382 return err 383 } 384 st.Language = &l 385 logg.Infof("language set", "language", l) 386 return nil 387 } 388 389 func(st *State) CloneEmpty() *State { 390 flagCount := st.BitSize - 8 391 return NewState(flagCount) 392 } 393 394 // String implements String interface 395 func(st *State) String() string { 396 var flags string 397 if st.debug { 398 flags = FlagDebugger.AsString(st.Flags, st.BitSize - 8) 399 } else { 400 flags = fmt.Sprintf("0x%x", st.Flags) 401 } 402 var lang string 403 if st.Language == nil { 404 lang = "(default)" 405 } else { 406 lang = fmt.Sprintf("%s", *st.Language) 407 } 408 return fmt.Sprintf("state @%p moves: %v idx: %v flags: %s path: %s lang: %s", st, st.Moves, st.SizeIdx, flags, strings.Join(st.ExecPath, "/"), lang) 409 } 410 411 // initializes all flags not in control of client. 412 func(st *State) resetBaseFlags() { 413 st.Flags[0] = 0 414 }