Commit 5f595574 authored by Yuki Shiino's avatar Yuki Shiino Committed by Commit Bot

IDL compiler: Refactor ExtendedAttributes

As a preparation to introduce identity operator to
ExtendedAttributes, refactors ExtendedAttributes
giving it immutability.

Bug: 839389
Change-Id: Ia985e9fc09ec0647ea819fe373a2482bd5473dfb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1724434
Commit-Queue: Yuki Shiino <yukishiino@chromium.org>
Reviewed-by: default avatarHitoshi Yoshida <peria@chromium.org>
Cr-Commit-Position: refs/heads/master@{#682592}
parent 1bc6e59d
......@@ -5,58 +5,61 @@
# This file defines some classes to implement extended attributes
# https://heycam.github.io/webidl/#idl-extended-attributes
from itertools import groupby
import itertools
class ExtendedAttribute(object):
"""ExtendedAttribute represents an exnteded attribute that
is described in either of following formats as spec defines.
a. [Key]
b. [Key=Value]
c. [Key=(Value1,Value2,...)]
d. [Key(ValueL1 ValueR1, ValueL2 ValueR2,...)]
e. [Key=Name(ValueL1 ValueR1, ValueL2 ValueR2,...)]
"""
_FORM_NO_ARGS = 'NoArgs' # for (a)
_FORM_IDENT = 'Ident' # for (b)
_FORM_IDENT_LIST = 'IdentList' # for (c)
_FORM_ARG_LIST = 'ArgList' # for (d)
_FORM_NAMED_ARG_LIST = 'NamedArgList' # for (e)
Represents a single extended attribute.
https://heycam.github.io/webidl/#dfn-extended-attribute
"""
# [Key]
_FORM_NO_ARGS = 'NoArgs'
# [Key=Value]
_FORM_IDENT = 'Ident'
# [Key=(Value1, Value2, ...)]
_FORM_IDENT_LIST = 'IdentList'
# [Key(Value1L Value1R, Value2L Value2R, ...)]
_FORM_ARG_LIST = 'ArgList'
# [Key=Name(Value1L Value1R, Value2L Value2R, ...)]
_FORM_NAMED_ARG_LIST = 'NamedArgList'
def __init__(self, key, values=None, arguments=None, name=None):
assert isinstance(key, str)
# |values| can be either of None, a single string, or a list.
assert values is None or isinstance(values, (str, tuple, list))
# |arguments| can be either of None or a list of pairs of strings.
assert arguments is None or isinstance(arguments, (tuple, list))
assert values is None or isinstance(values, str) or (isinstance(
values,
(list, tuple)) and all(isinstance(value, str) for value in values))
assert arguments is None or (isinstance(
arguments, (list, tuple)) and all(
isinstance(left, str) and isinstance(right, str)
for left, right in arguments))
assert name is None or isinstance(name, str)
self._format = None
self._key = key
self._values = values
self._arguments = arguments
self._values = None
self._arguments = None
self._name = name
if name is not None:
self._format = self._FORM_NAMED_ARG_LIST
if values is not None or arguments is None:
raise ValueError('Unknown format for ExtendedAttribute')
self._arguments = tuple(arguments)
elif arguments is not None:
assert all(
isinstance(arg, (tuple, list)) and len(arg) == 2
and isinstance(arg[0], str) and isinstance(arg[1], str)
for arg in arguments)
self._format = self._FORM_ARG_LIST
if values is not None:
raise ValueError('Unknown format for ExtendedAttribute')
self._arguments = tuple(arguments)
elif values is None:
self._format = self._FORM_NO_ARGS
elif isinstance(values, (tuple, list)):
self._format = self._FORM_IDENT_LIST
self._values = tuple(values)
elif isinstance(values, str):
self._format = self._FORM_IDENT
self._values = values
else:
raise ValueError('Unknown format for ExtendedAttribute')
self._format = self._FORM_IDENT_LIST
self._values = tuple(values)
def make_copy(self):
return ExtendedAttribute(
......@@ -83,30 +86,24 @@ class ExtendedAttribute(object):
@property
def key(self):
"""
Returns the key.
@return str
"""
return self._key
@property
def value(self):
"""
Returns the value for the format Ident. Returns None for the format
NoArgs. Raises an error otherwise.
@return str
Returns the value for format Ident. Returns None for format NoArgs.
Raises an error otherwise.
"""
if self._format in (self._FORM_NO_ARGS, self._FORM_IDENT):
return self._values
raise ValueError('"{}" does not have a single value.'.format(
str(self)))
raise ValueError('[{}] does not have a single value.'.format(
self.syntactic_form))
@property
def values(self):
"""
Returns a list of values for formats Ident and IdentList. Returns an
empty list for the format NorArgs. Raises an error otherwise.
@return tuple(str)
Returns a list of values for format Ident and IdentList. Returns an
empty list for format NorArgs. Raises an error otherwise.
"""
if self._format == self._FORM_NO_ARGS:
return ()
......@@ -114,28 +111,29 @@ class ExtendedAttribute(object):
return (self._values, )
if self._format == self._FORM_IDENT_LIST:
return self._values
raise ValueError('"{}" does not have values.'.format(str(self)))
raise ValueError('[{}] does not have a value.'.format(
self.syntactic_form))
@property
def arguments(self):
"""
Returns a tuple of value pairs for formats ArgList and NamedArgList.
Returns a list of value pairs for format ArgList and NamedArgList.
Raises an error otherwise.
@return tuple(Argument)
"""
if self._format in (self._FORM_ARG_LIST, self._FORM_NAMED_ARG_LIST):
return self._arguments
raise ValueError('"{}" does not have arguments.'.format(str(self)))
raise ValueError('[{}] does not have an argument.'.format(
self.syntactic_form))
@property
def name(self):
"""
Returns |Name| for the format NamedArgList. Raises an error otherwise.
@return str
Returns |Name| for format NamedArgList. Raises an error otherwise.
"""
if self._format == self._FORM_NAMED_ARG_LIST:
return self._name
raise ValueError('"{}" does not have a name.'.format(str(self)))
raise ValueError('[{}] does not have a name.'.format(
self.syntactic_form))
class ExtendedAttributes(object):
......@@ -145,7 +143,7 @@ class ExtendedAttributes(object):
For an IDL fragment
[A, A=(foo, bar), B=baz]
the generated ExtendedAttributes instance will be like
an ExtendedAttributes instance will be like
{
'A': (ExtendedAttribute('A'), ExtendedAttribute('A', values=('foo', 'bar'))),
'B': (ExtendedAttribute('B', value='baz')),
......@@ -159,26 +157,21 @@ class ExtendedAttributes(object):
for attr in attributes))
attributes = sorted(attributes or [], key=lambda x: x.key)
self._attributes = {
k: tuple(v)
for k, v in groupby(attributes, key=lambda x: x.key)
key: tuple(attrs)
for key, attrs in itertools.groupby(
attributes, key=lambda x: x.key)
}
def __bool__(self):
return bool(self._attributes)
def __contains__(self, key):
"""
Returns True if this has an extended attribute with the |key|.
@param str key
@return bool
"""
"""Returns True if this has an extended attribute with the |key|."""
return key in self._attributes
def __iter__(self):
"""
Yields all ExtendedAttribute instances.
"""
for attrs in self._attributes.values():
"""Yields all ExtendedAttribute instances."""
for attrs in self._attributes.itervalues():
for attr in attrs:
yield attr
......@@ -198,11 +191,8 @@ class ExtendedAttributes(object):
def get(self, key):
"""
Returns an exnteded attribute whose key is |key|.
If |self| has no such elements, returns None,
and if |self| has multiple elements, raises an error.
@param str key
@return ExtendedAttriute?
Returns an exnteded attribute whose key is |key|, or None if not found.
If there are multiple extended attributes with |key|, raises an error.
"""
values = self.get_list_of(key)
if len(values) == 0:
......@@ -215,13 +205,6 @@ class ExtendedAttributes(object):
def get_list_of(self, key):
"""
Returns a list of extended attributes whose keys are |identifier|.
@param str key
@return tuple(ExtendedAttribute)
Returns a list of extended attributes whose keys are |key|.
"""
return self._attributes.get(key, ())
def append(self, extended_attribute):
assert isinstance(extended_attribute, ExtendedAttribute)
key = extended_attribute.key
self._attributes[key] = self.get_list_of(key) + (extended_attribute, )
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