Index: components/policy/tools/generate_policy_source.py |
diff --git a/components/policy/tools/generate_policy_source.py b/components/policy/tools/generate_policy_source.py |
index 315650de2510ed9de2adaabfd24361db4e36c3d3..b067396134ca005aa43f085bb1095eea5e9d52b9 100755 |
--- a/components/policy/tools/generate_policy_source.py |
+++ b/components/policy/tools/generate_policy_source.py |
@@ -257,7 +257,6 @@ SIMPLE_SCHEMA_NAME_MAP = { |
'string' : 'TYPE_STRING', |
} |
- |
class SchemaNodesGenerator: |
"""Builds the internal structs to represent a JSON schema.""" |
@@ -271,6 +270,9 @@ class SchemaNodesGenerator: |
self.schema_nodes = [] |
self.property_nodes = [] |
self.properties_nodes = [] |
+ self.restriction_nodes = [] |
+ self.int_enums = [] |
+ self.string_enums = [] |
self.simple_types = { |
'boolean': None, |
'integer': None, |
@@ -279,6 +281,7 @@ class SchemaNodesGenerator: |
'string': None, |
} |
self.stringlist_type = None |
+ self.ranges = {} |
def GetString(self, s): |
return self.shared_strings[s] if s in self.shared_strings else '"%s"' % s |
@@ -288,6 +291,13 @@ class SchemaNodesGenerator: |
self.schema_nodes.append((type, extra, comment)) |
return index |
+ def AppendRestriction(self, first, second): |
+ r = (str(first), str(second)) |
+ if not r in self.ranges: |
+ self.ranges[r] = len(self.restriction_nodes) |
+ self.restriction_nodes.append(r) |
+ return self.ranges[r] |
+ |
def GetSimpleType(self, name): |
if self.simple_types[name] == None: |
self.simple_types[name] = self.AppendSchema( |
@@ -304,14 +314,79 @@ class SchemaNodesGenerator: |
'simple type: stringlist') |
return self.stringlist_type |
+ def SchemaHaveRestriction(self, schema): |
+ return 'minimum' in schema or 'maximum' in schema or 'enum' in schema |
+ |
+ def IsConsecutiveInterval(self, seq): |
+ sortedSeq = sorted(seq) |
+ return all(sortedSeq[i] + 1 == sortedSeq[i + 1] |
+ for i in xrange(len(sortedSeq) - 1)) |
+ |
+ def GetEnumIntegerType(self, schema, name): |
+ assert all(type(x) == int for x in schema['enum']) |
+ possible_values = schema['enum'] |
+ if self.IsConsecutiveInterval(possible_values): |
+ index = self.AppendRestriction(max(possible_values), min(possible_values)) |
+ return self.AppendSchema('TYPE_INTEGER', index, |
+ 'integer with enumeration restriction (use range instead): %s' % name) |
+ offset_begin = len(self.int_enums) |
+ self.int_enums += possible_values |
+ offset_end = len(self.int_enums) |
+ return self.AppendSchema('TYPE_INTEGER', |
+ self.AppendRestriction(offset_begin, offset_end), |
+ 'integer with enumeration restriction: %s' % name) |
+ |
+ def GetEnumStringType(self, schema, name): |
+ assert all(type(x) == str for x in schema['enum']) |
+ offset_begin = len(self.string_enums) |
+ self.string_enums += schema['enum'] |
+ offset_end = len(self.string_enums) |
+ return self.AppendSchema('TYPE_STRING', |
+ self.AppendRestriction(offset_begin, offset_end), |
+ 'string with enumeration restriction: %s' % name) |
+ |
+ def GetEnumType(self, schema, name): |
+ if len(schema['enum']) == 0: |
+ raise RuntimeError('Empty enumeration in %s' % name) |
+ elif schema['type'] == 'integer': |
+ return self.GetEnumIntegerType(schema, name) |
+ elif schema['type'] == 'string': |
+ return self.GetEnumStringType(schema, name) |
+ else: |
+ raise RuntimeError('Unknown enumeration type in %s' % name) |
+ |
+ def GetRangedType(self, schema, name): |
+ if schema['type'] != 'integer': |
+ raise RuntimeError('Unknown ranged type in %s' % name) |
+ min_value_set, max_value_set = False, False |
+ if 'minimum' in schema: |
+ min_value = int(schema['minimum']) |
+ min_value_set = True |
+ if 'maximum' in schema: |
+ max_value = int(schema['minimum']) |
+ max_value_set = True |
+ if min_value_set and max_value_set and min_value > max_value: |
+ raise RuntimeError('Invalid ranged type in %s' % name) |
+ index = self.AppendRestriction( |
+ str(max_value) if max_value_set else 'INT_MAX', |
+ str(min_value) if min_value_set else 'INT_MIN') |
+ return self.AppendSchema('TYPE_INTEGER', |
+ index, |
+ 'integer with ranged restriction: %s' % name) |
+ |
def Generate(self, schema, name): |
"""Generates the structs for the given schema. |
|schema|: a valid JSON schema in a dictionary. |
|name|: the name of the current node, for the generated comments.""" |
- # Simple types use shared nodes. |
if schema['type'] in self.simple_types: |
- return self.GetSimpleType(schema['type']) |
+ if not self.SchemaHaveRestriction(schema): |
+ # Simple types use shared nodes. |
+ return self.GetSimpleType(schema['type']) |
+ elif 'enum' in schema: |
+ return self.GetEnumType(schema, name) |
+ else: |
+ return self.GetRangedType(schema, name) |
if schema['type'] == 'array': |
# Special case for lists of strings, which is a common policy type. |
@@ -380,17 +455,37 @@ class SchemaNodesGenerator: |
f.write(' { %5d, %5d, %5d }, // %s\n' % node) |
f.write('};\n\n') |
+ f.write('const internal::RestrictionNode kRestrictionNodes[] = {\n') |
+ f.write('// FIRST, SECOND\n') |
+ for first, second in self.restriction_nodes: |
+ f.write(' {{ %-8s %4s}},\n' % (first + ',', second)) |
+ f.write('};\n\n') |
+ |
+ f.write('const int kIntegerEnumerations[] = {\n') |
+ for possible_values in self.int_enums: |
+ f.write(' %d,\n' % possible_values) |
+ f.write('};\n\n') |
+ |
+ f.write('const char* kStringEnumerations[] = {\n') |
+ for possible_values in self.string_enums: |
+ f.write(' %s,\n' % self.GetString(possible_values)) |
+ f.write('};\n\n') |
+ |
f.write('const internal::SchemaData kChromeSchemaData = {\n' |
' kSchemas,\n' |
' kPropertyNodes,\n' |
- ' kProperties,\n' |
- '};\n\n') |
+ ' kProperties,\n'); |
+ f.write(' kRestrictionNodes,\n' if self.restriction_nodes else ' NULL,\n') |
+ f.write(' kIntegerEnumerations,\n' if self.int_enums else ' NULL,\n') |
+ f.write(' kStringEnumerations,\n' if self.string_enums else ' NULL,\n') |
+ f.write('};\n\n') |
def _WritePolicyConstantSource(policies, os, f): |
f.write('#include "policy/policy_constants.h"\n' |
'\n' |
'#include <algorithm>\n' |
+ '#include <climits>\n' |
'\n' |
'#include "base/logging.h"\n' |
'#include "components/policy/core/common/schema_internal.h"\n' |