Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(429)

Unified Diff: mojom/mojom_parser/mojom/user_defined_types.go

Issue 1805743003: Mojom frontend: Compute, validate and populate struct field version info (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Rename ComputeDataForGenerators to ComputeFinalData Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « mojom/mojom_parser/mojom/types_test.go ('k') | mojom/mojom_parser/mojom/user_defined_types_test.go » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: mojom/mojom_parser/mojom/user_defined_types.go
diff --git a/mojom/mojom_parser/mojom/user_defined_types.go b/mojom/mojom_parser/mojom/user_defined_types.go
index 0da6dfcc657bc21e7020a6740065f6be306c3e2a..4daf9796e730780f6c179dd898ccfe0a9a25cb1e 100644
--- a/mojom/mojom_parser/mojom/user_defined_types.go
+++ b/mojom/mojom_parser/mojom/user_defined_types.go
@@ -80,6 +80,13 @@ type UserDefinedType interface {
// reachable from this UserDefinedType. This method must only be invoked
// after type resolution has succeeded.
FindReachableTypes() []string
+
+ // ComputeFinalData() is invoked on each user-defined type in a MojomDescriptor
+ // after the resolution and type validation phases have completed successfully.
+ // The method computes information that is useful for the code generators in the
+ // backend. Examples include struct field packing data and MinVersion values.
+ // See computed_data.go.
+ ComputeFinalData() error
}
// This struct is embedded in each of MojomStruct, MojomInterface
@@ -334,8 +341,13 @@ type MojomStruct struct {
fieldsByName map[string]*StructField
FieldsInLexicalOrder []*StructField
+
+ // This is computed after the parsing phase.
fieldsInOrdinalOrder []*StructField
+ // This is computed in ComputeVersionInfo which is invoked by ComputeFinalData().
+ versionInfo []StructVersion
+
// Used to form an error message in case of a duplicate field name.
userFacingName string
}
@@ -424,6 +436,13 @@ func (s *MojomStruct) FieldsInOrdinalOrder() []*StructField {
return s.fieldsInOrdinalOrder
}
+func (s *MojomStruct) VersionInfo() []StructVersion {
+ if s.versionInfo == nil {
+ panic("The method ComputeVersionInfo() must be invoked first.")
+ }
+ return s.versionInfo
+}
+
func (*MojomStruct) Kind() UserDefinedTypeKind {
return UserDefinedTypeKindStruct
}
@@ -499,6 +518,145 @@ func (s *MojomStruct) ComputeFieldOrdinals() error {
return nil
}
+var ErrMinVersionIllformed = errors.New("MinVersion attribute value illformed")
+var ErrMinVersionOutOfOrder = errors.New("MinVersion attribute value out of order")
+var ErrMinVersionNotNullable = errors.New("Non-Zero MinVersion attribute value on non-nullable field")
+
+type StructFieldMinVersionError struct {
+ // The field whose MinVersion is being set.
+ field *StructField
+
+ // The MinValue of the previous field. Only used for ErrMinVersionOutOfOrder
+ previousValue uint32
+
+ // The LiteralValue of the attribute assignment.
+ // NOTE: We use the following convention: literalValue.token == nil indicates that
+ // there was no MinVersion attribute on the given field. This can only happen with
+ // ErrMinVersionOutOfOrder
+ literalValue LiteralValue
+
+ // The type of error (ErrMinVersionIllfromed, ErrMinVersionOutOfOrder, ErrMinVersionNotNullable)
+ err error
+}
+
+// StructFieldMinVersionError implements error.
+func (e *StructFieldMinVersionError) Error() string {
+ var message string
+ var token lexer.Token
+ switch e.err {
+ case ErrMinVersionIllformed:
+ message = fmt.Sprintf("Invalid MinVersion attribute for field %s: %s. "+
+ "The value must be a non-negative 32-bit integer value.",
+ e.field.SimpleName(), e.literalValue)
+ token = *e.literalValue.token
+ case ErrMinVersionOutOfOrder:
+ if e.literalValue.token == nil {
+ message = fmt.Sprintf("Invalid missing MinVersion for field %s. "+
+ "The MinVersion must be non-decreasing as a function of the ordinal. "+
+ "This field must have a MinVersion attribute with a value at least %d.",
+ e.field.SimpleName(), e.previousValue)
+ token = e.field.NameToken()
+ } else {
+ message = fmt.Sprintf("Invalid MinVersion attribute for field %s: %s. "+
+ "The MinVersion must be non-decreasing as a function of the ordinal. "+
+ "This field's MinVersion must be at least %d.",
+ e.field.SimpleName(), e.literalValue.token.Text, e.previousValue)
+ token = *e.literalValue.token
+ }
+ case ErrMinVersionNotNullable:
+ message = fmt.Sprintf("Invalid type for field %s: %s. "+
+ "Non-nullable fields are only allowed in version 0 of of a struct. "+
+ "This field's MinVersion is %s.",
+ e.field.SimpleName(), e.field.FieldType.TypeName(), e.literalValue.token.Text)
+ switch fieldType := e.field.FieldType.(type) {
+ case *UserTypeRef:
+ token = fieldType.token
+ default:
+ // It would be nice for the green carets in the snippit in the error message to point at
+ // the type name, but other than for user type refs we don't store that token so
+ // instead we use the field's name.
+ token = e.field.NameToken()
+ }
+ }
+ return UserErrorMessage(e.field.OwningFile(), token, message)
+}
+
+// ComputeVersionInfo is invoked by ComputeFinalData() after the
+// parsing, resolution and type validation phases. It examines the |MinVersion|
+// attributes of all of the fields of the struct, validates the values, and
+// sets up the versionInfo array.
+func (s *MojomStruct) ComputeVersionInfo() error {
+ s.versionInfo = make([]StructVersion, 0)
+ previousMinVersion := uint32(0)
+ payloadSizeSoFar := uint32(0)
+ for i, field := range s.fieldsInOrdinalOrder {
+ value, literalValue, found, ok := field.minVersionAttribute()
+ if found == false {
+ if previousMinVersion != 0 {
+ return &StructFieldMinVersionError{
+ field: field,
+ previousValue: previousMinVersion,
+ literalValue: MakeStringLiteralValue("", nil),
+ err: ErrMinVersionOutOfOrder,
+ }
+ }
+ } else {
+ if !ok {
+ return &StructFieldMinVersionError{
+ field: field,
+ literalValue: literalValue,
+ err: ErrMinVersionIllformed,
+ }
+ }
+ if value < previousMinVersion {
+ return &StructFieldMinVersionError{
+ field: field,
+ previousValue: previousMinVersion,
+ literalValue: literalValue,
+ err: ErrMinVersionOutOfOrder,
+ }
+ }
+ }
+ if value != 0 && !field.FieldType.Nullable() {
+ return &StructFieldMinVersionError{
+ field: field,
+ literalValue: literalValue,
+ err: ErrMinVersionNotNullable,
+ }
+ }
+ field.minVersion = int64(value)
+ if value > previousMinVersion {
+ s.versionInfo = append(s.versionInfo, StructVersion{
+ VersionNumber: previousMinVersion,
+ NumFields: uint32(i),
+ NumBytes: payloadSizeSoFar,
+ })
+ previousMinVersion = value
+ }
+ // TODO(rudominer) Set payloadSizeSoFar to the payload size if the
+ // current |field| were the last field.
+ }
+ s.versionInfo = append(s.versionInfo, StructVersion{
+ VersionNumber: previousMinVersion,
+ NumFields: uint32(len(s.fieldsInOrdinalOrder)),
+ NumBytes: payloadSizeSoFar,
+ })
+
+ return nil
+}
+
+// ComputeFieldOffsets is invoked by ComputeFinalData after the
+// parsing, resolution and type validation phases. It computes the |offset|
+// and |bit| fields of each struct field.
+func (s *MojomStruct) ComputeFieldOffsets() error {
+ // TODO(rudominer) Implement MojomStruct.ComputeFieldOffsets
+ for _, field := range s.FieldsInLexicalOrder {
+ field.offset = 0
+ field.bit = 0
+ }
+ return nil
+}
+
func (m MojomStruct) String() string {
s := fmt.Sprintf("\n---------struct--------------\n")
s += fmt.Sprintf("%s\n", m.UserDefinedTypeBase)
@@ -547,14 +705,27 @@ type StructField struct {
FieldType TypeRef
DefaultValue ValueRef
- // TODO(rudominer) Implement struct field offset computation.
- Offset int32
+
+ // Computed Data. The values are computed and set in
+ // See mojom_types.mojom for the meanings.
+
+ // A valid offset is a uint32. We use -1 to indicate unset.
+ offset int64
+
+ // A valid |bit| value is a uint8. We use -1 to indicate unset.
+ bit int16
+
+ // A valid min version is a unt32. We use -1 to indicate unset.
+ minVersion int64
}
func NewStructField(declData DeclarationData, fieldType TypeRef, defaultValue ValueRef) *StructField {
field := StructField{FieldType: fieldType, DefaultValue: defaultValue}
declData.declaredObject = &field
field.DeclarationData = declData
+ field.offset = -1
+ field.bit = -1
+ field.minVersion = -1
return &field
}
@@ -600,6 +771,52 @@ func (f *StructField) KindString() string {
return "field"
}
+const minVersionAttributeName = "MinVersion"
+
+// minVersionAttribute() Attempts to return a uint32 corresponding to the "MinVersion" attribute of this field.
+// If found = false then no such attribute could be found and the rest of the return values should be ignored.
+// If found = true then |literalValue| is the LiteralValue of the found attribute. In this case:
+// If ok = false then |literalValue| does not contain a uint32 and |value| should be ignored.
+// If ok = true then |literalValue| contains the uint32 value in |value|.
+func (f *StructField) minVersionAttribute() (value uint32, literalValue LiteralValue, found, ok bool) {
+ if f.attributes == nil {
+ return 0, LiteralValue{}, false, false
+ }
+ for _, attribute := range f.attributes.List {
+ if attribute.Key == minVersionAttributeName {
+ value, ok := uint32Value(attribute.Value)
+ return value, attribute.Value, true, ok
+ }
+ }
+ return 0, LiteralValue{}, false, false
+}
+
+// MinVersion() returns the computed value of MinVersion for this field. This method should only be invoked
+// after the method ComputeVersionInfo() has been invoked on the containing MojomStruct and returned a nil error.
+// This method is different than the minVersionAttribute() method in that it does not just return a value
+// for fields that have the "MinVersion" attribute explicitly specified. Rather it returns a computed value for
+// every field after the "MinVersion" attributes for every field have been checked and validated.
+func (f *StructField) MinVersion() uint32 {
+ if f.minVersion < 0 {
+ panic("The method ComputeVersionInfo() must first be invoked for the containing struct.")
+ }
+ return uint32(f.minVersion)
+}
+
+func (f *StructField) Offset() uint32 {
+ if f.offset < 0 {
+ panic("The method ComputeFieldOffsets() must first be invoked for the containing struct.")
+ }
+ return uint32(f.offset)
+}
+
+func (f *StructField) Bit() uint8 {
+ if f.bit < 0 {
+ panic("The method ComputeFieldOffsets() must first be invoked for the containing struct.")
+ }
+ return uint8(f.bit)
+}
+
func (f StructField) String() string {
attributeString := ""
if f.attributes != nil {
@@ -616,6 +833,13 @@ func (f StructField) String() string {
return fmt.Sprintf("%s%s %s%s%s", attributeString, f.FieldType, f.simpleName, ordinalString, defaultValueString)
}
+// See StructVersion in mojom_types.mojom for a description of the fields.
+type StructVersion struct {
+ VersionNumber uint32
+ NumFields uint32
+ NumBytes uint32
+}
+
/////////////////////////////////////////////////////////////
// Interfaces and Methods
/////////////////////////////////////////////////////////////
« no previous file with comments | « mojom/mojom_parser/mojom/types_test.go ('k') | mojom/mojom_parser/mojom/user_defined_types_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698