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

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: 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 *
(...skipping 13 matching lines...) Expand all
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 self._types = namespace.types 34 self._types = namespace.types
not at google - send to devlin 2013/02/07 01:16:41 I didn't notice that you added this alias... it do
35 35
36 # Build a dictionary of Type Name --> Custom Dart code. 36 # Build a dictionary of Type Name --> Custom Dart code.
37 self._type_overrides = {} 37 self._type_overrides = {}
38 if dart_overrides_dir is not None: 38 if dart_overrides_dir is not None:
39 for filename in os.listdir(dart_overrides_dir): 39 for filename in os.listdir(dart_overrides_dir):
40 if filename.startswith(namespace.unix_name): 40 if filename.startswith(namespace.unix_name):
41 with open(os.path.join(dart_overrides_dir, filename)) as f: 41 with open(os.path.join(dart_overrides_dir, filename)) as f:
42 # Split off the namespace and file extension, leaving just the type. 42 # Split off the namespace and file extension, leaving just the type.
43 type_path = '.'.join(filename.split('.')[1:-1]) 43 type_path = '.'.join(filename.split('.')[1:-1])
44 self._type_overrides[type_path] = f.read() 44 self._type_overrides[type_path] = f.read()
45 45
46 # TODO(sashab): Add all inline type definitions to the global Types
47 # dictionary.
48 # List types do not apply - their types are automatically generated instead
49 # of the list type.
50
46 def Generate(self): 51 def Generate(self):
47 """Generates a Code object with the .dart for the entire namespace. 52 """Generates a Code object with the .dart for the entire namespace.
48 """ 53 """
49 c = Code() 54 c = Code()
50 (c.Append(LICENSE) 55 (c.Append(LICENSE.strip())
not at google - send to devlin 2013/02/07 01:16:41 Why strip()? P.S. you could make LICENCE a Code()
sashab 2013/02/08 01:53:34 The problem is getting the LICENSE (and the triple
56 .Append()
51 .Append('// Generated from namespace: %s' % self._namespace.name) 57 .Append('// Generated from namespace: %s' % self._namespace.name)
52 .Append() 58 .Append()
53 .Append('part of chrome;')) 59 .Append('part of chrome;'))
54 60
55 if self._types: 61 if self._types:
56 (c.Append() 62 (c.Append()
57 .Append('/**') 63 .Append('/**')
58 .Append(' * Types') 64 .Append(' * Types')
59 .Append(' */') 65 .Append(' */')
60 ) 66 )
61 for type_name in self._types: 67 for type_ in self._types.values():
62 c.Concat(self._GenerateType(self._types[type_name])) 68 # Check for custom dart for this whole type.
69 c.Append()
70 if not self._ConcatOverride(c, [type_.name], doc_property=type_):
not at google - send to devlin 2013/02/07 01:16:41 Without looking at the implementation of ConcatOve
sashab 2013/02/08 01:53:34 This is pretty much what I wanted to do before. No
71 c.Concat(self._GenerateType(type_))
not at google - send to devlin 2013/02/07 01:16:41 I suggest using Cblock() here rather than the c.Ap
sashab 2013/02/08 01:53:34 Don't think I need a blank line between /** Types
63 72
64 if self._namespace.events: 73 if self._namespace.events:
65 (c.Append() 74 (c.Append()
66 .Append('/**') 75 .Append('/**')
67 .Append(' * Events') 76 .Append(' * Events')
68 .Append(' */') 77 .Append(' */')
69 ) 78 )
70 for event_name in self._namespace.events: 79 for event_name in self._namespace.events:
71 c.Concat(self._GenerateEvent(self._namespace.events[event_name])) 80 c.Concat(self._GenerateEvent(self._namespace.events[event_name]))
72 81
73 (c.Append() 82 (c.Append()
74 .Append('/**') 83 .Append('/**')
75 .Append(' * Functions') 84 .Append(' * Functions')
76 .Append(' */') 85 .Append(' */')
77 ) 86 )
78 c.Concat(self._GenerateMainClass()) 87 c.Concat(self._GenerateMainClass())
79 88
80 return c 89 return c
81 90
82 def _GenerateType(self, type_): 91 def _GenerateType(self, type_):
83 """Given a Type object, returns the Code with the .dart for this 92 """Given a Type object, returns the Code with the .dart for this
84 type's definition. 93 type's definition.
85 94
86 Assumes this type is a Parameter Type (creatable by user), and creates an 95 Assumes this type is a Parameter Type (creatable by user), and creates an
87 object that extends ChromeObject. All parameters are specifiable as named 96 object that extends ChromeObject. All parameters are specifiable as named
88 arguments in the constructor, and all methods are wrapped with getters and 97 arguments in the constructor, and all methods are wrapped with getters and
89 setters that hide the JS() implementation. 98 setters that hide the JS() implementation.
99
100 List objects with inline types are created with a definition for the inline
101 type instead.
90 """ 102 """
103 if type_.property_type is PropertyType.ARRAY:
104 # This is an inline type definition: generate that type instead.
105 type_ = type_.item_type
106 # Save this to global types, just so future functions don't get confused.
107 self._types[type_.name] = type_
not at google - send to devlin 2013/02/07 01:16:41 This modifies the original model (since types_ is
sashab 2013/02/08 01:53:34 A little complicated... Basically for objects that
108
91 c = Code() 109 c = Code()
92 (c.Append() 110 (c.Concat(self._GenerateDocumentation(type_))
93 .Concat(self._GenerateDocumentation(type_))
94 .Sblock('class %(type_name)s extends ChromeObject {') 111 .Sblock('class %(type_name)s extends ChromeObject {')
95 ) 112 )
96 113
97 # Check whether this type has function members. If it does, don't allow 114 # Check whether this type has function members. If it does, don't allow
98 # public construction. 115 # public construction.
99 add_public_constructor = all(not self._IsFunction(p.type_) 116 add_public_constructor = all(not self._IsFunction(p.type_)
100 for p in type_.properties.values()) 117 for p in type_.properties.values())
101 constructor_fields = [self._GeneratePropertySignature(p) 118 constructor_fields = [self._GeneratePropertySignature(p)
102 for p in type_.properties.values()] 119 for p in type_.properties.values()]
103 120
(...skipping 23 matching lines...) Expand all
127 (c.Append() 144 (c.Append()
128 .Append('/*') 145 .Append('/*')
129 .Append(' * Public accessors') 146 .Append(' * Public accessors')
130 .Append(' */') 147 .Append(' */')
131 ) 148 )
132 for prop in properties: 149 for prop in properties:
133 type_name = self._GetDartType(prop.type_) 150 type_name = self._GetDartType(prop.type_)
134 151
135 # Check for custom dart for this whole property. 152 # Check for custom dart for this whole property.
136 c.Append() 153 c.Append()
137 if not self._ConcatOverride(c, type_, prop, add_doc=True): 154 if not self._ConcatOverride(c, [type_.name, prop.name],
155 doc_property=prop):
138 # Add the getter. 156 # Add the getter.
139 if not self._ConcatOverride(c, type_, prop, key_suffix='.get', 157 if not self._ConcatOverride(c, [type_.name, prop.name, '.get'],
140 add_doc=True): 158 doc_property=prop):
141 # Add the documentation for this property. 159 # Add the documentation for this property.
142 c.Concat(self._GenerateDocumentation(prop)) 160 c.Concat(self._GenerateDocumentation(prop))
143 161
144 if (self._IsBaseType(prop.type_) 162 if (self._IsBaseType(prop.type_, list_as_base=True)):
145 or self._IsListOfBaseTypes(prop.type_)):
146 c.Append("%s get %s => JS('%s', '#.%s', this._jsObject);" % 163 c.Append("%s get %s => JS('%s', '#.%s', this._jsObject);" %
147 (type_name, prop.name, type_name, prop.name)) 164 (type_name, prop.name, type_name, prop.name))
148 elif self._IsSerializableObjectType(prop.type_): 165 elif self._IsSerializableObjectType(prop.type_):
149 c.Append("%s get %s => new %s._proxy(JS('', '#.%s', " 166 c.Append("%s get %s => new %s._proxy(JS('', '#.%s', "
150 "this._jsObject));" 167 "this._jsObject));"
151 % (type_name, prop.name, type_name, prop.name)) 168 % (type_name, prop.name, type_name, prop.name))
152 elif self._IsListOfSerializableObjects(prop.type_): 169 elif self._IsListOfSerializableObjects(prop.type_):
153 (c.Sblock('%s get %s {' % (type_name, prop.name)) 170 array_type, array_type_name = prop.type_, type_name
154 .Append('%s __proxy_%s = new %s();' % (type_name, prop.name, 171 if prop.type_.property_type is not PropertyType.ARRAY:
155 type_name)) 172 # This is a reference to an array object, not the object itself.
173 array_type = self._types[prop.type_.ref_type]
not at google - send to devlin 2013/02/07 01:16:41 I think you should re-use CppTypeGenerator rather
sashab 2013/02/08 01:53:34 May no longer be needed; temporarily removed.
174 array_type_name =self._GetDartType(array_type)
175 (c.Sblock('%s get %s {' % (array_type_name, prop.name))
176 .Append('%s __proxy_%s = new %s();' % (array_type_name, prop.name,
177 array_type_name))
156 .Sblock("for (var o in JS('List', '#.%s', this._jsObject)) {" % 178 .Sblock("for (var o in JS('List', '#.%s', this._jsObject)) {" %
157 prop.name) 179 prop.name)
158 .Append('__proxy_%s.add(new %s._proxy(o));' % (prop.name, 180 .Append('__proxy_%s.add(new %s._proxy(o));' % (prop.name,
159 self._GetDartType(prop.type_.item_type))) 181 self._GetDartType(array_type.item_type)))
160 .Eblock('}') 182 .Eblock('}')
161 .Append('return __proxy_%s;' % prop.name) 183 .Append('return __proxy_%s;' % prop.name)
162 .Eblock('}') 184 .Eblock('}')
163 ) 185 )
164 elif self._IsObjectType(prop.type_): 186 elif self._IsObjectType(prop.type_):
165 # TODO(sashab): Think of a way to serialize generic Dart objects. 187 # TODO(sashab): Think of a way to serialize generic Dart objects.
166 c.Append("%s get %s => JS('%s', '#.%s', this._jsObject);" % 188 c.Append("%s get %s => JS('%s', '#.%s', this._jsObject);" %
167 (type_name, prop.name, type_name, prop.name)) 189 (type_name, prop.name, type_name, prop.name))
168 else: 190 else:
169 raise Exception( 191 raise Exception(
170 "Could not generate wrapper for %s.%s: unserializable type %s" % 192 "Could not generate wrapper for %s.%s: unserializable type %s" %
171 (type_.name, prop.name, type_name) 193 (type_.name, prop.name, type_name)
172 ) 194 )
173 195
174 # Add the setter. 196 # Add the setter.
175 c.Append() 197 c.Append()
176 if not self._ConcatOverride(c, type_, prop, key_suffix='.set'): 198 if not self._ConcatOverride(c, [type_.name, prop.name, '.set']):
177 wrapped_name = prop.name 199 wrapped_name = prop.name
178 if not self._IsBaseType(prop.type_): 200 if not self._IsBaseType(prop.type_):
179 wrapped_name = 'convertArgument(%s)' % prop.name 201 wrapped_name = 'convertArgument(%s)' % prop.name
180 202
181 (c.Sblock("void set %s(%s %s) {" % (prop.name, type_name, prop.name)) 203 (c.Sblock("void set %s(%s %s) {" % (prop.name, type_name, prop.name))
182 .Append("JS('void', '#.%s = #', this._jsObject, %s);" % 204 .Append("JS('void', '#.%s = #', this._jsObject, %s);" %
183 (prop.name, wrapped_name)) 205 (prop.name, wrapped_name))
184 .Eblock("}") 206 .Eblock("}")
185 ) 207 )
186 208
187 # Now add all the methods. 209 # Now add all the methods.
188 methods = [t for t in type_.properties.values() 210 methods = [t for t in type_.properties.values()
189 if self._IsFunction(t.type_)] 211 if self._IsFunction(t.type_)]
190 if methods: 212 if methods:
191 (c.Append() 213 (c.Append()
192 .Append('/*') 214 .Append('/*')
193 .Append(' * Methods') 215 .Append(' * Methods')
194 .Append(' */') 216 .Append(' */')
195 ) 217 )
196 for prop in methods: 218 for prop in methods:
197 c.Concat(self._GenerateFunction(prop.type_.function)) 219 # Check if there's an override for this method.
220 if not self._ConcatOverride(c, [type_.name, prop.name],
221 doc_property=prop):
222 c.Concat(self._GenerateFunction(prop.type_.function))
198 223
199 (c.Eblock('}') 224 (c.Eblock('}')
200 .Substitute({ 225 .Substitute({
201 'type_name': type_.simple_name, 226 'type_name': type_.simple_name,
202 'constructor_fields': ', '.join(constructor_fields) 227 'constructor_fields': ', '.join(constructor_fields)
203 }) 228 })
204 ) 229 )
205 230
206 return c 231 return c
207 232
208 def _GenerateDocumentation(self, prop): 233 def _GenerateDocumentation(self, prop):
209 """Given an object, generates the documentation for this object (as a 234 """Given an object, generates the documentation for this object (as a
210 code string) and returns the Code object. 235 code string) and returns the Code object.
211 236
212 Returns an empty code object if the object has no documentation. 237 Returns an empty code object if the object has no documentation.
213 238
214 Uses triple-quotes for the string. 239 Uses triple-quotes for the string.
215 """ 240 """
216 c = Code() 241 c = Code()
217 if prop.description is not None: 242 if prop.description is not None:
218 for line in prop.description.split('\n'): 243 for line in prop.description.split('\n'):
219 c.Comment(line, comment_prefix='/// ') 244 c.Comment(line, comment_prefix='/// ')
220 return c 245 return c
221 246
222 def _GenerateFunction(self, f): 247 def _GenerateFunction(self, f):
223 """Returns the Code object for the given function. 248 """Returns the Code object for the given function.
224 """ 249 """
225 c = Code() 250 c = Code()
226 (c.Append() 251 c.Concat(self._GenerateDocumentation(f))
227 .Concat(self._GenerateDocumentation(f))
228 )
229 252
230 if not self._NeedsProxiedCallback(f): 253 if not self._NeedsProxiedCallback(f):
231 c.Append("%s => %s;" % (self._GenerateFunctionSignature(f), 254 c.Append("%s => %s;" % (self._GenerateFunctionSignature(f),
232 self._GenerateProxyCall(f))) 255 self._GenerateProxyCall(f)))
233 return c 256 return c
234 257
235 (c.Sblock("%s {" % self._GenerateFunctionSignature(f)) 258 (c.Sblock("%s {" % self._GenerateFunctionSignature(f))
236 .Concat(self._GenerateProxiedFunction(f.callback, f.callback.name)) 259 .Concat(self._GenerateProxiedFunction(f.callback, f.callback.name))
237 .Append('%s;' % self._GenerateProxyCall(f)) 260 .Append('%s;' % self._GenerateProxyCall(f))
238 .Eblock('}') 261 .Eblock('}')
239 ) 262 )
240 263
241 return c 264 return c
242 265
243 def _GenerateProxiedFunction(self, f, callback_name): 266 def _GenerateProxiedFunction(self, f, callback_name):
244 """Given a function (assumed to be a callback), generates the proxied 267 """Given a function (assumed to be a callback), generates the proxied
245 version of this function, which calls |callback_name| if it is defined. 268 version of this function, which calls |callback_name| if it is defined.
246 269
247 Returns a Code object. 270 Returns a Code object.
248 """ 271 """
249 c = Code() 272 c = Code()
250 proxied_params = [] 273 proxied_params = []
251 # A list of Properties, containing List<*> objects that need proxying for 274 # A list of Properties, containing List<*> objects that need proxying for
252 # their members (by copying out each member and proxying it). 275 # their members (by copying out each member and proxying it).
253 lists_to_proxy = [] 276 lists_to_proxy = []
254 for p in f.params: 277 for p in f.params:
255 if self._IsBaseType(p.type_) or self._IsListOfBaseTypes(p.type_): 278 if self._IsBaseType(p.type_, list_as_base=True):
256 proxied_params.append(p.name) 279 proxied_params.append(p.name)
257 elif self._IsSerializableObjectType(p.type_): 280 elif self._IsSerializableObjectType(p.type_):
258 proxied_params.append('new %s._proxy(%s)' % ( 281 proxied_params.append('new %s._proxy(%s)' % (
259 self._GetDartType(p.type_), p.name)) 282 self._GetDartType(p.type_), p.name))
260 elif self._IsListOfSerializableObjects(p.type_): 283 elif self._IsListOfSerializableObjects(p.type_):
261 proxied_params.append('__proxy_%s' % p.name) 284 proxied_params.append('__proxy_%s' % p.name)
262 lists_to_proxy.append(p) 285 lists_to_proxy.append(p)
263 elif self._IsObjectType(p.type_): 286 elif self._IsObjectType(p.type_):
264 # TODO(sashab): Find a way to build generic JS objects back in Dart. 287 # TODO(sashab): Find a way to build generic JS objects back in Dart.
265 proxied_params.append('%s' % p.name) 288 proxied_params.append('%s' % p.name)
289 elif p.type_.property_type is PropertyType.ARRAY:
290 # TODO(sashab): This might be okay - what if this is a list of
291 # FileEntry elements? In this case, a basic list will proxy the objects
292 # fine.
293 proxied_params.append('%s' % p.name)
266 else: 294 else:
267 raise Exception( 295 raise Exception(
268 "Cannot automatically create proxy; can't wrap %s, type %s" % ( 296 "Cannot automatically create proxy; can't wrap %s, type %s" % (
269 self._GenerateFunctionSignature(f), self._GetDartType(p.type_))) 297 self._GenerateFunctionSignature(f), self._GetDartType(p.type_)))
270 298
271 (c.Sblock("void __proxy_callback(%s) {" % ', '.join(p.name for p in 299 (c.Sblock("void __proxy_callback(%s) {" % ', '.join(p.name for p in
272 f.params)) 300 f.params))
273 .Sblock('if (?%s) {' % callback_name) 301 .Sblock('if (?%s) {' % callback_name)
274 ) 302 )
275 303
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
418 event_name)) 446 event_name))
419 447
420 # Add functions. 448 # Add functions.
421 if self._namespace.functions: 449 if self._namespace.functions:
422 (c.Append() 450 (c.Append()
423 .Append('/*') 451 .Append('/*')
424 .Append(' * Functions') 452 .Append(' * Functions')
425 .Append(' */') 453 .Append(' */')
426 ) 454 )
427 for function in self._namespace.functions.values(): 455 for function in self._namespace.functions.values():
428 c.Concat(self._GenerateFunction(function)) 456 # Check for custom dart for this whole property.
457 c.Append()
458 if not self._ConcatOverride(c, [function.name], doc_property=function):
459 c.Concat(self._GenerateFunction(function))
429 460
430 # Add the constructor. 461 # Add the constructor.
431 (c.Append() 462 (c.Append()
432 .Sblock('API_%s(this._jsObject) {' % self._namespace.unix_name) 463 .Sblock('API_%s(this._jsObject) {' % self._namespace.unix_name)
433 ) 464 )
434 465
435 # Add events to constructor. 466 # Add events to constructor.
436 for event_name in self._namespace.events: 467 for event_name in self._namespace.events:
437 c.Append("%s = new Event_%s_%s(JS('', '#.%s', this._jsObject));" % 468 c.Append("%s = new Event_%s_%s(JS('', '#.%s', this._jsObject));" %
438 (event_name, self._namespace.unix_name, event_name, event_name)) 469 (event_name, self._namespace.unix_name, event_name, event_name))
(...skipping 13 matching lines...) Expand all
452 void onClosed() 483 void onClosed()
453 void doSomething(bool x, void callback([String x])) 484 void doSomething(bool x, void callback([String x]))
454 """ 485 """
455 if self._IsFunction(prop.type_): 486 if self._IsFunction(prop.type_):
456 return self._GenerateFunctionSignature(prop.type_.function) 487 return self._GenerateFunctionSignature(prop.type_.function)
457 return '%(type)s %(name)s' % { 488 return '%(type)s %(name)s' % {
458 'type': self._GetDartType(prop.type_), 489 'type': self._GetDartType(prop.type_),
459 'name': prop.simple_name 490 'name': prop.simple_name
460 } 491 }
461 492
462 def _GenerateFunctionSignature(self, function): 493 def _GenerateFunctionSignature(self, function, convert_optional=False):
463 """Given a function object, returns the signature for that function. 494 """Given a function object, returns the signature for that function.
464 Recursively generates the signature for callbacks. 495 Recursively generates the signature for callbacks.
465 Returns a String for the given function. 496 Returns a String for the given function.
466 497
467 If prepend_this is True, adds "this." to the function's name. 498 If convert_optional is True, changes optional parameters to be required.
468 499
469 e.g. 500 e.g.
470 void onClosed() 501 void onClosed()
471 bool isOpen([String type]) 502 bool isOpen([String type])
472 void doSomething(bool x, void callback([String x])) 503 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 """ 504 """
479 sig = '%(return_type)s %(name)s(%(params)s)' 505 sig = '%(return_type)s %(name)s(%(params)s)'
480 506
481 if function.returns: 507 if function.returns:
482 return_type = self._GetDartType(function.returns) 508 return_type = self._GetDartType(function.returns)
483 else: 509 else:
484 return_type = 'void' 510 return_type = 'void'
485 511
486 return sig % { 512 return sig % {
487 'return_type': return_type, 513 'return_type': return_type,
488 'name': function.simple_name, 514 'name': function.simple_name,
489 'params': self._GenerateParameterList(function.params, 515 'params': self._GenerateParameterList(function.params,
490 function.callback) 516 function.callback,
517 convert_optional=convert_optional)
491 } 518 }
492 519
493 def _GenerateParameterList(self, 520 def _GenerateParameterList(self,
494 params, 521 params,
495 callback=None, 522 callback=None,
496 convert_optional=False): 523 convert_optional=False):
497 """Given a list of function parameters, generates their signature (as a 524 """Given a list of function parameters, generates their signature (as a
498 string). 525 string).
499 526
500 e.g. 527 e.g.
(...skipping 10 matching lines...) Expand all
511 params_opt = [] 538 params_opt = []
512 for param in params: 539 for param in params:
513 p_sig = self._GeneratePropertySignature(param) 540 p_sig = self._GeneratePropertySignature(param)
514 if param.optional and not convert_optional: 541 if param.optional and not convert_optional:
515 params_opt.append(p_sig) 542 params_opt.append(p_sig)
516 else: 543 else:
517 params_req.append(p_sig) 544 params_req.append(p_sig)
518 545
519 # Add the callback, if it exists. 546 # Add the callback, if it exists.
520 if callback: 547 if callback:
521 c_sig = self._GenerateFunctionSignature(callback) 548 c_sig = self._GenerateFunctionSignature(callback, convert_optional=True)
522 if callback.optional: 549 if callback.optional:
523 params_opt.append(c_sig) 550 params_opt.append(c_sig)
524 else: 551 else:
525 params_req.append(c_sig) 552 params_req.append(c_sig)
526 553
527 # Join the parameters with commas. 554 # Join the parameters with commas.
528 # Optional parameters have to be in square brackets, e.g.: 555 # Optional parameters have to be in square brackets, e.g.:
529 # 556 #
530 # required params | optional params | output 557 # required params | optional params | output
531 # [] | [] | '' 558 # [] | [] | ''
532 # [x, y] | [] | 'x, y' 559 # [x, y] | [] | 'x, y'
533 # [] | [a, b] | '[a, b]' 560 # [] | [a, b] | '[a, b]'
534 # [x, y] | [a, b] | 'x, y, [a, b]' 561 # [x, y] | [a, b] | 'x, y, [a, b]'
535 if params_opt: 562 if params_opt:
536 params_opt[0] = '[%s' % params_opt[0] 563 params_opt[0] = '[%s' % params_opt[0]
537 params_opt[-1] = '%s]' % params_opt[-1] 564 params_opt[-1] = '%s]' % params_opt[-1]
538 param_sets = [', '.join(params_req), ', '.join(params_opt)] 565 param_sets = [', '.join(params_req), ', '.join(params_opt)]
539 566
540 # The 'if p' part here is needed to prevent commas where there are no 567 # The 'if p' part here is needed to prevent commas where there are no
541 # parameters of a certain type. 568 # parameters of a certain type.
542 # If there are no optional parameters, this prevents a _trailing_ comma, 569 # If there are no optional parameters, this prevents a _trailing_ comma,
543 # e.g. '(x, y,)'. Similarly, if there are no required parameters, this 570 # e.g. '(x, y,)'. Similarly, if there are no required parameters, this
544 # prevents a leading comma, e.g. '(, [a, b])'. 571 # prevents a leading comma, e.g. '(, [a, b])'.
545 return ', '.join(p for p in param_sets if p) 572 return ', '.join(p for p in param_sets if p)
546 573
547 def _ConcatOverride(self, c, type_, prop, key_suffix='', add_doc=False): 574 def _ConcatOverride(self, c, key_chain, doc_property=False):
not at google - send to devlin 2013/02/07 01:16:41 From what I can tell, this isn't always a property
sashab 2013/02/08 01:53:34 Done.
548 """Given a particular type and property to find in the custom dart 575 """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. 576 the custom dart overrides.
550 If there is, appends the override code, and returns True. 577 If there is an override for that key, appends the override code and returns
551 If not, returns False. 578 True. If not, returns False.
552 579
553 |key_suffix| will be added to the end of the key before searching, e.g. 580 If doc_property is given, adds the documentation for this property before
554 '.set' or '.get' can be used for setters and getters respectively. 581 the override code.
555
556 If add_doc is given, adds the documentation for this property before the
557 override code.
558 """ 582 """
559 contents = self._type_overrides.get('%s.%s%s' % (type_.name, prop.name, 583 contents = self._type_overrides.get('.'.join(key_chain))
560 key_suffix))
561 if contents is None: 584 if contents is None:
562 return False 585 return False
563 586
564 if prop is not None: 587 if doc_property is not None:
565 c.Concat(self._GenerateDocumentation(prop)) 588 c.Concat(self._GenerateDocumentation(doc_property))
566 for line in contents.split('\n'): 589 for line in contents.strip().split('\n'):
not at google - send to devlin 2013/02/07 01:16:41 why strip()?
sashab 2013/02/08 01:53:34 Good question. File contents always contain a trai
567 c.Append(line) 590 c.Append(line)
568 return True 591 return True
569 592
570 def _IsFunction(self, type_): 593 def _IsFunction(self, type_):
571 """Given a model.Type, returns whether this type is a function. 594 """Given a model.Type, returns whether this type is a function.
572 """ 595 """
573 return type_.property_type == PropertyType.FUNCTION 596 return type_.property_type == PropertyType.FUNCTION
574 597
575 def _IsSerializableObjectType(self, type_): 598 def _IsSerializableObjectType(self, type_):
576 """Given a model.Type, returns whether this type is a serializable object. 599 """Given a model.Type, returns whether this type is a serializable object.
577 Serializable objects are custom types defined in this namespace. 600 Serializable objects are custom types defined in this namespace.
601
602 If this object is a reference to something not in this namespace, assumes
603 its a serializable object.
578 """ 604 """
579 if (type_.property_type == PropertyType.REF 605 if type_.property_type is PropertyType.REF:
580 and type_.ref_type in self._types): 606 if type_.ref_type in self._types:
581 return self._IsObjectType(self._types[type_.ref_type]) 607 return self._IsObjectType(self._types[type_.ref_type])
608 return True
582 if (type_.property_type == PropertyType.OBJECT 609 if (type_.property_type == PropertyType.OBJECT
583 and type_.instance_of in self._types): 610 and type_.instance_of in self._types):
584 return self._IsObjectType(self._types[type_.instance_of]) 611 return self._IsObjectType(self._types[type_.instance_of])
585 return False 612 return False
586 613
587 def _IsObjectType(self, type_): 614 def _IsObjectType(self, type_):
588 """Given a model.Type, returns whether this type is an object. 615 """Given a model.Type, returns whether this type is an object.
589 """ 616 """
590 return (self._IsSerializableObjectType(type_) 617 return (self._IsSerializableObjectType(type_)
591 or type_.property_type in [PropertyType.OBJECT, PropertyType.ANY]) 618 or type_.property_type in [PropertyType.OBJECT, PropertyType.ANY])
592 619
593 def _IsListOfSerializableObjects(self, type_): 620 def _IsListOfSerializableObjects(self, type_):
594 """Given a model.Type, returns whether this type is a list of serializable 621 """Given a model.Type, returns whether this type is a list of serializable
595 objects (PropertyType.REF types). 622 objects (or regular objects, if this list is treated as a type - in this
623 case, the item type was defined inline).
624
625 If this type is a reference to something not in this namespace, assumes
626 it is not a list of serializable objects.
596 """ 627 """
628 if type_.property_type is PropertyType.REF:
629 if type_.ref_type in self._types:
630 return self._IsListOfSerializableObjects(self._types[type_.ref_type])
631 return False
597 return (type_.property_type is PropertyType.ARRAY and 632 return (type_.property_type is PropertyType.ARRAY and
598 type_.item_type.property_type is PropertyType.REF) 633 (self._IsSerializableObjectType(type_.item_type) or
634 (self._IsObjectType(type_.item_type) and type_.name in self._types)))
599 635
600 def _IsListOfBaseTypes(self, type_): 636 def _IsListOfBaseTypes(self, type_):
601 """Given a model.Type, returns whether this type is a list of base type 637 """Given a model.Type, returns whether this type is a list of base type
602 objects (PropertyType.REF types). 638 objects (PropertyType.REF types).
603 """ 639 """
604 return (type_.property_type is PropertyType.ARRAY and 640 return (type_.property_type is PropertyType.ARRAY and
605 self._IsBaseType(type_.item_type)) 641 self._IsBaseType(type_.item_type))
606 642
607 def _IsBaseType(self, type_): 643 def _IsBaseType(self, type_, list_as_base=False):
not at google - send to devlin 2013/02/07 01:16:41 list_as_base isn't descriptive on its own, I had t
sashab 2013/02/08 01:53:34 Before, lists had to be wrapped to be generated co
608 """Given a model.type_, returns whether this type is a base type 644 """Given a model.type_, returns whether this type is a base type
609 (string, number or boolean). 645 (string, number or boolean).
646
647 If type_ is a Choices object, returns True if all possible choices are base
648 types.
649
650 If list_as_base is True, counts List as a base type.
610 """ 651 """
611 return (self._GetDartType(type_) in 652 return (
612 ['bool', 'num', 'int', 'double', 'String']) 653 (self._GetDartType(type_) in ['bool', 'num', 'int', 'double', 'String'])
654 or (type_.property_type is PropertyType.ARRAY
655 and self._IsBaseType(type_.item_type, list_as_base=list_as_base))
656 or (type_.property_type is PropertyType.CHOICES
657 and all(self._IsBaseType(t, list_as_base=list_as_base)
658 for t in type_.choices))
659 )
613 660
614 def _GetDartType(self, type_): 661 def _GetDartType(self, type_):
615 """Given a model.Type object, returns its type as a Dart string. 662 """Given a model.Type object, returns its type as a Dart string.
616 """ 663 """
617 if type_ is None: 664 if type_ is None:
618 return 'void' 665 return 'void'
619 666
620 prop_type = type_.property_type 667 prop_type = type_.property_type
621 if prop_type is PropertyType.REF: 668 if prop_type is PropertyType.REF:
669 if type_.ref_type in self._types:
670 return self._GetDartType(self._types[type_.ref_type])
622 # TODO(sashab): If the type is foreign, it might have to be imported. 671 # TODO(sashab): If the type is foreign, it might have to be imported.
623 return StripNamespace(type_.ref_type) 672 return StripNamespace(type_.ref_type)
624 elif prop_type is PropertyType.BOOLEAN: 673 elif prop_type is PropertyType.BOOLEAN:
625 return 'bool' 674 return 'bool'
626 elif prop_type is PropertyType.INTEGER: 675 elif prop_type is PropertyType.INTEGER:
627 return 'int' 676 return 'int'
628 elif prop_type is PropertyType.INT64: 677 elif prop_type is PropertyType.INT64:
629 return 'num' 678 return 'num'
630 elif prop_type is PropertyType.DOUBLE: 679 elif prop_type is PropertyType.DOUBLE:
631 return 'double' 680 return 'double'
632 elif prop_type is PropertyType.STRING: 681 elif prop_type is PropertyType.STRING:
633 return 'String' 682 return 'String'
634 elif prop_type is PropertyType.ENUM: 683 elif prop_type is PropertyType.ENUM:
635 return 'String' 684 return 'String'
636 elif prop_type is PropertyType.CHOICES: 685 elif prop_type is PropertyType.CHOICES:
637 # TODO: What is a Choices type? Is it closer to a Map Dart object? 686 # TODO: Think of a nice way to generate code for Choices objects in Dart.
638 return 'Object' 687 return 'Object'
639 elif prop_type is PropertyType.ANY: 688 elif prop_type is PropertyType.ANY:
640 return 'Object' 689 return 'Object'
641 elif prop_type is PropertyType.OBJECT: 690 elif prop_type is PropertyType.OBJECT:
642 return type_.instance_of or 'Object' 691 if type_.instance_of is not None:
692 return type_.instance_of
693 if type(type_.parent) is not Function:
694 return type_.name
695 # If we're here, the parent's type is a Function. So it's name will be the
696 # name of the function parameter (its an inline type definition).
697 # TODO(sashab): When there is a nice way to generate code for inline
698 # types, change this to reflect the type's new name.
699 return 'Object'
643 elif prop_type is PropertyType.FUNCTION: 700 elif prop_type is PropertyType.FUNCTION:
644 return 'Function' 701 return 'Function'
645 elif prop_type is PropertyType.ARRAY: 702 elif prop_type is PropertyType.ARRAY:
646 return 'List<%s>' % self._GetDartType(type_.item_type) 703 return 'List<%s>' % self._GetDartType(type_.item_type)
647 elif prop_type is PropertyType.BINARY: 704 elif prop_type is PropertyType.BINARY:
648 return 'String' 705 return 'String'
649 else: 706 else:
650 raise NotImplementedError(prop_type) 707 raise NotImplementedError(prop_type)
651 708
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