Support uint64 literals in the parser
When an integer cannot be parsed, we attempt to parse it as a uint64. If that succeeds, we then have an unsigned literal that can then be used to compare unsigned values. This method allows us not to introduce new syntax to the language and continue just doing the right thing at the right time. But, it also delegates a lot of the heavy lifting to implicit casting in Reduce and Eval.pull/8838/head
parent
253b8c2b35
commit
a978b4fd3e
|
|
@ -179,6 +179,7 @@ func (*Dimension) node() {}
|
|||
func (Dimensions) node() {}
|
||||
func (*DurationLiteral) node() {}
|
||||
func (*IntegerLiteral) node() {}
|
||||
func (*UnsignedLiteral) node() {}
|
||||
func (*Field) node() {}
|
||||
func (Fields) node() {}
|
||||
func (*Measurement) node() {}
|
||||
|
|
@ -312,6 +313,7 @@ func (*Call) expr() {}
|
|||
func (*Distinct) expr() {}
|
||||
func (*DurationLiteral) expr() {}
|
||||
func (*IntegerLiteral) expr() {}
|
||||
func (*UnsignedLiteral) expr() {}
|
||||
func (*NilLiteral) expr() {}
|
||||
func (*NumberLiteral) expr() {}
|
||||
func (*ParenExpr) expr() {}
|
||||
|
|
@ -333,6 +335,7 @@ type Literal interface {
|
|||
func (*BooleanLiteral) literal() {}
|
||||
func (*DurationLiteral) literal() {}
|
||||
func (*IntegerLiteral) literal() {}
|
||||
func (*UnsignedLiteral) literal() {}
|
||||
func (*NilLiteral) literal() {}
|
||||
func (*NumberLiteral) literal() {}
|
||||
func (*RegexLiteral) literal() {}
|
||||
|
|
@ -3273,6 +3276,15 @@ type IntegerLiteral struct {
|
|||
// String returns a string representation of the literal.
|
||||
func (l *IntegerLiteral) String() string { return fmt.Sprintf("%d", l.Val) }
|
||||
|
||||
// UnsignedLiteral represents an unsigned literal. The parser will only use an unsigned literal if the parsed
|
||||
// integer is greater than math.MaxInt64.
|
||||
type UnsignedLiteral struct {
|
||||
Val uint64
|
||||
}
|
||||
|
||||
// String returns a string representation of the literal.
|
||||
func (l *UnsignedLiteral) String() string { return strconv.FormatUint(l.Val, 10) }
|
||||
|
||||
// BooleanLiteral represents a boolean literal.
|
||||
type BooleanLiteral struct {
|
||||
Val bool
|
||||
|
|
|
|||
|
|
@ -2601,6 +2601,11 @@ func (p *Parser) parseUnaryExpr() (Expr, error) {
|
|||
case INTEGER:
|
||||
v, err := strconv.ParseInt(lit, 10, 64)
|
||||
if err != nil {
|
||||
// The literal may be too large to fit into an int64. If it is, use an unsigned integer.
|
||||
// The check for negative numbers is handled somewhere else so this should always be a positive number.
|
||||
if v, err := strconv.ParseUint(lit, 10, 64); err == nil {
|
||||
return &UnsignedLiteral{Val: v}, nil
|
||||
}
|
||||
return nil, &ParseError{Message: "unable to parse integer", Pos: pos}
|
||||
}
|
||||
return &IntegerLiteral{Val: v}, nil
|
||||
|
|
@ -2677,6 +2682,16 @@ func (p *Parser) parseUnaryExpr() (Expr, error) {
|
|||
lit.Val *= float64(mul)
|
||||
case *IntegerLiteral:
|
||||
lit.Val *= int64(mul)
|
||||
case *UnsignedLiteral:
|
||||
if tok == SUB {
|
||||
// Because of twos-complement integers and the method we parse, math.MinInt64 will be parsed
|
||||
// as an UnsignedLiteral because it overflows an int64, but it fits into int64 if it were parsed
|
||||
// as a negative number instead.
|
||||
if lit.Val == uint64(math.MaxInt64+1) {
|
||||
return &IntegerLiteral{Val: int64(-lit.Val)}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("constant -%d underflows int64", lit.Val)
|
||||
}
|
||||
case *DurationLiteral:
|
||||
lit.Val *= time.Duration(mul)
|
||||
case *VarRef, *Call, *ParenExpr:
|
||||
|
|
|
|||
|
|
@ -3069,6 +3069,9 @@ func TestParser_ParseExpr(t *testing.T) {
|
|||
// Primitives
|
||||
{s: `100.0`, expr: &influxql.NumberLiteral{Val: 100}},
|
||||
{s: `100`, expr: &influxql.IntegerLiteral{Val: 100}},
|
||||
{s: `9223372036854775808`, expr: &influxql.UnsignedLiteral{Val: 9223372036854775808}},
|
||||
{s: `-9223372036854775808`, expr: &influxql.IntegerLiteral{Val: -9223372036854775808}},
|
||||
{s: `-9223372036854775809`, err: `constant -9223372036854775809 underflows int64`},
|
||||
{s: `-100.0`, expr: &influxql.NumberLiteral{Val: -100}},
|
||||
{s: `-100`, expr: &influxql.IntegerLiteral{Val: -100}},
|
||||
{s: `100.`, expr: &influxql.NumberLiteral{Val: 100}},
|
||||
|
|
|
|||
Loading…
Reference in New Issue