diff options
author | Ting-Wei Lan <tingwei.lan@cobinhood.com> | 2019-02-21 18:28:32 +0800 |
---|---|---|
committer | Jhih-Ming Huang <jm.huang@cobinhood.com> | 2019-05-06 10:44:04 +0800 |
commit | 7628271e5d363a9a7283efb6f7d8b1b52e392e45 (patch) | |
tree | 9f945adc38fcf76a6fafae0de774e963780dad78 /core/vm/sqlvm/parser/parser.go | |
parent | 1efc4819e3882a4c4def3bc88527fc51b6ef3a45 (diff) | |
download | dexon-7628271e5d363a9a7283efb6f7d8b1b52e392e45.tar dexon-7628271e5d363a9a7283efb6f7d8b1b52e392e45.tar.gz dexon-7628271e5d363a9a7283efb6f7d8b1b52e392e45.tar.bz2 dexon-7628271e5d363a9a7283efb6f7d8b1b52e392e45.tar.lz dexon-7628271e5d363a9a7283efb6f7d8b1b52e392e45.tar.xz dexon-7628271e5d363a9a7283efb6f7d8b1b52e392e45.tar.zst dexon-7628271e5d363a9a7283efb6f7d8b1b52e392e45.zip |
core: vm: sqlvm: fill source code position in AST nodes
Now all AST nodes should have position information recorded during
parsing. These fields are intended to be used to report errors and make
debugging easier. However, precise location of each token is currently
unavailable. It can be done in the future if it becomes necessary.
To make it easier to traverse an AST, GetChildren is modified to skip
nil nodes in the output. This means callers of GetChildren don't have
to check for nil in returned slices.
AST printer is modified to print the position and the corresponding
source code token. A few special handling for interfaces are removed
because reflection works better for structs.
Diffstat (limited to 'core/vm/sqlvm/parser/parser.go')
-rw-r--r-- | core/vm/sqlvm/parser/parser.go | 63 |
1 files changed, 57 insertions, 6 deletions
diff --git a/core/vm/sqlvm/parser/parser.go b/core/vm/sqlvm/parser/parser.go index fdde37dd5..e8aa49c89 100644 --- a/core/vm/sqlvm/parser/parser.go +++ b/core/vm/sqlvm/parser/parser.go @@ -164,9 +164,7 @@ func joinOperator(x ast.ExprNode, o ast.ExprNode) { case ast.UnaryOperator: joinOperator(op.GetTarget(), o) case ast.BinaryOperator: - op.SetObject(o) - case *ast.CastOperatorNode: - op.SourceExpr = o + opSetObject(op, o) case *ast.InOperatorNode: op.Left = o default: @@ -179,10 +177,10 @@ func rightJoinOperators(o ast.ExprNode, x []ast.ExprNode) ast.ExprNode { return o } l := len(x) + joinOperator(x[0], o) for idx := 0; idx < l-1; idx++ { joinOperator(x[idx+1], x[idx]) } - joinOperator(x[0], o) return x[l-1] } @@ -300,6 +298,22 @@ func resolveString(s []byte) ([]byte, []byte, errors.ErrorCode) { return o.Bytes(), nil, errors.ErrorCodeNil } +func walkSelfFirst(n ast.Node, v func(ast.Node, []ast.Node)) { + c := n.GetChildren() + v(n, c) + for i := range c { + walkSelfFirst(c[i], v) + } +} + +func walkChildrenFirst(n ast.Node, v func(ast.Node, []ast.Node)) { + c := n.GetChildren() + for i := range c { + walkChildrenFirst(c[i], v) + } + v(n, c) +} + // Parse parses SQL commands text and return an AST. func Parse(b []byte, o ...Option) ([]ast.Node, error) { // The string sent from the caller is not guaranteed to be valid UTF-8. @@ -333,6 +347,43 @@ func Parse(b []byte, o ...Option) ([]ast.Node, error) { stmts := assertNodeSlice(root) // Process the AST. + for i := range stmts { + if stmts[i] == nil { + continue + } + walkChildrenFirst(stmts[i], func(n ast.Node, c []ast.Node) { + minBegin := uint32(len(eb)) + maxEnd := uint32(0) + for _, cn := range append(c, n) { + if cn.HasPosition() { + begin := cn.GetPosition() + end := begin + cn.GetLength() + if begin < minBegin { + minBegin = begin + } + if end > maxEnd { + maxEnd = end + } + } + } + n.SetPosition(minBegin) + n.SetLength(maxEnd - minBegin) + }) + walkSelfFirst(stmts[i], func(n ast.Node, _ []ast.Node) { + begin := n.GetPosition() + end := begin + n.GetLength() + fixedBegin, ok := encMap[begin] + if !ok { + panic(fmt.Sprintf("cannot fix node begin byte offset %d", begin)) + } + fixedEnd, ok := encMap[end] + if !ok { + panic(fmt.Sprintf("cannot fix node end byte offset %d", end)) + } + n.SetPosition(fixedBegin) + n.SetLength(fixedEnd - fixedBegin) + }) + } if pigeonErr == nil { return stmts, pigeonErr } @@ -359,8 +410,8 @@ func Parse(b []byte, o ...Option) ([]ast.Node, error) { if offset, ok := encMap[sqlvmErrList[i].Position]; ok { sqlvmErrList[i].Position = offset } else { - panic(fmt.Sprintf( - "cannot fix byte offset %d", sqlvmErrList[i].Position)) + panic(fmt.Sprintf("cannot fix error position byte offset %d", + sqlvmErrList[i].Position)) } } return stmts, sqlvmErrList |