go-vise

Constrained Size Output Virtual Machine
Info | Log | Files | Refs | README | LICENSE

menu.go (2583B)


      1 package asm
      2 
      3 import (
      4 	"fmt"
      5 
      6 	"git.defalsify.org/vise.git/vm"
      7 )
      8 
      9 // BatchCode defines quasi-opcodes that expand to mulitple individual vm instructions.
     10 type BatchCode uint16
     11 
     12 const (
     13 	_MENU_OFFSET = 256
     14 	MENU_DOWN = _MENU_OFFSET
     15 	MENU_UP = _MENU_OFFSET + 1
     16 	MENU_NEXT = _MENU_OFFSET + 2
     17 	MENU_PREVIOUS = _MENU_OFFSET + 3
     18 )
     19 
     20 var (
     21 	batchCode = map[string]BatchCode{
     22 		"DOWN": MENU_DOWN,
     23 		"UP": MENU_UP,
     24 		"NEXT": MENU_NEXT,
     25 		"PREVIOUS": MENU_PREVIOUS,
     26 	}
     27 )
     28 
     29 type menuItem struct {
     30 	code BatchCode
     31 	choice string
     32 	display string
     33 	target string
     34 }
     35 
     36 // MenuProcessor handles code lines with BatchCode quasi-opcodes that control menu generation.
     37 // 
     38 // It creates vm instructions for display of menu and handling of input on either size of a vm.HALT instruction.
     39 type MenuProcessor struct {
     40 	items []menuItem
     41 	size uint32
     42 }
     43 
     44 // NewMenuProcessor creates a new MenuProcessor object.
     45 func NewMenuProcessor() MenuProcessor {
     46 	return MenuProcessor{}
     47 }
     48 
     49 // Add a menu batch instruction to be processed.
     50 //
     51 // Instructions will be rendered in the order in which they have been added.
     52 func(mp *MenuProcessor) Add(bop string, choice string, display string, target string) error {
     53 	bopCode := batchCode[bop]
     54 	if bopCode == 0 {
     55 		return fmt.Errorf("unknown menu instruction: %v", bop)
     56 	}
     57 	if len(target) > 0 && bopCode != MENU_DOWN {
     58 		return fmt.Errorf("target is only valid for DOWN")
     59 	}
     60 	m := menuItem{
     61 		code: bopCode,
     62 		choice: choice,
     63 		display: display,
     64 		target: target,
     65 	}
     66 	mp.items = append(mp.items, m)
     67 	return nil
     68 }
     69 
     70 // ToLines returns the generated bytecode from the added menu batch instructions.
     71 func (mp *MenuProcessor) ToLines() []byte {
     72 	preLines := []byte{}
     73 	postLines := []byte{}
     74 
     75 	for _, v := range mp.items {
     76 		switch v.code {
     77 		case MENU_UP:
     78 			preLines = vm.NewLine(preLines, vm.MOUT, []string{v.display, v.choice}, nil, nil)
     79 			postLines = vm.NewLine(postLines, vm.INCMP, []string{"_", v.choice}, nil, nil)
     80 		case MENU_NEXT:
     81 			preLines = vm.NewLine(preLines, vm.MNEXT, []string{v.display, v.choice}, nil, nil)
     82 			postLines = vm.NewLine(postLines, vm.INCMP, []string{">", v.choice}, nil, nil)
     83 		case MENU_PREVIOUS:
     84 			preLines = vm.NewLine(preLines, vm.MPREV, []string{v.display, v.choice}, nil, nil)
     85 			postLines = vm.NewLine(postLines, vm.INCMP, []string{"<", v.choice}, nil, nil)
     86 		default:
     87 			preLines = vm.NewLine(preLines, vm.MOUT, []string{v.display, v.choice}, nil, nil)
     88 			postLines = vm.NewLine(postLines, vm.INCMP, []string{v.target, v.choice}, nil, nil)
     89 		}
     90 	}
     91 
     92 	preLines = vm.NewLine(preLines, vm.HALT, nil, nil, nil)
     93 	return append(preLines, postLines...)
     94 }