Use the operator<< generator more widely.

Change-Id: Iae3b8f32f49f4c91cd41c53bbafb95db071d57bb
diff --git a/tools/generate-operator-out.py b/tools/generate-operator-out.py
index ca7df1e..91d4669 100755
--- a/tools/generate-operator-out.py
+++ b/tools/generate-operator-out.py
@@ -41,6 +41,7 @@
 _ENUM_VALUE_RE = re.compile(r'([A-Za-z0-9_]+)(.*)')
 _ENUM_END_RE = re.compile(r'^\s*\};$')
 _ENUMS = {}
+_NAMESPACES = {}
 
 def Confused(filename, line_number, line):
   sys.stderr.write('%s:%d: confused by:\n%s\n' % (filename, line_number, line))
@@ -51,19 +52,46 @@
   lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\n')
   in_enum = False
   line_number = 0
+
+  namespaces = []
+  enclosing_classes = []
+
   for raw_line in lines:
     line_number += 1
 
-    # TODO: take namespaces and enclosing classes/structs into account.
-
-    # Is this the start of a new enum?
     if not in_enum:
+      # Is this the start of a new enum?
       m = _ENUM_START_RE.search(raw_line)
       if m:
         # Yes, so add an empty entry to _ENUMS for this enum.
         enum_name = m.group(1)
+        if len(enclosing_classes) > 0:
+          enum_name = '::'.join(enclosing_classes) + '::' + enum_name
         _ENUMS[enum_name] = []
+        _NAMESPACES[enum_name] = '::'.join(namespaces)
         in_enum = True
+        continue
+
+      # Is this the start or end of a namespace?
+      m = re.compile(r'^namespace (\S+) \{').search(raw_line)
+      if m:
+        namespaces.append(m.group(1))
+        continue
+      m = re.compile(r'^\}\s+// namespace').search(raw_line)
+      if m:
+        namespaces = namespaces[0:len(namespaces) - 1]
+        continue
+
+      # Is this the start or end of an enclosing class or struct?
+      m = re.compile(r'^(?:class|struct) (\S+) \{').search(raw_line)
+      if m:
+        enclosing_classes.append(m.group(1))
+        continue
+      m = re.compile(r'^\};').search(raw_line)
+      if m:
+        enclosing_classes = enclosing_classes[0:len(enclosing_classes) - 1]
+        continue
+
       continue
 
     # Is this the end of the current enum?
@@ -74,8 +102,13 @@
       in_enum = False
       continue
 
+    # Whitespace?
+    line = raw_line.strip()
+    if len(line) == 0:
+      continue
+
     # Is this another enum value?
-    m = _ENUM_VALUE_RE.search(raw_line.strip())
+    m = _ENUM_VALUE_RE.search(line)
     if not m:
       Confused(filename, line_number, raw_line)
 
@@ -88,7 +121,7 @@
 
     # Lose literal values because we don't care; turn "= 123, // blah" into ", // blah".
     rest = m.group(2).strip()
-    m_literal = re.compile(r'= (0x[0-9a-f]+|-?[0-9]+)').search(rest)
+    m_literal = re.compile(r'= (0x[0-9a-f]+|-?[0-9]+|\'.\')').search(rest)
     if m_literal:
       rest = rest[(len(m_literal.group(0))):]
 
@@ -104,13 +137,15 @@
 
     # Anything left should be a comment.
     if len(rest) and not rest.startswith('// '):
-      print rest
       Confused(filename, line_number, raw_line)
 
     m_comment = re.compile(r'<<(.*?)>>').search(rest)
     if m_comment:
       enum_text = m_comment.group(1)
 
+    if len(enclosing_classes) > 0:
+      enum_value = '::'.join(enclosing_classes) + '::' + enum_value
+
     _ENUMS[enum_name].append((enum_value, enum_text))
 
 def main():
@@ -129,11 +164,14 @@
     print '#include "%s"' % header_file
 
   print
-  print 'namespace art {'
-  print
 
   for enum_name in _ENUMS:
     print '// This was automatically generated by %s --- do not edit!' % sys.argv[0]
+
+    namespaces = _NAMESPACES[enum_name].split('::')
+    for namespace in namespaces:
+      print 'namespace %s {' % namespace
+
     print 'std::ostream& operator<<(std::ostream& os, const %s& rhs) {' % enum_name
     print '  switch (rhs) {'
     for (enum_value, enum_text) in _ENUMS[enum_name]:
@@ -142,9 +180,10 @@
     print '  }'
     print '  return os;'
     print '}'
-    print
 
-  print '} // namespace art'
+    for namespace in reversed(namespaces):
+      print '}  // namespace %s' % namespace
+    print
 
   sys.exit(0)