go-toml/value_number.go

77 lines
2.8 KiB
Go

package parser
import (
"strconv"
"git.makaay.nl/mauricem/go-parsekit/parse"
)
var (
// Integers are whole numbers. Positive numbers may be prefixed with a
// plus sign. Negative numbers are prefixed with a minus sign. For large
// numbers, you may use underscores between digits to enhance readability.
// Each underscore must be surrounded by at least one digit on each side.
// Leading zeros are not allowed.
integerPrefix = a.Signed(a.DigitNotZero.Then(a.Digits.Optional()))
underscoreDigits = m.Drop(a.Underscore).Then(a.Digits)
integerSuffix = c.ZeroOrMore(underscoreDigits)
integer = integerPrefix.Then(integerSuffix)
// Integer values -0 and +0 are valid and identical to an unprefixed zero.
zero = a.Rune('0')
plusZero = a.Plus.Then(zero)
minusZero = a.Minus.Then(zero)
// Non-negative integer values may also be expressed in hexadecimal, octal,
// or binary. In these formats, leading + is not allowed and leading zeros
// are allowed (after the prefix). Hex values are case insensitive.
// Underscores are allowed between digits (but not between the prefix
// and the value).
// Hexadecimal with prefix `0x`.
hexDigits = c.OneOrMore(a.HexDigit)
underscoreHexDigits = m.Drop(a.Underscore).Then(hexDigits)
hexadecimal = a.Rune('x').Then(tok.Str("x", hexDigits.Then(c.ZeroOrMore(underscoreHexDigits))))
// Octal with prefix `0o`.
octalDigits = c.OneOrMore(a.RuneRange('0', '7'))
underscoreOctalDigits = m.Drop(a.Underscore).Then(octalDigits)
octal = a.Rune('o').Then(tok.Str("o", octalDigits.Then(c.ZeroOrMore(underscoreOctalDigits))))
// Binary with prefix `0b`.
binaryDigits = c.OneOrMore(a.RuneRange('0', '1'))
underscoreBinaryDigits = m.Drop(a.Underscore).Then(binaryDigits)
binary = a.Rune('b').Then(tok.Str("b", binaryDigits.Then(c.ZeroOrMore(underscoreBinaryDigits))))
)
func (t *parser) startInteger(p *parse.API) {
switch {
case p.Accept(zero):
p.Handle(t.startIntegerStartingWithZero)
case p.Accept(plusZero.Or(minusZero)):
t.emitCommand(csetIntVal, int64(0))
case p.Accept(tok.Int64(nil, integer)):
t.emitCommand(csetIntVal, p.Result().Value(0).(int64))
default:
p.Expected("an integer value")
}
}
func (t *parser) startIntegerStartingWithZero(p *parse.API) {
var value int64
var err error
switch {
case p.Accept(hexadecimal):
value, err = strconv.ParseInt(p.Result().Value(0).(string), 16, 64)
case p.Accept(octal):
value, err = strconv.ParseInt(p.Result().Value(0).(string), 8, 64)
case p.Accept(binary):
value, err = strconv.ParseInt(p.Result().Value(0).(string), 2, 64)
default:
t.emitCommand(csetIntVal, int64(0))
return
}
if err == nil {
t.emitCommand(csetIntVal, value)
} else {
p.Error("Cannot parse value 0%s: %s", p.Result().String(), err)
}
}