177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin#!/usr/bin/python
277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin#
477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# Copyright (C) 2012 The Android Open Source Project
577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin#
677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# Licensed under the Apache License, Version 2.0 (the "License");
777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# you may not use this file except in compliance with the License.
877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# You may obtain a copy of the License at
977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin#
1077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin#      http://www.apache.org/licenses/LICENSE-2.0
1177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin#
1277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# Unless required by applicable law or agreed to in writing, software
1377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# distributed under the License is distributed on an "AS IS" BASIS,
1477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# See the License for the specific language governing permissions and
1677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# limitations under the License.
1777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin#
1877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
1977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin"""
2077b63ca0447545a4dac3ac062f218d878ce01ba0Igor MurashkinA set of classes (models) each closely representing an XML node in the
2177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkinmetadata_properties.xml file.
2277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
2377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  Node: Base class for most nodes.
2477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  Entry: A node corresponding to <entry> elements.
2577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  Clone: A node corresponding to <clone> elements.
26aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin  MergedEntry: A node corresponding to either <entry> or <clone> elements.
2777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  Kind: A node corresponding to <dynamic>, <static>, <controls> elements.
2877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  InnerNamespace: A node corresponding to a <namespace> nested under a <kind>.
2977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  OuterNamespace: A node corresponding to a <namespace> with <kind> children.
3077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  Section: A node corresponding to a <section> element.
3177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  Enum: A class corresponding an <enum> element within an <entry>
32aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin  EnumValue: A class corresponding to a <value> element within an Enum
3377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  Metadata: Root node that also provides tree construction functionality.
3477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  Tag: A node corresponding to a top level <tag> element.
35b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin  Typedef: A node corresponding to a <typedef> element under <types>.
3677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin"""
3777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
3877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkinimport sys
395804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkinimport itertools
40586c861e6dab3fdf48fc8440c719ad0b59d49d72Igor Murashkinfrom collections import OrderedDict
4177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
4277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkinclass Node(object):
4377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
4477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  Base class for most nodes that are part of the Metadata graph.
4577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
4677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  Attributes (Read-Only):
4777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    parent: An edge to a parent Node.
4877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    name: A string describing the name, usually but not always the 'name'
4977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin          attribute of the corresponding XML node.
5077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
5177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
5277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def __init__(self):
5377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._parent = None
5477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._name = None
5577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
5677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
5777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def parent(self):
5877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._parent
5977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
6077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
6177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def name(self):
6277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._name
6377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
6477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def find_all(self, pred):
6577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
6677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Find all descendants that match the predicate.
6777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
6877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Args:
6977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      pred: a predicate function that acts as a filter for a Node
7077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
7177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Yields:
7277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      A sequence of all descendants for which pred(node) is true,
7377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      in a pre-order visit order.
7477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
7577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    if pred(self):
7677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      yield self
7777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
7877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    if self._get_children() is None:
7977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      return
8077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
8177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    for i in self._get_children():
8277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      for j in i.find_all(pred):
8377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        yield j
8477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
8577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def find_first(self, pred):
8677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
8777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Find the first descendant that matches the predicate.
8877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
8977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Args:
9077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      pred: a predicate function that acts as a filter for a Node
9177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
9277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Returns:
9377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      The first Node from find_all(pred), or None if there were no results.
9477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
9577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    for i in self.find_all(pred):
9677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      return i
9777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
9877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return None
9977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
10077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def find_parent_first(self, pred):
10177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
10277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Find the first ancestor that matches the predicate.
10377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
10477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Args:
10577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      pred: A predicate function that acts as a filter for a Node
10677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
10777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Returns:
10877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      The first ancestor closest to the node for which pred(node) is true.
10977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
11077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    for i in self.find_parents(pred):
11177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      return i
11277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
11377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return None
11477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
11577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def find_parents(self, pred):
11677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
11777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Find all ancestors that match the predicate.
11877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
11977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Args:
12077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      pred: A predicate function that acts as a filter for a Node
12177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
12277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Yields:
12377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      A sequence of all ancestors (closest to furthest) from the node,
12477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      where pred(node) is true.
12577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
12677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    parent = self.parent
12777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
12877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    while parent is not None:
12977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      if pred(parent):
13077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        yield parent
13177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      parent = parent.parent
13277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
13377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def sort_children(self):
13477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
13577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Sorts the immediate children in-place.
13677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
13777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._sort_by_name(self._children)
13877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
13977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def _sort_by_name(self, what):
14077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    what.sort(key=lambda x: x.name)
14177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
14277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def _get_name(self):
14377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return lambda x: x.name
14477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
14577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  # Iterate over all children nodes. None when node doesn't support children.
14677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def _get_children(self):
14777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return (i for i in self._children)
14877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
14977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def _children_name_map_matching(self, match=lambda x: True):
15077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    d = {}
151aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    for i in self._get_children():
15277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      if match(i):
15377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        d[i.name] = i
15477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return d
15577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
15677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @staticmethod
15777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def _dictionary_by_name(values):
158586c861e6dab3fdf48fc8440c719ad0b59d49d72Igor Murashkin    d = OrderedDict()
15977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    for i in values:
16077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      d[i.name] = i
16177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
16277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return d
16377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
16477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def validate_tree(self):
16577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
16677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Sanity check the tree recursively, ensuring for a node n, all children's
16777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    parents are also n.
16877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
16977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Returns:
17077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      True if validation succeeds, False otherwise.
17177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
17277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    succ = True
17377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    children = self._get_children()
17477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    if children is None:
17577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      return True
17677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
17777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    for child in self._get_children():
17877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      if child.parent != self:
17977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        print >> sys.stderr, ("ERROR: Node '%s' doesn't match the parent" +    \
18077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin                             "(expected: %s, actual %s)")                      \
18177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin                             %(child, self, child.parent)
18277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        succ = False
18377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
18477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      succ = child.validate_tree() and succ
18577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
18677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return succ
18777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
18877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def __str__(self):
18977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return "<%s name='%s'>" %(self.__class__, self.name)
19077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
19177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkinclass Metadata(Node):
19277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
19377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  A node corresponding to a <metadata> entry.
19477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
19577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  Attributes (Read-Only):
19677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    parent: An edge to the parent Node. This is always None for Metadata.
19777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    outer_namespaces: A sequence of immediate OuterNamespace children.
19877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    tags: A sequence of all Tag instances available in the graph.
199b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    types: An iterable of all Typedef instances available in the graph.
20077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
20177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
20277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def __init__(self):
20377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
20477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Initialize with no children. Use insert_* functions and then
20577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    construct_graph() to build up the Metadata from some source.
20677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
20777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# Private
20877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._entries = []
20977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    # kind => { name => entry }
21077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._entry_map = { 'static': {}, 'dynamic': {}, 'controls': {} }
211586c861e6dab3fdf48fc8440c719ad0b59d49d72Igor Murashkin    self._entries_ordered = [] # list of ordered Entry/Clone instances
21277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._clones = []
21377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
21477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# Public (Read Only)
21563c0fb27d923a32d9a398471ad318bfe84befbebEino-Ville Talvala    self._name = None
21677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._parent = None
21777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._outer_namespaces = None
21877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._tags = []
219b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    self._types = []
22077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
22177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
22277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def outer_namespaces(self):
22377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    if self._outer_namespaces is None:
22477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      return None
22577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    else:
22677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      return (i for i in self._outer_namespaces)
22777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
22877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
22977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def tags(self):
23077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return (i for i in self._tags)
23177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
232b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin  @property
233b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin  def types(self):
234b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    return (i for i in self._types)
235b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin
23677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def _get_properties(self):
23777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
23877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    for i in self._entries:
23977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      yield i
24077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
24177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    for i in self._clones:
24277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      yield i
24377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
24477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def insert_tag(self, tag, description=""):
24577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
24677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Insert a tag into the metadata.
24777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
24877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Args:
24977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      tag: A string identifier for a tag.
25077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      description: A string description for a tag.
25177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
25277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Example:
25377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      metadata.insert_tag("BC", "Backwards Compatibility for old API")
25477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
25577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Remarks:
25677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      Subsequent calls to insert_tag with the same tag are safe (they will
25777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      be ignored).
25877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
25977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    tag_ids = [tg.name for tg in self.tags if tg.name == tag]
26077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    if not tag_ids:
2616ad61d460aabf8db9b52e946bb38b8f20717b2a8Igor Murashkin      self._tags.append(Tag(tag, self, description))
26277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
263b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin  def insert_type(self, type_name, type_selector="typedef", **kwargs):
264b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    """
265b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    Insert a type into the metadata.
266b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin
267b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    Args:
268b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin      type_name: A type's name
269b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin      type_selector: The selector for the type, e.g. 'typedef'
270b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin
271b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    Args (if type_selector == 'typedef'):
272b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin      languages: A map of 'language name' -> 'fully qualified class path'
273b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin
274b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    Example:
275b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin      metadata.insert_type('rectangle', 'typedef',
276b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin                           { 'java': 'android.graphics.Rect' })
277b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin
278b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    Remarks:
279b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin      Subsequent calls to insert_type with the same type name are safe (they
280b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin      will be ignored)
281b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    """
282b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin
283b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    if type_selector != 'typedef':
284b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin      raise ValueError("Unsupported type_selector given " + type_selector)
285b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin
286b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    type_names = [tp.name for tp in self.types if tp.name == tp]
287b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    if not type_names:
288b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin      self._types.append(Typedef(type_name, self, kwargs.get('languages')))
289b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin
29077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def insert_entry(self, entry):
29177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
29277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Insert an entry into the metadata.
29377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
29477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Args:
29577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry: A key-value dictionary describing an entry. Refer to
29677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin             Entry#__init__ for the keys required/optional.
29777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
29877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Remarks:
29977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      Subsequent calls to insert_entry with the same entry+kind name are safe
30077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      (they will be ignored).
30177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
30277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    e = Entry(**entry)
30377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._entries.append(e)
30477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._entry_map[e.kind][e.name] = e
305586c861e6dab3fdf48fc8440c719ad0b59d49d72Igor Murashkin    self._entries_ordered.append(e)
30677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
30777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def insert_clone(self, clone):
30877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
30977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Insert a clone into the metadata.
31077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
31177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Args:
31277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      clone: A key-value dictionary describing a clone. Refer to
31377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin            Clone#__init__ for the keys required/optional.
31477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
31577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Remarks:
31677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      Subsequent calls to insert_clone with the same clone+kind name are safe
31777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      (they will be ignored). Also the target entry need not be inserted
31877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      ahead of the clone entry.
31977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
32077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    # figure out corresponding entry later. allow clone insert, entry insert
32177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    entry = None
32277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    c = Clone(entry, **clone)
32377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._entry_map[c.kind][c.name] = c
32477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._clones.append(c)
325586c861e6dab3fdf48fc8440c719ad0b59d49d72Igor Murashkin    self._entries_ordered.append(c)
32677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
32777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def prune_clones(self):
32877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
32977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Remove all clones that don't point to an existing entry.
33077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
33177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Remarks:
33277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      This should be called after all insert_entry/insert_clone calls have
33377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      finished.
33477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
33577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    remove_list = []
33677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    for p in self._clones:
33777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      if p.entry is None:
33877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        remove_list.append(p)
33977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
34077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    for p in remove_list:
34177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
34277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      # remove from parent's entries list
34377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      if p.parent is not None:
34477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        p.parent._entries.remove(p)
34577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      # remove from parents' _leafs list
346aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      for ancestor in p.find_parents(lambda x: not isinstance(x, Metadata)):
34777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        ancestor._leafs.remove(p)
34877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
34977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      # remove from global list
35077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      self._clones.remove(p)
35177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      self._entry_map[p.kind].pop(p.name)
352586c861e6dab3fdf48fc8440c719ad0b59d49d72Igor Murashkin      self._entries_ordered.remove(p)
35377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
35477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
35577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  # After all entries/clones are inserted,
35677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  # invoke this to generate the parent/child node graph all these objects
35777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def construct_graph(self):
35877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
35977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Generate the graph recursively, after which all Entry nodes will be
36077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    accessible recursively by crawling through the outer_namespaces sequence.
36177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
36277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Remarks:
36377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      This is safe to be called multiple times at any time. It should be done at
36477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      least once or there will be no graph.
36577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
36677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self.validate_tree()
36777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._construct_tags()
36877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self.validate_tree()
369b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    self._construct_types()
370b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    self.validate_tree()
37177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._construct_clones()
37277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self.validate_tree()
37377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._construct_outer_namespaces()
37477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self.validate_tree()
37577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
37677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def _construct_tags(self):
37777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    tag_dict = self._dictionary_by_name(self.tags)
37877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    for p in self._get_properties():
37977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      p._tags = []
38077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      for tag_id in p._tag_ids:
38177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        tag = tag_dict.get(tag_id)
38277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
38377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        if tag not in p._tags:
38477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin          p._tags.append(tag)
38577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
386617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin        if p not in tag.entries:
387617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin          tag._entries.append(p)
388617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin
389b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin  def _construct_types(self):
390b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    type_dict = self._dictionary_by_name(self.types)
391b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    for p in self._get_properties():
392b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin      if p._type_name:
393b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin        type_node = type_dict.get(p._type_name)
394b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin        p._typedef = type_node
395b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin
396b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin        if p not in type_node.entries:
397b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin          type_node._entries.append(p)
398b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin
39977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def _construct_clones(self):
40077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    for p in self._clones:
40177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      target_kind = p.target_kind
40277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      target_entry = self._entry_map[target_kind].get(p.name)
40377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      p._entry = target_entry
40477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
40577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      # should not throw if we pass validation
40677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      # but can happen when importing obsolete CSV entries
40777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      if target_entry is None:
40877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        print >> sys.stderr, ("WARNING: Clone entry '%s' target kind '%s'" +   \
40977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin                              " has no corresponding entry")                   \
41077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin                             %(p.name, p.target_kind)
41177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
41277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def _construct_outer_namespaces(self):
41377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
41477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    if self._outer_namespaces is None: #the first time this runs
41577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      self._outer_namespaces = []
41677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
41777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    root = self._dictionary_by_name(self._outer_namespaces)
41877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    for ons_name, ons in root.iteritems():
41977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      ons._leafs = []
42077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
421586c861e6dab3fdf48fc8440c719ad0b59d49d72Igor Murashkin    for p in self._entries_ordered:
42277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      ons_name = p.get_outer_namespace()
42377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      ons = root.get(ons_name, OuterNamespace(ons_name, self))
42477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      root[ons_name] = ons
42577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
42677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      if p not in ons._leafs:
42777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        ons._leafs.append(p)
42877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
42977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    for ons_name, ons in root.iteritems():
43077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
43177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      ons.validate_tree()
43277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
43377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      self._construct_sections(ons)
43477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
43577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      if ons not in self._outer_namespaces:
43677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        self._outer_namespaces.append(ons)
43777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
43877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      ons.validate_tree()
43977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
44077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def _construct_sections(self, outer_namespace):
44177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
44277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    sections_dict = self._dictionary_by_name(outer_namespace.sections)
44377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    for sec_name, sec in sections_dict.iteritems():
44477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      sec._leafs = []
44577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      sec.validate_tree()
44677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
44777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    for p in outer_namespace._leafs:
44877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      does_exist = sections_dict.get(p.get_section())
44977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
45077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      sec = sections_dict.get(p.get_section(), \
45177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin          Section(p.get_section(), outer_namespace))
45277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      sections_dict[p.get_section()] = sec
45377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
45477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      sec.validate_tree()
45577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
45677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      if p not in sec._leafs:
45777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        sec._leafs.append(p)
45877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
45977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    for sec_name, sec in sections_dict.iteritems():
46077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
46177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      if not sec.validate_tree():
46277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        print >> sys.stderr, ("ERROR: Failed to validate tree in " +           \
46377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin                             "construct_sections (start), with section = '%s'")\
46477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin                             %(sec)
46577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
46677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      self._construct_kinds(sec)
46777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
46877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      if sec not in outer_namespace.sections:
46977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        outer_namespace._sections.append(sec)
47077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
47177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      if not sec.validate_tree():
47277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        print >> sys.stderr, ("ERROR: Failed to validate tree in " +           \
47377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin                              "construct_sections (end), with section = '%s'") \
47477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin                             %(sec)
47577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
47677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  # 'controls', 'static' 'dynamic'. etc
47777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def _construct_kinds(self, section):
4785804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin    for kind in section.kinds:
47977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      kind._leafs = []
48077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      section.validate_tree()
48177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
4825804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin    group_entry_by_kind = itertools.groupby(section._leafs, lambda x: x.kind)
4835804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin    leaf_it = ((k, g) for k, g in group_entry_by_kind)
48477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
4855804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin    # allow multiple kinds with the same name. merge if adjacent
4865804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin    # e.g. dynamic,dynamic,static,static,dynamic -> dynamic,static,dynamic
4875804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin    # this helps maintain ABI compatibility when adding an entry in a new kind
4885804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin    for idx, (kind_name, entry_it) in enumerate(leaf_it):
4895804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin      if idx >= len(section._kinds):
4905804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin        kind = Kind(kind_name, section)
4915804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin        section._kinds.append(kind)
4925804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin        section.validate_tree()
49377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
4945804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin      kind = section._kinds[idx]
49577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
4965804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin      for p in entry_it:
4975804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin        if p not in kind._leafs:
4985804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin          kind._leafs.append(p)
49977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
5005804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin    for kind in section._kinds:
50177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      kind.validate_tree()
50277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      self._construct_inner_namespaces(kind)
50377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      kind.validate_tree()
50477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      self._construct_entries(kind)
50577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      kind.validate_tree()
50677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
50777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      if not section.validate_tree():
50877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        print >> sys.stderr, ("ERROR: Failed to validate tree in " +           \
50977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin                             "construct_kinds, with kind = '%s'") %(kind)
51077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
51177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      if not kind.validate_tree():
51277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        print >> sys.stderr, ("ERROR: Failed to validate tree in " +           \
51377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin                              "construct_kinds, with kind = '%s'") %(kind)
51477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
51577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def _construct_inner_namespaces(self, parent, depth=0):
51677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    #parent is InnerNamespace or Kind
51777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    ins_dict = self._dictionary_by_name(parent.namespaces)
51877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    for name, ins in ins_dict.iteritems():
51977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      ins._leafs = []
52077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
52177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    for p in parent._leafs:
52277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      ins_list = p.get_inner_namespace_list()
52377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
52477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      if len(ins_list) > depth:
52577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        ins_str = ins_list[depth]
52677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        ins = ins_dict.get(ins_str, InnerNamespace(ins_str, parent))
52777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        ins_dict[ins_str] = ins
52877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
52977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        if p not in ins._leafs:
53077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin          ins._leafs.append(p)
53177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
53277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    for name, ins in ins_dict.iteritems():
53377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      ins.validate_tree()
53477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      # construct children INS
53577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      self._construct_inner_namespaces(ins, depth + 1)
53677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      ins.validate_tree()
53777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      # construct children entries
53877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      self._construct_entries(ins, depth + 1)
53977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
54077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      if ins not in parent.namespaces:
54177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        parent._namespaces.append(ins)
54277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
54377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      if not ins.validate_tree():
54477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        print >> sys.stderr, ("ERROR: Failed to validate tree in " +           \
54577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin                              "construct_inner_namespaces, with ins = '%s'")   \
54677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin                             %(ins)
54777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
54877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  # doesnt construct the entries, so much as links them
54977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def _construct_entries(self, parent, depth=0):
55077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    #parent is InnerNamespace or Kind
55177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    entry_dict = self._dictionary_by_name(parent.entries)
55277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    for p in parent._leafs:
55377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      ins_list = p.get_inner_namespace_list()
55477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
55577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      if len(ins_list) == depth:
55677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        entry = entry_dict.get(p.name, p)
55777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        entry_dict[p.name] = entry
55877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
55977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    for name, entry in entry_dict.iteritems():
56077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
56177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      old_parent = entry.parent
56277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry._parent = parent
56377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
56477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      if entry not in parent.entries:
56577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        parent._entries.append(entry)
56677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
56777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      if old_parent is not None and old_parent != parent:
56877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        print >> sys.stderr, ("ERROR: Parent changed from '%s' to '%s' for " + \
56977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin                              "entry '%s'")                                    \
57077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin                             %(old_parent.name, parent.name, entry.name)
57177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
57277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def _get_children(self):
57377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    if self.outer_namespaces is not None:
57477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      for i in self.outer_namespaces:
57577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        yield i
57677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
57777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    if self.tags is not None:
57877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      for i in self.tags:
57977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        yield i
58077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
58177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkinclass Tag(Node):
58277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
58377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  A tag Node corresponding to a top-level <tag> element.
58477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
58577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  Attributes (Read-Only):
58677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    name: alias for id
58777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    id: The name of the tag, e.g. for <tag id="BC"/> id = 'BC'
58877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    description: The description of the tag, the contents of the <tag> element.
58977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    parent: An edge to the parent, which is always the Metadata root node.
59077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    entries: A sequence of edges to entries/clones that are using this Tag.
59177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
59277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def __init__(self, name, parent, description=""):
59377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._name        = name  # 'id' attribute in XML
59477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._id          = name
59577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._description = description
59677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._parent      = parent
59777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
59877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    # all entries that have this tag, including clones
599617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    self._entries     = []  # filled in by Metadata#construct_tags
60077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
60177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
60277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def id(self):
60377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._id
60477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
60577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
60677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def description(self):
60777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._description
60877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
60977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
61077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def entries(self):
61177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return (i for i in self._entries)
61277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
61377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def _get_children(self):
61477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return None
61577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
616b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkinclass Typedef(Node):
617b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin  """
618b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin  A typedef Node corresponding to a <typedef> element under a top-level <types>.
619b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin
620b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin  Attributes (Read-Only):
621b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    name: The name of this typedef as a string.
622b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    languages: A dictionary of 'language name' -> 'fully qualified class'.
623b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    parent: An edge to the parent, which is always the Metadata root node.
624b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    entries: An iterable over all entries which reference this typedef.
625b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin  """
626b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin  def __init__(self, name, parent, languages=None):
627b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    self._name        = name
628b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    self._parent      = parent
629b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin
630b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    # all entries that have this typedef
631b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    self._entries     = []  # filled in by Metadata#construct_types
632b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin
633b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    self._languages   = languages or {}
634b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin
635b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin  @property
636b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin  def languages(self):
637b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    return self._languages
638b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin
639b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin  @property
640b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin  def entries(self):
641b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    return (i for i in self._entries)
642b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin
643b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin  def _get_children(self):
644b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    return None
645b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin
64677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkinclass OuterNamespace(Node):
64777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
64877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  A node corresponding to a <namespace> element under <metadata>
64977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
65077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  Attributes (Read-Only):
65177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    name: The name attribute of the <namespace name="foo"> element.
65277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    parent: An edge to the parent, which is always the Metadata root node.
65377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    sections: A sequence of Section children.
65477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
65577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def __init__(self, name, parent, sections=[]):
65677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._name = name
65777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._parent = parent # MetadataSet
65877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._sections = sections[:]
65977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._leafs = []
66077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
66177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._children = self._sections
66277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
66377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
66477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def sections(self):
66577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return (i for i in self._sections)
66677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
66777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkinclass Section(Node):
66877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
66977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  A node corresponding to a <section> element under <namespace>
67077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
67177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  Attributes (Read-Only):
67277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    name: The name attribute of the <section name="foo"> element.
67377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    parent: An edge to the parent, which is always an OuterNamespace instance.
67477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    description: A string description of the section, or None.
67577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    kinds: A sequence of Kind children.
6765804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin    merged_kinds: A sequence of virtual Kind children,
6775804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin                  with each Kind's children merged by the kind.name
67877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
67977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def __init__(self, name, parent, description=None, kinds=[]):
68077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._name = name
68177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._parent = parent
68277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._description = description
68377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._kinds = kinds[:]
68477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
68577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._leafs = []
68677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
68777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
68877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
68977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def description(self):
69077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._description
69177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
69277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
69377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def kinds(self):
69477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return (i for i in self._kinds)
69577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
69677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def sort_children(self):
69777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self.validate_tree()
69877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    # order is always controls,static,dynamic
69977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    find_child = lambda x: [i for i in self._get_children() if i.name == x]
70077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    new_lst = find_child('controls') \
70177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin            + find_child('static')   \
70277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin            + find_child('dynamic')
70377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._kinds = new_lst
70477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self.validate_tree()
70577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
70677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def _get_children(self):
70777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return (i for i in self.kinds)
70877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
7095804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin  @property
7105804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin  def merged_kinds(self):
7115804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin
7125804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin    def aggregate_by_name(acc, el):
7135804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin      existing = [i for i in acc if i.name == el.name]
7145804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin      if existing:
7155804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin        k = existing[0]
7165804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin      else:
7175804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin        k = Kind(el.name, el.parent)
7185804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin        acc.append(k)
7195804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin
7205804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin      k._namespaces.extend(el._namespaces)
7215804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin      k._entries.extend(el._entries)
7225804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin
7235804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin      return acc
7245804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin
7255804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin    new_kinds_lst = reduce(aggregate_by_name, self.kinds, [])
7265804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin
7275804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin    for k in new_kinds_lst:
7285804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin      yield k
7295804a48bb15d245fb06f72cf6d64369f151fcc28Igor Murashkin
730aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin  def combine_kinds_into_single_node(self):
731aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    r"""
732aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    Combines the section's Kinds into a single node.
733aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
734aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    Combines all the children (kinds) of this section into a single
735aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    virtual Kind node.
736aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
737aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    Returns:
738aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      A new Kind node that collapses all Kind siblings into one, combining
739aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      all their children together.
740aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
741aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      For example, given self.kinds == [ x, y ]
742aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
743aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin        x  y               z
744aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      / |  | \    -->   / | | \
745aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      a b  c d          a b c d
746aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
747aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      a new instance z is returned in this example.
748aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
749aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    Remarks:
750aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      The children of the kinds are the same references as before, that is
751aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      their parents will point to the old parents and not to the new parent.
752aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    """
753aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    combined = Kind(name="combined", parent=self)
754aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
755aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    for k in self._get_children():
756aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      combined._namespaces.extend(k.namespaces)
757aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      combined._entries.extend(k.entries)
758aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
759aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    return combined
760aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
76177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkinclass Kind(Node):
76277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
76377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  A node corresponding to one of: <static>,<dynamic>,<controls> under a
76477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  <section> element.
76577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
76677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  Attributes (Read-Only):
76777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    name: A string which is one of 'static', 'dynamic, or 'controls'.
76877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    parent: An edge to the parent, which is always a Section  instance.
76977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    namespaces: A sequence of InnerNamespace children.
77077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    entries: A sequence of Entry/Clone children.
771617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    merged_entries: A sequence of MergedEntry virtual nodes from entries
77277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
77377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def __init__(self, name, parent):
77477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._name = name
77577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._parent = parent
77677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._namespaces = []
77777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._entries = []
77877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
77977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._leafs = []
78077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
78177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
78277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def namespaces(self):
78377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._namespaces
78477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
78577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
78677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def entries(self):
78777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._entries
78877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
789617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin  @property
790617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin  def merged_entries(self):
791617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    for i in self.entries:
792617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin      yield i.merge()
793617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin
79477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def sort_children(self):
79577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._namespaces.sort(key=self._get_name())
79677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._entries.sort(key=self._get_name())
79777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
79877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def _get_children(self):
79977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    for i in self.namespaces:
80077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      yield i
80177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    for i in self.entries:
80277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      yield i
80377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
804aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin  def combine_children_by_name(self):
805aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    r"""
806aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    Combine multiple children with the same name into a single node.
807aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
808aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    Returns:
809aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      A new Kind where all of the children with the same name were combined.
810aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
811aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      For example:
812aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
813aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      Given a Kind k:
814aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
815aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin              k
816aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin            / | \
817aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin            a b c
818aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin            | | |
819aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin            d e f
820aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
821aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      a.name == "foo"
822aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      b.name == "foo"
823aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      c.name == "bar"
824aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
825aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      The returned Kind will look like this:
826aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
827aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin             k'
828aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin            /  \
829aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin            a' c'
830aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin          / |  |
831aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin          d e  f
832aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
833aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    Remarks:
834aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      This operation is not recursive. To combine the grandchildren and other
835aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      ancestors, call this method on the ancestor nodes.
836aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    """
837aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    return Kind._combine_children_by_name(self, new_type=type(self))
838aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
839aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin  # new_type is either Kind or InnerNamespace
840aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin  @staticmethod
841aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin  def _combine_children_by_name(self, new_type):
842aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    new_ins_dict = OrderedDict()
843aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    new_ent_dict = OrderedDict()
844aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
845aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    for ins in self.namespaces:
846aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      new_ins = new_ins_dict.setdefault(ins.name,
847aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin                                        InnerNamespace(ins.name, parent=self))
848aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      new_ins._namespaces.extend(ins.namespaces)
849aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      new_ins._entries.extend(ins.entries)
850aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
851aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    for ent in self.entries:
852aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      new_ent = new_ent_dict.setdefault(ent.name,
853aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin                                        ent.merge())
854aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
855aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    kind = new_type(self.name, self.parent)
856aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    kind._namespaces = new_ins_dict.values()
857aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    kind._entries = new_ent_dict.values()
858aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
859aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    return kind
860aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
86177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkinclass InnerNamespace(Node):
86277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
86377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  A node corresponding to a <namespace> which is an ancestor of a Kind.
86477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  These namespaces may have other namespaces recursively, or entries as leafs.
86577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
86677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  Attributes (Read-Only):
86777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    name: Name attribute from the element, e.g. <namespace name="foo"> -> 'foo'
86877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    parent: An edge to the parent, which is an InnerNamespace or a Kind.
86977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    namespaces: A sequence of InnerNamespace children.
87077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    entries: A sequence of Entry/Clone children.
871617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    merged_entries: A sequence of MergedEntry virtual nodes from entries
87277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
87377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def __init__(self, name, parent):
87477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._name        = name
87577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._parent      = parent
87677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._namespaces  = []
87777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._entries     = []
87877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._leafs       = []
87977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
88077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
88177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def namespaces(self):
88277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._namespaces
88377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
88477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
88577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def entries(self):
88677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._entries
88777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
888617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin  @property
889617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin  def merged_entries(self):
890617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    for i in self.entries:
891617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin      yield i.merge()
892617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin
89377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def sort_children(self):
89477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._namespaces.sort(key=self._get_name())
89577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._entries.sort(key=self._get_name())
89677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
89777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def _get_children(self):
89877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    for i in self.namespaces:
89977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      yield i
90077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    for i in self.entries:
90177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      yield i
90277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
903aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin  def combine_children_by_name(self):
904aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    r"""
905aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    Combine multiple children with the same name into a single node.
906aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
907aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    Returns:
908aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      A new InnerNamespace where all of the children with the same name were
909aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      combined.
910aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
911aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      For example:
912aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
913aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      Given an InnerNamespace i:
914aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
915aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin              i
916aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin            / | \
917aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin            a b c
918aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin            | | |
919aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin            d e f
920aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
921aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      a.name == "foo"
922aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      b.name == "foo"
923aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      c.name == "bar"
924aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
925aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      The returned InnerNamespace will look like this:
926aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
927aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin             i'
928aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin            /  \
929aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin            a' c'
930aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin          / |  |
931aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin          d e  f
932aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
933aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    Remarks:
934aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      This operation is not recursive. To combine the grandchildren and other
935aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin      ancestors, call this method on the ancestor nodes.
936aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    """
937aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    return Kind._combine_children_by_name(self, new_type=type(self))
938aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
939375cfd3889aa72160273af802370c8f47f5c64d1Igor Murashkinclass EnumValue(Node):
94077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
94177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  A class corresponding to a <value> element within an <enum> within an <entry>.
94277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
94377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  Attributes (Read-Only):
94477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    name: A string,                 e.g. 'ON' or 'OFF'
94577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    id: An optional numeric string, e.g. '0' or '0xFF'
94677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    optional: A boolean
947b432916043290beb246054a77f8978b3136f4315Eino-Ville Talvala    hidden: A boolean, True if the enum should be hidden.
94877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    notes: A string describing the notes, or None.
949375cfd3889aa72160273af802370c8f47f5c64d1Igor Murashkin    parent: An edge to the parent, always an Enum instance.
95077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
951b432916043290beb246054a77f8978b3136f4315Eino-Ville Talvala  def __init__(self, name, parent, id=None, optional=False, hidden=False, notes=None):
95277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._name = name                    # str, e.g. 'ON' or 'OFF'
95377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._id = id                        # int, e.g. '0'
95477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._optional = optional            # bool
955b432916043290beb246054a77f8978b3136f4315Eino-Ville Talvala    self._hidden = hidden                # bool
95677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._notes = notes                  # None or str
957375cfd3889aa72160273af802370c8f47f5c64d1Igor Murashkin    self._parent = parent
95877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
95977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
96077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def id(self):
96177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._id
96277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
96377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
96477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def optional(self):
96577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._optional
96677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
96777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
968b432916043290beb246054a77f8978b3136f4315Eino-Ville Talvala  def hidden(self):
969b432916043290beb246054a77f8978b3136f4315Eino-Ville Talvala    return self._hidden
970b432916043290beb246054a77f8978b3136f4315Eino-Ville Talvala
971b432916043290beb246054a77f8978b3136f4315Eino-Ville Talvala  @property
97277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def notes(self):
97377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._notes
97477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
975375cfd3889aa72160273af802370c8f47f5c64d1Igor Murashkin  def _get_children(self):
976375cfd3889aa72160273af802370c8f47f5c64d1Igor Murashkin    return None
977375cfd3889aa72160273af802370c8f47f5c64d1Igor Murashkin
978375cfd3889aa72160273af802370c8f47f5c64d1Igor Murashkinclass Enum(Node):
97977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
98077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  A class corresponding to an <enum> element within an <entry>.
98177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
98277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  Attributes (Read-Only):
98377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    parent: An edge to the parent, always an Entry instance.
98477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    values: A sequence of EnumValue children.
985aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    has_values_with_id: A boolean representing if any of the children have a
986aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin        non-empty id property.
98777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
988b432916043290beb246054a77f8978b3136f4315Eino-Ville Talvala  def __init__(self, parent, values, ids={}, optionals=[], hiddens=[], notes={}):
98977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._values =                                                             \
990b432916043290beb246054a77f8978b3136f4315Eino-Ville Talvala      [ EnumValue(val, self, ids.get(val), val in optionals, val in hiddens,   \
991b432916043290beb246054a77f8978b3136f4315Eino-Ville Talvala                  notes.get(val))                                              \
99277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        for val in values ]
99377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
99477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._parent = parent
995375cfd3889aa72160273af802370c8f47f5c64d1Igor Murashkin    self._name = None
99677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
99777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
99877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def values(self):
99977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return (i for i in self._values)
100077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
1001aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin  @property
1002aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin  def has_values_with_id(self):
1003aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    return bool(any(i for i in self.values if i.id))
1004aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
1005375cfd3889aa72160273af802370c8f47f5c64d1Igor Murashkin  def _get_children(self):
1006375cfd3889aa72160273af802370c8f47f5c64d1Igor Murashkin    return (i for i in self._values)
1007375cfd3889aa72160273af802370c8f47f5c64d1Igor Murashkin
100877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkinclass Entry(Node):
100977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
101077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  A node corresponding to an <entry> element.
101177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
101277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  Attributes (Read-Only):
101377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    parent: An edge to the parent node, which is an InnerNamespace or Kind.
101477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    name: The fully qualified name string, e.g. 'android.shading.mode'
101577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    name_short: The name attribute from <entry name="mode">, e.g. mode
101677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    type: The type attribute from <entry type="bar">
101777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    kind: A string ('static', 'dynamic', 'controls') corresponding to the
101877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin          ancestor Kind#name
101977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    container: The container attribute from <entry container="array">, or None.
102077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    container_sizes: A sequence of size strings or None if container is None.
1021b556bc47068d816cb319a5d0e2f6841b007b38f2Igor Murashkin    enum: An Enum instance if the enum attribute is true, None otherwise.
1022f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala    visibility: The visibility of this entry ('system', 'hidden', 'public')
1023f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala                across the system. System entries are only visible in native code
1024f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala                headers. Hidden entries are marked @hide in managed code, while
1025f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala                public entries are visible in the Android SDK.
1026f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala    applied_visibility: As visibility, but always valid, defaulting to 'system'
1027f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala                        if no visibility is given for an entry.
10286c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin    synthetic: The C-level visibility of this entry ('false', 'true').
10296c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin               Synthetic entries will not be generated into the native metadata
10306c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin               list of entries (in C code). In general a synthetic entry is
10316c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin               glued together at the Java layer from multiple visibiltity=hidden
10326c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin               entries.
1033ca25627fc63255d147286ef9a9624059825eb548Igor Murashkin    hwlevel: The lowest hardware level at which the entry is guaranteed
1034ca25627fc63255d147286ef9a9624059825eb548Igor Murashkin             to be supported by the camera device. All devices with higher
1035ca25627fc63255d147286ef9a9624059825eb548Igor Murashkin             hwlevels will also include this entry. None means that the
1036ca25627fc63255d147286ef9a9624059825eb548Igor Murashkin             entry is optional on any hardware level.
10376c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin    deprecated: Marks an entry as @Deprecated in the Java layer; if within an
10386c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin               unreleased version this needs to be removed altogether. If applied
10396c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin               to an entry from an older release, then this means the entry
10406c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin               should be ignored by newer code.
1041ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray    optional: a bool representing the optional attribute, which denotes the entry
1042ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray              is required for hardware level full devices, but optional for other
1043ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray              hardware levels.  None if not present.
1044ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray    applied_optional: As optional but always valid, defaulting to False if no
1045ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray                      optional attribute is present.
104677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    tuple_values: A sequence of strings describing the tuple values,
104777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin                  None if container is not 'tuple'.
104877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    description: A string description, or None.
104977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    range: A string range, or None.
105077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    units: A string units, or None.
105177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    tags: A sequence of Tag nodes associated with this Entry.
105277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    type_notes: A string describing notes for the type, or None.
1053b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    typedef: A Typedef associated with this Entry, or None.
105477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
105577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  Remarks:
105677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Subclass Clone can be used interchangeable with an Entry,
105777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    for when we don't care about the underlying type.
105877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
105977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    parent and tags edges are invalid until after Metadata#construct_graph
106077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    has been invoked.
106177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
106277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def __init__(self, **kwargs):
106377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
106477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Instantiate a new Entry node.
106577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
106677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Args:
106777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      name: A string with the fully qualified name, e.g. 'android.shading.mode'
106877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      type: A string describing the type, e.g. 'int32'
106977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      kind: A string describing the kind, e.g. 'static'
107077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
107177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Args (if container):
107277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      container: A string describing the container, e.g. 'array' or 'tuple'
107377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      container_sizes: A list of string sizes if a container, or None otherwise
107477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
107577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Args (if container is 'tuple'):
107677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      tuple_values: A list of tuple values, e.g. ['width', 'height']
107777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
1078b556bc47068d816cb319a5d0e2f6841b007b38f2Igor Murashkin    Args (if the 'enum' attribute is true):
1079b556bc47068d816cb319a5d0e2f6841b007b38f2Igor Murashkin      enum: A boolean, True if this is an enum, False otherwise
108077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      enum_values: A list of value strings, e.g. ['ON', 'OFF']
108177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      enum_optionals: A list of optional enum values, e.g. ['OFF']
108277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      enum_notes: A dictionary of value->notes strings.
108377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      enum_ids: A dictionary of value->id strings.
108477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
108577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Args (optional):
108677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      description: A string with a description of the entry.
108777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      range: A string with the range of the values of the entry, e.g. '>= 0'
108877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      units: A string with the units of the values, e.g. 'inches'
1089a5b73c27ddbf032d1b3b4f628ac8fc0846c0ed2cEino-Ville Talvala      details: A string with the detailed documentation for the entry
1090a5b73c27ddbf032d1b3b4f628ac8fc0846c0ed2cEino-Ville Talvala      hal_details: A string with the HAL implementation details for the entry
109177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      tag_ids: A list of tag ID strings, e.g. ['BC', 'V1']
109277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      type_notes: A string with the notes for the type
1093f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala      visibility: A string describing the visibility, eg 'system', 'hidden',
1094f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala                  'public'
10956c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin      synthetic: A bool to mark whether this entry is visible only at the Java
10966c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin                 layer (True), or at both layers (False = default).
1097ca25627fc63255d147286ef9a9624059825eb548Igor Murashkin      hwlevel: A string of the HW level (one of 'legacy', 'limited', 'full')
10986c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin      deprecated: A bool to mark whether this is @Deprecated at the Java layer
10996c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin                 (default = False).
1100ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray      optional: A bool to mark whether optional for non-full hardware devices
1101b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin      typedef: A string corresponding to a typedef's name attribute.
110277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
110377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
110477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    if kwargs.get('type') is None:
110577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      print >> sys.stderr, "ERROR: Missing type for entry '%s' kind  '%s'"     \
110677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      %(kwargs.get('name'), kwargs.get('kind'))
110777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
110877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    # Attributes are Read-Only, but edges may be mutated by
110977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    # Metadata, particularly during construct_graph
111077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
111177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._name = kwargs['name']
111277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._type = kwargs['type']
111377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._kind = kwargs['kind'] # static, dynamic, or controls
111477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
111577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._init_common(**kwargs)
111677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
111777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
111877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def type(self):
111977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._type
112077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
112177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
112277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def kind(self):
112377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._kind
112477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
112577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
1126f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala  def visibility(self):
1127f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala    return self._visibility
1128f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala
1129f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala  @property
1130f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala  def applied_visibility(self):
1131f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala    return self._visibility or 'system'
1132f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala
1133f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala  @property
11346c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin  def synthetic(self):
11356c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin    return self._synthetic
11366c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin
11376c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin  @property
1138ca25627fc63255d147286ef9a9624059825eb548Igor Murashkin  def hwlevel(self):
1139ca25627fc63255d147286ef9a9624059825eb548Igor Murashkin    return self._hwlevel
1140ca25627fc63255d147286ef9a9624059825eb548Igor Murashkin
1141ca25627fc63255d147286ef9a9624059825eb548Igor Murashkin  @property
11426c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin  def deprecated(self):
11436c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin    return self._deprecated
11446c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin
1145ca25627fc63255d147286ef9a9624059825eb548Igor Murashkin  # TODO: optional should just return hwlevel is None
11466c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin  @property
1147ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray  def optional(self):
1148ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray    return self._optional
1149ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray
1150ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray  @property
1151ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray  def applied_optional(self):
1152ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray    return self._optional or False
1153ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray
1154ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray  @property
115577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def name_short(self):
115677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self.get_name_minimal()
115777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
115877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
115977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def container(self):
116077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._container
116177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
116277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
116377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def container_sizes(self):
116477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    if self._container_sizes is None:
116577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      return None
116677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    else:
116777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      return (i for i in self._container_sizes)
116877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
116977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
117077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def tuple_values(self):
117177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    if self._tuple_values is None:
117277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      return None
117377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    else:
117477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      return (i for i in self._tuple_values)
117577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
117677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
117777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def description(self):
117877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._description
117977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
118077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
118177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def range(self):
118277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._range
118377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
118477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
118577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def units(self):
118677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._units
118777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
118877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
1189a5b73c27ddbf032d1b3b4f628ac8fc0846c0ed2cEino-Ville Talvala  def details(self):
1190a5b73c27ddbf032d1b3b4f628ac8fc0846c0ed2cEino-Ville Talvala    return self._details
1191a5b73c27ddbf032d1b3b4f628ac8fc0846c0ed2cEino-Ville Talvala
1192a5b73c27ddbf032d1b3b4f628ac8fc0846c0ed2cEino-Ville Talvala  @property
1193a5b73c27ddbf032d1b3b4f628ac8fc0846c0ed2cEino-Ville Talvala  def hal_details(self):
1194a5b73c27ddbf032d1b3b4f628ac8fc0846c0ed2cEino-Ville Talvala    return self._hal_details
119577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
119677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
119777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def tags(self):
119877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    if self._tags is None:
119977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      return None
120077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    else:
120177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      return (i for i in self._tags)
120277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
120377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
120477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def type_notes(self):
120577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._type_notes
120677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
120777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
1208b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin  def typedef(self):
1209b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    return self._typedef
1210b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin
1211b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin  @property
121277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def enum(self):
121377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._enum
121477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
121577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def _get_children(self):
1216375cfd3889aa72160273af802370c8f47f5c64d1Igor Murashkin    if self.enum:
1217375cfd3889aa72160273af802370c8f47f5c64d1Igor Murashkin      yield self.enum
121877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
121977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def sort_children(self):
122077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return None
122177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
122277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def is_clone(self):
122377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
122477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Whether or not this is a Clone instance.
122577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
122677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Returns:
122777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      False
122877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
122977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return False
123077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
123177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def _init_common(self, **kwargs):
123277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
1233b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    self._parent = None # filled in by Metadata::_construct_entries
123477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
123577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._container = kwargs.get('container')
123677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._container_sizes = kwargs.get('container_sizes')
123777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
123877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    # access these via the 'enum' prop
123977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    enum_values = kwargs.get('enum_values')
124077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    enum_optionals = kwargs.get('enum_optionals')
1241b432916043290beb246054a77f8978b3136f4315Eino-Ville Talvala    enum_hiddens = kwargs.get('enum_hiddens')
1242aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    enum_notes = kwargs.get('enum_notes')  # { value => notes }
1243aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    enum_ids = kwargs.get('enum_ids')  # { value => notes }
124477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._tuple_values = kwargs.get('tuple_values')
124577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
124677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._description = kwargs.get('description')
124777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._range = kwargs.get('range')
124877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._units = kwargs.get('units')
1249a5b73c27ddbf032d1b3b4f628ac8fc0846c0ed2cEino-Ville Talvala    self._details = kwargs.get('details')
1250a5b73c27ddbf032d1b3b4f628ac8fc0846c0ed2cEino-Ville Talvala    self._hal_details = kwargs.get('hal_details')
125177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
125277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._tag_ids = kwargs.get('tag_ids', [])
1253b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    self._tags = None  # Filled in by Metadata::_construct_tags
125477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
125577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._type_notes = kwargs.get('type_notes')
1256b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    self._type_name = kwargs.get('type_name')
1257b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    self._typedef = None # Filled in by Metadata::_construct_types
125877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
1259b556bc47068d816cb319a5d0e2f6841b007b38f2Igor Murashkin    if kwargs.get('enum', False):
1260b432916043290beb246054a77f8978b3136f4315Eino-Ville Talvala      self._enum = Enum(self, enum_values, enum_ids, enum_optionals,
1261b432916043290beb246054a77f8978b3136f4315Eino-Ville Talvala                        enum_hiddens, enum_notes)
1262617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    else:
1263617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin      self._enum = None
126477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
1265f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala    self._visibility = kwargs.get('visibility')
12666c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin    self._synthetic = kwargs.get('synthetic', False)
1267ca25627fc63255d147286ef9a9624059825eb548Igor Murashkin    self._hwlevel = kwargs.get('hwlevel')
12686c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin    self._deprecated = kwargs.get('deprecated', False)
1269ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray    self._optional = kwargs.get('optional')
1270f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala
127177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._property_keys = kwargs
127277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
1273617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin  def merge(self):
1274617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    """
1275617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    Copy the attributes into a new entry, merging it with the target entry
1276617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    if it's a clone.
1277617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    """
1278617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    return MergedEntry(self)
1279617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin
128077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  # Helpers for accessing less than the fully qualified name
128177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
128277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def get_name_as_list(self):
128377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
128477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Returns the name as a list split by a period.
128577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
128677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    For example:
128777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry.name is 'android.lens.info.shading'
128877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry.get_name_as_list() == ['android', 'lens', 'info', 'shading']
128977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
129077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self.name.split(".")
129177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
129277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def get_inner_namespace_list(self):
129377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
129477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Returns the inner namespace part of the name as a list
129577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
129677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    For example:
129777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry.name is 'android.lens.info.shading'
129877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry.get_inner_namespace_list() == ['info']
129977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
130077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self.get_name_as_list()[2:-1]
130177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
130277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def get_outer_namespace(self):
130377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
130477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Returns the outer namespace as a string.
130577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
130677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    For example:
130777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry.name is 'android.lens.info.shading'
130877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry.get_outer_namespace() == 'android'
130977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
131077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Remarks:
131177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      Since outer namespaces are non-recursive,
131277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      and each entry has one, this does not need to be a list.
131377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
131477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self.get_name_as_list()[0]
131577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
131677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def get_section(self):
131777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
131877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Returns the section as a string.
131977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
132077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    For example:
132177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry.name is 'android.lens.info.shading'
132277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry.get_section() == ''
132377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
132477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Remarks:
132577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      Since outer namespaces are non-recursive,
132677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      and each entry has one, this does not need to be a list.
132777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
132877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self.get_name_as_list()[1]
132977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
133077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def get_name_minimal(self):
133177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
133277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Returns only the last component of the fully qualified name as a string.
133377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
133477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    For example:
133577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry.name is 'android.lens.info.shading'
133677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry.get_name_minimal() == 'shading'
133777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
133877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Remarks:
133977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry.name_short it an alias for this
134077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
134177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self.get_name_as_list()[-1]
134277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
13437b9a2dccf20bac314258708e55d8c75b2ecf892aIgor Murashkin  def get_path_without_name(self):
13447b9a2dccf20bac314258708e55d8c75b2ecf892aIgor Murashkin    """
13457b9a2dccf20bac314258708e55d8c75b2ecf892aIgor Murashkin    Returns a string path to the entry, with the name component excluded.
13467b9a2dccf20bac314258708e55d8c75b2ecf892aIgor Murashkin
13477b9a2dccf20bac314258708e55d8c75b2ecf892aIgor Murashkin    For example:
13487b9a2dccf20bac314258708e55d8c75b2ecf892aIgor Murashkin      entry.name is 'android.lens.info.shading'
13497b9a2dccf20bac314258708e55d8c75b2ecf892aIgor Murashkin      entry.get_path_without_name() == 'android.lens.info'
13507b9a2dccf20bac314258708e55d8c75b2ecf892aIgor Murashkin    """
13517b9a2dccf20bac314258708e55d8c75b2ecf892aIgor Murashkin    return ".".join(self.get_name_as_list()[0:-1])
13527b9a2dccf20bac314258708e55d8c75b2ecf892aIgor Murashkin
13537b9a2dccf20bac314258708e55d8c75b2ecf892aIgor Murashkin
135477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkinclass Clone(Entry):
135577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
135677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  A Node corresponding to a <clone> element. It has all the attributes of an
135777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  <entry> element (Entry) plus the additions specified below.
135877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
135977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  Attributes (Read-Only):
136077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    entry: an edge to an Entry object that this targets
136177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    target_kind: A string describing the kind of the target entry.
136277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    name: a string of the name, same as entry.name
136377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    kind: a string of the Kind ancestor, one of 'static', 'controls', 'dynamic'
136477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin          for the <clone> element.
136577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    type: always None, since a clone cannot override the type.
136677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
136777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def __init__(self, entry=None, **kwargs):
136877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
136977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Instantiate a new Clone node.
137077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
137177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Args:
137277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      name: A string with the fully qualified name, e.g. 'android.shading.mode'
137377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      type: A string describing the type, e.g. 'int32'
137477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      kind: A string describing the kind, e.g. 'static'
137577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      target_kind: A string for the kind of the target entry, e.g. 'dynamic'
137677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
137777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Args (if container):
137877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      container: A string describing the container, e.g. 'array' or 'tuple'
137977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      container_sizes: A list of string sizes if a container, or None otherwise
138077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
138177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Args (if container is 'tuple'):
138277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      tuple_values: A list of tuple values, e.g. ['width', 'height']
138377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
1384b556bc47068d816cb319a5d0e2f6841b007b38f2Igor Murashkin    Args (if the 'enum' attribute is true):
1385b556bc47068d816cb319a5d0e2f6841b007b38f2Igor Murashkin      enum: A boolean, True if this is an enum, False otherwise
138677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      enum_values: A list of value strings, e.g. ['ON', 'OFF']
138777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      enum_optionals: A list of optional enum values, e.g. ['OFF']
138877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      enum_notes: A dictionary of value->notes strings.
138977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      enum_ids: A dictionary of value->id strings.
139077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
139177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Args (optional):
139277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry: An edge to the corresponding target Entry.
139377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      description: A string with a description of the entry.
139477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      range: A string with the range of the values of the entry, e.g. '>= 0'
139577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      units: A string with the units of the values, e.g. 'inches'
1396a5b73c27ddbf032d1b3b4f628ac8fc0846c0ed2cEino-Ville Talvala      details: A string with the detailed documentation for the entry
1397a5b73c27ddbf032d1b3b4f628ac8fc0846c0ed2cEino-Ville Talvala      hal_details: A string with the HAL implementation details for the entry
139877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      tag_ids: A list of tag ID strings, e.g. ['BC', 'V1']
139977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      type_notes: A string with the notes for the type
140077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
140177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Remarks:
140277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      Note that type is not specified since it has to be the same as the
140377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry.type.
140477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
1405aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    self._entry = entry  # Entry object
140677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._target_kind = kwargs['target_kind']
1407aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    self._name = kwargs['name']  # same as entry.name
140877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._kind = kwargs['kind']
140977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
141077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    # illegal to override the type, it should be the same as the entry
141177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._type = None
141277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    # the rest of the kwargs are optional
141377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    # can be used to override the regular entry data
141477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._init_common(**kwargs)
141577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
141677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
141777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def entry(self):
141877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._entry
141977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
142077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
142177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def target_kind(self):
142277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._target_kind
142377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
142477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def is_clone(self):
142577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
142677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Whether or not this is a Clone instance.
142777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
142877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Returns:
142977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      True
143077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
143177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return True
143277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
1433617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkinclass MergedEntry(Entry):
1434617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin  """
1435617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin  A MergedEntry has all the attributes of a Clone and its target Entry merged
1436617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin  together.
1437617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin
1438617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin  Remarks:
1439617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    Useful when we want to 'unfold' a clone into a real entry by copying out
1440617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    the target entry data. In this case we don't care about distinguishing
1441617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    a clone vs an entry.
1442617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin  """
1443617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin  def __init__(self, entry):
1444617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    """
1445617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    Create a new instance of MergedEntry.
144677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
1447617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    Args:
1448617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin      entry: An Entry or Clone instance
1449617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    """
1450a5b73c27ddbf032d1b3b4f628ac8fc0846c0ed2cEino-Ville Talvala    props_distinct = ['description', 'units', 'range', 'details',
1451a5b73c27ddbf032d1b3b4f628ac8fc0846c0ed2cEino-Ville Talvala                      'hal_details', 'tags', 'kind']
145277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
1453617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    for p in props_distinct:
1454baacf9a9f032ca392b37b4982eafa43b0a8d4b52Igor Murashkin      p = '_' + p
1455617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin      if entry.is_clone():
1456baacf9a9f032ca392b37b4982eafa43b0a8d4b52Igor Murashkin        setattr(self, p, getattr(entry, p) or getattr(entry.entry, p))
1457617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin      else:
1458baacf9a9f032ca392b37b4982eafa43b0a8d4b52Igor Murashkin        setattr(self, p, getattr(entry, p))
1459617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin
1460baacf9a9f032ca392b37b4982eafa43b0a8d4b52Igor Murashkin    props_common = ['parent', 'name', 'container',
1461617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin                    'container_sizes', 'enum',
1462617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin                    'tuple_values',
1463617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin                    'type',
1464617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin                    'type_notes',
1465b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin                    'visibility',
14666c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin                    'synthetic',
1467ca25627fc63255d147286ef9a9624059825eb548Igor Murashkin                    'hwlevel',
14686c936c18e02b122baaa3d5056b0555b6cff256f8Igor Murashkin                    'deprecated',
1469ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray                    'optional',
1470b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin                    'typedef'
1471617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin                   ]
1472617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin
1473617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    for p in props_common:
1474baacf9a9f032ca392b37b4982eafa43b0a8d4b52Igor Murashkin      p = '_' + p
1475617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin      if entry.is_clone():
1476baacf9a9f032ca392b37b4982eafa43b0a8d4b52Igor Murashkin        setattr(self, p, getattr(entry.entry, p))
1477617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin      else:
1478baacf9a9f032ca392b37b4982eafa43b0a8d4b52Igor Murashkin        setattr(self, p, getattr(entry, p))
1479