package core import ( "math" "git.akyoto.dev/cli/q/src/asm" "git.akyoto.dev/cli/q/src/ast" "git.akyoto.dev/cli/q/src/cpu" "git.akyoto.dev/cli/q/src/errors" "git.akyoto.dev/cli/q/src/expression" "git.akyoto.dev/cli/q/src/token" "git.akyoto.dev/cli/q/src/types" ) // ExpressionToRegister puts the result of an expression into the specified register. func (f *Function) ExpressionToRegister(node *expression.Expression, register cpu.Register) (types.Type, error) { if node.IsFolded { f.RegisterNumber(asm.MOVE, register, node.Value) return types.Int, nil } if node.IsLeaf() { return f.TokenToRegister(node.Token, register) } if ast.IsFunctionCall(node) { types, err := f.CompileCall(node) if err != nil { return nil, err } if register != f.CPU.Output[0] { f.RegisterRegister(asm.MOVE, register, f.CPU.Output[0]) } if len(types) == 0 { return nil, nil } return types[0], err } if node.Token.Kind == token.Array { name := node.Children[0].Token.Text(f.File.Bytes) array := f.VariableByName(name) if array == nil { return nil, errors.New(&errors.UnknownIdentifier{Name: name}, f.File, node.Children[0].Token.Position) } index := node.Children[1] memory := asm.Memory{ Base: array.Register, Offset: 0, OffsetRegister: cpu.Register(math.MaxUint8), Length: byte(1), } if index.Token.IsNumeric() { offset, err := f.ToNumber(index.Token) if err != nil { return nil, err } memory.Offset = int8(offset) } else { typ, err := f.ExpressionToRegister(index, register) if err != nil { return nil, err } if !types.Is(typ, types.Int) { return nil, errors.New(&errors.TypeMismatch{Encountered: typ.Name(), Expected: types.Int.Name()}, f.File, index.Token.Position) } memory.OffsetRegister = register } f.MemoryRegister(asm.LOAD, memory, register) return types.Int, nil } if node.Token.Kind == token.Period { left := node.Children[0] leftText := left.Token.Text(f.File.Bytes) right := node.Children[1] rightText := right.Token.Text(f.File.Bytes) variable := f.VariableByName(leftText) if variable == nil { constant, isConst := f.Constants[f.Package+"."+leftText+"."+rightText] if isConst { return f.TokenToRegister(constant.Value, register) } return nil, errors.New(&errors.UnknownIdentifier{Name: leftText}, f.File, left.Token.Position) } field := variable.Type.(*types.Pointer).To.(*types.Struct).FieldByName(rightText) f.MemoryRegister(asm.LOAD, asm.Memory{Base: variable.Register, Offset: int8(field.Offset), Length: byte(field.Type.Size())}, register) return field.Type, nil } if len(node.Children) == 1 { if !node.Token.IsUnaryOperator() { return nil, errors.New(errors.MissingOperand, f.File, node.Token.End()) } typ, err := f.ExpressionToRegister(node.Children[0], register) if err != nil { return typ, err } return typ, f.ExecuteRegister(node.Token, register) } left := node.Children[0] right := node.Children[1] final := register if f.UsesRegister(right, register) { register = f.NewRegister() } typ, err := f.ExpressionToRegister(left, register) if err != nil { return nil, err } if typ == types.AnyPointer && right.Token.Kind == token.Identifier && f.VariableByName(right.Token.Text(f.File.Bytes)).Type == types.AnyPointer { typ = types.Int } err = f.Execute(node.Token, register, right) if register != final { f.RegisterRegister(asm.MOVE, final, register) f.FreeRegister(register) } return typ, err }