Commit 94be217d authored by Yuki Shiino's avatar Yuki Shiino Committed by Commit Bot

IDL compiler: Implement reference-resolution and dump-as-pickle

Resolves references to dictionaries (other references are
resolved to stubs for the time being), and dumps the database
object into a pickle file.

'pickle' only supports top-level classes, so DebugInfo.Location
is moved to a top-level class.  Also, reference-stubs are
temporarily necessary to pickle web_idl.Proxy instances.

Bug: 839389
Change-Id: Ifbdca0df8d34d1cad49bca854b32f0524aaff758
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1713066Reviewed-by: default avatarHitoshi Yoshida <peria@chromium.org>
Commit-Queue: Yuki Shiino <yukishiino@chromium.org>
Cr-Commit-Position: refs/heads/master@{#679936}
parent 521f1235
...@@ -137,51 +137,51 @@ class WithComponent(object): ...@@ -137,51 +137,51 @@ class WithComponent(object):
self._components.append(component) self._components.append(component)
class Location(object):
def __init__(self, filepath=None, line_number=None, column_number=None):
assert filepath is None or isinstance(filepath, str)
assert line_number is None or isinstance(line_number, int)
assert column_number is None or isinstance(column_number, int)
self._filepath = filepath
self._line_number = line_number
self._column_number = column_number
def __str__(self):
text = '{}'.format(self._filepath or '<<unknown path>>')
if self._line_number:
text += ':{}'.format(self._line_number)
if self._column_number:
text += ':{}'.format(self._column_number)
return text
def make_copy(self):
return Location(
filepath=self._filepath,
line_number=self._line_number,
column_number=self._column_number)
@property
def filepath(self):
return self._filepath
@property
def line_number(self):
return self._line_number
@property
def column_number(self):
return self._column_number
class DebugInfo(object): class DebugInfo(object):
"""Provides information useful for debugging.""" """Provides information useful for debugging."""
class Location(object):
def __init__(self, filepath=None, line_number=None,
column_number=None):
assert filepath is None or isinstance(filepath, str)
assert line_number is None or isinstance(line_number, int)
assert column_number is None or isinstance(column_number, int)
self._filepath = filepath
self._line_number = line_number
self._column_number = column_number
def __str__(self):
text = '{}'.format(self._filepath or '<<unknown path>>')
if self._line_number:
text += ':{}'.format(self._line_number)
if self._column_number:
text += ':{}'.format(self._column_number)
return text
def make_copy(self):
return DebugInfo.Location(
filepath=self._filepath,
line_number=self._line_number,
column_number=self._column_number)
@property
def filepath(self):
return self._filepath
@property
def line_number(self):
return self._line_number
@property
def column_number(self):
return self._column_number
def __init__(self, location=None, locations=None): def __init__(self, location=None, locations=None):
assert location is None or isinstance(location, DebugInfo.Location) assert location is None or isinstance(location, Location)
assert locations is None or (isinstance( assert locations is None or (isinstance(locations, (list, tuple))
locations, (list, tuple)) and all( and all(
isinstance(location, DebugInfo.Location) isinstance(location, Location)
for location in locations)) for location in locations))
assert not (location and locations) assert not (location and locations)
# The first entry is the primary location, e.g. location of non-partial # The first entry is the primary location, e.g. location of non-partial
# interface. The rest is secondary locations, e.g. location of partial # interface. The rest is secondary locations, e.g. location of partial
...@@ -189,17 +189,15 @@ class DebugInfo(object): ...@@ -189,17 +189,15 @@ class DebugInfo(object):
if locations: if locations:
self._locations = locations self._locations = locations
else: else:
self._locations = [location or DebugInfo.Location()] self._locations = [location or Location()]
def make_copy(self): def make_copy(self):
return DebugInfo( return DebugInfo(locations=map(Location.make_copy, self._locations))
locations=map(DebugInfo.Location.make_copy, self._locations))
@property @property
def location(self): def location(self):
""" """
Returns the primary location, i.e. location of the main definition. Returns the primary location, i.e. location of the main definition.
@return DebugInfo.Location
""" """
return self._locations[0] return self._locations[0]
...@@ -208,13 +206,12 @@ class DebugInfo(object): ...@@ -208,13 +206,12 @@ class DebugInfo(object):
""" """
Returns a list of locations of all related IDL definitions, including Returns a list of locations of all related IDL definitions, including
partial definitions and mixins. partial definitions and mixins.
@return tuple(DebugInfo.Location)
""" """
return tuple(self._locations) return tuple(self._locations)
def add_locations(self, locations): def add_locations(self, locations):
assert isinstance(locations, (list, tuple)) and all( assert isinstance(locations, (list, tuple)) and all(
isinstance(location, DebugInfo.Location) for location in locations) isinstance(location, Location) for location in locations)
self._locations.extend(locations) self._locations.extend(locations)
......
...@@ -62,7 +62,7 @@ class DatabaseBody(object): ...@@ -62,7 +62,7 @@ class DatabaseBody(object):
self._defs[kind][user_defined_type.identifier] = user_defined_type self._defs[kind][user_defined_type.identifier] = user_defined_type
def find_by_identifier(self, identifier): def find_by_identifier(self, identifier):
for defs_per_kind in self._defs: for defs_per_kind in self._defs.itervalues():
if identifier in defs_per_kind: if identifier in defs_per_kind:
return defs_per_kind[identifier] return defs_per_kind[identifier]
raise KeyError(identifier) raise KeyError(identifier)
......
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
# 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.
from .database import Database
from .database import DatabaseBody
from .dictionary import Dictionary
from .identifier_ir_map import IdentifierIRMap from .identifier_ir_map import IdentifierIRMap
from .idl_type import IdlTypeFactory from .idl_type import IdlTypeFactory
from .reference import RefByIdFactory from .reference import RefByIdFactory
...@@ -49,27 +52,28 @@ class IdlCompiler(object): ...@@ -49,27 +52,28 @@ class IdlCompiler(object):
self._ref_to_idl_type_factory = ref_to_idl_type_factory self._ref_to_idl_type_factory = ref_to_idl_type_factory
self._ref_to_idl_def_factory = ref_to_idl_def_factory self._ref_to_idl_def_factory = ref_to_idl_def_factory
self._idl_type_factory = idl_type_factory self._idl_type_factory = idl_type_factory
self._db = DatabaseBody()
self._did_run = False # Run only once.
def build_database(self): def build_database(self):
self._merge_partials() assert not self._did_run
self._merge_mixins() self._did_run = True
self._resolve_inheritances()
self._resolve_exposures()
self._define_unions()
self._generate_database()
def _generate_database(self):
"""
Returns an IDL database based on this compiler.
"""
pass
def _merge_partials(self): # Merge partial definitions.
""" self._merge_partial_interfaces()
Merges partial definitions with corresponding non-partial definitions.
"""
self._merge_partial_dictionaries() self._merge_partial_dictionaries()
# TODO(peria): Implement this. http:///crbug.com/839389
# Updates on IRs are finished. Create API objects.
self._create_public_objects()
# Resolve references.
self._resolve_references_to_idl_type()
self._resolve_references_to_idl_def()
return Database(self._db)
def _merge_partial_interfaces(self):
pass
def _merge_partial_dictionaries(self): def _merge_partial_dictionaries(self):
old_dictionaries = self._ir_map.find_by_kind( old_dictionaries = self._ir_map.find_by_kind(
...@@ -92,31 +96,27 @@ class IdlCompiler(object): ...@@ -92,31 +96,27 @@ class IdlCompiler(object):
]) ])
self._ir_map.add(new_dictionary) self._ir_map.add(new_dictionary)
def _merge_mixins(self): def _create_public_objects(self):
""" """Creates public representations of compiled objects."""
Merges mixins with interfaces that connected with includes statements. dictionary_irs = self._ir_map.find_by_kind(
""" IdentifierIRMap.IR.Kind.DICTIONARY)
self._ir_map.move_to_new_phase() for ir in dictionary_irs.itervalues():
# TODO(peria): Implement this. http:///crbug.com/839389 self._db.register(DatabaseBody.Kind.DICTIONARY, Dictionary(ir))
def _resolve_inheritances(self): def _resolve_references_to_idl_type(self):
""" def resolve(ref):
Resolves inheritances and [Unforgeable] # Resolve to stubs for the time being.
""" ref.set_target_object(False)
self._ir_map.move_to_new_phase()
# TODO(peria): Implement this. http:///crbug.com/839389 self._ref_to_idl_type_factory.for_each(resolve)
def _resolve_exposures(self): def _resolve_references_to_idl_def(self):
""" def resolve(ref):
Links [Exposed] interfaces/namespaces with [Global] interfaces try:
""" ref.set_target_object(
self._ir_map.move_to_new_phase() self._db.find_by_identifier(ref.identifier))
# TODO(peria): Implement this. http:///crbug.com/839389 except KeyError:
# Resolve to stubs for the time being.
def _define_unions(self): ref.set_target_object(False)
"""
Create a definition of union, that is unique in union types that have self._ref_to_idl_def_factory.for_each(resolve)
same flattened-like members.
"""
self._ir_map.move_to_new_phase()
# TODO(peria): Implement this. http:///crbug.com/839389
...@@ -8,6 +8,7 @@ from .attribute import Attribute ...@@ -8,6 +8,7 @@ from .attribute import Attribute
from .callback_function import CallbackFunction from .callback_function import CallbackFunction
from .callback_interface import CallbackInterface from .callback_interface import CallbackInterface
from .common import DebugInfo from .common import DebugInfo
from .common import Location
from .constant import Constant from .constant import Constant
from .dictionary import Dictionary from .dictionary import Dictionary
from .dictionary import DictionaryMember from .dictionary import DictionaryMember
...@@ -317,7 +318,7 @@ class _IRBuilder(object): ...@@ -317,7 +318,7 @@ class _IRBuilder(object):
def _build_debug_info(self, node): def _build_debug_info(self, node):
return DebugInfo( return DebugInfo(
location=DebugInfo.Location( location=Location(
filepath=node.GetProperty('FILENAME'), filepath=node.GetProperty('FILENAME'),
line_number=node.GetProperty('LINENO'), line_number=node.GetProperty('LINENO'),
column_number=node.GetProperty('POSITION'))) column_number=node.GetProperty('POSITION')))
......
...@@ -17,14 +17,14 @@ class Proxy(object): ...@@ -17,14 +17,14 @@ class Proxy(object):
""" """
Creates a new proxy to |target_object|. Creates a new proxy to |target_object|.
Keyword arguments: Args:
target_object -- The object to which attribute access is proxied. This target_object: The object to which attribute access is proxied.
can be set later by set_target_object. This can be set later by set_target_object.
target_attrs -- None or list of attribute names to be proxied. If None, target_attrs: None or list of attribute names to be proxied. If
all the attribute access is proxied. None, all the attribute access is proxied.
target_attrs_with_priority -- None or list of attribute names to be target_attrs_with_priority: None or list of attribute names to be
unconditionally proxied with priority over attributes defined on unconditionally proxied with priority over attributes defined on
|self|. If None, no attribute has priority over own attributes. |self|. If None, no attribute has priority over own attributes.
""" """
if target_attrs is not None: if target_attrs is not None:
assert isinstance(target_attrs, (list, set, tuple)) assert isinstance(target_attrs, (list, set, tuple))
...@@ -36,7 +36,7 @@ class Proxy(object): ...@@ -36,7 +36,7 @@ class Proxy(object):
def __getattr__(self, attribute): def __getattr__(self, attribute):
target_object = object.__getattribute__(self, '_target_object') target_object = object.__getattribute__(self, '_target_object')
target_attrs = object.__getattribute__(self, '_target_attrs') target_attrs = object.__getattribute__(self, '_target_attrs')
assert target_object assert target_object is not None
if target_attrs is None or attribute in target_attrs: if target_attrs is None or attribute in target_attrs:
return getattr(target_object, attribute) return getattr(target_object, attribute)
raise AttributeError raise AttributeError
...@@ -80,7 +80,7 @@ class Proxy(object): ...@@ -80,7 +80,7 @@ class Proxy(object):
@property @property
def target_object(self): def target_object(self):
assert self._target_object assert self._target_object is not None
return self._target_object return self._target_object
...@@ -151,4 +151,4 @@ class RefByIdFactory(object): ...@@ -151,4 +151,4 @@ class RefByIdFactory(object):
assert callable(callback) assert callable(callback)
self._is_frozen = True self._is_frozen = True
for ref in self._references: for ref in self._references:
resolver(ref) callback(ref)
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