blob: c8a3c9a30e9779e4128af38aa6f2d3c61eca5b25 [file] [log] [blame]
[email protected]15f08dd2012-01-27 07:29:481# 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
3# found in the LICENSE file.
4
5import os.path
[email protected]cfe484902012-02-15 14:52:326import re
[email protected]712eca0f2012-02-21 01:13:077import copy
[email protected]15f08dd2012-01-27 07:29:488
9class Model(object):
10 """Model of all namespaces that comprise an API.
[email protected]cfe484902012-02-15 14:52:3211
12 Properties:
13 - |namespaces| a map of a namespace name to its model.Namespace
[email protected]15f08dd2012-01-27 07:29:4814 """
15 def __init__(self):
16 self.namespaces = {}
17
18 def AddNamespace(self, json, source_file):
[email protected]cfe484902012-02-15 14:52:3219 """Add a namespace's json to the model if it doesn't have "nocompile"
20 property set to true. Returns the new namespace or None if a namespace
21 wasn't added.
[email protected]15f08dd2012-01-27 07:29:4822 """
[email protected]cfe484902012-02-15 14:52:3223 if json.get('nocompile', False):
[email protected]15f08dd2012-01-27 07:29:4824 return None
25 namespace = Namespace(json, source_file)
26 self.namespaces[namespace.name] = namespace
27 return namespace
28
29class Namespace(object):
30 """An API namespace.
[email protected]cfe484902012-02-15 14:52:3231
32 Properties:
33 - |name| the name of the namespace
[email protected]712eca0f2012-02-21 01:13:0734 - |unix_name| the unix_name of the namespace
35 - |source_file| the file that contained the namespace definition
36 - |source_file_dir| the directory component of |source_file|
37 - |source_file_filename| the filename component of |source_file|
[email protected]cfe484902012-02-15 14:52:3238 - |types| a map of type names to their model.Type
39 - |functions| a map of function names to their model.Function
[email protected]15f08dd2012-01-27 07:29:4840 """
41 def __init__(self, json, source_file):
42 self.name = json['namespace']
[email protected]712eca0f2012-02-21 01:13:0743 self.unix_name = _UnixName(self.name)
[email protected]15f08dd2012-01-27 07:29:4844 self.source_file = source_file
45 self.source_file_dir, self.source_file_filename = os.path.split(source_file)
[email protected]15f08dd2012-01-27 07:29:4846 self.types = {}
47 self.functions = {}
[email protected]712eca0f2012-02-21 01:13:0748 for type_json in json.get('types', []):
[email protected]15f08dd2012-01-27 07:29:4849 type_ = Type(type_json)
50 self.types[type_.name] = type_
[email protected]712eca0f2012-02-21 01:13:0751 for function_json in json.get('functions', []):
[email protected]cfe484902012-02-15 14:52:3252 if not function_json.get('nocompile', False):
[email protected]15f08dd2012-01-27 07:29:4853 function = Function(function_json)
54 self.functions[function.name] = function
55
56class Type(object):
57 """A Type defined in the json.
[email protected]cfe484902012-02-15 14:52:3258
59 Properties:
60 - |name| the type name
61 - |description| the description of the type (if provided)
62 - |properties| a map of property names to their model.Property
[email protected]15f08dd2012-01-27 07:29:4863 """
64 def __init__(self, json):
65 self.name = json['id']
66 self.description = json.get('description')
67 self.properties = {}
68 for prop_name, prop_json in json['properties'].items():
69 self.properties[prop_name] = Property(prop_name, prop_json)
70
71class Callback(object):
72 """A callback parameter to a Function.
[email protected]cfe484902012-02-15 14:52:3273
74 Properties:
75 - |params| the parameters to this callback.
[email protected]15f08dd2012-01-27 07:29:4876 """
77 def __init__(self, json):
78 params = json['parameters']
[email protected]cfe484902012-02-15 14:52:3279 self.params = []
[email protected]15f08dd2012-01-27 07:29:4880 if len(params) == 0:
[email protected]cfe484902012-02-15 14:52:3281 return
[email protected]15f08dd2012-01-27 07:29:4882 elif len(params) == 1:
83 param = params[0]
[email protected]cfe484902012-02-15 14:52:3284 self.params.append(Property(param['name'], param))
[email protected]15f08dd2012-01-27 07:29:4885 else:
86 raise AssertionError("Callbacks can have at most a single parameter")
87
88class Function(object):
89 """A Function defined in the API.
[email protected]cfe484902012-02-15 14:52:3290
91 Properties:
92 - |name| the function name
93 - |params| a list of parameters to the function (order matters). A separate
94 parameter is used for each choice of a 'choices' parameter.
95 - |description| a description of the function (if provided)
96 - |callback| the callback parameter to the function. There should be exactly
97 one
[email protected]15f08dd2012-01-27 07:29:4898 """
99 def __init__(self, json):
100 self.name = json['name']
101 self.params = []
102 self.description = json['description']
103 self.callback = None
[email protected]15f08dd2012-01-27 07:29:48104 for param in json['parameters']:
105 if param.get('type') == 'function':
[email protected]cfe484902012-02-15 14:52:32106 assert (not self.callback), self.name + " has more than one callback"
[email protected]15f08dd2012-01-27 07:29:48107 self.callback = Callback(param)
108 else:
109 self.params.append(Property(param['name'], param))
[email protected]cfe484902012-02-15 14:52:32110 assert (self.callback), self.name + " does not support callback"
[email protected]15f08dd2012-01-27 07:29:48111
[email protected]cfe484902012-02-15 14:52:32112# TODO(calamity): handle Enum
[email protected]15f08dd2012-01-27 07:29:48113class Property(object):
114 """A property of a type OR a parameter to a function.
115
[email protected]cfe484902012-02-15 14:52:32116 Properties:
117 - |name| name of the property as in the json. This shouldn't change since
118 it is the key used to access DictionaryValues
119 - |unix_name| the unix_style_name of the property. Used as variable name
120 - |optional| a boolean representing whether the property is optional
121 - |description| a description of the property (if provided)
122 - |type_| the model.PropertyType of this property
123 - |ref_type| the type that the REF property is referencing. Can be used to
124 map to its model.Type
125 - |item_type| a model.Property representing the type of each element in an
126 ARRAY
127 - |properties| the properties of an OBJECT parameter
[email protected]15f08dd2012-01-27 07:29:48128 """
129 def __init__(self, name, json):
[email protected]cfe484902012-02-15 14:52:32130 if not re.match('^[a-z][a-zA-Z0-9]*$', name):
131 raise AssertionError('Name %s must be lowerCamelCase' % name)
[email protected]15f08dd2012-01-27 07:29:48132 self.name = name
[email protected]cfe484902012-02-15 14:52:32133 self._unix_name = _UnixName(self.name)
134 self._unix_name_used = False
[email protected]15f08dd2012-01-27 07:29:48135 self.optional = json.get('optional', False)
136 self.description = json.get('description')
[email protected]15f08dd2012-01-27 07:29:48137 if '$ref' in json:
138 self.ref_type = json['$ref']
139 self.type_ = PropertyType.REF
140 elif 'type' in json:
141 json_type = json['type']
142 if json_type == 'string':
143 self.type_ = PropertyType.STRING
[email protected]cfe484902012-02-15 14:52:32144 elif json_type == 'any':
145 self.type_ = PropertyType.ANY
146 elif json_type == 'boolean':
[email protected]15f08dd2012-01-27 07:29:48147 self.type_ = PropertyType.BOOLEAN
148 elif json_type == 'integer':
149 self.type_ = PropertyType.INTEGER
[email protected]cfe484902012-02-15 14:52:32150 elif json_type == 'number':
[email protected]15f08dd2012-01-27 07:29:48151 self.type_ = PropertyType.DOUBLE
152 elif json_type == 'array':
[email protected]cfe484902012-02-15 14:52:32153 self.item_type = Property(name + "Element", json['items'])
[email protected]15f08dd2012-01-27 07:29:48154 self.type_ = PropertyType.ARRAY
155 elif json_type == 'object':
156 self.properties = {}
157 self.type_ = PropertyType.OBJECT
158 for key, val in json['properties'].items():
159 self.properties[key] = Property(key, val)
160 else:
161 raise NotImplementedError(json_type)
162 elif 'choices' in json:
[email protected]cfe484902012-02-15 14:52:32163 assert len(json['choices']), 'Choices has no choices\n%s' % json
[email protected]15f08dd2012-01-27 07:29:48164 self.choices = {}
[email protected]cfe484902012-02-15 14:52:32165 self.type_ = PropertyType.CHOICES
166 for choice_json in json['choices']:
167 choice = Property(self.name, choice_json)
168 # A choice gets its unix_name set in
169 # cpp_type_generator.GetExpandedChoicesInParams
170 choice._unix_name = None
171 # The existence of any single choice is optional
172 choice.optional = True
173 self.choices[choice.type_] = choice
174 else:
175 raise NotImplementedError(json)
176
177 def GetUnixName(self):
178 """Gets the property's unix_name. Raises AttributeError if not set.
179 """
180 if self._unix_name is None:
181 raise AttributeError('No unix_name set on %s' % self.name)
182 self._unix_name_used = True
183 return self._unix_name
184
185 def SetUnixName(self, unix_name):
186 """Set the property's unix_name. Raises AttributeError if the unix_name has
187 already been used (GetUnixName has been called).
188 """
189 if unix_name == self._unix_name:
190 return
191 if self._unix_name_used:
192 raise AttributeError(
193 'Cannot set the unix_name on %s; '
194 'it is already used elsewhere as %s' %
195 (self.name, self._unix_name))
196 self._unix_name = unix_name
197
[email protected]712eca0f2012-02-21 01:13:07198 def Copy(self):
199 """Makes a copy of this model.Property object and allow the unix_name to be
200 set again.
201 """
202 property_copy = copy.copy(self)
203 property_copy._unix_name_used = False
204 return property_copy
205
[email protected]cfe484902012-02-15 14:52:32206 unix_name = property(GetUnixName, SetUnixName)
[email protected]15f08dd2012-01-27 07:29:48207
208class PropertyType(object):
209 """Enum of different types of properties/parameters.
210 """
211 class _Info(object):
[email protected]cfe484902012-02-15 14:52:32212 def __init__(self, is_fundamental, name):
[email protected]15f08dd2012-01-27 07:29:48213 self.is_fundamental = is_fundamental
[email protected]cfe484902012-02-15 14:52:32214 self.name = name
[email protected]15f08dd2012-01-27 07:29:48215
[email protected]cfe484902012-02-15 14:52:32216 def __repr__(self):
217 return self.name
218
219 INTEGER = _Info(True, "INTEGER")
220 DOUBLE = _Info(True, "DOUBLE")
221 BOOLEAN = _Info(True, "BOOLEAN")
222 STRING = _Info(True, "STRING")
223 ARRAY = _Info(False, "ARRAY")
224 REF = _Info(False, "REF")
225 CHOICES = _Info(False, "CHOICES")
226 OBJECT = _Info(False, "OBJECT")
227 ANY = _Info(False, "ANY")
228
229def _UnixName(name):
[email protected]712eca0f2012-02-21 01:13:07230 """Returns the unix_style name for a given lowerCamelCase string.
[email protected]cfe484902012-02-15 14:52:32231 """
232 return '_'.join([x.lower()
233 for x in re.findall('[A-Z][a-z_]*', name[0].upper() + name[1:])])
234