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 |