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

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