Index: tools/json_schema_compiler/dart_generator.py |
diff --git a/tools/json_schema_compiler/dart_generator.py b/tools/json_schema_compiler/dart_generator.py |
index 9503ef337f1ba6845f3938de901783ddca474dc8..e97048f863e12fa40157cc1de987a0c5cfb54eb1 100644 |
--- a/tools/json_schema_compiler/dart_generator.py |
+++ b/tools/json_schema_compiler/dart_generator.py |
@@ -43,11 +43,17 @@ class _Generator(object): |
type_path = '.'.join(filename.split('.')[1:-1]) |
self._type_overrides[type_path] = f.read() |
+ # TODO(sashab): Add all inline type definitions to the global Types |
+ # dictionary. |
+ # List types do not apply - their types are automatically generated instead |
+ # of the list type. |
+ |
def Generate(self): |
"""Generates a Code object with the .dart for the entire namespace. |
""" |
c = Code() |
- (c.Append(LICENSE) |
+ (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
|
+ .Append() |
.Append('// Generated from namespace: %s' % self._namespace.name) |
.Append() |
.Append('part of chrome;')) |
@@ -58,8 +64,11 @@ class _Generator(object): |
.Append(' * Types') |
.Append(' */') |
) |
- for type_name in self._types: |
- c.Concat(self._GenerateType(self._types[type_name])) |
+ for type_ in self._types.values(): |
+ # Check for custom dart for this whole type. |
+ c.Append() |
+ 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
|
+ 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
|
if self._namespace.events: |
(c.Append() |
@@ -87,10 +96,18 @@ class _Generator(object): |
object that extends ChromeObject. All parameters are specifiable as named |
arguments in the constructor, and all methods are wrapped with getters and |
setters that hide the JS() implementation. |
+ |
+ List objects with inline types are created with a definition for the inline |
+ type instead. |
""" |
+ if type_.property_type is PropertyType.ARRAY: |
+ # This is an inline type definition: generate that type instead. |
+ type_ = type_.item_type |
+ # Save this to global types, just so future functions don't get confused. |
+ 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
|
+ |
c = Code() |
- (c.Append() |
- .Concat(self._GenerateDocumentation(type_)) |
+ (c.Concat(self._GenerateDocumentation(type_)) |
.Sblock('class %(type_name)s extends ChromeObject {') |
) |
@@ -134,15 +151,15 @@ class _Generator(object): |
# Check for custom dart for this whole property. |
c.Append() |
- if not self._ConcatOverride(c, type_, prop, add_doc=True): |
+ if not self._ConcatOverride(c, [type_.name, prop.name], |
+ doc_property=prop): |
# Add the getter. |
- if not self._ConcatOverride(c, type_, prop, key_suffix='.get', |
- add_doc=True): |
+ if not self._ConcatOverride(c, [type_.name, prop.name, '.get'], |
+ doc_property=prop): |
# Add the documentation for this property. |
c.Concat(self._GenerateDocumentation(prop)) |
- if (self._IsBaseType(prop.type_) |
- or self._IsListOfBaseTypes(prop.type_)): |
+ if (self._IsBaseType(prop.type_, list_as_base=True)): |
c.Append("%s get %s => JS('%s', '#.%s', this._jsObject);" % |
(type_name, prop.name, type_name, prop.name)) |
elif self._IsSerializableObjectType(prop.type_): |
@@ -150,13 +167,18 @@ class _Generator(object): |
"this._jsObject));" |
% (type_name, prop.name, type_name, prop.name)) |
elif self._IsListOfSerializableObjects(prop.type_): |
- (c.Sblock('%s get %s {' % (type_name, prop.name)) |
- .Append('%s __proxy_%s = new %s();' % (type_name, prop.name, |
- type_name)) |
+ array_type, array_type_name = prop.type_, type_name |
+ if prop.type_.property_type is not PropertyType.ARRAY: |
+ # This is a reference to an array object, not the object itself. |
+ 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.
|
+ array_type_name =self._GetDartType(array_type) |
+ (c.Sblock('%s get %s {' % (array_type_name, prop.name)) |
+ .Append('%s __proxy_%s = new %s();' % (array_type_name, prop.name, |
+ array_type_name)) |
.Sblock("for (var o in JS('List', '#.%s', this._jsObject)) {" % |
prop.name) |
.Append('__proxy_%s.add(new %s._proxy(o));' % (prop.name, |
- self._GetDartType(prop.type_.item_type))) |
+ self._GetDartType(array_type.item_type))) |
.Eblock('}') |
.Append('return __proxy_%s;' % prop.name) |
.Eblock('}') |
@@ -173,7 +195,7 @@ class _Generator(object): |
# Add the setter. |
c.Append() |
- if not self._ConcatOverride(c, type_, prop, key_suffix='.set'): |
+ if not self._ConcatOverride(c, [type_.name, prop.name, '.set']): |
wrapped_name = prop.name |
if not self._IsBaseType(prop.type_): |
wrapped_name = 'convertArgument(%s)' % prop.name |
@@ -194,7 +216,10 @@ class _Generator(object): |
.Append(' */') |
) |
for prop in methods: |
- c.Concat(self._GenerateFunction(prop.type_.function)) |
+ # Check if there's an override for this method. |
+ if not self._ConcatOverride(c, [type_.name, prop.name], |
+ doc_property=prop): |
+ c.Concat(self._GenerateFunction(prop.type_.function)) |
(c.Eblock('}') |
.Substitute({ |
@@ -223,9 +248,7 @@ class _Generator(object): |
"""Returns the Code object for the given function. |
""" |
c = Code() |
- (c.Append() |
- .Concat(self._GenerateDocumentation(f)) |
- ) |
+ c.Concat(self._GenerateDocumentation(f)) |
if not self._NeedsProxiedCallback(f): |
c.Append("%s => %s;" % (self._GenerateFunctionSignature(f), |
@@ -252,7 +275,7 @@ class _Generator(object): |
# their members (by copying out each member and proxying it). |
lists_to_proxy = [] |
for p in f.params: |
- if self._IsBaseType(p.type_) or self._IsListOfBaseTypes(p.type_): |
+ if self._IsBaseType(p.type_, list_as_base=True): |
proxied_params.append(p.name) |
elif self._IsSerializableObjectType(p.type_): |
proxied_params.append('new %s._proxy(%s)' % ( |
@@ -263,6 +286,11 @@ class _Generator(object): |
elif self._IsObjectType(p.type_): |
# TODO(sashab): Find a way to build generic JS objects back in Dart. |
proxied_params.append('%s' % p.name) |
+ elif p.type_.property_type is PropertyType.ARRAY: |
+ # TODO(sashab): This might be okay - what if this is a list of |
+ # FileEntry elements? In this case, a basic list will proxy the objects |
+ # fine. |
+ proxied_params.append('%s' % p.name) |
else: |
raise Exception( |
"Cannot automatically create proxy; can't wrap %s, type %s" % ( |
@@ -425,7 +453,10 @@ class _Generator(object): |
.Append(' */') |
) |
for function in self._namespace.functions.values(): |
- c.Concat(self._GenerateFunction(function)) |
+ # Check for custom dart for this whole property. |
+ c.Append() |
+ if not self._ConcatOverride(c, [function.name], doc_property=function): |
+ c.Concat(self._GenerateFunction(function)) |
# Add the constructor. |
(c.Append() |
@@ -459,22 +490,17 @@ class _Generator(object): |
'name': prop.simple_name |
} |
- def _GenerateFunctionSignature(self, function): |
+ def _GenerateFunctionSignature(self, function, convert_optional=False): |
"""Given a function object, returns the signature for that function. |
Recursively generates the signature for callbacks. |
Returns a String for the given function. |
- If prepend_this is True, adds "this." to the function's name. |
+ If convert_optional is True, changes optional parameters to be required. |
e.g. |
void onClosed() |
bool isOpen([String type]) |
void doSomething(bool x, void callback([String x])) |
- |
- e.g. If prepend_this is True: |
- void this.onClosed() |
- bool this.isOpen([String type]) |
- void this.doSomething(bool x, void callback([String x])) |
""" |
sig = '%(return_type)s %(name)s(%(params)s)' |
@@ -487,7 +513,8 @@ class _Generator(object): |
'return_type': return_type, |
'name': function.simple_name, |
'params': self._GenerateParameterList(function.params, |
- function.callback) |
+ function.callback, |
+ convert_optional=convert_optional) |
} |
def _GenerateParameterList(self, |
@@ -518,7 +545,7 @@ class _Generator(object): |
# Add the callback, if it exists. |
if callback: |
- c_sig = self._GenerateFunctionSignature(callback) |
+ c_sig = self._GenerateFunctionSignature(callback, convert_optional=True) |
if callback.optional: |
params_opt.append(c_sig) |
else: |
@@ -544,26 +571,22 @@ class _Generator(object): |
# prevents a leading comma, e.g. '(, [a, b])'. |
return ', '.join(p for p in param_sets if p) |
- def _ConcatOverride(self, c, type_, prop, key_suffix='', add_doc=False): |
- """Given a particular type and property to find in the custom dart |
- overrides, checks whether there is an override for that key. |
- If there is, appends the override code, and returns True. |
- If not, returns False. |
- |
- |key_suffix| will be added to the end of the key before searching, e.g. |
- '.set' or '.get' can be used for setters and getters respectively. |
+ 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.
|
+ """Given a list of keys, joins them with periods and searches for them in |
+ the custom dart overrides. |
+ If there is an override for that key, appends the override code and returns |
+ True. If not, returns False. |
- If add_doc is given, adds the documentation for this property before the |
- override code. |
+ If doc_property is given, adds the documentation for this property before |
+ the override code. |
""" |
- contents = self._type_overrides.get('%s.%s%s' % (type_.name, prop.name, |
- key_suffix)) |
+ contents = self._type_overrides.get('.'.join(key_chain)) |
if contents is None: |
return False |
- if prop is not None: |
- c.Concat(self._GenerateDocumentation(prop)) |
- for line in contents.split('\n'): |
+ if doc_property is not None: |
+ c.Concat(self._GenerateDocumentation(doc_property)) |
+ 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
|
c.Append(line) |
return True |
@@ -575,10 +598,14 @@ class _Generator(object): |
def _IsSerializableObjectType(self, type_): |
"""Given a model.Type, returns whether this type is a serializable object. |
Serializable objects are custom types defined in this namespace. |
+ |
+ If this object is a reference to something not in this namespace, assumes |
+ its a serializable object. |
""" |
- if (type_.property_type == PropertyType.REF |
- and type_.ref_type in self._types): |
- return self._IsObjectType(self._types[type_.ref_type]) |
+ if type_.property_type is PropertyType.REF: |
+ if type_.ref_type in self._types: |
+ return self._IsObjectType(self._types[type_.ref_type]) |
+ return True |
if (type_.property_type == PropertyType.OBJECT |
and type_.instance_of in self._types): |
return self._IsObjectType(self._types[type_.instance_of]) |
@@ -592,10 +619,19 @@ class _Generator(object): |
def _IsListOfSerializableObjects(self, type_): |
"""Given a model.Type, returns whether this type is a list of serializable |
- objects (PropertyType.REF types). |
+ objects (or regular objects, if this list is treated as a type - in this |
+ case, the item type was defined inline). |
+ |
+ If this type is a reference to something not in this namespace, assumes |
+ it is not a list of serializable objects. |
""" |
+ if type_.property_type is PropertyType.REF: |
+ if type_.ref_type in self._types: |
+ return self._IsListOfSerializableObjects(self._types[type_.ref_type]) |
+ return False |
return (type_.property_type is PropertyType.ARRAY and |
- type_.item_type.property_type is PropertyType.REF) |
+ (self._IsSerializableObjectType(type_.item_type) or |
+ (self._IsObjectType(type_.item_type) and type_.name in self._types))) |
def _IsListOfBaseTypes(self, type_): |
"""Given a model.Type, returns whether this type is a list of base type |
@@ -604,12 +640,23 @@ class _Generator(object): |
return (type_.property_type is PropertyType.ARRAY and |
self._IsBaseType(type_.item_type)) |
- def _IsBaseType(self, type_): |
+ 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
|
"""Given a model.type_, returns whether this type is a base type |
(string, number or boolean). |
+ |
+ If type_ is a Choices object, returns True if all possible choices are base |
+ types. |
+ |
+ If list_as_base is True, counts List as a base type. |
""" |
- return (self._GetDartType(type_) in |
- ['bool', 'num', 'int', 'double', 'String']) |
+ return ( |
+ (self._GetDartType(type_) in ['bool', 'num', 'int', 'double', 'String']) |
+ or (type_.property_type is PropertyType.ARRAY |
+ and self._IsBaseType(type_.item_type, list_as_base=list_as_base)) |
+ or (type_.property_type is PropertyType.CHOICES |
+ and all(self._IsBaseType(t, list_as_base=list_as_base) |
+ for t in type_.choices)) |
+ ) |
def _GetDartType(self, type_): |
"""Given a model.Type object, returns its type as a Dart string. |
@@ -619,6 +666,8 @@ class _Generator(object): |
prop_type = type_.property_type |
if prop_type is PropertyType.REF: |
+ if type_.ref_type in self._types: |
+ return self._GetDartType(self._types[type_.ref_type]) |
# TODO(sashab): If the type is foreign, it might have to be imported. |
return StripNamespace(type_.ref_type) |
elif prop_type is PropertyType.BOOLEAN: |
@@ -634,12 +683,20 @@ class _Generator(object): |
elif prop_type is PropertyType.ENUM: |
return 'String' |
elif prop_type is PropertyType.CHOICES: |
- # TODO: What is a Choices type? Is it closer to a Map Dart object? |
+ # TODO: Think of a nice way to generate code for Choices objects in Dart. |
return 'Object' |
elif prop_type is PropertyType.ANY: |
return 'Object' |
elif prop_type is PropertyType.OBJECT: |
- return type_.instance_of or 'Object' |
+ if type_.instance_of is not None: |
+ return type_.instance_of |
+ if type(type_.parent) is not Function: |
+ return type_.name |
+ # If we're here, the parent's type is a Function. So it's name will be the |
+ # name of the function parameter (its an inline type definition). |
+ # TODO(sashab): When there is a nice way to generate code for inline |
+ # types, change this to reflect the type's new name. |
+ return 'Object' |
elif prop_type is PropertyType.FUNCTION: |
return 'Function' |
elif prop_type is PropertyType.ARRAY: |