| OLD | NEW |
| 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import copy | 5 import copy |
| 6 import os.path | 6 import os.path |
| 7 import re | 7 import re |
| 8 | 8 |
| 9 class ParseException(Exception): | 9 class ParseException(Exception): |
| 10 """Thrown when data in the model is invalid. | 10 """Thrown when data in the model is invalid. |
| (...skipping 24 matching lines...) Expand all Loading... |
| 35 """An API namespace. | 35 """An API namespace. |
| 36 | 36 |
| 37 Properties: | 37 Properties: |
| 38 - |name| the name of the namespace | 38 - |name| the name of the namespace |
| 39 - |unix_name| the unix_name of the namespace | 39 - |unix_name| the unix_name of the namespace |
| 40 - |source_file| the file that contained the namespace definition | 40 - |source_file| the file that contained the namespace definition |
| 41 - |source_file_dir| the directory component of |source_file| | 41 - |source_file_dir| the directory component of |source_file| |
| 42 - |source_file_filename| the filename component of |source_file| | 42 - |source_file_filename| the filename component of |source_file| |
| 43 - |types| a map of type names to their model.Type | 43 - |types| a map of type names to their model.Type |
| 44 - |functions| a map of function names to their model.Function | 44 - |functions| a map of function names to their model.Function |
| 45 - |events| a map of event names to their model.Function |
| 45 - |properties| a map of property names to their model.Property | 46 - |properties| a map of property names to their model.Property |
| 46 """ | 47 """ |
| 47 def __init__(self, json, source_file): | 48 def __init__(self, json, source_file): |
| 48 self.name = json['namespace'] | 49 self.name = json['namespace'] |
| 49 self.unix_name = UnixName(self.name) | 50 self.unix_name = UnixName(self.name) |
| 50 self.source_file = source_file | 51 self.source_file = source_file |
| 51 self.source_file_dir, self.source_file_filename = os.path.split(source_file) | 52 self.source_file_dir, self.source_file_filename = os.path.split(source_file) |
| 52 self.parent = None | 53 self.parent = None |
| 53 _AddTypes(self, json) | 54 _AddTypes(self, json) |
| 54 _AddFunctions(self, json) | 55 _AddFunctions(self, json) |
| 56 _AddEvents(self, json) |
| 55 _AddProperties(self, json) | 57 _AddProperties(self, json) |
| 56 | 58 |
| 57 class Type(object): | 59 class Type(object): |
| 58 """A Type defined in the json. | 60 """A Type defined in the json. |
| 59 | 61 |
| 60 Properties: | 62 Properties: |
| 61 - |name| the type name | 63 - |name| the type name |
| 62 - |description| the description of the type (if provided) | 64 - |description| the description of the type (if provided) |
| 63 - |properties| a map of property unix_names to their model.Property | 65 - |properties| a map of property unix_names to their model.Property |
| 64 - |functions| a map of function names to their model.Function | 66 - |functions| a map of function names to their model.Function |
| (...skipping 30 matching lines...) Expand all Loading... |
| 95 | 97 |
| 96 additional_properties_key = 'additionalProperties' | 98 additional_properties_key = 'additionalProperties' |
| 97 additional_properties = json.get(additional_properties_key) | 99 additional_properties = json.get(additional_properties_key) |
| 98 if additional_properties: | 100 if additional_properties: |
| 99 self.properties[additional_properties_key] = Property( | 101 self.properties[additional_properties_key] = Property( |
| 100 self, | 102 self, |
| 101 additional_properties_key, | 103 additional_properties_key, |
| 102 additional_properties, | 104 additional_properties, |
| 103 is_additional_properties=True) | 105 is_additional_properties=True) |
| 104 | 106 |
| 105 class Callback(object): | |
| 106 """A callback parameter to a Function. | |
| 107 | |
| 108 Properties: | |
| 109 - |params| the parameters to this callback. | |
| 110 """ | |
| 111 def __init__(self, parent, json): | |
| 112 params = json['parameters'] | |
| 113 self.parent = parent | |
| 114 self.description = json.get('description') | |
| 115 self.optional = json.get('optional', False) | |
| 116 self.params = [] | |
| 117 if len(params) == 0: | |
| 118 return | |
| 119 elif len(params) == 1: | |
| 120 param = params[0] | |
| 121 self.params.append(Property(self, param['name'], param, | |
| 122 from_client=True)) | |
| 123 else: | |
| 124 raise ParseException( | |
| 125 self, | |
| 126 "Callbacks can have at most a single parameter") | |
| 127 | |
| 128 class Function(object): | 107 class Function(object): |
| 129 """A Function defined in the API. | 108 """A Function defined in the API. |
| 130 | 109 |
| 131 Properties: | 110 Properties: |
| 132 - |name| the function name | 111 - |name| the function name |
| 133 - |params| a list of parameters to the function (order matters). A separate | 112 - |params| a list of parameters to the function (order matters). A separate |
| 134 parameter is used for each choice of a 'choices' parameter. | 113 parameter is used for each choice of a 'choices' parameter. |
| 135 - |description| a description of the function (if provided) | 114 - |description| a description of the function (if provided) |
| 136 - |callback| the callback parameter to the function. There should be exactly | 115 - |callback| the callback parameter to the function. There should be exactly |
| 137 one | 116 one |
| 138 """ | 117 """ |
| 139 def __init__(self, parent, json): | 118 def __init__(self, parent, json, from_json=False, from_client=False): |
| 140 self.name = json['name'] | 119 self.name = json['name'] |
| 141 self.params = [] | 120 self.params = [] |
| 142 self.description = json.get('description') | 121 self.description = json.get('description') |
| 143 self.callback = None | 122 self.callback = None |
| 144 self.parent = parent | 123 self.parent = parent |
| 145 self.nocompile = json.get('nocompile') | 124 self.nocompile = json.get('nocompile') |
| 146 for param in json['parameters']: | 125 for param in json.get('parameters', []): |
| 147 if param.get('type') == 'function': | 126 if param.get('type') == 'function': |
| 148 if self.callback: | 127 if self.callback: |
| 149 raise ParseException(self, self.name + " has more than one callback") | 128 raise ParseException(self, self.name + " has more than one callback") |
| 150 self.callback = Callback(self, param) | 129 self.callback = Function(self, param, from_client=True) |
| 151 else: | 130 else: |
| 152 self.params.append(Property(self, param['name'], param, | 131 self.params.append(Property(self, param['name'], param, |
| 153 from_json=True)) | 132 from_json=from_json, from_client=from_client)) |
| 154 | 133 |
| 155 class Property(object): | 134 class Property(object): |
| 156 """A property of a type OR a parameter to a function. | 135 """A property of a type OR a parameter to a function. |
| 157 | 136 |
| 158 Properties: | 137 Properties: |
| 159 - |name| name of the property as in the json. This shouldn't change since | 138 - |name| name of the property as in the json. This shouldn't change since |
| 160 it is the key used to access DictionaryValues | 139 it is the key used to access DictionaryValues |
| 161 - |unix_name| the unix_style_name of the property. Used as variable name | 140 - |unix_name| the unix_style_name of the property. Used as variable name |
| 162 - |optional| a boolean representing whether the property is optional | 141 - |optional| a boolean representing whether the property is optional |
| 163 - |description| a description of the property (if provided) | 142 - |description| a description of the property (if provided) |
| 164 - |type_| the model.PropertyType of this property | 143 - |type_| the model.PropertyType of this property |
| 165 - |ref_type| the type that the REF property is referencing. Can be used to | 144 - |ref_type| the type that the REF property is referencing. Can be used to |
| 166 map to its model.Type | 145 map to its model.Type |
| 167 - |item_type| a model.Property representing the type of each element in an | 146 - |item_type| a model.Property representing the type of each element in an |
| 168 ARRAY | 147 ARRAY |
| 169 - |properties| the properties of an OBJECT parameter | 148 - |properties| the properties of an OBJECT parameter |
| 149 - |from_client| indicates that instances of the Type can originate from the |
| 150 users of generated code, such as top-level types and function results |
| 151 - |from_json| indicates that instances of the Type can originate from the |
| 152 JSON (as described by the schema), such as top-level types and function |
| 153 parameters |
| 170 """ | 154 """ |
| 171 | 155 |
| 172 def __init__(self, parent, name, json, is_additional_properties=False, | 156 def __init__(self, parent, name, json, is_additional_properties=False, |
| 173 from_json=False, from_client=False): | 157 from_json=False, from_client=False): |
| 174 """ | |
| 175 Parameters: | |
| 176 - |from_json| indicates that instances of the Type can originate from the | |
| 177 JSON (as described by the schema), such as top-level types and function | |
| 178 parameters | |
| 179 - |from_client| indicates that instances of the Type can originate from the | |
| 180 users of generated code, such as top-level types and function results | |
| 181 """ | |
| 182 self.name = name | 158 self.name = name |
| 183 self._unix_name = UnixName(self.name) | 159 self._unix_name = UnixName(self.name) |
| 184 self._unix_name_used = False | 160 self._unix_name_used = False |
| 185 self.optional = json.get('optional', False) | 161 self.optional = json.get('optional', False) |
| 186 self.functions = [] | 162 self.functions = [] |
| 187 self.has_value = False | 163 self.has_value = False |
| 188 self.description = json.get('description') | 164 self.description = json.get('description') |
| 189 self.parent = parent | 165 self.parent = parent |
| 166 self.from_json = from_json |
| 167 self.from_client = from_client |
| 190 _AddProperties(self, json) | 168 _AddProperties(self, json) |
| 191 if is_additional_properties: | 169 if is_additional_properties: |
| 192 self.type_ = PropertyType.ADDITIONAL_PROPERTIES | 170 self.type_ = PropertyType.ADDITIONAL_PROPERTIES |
| 193 elif '$ref' in json: | 171 elif '$ref' in json: |
| 194 self.ref_type = json['$ref'] | 172 self.ref_type = json['$ref'] |
| 195 self.type_ = PropertyType.REF | 173 self.type_ = PropertyType.REF |
| 196 elif 'enum' in json: | 174 elif 'enum' in json: |
| 197 self.enum_values = [] | 175 self.enum_values = [] |
| 198 for value in json['enum']: | 176 for value in json['enum']: |
| 199 self.enum_values.append(value) | 177 self.enum_values.append(value) |
| (...skipping 11 matching lines...) Expand all Loading... |
| 211 elif json_type == 'number': | 189 elif json_type == 'number': |
| 212 self.type_ = PropertyType.DOUBLE | 190 self.type_ = PropertyType.DOUBLE |
| 213 elif json_type == 'array': | 191 elif json_type == 'array': |
| 214 self.item_type = Property(self, name + "Element", json['items'], | 192 self.item_type = Property(self, name + "Element", json['items'], |
| 215 from_json=from_json, | 193 from_json=from_json, |
| 216 from_client=from_client) | 194 from_client=from_client) |
| 217 self.type_ = PropertyType.ARRAY | 195 self.type_ = PropertyType.ARRAY |
| 218 elif json_type == 'object': | 196 elif json_type == 'object': |
| 219 self.type_ = PropertyType.OBJECT | 197 self.type_ = PropertyType.OBJECT |
| 220 # These members are read when this OBJECT Property is used as a Type | 198 # These members are read when this OBJECT Property is used as a Type |
| 221 self.from_json = from_json | |
| 222 self.from_client = from_client | |
| 223 type_ = Type(self, self.name, json) | 199 type_ = Type(self, self.name, json) |
| 224 # self.properties will already have some value from |_AddProperties|. | 200 # self.properties will already have some value from |_AddProperties|. |
| 225 self.properties.update(type_.properties) | 201 self.properties.update(type_.properties) |
| 226 self.functions = type_.functions | 202 self.functions = type_.functions |
| 227 elif json_type == 'binary': | 203 elif json_type == 'binary': |
| 228 self.type_ = PropertyType.BINARY | 204 self.type_ = PropertyType.BINARY |
| 229 else: | 205 else: |
| 230 raise ParseException(self, 'type ' + json_type + ' not recognized') | 206 raise ParseException(self, 'type ' + json_type + ' not recognized') |
| 231 elif 'choices' in json: | 207 elif 'choices' in json: |
| 232 if not json['choices']: | 208 if not json['choices'] or len(json['choices']) == 0: |
| 233 raise ParseException(self, 'Choices has no choices') | 209 raise ParseException(self, 'Choices has no choices') |
| 234 self.choices = {} | 210 self.choices = {} |
| 235 self.type_ = PropertyType.CHOICES | 211 self.type_ = PropertyType.CHOICES |
| 236 for choice_json in json['choices']: | 212 for choice_json in json['choices']: |
| 237 choice = Property(self, self.name, choice_json, | 213 choice = Property(self, self.name, choice_json, |
| 238 from_json=from_json, | 214 from_json=from_json, |
| 239 from_client=from_client) | 215 from_client=from_client) |
| 240 # A choice gets its unix_name set in | 216 choice.unix_name = UnixName(self.name + choice.type_.name) |
| 241 # cpp_type_generator.GetExpandedChoicesInParams | |
| 242 choice._unix_name = None | |
| 243 # The existence of any single choice is optional | 217 # The existence of any single choice is optional |
| 244 choice.optional = True | 218 choice.optional = True |
| 245 self.choices[choice.type_] = choice | 219 self.choices[choice.type_] = choice |
| 246 elif 'value' in json: | 220 elif 'value' in json: |
| 247 self.has_value = True | 221 self.has_value = True |
| 248 self.value = json['value'] | 222 self.value = json['value'] |
| 249 if type(self.value) == int: | 223 if type(self.value) == int: |
| 250 self.type_ = PropertyType.INTEGER | 224 self.type_ = PropertyType.INTEGER |
| 251 else: | 225 else: |
| 252 # TODO(kalman): support more types as necessary. | 226 # TODO(kalman): support more types as necessary. |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 335 | 309 |
| 336 def _AddTypes(model, json): | 310 def _AddTypes(model, json): |
| 337 """Adds Type objects to |model| contained in the 'types' field of |json|. | 311 """Adds Type objects to |model| contained in the 'types' field of |json|. |
| 338 """ | 312 """ |
| 339 model.types = {} | 313 model.types = {} |
| 340 for type_json in json.get('types', []): | 314 for type_json in json.get('types', []): |
| 341 type_ = Type(model, type_json['id'], type_json) | 315 type_ = Type(model, type_json['id'], type_json) |
| 342 model.types[type_.name] = type_ | 316 model.types[type_.name] = type_ |
| 343 | 317 |
| 344 def _AddFunctions(model, json): | 318 def _AddFunctions(model, json): |
| 345 """Adds Function objects to |model| contained in the 'types' field of |json|. | 319 """Adds Function objects to |model| contained in the 'functions' field of |
| 320 |json|. |
| 346 """ | 321 """ |
| 347 model.functions = {} | 322 model.functions = {} |
| 348 for function_json in json.get('functions', []): | 323 for function_json in json.get('functions', []): |
| 349 function = Function(model, function_json) | 324 function = Function(model, function_json, from_json=True) |
| 350 model.functions[function.name] = function | 325 model.functions[function.name] = function |
| 351 | 326 |
| 327 def _AddEvents(model, json): |
| 328 """Adds Function objects to |model| contained in the 'events' field of |json|. |
| 329 """ |
| 330 model.events = {} |
| 331 for event_json in json.get('events', []): |
| 332 event = Function(model, event_json, from_client=True) |
| 333 model.events[event.name] = event |
| 334 |
| 352 def _AddProperties(model, json, from_json=False, from_client=False): | 335 def _AddProperties(model, json, from_json=False, from_client=False): |
| 353 """Adds model.Property objects to |model| contained in the 'properties' field | 336 """Adds model.Property objects to |model| contained in the 'properties' field |
| 354 of |json|. | 337 of |json|. |
| 355 """ | 338 """ |
| 356 model.properties = {} | 339 model.properties = {} |
| 357 for name, property_json in json.get('properties', {}).items(): | 340 for name, property_json in json.get('properties', {}).items(): |
| 358 # TODO(calamity): support functions (callbacks) as properties. The model | 341 # TODO(calamity): support functions (callbacks) as properties. The model |
| 359 # doesn't support it yet because the h/cc generators don't -- this is | 342 # doesn't support it yet because the h/cc generators don't -- this is |
| 360 # because we'd need to hook it into a base::Callback or something. | 343 # because we'd need to hook it into a base::Callback or something. |
| 361 # | 344 # |
| 362 # However, pragmatically it's not necessary to support them anyway, since | 345 # However, pragmatically it's not necessary to support them anyway, since |
| 363 # the instances of functions-on-properties in the extension APIs are all | 346 # the instances of functions-on-properties in the extension APIs are all |
| 364 # handled in pure Javascript on the render process (and .: never reach | 347 # handled in pure Javascript on the render process (and .: never reach |
| 365 # C++ let alone the browser). | 348 # C++ let alone the browser). |
| 366 if property_json.get('type') == 'function': | 349 if property_json.get('type') == 'function': |
| 367 continue | 350 continue |
| 368 model.properties[name] = Property( | 351 model.properties[name] = Property( |
| 369 model, | 352 model, |
| 370 name, | 353 name, |
| 371 property_json, | 354 property_json, |
| 372 from_json=from_json, | 355 from_json=from_json, |
| 373 from_client=from_client) | 356 from_client=from_client) |
| OLD | NEW |