12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)"""
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Generator language component for compiler.py that adds Dart language support.
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)"""
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from code import Code
958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)from model import Function, PropertyType
1058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)from schema_util import StripNamespace
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import os
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from datetime import datetime
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)LICENSE = (
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)"""// Copyright (c) %s, the Dart project authors.  Please see the AUTHORS file
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// for details. All rights reserved. Use of this source code is governed by a
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// BSD-style license that can be found in the LICENSE file.""" %
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    datetime.now().year)
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class DartGenerator(object):
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def __init__(self, dart_overrides_dir=None):
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self._dart_overrides_dir = dart_overrides_dir
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def Generate(self, namespace):
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return _Generator(namespace, self._dart_overrides_dir).Generate()
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class _Generator(object):
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  """A .dart generator for a namespace.
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  """
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def __init__(self, namespace, dart_overrides_dir=None):
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self._namespace = namespace
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # TODO(sashab): Once inline type definitions start being added to
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # self._types, make a _FindType(self, type_) function that looks at
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # self._namespace.types.
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self._types = namespace.types
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Build a dictionary of Type Name --> Custom Dart code.
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self._type_overrides = {}
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if dart_overrides_dir is not None:
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for filename in os.listdir(dart_overrides_dir):
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if filename.startswith(namespace.unix_name):
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          with open(os.path.join(dart_overrides_dir, filename)) as f:
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            # Split off the namespace and file extension, leaving just the type.
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            type_path = '.'.join(filename.split('.')[1:-1])
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            self._type_overrides[type_path] = f.read()
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # TODO(sashab): Add all inline type definitions to the global Types
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # dictionary here, so they have proper names, and are implemented along with
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # all other types. Also update the parameters/members with these types
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # to reference these new types instead.
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def Generate(self):
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Generates a Code object with the .dart for the entire namespace.
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    c = Code()
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    (c.Append(LICENSE)
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Append()
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Append('// Generated from namespace: %s' % self._namespace.name)
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Append()
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Append('part of chrome;'))
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if self._types:
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (c.Append()
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Append('/**')
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Append(' * Types')
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Append(' */')
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Append()
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      )
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for type_ in self._types.values():
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # Check for custom dart for this whole type.
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      override = self._GetOverride([type_.name], document_with=type_)
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      c.Cblock(override if override is not None else self._GenerateType(type_))
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if self._namespace.events:
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (c.Append('/**')
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Append(' * Events')
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Append(' */')
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Append()
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      )
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for event_name in self._namespace.events:
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      c.Cblock(self._GenerateEvent(self._namespace.events[event_name]))
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    (c.Append('/**')
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Append(' * Functions')
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Append(' */')
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Append()
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    )
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    c.Cblock(self._GenerateMainClass())
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return c
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _GenerateType(self, type_):
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Given a Type object, returns the Code with the .dart for this
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    type's definition.
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Assumes this type is a Parameter Type (creatable by user), and creates an
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    object that extends ChromeObject. All parameters are specifiable as named
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    arguments in the constructor, and all methods are wrapped with getters and
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    setters that hide the JS() implementation.
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    c = Code()
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Since enums are just treated as strings for now, don't generate their
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # type.
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # TODO(sashab): Find a nice way to wrap enum objects.
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if type_.property_type is PropertyType.ENUM:
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return c
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    (c.Concat(self._GenerateDocumentation(type_))
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Sblock('class %(type_name)s extends ChromeObject {')
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    )
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Check whether this type has function members. If it does, don't allow
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # public construction.
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    add_public_constructor = all(not self._IsFunction(p.type_)
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 for p in type_.properties.values())
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    constructor_fields = [self._GeneratePropertySignature(p)
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          for p in type_.properties.values()]
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if add_public_constructor:
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (c.Append('/*')
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Append(' * Public constructor')
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Append(' */')
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Sblock('%(type_name)s({%(constructor_fields)s}) {')
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      )
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for prop_name in type_.properties:
1317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        (c.Sblock('if (%s != null)' % prop_name)
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          .Append('this.%s = %s;' % (prop_name, prop_name))
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          .Eblock()
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        )
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (c.Eblock('}')
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Append()
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      )
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    (c.Append('/*')
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Append(' * Private constructor')
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Append(' */')
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Append('%(type_name)s._proxy(_jsObject) : super._proxy(_jsObject);')
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    )
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Add an accessor (getter & setter) for each property.
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    properties = [p for p in type_.properties.values()
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  if not self._IsFunction(p.type_)]
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if properties:
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (c.Append()
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Append('/*')
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Append(' * Public accessors')
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Append(' */')
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      )
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for prop in properties:
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      override = self._GetOverride([type_.name, prop.name], document_with=prop)
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      c.Concat(override if override is not None
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               else self._GenerateGetterAndSetter(type_, prop))
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Now add all the methods.
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    methods = [t for t in type_.properties.values()
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               if self._IsFunction(t.type_)]
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if methods:
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (c.Append()
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Append('/*')
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Append(' * Methods')
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Append(' */')
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      )
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for prop in methods:
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # Check if there's an override for this method.
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      override = self._GetOverride([type_.name, prop.name], document_with=prop)
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      c.Cblock(override if override is not None
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               else self._GenerateFunction(prop.type_.function))
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    (c.Eblock('}')
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Substitute({
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        'type_name': self._AddPrefix(type_.simple_name),
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        'constructor_fields': ', '.join(constructor_fields)
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      })
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    )
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return c
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _GenerateGetterAndSetter(self, type_, prop):
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Given a Type and Property, returns the Code object for the getter and
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    setter for that property.
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    c = Code()
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    override = self._GetOverride([type_.name, prop.name, '.get'],
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 document_with=prop)
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    c.Cblock(override if override is not None
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             else self._GenerateGetter(type_, prop))
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    override = self._GetOverride([type_.name, prop.name, '.set'])
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    c.Cblock(override if override is not None
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             else self._GenerateSetter(type_, prop))
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return c
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _GenerateGetter(self, type_, prop):
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Given a Type and Property, returns the Code object for the getter for
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    that property.
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Also adds the documentation for this property before the method.
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    c = Code()
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    c.Concat(self._GenerateDocumentation(prop))
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    type_name = self._GetDartType(prop.type_)
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (self._IsBaseType(prop.type_)):
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      c.Append("%s get %s => JS('%s', '#.%s', this._jsObject);" %
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          (type_name, prop.name, type_name, prop.name))
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif self._IsSerializableObjectType(prop.type_):
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      c.Append("%s get %s => new %s._proxy(JS('', '#.%s', "
212b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)               "this._jsObject));" %
213b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)          (type_name, prop.name, type_name, prop.name))
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif self._IsListOfSerializableObjects(prop.type_):
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (c.Sblock('%s get %s {' % (type_name, prop.name))
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Append('%s __proxy_%s = new %s();' % (type_name, prop.name,
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                               type_name))
218b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        .Append("int count = JS('int', '#.%s.length', this._jsObject);" %
219b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)            prop.name)
220b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        .Sblock("for (int i = 0; i < count; i++) {")
22190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        .Append("var item = JS('', '#.%s[#]', this._jsObject, i);" % prop.name)
222b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        .Append('__proxy_%s.add(new %s._proxy(item));' % (prop.name,
223b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)            self._GetDartType(prop.type_.item_type)))
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Eblock('}')
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Append('return __proxy_%s;' % prop.name)
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Eblock('}')
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      )
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif self._IsObjectType(prop.type_):
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # TODO(sashab): Think of a way to serialize generic Dart objects.
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if type_name in self._types:
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        c.Append("%s get %s => new %s._proxy(JS('%s', '#.%s', "
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 "this._jsObject));" %
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            (type_name, prop.name, type_name, type_name, prop.name))
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      else:
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        c.Append("%s get %s => JS('%s', '#.%s', this._jsObject);" %
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            (type_name, prop.name, type_name, prop.name))
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else:
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      raise Exception(
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          "Could not generate wrapper for %s.%s: unserializable type %s" %
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          (type_.name, prop.name, type_name)
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      )
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return c
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _GenerateSetter(self, type_, prop):
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Given a Type and Property, returns the Code object for the setter for
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    that property.
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    c = Code()
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    type_name = self._GetDartType(prop.type_)
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    wrapped_name = prop.name
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if not self._IsBaseType(prop.type_):
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      wrapped_name = 'convertArgument(%s)' % prop.name
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    (c.Sblock("void set %s(%s %s) {" % (prop.name, type_name, prop.name))
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Append("JS('void', '#.%s = #', this._jsObject, %s);" %
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        (prop.name, wrapped_name))
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Eblock("}")
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    )
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return c
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _GenerateDocumentation(self, prop):
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Given an object, generates the documentation for this object (as a
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    code string) and returns the Code object.
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Returns an empty code object if the object has no documentation.
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Uses triple-quotes for the string.
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    c = Code()
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if prop.description is not None:
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for line in prop.description.split('\n'):
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        c.Comment(line, comment_prefix='/// ')
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return c
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _GenerateFunction(self, f):
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Returns the Code object for the given function.
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    c = Code()
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    c.Concat(self._GenerateDocumentation(f))
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if not self._NeedsProxiedCallback(f):
28258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      c.Append("%s => %s;" % (self._GenerateFunctionSignature(f),
28358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                              self._GenerateProxyCall(f)))
28458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      return c
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    (c.Sblock("%s {" % self._GenerateFunctionSignature(f))
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Concat(self._GenerateProxiedFunction(f.callback, f.callback.name))
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Append('%s;' % self._GenerateProxyCall(f))
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Eblock('}')
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    )
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return c
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _GenerateProxiedFunction(self, f, callback_name):
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Given a function (assumed to be a callback), generates the proxied
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    version of this function, which calls |callback_name| if it is defined.
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Returns a Code object.
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    c = Code()
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    proxied_params = []
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # A list of Properties, containing List<*> objects that need proxying for
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # their members (by copying out each member and proxying it).
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    lists_to_proxy = []
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for p in f.params:
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if self._IsBaseType(p.type_):
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        proxied_params.append(p.name)
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      elif self._IsSerializableObjectType(p.type_):
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        proxied_params.append('new %s._proxy(%s)' % (
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            self._GetDartType(p.type_), p.name))
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      elif self._IsListOfSerializableObjects(p.type_):
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        proxied_params.append('__proxy_%s' % p.name)
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        lists_to_proxy.append(p)
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      elif self._IsObjectType(p.type_):
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        # TODO(sashab): Find a way to build generic JS objects back in Dart.
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        proxied_params.append('%s' % p.name)
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      elif p.type_.property_type is PropertyType.ARRAY:
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        # TODO(sashab): This might be okay - what if this is a list of
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        # FileEntry elements? In this case, a basic list will proxy the objects
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        # fine.
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        proxied_params.append('%s' % p.name)
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      else:
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        raise Exception(
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            "Cannot automatically create proxy; can't wrap %s, type %s" % (
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                self._GenerateFunctionSignature(f), self._GetDartType(p.type_)))
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    (c.Sblock("void __proxy_callback(%s) {" % ', '.join(p.name for p in
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                               f.params))
3297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      .Sblock('if (%s != null) {' % callback_name)
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    )
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Add the proxied lists.
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for list_to_proxy in lists_to_proxy:
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (c.Append("%s __proxy_%s = new %s();" % (
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    self._GetDartType(list_to_proxy.type_),
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    list_to_proxy.name,
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    self._GetDartType(list_to_proxy.type_)))
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Sblock("for (var o in %s) {" % list_to_proxy.name)
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Append('__proxy_%s.add(new %s._proxy(o));' % (list_to_proxy.name,
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            self._GetDartType(list_to_proxy.type_.item_type)))
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Eblock("}")
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      )
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    (c.Append("%s(%s);" % (callback_name, ', '.join(proxied_params)))
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Eblock('}')
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Eblock('}')
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    )
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return c
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _NeedsProxiedCallback(self, f):
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Given a function, returns True if this function's callback needs to be
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    proxied, False if not.
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Function callbacks need to be proxied if they have at least one
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    non-base-type parameter.
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return f.callback and self._NeedsProxy(f.callback)
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _NeedsProxy(self, f):
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Given a function, returns True if it needs to be proxied, False if not.
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    A function needs to be proxied if any of its members are non-base types.
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    This means that, when the function object is passed to Javascript, it
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    needs to be wrapped in a "proxied" call that converts the JS inputs to Dart
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    objects explicitly, before calling the real function with these new objects.
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return any(not self._IsBaseType(p.type_) for p in f.params)
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _GenerateProxyCall(self, function, call_target='this._jsObject'):
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Given a function, generates the code to call that function via JS().
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Returns a string.
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    |call_target| is the name of the object to call the function on. The default
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    is this._jsObject.
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    e.g.
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        JS('void', '#.resizeTo(#, #)', this._jsObject, width, height)
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        JS('void', '#.setBounds(#)', this._jsObject, convertArgument(bounds))
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    n_params = len(function.params)
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if function.callback:
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      n_params += 1
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return_type_str = self._GetDartType(function.returns)
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    params = []
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # If this object is serializable, don't convert the type from JS - pass the
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # JS object straight into the proxy.
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if self._IsSerializableObjectType(function.returns):
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      params.append("''")
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else:
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      params.append("'%s'" % return_type_str)
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    params.append("'#.%s(%s)'" % (function.name, ', '.join(['#'] * n_params)))
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    params.append(call_target)
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for param in function.params:
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if not self._IsBaseType(param.type_):
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        params.append('convertArgument(%s)' % param.name)
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      else:
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        params.append(param.name)
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if function.callback:
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # If this isn't a base type, we need a proxied callback.
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      callback_name = function.callback.name
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if self._NeedsProxiedCallback(function):
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        callback_name = "__proxy_callback"
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      params.append('convertDartClosureToJS(%s, %s)' % (callback_name,
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    len(function.callback.params)))
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # If the object is serializable, call the proxy constructor for this type.
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    proxy_call = 'JS(%s)' % ', '.join(params)
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if self._IsSerializableObjectType(function.returns):
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      proxy_call = 'new %s._proxy(%s)' % (return_type_str, proxy_call)
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return proxy_call
4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _GenerateEvent(self, event):
4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Given a Function object, returns the Code with the .dart for this event,
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    represented by the function.
4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    All events extend the Event base type.
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    c = Code()
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Add documentation for this event.
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    (c.Concat(self._GenerateDocumentation(event))
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Sblock('class Event_%(event_name)s extends Event {')
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    )
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # If this event needs a proxy, all calls need to be proxied.
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    needs_proxy = self._NeedsProxy(event)
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Override Event callback type definitions.
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for ret_type, event_func in (('void', 'addListener'),
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 ('void', 'removeListener'),
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 ('bool', 'hasListener')):
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      param_list = self._GenerateParameterList(event.params, event.callback,
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                               convert_optional=True)
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if needs_proxy:
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        (c.Sblock('%s %s(void callback(%s)) {' % (ret_type, event_func,
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                 param_list))
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          .Concat(self._GenerateProxiedFunction(event, 'callback'))
443b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)          .Append('super.%s(__proxy_callback);' % event_func)
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          .Eblock('}')
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        )
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      else:
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        c.Append('%s %s(void callback(%s)) => super.%s(callback);' %
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            (ret_type, event_func, param_list, event_func))
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      c.Append()
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Generate the constructor.
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    (c.Append('Event_%(event_name)s(jsObject) : '
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              'super._(jsObject, %(param_num)d);')
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Eblock('}')
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Substitute({
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        'event_name': self._namespace.unix_name + '_' + event.name,
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        'param_num': len(event.params)
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      })
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    )
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return c
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _GenerateMainClass(self):
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Generates the main class for this file, which links to all functions
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    and events.
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Returns a code object.
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    c = Code()
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    (c.Sblock('class API_%s {' % self._namespace.unix_name)
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Append('/*')
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Append(' * API connection')
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Append(' */')
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Append('Object _jsObject;')
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    )
4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Add events.
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if self._namespace.events:
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (c.Append()
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Append('/*')
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Append(' * Events')
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Append(' */')
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      )
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for event_name in self._namespace.events:
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      c.Append('Event_%s_%s %s;' % (self._namespace.unix_name, event_name,
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    event_name))
4872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Add functions.
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if self._namespace.functions:
4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (c.Append()
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Append('/*')
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Append(' * Functions')
4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        .Append(' */')
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      )
4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for function in self._namespace.functions.values():
4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # Check for custom dart for this whole property.
4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      override = self._GetOverride([function.name], document_with=function)
4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      c.Cblock(override if override is not None
4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               else self._GenerateFunction(function))
5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Add the constructor.
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    c.Sblock('API_%s(this._jsObject) {' % self._namespace.unix_name)
5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Add events to constructor.
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for event_name in self._namespace.events:
5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      c.Append("%s = new Event_%s_%s(JS('', '#.%s', this._jsObject));" %
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        (event_name, self._namespace.unix_name, event_name, event_name))
5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    (c.Eblock('}')
5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      .Eblock('}')
5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    )
5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return c
5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _GeneratePropertySignature(self, prop):
5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Given a property, returns a signature for that property.
5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Recursively generates the signature for callbacks.
5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Returns a String for the given property.
5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    e.g.
5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      bool x
5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      void onClosed()
5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      void doSomething(bool x, void callback([String x]))
5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
5242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if self._IsFunction(prop.type_):
5252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return self._GenerateFunctionSignature(prop.type_.function)
5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return '%(type)s %(name)s' % {
5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               'type': self._GetDartType(prop.type_),
5282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               'name': prop.simple_name
5292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           }
5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _GenerateFunctionSignature(self, function, convert_optional=False):
5322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Given a function object, returns the signature for that function.
5332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Recursively generates the signature for callbacks.
5342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Returns a String for the given function.
5352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    If convert_optional is True, changes optional parameters to be required.
5372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    e.g.
5392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      void onClosed()
5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      bool isOpen([String type])
5412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      void doSomething(bool x, void callback([String x]))
5422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
5432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sig = '%(return_type)s %(name)s(%(params)s)'
5442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if function.returns:
5462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return_type = self._GetDartType(function.returns)
5472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else:
5482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return_type = 'void'
5492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return sig % {
5512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        'return_type': return_type,
5522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        'name': function.simple_name,
5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        'params': self._GenerateParameterList(function.params,
5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                              function.callback,
5552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                              convert_optional=convert_optional)
5562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
5572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _GenerateParameterList(self,
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             params,
5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             callback=None,
5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             convert_optional=False):
5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Given a list of function parameters, generates their signature (as a
5632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    string).
5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    e.g.
5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      [String type]
5672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      bool x, void callback([String x])
5682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    If convert_optional is True, changes optional parameters to be required.
5702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Useful for callbacks, where optional parameters are treated as required.
5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
5722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Params lists (required & optional), to be joined with commas.
5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # TODO(sashab): Don't assume optional params always come after required
5742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # ones.
5752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    params_req = []
5762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    params_opt = []
5772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for param in params:
5782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      p_sig = self._GeneratePropertySignature(param)
5792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if param.optional and not convert_optional:
5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        params_opt.append(p_sig)
5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      else:
5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        params_req.append(p_sig)
5832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Add the callback, if it exists.
5852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if callback:
5862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      c_sig = self._GenerateFunctionSignature(callback, convert_optional=True)
5872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if callback.optional:
5882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        params_opt.append(c_sig)
5892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      else:
5902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        params_req.append(c_sig)
5912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Join the parameters with commas.
5932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Optional parameters have to be in square brackets, e.g.:
5942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    #
5952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    #  required params | optional params |     output
5962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    #        []        |        []       |       ''
5972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    #      [x, y]      |        []       |     'x, y'
5982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    #        []        |      [a, b]     |    '[a, b]'
5992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    #      [x, y]      |      [a, b]     | 'x, y, [a, b]'
6002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if params_opt:
6012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      params_opt[0] = '[%s' % params_opt[0]
6022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      params_opt[-1] = '%s]' % params_opt[-1]
6032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    param_sets = [', '.join(params_req), ', '.join(params_opt)]
6042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # The 'if p' part here is needed to prevent commas where there are no
6062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # parameters of a certain type.
6072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # If there are no optional parameters, this prevents a _trailing_ comma,
6082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # e.g. '(x, y,)'. Similarly, if there are no required parameters, this
6092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # prevents a leading comma, e.g. '(, [a, b])'.
6102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return ', '.join(p for p in param_sets if p)
6112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _GetOverride(self, key_chain, document_with=None):
6132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Given a list of keys, joins them with periods and searches for them in
6142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    the custom dart overrides.
6152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    If there is an override for that key, finds the override code and returns
6162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    the Code object. If not, returns None.
6172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    If document_with is not None, adds the documentation for this property
6192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    before the override code.
6202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
6212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    c = Code()
6222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    contents = self._type_overrides.get('.'.join(key_chain))
6232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if contents is None:
6242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return None
6252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if document_with is not None:
6272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      c.Concat(self._GenerateDocumentation(document_with))
6282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for line in contents.strip('\n').split('\n'):
6292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      c.Append(line)
6302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return c
6312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _AddPrefix(self, name):
6332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Given the name of a type, prefixes the namespace (as camelcase) and
6342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    returns the new name.
6352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
6362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # TODO(sashab): Split the dart library into multiple files, avoiding the
6372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # need for this prefixing.
6382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return ('%s%s' % (
6392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ''.join(s.capitalize() for s in self._namespace.name.split('.')),
6402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        name))
6412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _IsFunction(self, type_):
6432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Given a model.Type, returns whether this type is a function.
6442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
6452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return type_.property_type == PropertyType.FUNCTION
6462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _IsSerializableObjectType(self, type_):
6482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Given a model.Type, returns whether this type is a serializable object.
6492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Serializable objects are custom types defined in this namespace.
6502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    If this object is a reference to something not in this namespace, assumes
6522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    its a serializable object.
6532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
6542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if type_ is None:
6552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return False
6562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if type_.property_type is PropertyType.CHOICES:
6572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return all(self._IsSerializableObjectType(c) for c in type_.choices)
6582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if type_.property_type is PropertyType.REF:
6592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if type_.ref_type in self._types:
6602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return self._IsObjectType(self._types[type_.ref_type])
6612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return True
6622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (type_.property_type == PropertyType.OBJECT
6632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        and type_.instance_of in self._types):
6642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return self._IsObjectType(self._types[type_.instance_of])
6652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return False
6662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _IsObjectType(self, type_):
6682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Given a model.Type, returns whether this type is an object.
6692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
6702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return (self._IsSerializableObjectType(type_)
6712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            or type_.property_type in [PropertyType.OBJECT, PropertyType.ANY])
6722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _IsListOfSerializableObjects(self, type_):
6742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Given a model.Type, returns whether this type is a list of serializable
6752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    objects (or regular objects, if this list is treated as a type - in this
6762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case, the item type was defined inline).
6772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    If this type is a reference to something not in this namespace, assumes
6792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    it is not a list of serializable objects.
6802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
6812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if type_.property_type is PropertyType.CHOICES:
6822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return all(self._IsListOfSerializableObjects(c) for c in type_.choices)
6832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if type_.property_type is PropertyType.REF:
6842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if type_.ref_type in self._types:
6852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return self._IsListOfSerializableObjects(self._types[type_.ref_type])
6862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return False
6872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return (type_.property_type is PropertyType.ARRAY and
6882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        (self._IsSerializableObjectType(type_.item_type)))
6892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _IsListOfBaseTypes(self, type_):
6912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Given a model.Type, returns whether this type is a list of base type
6922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    objects (PropertyType.REF types).
6932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
6942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if type_.property_type is PropertyType.CHOICES:
6952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return all(self._IsListOfBaseTypes(c) for c in type_.choices)
6962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return (type_.property_type is PropertyType.ARRAY and
6972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            self._IsBaseType(type_.item_type))
6982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _IsBaseType(self, type_):
7002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Given a model.type_, returns whether this type is a base type
7012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    (string, number, boolean, or a list of these).
7022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    If type_ is a Choices object, returns True if all possible choices are base
7042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    types.
7052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
7062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # TODO(sashab): Remove 'Choices' as a base type once they are wrapped in
7072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # native Dart classes.
7082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if type_.property_type is PropertyType.CHOICES:
7092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return all(self._IsBaseType(c) for c in type_.choices)
7102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return (
7112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        (self._GetDartType(type_) in ['bool', 'num', 'int', 'double', 'String'])
7122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        or (type_.property_type is PropertyType.ARRAY
7132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            and self._IsBaseType(type_.item_type))
7142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    )
7152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def _GetDartType(self, type_):
7172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Given a model.Type object, returns its type as a Dart string.
7182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
7192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if type_ is None:
7202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return 'void'
7212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    prop_type = type_.property_type
7232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if prop_type is PropertyType.REF:
7242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if type_.ref_type in self._types:
7252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return self._GetDartType(self._types[type_.ref_type])
7262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # TODO(sashab): If the type is foreign, it might have to be imported.
7272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return StripNamespace(type_.ref_type)
7282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif prop_type is PropertyType.BOOLEAN:
7292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return 'bool'
7302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif prop_type is PropertyType.INTEGER:
7312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return 'int'
7322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif prop_type is PropertyType.INT64:
7332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return 'num'
7342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif prop_type is PropertyType.DOUBLE:
7352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return 'double'
7362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif prop_type is PropertyType.STRING:
7372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return 'String'
7382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif prop_type is PropertyType.ENUM:
7392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return 'String'
7402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif prop_type is PropertyType.CHOICES:
7412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # TODO(sashab): Think of a nice way to generate code for Choices objects
7422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # in Dart.
7432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return 'Object'
7442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif prop_type is PropertyType.ANY:
7452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return 'Object'
7462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif prop_type is PropertyType.OBJECT:
7472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # TODO(sashab): type_.name is the name of the function's parameter for
7482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # inline types defined in functions. Think of a way to generate names
7492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # for this, or remove all inline type definitions at the start.
7502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if type_.instance_of is not None:
7512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return type_.instance_of
7522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if not isinstance(type_.parent, Function):
7532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return self._AddPrefix(type_.name)
7542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return 'Object'
7552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif prop_type is PropertyType.FUNCTION:
7562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return 'Function'
7572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif prop_type is PropertyType.ARRAY:
7582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return 'List<%s>' % self._GetDartType(type_.item_type)
7592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    elif prop_type is PropertyType.BINARY:
7602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return 'String'
7612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else:
7622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      raise NotImplementedError(prop_type)
7632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
764