Revert "libmojo: Uprev the library to r456626 from Chromium"

This reverts commit 8ac9103e05b66812c25348943383f9365d1ce3e0.

Reason for revert: Broke the mac_sdk
Exempt-From-Owner-Approval: Fixing mac_sdk

Change-Id: I0b74d1abaa66933a93fd6f82ff018e8948c1204e
diff --git a/build/android/gyp/util/build_utils.py b/build/android/gyp/util/build_utils.py
index 7b2f48d..371ad90 100644
--- a/build/android/gyp/util/build_utils.py
+++ b/build/android/gyp/util/build_utils.py
@@ -23,16 +23,12 @@
 sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
 from pylib.constants import host_paths
 
-sys.path.append(os.path.join(os.path.dirname(__file__),
-                             os.pardir, os.pardir, os.pardir))
-import gn_helpers
-
 COLORAMA_ROOT = os.path.join(host_paths.DIR_SOURCE_ROOT,
                              'third_party', 'colorama', 'src')
 # aapt should ignore OWNERS files in addition the default ignore pattern.
 AAPT_IGNORE_PATTERN = ('!OWNERS:!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:' +
                        '!CVS:!thumbs.db:!picasa.ini:!*~:!*.d.stamp')
-HERMETIC_TIMESTAMP = (2001, 1, 1, 0, 0, 0)
+_HERMETIC_TIMESTAMP = (2001, 1, 1, 0, 0, 0)
 _HERMETIC_FILE_ATTR = (0644 << 16L)
 
 
@@ -82,23 +78,31 @@
 
 
 def ParseGnList(gn_string):
-  """Converts a command-line parameter into a list.
+  # TODO(brettw) bug 573132: This doesn't handle GN escaping properly, so any
+  # weird characters like $ or \ in the strings will be corrupted.
+  #
+  # The code should import build/gn_helpers.py and then do:
+  #   parser = gn_helpers.GNValueParser(gn_string)
+  #   return return parser.ParseList()
+  # As of this writing, though, there is a CastShell build script that sends
+  # JSON through this function, and using correct GN parsing corrupts that.
+  #
+  # We need to be consistent about passing either JSON or GN lists through
+  # this function.
+  return ast.literal_eval(gn_string)
 
-  If the input starts with a '[' it is assumed to be a GN-formatted list and
-  it will be parsed accordingly. When empty an empty list will be returned.
-  Otherwise, the parameter will be treated as a single raw string (not
-  GN-formatted in that it's not assumed to have literal quotes that must be
-  removed) and a list will be returned containing that string.
 
-  The common use for this behavior is in the Android build where things can
-  take lists of @FileArg references that are expanded via ExpandFileArgs.
-  """
-  if gn_string.startswith('['):
-    parser = gn_helpers.GNValueParser(gn_string)
-    return parser.ParseList()
-  if len(gn_string):
-    return [ gn_string ]
-  return []
+def ParseGypList(gyp_string):
+  # The ninja generator doesn't support $ in strings, so use ## to
+  # represent $.
+  # TODO(cjhopman): Remove when
+  # https://code.google.com/p/gyp/issues/detail?id=327
+  # is addressed.
+  gyp_string = gyp_string.replace('##', '$')
+
+  if gyp_string.startswith('['):
+    return ParseGnList(gyp_string)
+  return shlex.split(gyp_string)
 
 
 def CheckOptions(options, parser, required=None):
@@ -224,7 +228,6 @@
   if not zipfile.is_zipfile(zip_path):
     raise Exception('Invalid zip file: %s' % zip_path)
 
-  extracted = []
   with zipfile.ZipFile(zip_path) as z:
     for name in z.namelist():
       if name.endswith('/'):
@@ -245,12 +248,8 @@
         dest = os.path.join(path, name)
         MakeDirectory(os.path.dirname(dest))
         os.symlink(z.read(name), dest)
-        extracted.append(dest)
       else:
         z.extract(name, path)
-        extracted.append(os.path.join(path, name))
-
-  return extracted
 
 
 def AddToZipHermetic(zip_file, zip_path, src_path=None, data=None,
@@ -268,7 +267,7 @@
   assert (src_path is None) != (data is None), (
       '|src_path| and |data| are mutually exclusive.')
   CheckZipPath(zip_path)
-  zipinfo = zipfile.ZipInfo(filename=zip_path, date_time=HERMETIC_TIMESTAMP)
+  zipinfo = zipfile.ZipInfo(filename=zip_path, date_time=_HERMETIC_TIMESTAMP)
   zipinfo.external_attr = _HERMETIC_FILE_ATTR
 
   if src_path and os.path.islink(src_path):
@@ -333,14 +332,7 @@
   path_transform = path_transform or (lambda p, z: p)
   added_names = set()
 
-  output_is_already_open = not isinstance(output, basestring)
-  if output_is_already_open:
-    assert isinstance(output, zipfile.ZipFile)
-    out_zip = output
-  else:
-    out_zip = zipfile.ZipFile(output, 'w')
-
-  try:
+  with zipfile.ZipFile(output, 'w') as out_zip:
     for in_file in inputs:
       with zipfile.ZipFile(in_file, 'r') as in_zip:
         in_zip._expected_crc = None
@@ -351,12 +343,8 @@
           dst_name = path_transform(info.filename, in_file)
           already_added = dst_name in added_names
           if not already_added and not MatchesGlob(dst_name, exclude_patterns):
-            AddToZipHermetic(out_zip, dst_name, data=in_zip.read(info),
-                             compress=info.compress_type != zipfile.ZIP_STORED)
+            AddToZipHermetic(out_zip, dst_name, data=in_zip.read(info))
             added_names.add(dst_name)
-  finally:
-    if not output_is_already_open:
-      out_zip.close()
 
 
 def PrintWarning(message):
@@ -411,7 +399,8 @@
   A path is assumed to be a "system" import if it is outside of chromium's
   src/. The paths will be relative to the current directory.
   """
-  module_paths = GetModulePaths()
+  module_paths = (m.__file__ for m in sys.modules.itervalues()
+                  if m is not None and hasattr(m, '__file__'))
 
   abs_module_paths = map(os.path.abspath, module_paths)
 
@@ -428,30 +417,6 @@
   return sorted(set(non_system_module_paths))
 
 
-def GetModulePaths():
-  """Returns the paths to all of the modules in sys.modules."""
-  ForceLazyModulesToLoad()
-  return (m.__file__ for m in sys.modules.itervalues()
-          if m is not None and hasattr(m, '__file__'))
-
-
-def ForceLazyModulesToLoad():
-  """Forces any lazily imported modules to fully load themselves.
-
-  Inspecting the modules' __file__ attribute causes lazily imported modules
-  (e.g. from email) to get fully imported and update sys.modules. Iterate
-  over the values until sys.modules stabilizes so that no modules are missed.
-  """
-  while True:
-    num_modules_before = len(sys.modules.keys())
-    for m in sys.modules.values():
-      if m is not None and hasattr(m, '__file__'):
-        _ = m.__file__
-    num_modules_after = len(sys.modules.keys())
-    if num_modules_before == num_modules_after:
-      break
-
-
 def AddDepfileOption(parser):
   # TODO(agrieve): Get rid of this once we've moved to argparse.
   if hasattr(parser, 'add_option'):
@@ -459,20 +424,14 @@
   else:
     func = parser.add_argument
   func('--depfile',
-       help='Path to depfile (refer to `gn help depfile`)')
+       help='Path to depfile. Must be specified as the action\'s first output.')
 
 
-def WriteDepfile(depfile_path, first_gn_output, inputs=None, add_pydeps=True):
-  assert depfile_path != first_gn_output  # http://crbug.com/646165
-  inputs = inputs or []
-  if add_pydeps:
-    inputs = GetPythonDependencies() + inputs
-  MakeDirectory(os.path.dirname(depfile_path))
-  # Ninja does not support multiple outputs in depfiles.
-  with open(depfile_path, 'w') as depfile:
-    depfile.write(first_gn_output.replace(' ', '\\ '))
+def WriteDepfile(path, dependencies):
+  with open(path, 'w') as depfile:
+    depfile.write(path)
     depfile.write(': ')
-    depfile.write(' '.join(i.replace(' ', '\\ ') for i in inputs))
+    depfile.write(' '.join(dependencies))
     depfile.write('\n')
 
 
@@ -510,25 +469,11 @@
     for k in lookup_path[1:]:
       expansion = expansion[k]
 
-    # This should match ParseGNList. The output is either a GN-formatted list
-    # or a literal (with no quotes).
-    if isinstance(expansion, list):
-      new_args[i] = arg[:match.start()] + gn_helpers.ToGNString(expansion)
-    else:
-      new_args[i] = arg[:match.start()] + str(expansion)
+    new_args[i] = arg[:match.start()] + str(expansion)
 
   return new_args
 
 
-def ReadSourcesList(sources_list_file_name):
-  """Reads a GN-written file containing list of file names and returns a list.
-
-  Note that this function should not be used to parse response files.
-  """
-  with open(sources_list_file_name) as f:
-    return [file_name.strip() for file_name in f]
-
-
 def CallAndWriteDepfileIfStale(function, options, record_path=None,
                                input_paths=None, input_strings=None,
                                output_paths=None, force=False,
@@ -568,8 +513,7 @@
       all_depfile_deps = list(python_deps)
       if depfile_deps:
         all_depfile_deps.extend(depfile_deps)
-      WriteDepfile(options.depfile, output_paths[0], all_depfile_deps,
-                   add_pydeps=False)
+      WriteDepfile(options.depfile, all_depfile_deps)
     if stamp_file:
       Touch(stamp_file)
 
diff --git a/build/android/pylib/__init__.py b/build/android/pylib/__init__.py
index b93eb4f..16ee312 100644
--- a/build/android/pylib/__init__.py
+++ b/build/android/pylib/__init__.py
@@ -5,27 +5,9 @@
 import os
 import sys
 
-
-_CATAPULT_PATH = os.path.abspath(os.path.join(
-    os.path.dirname(__file__), '..', '..', '..', 'third_party', 'catapult'))
-
-_DEVIL_PATH = os.path.join(_CATAPULT_PATH, 'devil')
-
-_PYTRACE_PATH = os.path.join(_CATAPULT_PATH, 'common', 'py_trace_event')
-
-_PY_UTILS_PATH = os.path.join(_CATAPULT_PATH, 'common', 'py_utils')
-
-_TRACE2HTML_PATH = os.path.join(_CATAPULT_PATH, 'tracing')
-
+_DEVIL_PATH = os.path.abspath(os.path.join(
+    os.path.dirname(__file__), '..', '..', '..', 'third_party', 'catapult',
+    'devil'))
 
 if _DEVIL_PATH not in sys.path:
   sys.path.append(_DEVIL_PATH)
-
-if _PYTRACE_PATH not in sys.path:
-  sys.path.append(_PYTRACE_PATH)
-
-if _PY_UTILS_PATH not in sys.path:
-  sys.path.append(_PY_UTILS_PATH)
-
-if _TRACE2HTML_PATH not in sys.path:
-  sys.path.append(_TRACE2HTML_PATH)
diff --git a/build/android/pylib/constants/__init__.py b/build/android/pylib/constants/__init__.py
index 916ee27..9b25dcd 100644
--- a/build/android/pylib/constants/__init__.py
+++ b/build/android/pylib/constants/__init__.py
@@ -37,28 +37,28 @@
     'chromecast_shell': chrome.PackageInfo(
         'com.google.android.apps.mediashell',
         'com.google.android.apps.mediashell.MediaShellActivity',
-        'castshell-command-line',
+        '/data/local/tmp/castshell-command-line',
         None),
     'android_webview_shell': chrome.PackageInfo(
         'org.chromium.android_webview.shell',
         'org.chromium.android_webview.shell.AwShellActivity',
-        'android-webview-command-line',
+        '/data/local/tmp/android-webview-command-line',
         None),
     'gtest': chrome.PackageInfo(
         'org.chromium.native_test',
         'org.chromium.native_test.NativeUnitTestActivity',
-        'chrome-native-tests-command-line',
+        '/data/local/tmp/chrome-native-tests-command-line',
         None),
     'components_browsertests': chrome.PackageInfo(
         'org.chromium.components_browsertests_apk',
         ('org.chromium.components_browsertests_apk' +
          '.ComponentsBrowserTestsActivity'),
-        'chrome-native-tests-command-line',
+        '/data/local/tmp/chrome-native-tests-command-line',
         None),
     'content_browsertests': chrome.PackageInfo(
         'org.chromium.content_browsertests_apk',
         'org.chromium.content_browsertests_apk.ContentBrowserTestsActivity',
-        'chrome-native-tests-command-line',
+        '/data/local/tmp/chrome-native-tests-command-line',
         None),
     'chromedriver_webview_shell': chrome.PackageInfo(
         'org.chromium.chromedriver_webview_shell',
@@ -96,7 +96,7 @@
 SCREENSHOTS_DIR = os.path.join(DIR_SOURCE_ROOT, 'out_screenshots')
 
 ANDROID_SDK_VERSION = version_codes.MARSHMALLOW
-ANDROID_SDK_BUILD_TOOLS_VERSION = '24.0.2'
+ANDROID_SDK_BUILD_TOOLS_VERSION = '23.0.1'
 ANDROID_SDK_ROOT = os.path.join(DIR_SOURCE_ROOT,
                                 'third_party', 'android_tools', 'sdk')
 ANDROID_SDK_TOOLS = os.path.join(ANDROID_SDK_ROOT,
@@ -140,9 +140,9 @@
 }
 
 LOCAL_MACHINE_TESTS = ['junit', 'python']
-VALID_ENVIRONMENTS = ['local']
+VALID_ENVIRONMENTS = ['local', 'remote_device']
 VALID_TEST_TYPES = ['gtest', 'instrumentation', 'junit', 'linker', 'monkey',
-                    'perf', 'python']
+                    'perf', 'python', 'uirobot']
 VALID_DEVICE_TYPES = ['Android', 'iOS']
 
 
diff --git a/build/build_config.h b/build/build_config.h
index fd5489f..c3d82d0 100644
--- a/build/build_config.h
+++ b/build/build_config.h
@@ -6,7 +6,6 @@
 //  Operating System:
 //    OS_WIN / OS_MACOSX / OS_LINUX / OS_POSIX (MACOSX or LINUX) /
 //    OS_NACL (NACL_SFI or NACL_NONSFI) / OS_NACL_SFI / OS_NACL_NONSFI
-//    OS_CHROMEOS is set by the build system
 //  Compiler:
 //    COMPILER_MSVC / COMPILER_GCC
 //  Processor:
@@ -49,10 +48,9 @@
 #endif
 #elif defined(_WIN32)
 #define OS_WIN 1
+#define TOOLKIT_VIEWS 1
 #elif defined(__FreeBSD__)
 #define OS_FREEBSD 1
-#elif defined(__NetBSD__)
-#define OS_NETBSD 1
 #elif defined(__OpenBSD__)
 #define OS_OPENBSD 1
 #elif defined(__sun)
@@ -69,16 +67,15 @@
 
 // For access to standard BSD features, use OS_BSD instead of a
 // more specific macro.
-#if defined(OS_FREEBSD) || defined(OS_NETBSD) || defined(OS_OPENBSD)
+#if defined(OS_FREEBSD) || defined(OS_OPENBSD)
 #define OS_BSD 1
 #endif
 
 // For access to standard POSIXish features, use OS_POSIX instead of a
 // more specific macro.
 #if defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_FREEBSD) ||     \
-    defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_SOLARIS) ||   \
-    defined(OS_ANDROID) || defined(OS_OPENBSD) || defined(OS_SOLARIS) ||  \
-    defined(OS_ANDROID) || defined(OS_NACL) || defined(OS_QNX)
+    defined(OS_OPENBSD) || defined(OS_SOLARIS) || defined(OS_ANDROID) ||  \
+    defined(OS_NACL) || defined(OS_QNX)
 #define OS_POSIX 1
 #endif
 
@@ -111,31 +108,6 @@
 #define ARCH_CPU_X86 1
 #define ARCH_CPU_32_BITS 1
 #define ARCH_CPU_LITTLE_ENDIAN 1
-#elif defined(__s390x__)
-#define ARCH_CPU_S390_FAMILY 1
-#define ARCH_CPU_S390X 1
-#define ARCH_CPU_64_BITS 1
-#define ARCH_CPU_BIG_ENDIAN 1
-#elif defined(__s390__)
-#define ARCH_CPU_S390_FAMILY 1
-#define ARCH_CPU_S390 1
-#define ARCH_CPU_31_BITS 1
-#define ARCH_CPU_BIG_ENDIAN 1
-#elif defined(__PPC64__) && defined(__BIG_ENDIAN__)
-#define ARCH_CPU_PPC64_FAMILY 1
-#define ARCH_CPU_PPC64 1
-#define ARCH_CPU_64_BITS 1
-#define ARCH_CPU_BIG_ENDIAN 1
-#elif defined(__PPC64__) && defined(__LITTLE_ENDIAN__)
-#define ARCH_CPU_PPC64_FAMILY 1
-#define ARCH_CPU_PPC64 1
-#define ARCH_CPU_64_BITS 1
-#define ARCH_CPU_LITTLE_ENDIAN 1
-#elif defined(__PPC__)
-#define ARCH_CPU_PPC_FAMILY 1
-#define ARCH_CPU_PPC 1
-#define ARCH_CPU_32_BITS 1
-#define ARCH_CPU_BIG_ENDIAN 1
 #elif defined(__ARMEL__)
 #define ARCH_CPU_ARM_FAMILY 1
 #define ARCH_CPU_ARMEL 1
diff --git a/build/gn_helpers.py b/build/gn_helpers.py
deleted file mode 100644
index 33cc578..0000000
--- a/build/gn_helpers.py
+++ /dev/null
@@ -1,351 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Helper functions useful when writing scripts that integrate with GN.
-
-The main functions are ToGNString and FromGNString which convert between
-serialized GN veriables and Python variables.
-
-To use in a random python file in the build:
-
-  import os
-  import sys
-
-  sys.path.append(os.path.join(os.path.dirname(__file__),
-                               os.pardir, os.pardir, "build"))
-  import gn_helpers
-
-Where the sequence of parameters to join is the relative path from your source
-file to the build directory."""
-
-class GNException(Exception):
-  pass
-
-
-def ToGNString(value, allow_dicts = True):
-  """Returns a stringified GN equivalent of the Python value.
-
-  allow_dicts indicates if this function will allow converting dictionaries
-  to GN scopes. This is only possible at the top level, you can't nest a
-  GN scope in a list, so this should be set to False for recursive calls."""
-  if isinstance(value, basestring):
-    if value.find('\n') >= 0:
-      raise GNException("Trying to print a string with a newline in it.")
-    return '"' + \
-        value.replace('\\', '\\\\').replace('"', '\\"').replace('$', '\\$') + \
-        '"'
-
-  if isinstance(value, unicode):
-    return ToGNString(value.encode('utf-8'))
-
-  if isinstance(value, bool):
-    if value:
-      return "true"
-    return "false"
-
-  if isinstance(value, list):
-    return '[ %s ]' % ', '.join(ToGNString(v) for v in value)
-
-  if isinstance(value, dict):
-    if not allow_dicts:
-      raise GNException("Attempting to recursively print a dictionary.")
-    result = ""
-    for key in sorted(value):
-      if not isinstance(key, basestring):
-        raise GNException("Dictionary key is not a string.")
-      result += "%s = %s\n" % (key, ToGNString(value[key], False))
-    return result
-
-  if isinstance(value, int):
-    return str(value)
-
-  raise GNException("Unsupported type when printing to GN.")
-
-
-def FromGNString(input_string):
-  """Converts the input string from a GN serialized value to Python values.
-
-  For details on supported types see GNValueParser.Parse() below.
-
-  If your GN script did:
-    something = [ "file1", "file2" ]
-    args = [ "--values=$something" ]
-  The command line would look something like:
-    --values="[ \"file1\", \"file2\" ]"
-  Which when interpreted as a command line gives the value:
-    [ "file1", "file2" ]
-
-  You can parse this into a Python list using GN rules with:
-    input_values = FromGNValues(options.values)
-  Although the Python 'ast' module will parse many forms of such input, it
-  will not handle GN escaping properly, nor GN booleans. You should use this
-  function instead.
-
-
-  A NOTE ON STRING HANDLING:
-
-  If you just pass a string on the command line to your Python script, or use
-  string interpolation on a string variable, the strings will not be quoted:
-    str = "asdf"
-    args = [ str, "--value=$str" ]
-  Will yield the command line:
-    asdf --value=asdf
-  The unquoted asdf string will not be valid input to this function, which
-  accepts only quoted strings like GN scripts. In such cases, you can just use
-  the Python string literal directly.
-
-  The main use cases for this is for other types, in particular lists. When
-  using string interpolation on a list (as in the top example) the embedded
-  strings will be quoted and escaped according to GN rules so the list can be
-  re-parsed to get the same result."""
-  parser = GNValueParser(input_string)
-  return parser.Parse()
-
-
-def FromGNArgs(input_string):
-  """Converts a string with a bunch of gn arg assignments into a Python dict.
-
-  Given a whitespace-separated list of
-
-    <ident> = (integer | string | boolean | <list of the former>)
-
-  gn assignments, this returns a Python dict, i.e.:
-
-    FromGNArgs("foo=true\nbar=1\n") -> { 'foo': True, 'bar': 1 }.
-
-  Only simple types and lists supported; variables, structs, calls
-  and other, more complicated things are not.
-
-  This routine is meant to handle only the simple sorts of values that
-  arise in parsing --args.
-  """
-  parser = GNValueParser(input_string)
-  return parser.ParseArgs()
-
-
-def UnescapeGNString(value):
-  """Given a string with GN escaping, returns the unescaped string.
-
-  Be careful not to feed with input from a Python parsing function like
-  'ast' because it will do Python unescaping, which will be incorrect when
-  fed into the GN unescaper."""
-  result = ''
-  i = 0
-  while i < len(value):
-    if value[i] == '\\':
-      if i < len(value) - 1:
-        next_char = value[i + 1]
-        if next_char in ('$', '"', '\\'):
-          # These are the escaped characters GN supports.
-          result += next_char
-          i += 1
-        else:
-          # Any other backslash is a literal.
-          result += '\\'
-    else:
-      result += value[i]
-    i += 1
-  return result
-
-
-def _IsDigitOrMinus(char):
-  return char in "-0123456789"
-
-
-class GNValueParser(object):
-  """Duplicates GN parsing of values and converts to Python types.
-
-  Normally you would use the wrapper function FromGNValue() below.
-
-  If you expect input as a specific type, you can also call one of the Parse*
-  functions directly. All functions throw GNException on invalid input. """
-  def __init__(self, string):
-    self.input = string
-    self.cur = 0
-
-  def IsDone(self):
-    return self.cur == len(self.input)
-
-  def ConsumeWhitespace(self):
-    while not self.IsDone() and self.input[self.cur] in ' \t\n':
-      self.cur += 1
-
-  def Parse(self):
-    """Converts a string representing a printed GN value to the Python type.
-
-    See additional usage notes on FromGNString above.
-
-    - GN booleans ('true', 'false') will be converted to Python booleans.
-
-    - GN numbers ('123') will be converted to Python numbers.
-
-    - GN strings (double-quoted as in '"asdf"') will be converted to Python
-      strings with GN escaping rules. GN string interpolation (embedded
-      variables preceeded by $) are not supported and will be returned as
-      literals.
-
-    - GN lists ('[1, "asdf", 3]') will be converted to Python lists.
-
-    - GN scopes ('{ ... }') are not supported."""
-    result = self._ParseAllowTrailing()
-    self.ConsumeWhitespace()
-    if not self.IsDone():
-      raise GNException("Trailing input after parsing:\n  " +
-                        self.input[self.cur:])
-    return result
-
-  def ParseArgs(self):
-    """Converts a whitespace-separated list of ident=literals to a dict.
-
-    See additional usage notes on FromGNArgs, above.
-    """
-    d = {}
-
-    self.ConsumeWhitespace()
-    while not self.IsDone():
-      ident = self._ParseIdent()
-      self.ConsumeWhitespace()
-      if self.input[self.cur] != '=':
-        raise GNException("Unexpected token: " + self.input[self.cur:])
-      self.cur += 1
-      self.ConsumeWhitespace()
-      val = self._ParseAllowTrailing()
-      self.ConsumeWhitespace()
-      d[ident] = val
-
-    return d
-
-  def _ParseAllowTrailing(self):
-    """Internal version of Parse that doesn't check for trailing stuff."""
-    self.ConsumeWhitespace()
-    if self.IsDone():
-      raise GNException("Expected input to parse.")
-
-    next_char = self.input[self.cur]
-    if next_char == '[':
-      return self.ParseList()
-    elif _IsDigitOrMinus(next_char):
-      return self.ParseNumber()
-    elif next_char == '"':
-      return self.ParseString()
-    elif self._ConstantFollows('true'):
-      return True
-    elif self._ConstantFollows('false'):
-      return False
-    else:
-      raise GNException("Unexpected token: " + self.input[self.cur:])
-
-  def _ParseIdent(self):
-    ident = ''
-
-    next_char = self.input[self.cur]
-    if not next_char.isalpha() and not next_char=='_':
-      raise GNException("Expected an identifier: " + self.input[self.cur:])
-
-    ident += next_char
-    self.cur += 1
-
-    next_char = self.input[self.cur]
-    while next_char.isalpha() or next_char.isdigit() or next_char=='_':
-      ident += next_char
-      self.cur += 1
-      next_char = self.input[self.cur]
-
-    return ident
-
-  def ParseNumber(self):
-    self.ConsumeWhitespace()
-    if self.IsDone():
-      raise GNException('Expected number but got nothing.')
-
-    begin = self.cur
-
-    # The first character can include a negative sign.
-    if not self.IsDone() and _IsDigitOrMinus(self.input[self.cur]):
-      self.cur += 1
-    while not self.IsDone() and self.input[self.cur].isdigit():
-      self.cur += 1
-
-    number_string = self.input[begin:self.cur]
-    if not len(number_string) or number_string == '-':
-      raise GNException("Not a valid number.")
-    return int(number_string)
-
-  def ParseString(self):
-    self.ConsumeWhitespace()
-    if self.IsDone():
-      raise GNException('Expected string but got nothing.')
-
-    if self.input[self.cur] != '"':
-      raise GNException('Expected string beginning in a " but got:\n  ' +
-                        self.input[self.cur:])
-    self.cur += 1  # Skip over quote.
-
-    begin = self.cur
-    while not self.IsDone() and self.input[self.cur] != '"':
-      if self.input[self.cur] == '\\':
-        self.cur += 1  # Skip over the backslash.
-        if self.IsDone():
-          raise GNException("String ends in a backslash in:\n  " +
-                            self.input)
-      self.cur += 1
-
-    if self.IsDone():
-      raise GNException('Unterminated string:\n  ' + self.input[begin:])
-
-    end = self.cur
-    self.cur += 1  # Consume trailing ".
-
-    return UnescapeGNString(self.input[begin:end])
-
-  def ParseList(self):
-    self.ConsumeWhitespace()
-    if self.IsDone():
-      raise GNException('Expected list but got nothing.')
-
-    # Skip over opening '['.
-    if self.input[self.cur] != '[':
-      raise GNException("Expected [ for list but got:\n  " +
-                        self.input[self.cur:])
-    self.cur += 1
-    self.ConsumeWhitespace()
-    if self.IsDone():
-      raise GNException("Unterminated list:\n  " + self.input)
-
-    list_result = []
-    previous_had_trailing_comma = True
-    while not self.IsDone():
-      if self.input[self.cur] == ']':
-        self.cur += 1  # Skip over ']'.
-        return list_result
-
-      if not previous_had_trailing_comma:
-        raise GNException("List items not separated by comma.")
-
-      list_result += [ self._ParseAllowTrailing() ]
-      self.ConsumeWhitespace()
-      if self.IsDone():
-        break
-
-      # Consume comma if there is one.
-      previous_had_trailing_comma = self.input[self.cur] == ','
-      if previous_had_trailing_comma:
-        # Consume comma.
-        self.cur += 1
-        self.ConsumeWhitespace()
-
-    raise GNException("Unterminated list:\n  " + self.input)
-
-  def _ConstantFollows(self, constant):
-    """Returns true if the given constant follows immediately at the current
-    location in the input. If it does, the text is consumed and the function
-    returns true. Otherwise, returns false and the current position is
-    unchanged."""
-    end = self.cur + len(constant)
-    if end > len(self.input):
-      return False  # Not enough room.
-    if self.input[self.cur:end] == constant:
-      self.cur = end
-      return True
-    return False