| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of protoc; | 5 part of protoc; |
| 6 | 6 |
| 7 class ProtobufField { | 7 class ProtobufField { |
| 8 static final RegExp HEX_LITERAL_REGEX = | 8 static final RegExp HEX_LITERAL_REGEX = |
| 9 new RegExp(r'^0x[0-9a-f]+$', multiLine: false, caseSensitive: false); | 9 new RegExp(r'^0x[0-9a-f]+$', multiLine: false, caseSensitive: false); |
| 10 static final RegExp INTEGER_LITERAL_REGEX = new RegExp(r'^[+-]?[0-9]+$'); | 10 static final RegExp INTEGER_LITERAL_REGEX = new RegExp(r'^[+-]?[0-9]+$'); |
| 11 static final RegExp DECIMAL_LITERAL_REGEX_A = new RegExp( | 11 static final RegExp DECIMAL_LITERAL_REGEX_A = new RegExp( |
| 12 r'^[+-]?([0-9]*)\.[0-9]+(e[+-]?[0-9]+)?$', | 12 r'^[+-]?([0-9]*)\.[0-9]+(e[+-]?[0-9]+)?$', |
| 13 multiLine: false, | 13 multiLine: false, |
| 14 caseSensitive: false); | 14 caseSensitive: false); |
| 15 static final RegExp DECIMAL_LITERAL_REGEX_B = new RegExp( | 15 static final RegExp DECIMAL_LITERAL_REGEX_B = new RegExp( |
| 16 r'^[+-]?[0-9]+e[+-]?[0-9]+$', | 16 r'^[+-]?[0-9]+e[+-]?[0-9]+$', |
| 17 multiLine: false, | 17 multiLine: false, |
| 18 caseSensitive: false); | 18 caseSensitive: false); |
| 19 | 19 |
| 20 final FieldDescriptorProto _field; | 20 final FieldDescriptorProto descriptor; |
| 21 | 21 |
| 22 /// The index of this field in MessageGenerator._fieldList. | 22 /// Dart names within a GeneratedMessage or `null` for an extension. |
| 23 /// The same index will be stored in FieldInfo.index. | 23 final MemberNames memberNames; |
| 24 /// For extension fields, this will be null. | |
| 25 final int index; | |
| 26 | 24 |
| 27 final String fqname; | 25 final String fqname; |
| 28 final BaseType baseType; | 26 final BaseType baseType; |
| 29 final GenerationOptions _genOptions; | |
| 30 | 27 |
| 31 ProtobufField(FieldDescriptorProto field, this.index, | 28 ProtobufField.message( |
| 29 MemberNames names, ProtobufContainer parent, GenerationContext ctx) |
| 30 : this._(names.descriptor, names, parent, ctx); |
| 31 |
| 32 ProtobufField.extension(FieldDescriptorProto descriptor, |
| 32 ProtobufContainer parent, GenerationContext ctx) | 33 ProtobufContainer parent, GenerationContext ctx) |
| 33 : _field = field, | 34 : this._(descriptor, null, parent, ctx); |
| 34 fqname = '${parent.fqname}.${field.name}', | |
| 35 baseType = new BaseType(field, ctx), | |
| 36 _genOptions = ctx.options; | |
| 37 | 35 |
| 38 int get number => _field.number; | 36 ProtobufField._(FieldDescriptorProto descriptor, MemberNames dartNames, |
| 37 ProtobufContainer parent, GenerationContext ctx) |
| 38 : this.descriptor = descriptor, |
| 39 this.memberNames = dartNames, |
| 40 fqname = '${parent.fqname}.${descriptor.name}', |
| 41 baseType = new BaseType(descriptor, ctx); |
| 42 |
| 43 /// The index of this field in MessageGenerator.fieldList. |
| 44 /// |
| 45 /// `null` for an extension. |
| 46 int get index => memberNames?.index; |
| 39 | 47 |
| 40 bool get isRequired => | 48 bool get isRequired => |
| 41 _field.label == FieldDescriptorProto_Label.LABEL_REQUIRED; | 49 descriptor.label == FieldDescriptorProto_Label.LABEL_REQUIRED; |
| 42 | 50 |
| 43 bool get isRepeated => | 51 bool get isRepeated => |
| 44 _field.label == FieldDescriptorProto_Label.LABEL_REPEATED; | 52 descriptor.label == FieldDescriptorProto_Label.LABEL_REPEATED; |
| 45 | 53 |
| 46 /// True if the field is to be encoded with [packed=true] encoding. | 54 /// True if the field is to be encoded with [packed=true] encoding. |
| 47 bool get isPacked => | 55 bool get isPacked => |
| 48 isRepeated && _field.options != null && _field.options.packed; | 56 isRepeated && descriptor.options != null && descriptor.options.packed; |
| 49 | 57 |
| 50 /// True if this field uses the Int64 from the fixnum package. | 58 /// True if this field uses the Int64 from the fixnum package. |
| 51 bool get needsFixnumImport => baseType.unprefixed == "Int64"; | 59 bool get needsFixnumImport => baseType.unprefixed == "Int64"; |
| 52 | 60 |
| 53 /// Returns the expression to use for the Dart type. | 61 /// Returns the expression to use for the Dart type. |
| 54 /// | 62 /// |
| 55 /// This will be a List for repeated types. | 63 /// This will be a List for repeated types. |
| 56 /// [package] is the package where we are generating code. | 64 /// [package] is the package where we are generating code. |
| 57 String getDartType(String package) { | 65 String getDartType(String package) { |
| 58 if (isRepeated) return baseType.getRepeatedDartType(package); | 66 if (isRepeated) return baseType.getRepeatedDartType(package); |
| 59 return baseType.getDartType(package); | 67 return baseType.getDartType(package); |
| 60 } | 68 } |
| 61 | 69 |
| 70 /// Returns the tag number of the underlying proto field. |
| 71 int get number => descriptor.number; |
| 72 |
| 62 /// Returns the constant in PbFieldType corresponding to this type. | 73 /// Returns the constant in PbFieldType corresponding to this type. |
| 63 String get typeConstant { | 74 String get typeConstant { |
| 64 String prefix = 'O'; | 75 String prefix = 'O'; |
| 65 if (isRequired) { | 76 if (isRequired) { |
| 66 prefix = 'Q'; | 77 prefix = 'Q'; |
| 67 } else if (isPacked) { | 78 } else if (isPacked) { |
| 68 prefix = 'K'; | 79 prefix = 'K'; |
| 69 } else if (isRepeated) { | 80 } else if (isRepeated) { |
| 70 prefix = 'P'; | 81 prefix = 'P'; |
| 71 } | 82 } |
| 72 return "PbFieldType." + prefix + baseType.typeConstantSuffix; | 83 return "PbFieldType." + prefix + baseType.typeConstantSuffix; |
| 73 } | 84 } |
| 74 | 85 |
| 75 /// The name to use by default for the Dart getter and setter. | |
| 76 /// (A suffix will be added if there is a conflict.) | |
| 77 String get dartFieldName { | |
| 78 String name = _fieldMethodSuffix; | |
| 79 return '${name[0].toLowerCase()}${name.substring(1)}'; | |
| 80 } | |
| 81 | |
| 82 String get hasMethodName => 'has$_fieldMethodSuffix'; | |
| 83 String get clearMethodName => 'clear$_fieldMethodSuffix'; | |
| 84 | |
| 85 /// The suffix to use for this field in Dart method names. | |
| 86 /// (It should be camelcase and begin with an uppercase letter.) | |
| 87 String get _fieldMethodSuffix { | |
| 88 String underscoresToCamelCase(String s) { | |
| 89 cap(s) => s.isEmpty ? s : '${s[0].toUpperCase()}${s.substring(1)}'; | |
| 90 return s.split('_').map(cap).join(''); | |
| 91 } | |
| 92 | |
| 93 // For groups, use capitalization of 'typeName' rather than 'name'. | |
| 94 if (baseType.isGroup) { | |
| 95 String name = _field.typeName; | |
| 96 int index = name.lastIndexOf('.'); | |
| 97 if (index != -1) { | |
| 98 name = name.substring(index + 1); | |
| 99 } | |
| 100 return underscoresToCamelCase(name); | |
| 101 } | |
| 102 var name = _genOptions.fieldNameOverrides[fqname]; | |
| 103 return name != null ? name : underscoresToCamelCase(_field.name); | |
| 104 } | |
| 105 | |
| 106 /// Returns Dart code adding this field to a BuilderInfo object. | 86 /// Returns Dart code adding this field to a BuilderInfo object. |
| 107 /// The call will start with ".." and a method name. | 87 /// The call will start with ".." and a method name. |
| 108 /// [package] is the package where the code will be evaluated. | 88 /// [package] is the package where the code will be evaluated. |
| 109 String generateBuilderInfoCall(String package) { | 89 String generateBuilderInfoCall(String package, String dartFieldName) { |
| 110 String quotedName = "'$dartFieldName'"; | 90 String quotedName = "'$dartFieldName'"; |
| 111 String type = baseType.getDartType(package); | 91 String type = baseType.getDartType(package); |
| 112 | 92 |
| 113 if (isRepeated) { | 93 if (isRepeated) { |
| 114 if (baseType.isMessage || baseType.isGroup) { | 94 if (baseType.isMessage || baseType.isGroup) { |
| 115 return '..pp/*<$type>*/($number, $quotedName, $typeConstant,' | 95 return '..pp/*<$type>*/($number, $quotedName, $typeConstant,' |
| 116 ' $type.$checkItem, $type.create)'; | 96 ' $type.$checkItem, $type.create)'; |
| 117 } else if (baseType.isEnum) { | 97 } else if (baseType.isEnum) { |
| 118 return '..pp/*<$type>*/($number, $quotedName, $typeConstant,' | 98 return '..pp/*<$type>*/($number, $quotedName, $typeConstant,' |
| 119 ' $type.$checkItem, null, $type.valueOf)'; | 99 ' $type.$checkItem, null, $type.valueOf)'; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 138 | 118 |
| 139 return prefix + ', $makeDefault)'; | 119 return prefix + ', $makeDefault)'; |
| 140 } | 120 } |
| 141 | 121 |
| 142 /// Returns a Dart expression that evaluates to this field's default value. | 122 /// Returns a Dart expression that evaluates to this field's default value. |
| 143 /// | 123 /// |
| 144 /// Returns "null" if unavailable, in which case FieldSet._getDefault() | 124 /// Returns "null" if unavailable, in which case FieldSet._getDefault() |
| 145 /// should be called instead. | 125 /// should be called instead. |
| 146 String getDefaultExpr() { | 126 String getDefaultExpr() { |
| 147 if (isRepeated) return "null"; | 127 if (isRepeated) return "null"; |
| 148 switch (_field.type) { | 128 switch (descriptor.type) { |
| 149 case FieldDescriptorProto_Type.TYPE_BOOL: | 129 case FieldDescriptorProto_Type.TYPE_BOOL: |
| 150 return _getDefaultAsBoolExpr("false"); | 130 return _getDefaultAsBoolExpr("false"); |
| 151 case FieldDescriptorProto_Type.TYPE_INT32: | 131 case FieldDescriptorProto_Type.TYPE_INT32: |
| 152 case FieldDescriptorProto_Type.TYPE_UINT32: | 132 case FieldDescriptorProto_Type.TYPE_UINT32: |
| 153 case FieldDescriptorProto_Type.TYPE_SINT32: | 133 case FieldDescriptorProto_Type.TYPE_SINT32: |
| 154 case FieldDescriptorProto_Type.TYPE_FIXED32: | 134 case FieldDescriptorProto_Type.TYPE_FIXED32: |
| 155 case FieldDescriptorProto_Type.TYPE_SFIXED32: | 135 case FieldDescriptorProto_Type.TYPE_SFIXED32: |
| 156 return _getDefaultAsInt32Expr("0"); | 136 return _getDefaultAsInt32Expr("0"); |
| 157 case FieldDescriptorProto_Type.TYPE_STRING: | 137 case FieldDescriptorProto_Type.TYPE_STRING: |
| 158 return _getDefaultAsStringExpr("''"); | 138 return _getDefaultAsStringExpr("''"); |
| 159 default: | 139 default: |
| 160 return "null"; | 140 return "null"; |
| 161 } | 141 } |
| 162 } | 142 } |
| 163 | 143 |
| 164 /// Returns a function expression that returns the field's default value. | 144 /// Returns a function expression that returns the field's default value. |
| 165 /// | 145 /// |
| 166 /// [package] is the package where the expression will be evaluated. | 146 /// [package] is the package where the expression will be evaluated. |
| 167 /// Returns null if this field doesn't have an initializer. | 147 /// Returns null if this field doesn't have an initializer. |
| 168 String generateDefaultFunction(String package) { | 148 String generateDefaultFunction(String package) { |
| 169 if (isRepeated) { | 149 if (isRepeated) { |
| 170 return '() => new PbList()'; | 150 return '() => new PbList()'; |
| 171 } | 151 } |
| 172 | 152 |
| 173 bool samePackage = package == baseType.package; | 153 bool samePackage = package == baseType.package; |
| 174 | 154 |
| 175 switch (_field.type) { | 155 switch (descriptor.type) { |
| 176 case FieldDescriptorProto_Type.TYPE_BOOL: | 156 case FieldDescriptorProto_Type.TYPE_BOOL: |
| 177 return _getDefaultAsBoolExpr(null); | 157 return _getDefaultAsBoolExpr(null); |
| 178 case FieldDescriptorProto_Type.TYPE_FLOAT: | 158 case FieldDescriptorProto_Type.TYPE_FLOAT: |
| 179 case FieldDescriptorProto_Type.TYPE_DOUBLE: | 159 case FieldDescriptorProto_Type.TYPE_DOUBLE: |
| 180 if (!_field.hasDefaultValue()) { | 160 if (!descriptor.hasDefaultValue()) { |
| 181 return null; | 161 return null; |
| 182 } else if ('0.0' == _field.defaultValue || '0' == _field.defaultValue) { | 162 } else if ('0.0' == descriptor.defaultValue || |
| 163 '0' == descriptor.defaultValue) { |
| 183 return null; | 164 return null; |
| 184 } else if (_field.defaultValue == 'inf') { | 165 } else if (descriptor.defaultValue == 'inf') { |
| 185 return 'double.INFINITY'; | 166 return 'double.INFINITY'; |
| 186 } else if (_field.defaultValue == '-inf') { | 167 } else if (descriptor.defaultValue == '-inf') { |
| 187 return 'double.NEGATIVE_INFINITY'; | 168 return 'double.NEGATIVE_INFINITY'; |
| 188 } else if (_field.defaultValue == 'nan') { | 169 } else if (descriptor.defaultValue == 'nan') { |
| 189 return 'double.NAN'; | 170 return 'double.NAN'; |
| 190 } else if (HEX_LITERAL_REGEX.hasMatch(_field.defaultValue)) { | 171 } else if (HEX_LITERAL_REGEX.hasMatch(descriptor.defaultValue)) { |
| 191 return '(${_field.defaultValue}).toDouble()'; | 172 return '(${descriptor.defaultValue}).toDouble()'; |
| 192 } else if (INTEGER_LITERAL_REGEX.hasMatch(_field.defaultValue)) { | 173 } else if (INTEGER_LITERAL_REGEX.hasMatch(descriptor.defaultValue)) { |
| 193 return '${_field.defaultValue}.0'; | 174 return '${descriptor.defaultValue}.0'; |
| 194 } else if (DECIMAL_LITERAL_REGEX_A.hasMatch(_field.defaultValue) || | 175 } else if (DECIMAL_LITERAL_REGEX_A.hasMatch(descriptor.defaultValue) || |
| 195 DECIMAL_LITERAL_REGEX_B.hasMatch(_field.defaultValue)) { | 176 DECIMAL_LITERAL_REGEX_B.hasMatch(descriptor.defaultValue)) { |
| 196 return '${_field.defaultValue}'; | 177 return '${descriptor.defaultValue}'; |
| 197 } | 178 } |
| 198 throw _invalidDefaultValue; | 179 throw _invalidDefaultValue; |
| 199 case FieldDescriptorProto_Type.TYPE_INT32: | 180 case FieldDescriptorProto_Type.TYPE_INT32: |
| 200 case FieldDescriptorProto_Type.TYPE_UINT32: | 181 case FieldDescriptorProto_Type.TYPE_UINT32: |
| 201 case FieldDescriptorProto_Type.TYPE_SINT32: | 182 case FieldDescriptorProto_Type.TYPE_SINT32: |
| 202 case FieldDescriptorProto_Type.TYPE_FIXED32: | 183 case FieldDescriptorProto_Type.TYPE_FIXED32: |
| 203 case FieldDescriptorProto_Type.TYPE_SFIXED32: | 184 case FieldDescriptorProto_Type.TYPE_SFIXED32: |
| 204 return _getDefaultAsInt32Expr(null); | 185 return _getDefaultAsInt32Expr(null); |
| 205 case FieldDescriptorProto_Type.TYPE_INT64: | 186 case FieldDescriptorProto_Type.TYPE_INT64: |
| 206 case FieldDescriptorProto_Type.TYPE_UINT64: | 187 case FieldDescriptorProto_Type.TYPE_UINT64: |
| 207 case FieldDescriptorProto_Type.TYPE_SINT64: | 188 case FieldDescriptorProto_Type.TYPE_SINT64: |
| 208 case FieldDescriptorProto_Type.TYPE_FIXED64: | 189 case FieldDescriptorProto_Type.TYPE_FIXED64: |
| 209 case FieldDescriptorProto_Type.TYPE_SFIXED64: | 190 case FieldDescriptorProto_Type.TYPE_SFIXED64: |
| 210 var value = '0'; | 191 var value = '0'; |
| 211 if (_field.hasDefaultValue()) value = _field.defaultValue; | 192 if (descriptor.hasDefaultValue()) value = descriptor.defaultValue; |
| 212 if (value == '0') return 'Int64.ZERO'; | 193 if (value == '0') return 'Int64.ZERO'; |
| 213 return "parseLongInt('$value')"; | 194 return "parseLongInt('$value')"; |
| 214 case FieldDescriptorProto_Type.TYPE_STRING: | 195 case FieldDescriptorProto_Type.TYPE_STRING: |
| 215 return _getDefaultAsStringExpr(null); | 196 return _getDefaultAsStringExpr(null); |
| 216 case FieldDescriptorProto_Type.TYPE_BYTES: | 197 case FieldDescriptorProto_Type.TYPE_BYTES: |
| 217 if (!_field.hasDefaultValue() || _field.defaultValue.isEmpty) { | 198 if (!descriptor.hasDefaultValue() || descriptor.defaultValue.isEmpty) { |
| 218 return null; | 199 return null; |
| 219 } | 200 } |
| 220 String byteList = _field.defaultValue.codeUnits | 201 String byteList = descriptor.defaultValue.codeUnits |
| 221 .map((b) => '0x${b.toRadixString(16)}') | 202 .map((b) => '0x${b.toRadixString(16)}') |
| 222 .join(','); | 203 .join(','); |
| 223 return '() => <int>[$byteList]'; | 204 return '() => <int>[$byteList]'; |
| 224 case FieldDescriptorProto_Type.TYPE_GROUP: | 205 case FieldDescriptorProto_Type.TYPE_GROUP: |
| 225 case FieldDescriptorProto_Type.TYPE_MESSAGE: | 206 case FieldDescriptorProto_Type.TYPE_MESSAGE: |
| 226 if (samePackage) return '${baseType.unprefixed}.getDefault'; | 207 if (samePackage) return '${baseType.unprefixed}.getDefault'; |
| 227 return "${baseType.prefixed}.getDefault"; | 208 return "${baseType.prefixed}.getDefault"; |
| 228 case FieldDescriptorProto_Type.TYPE_ENUM: | 209 case FieldDescriptorProto_Type.TYPE_ENUM: |
| 229 var className = samePackage ? baseType.unprefixed : baseType.prefixed; | 210 var className = samePackage ? baseType.unprefixed : baseType.prefixed; |
| 230 EnumGenerator gen = baseType.generator; | 211 EnumGenerator gen = baseType.generator; |
| 231 if (_field.hasDefaultValue() && !_field.defaultValue.isEmpty) { | 212 if (descriptor.hasDefaultValue() && !descriptor.defaultValue.isEmpty) { |
| 232 return '$className.${_field.defaultValue}'; | 213 return '$className.${descriptor.defaultValue}'; |
| 233 } else if (!gen._canonicalValues.isEmpty) { | 214 } else if (!gen._canonicalValues.isEmpty) { |
| 234 return '$className.${gen._canonicalValues[0].name}'; | 215 return '$className.${gen._canonicalValues[0].name}'; |
| 235 } | 216 } |
| 236 return null; | 217 return null; |
| 237 default: | 218 default: |
| 238 throw _typeNotImplemented("generatedDefaultFunction"); | 219 throw _typeNotImplemented("generatedDefaultFunction"); |
| 239 } | 220 } |
| 240 } | 221 } |
| 241 | 222 |
| 242 String _getDefaultAsBoolExpr(String noDefault) { | 223 String _getDefaultAsBoolExpr(String noDefault) { |
| 243 if (_field.hasDefaultValue() && 'false' != _field.defaultValue) { | 224 if (descriptor.hasDefaultValue() && 'false' != descriptor.defaultValue) { |
| 244 return '${_field.defaultValue}'; | 225 return '${descriptor.defaultValue}'; |
| 245 } | 226 } |
| 246 return noDefault; | 227 return noDefault; |
| 247 } | 228 } |
| 248 | 229 |
| 249 String _getDefaultAsStringExpr(String noDefault) { | 230 String _getDefaultAsStringExpr(String noDefault) { |
| 250 if (!_field.hasDefaultValue() || _field.defaultValue.isEmpty) { | 231 if (!descriptor.hasDefaultValue() || descriptor.defaultValue.isEmpty) { |
| 251 return noDefault; | 232 return noDefault; |
| 252 } | 233 } |
| 253 // TODO(skybrian): fix dubious escaping. | 234 // TODO(skybrian): fix dubious escaping. |
| 254 String value = _field.defaultValue.replaceAll(r'$', r'\$'); | 235 String value = descriptor.defaultValue.replaceAll(r'$', r'\$'); |
| 255 return '\'$value\''; | 236 return '\'$value\''; |
| 256 } | 237 } |
| 257 | 238 |
| 258 String _getDefaultAsInt32Expr(String noDefault) { | 239 String _getDefaultAsInt32Expr(String noDefault) { |
| 259 if (_field.hasDefaultValue() && '0' != _field.defaultValue) { | 240 if (descriptor.hasDefaultValue() && '0' != descriptor.defaultValue) { |
| 260 return '${_field.defaultValue}'; | 241 return '${descriptor.defaultValue}'; |
| 261 } | 242 } |
| 262 return noDefault; | 243 return noDefault; |
| 263 } | 244 } |
| 264 | 245 |
| 265 get _invalidDefaultValue => "dart-protoc-plugin:" | 246 get _invalidDefaultValue => "dart-protoc-plugin:" |
| 266 " invalid default value (${_field.defaultValue})" | 247 " invalid default value (${descriptor.defaultValue})" |
| 267 " found in field $fqname"; | 248 " found in field $fqname"; |
| 268 | 249 |
| 269 _typeNotImplemented(String methodName) => "dart-protoc-plugin:" | 250 _typeNotImplemented(String methodName) => "dart-protoc-plugin:" |
| 270 " $methodName not implemented for type (${_field.type})" | 251 " $methodName not implemented for type (${descriptor.type})" |
| 271 " found in field $fqname"; | 252 " found in field $fqname"; |
| 272 } | 253 } |
| OLD | NEW |