func intOp(op token.Token, x, y *BasicLit, combine bool) (*BasicLit, error) { out := &BasicLit{ Kind: x.Kind, } l, err := strconv.Atoi(x.Value) if err != nil { return out, err } r, err := strconv.Atoi(y.Value) if err != nil { return out, err } var t int switch op { case token.ADD: t = l + r case token.SUB: t = l - r case token.QUO: // Sass division can create floats, so much treat // ints as floats then test for fitting inside INT fl, fr := float64(l), float64(r) if math.Remainder(fl, fr) != 0 { return floatOp(op, x, y, combine) } t = l / r case token.MUL: t = l * r default: panic("unsupported intOp" + op.String()) } out.Value = strconv.Itoa(t) return out, nil }
func stringOp(op token.Token, x, y *BasicLit, combine bool) (*BasicLit, error) { kind := token.STRING if op == token.ADD { return &BasicLit{ Kind: kind, Value: x.Value + y.Value, }, nil } return &BasicLit{ Kind: kind, Value: x.Value + op.String() + y.Value, }, nil }
func otherOp(op token.Token, x, y *BasicLit, combine bool) (*BasicLit, error) { if !combine && op == token.QUO { return stringOp(op, x, y, combine) } a, b := x, y // Order for non-string operations is not important. Reorder for simpler logic switch { case x.Kind == token.INT || x.Kind == token.FLOAT: a = y b = x case y.Kind == token.INT || y.Kind == token.FLOAT: default: if op == token.MUL { return nil, fmt.Errorf("unsupported operation: %s %s %s", x, op, y) } } var kind token.Token switch a.Kind { case token.ILLEGAL: default: kind = a.Kind } switch b.Kind { case token.ILLEGAL: default: switch { case kind == token.ILLEGAL: kind = b.Kind case b.Kind == token.INT || b.Kind == token.FLOAT: case kind != b.Kind: return nil, fmt.Errorf("illegal unit operation %s %s", a.Kind, b.Kind) } } xx := &BasicLit{ Value: strings.TrimSuffix(a.Value, a.Kind.String()), } yy := &BasicLit{ Value: strings.TrimSuffix(b.Value, b.Kind.String()), } f, err := floatOp(op, xx, yy, combine) return &BasicLit{ Kind: kind, Value: f.Value + kind.String(), }, err }
// colorOpString perform combinations on the string values func colorOpString(tok token.Token, x, y *BasicLit, combine bool) (*BasicLit, error) { fmt.Println("cOpS", tok, x.Value, y.Value) lit := &BasicLit{ Kind: token.STRING, ValuePos: x.Pos(), } switch tok { case token.ADD: lit.Value = x.Value + y.Value case token.SUB: lit.Value = x.Value + tok.String() + y.Value case token.QUO: lit.Value = x.Value + tok.String() + y.Value case token.MUL: return nil, fmt.Errorf(`Undefined operation: "%s %s %s".`, x.Value, tok, y.Value) } fmt.Println("out", lit.Value) return lit, nil }
func floatOp(op token.Token, x, y *BasicLit, combine bool) (*BasicLit, error) { out := &BasicLit{ Kind: token.FLOAT, } if !combine { out.Value = x.Value + op.String() + y.Value return out, nil } l, err := strconv.ParseFloat(x.Value, 64) if err != nil { return out, err } r, err := strconv.ParseFloat(y.Value, 64) if err != nil { return out, err } var t float64 switch op { case token.ADD: t = l + r case token.SUB: t = l - r case token.QUO: // Sass division can create floats, so much treat // ints as floats then test for fitting inside INT t = l / r case token.MUL: t = l * r default: panic("unsupported intOp" + op.String()) } out.Value = strconv.FormatFloat(t, 'G', -1, 64) if math.Remainder(t, 1) == 0 { out.Kind = token.INT } return out, nil }