| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- // Author: simon
- // Author: ynwdlxm@163.com
- // Date: 2022/10/19 14:39
- // Desc: Compiler
- package compiler
- import (
- "fmt"
- "github/runnignwater/monkey/ast"
- "github/runnignwater/monkey/code"
- "github/runnignwater/monkey/object"
- )
- type Compiler struct {
- instructions code.Instructions // hold the generated bytecode
- constants []object.Object // slice that serves as our constant pool
- }
- func New() *Compiler {
- return &Compiler{
- instructions: code.Instructions{},
- constants: []object.Object{},
- }
- }
- func (c *Compiler) Compile(node ast.Node) error {
- switch node := node.(type) {
- case *ast.Program:
- for _, s := range node.Statements {
- err := c.Compile(s)
- if err != nil {
- return err
- }
- }
- case *ast.ExpressionStatement:
- err := c.Compile(node.Expression)
- if err != nil {
- return err
- }
- c.emit(code.OpPop)
- case *ast.InfixExpression:
- if node.Operator == "<" {
- err := c.Compile(node.Right)
- if err != nil {
- return err
- }
- err = c.Compile(node.Left)
- if err != nil {
- return err
- }
- c.emit(code.OpGreaterThan)
- return nil
- }
- err := c.Compile(node.Left)
- if err != nil {
- return err
- }
- err = c.Compile(node.Right)
- if err != nil {
- return err
- }
- switch node.Operator {
- case "+":
- c.emit(code.OpAdd)
- case "-":
- c.emit(code.OpSub)
- case "*":
- c.emit(code.OpMul)
- case "/":
- c.emit(code.OpDiv)
- case ">":
- c.emit(code.OpGreaterThan)
- case "==":
- c.emit(code.OpEqual)
- case "!=":
- c.emit(code.OpNotEqual)
- default:
- return fmt.Errorf("unknown operator %s", node.Operator)
- }
- case *ast.PrefixExpression:
- err := c.Compile(node.Right)
- if err != nil {
- return err
- }
- switch node.Operator {
- case "!":
- c.emit(code.OpBang)
- case "-":
- c.emit(code.OpMinus)
- default:
- return fmt.Errorf("unknown operator %s", node.Operator)
- }
- case *ast.Boolean:
- if node.Value {
- c.emit(code.OpTrue)
- } else {
- c.emit(code.OpFalse)
- }
- case *ast.IntegerLiteral:
- integer := &object.Integer{Value: node.Value}
- c.emit(code.OpConstant, c.addConstant(integer))
- }
- return nil
- }
- func (c *Compiler) addConstant(obj object.Object) int {
- c.constants = append(c.constants, obj)
- return len(c.constants) - 1
- }
- func (c *Compiler) addInstruction(ins []byte) int {
- posNewInstruction := len(c.instructions)
- c.instructions = append(c.instructions, ins...)
- return posNewInstruction
- }
- // emit generate an instruction and add it to the results,
- // either by printing it, writing it to a file or
- // by adding it to a collection in memory
- //
- // op code.Opcode
- //
- // operands [operand]int
- func (c *Compiler) emit(op code.Opcode, operands ...int) int {
- ins := code.Make(op, operands...)
- pos := c.addInstruction(ins)
- return pos
- }
- func (c *Compiler) ByteCode() *ByteCode {
- return &ByteCode{
- Instructions: c.instructions,
- Constants: c.constants,
- }
- }
- type ByteCode struct {
- Instructions code.Instructions
- Constants []object.Object
- }
|