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
20877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# Private
20977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._entries = []
21077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    # kind => { name => entry }
21177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._entry_map = { 'static': {}, 'dynamic': {}, 'controls': {} }
212586c861e6dab3fdf48fc8440c719ad0b59d49d72Igor Murashkin    self._entries_ordered = [] # list of ordered Entry/Clone instances
21377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._clones = []
21477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
21577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin# Public (Read Only)
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
94777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    notes: A string describing the notes, or None.
948375cfd3889aa72160273af802370c8f47f5c64d1Igor Murashkin    parent: An edge to the parent, always an Enum instance.
94977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
950375cfd3889aa72160273af802370c8f47f5c64d1Igor Murashkin  def __init__(self, name, parent, id=None, optional=False, notes=None):
95177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._name = name                    # str, e.g. 'ON' or 'OFF'
95277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._id = id                        # int, e.g. '0'
95377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._optional = optional            # bool
95477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._notes = notes                  # None or str
955375cfd3889aa72160273af802370c8f47f5c64d1Igor Murashkin    self._parent = parent
95677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
95777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
95877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def id(self):
95977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._id
96077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
96177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
96277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def optional(self):
96377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._optional
96477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
96577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
96677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def notes(self):
96777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._notes
96877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
969375cfd3889aa72160273af802370c8f47f5c64d1Igor Murashkin  def _get_children(self):
970375cfd3889aa72160273af802370c8f47f5c64d1Igor Murashkin    return None
971375cfd3889aa72160273af802370c8f47f5c64d1Igor Murashkin
972375cfd3889aa72160273af802370c8f47f5c64d1Igor Murashkinclass Enum(Node):
97377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
97477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  A class corresponding to an <enum> element within an <entry>.
97577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
97677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  Attributes (Read-Only):
97777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    parent: An edge to the parent, always an Entry instance.
97877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    values: A sequence of EnumValue children.
979aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    has_values_with_id: A boolean representing if any of the children have a
980aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin        non-empty id property.
98177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
98277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def __init__(self, parent, values, ids={}, optionals=[], notes={}):
98377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._values =                                                             \
984375cfd3889aa72160273af802370c8f47f5c64d1Igor Murashkin      [ EnumValue(val, self, ids.get(val), val in optionals, notes.get(val))   \
98577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin        for val in values ]
98677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
98777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._parent = parent
988375cfd3889aa72160273af802370c8f47f5c64d1Igor Murashkin    self._name = None
98977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
99077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
99177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def values(self):
99277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return (i for i in self._values)
99377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
994aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin  @property
995aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin  def has_values_with_id(self):
996aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    return bool(any(i for i in self.values if i.id))
997aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin
998375cfd3889aa72160273af802370c8f47f5c64d1Igor Murashkin  def _get_children(self):
999375cfd3889aa72160273af802370c8f47f5c64d1Igor Murashkin    return (i for i in self._values)
1000375cfd3889aa72160273af802370c8f47f5c64d1Igor Murashkin
100177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkinclass Entry(Node):
100277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
100377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  A node corresponding to an <entry> element.
100477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
100577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  Attributes (Read-Only):
100677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    parent: An edge to the parent node, which is an InnerNamespace or Kind.
100777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    name: The fully qualified name string, e.g. 'android.shading.mode'
100877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    name_short: The name attribute from <entry name="mode">, e.g. mode
100977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    type: The type attribute from <entry type="bar">
101077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    kind: A string ('static', 'dynamic', 'controls') corresponding to the
101177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin          ancestor Kind#name
101277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    container: The container attribute from <entry container="array">, or None.
101377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    container_sizes: A sequence of size strings or None if container is None.
1014b556bc47068d816cb319a5d0e2f6841b007b38f2Igor Murashkin    enum: An Enum instance if the enum attribute is true, None otherwise.
1015f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala    visibility: The visibility of this entry ('system', 'hidden', 'public')
1016f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala                across the system. System entries are only visible in native code
1017f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala                headers. Hidden entries are marked @hide in managed code, while
1018f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala                public entries are visible in the Android SDK.
1019f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala    applied_visibility: As visibility, but always valid, defaulting to 'system'
1020f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala                        if no visibility is given for an entry.
1021ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray    optional: a bool representing the optional attribute, which denotes the entry
1022ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray              is required for hardware level full devices, but optional for other
1023ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray              hardware levels.  None if not present.
1024ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray    applied_optional: As optional but always valid, defaulting to False if no
1025ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray                      optional attribute is present.
102677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    tuple_values: A sequence of strings describing the tuple values,
102777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin                  None if container is not 'tuple'.
102877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    description: A string description, or None.
102977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    range: A string range, or None.
103077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    units: A string units, or None.
103177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    tags: A sequence of Tag nodes associated with this Entry.
103277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    type_notes: A string describing notes for the type, or None.
1033b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    typedef: A Typedef associated with this Entry, or None.
103477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
103577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  Remarks:
103677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Subclass Clone can be used interchangeable with an Entry,
103777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    for when we don't care about the underlying type.
103877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
103977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    parent and tags edges are invalid until after Metadata#construct_graph
104077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    has been invoked.
104177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
104277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def __init__(self, **kwargs):
104377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
104477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Instantiate a new Entry node.
104577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
104677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Args:
104777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      name: A string with the fully qualified name, e.g. 'android.shading.mode'
104877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      type: A string describing the type, e.g. 'int32'
104977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      kind: A string describing the kind, e.g. 'static'
105077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
105177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Args (if container):
105277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      container: A string describing the container, e.g. 'array' or 'tuple'
105377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      container_sizes: A list of string sizes if a container, or None otherwise
105477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
105577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Args (if container is 'tuple'):
105677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      tuple_values: A list of tuple values, e.g. ['width', 'height']
105777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
1058b556bc47068d816cb319a5d0e2f6841b007b38f2Igor Murashkin    Args (if the 'enum' attribute is true):
1059b556bc47068d816cb319a5d0e2f6841b007b38f2Igor Murashkin      enum: A boolean, True if this is an enum, False otherwise
106077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      enum_values: A list of value strings, e.g. ['ON', 'OFF']
106177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      enum_optionals: A list of optional enum values, e.g. ['OFF']
106277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      enum_notes: A dictionary of value->notes strings.
106377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      enum_ids: A dictionary of value->id strings.
106477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
106577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Args (optional):
106677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      description: A string with a description of the entry.
106777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      range: A string with the range of the values of the entry, e.g. '>= 0'
106877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      units: A string with the units of the values, e.g. 'inches'
106977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      notes: A string with the notes for the entry
107077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      tag_ids: A list of tag ID strings, e.g. ['BC', 'V1']
107177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      type_notes: A string with the notes for the type
1072f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala      visibility: A string describing the visibility, eg 'system', 'hidden',
1073f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala                  'public'
1074ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray      optional: A bool to mark whether optional for non-full hardware devices
1075b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin      typedef: A string corresponding to a typedef's name attribute.
107677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
107777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
107877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    if kwargs.get('type') is None:
107977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      print >> sys.stderr, "ERROR: Missing type for entry '%s' kind  '%s'"     \
108077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      %(kwargs.get('name'), kwargs.get('kind'))
108177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
108277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    # Attributes are Read-Only, but edges may be mutated by
108377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    # Metadata, particularly during construct_graph
108477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
108577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._name = kwargs['name']
108677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._type = kwargs['type']
108777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._kind = kwargs['kind'] # static, dynamic, or controls
108877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
108977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._init_common(**kwargs)
109077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
109177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
109277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def type(self):
109377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._type
109477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
109577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
109677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def kind(self):
109777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._kind
109877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
109977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
1100f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala  def visibility(self):
1101f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala    return self._visibility
1102f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala
1103f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala  @property
1104f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala  def applied_visibility(self):
1105f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala    return self._visibility or 'system'
1106f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala
1107f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala  @property
1108ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray  def optional(self):
1109ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray    return self._optional
1110ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray
1111ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray  @property
1112ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray  def applied_optional(self):
1113ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray    return self._optional or False
1114ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray
1115ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray  @property
111677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def name_short(self):
111777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self.get_name_minimal()
111877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
111977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
112077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def container(self):
112177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._container
112277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
112377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
112477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def container_sizes(self):
112577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    if self._container_sizes is None:
112677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      return None
112777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    else:
112877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      return (i for i in self._container_sizes)
112977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
113077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
113177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def tuple_values(self):
113277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    if self._tuple_values is None:
113377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      return None
113477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    else:
113577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      return (i for i in self._tuple_values)
113677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
113777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
113877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def description(self):
113977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._description
114077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
114177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
114277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def range(self):
114377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._range
114477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
114577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
114677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def units(self):
114777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._units
114877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
114977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
115077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def notes(self):
115177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._notes
115277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
115377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
115477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def tags(self):
115577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    if self._tags is None:
115677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      return None
115777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    else:
115877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      return (i for i in self._tags)
115977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
116077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
116177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def type_notes(self):
116277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._type_notes
116377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
116477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
1165b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin  def typedef(self):
1166b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    return self._typedef
1167b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin
1168b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin  @property
116977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def enum(self):
117077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._enum
117177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
117277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def _get_children(self):
1173375cfd3889aa72160273af802370c8f47f5c64d1Igor Murashkin    if self.enum:
1174375cfd3889aa72160273af802370c8f47f5c64d1Igor Murashkin      yield self.enum
117577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
117677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def sort_children(self):
117777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return None
117877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
117977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def is_clone(self):
118077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
118177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Whether or not this is a Clone instance.
118277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
118377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Returns:
118477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      False
118577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
118677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return False
118777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
118877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def _init_common(self, **kwargs):
118977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
1190b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    self._parent = None # filled in by Metadata::_construct_entries
119177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
119277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._container = kwargs.get('container')
119377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._container_sizes = kwargs.get('container_sizes')
119477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
119577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    # access these via the 'enum' prop
119677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    enum_values = kwargs.get('enum_values')
119777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    enum_optionals = kwargs.get('enum_optionals')
1198aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    enum_notes = kwargs.get('enum_notes')  # { value => notes }
1199aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    enum_ids = kwargs.get('enum_ids')  # { value => notes }
120077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._tuple_values = kwargs.get('tuple_values')
120177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
120277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._description = kwargs.get('description')
120377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._range = kwargs.get('range')
120477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._units = kwargs.get('units')
120577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._notes = kwargs.get('notes')
120677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
120777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._tag_ids = kwargs.get('tag_ids', [])
1208b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    self._tags = None  # Filled in by Metadata::_construct_tags
120977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
121077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._type_notes = kwargs.get('type_notes')
1211b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    self._type_name = kwargs.get('type_name')
1212b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin    self._typedef = None # Filled in by Metadata::_construct_types
121377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
1214b556bc47068d816cb319a5d0e2f6841b007b38f2Igor Murashkin    if kwargs.get('enum', False):
121577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      self._enum = Enum(self, enum_values, enum_ids, enum_optionals, enum_notes)
1216617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    else:
1217617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin      self._enum = None
121877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
1219f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala    self._visibility = kwargs.get('visibility')
1220ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray    self._optional = kwargs.get('optional')
1221f384f0a06cf156c51c4ca584a4323e132c15f64fEino-Ville Talvala
122277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._property_keys = kwargs
122377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
1224617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin  def merge(self):
1225617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    """
1226617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    Copy the attributes into a new entry, merging it with the target entry
1227617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    if it's a clone.
1228617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    """
1229617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    return MergedEntry(self)
1230617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin
123177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  # Helpers for accessing less than the fully qualified name
123277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
123377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def get_name_as_list(self):
123477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
123577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Returns the name as a list split by a period.
123677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
123777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    For example:
123877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry.name is 'android.lens.info.shading'
123977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry.get_name_as_list() == ['android', 'lens', 'info', 'shading']
124077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
124177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self.name.split(".")
124277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
124377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def get_inner_namespace_list(self):
124477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
124577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Returns the inner namespace part of the name as a list
124677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
124777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    For example:
124877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry.name is 'android.lens.info.shading'
124977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry.get_inner_namespace_list() == ['info']
125077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
125177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self.get_name_as_list()[2:-1]
125277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
125377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def get_outer_namespace(self):
125477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
125577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Returns the outer namespace as a string.
125677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
125777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    For example:
125877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry.name is 'android.lens.info.shading'
125977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry.get_outer_namespace() == 'android'
126077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
126177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Remarks:
126277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      Since outer namespaces are non-recursive,
126377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      and each entry has one, this does not need to be a list.
126477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
126577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self.get_name_as_list()[0]
126677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
126777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def get_section(self):
126877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
126977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Returns the section as a string.
127077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
127177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    For example:
127277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry.name is 'android.lens.info.shading'
127377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry.get_section() == ''
127477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
127577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Remarks:
127677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      Since outer namespaces are non-recursive,
127777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      and each entry has one, this does not need to be a list.
127877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
127977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self.get_name_as_list()[1]
128077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
128177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def get_name_minimal(self):
128277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
128377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Returns only the last component of the fully qualified name as a string.
128477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
128577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    For example:
128677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry.name is 'android.lens.info.shading'
128777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry.get_name_minimal() == 'shading'
128877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
128977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Remarks:
129077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry.name_short it an alias for this
129177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
129277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self.get_name_as_list()[-1]
129377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
12947b9a2dccf20bac314258708e55d8c75b2ecf892aIgor Murashkin  def get_path_without_name(self):
12957b9a2dccf20bac314258708e55d8c75b2ecf892aIgor Murashkin    """
12967b9a2dccf20bac314258708e55d8c75b2ecf892aIgor Murashkin    Returns a string path to the entry, with the name component excluded.
12977b9a2dccf20bac314258708e55d8c75b2ecf892aIgor Murashkin
12987b9a2dccf20bac314258708e55d8c75b2ecf892aIgor Murashkin    For example:
12997b9a2dccf20bac314258708e55d8c75b2ecf892aIgor Murashkin      entry.name is 'android.lens.info.shading'
13007b9a2dccf20bac314258708e55d8c75b2ecf892aIgor Murashkin      entry.get_path_without_name() == 'android.lens.info'
13017b9a2dccf20bac314258708e55d8c75b2ecf892aIgor Murashkin    """
13027b9a2dccf20bac314258708e55d8c75b2ecf892aIgor Murashkin    return ".".join(self.get_name_as_list()[0:-1])
13037b9a2dccf20bac314258708e55d8c75b2ecf892aIgor Murashkin
13047b9a2dccf20bac314258708e55d8c75b2ecf892aIgor Murashkin
130577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkinclass Clone(Entry):
130677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
130777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  A Node corresponding to a <clone> element. It has all the attributes of an
130877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  <entry> element (Entry) plus the additions specified below.
130977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
131077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  Attributes (Read-Only):
131177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    entry: an edge to an Entry object that this targets
131277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    target_kind: A string describing the kind of the target entry.
131377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    name: a string of the name, same as entry.name
131477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    kind: a string of the Kind ancestor, one of 'static', 'controls', 'dynamic'
131577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin          for the <clone> element.
131677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    type: always None, since a clone cannot override the type.
131777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  """
131877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def __init__(self, entry=None, **kwargs):
131977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
132077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Instantiate a new Clone node.
132177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
132277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Args:
132377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      name: A string with the fully qualified name, e.g. 'android.shading.mode'
132477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      type: A string describing the type, e.g. 'int32'
132577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      kind: A string describing the kind, e.g. 'static'
132677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      target_kind: A string for the kind of the target entry, e.g. 'dynamic'
132777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
132877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Args (if container):
132977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      container: A string describing the container, e.g. 'array' or 'tuple'
133077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      container_sizes: A list of string sizes if a container, or None otherwise
133177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
133277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Args (if container is 'tuple'):
133377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      tuple_values: A list of tuple values, e.g. ['width', 'height']
133477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
1335b556bc47068d816cb319a5d0e2f6841b007b38f2Igor Murashkin    Args (if the 'enum' attribute is true):
1336b556bc47068d816cb319a5d0e2f6841b007b38f2Igor Murashkin      enum: A boolean, True if this is an enum, False otherwise
133777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      enum_values: A list of value strings, e.g. ['ON', 'OFF']
133877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      enum_optionals: A list of optional enum values, e.g. ['OFF']
133977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      enum_notes: A dictionary of value->notes strings.
134077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      enum_ids: A dictionary of value->id strings.
134177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
134277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Args (optional):
134377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry: An edge to the corresponding target Entry.
134477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      description: A string with a description of the entry.
134577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      range: A string with the range of the values of the entry, e.g. '>= 0'
134677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      units: A string with the units of the values, e.g. 'inches'
134777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      notes: A string with the notes for the entry
134877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      tag_ids: A list of tag ID strings, e.g. ['BC', 'V1']
134977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      type_notes: A string with the notes for the type
135077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
135177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Remarks:
135277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      Note that type is not specified since it has to be the same as the
135377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      entry.type.
135477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
1355aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    self._entry = entry  # Entry object
135677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._target_kind = kwargs['target_kind']
1357aa133d352a42aebf93320eded40c75b4d7cff6e7Igor Murashkin    self._name = kwargs['name']  # same as entry.name
135877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._kind = kwargs['kind']
135977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
136077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    # illegal to override the type, it should be the same as the entry
136177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._type = None
136277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    # the rest of the kwargs are optional
136377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    # can be used to override the regular entry data
136477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    self._init_common(**kwargs)
136577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
136677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
136777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def entry(self):
136877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._entry
136977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
137077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  @property
137177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def target_kind(self):
137277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return self._target_kind
137377b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
137477b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin  def is_clone(self):
137577b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
137677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Whether or not this is a Clone instance.
137777b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
137877b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    Returns:
137977b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin      True
138077b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    """
138177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin    return True
138277b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
1383617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkinclass MergedEntry(Entry):
1384617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin  """
1385617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin  A MergedEntry has all the attributes of a Clone and its target Entry merged
1386617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin  together.
1387617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin
1388617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin  Remarks:
1389617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    Useful when we want to 'unfold' a clone into a real entry by copying out
1390617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    the target entry data. In this case we don't care about distinguishing
1391617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    a clone vs an entry.
1392617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin  """
1393617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin  def __init__(self, entry):
1394617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    """
1395617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    Create a new instance of MergedEntry.
139677b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
1397617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    Args:
1398617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin      entry: An Entry or Clone instance
1399617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    """
1400617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    props_distinct = ['description', 'units', 'range', 'notes', 'tags', 'kind']
140177b63ca0447545a4dac3ac062f218d878ce01ba0Igor Murashkin
1402617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    for p in props_distinct:
1403baacf9a9f032ca392b37b4982eafa43b0a8d4b52Igor Murashkin      p = '_' + p
1404617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin      if entry.is_clone():
1405baacf9a9f032ca392b37b4982eafa43b0a8d4b52Igor Murashkin        setattr(self, p, getattr(entry, p) or getattr(entry.entry, p))
1406617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin      else:
1407baacf9a9f032ca392b37b4982eafa43b0a8d4b52Igor Murashkin        setattr(self, p, getattr(entry, p))
1408617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin
1409baacf9a9f032ca392b37b4982eafa43b0a8d4b52Igor Murashkin    props_common = ['parent', 'name', 'container',
1410617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin                    'container_sizes', 'enum',
1411617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin                    'tuple_values',
1412617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin                    'type',
1413617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin                    'type_notes',
1414b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin                    'visibility',
1415ef40ad6249555a0a45c57907f4b9509b59e3e9f5Alex Ray                    'optional',
1416b8dc88148bca2e5a267c2ff39aff94b98b00ad6dIgor Murashkin                    'typedef'
1417617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin                   ]
1418617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin
1419617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin    for p in props_common:
1420baacf9a9f032ca392b37b4982eafa43b0a8d4b52Igor Murashkin      p = '_' + p
1421617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin      if entry.is_clone():
1422baacf9a9f032ca392b37b4982eafa43b0a8d4b52Igor Murashkin        setattr(self, p, getattr(entry.entry, p))
1423617da1675f9ea7b6ea33d9e6f47e0a07379f14b1Igor Murashkin      else:
1424baacf9a9f032ca392b37b4982eafa43b0a8d4b52Igor Murashkin        setattr(self, p, getattr(entry, p))
1425