menu.go (2595B)
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 }