code.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. package code
  2. // Author: simon
  3. // Author: ynwdlxm@163.com
  4. // Date: 2022/10/19 13:12
  5. // Desc: bytecode
  6. import (
  7. "bytes"
  8. "encoding/binary"
  9. "fmt"
  10. )
  11. type Opcode byte
  12. const (
  13. OpConstant Opcode = iota
  14. OpAdd // +
  15. OpSub // -
  16. OpMul // *
  17. OpDiv // /
  18. OpPop
  19. OpTrue // true
  20. OpFalse // false
  21. OpEqual // ==
  22. OpNotEqual // !=
  23. OpGreaterThan // >
  24. OpMinus
  25. OpBang
  26. OpJumpNotTruthy
  27. OpJump
  28. OpNull
  29. OpGetGlobal
  30. OpSetGlobal
  31. OpArray
  32. OpHash
  33. OpIndex
  34. OpCall
  35. OpReturnValue
  36. OpReturn // no return value
  37. )
  38. type Instructions []byte
  39. // String MiniDisassembler
  40. func (ins Instructions) String() string {
  41. var out bytes.Buffer
  42. i := 0
  43. for i < len(ins) {
  44. def, err := Lookup(ins[i])
  45. if err != nil {
  46. _, err := fmt.Fprintf(&out, "ERROR: %s\n", err)
  47. if err != nil {
  48. return ""
  49. }
  50. continue
  51. }
  52. operands, read := ReadOperands(def, ins[i+1:])
  53. _, err = fmt.Fprintf(&out, "%04d %s\n", i, ins.fmtInstructions(def, operands))
  54. if err != nil {
  55. return ""
  56. }
  57. i += 1 + read
  58. }
  59. return out.String()
  60. }
  61. func (ins Instructions) fmtInstructions(def *Definition, operands []int) string {
  62. operandCount := len(def.OperandWidths)
  63. if len(operands) != operandCount {
  64. return fmt.Sprintf("ERROR: operand len %d does not match defined %d\n", len(operands), operandCount)
  65. }
  66. switch operandCount {
  67. case 0:
  68. return def.Name
  69. case 1:
  70. return fmt.Sprintf("%s %d", def.Name, operands[0])
  71. }
  72. return fmt.Sprintf("ERROR: unhandled operandCount for %s\n", def.Name)
  73. }
  74. // Definition For debugging and testing purposes
  75. //
  76. // it’s handy being able to look up how many operands an opcode has and what its human-readable name is.
  77. // In order to achieve that, we’ll add proper definitions and some tooling
  78. //
  79. // Name helps to make an opcode readable
  80. // OperandWidths contains the number of bytes each operand takes up
  81. type Definition struct {
  82. Name string
  83. OperandWidths []int
  84. }
  85. var definitions = map[Opcode]*Definition{
  86. OpConstant: {"OpConstant", []int{2}},
  87. OpAdd: {"OpAdd", []int{}}, // doesn't have any operands
  88. OpSub: {"OpSub", []int{}},
  89. OpMul: {"OpMul", []int{}},
  90. OpDiv: {"OpDiv", []int{}},
  91. OpPop: {"OpPop", []int{}},
  92. OpTrue: {"OpTrue", []int{}},
  93. OpFalse: {"OpFalse", []int{}},
  94. OpEqual: {"OpEqual", []int{}},
  95. OpNotEqual: {"OpNotEqual", []int{}},
  96. OpGreaterThan: {"OpGreaterThan", []int{}},
  97. OpMinus: {"OpMinus", []int{}},
  98. OpBang: {"OpBang", []int{}},
  99. OpJumpNotTruthy: {"OpJumpNotTruthy", []int{2}},
  100. OpJump: {"OpJump", []int{2}},
  101. OpNull: {"OpNull", []int{}},
  102. OpGetGlobal: {"OpGetGlobal", []int{2}},
  103. OpSetGlobal: {"OpSetGlobal", []int{2}},
  104. OpArray: {"OpArray", []int{2}},
  105. OpHash: {"OpHash", []int{2}},
  106. OpIndex: {"OpIndex", []int{}},
  107. OpCall: {"OpCall", []int{}},
  108. OpReturnValue: {"OpReturnValue", []int{}},
  109. OpReturn: {"OpReturn", []int{}},
  110. }
  111. func Lookup(op byte) (*Definition, error) {
  112. def, ok := definitions[Opcode(op)]
  113. if !ok {
  114. return nil, fmt.Errorf("opcode %d undefined", op)
  115. }
  116. return def, nil
  117. }
  118. func Make(op Opcode, operands ...int) []byte {
  119. def, ok := definitions[op]
  120. if !ok {
  121. return []byte{}
  122. }
  123. instructionLen := 1
  124. for _, w := range def.OperandWidths {
  125. instructionLen += w
  126. }
  127. instruction := make([]byte, instructionLen) // allocate the byte slice
  128. instruction[0] = byte(op)
  129. offset := 1
  130. for i, o := range operands {
  131. width := def.OperandWidths[i]
  132. switch width {
  133. case 2:
  134. binary.BigEndian.PutUint16(instruction[offset:], uint16(o))
  135. }
  136. offset += width
  137. }
  138. return instruction
  139. }
  140. // ReadOperands reverses everything Make did
  141. func ReadOperands(def *Definition, ins Instructions) ([]int, int) {
  142. operands := make([]int, len(def.OperandWidths))
  143. offset := 0
  144. for i, width := range def.OperandWidths {
  145. switch width {
  146. case 2:
  147. operands[i] = int(ReadUint16(ins[offset:]))
  148. }
  149. offset += width
  150. }
  151. return operands, offset
  152. }
  153. func ReadUint16(ins Instructions) uint16 {
  154. return binary.BigEndian.Uint16(ins)
  155. }