Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(200)

Side by Side Diff: tools/json_schema_compiler/model.py

Issue 23594008: Initial code generation for features. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Merged from Master. Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 os.path 5 import os.path
6 6
7 from json_parse import OrderedDict 7 from json_parse import OrderedDict
8 from memoize import memoize 8 from memoize import memoize
9 9
10
10 class ParseException(Exception): 11 class ParseException(Exception):
11 """Thrown when data in the model is invalid. 12 """Thrown when data in the model is invalid.
12 """ 13 """
13 def __init__(self, parent, message): 14 def __init__(self, parent, message):
14 hierarchy = _GetModelHierarchy(parent) 15 hierarchy = _GetModelHierarchy(parent)
15 hierarchy.append(message) 16 hierarchy.append(message)
16 Exception.__init__( 17 Exception.__init__(
17 self, 'Model parse exception at:\n' + '\n'.join(hierarchy)) 18 self, 'Model parse exception at:\n' + '\n'.join(hierarchy))
18 19
20
19 class Model(object): 21 class Model(object):
20 """Model of all namespaces that comprise an API. 22 """Model of all namespaces that comprise an API.
21 23
22 Properties: 24 Properties:
23 - |namespaces| a map of a namespace name to its model.Namespace 25 - |namespaces| a map of a namespace name to its model.Namespace
24 """ 26 """
25 def __init__(self): 27 def __init__(self):
26 self.namespaces = {} 28 self.namespaces = {}
27 29
28 def AddNamespace(self, json, source_file, include_compiler_options=False): 30 def AddNamespace(self, json, source_file, include_compiler_options=False):
29 """Add a namespace's json to the model and returns the namespace. 31 """Add a namespace's json to the model and returns the namespace.
30 """ 32 """
31 namespace = Namespace(json, 33 namespace = Namespace(json,
32 source_file, 34 source_file,
33 include_compiler_options=include_compiler_options) 35 include_compiler_options=include_compiler_options)
34 self.namespaces[namespace.name] = namespace 36 self.namespaces[namespace.name] = namespace
35 return namespace 37 return namespace
36 38
39
40 def CreateFeature(name, model):
41 if isinstance(model, dict):
42 return SimpleFeature(name, model)
43 return ComplexFeature(name, [SimpleFeature(name, child) for child in model])
44
45
46 class ComplexFeature(object):
47 """A complex feature which may be made of several simple features.
48
49 Properties:
50 - |name| the name of the feature
51 - |unix_name| the unix_name of the feature
52 - |feature_list| a list of simple features which make up the feature
53 """
54 def __init__(self, feature_name, features):
55 self.name = feature_name
56 self.unix_name = UnixName(self.name)
57 self.feature_list = features
58
59 class SimpleFeature(object):
60 """A simple feature, which can make up a complex feature, as specified in
61 files such as chrome/common/extensions/api/_permission_features.json.
62
63 Properties:
64 - |name| the name of the feature
65 - |unix_name| the unix_name of the feature
66 - |channel| the channel where the feature is released
67 - |extension_types| the types which can use the feature
68 - |whitelist| a list of extensions allowed to use the feature
69 """
70 def __init__(self, feature_name, feature_def):
71 self.name = feature_name
72 self.unix_name = UnixName(self.name)
73 self.channel = feature_def['channel']
74 self.extension_types = feature_def['extension_types']
75 self.whitelist = feature_def.get('whitelist')
76
77
37 class Namespace(object): 78 class Namespace(object):
38 """An API namespace. 79 """An API namespace.
39 80
40 Properties: 81 Properties:
41 - |name| the name of the namespace 82 - |name| the name of the namespace
42 - |description| the description of the namespace 83 - |description| the description of the namespace
43 - |unix_name| the unix_name of the namespace 84 - |unix_name| the unix_name of the namespace
44 - |source_file| the file that contained the namespace definition 85 - |source_file| the file that contained the namespace definition
45 - |source_file_dir| the directory component of |source_file| 86 - |source_file_dir| the directory component of |source_file|
46 - |source_file_filename| the filename component of |source_file| 87 - |source_file_filename| the filename component of |source_file|
(...skipping 21 matching lines...) Expand all
68 self.platforms = _GetPlatforms(json) 109 self.platforms = _GetPlatforms(json)
69 toplevel_origin = Origin(from_client=True, from_json=True) 110 toplevel_origin = Origin(from_client=True, from_json=True)
70 self.types = _GetTypes(self, json, self, toplevel_origin) 111 self.types = _GetTypes(self, json, self, toplevel_origin)
71 self.functions = _GetFunctions(self, json, self) 112 self.functions = _GetFunctions(self, json, self)
72 self.events = _GetEvents(self, json, self) 113 self.events = _GetEvents(self, json, self)
73 self.properties = _GetProperties(self, json, self, toplevel_origin) 114 self.properties = _GetProperties(self, json, self, toplevel_origin)
74 self.compiler_options = (json.get('compiler_options', {}) 115 self.compiler_options = (json.get('compiler_options', {})
75 if include_compiler_options else {}) 116 if include_compiler_options else {})
76 self.documentation_options = json.get('documentation_options', {}) 117 self.documentation_options = json.get('documentation_options', {})
77 118
119
78 class Origin(object): 120 class Origin(object):
79 """Stores the possible origin of model object as a pair of bools. These are: 121 """Stores the possible origin of model object as a pair of bools. These are:
80 122
81 |from_client| indicating that instances can originate from users of 123 |from_client| indicating that instances can originate from users of
82 generated code (for example, function results), or 124 generated code (for example, function results), or
83 |from_json| indicating that instances can originate from the JSON (for 125 |from_json| indicating that instances can originate from the JSON (for
84 example, function parameters) 126 example, function parameters)
85 127
86 It is possible for model objects to originate from both the client and json, 128 It is possible for model objects to originate from both the client and json,
87 for example Types defined in the top-level schema, in which case both 129 for example Types defined in the top-level schema, in which case both
88 |from_client| and |from_json| would be True. 130 |from_client| and |from_json| would be True.
89 """ 131 """
90 def __init__(self, from_client=False, from_json=False): 132 def __init__(self, from_client=False, from_json=False):
91 if not from_client and not from_json: 133 if not from_client and not from_json:
92 raise ValueError('One of from_client or from_json must be true') 134 raise ValueError('One of from_client or from_json must be true')
93 self.from_client = from_client 135 self.from_client = from_client
94 self.from_json = from_json 136 self.from_json = from_json
95 137
138
96 class Type(object): 139 class Type(object):
97 """A Type defined in the json. 140 """A Type defined in the json.
98 141
99 Properties: 142 Properties:
100 - |name| the type name 143 - |name| the type name
101 - |namespace| the Type's namespace 144 - |namespace| the Type's namespace
102 - |description| the description of the type (if provided) 145 - |description| the description of the type (if provided)
103 - |properties| a map of property unix_names to their model.Property 146 - |properties| a map of property unix_names to their model.Property
104 - |functions| a map of function names to their model.Function 147 - |functions| a map of function names to their model.Function
105 - |events| a map of event names to their model.Event 148 - |events| a map of event names to their model.Event
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 self.additional_properties = None 235 self.additional_properties = None
193 elif json_type == 'function': 236 elif json_type == 'function':
194 self.property_type = PropertyType.FUNCTION 237 self.property_type = PropertyType.FUNCTION
195 # Sometimes we might have an unnamed function, e.g. if it's a property 238 # Sometimes we might have an unnamed function, e.g. if it's a property
196 # of an object. Use the name of the property in that case. 239 # of an object. Use the name of the property in that case.
197 function_name = json.get('name', name) 240 function_name = json.get('name', name)
198 self.function = Function(self, function_name, json, namespace, origin) 241 self.function = Function(self, function_name, json, namespace, origin)
199 else: 242 else:
200 raise ParseException(self, 'Unsupported JSON type %s' % json_type) 243 raise ParseException(self, 'Unsupported JSON type %s' % json_type)
201 244
245
202 class Function(object): 246 class Function(object):
203 """A Function defined in the API. 247 """A Function defined in the API.
204 248
205 Properties: 249 Properties:
206 - |name| the function name 250 - |name| the function name
207 - |platforms| if not None, the list of platforms that the function is 251 - |platforms| if not None, the list of platforms that the function is
208 available to 252 available to
209 - |params| a list of parameters to the function (order matters). A separate 253 - |params| a list of parameters to the function (order matters). A separate
210 parameter is used for each choice of a 'choices' parameter 254 parameter is used for each choice of a 'choices' parameter
211 - |deprecated| a reason and possible alternative for a deprecated function 255 - |deprecated| a reason and possible alternative for a deprecated function
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
265 Origin(from_client=True)) 309 Origin(from_client=True))
266 310
267 self.returns = None 311 self.returns = None
268 if 'returns' in json: 312 if 'returns' in json:
269 self.returns = Type(self, 313 self.returns = Type(self,
270 '%sReturnType' % name, 314 '%sReturnType' % name,
271 json['returns'], 315 json['returns'],
272 namespace, 316 namespace,
273 origin) 317 origin)
274 318
319
275 class Property(object): 320 class Property(object):
276 """A property of a type OR a parameter to a function. 321 """A property of a type OR a parameter to a function.
277 Properties: 322 Properties:
278 - |name| name of the property as in the json. This shouldn't change since 323 - |name| name of the property as in the json. This shouldn't change since
279 it is the key used to access DictionaryValues 324 it is the key used to access DictionaryValues
280 - |unix_name| the unix_style_name of the property. Used as variable name 325 - |unix_name| the unix_style_name of the property. Used as variable name
281 - |optional| a boolean representing whether the property is optional 326 - |optional| a boolean representing whether the property is optional
282 - |description| a description of the property (if provided) 327 - |description| a description of the property (if provided)
283 - |type_| the model.Type of this property 328 - |type_| the model.Type of this property
284 - |simple_name| the name of this Property without a namespace 329 - |simple_name| the name of this Property without a namespace
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
377 return type(other) == type(self) and other.name == self.name 422 return type(other) == type(self) and other.name == self.name
378 def __ne__(self, other): 423 def __ne__(self, other):
379 return not (self == other) 424 return not (self == other)
380 425
381 def __repr__(self): 426 def __repr__(self):
382 return self.name 427 return self.name
383 428
384 def __str__(self): 429 def __str__(self):
385 return repr(self) 430 return repr(self)
386 431
432
387 class _PropertyTypeInfo(_Enum): 433 class _PropertyTypeInfo(_Enum):
388 def __init__(self, is_fundamental, name): 434 def __init__(self, is_fundamental, name):
389 _Enum.__init__(self, name) 435 _Enum.__init__(self, name)
390 self.is_fundamental = is_fundamental 436 self.is_fundamental = is_fundamental
391 437
438
392 class PropertyType(object): 439 class PropertyType(object):
393 """Enum of different types of properties/parameters. 440 """Enum of different types of properties/parameters.
394 """ 441 """
395 ANY = _PropertyTypeInfo(False, "any") 442 ANY = _PropertyTypeInfo(False, "any")
396 ARRAY = _PropertyTypeInfo(False, "array") 443 ARRAY = _PropertyTypeInfo(False, "array")
397 BINARY = _PropertyTypeInfo(False, "binary") 444 BINARY = _PropertyTypeInfo(False, "binary")
398 BOOLEAN = _PropertyTypeInfo(True, "boolean") 445 BOOLEAN = _PropertyTypeInfo(True, "boolean")
399 CHOICES = _PropertyTypeInfo(False, "choices") 446 CHOICES = _PropertyTypeInfo(False, "choices")
400 DOUBLE = _PropertyTypeInfo(True, "double") 447 DOUBLE = _PropertyTypeInfo(True, "double")
401 ENUM = _PropertyTypeInfo(False, "enum") 448 ENUM = _PropertyTypeInfo(False, "enum")
402 FUNCTION = _PropertyTypeInfo(False, "function") 449 FUNCTION = _PropertyTypeInfo(False, "function")
403 INT64 = _PropertyTypeInfo(True, "int64") 450 INT64 = _PropertyTypeInfo(True, "int64")
404 INTEGER = _PropertyTypeInfo(True, "integer") 451 INTEGER = _PropertyTypeInfo(True, "integer")
405 OBJECT = _PropertyTypeInfo(False, "object") 452 OBJECT = _PropertyTypeInfo(False, "object")
406 REF = _PropertyTypeInfo(False, "ref") 453 REF = _PropertyTypeInfo(False, "ref")
407 STRING = _PropertyTypeInfo(True, "string") 454 STRING = _PropertyTypeInfo(True, "string")
408 455
456
409 @memoize 457 @memoize
410 def UnixName(name): 458 def UnixName(name):
411 '''Returns the unix_style name for a given lowerCamelCase string. 459 '''Returns the unix_style name for a given lowerCamelCase string.
412 ''' 460 '''
413 unix_name = [] 461 unix_name = []
414 for i, c in enumerate(name): 462 for i, c in enumerate(name):
415 if c.isupper() and i > 0 and name[i - 1] != '_': 463 if c.isupper() and i > 0 and name[i - 1] != '_':
416 # Replace lowerUpper with lower_Upper. 464 # Replace lowerUpper with lower_Upper.
417 if name[i - 1].islower(): 465 if name[i - 1].islower():
418 unix_name.append('_') 466 unix_name.append('_')
419 # Replace ACMEWidgets with ACME_Widgets 467 # Replace ACMEWidgets with ACME_Widgets
420 elif i + 1 < len(name) and name[i + 1].islower(): 468 elif i + 1 < len(name) and name[i + 1].islower():
421 unix_name.append('_') 469 unix_name.append('_')
422 if c == '.': 470 if c == '.':
423 # Replace hello.world with hello_world. 471 # Replace hello.world with hello_world.
424 unix_name.append('_') 472 unix_name.append('_')
425 else: 473 else:
426 # Everything is lowercase. 474 # Everything is lowercase.
427 unix_name.append(c.lower()) 475 unix_name.append(c.lower())
428 return ''.join(unix_name) 476 return ''.join(unix_name)
429 477
478
430 def _StripNamespace(name, namespace): 479 def _StripNamespace(name, namespace):
431 if name.startswith(namespace.name + '.'): 480 if name.startswith(namespace.name + '.'):
432 return name[len(namespace.name + '.'):] 481 return name[len(namespace.name + '.'):]
433 return name 482 return name
434 483
484
435 def _GetModelHierarchy(entity): 485 def _GetModelHierarchy(entity):
436 """Returns the hierarchy of the given model entity.""" 486 """Returns the hierarchy of the given model entity."""
437 hierarchy = [] 487 hierarchy = []
438 while entity is not None: 488 while entity is not None:
439 hierarchy.append(getattr(entity, 'name', repr(entity))) 489 hierarchy.append(getattr(entity, 'name', repr(entity)))
440 if isinstance(entity, Namespace): 490 if isinstance(entity, Namespace):
441 hierarchy.insert(0, ' in %s' % entity.source_file) 491 hierarchy.insert(0, ' in %s' % entity.source_file)
442 entity = getattr(entity, 'parent', None) 492 entity = getattr(entity, 'parent', None)
443 hierarchy.reverse() 493 hierarchy.reverse()
444 return hierarchy 494 return hierarchy
445 495
496
446 def _GetTypes(parent, json, namespace, origin): 497 def _GetTypes(parent, json, namespace, origin):
447 """Creates Type objects extracted from |json|. 498 """Creates Type objects extracted from |json|.
448 """ 499 """
449 types = OrderedDict() 500 types = OrderedDict()
450 for type_json in json.get('types', []): 501 for type_json in json.get('types', []):
451 type_ = Type(parent, type_json['id'], type_json, namespace, origin) 502 type_ = Type(parent, type_json['id'], type_json, namespace, origin)
452 types[type_.name] = type_ 503 types[type_.name] = type_
453 return types 504 return types
454 505
506
455 def _GetFunctions(parent, json, namespace): 507 def _GetFunctions(parent, json, namespace):
456 """Creates Function objects extracted from |json|. 508 """Creates Function objects extracted from |json|.
457 """ 509 """
458 functions = OrderedDict() 510 functions = OrderedDict()
459 for function_json in json.get('functions', []): 511 for function_json in json.get('functions', []):
460 function = Function(parent, 512 function = Function(parent,
461 function_json['name'], 513 function_json['name'],
462 function_json, 514 function_json,
463 namespace, 515 namespace,
464 Origin(from_json=True)) 516 Origin(from_json=True))
465 functions[function.name] = function 517 functions[function.name] = function
466 return functions 518 return functions
467 519
520
468 def _GetEvents(parent, json, namespace): 521 def _GetEvents(parent, json, namespace):
469 """Creates Function objects generated from the events in |json|. 522 """Creates Function objects generated from the events in |json|.
470 """ 523 """
471 events = OrderedDict() 524 events = OrderedDict()
472 for event_json in json.get('events', []): 525 for event_json in json.get('events', []):
473 event = Function(parent, 526 event = Function(parent,
474 event_json['name'], 527 event_json['name'],
475 event_json, 528 event_json,
476 namespace, 529 namespace,
477 Origin(from_client=True)) 530 Origin(from_client=True))
478 events[event.name] = event 531 events[event.name] = event
479 return events 532 return events
480 533
534
481 def _GetProperties(parent, json, namespace, origin): 535 def _GetProperties(parent, json, namespace, origin):
482 """Generates Property objects extracted from |json|. 536 """Generates Property objects extracted from |json|.
483 """ 537 """
484 properties = OrderedDict() 538 properties = OrderedDict()
485 for name, property_json in json.get('properties', {}).items(): 539 for name, property_json in json.get('properties', {}).items():
486 properties[name] = Property(parent, name, property_json, namespace, origin) 540 properties[name] = Property(parent, name, property_json, namespace, origin)
487 return properties 541 return properties
488 542
543
489 class _PlatformInfo(_Enum): 544 class _PlatformInfo(_Enum):
490 def __init__(self, name): 545 def __init__(self, name):
491 _Enum.__init__(self, name) 546 _Enum.__init__(self, name)
492 547
548
493 class Platforms(object): 549 class Platforms(object):
494 """Enum of the possible platforms. 550 """Enum of the possible platforms.
495 """ 551 """
496 CHROMEOS = _PlatformInfo("chromeos") 552 CHROMEOS = _PlatformInfo("chromeos")
497 CHROMEOS_TOUCH = _PlatformInfo("chromeos_touch") 553 CHROMEOS_TOUCH = _PlatformInfo("chromeos_touch")
498 LINUX = _PlatformInfo("linux") 554 LINUX = _PlatformInfo("linux")
499 MAC = _PlatformInfo("mac") 555 MAC = _PlatformInfo("mac")
500 WIN = _PlatformInfo("win") 556 WIN = _PlatformInfo("win")
501 557
558
502 def _GetPlatforms(json): 559 def _GetPlatforms(json):
503 if 'platforms' not in json or json['platforms'] == None: 560 if 'platforms' not in json or json['platforms'] == None:
504 return None 561 return None
505 # Sanity check: platforms should not be an empty list. 562 # Sanity check: platforms should not be an empty list.
506 if not json['platforms']: 563 if not json['platforms']:
507 raise ValueError('"platforms" cannot be an empty list') 564 raise ValueError('"platforms" cannot be an empty list')
508 platforms = [] 565 platforms = []
509 for platform_name in json['platforms']: 566 for platform_name in json['platforms']:
510 for platform_enum in _Enum.GetAll(Platforms): 567 for platform_enum in _Enum.GetAll(Platforms):
511 if platform_name == platform_enum.name: 568 if platform_name == platform_enum.name:
512 platforms.append(platform_enum) 569 platforms.append(platform_enum)
513 break 570 break
514 return platforms 571 return platforms
OLDNEW
« no previous file with comments | « tools/json_schema_compiler/features_h_generator.py ('k') | tools/json_schema_compiler/schema_loader.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698