package core import ( "fmt" "git.urbach.dev/cli/q/src/asm" "git.urbach.dev/cli/q/src/ast" "git.urbach.dev/cli/q/src/errors" "git.urbach.dev/cli/q/src/eval" "git.urbach.dev/cli/q/src/token" ) // CompileAssign compiles an assign statement. func (f *Function) CompileAssign(node *ast.Assign) error { left := node.Expression.Children[0] right := node.Expression.Children[1] if left.Token.Kind == token.Separator { if right.Token.Kind == token.Div { return f.CompileAssignDivision(node.Expression) } if right.Token.Kind == token.Call { return f.MultiAssign(left, right) } return errors.New(errors.NotImplemented, f.File, node.Expression.Token.Position) } leftValue, err := f.Evaluate(left) if err != nil { return err } operation := node.Expression.Token switch leftValue := leftValue.(type) { case *eval.Register: if !f.RegisterIsUsed(leftValue.Register) { f.UseRegister(leftValue.Register) defer f.FreeRegister(leftValue.Register) } f.Execute(operation, leftValue.Register, right) case *eval.Memory: if !f.RegisterIsUsed(leftValue.Memory.Base) { f.UseRegister(leftValue.Memory.Base) defer f.FreeRegister(leftValue.Memory.Base) } if operation.Kind == token.Assign { rightValue, err := f.Evaluate(right) if err != nil { return err } leftSize := leftValue.Memory.Length rightSize := uint8(rightValue.Type().Size()) if rightSize != 0 && leftSize != rightSize { panic("memory store length mismatch") } f.ValueToMemory(rightValue, leftValue.Memory) return nil } tmp := f.NewRegister() f.ValueToRegister(leftValue, tmp) err := f.Execute(operation, tmp, right) if err != nil { return err } f.MemoryRegister(asm.STORE, leftValue.Memory, tmp) f.FreeRegister(tmp) default: panic(fmt.Errorf("%s: not implemented: %v", f.UniqueName, leftValue)) } return nil }