compiler.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. // Author: simon
  2. // Author: ynwdlxm@163.com
  3. // Date: 2022/10/19 14:39
  4. // Desc: Compiler
  5. package compiler
  6. import (
  7. "fmt"
  8. "github/runnignwater/monkey/ast"
  9. "github/runnignwater/monkey/code"
  10. "github/runnignwater/monkey/object"
  11. )
  12. type EmittedInstruction struct {
  13. Opcode code.Opcode
  14. Position int
  15. }
  16. type Compiler struct {
  17. instructions code.Instructions // hold the generated bytecode
  18. constants []object.Object // slice that serves as our constant pool
  19. lastInstruction EmittedInstruction
  20. previousInstruction EmittedInstruction
  21. }
  22. func New() *Compiler {
  23. return &Compiler{
  24. instructions: code.Instructions{},
  25. constants: []object.Object{},
  26. lastInstruction: EmittedInstruction{},
  27. previousInstruction: EmittedInstruction{},
  28. }
  29. }
  30. func (c *Compiler) Compile(node ast.Node) error {
  31. switch node := node.(type) {
  32. case *ast.Program:
  33. for _, s := range node.Statements {
  34. err := c.Compile(s)
  35. if err != nil {
  36. return err
  37. }
  38. }
  39. case *ast.ExpressionStatement:
  40. err := c.Compile(node.Expression)
  41. if err != nil {
  42. return err
  43. }
  44. c.emit(code.OpPop)
  45. case *ast.InfixExpression:
  46. if node.Operator == "<" {
  47. err := c.Compile(node.Right)
  48. if err != nil {
  49. return err
  50. }
  51. err = c.Compile(node.Left)
  52. if err != nil {
  53. return err
  54. }
  55. c.emit(code.OpGreaterThan)
  56. return nil
  57. }
  58. err := c.Compile(node.Left)
  59. if err != nil {
  60. return err
  61. }
  62. err = c.Compile(node.Right)
  63. if err != nil {
  64. return err
  65. }
  66. switch node.Operator {
  67. case "+":
  68. c.emit(code.OpAdd)
  69. case "-":
  70. c.emit(code.OpSub)
  71. case "*":
  72. c.emit(code.OpMul)
  73. case "/":
  74. c.emit(code.OpDiv)
  75. case ">":
  76. c.emit(code.OpGreaterThan)
  77. case "==":
  78. c.emit(code.OpEqual)
  79. case "!=":
  80. c.emit(code.OpNotEqual)
  81. default:
  82. return fmt.Errorf("unknown operator %s", node.Operator)
  83. }
  84. case *ast.PrefixExpression:
  85. err := c.Compile(node.Right)
  86. if err != nil {
  87. return err
  88. }
  89. switch node.Operator {
  90. case "!":
  91. c.emit(code.OpBang)
  92. case "-":
  93. c.emit(code.OpMinus)
  94. default:
  95. return fmt.Errorf("unknown operator %s", node.Operator)
  96. }
  97. case *ast.IfExpression:
  98. err := c.Compile(node.Condition)
  99. if err != nil {
  100. return err
  101. }
  102. // Emit an 'OpJumNotTruthy` with a bogus value
  103. jumpNotTruthyPos := c.emit(code.OpJumpNotTruthy, 9999)
  104. err = c.Compile(node.Consequence)
  105. if err != nil {
  106. return err
  107. }
  108. if c.lastInstructionIsPop() {
  109. c.removeLastPop()
  110. }
  111. // Emit an `OpJump` with a bogus value
  112. jumpPos := c.emit(code.OpJump, 9999)
  113. afterConsequencePos := len(c.instructions)
  114. c.changOperand(jumpNotTruthyPos, afterConsequencePos)
  115. if node.Alternative == nil {
  116. c.emit(code.OpNull)
  117. } else {
  118. err := c.Compile(node.Alternative)
  119. if err != nil {
  120. return err
  121. }
  122. if c.lastInstructionIsPop() {
  123. c.removeLastPop()
  124. }
  125. }
  126. afterAlternativePos := len(c.instructions)
  127. c.changOperand(jumpPos, afterAlternativePos)
  128. case *ast.BlockStatement:
  129. for _, s := range node.Statements {
  130. err := c.Compile(s)
  131. if err != nil {
  132. return err
  133. }
  134. }
  135. case *ast.Boolean:
  136. if node.Value {
  137. c.emit(code.OpTrue)
  138. } else {
  139. c.emit(code.OpFalse)
  140. }
  141. case *ast.IntegerLiteral:
  142. integer := &object.Integer{Value: node.Value}
  143. c.emit(code.OpConstant, c.addConstant(integer))
  144. }
  145. return nil
  146. }
  147. func (c *Compiler) addConstant(obj object.Object) int {
  148. c.constants = append(c.constants, obj)
  149. return len(c.constants) - 1
  150. }
  151. func (c *Compiler) addInstruction(ins []byte) int {
  152. posNewInstruction := len(c.instructions)
  153. c.instructions = append(c.instructions, ins...)
  154. return posNewInstruction
  155. }
  156. // emit generate an instruction and add it to the results,
  157. // either by printing it, writing it to a file or
  158. // by adding it to a collection in memory
  159. //
  160. // op code.Opcode
  161. //
  162. // operands [operand]int
  163. func (c *Compiler) emit(op code.Opcode, operands ...int) int {
  164. ins := code.Make(op, operands...)
  165. pos := c.addInstruction(ins)
  166. c.setLastInstruction(op, pos)
  167. return pos
  168. }
  169. func (c *Compiler) setLastInstruction(op code.Opcode, pos int) {
  170. previous := c.lastInstruction
  171. last := EmittedInstruction{Opcode: op, Position: pos}
  172. c.previousInstruction = previous
  173. c.lastInstruction = last
  174. }
  175. func (c *Compiler) lastInstructionIsPop() bool {
  176. return c.lastInstruction.Opcode == code.OpPop
  177. }
  178. func (c *Compiler) removeLastPop() {
  179. c.instructions = c.instructions[:c.lastInstruction.Position]
  180. c.lastInstruction = c.previousInstruction
  181. }
  182. func (c *Compiler) replaceInstruction(pos int, newInstruction []byte) {
  183. for i := 0; i < len(newInstruction); i++ {
  184. c.instructions[pos+i] = newInstruction[i]
  185. }
  186. }
  187. func (c *Compiler) changOperand(opPos int, operand int) {
  188. op := code.Opcode(c.instructions[opPos])
  189. newInstruction := code.Make(op, operand)
  190. c.replaceInstruction(opPos, newInstruction)
  191. }
  192. func (c *Compiler) ByteCode() *ByteCode {
  193. return &ByteCode{
  194. Instructions: c.instructions,
  195. Constants: c.constants,
  196. }
  197. }
  198. type ByteCode struct {
  199. Instructions code.Instructions
  200. Constants []object.Object
  201. }