go-vise

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

debug.go (5443B)


      1 package vm
      2 
      3 import (
      4 	"bytes"
      5 	"fmt"
      6 	"io"
      7 )
      8 
      9 type ParseHandler struct {
     10 	Catch  func(string, uint32, bool) error
     11 	Croak  func(uint32, bool) error
     12 	Load   func(string, uint32) error
     13 	Reload func(string) error
     14 	Map    func(string) error
     15 	Move   func(string) error
     16 	Halt   func() error
     17 	InCmp  func(string, string) error
     18 	MOut   func(string, string) error
     19 	MSink  func() error
     20 	MNext  func(string, string) error
     21 	MPrev  func(string, string) error
     22 	cur    string
     23 	n      int
     24 	w      io.Writer
     25 }
     26 
     27 func NewParseHandler() *ParseHandler {
     28 	return &ParseHandler{}
     29 }
     30 
     31 func (ph *ParseHandler) Length() int {
     32 	return ph.n
     33 }
     34 
     35 func (ph *ParseHandler) WithDefaultHandlers() *ParseHandler {
     36 	ph.Catch = ph.catch
     37 	ph.Croak = ph.croak
     38 	ph.Load = ph.load
     39 	ph.Reload = ph.reload
     40 	ph.Map = ph.maph
     41 	ph.Move = ph.move
     42 	ph.Halt = ph.halt
     43 	ph.InCmp = ph.incmp
     44 	ph.MOut = ph.mout
     45 	ph.MSink = ph.msink
     46 	ph.MNext = ph.mnext
     47 	ph.MPrev = ph.mprev
     48 	return ph
     49 }
     50 
     51 func (ph *ParseHandler) WithWriter(w io.Writer) *ParseHandler {
     52 	ph.w = w
     53 	return ph
     54 }
     55 
     56 // TODO: output op sym
     57 func (ph *ParseHandler) flush() error {
     58 	if ph.w != nil {
     59 		n, err := io.WriteString(ph.w, ph.cur)
     60 		if err != nil {
     61 			return err
     62 		}
     63 		ph.n += n
     64 		ph.cur = ""
     65 		//logg.Tracef("instruction debug write", "bytes", n, "instruction", s)
     66 		logg.Tracef("instruction debug write", "bytes", n)
     67 	}
     68 	return nil
     69 }
     70 
     71 func (ph *ParseHandler) catch(sym string, flag uint32, inv bool) error {
     72 	s := OpcodeString[CATCH]
     73 	vv := 0
     74 	if inv {
     75 		vv = 1
     76 	}
     77 	ph.cur = fmt.Sprintf("%s %s %v %v\n", s, sym, flag, vv)
     78 	return nil
     79 }
     80 
     81 func (ph *ParseHandler) croak(flag uint32, inv bool) error {
     82 	s := OpcodeString[CROAK]
     83 	vv := 0
     84 	if inv {
     85 		vv = 1
     86 	}
     87 	ph.cur = fmt.Sprintf("%s %v %v\n", s, flag, vv)
     88 	return nil
     89 }
     90 
     91 func (ph *ParseHandler) load(sym string, length uint32) error {
     92 	s := OpcodeString[LOAD]
     93 	ph.cur = fmt.Sprintf("%s %s %v\n", s, sym, length)
     94 	return nil
     95 }
     96 
     97 func (ph *ParseHandler) reload(sym string) error {
     98 	s := OpcodeString[RELOAD]
     99 	ph.cur = fmt.Sprintf("%s %s\n", s, sym)
    100 	return nil
    101 }
    102 
    103 func (ph *ParseHandler) maph(sym string) error {
    104 	s := OpcodeString[MAP]
    105 	ph.cur = fmt.Sprintf("%s %s\n", s, sym)
    106 	return nil
    107 }
    108 
    109 func (ph *ParseHandler) move(sym string) error {
    110 	s := OpcodeString[MOVE]
    111 	ph.cur = fmt.Sprintf("%s %s\n", s, sym)
    112 	return nil
    113 }
    114 
    115 func (ph *ParseHandler) incmp(sym string, sel string) error {
    116 	s := OpcodeString[INCMP]
    117 	ph.cur = fmt.Sprintf("%s %s %v\n", s, sym, sel)
    118 	return nil
    119 }
    120 
    121 func (ph *ParseHandler) halt() error {
    122 	s := OpcodeString[HALT]
    123 	ph.cur = fmt.Sprintf("%s\n", s)
    124 	return nil
    125 }
    126 
    127 func (ph *ParseHandler) msink() error {
    128 	s := OpcodeString[MSINK]
    129 	ph.cur = fmt.Sprintf("%s\n", s)
    130 	return nil
    131 }
    132 
    133 func (ph *ParseHandler) mout(sym string, sel string) error {
    134 	s := OpcodeString[MOUT]
    135 	ph.cur = fmt.Sprintf("%s %s %v\n", s, sym, sel)
    136 	return nil
    137 }
    138 
    139 func (ph *ParseHandler) mnext(sym string, sel string) error {
    140 	s := OpcodeString[MNEXT]
    141 	ph.cur = fmt.Sprintf("%s %s %s\n", s, sym, sel)
    142 	return nil
    143 }
    144 
    145 func (ph *ParseHandler) mprev(sym string, sel string) error {
    146 	s := OpcodeString[MPREV]
    147 	ph.cur = fmt.Sprintf("%s %s %s\n", s, sym, sel)
    148 	return nil
    149 }
    150 
    151 // ToString verifies all instructions in bytecode and returns an assmebly code instruction for it.
    152 func (ph *ParseHandler) ToString(b []byte) (string, error) {
    153 	buf := bytes.NewBuffer(nil)
    154 	ph = ph.WithWriter(buf)
    155 	n, err := ph.ParseAll(b)
    156 	if err != nil {
    157 		return "", err
    158 	}
    159 	logg.Tracef("", "bytes_written", n)
    160 	return buf.String(), nil
    161 }
    162 
    163 // ParseAll parses and verifies all instructions from bytecode.
    164 //
    165 // If writer is not nil, the parsed instruction as assembly code line string is written to it.
    166 //
    167 // Bytecode is consumed (and written) one instruction at a time.
    168 //
    169 // It fails on any parse error encountered before the bytecode EOF is reached.
    170 func (ph *ParseHandler) ParseAll(b []byte) (int, error) {
    171 	var s string
    172 	running := true
    173 	for running {
    174 		op, bb, err := opSplit(b)
    175 		b = bb
    176 		if err != nil {
    177 			return ph.Length(), err
    178 		}
    179 		s = OpcodeString[op]
    180 		if s == "" {
    181 			return ph.Length(), fmt.Errorf("unknown opcode: %v", op)
    182 		}
    183 
    184 		switch op {
    185 		case CATCH:
    186 			r, n, m, bb, err := ParseCatch(b)
    187 			b = bb
    188 			if err == nil {
    189 				err = ph.Catch(r, n, m)
    190 			}
    191 		case CROAK:
    192 			n, m, bb, err := ParseCroak(b)
    193 			b = bb
    194 			if err == nil {
    195 				err = ph.Croak(n, m)
    196 			}
    197 		case LOAD:
    198 			r, n, bb, err := ParseLoad(b)
    199 			b = bb
    200 			if err == nil {
    201 				err = ph.Load(r, n)
    202 			}
    203 		case RELOAD:
    204 			r, bb, err := ParseReload(b)
    205 			b = bb
    206 			if err == nil {
    207 				err = ph.Reload(r)
    208 			}
    209 		case MAP:
    210 			r, bb, err := ParseMap(b)
    211 			b = bb
    212 			if err == nil {
    213 				err = ph.Map(r)
    214 			}
    215 		case MOVE:
    216 			r, bb, err := ParseMove(b)
    217 			b = bb
    218 			if err == nil {
    219 				err = ph.Move(r)
    220 			}
    221 		case INCMP:
    222 			r, v, bb, err := ParseInCmp(b)
    223 			b = bb
    224 			if err == nil {
    225 				err = ph.InCmp(r, v)
    226 			}
    227 		case HALT:
    228 			b, err = ParseHalt(b)
    229 			if err == nil {
    230 				err = ph.Halt()
    231 			}
    232 		case MSINK:
    233 			b, err = ParseMSink(b)
    234 			if err == nil {
    235 				err = ph.MSink()
    236 			}
    237 		case MOUT:
    238 			r, v, bb, err := ParseMOut(b)
    239 			b = bb
    240 			if err == nil {
    241 				err = ph.MOut(r, v)
    242 			}
    243 		case MNEXT:
    244 			r, v, bb, err := ParseMNext(b)
    245 			b = bb
    246 			if err == nil {
    247 				err = ph.MNext(r, v)
    248 			}
    249 		case MPREV:
    250 			r, v, bb, err := ParseMPrev(b)
    251 			b = bb
    252 			if err == nil {
    253 				err = ph.MPrev(r, v)
    254 			}
    255 		}
    256 		if err != nil {
    257 			return ph.Length(), err
    258 		}
    259 		ph.flush()
    260 
    261 		//rs += "\n"
    262 		if len(b) == 0 {
    263 			running = false
    264 		}
    265 	}
    266 	return ph.Length(), nil
    267 }