package build import ( "strconv" "git.akyoto.dev/cli/q/src/build/asm" "git.akyoto.dev/cli/q/src/build/cpu" "git.akyoto.dev/cli/q/src/build/expression" "git.akyoto.dev/cli/q/src/build/token" "git.akyoto.dev/cli/q/src/errors" ) // Execute executes an operation on a register with a value operand. func (f *Function) Execute(operation token.Token, register cpu.Register, value *expression.Expression) error { if value.IsLeaf() { return f.ExecuteLeaf(operation, register, value.Token) } temporary, found := f.CPU.FindFree(f.CPU.General) if !found { panic("no free registers") } f.CPU.Use(temporary) defer f.CPU.Free(temporary) err := f.ExpressionToRegister(value, temporary) if err != nil { return err } return f.ExecuteRegisterRegister(operation, register, temporary) } // ExecuteLeaf performs an operation on a register with the given leaf operand. func (f *Function) ExecuteLeaf(operation token.Token, register cpu.Register, operand token.Token) error { switch operand.Kind { case token.Number: value := operand.Text() number, err := strconv.Atoi(value) if err != nil { return err } return f.ExecuteRegisterNumber(operation, register, number) case token.Identifier: name := operand.Text() variable, exists := f.Variables[name] if !exists { return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, operand.Position) } return f.ExecuteRegisterRegister(operation, register, variable.Register) } return errors.New(errors.NotImplemented, f.File, operation.Position) } // ExecuteRegisterNumber performs an operation on a register and a number. func (f *Function) ExecuteRegisterNumber(operation token.Token, register cpu.Register, number int) error { switch operation.Text() { case "+", "+=": f.Assembler.RegisterNumber(asm.ADD, register, number) case "-", "-=": f.Assembler.RegisterNumber(asm.SUB, register, number) case "*", "*=": f.Assembler.RegisterNumber(asm.MUL, register, number) case "/", "/=": f.Assembler.RegisterNumber(asm.DIV, register, number) case "=": f.Assembler.RegisterNumber(asm.MOVE, register, number) default: return errors.New(&errors.InvalidOperator{Operator: operation.Text()}, f.File, operation.Position) } return nil } // ExecuteRegisterRegister performs an operation on two registers. func (f *Function) ExecuteRegisterRegister(operation token.Token, destination cpu.Register, source cpu.Register) error { switch operation.Text() { case "+", "+=": f.Assembler.RegisterRegister(asm.ADD, destination, source) case "-", "-=": f.Assembler.RegisterRegister(asm.SUB, destination, source) case "*", "*=": f.Assembler.RegisterRegister(asm.MUL, destination, source) case "/", "/=": f.Assembler.RegisterRegister(asm.DIV, destination, source) case "=": f.Assembler.RegisterRegister(asm.MOVE, destination, source) default: return errors.New(&errors.InvalidOperator{Operator: operation.Text()}, f.File, operation.Position) } return nil }