package core import ( "fmt" "git.urbach.dev/cli/q/src/asm" "git.urbach.dev/cli/q/src/errors" "git.urbach.dev/cli/q/src/eval" "git.urbach.dev/cli/q/src/expression" "git.urbach.dev/cli/q/src/scope" "git.urbach.dev/cli/q/src/token" "git.urbach.dev/cli/q/src/types" "git.urbach.dev/cli/q/src/x86" ) // CompileAssignDivision compiles an assign statement that has quotient and remainder on the left side and division on the right. func (f *Function) CompileAssignDivision(expr *expression.Expression) error { var ( variables = expr.Children[0] division = expr.Children[1] quotientVariable *scope.Variable remainderVariable *scope.Variable err error ) if expr.Token.Kind == token.Define { quotientVariable, err = f.Define(variables.Children[0]) if err != nil { return err } remainderVariable, err = f.Define(variables.Children[1]) if err != nil { return err } quotientVariable.Value.Typ = types.Int remainderVariable.Value.Typ = types.Int f.AddVariable(quotientVariable) f.AddVariable(remainderVariable) } else { quotient := variables.Children[0] name := quotient.Token.Text(f.File.Bytes) quotientVariable = f.VariableByName(name) if quotientVariable == nil { return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, quotient.Token.Position) } remainder := variables.Children[1] name = remainder.Token.Text(f.File.Bytes) remainderVariable = f.VariableByName(name) if remainderVariable == nil { return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, remainder.Token.Position) } defer f.UseVariable(quotientVariable) defer f.UseVariable(remainderVariable) } dividendExpr := division.Children[0] dividend, err := f.Evaluate(dividendExpr) if err != nil { return err } if !types.Is(dividend.Type(), types.AnyInt) { return errors.New(&errors.TypeMismatch{Encountered: dividend.Type().Name(), Expected: types.AnyInt.Name()}, f.File, dividendExpr.Token.Position) } divisor := division.Children[1] switch dividend := dividend.(type) { case *eval.Number: f.SaveRegister(x86.RAX) f.RegisterNumber(asm.MOVE, x86.RAX, dividend.Number) err = f.Execute(division.Token, x86.RAX, divisor) case *eval.Register: if dividend.Register != quotientVariable.Value.Register && dividend.IsAlive() { tmp := f.NewRegister() f.RegisterRegister(asm.MOVE, tmp, dividend.Register) err = f.Execute(division.Token, tmp, divisor) f.FreeRegister(tmp) } else { err = f.Execute(division.Token, dividend.Register, divisor) } default: panic(fmt.Errorf("%s: not implemented: %v", f.UniqueName, dividend)) } f.RegisterRegister(asm.MOVE, quotientVariable.Value.Register, x86.RAX) f.RegisterRegister(asm.MOVE, remainderVariable.Value.Register, x86.RDX) return err }