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

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

Issue 10022005: Let json schema compiler handle using arrays as types (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 8 years, 8 months 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 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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698