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 Model(object): | 9 class Model(object): |
10 """Model of all namespaces that comprise an API. | 10 """Model of all namespaces that comprise an API. |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
43 self.unix_name = UnixName(self.name) | 43 self.unix_name = UnixName(self.name) |
44 self.source_file = source_file | 44 self.source_file = source_file |
45 self.source_file_dir, self.source_file_filename = os.path.split(source_file) | 45 self.source_file_dir, self.source_file_filename = os.path.split(source_file) |
46 self.types = {} | 46 self.types = {} |
47 self.functions = {} | 47 self.functions = {} |
48 self.parent = None | 48 self.parent = None |
49 # TODO(calamity): Implement properties on namespaces for shared structures | 49 # TODO(calamity): Implement properties on namespaces for shared structures |
50 # or constants across a namespace (e.g Windows::WINDOW_ID_NONE). | 50 # or constants across a namespace (e.g Windows::WINDOW_ID_NONE). |
51 for property_json in json.get('properties', []): | 51 for property_json in json.get('properties', []): |
52 pass | 52 pass |
53 for type_json in json.get('types', []): | 53 for type_json in json.get('types', []): |
Yoyo Zhou
2012/04/09 23:48:47
This looks fragile. You're building the types and
cduvall
2012/04/10 03:06:08
Fixed this to not pass types around everywhere.
| |
54 type_ = Type(self, type_json['id'], type_json) | 54 type_ = Type(self, type_json['id'], type_json, self.types) |
55 self.types[type_.name] = type_ | 55 self.types[type_.name] = type_ |
56 for function_json in json.get('functions', []): | 56 for function_json in json.get('functions', []): |
57 if not function_json.get('nocompile', False): | 57 if not function_json.get('nocompile', False): |
58 self.functions[function_json['name']] = Function(self, function_json) | 58 self.functions[function_json['name']] = Function(self, function_json, |
Yoyo Zhou
2012/04/09 23:48:47
nit: line continuation should be 4 spaces if you p
cduvall
2012/04/10 03:06:08
Done.
| |
59 self.types) | |
59 | 60 |
60 class Type(object): | 61 class Type(object): |
61 """A Type defined in the json. | 62 """A Type defined in the json. |
62 | 63 |
63 Properties: | 64 Properties: |
64 - |name| the type name | 65 - |name| the type name |
65 - |description| the description of the type (if provided) | 66 - |description| the description of the type (if provided) |
66 - |properties| a map of property unix_names to their model.Property | 67 - |properties| a map of property unix_names to their model.Property |
67 - |functions| a map of function names to their model.Function | 68 - |functions| a map of function names to their model.Function |
68 - |from_client| indicates that instances of the Type can originate from the | 69 - |from_client| indicates that instances of the Type can originate from the |
69 users of generated code, such as top-level types and function results | 70 users of generated code, such as top-level types and function results |
70 - |from_json| indicates that instances of the Type can originate from the | 71 - |from_json| indicates that instances of the Type can originate from the |
71 JSON (as described by the schema), such as top-level types and function | 72 JSON (as described by the schema), such as top-level types and function |
72 parameters | 73 parameters |
73 """ | 74 """ |
74 def __init__(self, parent, name, json): | 75 def __init__(self, parent, name, json, types): |
75 if not ( | 76 if json.get('type') == 'array': |
76 'properties' in json or | 77 self.type_ = PropertyType.ARRAY |
77 'additionalProperties' in json or | 78 self.item_type = Property(self, name + "Element", json['items'], types, |
78 'functions' in json): | 79 from_json=True, |
79 raise ParseException(name + " has no properties or functions") | 80 from_client=True) |
81 else: | |
82 if not ( | |
83 'properties' in json or | |
84 'additionalProperties' in json or | |
85 'functions' in json): | |
86 raise ParseException(name + " has no properties or functions") | |
87 self.type_ = PropertyType.OBJECT | |
80 self.name = name | 88 self.name = name |
81 self.description = json.get('description') | 89 self.description = json.get('description') |
82 self.from_json = True | 90 self.from_json = True |
83 self.from_client = True | 91 self.from_client = True |
84 self.properties = {} | 92 self.properties = {} |
85 self.functions = {} | 93 self.functions = {} |
86 self.parent = parent | 94 self.parent = parent |
87 for function_json in json.get('functions', []): | 95 for function_json in json.get('functions', []): |
88 if not function_json.get('nocompile', False): | 96 if not function_json.get('nocompile', False): |
89 self.functions[function_json['name']] = Function(self, function_json) | 97 self.functions[function_json['name']] = Function(self, function_json, |
98 types) | |
90 props = [] | 99 props = [] |
91 for prop_name, prop_json in json.get('properties', {}).items(): | 100 for prop_name, prop_json in json.get('properties', {}).items(): |
92 # TODO(calamity): support functions (callbacks) as properties. The model | 101 # TODO(calamity): support functions (callbacks) as properties. The model |
93 # doesn't support it yet because the h/cc generators don't -- this is | 102 # doesn't support it yet because the h/cc generators don't -- this is |
94 # because we'd need to hook it into a base::Callback or something. | 103 # because we'd need to hook it into a base::Callback or something. |
95 # | 104 # |
96 # However, pragmatically it's not necessary to support them anyway, since | 105 # However, pragmatically it's not necessary to support them anyway, since |
97 # the instances of functions-on-properties in the extension APIs are all | 106 # the instances of functions-on-properties in the extension APIs are all |
98 # handled in pure Javascript on the render process (and .: never reach | 107 # handled in pure Javascript on the render process (and .: never reach |
99 # C++ let alone the browser). | 108 # C++ let alone the browser). |
100 if prop_json.get('type') == 'function': | 109 if prop_json.get('type') == 'function': |
101 continue | 110 continue |
102 props.append(Property(self, prop_name, prop_json, | 111 props.append(Property(self, prop_name, prop_json, types, |
103 from_json=True, | 112 from_json=True, |
104 from_client=True)) | 113 from_client=True)) |
105 | 114 |
106 additional_properties = json.get('additionalProperties') | 115 additional_properties = json.get('additionalProperties') |
107 if additional_properties: | 116 if additional_properties: |
108 props.append(Property(self, 'additionalProperties', additional_properties, | 117 props.append(Property(self, 'additionalProperties', additional_properties, |
109 is_additional_properties=True)) | 118 types, is_additional_properties=True)) |
110 | 119 |
111 for prop in props: | 120 for prop in props: |
112 if prop.unix_name in self.properties: | 121 if prop.unix_name in self.properties: |
113 raise ParseException( | 122 raise ParseException( |
114 self.properties[prop.unix_name].name + ' and ' + prop.name + | 123 self.properties[prop.unix_name].name + ' and ' + prop.name + |
115 ' are both named ' + prop.unix_name) | 124 ' are both named ' + prop.unix_name) |
116 self.properties[prop.unix_name] = prop | 125 self.properties[prop.unix_name] = prop |
117 | 126 |
118 class Callback(object): | 127 class Callback(object): |
119 """A callback parameter to a Function. | 128 """A callback parameter to a Function. |
120 | 129 |
121 Properties: | 130 Properties: |
122 - |params| the parameters to this callback. | 131 - |params| the parameters to this callback. |
123 """ | 132 """ |
124 def __init__(self, parent, json): | 133 def __init__(self, parent, json, types): |
125 params = json['parameters'] | 134 params = json['parameters'] |
126 self.parent = parent | 135 self.parent = parent |
127 self.params = [] | 136 self.params = [] |
128 if len(params) == 0: | 137 if len(params) == 0: |
129 return | 138 return |
130 elif len(params) == 1: | 139 elif len(params) == 1: |
131 param = params[0] | 140 param = params[0] |
132 self.params.append(Property(self, param['name'], param, | 141 self.params.append(Property(self, param['name'], param, types, |
133 from_client=True)) | 142 from_client=True)) |
134 else: | 143 else: |
135 raise ParseException("Callbacks can have at most a single parameter") | 144 raise ParseException("Callbacks can have at most a single parameter") |
136 | 145 |
137 class Function(object): | 146 class Function(object): |
138 """A Function defined in the API. | 147 """A Function defined in the API. |
139 | 148 |
140 Properties: | 149 Properties: |
141 - |name| the function name | 150 - |name| the function name |
142 - |params| a list of parameters to the function (order matters). A separate | 151 - |params| a list of parameters to the function (order matters). A separate |
143 parameter is used for each choice of a 'choices' parameter. | 152 parameter is used for each choice of a 'choices' parameter. |
144 - |description| a description of the function (if provided) | 153 - |description| a description of the function (if provided) |
145 - |callback| the callback parameter to the function. There should be exactly | 154 - |callback| the callback parameter to the function. There should be exactly |
146 one | 155 one |
147 """ | 156 """ |
148 def __init__(self, parent, json): | 157 def __init__(self, parent, json, types): |
149 self.name = json['name'] | 158 self.name = json['name'] |
150 self.params = [] | 159 self.params = [] |
151 self.description = json.get('description') | 160 self.description = json.get('description') |
152 self.callback = None | 161 self.callback = None |
153 self.parent = parent | 162 self.parent = parent |
154 for param in json['parameters']: | 163 for param in json['parameters']: |
155 if param.get('type') == 'function': | 164 if param.get('type') == 'function': |
156 if self.callback: | 165 if self.callback: |
157 raise ParseException(self.name + " has more than one callback") | 166 raise ParseException(self.name + " has more than one callback") |
158 self.callback = Callback(self, param) | 167 self.callback = Callback(self, param, types) |
159 else: | 168 else: |
160 self.params.append(Property(self, param['name'], param, | 169 self.params.append(Property(self, param['name'], param, types, |
161 from_json=True)) | 170 from_json=True)) |
162 | 171 |
163 class Property(object): | 172 class Property(object): |
164 """A property of a type OR a parameter to a function. | 173 """A property of a type OR a parameter to a function. |
165 | 174 |
166 Properties: | 175 Properties: |
Yoyo Zhou
2012/04/09 23:48:47
Make sure to update these.
cduvall
2012/04/10 03:06:08
Done.
| |
167 - |name| name of the property as in the json. This shouldn't change since | 176 - |name| name of the property as in the json. This shouldn't change since |
168 it is the key used to access DictionaryValues | 177 it is the key used to access DictionaryValues |
169 - |unix_name| the unix_style_name of the property. Used as variable name | 178 - |unix_name| the unix_style_name of the property. Used as variable name |
170 - |optional| a boolean representing whether the property is optional | 179 - |optional| a boolean representing whether the property is optional |
171 - |description| a description of the property (if provided) | 180 - |description| a description of the property (if provided) |
172 - |type_| the model.PropertyType of this property | 181 - |type_| the model.PropertyType of this property |
173 - |ref_type| the type that the REF property is referencing. Can be used to | 182 - |ref_type| the type that the REF property is referencing. Can be used to |
174 map to its model.Type | 183 map to its model.Type |
175 - |item_type| a model.Property representing the type of each element in an | 184 - |item_type| a model.Property representing the type of each element in an |
176 ARRAY | 185 ARRAY |
177 - |properties| the properties of an OBJECT parameter | 186 - |properties| the properties of an OBJECT parameter |
178 """ | 187 """ |
179 | 188 |
180 def __init__(self, parent, name, json, is_additional_properties=False, | 189 def __init__(self, parent, name, json, types, is_additional_properties=False, |
181 from_json=False, from_client=False): | 190 from_json=False, from_client=False): |
182 """ | 191 """ |
183 Parameters: | 192 Parameters: |
184 - |from_json| indicates that instances of the Type can originate from the | 193 - |from_json| indicates that instances of the Type can originate from the |
185 JSON (as described by the schema), such as top-level types and function | 194 JSON (as described by the schema), such as top-level types and function |
186 parameters | 195 parameters |
187 - |from_client| indicates that instances of the Type can originate from the | 196 - |from_client| indicates that instances of the Type can originate from the |
188 users of generated code, such as top-level types and function results | 197 users of generated code, such as top-level types and function results |
189 """ | 198 """ |
190 self.name = name | 199 self.name = name |
191 self._unix_name = UnixName(self.name) | 200 self._unix_name = UnixName(self.name) |
192 self._unix_name_used = False | 201 self._unix_name_used = False |
193 self.optional = json.get('optional', False) | 202 self.optional = json.get('optional', False) |
194 self.description = json.get('description') | 203 self.description = json.get('description') |
195 self.parent = parent | 204 self.parent = parent |
205 self.is_array = False | |
196 if is_additional_properties: | 206 if is_additional_properties: |
197 self.type_ = PropertyType.ADDITIONAL_PROPERTIES | 207 self.type_ = PropertyType.ADDITIONAL_PROPERTIES |
198 elif '$ref' in json: | 208 elif '$ref' in json: |
199 self.ref_type = json['$ref'] | 209 self.ref_type = json['$ref'] |
200 self.type_ = PropertyType.REF | 210 self.type_ = PropertyType.REF |
211 if self.ref_type in types: | |
212 type_reffed = types[self.ref_type] | |
213 self.is_array = type_reffed.type_ == PropertyType.ARRAY | |
214 if self.is_array: | |
215 self.item_type = type_reffed.item_type | |
201 elif 'enum' in json: | 216 elif 'enum' in json: |
202 self.enum_values = [] | 217 self.enum_values = [] |
203 for value in json['enum']: | 218 for value in json['enum']: |
204 self.enum_values.append(value) | 219 self.enum_values.append(value) |
205 self.type_ = PropertyType.ENUM | 220 self.type_ = PropertyType.ENUM |
206 elif 'type' in json: | 221 elif 'type' in json: |
207 json_type = json['type'] | 222 json_type = json['type'] |
208 if json_type == 'string': | 223 if json_type == 'string': |
209 self.type_ = PropertyType.STRING | 224 self.type_ = PropertyType.STRING |
210 elif json_type == 'any': | 225 elif json_type == 'any': |
211 self.type_ = PropertyType.ANY | 226 self.type_ = PropertyType.ANY |
212 elif json_type == 'boolean': | 227 elif json_type == 'boolean': |
213 self.type_ = PropertyType.BOOLEAN | 228 self.type_ = PropertyType.BOOLEAN |
214 elif json_type == 'integer': | 229 elif json_type == 'integer': |
215 self.type_ = PropertyType.INTEGER | 230 self.type_ = PropertyType.INTEGER |
216 elif json_type == 'number': | 231 elif json_type == 'number': |
217 self.type_ = PropertyType.DOUBLE | 232 self.type_ = PropertyType.DOUBLE |
218 elif json_type == 'array': | 233 elif json_type == 'array': |
219 self.item_type = Property(self, name + "Element", json['items'], | 234 self.item_type = Property(self, name + "Element", json['items'], types, |
220 from_json=from_json, | 235 from_json=from_json, |
221 from_client=from_client) | 236 from_client=from_client) |
222 self.type_ = PropertyType.ARRAY | 237 self.type_ = PropertyType.ARRAY |
223 elif json_type == 'object': | 238 elif json_type == 'object': |
224 self.type_ = PropertyType.OBJECT | 239 self.type_ = PropertyType.OBJECT |
225 # These members are read when this OBJECT Property is used as a Type | 240 # These members are read when this OBJECT Property is used as a Type |
226 self.properties = {} | 241 self.properties = {} |
227 self.from_json = from_json | 242 self.from_json = from_json |
228 self.from_client = from_client | 243 self.from_client = from_client |
229 type_ = Type(self, self.name, json) | 244 type_ = Type(self, self.name, json, types) |
230 self.properties = type_.properties | 245 self.properties = type_.properties |
231 self.functions = type_.functions | 246 self.functions = type_.functions |
232 else: | 247 else: |
233 raise ParseException(self, 'type ' + json_type + ' not recognized') | 248 raise ParseException(self, 'type ' + json_type + ' not recognized') |
234 elif 'choices' in json: | 249 elif 'choices' in json: |
235 if not json['choices']: | 250 if not json['choices']: |
236 raise ParseException('Choices has no choices') | 251 raise ParseException('Choices has no choices') |
237 self.choices = {} | 252 self.choices = {} |
238 self.type_ = PropertyType.CHOICES | 253 self.type_ = PropertyType.CHOICES |
239 for choice_json in json['choices']: | 254 for choice_json in json['choices']: |
240 choice = Property(self, self.name, choice_json, | 255 choice = Property(self, self.name, choice_json, types, |
241 from_json=from_json, | 256 from_json=from_json, |
242 from_client=from_client) | 257 from_client=from_client) |
243 # A choice gets its unix_name set in | 258 # A choice gets its unix_name set in |
244 # cpp_type_generator.GetExpandedChoicesInParams | 259 # cpp_type_generator.GetExpandedChoicesInParams |
245 choice._unix_name = None | 260 choice._unix_name = None |
246 # The existence of any single choice is optional | 261 # The existence of any single choice is optional |
247 choice.optional = True | 262 choice.optional = True |
248 self.choices[choice.type_] = choice | 263 self.choices[choice.type_] = choice |
249 else: | 264 else: |
250 raise ParseException('Property has no type, $ref or choices') | 265 raise ParseException('Property has no type, $ref or choices') |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
325 """Returns the hierarchy of the given model entity.""" | 340 """Returns the hierarchy of the given model entity.""" |
326 hierarchy = [] | 341 hierarchy = [] |
327 while entity: | 342 while entity: |
328 try: | 343 try: |
329 hierarchy.append(entity.name) | 344 hierarchy.append(entity.name) |
330 except AttributeError: | 345 except AttributeError: |
331 hierarchy.append(repr(entity)) | 346 hierarchy.append(repr(entity)) |
332 entity = entity.parent | 347 entity = entity.parent |
333 hierarchy.reverse() | 348 hierarchy.reverse() |
334 return hierarchy | 349 return hierarchy |
OLD | NEW |