Merge pull request #8838 from influxdata/js-uint-literal-support

Support uint64 literals in the parser
pull/8843/head
Jonathan A. Sternberg 2017-09-15 12:42:43 -05:00 committed by GitHub
commit 6bd2ae05d4
3 changed files with 30 additions and 0 deletions

View File

@ -190,6 +190,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() {}
@ -323,6 +324,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() {}
@ -344,6 +346,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() {}
@ -3284,6 +3287,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

View File

@ -2603,6 +2603,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
@ -2679,6 +2684,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:

View File

@ -3075,6 +3075,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}},