diff options
author | Ting-Wei Lan <lantw44@gmail.com> | 2019-05-03 20:16:23 +0800 |
---|---|---|
committer | Ting-Wei Lan <tingwei.lan@cobinhood.com> | 2019-05-14 11:04:15 +0800 |
commit | 205ebe4072b72db336ec855a65b031591cf3f7ab (patch) | |
tree | 7ed5be8f448d0a728c0063de2c67d40a177e3180 /core/vm | |
parent | d4c1848efc0cd1482f324dd456e37379f8e37cf0 (diff) | |
download | dexon-205ebe4072b72db336ec855a65b031591cf3f7ab.tar dexon-205ebe4072b72db336ec855a65b031591cf3f7ab.tar.gz dexon-205ebe4072b72db336ec855a65b031591cf3f7ab.tar.bz2 dexon-205ebe4072b72db336ec855a65b031591cf3f7ab.tar.lz dexon-205ebe4072b72db336ec855a65b031591cf3f7ab.tar.xz dexon-205ebe4072b72db336ec855a65b031591cf3f7ab.tar.zst dexon-205ebe4072b72db336ec855a65b031591cf3f7ab.zip |
code backup 29
Diffstat (limited to 'core/vm')
-rw-r--r-- | core/vm/sqlvm/ast/ast.go | 7 | ||||
-rw-r--r-- | core/vm/sqlvm/checker/checker.go | 359 | ||||
-rw-r--r-- | core/vm/sqlvm/checker/utils.go | 28 |
3 files changed, 383 insertions, 11 deletions
diff --git a/core/vm/sqlvm/ast/ast.go b/core/vm/sqlvm/ast/ast.go index 9b0efd8f3..6358af16c 100644 --- a/core/vm/sqlvm/ast/ast.go +++ b/core/vm/sqlvm/ast/ast.go @@ -910,17 +910,12 @@ func (n *LessOperatorNode) GetType() DataType { // ConcatOperatorNode is '||'. type ConcatOperatorNode struct { - UntaggedExprNodeBase + TaggedExprNodeBase BinaryOperatorNode } var _ BinaryOperator = (*ConcatOperatorNode)(nil) -// GetType returns the type of 'bytes'. -func (n *ConcatOperatorNode) GetType() DataType { - return ComposeDataType(DataTypeMajorDynamicBytes, DataTypeMinorDontCare) -} - // AddOperatorNode is '+'. type AddOperatorNode struct { TaggedExprNodeBase diff --git a/core/vm/sqlvm/checker/checker.go b/core/vm/sqlvm/checker/checker.go index f376afc1d..995cd0485 100644 --- a/core/vm/sqlvm/checker/checker.go +++ b/core/vm/sqlvm/checker/checker.go @@ -889,7 +889,7 @@ func checkExpr(n ast.ExprNode, return checkLessOperator(n, s, o, c, el, tr, ta) case *ast.ConcatOperatorNode: - return n + return checkConcatOperator(n, s, o, c, el, tr, ta) case *ast.AddOperatorNode: return n @@ -1023,6 +1023,7 @@ func checkVariable(n *ast.IdentifierNode, dt := s[tr].Columns[cr].Type switch a := ta.(type) { case typeActionInferDefault: + case typeActionInferWithMajor: case typeActionInferWithSize: case typeActionAssign: if !dt.Equal(a.dt) { @@ -1080,6 +1081,7 @@ func checkBoolValue(n *ast.BoolValueNode, switch a := ta.(type) { case typeActionInferDefault: + case typeActionInferWithMajor: case typeActionInferWithSize: case typeActionAssign: major, _ := ast.DecomposeDataType(a.dt) @@ -1098,6 +1100,7 @@ func checkAddressValue(n *ast.AddressValueNode, switch a := ta.(type) { case typeActionInferDefault: + case typeActionInferWithMajor: case typeActionInferWithSize: case typeActionAssign: major, _ := ast.DecomposeDataType(a.dt) @@ -1473,6 +1476,34 @@ executeTypeAction: ta = newTypeActionAssign(dt) goto executeTypeAction + case typeActionInferWithMajor: + switch a.major { + case ast.DataTypeMajorFixedBytes: + if len(n.V) < 1 || len(n.V) > 32 { + el.Append(errors.Error{ + Position: n.GetPosition(), + Length: n.GetLength(), + Category: errors.ErrorCategorySemantic, + Code: errors.ErrorCodeTypeError, + Severity: errors.ErrorSeverityError, + Prefix: fn, + Message: fmt.Sprintf( + "cannot infer %s (length %d) as fixed-size bytes", + ast.QuoteString(n.V), len(n.V)), + }, nil) + return nil + } + minor := ast.DataTypeMinor(len(n.V)) + dt = ast.ComposeDataType(a.major, minor) + ta = newTypeActionAssign(dt) + case ast.DataTypeMajorDynamicBytes: + dt = ast.ComposeDataType(a.major, ast.DataTypeMinorDontCare) + ta = newTypeActionAssign(dt) + default: + ta = newTypeActionInferDefault() + } + goto executeTypeAction + case typeActionInferWithSize: major := ast.DataTypeMajorFixedBytes minor := ast.DataTypeMinor(a.size - 1) @@ -1525,6 +1556,8 @@ func checkNullValue(n *ast.NullValueNode, switch a := ta.(type) { case typeActionInferDefault: dt = ast.DataTypeNull + case typeActionInferWithMajor: + dt = ast.DataTypeNull case typeActionInferWithSize: dt = ast.DataTypeNull case typeActionAssign: @@ -1673,6 +1706,11 @@ func checkPosOperator(n *ast.PosOperatorNode, r = checkExpr(r, s, o, c, el, tr, ta) } + case typeActionInferWithMajor: + if dt.Pending() { + r = checkExpr(r, s, o, c, el, tr, ta) + } + case typeActionInferWithSize: if dt.Pending() { r = checkExpr(r, s, o, c, el, tr, ta) @@ -1771,6 +1809,11 @@ func checkNegOperator(n *ast.NegOperatorNode, r = checkExpr(r, s, o, c, el, tr, ta) } + case typeActionInferWithMajor: + if dt.Pending() { + r = checkExpr(r, s, o, c, el, tr, ta) + } + case typeActionInferWithSize: if dt.Pending() { r = checkExpr(r, s, o, c, el, tr, ta) @@ -1859,6 +1902,7 @@ func checkNotOperator(n *ast.NotOperatorNode, switch a := ta.(type) { case typeActionInferDefault: + case typeActionInferWithMajor: case typeActionInferWithSize: case typeActionAssign: if !dt.Equal(a.dt) { @@ -1942,6 +1986,7 @@ func checkAndOperator(n *ast.AndOperatorNode, switch a := ta.(type) { case typeActionInferDefault: + case typeActionInferWithMajor: case typeActionInferWithSize: case typeActionAssign: if !dt.Equal(a.dt) { @@ -2013,6 +2058,7 @@ func checkOrOperator(n *ast.OrOperatorNode, switch a := ta.(type) { case typeActionInferDefault: + case typeActionInferWithMajor: case typeActionInferWithSize: case typeActionAssign: if !dt.Equal(a.dt) { @@ -2310,6 +2356,7 @@ func checkRelationalOperator(n ast.BinaryOperator, switch a := ta.(type) { case typeActionInferDefault: + case typeActionInferWithMajor: case typeActionInferWithSize: case typeActionAssign: if !dt.Equal(a.dt) { @@ -2477,3 +2524,313 @@ func checkLessOperator(n *ast.LessOperatorNode, }, ) } + +func validateBytesType(dt ast.DataType, el *errors.ErrorList, n ast.ExprNode, + fn, op string) bool { + + if !dt.Pending() { + major, _ := ast.DecomposeDataType(dt) + switch major { + case ast.DataTypeMajorFixedBytes, + ast.DataTypeMajorDynamicBytes: + default: + elAppendTypeErrorOperatorDataType(el, n, fn, op, dt) + return false + } + } + return true +} + +type extractBytesValueStatus uint8 + +const ( + extractBytesValueStatusError extractBytesValueStatus = iota + extractBytesValueStatusBytes + extractBytesValueStatusNullWithType + extractBytesValueStatusNullWithoutType +) + +func extractBytesValue(n ast.Valuer, el *errors.ErrorList, + fn, op string) ([]byte, extractBytesValueStatus) { + + switch n := n.(type) { + case *ast.BytesValueNode: + return n.V, extractBytesValueStatusBytes + case *ast.NullValueNode: + if n.GetType().Pending() { + return nil, extractBytesValueStatusNullWithoutType + } + return nil, extractBytesValueStatusNullWithType + case *ast.BoolValueNode: + case *ast.AddressValueNode: + case *ast.IntegerValueNode: + case *ast.DecimalValueNode: + default: + panic(unknownValueNodeType(n)) + } + elAppendTypeErrorOperatorValueNode(el, n, fn, op) + return nil, extractBytesValueStatusError +} + +func checkConcatOperator(n *ast.ConcatOperatorNode, + s schema.Schema, o CheckOptions, c *schemaCache, el *errors.ErrorList, + tr schema.TableRef, ta typeAction) ast.ExprNode { + + fn := "CheckConcatOperator" + op := "binary operator ||" + + object := n.GetObject() + object = checkExpr(object, s, o, c, el, tr, nil) + if object == nil { + return nil + } + subject := n.GetSubject() + subject = checkExpr(subject, s, o, c, el, tr, nil) + if subject == nil { + return nil + } + n.SetObject(object) + n.SetSubject(subject) + r := ast.ExprNode(n) + + dtObject := object.GetType() + if !validateBytesType(dtObject, el, object, fn, op) { + return nil + } + dtSubject := subject.GetType() + if !validateBytesType(dtSubject, el, subject, fn, op) { + return nil + } + + dtObjectDetermined := !dtObject.Pending() + dtSubjectDetermined := !dtSubject.Pending() + + // We cannot use inferBinaryOperatorType because we allows two sides of the + // operator to have different types. + unknownBytesMajor := func(major ast.DataTypeMajor) string { + return fmt.Sprintf("%02x is not a bytes type", uint8(major)) + } + describeBytesMajor := func(major ast.DataTypeMajor) string { + switch major { + case ast.DataTypeMajorFixedBytes: + return "fixed-size" + case ast.DataTypeMajorDynamicBytes: + return "dynamically-sized" + default: + panic(unknownBytesMajor(major)) + } + } + reportMismatch := func(n ast.ExprNode, major1, major2 ast.DataTypeMajor) { + el.Append(errors.Error{ + Position: n.GetPosition(), + Length: n.GetLength(), + Category: errors.ErrorCategorySemantic, + Code: errors.ErrorCodeTypeError, + Severity: errors.ErrorSeverityError, + Prefix: fn, + Message: fmt.Sprintf("cannot use %s between %s and %s bytes", op, + describeBytesMajor(major1), describeBytesMajor(major2)), + }, nil) + } + reportTooBig := func(dt1, dt2 ast.DataType) { + el.Append(errors.Error{ + Position: n.GetPosition(), + Length: n.GetLength(), + Category: errors.ErrorCategorySemantic, + Code: errors.ErrorCodeTypeError, + Severity: errors.ErrorSeverityError, + Prefix: fn, + Message: fmt.Sprintf( + "cannot use %s between %s (%04x) and %s (%04x) because "+ + "the result will be longer than 32 bytes", + op, dt1.String(), uint16(dt1), dt2.String(), uint16(dt2)), + }, nil) + el.Append(errors.Error{ + Position: n.GetPosition(), + Length: n.GetLength(), + Category: 0, + Code: 0, + Severity: errors.ErrorSeverityNote, + Prefix: fn, + Message: fmt.Sprintf( + "convert both arguments to %s bytes in order to "+ + "produce a binary string that is bigger than a slot", + describeBytesMajor(ast.DataTypeMajorDynamicBytes)), + }, nil) + } + updateObject := func() { + n.SetObject(object) + dtObject = object.GetType() + dtObjectDetermined = !dtObject.Pending() + } + updateSubject := func() { + n.SetSubject(subject) + dtSubject = subject.GetType() + dtSubjectDetermined = !dtSubject.Pending() + } + infer := func() (ast.DataType, bool) { + if !dtObjectDetermined { + panic("dtObject is pending") + } + if !dtSubjectDetermined { + panic("dtSubject is pending") + } + majorObject, minorObject := ast.DecomposeDataType(dtObject) + majorSubject, minorSubject := ast.DecomposeDataType(dtSubject) + if majorObject != majorSubject { + reportMismatch(n, majorObject, majorSubject) + return ast.DataTypeBad, false + } + switch majorObject { + case ast.DataTypeMajorFixedBytes: + sizeObject := int(minorObject) + 1 + sizeSubject := int(minorSubject) + 1 + sizeOperator := sizeObject + sizeSubject + if sizeOperator > 32 { + reportTooBig(dtObject, dtSubject) + return ast.DataTypeBad, false + } + majorOperator := ast.DataTypeMajorFixedBytes + minorOperator := ast.DataTypeMinor(sizeOperator - 1) + return ast.ComposeDataType(majorOperator, minorOperator), true + case ast.DataTypeMajorDynamicBytes: + return dtObject, true + default: + panic(unknownBytesMajor(majorObject)) + } + } + + switch { + case dtObjectDetermined && dtSubjectDetermined: + dt, ok := infer() + if !ok { + return nil + } + n.SetType(dt) + + case dtObjectDetermined && !dtSubjectDetermined: + var action typeAction + major, _ := ast.DecomposeDataType(dtObject) + switch major { + case ast.DataTypeMajorFixedBytes: + action = newTypeActionInferWithMajor(ast.DataTypeMajorFixedBytes) + case ast.DataTypeMajorDynamicBytes: + action = newTypeActionAssign(dtObject) + default: + panic(unknownBytesMajor(major)) + } + subject = checkExpr(subject, s, o, c, el, tr, action) + if subject == nil { + return nil + } + updateSubject() + dt, ok := infer() + if !ok { + return nil + } + n.SetType(dt) + + case !dtObjectDetermined && dtSubjectDetermined: + var action typeAction + major, _ := ast.DecomposeDataType(dtSubject) + switch major { + case ast.DataTypeMajorFixedBytes: + action = newTypeActionInferWithMajor(ast.DataTypeMajorFixedBytes) + case ast.DataTypeMajorDynamicBytes: + action = newTypeActionAssign(dtSubject) + default: + panic(unknownBytesMajor(major)) + } + object = checkExpr(object, s, o, c, el, tr, action) + if object == nil { + return nil + } + updateObject() + dt, ok := infer() + if !ok { + return nil + } + n.SetType(dt) + + case !dtObjectDetermined && !dtSubjectDetermined: + // Keep it undetermined if both sides are pending. + + default: + panic("unreachable") + } + dt := n.GetType() + + if object, ok := object.(ast.Valuer); ok { + if subject, ok := subject.(ast.Valuer); ok { + null := false + v1, status := extractBytesValue(object, el, fn, op) + switch status { + case extractBytesValueStatusError: + return nil + case extractBytesValueStatusBytes: + case extractBytesValueStatusNullWithType: + null = true + case extractBytesValueStatusNullWithoutType: + elAppendTypeErrorOperatorValueNode(el, object, fn, op) + return nil + default: + panic(fmt.Sprintf("unknown status %d", status)) + } + v2, status := extractBytesValue(subject, el, fn, op) + switch status { + case extractBytesValueStatusError: + return nil + case extractBytesValueStatusBytes: + case extractBytesValueStatusNullWithType: + null = true + case extractBytesValueStatusNullWithoutType: + elAppendTypeErrorOperatorValueNode(el, subject, fn, op) + return nil + default: + panic(fmt.Sprintf("unknown status %d", status)) + } + if null { + node := &ast.NullValueNode{} + r = node + } else { + node := &ast.BytesValueNode{} + node.V = make([]byte, 0, len(v1)+len(v2)) + node.V = append(node.V, v1...) + node.V = append(node.V, v2...) + r = node + } + r.SetPosition(n.GetPosition()) + r.SetLength(n.GetLength()) + r.SetToken(n.GetToken()) + r.SetType(dt) + } + } + + switch a := ta.(type) { + case typeActionInferDefault: + if dt.Pending() { + r = checkExpr(r, s, o, c, el, tr, ta) + } + + case typeActionInferWithMajor: + if dt.Pending() { + r = checkExpr(r, s, o, c, el, tr, ta) + } + + case typeActionInferWithSize: + if dt.Pending() { + r = checkExpr(r, s, o, c, el, tr, ta) + } + + case typeActionAssign: + if dt.Pending() { + r = checkExpr(r, s, o, c, el, tr, ta) + } else { + if !dt.Equal(a.dt) { + elAppendTypeErrorAssignDataType(el, n, fn, a.dt, dt) + return nil + } + } + } + return r +} diff --git a/core/vm/sqlvm/checker/utils.go b/core/vm/sqlvm/checker/utils.go index 36a77ef9e..7dbe89125 100644 --- a/core/vm/sqlvm/checker/utils.go +++ b/core/vm/sqlvm/checker/utils.go @@ -452,7 +452,7 @@ type typeAction interface { // If the type of the node is already determined, it should ignore the request. type typeActionInferDefault struct{} -func newTypeActionInferDefaultSize() typeActionInferDefault { +func newTypeActionInferDefault() typeActionInferDefault { return typeActionInferDefault{} } @@ -460,6 +460,26 @@ var _ typeAction = typeActionInferDefault{} func (typeActionInferDefault) ˉtypeAction() {} +// typeActionInferWithMajor requests the node to infer the type with preference +// to a specific major type. It usually that the parent node cares the major +// type but does not care the size of it. It is an advisory request. If it is +// impossible to infer the node as the specified type, it should automatically +// fallback to the default case as if typeActionInferDefault were used. If the +// type is already determined, the request is ignored and the parent node should +// be able to handle the problem by itself. +type typeActionInferWithMajor struct { + major ast.DataTypeMajor +} + +func newTypeActionInferWithMajor(category ast.DataTypeMajor, +) typeActionInferWithMajor { + return typeActionInferWithMajor{major: category} +} + +var _ typeAction = typeActionInferWithMajor{} + +func (typeActionInferWithMajor) ˉtypeAction() {} + // typeActionInferWithSize requests the node to infer the type with size // requirement. The size is measured in bytes. It is indented to be used in // CAST to support conversion between integer and fixed-size bytes types. @@ -477,13 +497,13 @@ var _ typeAction = typeActionInferWithSize{} func (typeActionInferWithSize) ˉtypeAction() {} +// typeActionAssign requests the node to have a specific type. It is a +// mandatory request. If the node is unable to meet the requirement, it should +// throw an error. It is not allowed to ignore the request. type typeActionAssign struct { dt ast.DataType } -// newTypeActionAssign requests the node to have a specific type. It is a -// mandatory request. If the node is unable to meet the requirement, it should -// throw an error. It is not allowed to ignore the request. func newTypeActionAssign(expected ast.DataType) typeActionAssign { return typeActionAssign{dt: expected} } |