package compiler import ( "fmt" "gitea.paas.celticinfo.fr/oabrivard/monkeylang/monkey5/ast" "gitea.paas.celticinfo.fr/oabrivard/monkeylang/monkey5/code" "gitea.paas.celticinfo.fr/oabrivard/monkeylang/monkey5/object" ) type Compiler struct { instructions code.Instructions constants []object.Object } 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 } switch node.Operator { case "+": c.emit(code.OpAdd) default: return fmt.Errorf("unknown operator %s", node.Operator) } case *ast.IntegerLiteral: integer := &object.Integer{Value: node.Value} c.emit(code.OpConstant, c.addConstant(integer)) } return nil } func (c *Compiler) Bytecode() *Bytecode { return &Bytecode{ Instructions: c.instructions, Constants: c.constants, } } func (c *Compiler) addConstant(obj object.Object) int { c.constants = append(c.constants, obj) return len(c.constants) - 1 } func (c *Compiler) emit(op code.Opcode, operands ...int) int { ins := code.Make(op, operands...) pos := c.addInstruction(ins) return pos } func (c *Compiler) addInstruction(ins []byte) int { posNewInstruction := len(c.instructions) c.instructions = append(c.instructions, ins...) return posNewInstruction } type Bytecode struct { Instructions code.Instructions Constants []object.Object }