| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 '''python %prog [options] platform chromium_os_flag template | 6 '''python %prog [options] platform chromium_os_flag template |
| 7 | 7 |
| 8 platform specifies which platform source is being generated for | 8 platform specifies which platform source is being generated for |
| 9 and can be one of (win, mac, linux) | 9 and can be one of (win, mac, linux) |
| 10 chromium_os_flag should be 1 if this is a Chromium OS build | 10 chromium_os_flag should be 1 if this is a Chromium OS build |
| (...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 277 'boolean': None, | 277 'boolean': None, |
| 278 'integer': None, | 278 'integer': None, |
| 279 'null': None, | 279 'null': None, |
| 280 'number': None, | 280 'number': None, |
| 281 'string': None, | 281 'string': None, |
| 282 } | 282 } |
| 283 self.stringlist_type = None | 283 self.stringlist_type = None |
| 284 self.ranges = {} | 284 self.ranges = {} |
| 285 | 285 |
| 286 def GetString(self, s): | 286 def GetString(self, s): |
| 287 return self.shared_strings[s] if s in self.shared_strings else '"%s"' % s | 287 if s in self.shared_strings: |
| 288 return self.shared_strings[s] |
| 289 # Generate JSON escaped string, which is slightly different from desired |
| 290 # C/C++ escaped string. Known differences includes unicode escaping format. |
| 291 return json.dumps(s) |
| 288 | 292 |
| 289 def AppendSchema(self, type, extra, comment=''): | 293 def AppendSchema(self, type, extra, comment=''): |
| 290 index = len(self.schema_nodes) | 294 index = len(self.schema_nodes) |
| 291 self.schema_nodes.append((type, extra, comment)) | 295 self.schema_nodes.append((type, extra, comment)) |
| 292 return index | 296 return index |
| 293 | 297 |
| 294 def AppendRestriction(self, first, second): | 298 def AppendRestriction(self, first, second): |
| 295 r = (str(first), str(second)) | 299 r = (str(first), str(second)) |
| 296 if not r in self.ranges: | 300 if not r in self.ranges: |
| 297 self.ranges[r] = len(self.restriction_nodes) | 301 self.ranges[r] = len(self.restriction_nodes) |
| (...skipping 10 matching lines...) Expand all Loading... |
| 308 | 312 |
| 309 def GetStringList(self): | 313 def GetStringList(self): |
| 310 if self.stringlist_type == None: | 314 if self.stringlist_type == None: |
| 311 self.stringlist_type = self.AppendSchema( | 315 self.stringlist_type = self.AppendSchema( |
| 312 'TYPE_LIST', | 316 'TYPE_LIST', |
| 313 self.GetSimpleType('string'), | 317 self.GetSimpleType('string'), |
| 314 'simple type: stringlist') | 318 'simple type: stringlist') |
| 315 return self.stringlist_type | 319 return self.stringlist_type |
| 316 | 320 |
| 317 def SchemaHaveRestriction(self, schema): | 321 def SchemaHaveRestriction(self, schema): |
| 318 return 'minimum' in schema or 'maximum' in schema or 'enum' in schema | 322 return any(keyword in schema for keyword in |
| 323 ['minimum', 'maximum', 'enum', 'pattern']) |
| 319 | 324 |
| 320 def IsConsecutiveInterval(self, seq): | 325 def IsConsecutiveInterval(self, seq): |
| 321 sortedSeq = sorted(seq) | 326 sortedSeq = sorted(seq) |
| 322 return all(sortedSeq[i] + 1 == sortedSeq[i + 1] | 327 return all(sortedSeq[i] + 1 == sortedSeq[i + 1] |
| 323 for i in xrange(len(sortedSeq) - 1)) | 328 for i in xrange(len(sortedSeq) - 1)) |
| 324 | 329 |
| 325 def GetEnumIntegerType(self, schema, name): | 330 def GetEnumIntegerType(self, schema, name): |
| 326 assert all(type(x) == int for x in schema['enum']) | 331 assert all(type(x) == int for x in schema['enum']) |
| 327 possible_values = schema['enum'] | 332 possible_values = schema['enum'] |
| 328 if self.IsConsecutiveInterval(possible_values): | 333 if self.IsConsecutiveInterval(possible_values): |
| (...skipping 19 matching lines...) Expand all Loading... |
| 348 def GetEnumType(self, schema, name): | 353 def GetEnumType(self, schema, name): |
| 349 if len(schema['enum']) == 0: | 354 if len(schema['enum']) == 0: |
| 350 raise RuntimeError('Empty enumeration in %s' % name) | 355 raise RuntimeError('Empty enumeration in %s' % name) |
| 351 elif schema['type'] == 'integer': | 356 elif schema['type'] == 'integer': |
| 352 return self.GetEnumIntegerType(schema, name) | 357 return self.GetEnumIntegerType(schema, name) |
| 353 elif schema['type'] == 'string': | 358 elif schema['type'] == 'string': |
| 354 return self.GetEnumStringType(schema, name) | 359 return self.GetEnumStringType(schema, name) |
| 355 else: | 360 else: |
| 356 raise RuntimeError('Unknown enumeration type in %s' % name) | 361 raise RuntimeError('Unknown enumeration type in %s' % name) |
| 357 | 362 |
| 363 def GetPatternType(self, schema, name): |
| 364 if schema['type'] != 'string': |
| 365 raise RuntimeError('Unknown pattern type in %s' % name) |
| 366 pattern = schema['pattern'] |
| 367 # Try to compile the pattern to validate it, note that the syntax used |
| 368 # here might be slightly different from re2. |
| 369 # TODO(binjin): Add a python wrapper of re2 and use it here. |
| 370 re.compile(pattern) |
| 371 index = len(self.string_enums); |
| 372 self.string_enums.append(pattern); |
| 373 return self.AppendSchema('TYPE_STRING', |
| 374 self.AppendRestriction(index, index), |
| 375 'string with pattern restriction: %s' % name); |
| 376 |
| 358 def GetRangedType(self, schema, name): | 377 def GetRangedType(self, schema, name): |
| 359 if schema['type'] != 'integer': | 378 if schema['type'] != 'integer': |
| 360 raise RuntimeError('Unknown ranged type in %s' % name) | 379 raise RuntimeError('Unknown ranged type in %s' % name) |
| 361 min_value_set, max_value_set = False, False | 380 min_value_set, max_value_set = False, False |
| 362 if 'minimum' in schema: | 381 if 'minimum' in schema: |
| 363 min_value = int(schema['minimum']) | 382 min_value = int(schema['minimum']) |
| 364 min_value_set = True | 383 min_value_set = True |
| 365 if 'maximum' in schema: | 384 if 'maximum' in schema: |
| 366 max_value = int(schema['minimum']) | 385 max_value = int(schema['minimum']) |
| 367 max_value_set = True | 386 max_value_set = True |
| (...skipping 10 matching lines...) Expand all Loading... |
| 378 """Generates the structs for the given schema. | 397 """Generates the structs for the given schema. |
| 379 | 398 |
| 380 |schema|: a valid JSON schema in a dictionary. | 399 |schema|: a valid JSON schema in a dictionary. |
| 381 |name|: the name of the current node, for the generated comments.""" | 400 |name|: the name of the current node, for the generated comments.""" |
| 382 if schema['type'] in self.simple_types: | 401 if schema['type'] in self.simple_types: |
| 383 if not self.SchemaHaveRestriction(schema): | 402 if not self.SchemaHaveRestriction(schema): |
| 384 # Simple types use shared nodes. | 403 # Simple types use shared nodes. |
| 385 return self.GetSimpleType(schema['type']) | 404 return self.GetSimpleType(schema['type']) |
| 386 elif 'enum' in schema: | 405 elif 'enum' in schema: |
| 387 return self.GetEnumType(schema, name) | 406 return self.GetEnumType(schema, name) |
| 407 elif 'pattern' in schema: |
| 408 return self.GetPatternType(schema, name) |
| 388 else: | 409 else: |
| 389 return self.GetRangedType(schema, name) | 410 return self.GetRangedType(schema, name) |
| 390 | 411 |
| 391 if schema['type'] == 'array': | 412 if schema['type'] == 'array': |
| 392 # Special case for lists of strings, which is a common policy type. | 413 # Special case for lists of strings, which is a common policy type. |
| 393 if schema['items']['type'] == 'string': | 414 if schema['items']['type'] == 'string': |
| 394 return self.GetStringList() | 415 return self.GetStringList() |
| 395 return self.AppendSchema( | 416 return self.AppendSchema( |
| 396 'TYPE_LIST', | 417 'TYPE_LIST', |
| 397 self.Generate(schema['items'], 'items of ' + name)) | 418 self.Generate(schema['items'], 'items of ' + name)) |
| 398 elif schema['type'] == 'object': | 419 elif schema['type'] == 'object': |
| 399 # Reserve an index first, so that dictionaries come before their | 420 # Reserve an index first, so that dictionaries come before their |
| 400 # properties. This makes sure that the root node is the first in the | 421 # properties. This makes sure that the root node is the first in the |
| 401 # SchemaNodes array. | 422 # SchemaNodes array. |
| 402 index = self.AppendSchema('TYPE_DICTIONARY', -1) | 423 index = self.AppendSchema('TYPE_DICTIONARY', -1) |
| 403 | 424 |
| 404 if 'additionalProperties' in schema: | 425 if 'additionalProperties' in schema: |
| 405 additionalProperties = self.Generate( | 426 additionalProperties = self.Generate( |
| 406 schema['additionalProperties'], | 427 schema['additionalProperties'], |
| 407 'additionalProperties of ' + name) | 428 'additionalProperties of ' + name) |
| 408 else: | 429 else: |
| 409 additionalProperties = -1 | 430 additionalProperties = -1 |
| 410 | 431 |
| 411 # Properties must be sorted by name, for the binary search lookup. | 432 # Properties must be sorted by name, for the binary search lookup. |
| 412 # Note that |properties| must be evaluated immediately, so that all the | 433 # Note that |properties| must be evaluated immediately, so that all the |
| 413 # recursive calls to Generate() append the necessary child nodes; if | 434 # recursive calls to Generate() append the necessary child nodes; if |
| 414 # |properties| were a generator then this wouldn't work. | 435 # |properties| were a generator then this wouldn't work. |
| 415 sorted_properties = sorted(schema.get('properties', {}).items()) | 436 sorted_properties = sorted(schema.get('properties', {}).items()) |
| 416 properties = [ (self.GetString(key), self.Generate(schema, key)) | 437 properties = [ (self.GetString(key), self.Generate(subschema, key)) |
| 417 for key, schema in sorted_properties ] | 438 for key, subschema in sorted_properties ] |
| 439 |
| 440 pattern_properties = [] |
| 441 for pattern, subschema in schema.get('patternProperties', {}).items(): |
| 442 pattern_properties.append((self.GetString(pattern), |
| 443 self.Generate(subschema, pattern))); |
| 444 |
| 418 begin = len(self.property_nodes) | 445 begin = len(self.property_nodes) |
| 419 self.property_nodes += properties | 446 self.property_nodes += properties |
| 420 end = len(self.property_nodes) | 447 end = len(self.property_nodes) |
| 448 self.property_nodes += pattern_properties |
| 449 pattern_end = len(self.property_nodes) |
| 450 |
| 421 if index == 0: | 451 if index == 0: |
| 422 self.root_properties_begin = begin | 452 self.root_properties_begin = begin |
| 423 self.root_properties_end = end | 453 self.root_properties_end = end |
| 424 | 454 |
| 425 extra = len(self.properties_nodes) | 455 extra = len(self.properties_nodes) |
| 426 self.properties_nodes.append((begin, end, additionalProperties, name)) | 456 self.properties_nodes.append((begin, end, pattern_end, |
| 457 additionalProperties, name)) |
| 427 | 458 |
| 428 # Set the right data at |index| now. | 459 # Set the right data at |index| now. |
| 429 self.schema_nodes[index] = ('TYPE_DICTIONARY', extra, name) | 460 self.schema_nodes[index] = ('TYPE_DICTIONARY', extra, name) |
| 430 return index | 461 return index |
| 431 else: | 462 else: |
| 432 assert False | 463 assert False |
| 433 | 464 |
| 434 def Write(self, f): | 465 def Write(self, f): |
| 435 """Writes the generated structs to the given file. | 466 """Writes the generated structs to the given file. |
| 436 | 467 |
| 437 |f| an open file to write to.""" | 468 |f| an open file to write to.""" |
| 438 f.write('const internal::SchemaNode kSchemas[] = {\n' | 469 f.write('const internal::SchemaNode kSchemas[] = {\n' |
| 439 '// Type Extra\n') | 470 '// Type Extra\n') |
| 440 for type, extra, comment in self.schema_nodes: | 471 for type, extra, comment in self.schema_nodes: |
| 441 type += ',' | 472 type += ',' |
| 442 f.write(' { base::Value::%-18s %3d }, // %s\n' % (type, extra, comment)) | 473 f.write(' { base::Value::%-18s %3d }, // %s\n' % (type, extra, comment)) |
| 443 f.write('};\n\n') | 474 f.write('};\n\n') |
| 444 | 475 |
| 445 if self.property_nodes: | 476 if self.property_nodes: |
| 446 f.write('const internal::PropertyNode kPropertyNodes[] = {\n' | 477 f.write('const internal::PropertyNode kPropertyNodes[] = {\n' |
| 447 '// Property #Schema\n') | 478 '// Property #Schema\n') |
| 448 for key, schema in self.property_nodes: | 479 for key, schema in self.property_nodes: |
| 449 key += ',' | 480 key += ',' |
| 450 f.write(' { %-50s %6d },\n' % (key, schema)) | 481 f.write(' { %-50s %6d },\n' % (key, schema)) |
| 451 f.write('};\n\n') | 482 f.write('};\n\n') |
| 452 | 483 |
| 453 if self.properties_nodes: | 484 if self.properties_nodes: |
| 454 f.write('const internal::PropertiesNode kProperties[] = {\n' | 485 f.write('const internal::PropertiesNode kProperties[] = {\n' |
| 455 '// Begin End Additional Properties\n') | 486 '// Begin End PatternEnd Additional Properties\n') |
| 456 for node in self.properties_nodes: | 487 for node in self.properties_nodes: |
| 457 f.write(' { %5d, %5d, %5d }, // %s\n' % node) | 488 f.write(' { %5d, %5d, %10d, %5d }, // %s\n' % node) |
| 458 f.write('};\n\n') | 489 f.write('};\n\n') |
| 459 | 490 |
| 460 if self.restriction_nodes: | 491 if self.restriction_nodes: |
| 461 f.write('const internal::RestrictionNode kRestrictionNodes[] = {\n') | 492 f.write('const internal::RestrictionNode kRestrictionNodes[] = {\n') |
| 462 f.write('// FIRST, SECOND\n') | 493 f.write('// FIRST, SECOND\n') |
| 463 for first, second in self.restriction_nodes: | 494 for first, second in self.restriction_nodes: |
| 464 f.write(' {{ %-8s %4s}},\n' % (first + ',', second)) | 495 f.write(' {{ %-8s %4s}},\n' % (first + ',', second)) |
| 465 f.write('};\n\n') | 496 f.write('};\n\n') |
| 466 | 497 |
| 467 if self.int_enums: | 498 if self.int_enums: |
| (...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 839 def _WriteCloudPolicyDecoder(policies, os, f): | 870 def _WriteCloudPolicyDecoder(policies, os, f): |
| 840 f.write(CPP_HEAD) | 871 f.write(CPP_HEAD) |
| 841 for policy in policies: | 872 for policy in policies: |
| 842 if policy.is_supported and not policy.is_device_only: | 873 if policy.is_supported and not policy.is_device_only: |
| 843 _WritePolicyCode(f, policy) | 874 _WritePolicyCode(f, policy) |
| 844 f.write(CPP_FOOT) | 875 f.write(CPP_FOOT) |
| 845 | 876 |
| 846 | 877 |
| 847 if __name__ == '__main__': | 878 if __name__ == '__main__': |
| 848 sys.exit(main()) | 879 sys.exit(main()) |
| OLD | NEW |