package core import ( "git.urbach.dev/cli/q/src/errors" "git.urbach.dev/cli/q/src/expression" "git.urbach.dev/cli/q/src/optimizer" "git.urbach.dev/cli/q/src/ssa" "git.urbach.dev/cli/q/src/token" "git.urbach.dev/cli/q/src/types" ) // evaluateBinary converts a binary expression to an SSA value. func (f *Function) evaluateBinary(expr *expression.Expression) (ssa.Value, error) { left := expr.Children[0] right := expr.Children[1] swapped := false if expr.Token.Kind.IsCommutative() { leftComplexity := optimizer.Complexity(left) rightComplexity := optimizer.Complexity(right) if rightComplexity > leftComplexity { left, right = right, left swapped = true } } leftValue, err := f.evaluateRight(left) if err != nil { return nil, err } rightValue, err := f.evaluateRight(right) if err != nil { return nil, err } leftType := leftValue.Type() rightType := rightValue.Type() leftStructType, leftIsStruct := types.Unwrap(leftType).(*types.Struct) rightStructType, rightIsStruct := types.Unwrap(rightType).(*types.Struct) if leftIsStruct && rightIsStruct && leftStructType == types.String && rightStructType == types.String { switch expr.Token.Kind { case token.Add: return f.evaluateStringOp("concat", leftValue, rightValue, expr.Source()) case token.Equal: return f.evaluateStringOp("equal", leftValue, rightValue, expr.Source()) case token.NotEqual: equal, err := f.evaluateStringOp("equal", leftValue, rightValue, expr.Source()) if err != nil { return nil, err } v := f.Append(&ssa.UnaryOp{ Op: token.Not, Operand: equal, Source: expr.Source(), }) return v, nil } } if leftIsStruct || rightIsStruct { return nil, errors.New(InvalidStructOperation, f.File, expr.Token) } if !types.IsCastable(leftType, rightType) && !types.IsCastable(rightType, leftType) { return nil, errors.New(&TypeMismatch{Encountered: leftType.Name(), Expected: rightType.Name()}, f.File, left.Source()) } v := &ssa.BinaryOp{ Left: leftValue, Right: rightValue, Op: expr.Token.Kind, Swapped: swapped, Source: expr.Source(), } if v.Op.IsComparison() { f.Block().Append(v) return v, nil } return f.Append(v), nil }