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

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

Issue 12221050: Improvements to JSON Schema Compiler's Dart Generation (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Style/comment fixes Created 7 years, 10 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 Generator language component for compiler.py that adds Dart language support. 5 Generator language component for compiler.py that adds Dart language support.
6 """ 6 """
7 7
8 from code import Code 8 from code import Code
9 from model import * 9 from model import *
10 from schema_util import * 10 from schema_util import *
11 11
12 import os 12 import os
13 from datetime import datetime 13 from datetime import datetime
14 14
15 LICENSE = (""" 15 LICENSE = (
16 // Copyright (c) %s, the Dart project authors. Please see the AUTHORS file 16 """// Copyright (c) %s, the Dart project authors. Please see the AUTHORS file
17 // for details. All rights reserved. Use of this source code is governed by a 17 // for details. All rights reserved. Use of this source code is governed by a
18 // BSD-style license that can be found in the LICENSE file.""" % 18 // BSD-style license that can be found in the LICENSE file.""" %
19 datetime.now().year) 19 datetime.now().year)
20 20
21 class DartGenerator(object): 21 class DartGenerator(object):
22 def __init__(self, dart_overrides_dir=None): 22 def __init__(self, dart_overrides_dir=None):
23 self._dart_overrides_dir = dart_overrides_dir 23 self._dart_overrides_dir = dart_overrides_dir
24 24
25 def Generate(self, namespace): 25 def Generate(self, namespace):
26 return _Generator(namespace, self._dart_overrides_dir).Generate() 26 return _Generator(namespace, self._dart_overrides_dir).Generate()
27 27
28 class _Generator(object): 28 class _Generator(object):
29 """A .dart generator for a namespace. 29 """A .dart generator for a namespace.
30 """ 30 """
31 31
32 def __init__(self, namespace, dart_overrides_dir=None): 32 def __init__(self, namespace, dart_overrides_dir=None):
33 self._namespace = namespace 33 self._namespace = namespace
34 # TODO(sashab): Once inline type definitions start being added to
35 # self._types, make a _FindType(self, type_) function that looks at
36 # self._namespace.types.
34 self._types = namespace.types 37 self._types = namespace.types
35 38
36 # Build a dictionary of Type Name --> Custom Dart code. 39 # Build a dictionary of Type Name --> Custom Dart code.
37 self._type_overrides = {} 40 self._type_overrides = {}
38 if dart_overrides_dir is not None: 41 if dart_overrides_dir is not None:
39 for filename in os.listdir(dart_overrides_dir): 42 for filename in os.listdir(dart_overrides_dir):
40 if filename.startswith(namespace.unix_name): 43 if filename.startswith(namespace.unix_name):
41 with open(os.path.join(dart_overrides_dir, filename)) as f: 44 with open(os.path.join(dart_overrides_dir, filename)) as f:
42 # Split off the namespace and file extension, leaving just the type. 45 # Split off the namespace and file extension, leaving just the type.
43 type_path = '.'.join(filename.split('.')[1:-1]) 46 type_path = '.'.join(filename.split('.')[1:-1])
44 self._type_overrides[type_path] = f.read() 47 self._type_overrides[type_path] = f.read()
45 48
49 # TODO(sashab): Add all inline type definitions to the global Types
50 # dictionary here, so they have proper names, and are implemented along with
51 # all other types. Also update the parameters/members with these types
52 # to reference these new types instead.
53
46 def Generate(self): 54 def Generate(self):
47 """Generates a Code object with the .dart for the entire namespace. 55 """Generates a Code object with the .dart for the entire namespace.
48 """ 56 """
49 c = Code() 57 c = Code()
50 (c.Append(LICENSE) 58 (c.Append(LICENSE)
59 .Append()
51 .Append('// Generated from namespace: %s' % self._namespace.name) 60 .Append('// Generated from namespace: %s' % self._namespace.name)
52 .Append() 61 .Append()
53 .Append('part of chrome;')) 62 .Append('part of chrome;'))
54 63
55 if self._types: 64 if self._types:
56 (c.Append() 65 (c.Append()
57 .Append('/**') 66 .Append('/**')
58 .Append(' * Types') 67 .Append(' * Types')
59 .Append(' */') 68 .Append(' */')
69 .Append()
60 ) 70 )
61 for type_name in self._types: 71 for type_ in self._types.values():
62 c.Concat(self._GenerateType(self._types[type_name])) 72 # Check for custom dart for this whole type.
73 override = self._GetOverride([type_.name], document_with=type_)
74 c.Cblock(override if override is not None else self._GenerateType(type_))
63 75
64 if self._namespace.events: 76 if self._namespace.events:
65 (c.Append() 77 (c.Append('/**')
66 .Append('/**')
67 .Append(' * Events') 78 .Append(' * Events')
68 .Append(' */') 79 .Append(' */')
80 .Append()
69 ) 81 )
70 for event_name in self._namespace.events: 82 for event_name in self._namespace.events:
71 c.Concat(self._GenerateEvent(self._namespace.events[event_name])) 83 c.Cblock(self._GenerateEvent(self._namespace.events[event_name]))
72 84
73 (c.Append() 85 (c.Append('/**')
74 .Append('/**')
75 .Append(' * Functions') 86 .Append(' * Functions')
76 .Append(' */') 87 .Append(' */')
88 .Append()
77 ) 89 )
78 c.Concat(self._GenerateMainClass()) 90 c.Cblock(self._GenerateMainClass())
79 91
80 return c 92 return c
81 93
82 def _GenerateType(self, type_): 94 def _GenerateType(self, type_):
83 """Given a Type object, returns the Code with the .dart for this 95 """Given a Type object, returns the Code with the .dart for this
84 type's definition. 96 type's definition.
85 97
86 Assumes this type is a Parameter Type (creatable by user), and creates an 98 Assumes this type is a Parameter Type (creatable by user), and creates an
87 object that extends ChromeObject. All parameters are specifiable as named 99 object that extends ChromeObject. All parameters are specifiable as named
88 arguments in the constructor, and all methods are wrapped with getters and 100 arguments in the constructor, and all methods are wrapped with getters and
89 setters that hide the JS() implementation. 101 setters that hide the JS() implementation.
90 """ 102 """
91 c = Code() 103 c = Code()
92 (c.Append() 104
93 .Concat(self._GenerateDocumentation(type_)) 105 # Since enums are just treated as strings for now, don't generate their
106 # type.
107 # TODO(sashab): Find a nice way to wrap enum objects.
108 if type_.property_type is PropertyType.ENUM:
109 return c
110
111 (c.Concat(self._GenerateDocumentation(type_))
94 .Sblock('class %(type_name)s extends ChromeObject {') 112 .Sblock('class %(type_name)s extends ChromeObject {')
95 ) 113 )
96 114
97 # Check whether this type has function members. If it does, don't allow 115 # Check whether this type has function members. If it does, don't allow
98 # public construction. 116 # public construction.
99 add_public_constructor = all(not self._IsFunction(p.type_) 117 add_public_constructor = all(not self._IsFunction(p.type_)
100 for p in type_.properties.values()) 118 for p in type_.properties.values())
101 constructor_fields = [self._GeneratePropertySignature(p) 119 constructor_fields = [self._GeneratePropertySignature(p)
102 for p in type_.properties.values()] 120 for p in type_.properties.values()]
103 121
104 if add_public_constructor: 122 if add_public_constructor:
105 (c.Append('/*') 123 (c.Append('/*')
106 .Append(' * Public constructor') 124 .Append(' * Public constructor')
107 .Append(' */') 125 .Append(' */')
108 .Sblock('%(type_name)s({%(constructor_fields)s}) {') 126 .Sblock('%(type_name)s({%(constructor_fields)s}) {')
109 ) 127 )
110 128
111 for prop_name in type_.properties: 129 for prop_name in type_.properties:
112 c.Append('this.%s = %s;' % (prop_name, prop_name)) 130 (c.Sblock('if (?%s)' % prop_name)
131 .Append('this.%s = %s;' % (prop_name, prop_name))
132 .Eblock()
133 )
113 (c.Eblock('}') 134 (c.Eblock('}')
114 .Append() 135 .Append()
115 ) 136 )
116 137
117 (c.Append('/*') 138 (c.Append('/*')
118 .Append(' * Private constructor') 139 .Append(' * Private constructor')
119 .Append(' */') 140 .Append(' */')
120 .Append('%(type_name)s._proxy(_jsObject) : super._proxy(_jsObject);') 141 .Append('%(type_name)s._proxy(_jsObject) : super._proxy(_jsObject);')
121 ) 142 )
122 143
123 # Add an accessor (getter & setter) for each property. 144 # Add an accessor (getter & setter) for each property.
124 properties = [p for p in type_.properties.values() 145 properties = [p for p in type_.properties.values()
125 if not self._IsFunction(p.type_)] 146 if not self._IsFunction(p.type_)]
126 if properties: 147 if properties:
127 (c.Append() 148 (c.Append()
128 .Append('/*') 149 .Append('/*')
129 .Append(' * Public accessors') 150 .Append(' * Public accessors')
130 .Append(' */') 151 .Append(' */')
131 ) 152 )
132 for prop in properties: 153 for prop in properties:
133 type_name = self._GetDartType(prop.type_) 154 override = self._GetOverride([type_.name, prop.name], document_with=prop)
134 155 c.Concat(override if override is not None
135 # Check for custom dart for this whole property. 156 else self._GenerateGetterAndSetter(type_, prop))
136 c.Append()
137 if not self._ConcatOverride(c, type_, prop, add_doc=True):
138 # Add the getter.
139 if not self._ConcatOverride(c, type_, prop, key_suffix='.get',
140 add_doc=True):
141 # Add the documentation for this property.
142 c.Concat(self._GenerateDocumentation(prop))
143
144 if (self._IsBaseType(prop.type_)
145 or self._IsListOfBaseTypes(prop.type_)):
146 c.Append("%s get %s => JS('%s', '#.%s', this._jsObject);" %
147 (type_name, prop.name, type_name, prop.name))
148 elif self._IsSerializableObjectType(prop.type_):
149 c.Append("%s get %s => new %s._proxy(JS('', '#.%s', "
150 "this._jsObject));"
151 % (type_name, prop.name, type_name, prop.name))
152 elif self._IsListOfSerializableObjects(prop.type_):
153 (c.Sblock('%s get %s {' % (type_name, prop.name))
154 .Append('%s __proxy_%s = new %s();' % (type_name, prop.name,
155 type_name))
156 .Sblock("for (var o in JS('List', '#.%s', this._jsObject)) {" %
157 prop.name)
158 .Append('__proxy_%s.add(new %s._proxy(o));' % (prop.name,
159 self._GetDartType(prop.type_.item_type)))
160 .Eblock('}')
161 .Append('return __proxy_%s;' % prop.name)
162 .Eblock('}')
163 )
164 elif self._IsObjectType(prop.type_):
165 # TODO(sashab): Think of a way to serialize generic Dart objects.
166 c.Append("%s get %s => JS('%s', '#.%s', this._jsObject);" %
167 (type_name, prop.name, type_name, prop.name))
168 else:
169 raise Exception(
170 "Could not generate wrapper for %s.%s: unserializable type %s" %
171 (type_.name, prop.name, type_name)
172 )
173
174 # Add the setter.
175 c.Append()
176 if not self._ConcatOverride(c, type_, prop, key_suffix='.set'):
177 wrapped_name = prop.name
178 if not self._IsBaseType(prop.type_):
179 wrapped_name = 'convertArgument(%s)' % prop.name
180
181 (c.Sblock("void set %s(%s %s) {" % (prop.name, type_name, prop.name))
182 .Append("JS('void', '#.%s = #', this._jsObject, %s);" %
183 (prop.name, wrapped_name))
184 .Eblock("}")
185 )
186 157
187 # Now add all the methods. 158 # Now add all the methods.
188 methods = [t for t in type_.properties.values() 159 methods = [t for t in type_.properties.values()
189 if self._IsFunction(t.type_)] 160 if self._IsFunction(t.type_)]
190 if methods: 161 if methods:
191 (c.Append() 162 (c.Append()
192 .Append('/*') 163 .Append('/*')
193 .Append(' * Methods') 164 .Append(' * Methods')
194 .Append(' */') 165 .Append(' */')
195 ) 166 )
196 for prop in methods: 167 for prop in methods:
197 c.Concat(self._GenerateFunction(prop.type_.function)) 168 # Check if there's an override for this method.
169 override = self._GetOverride([type_.name, prop.name], document_with=prop)
170 c.Cblock(override if override is not None
171 else self._GenerateFunction(prop.type_.function))
198 172
199 (c.Eblock('}') 173 (c.Eblock('}')
200 .Substitute({ 174 .Substitute({
201 'type_name': type_.simple_name, 175 'type_name': self._AddPrefix(type_.simple_name),
202 'constructor_fields': ', '.join(constructor_fields) 176 'constructor_fields': ', '.join(constructor_fields)
203 }) 177 })
204 ) 178 )
205 179
206 return c 180 return c
207 181
182 def _GenerateGetterAndSetter(self, type_, prop):
183 """Given a Type and Property, returns the Code object for the getter and
184 setter for that property.
185 """
186 c = Code()
187 override = self._GetOverride([type_.name, prop.name, '.get'],
188 document_with=prop)
189 c.Cblock(override if override is not None
190 else self._GenerateGetter(type_, prop))
191 override = self._GetOverride([type_.name, prop.name, '.set'])
192 c.Cblock(override if override is not None
193 else self._GenerateSetter(type_, prop))
194 return c
195
196 def _GenerateGetter(self, type_, prop):
197 """Given a Type and Property, returns the Code object for the getter for
198 that property.
199
200 Also adds the documentation for this property before the method.
201 """
202 c = Code()
203 c.Concat(self._GenerateDocumentation(prop))
204
205 type_name = self._GetDartType(prop.type_)
206 if (self._IsBaseType(prop.type_)):
207 c.Append("%s get %s => JS('%s', '#.%s', this._jsObject);" %
208 (type_name, prop.name, type_name, prop.name))
209 elif self._IsSerializableObjectType(prop.type_):
210 c.Append("%s get %s => new %s._proxy(JS('', '#.%s', "
211 "this._jsObject));"
212 % (type_name, prop.name, type_name, prop.name))
213 elif self._IsListOfSerializableObjects(prop.type_):
214 (c.Sblock('%s get %s {' % (type_name, prop.name))
215 .Append('%s __proxy_%s = new %s();' % (type_name, prop.name,
216 type_name))
217 .Sblock("for (var o in JS('List', '#.%s', this._jsObject)) {" %
218 prop.name)
219 .Append('__proxy_%s.add(new %s._proxy(o));' % (prop.name,
220 self._GetDartType(prop.type_.item_type)))
221 .Eblock('}')
222 .Append('return __proxy_%s;' % prop.name)
223 .Eblock('}')
224 )
225 elif self._IsObjectType(prop.type_):
226 # TODO(sashab): Think of a way to serialize generic Dart objects.
227 c.Append("%s get %s => JS('%s', '#.%s', this._jsObject);" %
228 (type_name, prop.name, type_name, prop.name))
229 else:
230 raise Exception(
231 "Could not generate wrapper for %s.%s: unserializable type %s" %
232 (type_.name, prop.name, type_name)
233 )
234 return c
235
236 def _GenerateSetter(self, type_, prop):
237 """Given a Type and Property, returns the Code object for the setter for
238 that property.
239 """
240 c = Code()
241 type_name = self._GetDartType(prop.type_)
242 wrapped_name = prop.name
243 if not self._IsBaseType(prop.type_):
244 wrapped_name = 'convertArgument(%s)' % prop.name
245
246 (c.Sblock("void set %s(%s %s) {" % (prop.name, type_name, prop.name))
247 .Append("JS('void', '#.%s = #', this._jsObject, %s);" %
248 (prop.name, wrapped_name))
249 .Eblock("}")
250 )
251 return c
252
208 def _GenerateDocumentation(self, prop): 253 def _GenerateDocumentation(self, prop):
209 """Given an object, generates the documentation for this object (as a 254 """Given an object, generates the documentation for this object (as a
210 code string) and returns the Code object. 255 code string) and returns the Code object.
211 256
212 Returns an empty code object if the object has no documentation. 257 Returns an empty code object if the object has no documentation.
213 258
214 Uses triple-quotes for the string. 259 Uses triple-quotes for the string.
215 """ 260 """
216 c = Code() 261 c = Code()
217 if prop.description is not None: 262 if prop.description is not None:
218 for line in prop.description.split('\n'): 263 for line in prop.description.split('\n'):
219 c.Comment(line, comment_prefix='/// ') 264 c.Comment(line, comment_prefix='/// ')
220 return c 265 return c
221 266
222 def _GenerateFunction(self, f): 267 def _GenerateFunction(self, f):
223 """Returns the Code object for the given function. 268 """Returns the Code object for the given function.
224 """ 269 """
225 c = Code() 270 c = Code()
226 (c.Append() 271 c.Concat(self._GenerateDocumentation(f))
227 .Concat(self._GenerateDocumentation(f))
228 )
229 272
230 if not self._NeedsProxiedCallback(f): 273 if not self._NeedsProxiedCallback(f):
231 c.Append("%s => %s;" % (self._GenerateFunctionSignature(f), 274 c.Append("%s => %s;" % (self._GenerateFunctionSignature(f),
232 self._GenerateProxyCall(f))) 275 self._GenerateProxyCall(f)))
233 return c 276 return c
234 277
235 (c.Sblock("%s {" % self._GenerateFunctionSignature(f)) 278 (c.Sblock("%s {" % self._GenerateFunctionSignature(f))
236 .Concat(self._GenerateProxiedFunction(f.callback, f.callback.name)) 279 .Concat(self._GenerateProxiedFunction(f.callback, f.callback.name))
237 .Append('%s;' % self._GenerateProxyCall(f)) 280 .Append('%s;' % self._GenerateProxyCall(f))
238 .Eblock('}') 281 .Eblock('}')
239 ) 282 )
240 283
241 return c 284 return c
242 285
243 def _GenerateProxiedFunction(self, f, callback_name): 286 def _GenerateProxiedFunction(self, f, callback_name):
244 """Given a function (assumed to be a callback), generates the proxied 287 """Given a function (assumed to be a callback), generates the proxied
245 version of this function, which calls |callback_name| if it is defined. 288 version of this function, which calls |callback_name| if it is defined.
246 289
247 Returns a Code object. 290 Returns a Code object.
248 """ 291 """
249 c = Code() 292 c = Code()
250 proxied_params = [] 293 proxied_params = []
251 # A list of Properties, containing List<*> objects that need proxying for 294 # A list of Properties, containing List<*> objects that need proxying for
252 # their members (by copying out each member and proxying it). 295 # their members (by copying out each member and proxying it).
253 lists_to_proxy = [] 296 lists_to_proxy = []
254 for p in f.params: 297 for p in f.params:
255 if self._IsBaseType(p.type_) or self._IsListOfBaseTypes(p.type_): 298 if self._IsBaseType(p.type_):
256 proxied_params.append(p.name) 299 proxied_params.append(p.name)
257 elif self._IsSerializableObjectType(p.type_): 300 elif self._IsSerializableObjectType(p.type_):
258 proxied_params.append('new %s._proxy(%s)' % ( 301 proxied_params.append('new %s._proxy(%s)' % (
259 self._GetDartType(p.type_), p.name)) 302 self._GetDartType(p.type_), p.name))
260 elif self._IsListOfSerializableObjects(p.type_): 303 elif self._IsListOfSerializableObjects(p.type_):
261 proxied_params.append('__proxy_%s' % p.name) 304 proxied_params.append('__proxy_%s' % p.name)
262 lists_to_proxy.append(p) 305 lists_to_proxy.append(p)
263 elif self._IsObjectType(p.type_): 306 elif self._IsObjectType(p.type_):
264 # TODO(sashab): Find a way to build generic JS objects back in Dart. 307 # TODO(sashab): Find a way to build generic JS objects back in Dart.
265 proxied_params.append('%s' % p.name) 308 proxied_params.append('%s' % p.name)
309 elif p.type_.property_type is PropertyType.ARRAY:
310 # TODO(sashab): This might be okay - what if this is a list of
311 # FileEntry elements? In this case, a basic list will proxy the objects
312 # fine.
313 proxied_params.append('%s' % p.name)
266 else: 314 else:
267 raise Exception( 315 raise Exception(
268 "Cannot automatically create proxy; can't wrap %s, type %s" % ( 316 "Cannot automatically create proxy; can't wrap %s, type %s" % (
269 self._GenerateFunctionSignature(f), self._GetDartType(p.type_))) 317 self._GenerateFunctionSignature(f), self._GetDartType(p.type_)))
270 318
271 (c.Sblock("void __proxy_callback(%s) {" % ', '.join(p.name for p in 319 (c.Sblock("void __proxy_callback(%s) {" % ', '.join(p.name for p in
272 f.params)) 320 f.params))
273 .Sblock('if (?%s) {' % callback_name) 321 .Sblock('if (?%s) {' % callback_name)
274 ) 322 )
275 323
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
346 394
347 def _GenerateEvent(self, event): 395 def _GenerateEvent(self, event):
348 """Given a Function object, returns the Code with the .dart for this event, 396 """Given a Function object, returns the Code with the .dart for this event,
349 represented by the function. 397 represented by the function.
350 398
351 All events extend the Event base type. 399 All events extend the Event base type.
352 """ 400 """
353 c = Code() 401 c = Code()
354 402
355 # Add documentation for this event. 403 # Add documentation for this event.
356 (c.Append() 404 (c.Concat(self._GenerateDocumentation(event))
357 .Concat(self._GenerateDocumentation(event))
358 .Sblock('class Event_%(event_name)s extends Event {') 405 .Sblock('class Event_%(event_name)s extends Event {')
359 ) 406 )
360 407
361 # If this event needs a proxy, all calls need to be proxied. 408 # If this event needs a proxy, all calls need to be proxied.
362 needs_proxy = self._NeedsProxy(event) 409 needs_proxy = self._NeedsProxy(event)
363 410
364 # Override Event callback type definitions. 411 # Override Event callback type definitions.
365 for ret_type, event_func in (('void', 'addListener'), 412 for ret_type, event_func in (('void', 'addListener'),
366 ('void', 'removeListener'), 413 ('void', 'removeListener'),
367 ('bool', 'hasListener')): 414 ('bool', 'hasListener')):
368 param_list = self._GenerateParameterList(event.params, event.callback, 415 param_list = self._GenerateParameterList(event.params, event.callback,
369 convert_optional=True) 416 convert_optional=True)
370 if needs_proxy: 417 if needs_proxy:
371 (c.Sblock('%s %s(void callback(%s)) {' % (ret_type, event_func, 418 (c.Sblock('%s %s(void callback(%s)) {' % (ret_type, event_func,
372 param_list)) 419 param_list))
373 .Concat(self._GenerateProxiedFunction(event, 'callback')) 420 .Concat(self._GenerateProxiedFunction(event, 'callback'))
374 .Append('super.%s(callback);' % event_func) 421 .Append('super.%s(callback);' % event_func)
375 .Eblock('}') 422 .Eblock('}')
376 ) 423 )
377 else: 424 else:
378 c.Append('%s %s(void callback(%s)) => super.%s(callback);' % 425 c.Append('%s %s(void callback(%s)) => super.%s(callback);' %
379 (ret_type, event_func, param_list, event_func)) 426 (ret_type, event_func, param_list, event_func))
380 c.Append() 427 c.Append()
381 428
382 # Generate the constructor. 429 # Generate the constructor.
383 (c.Append('Event_%(event_name)s(jsObject) : ' 430 (c.Append('Event_%(event_name)s(jsObject) : '
384 'super(jsObject, %(param_num)d);') 431 'super._(jsObject, %(param_num)d);')
385 .Eblock('}') 432 .Eblock('}')
386 .Substitute({ 433 .Substitute({
387 'event_name': self._namespace.unix_name + '_' + event.name, 434 'event_name': self._namespace.unix_name + '_' + event.name,
388 'param_num': len(event.params) 435 'param_num': len(event.params)
389 }) 436 })
390 ) 437 )
391 438
392 return c 439 return c
393 440
394 def _GenerateMainClass(self): 441 def _GenerateMainClass(self):
395 """Generates the main class for this file, which links to all functions 442 """Generates the main class for this file, which links to all functions
396 and events. 443 and events.
397 444
398 Returns a code object. 445 Returns a code object.
399 """ 446 """
400 c = Code() 447 c = Code()
401 (c.Append() 448 (c.Sblock('class API_%s {' % self._namespace.unix_name)
402 .Sblock('class API_%s {' % self._namespace.unix_name)
403 .Append('/*') 449 .Append('/*')
404 .Append(' * API connection') 450 .Append(' * API connection')
405 .Append(' */') 451 .Append(' */')
406 .Append('Object _jsObject;') 452 .Append('Object _jsObject;')
407 ) 453 )
408 454
409 # Add events. 455 # Add events.
410 if self._namespace.events: 456 if self._namespace.events:
411 (c.Append() 457 (c.Append()
412 .Append('/*') 458 .Append('/*')
413 .Append(' * Events') 459 .Append(' * Events')
414 .Append(' */') 460 .Append(' */')
415 ) 461 )
416 for event_name in self._namespace.events: 462 for event_name in self._namespace.events:
417 c.Append('Event_%s_%s %s;' % (self._namespace.unix_name, event_name, 463 c.Append('Event_%s_%s %s;' % (self._namespace.unix_name, event_name,
418 event_name)) 464 event_name))
419 465
420 # Add functions. 466 # Add functions.
421 if self._namespace.functions: 467 if self._namespace.functions:
422 (c.Append() 468 (c.Append()
423 .Append('/*') 469 .Append('/*')
424 .Append(' * Functions') 470 .Append(' * Functions')
425 .Append(' */') 471 .Append(' */')
426 ) 472 )
427 for function in self._namespace.functions.values(): 473 for function in self._namespace.functions.values():
428 c.Concat(self._GenerateFunction(function)) 474 # Check for custom dart for this whole property.
475 override = self._GetOverride([function.name], document_with=function)
476 c.Cblock(override if override is not None
477 else self._GenerateFunction(function))
429 478
430 # Add the constructor. 479 # Add the constructor.
431 (c.Append() 480 c.Sblock('API_%s(this._jsObject) {' % self._namespace.unix_name)
432 .Sblock('API_%s(this._jsObject) {' % self._namespace.unix_name)
433 )
434 481
435 # Add events to constructor. 482 # Add events to constructor.
436 for event_name in self._namespace.events: 483 for event_name in self._namespace.events:
437 c.Append("%s = new Event_%s_%s(JS('', '#.%s', this._jsObject));" % 484 c.Append("%s = new Event_%s_%s(JS('', '#.%s', this._jsObject));" %
438 (event_name, self._namespace.unix_name, event_name, event_name)) 485 (event_name, self._namespace.unix_name, event_name, event_name))
439 486
440 (c.Eblock('}') 487 (c.Eblock('}')
441 .Eblock('}') 488 .Eblock('}')
442 ) 489 )
443 return c 490 return c
444 491
445 def _GeneratePropertySignature(self, prop): 492 def _GeneratePropertySignature(self, prop):
446 """Given a property, returns a signature for that property. 493 """Given a property, returns a signature for that property.
447 Recursively generates the signature for callbacks. 494 Recursively generates the signature for callbacks.
448 Returns a String for the given property. 495 Returns a String for the given property.
449 496
450 e.g. 497 e.g.
451 bool x 498 bool x
452 void onClosed() 499 void onClosed()
453 void doSomething(bool x, void callback([String x])) 500 void doSomething(bool x, void callback([String x]))
454 """ 501 """
455 if self._IsFunction(prop.type_): 502 if self._IsFunction(prop.type_):
456 return self._GenerateFunctionSignature(prop.type_.function) 503 return self._GenerateFunctionSignature(prop.type_.function)
457 return '%(type)s %(name)s' % { 504 return '%(type)s %(name)s' % {
458 'type': self._GetDartType(prop.type_), 505 'type': self._GetDartType(prop.type_),
459 'name': prop.simple_name 506 'name': prop.simple_name
460 } 507 }
461 508
462 def _GenerateFunctionSignature(self, function): 509 def _GenerateFunctionSignature(self, function, convert_optional=False):
463 """Given a function object, returns the signature for that function. 510 """Given a function object, returns the signature for that function.
464 Recursively generates the signature for callbacks. 511 Recursively generates the signature for callbacks.
465 Returns a String for the given function. 512 Returns a String for the given function.
466 513
467 If prepend_this is True, adds "this." to the function's name. 514 If convert_optional is True, changes optional parameters to be required.
468 515
469 e.g. 516 e.g.
470 void onClosed() 517 void onClosed()
471 bool isOpen([String type]) 518 bool isOpen([String type])
472 void doSomething(bool x, void callback([String x])) 519 void doSomething(bool x, void callback([String x]))
473
474 e.g. If prepend_this is True:
475 void this.onClosed()
476 bool this.isOpen([String type])
477 void this.doSomething(bool x, void callback([String x]))
478 """ 520 """
479 sig = '%(return_type)s %(name)s(%(params)s)' 521 sig = '%(return_type)s %(name)s(%(params)s)'
480 522
481 if function.returns: 523 if function.returns:
482 return_type = self._GetDartType(function.returns) 524 return_type = self._GetDartType(function.returns)
483 else: 525 else:
484 return_type = 'void' 526 return_type = 'void'
485 527
486 return sig % { 528 return sig % {
487 'return_type': return_type, 529 'return_type': return_type,
488 'name': function.simple_name, 530 'name': function.simple_name,
489 'params': self._GenerateParameterList(function.params, 531 'params': self._GenerateParameterList(function.params,
490 function.callback) 532 function.callback,
533 convert_optional=convert_optional)
491 } 534 }
492 535
493 def _GenerateParameterList(self, 536 def _GenerateParameterList(self,
494 params, 537 params,
495 callback=None, 538 callback=None,
496 convert_optional=False): 539 convert_optional=False):
497 """Given a list of function parameters, generates their signature (as a 540 """Given a list of function parameters, generates their signature (as a
498 string). 541 string).
499 542
500 e.g. 543 e.g.
(...skipping 10 matching lines...) Expand all
511 params_opt = [] 554 params_opt = []
512 for param in params: 555 for param in params:
513 p_sig = self._GeneratePropertySignature(param) 556 p_sig = self._GeneratePropertySignature(param)
514 if param.optional and not convert_optional: 557 if param.optional and not convert_optional:
515 params_opt.append(p_sig) 558 params_opt.append(p_sig)
516 else: 559 else:
517 params_req.append(p_sig) 560 params_req.append(p_sig)
518 561
519 # Add the callback, if it exists. 562 # Add the callback, if it exists.
520 if callback: 563 if callback:
521 c_sig = self._GenerateFunctionSignature(callback) 564 c_sig = self._GenerateFunctionSignature(callback, convert_optional=True)
522 if callback.optional: 565 if callback.optional:
523 params_opt.append(c_sig) 566 params_opt.append(c_sig)
524 else: 567 else:
525 params_req.append(c_sig) 568 params_req.append(c_sig)
526 569
527 # Join the parameters with commas. 570 # Join the parameters with commas.
528 # Optional parameters have to be in square brackets, e.g.: 571 # Optional parameters have to be in square brackets, e.g.:
529 # 572 #
530 # required params | optional params | output 573 # required params | optional params | output
531 # [] | [] | '' 574 # [] | [] | ''
532 # [x, y] | [] | 'x, y' 575 # [x, y] | [] | 'x, y'
533 # [] | [a, b] | '[a, b]' 576 # [] | [a, b] | '[a, b]'
534 # [x, y] | [a, b] | 'x, y, [a, b]' 577 # [x, y] | [a, b] | 'x, y, [a, b]'
535 if params_opt: 578 if params_opt:
536 params_opt[0] = '[%s' % params_opt[0] 579 params_opt[0] = '[%s' % params_opt[0]
537 params_opt[-1] = '%s]' % params_opt[-1] 580 params_opt[-1] = '%s]' % params_opt[-1]
538 param_sets = [', '.join(params_req), ', '.join(params_opt)] 581 param_sets = [', '.join(params_req), ', '.join(params_opt)]
539 582
540 # The 'if p' part here is needed to prevent commas where there are no 583 # The 'if p' part here is needed to prevent commas where there are no
541 # parameters of a certain type. 584 # parameters of a certain type.
542 # If there are no optional parameters, this prevents a _trailing_ comma, 585 # If there are no optional parameters, this prevents a _trailing_ comma,
543 # e.g. '(x, y,)'. Similarly, if there are no required parameters, this 586 # e.g. '(x, y,)'. Similarly, if there are no required parameters, this
544 # prevents a leading comma, e.g. '(, [a, b])'. 587 # prevents a leading comma, e.g. '(, [a, b])'.
545 return ', '.join(p for p in param_sets if p) 588 return ', '.join(p for p in param_sets if p)
546 589
547 def _ConcatOverride(self, c, type_, prop, key_suffix='', add_doc=False): 590 def _GetOverride(self, key_chain, document_with=None):
548 """Given a particular type and property to find in the custom dart 591 """Given a list of keys, joins them with periods and searches for them in
549 overrides, checks whether there is an override for that key. 592 the custom dart overrides.
550 If there is, appends the override code, and returns True. 593 If there is an override for that key, finds the override code and returns
551 If not, returns False. 594 the Code object. If not, returns None.
552 595
553 |key_suffix| will be added to the end of the key before searching, e.g. 596 If document_with is not None, adds the documentation for this property
554 '.set' or '.get' can be used for setters and getters respectively. 597 before the override code.
598 """
599 c = Code()
600 contents = self._type_overrides.get('.'.join(key_chain))
601 if contents is None:
602 return None
555 603
556 If add_doc is given, adds the documentation for this property before the 604 if document_with is not None:
557 override code. 605 c.Concat(self._GenerateDocumentation(document_with))
606 for line in contents.strip('\n').split('\n'):
607 c.Append(line)
608 return c
609
610 def _AddPrefix(self, name):
611 """Given the name of a type, prefixes the namespace (as camelcase) and
612 return the new name.
558 """ 613 """
559 contents = self._type_overrides.get('%s.%s%s' % (type_.name, prop.name, 614 # TODO(sashab): Split the dart library into multiple files, avoiding the
560 key_suffix)) 615 # need for this prefixing.
561 if contents is None: 616 return ('%s%s' % (
562 return False 617 ''.join(s.capitalize() for s in self._namespace.name.split('.')),
563 618 name))
564 if prop is not None:
565 c.Concat(self._GenerateDocumentation(prop))
566 for line in contents.split('\n'):
567 c.Append(line)
568 return True
569 619
570 def _IsFunction(self, type_): 620 def _IsFunction(self, type_):
571 """Given a model.Type, returns whether this type is a function. 621 """Given a model.Type, returns whether this type is a function.
572 """ 622 """
573 return type_.property_type == PropertyType.FUNCTION 623 return type_.property_type == PropertyType.FUNCTION
574 624
575 def _IsSerializableObjectType(self, type_): 625 def _IsSerializableObjectType(self, type_):
576 """Given a model.Type, returns whether this type is a serializable object. 626 """Given a model.Type, returns whether this type is a serializable object.
577 Serializable objects are custom types defined in this namespace. 627 Serializable objects are custom types defined in this namespace.
628
629 If this object is a reference to something not in this namespace, assumes
630 its a serializable object.
578 """ 631 """
579 if (type_.property_type == PropertyType.REF 632 if type_.property_type is PropertyType.CHOICES:
580 and type_.ref_type in self._types): 633 return all(self._IsSerializableObjectType(c) for c in type_.choices)
581 return self._IsObjectType(self._types[type_.ref_type]) 634 if type_.property_type is PropertyType.REF:
635 if type_.ref_type in self._types:
636 return self._IsObjectType(self._types[type_.ref_type])
637 return True
582 if (type_.property_type == PropertyType.OBJECT 638 if (type_.property_type == PropertyType.OBJECT
583 and type_.instance_of in self._types): 639 and type_.instance_of in self._types):
584 return self._IsObjectType(self._types[type_.instance_of]) 640 return self._IsObjectType(self._types[type_.instance_of])
585 return False 641 return False
586 642
587 def _IsObjectType(self, type_): 643 def _IsObjectType(self, type_):
588 """Given a model.Type, returns whether this type is an object. 644 """Given a model.Type, returns whether this type is an object.
589 """ 645 """
590 return (self._IsSerializableObjectType(type_) 646 return (self._IsSerializableObjectType(type_)
591 or type_.property_type in [PropertyType.OBJECT, PropertyType.ANY]) 647 or type_.property_type in [PropertyType.OBJECT, PropertyType.ANY])
592 648
593 def _IsListOfSerializableObjects(self, type_): 649 def _IsListOfSerializableObjects(self, type_):
594 """Given a model.Type, returns whether this type is a list of serializable 650 """Given a model.Type, returns whether this type is a list of serializable
595 objects (PropertyType.REF types). 651 objects (or regular objects, if this list is treated as a type - in this
652 case, the item type was defined inline).
653
654 If this type is a reference to something not in this namespace, assumes
655 it is not a list of serializable objects.
596 """ 656 """
657 if type_.property_type is PropertyType.CHOICES:
658 return all(self._IsListOfSerializableObjects(c) for c in type_.choices)
659 if type_.property_type is PropertyType.REF:
660 if type_.ref_type in self._types:
661 return self._IsListOfSerializableObjects(self._types[type_.ref_type])
662 return False
597 return (type_.property_type is PropertyType.ARRAY and 663 return (type_.property_type is PropertyType.ARRAY and
598 type_.item_type.property_type is PropertyType.REF) 664 (self._IsSerializableObjectType(type_.item_type)))
599 665
600 def _IsListOfBaseTypes(self, type_): 666 def _IsListOfBaseTypes(self, type_):
601 """Given a model.Type, returns whether this type is a list of base type 667 """Given a model.Type, returns whether this type is a list of base type
602 objects (PropertyType.REF types). 668 objects (PropertyType.REF types).
603 """ 669 """
670 if type_.property_type is PropertyType.CHOICES:
671 return all(self._IsListOfBaseTypes(c) for c in type_.choices)
604 return (type_.property_type is PropertyType.ARRAY and 672 return (type_.property_type is PropertyType.ARRAY and
605 self._IsBaseType(type_.item_type)) 673 self._IsBaseType(type_.item_type))
606 674
607 def _IsBaseType(self, type_): 675 def _IsBaseType(self, type_):
608 """Given a model.type_, returns whether this type is a base type 676 """Given a model.type_, returns whether this type is a base type
609 (string, number or boolean). 677 (string, number, boolean, or a list of these).
678
679 If type_ is a Choices object, returns True if all possible choices are base
680 types.
610 """ 681 """
611 return (self._GetDartType(type_) in 682 # TODO(sashab): Remove 'Choices' as a base type once they are wrapped in
612 ['bool', 'num', 'int', 'double', 'String']) 683 # native Dart classes.
684 if type_.property_type is PropertyType.CHOICES:
685 return all(self._IsBaseType(c) for c in type_.choices)
686 return (
687 (self._GetDartType(type_) in ['bool', 'num', 'int', 'double', 'String'])
688 or (type_.property_type is PropertyType.ARRAY
689 and self._IsBaseType(type_.item_type))
690 )
613 691
614 def _GetDartType(self, type_): 692 def _GetDartType(self, type_):
615 """Given a model.Type object, returns its type as a Dart string. 693 """Given a model.Type object, returns its type as a Dart string.
616 """ 694 """
617 if type_ is None: 695 if type_ is None:
618 return 'void' 696 return 'void'
619 697
620 prop_type = type_.property_type 698 prop_type = type_.property_type
621 if prop_type is PropertyType.REF: 699 if prop_type is PropertyType.REF:
700 if type_.ref_type in self._types:
701 return self._GetDartType(self._types[type_.ref_type])
622 # TODO(sashab): If the type is foreign, it might have to be imported. 702 # TODO(sashab): If the type is foreign, it might have to be imported.
623 return StripNamespace(type_.ref_type) 703 return StripNamespace(type_.ref_type)
624 elif prop_type is PropertyType.BOOLEAN: 704 elif prop_type is PropertyType.BOOLEAN:
625 return 'bool' 705 return 'bool'
626 elif prop_type is PropertyType.INTEGER: 706 elif prop_type is PropertyType.INTEGER:
627 return 'int' 707 return 'int'
628 elif prop_type is PropertyType.INT64: 708 elif prop_type is PropertyType.INT64:
629 return 'num' 709 return 'num'
630 elif prop_type is PropertyType.DOUBLE: 710 elif prop_type is PropertyType.DOUBLE:
631 return 'double' 711 return 'double'
632 elif prop_type is PropertyType.STRING: 712 elif prop_type is PropertyType.STRING:
633 return 'String' 713 return 'String'
634 elif prop_type is PropertyType.ENUM: 714 elif prop_type is PropertyType.ENUM:
635 return 'String' 715 return 'String'
636 elif prop_type is PropertyType.CHOICES: 716 elif prop_type is PropertyType.CHOICES:
637 # TODO: What is a Choices type? Is it closer to a Map Dart object? 717 # TODO(sashab): Think of a nice way to generate code for Choices objects
718 # in Dart.
638 return 'Object' 719 return 'Object'
639 elif prop_type is PropertyType.ANY: 720 elif prop_type is PropertyType.ANY:
640 return 'Object' 721 return 'Object'
641 elif prop_type is PropertyType.OBJECT: 722 elif prop_type is PropertyType.OBJECT:
642 return type_.instance_of or 'Object' 723 # TODO(sashab): type_.name is the name of the function's parameter for
724 # inline types defined in functions. Think of a way to generate names
725 # for this, or remove all inline type definitions at the start.
726 if type_.instance_of is not None:
727 return type_.instance_of
728 if not isinstance(type_.parent, Function):
729 return self._AddPrefix(type_.name)
730 return 'Object'
643 elif prop_type is PropertyType.FUNCTION: 731 elif prop_type is PropertyType.FUNCTION:
644 return 'Function' 732 return 'Function'
645 elif prop_type is PropertyType.ARRAY: 733 elif prop_type is PropertyType.ARRAY:
646 return 'List<%s>' % self._GetDartType(type_.item_type) 734 return 'List<%s>' % self._GetDartType(type_.item_type)
647 elif prop_type is PropertyType.BINARY: 735 elif prop_type is PropertyType.BINARY:
648 return 'String' 736 return 'String'
649 else: 737 else:
650 raise NotImplementedError(prop_type) 738 raise NotImplementedError(prop_type)
651 739
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698