aboutsummaryrefslogtreecommitdiffstats
path: root/core/vm/sqlvm/parser/parser.go
diff options
context:
space:
mode:
authorTing-Wei Lan <tingwei.lan@cobinhood.com>2019-01-24 17:46:39 +0800
committerJhih-Ming Huang <jm.huang@cobinhood.com>2019-05-06 10:44:03 +0800
commitf73b9db5523ec173d738f96a5127061ad8b37164 (patch)
tree168be62c8632dd70887e2a7a71d23694e12c39f2 /core/vm/sqlvm/parser/parser.go
parentd07af9fe6ba1299bec081b77d575d31a23a2f6e1 (diff)
downloaddexon-f73b9db5523ec173d738f96a5127061ad8b37164.tar
dexon-f73b9db5523ec173d738f96a5127061ad8b37164.tar.gz
dexon-f73b9db5523ec173d738f96a5127061ad8b37164.tar.bz2
dexon-f73b9db5523ec173d738f96a5127061ad8b37164.tar.lz
dexon-f73b9db5523ec173d738f96a5127061ad8b37164.tar.xz
dexon-f73b9db5523ec173d738f96a5127061ad8b37164.tar.zst
dexon-f73b9db5523ec173d738f96a5127061ad8b37164.zip
core: vm: sqlvm: parser: properly handle errors
Instead of ignoring errors, errors returned from external functions are normalized and reported to users. Errors which should be impossible to occur are converted to panic calls.
Diffstat (limited to 'core/vm/sqlvm/parser/parser.go')
-rw-r--r--core/vm/sqlvm/parser/parser.go85
1 files changed, 72 insertions, 13 deletions
diff --git a/core/vm/sqlvm/parser/parser.go b/core/vm/sqlvm/parser/parser.go
index 19d5e7477..8904c747c 100644
--- a/core/vm/sqlvm/parser/parser.go
+++ b/core/vm/sqlvm/parser/parser.go
@@ -1,16 +1,21 @@
package parser
import (
+ "bytes"
"encoding/hex"
+ "fmt"
"strconv"
"strings"
"github.com/dexon-foundation/dexon/core/vm/sqlvm/ast"
+ "github.com/dexon-foundation/dexon/core/vm/sqlvm/errors"
"github.com/shopspring/decimal"
)
// Parser was generated with pigeon v1.0.0-99-gbb0192c.
//go:generate pigeon -no-recover -o grammar.go grammar.peg
+//go:generate sh -c "sed -f grammar.sed grammar.go > grammar_new.go"
+//go:generate mv grammar_new.go grammar.go
//go:generate goimports -w grammar.go
func prepend(x interface{}, xs interface{}) []interface{} {
@@ -34,7 +39,10 @@ func hexToInteger(h []byte) interface{} {
l := len(h)
base := decimal.New(16, 0)
for idx, b := range h {
- i, _ := strconv.ParseInt(string([]byte{b}), 16, 32)
+ i, err := strconv.ParseInt(string([]byte{b}), 16, 32)
+ if err != nil {
+ panic(fmt.Sprintf("invalid hex digit %s: %v", []byte{b}, err))
+ }
d = d.Add(
decimal.New(i, 0).
Mul(base.Pow(decimal.New(int64(l-idx-1), 0))),
@@ -44,21 +52,54 @@ func hexToInteger(h []byte) interface{} {
}
func hexToBytes(h []byte) []byte {
- bs, _ := hex.DecodeString(string(h))
+ bs := make([]byte, hex.DecodedLen(len(h)))
+ _, err := hex.Decode(bs, h)
+ if err != nil {
+ panic(fmt.Sprintf("invalid hex string %s: %v", h, err))
+ }
return bs
}
-func toUint(b []byte) uint32 {
- i, _ := strconv.ParseUint(string(b), 10, 32)
- return uint32(i)
+func convertNumError(err error) errors.ErrorCode {
+ if err == nil {
+ return errors.ErrorCodeNil
+ }
+ switch err.(*strconv.NumError).Err {
+ case strconv.ErrSyntax:
+ return errors.ErrorCodeSyntax
+ case strconv.ErrRange:
+ return errors.ErrorCodeIntegerRange
+ }
+ panic(fmt.Sprintf("unknown NumError: %v", err))
+}
+
+func convertDecimalError(err error) errors.ErrorCode {
+ if err == nil {
+ return errors.ErrorCodeNil
+ }
+ errStr := err.Error()
+ if strings.HasSuffix(errStr, "decimal: fractional part too long") {
+ return errors.ErrorCodeFractionalPartTooLong
+ } else if strings.HasSuffix(errStr, "decimal: exponent is not numeric") {
+ return errors.ErrorCodeSyntax
+ } else if strings.HasSuffix(errStr, "decimal: too many .s") {
+ return errors.ErrorCodeSyntax
+ }
+ panic(fmt.Sprintf("unknown decimal error: %v", err))
+}
+
+func toUint(b []byte) (uint32, errors.ErrorCode) {
+ i, err := strconv.ParseUint(string(b), 10, 32)
+ return uint32(i), convertNumError(err)
}
-func toDecimal(b []byte) decimal.Decimal {
- return decimal.RequireFromString(string(b))
+func toDecimal(b []byte) (decimal.Decimal, errors.ErrorCode) {
+ d, err := decimal.NewFromString(string(b))
+ return d, convertDecimalError(err)
}
func toLower(b []byte) []byte {
- return []byte(strings.ToLower(string(b)))
+ return bytes.ToLower(b)
}
func joinBytes(x interface{}) []byte {
@@ -105,10 +146,7 @@ func rightJoinOperators(o interface{}, x interface{}) interface{} {
return o
}
l := len(xs)
- for idx := range xs {
- if idx == l-1 {
- break
- }
+ for idx := 0; idx < l-1; idx++ {
joinOperator(xs[idx+1], xs[idx])
}
joinOperator(xs[0], o)
@@ -122,5 +160,26 @@ func resolveString(s []byte) []byte {
// ParseString parses input string to AST.
func ParseString(s string) (interface{}, error) {
- return ParseReader("parser", strings.NewReader(s))
+ root, pigeonErr := ParseReader("", strings.NewReader(s))
+ if pigeonErr == nil {
+ return root, pigeonErr
+ }
+ pigeonErrList := pigeonErr.(errList)
+ sqlvmErrList := make(errors.ErrorList, len(pigeonErrList))
+ for i := range pigeonErrList {
+ parserErr := pigeonErrList[i].(*parserError)
+ if sqlvmErr, ok := parserErr.Inner.(errors.Error); ok {
+ sqlvmErrList[i] = sqlvmErr
+ } else {
+ sqlvmErrList[i] = errors.Error{
+ Position: uint32(parserErr.pos.offset),
+ Category: errors.ErrorCategoryGrammar,
+ Code: errors.ErrorCodeParser,
+ Token: "",
+ Prefix: parserErr.prefix,
+ Message: parserErr.Inner.Error(),
+ }
+ }
+ }
+ return root, sqlvmErrList
}