// number = int_lit [ "p" int_lit ] . // func (p *gcParser) parseNumber() (x operand) { x.mode = constant // mantissa mant := exact.MakeFromLiteral(p.parseInt(), token.INT) assert(mant != nil) if p.lit == "p" { // exponent (base 2) p.next() exp, err := strconv.ParseInt(p.parseInt(), 10, 0) if err != nil { p.error(err) } if exp < 0 { denom := exact.MakeInt64(1) denom = exact.Shift(denom, token.SHL, uint(-exp)) x.typ = Typ[UntypedFloat] x.val = exact.BinaryOp(mant, token.QUO, denom) return } if exp > 0 { mant = exact.Shift(mant, token.SHL, uint(exp)) } x.typ = Typ[UntypedFloat] x.val = mant return } x.typ = Typ[UntypedInt] x.val = mant return }
func (check *checker) shift(x, y *operand, op token.Token) { untypedx := isUntyped(x.typ) // The lhs must be of integer type or be representable // as an integer; otherwise the shift has no chance. if !isInteger(x.typ) && (!untypedx || !isRepresentableConst(x.val, nil, UntypedInt)) { check.invalidOp(x.pos(), "shifted operand %s must be integer", x) x.mode = invalid return } // spec: "The right operand in a shift expression must have unsigned // integer type or be an untyped constant that can be converted to // unsigned integer type." switch { case isInteger(y.typ) && isUnsigned(y.typ): // nothing to do case isUntyped(y.typ): check.convertUntyped(y, Typ[UntypedInt]) if y.mode == invalid { x.mode = invalid return } default: check.invalidOp(y.pos(), "shift count %s must be unsigned integer", y) x.mode = invalid return } if x.mode == constant { if y.mode == constant { if untypedx { x.typ = Typ[UntypedInt] } // rhs must be within reasonable bounds const stupidShift = 1024 s, ok := exact.Uint64Val(y.val) if !ok || s >= stupidShift { check.invalidOp(y.pos(), "%s: stupid shift", y) x.mode = invalid return } // everything's ok x.val = exact.Shift(x.val, op, uint(s)) return } // non-constant shift with constant lhs if untypedx { // spec: "If the left operand of a non-constant shift expression is // an untyped constant, the type of the constant is what it would be // if the shift expression were replaced by its left operand alone; // the type is int if it cannot be determined from the context (for // instance, if the shift expression is an operand in a comparison // against an untyped constant)". // Delay operand checking until we know the final type: // The lhs expression must be in the untyped map, mark // the entry as lhs shift operand. if info, ok := check.untyped[x.expr]; ok { info.isLhs = true check.untyped[x.expr] = info } else { unreachable() } // keep x's type x.mode = value return } } // non-constant shift - lhs must be an integer if !isInteger(x.typ) { check.invalidOp(x.pos(), "shifted operand %s must be integer", x) x.mode = invalid return } // non-constant shift x.mode = value }