package vm import ( "encoding/binary" "fmt" "regexp" "github.com/antonmedv/expr/file" ) type Program struct { Source *file.Source Locations map[int]file.Location Constants []interface{} Bytecode []byte } func (program *Program) Disassemble() string { out := "" ip := 0 for ip < len(program.Bytecode) { pp := ip op := program.Bytecode[ip] ip++ readArg := func() uint16 { if ip+1 >= len(program.Bytecode) { return 0 } i := binary.LittleEndian.Uint16([]byte{program.Bytecode[ip], program.Bytecode[ip+1]}) ip += 2 return i } code := func(label string) { out += fmt.Sprintf("%v\t%v\n", pp, label) } jump := func(label string) { a := readArg() out += fmt.Sprintf("%v\t%v\t%v\t(%v)\n", pp, label, a, ip+int(a)) } back := func(label string) { a := readArg() out += fmt.Sprintf("%v\t%v\t%v\t(%v)\n", pp, label, a, ip-int(a)) } argument := func(label string) { a := readArg() out += fmt.Sprintf("%v\t%v\t%v\n", pp, label, a) } constant := func(label string) { a := readArg() var c interface{} if int(a) < len(program.Constants) { c = program.Constants[a] } if r, ok := c.(*regexp.Regexp); ok { c = r.String() } out += fmt.Sprintf("%v\t%v\t%v\t%#v\n", pp, label, a, c) } switch op { case OpPush: constant("OpPush") case OpPop: code("OpPop") case OpRot: code("OpRot") case OpFetch: constant("OpFetch") case OpFetchNilSafe: constant("OpFetchNilSafe") case OpFetchMap: constant("OpFetchMap") case OpTrue: code("OpTrue") case OpFalse: code("OpFalse") case OpNil: code("OpNil") case OpNegate: code("OpNegate") case OpNot: code("OpNot") case OpEqual: code("OpEqual") case OpEqualInt: code("OpEqualInt") case OpEqualString: code("OpEqualString") case OpJump: jump("OpJump") case OpJumpIfTrue: jump("OpJumpIfTrue") case OpJumpIfFalse: jump("OpJumpIfFalse") case OpJumpBackward: back("OpJumpBackward") case OpIn: code("OpIn") case OpLess: code("OpLess") case OpMore: code("OpMore") case OpLessOrEqual: code("OpLessOrEqual") case OpMoreOrEqual: code("OpMoreOrEqual") case OpAdd: code("OpAdd") case OpSubtract: code("OpSubtract") case OpMultiply: code("OpMultiply") case OpDivide: code("OpDivide") case OpModulo: code("OpModulo") case OpExponent: code("OpExponent") case OpRange: code("OpRange") case OpMatches: code("OpMatches") case OpMatchesConst: constant("OpMatchesConst") case OpContains: code("OpContains") case OpStartsWith: code("OpStartsWith") case OpEndsWith: code("OpEndsWith") case OpIndex: code("OpIndex") case OpSlice: code("OpSlice") case OpProperty: constant("OpProperty") case OpPropertyNilSafe: constant("OpPropertyNilSafe") case OpCall: constant("OpCall") case OpCallFast: constant("OpCallFast") case OpMethod: constant("OpMethod") case OpMethodNilSafe: constant("OpMethodNilSafe") case OpArray: code("OpArray") case OpMap: code("OpMap") case OpLen: code("OpLen") case OpCast: argument("OpCast") case OpStore: constant("OpStore") case OpLoad: constant("OpLoad") case OpInc: constant("OpInc") case OpBegin: code("OpBegin") case OpEnd: code("OpEnd") default: out += fmt.Sprintf("%v\t%#x\n", pp, op) } } return out }