Commit 980a58e4 authored by Ken Rockot's avatar Ken Rockot Committed by Commit Bot

Apply Python formatting to mojom library

This is strictly a formatting change, generated by manually running yapf
over the affected files. It's a precursor to a subsequent move and minor
refactoring of this code, as modified files will always get yapf applied
and that would otherwise create a lot of noise in the coming CLs.

Bug: 1060467
Change-Id: I188ac6cc71fda2cd08a6f4695f67c5c0f04d2737
Tbr: oksamyt@chromium.org
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2098265Reviewed-by: default avatarKen Rockot <rockot@google.com>
Commit-Queue: Ken Rockot <rockot@google.com>
Cr-Commit-Position: refs/heads/master@{#749272}
parent 515438bc
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
class Error(Exception): class Error(Exception):
"""Base class for Mojo IDL bindings parser/generator errors.""" """Base class for Mojo IDL bindings parser/generator errors."""
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import errno import errno
import os.path import os.path
def EnsureDirectoryExists(path, always_try_to_create=False): def EnsureDirectoryExists(path, always_try_to_create=False):
"""A wrapper for os.makedirs that does not error if the directory already """A wrapper for os.makedirs that does not error if the directory already
exists. A different process could be racing to create this directory.""" exists. A different process could be racing to create this directory."""
......
# Copyright 2015 The Chromium Authors. All rights reserved. # Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
"""Resolves the values used for constants and enums.""" """Resolves the values used for constants and enums."""
from itertools import ifilter from itertools import ifilter
import mojom.generate.module as mojom import mojom.generate.module as mojom
def ResolveConstants(module, expression_to_text): def ResolveConstants(module, expression_to_text):
in_progress = set() in_progress = set()
computed = set() computed = set()
...@@ -14,8 +14,9 @@ def ResolveConstants(module, expression_to_text): ...@@ -14,8 +14,9 @@ def ResolveConstants(module, expression_to_text):
def GetResolvedValue(named_value): def GetResolvedValue(named_value):
assert isinstance(named_value, (mojom.EnumValue, mojom.ConstantValue)) assert isinstance(named_value, (mojom.EnumValue, mojom.ConstantValue))
if isinstance(named_value, mojom.EnumValue): if isinstance(named_value, mojom.EnumValue):
field = next(ifilter(lambda field: field.name == named_value.name, field = next(
named_value.enum.fields), None) ifilter(lambda field: field.name == named_value.name,
named_value.enum.fields), None)
if not field: if not field:
raise RuntimeError( raise RuntimeError(
'Unable to get computed value for field %s of enum %s' % 'Unable to get computed value for field %s of enum %s' %
......
# Copyright 2013 The Chromium Authors. All rights reserved. # Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
"""Code shared by the various language-specific code generators.""" """Code shared by the various language-specific code generators."""
from __future__ import print_function from __future__ import print_function
...@@ -35,6 +34,7 @@ def SplitCamelCase(identifier): ...@@ -35,6 +34,7 @@ def SplitCamelCase(identifier):
identifier = re.sub('([a-z][0-9]*)(?=[A-Z])', r'\1_', identifier) identifier = re.sub('([a-z][0-9]*)(?=[A-Z])', r'\1_', identifier)
return [x.lower() for x in identifier.split('_')] return [x.lower() for x in identifier.split('_')]
def ToCamel(identifier, lower_initial=False, dilimiter='_'): def ToCamel(identifier, lower_initial=False, dilimiter='_'):
"""Splits |identifier| using |dilimiter|, makes the first character of each """Splits |identifier| using |dilimiter|, makes the first character of each
word uppercased (but makes the first character of the first word lowercased word uppercased (but makes the first character of the first word lowercased
...@@ -42,11 +42,12 @@ def ToCamel(identifier, lower_initial=False, dilimiter='_'): ...@@ -42,11 +42,12 @@ def ToCamel(identifier, lower_initial=False, dilimiter='_'):
each word, all the characters except the first one are untouched. each word, all the characters except the first one are untouched.
""" """
result = ''.join(word[0].upper() + word[1:] result = ''.join(word[0].upper() + word[1:]
for word in identifier.split(dilimiter) if word) for word in identifier.split(dilimiter) if word)
if lower_initial and result: if lower_initial and result:
result = result[0].lower() + result[1:] result = result[0].lower() + result[1:]
return result return result
def ToConstantCase(identifier): def ToConstantCase(identifier):
"""Splits camel-cased |identifier| into lower case words, removes the first """Splits camel-cased |identifier| into lower case words, removes the first
word if it's "k" and joins them using "_" e.g. for "URLLoaderFactory", returns word if it's "k" and joins them using "_" e.g. for "URLLoaderFactory", returns
...@@ -62,6 +63,7 @@ def ToConstantCase(identifier): ...@@ -62,6 +63,7 @@ def ToConstantCase(identifier):
return '_'.join([word.upper() for word in words]) return '_'.join([word.upper() for word in words])
class Stylizer(object): class Stylizer(object):
"""Stylizers specify naming rules to map mojom names to names in generated """Stylizers specify naming rules to map mojom names to names in generated
code. For example, if you would like method_name in mojom to be mapped to code. For example, if you would like method_name in mojom to be mapped to
...@@ -167,8 +169,11 @@ def AddComputedData(module): ...@@ -167,8 +169,11 @@ def AddComputedData(module):
method.mojom_name) method.mojom_name)
struct = mojom.Struct(params_class, module=method.interface.module) struct = mojom.Struct(params_class, module=method.interface.module)
for param in method.parameters: for param in method.parameters:
struct.AddField(param.mojom_name, param.kind, param.ordinal, struct.AddField(
attributes=param.attributes) param.mojom_name,
param.kind,
param.ordinal,
attributes=param.attributes)
_AddStructComputedData(False, struct) _AddStructComputedData(False, struct)
return struct return struct
...@@ -178,8 +183,11 @@ def AddComputedData(module): ...@@ -178,8 +183,11 @@ def AddComputedData(module):
method.mojom_name) method.mojom_name)
struct = mojom.Struct(params_class, module=method.interface.module) struct = mojom.Struct(params_class, module=method.interface.module)
for param in method.response_parameters: for param in method.response_parameters:
struct.AddField(param.mojom_name, param.kind, param.ordinal, struct.AddField(
attributes=param.attributes) param.mojom_name,
param.kind,
param.ordinal,
attributes=param.attributes)
_AddStructComputedData(False, struct) _AddStructComputedData(False, struct)
return struct return struct
...@@ -194,15 +202,24 @@ def AddComputedData(module): ...@@ -194,15 +202,24 @@ def AddComputedData(module):
class Generator(object): class Generator(object):
# Pass |output_dir| to emit files to disk. Omit |output_dir| to echo all # Pass |output_dir| to emit files to disk. Omit |output_dir| to echo all
# files to stdout. # files to stdout.
def __init__(self, module, output_dir=None, typemap=None, variant=None, def __init__(self,
bytecode_path=None, for_blink=False, module,
output_dir=None,
typemap=None,
variant=None,
bytecode_path=None,
for_blink=False,
js_bindings_mode="new", js_bindings_mode="new",
js_generate_struct_deserializers=False, js_generate_struct_deserializers=False,
export_attribute=None, export_attribute=None,
export_header=None, generate_non_variant_code=False, export_header=None,
support_lazy_serialization=False, disallow_native_types=False, generate_non_variant_code=False,
disallow_interfaces=False, generate_message_ids=False, support_lazy_serialization=False,
generate_fuzzing=False, enable_kythe_annotations=False, disallow_native_types=False,
disallow_interfaces=False,
generate_message_ids=False,
generate_fuzzing=False,
enable_kythe_annotations=False,
extra_cpp_template_paths=None): extra_cpp_template_paths=None):
self.module = module self.module = module
self.output_dir = output_dir self.output_dir = output_dir
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
# method = interface.AddMethod('Tat', 0) # method = interface.AddMethod('Tat', 0)
# method.AddParameter('baz', 0, mojom.INT32) # method.AddParameter('baz', 0, mojom.INT32)
# We use our own version of __repr__ when displaying the AST, as the # We use our own version of __repr__ when displaying the AST, as the
# AST currently doesn't capture which nodes are reference (e.g. to # AST currently doesn't capture which nodes are reference (e.g. to
# types) and which nodes are definitions. This allows us to e.g. print # types) and which nodes are definitions. This allows us to e.g. print
...@@ -40,15 +41,16 @@ def Repr(obj, as_ref=True): ...@@ -40,15 +41,16 @@ def Repr(obj, as_ref=True):
if not obj: if not obj:
return '[]' return '[]'
else: else:
return ('[\n%s\n]' % (',\n'.join(' %s' % Repr(elem, as_ref).replace( return ('[\n%s\n]' % (',\n'.join(
'\n', '\n ') for elem in obj))) ' %s' % Repr(elem, as_ref).replace('\n', '\n ')
for elem in obj)))
elif isinstance(obj, dict): elif isinstance(obj, dict):
if not obj: if not obj:
return '{}' return '{}'
else: else:
return ('{\n%s\n}' % (',\n'.join(' %s: %s' % ( return ('{\n%s\n}' % (',\n'.join(
Repr(key, as_ref).replace('\n', '\n '), ' %s: %s' % (Repr(key, as_ref).replace('\n', '\n '),
Repr(val, as_ref).replace('\n', '\n ')) Repr(val, as_ref).replace('\n', '\n '))
for key, val in obj.items()))) for key, val in obj.items())))
else: else:
return repr(obj) return repr(obj)
...@@ -66,6 +68,7 @@ def GenericRepr(obj, names): ...@@ -66,6 +68,7 @@ def GenericRepr(obj, names):
Returns: Returns:
A str representation of |obj|. A str representation of |obj|.
""" """
def ReprIndent(name, as_ref): def ReprIndent(name, as_ref):
return ' %s=%s' % (name, Repr(getattr(obj, name), as_ref).replace( return ' %s=%s' % (name, Repr(getattr(obj, name), as_ref).replace(
'\n', '\n ')) '\n', '\n '))
...@@ -83,6 +86,7 @@ class Kind(object): ...@@ -83,6 +86,7 @@ class Kind(object):
parent_kind: The enclosing type. For example, an enum defined parent_kind: The enclosing type. For example, an enum defined
inside an interface has that interface as its parent. May be None. inside an interface has that interface as its parent. May be None.
""" """
def __init__(self, spec=None, module=None): def __init__(self, spec=None, module=None):
self.spec = spec self.spec = spec
self.module = module self.module = module
...@@ -105,6 +109,7 @@ class ReferenceKind(Kind): ...@@ -105,6 +109,7 @@ class ReferenceKind(Kind):
Attributes: Attributes:
is_nullable: True if the type is nullable. is_nullable: True if the type is nullable.
""" """
def __init__(self, spec=None, is_nullable=False, module=None): def __init__(self, spec=None, is_nullable=False, module=None):
assert spec is None or is_nullable == spec.startswith('?') assert spec is None or is_nullable == spec.startswith('?')
Kind.__init__(self, spec, module) Kind.__init__(self, spec, module)
...@@ -155,6 +160,7 @@ class ReferenceKind(Kind): ...@@ -155,6 +160,7 @@ class ReferenceKind(Kind):
a.name = 'test_struct_2' a.name = 'test_struct_2'
print(b.name) # Outputs 'test_struct_2'. print(b.name) # Outputs 'test_struct_2'.
""" """
def Get(self): def Get(self):
try: try:
return self.shared_definition[name] return self.shared_definition[name]
...@@ -168,63 +174,61 @@ class ReferenceKind(Kind): ...@@ -168,63 +174,61 @@ class ReferenceKind(Kind):
# Initialize the set of primitive types. These can be accessed by clients. # Initialize the set of primitive types. These can be accessed by clients.
BOOL = Kind('b') BOOL = Kind('b')
INT8 = Kind('i8') INT8 = Kind('i8')
INT16 = Kind('i16') INT16 = Kind('i16')
INT32 = Kind('i32') INT32 = Kind('i32')
INT64 = Kind('i64') INT64 = Kind('i64')
UINT8 = Kind('u8') UINT8 = Kind('u8')
UINT16 = Kind('u16') UINT16 = Kind('u16')
UINT32 = Kind('u32') UINT32 = Kind('u32')
UINT64 = Kind('u64') UINT64 = Kind('u64')
FLOAT = Kind('f') FLOAT = Kind('f')
DOUBLE = Kind('d') DOUBLE = Kind('d')
STRING = ReferenceKind('s') STRING = ReferenceKind('s')
HANDLE = ReferenceKind('h') HANDLE = ReferenceKind('h')
DCPIPE = ReferenceKind('h:d:c') DCPIPE = ReferenceKind('h:d:c')
DPPIPE = ReferenceKind('h:d:p') DPPIPE = ReferenceKind('h:d:p')
MSGPIPE = ReferenceKind('h:m') MSGPIPE = ReferenceKind('h:m')
SHAREDBUFFER = ReferenceKind('h:s') SHAREDBUFFER = ReferenceKind('h:s')
PLATFORMHANDLE = ReferenceKind('h:p') PLATFORMHANDLE = ReferenceKind('h:p')
NULLABLE_STRING = ReferenceKind('?s', True) NULLABLE_STRING = ReferenceKind('?s', True)
NULLABLE_HANDLE = ReferenceKind('?h', True) NULLABLE_HANDLE = ReferenceKind('?h', True)
NULLABLE_DCPIPE = ReferenceKind('?h:d:c', True) NULLABLE_DCPIPE = ReferenceKind('?h:d:c', True)
NULLABLE_DPPIPE = ReferenceKind('?h:d:p', True) NULLABLE_DPPIPE = ReferenceKind('?h:d:p', True)
NULLABLE_MSGPIPE = ReferenceKind('?h:m', True) NULLABLE_MSGPIPE = ReferenceKind('?h:m', True)
NULLABLE_SHAREDBUFFER = ReferenceKind('?h:s', True) NULLABLE_SHAREDBUFFER = ReferenceKind('?h:s', True)
NULLABLE_PLATFORMHANDLE = ReferenceKind('?h:p', True) NULLABLE_PLATFORMHANDLE = ReferenceKind('?h:p', True)
# Collection of all Primitive types # Collection of all Primitive types
PRIMITIVES = ( PRIMITIVES = (
BOOL, BOOL,
INT8, INT8,
INT16, INT16,
INT32, INT32,
INT64, INT64,
UINT8, UINT8,
UINT16, UINT16,
UINT32, UINT32,
UINT64, UINT64,
FLOAT, FLOAT,
DOUBLE, DOUBLE,
STRING, STRING,
HANDLE, HANDLE,
DCPIPE, DCPIPE,
DPPIPE, DPPIPE,
MSGPIPE, MSGPIPE,
SHAREDBUFFER, SHAREDBUFFER,
PLATFORMHANDLE, PLATFORMHANDLE,
NULLABLE_STRING, NULLABLE_STRING,
NULLABLE_HANDLE, NULLABLE_HANDLE,
NULLABLE_DCPIPE, NULLABLE_DCPIPE,
NULLABLE_DPPIPE, NULLABLE_DPPIPE,
NULLABLE_MSGPIPE, NULLABLE_MSGPIPE,
NULLABLE_SHAREDBUFFER, NULLABLE_SHAREDBUFFER,
NULLABLE_PLATFORMHANDLE, NULLABLE_PLATFORMHANDLE,
) )
ATTRIBUTE_MIN_VERSION = 'MinVersion' ATTRIBUTE_MIN_VERSION = 'MinVersion'
ATTRIBUTE_EXTENSIBLE = 'Extensible' ATTRIBUTE_EXTENSIBLE = 'Extensible'
ATTRIBUTE_SYNC = 'Sync' ATTRIBUTE_SYNC = 'Sync'
...@@ -238,8 +242,8 @@ class NamedValue(object): ...@@ -238,8 +242,8 @@ class NamedValue(object):
def GetSpec(self): def GetSpec(self):
return (self.module.mojom_namespace + '.' + return (self.module.mojom_namespace + '.' +
(self.parent_kind and (self.parent_kind.mojom_name + '.') or "") + (self.parent_kind and
self.mojom_name) (self.parent_kind.mojom_name + '.') or "") + self.mojom_name)
class BuiltinValue(object): class BuiltinValue(object):
...@@ -265,8 +269,8 @@ class EnumValue(NamedValue): ...@@ -265,8 +269,8 @@ class EnumValue(NamedValue):
def GetSpec(self): def GetSpec(self):
return (self.module.mojom_namespace + '.' + return (self.module.mojom_namespace + '.' +
(self.parent_kind and (self.parent_kind.mojom_name + '.') or "") + (self.parent_kind and (self.parent_kind.mojom_name + '.')
self.enum.mojom_name + '.' + self.mojom_name) or "") + self.enum.mojom_name + '.' + self.mojom_name)
@property @property
def name(self): def name(self):
...@@ -285,7 +289,11 @@ class Constant(object): ...@@ -285,7 +289,11 @@ class Constant(object):
class Field(object): class Field(object):
def __init__(self, mojom_name=None, kind=None, ordinal=None, default=None, def __init__(self,
mojom_name=None,
kind=None,
ordinal=None,
default=None,
attributes=None): attributes=None):
if self.__class__.__name__ == 'Field': if self.__class__.__name__ == 'Field':
raise Exception() raise Exception()
...@@ -309,10 +317,12 @@ class Field(object): ...@@ -309,10 +317,12 @@ class Field(object):
if self.attributes else None if self.attributes else None
class StructField(Field): pass class StructField(Field):
pass
class UnionField(Field): pass class UnionField(Field):
pass
class Struct(ReferenceKind): class Struct(ReferenceKind):
...@@ -357,14 +367,21 @@ class Struct(ReferenceKind): ...@@ -357,14 +367,21 @@ class Struct(ReferenceKind):
def Repr(self, as_ref=True): def Repr(self, as_ref=True):
if as_ref: if as_ref:
return '<%s mojom_name=%r module=%s>' % ( return '<%s mojom_name=%r module=%s>' % (self.__class__.__name__,
self.__class__.__name__, self.mojom_name, self.mojom_name,
Repr(self.module, as_ref=True)) Repr(self.module, as_ref=True))
else: else:
return GenericRepr(self, return GenericRepr(self, {
{'mojom_name': False, 'fields': False, 'module': True}) 'mojom_name': False,
'fields': False,
def AddField(self, mojom_name, kind, ordinal=None, default=None, 'module': True
})
def AddField(self,
mojom_name,
kind,
ordinal=None,
default=None,
attributes=None): attributes=None):
field = StructField(mojom_name, kind, ordinal, default, attributes) field = StructField(mojom_name, kind, ordinal, default, attributes)
self.fields.append(field) self.fields.append(field)
...@@ -409,8 +426,8 @@ class Union(ReferenceKind): ...@@ -409,8 +426,8 @@ class Union(ReferenceKind):
def Repr(self, as_ref=True): def Repr(self, as_ref=True):
if as_ref: if as_ref:
return '<%s spec=%r is_nullable=%r fields=%s>' % ( return '<%s spec=%r is_nullable=%r fields=%s>' % (
self.__class__.__name__, self.spec, self.is_nullable, self.__class__.__name__, self.spec, self.is_nullable, Repr(
Repr(self.fields)) self.fields))
else: else:
return GenericRepr(self, {'fields': True, 'is_nullable': False}) return GenericRepr(self, {'fields': True, 'is_nullable': False})
...@@ -452,11 +469,14 @@ class Array(ReferenceKind): ...@@ -452,11 +469,14 @@ class Array(ReferenceKind):
def Repr(self, as_ref=True): def Repr(self, as_ref=True):
if as_ref: if as_ref:
return '<%s spec=%r is_nullable=%r kind=%s length=%r>' % ( return '<%s spec=%r is_nullable=%r kind=%s length=%r>' % (
self.__class__.__name__, self.spec, self.is_nullable, Repr(self.kind), self.__class__.__name__, self.spec, self.is_nullable, Repr(
self.length) self.kind), self.length)
else: else:
return GenericRepr(self, {'kind': True, 'length': False, return GenericRepr(self, {
'is_nullable': False}) 'kind': True,
'length': False,
'is_nullable': False
})
class Map(ReferenceKind): class Map(ReferenceKind):
...@@ -471,9 +491,8 @@ class Map(ReferenceKind): ...@@ -471,9 +491,8 @@ class Map(ReferenceKind):
def __init__(self, key_kind=None, value_kind=None): def __init__(self, key_kind=None, value_kind=None):
if (key_kind is not None and value_kind is not None): if (key_kind is not None and value_kind is not None):
ReferenceKind.__init__(self, ReferenceKind.__init__(
'm[' + key_kind.spec + '][' + value_kind.spec + self, 'm[' + key_kind.spec + '][' + value_kind.spec + ']')
']')
if IsNullableKind(key_kind): if IsNullableKind(key_kind):
raise Exception("Nullable kinds cannot be keys in maps.") raise Exception("Nullable kinds cannot be keys in maps.")
if IsAnyHandleKind(key_kind): if IsAnyHandleKind(key_kind):
...@@ -588,7 +607,11 @@ class AssociatedInterfaceRequest(ReferenceKind): ...@@ -588,7 +607,11 @@ class AssociatedInterfaceRequest(ReferenceKind):
class Parameter(object): class Parameter(object):
def __init__(self, mojom_name=None, kind=None, ordinal=None, default=None, def __init__(self,
mojom_name=None,
kind=None,
ordinal=None,
default=None,
attributes=None): attributes=None):
self.mojom_name = mojom_name self.mojom_name = mojom_name
self.ordinal = ordinal self.ordinal = ordinal
...@@ -624,16 +647,27 @@ class Method(object): ...@@ -624,16 +647,27 @@ class Method(object):
if as_ref: if as_ref:
return '<%s mojom_name=%r>' % (self.__class__.__name__, self.mojom_name) return '<%s mojom_name=%r>' % (self.__class__.__name__, self.mojom_name)
else: else:
return GenericRepr(self, {'mojom_name': False, 'parameters': True, return GenericRepr(self, {
'response_parameters': True}) 'mojom_name': False,
'parameters': True,
def AddParameter(self, mojom_name, kind, ordinal=None, default=None, 'response_parameters': True
})
def AddParameter(self,
mojom_name,
kind,
ordinal=None,
default=None,
attributes=None): attributes=None):
parameter = Parameter(mojom_name, kind, ordinal, default, attributes) parameter = Parameter(mojom_name, kind, ordinal, default, attributes)
self.parameters.append(parameter) self.parameters.append(parameter)
return parameter return parameter
def AddResponseParameter(self, mojom_name, kind, ordinal=None, default=None, def AddResponseParameter(self,
mojom_name,
kind,
ordinal=None,
default=None,
attributes=None): attributes=None):
if self.response_parameters == None: if self.response_parameters == None:
self.response_parameters = [] self.response_parameters = []
...@@ -689,8 +723,11 @@ class Interface(ReferenceKind): ...@@ -689,8 +723,11 @@ class Interface(ReferenceKind):
if as_ref: if as_ref:
return '<%s mojom_name=%r>' % (self.__class__.__name__, self.mojom_name) return '<%s mojom_name=%r>' % (self.__class__.__name__, self.mojom_name)
else: else:
return GenericRepr(self, {'mojom_name': False, 'attributes': False, return GenericRepr(self, {
'methods': False}) 'mojom_name': False,
'attributes': False,
'methods': False
})
def AddMethod(self, mojom_name, ordinal=None, attributes=None): def AddMethod(self, mojom_name, ordinal=None, attributes=None):
method = Method(self, mojom_name, ordinal, attributes) method = Method(self, mojom_name, ordinal, attributes)
...@@ -723,7 +760,10 @@ class AssociatedInterface(ReferenceKind): ...@@ -723,7 +760,10 @@ class AssociatedInterface(ReferenceKind):
class EnumField(object): class EnumField(object):
def __init__(self, mojom_name=None, value=None, attributes=None, def __init__(self,
mojom_name=None,
value=None,
attributes=None,
numeric_value=None): numeric_value=None):
self.mojom_name = mojom_name self.mojom_name = mojom_name
self.value = value self.value = value
...@@ -771,8 +811,7 @@ class Enum(Kind): ...@@ -771,8 +811,7 @@ class Enum(Kind):
class Module(object): class Module(object):
def __init__(self, path=None, mojom_namespace=None, def __init__(self, path=None, mojom_namespace=None, attributes=None):
attributes=None):
self.path = path self.path = path
self.mojom_namespace = mojom_namespace self.mojom_namespace = mojom_namespace
self.structs = [] self.structs = []
...@@ -794,9 +833,15 @@ class Module(object): ...@@ -794,9 +833,15 @@ class Module(object):
return '<%s path=%r mojom_namespace=%r>' % ( return '<%s path=%r mojom_namespace=%r>' % (
self.__class__.__name__, self.path, self.mojom_namespace) self.__class__.__name__, self.path, self.mojom_namespace)
else: else:
return GenericRepr(self, {'path': False, 'mojom_namespace': False, return GenericRepr(
'attributes': False, 'structs': False, self, {
'interfaces': False, 'unions': False}) 'path': False,
'mojom_namespace': False,
'attributes': False,
'structs': False,
'interfaces': False,
'unions': False
})
def AddInterface(self, mojom_name, attributes=None): def AddInterface(self, mojom_name, attributes=None):
interface = Interface(mojom_name, self, attributes) interface = Interface(mojom_name, self, attributes)
...@@ -843,15 +888,11 @@ def IsDoubleKind(kind): ...@@ -843,15 +888,11 @@ def IsDoubleKind(kind):
def IsIntegralKind(kind): def IsIntegralKind(kind):
return (kind.spec == BOOL.spec or return (kind.spec == BOOL.spec or kind.spec == INT8.spec
kind.spec == INT8.spec or or kind.spec == INT16.spec or kind.spec == INT32.spec
kind.spec == INT16.spec or or kind.spec == INT64.spec or kind.spec == UINT8.spec
kind.spec == INT32.spec or or kind.spec == UINT16.spec or kind.spec == UINT32.spec
kind.spec == INT64.spec or or kind.spec == UINT64.spec)
kind.spec == UINT8.spec or
kind.spec == UINT16.spec or
kind.spec == UINT32.spec or
kind.spec == UINT64.spec)
def IsStringKind(kind): def IsStringKind(kind):
...@@ -875,13 +916,13 @@ def IsMessagePipeKind(kind): ...@@ -875,13 +916,13 @@ def IsMessagePipeKind(kind):
def IsSharedBufferKind(kind): def IsSharedBufferKind(kind):
return (kind.spec == SHAREDBUFFER.spec or return (kind.spec == SHAREDBUFFER.spec
kind.spec == NULLABLE_SHAREDBUFFER.spec) or kind.spec == NULLABLE_SHAREDBUFFER.spec)
def IsPlatformHandleKind(kind): def IsPlatformHandleKind(kind):
return (kind.spec == PLATFORMHANDLE.spec or return (kind.spec == PLATFORMHANDLE.spec
kind.spec == NULLABLE_PLATFORMHANDLE.spec) or kind.spec == NULLABLE_PLATFORMHANDLE.spec)
def IsStructKind(kind): def IsStructKind(kind):
...@@ -911,6 +952,7 @@ def IsInterfaceRequestKind(kind): ...@@ -911,6 +952,7 @@ def IsInterfaceRequestKind(kind):
def IsAssociatedInterfaceRequestKind(kind): def IsAssociatedInterfaceRequestKind(kind):
return isinstance(kind, AssociatedInterfaceRequest) return isinstance(kind, AssociatedInterfaceRequest)
def IsPendingRemoteKind(kind): def IsPendingRemoteKind(kind):
return isinstance(kind, PendingRemote) return isinstance(kind, PendingRemote)
...@@ -948,24 +990,21 @@ def IsObjectKind(kind): ...@@ -948,24 +990,21 @@ def IsObjectKind(kind):
def IsPointerKind(kind): def IsPointerKind(kind):
return (IsStructKind(kind) or IsArrayKind(kind) or IsStringKind(kind) or return (IsStructKind(kind) or IsArrayKind(kind) or IsStringKind(kind)
IsMapKind(kind)) or IsMapKind(kind))
# Please note that it doesn't include any interface kind. # Please note that it doesn't include any interface kind.
def IsAnyHandleKind(kind): def IsAnyHandleKind(kind):
return (IsGenericHandleKind(kind) or return (IsGenericHandleKind(kind) or IsDataPipeConsumerKind(kind)
IsDataPipeConsumerKind(kind) or or IsDataPipeProducerKind(kind) or IsMessagePipeKind(kind)
IsDataPipeProducerKind(kind) or or IsSharedBufferKind(kind) or IsPlatformHandleKind(kind))
IsMessagePipeKind(kind) or
IsSharedBufferKind(kind) or
IsPlatformHandleKind(kind))
def IsAnyInterfaceKind(kind): def IsAnyInterfaceKind(kind):
return (IsInterfaceKind(kind) or IsInterfaceRequestKind(kind) or return (IsInterfaceKind(kind) or IsInterfaceRequestKind(kind)
IsAssociatedKind(kind) or IsPendingRemoteKind(kind) or or IsAssociatedKind(kind) or IsPendingRemoteKind(kind)
IsPendingReceiverKind(kind)) or IsPendingReceiverKind(kind))
def IsAnyHandleOrInterfaceKind(kind): def IsAnyHandleOrInterfaceKind(kind):
...@@ -973,10 +1012,10 @@ def IsAnyHandleOrInterfaceKind(kind): ...@@ -973,10 +1012,10 @@ def IsAnyHandleOrInterfaceKind(kind):
def IsAssociatedKind(kind): def IsAssociatedKind(kind):
return (IsAssociatedInterfaceKind(kind) or return (IsAssociatedInterfaceKind(kind)
IsAssociatedInterfaceRequestKind(kind) or or IsAssociatedInterfaceRequestKind(kind)
IsPendingAssociatedRemoteKind(kind) or or IsPendingAssociatedRemoteKind(kind)
IsPendingAssociatedReceiverKind(kind)) or IsPendingAssociatedReceiverKind(kind))
def HasCallbacks(interface): def HasCallbacks(interface):
...@@ -1011,7 +1050,7 @@ def _AnyMethodParameterRecursive(method, predicate, visited_kinds=None): ...@@ -1011,7 +1050,7 @@ def _AnyMethodParameterRecursive(method, predicate, visited_kinds=None):
if _HasProperty(field.kind): if _HasProperty(field.kind):
return True return True
if IsMapKind(kind): if IsMapKind(kind):
if _HasProperty(kind.key_kind) or _HasProperty(kind.value_kind): if _HasProperty(kind.key_kind) or _HasProperty(kind.value_kind):
return True return True
return False return False
...@@ -1031,8 +1070,8 @@ def _AnyMethodParameterRecursive(method, predicate, visited_kinds=None): ...@@ -1031,8 +1070,8 @@ def _AnyMethodParameterRecursive(method, predicate, visited_kinds=None):
# Finds out whether a method passes associated interfaces and associated # Finds out whether a method passes associated interfaces and associated
# interface requests. # interface requests.
def MethodPassesAssociatedKinds(method, visited_kinds=None): def MethodPassesAssociatedKinds(method, visited_kinds=None):
return _AnyMethodParameterRecursive(method, IsAssociatedKind, return _AnyMethodParameterRecursive(
visited_kinds=visited_kinds) method, IsAssociatedKind, visited_kinds=visited_kinds)
# Determines whether a method passes interfaces. # Determines whether a method passes interfaces.
...@@ -1062,6 +1101,7 @@ def ContainsHandlesOrInterfaces(kind): ...@@ -1062,6 +1101,7 @@ def ContainsHandlesOrInterfaces(kind):
# We remember the types we already checked to avoid infinite recursion when # We remember the types we already checked to avoid infinite recursion when
# checking recursive (or mutually recursive) types: # checking recursive (or mutually recursive) types:
checked = set() checked = set()
def Check(kind): def Check(kind):
if kind.spec in checked: if kind.spec in checked:
return False return False
...@@ -1080,6 +1120,7 @@ def ContainsHandlesOrInterfaces(kind): ...@@ -1080,6 +1120,7 @@ def ContainsHandlesOrInterfaces(kind):
return Check(kind.key_kind) or Check(kind.value_kind) return Check(kind.key_kind) or Check(kind.value_kind)
else: else:
return False return False
return Check(kind) return Check(kind)
...@@ -1098,6 +1139,7 @@ def ContainsNativeTypes(kind): ...@@ -1098,6 +1139,7 @@ def ContainsNativeTypes(kind):
# We remember the types we already checked to avoid infinite recursion when # We remember the types we already checked to avoid infinite recursion when
# checking recursive (or mutually recursive) types: # checking recursive (or mutually recursive) types:
checked = set() checked = set()
def Check(kind): def Check(kind):
if kind.spec in checked: if kind.spec in checked:
return False return False
...@@ -1120,4 +1162,5 @@ def ContainsNativeTypes(kind): ...@@ -1120,4 +1162,5 @@ def ContainsNativeTypes(kind):
return Check(kind.key_kind) or Check(kind.value_kind) return Check(kind.key_kind) or Check(kind.value_kind)
else: else:
return False return False
return Check(kind) return Check(kind)
...@@ -14,47 +14,49 @@ import mojom.generate.module as mojom ...@@ -14,47 +14,49 @@ import mojom.generate.module as mojom
# Size of struct header in bytes: num_bytes [4B] + version [4B]. # Size of struct header in bytes: num_bytes [4B] + version [4B].
HEADER_SIZE = 8 HEADER_SIZE = 8
class PackedField(object): class PackedField(object):
kind_to_size = { kind_to_size = {
mojom.BOOL: 1, mojom.BOOL: 1,
mojom.INT8: 1, mojom.INT8: 1,
mojom.UINT8: 1, mojom.UINT8: 1,
mojom.INT16: 2, mojom.INT16: 2,
mojom.UINT16: 2, mojom.UINT16: 2,
mojom.INT32: 4, mojom.INT32: 4,
mojom.UINT32: 4, mojom.UINT32: 4,
mojom.FLOAT: 4, mojom.FLOAT: 4,
mojom.HANDLE: 4, mojom.HANDLE: 4,
mojom.MSGPIPE: 4, mojom.MSGPIPE: 4,
mojom.SHAREDBUFFER: 4, mojom.SHAREDBUFFER: 4,
mojom.PLATFORMHANDLE: 4, mojom.PLATFORMHANDLE: 4,
mojom.DCPIPE: 4, mojom.DCPIPE: 4,
mojom.DPPIPE: 4, mojom.DPPIPE: 4,
mojom.NULLABLE_HANDLE: 4, mojom.NULLABLE_HANDLE: 4,
mojom.NULLABLE_MSGPIPE: 4, mojom.NULLABLE_MSGPIPE: 4,
mojom.NULLABLE_SHAREDBUFFER: 4, mojom.NULLABLE_SHAREDBUFFER: 4,
mojom.NULLABLE_PLATFORMHANDLE: 4, mojom.NULLABLE_PLATFORMHANDLE: 4,
mojom.NULLABLE_DCPIPE: 4, mojom.NULLABLE_DCPIPE: 4,
mojom.NULLABLE_DPPIPE: 4, mojom.NULLABLE_DPPIPE: 4,
mojom.INT64: 8, mojom.INT64: 8,
mojom.UINT64: 8, mojom.UINT64: 8,
mojom.DOUBLE: 8, mojom.DOUBLE: 8,
mojom.STRING: 8, mojom.STRING: 8,
mojom.NULLABLE_STRING: 8 mojom.NULLABLE_STRING: 8
} }
@classmethod @classmethod
def GetSizeForKind(cls, kind): def GetSizeForKind(cls, kind):
if isinstance(kind, (mojom.Array, mojom.Map, mojom.Struct, if isinstance(kind, (mojom.Array, mojom.Map, mojom.Struct, mojom.Interface,
mojom.Interface, mojom.AssociatedInterface, mojom.AssociatedInterface, mojom.PendingRemote,
mojom.PendingRemote, mojom.PendingAssociatedRemote)): mojom.PendingAssociatedRemote)):
return 8 return 8
if isinstance(kind, mojom.Union): if isinstance(kind, mojom.Union):
return 16 return 16
if isinstance(kind, (mojom.InterfaceRequest, mojom.PendingReceiver)): if isinstance(kind, (mojom.InterfaceRequest, mojom.PendingReceiver)):
kind = mojom.MSGPIPE kind = mojom.MSGPIPE
if isinstance(kind, (mojom.AssociatedInterfaceRequest, if isinstance(
mojom.PendingAssociatedReceiver)): kind,
(mojom.AssociatedInterfaceRequest, mojom.PendingAssociatedReceiver)):
return 4 return 4
if isinstance(kind, mojom.Enum): if isinstance(kind, mojom.Enum):
# TODO(mpcomplete): what about big enums? # TODO(mpcomplete): what about big enums?
...@@ -98,9 +100,8 @@ def GetPad(offset, alignment): ...@@ -98,9 +100,8 @@ def GetPad(offset, alignment):
def GetFieldOffset(field, last_field): def GetFieldOffset(field, last_field):
"""Returns a 2-tuple of the field offset and bit (for BOOLs).""" """Returns a 2-tuple of the field offset and bit (for BOOLs)."""
if (field.field.kind == mojom.BOOL and if (field.field.kind == mojom.BOOL and last_field.field.kind == mojom.BOOL
last_field.field.kind == mojom.BOOL and and last_field.bit < 7):
last_field.bit < 7):
return (last_field.offset, last_field.bit + 1) return (last_field.offset, last_field.bit + 1)
offset = last_field.offset + last_field.size offset = last_field.offset + last_field.size
...@@ -152,13 +153,13 @@ class PackedStruct(object): ...@@ -152,13 +153,13 @@ class PackedStruct(object):
next_min_version = packed_field.field.min_version next_min_version = packed_field.field.min_version
packed_field.min_version = next_min_version packed_field.min_version = next_min_version
if (packed_field.min_version != 0 and if (packed_field.min_version != 0
mojom.IsReferenceKind(packed_field.field.kind) and and mojom.IsReferenceKind(packed_field.field.kind)
not packed_field.field.kind.is_nullable): and not packed_field.field.kind.is_nullable):
raise Exception("Non-nullable fields are only allowed in version 0 of " raise Exception("Non-nullable fields are only allowed in version 0 of "
"a struct. %s.%s is defined with [MinVersion=%d]." "a struct. %s.%s is defined with [MinVersion=%d]." %
% (self.struct.name, packed_field.field.name, (self.struct.name, packed_field.field.name,
packed_field.min_version)) packed_field.min_version))
src_field = src_fields[0] src_field = src_fields[0]
src_field.offset = 0 src_field.offset = 0
...@@ -247,10 +248,11 @@ def GetVersionInfo(packed_struct): ...@@ -247,10 +248,11 @@ def GetVersionInfo(packed_struct):
# The fields are iterated in ordinal order here. However, the size of a # The fields are iterated in ordinal order here. However, the size of a
# version is determined by the last field of that version in pack order, # version is determined by the last field of that version in pack order,
# instead of ordinal order. Therefore, we need to calculate the max value. # instead of ordinal order. Therefore, we need to calculate the max value.
last_payload_size = max(GetPayloadSizeUpToField(packed_field), last_payload_size = max(
last_payload_size) GetPayloadSizeUpToField(packed_field), last_payload_size)
assert len(versions) == 0 or last_num_fields != versions[-1].num_fields assert len(versions) == 0 or last_num_fields != versions[-1].num_fields
versions.append(VersionInfo(last_version, last_num_fields, versions.append(
last_payload_size + HEADER_SIZE)) VersionInfo(last_version, last_num_fields,
last_payload_size + HEADER_SIZE))
return versions return versions
...@@ -16,57 +16,66 @@ import jinja2 ...@@ -16,57 +16,66 @@ import jinja2
def ApplyTemplate(mojo_generator, path_to_template, params, **kwargs): def ApplyTemplate(mojo_generator, path_to_template, params, **kwargs):
loader = jinja2.ModuleLoader(os.path.join( loader = jinja2.ModuleLoader(
mojo_generator.bytecode_path, "%s.zip" % mojo_generator.GetTemplatePrefix( os.path.join(mojo_generator.bytecode_path,
))) "%s.zip" % mojo_generator.GetTemplatePrefix()))
final_kwargs = dict(mojo_generator.GetJinjaParameters()) final_kwargs = dict(mojo_generator.GetJinjaParameters())
final_kwargs.update(kwargs) final_kwargs.update(kwargs)
jinja_env = jinja2.Environment(loader=loader, jinja_env = jinja2.Environment(
keep_trailing_newline=True, loader=loader, keep_trailing_newline=True, **final_kwargs)
**final_kwargs)
jinja_env.globals.update(mojo_generator.GetGlobals()) jinja_env.globals.update(mojo_generator.GetGlobals())
jinja_env.filters.update(mojo_generator.GetFilters()) jinja_env.filters.update(mojo_generator.GetFilters())
template = jinja_env.get_template(path_to_template) template = jinja_env.get_template(path_to_template)
return template.render(params) return template.render(params)
def UseJinja(path_to_template, **kwargs): def UseJinja(path_to_template, **kwargs):
def RealDecorator(generator): def RealDecorator(generator):
def GeneratorInternal(*args, **kwargs2): def GeneratorInternal(*args, **kwargs2):
parameters = generator(*args, **kwargs2) parameters = generator(*args, **kwargs2)
return ApplyTemplate(args[0], path_to_template, parameters, **kwargs) return ApplyTemplate(args[0], path_to_template, parameters, **kwargs)
GeneratorInternal.__name__ = generator.__name__ GeneratorInternal.__name__ = generator.__name__
return GeneratorInternal return GeneratorInternal
return RealDecorator return RealDecorator
def ApplyImportedTemplate(mojo_generator, path_to_template, filename, params, **kwargs): def ApplyImportedTemplate(mojo_generator, path_to_template, filename, params,
**kwargs):
loader = jinja2.FileSystemLoader(searchpath=path_to_template) loader = jinja2.FileSystemLoader(searchpath=path_to_template)
final_kwargs = dict(mojo_generator.GetJinjaParameters()) final_kwargs = dict(mojo_generator.GetJinjaParameters())
final_kwargs.update(kwargs) final_kwargs.update(kwargs)
jinja_env = jinja2.Environment(loader=loader, jinja_env = jinja2.Environment(
keep_trailing_newline=True, loader=loader, keep_trailing_newline=True, **final_kwargs)
**final_kwargs)
jinja_env.globals.update(mojo_generator.GetGlobals()) jinja_env.globals.update(mojo_generator.GetGlobals())
jinja_env.filters.update(mojo_generator.GetFilters()) jinja_env.filters.update(mojo_generator.GetFilters())
template = jinja_env.get_template(filename) template = jinja_env.get_template(filename)
return template.render(params) return template.render(params)
def UseJinjaForImportedTemplate(func): def UseJinjaForImportedTemplate(func):
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
parameters = func(*args, **kwargs) parameters = func(*args, **kwargs)
path_to_template = args[1] path_to_template = args[1]
filename = args[2] filename = args[2]
return ApplyImportedTemplate(args[0], path_to_template, filename, parameters) return ApplyImportedTemplate(args[0], path_to_template, filename,
parameters)
wrapper.__name__ = func.__name__ wrapper.__name__ = func.__name__
return wrapper return wrapper
def PrecompileTemplates(generator_modules, output_dir): def PrecompileTemplates(generator_modules, output_dir):
for module in generator_modules.values(): for module in generator_modules.values():
generator = module.Generator(None) generator = module.Generator(None)
jinja_env = jinja2.Environment(loader=jinja2.FileSystemLoader([os.path.join( jinja_env = jinja2.Environment(
os.path.dirname(module.__file__), generator.GetTemplatePrefix())])) loader=jinja2.FileSystemLoader([
os.path.join(
os.path.dirname(module.__file__), generator.GetTemplatePrefix())
]))
jinja_env.filters.update(generator.GetFilters()) jinja_env.filters.update(generator.GetFilters())
jinja_env.compile_templates( jinja_env.compile_templates(
os.path.join(output_dir, "%s.zip" % generator.GetTemplatePrefix()), os.path.join(output_dir, "%s.zip" % generator.GetTemplatePrefix()),
......
# Copyright 2013 The Chromium Authors. All rights reserved. # Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
"""Convert parse tree to AST. """Convert parse tree to AST.
This module converts the parse tree to the AST we use for code generation. The This module converts the parse tree to the AST we use for code generation. The
...@@ -17,6 +16,7 @@ import re ...@@ -17,6 +16,7 @@ import re
import mojom.generate.module as mojom import mojom.generate.module as mojom
from mojom.parse import ast from mojom.parse import ast
def _DuplicateName(values): def _DuplicateName(values):
"""Returns the 'mojom_name' of the first entry in |values| whose 'mojom_name' """Returns the 'mojom_name' of the first entry in |values| whose 'mojom_name'
has already been encountered. If there are no duplicates, returns None.""" has already been encountered. If there are no duplicates, returns None."""
...@@ -27,6 +27,7 @@ def _DuplicateName(values): ...@@ -27,6 +27,7 @@ def _DuplicateName(values):
names.add(value.mojom_name) names.add(value.mojom_name)
return None return None
def _ElemsOfType(elems, elem_type, scope): def _ElemsOfType(elems, elem_type, scope):
"""Find all elements of the given type. """Find all elements of the given type.
...@@ -48,25 +49,28 @@ def _ElemsOfType(elems, elem_type, scope): ...@@ -48,25 +49,28 @@ def _ElemsOfType(elems, elem_type, scope):
(duplicate_name, scope)) (duplicate_name, scope))
return result return result
def _MapKind(kind): def _MapKind(kind):
map_to_kind = {'bool': 'b', map_to_kind = {
'int8': 'i8', 'bool': 'b',
'int16': 'i16', 'int8': 'i8',
'int32': 'i32', 'int16': 'i16',
'int64': 'i64', 'int32': 'i32',
'uint8': 'u8', 'int64': 'i64',
'uint16': 'u16', 'uint8': 'u8',
'uint32': 'u32', 'uint16': 'u16',
'uint64': 'u64', 'uint32': 'u32',
'float': 'f', 'uint64': 'u64',
'double': 'd', 'float': 'f',
'string': 's', 'double': 'd',
'handle': 'h', 'string': 's',
'handle<data_pipe_consumer>': 'h:d:c', 'handle': 'h',
'handle<data_pipe_producer>': 'h:d:p', 'handle<data_pipe_consumer>': 'h:d:c',
'handle<message_pipe>': 'h:m', 'handle<data_pipe_producer>': 'h:d:p',
'handle<shared_buffer>': 'h:s', 'handle<message_pipe>': 'h:m',
'handle<platform>': 'h:p'} 'handle<shared_buffer>': 'h:s',
'handle<platform>': 'h:p'
}
if kind.endswith('?'): if kind.endswith('?'):
base_kind = _MapKind(kind[0:-1]) base_kind = _MapKind(kind[0:-1])
# NOTE: This doesn't rule out enum types. Those will be detected later, when # NOTE: This doesn't rule out enum types. Those will be detected later, when
...@@ -74,17 +78,16 @@ def _MapKind(kind): ...@@ -74,17 +78,16 @@ def _MapKind(kind):
reference_kinds = ('m', 's', 'h', 'a', 'r', 'x', 'asso', 'rmt', 'rcv', reference_kinds = ('m', 's', 'h', 'a', 'r', 'x', 'asso', 'rmt', 'rcv',
'rma', 'rca') 'rma', 'rca')
if re.split('[^a-z]', base_kind, 1)[0] not in reference_kinds: if re.split('[^a-z]', base_kind, 1)[0] not in reference_kinds:
raise Exception( raise Exception('A type (spec "%s") cannot be made nullable' % base_kind)
'A type (spec "%s") cannot be made nullable' % base_kind)
return '?' + base_kind return '?' + base_kind
if kind.endswith('}'): if kind.endswith('}'):
lbracket = kind.rfind('{') lbracket = kind.rfind('{')
value = kind[0:lbracket] value = kind[0:lbracket]
return 'm[' + _MapKind(kind[lbracket+1:-1]) + '][' + _MapKind(value) + ']' return 'm[' + _MapKind(kind[lbracket + 1:-1]) + '][' + _MapKind(value) + ']'
if kind.endswith(']'): if kind.endswith(']'):
lbracket = kind.rfind('[') lbracket = kind.rfind('[')
typename = kind[0:lbracket] typename = kind[0:lbracket]
return 'a' + kind[lbracket+1:-1] + ':' + _MapKind(typename) return 'a' + kind[lbracket + 1:-1] + ':' + _MapKind(typename)
if kind.endswith('&'): if kind.endswith('&'):
return 'r:' + _MapKind(kind[0:-1]) return 'r:' + _MapKind(kind[0:-1])
if kind.startswith('asso<'): if kind.startswith('asso<'):
...@@ -106,25 +109,26 @@ def _MapKind(kind): ...@@ -106,25 +109,26 @@ def _MapKind(kind):
return map_to_kind[kind] return map_to_kind[kind]
return 'x:' + kind return 'x:' + kind
def _AttributeListToDict(attribute_list): def _AttributeListToDict(attribute_list):
if attribute_list is None: if attribute_list is None:
return None return None
assert isinstance(attribute_list, ast.AttributeList) assert isinstance(attribute_list, ast.AttributeList)
# TODO(vtl): Check for duplicate keys here. # TODO(vtl): Check for duplicate keys here.
return dict([(attribute.key, attribute.value) return dict(
for attribute in attribute_list]) [(attribute.key, attribute.value) for attribute in attribute_list])
builtin_values = frozenset([ builtin_values = frozenset([
"double.INFINITY", "double.INFINITY", "double.NEGATIVE_INFINITY", "double.NAN",
"double.NEGATIVE_INFINITY", "float.INFINITY", "float.NEGATIVE_INFINITY", "float.NAN"
"double.NAN", ])
"float.INFINITY",
"float.NEGATIVE_INFINITY",
"float.NAN"])
def _IsBuiltinValue(value): def _IsBuiltinValue(value):
return value in builtin_values return value in builtin_values
def _LookupKind(kinds, spec, scope): def _LookupKind(kinds, spec, scope):
"""Tries to find which Kind a spec refers to, given the scope in which its """Tries to find which Kind a spec refers to, given the scope in which its
referenced. Starts checking from the narrowest scope to most general. For referenced. Starts checking from the narrowest scope to most general. For
...@@ -148,6 +152,7 @@ def _LookupKind(kinds, spec, scope): ...@@ -148,6 +152,7 @@ def _LookupKind(kinds, spec, scope):
return kinds.get(spec) return kinds.get(spec)
def _LookupValue(values, mojom_name, scope, kind): def _LookupValue(values, mojom_name, scope, kind):
"""Like LookupKind, but for constant values.""" """Like LookupKind, but for constant values."""
# If the type is an enum, the value can be specified as a qualified name, in # If the type is an enum, the value can be specified as a qualified name, in
...@@ -167,6 +172,7 @@ def _LookupValue(values, mojom_name, scope, kind): ...@@ -167,6 +172,7 @@ def _LookupValue(values, mojom_name, scope, kind):
return values.get(mojom_name) return values.get(mojom_name)
def _FixupExpression(module, value, scope, kind): def _FixupExpression(module, value, scope, kind):
"""Translates an IDENTIFIER into a built-in value or structured NamedValue """Translates an IDENTIFIER into a built-in value or structured NamedValue
object.""" object."""
...@@ -181,6 +187,7 @@ def _FixupExpression(module, value, scope, kind): ...@@ -181,6 +187,7 @@ def _FixupExpression(module, value, scope, kind):
return mojom.BuiltinValue(value[1]) return mojom.BuiltinValue(value[1])
return value return value
def _Kind(kinds, spec, scope): def _Kind(kinds, spec, scope):
"""Convert a type name into a mojom.Kind object. """Convert a type name into a mojom.Kind object.
...@@ -214,7 +221,7 @@ def _Kind(kinds, spec, scope): ...@@ -214,7 +221,7 @@ def _Kind(kinds, spec, scope):
elif spec.startswith('a'): elif spec.startswith('a'):
colon = spec.find(':') colon = spec.find(':')
length = int(spec[1:colon]) length = int(spec[1:colon])
kind = mojom.Array(_Kind(kinds, spec[colon+1:], scope), length) kind = mojom.Array(_Kind(kinds, spec[colon + 1:], scope), length)
elif spec.startswith('r:'): elif spec.startswith('r:'):
kind = mojom.InterfaceRequest(_Kind(kinds, spec[2:], scope)) kind = mojom.InterfaceRequest(_Kind(kinds, spec[2:], scope))
elif spec.startswith('rmt:'): elif spec.startswith('rmt:'):
...@@ -232,25 +239,26 @@ def _Kind(kinds, spec, scope): ...@@ -232,25 +239,26 @@ def _Kind(kinds, spec, scope):
# inside the key type spec. # inside the key type spec.
key_end = spec.find(']') key_end = spec.find(']')
assert key_end != -1 and key_end < len(spec) - 1 assert key_end != -1 and key_end < len(spec) - 1
assert spec[key_end+1] == '[' and spec[-1] == ']' assert spec[key_end + 1] == '[' and spec[-1] == ']'
first_kind = spec[2:key_end] first_kind = spec[2:key_end]
second_kind = spec[key_end+2:-1] second_kind = spec[key_end + 2:-1]
kind = mojom.Map(_Kind(kinds, first_kind, scope), kind = mojom.Map(
_Kind(kinds, second_kind, scope)) _Kind(kinds, first_kind, scope), _Kind(kinds, second_kind, scope))
else: else:
kind = mojom.Kind(spec) kind = mojom.Kind(spec)
kinds[spec] = kind kinds[spec] = kind
return kind return kind
def _Import(module, import_module): def _Import(module, import_module):
# Copy the struct kinds from our imports into the current module. # Copy the struct kinds from our imports into the current module.
importable_kinds = (mojom.Struct, mojom.Union, mojom.Enum, mojom.Interface) importable_kinds = (mojom.Struct, mojom.Union, mojom.Enum, mojom.Interface)
for kind in import_module.kinds.values(): for kind in import_module.kinds.values():
if (isinstance(kind, importable_kinds) and if (isinstance(kind, importable_kinds)
kind.module.path == import_module.path): and kind.module.path == import_module.path):
module.kinds[kind.spec] = kind module.kinds[kind.spec] = kind
# Ditto for values. # Ditto for values.
for value in import_module.values.values(): for value in import_module.values.values():
...@@ -259,6 +267,7 @@ def _Import(module, import_module): ...@@ -259,6 +267,7 @@ def _Import(module, import_module):
return import_module return import_module
def _Struct(module, parsed_struct): def _Struct(module, parsed_struct):
""" """
Args: Args:
...@@ -287,8 +296,8 @@ def _Struct(module, parsed_struct): ...@@ -287,8 +296,8 @@ def _Struct(module, parsed_struct):
lambda constant: _Constant(module, constant, struct), lambda constant: _Constant(module, constant, struct),
_ElemsOfType(parsed_struct.body, ast.Const, parsed_struct.mojom_name)) _ElemsOfType(parsed_struct.body, ast.Const, parsed_struct.mojom_name))
# Stash fields parsed_struct here temporarily. # Stash fields parsed_struct here temporarily.
struct.fields_data = _ElemsOfType( struct.fields_data = _ElemsOfType(parsed_struct.body, ast.StructField,
parsed_struct.body, ast.StructField, parsed_struct.mojom_name) parsed_struct.mojom_name)
struct.attributes = _AttributeListToDict(parsed_struct.attribute_list) struct.attributes = _AttributeListToDict(parsed_struct.attribute_list)
# Enforce that a [Native] attribute is set to make native-only struct # Enforce that a [Native] attribute is set to make native-only struct
...@@ -303,6 +312,7 @@ def _Struct(module, parsed_struct): ...@@ -303,6 +312,7 @@ def _Struct(module, parsed_struct):
return struct return struct
def _Union(module, parsed_union): def _Union(module, parsed_union):
""" """
Args: Args:
...@@ -317,11 +327,12 @@ def _Union(module, parsed_union): ...@@ -317,11 +327,12 @@ def _Union(module, parsed_union):
union.spec = 'x:' + module.mojom_namespace + '.' + union.mojom_name union.spec = 'x:' + module.mojom_namespace + '.' + union.mojom_name
module.kinds[union.spec] = union module.kinds[union.spec] = union
# Stash fields parsed_union here temporarily. # Stash fields parsed_union here temporarily.
union.fields_data = _ElemsOfType( union.fields_data = _ElemsOfType(parsed_union.body, ast.UnionField,
parsed_union.body, ast.UnionField, parsed_union.mojom_name) parsed_union.mojom_name)
union.attributes = _AttributeListToDict(parsed_union.attribute_list) union.attributes = _AttributeListToDict(parsed_union.attribute_list)
return union return union
def _StructField(module, parsed_field, struct): def _StructField(module, parsed_field, struct):
""" """
Args: Args:
...@@ -334,16 +345,16 @@ def _StructField(module, parsed_field, struct): ...@@ -334,16 +345,16 @@ def _StructField(module, parsed_field, struct):
""" """
field = mojom.StructField() field = mojom.StructField()
field.mojom_name = parsed_field.mojom_name field.mojom_name = parsed_field.mojom_name
field.kind = _Kind( field.kind = _Kind(module.kinds, _MapKind(parsed_field.typename),
module.kinds, _MapKind(parsed_field.typename), (module.mojom_namespace, struct.mojom_name))
(module.mojom_namespace, struct.mojom_name))
field.ordinal = parsed_field.ordinal.value if parsed_field.ordinal else None field.ordinal = parsed_field.ordinal.value if parsed_field.ordinal else None
field.default = _FixupExpression( field.default = _FixupExpression(module, parsed_field.default_value,
module, parsed_field.default_value, (module.mojom_namespace, struct.mojom_name),
(module.mojom_namespace, struct.mojom_name), field.kind) field.kind)
field.attributes = _AttributeListToDict(parsed_field.attribute_list) field.attributes = _AttributeListToDict(parsed_field.attribute_list)
return field return field
def _UnionField(module, parsed_field, union): def _UnionField(module, parsed_field, union):
""" """
Args: Args:
...@@ -356,15 +367,15 @@ def _UnionField(module, parsed_field, union): ...@@ -356,15 +367,15 @@ def _UnionField(module, parsed_field, union):
""" """
field = mojom.UnionField() field = mojom.UnionField()
field.mojom_name = parsed_field.mojom_name field.mojom_name = parsed_field.mojom_name
field.kind = _Kind( field.kind = _Kind(module.kinds, _MapKind(parsed_field.typename),
module.kinds, _MapKind(parsed_field.typename), (module.mojom_namespace, union.mojom_name))
(module.mojom_namespace, union.mojom_name))
field.ordinal = parsed_field.ordinal.value if parsed_field.ordinal else None field.ordinal = parsed_field.ordinal.value if parsed_field.ordinal else None
field.default = _FixupExpression( field.default = _FixupExpression(
module, None, (module.mojom_namespace, union.mojom_name), field.kind) module, None, (module.mojom_namespace, union.mojom_name), field.kind)
field.attributes = _AttributeListToDict(parsed_field.attribute_list) field.attributes = _AttributeListToDict(parsed_field.attribute_list)
return field return field
def _Parameter(module, parsed_param, interface): def _Parameter(module, parsed_param, interface):
""" """
Args: Args:
...@@ -377,15 +388,15 @@ def _Parameter(module, parsed_param, interface): ...@@ -377,15 +388,15 @@ def _Parameter(module, parsed_param, interface):
""" """
parameter = mojom.Parameter() parameter = mojom.Parameter()
parameter.mojom_name = parsed_param.mojom_name parameter.mojom_name = parsed_param.mojom_name
parameter.kind = _Kind( parameter.kind = _Kind(module.kinds, _MapKind(parsed_param.typename),
module.kinds, _MapKind(parsed_param.typename), (module.mojom_namespace, interface.mojom_name))
(module.mojom_namespace, interface.mojom_name)) parameter.ordinal = (parsed_param.ordinal.value
parameter.ordinal = ( if parsed_param.ordinal else None)
parsed_param.ordinal.value if parsed_param.ordinal else None)
parameter.default = None # TODO(tibell): We never have these. Remove field? parameter.default = None # TODO(tibell): We never have these. Remove field?
parameter.attributes = _AttributeListToDict(parsed_param.attribute_list) parameter.attributes = _AttributeListToDict(parsed_param.attribute_list)
return parameter return parameter
def _Method(module, parsed_method, interface): def _Method(module, parsed_method, interface):
""" """
Args: Args:
...@@ -397,7 +408,8 @@ def _Method(module, parsed_method, interface): ...@@ -397,7 +408,8 @@ def _Method(module, parsed_method, interface):
{mojom.Method} AST method. {mojom.Method} AST method.
""" """
method = mojom.Method( method = mojom.Method(
interface, parsed_method.mojom_name, interface,
parsed_method.mojom_name,
ordinal=parsed_method.ordinal.value if parsed_method.ordinal else None) ordinal=parsed_method.ordinal.value if parsed_method.ordinal else None)
method.parameters = list( method.parameters = list(
map(lambda parameter: _Parameter(module, parameter, interface), map(lambda parameter: _Parameter(module, parameter, interface),
...@@ -417,6 +429,7 @@ def _Method(module, parsed_method, interface): ...@@ -417,6 +429,7 @@ def _Method(module, parsed_method, interface):
return method return method
def _Interface(module, parsed_iface): def _Interface(module, parsed_iface):
""" """
Args: Args:
...@@ -437,11 +450,12 @@ def _Interface(module, parsed_iface): ...@@ -437,11 +450,12 @@ def _Interface(module, parsed_iface):
lambda constant: _Constant(module, constant, interface), lambda constant: _Constant(module, constant, interface),
_ElemsOfType(parsed_iface.body, ast.Const, parsed_iface.mojom_name)) _ElemsOfType(parsed_iface.body, ast.Const, parsed_iface.mojom_name))
# Stash methods parsed_iface here temporarily. # Stash methods parsed_iface here temporarily.
interface.methods_data = _ElemsOfType( interface.methods_data = _ElemsOfType(parsed_iface.body, ast.Method,
parsed_iface.body, ast.Method, parsed_iface.mojom_name) parsed_iface.mojom_name)
interface.attributes = _AttributeListToDict(parsed_iface.attribute_list) interface.attributes = _AttributeListToDict(parsed_iface.attribute_list)
return interface return interface
def _EnumField(module, enum, parsed_field, parent_kind): def _EnumField(module, enum, parsed_field, parent_kind):
""" """
Args: Args:
...@@ -464,13 +478,14 @@ def _EnumField(module, enum, parsed_field, parent_kind): ...@@ -464,13 +478,14 @@ def _EnumField(module, enum, parsed_field, parent_kind):
module, parsed_field.value, module, parsed_field.value,
(module.mojom_namespace, parent_kind.mojom_name), enum) (module.mojom_namespace, parent_kind.mojom_name), enum)
else: else:
field.value = _FixupExpression( field.value = _FixupExpression(module, parsed_field.value,
module, parsed_field.value, (module.mojom_namespace, ), enum) (module.mojom_namespace, ), enum)
field.attributes = _AttributeListToDict(parsed_field.attribute_list) field.attributes = _AttributeListToDict(parsed_field.attribute_list)
value = mojom.EnumValue(module, enum, field) value = mojom.EnumValue(module, enum, field)
module.values[value.GetSpec()] = value module.values[value.GetSpec()] = value
return field return field
def _ResolveNumericEnumValues(enum_fields): def _ResolveNumericEnumValues(enum_fields):
""" """
Given a reference to a list of mojom.EnumField, resolves and assigns their Given a reference to a list of mojom.EnumField, resolves and assigns their
...@@ -510,6 +525,7 @@ def _ResolveNumericEnumValues(enum_fields): ...@@ -510,6 +525,7 @@ def _ResolveNumericEnumValues(enum_fields):
return min_value, max_value return min_value, max_value
def _Enum(module, parsed_enum, parent_kind): def _Enum(module, parsed_enum, parent_kind):
""" """
Args: Args:
...@@ -545,6 +561,7 @@ def _Enum(module, parsed_enum, parent_kind): ...@@ -545,6 +561,7 @@ def _Enum(module, parsed_enum, parent_kind):
return enum return enum
def _Constant(module, parsed_const, parent_kind): def _Constant(module, parsed_const, parent_kind):
""" """
Args: Args:
...@@ -584,21 +601,20 @@ def _CollectReferencedKinds(module, all_defined_kinds): ...@@ -584,21 +601,20 @@ def _CollectReferencedKinds(module, all_defined_kinds):
return extract_referenced_user_kinds(kind.kind) return extract_referenced_user_kinds(kind.kind)
if mojom.IsMapKind(kind): if mojom.IsMapKind(kind):
return (extract_referenced_user_kinds(kind.key_kind) + return (extract_referenced_user_kinds(kind.key_kind) +
extract_referenced_user_kinds(kind.value_kind)) extract_referenced_user_kinds(kind.value_kind))
if mojom.IsInterfaceRequestKind(kind) or mojom.IsAssociatedKind(kind): if mojom.IsInterfaceRequestKind(kind) or mojom.IsAssociatedKind(kind):
return [kind.kind] return [kind.kind]
if mojom.IsStructKind(kind): if mojom.IsStructKind(kind):
return [kind] return [kind]
if (mojom.IsInterfaceKind(kind) or mojom.IsEnumKind(kind) or if (mojom.IsInterfaceKind(kind) or mojom.IsEnumKind(kind)
mojom.IsUnionKind(kind)): or mojom.IsUnionKind(kind)):
return [kind] return [kind]
return [] return []
def sanitize_kind(kind): def sanitize_kind(kind):
"""Removes nullability from a kind""" """Removes nullability from a kind"""
if kind.spec.startswith('?'): if kind.spec.startswith('?'):
return _Kind(module.kinds, kind.spec[1:], return _Kind(module.kinds, kind.spec[1:], (module.mojom_namespace, ''))
(module.mojom_namespace, ''))
return kind return kind
referenced_user_kinds = {} referenced_user_kinds = {}
...@@ -614,9 +630,9 @@ def _CollectReferencedKinds(module, all_defined_kinds): ...@@ -614,9 +630,9 @@ def _CollectReferencedKinds(module, all_defined_kinds):
for method in interface.methods: for method in interface.methods:
for param in itertools.chain(method.parameters or [], for param in itertools.chain(method.parameters or [],
method.response_parameters or []): method.response_parameters or []):
if (mojom.IsStructKind(param.kind) or mojom.IsUnionKind(param.kind) or if (mojom.IsStructKind(param.kind) or mojom.IsUnionKind(param.kind)
mojom.IsEnumKind(param.kind) or or mojom.IsEnumKind(param.kind)
mojom.IsAnyInterfaceKind(param.kind)): or mojom.IsAnyInterfaceKind(param.kind)):
for referenced_kind in extract_referenced_user_kinds(param.kind): for referenced_kind in extract_referenced_user_kinds(param.kind):
sanitized_kind = sanitize_kind(referenced_kind) sanitized_kind = sanitize_kind(referenced_kind)
referenced_user_kinds[sanitized_kind.spec] = sanitized_kind referenced_user_kinds[sanitized_kind.spec] = sanitized_kind
...@@ -646,8 +662,8 @@ def _Module(tree, path, imports): ...@@ -646,8 +662,8 @@ def _Module(tree, path, imports):
# Imports must come first, because they add to module.kinds which is used # Imports must come first, because they add to module.kinds which is used
# by by the others. # by by the others.
module.imports = [ module.imports = [
_Import(module, imports[imp.import_filename]) _Import(module, imports[imp.import_filename]) for imp in tree.import_list
for imp in tree.import_list] ]
if tree.module and tree.module.attribute_list: if tree.module and tree.module.attribute_list:
assert isinstance(tree.module.attribute_list, ast.AttributeList) assert isinstance(tree.module.attribute_list, ast.AttributeList)
# TODO(vtl): Check for duplicate keys here. # TODO(vtl): Check for duplicate keys here.
...@@ -703,11 +719,12 @@ def _Module(tree, path, imports): ...@@ -703,11 +719,12 @@ def _Module(tree, path, imports):
all_defined_kinds.values()) all_defined_kinds.values())
imported_kind_specs = set(all_referenced_kinds.keys()).difference( imported_kind_specs = set(all_referenced_kinds.keys()).difference(
set(all_defined_kinds.keys())) set(all_defined_kinds.keys()))
module.imported_kinds = dict((spec, all_referenced_kinds[spec]) module.imported_kinds = dict(
for spec in imported_kind_specs) (spec, all_referenced_kinds[spec]) for spec in imported_kind_specs)
return module return module
def OrderedModule(tree, path, imports): def OrderedModule(tree, path, imports):
"""Convert parse tree to AST module. """Convert parse tree to AST module.
......
# Copyright 2014 The Chromium Authors. All rights reserved. # Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
"""Node classes for the AST for a Mojo IDL file.""" """Node classes for the AST for a Mojo IDL file."""
# Note: For convenience of testing, you probably want to define __eq__() methods # Note: For convenience of testing, you probably want to define __eq__() methods
...@@ -393,7 +392,6 @@ class Union(Definition): ...@@ -393,7 +392,6 @@ class Union(Definition):
class UnionField(Definition): class UnionField(Definition):
def __init__(self, mojom_name, attribute_list, ordinal, typename, **kwargs): def __init__(self, mojom_name, attribute_list, ordinal, typename, **kwargs):
assert isinstance(mojom_name, str) assert isinstance(mojom_name, str)
assert attribute_list is None or isinstance(attribute_list, AttributeList) assert attribute_list is None or isinstance(attribute_list, AttributeList)
......
# Copyright 2018 The Chromium Authors. All rights reserved. # Copyright 2018 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
"""Helpers for processing conditionally enabled features in a mojom.""" """Helpers for processing conditionally enabled features in a mojom."""
from . import ast from . import ast
from ..error import Error from ..error import Error
class EnableIfError(Error): class EnableIfError(Error):
""" Class for errors from .""" """ Class for errors from ."""
def __init__(self, filename, message, lineno=None): def __init__(self, filename, message, lineno=None):
Error.__init__(self, filename, message, lineno=lineno, addenda=None) Error.__init__(self, filename, message, lineno=lineno, addenda=None)
def _IsEnabled(definition, enabled_features): def _IsEnabled(definition, enabled_features):
"""Returns true if a definition is enabled. """Returns true if a definition is enabled.
...@@ -28,9 +29,10 @@ def _IsEnabled(definition, enabled_features): ...@@ -28,9 +29,10 @@ def _IsEnabled(definition, enabled_features):
for a in definition.attribute_list: for a in definition.attribute_list:
if a.key == 'EnableIf': if a.key == 'EnableIf':
if already_defined: if already_defined:
raise EnableIfError(definition.filename, raise EnableIfError(
"EnableIf attribute may only be defined once per field.", definition.filename,
definition.lineno) "EnableIf attribute may only be defined once per field.",
definition.lineno)
already_defined = True already_defined = True
for attribute in definition.attribute_list: for attribute in definition.attribute_list:
...@@ -69,12 +71,12 @@ def _FilterDefinition(definition, enabled_features): ...@@ -69,12 +71,12 @@ def _FilterDefinition(definition, enabled_features):
def RemoveDisabledDefinitions(mojom, enabled_features): def RemoveDisabledDefinitions(mojom, enabled_features):
"""Removes conditionally disabled definitions from a Mojom node.""" """Removes conditionally disabled definitions from a Mojom node."""
mojom.import_list = ast.ImportList([ mojom.import_list = ast.ImportList([
imported_file for imported_file in mojom.import_list imported_file for imported_file in mojom.import_list
if _IsEnabled(imported_file, enabled_features) if _IsEnabled(imported_file, enabled_features)
]) ])
mojom.definition_list = [ mojom.definition_list = [
definition for definition in mojom.definition_list definition for definition in mojom.definition_list
if _IsEnabled(definition, enabled_features) if _IsEnabled(definition, enabled_features)
] ]
for definition in mojom.definition_list: for definition in mojom.definition_list:
_FilterDefinition(definition, enabled_features) _FilterDefinition(definition, enabled_features)
...@@ -6,6 +6,7 @@ import imp ...@@ -6,6 +6,7 @@ import imp
import os.path import os.path
import sys import sys
def _GetDirAbove(dirname): def _GetDirAbove(dirname):
"""Returns the directory "above" this file containing |dirname| (which must """Returns the directory "above" this file containing |dirname| (which must
also be "above" this file).""" also be "above" this file)."""
...@@ -16,6 +17,7 @@ def _GetDirAbove(dirname): ...@@ -16,6 +17,7 @@ def _GetDirAbove(dirname):
if tail == dirname: if tail == dirname:
return path return path
try: try:
imp.find_module("ply") imp.find_module("ply")
except ImportError: except ImportError:
...@@ -35,7 +37,6 @@ class LexError(Error): ...@@ -35,7 +37,6 @@ class LexError(Error):
# We have methods which look like they could be functions: # We have methods which look like they could be functions:
# pylint: disable=R0201 # pylint: disable=R0201
class Lexer(object): class Lexer(object):
def __init__(self, filename): def __init__(self, filename):
self.filename = filename self.filename = filename
...@@ -51,25 +52,24 @@ class Lexer(object): ...@@ -51,25 +52,24 @@ class Lexer(object):
## Reserved keywords ## Reserved keywords
## ##
keywords = ( keywords = (
'HANDLE', 'HANDLE',
'IMPORT',
'IMPORT', 'MODULE',
'MODULE', 'STRUCT',
'STRUCT', 'UNION',
'UNION', 'INTERFACE',
'INTERFACE', 'ENUM',
'ENUM', 'CONST',
'CONST', 'TRUE',
'TRUE', 'FALSE',
'FALSE', 'DEFAULT',
'DEFAULT', 'ARRAY',
'ARRAY', 'MAP',
'MAP', 'ASSOCIATED',
'ASSOCIATED', 'PENDING_REMOTE',
'PENDING_REMOTE', 'PENDING_RECEIVER',
'PENDING_RECEIVER', 'PENDING_ASSOCIATED_REMOTE',
'PENDING_ASSOCIATED_REMOTE', 'PENDING_ASSOCIATED_RECEIVER',
'PENDING_ASSOCIATED_RECEIVER',
) )
keyword_map = {} keyword_map = {}
...@@ -80,36 +80,42 @@ class Lexer(object): ...@@ -80,36 +80,42 @@ class Lexer(object):
## All the tokens recognized by the lexer ## All the tokens recognized by the lexer
## ##
tokens = keywords + ( tokens = keywords + (
# Identifiers # Identifiers
'NAME', 'NAME',
# Constants # Constants
'ORDINAL', 'ORDINAL',
'INT_CONST_DEC', 'INT_CONST_HEX', 'INT_CONST_DEC',
'FLOAT_CONST', 'INT_CONST_HEX',
'FLOAT_CONST',
# String literals
'STRING_LITERAL', # String literals
'STRING_LITERAL',
# Operators
'MINUS', # Operators
'PLUS', 'MINUS',
'AMP', 'PLUS',
'QSTN', 'AMP',
'QSTN',
# Assignment
'EQUALS', # Assignment
'EQUALS',
# Request / response
'RESPONSE', # Request / response
'RESPONSE',
# Delimiters
'LPAREN', 'RPAREN', # ( ) # Delimiters
'LBRACKET', 'RBRACKET', # [ ] 'LPAREN',
'LBRACE', 'RBRACE', # { } 'RPAREN', # ( )
'LANGLE', 'RANGLE', # < > 'LBRACKET',
'SEMI', # ; 'RBRACKET', # [ ]
'COMMA', 'DOT' # , . 'LBRACE',
'RBRACE', # { }
'LANGLE',
'RANGLE', # < >
'SEMI', # ;
'COMMA',
'DOT' # , .
) )
## ##
...@@ -124,7 +130,7 @@ class Lexer(object): ...@@ -124,7 +130,7 @@ class Lexer(object):
# integer constants (K&R2: A.2.5.1) # integer constants (K&R2: A.2.5.1)
decimal_constant = '0|([1-9][0-9]*)' decimal_constant = '0|([1-9][0-9]*)'
hex_constant = hex_prefix+hex_digits hex_constant = hex_prefix + hex_digits
# Don't allow octal constants (even invalid octal). # Don't allow octal constants (even invalid octal).
octal_constant_disallowed = '0[0-9]+' octal_constant_disallowed = '0[0-9]+'
...@@ -144,9 +150,9 @@ class Lexer(object): ...@@ -144,9 +150,9 @@ class Lexer(object):
r"""(\\("""+simple_escape+'|'+decimal_escape+'|'+hex_escape+'))' r"""(\\("""+simple_escape+'|'+decimal_escape+'|'+hex_escape+'))'
# string literals (K&R2: A.2.6) # string literals (K&R2: A.2.6)
string_char = r"""([^"\\\n]|"""+escape_sequence+')' string_char = r"""([^"\\\n]|""" + escape_sequence + ')'
string_literal = '"'+string_char+'*"' string_literal = '"' + string_char + '*"'
bad_string_literal = '"'+string_char+'*'+bad_escape+string_char+'*"' bad_string_literal = '"' + string_char + '*' + bad_escape + string_char + '*"'
# floating constants (K&R2: A.2.5.3) # floating constants (K&R2: A.2.5.3)
exponent_part = r"""([eE][-+]?[0-9]+)""" exponent_part = r"""([eE][-+]?[0-9]+)"""
...@@ -160,7 +166,8 @@ class Lexer(object): ...@@ -160,7 +166,8 @@ class Lexer(object):
missing_ordinal_value = r'@' missing_ordinal_value = r'@'
# Don't allow ordinal values in octal (even invalid octal, like 09) or # Don't allow ordinal values in octal (even invalid octal, like 09) or
# hexadecimal. # hexadecimal.
octal_or_hex_ordinal_disallowed = r'@((0[0-9]+)|('+hex_prefix+hex_digits+'))' octal_or_hex_ordinal_disallowed = (
r'@((0[0-9]+)|(' + hex_prefix + hex_digits + '))')
## ##
## Rules for the normal state ## Rules for the normal state
...@@ -173,31 +180,31 @@ class Lexer(object): ...@@ -173,31 +180,31 @@ class Lexer(object):
t.lexer.lineno += len(t.value) t.lexer.lineno += len(t.value)
# Operators # Operators
t_MINUS = r'-' t_MINUS = r'-'
t_PLUS = r'\+' t_PLUS = r'\+'
t_AMP = r'&' t_AMP = r'&'
t_QSTN = r'\?' t_QSTN = r'\?'
# = # =
t_EQUALS = r'=' t_EQUALS = r'='
# => # =>
t_RESPONSE = r'=>' t_RESPONSE = r'=>'
# Delimiters # Delimiters
t_LPAREN = r'\(' t_LPAREN = r'\('
t_RPAREN = r'\)' t_RPAREN = r'\)'
t_LBRACKET = r'\[' t_LBRACKET = r'\['
t_RBRACKET = r'\]' t_RBRACKET = r'\]'
t_LBRACE = r'\{' t_LBRACE = r'\{'
t_RBRACE = r'\}' t_RBRACE = r'\}'
t_LANGLE = r'<' t_LANGLE = r'<'
t_RANGLE = r'>' t_RANGLE = r'>'
t_COMMA = r',' t_COMMA = r','
t_DOT = r'\.' t_DOT = r'\.'
t_SEMI = r';' t_SEMI = r';'
t_STRING_LITERAL = string_literal t_STRING_LITERAL = string_literal
# The following floating and integer constants are defined as # The following floating and integer constants are defined as
# functions to impose a strict order (otherwise, decimal # functions to impose a strict order (otherwise, decimal
......
# Copyright 2014 The Chromium Authors. All rights reserved. # Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
"""Generates a syntax tree from a Mojo IDL file.""" """Generates a syntax tree from a Mojo IDL file."""
import os.path import os.path
...@@ -17,7 +16,6 @@ from ..error import Error ...@@ -17,7 +16,6 @@ from ..error import Error
from . import ast from . import ast
from .lexer import Lexer from .lexer import Lexer
_MAX_ORDINAL_VALUE = 0xffffffff _MAX_ORDINAL_VALUE = 0xffffffff
_MAX_ARRAY_SIZE = 0xffffffff _MAX_ARRAY_SIZE = 0xffffffff
...@@ -26,14 +24,17 @@ class ParseError(Error): ...@@ -26,14 +24,17 @@ class ParseError(Error):
"""Class for errors from the parser.""" """Class for errors from the parser."""
def __init__(self, filename, message, lineno=None, snippet=None): def __init__(self, filename, message, lineno=None, snippet=None):
Error.__init__(self, filename, message, lineno=lineno, Error.__init__(
addenda=([snippet] if snippet else None)) self,
filename,
message,
lineno=lineno,
addenda=([snippet] if snippet else None))
# We have methods which look like they could be functions: # We have methods which look like they could be functions:
# pylint: disable=R0201 # pylint: disable=R0201
class Parser(object): class Parser(object):
def __init__(self, lexer, source, filename): def __init__(self, lexer, source, filename):
self.tokens = lexer.tokens self.tokens = lexer.tokens
self.source = source self.source = source
...@@ -65,23 +66,28 @@ class Parser(object): ...@@ -65,23 +66,28 @@ class Parser(object):
def p_root_2(self, p): def p_root_2(self, p):
"""root : root module""" """root : root module"""
if p[1].module is not None: if p[1].module is not None:
raise ParseError(self.filename, raise ParseError(
"Multiple \"module\" statements not allowed:", self.filename,
p[2].lineno, snippet=self._GetSnippet(p[2].lineno)) "Multiple \"module\" statements not allowed:",
p[2].lineno,
snippet=self._GetSnippet(p[2].lineno))
if p[1].import_list.items or p[1].definition_list: if p[1].import_list.items or p[1].definition_list:
raise ParseError( raise ParseError(
self.filename, self.filename,
"\"module\" statements must precede imports and definitions:", "\"module\" statements must precede imports and definitions:",
p[2].lineno, snippet=self._GetSnippet(p[2].lineno)) p[2].lineno,
snippet=self._GetSnippet(p[2].lineno))
p[0] = p[1] p[0] = p[1]
p[0].module = p[2] p[0].module = p[2]
def p_root_3(self, p): def p_root_3(self, p):
"""root : root import""" """root : root import"""
if p[1].definition_list: if p[1].definition_list:
raise ParseError(self.filename, raise ParseError(
"\"import\" statements must precede definitions:", self.filename,
p[2].lineno, snippet=self._GetSnippet(p[2].lineno)) "\"import\" statements must precede definitions:",
p[2].lineno,
snippet=self._GetSnippet(p[2].lineno))
p[0] = p[1] p[0] = p[1]
p[0].import_list.Append(p[2]) p[0].import_list.Append(p[2])
...@@ -94,8 +100,8 @@ class Parser(object): ...@@ -94,8 +100,8 @@ class Parser(object):
"""import : attribute_section IMPORT STRING_LITERAL SEMI""" """import : attribute_section IMPORT STRING_LITERAL SEMI"""
# 'eval' the literal to strip the quotes. # 'eval' the literal to strip the quotes.
# TODO(vtl): This eval is dubious. We should unquote/unescape ourselves. # TODO(vtl): This eval is dubious. We should unquote/unescape ourselves.
p[0] = ast.Import(p[1], eval(p[3]), filename=self.filename, p[0] = ast.Import(
lineno=p.lineno(2)) p[1], eval(p[3]), filename=self.filename, lineno=p.lineno(2))
def p_module(self, p): def p_module(self, p):
"""module : attribute_section MODULE identifier_wrapped SEMI""" """module : attribute_section MODULE identifier_wrapped SEMI"""
...@@ -251,8 +257,8 @@ class Parser(object): ...@@ -251,8 +257,8 @@ class Parser(object):
def p_parameter(self, p): def p_parameter(self, p):
"""parameter : attribute_section typename NAME ordinal""" """parameter : attribute_section typename NAME ordinal"""
p[0] = ast.Parameter(p[3], p[1], p[4], p[2], p[0] = ast.Parameter(
filename=self.filename, lineno=p.lineno(3)) p[3], p[1], p[4], p[2], filename=self.filename, lineno=p.lineno(3))
def p_typename(self, p): def p_typename(self, p):
"""typename : nonnullable_typename QSTN """typename : nonnullable_typename QSTN
...@@ -307,16 +313,15 @@ class Parser(object): ...@@ -307,16 +313,15 @@ class Parser(object):
if len(p) == 2: if len(p) == 2:
p[0] = p[1] p[0] = p[1]
else: else:
if p[3] not in ('data_pipe_consumer', if p[3] not in ('data_pipe_consumer', 'data_pipe_producer',
'data_pipe_producer', 'message_pipe', 'shared_buffer', 'platform'):
'message_pipe',
'shared_buffer',
'platform'):
# Note: We don't enable tracking of line numbers for everything, so we # Note: We don't enable tracking of line numbers for everything, so we
# can't use |p.lineno(3)|. # can't use |p.lineno(3)|.
raise ParseError(self.filename, "Invalid handle type %r:" % p[3], raise ParseError(
lineno=p.lineno(1), self.filename,
snippet=self._GetSnippet(p.lineno(1))) "Invalid handle type %r:" % p[3],
lineno=p.lineno(1),
snippet=self._GetSnippet(p.lineno(1)))
p[0] = "handle<" + p[3] + ">" p[0] = "handle<" + p[3] + ">"
def p_array(self, p): def p_array(self, p):
...@@ -327,9 +332,11 @@ class Parser(object): ...@@ -327,9 +332,11 @@ class Parser(object):
"""fixed_array : ARRAY LANGLE typename COMMA INT_CONST_DEC RANGLE""" """fixed_array : ARRAY LANGLE typename COMMA INT_CONST_DEC RANGLE"""
value = int(p[5]) value = int(p[5])
if value == 0 or value > _MAX_ARRAY_SIZE: if value == 0 or value > _MAX_ARRAY_SIZE:
raise ParseError(self.filename, "Fixed array size %d invalid:" % value, raise ParseError(
lineno=p.lineno(5), self.filename,
snippet=self._GetSnippet(p.lineno(5))) "Fixed array size %d invalid:" % value,
lineno=p.lineno(5),
snippet=self._GetSnippet(p.lineno(5)))
p[0] = p[3] + "[" + p[5] + "]" p[0] = p[3] + "[" + p[5] + "]"
def p_associative_array(self, p): def p_associative_array(self, p):
...@@ -352,9 +359,11 @@ class Parser(object): ...@@ -352,9 +359,11 @@ class Parser(object):
"""ordinal : ORDINAL""" """ordinal : ORDINAL"""
value = int(p[1][1:]) value = int(p[1][1:])
if value > _MAX_ORDINAL_VALUE: if value > _MAX_ORDINAL_VALUE:
raise ParseError(self.filename, "Ordinal value %d too large:" % value, raise ParseError(
lineno=p.lineno(1), self.filename,
snippet=self._GetSnippet(p.lineno(1))) "Ordinal value %d too large:" % value,
lineno=p.lineno(1),
snippet=self._GetSnippet(p.lineno(1)))
p[0] = ast.Ordinal(value, filename=self.filename, lineno=p.lineno(1)) p[0] = ast.Ordinal(value, filename=self.filename, lineno=p.lineno(1))
def p_enum_1(self, p): def p_enum_1(self, p):
...@@ -362,13 +371,13 @@ class Parser(object): ...@@ -362,13 +371,13 @@ class Parser(object):
RBRACE SEMI RBRACE SEMI
| attribute_section ENUM NAME LBRACE nonempty_enum_value_list \ | attribute_section ENUM NAME LBRACE nonempty_enum_value_list \
COMMA RBRACE SEMI""" COMMA RBRACE SEMI"""
p[0] = ast.Enum(p[3], p[1], p[5], filename=self.filename, p[0] = ast.Enum(
lineno=p.lineno(2)) p[3], p[1], p[5], filename=self.filename, lineno=p.lineno(2))
def p_enum_2(self, p): def p_enum_2(self, p):
"""enum : attribute_section ENUM NAME SEMI""" """enum : attribute_section ENUM NAME SEMI"""
p[0] = ast.Enum(p[3], p[1], None, filename=self.filename, p[0] = ast.Enum(
lineno=p.lineno(2)) p[3], p[1], None, filename=self.filename, lineno=p.lineno(2))
def p_enum_value_list_1(self, p): def p_enum_value_list_1(self, p):
"""enum_value_list : """ """enum_value_list : """
...@@ -391,8 +400,12 @@ class Parser(object): ...@@ -391,8 +400,12 @@ class Parser(object):
"""enum_value : attribute_section NAME """enum_value : attribute_section NAME
| attribute_section NAME EQUALS int | attribute_section NAME EQUALS int
| attribute_section NAME EQUALS identifier_wrapped""" | attribute_section NAME EQUALS identifier_wrapped"""
p[0] = ast.EnumValue(p[2], p[1], p[4] if len(p) == 5 else None, p[0] = ast.EnumValue(
filename=self.filename, lineno=p.lineno(2)) p[2],
p[1],
p[4] if len(p) == 5 else None,
filename=self.filename,
lineno=p.lineno(2))
def p_const(self, p): def p_const(self, p):
"""const : attribute_section CONST typename NAME EQUALS constant SEMI""" """const : attribute_section CONST typename NAME EQUALS constant SEMI"""
...@@ -446,8 +459,11 @@ class Parser(object): ...@@ -446,8 +459,11 @@ class Parser(object):
# TODO(vtl): Can we figure out what's missing? # TODO(vtl): Can we figure out what's missing?
raise ParseError(self.filename, "Unexpected end of file") raise ParseError(self.filename, "Unexpected end of file")
raise ParseError(self.filename, "Unexpected %r:" % e.value, lineno=e.lineno, raise ParseError(
snippet=self._GetSnippet(e.lineno)) self.filename,
"Unexpected %r:" % e.value,
lineno=e.lineno,
snippet=self._GetSnippet(e.lineno))
def _GetSnippet(self, lineno): def _GetSnippet(self, lineno):
return self.source.split('\n')[lineno - 1] return self.source.split('\n')[lineno - 1]
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment