1 # Copyright 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
17 sys
.path
.append(os
.path
.join(os
.path
.dirname(__file__
), '..', '..',
22 class _PpapiGeneratorBase(object):
23 """A base class for ppapi generators.
25 Implementations should set TEMPLATE_NAME to a string containing the name of
26 the template file without its extension. The template will be rendered with
27 the following symbols available:
28 name: A string containing the name of the namespace.
29 enums: A list of enums within the namespace.
30 types: A list of types within the namespace, sorted such that no element
31 depends on an earlier element.
32 events: A dict of events within the namespace.
33 functions: A dict of functions within the namespace.
34 year: An int containing the current year.
35 source_file: The name of the input file.
38 def __init__(self
, namespace
):
39 self
._namespace
= namespace
40 self
._required
_types
= {}
41 self
._array
_types
= set()
42 self
._optional
_types
= set()
43 self
._optional
_array
_types
= set()
44 self
._dependencies
= collections
.OrderedDict()
48 self
.jinja_environment
= jinja2
.Environment(
49 loader
=jinja2
.FileSystemLoader(os
.path
.join(os
.path
.dirname(__file__
),
50 'templates', 'ppapi')))
52 self
._ResolveTypeDependencies
()
54 def _SetupFilters(self
):
55 self
.jinja_environment
.filters
.update({
56 'ppapi_type': self
.ToPpapiType
,
57 'classname': cpp_util
.Classname
,
58 'enum_value': self
.EnumValueName
,
59 'return_type': self
.GetFunctionReturnType
,
60 'format_param_type': self
.FormatParamType
,
61 'needs_optional': self
.NeedsOptional
,
62 'needs_array': self
.NeedsArray
,
63 'needs_optional_array': self
.NeedsOptionalArray
,
64 'has_array_outs': self
.HasArrayOuts
,
67 def Render(self
, template_name
, values
):
68 generated_code
= code
.Code()
69 template
= self
.jinja_environment
.get_template(
70 '%s.template' % template_name
)
71 generated_code
.Append(template
.render(values
))
75 """Generates a Code object for a single namespace."""
76 return self
.Render(self
.TEMPLATE_NAME
, {
77 'name': self
._namespace
.name
,
80 'events': self
._namespace
.events
,
81 'functions': self
._namespace
.functions
,
82 # TODO(sammc): Don't change years when regenerating existing output files.
83 'year': datetime
.date
.today().year
,
84 'source_file': self
._namespace
.source_file
,
87 def _ResolveTypeDependencies(self
):
88 """Calculates the transitive closure of the types in _required_types.
90 Returns a tuple containing the list of struct types and the list of enum
91 types. The list of struct types is ordered such that no type depends on a
92 type later in the list.
95 if self
._namespace
.functions
:
96 for function
in self
._namespace
.functions
.itervalues():
97 self
._FindFunctionDependencies
(function
)
99 if self
._namespace
.events
:
100 for event
in self
._namespace
.events
.itervalues():
101 self
._FindFunctionDependencies
(event
)
102 resolved_types
= set()
103 while resolved_types
< set(self
._required
_types
):
104 for typename
in sorted(set(self
._required
_types
) - resolved_types
):
105 type_
= self
._required
_types
[typename
]
106 self
._dependencies
.setdefault(typename
, set())
107 for member
in type_
.properties
.itervalues():
108 self
._RegisterDependency
(member
, self
._NameComponents
(type_
))
109 resolved_types
.add(typename
)
110 while self
._dependencies
:
111 for name
, deps
in self
._dependencies
.items():
113 if (self
._required
_types
[name
].property_type
==
114 model
.PropertyType
.ENUM
):
115 self
._enums
.append(self
._required
_types
[name
])
117 self
._types
.append(self
._required
_types
[name
])
118 for deps
in self
._dependencies
.itervalues():
120 del self
._dependencies
[name
]
123 raise ValueError('Circular dependency %s' % self
._dependencies
)
125 def _FindFunctionDependencies(self
, function
):
126 for param
in function
.params
:
127 self
._RegisterDependency
(param
, None)
128 if function
.callback
:
129 for param
in function
.callback
.params
:
130 self
._RegisterDependency
(param
, None)
132 self
._RegisterTypeDependency
(function
.returns
, None, False, False)
134 def _RegisterDependency(self
, member
, depender
):
135 self
._RegisterTypeDependency
(member
.type_
, depender
, member
.optional
, False)
137 def _RegisterTypeDependency(self
, type_
, depender
, optional
, array
):
138 if type_
.property_type
== model
.PropertyType
.ARRAY
:
139 self
._RegisterTypeDependency
(type_
.item_type
, depender
, optional
, True)
140 elif type_
.property_type
== model
.PropertyType
.REF
:
141 self
._RegisterTypeDependency
(self
._namespace
.types
[type_
.ref_type
],
142 depender
, optional
, array
)
143 elif type_
.property_type
in (model
.PropertyType
.OBJECT
,
144 model
.PropertyType
.ENUM
):
145 name_components
= self
._NameComponents
(type_
)
146 self
._required
_types
[name_components
] = type_
148 self
._dependencies
.setdefault(depender
, set()).add(
151 self
._array
_types
.add(name_components
)
153 self
._optional
_array
_types
.add(name_components
)
155 self
._optional
_types
.add(name_components
)
158 def _NameComponents(entity
):
159 """Returns a tuple of the fully-qualified name of an entity."""
162 if (not isinstance(entity
, model
.Type
) or
163 entity
.property_type
!= model
.PropertyType
.ARRAY
):
164 names
.append(entity
.name
)
165 entity
= entity
.parent
166 return tuple(reversed(names
[:-1]))
168 def ToPpapiType(self
, type_
, array
=False, optional
=False):
169 """Returns a string containing the name of the Pepper C type for |type_|.
171 If array is True, returns the name of an array of |type_|. If optional is
172 True, returns the name of an optional |type_|. If both array and optional
173 are True, returns the name of an optional array of |type_|.
175 if isinstance(type_
, model
.Function
) or type_
.property_type
in (
176 model
.PropertyType
.OBJECT
, model
.PropertyType
.ENUM
):
177 return self
._FormatPpapiTypeName
(
178 array
, optional
, '_'.join(
179 cpp_util
.Classname(s
) for s
in self
._NameComponents
(type_
)),
180 namespace
=cpp_util
.Classname(self
._namespace
.name
))
181 elif type_
.property_type
== model
.PropertyType
.REF
:
182 return self
.ToPpapiType(self
._namespace
.types
[type_
.ref_type
],
183 optional
=optional
, array
=array
)
184 elif type_
.property_type
== model
.PropertyType
.ARRAY
:
185 return self
.ToPpapiType(type_
.item_type
, array
=True,
187 elif type_
.property_type
== model
.PropertyType
.STRING
and not array
:
189 elif array
or optional
:
190 if type_
.property_type
in self
._PPAPI
_COMPOUND
_PRIMITIVE
_TYPE
_MAP
:
191 return self
._FormatPpapiTypeName
(
193 self
._PPAPI
_COMPOUND
_PRIMITIVE
_TYPE
_MAP
[type_
.property_type
], '')
194 return self
._PPAPI
_PRIMITIVE
_TYPE
_MAP
.get(type_
.property_type
, 'PP_Var')
196 _PPAPI_PRIMITIVE_TYPE_MAP
= {
197 model
.PropertyType
.BOOLEAN
: 'PP_Bool',
198 model
.PropertyType
.DOUBLE
: 'double_t',
199 model
.PropertyType
.INT64
: 'int64_t',
200 model
.PropertyType
.INTEGER
: 'int32_t',
202 _PPAPI_COMPOUND_PRIMITIVE_TYPE_MAP
= {
203 model
.PropertyType
.BOOLEAN
: 'Bool',
204 model
.PropertyType
.DOUBLE
: 'Double',
205 model
.PropertyType
.INT64
: 'Int64',
206 model
.PropertyType
.INTEGER
: 'Int32',
207 model
.PropertyType
.STRING
: 'String',
211 def _FormatPpapiTypeName(array
, optional
, name
, namespace
=''):
213 namespace
= '%s_' % namespace
216 return 'PP_%sOptional_%s_Array' % (namespace
, name
)
217 return 'PP_%s%s_Array' % (namespace
, name
)
219 return 'PP_%sOptional_%s' % (namespace
, name
)
220 return 'PP_%s%s' % (namespace
, name
)
222 def NeedsOptional(self
, type_
):
223 """Returns True if an optional |type_| is required."""
224 return self
._NameComponents
(type_
) in self
._optional
_types
226 def NeedsArray(self
, type_
):
227 """Returns True if an array of |type_| is required."""
228 return self
._NameComponents
(type_
) in self
._array
_types
230 def NeedsOptionalArray(self
, type_
):
231 """Returns True if an optional array of |type_| is required."""
232 return self
._NameComponents
(type_
) in self
._optional
_array
_types
234 def FormatParamType(self
, param
):
235 """Formats the type of a parameter or property."""
236 return self
.ToPpapiType(param
.type_
, optional
=param
.optional
)
239 def GetFunctionReturnType(function
):
240 return 'int32_t' if function
.callback
or function
.returns
else 'void'
242 def EnumValueName(self
, enum_value
, enum_type
):
243 """Returns a string containing the name for an enum value."""
244 return '%s_%s' % (self
.ToPpapiType(enum_type
).upper(),
245 enum_value
.name
.upper())
247 def _ResolveType(self
, type_
):
248 if type_
.property_type
== model
.PropertyType
.REF
:
249 return self
._ResolveType
(self
._namespace
.types
[type_
.ref_type
])
250 if type_
.property_type
== model
.PropertyType
.ARRAY
:
251 return self
._ResolveType
(type_
.item_type
)
254 def _IsOrContainsArray(self
, type_
):
255 if type_
.property_type
== model
.PropertyType
.ARRAY
:
257 type_
= self
._ResolveType
(type_
)
258 if type_
.property_type
== model
.PropertyType
.OBJECT
:
259 return any(self
._IsOrContainsArray
(param
.type_
)
260 for param
in type_
.properties
.itervalues())
263 def HasArrayOuts(self
, function
):
264 """Returns True if the function produces any arrays as outputs.
266 This includes arrays that are properties of other objects.
268 if function
.callback
:
269 for param
in function
.callback
.params
:
270 if self
._IsOrContainsArray
(param
.type_
):
272 return function
.returns
and self
._IsOrContainsArray
(function
.returns
)
275 class _IdlGenerator(_PpapiGeneratorBase
):
276 TEMPLATE_NAME
= 'idl'
279 class _GeneratorWrapper(object):
280 def __init__(self
, generator_factory
):
281 self
._generator
_factory
= generator_factory
283 def Generate(self
, namespace
):
284 return self
._generator
_factory
(namespace
).Generate()
287 class PpapiGenerator(object):
289 self
.idl_generator
= _GeneratorWrapper(_IdlGenerator
)