v2: errors (#534)

```
name                              old time/op    new time/op    delta
UnmarshalDataset/config-32          86.7ms ± 2%    87.5ms ± 2%     ~     (p=0.113 n=9+10)
UnmarshalDataset/canada-32           129ms ± 4%     106ms ± 3%  -17.94%  (p=0.000 n=10+10)
UnmarshalDataset/citm_catalog-32    59.4ms ± 5%    58.7ms ± 5%     ~     (p=0.393 n=10+10)
UnmarshalDataset/twitter-32         27.0ms ± 7%    26.9ms ± 6%     ~     (p=0.720 n=10+9)
UnmarshalDataset/code-32             326ms ± 4%     322ms ± 7%     ~     (p=0.661 n=9+10)
UnmarshalDataset/example-32          510µs ±11%     526µs ± 7%     ~     (p=0.182 n=10+9)
UnmarshalSimple-32                  1.41µs ± 6%    1.41µs ± 4%     ~     (p=0.736 n=10+9)
ReferenceFile-32                    45.6µs ± 3%    43.9µs ±10%     ~     (p=0.089 n=10+10)

name                              old speed      new speed      delta
UnmarshalDataset/config-32        12.1MB/s ± 2%  12.0MB/s ± 2%     ~     (p=0.108 n=9+10)
UnmarshalDataset/canada-32        17.1MB/s ± 4%  20.9MB/s ± 3%  +21.86%  (p=0.000 n=10+10)
UnmarshalDataset/citm_catalog-32  9.41MB/s ± 5%  9.51MB/s ± 5%     ~     (p=0.362 n=10+10)
UnmarshalDataset/twitter-32       16.4MB/s ± 8%  16.5MB/s ± 6%     ~     (p=0.704 n=10+9)
UnmarshalDataset/code-32          8.24MB/s ± 4%  8.34MB/s ± 7%     ~     (p=0.675 n=9+10)
UnmarshalDataset/example-32       15.9MB/s ±11%  15.4MB/s ± 7%     ~     (p=0.182 n=10+9)
ReferenceFile-32                   115MB/s ± 4%   120MB/s ±10%     ~     (p=0.085 n=10+10)

name                              old alloc/op   new alloc/op   delta
UnmarshalDataset/config-32          16.9MB ± 0%    16.9MB ± 0%   -0.02%  (p=0.000 n=10+10)
UnmarshalDataset/canada-32          76.8MB ± 0%    74.3MB ± 0%   -3.31%  (p=0.000 n=10+10)
UnmarshalDataset/citm_catalog-32    37.3MB ± 0%    37.1MB ± 0%   -0.60%  (p=0.000 n=9+10)
UnmarshalDataset/twitter-32         15.6MB ± 0%    15.6MB ± 0%   -0.09%  (p=0.000 n=10+10)
UnmarshalDataset/code-32            60.2MB ± 0%    59.3MB ± 0%   -1.51%  (p=0.000 n=10+9)
UnmarshalDataset/example-32          238kB ± 0%     238kB ± 0%   -0.18%  (p=0.000 n=10+10)
ReferenceFile-32                    11.8kB ± 0%    11.8kB ± 0%     ~     (all equal)

name                              old allocs/op  new allocs/op  delta
UnmarshalDataset/config-32            653k ± 0%      645k ± 0%   -1.20%  (p=0.000 n=10+6)
UnmarshalDataset/canada-32           1.01M ± 0%     0.90M ± 0%  -11.04%  (p=0.000 n=9+10)
UnmarshalDataset/citm_catalog-32      384k ± 0%      370k ± 0%   -3.75%  (p=0.000 n=10+10)
UnmarshalDataset/twitter-32           160k ± 0%      157k ± 0%   -1.32%  (p=0.000 n=10+10)
UnmarshalDataset/code-32             2.97M ± 0%     2.91M ± 0%   -2.15%  (p=0.000 n=10+7)
UnmarshalDataset/example-32          3.69k ± 0%     3.63k ± 0%   -1.52%  (p=0.000 n=10+10)
ReferenceFile-32                       253 ± 0%       253 ± 0%     ~     (all equal)
```
This commit is contained in:
Thomas Pelletier
2021-05-08 16:04:25 -04:00
committed by GitHub
parent 4545a3e94b
commit ea225df3ed
12 changed files with 325 additions and 656 deletions
+23 -41
View File
@@ -2,7 +2,6 @@ package toml
import (
"bytes"
"errors"
"fmt"
"strconv"
@@ -225,19 +224,13 @@ func (p *parser) parseKeyval(b []byte) (ast.Reference, []byte, error) {
return ref, b, err
}
var (
errExpectedValNotEOF = errors.New("expected value, not eof")
errExpectedTrue = errors.New("expected 'true'")
errExpectedFalse = errors.New("expected 'false'")
)
//nolint:cyclop,funlen
func (p *parser) parseVal(b []byte) (ast.Reference, []byte, error) {
// val = string / boolean / array / inline-table / date-time / float / integer
var ref ast.Reference
if len(b) == 0 {
return ref, nil, errExpectedValNotEOF
return ref, nil, newDecodeError(b, "expected value, not eof")
}
var err error
@@ -278,7 +271,7 @@ func (p *parser) parseVal(b []byte) (ast.Reference, []byte, error) {
return ref, b, err
case 't':
if !scanFollowsTrue(b) {
return ref, nil, errExpectedTrue
return ref, nil, newDecodeError(atmost(b, 4), "expected 'true'")
}
ref = p.builder.Push(ast.Node{
@@ -289,7 +282,7 @@ func (p *parser) parseVal(b []byte) (ast.Reference, []byte, error) {
return ref, b[4:], nil
case 'f':
if !scanFollowsFalse(b) {
return ast.Reference{}, nil, errExpectedFalse
return ref, nil, newDecodeError(atmost(b, 5), "expected 'false'")
}
ref = p.builder.Push(ast.Node{
@@ -307,6 +300,13 @@ func (p *parser) parseVal(b []byte) (ast.Reference, []byte, error) {
}
}
func atmost(b []byte, n int) []byte {
if n >= len(b) {
return b
}
return b[:n]
}
func (p *parser) parseLiteralString(b []byte) ([]byte, []byte, error) {
v, rest, err := scanLiteralString(b)
if err != nil {
@@ -370,8 +370,6 @@ func (p *parser) parseInlineTable(b []byte) (ast.Reference, []byte, error) {
return parent, rest, err
}
var errArrayCannotStartWithComma = errors.New("array cannot start with comma")
//nolint:funlen,cyclop
func (p *parser) parseValArray(b []byte) (ast.Reference, []byte, error) {
// array = array-open [ array-values ] ws-comment-newline array-close
@@ -409,7 +407,7 @@ func (p *parser) parseValArray(b []byte) (ast.Reference, []byte, error) {
if b[0] == ',' {
if first {
return parent, nil, errArrayCannotStartWithComma
return parent, nil, newDecodeError(b[0:1], "array cannot start with comma")
}
b = b[1:]
@@ -494,8 +492,6 @@ func (p *parser) parseMultilineLiteralString(b []byte) ([]byte, []byte, error) {
return token[i : len(token)-3], rest, err
}
var errInvalidEscapeChar = errors.New("invalid escaped character")
//nolint:funlen,gocognit,cyclop
func (p *parser) parseMultilineBasicString(b []byte) ([]byte, []byte, error) {
// ml-basic-string = ml-basic-string-delim [ newline ] ml-basic-body
@@ -582,7 +578,7 @@ func (p *parser) parseMultilineBasicString(b []byte) ([]byte, []byte, error) {
builder.WriteString(x)
i += 8
default:
return nil, nil, fmt.Errorf("parseMultilineBasicString: %w - %#U", errInvalidEscapeChar, c)
return nil, nil, newDecodeError(token[i:i+1], "invalid escaped character %#U", c)
}
} else {
builder.WriteByte(c)
@@ -721,7 +717,7 @@ func (p *parser) parseBasicString(b []byte) ([]byte, []byte, error) {
builder.WriteString(x)
i += 8
default:
return nil, nil, fmt.Errorf("parseBasicString: %w - %#U", errInvalidEscapeChar, c)
return nil, nil, newDecodeError(token[i:i+1], "invalid escaped character %#U", c)
}
} else {
builder.WriteByte(c)
@@ -731,18 +727,17 @@ func (p *parser) parseBasicString(b []byte) ([]byte, []byte, error) {
return builder.Bytes(), rest, nil
}
var errUnicodePointNeedsRightCountChar = errors.New("unicode point needs right number of hex characters")
func hexToString(b []byte, length int) (string, error) {
if len(b) < length {
return "", fmt.Errorf("hexToString: %w - %d", errUnicodePointNeedsRightCountChar, length)
return "", newDecodeError(b, "unicode point needs %d character, not %d", length, len(b))
}
b = b[:length]
//nolint:godox
// TODO: slow
intcode, err := strconv.ParseInt(string(b[:length]), 16, 32)
intcode, err := strconv.ParseInt(string(b), 16, 32)
if err != nil {
return "", fmt.Errorf("hexToString: %w", err)
return "", newDecodeError(b, "couldn't parse hexadecimal number: %w", err)
}
return string(rune(intcode)), nil
@@ -757,17 +752,12 @@ func (p *parser) parseWhitespace(b []byte) []byte {
return rest
}
var (
errExpectedInf = errors.New("expected 'inf'")
errExpectedNan = errors.New("expected 'nan'")
)
//nolint:cyclop
func (p *parser) parseIntOrFloatOrDateTime(b []byte) (ast.Reference, []byte, error) {
switch b[0] {
case 'i':
if !scanFollowsInf(b) {
return ast.Reference{}, nil, errExpectedInf
return ast.Reference{}, nil, newDecodeError(atmost(b, 3), "expected 'inf'")
}
return p.builder.Push(ast.Node{
@@ -776,7 +766,7 @@ func (p *parser) parseIntOrFloatOrDateTime(b []byte) (ast.Reference, []byte, err
}), b[3:], nil
case 'n':
if !scanFollowsNan(b) {
return ast.Reference{}, nil, errExpectedNan
return ast.Reference{}, nil, newDecodeError(atmost(b, 3), "expected 'nan'")
}
return p.builder.Push(ast.Node{
@@ -821,8 +811,6 @@ func digitsToInt(b []byte) int {
return x
}
var errTimezoneButNoTimeComponent = errors.New("possible DateTime cannot have a timezone but no time component")
//nolint:gocognit,cyclop
func (p *parser) scanDateTime(b []byte) (ast.Reference, []byte, error) {
// scans for contiguous characters in [0-9T:Z.+-], and up to one space if
@@ -867,7 +855,7 @@ byteLoop:
}
} else {
if hasTz {
return ast.Reference{}, nil, errTimezoneButNoTimeComponent
return ast.Reference{}, nil, newDecodeError(b, "date-time has timezone but not time component")
}
kind = ast.LocalDate
}
@@ -878,12 +866,6 @@ byteLoop:
}), b[i:], nil
}
var (
errUnexpectedCharI = fmt.Errorf("unexpected character i while scanning for a number")
errUnexpectedCharN = fmt.Errorf("unexpected character n while scanning for a number")
errExpectedIntOrFloat = fmt.Errorf("expected integer or float")
)
//nolint:funlen,gocognit,cyclop
func (p *parser) scanIntOrFloat(b []byte) (ast.Reference, []byte, error) {
i := 0
@@ -940,7 +922,7 @@ func (p *parser) scanIntOrFloat(b []byte) (ast.Reference, []byte, error) {
}), b[i+3:], nil
}
return ast.Reference{}, nil, errUnexpectedCharI
return ast.Reference{}, nil, newDecodeError(b[i:i+1], "unexpected character 'i' while scanning for a number")
}
if c == 'n' {
@@ -951,14 +933,14 @@ func (p *parser) scanIntOrFloat(b []byte) (ast.Reference, []byte, error) {
}), b[i+3:], nil
}
return ast.Reference{}, nil, errUnexpectedCharN
return ast.Reference{}, nil, newDecodeError(b[i:i+1], "unexpected character 'n' while scanning for a number")
}
break
}
if i == 0 {
return ast.Reference{}, b, errExpectedIntOrFloat
return ast.Reference{}, b, newDecodeError(b, "incomplete number")
}
kind := ast.Integer