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
......
...@@ -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 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