// Author: simon // Author: ynwdlxm@163.com // Date: 2022/10/19 14:39 // Desc: Compiler package compiler import ( "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 } case *ast.InfixExpression: err := c.Compile(node.Left) if err != nil { return err } err = c.Compile(node.Right) if err != nil { return err } 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 }