[
  {
    "path": ".gitignore",
    "content": ".DS_Store\n*.pyc\n/node_modules/\n/out/\n/npm/skew.js\n/npm/skewc\n/npm/skew.cpp\n/npm/skew.h\n/npm/skew.d.ts\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: node_js\nnode_js:\n  - stable\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2015 Evan Wallace\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Skew Programming Language\n\nVisit https://evanw.github.io/skew-lang.org/ for more information and a live demo of the compiler.\n"
  },
  {
    "path": "build.py",
    "content": "#!/usr/bin/env python\n\nimport os\nimport sys\nimport glob\nimport gzip\nimport json\nimport time\nimport pipes\nimport base64\nimport shutil\nimport subprocess\n\nSOURCES = (\n  glob.glob('src/backend/*.sk') +\n  glob.glob('src/core/*.sk') +\n  glob.glob('src/driver/*.sk') +\n  glob.glob('src/frontend/*.sk') +\n  glob.glob('src/lib/*.sk') +\n  glob.glob('src/middle/*.sk') +\n  glob.glob('tests/*.sk')\n)\n\nPUBLIC_CPP_FILES = [\n  'src/cpp/skew.cpp',\n  'src/cpp/skew.h',\n]\n\nFLAGS = [\n  '--inline-functions',\n  '--verbose',\n  '--message-limit=0',\n]\n\nCPP_FLAGS = [\n  '-std=c++11',\n  '-Wall',\n  '-Wextra',\n  '-Wno-switch',\n  '-Wno-unused-parameter',\n  '-Wno-unused-variable',\n  '-include', 'src/cpp/skew.h',\n  '-include', 'src/cpp/support.h',\n]\n\nCPP_DEBUG_FLAGS = [\n  'src/cpp/skew.cpp',\n  'src/cpp/support.cpp',\n]\n\nCPP_RELEASE_FLAGS = [\n  '-O3',\n  '-DNDEBUG',\n  '-fomit-frame-pointer',\n  '-include', 'src/cpp/skew.cpp',\n  '-include', 'src/cpp/support.cpp',\n  '-include', 'src/cpp/fast.cpp',\n]\n\nCPP_GC_FLAGS = [\n  '-DSKEW_GC_MARK_AND_SWEEP',\n]\n\nnode_binary = None\njobs = {}\n\n################################################################################\n\ndef job(fn):\n  jobs[fn.__name__] = fn\n  return fn\n\ndef run(args, exit_on_failure=True, **kwargs):\n  # Print the command for debugging so that it can be copied and pasted into a terminal directly\n  print(' '.join(map(pipes.quote, args)))\n\n  # Start the process\n  process = subprocess.Popen(args, stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr, **kwargs)\n  try:\n    process.wait()\n\n    # Abort on failure\n    if exit_on_failure and process.returncode:\n      print('error: command exited with code %d' % process.returncode)\n      sys.exit(1)\n\n    return process.returncode\n\n  # Ensure the process is terminated\n  finally:\n    try:\n      process.terminate()\n    except:\n      pass\n\ndef watch_folder(folder, callback):\n  before = None\n\n  while True:\n    after = ''\n\n    for path, name, files in os.walk(folder):\n      for f in files:\n        both = '%s/%s' % (path, f)\n        try:\n          mtime = os.stat(both).st_mtime\n        except:\n          mtime = -1\n        after += both + '%d,' % mtime\n\n    if before != after:\n      before = after\n      callback()\n\n    time.sleep(0.1)\n\ndef load_version():\n  return json.load(open('npm/package.json'))['version']\n\ndef update_version(version):\n  open('src/frontend/version.sk', 'w').write('namespace Skew {\\n  const VERSION = %s\\n}\\n' % json.dumps(version))\n\ndef check_same(a, b):\n  run(['diff', a, b])\n\ndef mkdir(path):\n  try:\n    os.makedirs(path)\n  except:\n    pass\n\ndef rmtree(path):\n  try:\n    shutil.rmtree(path)\n  except:\n    pass\n\ndef run_js(source, args, exit_on_failure=True):\n  global node_binary\n\n  if node_binary is None:\n    node_binary = 'nodejs' if run(['which', 'nodejs'], exit_on_failure=False) == 0 else 'node'\n\n  run([node_binary, source] + args, exit_on_failure=exit_on_failure)\n\ndef run_cs(source, args):\n  run(['mono', '--debug', source] + args)\n\ndef run_cpp(source, args):\n  run([source] + args)\n\ndef skewc_js(source, target, sources=SOURCES, build='SKEWC', release=False, exit_on_failure=True):\n  run_js(source, sources + FLAGS + ['--output-file=' + target, '--define:BUILD=' + build] + (['--release'] if release else []), exit_on_failure=exit_on_failure)\n\ndef skewc_cs(source, target, sources=SOURCES, build='SKEWC', release=False):\n  run_cs(source, sources + FLAGS + ['--output-file=' + target, '--define:BUILD=' + build] + (['--release'] if release else []))\n\ndef skewc_cpp(source, target, sources=SOURCES, build='SKEWC', release=False):\n  run_cpp(source, sources + FLAGS + ['--output-file=' + target, '--define:BUILD=' + build] + (['--release'] if release else []))\n\ndef compile_cs(sources, target):\n  run(['mcs', '-debug'] + sources + ['-out:' + target])\n\ndef compile_cpp(source, target, release=False, gc=False):\n  run(['c++', source, '-o', target] + CPP_FLAGS + (CPP_RELEASE_FLAGS if release else CPP_DEBUG_FLAGS) + (CPP_GC_FLAGS if gc else []))\n\n################################################################################\n\n@job\ndef default():\n  mkdir('out')\n  skewc_js('skewc.js', 'out/skewc.min.js', build='SKEWC', release=True)\n  skewc_js('skewc.js', 'out/skew-api.min.js', build='API', release=True)\n\n@job\ndef clean():\n  rmtree('out')\n\n@job\ndef replace():\n  mkdir('out')\n  skewc_js('skewc.js', 'out/skewc.js', build='SKEWC')\n  skewc_js('out/skewc.js', 'out/skewc2.js', build='SKEWC')\n  skewc_js('out/skewc2.js', 'out/skewc3.js', build='SKEWC')\n  check_same('out/skewc2.js', 'out/skewc3.js')\n  os.remove('skewc.js')\n  os.remove('out/skewc2.js')\n  os.rename('out/skewc3.js', 'skewc.js')\n\n@job\ndef check():\n  check_js()\n  check_cs()\n  check_cpp()\n\n@job\ndef check_js():\n  mkdir('out')\n  skewc_js('skewc.js', 'out/skewc.min.js', build='SKEWC', release=True)\n  skewc_js('out/skewc.min.js', 'out/skewc2.min.js', build='SKEWC', release=True)\n  skewc_js('out/skewc2.min.js', 'out/skewc3.min.js', build='SKEWC', release=True)\n  check_same('out/skewc2.min.js', 'out/skewc3.min.js')\n\n@job\ndef check_cs():\n  mkdir('out')\n  skewc_js('skewc.js', 'out/skewc.cs', build='SKEWC')\n\n  # Iteration 1\n  compile_cs(['out/skewc.cs'], 'out/skewc.exe')\n  skewc_cs('out/skewc.exe', 'out/skewc2.cs', build='SKEWC')\n\n  # Iteration 2\n  compile_cs(['out/skewc2.cs'], 'out/skewc2.exe')\n  skewc_cs('out/skewc2.exe', 'out/skewc3.cs', build='SKEWC')\n  check_same('out/skewc2.cs', 'out/skewc3.cs')\n\n@job\ndef check_cpp():\n  mkdir('out')\n  skewc_js('skewc.js', 'out/skewc.cpp', build='SKEWC', release=True)\n\n  # Iteration 1: Debug\n  compile_cpp('out/skewc.cpp', 'out/skewc')\n  skewc_cpp('out/skewc', 'out/skewc2.cpp', build='SKEWC')\n\n  # Iteration 2: Release\n  compile_cpp('out/skewc2.cpp', 'out/skewc2', release=True)\n  skewc_cpp('out/skewc2', 'out/skewc3.cpp', build='SKEWC')\n  check_same('out/skewc2.cpp', 'out/skewc3.cpp')\n\n  # Iteration 3: GC\n  compile_cpp('out/skewc3.cpp', 'out/skewc3', gc=True)\n  skewc_cpp('out/skewc3', 'out/skewc4.cpp', build='SKEWC')\n  check_same('out/skewc3.cpp', 'out/skewc4.cpp')\n\n@job\ndef check_determinism():\n  # Generate JavaScript debug and release builds\n  mkdir('out')\n  skewc_js('skewc.js', 'out/skewc.js.js', build='SKEWC')\n  skewc_js('skewc.js', 'out/skewc.js.min.js', build='SKEWC', release=True)\n\n  # Check C#\n  skewc_js('skewc.js', 'out/skewc.cs', build='SKEWC')\n  compile_cs(['out/skewc.cs'], 'out/skewc.exe')\n  skewc_cs('out/skewc.exe', 'out/skewc.cs.js', build='SKEWC')\n  check_same('out/skewc.js.js', 'out/skewc.cs.js')\n  skewc_cs('out/skewc.exe', 'out/skewc.cs.min.js', build='SKEWC', release=True)\n  check_same('out/skewc.js.min.js', 'out/skewc.cs.min.js')\n\n  # Check C++\n  skewc_js('skewc.js', 'out/skewc.cpp', build='SKEWC')\n  compile_cpp('out/skewc.cpp', 'out/skewc')\n  skewc_cpp('out/skewc', 'out/skewc.cpp.js', build='SKEWC')\n  check_same('out/skewc.js.js', 'out/skewc.cpp.js')\n  skewc_cpp('out/skewc', 'out/skewc.cpp.min.js', build='SKEWC', release=True)\n  check_same('out/skewc.js.min.js', 'out/skewc.cpp.min.js')\n\n@job\ndef test():\n  test_js()\n  test_cs()\n  test_cpp()\n\n@job\ndef test_js():\n  mkdir('out')\n  skewc_js('skewc.js', 'out/skewc.js', build='SKEWC')\n\n  # Debug\n  skewc_js('out/skewc.js', 'out/test.js', build='TEST')\n  run_js('out/test.js', [])\n\n  # Release\n  skewc_js('out/skewc.js', 'out/test.min.js', build='TEST', release=True)\n  run_js('out/test.min.js', [])\n\n@job\ndef test_cs():\n  mkdir('out')\n  skewc_js('skewc.js', 'out/skewc.js', build='SKEWC')\n\n  # Single file\n  skewc_js('out/skewc.js', 'out/test.cs', build='TEST')\n  compile_cs(['out/test.cs'], 'out/test.exe')\n  run_cs('out/test.exe', [])\n\n  # Multiple files\n  rmtree('out/cs')\n  mkdir('out/cs')\n  run_js('out/skewc.js', SOURCES + ['--target=cs', '--output-dir=out/cs', '--define:BUILD=TEST'])\n  compile_cs(glob.glob('out/cs/*.cs'), 'out/test.exe')\n  run_cs('out/test.exe', [])\n\n@job\ndef test_cpp():\n  mkdir('out')\n  skewc_js('skewc.js', 'out/skewc.js', build='SKEWC')\n\n  # Debug\n  skewc_js('out/skewc.js', 'out/test.debug.cpp', build='TEST')\n  compile_cpp('out/test.debug.cpp', 'out/test.debug')\n  run_cpp('out/test.debug', [])\n\n  # Release\n  skewc_js('out/skewc.js', 'out/test.release.cpp', build='TEST', release=True)\n  compile_cpp('out/test.release.cpp', 'out/test.release', release=True)\n  run_cpp('out/test.release', [])\n\n  # GC\n  skewc_js('out/skewc.js', 'out/test.gc.cpp', build='TEST')\n  compile_cpp('out/test.gc.cpp', 'out/test.gc', gc=True)\n  run_cpp('out/test.gc', [])\n\n@job\ndef benchmark():\n  mkdir('out')\n  open('out/benchmark.sk', 'w').write('\\n'.join(open(f).read() for f in SOURCES))\n  skewc_js('skewc.js', 'out/benchmark.js', sources=['out/benchmark.sk'], release=True)\n\n@job\ndef watch():\n  mkdir('out')\n  watch_folder('src', lambda: skewc_js('skewc.js', 'out/skew-api.js', build='API', exit_on_failure=False))\n\n@job\ndef flex():\n  run(['python', 'src/frontend/lexer.py'])\n\n@job\ndef publish():\n  test()\n  check()\n  run(['npm', 'version', 'patch'], cwd='npm')\n  version = load_version()\n  update_version(version)\n  replace()\n  skewc_js('skewc.js', 'out/skewc.min.js', build='SKEWC', release=True)\n  skewc_js('skewc.js', 'npm/skew.js', build='API', release=True)\n  open('npm/skewc', 'w').write('#!/usr/bin/env node\\n' + open('out/skewc.min.js').read())\n  run(['chmod', '+x', 'npm/skewc'])\n  shutil.copyfile('src/driver/jsapi.d.ts', 'npm/skew.d.ts')\n  for name in PUBLIC_CPP_FILES:\n    shutil.copyfile(name, 'npm/' + os.path.basename(name))\n  run(['npm', 'publish'], cwd='npm')\n\n################################################################################\n\ndef main(args):\n  if not args:\n    args = ['default']\n\n  for arg in args:\n    if arg in jobs:\n      jobs[arg]()\n    else:\n      sys.exit('error: unknown job name \"%s\"' % arg)\n\nmain(sys.argv[1:])\n"
  },
  {
    "path": "docs/compiler.md",
    "content": "# Compiler\n\nThis documents the internals of the compiler.\n\n## Development\n\nDevelopment on the compiler itself is straightforward since the compiler compiles itself. The current build of the compiler in JavaScript is included in the repo as `skewc.js` and is used by `build.py`. Here are some useful commands (see `Makefile` for a complete list):\n\n* `./build.py`: Build the compiler into `out/browser.js` which can be tested using `www/index.html`\n* `./build.py check`: Run various sanity checks including compiling the compiler with itself a few times\n* `./build.py test`: Run all tests using all supported language targets\n* `./build.py replace`: Replace the top-level `skewc.js` file with a newer version of itself\n\nThe core of the compiler is the `compile` method in `src/middle/compiler.sk` and is a good place to start reading for an overview of the compilation process.\n\n## Lexing\n\nThe lexer is split into two files, `src/frontend/token.sk` and `src/frontend/lexer.sk`. It started off as a hand-written lexer but now uses [flex](http://flex.sourceforge.net/) for speed. The `src/frontend/build.py` script takes `src/frontend/flex.l` and generates `lexer.sk` by running flex and extracting the embedded magic constants and lookup tables from its output. Use `./build.py flex` to do this from the root directory. The generated lexer source code is checked in because it changes infrequently and because it avoids requiring flex as a dependency. The output of flex is awful for a number of reasons but it's really fast.\n\nLexing technically requires infinite lookahead due to the generic type syntax. Like C#, angle brackets are matched using syntactic structure alone without a symbol table. When a `<` token is encountered, it's only considered the start of a parameterization expression if there's a matching `>` ahead in the token stream and the tokens in between meet certain conditions. This lookahead may sound expensive, but it can be done efficiently without backtracking by storing information in a stack. This is done during the lexing pass in `token.sk` and means the lexer is still O(n). Using angle brackets for generics adds the additional complexity of needing to split tokens that start with a `>`. For example, the type `Foo<Bar<T>>` should end with two `>` tokens, not one `>>` token.\n\n## Parsing\n\nThe hand-written parser uses recursive descent for statements and a Pratt parser for expressions. Pratt parsing support is in `src/frontend/pratt.sk` and the grammar implementation is in `src/frontend/parser.sk`. For a grammar overview, look at `createExpressionParser` for expressions and `parseStatement` for statements.\n\n## Syntax Tree\n\nUnlike many object-oriented syntax trees, this syntax tree just uses a single `Node` object, defined in `src/core/node.sk`. This makes syntax trees much easier to traverse and optimize. Tree traversal involves a single recursive function instead of a massive visitor object. Structure invariants are maintained by convention and runtime asserts instead of the type system. Primitive literal nodes use `Content` objects to store their constant values, defined in `src/core/content.sk`.\n\n## Preprocessing\n\nBefore type checking begins, all parsed syntax trees are merged and preprocessed. Preprocessing is done using an order-independent, outside-in algorithm. A worklist is seeded with top-level preprocessor directives and preprocessing iterates until a fixed point is reached. Each iteration attempts to process top-level `if` directives and the constant variables they reference. Error reporting is delayed until the end since only then can unbound variables be classified as errors. Preprocessing should be pretty fast since it doesn't need to traverse into function definitions.\n\n## Type Checking\n\nType checking starts by creating a symbol for each declaration, creating a scope for each block that needs one, and inserting each symbol into its enclosing scope. Each scope can both reference symbols on a type and store local symbols. For example, two adjacent namespace declarations with the same name have two separate scopes that both reference the same type.\n\nOnce all symbols and scopes are prepared, type checking is done using a single tree traversal. Type checking is made order-independent by applying it recursively. For example, resolving the body of a function may require resolving the type of a variable, which may require resolving its initializer, which may require resolving a constructor, which would then require resolving the enclosing type, which may require resolving base types, and so on:\n\n    def foo { bar.baz }\n    var bar = Bar.new\n    class Bar : Baz {}\n    class Baz { def baz {} }\n\nTo prevent cycles, symbol resolution is separated into an initialization phase and a resolution phase. The initialization phase resolves just enough to know the type of the symbol while the resolution phase fully resolves the symbol's contents. Using a symbol requires initializing it but not resolving it. Cycles are detected by giving each symbol three states: uninitialized, initializing, and initialized. Encountering an initializing symbol is an error. These rules ensure that `class Foo { var foo Foo }` is valid but `class Foo : Foo {}` is an error.\n\nLimited type inference is performed using type context propagation. A type hint can optionally be provided during expression resolution and will be used to provide missing information if available. For example, type context from the variable type in `var foo List<double> = [0]` ensures that the list literal contains doubles instead of ints.\n"
  },
  {
    "path": "extras/Atom/README.md",
    "content": "# Atom Syntax Definitions for Skew\n\nRun `apm install skew` to install syntax highlighting for the [Atom editor](https://atom.io). The package repository that it installs from is at https://github.com/evanw/skew-atom.\n"
  },
  {
    "path": "extras/Sublime Text/README.md",
    "content": "# Sublime Text Syntax Definitions for Skew\n\n## Installing\nTo install, copy the \"Skew\" folder into the appropriate location for the given platform and version listed below.\n[(more information about Sublime Text packages)](http://docs.sublimetext.info/en/latest/basic_concepts.html#the-packages-directory)\n\n### OS X\n_Sublime Text 2_\n\n    ~/Library/Application Support/Sublime Text 2/Packages/\n\n_Sublime Text 3_\n\n    ~/Library/Application Support/Sublime Text 3/Packages/\n\n### Windows\n_Sublime Text 2_\n\n    %APPDATA%\\Sublime Text 2\\Packages\n\n_Sublime Text 3_\n\n    %APPDATA%\\Sublime Text 3\\Packages\n\n### Linux\n_Sublime Text 2_\n\n    ~/.Sublime Text 2/Packages\n\n_Sublime Text 3_\n\n    ~/.Sublime Text 3/Packages\n"
  },
  {
    "path": "extras/Sublime Text/Skew/Comments.tmPreferences",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n  <key>name</key>\n  <string>Comments</string>\n  <key>scope</key>\n  <string>source.skew</string>\n  <key>settings</key>\n  <dict>\n    <key>shellVariables</key>\n    <array>\n      <dict>\n        <key>name</key>\n        <string>TM_COMMENT_START</string>\n        <key>value</key>\n        <string># </string>\n      </dict>\n    </array>\n  </dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "extras/Sublime Text/Skew/Skew.sublime-completions",
    "content": "{\n  \"scope\": \"source.skew\",\n  \"completions\": [\n    { \"trigger\": \"as\", \"contents\": \"as\" },\n    { \"trigger\": \"break\", \"contents\": \"break\" },\n    { \"trigger\": \"case\", \"contents\": \"case\" },\n    { \"trigger\": \"catch\", \"contents\": \"catch\" },\n    { \"trigger\": \"class\", \"contents\": \"class\" },\n    { \"trigger\": \"const\", \"contents\": \"const\" },\n    { \"trigger\": \"continue\", \"contents\": \"continue\" },\n    { \"trigger\": \"def\", \"contents\": \"def\" },\n    { \"trigger\": \"default\", \"contents\": \"default\" },\n    { \"trigger\": \"dynamic\", \"contents\": \"dynamic\" },\n    { \"trigger\": \"else\", \"contents\": \"else\" },\n    { \"trigger\": \"enum\", \"contents\": \"enum\" },\n    { \"trigger\": \"false\", \"contents\": \"false\" },\n    { \"trigger\": \"finally\", \"contents\": \"finally\" },\n    { \"trigger\": \"for\", \"contents\": \"for\" },\n    { \"trigger\": \"if\", \"contents\": \"if\" },\n    { \"trigger\": \"in\", \"contents\": \"in\" },\n    { \"trigger\": \"interface\", \"contents\": \"interface\" },\n    { \"trigger\": \"is\", \"contents\": \"is\" },\n    { \"trigger\": \"namespace\", \"contents\": \"namespace\" },\n    { \"trigger\": \"null\", \"contents\": \"null\" },\n    { \"trigger\": \"over\", \"contents\": \"over\" },\n    { \"trigger\": \"return\", \"contents\": \"return\" },\n    { \"trigger\": \"super\", \"contents\": \"super\" },\n    { \"trigger\": \"switch\", \"contents\": \"switch\" },\n    { \"trigger\": \"throw\", \"contents\": \"throw\" },\n    { \"trigger\": \"true\", \"contents\": \"true\" },\n    { \"trigger\": \"try\", \"contents\": \"try\" },\n    { \"trigger\": \"var\", \"contents\": \"var\" },\n    { \"trigger\": \"while\", \"contents\": \"while\" }\n  ]\n}\n"
  },
  {
    "path": "extras/Sublime Text/Skew/Skew.tmLanguage",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n  <key>fileTypes</key>\n  <array>\n    <string>sk</string>\n  </array>\n  <key>name</key>\n  <string>Skew</string>\n  <key>scopeName</key>\n  <string>source.skew</string>\n  <key>patterns</key>\n  <array>\n    <dict>\n      <key>match</key>\n      <string>#.*</string>\n      <key>name</key>\n      <string>comment.skew</string>\n    </dict>\n    <dict>\n      <key>match</key>\n      <string>\\b(?:as|break|case|continue|default|else|finally|if|in|is|return|super|switch|throw|try|while)\\b</string>\n      <key>name</key>\n      <string>keyword.skew</string>\n    </dict>\n    <dict>\n      <key>match</key>\n      <string>\\b(?:[A-Z_][A-Z0-9_]+|null|true|false|self|0b[01]+(?:\\.[01]+)?|0o[0-7]+(?:\\.[0-7]+)?|0x[0-9A-Fa-f]+(?:\\.[0-9A-Fa-f]+)?|[0-9]+(?:\\.[0-9]+)?(?:e[+-]?[0-9]+)?f?)\\b</string>\n      <key>name</key>\n      <string>constant.numeric.skew</string>\n    </dict>\n    <dict>\n      <key>match</key>\n      <string>@[A-Za-z_][A-Za-z0-9_]*\\b</string>\n      <key>name</key>\n      <string>keyword.skew</string>\n    </dict>\n    <dict>\n      <key>match</key>\n      <string>\\b(?:bool|double|dynamic|fn|int|string|[A-Z][A-Za-z0-9_]*(?:\\.[A-Z][A-Za-z0-9_]*[a-z][A-Za-z0-9_]*)*)\\b(?:&lt;.*?&gt;(?!&gt;))?</string>\n      <key>name</key>\n      <string>storage.type.skew</string>\n    </dict>\n    <dict>\n      <key>match</key>\n      <string>\\bdef\\b(?:\\s+([A-Za-z0-9_\\-\\+\\*/%!^&amp;|~=&gt;&lt;\\[\\]\\{\\}\\.]+))?</string>\n      <key>name</key>\n      <string>keyword.skew</string>\n      <key>captures</key>\n      <dict>\n        <key>1</key>\n        <dict>\n          <key>name</key>\n          <string>entity.name.function.skew</string>\n        </dict>\n      </dict>\n    </dict>\n    <dict>\n      <key>match</key>\n      <string>\\b(?:catch|const|for|var)\\b(?:\\s+([A-Za-z0-9_\\.]+))?</string>\n      <key>name</key>\n      <string>keyword.skew</string>\n      <key>captures</key>\n      <dict>\n        <key>1</key>\n        <dict>\n          <key>name</key>\n          <string>entity.name.function.skew</string>\n        </dict>\n      </dict>\n    </dict>\n    <dict>\n      <key>match</key>\n      <string>^\\s*\\b(?:class|def|enum|flags|interface|namespace|over|type)\\b(?:\\s+([A-Za-z0-9_\\.]+))?</string>\n      <key>name</key>\n      <string>keyword.skew</string>\n      <key>captures</key>\n      <dict>\n        <key>1</key>\n        <dict>\n          <key>name</key>\n          <string>entity.name.function.skew</string>\n        </dict>\n      </dict>\n    </dict>\n    <dict>\n      <key>begin</key>\n      <string>'</string>\n      <key>end</key>\n      <string>'</string>\n      <key>name</key>\n      <string>string.quoted.single.skew</string>\n      <key>patterns</key>\n      <array>\n        <dict>\n          <key>match</key>\n          <string>\\\\.</string>\n          <key>name</key>\n          <string>constant.character.escape.skew</string>\n        </dict>\n      </array>\n    </dict>\n    <dict>\n      <key>begin</key>\n      <string>\"</string>\n      <key>end</key>\n      <string>\"</string>\n      <key>name</key>\n      <string>string.quoted.double.skew</string>\n      <key>patterns</key>\n      <array>\n        <dict>\n          <key>begin</key>\n          <string>\\\\\\(</string>\n          <key>end</key>\n          <string>\\)</string>\n          <key>name</key>\n          <string>string.interpolated.skew</string>\n        </dict>\n        <dict>\n          <key>match</key>\n          <string>\\\\.</string>\n          <key>name</key>\n          <string>constant.character.escape.skew</string>\n        </dict>\n      </array>\n    </dict>\n  </array>\n</dict>\n</plist>\n"
  },
  {
    "path": "npm/README",
    "content": "See [http://skew-lang.org](http://skew-lang.org) for more information.\n"
  },
  {
    "path": "npm/package.json",
    "content": "{\n  \"name\": \"skew\",\n  \"version\": \"0.9.19\",\n  \"author\": \"Evan Wallace\",\n  \"description\": \"A compiler for the Skew programming language\",\n  \"license\": \"MIT\",\n  \"main\": \"skew.js\",\n  \"bin\": {\n    \"skewc\": \"skewc\"\n  },\n  \"types\": \"./skew.d.ts\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/evanw/skew\"\n  }\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"scripts\": {\n    \"test\": \"python build.py test_js\"\n  }\n}\n"
  },
  {
    "path": "skewc.js",
    "content": "(function() {\n  var __create = Object.create ? Object.create : function(prototype) {\n    return {'__proto__': prototype};\n  };\n\n  function __extends(derived, base) {\n    derived.prototype = __create(base.prototype);\n    derived.prototype.constructor = derived;\n  }\n\n  var __imul = Math.imul ? Math.imul : function(a, b) {\n    return (a * (b >>> 16) << 16) + a * (b & 65535) | 0;\n  };\n\n  function assert(truth) {\n    if (!truth) {\n      throw Error('Assertion failed');\n    }\n  }\n\n  var Target = {\n    CSHARP: 2,\n    JAVASCRIPT: 3\n  };\n\n  function StringBuilder() {\n    this.buffer = '';\n  }\n\n  function Box(value) {\n    this.value = value;\n  }\n\n  var Unicode = {};\n\n  Unicode.codeUnitCountForCodePoints = function(codePoints, encoding) {\n    var count = 0;\n\n    switch (encoding) {\n      case Unicode.Encoding.UTF8: {\n        for (var i = 0, list = codePoints, count1 = list.length; i < count1; i = i + 1 | 0) {\n          var codePoint = in_List.get(list, i);\n\n          if (codePoint < 128) {\n            count = count + 1 | 0;\n          }\n\n          else if (codePoint < 2048) {\n            count = count + 2 | 0;\n          }\n\n          else if (codePoint < 65536) {\n            count = count + 3 | 0;\n          }\n\n          else {\n            count = count + 4 | 0;\n          }\n        }\n        break;\n      }\n\n      case Unicode.Encoding.UTF16: {\n        for (var i1 = 0, list1 = codePoints, count2 = list1.length; i1 < count2; i1 = i1 + 1 | 0) {\n          var codePoint1 = in_List.get(list1, i1);\n\n          if (codePoint1 < 65536) {\n            count = count + 1 | 0;\n          }\n\n          else {\n            count = count + 2 | 0;\n          }\n        }\n        break;\n      }\n\n      case Unicode.Encoding.UTF32: {\n        count = codePoints.length;\n        break;\n      }\n    }\n\n    return count;\n  };\n\n  Unicode.Encoding = {\n    UTF8: 0,\n    UTF16: 1,\n    UTF32: 2\n  };\n\n  Unicode.StringIterator = function() {\n    this.value = '';\n    this.index = 0;\n    this.stop = 0;\n  };\n\n  Unicode.StringIterator.prototype.reset = function(text, start) {\n    this.value = text;\n    this.index = start;\n    this.stop = text.length;\n    return this;\n  };\n\n  Unicode.StringIterator.prototype.nextCodePoint = function() {\n    if (this.index >= this.stop) {\n      return -1;\n    }\n\n    var a = in_string.get1(this.value, (this.index = this.index + 1 | 0) + -1 | 0);\n\n    if ((a & 64512) != 55296) {\n      return a;\n    }\n\n    if (this.index >= this.stop) {\n      return -1;\n    }\n\n    var b = in_string.get1(this.value, (this.index = this.index + 1 | 0) + -1 | 0);\n    return ((a << 10) + b | 0) + ((65536 - (55296 << 10) | 0) - 56320 | 0) | 0;\n  };\n\n  /////////////////////////////////////////////////////////////////////////////////\n  //\n  // This is a generated file, all edits will be lost!\n  //\n  /////////////////////////////////////////////////////////////////////////////////\n\n  var Skew = {};\n\n  Skew.quoteString = function(text, style, octal) {\n    var count = text.length;\n\n    // Use whichever quote character is less frequent\n    if (style == Skew.QuoteStyle.SHORTEST) {\n      var singleQuotes = 0;\n      var doubleQuotes = 0;\n\n      for (var i = 0, count1 = count; i < count1; i = i + 1 | 0) {\n        var c = in_string.get1(text, i);\n\n        if (c == 34) {\n          doubleQuotes = doubleQuotes + 1 | 0;\n        }\n\n        else if (c == 39) {\n          singleQuotes = singleQuotes + 1 | 0;\n        }\n      }\n\n      style = singleQuotes <= doubleQuotes ? Skew.QuoteStyle.SINGLE : Skew.QuoteStyle.DOUBLE;\n    }\n\n    var builder = new StringBuilder();\n    var quoteString = style == Skew.QuoteStyle.SINGLE ? \"'\" : '\"';\n    var quote = style == Skew.QuoteStyle.TYPESCRIPT_TEMPLATE ? 96 : style == Skew.QuoteStyle.SINGLE ? 39 : 34;\n    var escaped = '';\n\n    // Append long runs of unescaped characters using a single slice for speed\n    var start = 0;\n\n    if (style != Skew.QuoteStyle.TYPESCRIPT_TEMPLATE) {\n      builder.buffer += quoteString;\n    }\n\n    for (var i1 = 0, count2 = count; i1 < count2; i1 = i1 + 1 | 0) {\n      var c1 = in_string.get1(text, i1);\n\n      if (c1 == quote) {\n        escaped = '\\\\' + quoteString;\n      }\n\n      else if (c1 == 10) {\n        escaped = '\\\\n';\n      }\n\n      else if (c1 == 13) {\n        escaped = '\\\\r';\n      }\n\n      else if (c1 == 9) {\n        escaped = '\\\\t';\n      }\n\n      else if (c1 == 0) {\n        // Avoid issues around accidental octal encoding\n        var next = (i1 + 1 | 0) < count ? in_string.get1(text, i1 + 1 | 0) : 0;\n        escaped = octal == Skew.QuoteOctal.OCTAL_WORKAROUND && next >= 48 && next <= 57 ? '\\\\000' : '\\\\0';\n      }\n\n      else if (c1 == 92) {\n        escaped = '\\\\\\\\';\n      }\n\n      else if (c1 == 36 && style == Skew.QuoteStyle.TYPESCRIPT_TEMPLATE) {\n        escaped = '\\\\$';\n      }\n\n      else if (c1 < 32) {\n        escaped = '\\\\x' + in_string.get(Skew.HEX, c1 >> 4) + in_string.get(Skew.HEX, c1 & 15);\n      }\n\n      else {\n        continue;\n      }\n\n      builder.buffer += in_string.slice2(text, start, i1);\n      builder.buffer += escaped;\n      start = i1 + 1 | 0;\n    }\n\n    builder.buffer += in_string.slice2(text, start, count);\n\n    if (style != Skew.QuoteStyle.TYPESCRIPT_TEMPLATE) {\n      builder.buffer += quoteString;\n    }\n\n    return builder.buffer;\n  };\n\n  // A single base 64 digit can contain 6 bits of data. For the base 64 variable\n  // length quantities we use in the source map spec, the first bit is the sign,\n  // the next four bits are the actual value, and the 6th bit is the continuation\n  // bit. The continuation bit tells us whether there are more digits in this\n  // value following this digit.\n  //\n  //   Continuation\n  //   |    Sign\n  //   |    |\n  //   V    V\n  //   101011\n  //\n  Skew.encodeVLQ = function(value) {\n    var vlq = value < 0 ? -value << 1 | 1 : value << 1;\n    var encoded = '';\n\n    while (true) {\n      var digit = vlq & 31;\n      vlq >>= 5;\n\n      // If there are still more digits in this value, we must make sure the\n      // continuation bit is marked\n      if (vlq != 0) {\n        digit |= 32;\n      }\n\n      encoded += in_string.get(Skew.BASE64, digit);\n\n      if (vlq == 0) {\n        break;\n      }\n    }\n\n    return encoded;\n  };\n\n  Skew.hashCombine = function(left, right) {\n    return left ^ ((right - 1640531527 | 0) + (left << 6) | 0) + (left >> 2);\n  };\n\n  Skew.splitPath = function(path) {\n    var slashIndex = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\\\'));\n    return slashIndex == -1 ? new Skew.SplitPath('.', path) : new Skew.SplitPath(in_string.slice2(path, 0, slashIndex), in_string.slice1(path, slashIndex + 1 | 0));\n  };\n\n  Skew.withUppercaseFirstLetter = function(text) {\n    return text == '' ? text : in_string.get(text, 0).toUpperCase() + in_string.slice1(text, 1);\n  };\n\n  Skew.indentIndex = function(text) {\n    var i = 0;\n\n    while (i < text.length && (in_string.get1(text, i) == 32 || in_string.get1(text, i) == 9)) {\n      i = i + 1 | 0;\n    }\n\n    return i;\n  };\n\n  Skew.indentOfLine = function(line) {\n    return in_string.slice2(line, 0, Skew.indentIndex(line));\n  };\n\n  Skew.lineWithoutIndent = function(line) {\n    return in_string.slice1(line, Skew.indentIndex(line));\n  };\n\n  Skew.bytesToString = function(bytes) {\n    var KB = 1 << 10;\n    var MB = 1 << 20;\n    var GB = 1 << 30;\n\n    if (bytes == 1) {\n      return '1 byte';\n    }\n\n    if (bytes < KB) {\n      return bytes.toString() + ' bytes';\n    }\n\n    if (bytes < MB) {\n      return (Math.round(bytes / KB * 10) / 10).toString() + 'kb';\n    }\n\n    if (bytes < GB) {\n      return (Math.round(bytes / MB * 10) / 10).toString() + 'mb';\n    }\n\n    return (Math.round(bytes / GB * 10) / 10).toString() + 'gb';\n  };\n\n  Skew.doubleToStringWithDot = function(value) {\n    // These cases are different for each language target and must be handled before this\n    assert(isFinite(value));\n    var text = value.toString();\n\n    // The C# implementation of double.ToString() uses an uppercase \"E\"\n    if (TARGET == Target.CSHARP) {\n      text = text.toLowerCase();\n    }\n\n    // \"1\" => \"1.0\"\n    // \"1.5\" => \"1.5\"\n    // \"1e+100\" => \"1.0e+100\"\n    // \"1.5e+100\" => \"1.5e+100\"\n    if (!(text.indexOf('.') != -1)) {\n      var e = text.indexOf('e');\n\n      if (e != -1) {\n        text = in_string.slice2(text, 0, e) + '.0' + in_string.slice1(text, e);\n      }\n\n      else {\n        text += '.0';\n      }\n    }\n\n    return text;\n  };\n\n  // The cost of changing the case of a letter is 0.5 instead of 1\n  Skew.caseAwareLevenshteinEditDistance = function(a, b) {\n    var an = a.length;\n    var bn = b.length;\n    var v0 = [];\n    var v1 = [];\n\n    for (var i = 0, count = bn + 1 | 0; i < count; i = i + 1 | 0) {\n      v0.push(i);\n      v1.push(i);\n    }\n\n    for (var i1 = 0, count3 = an; i1 < count3; i1 = i1 + 1 | 0) {\n      var ca = in_string.get1(a, i1);\n      in_List.set(v1, 0, i1 + 1 | 0);\n\n      for (var j = 0, count1 = bn; j < count1; j = j + 1 | 0) {\n        var cb = in_string.get1(b, j);\n        in_List.set(v1, j + 1 | 0, Math.min(in_List.get(v0, j) + (ca == cb ? 0 : Skew.toLowerCase(ca) == Skew.toLowerCase(cb) ? 0.5 : 1), Math.min(in_List.get(v1, j), in_List.get(v0, j + 1 | 0)) + 1));\n      }\n\n      for (var j1 = 0, count2 = bn + 1 | 0; j1 < count2; j1 = j1 + 1 | 0) {\n        in_List.set(v0, j1, in_List.get(v1, j1));\n      }\n    }\n\n    return in_List.get(v1, bn);\n  };\n\n  Skew.toLowerCase = function(c) {\n    return c >= 65 && c <= 90 ? (97 - 65 | 0) + c | 0 : c;\n  };\n\n  Skew.replaceSingleQuotesWithDoubleQuotes = function(text) {\n    assert(text.startsWith(\"'\"));\n    assert(text.endsWith(\"'\"));\n    var builder = new StringBuilder();\n    var start = 1;\n    var limit = text.length - 1 | 0;\n    builder.buffer += '\"';\n\n    for (var i = start; i < limit; i = i + 1 | 0) {\n      var c = in_string.get1(text, i);\n\n      if (c == 34) {\n        builder.buffer += in_string.slice2(text, start, i);\n        builder.buffer += '\\\\\"';\n        start = i + 1 | 0;\n      }\n\n      else if (c == 92) {\n        if (in_string.get1(text, i + 1 | 0) == 39) {\n          builder.buffer += in_string.slice2(text, start, i);\n          builder.buffer += \"'\";\n          start = i + 2 | 0;\n        }\n\n        i = i + 1 | 0;\n      }\n    }\n\n    builder.buffer += in_string.slice2(text, start, limit);\n    builder.buffer += '\"';\n    return builder.buffer;\n  };\n\n  Skew.argumentCountForOperator = function(text) {\n    if (Skew.validArgumentCounts == null) {\n      Skew.validArgumentCounts = new Map();\n\n      for (var i = 0, list = Array.from(Skew.operatorInfo.values()), count = list.length; i < count; i = i + 1 | 0) {\n        var value = in_List.get(list, i);\n        in_StringMap.set(Skew.validArgumentCounts, value.text, value.validArgumentCounts);\n      }\n\n      in_StringMap.set(Skew.validArgumentCounts, '<>...</>', [1]);\n      in_StringMap.set(Skew.validArgumentCounts, '[...]', [1]);\n      in_StringMap.set(Skew.validArgumentCounts, '[new]', [0, 1]);\n      in_StringMap.set(Skew.validArgumentCounts, '{...}', [2]);\n      in_StringMap.set(Skew.validArgumentCounts, '{new}', [0, 2]);\n    }\n\n    return in_StringMap.get(Skew.validArgumentCounts, text, null);\n  };\n\n  Skew.skewcMain = function($arguments) {\n    var log = new Skew.Log();\n    var diagnosticLimit = 0;\n    var printDiagnostic = function(diagnostic) {\n      var terminalWidth = process.stdout.columns;\n\n      if (diagnosticLimit > 0 && log.diagnostics.length >= diagnosticLimit) {\n        return;\n      }\n\n      if (diagnostic.range != null) {\n        Skew.printWithColor(Terminal.Color.BOLD, diagnostic.range.locationString() + ': ');\n      }\n\n      switch (diagnostic.kind) {\n        case Skew.DiagnosticKind.WARNING: {\n          Skew.printWarning(diagnostic.text);\n          break;\n        }\n\n        case Skew.DiagnosticKind.ERROR: {\n          Skew.printError(diagnostic.text);\n          break;\n        }\n      }\n\n      if (diagnostic.range != null) {\n        var formatted = diagnostic.range.format(terminalWidth);\n        process.stdout.write(formatted.line + '\\n');\n        Skew.printWithColor(Terminal.Color.GREEN, formatted.range + '\\n');\n      }\n\n      if (diagnostic.noteRange != null) {\n        var formatted1 = diagnostic.noteRange.format(terminalWidth);\n        Skew.printWithColor(Terminal.Color.BOLD, diagnostic.noteRange.locationString() + ': ');\n        Skew.printNote(diagnostic.noteText);\n        process.stdout.write(formatted1.line + '\\n');\n        Skew.printWithColor(Terminal.Color.GREEN, formatted1.range + '\\n');\n      }\n    };\n\n    // Print diagnostics immediately when generated to improve perceived speed\n    log.appendCallback = printDiagnostic;\n\n    // Translate frontend flags to compiler options\n    var parser = new Skew.Options.Parser();\n    var options = Skew.parseOptions(log, parser, $arguments);\n    diagnosticLimit = parser.intForOption(Skew.Option.MESSAGE_LIMIT, Skew.DEFAULT_MESSAGE_LIMIT);\n    var fixAll = parser.boolForOption(Skew.Option.FIX_ALL, false);\n    var fixCount = 0;\n\n    // Optionally have the log transform warnings into errors\n    if (options != null) {\n      log.warningsAreErrors = options.warningsAreErrors;\n    }\n\n    // Suppress logging during fixes\n    if (fixAll) {\n      log = new Skew.Log();\n    }\n\n    // Iterate until fixed point when applying fixes\n    while (true) {\n      var inputs = [];\n      var inputRanges = [];\n      Skew.readSources(log, parser.normalArguments, inputs, inputRanges);\n\n      // Run the compilation\n      if (!log.hasErrors() && options != null) {\n        var result = Skew.compile(log, options, inputs);\n\n        // Write all outputs\n        if (!log.hasErrors()) {\n          for (var i = 0, list = result.outputs, count1 = list.length; i < count1; i = i + 1 | 0) {\n            var output = in_List.get(list, i);\n\n            if (output.name != null && !IO.writeFile(output.name, output.contents)) {\n              var outputFile = parser.rangeForOption(Skew.Option.OUTPUT_FILE);\n              var outputDirectory = parser.rangeForOption(Skew.Option.OUTPUT_DIRECTORY);\n              log.commandLineErrorUnwritableFile(outputFile != null ? outputFile : outputDirectory, output.name);\n              break;\n            }\n          }\n\n          // Print compilation statistics\n          if (!log.hasErrors()) {\n            Skew.printWithColor(Terminal.Color.GRAY, result.statistics(inputs, options.verbose ? Skew.StatisticsKind.LONG : Skew.StatisticsKind.SHORT) + '\\n');\n          }\n        }\n      }\n\n      if (!fixAll) {\n        break;\n      }\n\n      // Attempt to automatically fix warnings and errors\n      var applyLog = new Skew.Log();\n      var count = Skew.applyFixes(log, applyLog, function(source) {\n        for (var i = 0, count2 = inputs.length; i < count2; i = i + 1 | 0) {\n          if (source.name == in_List.get(inputs, i).name) {\n            return in_List.get(inputRanges, i);\n          }\n        }\n\n        return parser.rangeForOption(Skew.Option.FIX_ALL);\n      });\n      fixCount = fixCount + count | 0;\n      log = applyLog;\n\n      if (count == 0 || applyLog.hasErrors()) {\n        break;\n      }\n    }\n\n    // Print diagnostics afterward when applying fixes since they aren't printed earlier\n    if (fixAll) {\n      for (var i1 = 0, list1 = log.diagnostics, count2 = list1.length; i1 < count2; i1 = i1 + 1 | 0) {\n        var diagnostic = in_List.get(list1, i1);\n        printDiagnostic(diagnostic);\n      }\n\n      process.stdout.write(fixCount.toString() + ' ' + (fixCount == 1 ? 'fix' : 'fixes') + ' applied' + '\\n');\n    }\n\n    // Print any errors and warnings\n    Skew.printLogSummary(log, diagnosticLimit);\n\n    // Optionally report a failure if any warnings were found\n    if (options != null && options.warningsAreErrors) {\n      return log.hasErrors() || log.hasWarnings() ? 1 : 0;\n    }\n\n    else {\n      return log.hasErrors() ? 1 : 0;\n    }\n  };\n\n  Skew.printWithColor = function(color, text) {\n    Terminal.setColor(color);\n    process.stdout.write(text);\n    Terminal.setColor(Terminal.Color.DEFAULT);\n  };\n\n  Skew.printError = function(text) {\n    Skew.printWithColor(Terminal.Color.RED, 'error: ');\n    Skew.printWithColor(Terminal.Color.BOLD, text + '\\n');\n  };\n\n  Skew.printNote = function(text) {\n    Skew.printWithColor(Terminal.Color.GRAY, 'note: ');\n    Skew.printWithColor(Terminal.Color.BOLD, text + '\\n');\n  };\n\n  Skew.printWarning = function(text) {\n    Skew.printWithColor(Terminal.Color.MAGENTA, 'warning: ');\n    Skew.printWithColor(Terminal.Color.BOLD, text + '\\n');\n  };\n\n  Skew.printUsage = function(parser) {\n    Skew.printWithColor(Terminal.Color.GREEN, '\\nusage: ');\n    Skew.printWithColor(Terminal.Color.BOLD, 'skewc [flags] [inputs]\\n');\n    process.stdout.write(parser.usageText(Math.min(process.stdout.columns, 80)));\n  };\n\n  Skew.printLogSummary = function(log, diagnosticLimit) {\n    var hasErrors = log.hasErrors();\n    var hasWarnings = log.hasWarnings();\n    var summary = '';\n\n    if (hasWarnings) {\n      summary += Skew.PrettyPrint.plural1(log.warningCount(), 'warning');\n\n      if (hasErrors) {\n        summary += ' and ';\n      }\n    }\n\n    if (hasErrors) {\n      summary += Skew.PrettyPrint.plural1(log.errorCount(), 'error');\n    }\n\n    if (hasWarnings || hasErrors) {\n      process.stdout.write(summary + ' generated');\n\n      if (log.wasWarningCount() > 0) {\n        process.stdout.write(' (warnings are being treated as errors due to \"--warnings-are-errors\")');\n      }\n\n      if (diagnosticLimit > 0 && log.diagnostics.length > diagnosticLimit) {\n        Skew.printWithColor(Terminal.Color.GRAY, ' (only showing ' + Skew.PrettyPrint.plural1(diagnosticLimit, 'message') + ', use \"--message-limit=0\" to see all)');\n      }\n\n      process.stdout.write('\\n');\n    }\n  };\n\n  Skew.readSources = function(log, normalArguments, inputs, inputRanges) {\n    var visit = null;\n    visit = function(range, path, isExplicit) {\n      if (Skew.splitPath(path).entry.startsWith('.')) {\n        return;\n      }\n\n      // Directories\n      if (IO.isDirectory(path)) {\n        var entries = IO.readDirectory(path);\n\n        if (entries == null) {\n          log.commandLineErrorUnreadableFile(range, path);\n        }\n\n        for (var i = 0, list = entries, count = list.length; i < count; i = i + 1 | 0) {\n          var entry = in_List.get(list, i);\n\n          if (!entry.startsWith('.')) {\n            visit(range, path + '/' + entry, false);\n          }\n        }\n      }\n\n      // Files (ignore non-skew files that aren't explicitly specified)\n      else if (isExplicit || path.endsWith('.sk')) {\n        var contents = IO.readFile(path);\n\n        if (contents == null) {\n          log.commandLineErrorUnreadableFile(range, path);\n        }\n\n        else {\n          inputs.push(new Skew.Source(path, contents));\n          inputRanges.push(range);\n        }\n      }\n    };\n\n    // Recursively visit input directories\n    for (var i = 0, list = normalArguments, count = list.length; i < count; i = i + 1 | 0) {\n      var range = in_List.get(list, i);\n      visit(range, range.toString(), true);\n    }\n  };\n\n  Skew.parseOptions = function(log, parser, $arguments) {\n    // Configure the parser\n    parser.define(Skew.Options.Type.BOOL, Skew.Option.HELP, '--help', 'Prints this message.').aliases(['-help', '?', '-?', '-h', '-H', '/?', '/h', '/H']);\n    parser.define(Skew.Options.Type.STRING, Skew.Option.TARGET, '--target', 'Sets the target format. Valid targets are ' + Skew.joinKeys(Array.from(Skew.VALID_TARGETS.keys())) + '.');\n    parser.define(Skew.Options.Type.STRING, Skew.Option.OUTPUT_FILE, '--output-file', 'Combines all output into a single file. Mutually exclusive with --output-dir.');\n    parser.define(Skew.Options.Type.STRING, Skew.Option.OUTPUT_DIRECTORY, '--output-dir', 'Places all output files in the specified directory. Mutually exclusive with --output-file.');\n    parser.define(Skew.Options.Type.BOOL, Skew.Option.NO_OUTPUT, '--no-output', 'Stops after the type checking pass and does not generate any output.');\n    parser.define(Skew.Options.Type.BOOL, Skew.Option.RELEASE, '--release', 'Implies --js-mangle, --js-minify, --fold-constants, --inline-functions, --globalize-functions, and --define:RELEASE=true.');\n    parser.define(Skew.Options.Type.BOOL, Skew.Option.VERBOSE, '--verbose', 'Prints out information about the compilation.');\n    parser.define(Skew.Options.Type.BOOL, Skew.Option.VERSION, '--version', 'Prints the current compiler version (' + Skew.VERSION + ') and exits.');\n    parser.define(Skew.Options.Type.INT, Skew.Option.MESSAGE_LIMIT, '--message-limit', 'Sets the maximum number of messages to report. ' + ('Pass 0 to disable the message limit. The default is ' + Skew.DEFAULT_MESSAGE_LIMIT.toString() + '.'));\n    parser.define(Skew.Options.Type.STRING_LIST, Skew.Option.DEFINE, '--define', 'Override variable values at compile time.');\n    parser.define(Skew.Options.Type.BOOL, Skew.Option.JS_MANGLE, '--js-mangle', 'Transforms emitted JavaScript to be as small as possible. The \"@export\" annotation prevents renaming a symbol.');\n    parser.define(Skew.Options.Type.BOOL, Skew.Option.JS_MINIFY, '--js-minify', 'Remove whitespace when compiling to JavaScript.');\n    parser.define(Skew.Options.Type.BOOL, Skew.Option.JS_SOURCE_MAP, '--js-source-map', 'Generates a source map when targeting JavaScript. ' + 'The source map is saved with the \".map\" extension in the same directory as the main output file.');\n    parser.define(Skew.Options.Type.BOOL, Skew.Option.FOLD_CONSTANTS, '--fold-constants', 'Evaluates constants at compile time and removes dead code inside functions.');\n    parser.define(Skew.Options.Type.BOOL, Skew.Option.INLINE_FUNCTIONS, '--inline-functions', 'Uses heuristics to automatically inline simple global functions.');\n    parser.define(Skew.Options.Type.BOOL, Skew.Option.GLOBALIZE_FUNCTIONS, '--globalize-functions', 'Convert instance functions to global functions for better inlining.');\n    parser.define(Skew.Options.Type.BOOL, Skew.Option.FIX_ALL, '--fix-all', 'Attempt to automatically fix as many errors and warnings as possible. ' + \"THIS WILL WRITE OVER YOUR SOURCE CODE. Make sure you know what you're doing.\");\n    parser.define(Skew.Options.Type.BOOL, Skew.Option.IGNORED_COMMENT_WARNING, '--ignored-comment-warning', \"Warn when the compiler doesn't store a comment in the parse tree.\");\n    parser.define(Skew.Options.Type.BOOL, Skew.Option.WARNINGS_ARE_ERRORS, '--warnings-are-errors', 'Turns warnings into errors.');\n\n    // Parse the command line arguments\n    parser.parse(log, $arguments);\n\n    if (log.hasErrors()) {\n      return null;\n    }\n\n    // Early-out when printing the usage text\n    if (parser.boolForOption(Skew.Option.HELP, $arguments.length == 0)) {\n      Skew.printUsage(parser);\n      return null;\n    }\n\n    // Early-out when printing the version\n    if (parser.boolForOption(Skew.Option.VERSION, false)) {\n      process.stdout.write(Skew.VERSION + '\\n');\n      return null;\n    }\n\n    // Set up the options for the compiler\n    var options = new Skew.CompilerOptions();\n    var releaseFlag = parser.boolForOption(Skew.Option.RELEASE, false);\n    options.foldAllConstants = parser.boolForOption(Skew.Option.FOLD_CONSTANTS, releaseFlag);\n    options.globalizeAllFunctions = parser.boolForOption(Skew.Option.GLOBALIZE_FUNCTIONS, releaseFlag);\n    options.inlineAllFunctions = parser.boolForOption(Skew.Option.INLINE_FUNCTIONS, releaseFlag);\n    options.jsMangle = parser.boolForOption(Skew.Option.JS_MANGLE, releaseFlag);\n    options.jsMinify = parser.boolForOption(Skew.Option.JS_MINIFY, releaseFlag);\n    options.jsSourceMap = parser.boolForOption(Skew.Option.JS_SOURCE_MAP, false);\n    options.stopAfterResolve = parser.boolForOption(Skew.Option.NO_OUTPUT, false);\n    options.verbose = parser.boolForOption(Skew.Option.VERBOSE, false);\n    options.warnAboutIgnoredComments = parser.boolForOption(Skew.Option.IGNORED_COMMENT_WARNING, false);\n    options.warningsAreErrors = parser.boolForOption(Skew.Option.WARNINGS_ARE_ERRORS, false);\n\n    // Prepare the defines\n    if (releaseFlag) {\n      options.define('RELEASE', 'true');\n    }\n\n    for (var i = 0, list = parser.rangeListForOption(Skew.Option.DEFINE), count = list.length; i < count; i = i + 1 | 0) {\n      var range = in_List.get(list, i);\n      var name = range.toString();\n      var equals = name.indexOf('=');\n\n      if (equals < 0) {\n        log.commandLineErrorExpectedDefineValue(range, name);\n        continue;\n      }\n\n      in_StringMap.set(options.defines, in_string.slice2(name, 0, equals), new Skew.Define(range.fromStart(equals), range.fromEnd((name.length - equals | 0) - 1 | 0)));\n    }\n\n    // There must be at least one source file\n    var end = parser.source.contents.length;\n    var trailingSpace = new Skew.Range(parser.source, end - 1 | 0, end);\n\n    if (parser.normalArguments.length == 0 && !options.stopAfterResolve) {\n      log.commandLineErrorNoInputFiles(trailingSpace);\n    }\n\n    // Parse the output location\n    if (!options.stopAfterResolve) {\n      var outputFile = parser.rangeForOption(Skew.Option.OUTPUT_FILE);\n      var outputDirectory = parser.rangeForOption(Skew.Option.OUTPUT_DIRECTORY);\n\n      if (outputFile == null && outputDirectory == null) {\n        log.commandLineErrorMissingOutput(trailingSpace, '--output-file', '--output-dir');\n      }\n\n      else if (outputFile != null && outputDirectory != null) {\n        log.commandLineErrorDuplicateOutput(outputFile.start > outputDirectory.start ? outputFile : outputDirectory, '--output-file', '--output-dir');\n      }\n\n      else if (outputFile != null) {\n        options.outputFile = outputFile.toString();\n      }\n\n      else {\n        options.outputDirectory = outputDirectory.toString();\n      }\n    }\n\n    // Check the target format\n    var target = parser.rangeForOption(Skew.Option.TARGET);\n\n    if (target != null) {\n      options.target = Skew.parseEnum(log, 'target', Skew.VALID_TARGETS, target, null);\n    }\n\n    else if (!options.createTargetFromExtension()) {\n      log.commandLineErrorMissingTarget(trailingSpace);\n    }\n\n    return options;\n  };\n\n  Skew.applyFixes = function(log, applyLog, rangeForSource) {\n    var fixCount = 0;\n\n    // Collect diagnostics by source file\n    var map = new Map();\n\n    for (var i1 = 0, list = log.diagnostics, count = list.length; i1 < count; i1 = i1 + 1 | 0) {\n      var diagnostic = in_List.get(list, i1);\n\n      if (diagnostic.range != null && diagnostic.fixes != null && diagnostic.fixes.length == 1) {\n        var name = diagnostic.range.source.name;\n        var diagnostics = in_StringMap.get(map, name, null);\n\n        if (diagnostics == null) {\n          in_StringMap.set(map, name, diagnostics = []);\n        }\n\n        diagnostics.push(diagnostic);\n      }\n    }\n\n    // Apply for each source file\n    for (var i2 = 0, list1 = Array.from(map.values()), count2 = list1.length; i2 < count2; i2 = i2 + 1 | 0) {\n      var diagnostics1 = in_List.get(list1, i2);\n      var source = in_List.first(diagnostics1).range.source;\n      var contents = source.contents;\n      diagnostics1.sort(function(a, b) {\n        return in_int.compare(b.range.start, a.range.start);\n      });\n\n      // Apply fixes in reverse to avoid issues with changing offsets\n      var last = contents.length;\n\n      for (var i = 0, count1 = diagnostics1.length; i < count1; i = i + 1 | 0) {\n        var fix = in_List.first(in_List.get(diagnostics1, i).fixes);\n\n        // Typo correction isn't robust enough right now to fix automatically\n        if (fix.kind == Skew.FixKind.SYMBOL_TYPO || fix.range.end > last) {\n          continue;\n        }\n\n        contents = in_string.slice2(contents, 0, fix.range.start) + fix.replacement + in_string.slice1(contents, fix.range.end);\n        last = fix.range.start;\n        fixCount = fixCount + 1 | 0;\n      }\n\n      // Write over the source file in place\n      if (!IO.writeFile(source.name, contents)) {\n        applyLog.commandLineErrorUnwritableFile(rangeForSource(source), source.name);\n      }\n    }\n\n    return fixCount;\n  };\n\n  Skew.joinKeys = function(keys) {\n    keys.sort(Skew.SORT_STRINGS);\n    return Skew.PrettyPrint.joinQuoted(keys, 'and');\n  };\n\n  Skew.parseEnum = function(log, name, map, range, defaultValue) {\n    if (range != null) {\n      var key = range.toString();\n\n      if (map.has(key)) {\n        return in_StringMap.get1(map, key);\n      }\n\n      var keys = Array.from(map.keys());\n\n      // Sort so the order is deterministic\n      keys.sort(Skew.SORT_STRINGS);\n      log.commandLineErrorInvalidEnum(range, name, key, keys);\n    }\n\n    return defaultValue;\n  };\n\n  // This is the inner loop from \"flex\", an ancient lexer generator. The output\n  // of flex is pretty bad (obfuscated variable names and the opposite of modular\n  // code) but it's fast and somewhat standard for compiler design. The code below\n  // replaces a simple hand-coded lexer and offers much better performance.\n  Skew.tokenize = function(log, source) {\n    var comments = null;\n    var tokens = [];\n    var text = source.contents;\n    var count = text.length;\n    var previousKind = Skew.TokenKind.NULL;\n    var previousWasComment = false;\n    var stack = [];\n\n    // For backing up\n    var yy_last_accepting_state = 0;\n    var yy_last_accepting_cpos = 0;\n\n    // The current character pointer\n    var yy_cp = 0;\n\n    while (yy_cp < count) {\n      // Reset the NFA\n      var yy_current_state = 1;\n\n      // The pointer to the beginning of the token\n      var yy_bp = yy_cp;\n      var yy_act = Skew.TokenKind.ERROR;\n\n      // Special-case string interpolation\n      var c = in_string.get1(text, yy_cp);\n      var isStringInterpolation = c == 34;\n\n      if (c == 41) {\n        for (var i = stack.length - 1 | 0; i >= 0; i = i - 1 | 0) {\n          var kind = in_List.get(stack, i).kind;\n\n          if (kind == Skew.TokenKind.STRING_INTERPOLATION_START) {\n            isStringInterpolation = true;\n          }\n\n          else if (kind != Skew.TokenKind.LESS_THAN) {\n            break;\n          }\n        }\n      }\n\n      if (isStringInterpolation) {\n        var isExit = c == 41;\n        yy_cp = yy_cp + 1 | 0;\n\n        while (yy_cp < count) {\n          c = in_string.get1(text, (yy_cp = yy_cp + 1 | 0) + -1 | 0);\n\n          if (c == 34) {\n            yy_act = isExit ? Skew.TokenKind.STRING_INTERPOLATION_END : Skew.TokenKind.STRING;\n            break;\n          }\n\n          if (c == 92) {\n            if (yy_cp == count) {\n              break;\n            }\n\n            c = in_string.get1(text, (yy_cp = yy_cp + 1 | 0) + -1 | 0);\n\n            if (c == 40) {\n              yy_act = isExit ? Skew.TokenKind.STRING_INTERPOLATION_CONTINUE : Skew.TokenKind.STRING_INTERPOLATION_START;\n              break;\n            }\n          }\n        }\n      }\n\n      // Special-case XML literals\n      else if (c == 62 && !(stack.length == 0) && in_List.last(stack).kind == Skew.TokenKind.XML_START) {\n        yy_cp = yy_cp + 1 | 0;\n        yy_act = Skew.TokenKind.XML_END;\n      }\n\n      // Search for a match\n      else {\n        while (yy_current_state != Skew.YY_JAM_STATE) {\n          if (yy_cp >= count) {\n            // This prevents syntax errors from causing infinite loops\n            break;\n          }\n\n          c = in_string.get1(text, yy_cp);\n\n          // All of the interesting characters are ASCII\n          var index = c < 127 ? c : 127;\n          var yy_c = in_List.get(Skew.yy_ec, index);\n\n          if (in_List.get(Skew.yy_accept, yy_current_state) != Skew.TokenKind.YY_INVALID_ACTION) {\n            yy_last_accepting_state = yy_current_state;\n            yy_last_accepting_cpos = yy_cp;\n          }\n\n          while (in_List.get(Skew.yy_chk, in_List.get(Skew.yy_base, yy_current_state) + yy_c | 0) != yy_current_state) {\n            yy_current_state = in_List.get(Skew.yy_def, yy_current_state);\n\n            if (yy_current_state >= Skew.YY_ACCEPT_LENGTH) {\n              yy_c = in_List.get(Skew.yy_meta, yy_c);\n            }\n          }\n\n          yy_current_state = in_List.get(Skew.yy_nxt, in_List.get(Skew.yy_base, yy_current_state) + yy_c | 0);\n          yy_cp = yy_cp + 1 | 0;\n        }\n\n        // Find the action\n        yy_act = in_List.get(Skew.yy_accept, yy_current_state);\n\n        while (yy_act == Skew.TokenKind.YY_INVALID_ACTION) {\n          // Have to back up\n          yy_cp = yy_last_accepting_cpos;\n          yy_current_state = yy_last_accepting_state;\n          yy_act = in_List.get(Skew.yy_accept, yy_current_state);\n        }\n\n        // Ignore whitespace\n        if (yy_act == Skew.TokenKind.WHITESPACE) {\n          continue;\n        }\n\n        // Stop at the end of the file\n        if (yy_act == Skew.TokenKind.END_OF_FILE) {\n          break;\n        }\n      }\n\n      // Special-case XML literals\n      if (yy_act == Skew.TokenKind.LESS_THAN && !Skew.FORBID_XML_AFTER.has(previousKind)) {\n        yy_act = Skew.TokenKind.XML_START;\n      }\n\n      // This is the default action in flex, which is usually called ECHO\n      else if (yy_act == Skew.TokenKind.ERROR) {\n        var iterator = Unicode.StringIterator.INSTANCE.reset(text, yy_bp);\n        iterator.nextCodePoint();\n        var range = new Skew.Range(source, yy_bp, iterator.index);\n        log.syntaxErrorExtraData(range, range.toString());\n        break;\n      }\n\n      var token = new Skew.Token(new Skew.Range(source, yy_bp, yy_cp), yy_act, null);\n\n      // Have a nice error message for certain tokens\n      if (yy_act == Skew.TokenKind.COMMENT_ERROR) {\n        log.syntaxErrorSlashComment(token.range);\n        token.kind = Skew.TokenKind.COMMENT;\n      }\n\n      else if (yy_act == Skew.TokenKind.NOT_EQUAL_ERROR) {\n        log.syntaxErrorOperatorTypo(token.range, '!=');\n        token.kind = Skew.TokenKind.NOT_EQUAL;\n      }\n\n      else if (yy_act == Skew.TokenKind.EQUAL_ERROR) {\n        log.syntaxErrorOperatorTypo(token.range, '==');\n        token.kind = Skew.TokenKind.EQUAL;\n      }\n\n      // Tokens that start with a greater than may need to be split, potentially multiple times\n      var loop = true;\n\n      while (loop) {\n        var tokenStartsWithGreaterThan = in_string.get1(text, token.range.start) == 62;\n        var tokenKind = token.kind;\n        loop = false;\n\n        // Remove tokens from the stack if they aren't working out\n        while (!(stack.length == 0)) {\n          var top = in_List.last(stack);\n          var topKind = top.kind;\n\n          // Stop parsing a type if we find a token that no type expression uses\n          if (topKind == Skew.TokenKind.LESS_THAN && tokenKind != Skew.TokenKind.LESS_THAN && tokenKind != Skew.TokenKind.IDENTIFIER && tokenKind != Skew.TokenKind.COMMA && tokenKind != Skew.TokenKind.DYNAMIC && tokenKind != Skew.TokenKind.DOT && tokenKind != Skew.TokenKind.LEFT_PARENTHESIS && tokenKind != Skew.TokenKind.RIGHT_PARENTHESIS && !tokenStartsWithGreaterThan) {\n            in_List.removeLast(stack);\n          }\n\n          else {\n            break;\n          }\n        }\n\n        // Group open\n        if (tokenKind == Skew.TokenKind.LEFT_PARENTHESIS || tokenKind == Skew.TokenKind.LEFT_BRACE || tokenKind == Skew.TokenKind.LEFT_BRACKET || tokenKind == Skew.TokenKind.LESS_THAN || tokenKind == Skew.TokenKind.STRING_INTERPOLATION_START || tokenKind == Skew.TokenKind.XML_START) {\n          stack.push(token);\n        }\n\n        // Group close\n        else if (tokenKind == Skew.TokenKind.RIGHT_PARENTHESIS || tokenKind == Skew.TokenKind.RIGHT_BRACE || tokenKind == Skew.TokenKind.RIGHT_BRACKET || tokenKind == Skew.TokenKind.STRING_INTERPOLATION_END || tokenKind == Skew.TokenKind.XML_END || tokenStartsWithGreaterThan) {\n          // Search for a matching opposite token\n          while (!(stack.length == 0)) {\n            var top1 = in_List.last(stack);\n            var topKind1 = top1.kind;\n\n            // Don't match \">\" that don't work since they are just operators\n            if (tokenStartsWithGreaterThan && topKind1 != Skew.TokenKind.LESS_THAN) {\n              break;\n            }\n\n            // Consume the current token\n            in_List.removeLast(stack);\n\n            // Stop if it's a match\n            if (tokenKind == Skew.TokenKind.RIGHT_PARENTHESIS && topKind1 == Skew.TokenKind.LEFT_PARENTHESIS || tokenKind == Skew.TokenKind.RIGHT_BRACKET && topKind1 == Skew.TokenKind.LEFT_BRACKET || tokenKind == Skew.TokenKind.RIGHT_BRACE && topKind1 == Skew.TokenKind.LEFT_BRACE || tokenKind == Skew.TokenKind.STRING_INTERPOLATION_END && topKind1 == Skew.TokenKind.STRING_INTERPOLATION_START) {\n              break;\n            }\n\n            // Special-case angle brackets matches and ignore tentative matches that didn't work out\n            if (topKind1 == Skew.TokenKind.LESS_THAN && tokenStartsWithGreaterThan) {\n              // Break apart operators that start with a closing angle bracket\n              if (tokenKind != Skew.TokenKind.GREATER_THAN) {\n                var start = token.range.start;\n                tokens.push(new Skew.Token(new Skew.Range(source, start, start + 1 | 0), Skew.TokenKind.PARAMETER_LIST_END, null));\n                token.range = new Skew.Range(source, start + 1 | 0, token.range.end);\n                token.kind = tokenKind == Skew.TokenKind.SHIFT_RIGHT ? Skew.TokenKind.GREATER_THAN : tokenKind == Skew.TokenKind.UNSIGNED_SHIFT_RIGHT ? Skew.TokenKind.SHIFT_RIGHT : tokenKind == Skew.TokenKind.GREATER_THAN_OR_EQUAL ? Skew.TokenKind.ASSIGN : tokenKind == Skew.TokenKind.ASSIGN_SHIFT_RIGHT ? Skew.TokenKind.GREATER_THAN_OR_EQUAL : tokenKind == Skew.TokenKind.ASSIGN_UNSIGNED_SHIFT_RIGHT ? Skew.TokenKind.ASSIGN_SHIFT_RIGHT : Skew.TokenKind.NULL;\n                assert(token.kind != Skew.TokenKind.NULL);\n\n                // Split this token again\n                loop = tokenKind != Skew.TokenKind.GREATER_THAN_OR_EQUAL;\n              }\n\n              else {\n                token.kind = Skew.TokenKind.PARAMETER_LIST_END;\n              }\n\n              // Convert the \"<\" into a bound for type parameter lists\n              top1.kind = Skew.TokenKind.PARAMETER_LIST_START;\n\n              // Stop the search since we found a match\n              break;\n            }\n          }\n        }\n      }\n\n      // Remove newlines based on the previous token to enable line continuations.\n      // Make sure to be conservative. We want to be like Python, not like\n      // JavaScript ASI! Anything that is at all ambiguous should be disallowed.\n      //\n      // Examples:\n      // - \"var x = 0 \\n .toString\"\n      // - \"var x = 0 # comment \\n .toString\"\n      // - \"var x = 0 \\n # comment \\n .toString\"\n      // - \"var x = 0 \\n ### \\n multi-line comment \\n ### \\n return 0\"\n      //\n      if (previousKind == Skew.TokenKind.NEWLINE && token.kind == Skew.TokenKind.NEWLINE) {\n        if (comments != null && !previousWasComment) {\n          in_List.last(comments).hasGapBelow = true;\n        }\n\n        previousWasComment = false;\n        continue;\n      }\n\n      else if (previousKind == Skew.TokenKind.NEWLINE && Skew.REMOVE_WHITESPACE_BEFORE.has(token.kind)) {\n        var last = in_List.takeLast(tokens);\n\n        if (last.comments != null) {\n          if (comments == null) {\n            comments = [];\n          }\n\n          in_List.append1(comments, last.comments);\n        }\n      }\n\n      // Attach comments to tokens instead of having comments be tokens\n      previousWasComment = token.kind == Skew.TokenKind.COMMENT;\n\n      if (previousWasComment) {\n        if (comments == null) {\n          comments = [];\n        }\n\n        if (comments.length == 0 || in_List.last(comments).hasGapBelow) {\n          comments.push(new Skew.Comment(token.range, [], false, false));\n        }\n\n        var range1 = token.range;\n        var line = in_string.slice2(source.contents, range1.start + 1 | 0, range1.end);\n        var hashes = 0;\n\n        for (var j = 0, count1 = line.length; j < count1; j = j + 1 | 0) {\n          if (in_string.get1(line, j) != 35) {\n            break;\n          }\n\n          hashes = hashes + 1 | 0;\n        }\n\n        if (hashes != 0) {\n          line = in_string.repeat('/', hashes) + in_string.slice1(line, hashes);\n        }\n\n        in_List.last(comments).lines.push(line);\n        continue;\n      }\n\n      previousKind = token.kind;\n\n      if (previousKind != Skew.TokenKind.NEWLINE) {\n        token.comments = comments;\n        comments = null;\n      }\n\n      // Capture trailing comments\n      if (!(tokens.length == 0) && comments != null && comments.length == 1 && in_List.first(comments).lines.length == 1 && !in_List.first(comments).hasGapBelow) {\n        in_List.first(comments).isTrailing = true;\n        token.comments = comments;\n        comments = null;\n      }\n\n      // Accumulate the token for this iteration\n      tokens.push(token);\n    }\n\n    // Every token stream ends in END_OF_FILE\n    tokens.push(new Skew.Token(new Skew.Range(source, yy_cp, yy_cp), Skew.TokenKind.END_OF_FILE, comments));\n\n    // Also return preprocessor token presence so the preprocessor can be avoided\n    return tokens;\n  };\n\n  // Remove all code that isn't reachable from the entry point or from an\n  // imported or exported symbol. This is called tree shaking here but is also\n  // known as dead code elimination. Tree shaking is perhaps a better name\n  // because this pass doesn't remove dead code inside functions.\n  Skew.shakingPass = function(global, entryPoint, mode) {\n    var graph = new Skew.UsageGraph(global, mode);\n    var symbols = [];\n    Skew.Shaking.collectExportedSymbols(global, symbols, entryPoint);\n    var usages = graph.usagesForSymbols(symbols);\n\n    if (usages != null) {\n      Skew.Shaking.removeUnusedSymbols(global, usages);\n    }\n  };\n\n  Skew.compile = function(log, options, inputs) {\n    inputs = inputs.slice();\n    options.target.includeSources(inputs);\n    options.target.editOptions(options);\n    inputs.unshift(new Skew.Source('<unicode>', Skew.UNICODE_LIBRARY));\n    inputs.unshift(new Skew.Source('<native>', Skew.NATIVE_LIBRARY));\n    var context = new Skew.PassContext(log, options, inputs);\n    var passTimers = [];\n    var totalTimer = new Skew.Timer();\n    totalTimer.start();\n\n    // Run all passes, stop compilation if there are errors after resolving (wait until then to make IDE mode better)\n    for (var i = 0, list = options.passes, count = list.length; i < count; i = i + 1 | 0) {\n      var pass = in_List.get(list, i);\n\n      if (context.isResolvePassComplete && log.hasErrors()) {\n        break;\n      }\n\n      if (pass.shouldRun()) {\n        var passTimer = new Skew.PassTimer(pass.kind());\n        passTimers.push(passTimer);\n        passTimer.timer.start();\n        pass.run(context);\n        passTimer.timer.stop();\n        context.verify();\n      }\n    }\n\n    totalTimer.stop();\n    return new Skew.CompilerResult(context.cache, context.global, context.outputs, passTimers, totalTimer);\n  };\n\n  Skew.SORT_STRINGS = function(a, b) {\n    return in_string.compare(a, b);\n  };\n\n  Skew.PassKind = {\n    EMITTING: 0,\n    LEXING: 1,\n    PARSING: 2,\n    RESOLVING: 3,\n    LAMBDA_CONVERSION: 4,\n    CALL_GRAPH: 5,\n    INLINING: 6,\n    FOLDING: 7,\n    MOTION: 8,\n    GLOBALIZING: 9,\n    MERGING: 10,\n    INTERFACE_REMOVAL: 11,\n    RENAMING: 12\n  };\n\n  Skew.EmitMode = {\n    ALWAYS_EMIT: 0,\n    SKIP_IF_EMPTY: 1\n  };\n\n  Skew.Emitter = function() {\n    this._sources = [];\n    this._prefix = new StringBuilder();\n    this._code = new StringBuilder();\n    this._indentAmount = '  ';\n    this._indent = '';\n  };\n\n  Skew.Emitter.prototype.sources = function() {\n    return this._sources;\n  };\n\n  Skew.Emitter.prototype._increaseIndent = function() {\n    this._indent += this._indentAmount;\n  };\n\n  Skew.Emitter.prototype._decreaseIndent = function() {\n    this._indent = in_string.slice1(this._indent, this._indentAmount.length);\n  };\n\n  Skew.Emitter.prototype._emit = function(text) {\n    this._code.buffer += text;\n  };\n\n  Skew.Emitter.prototype._emitPrefix = function(text) {\n    this._prefix.buffer += text;\n  };\n\n  Skew.Emitter.prototype._createSource = function(name, mode) {\n    var code = this._code.buffer;\n\n    if (mode == Skew.EmitMode.ALWAYS_EMIT || code != '') {\n      this._prefix.buffer += code;\n      this._sources.push(new Skew.Source(name, this._prefix.buffer));\n    }\n\n    this._prefix = new StringBuilder();\n    this._code = new StringBuilder();\n  };\n\n  Skew.Emitter.prototype._collectObjects = function(global) {\n    var objects = [];\n    this._findObjects(objects, global);\n    return objects;\n  };\n\n  Skew.Emitter.prototype._sortedObjects = function(global) {\n    var objects = this._collectObjects(global);\n\n    // Sort by inheritance and containment\n    for (var i = 0, count = objects.length; i < count; i = i + 1 | 0) {\n      var j = i;\n\n      // Select an object that comes before all other types\n      while (j < objects.length) {\n        var object = in_List.get(objects, j);\n        var k = i;\n\n        // Check to see if this comes before all other types\n        while (k < objects.length) {\n          if (j != k && Skew.Emitter._objectComesBefore(in_List.get(objects, k), object)) {\n            break;\n          }\n\n          k = k + 1 | 0;\n        }\n\n        if (k == objects.length) {\n          break;\n        }\n\n        j = j + 1 | 0;\n      }\n\n      // Swap the object into the correct order\n      if (j < objects.length) {\n        in_List.swap(objects, i, j);\n      }\n    }\n\n    return objects;\n  };\n\n  Skew.Emitter.prototype._markVirtualFunctions = function(symbol) {\n    for (var i = 0, list = symbol.objects, count = list.length; i < count; i = i + 1 | 0) {\n      var object = in_List.get(list, i);\n      this._markVirtualFunctions(object);\n    }\n\n    for (var i2 = 0, list2 = symbol.functions, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n      var $function = in_List.get(list2, i2);\n\n      if ($function.overridden != null) {\n        $function.overridden.flags |= Skew.SymbolFlags.IS_VIRTUAL;\n        $function.flags |= Skew.SymbolFlags.IS_VIRTUAL;\n      }\n\n      if ($function.implementations != null) {\n        for (var i1 = 0, list1 = $function.implementations, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n          var other = in_List.get(list1, i1);\n          other.flags |= Skew.SymbolFlags.IS_VIRTUAL;\n          $function.flags |= Skew.SymbolFlags.IS_VIRTUAL;\n        }\n      }\n    }\n  };\n\n  Skew.Emitter.prototype._findObjects = function(objects, object) {\n    objects.push(object);\n\n    for (var i = 0, list = object.objects, count = list.length; i < count; i = i + 1 | 0) {\n      var o = in_List.get(list, i);\n      this._findObjects(objects, o);\n    }\n  };\n\n  Skew.Emitter._isContainedBy = function(inner, outer) {\n    if (inner.parent == null) {\n      return false;\n    }\n\n    if (inner.parent == outer) {\n      return true;\n    }\n\n    return Skew.Emitter._isContainedBy(inner.parent.asObjectSymbol(), outer);\n  };\n\n  Skew.Emitter._objectComesBefore = function(before, after) {\n    return after.hasBaseClass(before) || after.hasInterface(before) || Skew.Emitter._isContainedBy(after, before) || after.forwardTo == before;\n  };\n\n  // These dump() functions are helpful for debugging syntax trees\n  Skew.LispTreeEmitter = function(_options) {\n    Skew.Emitter.call(this);\n    this._options = _options;\n  };\n\n  __extends(Skew.LispTreeEmitter, Skew.Emitter);\n\n  Skew.LispTreeEmitter.prototype.visit = function(global) {\n    this._visitObject(global);\n    this._emit('\\n');\n    this._createSource(this._options.outputDirectory != null ? this._options.outputDirectory + '/compiled.lisp' : this._options.outputFile, Skew.EmitMode.ALWAYS_EMIT);\n  };\n\n  Skew.LispTreeEmitter.prototype._visitObject = function(symbol) {\n    this._emit('(' + this._mangleKind(in_List.get(Skew.in_SymbolKind._strings, symbol.kind)) + ' ' + Skew.quoteString(symbol.name, Skew.QuoteStyle.DOUBLE, Skew.QuoteOctal.OCTAL_WORKAROUND));\n    this._increaseIndent();\n\n    for (var i = 0, list = symbol.objects, count = list.length; i < count; i = i + 1 | 0) {\n      var object = in_List.get(list, i);\n      this._emit('\\n' + this._indent);\n      this._visitObject(object);\n    }\n\n    for (var i1 = 0, list1 = symbol.functions, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n      var $function = in_List.get(list1, i1);\n      this._emit('\\n' + this._indent);\n      this._visitFunction($function);\n    }\n\n    for (var i2 = 0, list2 = symbol.variables, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n      var variable = in_List.get(list2, i2);\n      this._emit('\\n' + this._indent);\n      this._visitVariable(variable);\n    }\n\n    this._decreaseIndent();\n    this._emit(')');\n  };\n\n  Skew.LispTreeEmitter.prototype._visitFunction = function(symbol) {\n    this._emit('(' + this._mangleKind(in_List.get(Skew.in_SymbolKind._strings, symbol.kind)) + ' ' + Skew.quoteString(symbol.name, Skew.QuoteStyle.DOUBLE, Skew.QuoteOctal.OCTAL_WORKAROUND));\n    this._increaseIndent();\n\n    for (var i = 0, list = symbol.$arguments, count = list.length; i < count; i = i + 1 | 0) {\n      var argument = in_List.get(list, i);\n      this._emit('\\n' + this._indent);\n      this._visitVariable(argument);\n    }\n\n    this._emit('\\n' + this._indent);\n    this._visitNode(symbol.returnType);\n    this._emit('\\n' + this._indent);\n    this._visitNode(symbol.block);\n    this._decreaseIndent();\n    this._emit(')');\n  };\n\n  Skew.LispTreeEmitter.prototype._visitVariable = function(symbol) {\n    this._emit('(' + this._mangleKind(in_List.get(Skew.in_SymbolKind._strings, symbol.kind)) + ' ' + Skew.quoteString(symbol.name, Skew.QuoteStyle.DOUBLE, Skew.QuoteOctal.OCTAL_WORKAROUND) + ' ');\n    this._visitNode(symbol.type);\n    this._emit(' ');\n    this._visitNode(symbol.value);\n    this._emit(')');\n  };\n\n  Skew.LispTreeEmitter.prototype._visitNode = function(node) {\n    if (node == null) {\n      this._emit('nil');\n      return;\n    }\n\n    this._emit('(' + this._mangleKind(in_List.get(Skew.in_NodeKind._strings, node.kind)));\n    var content = node.content;\n\n    if (content != null) {\n      switch (content.kind()) {\n        case Skew.ContentKind.INT: {\n          this._emit(' ' + Skew.in_Content.asInt(content).toString());\n          break;\n        }\n\n        case Skew.ContentKind.BOOL: {\n          this._emit(' ' + Skew.in_Content.asBool(content).toString());\n          break;\n        }\n\n        case Skew.ContentKind.DOUBLE: {\n          this._emit(' ' + Skew.in_Content.asDouble(content).toString());\n          break;\n        }\n\n        case Skew.ContentKind.STRING: {\n          this._emit(' ' + Skew.quoteString(Skew.in_Content.asString(content), Skew.QuoteStyle.DOUBLE, Skew.QuoteOctal.OCTAL_WORKAROUND));\n          break;\n        }\n      }\n    }\n\n    if (node.kind == Skew.NodeKind.VARIABLE) {\n      this._emit(' ');\n      this._visitVariable(node.symbol.asVariableSymbol());\n    }\n\n    else if (node.kind == Skew.NodeKind.LAMBDA) {\n      this._emit(' ');\n      this._visitFunction(node.symbol.asFunctionSymbol());\n    }\n\n    else if (node.hasChildren()) {\n      this._increaseIndent();\n\n      for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n        this._emit('\\n' + this._indent);\n        this._visitNode(child);\n      }\n\n      this._decreaseIndent();\n    }\n\n    this._emit(')');\n  };\n\n  Skew.LispTreeEmitter.prototype._mangleKind = function(kind) {\n    return kind.toLowerCase().split('_').join('-');\n  };\n\n  Skew.CSharpEmitter = function(_options, _cache) {\n    Skew.Emitter.call(this);\n    this._options = _options;\n    this._cache = _cache;\n    this._previousNode = null;\n    this._previousSymbol = null;\n    this._namespaceStack = [];\n    this._symbolsCheckedForUsing = new Map();\n    this._usingNames = new Map();\n    this._loopLabels = new Map();\n    this._enclosingFunction = null;\n  };\n\n  __extends(Skew.CSharpEmitter, Skew.Emitter);\n\n  Skew.CSharpEmitter.prototype.visit = function(global) {\n    this._indentAmount = '    ';\n    this._moveGlobalsIntoClasses(global);\n\n    // Generate the entry point\n    var entryPoint = this._cache.entryPointSymbol;\n\n    if (entryPoint != null) {\n      entryPoint.name = 'Main';\n\n      // The entry point in C# takes an array, not a list\n      if (entryPoint.$arguments.length == 1) {\n        var argument = in_List.first(entryPoint.$arguments);\n        var array = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_ARGUMENT, argument.name);\n        array.type = new Skew.Node(Skew.NodeKind.NAME).withContent(new Skew.StringContent('string[]')).withType(Skew.Type.DYNAMIC);\n        array.resolvedType = Skew.Type.DYNAMIC;\n        entryPoint.$arguments = [array];\n        entryPoint.resolvedType.argumentTypes = [array.resolvedType];\n\n        // Create the list from the array\n        if (entryPoint.block != null) {\n          array.name = entryPoint.scope.generateName(array.name);\n          argument.kind = Skew.SymbolKind.VARIABLE_LOCAL;\n          argument.value = Skew.Node.createCall(new Skew.Node(Skew.NodeKind.DOT).withContent(new Skew.StringContent('new')).appendChild(new Skew.Node(Skew.NodeKind.TYPE).withType(argument.resolvedType)).withType(Skew.Type.DYNAMIC)).withType(Skew.Type.DYNAMIC).appendChild(Skew.Node.createSymbolReference(array));\n          entryPoint.block.prependChild(new Skew.Node(Skew.NodeKind.VARIABLES).appendChild(Skew.Node.createVariable(argument)));\n        }\n      }\n    }\n\n    // Avoid emitting unnecessary stuff\n    Skew.shakingPass(global, entryPoint, Skew.ShakingMode.USE_TYPES);\n    this._markVirtualFunctions(global);\n    var emitIndividualFiles = this._options.outputDirectory != null;\n    var objects = this._collectObjects(global);\n\n    for (var i1 = 0, list1 = objects, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n      var object = in_List.get(list1, i1);\n\n      // Convert \"flags\" types to wrapped types\n      if (object.kind == Skew.SymbolKind.OBJECT_FLAGS) {\n        object.kind = Skew.SymbolKind.OBJECT_WRAPPED;\n        object.wrappedType = this._cache.intType;\n\n        // Enum values become normal global variables\n        for (var i = 0, list = object.variables, count = list.length; i < count; i = i + 1 | 0) {\n          var variable = in_List.get(list, i);\n\n          if (variable.kind == Skew.SymbolKind.VARIABLE_ENUM_OR_FLAGS) {\n            variable.kind = Skew.SymbolKind.VARIABLE_GLOBAL;\n            variable.flags |= Skew.SymbolFlags.IS_CSHARP_CONST;\n          }\n        }\n      }\n    }\n\n    // All code in C# is inside objects, so just emit objects recursively\n    for (var i2 = 0, list2 = objects, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n      var object1 = in_List.get(list2, i2);\n\n      // Nested objects will be emitted by their parent\n      if (object1.parent != null && object1.parent.kind == Skew.SymbolKind.OBJECT_CLASS) {\n        continue;\n      }\n\n      this._emitObject(object1);\n\n      // Emit each object into its own file if requested\n      if (emitIndividualFiles) {\n        this._finalizeEmittedFile();\n        this._createSource(this._options.outputDirectory + '/' + Skew.CSharpEmitter._fullName(object1) + '.cs', Skew.EmitMode.SKIP_IF_EMPTY);\n      }\n    }\n\n    // Emit a single file if requested\n    if (!emitIndividualFiles) {\n      this._finalizeEmittedFile();\n      this._createSource(this._options.outputFile, Skew.EmitMode.ALWAYS_EMIT);\n    }\n  };\n\n  Skew.CSharpEmitter.prototype._moveGlobalsIntoClasses = function(symbol) {\n    if (!Skew.in_SymbolKind.isNamespaceOrGlobal(symbol.kind)) {\n      return;\n    }\n\n    // Just change namespaces into classes if there aren't nested objects\n    if (symbol.kind == Skew.SymbolKind.OBJECT_NAMESPACE && symbol.objects.length == 0 && (!(symbol.functions.length == 0) || !(symbol.variables.length == 0))) {\n      symbol.kind = Skew.SymbolKind.OBJECT_CLASS;\n      return;\n    }\n\n    var globals = null;\n    var lazilyCreateGlobals = function() {\n      if (globals == null) {\n        globals = new Skew.ObjectSymbol(Skew.SymbolKind.OBJECT_CLASS, symbol.scope.generateName(symbol.kind == Skew.SymbolKind.OBJECT_NAMESPACE ? symbol.name + 'Globals' : 'Globals'));\n        globals.resolvedType = new Skew.Type(Skew.TypeKind.SYMBOL, globals);\n        globals.state = Skew.SymbolState.INITIALIZED;\n        globals.parent = symbol;\n        symbol.objects.push(globals);\n      }\n    };\n\n    for (var i = 0, list = symbol.objects, count = list.length; i < count; i = i + 1 | 0) {\n      var object = in_List.get(list, i);\n      this._moveGlobalsIntoClasses(object);\n    }\n\n    in_List.removeIf(symbol.functions, function($function) {\n      if ($function.kind != Skew.SymbolKind.FUNCTION_ANNOTATION && !$function.isImported()) {\n        lazilyCreateGlobals();\n        $function.parent = globals;\n        globals.functions.push($function);\n        return true;\n      }\n\n      return false;\n    });\n    in_List.removeIf(symbol.variables, function(variable) {\n      if (variable.kind == Skew.SymbolKind.VARIABLE_GLOBAL && !variable.isImported()) {\n        lazilyCreateGlobals();\n        variable.parent = globals;\n        globals.variables.push(variable);\n        return true;\n      }\n\n      return false;\n    });\n  };\n\n  Skew.CSharpEmitter.prototype._adjustNamespace = function(symbol) {\n    // Get the namespace chain for this symbol\n    var symbols = [];\n\n    while (symbol != null && symbol.kind != Skew.SymbolKind.OBJECT_GLOBAL) {\n      if (symbol.kind == Skew.SymbolKind.OBJECT_NAMESPACE) {\n        symbols.unshift(symbol);\n      }\n\n      symbol = symbol.parent;\n    }\n\n    // Find the intersection\n    var limit = Math.min(this._namespaceStack.length, symbols.length);\n    var i = 0;\n\n    while (i < limit) {\n      if (in_List.get(this._namespaceStack, i) != in_List.get(symbols, i)) {\n        break;\n      }\n\n      i = i + 1 | 0;\n    }\n\n    // Leave the old namespace\n    while (this._namespaceStack.length > i) {\n      var object = in_List.takeLast(this._namespaceStack);\n      this._decreaseIndent();\n      this._emit(this._indent + '}\\n');\n      this._emitNewlineAfterSymbol(object);\n    }\n\n    // Enter the new namespace\n    while (this._namespaceStack.length < symbols.length) {\n      var object1 = in_List.get(symbols, this._namespaceStack.length);\n      this._emitNewlineBeforeSymbol(object1);\n      this._emit(this._indent + 'namespace ' + Skew.CSharpEmitter._mangleName(object1) + '\\n');\n      this._emit(this._indent + '{\\n');\n      this._increaseIndent();\n      this._namespaceStack.push(object1);\n    }\n  };\n\n  Skew.CSharpEmitter.prototype._finalizeEmittedFile = function() {\n    var usings = Array.from(this._usingNames.keys());\n\n    if (!(usings.length == 0)) {\n      // Sort so the order is deterministic\n      usings.sort(Skew.SORT_STRINGS);\n\n      for (var i = 0, list = usings, count = list.length; i < count; i = i + 1 | 0) {\n        var using = in_List.get(list, i);\n        this._emitPrefix('using ' + using + ';\\n');\n      }\n\n      this._emitPrefix('\\n');\n    }\n\n    this._adjustNamespace(null);\n    this._previousSymbol = null;\n    this._symbolsCheckedForUsing = new Map();\n    this._usingNames = new Map();\n  };\n\n  Skew.CSharpEmitter.prototype._handleSymbol = function(symbol) {\n    if (!Skew.in_SymbolKind.isLocal(symbol.kind) && !this._symbolsCheckedForUsing.has(symbol.id)) {\n      in_IntMap.set(this._symbolsCheckedForUsing, symbol.id, 0);\n\n      if (symbol.annotations != null) {\n        for (var i = 0, list = symbol.annotations, count = list.length; i < count; i = i + 1 | 0) {\n          var annotation = in_List.get(list, i);\n\n          if (annotation.symbol != null && annotation.symbol.fullName() == 'using') {\n            var value = annotation.annotationValue();\n\n            if (value.childCount() == 2) {\n              in_StringMap.set(this._usingNames, value.lastChild().asString(), 0);\n            }\n          }\n        }\n      }\n\n      if (symbol.parent != null) {\n        this._handleSymbol(symbol.parent);\n      }\n    }\n  };\n\n  Skew.CSharpEmitter.prototype._emitNewlineBeforeSymbol = function(symbol) {\n    if (this._previousSymbol != null && (!Skew.in_SymbolKind.isVariable(this._previousSymbol.kind) || !Skew.in_SymbolKind.isVariable(symbol.kind) || symbol.comments != null)) {\n      this._emit('\\n');\n    }\n\n    this._previousSymbol = null;\n  };\n\n  Skew.CSharpEmitter.prototype._emitNewlineAfterSymbol = function(symbol) {\n    this._previousSymbol = symbol;\n  };\n\n  Skew.CSharpEmitter.prototype._emitNewlineBeforeStatement = function(node) {\n    if (this._previousNode != null && (node.comments != null || !Skew.CSharpEmitter._isCompactNodeKind(this._previousNode.kind) || !Skew.CSharpEmitter._isCompactNodeKind(node.kind))) {\n      this._emit('\\n');\n    }\n\n    this._previousNode = null;\n  };\n\n  Skew.CSharpEmitter.prototype._emitNewlineAfterStatement = function(node) {\n    this._previousNode = node;\n  };\n\n  Skew.CSharpEmitter.prototype._emitComments = function(comments) {\n    if (comments != null) {\n      for (var i1 = 0, list1 = comments, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n        var comment = in_List.get(list1, i1);\n\n        for (var i = 0, list = comment.lines, count = list.length; i < count; i = i + 1 | 0) {\n          var line = in_List.get(list, i);\n          this._emit(this._indent + '//' + line + '\\n');\n        }\n\n        if (comment.hasGapBelow) {\n          this._emit('\\n');\n        }\n      }\n    }\n  };\n\n  Skew.CSharpEmitter.prototype._emitObject = function(symbol) {\n    this._handleSymbol(symbol);\n\n    if (symbol.isImported() || Skew.in_SymbolKind.isNamespaceOrGlobal(symbol.kind)) {\n      return;\n    }\n\n    this._adjustNamespace(symbol);\n    this._emitNewlineBeforeSymbol(symbol);\n    this._emitComments(symbol.comments);\n    this._emit(this._indent + 'public ');\n\n    if (symbol.isAbstract()) {\n      this._emit('abstract ');\n    }\n\n    switch (symbol.kind) {\n      case Skew.SymbolKind.OBJECT_CLASS: {\n        this._emit('class ');\n        break;\n      }\n\n      case Skew.SymbolKind.OBJECT_ENUM:\n      case Skew.SymbolKind.OBJECT_FLAGS: {\n        this._emit('enum ');\n        break;\n      }\n\n      case Skew.SymbolKind.OBJECT_INTERFACE: {\n        this._emit('interface ');\n        break;\n      }\n\n      case Skew.SymbolKind.OBJECT_WRAPPED:\n      case Skew.SymbolKind.OBJECT_NAMESPACE: {\n        this._emit('static class ');\n        break;\n      }\n\n      default: {\n        assert(false);\n        break;\n      }\n    }\n\n    this._emit(Skew.CSharpEmitter._mangleName(symbol));\n    this._emitTypeParameters(symbol.parameters);\n\n    if ((symbol.$extends != null || symbol.$implements != null) && symbol.kind != Skew.SymbolKind.OBJECT_WRAPPED) {\n      this._emit(' : ');\n\n      if (symbol.$extends != null) {\n        this._emitExpressionOrType(symbol.$extends, symbol.baseType);\n      }\n\n      if (symbol.$implements != null) {\n        for (var i = 0, list = symbol.$implements, count = list.length; i < count; i = i + 1 | 0) {\n          var node = in_List.get(list, i);\n\n          if (node != in_List.first(symbol.$implements) || symbol.$extends != null) {\n            this._emit(', ');\n          }\n\n          this._emitExpressionOrType(node, node.resolvedType);\n        }\n      }\n    }\n\n    this._emit('\\n' + this._indent + '{\\n');\n    this._increaseIndent();\n\n    for (var i1 = 0, list1 = symbol.objects, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n      var object = in_List.get(list1, i1);\n      this._emitObject(object);\n    }\n\n    for (var i2 = 0, list2 = symbol.variables, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n      var variable = in_List.get(list2, i2);\n      this._emitVariable(variable);\n    }\n\n    for (var i3 = 0, list3 = symbol.functions, count3 = list3.length; i3 < count3; i3 = i3 + 1 | 0) {\n      var $function = in_List.get(list3, i3);\n      this._emitFunction($function);\n    }\n\n    this._decreaseIndent();\n    this._emit(this._indent + '}\\n');\n    this._emitNewlineAfterSymbol(symbol);\n  };\n\n  Skew.CSharpEmitter.prototype._emitTypeParameters = function(parameters) {\n    if (parameters != null) {\n      this._emit('<');\n\n      for (var i = 0, list = parameters, count = list.length; i < count; i = i + 1 | 0) {\n        var parameter = in_List.get(list, i);\n\n        if (parameter != in_List.first(parameters)) {\n          this._emit(', ');\n        }\n\n        this._emit(Skew.CSharpEmitter._mangleName(parameter));\n      }\n\n      this._emit('>');\n    }\n  };\n\n  Skew.CSharpEmitter.prototype._emitArgumentList = function(symbol) {\n    this._emit('(');\n\n    for (var i = 0, list = symbol.$arguments, count = list.length; i < count; i = i + 1 | 0) {\n      var argument = in_List.get(list, i);\n\n      if (argument != in_List.first(symbol.$arguments)) {\n        this._emit(', ');\n      }\n\n      this._emitExpressionOrType(argument.type, argument.resolvedType);\n      this._emit(' ' + Skew.CSharpEmitter._mangleName(argument));\n    }\n\n    this._emit(')');\n  };\n\n  Skew.CSharpEmitter.prototype._emitVariable = function(symbol) {\n    this._handleSymbol(symbol);\n\n    if (symbol.isImported()) {\n      return;\n    }\n\n    this._emitNewlineBeforeSymbol(symbol);\n    this._emitComments(symbol.comments);\n\n    if (symbol.kind == Skew.SymbolKind.VARIABLE_ENUM_OR_FLAGS) {\n      this._emit(this._indent + Skew.CSharpEmitter._mangleName(symbol));\n\n      if (symbol.value != null) {\n        // Enum values are initialized with integers\n        symbol.value.resolvedType = this._cache.intType;\n        this._emit(' = ');\n        this._emitExpression(symbol.value, Skew.Precedence.COMMA);\n      }\n\n      this._emit(',\\n');\n    }\n\n    else {\n      this._emit(this._indent + 'public ');\n\n      if (symbol.kind == Skew.SymbolKind.VARIABLE_GLOBAL) {\n        this._emit(symbol.isCSharpConst() ? 'const ' : 'static ');\n      }\n\n      this._emitExpressionOrType(symbol.type, symbol.resolvedType);\n      this._emit(' ' + Skew.CSharpEmitter._mangleName(symbol));\n\n      if (symbol.value != null) {\n        this._emit(' = ');\n        this._emitExpression(symbol.value, Skew.Precedence.COMMA);\n      }\n\n      this._emit(';\\n');\n    }\n\n    this._emitNewlineAfterSymbol(symbol);\n  };\n\n  Skew.CSharpEmitter.prototype._emitFunction = function(symbol) {\n    this._handleSymbol(symbol);\n\n    if (symbol.isImported()) {\n      return;\n    }\n\n    // C# has sane capture rules for \"this\" so no variable insertion is needed\n    if (symbol.$this != null) {\n      symbol.$this.name = 'this';\n      symbol.$this.flags |= Skew.SymbolFlags.IS_EXPORTED;\n    }\n\n    this._enclosingFunction = symbol;\n    this._emitNewlineBeforeSymbol(symbol);\n    this._emitComments(symbol.comments);\n    this._emit(this._indent);\n\n    if (symbol.parent.kind != Skew.SymbolKind.OBJECT_INTERFACE) {\n      this._emit('public ');\n    }\n\n    if (symbol.kind == Skew.SymbolKind.FUNCTION_GLOBAL) {\n      this._emit('static ');\n    }\n\n    if (symbol.kind != Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n      if (symbol.parent.kind != Skew.SymbolKind.OBJECT_INTERFACE) {\n        if (symbol.block == null) {\n          this._emit('abstract ');\n        }\n\n        else if (symbol.overridden != null) {\n          this._emit('override ');\n        }\n\n        else if (symbol.isVirtual()) {\n          this._emit('virtual ');\n        }\n      }\n\n      this._emitExpressionOrType(symbol.returnType, symbol.resolvedType.returnType);\n      this._emit(' ');\n    }\n\n    this._emit(Skew.CSharpEmitter._mangleName(symbol));\n    this._emitTypeParameters(symbol.parameters);\n    this._emitArgumentList(symbol);\n    var block = symbol.block;\n\n    if (block == null) {\n      this._emit(';\\n');\n    }\n\n    else {\n      // Move the super constructor call out of the function body\n      if (symbol.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR && block.hasChildren()) {\n        var first = block.firstChild();\n\n        if (first.kind == Skew.NodeKind.EXPRESSION) {\n          var call = first.expressionValue();\n\n          if (call.kind == Skew.NodeKind.CALL && call.callValue().kind == Skew.NodeKind.SUPER) {\n            this._emit(' : ');\n            first.remove();\n            this._emitExpression(call, Skew.Precedence.LOWEST);\n          }\n        }\n      }\n\n      this._emit('\\n');\n      this._emitBlock(block);\n      this._emit('\\n');\n    }\n\n    this._emitNewlineAfterSymbol(symbol);\n    this._enclosingFunction = null;\n  };\n\n  Skew.CSharpEmitter.prototype._emitType = function(type) {\n    if (type == null) {\n      this._emit('void');\n      return;\n    }\n\n    type = this._cache.unwrappedType(type);\n\n    if (type == Skew.Type.DYNAMIC) {\n      this._emit('dynamic');\n    }\n\n    else if (type.kind == Skew.TypeKind.LAMBDA) {\n      var argumentTypes = type.argumentTypes;\n      var returnType = type.returnType;\n      this._emit(returnType != null ? 'System.Func' : 'System.Action');\n\n      if (!(argumentTypes.length == 0) || returnType != null) {\n        this._emit('<');\n\n        for (var i = 0, count = argumentTypes.length; i < count; i = i + 1 | 0) {\n          if (i != 0) {\n            this._emit(', ');\n          }\n\n          this._emitType(in_List.get(argumentTypes, i));\n        }\n\n        if (returnType != null) {\n          if (!(argumentTypes.length == 0)) {\n            this._emit(', ');\n          }\n\n          this._emitType(returnType);\n        }\n\n        this._emit('>');\n      }\n    }\n\n    else {\n      assert(type.kind == Skew.TypeKind.SYMBOL);\n      this._handleSymbol(type.symbol);\n      this._emit(Skew.CSharpEmitter._fullName(type.symbol));\n\n      if (type.isParameterized()) {\n        this._emit('<');\n\n        if (this._cache.isIntMap(type) || this._cache.isStringMap(type)) {\n          this._emit(this._cache.isIntMap(type) ? 'int' : 'string');\n          this._emit(', ');\n          this._emitType(in_List.first(type.substitutions));\n        }\n\n        else {\n          for (var i1 = 0, count1 = type.substitutions.length; i1 < count1; i1 = i1 + 1 | 0) {\n            if (i1 != 0) {\n              this._emit(', ');\n            }\n\n            this._emitType(in_List.get(type.substitutions, i1));\n          }\n        }\n\n        this._emit('>');\n      }\n    }\n  };\n\n  Skew.CSharpEmitter.prototype._emitExpressionOrType = function(node, type) {\n    if (node != null && (type == null || type == Skew.Type.DYNAMIC)) {\n      this._emitExpression(node, Skew.Precedence.LOWEST);\n    }\n\n    else {\n      this._emitType(type);\n    }\n  };\n\n  Skew.CSharpEmitter.prototype._emitStatements = function(node) {\n    this._previousNode = null;\n\n    for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n      this._emitNewlineBeforeStatement(child);\n      this._emitComments(child.comments);\n      this._emitStatement(child);\n      this._emitNewlineAfterStatement(child);\n    }\n\n    this._previousNode = null;\n  };\n\n  Skew.CSharpEmitter.prototype._emitBlock = function(node) {\n    assert(node.kind == Skew.NodeKind.BLOCK);\n    this._emit(this._indent + '{\\n');\n    this._increaseIndent();\n    this._emitStatements(node);\n    this._decreaseIndent();\n    this._emit(this._indent + '}');\n  };\n\n  Skew.CSharpEmitter.prototype._emitIf = function(node) {\n    this._emit('if (');\n    this._emitExpression(node.ifTest(), Skew.Precedence.LOWEST);\n    this._emit(')\\n');\n    this._emitBlock(node.ifTrue());\n    this._emit('\\n');\n    var block = node.ifFalse();\n\n    if (block != null) {\n      var singleIf = block.hasOneChild() && block.firstChild().kind == Skew.NodeKind.IF ? block.firstChild() : null;\n\n      if (block.comments != null || singleIf != null && singleIf.comments != null) {\n        this._emit('\\n');\n        this._emitComments(block.comments);\n\n        if (singleIf != null) {\n          this._emitComments(singleIf.comments);\n        }\n      }\n\n      this._emit(this._indent + 'else');\n\n      if (singleIf != null) {\n        this._emit(' ');\n        this._emitIf(singleIf);\n      }\n\n      else {\n        this._emit('\\n');\n        this._emitBlock(block);\n        this._emit('\\n');\n      }\n    }\n  };\n\n  Skew.CSharpEmitter.prototype._scanForSwitchBreak = function(node, loop) {\n    if (node.kind == Skew.NodeKind.BREAK) {\n      for (var parent = node.parent(); parent != loop; parent = parent.parent()) {\n        if (parent.kind == Skew.NodeKind.SWITCH) {\n          var label = in_IntMap.get(this._loopLabels, loop.id, null);\n\n          if (label == null) {\n            label = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_LOCAL, this._enclosingFunction.scope.generateName('label'));\n            in_IntMap.set(this._loopLabels, loop.id, label);\n          }\n\n          in_IntMap.set(this._loopLabels, node.id, label);\n          break;\n        }\n      }\n    }\n\n    // Stop at nested loops since those will be tested later\n    else if (node == loop || !Skew.in_NodeKind.isLoop(node.kind)) {\n      for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n        this._scanForSwitchBreak(child, loop);\n      }\n    }\n  };\n\n  Skew.CSharpEmitter.prototype._emitStatement = function(node) {\n    if (Skew.in_NodeKind.isLoop(node.kind)) {\n      this._scanForSwitchBreak(node, node);\n    }\n\n    switch (node.kind) {\n      case Skew.NodeKind.COMMENT_BLOCK: {\n        break;\n      }\n\n      case Skew.NodeKind.VARIABLES: {\n        for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n          var symbol = child.symbol.asVariableSymbol();\n          this._emit(this._indent);\n          this._emitExpressionOrType(symbol.type, symbol.resolvedType);\n          this._emit(' ' + Skew.CSharpEmitter._mangleName(symbol));\n\n          if (symbol.value != null) {\n            this._emit(' = ');\n            this._emitExpression(symbol.value, Skew.Precedence.ASSIGN);\n          }\n\n          this._emit(';\\n');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.EXPRESSION: {\n        this._emit(this._indent);\n        this._emitExpression(node.expressionValue(), Skew.Precedence.LOWEST);\n        this._emit(';\\n');\n        break;\n      }\n\n      case Skew.NodeKind.BREAK: {\n        var label = in_IntMap.get(this._loopLabels, node.id, null);\n\n        if (label != null) {\n          this._emit(this._indent + 'goto ' + Skew.CSharpEmitter._mangleName(label) + ';\\n');\n        }\n\n        else {\n          this._emit(this._indent + 'break;\\n');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.CONTINUE: {\n        this._emit(this._indent + 'continue;\\n');\n        break;\n      }\n\n      case Skew.NodeKind.IF: {\n        this._emit(this._indent);\n        this._emitIf(node);\n        break;\n      }\n\n      case Skew.NodeKind.SWITCH: {\n        var switchValue = node.switchValue();\n        this._emit(this._indent + 'switch (');\n        this._emitExpression(switchValue, Skew.Precedence.LOWEST);\n        this._emit(')\\n' + this._indent + '{\\n');\n        this._increaseIndent();\n\n        for (var child1 = switchValue.nextSibling(); child1 != null; child1 = child1.nextSibling()) {\n          var block = child1.caseBlock();\n\n          if (child1.previousSibling() != switchValue) {\n            this._emit('\\n');\n          }\n\n          if (child1.hasOneChild()) {\n            this._emit(this._indent + 'default:');\n          }\n\n          else {\n            for (var value = child1.firstChild(); value != block; value = value.nextSibling()) {\n              if (value.previousSibling() != null) {\n                this._emit('\\n');\n              }\n\n              this._emit(this._indent + 'case ');\n              this._emitExpression(value, Skew.Precedence.LOWEST);\n              this._emit(':');\n            }\n          }\n\n          this._emit('\\n' + this._indent + '{\\n');\n          this._increaseIndent();\n          this._emitStatements(block);\n\n          if (block.hasControlFlowAtEnd()) {\n            this._emit(this._indent + 'break;\\n');\n          }\n\n          this._decreaseIndent();\n          this._emit(this._indent + '}\\n');\n        }\n\n        this._decreaseIndent();\n        this._emit(this._indent + '}\\n');\n        break;\n      }\n\n      case Skew.NodeKind.RETURN: {\n        this._emit(this._indent + 'return');\n        var value1 = node.returnValue();\n\n        if (value1 != null) {\n          this._emit(' ');\n          this._emitExpression(value1, Skew.Precedence.LOWEST);\n        }\n\n        this._emit(';\\n');\n        break;\n      }\n\n      case Skew.NodeKind.THROW: {\n        this._emit(this._indent + 'throw ');\n        this._emitExpression(node.throwValue(), Skew.Precedence.LOWEST);\n        this._emit(';\\n');\n        break;\n      }\n\n      case Skew.NodeKind.FOREACH: {\n        this._emit(this._indent + 'foreach (var ' + Skew.CSharpEmitter._mangleName(node.symbol) + ' in ');\n        this._emitExpression(node.foreachValue(), Skew.Precedence.LOWEST);\n        this._emit(')\\n');\n        this._emitBlock(node.foreachBlock());\n        this._emit('\\n');\n        break;\n      }\n\n      case Skew.NodeKind.FOR: {\n        var setup = node.forSetup();\n        var test = node.forTest();\n        var update = node.forUpdate();\n        this._emit(this._indent + 'for (');\n\n        if (!setup.isEmptySequence()) {\n          if (setup.kind == Skew.NodeKind.VARIABLES) {\n            var symbol1 = setup.firstChild().symbol.asVariableSymbol();\n            this._emitExpressionOrType(symbol1.type, symbol1.resolvedType);\n            this._emit(' ');\n\n            for (var child2 = setup.firstChild(); child2 != null; child2 = child2.nextSibling()) {\n              symbol1 = child2.symbol.asVariableSymbol();\n              assert(child2.kind == Skew.NodeKind.VARIABLE);\n\n              if (child2.previousSibling() != null) {\n                this._emit(', ');\n              }\n\n              this._emit(Skew.CSharpEmitter._mangleName(symbol1) + ' = ');\n              this._emitExpression(symbol1.value, Skew.Precedence.COMMA);\n            }\n          }\n\n          else {\n            this._emitExpression(setup, Skew.Precedence.LOWEST);\n          }\n        }\n\n        this._emit('; ');\n\n        if (!test.isEmptySequence()) {\n          this._emitExpression(test, Skew.Precedence.LOWEST);\n        }\n\n        this._emit('; ');\n\n        if (!update.isEmptySequence()) {\n          this._emitExpression(update, Skew.Precedence.LOWEST);\n        }\n\n        this._emit(')\\n');\n        this._emitBlock(node.forBlock());\n        this._emit('\\n');\n        break;\n      }\n\n      case Skew.NodeKind.TRY: {\n        var tryBlock = node.tryBlock();\n        var finallyBlock = node.finallyBlock();\n        this._emit(this._indent + 'try\\n');\n        this._emitBlock(tryBlock);\n        this._emit('\\n');\n\n        for (var child3 = tryBlock.nextSibling(); child3 != finallyBlock; child3 = child3.nextSibling()) {\n          if (child3.comments != null) {\n            this._emit('\\n');\n            this._emitComments(child3.comments);\n          }\n\n          this._emit(this._indent + 'catch');\n\n          if (child3.symbol != null) {\n            this._emit(' (');\n            this._emitExpressionOrType(child3.symbol.asVariableSymbol().type, child3.symbol.resolvedType);\n            this._emit(' ' + Skew.CSharpEmitter._mangleName(child3.symbol) + ')');\n          }\n\n          this._emit('\\n');\n          this._emitBlock(child3.catchBlock());\n          this._emit('\\n');\n        }\n\n        if (finallyBlock != null) {\n          if (finallyBlock.comments != null) {\n            this._emit('\\n');\n            this._emitComments(finallyBlock.comments);\n          }\n\n          this._emit(this._indent + 'finally\\n');\n          this._emitBlock(finallyBlock);\n          this._emit('\\n');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.WHILE: {\n        this._emit(this._indent + 'while (');\n        this._emitExpression(node.whileTest(), Skew.Precedence.LOWEST);\n        this._emit(')\\n');\n        this._emitBlock(node.whileBlock());\n        this._emit('\\n');\n        break;\n      }\n\n      default: {\n        assert(false);\n        break;\n      }\n    }\n\n    if (Skew.in_NodeKind.isLoop(node.kind)) {\n      var label1 = in_IntMap.get(this._loopLabels, node.id, null);\n\n      if (label1 != null) {\n        this._emit(this._indent + Skew.CSharpEmitter._mangleName(label1) + (node.nextSibling() != null ? ':\\n' : ':;\\n'));\n      }\n    }\n  };\n\n  Skew.CSharpEmitter.prototype._emitContent = function(content) {\n    switch (content.kind()) {\n      case Skew.ContentKind.BOOL: {\n        this._emit(Skew.in_Content.asBool(content).toString());\n        break;\n      }\n\n      case Skew.ContentKind.INT: {\n        this._emit(Skew.in_Content.asInt(content).toString());\n        break;\n      }\n\n      case Skew.ContentKind.DOUBLE: {\n        var value = Skew.in_Content.asDouble(content);\n\n        if (!isFinite(value)) {\n          in_StringMap.set(this._usingNames, 'System', 0);\n        }\n\n        this._emit(isNaN(value) ? 'Double.NaN' : value == 1 / 0 ? 'Double.PositiveInfinity' : value == -(1 / 0) ? 'Double.NegativeInfinity' : Skew.doubleToStringWithDot(value));\n        break;\n      }\n\n      case Skew.ContentKind.STRING: {\n        this._emit(Skew.quoteString(Skew.in_Content.asString(content), Skew.QuoteStyle.DOUBLE, Skew.QuoteOctal.NORMAL));\n        break;\n      }\n    }\n  };\n\n  Skew.CSharpEmitter.prototype._emitCommaSeparatedExpressions = function(from, to) {\n    while (from != to) {\n      this._emitExpression(from, Skew.Precedence.COMMA);\n      from = from.nextSibling();\n\n      if (from != to) {\n        this._emit(', ');\n      }\n    }\n  };\n\n  Skew.CSharpEmitter.prototype._emitExpression = function(node, precedence) {\n    var kind = node.kind;\n    var symbol = node.symbol;\n\n    if (symbol != null) {\n      this._handleSymbol(symbol);\n    }\n\n    switch (kind) {\n      case Skew.NodeKind.TYPE:\n      case Skew.NodeKind.LAMBDA_TYPE: {\n        this._emitType(node.resolvedType);\n        break;\n      }\n\n      case Skew.NodeKind.NULL: {\n        this._emit('null');\n        break;\n      }\n\n      case Skew.NodeKind.NAME: {\n        this._emit(symbol != null ? Skew.CSharpEmitter._fullName(symbol) : node.asString());\n        break;\n      }\n\n      case Skew.NodeKind.DOT: {\n        this._emitExpression(node.dotTarget(), Skew.Precedence.MEMBER);\n        this._emit('.' + (symbol != null ? Skew.CSharpEmitter._mangleName(symbol) : node.asString()));\n        break;\n      }\n\n      case Skew.NodeKind.CONSTANT: {\n        var wrap = precedence == Skew.Precedence.MEMBER && node.isNumberLessThanZero() && (!node.isDouble() || isFinite(node.asDouble()));\n\n        if (wrap) {\n          this._emit('(');\n        }\n\n        if (node.resolvedType.isEnumOrFlags()) {\n          this._emit('(');\n          this._emitType(node.resolvedType);\n          this._emit(')');\n        }\n\n        this._emitContent(node.content);\n\n        if (wrap) {\n          this._emit(')');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.CALL: {\n        var value = node.callValue();\n        var wrap1 = value.kind == Skew.NodeKind.LAMBDA;\n\n        if (wrap1) {\n          this._emit('new ');\n          this._emitType(value.resolvedType);\n          this._emit('(');\n        }\n\n        if (value.kind == Skew.NodeKind.SUPER) {\n          this._emit('base');\n\n          if (symbol.kind != Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n            this._emit('.');\n            this._emit(Skew.CSharpEmitter._mangleName(symbol));\n          }\n        }\n\n        else if (symbol != null && symbol.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n          this._emit('new ');\n          this._emitType(node.resolvedType);\n        }\n\n        else if (value.kind == Skew.NodeKind.DOT && value.asString() == 'new') {\n          this._emit('new ');\n          this._emitExpression(value.dotTarget(), Skew.Precedence.MEMBER);\n        }\n\n        else {\n          this._emitExpression(value, Skew.Precedence.UNARY_POSTFIX);\n        }\n\n        if (wrap1) {\n          this._emit(')');\n        }\n\n        this._emit('(');\n        this._emitCommaSeparatedExpressions(value.nextSibling(), null);\n        this._emit(')');\n        break;\n      }\n\n      case Skew.NodeKind.CAST: {\n        var resolvedType = node.resolvedType;\n        var type = node.castType();\n        var value1 = node.castValue();\n\n        if (type.kind == Skew.NodeKind.TYPE && type.resolvedType == Skew.Type.DYNAMIC) {\n          this._emitExpression(value1, precedence);\n        }\n\n        // Automatically promote integer literals to doubles instead of using a cast\n        else if (this._cache.isEquivalentToDouble(resolvedType) && value1.isInt()) {\n          this._emitExpression(this._cache.createDouble(value1.asInt()), precedence);\n        }\n\n        // C# doesn't have a cast from bool to int\n        else if (this._cache.isNumeric(resolvedType) && value1.resolvedType == this._cache.boolType) {\n          this._emitExpression(Skew.Node.createHook(value1.remove(), this._cache.createInt(1), this._cache.createInt(0)).withType(this._cache.intType), precedence);\n        }\n\n        // C# doesn't have a cast from int to bool\n        else if (resolvedType == this._cache.boolType && this._cache.isNumeric(value1.resolvedType)) {\n          this._emitExpression(Skew.Node.createBinary(Skew.NodeKind.NOT_EQUAL, value1.remove(), this._cache.createInt(0)).withType(this._cache.boolType), precedence);\n        }\n\n        // Only emit a cast if the underlying types are different\n        else if (this._cache.unwrappedType(value1.resolvedType) != this._cache.unwrappedType(type.resolvedType) || type.resolvedType == Skew.Type.DYNAMIC) {\n          if (Skew.Precedence.UNARY_POSTFIX < precedence) {\n            this._emit('(');\n          }\n\n          this._emit('(');\n          this._emitExpressionOrType(type, type.resolvedType);\n          this._emit(')');\n          this._emitExpression(value1, Skew.Precedence.UNARY_POSTFIX);\n\n          if (Skew.Precedence.UNARY_POSTFIX < precedence) {\n            this._emit(')');\n          }\n        }\n\n        // Otherwise, pretend the cast isn't there\n        else {\n          this._emitExpression(value1, precedence);\n        }\n        break;\n      }\n\n      case Skew.NodeKind.TYPE_CHECK: {\n        var value2 = node.typeCheckValue();\n        var type1 = node.typeCheckType();\n\n        if (Skew.Precedence.COMPARE < precedence) {\n          this._emit('(');\n        }\n\n        this._emitExpression(value2, Skew.Precedence.LOWEST);\n        this._emit(' is ');\n        this._emitExpressionOrType(type1, type1.resolvedType);\n\n        if (Skew.Precedence.COMPARE < precedence) {\n          this._emit(')');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.INITIALIZER_LIST: {\n        this._emit('new ');\n        this._emitType(node.resolvedType);\n\n        if (node.hasChildren()) {\n          this._emit(' { ');\n          this._emitCommaSeparatedExpressions(node.firstChild(), null);\n          this._emit(' }');\n        }\n\n        else {\n          this._emit('()');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.INDEX: {\n        this._emitExpression(node.indexLeft(), Skew.Precedence.UNARY_POSTFIX);\n        this._emit('[');\n        this._emitExpression(node.indexRight(), Skew.Precedence.LOWEST);\n        this._emit(']');\n        break;\n      }\n\n      case Skew.NodeKind.ASSIGN_INDEX: {\n        if (Skew.Precedence.ASSIGN < precedence) {\n          this._emit('(');\n        }\n\n        this._emitExpression(node.assignIndexLeft(), Skew.Precedence.UNARY_POSTFIX);\n        this._emit('[');\n        this._emitExpression(node.assignIndexCenter(), Skew.Precedence.LOWEST);\n        this._emit('] = ');\n        this._emitExpression(node.assignIndexRight(), Skew.Precedence.ASSIGN);\n\n        if (Skew.Precedence.ASSIGN < precedence) {\n          this._emit(')');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.PARAMETERIZE: {\n        var value3 = node.parameterizeValue();\n\n        if (value3.isType()) {\n          this._emitType(node.resolvedType);\n        }\n\n        else {\n          this._emitExpression(value3, precedence);\n          this._emit('<');\n          this._emitCommaSeparatedExpressions(value3.nextSibling(), null);\n          this._emit('>');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.SEQUENCE: {\n        if (Skew.Precedence.COMMA <= precedence) {\n          this._emit('(');\n        }\n\n        this._emitCommaSeparatedExpressions(node.firstChild(), null);\n\n        if (Skew.Precedence.COMMA <= precedence) {\n          this._emit(')');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.HOOK: {\n        if (Skew.Precedence.ASSIGN < precedence) {\n          this._emit('(');\n        }\n\n        this._emitExpression(node.hookTest(), Skew.Precedence.LOGICAL_OR);\n        this._emit(' ? ');\n        this._emitExpression(node.hookTrue(), Skew.Precedence.ASSIGN);\n        this._emit(' : ');\n        this._emitExpression(node.hookFalse(), Skew.Precedence.ASSIGN);\n\n        if (Skew.Precedence.ASSIGN < precedence) {\n          this._emit(')');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.LAMBDA: {\n        var oldEnclosingFunction = this._enclosingFunction;\n        this._enclosingFunction = symbol.asFunctionSymbol();\n        this._emitArgumentList(symbol.asFunctionSymbol());\n        this._emit(' =>\\n');\n        this._emitBlock(symbol.asFunctionSymbol().block);\n        this._enclosingFunction = oldEnclosingFunction;\n        break;\n      }\n\n      case Skew.NodeKind.COMPLEMENT:\n      case Skew.NodeKind.NEGATIVE:\n      case Skew.NodeKind.NOT:\n      case Skew.NodeKind.POSITIVE:\n      case Skew.NodeKind.POSTFIX_DECREMENT:\n      case Skew.NodeKind.POSTFIX_INCREMENT:\n      case Skew.NodeKind.PREFIX_DECREMENT:\n      case Skew.NodeKind.PREFIX_INCREMENT: {\n        var value4 = node.unaryValue();\n        var info = in_IntMap.get1(Skew.operatorInfo, kind);\n        var sign = node.sign();\n\n        if (info.precedence < precedence) {\n          this._emit('(');\n        }\n\n        if (!Skew.in_NodeKind.isUnaryPostfix(kind)) {\n          this._emit(info.text);\n\n          // Prevent \"x - -1\" from becoming \"x--1\"\n          if (sign != Skew.NodeKind.NULL && sign == value4.sign()) {\n            this._emit(' ');\n          }\n        }\n\n        this._emitExpression(value4, info.precedence);\n\n        if (Skew.in_NodeKind.isUnaryPostfix(kind)) {\n          this._emit(info.text);\n        }\n\n        if (info.precedence < precedence) {\n          this._emit(')');\n        }\n        break;\n      }\n\n      default: {\n        if (Skew.in_NodeKind.isBinary(kind)) {\n          var left = node.binaryLeft();\n          var right = node.binaryRight();\n\n          // Some types stupidly don't implement operator \"==\"\n          if ((kind == Skew.NodeKind.EQUAL || kind == Skew.NodeKind.NOT_EQUAL) && left.resolvedType.isParameter() && right.resolvedType.isParameter()) {\n            if (kind == Skew.NodeKind.NOT_EQUAL) {\n              this._emit('!');\n            }\n\n            this._emit('EqualityComparer<');\n            this._emitType(left.resolvedType);\n            this._emit('>.Default.Equals(');\n            this._emitExpression(left, Skew.Precedence.COMMA);\n            this._emit(', ');\n            this._emitExpression(right, Skew.Precedence.COMMA);\n            this._emit(')');\n            in_StringMap.set(this._usingNames, 'System.Collections.Generic', 0);\n          }\n\n          else {\n            var info1 = in_IntMap.get1(Skew.operatorInfo, kind);\n\n            if (info1.precedence < precedence) {\n              this._emit('(');\n            }\n\n            this._emitExpression(left, info1.precedence + (info1.associativity == Skew.Associativity.RIGHT | 0) | 0);\n            this._emit(' ' + info1.text + ' ');\n            this._emitExpression(right, info1.precedence + (info1.associativity == Skew.Associativity.LEFT | 0) | 0);\n\n            if (info1.precedence < precedence) {\n              this._emit(')');\n            }\n          }\n        }\n\n        else {\n          assert(false);\n        }\n        break;\n      }\n    }\n  };\n\n  Skew.CSharpEmitter._isCompactNodeKind = function(kind) {\n    return kind == Skew.NodeKind.EXPRESSION || kind == Skew.NodeKind.VARIABLES || Skew.in_NodeKind.isJump(kind);\n  };\n\n  Skew.CSharpEmitter._fullName = function(symbol) {\n    var parent = symbol.parent;\n\n    if (parent != null && parent.kind != Skew.SymbolKind.OBJECT_GLOBAL && !Skew.in_SymbolKind.isParameter(symbol.kind)) {\n      var enclosingName = Skew.CSharpEmitter._fullName(parent);\n\n      if (symbol.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n        return enclosingName;\n      }\n\n      return enclosingName + '.' + Skew.CSharpEmitter._mangleName(symbol);\n    }\n\n    return Skew.CSharpEmitter._mangleName(symbol);\n  };\n\n  Skew.CSharpEmitter._mangleName = function(symbol) {\n    symbol = symbol.forwarded();\n\n    if (symbol.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n      symbol = symbol.parent;\n    }\n\n    if (!symbol.isImportedOrExported() && Skew.CSharpEmitter._isKeyword.has(symbol.name)) {\n      return '_' + symbol.name;\n    }\n\n    return symbol.name;\n  };\n\n  Skew.JavaScriptEmitter = function(_context, _options, _cache) {\n    Skew.Emitter.call(this);\n    this._context = _context;\n    this._options = _options;\n    this._cache = _cache;\n    this._isSpecialVariableNeeded = new Map();\n    this._loopLabels = new Map();\n    this._specialVariables = new Map();\n    this._global = null;\n    this._symbolsToExport = [];\n    this._allSpecialVariables = null;\n    this._exportsNamespace = null;\n    this._enclosingFunction = null;\n    this._enclosingLoop = null;\n    this._namespacePrefix = '';\n    this._previousNode = null;\n    this._previousSymbol = null;\n    this._parenthesizeInExpressions = 0;\n    this._currentColumn = 0;\n    this._currentLine = 0;\n    this._generator = new Skew.SourceMapGenerator();\n    this._previousSource = null;\n    this._previousStart = 0;\n    this._sourceMap = false;\n    this._allSymbols = [];\n    this._localVariableUnionFind = new Skew.UnionFind();\n    this._namingGroupIndexForSymbol = new Map();\n    this._symbolCounts = new Map();\n    this._nextSymbolName = 0;\n    this._mangle = false;\n    this._minify = false;\n    this._needsSemicolon = false;\n    this._newline = '\\n';\n    this._space = ' ';\n    this._previousCodeUnit = 0;\n    this._currentSelf = null;\n    this._needsSelf = false;\n  };\n\n  __extends(Skew.JavaScriptEmitter, Skew.Emitter);\n\n  Skew.JavaScriptEmitter.prototype.visit = function(global) {\n    this._mangle = this._options.jsMangle;\n    this._minify = this._options.jsMinify;\n    this._sourceMap = this._options.jsSourceMap;\n    this._global = global;\n\n    if (this._minify) {\n      this._indentAmount = '';\n      this._newline = '';\n      this._space = '';\n    }\n\n    // Load special-cased variables\n    for (var i = 0, list = global.variables, count = list.length; i < count; i = i + 1 | 0) {\n      var variable = in_List.get(list, i);\n      var special = in_StringMap.get(Skew.JavaScriptEmitter._specialVariableMap, variable.name, Skew.JavaScriptEmitter.SpecialVariable.NONE);\n\n      if (special != Skew.JavaScriptEmitter.SpecialVariable.NONE) {\n        in_IntMap.set(this._specialVariables, special, variable);\n      }\n    }\n\n    assert(this._specialVariables.has(Skew.JavaScriptEmitter.SpecialVariable.AS_STRING));\n    assert(this._specialVariables.has(Skew.JavaScriptEmitter.SpecialVariable.CREATE));\n    assert(this._specialVariables.has(Skew.JavaScriptEmitter.SpecialVariable.EXTENDS));\n    assert(this._specialVariables.has(Skew.JavaScriptEmitter.SpecialVariable.IS_BOOL));\n    assert(this._specialVariables.has(Skew.JavaScriptEmitter.SpecialVariable.IS_DOUBLE));\n    assert(this._specialVariables.has(Skew.JavaScriptEmitter.SpecialVariable.IS_INT));\n    assert(this._specialVariables.has(Skew.JavaScriptEmitter.SpecialVariable.IS_STRING));\n    assert(this._specialVariables.has(Skew.JavaScriptEmitter.SpecialVariable.MULTIPLY));\n    assert(this._specialVariables.has(Skew.JavaScriptEmitter.SpecialVariable.PROTOTYPE));\n\n    // These don't need to be initialized\n    in_IntMap.get1(this._specialVariables, Skew.JavaScriptEmitter.SpecialVariable.PROTOTYPE).value = null;\n\n    // Sort these so their order is deterministic\n    this._allSpecialVariables = Array.from(this._specialVariables.values());\n    this._allSpecialVariables.sort(Skew.Symbol.SORT_VARIABLES_BY_ID);\n\n    // Preprocess the code\n    if (this._mangle) {\n      this._liftGlobals1(global);\n    }\n\n    if (this._options.inlineAllFunctions) {\n      this._maybeInlineFunctions(global);\n    }\n\n    Skew.shakingPass(global, this._cache.entryPointSymbol, Skew.ShakingMode.IGNORE_TYPES);\n    this._prepareGlobal(global);\n    this._convertLambdasToFunctions(global);\n    var objects = this._sortedObjects(global);\n\n    // Make sure the \"__create\" variable is inserted when used even if \"__extends\" isn't used\n    var create = in_IntMap.get1(this._specialVariables, Skew.JavaScriptEmitter.SpecialVariable.CREATE);\n\n    if (global.variables.indexOf(create) != -1) {\n      in_IntMap.set(this._isSpecialVariableNeeded, create.id, 0);\n    }\n\n    // The entire body of code is wrapped in a closure for safety\n    this._emit(this._indent + '(function(' + (this._exportsNamespace != null ? Skew.JavaScriptEmitter._mangleName(this._exportsNamespace) : '') + ')' + this._space + '{' + this._newline + '');\n    this._increaseIndent();\n\n    // Emit special-cased variables that must come first\n    for (var i1 = 0, list1 = this._allSpecialVariables, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n      var variable1 = in_List.get(list1, i1);\n\n      if (this._isSpecialVariableNeeded.has(variable1.id)) {\n        if (variable1.value != null && variable1.value.kind == Skew.NodeKind.LAMBDA) {\n          this._emitFunction(this._convertLambdaToFunction(variable1));\n        }\n\n        else {\n          this._emitVariable(variable1);\n        }\n      }\n    }\n\n    // Emit objects and functions\n    for (var i2 = 0, list2 = objects, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n      var object = in_List.get(list2, i2);\n      this._emitObject(object);\n    }\n\n    // Emit variables\n    var statement = new Skew.Node(Skew.NodeKind.VARIABLES);\n\n    for (var i4 = 0, list4 = objects, count4 = list4.length; i4 < count4; i4 = i4 + 1 | 0) {\n      var object1 = in_List.get(list4, i4);\n      this._namespacePrefix = '';\n\n      for (var o = object1; o.kind != Skew.SymbolKind.OBJECT_GLOBAL; o = o.parent.asObjectSymbol()) {\n        this._namespacePrefix = Skew.JavaScriptEmitter._mangleName(o) + '.' + this._namespacePrefix;\n      }\n\n      for (var i3 = 0, list3 = object1.variables, count3 = list3.length; i3 < count3; i3 = i3 + 1 | 0) {\n        var variable2 = in_List.get(list3, i3);\n\n        if (!(this._allSpecialVariables.indexOf(variable2) != -1)) {\n          if (this._mangle && this._namespacePrefix == '' && !variable2.isImportedOrExported()) {\n            statement.appendChild(Skew.Node.createVariable(variable2));\n          }\n\n          else {\n            this._emitVariable(variable2);\n          }\n        }\n      }\n    }\n\n    this._namespacePrefix = '';\n\n    // Group adjacent variables into a single statement during mangling\n    if (statement.hasChildren()) {\n      this._emitNewlineBeforeSymbol(statement.firstChild().symbol);\n      this._emitStatement(statement);\n      this._emitNewlineAfterSymbol(statement.firstChild().symbol);\n\n      for (var child = statement.firstChild(); child != null; child = child.nextSibling()) {\n        child.removeChildren();\n      }\n    }\n\n    // Emit entry point\n    var entryPointSymbol = this._cache.entryPointSymbol;\n\n    if (entryPointSymbol != null) {\n      var type = entryPointSymbol.resolvedType;\n      var callText = Skew.JavaScriptEmitter._fullName(entryPointSymbol) + (type.argumentTypes.length == 0 ? '()' : '(process.argv.slice(2))');\n      this._emitSemicolonIfNeeded();\n      this._emit(this._newline + this._indent + (type.returnType == this._cache.intType ? 'process.exit(' + callText + ')' : callText));\n      this._emitSemicolonAfterStatement();\n    }\n\n    // End the closure wrapping everything\n    this._decreaseIndent();\n    this._emit(this._indent + '})(' + (this._exportsNamespace != null ? 'this' : '') + ');\\n');\n    var codeName = this._options.outputDirectory != null ? this._options.outputDirectory + '/compiled.js' : this._options.outputFile;\n    var mapName = codeName != null ? codeName + '.map' : null;\n\n    // Obfuscate the sourceMappingURL so it's not incorrectly picked up as the\n    // sourceMappingURL for the compiled JavaScript compiler file\n    if (this._sourceMap) {\n      this._emit('/');\n      this._emit('/# sourceMappingURL=' + Skew.splitPath(mapName).entry + '\\n');\n    }\n\n    this._createSource(codeName, Skew.EmitMode.ALWAYS_EMIT);\n\n    // Create the source map\n    if (this._sourceMap) {\n      this._emit(this._generator.toString());\n      this._createSource(mapName, Skew.EmitMode.ALWAYS_EMIT);\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._emit = function(text) {\n    if (this._minify || this._sourceMap) {\n      var n = text.length;\n\n      for (var i = 0, count = n; i < count; i = i + 1 | 0) {\n        if (in_string.get1(text, i) == 10) {\n          this._currentColumn = 0;\n          this._currentLine = this._currentLine + 1 | 0;\n        }\n\n        else {\n          this._currentColumn = this._currentColumn + 1 | 0;\n        }\n      }\n\n      if (n != 0) {\n        this._previousCodeUnit = in_string.get1(text, n - 1 | 0);\n      }\n    }\n\n    this._code.buffer += text;\n  };\n\n  Skew.JavaScriptEmitter.prototype._liftGlobals1 = function(global) {\n    var globalObjects = [];\n    var globalFunctions = [];\n    var globalVariables = [];\n    this._liftGlobals2(global, globalObjects, globalFunctions, globalVariables);\n\n    for (var i = 0, list = globalObjects, count = list.length; i < count; i = i + 1 | 0) {\n      var object = in_List.get(list, i);\n      object.parent = global;\n    }\n\n    for (var i1 = 0, list1 = globalFunctions, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n      var $function = in_List.get(list1, i1);\n      $function.parent = global;\n    }\n\n    for (var i2 = 0, list2 = globalVariables, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n      var variable = in_List.get(list2, i2);\n      variable.parent = global;\n    }\n\n    in_List.append1(global.objects, globalObjects);\n    in_List.append1(global.functions, globalFunctions);\n    in_List.append1(global.variables, globalVariables);\n  };\n\n  Skew.JavaScriptEmitter.prototype._liftGlobals2 = function(symbol, globalObjects, globalFunctions, globalVariables) {\n    var self = this;\n    var shouldLiftGlobals = symbol.parent != null;\n\n    // Scan over child objects\n    in_List.removeIf(symbol.objects, function(object) {\n      self._liftGlobals2(object, globalObjects, globalFunctions, globalVariables);\n\n      if (shouldLiftGlobals && !object.isImportedOrExported()) {\n        globalObjects.push(object);\n        return true;\n      }\n\n      return false;\n    });\n    in_List.removeIf(symbol.functions, function($function) {\n      if (shouldLiftGlobals && $function.kind == Skew.SymbolKind.FUNCTION_GLOBAL && !$function.isImportedOrExported()) {\n        globalFunctions.push($function);\n        return true;\n      }\n\n      return false;\n    });\n\n    // Scan over child variables\n    in_List.removeIf(symbol.variables, function(variable) {\n      if (shouldLiftGlobals && variable.kind == Skew.SymbolKind.VARIABLE_GLOBAL && !variable.isImportedOrExported()) {\n        globalVariables.push(variable);\n        return true;\n      }\n\n      return false;\n    });\n  };\n\n  Skew.JavaScriptEmitter.prototype._collectInlineableFunctions = function(symbol, listAppends, mapInserts) {\n    for (var i = 0, list = symbol.objects, count = list.length; i < count; i = i + 1 | 0) {\n      var object = in_List.get(list, i);\n      this._collectInlineableFunctions(object, listAppends, mapInserts);\n    }\n\n    for (var i3 = 0, list3 = symbol.functions, count3 = list3.length; i3 < count3; i3 = i3 + 1 | 0) {\n      var $function = in_List.get(list3, i3);\n\n      if ($function.block == null || !$function.block.hasTwoChildren()) {\n        continue;\n      }\n\n      var $arguments = $function.$arguments;\n\n      // \"foo([], 0)\" => \"[0]\" where \"foo\" is \"def foo(a, b) { a.push(b); return a }\"\n      if ($arguments.length == 2) {\n        var first = $function.block.firstChild();\n        var second = $function.block.lastChild();\n\n        if (first.kind == Skew.NodeKind.EXPRESSION && first.expressionValue().kind == Skew.NodeKind.CALL && second.kind == Skew.NodeKind.RETURN && second.returnValue() != null) {\n          var call = first.expressionValue();\n          var callValue = call.callValue();\n\n          if (call.hasTwoChildren() && callValue.kind == Skew.NodeKind.DOT && callValue.asString() == 'push' && Skew.JavaScriptEmitter._isReferenceTo(callValue.dotTarget(), in_List.get($arguments, 0)) && Skew.JavaScriptEmitter._isReferenceTo(call.lastChild(), in_List.get($arguments, 1)) && Skew.JavaScriptEmitter._isReferenceTo(second.returnValue(), in_List.get($arguments, 0))) {\n            for (var i1 = 0, list1 = this._context.callGraph.callInfoForSymbol($function).callSites, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n              var callSite = in_List.get(list1, i1);\n\n              if (callSite != null && callSite.callNode.kind == Skew.NodeKind.CALL) {\n                assert(callSite.callNode.symbol == $function);\n                listAppends.push(callSite.callNode);\n              }\n            }\n          }\n        }\n      }\n\n      // \"foo({}, 0, 1)\" => \"{0: 1}\" where \"foo\" is \"def foo(a, b, c) { a[b] = c; return a }\"\n      else if ($arguments.length == 3) {\n        var keyType = in_List.get($arguments, 1).resolvedType;\n        var first1 = $function.block.firstChild();\n        var second1 = $function.block.lastChild();\n\n        if ((keyType == Skew.Type.DYNAMIC || this._cache.isEquivalentToInt(keyType) || this._cache.isEquivalentToString(keyType)) && first1.kind == Skew.NodeKind.EXPRESSION && first1.expressionValue().kind == Skew.NodeKind.ASSIGN_INDEX && second1.kind == Skew.NodeKind.RETURN && second1.returnValue() != null) {\n          var assign = first1.expressionValue();\n\n          if (Skew.JavaScriptEmitter._isReferenceTo(assign.assignIndexLeft(), in_List.get($arguments, 0)) && Skew.JavaScriptEmitter._isReferenceTo(assign.assignIndexCenter(), in_List.get($arguments, 1)) && Skew.JavaScriptEmitter._isReferenceTo(assign.assignIndexRight(), in_List.get($arguments, 2)) && Skew.JavaScriptEmitter._isReferenceTo(second1.returnValue(), in_List.get($arguments, 0))) {\n            for (var i2 = 0, list2 = this._context.callGraph.callInfoForSymbol($function).callSites, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n              var callSite1 = in_List.get(list2, i2);\n\n              if (callSite1 != null && callSite1.callNode.kind == Skew.NodeKind.CALL) {\n                assert(callSite1.callNode.symbol == $function);\n                mapInserts.push(callSite1.callNode);\n              }\n            }\n          }\n        }\n      }\n    }\n  };\n\n  // This uses iteration until fixed point to avoid dependence on inlining order\n  Skew.JavaScriptEmitter.prototype._maybeInlineFunctions = function(global) {\n    var listAppends = [];\n    var mapInserts = [];\n    this._collectInlineableFunctions(global, listAppends, mapInserts);\n\n    // List append fixed point\n    var changed = true;\n\n    while (changed) {\n      changed = false;\n\n      for (var i = 0, count = listAppends.length; i < count; i = i + 1 | 0) {\n        var node = in_List.get(listAppends, i);\n\n        // This will be null if it was already inlined\n        if (node == null) {\n          continue;\n        }\n\n        var firstArgument = node.callValue().nextSibling();\n        var secondArgument = firstArgument.nextSibling();\n\n        // List expressions are sometimes casted\n        if (firstArgument.kind == Skew.NodeKind.CAST) {\n          firstArgument = firstArgument.castValue();\n        }\n\n        // Only check when the inputs are constants\n        if (firstArgument.kind == Skew.NodeKind.INITIALIZER_LIST) {\n          node.become(firstArgument.remove().appendChild(secondArgument.remove()));\n          in_List.set(listAppends, i, null);\n          changed = true;\n        }\n      }\n    }\n\n    // Map insert fixed point\n    changed = true;\n\n    while (changed) {\n      changed = false;\n\n      for (var i1 = 0, count1 = mapInserts.length; i1 < count1; i1 = i1 + 1 | 0) {\n        var node1 = in_List.get(mapInserts, i1);\n\n        // This will be null if it was already inlined\n        if (node1 == null) {\n          continue;\n        }\n\n        var firstArgument1 = node1.callValue().nextSibling();\n        var secondArgument1 = firstArgument1.nextSibling();\n        var thirdArgument = secondArgument1.nextSibling();\n\n        // Map expressions are sometimes casted\n        if (firstArgument1.kind == Skew.NodeKind.CAST) {\n          firstArgument1 = firstArgument1.castValue();\n        }\n\n        // Only check when the inputs are constants\n        if (firstArgument1.kind == Skew.NodeKind.INITIALIZER_MAP && (secondArgument1.isInt() || secondArgument1.isString())) {\n          node1.become(firstArgument1.remove().appendChild(Skew.Node.createPair(secondArgument1.remove(), thirdArgument.remove()).withType(Skew.Type.DYNAMIC)));\n          in_List.set(mapInserts, i1, null);\n          changed = true;\n        }\n      }\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._prepareGlobal = function(global) {\n    // Lower certain stuff into JavaScript (for example, \"x as bool\" becomes \"!!x\")\n    this._patchObject(global);\n    this._exportSymbols();\n\n    // Skip everything below if we aren't mangling\n    if (!this._mangle) {\n      return;\n    }\n\n    // These will be culled by tree shaking regardless of whether they are needed\n    for (var i = 0, list = this._allSpecialVariables, count = list.length; i < count; i = i + 1 | 0) {\n      var variable = in_List.get(list, i);\n\n      if (this._isSpecialVariableNeeded.has(variable.id)) {\n        this._allocateNamingGroupIndex(variable);\n        this._patchNode(variable.value);\n      }\n    }\n\n    // Rename symbols based on frequency for better compression\n    this._renameSymbols();\n  };\n\n  Skew.JavaScriptEmitter.prototype._convertLambdaToFunction = function(variable) {\n    var $function = variable.value.symbol.asFunctionSymbol();\n    $function.kind = Skew.SymbolKind.FUNCTION_GLOBAL;\n    $function.parent = variable.parent;\n    $function.name = variable.name;\n\n    if ($function.block.parent() != null) {\n      $function.block.remove();\n    }\n\n    return $function;\n  };\n\n  Skew.JavaScriptEmitter.prototype._convertLambdasToFunctions = function(symbol) {\n    var self = this;\n\n    for (var i = 0, list = symbol.objects, count = list.length; i < count; i = i + 1 | 0) {\n      var object = in_List.get(list, i);\n      self._convertLambdasToFunctions(object);\n    }\n\n    in_List.removeIf(symbol.variables, function(variable) {\n      if (variable.kind == Skew.SymbolKind.VARIABLE_GLOBAL && variable.isConst() && !variable.isExported() && variable.value != null && variable.value.kind == Skew.NodeKind.LAMBDA) {\n        symbol.functions.push(self._convertLambdaToFunction(variable));\n        return true;\n      }\n\n      return false;\n    });\n  };\n\n  Skew.JavaScriptEmitter.prototype._allocateNamingGroupIndex = function(symbol) {\n    if (this._mangle && !this._namingGroupIndexForSymbol.has(symbol.id)) {\n      var index = this._localVariableUnionFind.allocate1();\n      in_IntMap.set(this._namingGroupIndexForSymbol, symbol.id, index);\n      this._allSymbols.push(symbol);\n\n      // Explicitly add function arguments since they won't be reached by\n      // normal tree traversal\n      if (Skew.in_SymbolKind.isFunction(symbol.kind)) {\n        var $this = symbol.asFunctionSymbol().$this;\n\n        if ($this != null) {\n          this._allocateNamingGroupIndex($this);\n        }\n\n        for (var i = 0, list = symbol.asFunctionSymbol().$arguments, count = list.length; i < count; i = i + 1 | 0) {\n          var argument = in_List.get(list, i);\n          this._allocateNamingGroupIndex(argument);\n        }\n      }\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._renameSymbols = function() {\n    // This holds the groups used for naming. Unioning two labels using\n    // this object will cause both groups of symbols to have the same name.\n    var namingGroupsUnionFind = new Skew.UnionFind().allocate2(this._allSymbols.length);\n\n    // These are optional and only reduce the number of generated names\n    var order = [];\n    this._aliasLocalVariables(namingGroupsUnionFind, order);\n    this._aliasUnrelatedProperties(namingGroupsUnionFind, order);\n\n    // Ensure all overridden symbols have the same generated name. This is\n    // manditory for correctness, otherwise virtual functions break.\n    var namingGroupMap = new Map();\n\n    for (var i = 0, list = this._allSymbols, count1 = list.length; i < count1; i = i + 1 | 0) {\n      var symbol = in_List.get(list, i);\n\n      if (Skew.in_SymbolKind.isFunction(symbol.kind)) {\n        var $function = symbol.asFunctionSymbol();\n        assert(this._namingGroupIndexForSymbol.has($function.id));\n        var id = in_IntMap.get(namingGroupMap, $function.namingGroup, -1);\n\n        if (id == -1) {\n          in_IntMap.set(namingGroupMap, $function.namingGroup, in_IntMap.get1(this._namingGroupIndexForSymbol, $function.id));\n        }\n\n        else {\n          namingGroupsUnionFind.union(id, in_IntMap.get1(this._namingGroupIndexForSymbol, $function.id));\n        }\n      }\n    }\n\n    // Collect all reserved names together into one big set for querying\n    var reservedNames = new Map(Skew.JavaScriptEmitter._isKeyword);\n\n    for (var i1 = 0, list1 = this._allSymbols, count2 = list1.length; i1 < count2; i1 = i1 + 1 | 0) {\n      var symbol1 = in_List.get(list1, i1);\n\n      if (!Skew.JavaScriptEmitter._shouldRenameSymbol(symbol1)) {\n        in_StringMap.set(reservedNames, symbol1.name, 0);\n      }\n    }\n\n    // Everything that should have the same name is now grouped together.\n    // Generate and assign names to all internal symbols, but use shorter\n    // names for more frequently used symbols.\n    var sortedGroups = [];\n\n    for (var i3 = 0, list2 = this._extractGroups(namingGroupsUnionFind, Skew.JavaScriptEmitter.ExtractGroupsMode.ALL_SYMBOLS), count4 = list2.length; i3 < count4; i3 = i3 + 1 | 0) {\n      var group = in_List.get(list2, i3);\n      var count = 0;\n\n      for (var i2 = 0, count3 = group.length; i2 < count3; i2 = i2 + 1 | 0) {\n        var symbol2 = in_List.get(group, i2);\n\n        if (Skew.JavaScriptEmitter._shouldRenameSymbol(symbol2)) {\n          count = count + in_IntMap.get(this._symbolCounts, symbol2.id, 0) | 0;\n        }\n      }\n\n      sortedGroups.push(new Skew.JavaScriptEmitter.SymbolGroup(group, count));\n    }\n\n    // Create a total order to make builds deterministic when maps use hashing\n    sortedGroups.sort(function(a, b) {\n      var difference = in_int.compare(b.count, a.count);\n\n      if (difference == 0) {\n        difference = in_int.compare(b.symbols.length, a.symbols.length);\n\n        for (var i = 0; difference == 0 && i < a.symbols.length; i = i + 1 | 0) {\n          difference = in_int.compare(in_List.get(a.symbols, i).id, in_List.get(b.symbols, i).id);\n        }\n      }\n\n      return difference;\n    });\n\n    for (var i5 = 0, list4 = sortedGroups, count6 = list4.length; i5 < count6; i5 = i5 + 1 | 0) {\n      var group1 = in_List.get(list4, i5);\n      var name = '';\n\n      for (var i4 = 0, list3 = group1.symbols, count5 = list3.length; i4 < count5; i4 = i4 + 1 | 0) {\n        var symbol3 = in_List.get(list3, i4);\n\n        if (Skew.JavaScriptEmitter._shouldRenameSymbol(symbol3)) {\n          if (name == '') {\n            name = this._generateSymbolName(reservedNames);\n          }\n\n          symbol3.name = name;\n        }\n      }\n    }\n  };\n\n  // Merge local variables from different functions together in the order\n  // they were declared. This will cause every argument list to use the same\n  // variables in the same order, which should offer better gzip:\n  //\n  //   function d(a, b) {}\n  //   function e(a, b, c) {}\n  //\n  Skew.JavaScriptEmitter.prototype._aliasLocalVariables = function(unionFind, order) {\n    this._zipTogetherInOrder(unionFind, order, this._extractGroups(this._localVariableUnionFind, Skew.JavaScriptEmitter.ExtractGroupsMode.ONLY_LOCAL_VARIABLES));\n  };\n\n  // Merge all related types together into naming groups. This ensures names\n  // will be unique within a subclass hierarchy allowing names to be\n  // duplicated in separate subclass hierarchies.\n  Skew.JavaScriptEmitter.prototype._aliasUnrelatedProperties = function(unionFind, order) {\n    var relatedTypesUnionFind = new Skew.UnionFind().allocate2(this._allSymbols.length);\n\n    for (var i = 0, count1 = this._allSymbols.length; i < count1; i = i + 1 | 0) {\n      var symbol = in_List.get(this._allSymbols, i);\n\n      if (symbol.kind == Skew.SymbolKind.OBJECT_CLASS) {\n        var baseClass = symbol.asObjectSymbol().baseClass;\n\n        if (baseClass != null) {\n          relatedTypesUnionFind.union(i, in_IntMap.get1(this._namingGroupIndexForSymbol, baseClass.id));\n        }\n\n        for (var i1 = 0, list = symbol.asObjectSymbol().variables, count = list.length; i1 < count; i1 = i1 + 1 | 0) {\n          var variable = in_List.get(list, i1);\n          relatedTypesUnionFind.union(i, in_IntMap.get1(this._namingGroupIndexForSymbol, variable.id));\n        }\n      }\n    }\n\n    this._zipTogetherInOrder(unionFind, order, this._extractGroups(relatedTypesUnionFind, Skew.JavaScriptEmitter.ExtractGroupsMode.ONLY_INSTANCE_VARIABLES));\n  };\n\n  Skew.JavaScriptEmitter.prototype._zipTogetherInOrder = function(unionFind, order, groups) {\n    for (var i1 = 0, list = groups, count1 = list.length; i1 < count1; i1 = i1 + 1 | 0) {\n      var group = in_List.get(list, i1);\n\n      for (var i = 0, count = group.length; i < count; i = i + 1 | 0) {\n        var symbol = in_List.get(group, i);\n        var index = in_IntMap.get1(this._namingGroupIndexForSymbol, symbol.id);\n\n        if (i >= order.length) {\n          order.push(index);\n        }\n\n        else {\n          unionFind.union(index, in_List.get(order, i));\n        }\n      }\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._generateSymbolName = function(reservedNames) {\n    while (true) {\n      var name = Skew.JavaScriptEmitter._numberToName(this._nextSymbolName);\n      this._nextSymbolName = this._nextSymbolName + 1 | 0;\n\n      if (!reservedNames.has(name)) {\n        return name;\n      }\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._extractGroups = function(unionFind, mode) {\n    var labelToGroup = new Map();\n\n    for (var i = 0, list = this._allSymbols, count = list.length; i < count; i = i + 1 | 0) {\n      var symbol = in_List.get(list, i);\n\n      if (mode == Skew.JavaScriptEmitter.ExtractGroupsMode.ONLY_LOCAL_VARIABLES && !Skew.in_SymbolKind.isLocalOrArgumentVariable(symbol.kind) || mode == Skew.JavaScriptEmitter.ExtractGroupsMode.ONLY_INSTANCE_VARIABLES && symbol.kind != Skew.SymbolKind.VARIABLE_INSTANCE) {\n        continue;\n      }\n\n      assert(this._namingGroupIndexForSymbol.has(symbol.id));\n      var label = unionFind.find(in_IntMap.get1(this._namingGroupIndexForSymbol, symbol.id));\n      var group = in_IntMap.get(labelToGroup, label, null);\n\n      if (group == null) {\n        group = [];\n        in_IntMap.set(labelToGroup, label, group);\n      }\n\n      group.push(symbol);\n    }\n\n    // Sort each resulting group to make builds deterministic when maps use hashing\n    var groups = Array.from(labelToGroup.values());\n\n    for (var i1 = 0, list1 = groups, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n      var group1 = in_List.get(list1, i1);\n      group1.sort(Skew.Symbol.SORT_BY_ID);\n    }\n\n    return groups;\n  };\n\n  Skew.JavaScriptEmitter.prototype._addMapping = function(range) {\n    if (this._sourceMap && range != null) {\n      var source = range.source;\n      var start = range.start;\n\n      if (this._previousSource != source || this._previousStart != start) {\n        var location = source.indexToLineColumn(start);\n        this._generator.addMapping(source, location.line, location.column, this._currentLine, this._currentColumn);\n        this._previousStart = start;\n        this._previousSource = source;\n      }\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._emitSemicolonAfterStatement = function() {\n    if (!this._minify) {\n      this._emit(';\\n');\n    }\n\n    else {\n      this._needsSemicolon = true;\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._emitSemicolonIfNeeded = function() {\n    if (this._needsSemicolon) {\n      this._emit(';');\n      this._needsSemicolon = false;\n    }\n\n    this._maybeEmitMinifedNewline();\n  };\n\n  // Lots of text editors choke up on long lines, so add a newline every now\n  // and then for usability's sake\n  Skew.JavaScriptEmitter.prototype._maybeEmitMinifedNewline = function() {\n    if (this._minify && this._currentColumn > 1024) {\n      this._emit('\\n');\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._emitNewlineBeforeSymbol = function(symbol) {\n    this._emitSemicolonIfNeeded();\n\n    if (!this._minify && this._previousSymbol != null && (!Skew.in_SymbolKind.isObject(this._previousSymbol.kind) || !Skew.in_SymbolKind.isObject(symbol.kind) || symbol.comments != null || Skew.in_SymbolKind.isEnumOrFlags(this._previousSymbol.kind) || Skew.in_SymbolKind.isEnumOrFlags(symbol.kind)) && (!Skew.in_SymbolKind.isVariable(this._previousSymbol.kind) || !Skew.in_SymbolKind.isVariable(symbol.kind) || symbol.comments != null)) {\n      this._emit('\\n');\n    }\n\n    this._previousSymbol = null;\n    this._addMapping(symbol.range);\n  };\n\n  Skew.JavaScriptEmitter.prototype._emitNewlineAfterSymbol = function(symbol) {\n    this._previousSymbol = symbol;\n  };\n\n  Skew.JavaScriptEmitter.prototype._emitNewlineBeforeStatement = function(node) {\n    if (!this._minify && this._previousNode != null && (node.comments != null || !Skew.JavaScriptEmitter._isCompactNodeKind(this._previousNode.kind) || !Skew.JavaScriptEmitter._isCompactNodeKind(node.kind))) {\n      this._emit('\\n');\n    }\n\n    else {\n      this._maybeEmitMinifedNewline();\n    }\n\n    this._previousNode = null;\n  };\n\n  Skew.JavaScriptEmitter.prototype._emitNewlineAfterStatement = function(node) {\n    this._previousNode = node;\n  };\n\n  Skew.JavaScriptEmitter.prototype._emitComments = function(comments) {\n    if (comments != null && !this._minify) {\n      for (var i1 = 0, list1 = comments, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n        var comment = in_List.get(list1, i1);\n\n        for (var i = 0, list = comment.lines, count = list.length; i < count; i = i + 1 | 0) {\n          var line = in_List.get(list, i);\n          this._emit(this._indent + '//' + line + '\\n');\n        }\n\n        if (comment.hasGapBelow) {\n          this._emit('\\n');\n        }\n      }\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._emitObject = function(symbol) {\n    if (symbol.isImported()) {\n      return;\n    }\n\n    var foundPrimaryConstructor = false;\n    this._namespacePrefix = symbol.parent != null ? Skew.JavaScriptEmitter._computeNamespacePrefix(symbol.parent.asObjectSymbol()) : '';\n\n    switch (symbol.kind) {\n      case Skew.SymbolKind.OBJECT_NAMESPACE:\n      case Skew.SymbolKind.OBJECT_INTERFACE:\n      case Skew.SymbolKind.OBJECT_WRAPPED: {\n        if (symbol.forwardTo == null && symbol != this._exportsNamespace) {\n          this._emitNewlineBeforeSymbol(symbol);\n          this._emitComments(symbol.comments);\n          this._emit(this._indent + (this._namespacePrefix == '' ? 'var ' : this._namespacePrefix) + Skew.JavaScriptEmitter._mangleName(symbol) + this._space + '=' + this._space + '{}');\n          this._emitSemicolonAfterStatement();\n          this._emitNewlineAfterSymbol(symbol);\n        }\n        break;\n      }\n\n      case Skew.SymbolKind.OBJECT_ENUM:\n      case Skew.SymbolKind.OBJECT_FLAGS: {\n        this._emitNewlineBeforeSymbol(symbol);\n        this._emitComments(symbol.comments);\n        this._emit(this._indent + (this._namespacePrefix == '' ? 'var ' : this._namespacePrefix) + Skew.JavaScriptEmitter._mangleName(symbol) + this._space + '=' + this._space + '{');\n        this._increaseIndent();\n        var isFirst = true;\n\n        for (var i = 0, list = symbol.variables, count = list.length; i < count; i = i + 1 | 0) {\n          var variable = in_List.get(list, i);\n\n          if (variable.kind == Skew.SymbolKind.VARIABLE_ENUM_OR_FLAGS) {\n            if (isFirst) {\n              isFirst = false;\n            }\n\n            else {\n              this._emit(',');\n            }\n\n            this._emit(this._newline);\n            this._emitNewlineBeforeSymbol(variable);\n            this._emitComments(variable.comments);\n            this._emit(this._indent + Skew.JavaScriptEmitter._mangleName(variable) + ':' + this._space);\n            this._emitExpression(variable.value, Skew.Precedence.COMMA);\n            this._emitNewlineAfterSymbol(variable);\n          }\n        }\n\n        this._decreaseIndent();\n\n        if (!isFirst && !this._minify) {\n          this._emit('\\n' + this._indent);\n        }\n\n        this._emit('}');\n        this._emitSemicolonAfterStatement();\n        this._emitNewlineAfterSymbol(symbol);\n        break;\n      }\n\n      case Skew.SymbolKind.OBJECT_CLASS: {\n        var variable1 = in_IntMap.get1(this._specialVariables, Skew.JavaScriptEmitter.SpecialVariable.EXTENDS);\n\n        for (var i1 = 0, list1 = symbol.functions, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n          var $function = in_List.get(list1, i1);\n\n          if ($function.isPrimaryConstructor()) {\n            if ($function.comments == null && symbol.comments != null) {\n              $function.comments = symbol.comments;\n            }\n\n            this._emitFunction($function);\n\n            if (symbol.baseClass != null || symbol.kind == Skew.SymbolKind.OBJECT_CLASS && symbol.$extends != null) {\n              if (!this._minify) {\n                this._emit('\\n' + this._indent);\n              }\n\n              this._emitSemicolonIfNeeded();\n              this._addMapping(variable1.range);\n              this._emit(Skew.JavaScriptEmitter._mangleName(variable1) + '(' + Skew.JavaScriptEmitter._fullName(symbol) + ',' + this._space);\n\n              if (symbol.baseClass != null) {\n                this._emit(Skew.JavaScriptEmitter._fullName(symbol.baseClass));\n              }\n\n              else {\n                assert(symbol.kind == Skew.SymbolKind.OBJECT_CLASS && symbol.$extends != null);\n                this._emitExpression(symbol.$extends, Skew.Precedence.LOWEST);\n              }\n\n              this._emit(')');\n              this._emitSemicolonAfterStatement();\n            }\n\n            foundPrimaryConstructor = true;\n            break;\n          }\n        }\n\n        // Emit a namespace if the class is never constructed\n        if (!foundPrimaryConstructor) {\n          this._emitNewlineBeforeSymbol(symbol);\n          this._emit(this._indent + (this._namespacePrefix == '' && !symbol.isExported() ? 'var ' : this._namespacePrefix) + Skew.JavaScriptEmitter._mangleName(symbol) + this._space + '=' + this._space + '{}');\n          this._emitSemicolonAfterStatement();\n        }\n        break;\n      }\n    }\n\n    if (symbol.kind != Skew.SymbolKind.OBJECT_GLOBAL) {\n      this._namespacePrefix += Skew.JavaScriptEmitter._mangleName(symbol) + '.';\n    }\n\n    if (symbol.usePrototypeCache()) {\n      this._emitSemicolonIfNeeded();\n      this._emit(this._newline + this._indent + Skew.JavaScriptEmitter._mangleName(in_IntMap.get1(this._specialVariables, Skew.JavaScriptEmitter.SpecialVariable.PROTOTYPE)) + this._space + '=' + this._space + Skew.JavaScriptEmitter._fullName(symbol) + '.prototype');\n      this._emitSemicolonAfterStatement();\n    }\n\n    // Ignore instance functions if the class is never constructed\n    for (var i2 = 0, list2 = symbol.functions, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n      var function1 = in_List.get(list2, i2);\n\n      if (foundPrimaryConstructor ? !function1.isPrimaryConstructor() : function1.kind == Skew.SymbolKind.FUNCTION_GLOBAL) {\n        this._emitFunction(function1);\n      }\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._emitArgumentList = function($arguments) {\n    for (var i = 0, list = $arguments, count = list.length; i < count; i = i + 1 | 0) {\n      var argument = in_List.get(list, i);\n\n      if (argument != in_List.first($arguments)) {\n        this._emit(',' + this._space);\n      }\n\n      this._addMapping(argument.range);\n      this._emit(Skew.JavaScriptEmitter._mangleName(argument));\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._emitFunction = function(symbol) {\n    if (symbol.block == null) {\n      return;\n    }\n\n    this._emitNewlineBeforeSymbol(symbol);\n    this._emitComments(symbol.comments);\n    var isExpression = this._namespacePrefix != '' || symbol.isExported();\n    var name = Skew.JavaScriptEmitter._mangleName(symbol.isPrimaryConstructor() ? symbol.parent : symbol);\n\n    if (isExpression) {\n      this._emit(this._indent + (symbol.kind != Skew.SymbolKind.FUNCTION_INSTANCE ? this._namespacePrefix : symbol.parent.usePrototypeCache() ? Skew.JavaScriptEmitter._mangleName(in_IntMap.get1(this._specialVariables, Skew.JavaScriptEmitter.SpecialVariable.PROTOTYPE)) + '.' : this._namespacePrefix + 'prototype.') + name + this._space + '=' + this._space + 'function(');\n    }\n\n    else {\n      this._emit(this._indent + 'function ' + name + '(');\n    }\n\n    this._emitArgumentList(symbol.$arguments);\n    this._emit(')' + this._space + '{' + this._newline);\n    this._increaseIndent();\n    this._enclosingFunction = symbol;\n    this._emitStatements(symbol.block);\n    this._enclosingFunction = null;\n    this._decreaseIndent();\n    this._emit(this._indent + '}');\n\n    if (isExpression) {\n      this._emitSemicolonAfterStatement();\n    }\n\n    else {\n      this._needsSemicolon = false;\n      this._emit(this._newline);\n    }\n\n    this._emitNewlineAfterSymbol(symbol);\n\n    // Secondary constructors need the same prototype as the primary constructor\n    if (symbol.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR && !symbol.isPrimaryConstructor()) {\n      this._emitSemicolonIfNeeded();\n      this._emit(this._newline + this._indent + Skew.JavaScriptEmitter._fullName(symbol) + '.prototype' + this._space + '=' + this._space + (symbol.parent.usePrototypeCache() ? Skew.JavaScriptEmitter._mangleName(in_IntMap.get1(this._specialVariables, Skew.JavaScriptEmitter.SpecialVariable.PROTOTYPE)) : Skew.JavaScriptEmitter._fullName(symbol.parent) + '.prototype'));\n      this._emitSemicolonAfterStatement();\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._emitVariable = function(symbol) {\n    if (symbol.isImported()) {\n      return;\n    }\n\n    if (symbol.kind != Skew.SymbolKind.VARIABLE_INSTANCE && symbol.kind != Skew.SymbolKind.VARIABLE_ENUM_OR_FLAGS && (symbol.value != null || this._namespacePrefix == '' || Skew.in_SymbolKind.isLocalOrArgumentVariable(symbol.kind))) {\n      this._emitNewlineBeforeSymbol(symbol);\n      this._emitComments(symbol.comments);\n      this._emit(this._indent + (this._namespacePrefix == '' || Skew.in_SymbolKind.isLocalOrArgumentVariable(symbol.kind) ? 'var ' : this._namespacePrefix) + Skew.JavaScriptEmitter._mangleName(symbol));\n\n      if (symbol.value != null) {\n        this._emit(this._space + '=' + this._space);\n        this._emitExpression(symbol.value, Skew.Precedence.COMMA);\n      }\n\n      this._emitSemicolonAfterStatement();\n      this._emitNewlineAfterSymbol(symbol);\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._emitStatements = function(node) {\n    this._previousNode = null;\n\n    for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n      this._emitSemicolonIfNeeded();\n      this._emitNewlineBeforeStatement(child);\n      this._addMapping(child.range);\n      this._emitComments(child.comments);\n      this._emitStatement(child);\n      this._emitNewlineAfterStatement(child);\n    }\n\n    this._previousNode = null;\n  };\n\n  Skew.JavaScriptEmitter.prototype._emitBlock = function(node, after, mode) {\n    var shouldMinify = mode == Skew.JavaScriptEmitter.BracesMode.CAN_OMIT_BRACES && this._minify;\n    this._addMapping(node.range);\n\n    if (shouldMinify && !node.hasChildren()) {\n      this._emit(';');\n    }\n\n    else if (shouldMinify && node.hasOneChild() && node.firstChild().kind != Skew.NodeKind.COMMENT_BLOCK) {\n      if (after == Skew.JavaScriptEmitter.AfterToken.AFTER_KEYWORD) {\n        this._emit(' ');\n      }\n\n      this._emitStatement(node.firstChild());\n    }\n\n    else {\n      this._emit(this._space + '{' + this._newline);\n\n      if (node.hasChildren()) {\n        this._increaseIndent();\n        this._emitStatements(node);\n        this._decreaseIndent();\n      }\n\n      this._emit(this._indent + '}');\n      this._needsSemicolon = false;\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._emitVariables = function(node) {\n    this._emit('var ');\n\n    for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n      if (child.previousSibling() != null) {\n        this._emit(',' + this._space);\n      }\n\n      var symbol = child.symbol.asVariableSymbol();\n      this._emit(Skew.JavaScriptEmitter._mangleName(symbol));\n\n      if (symbol.value != null) {\n        this._emit(this._space + '=' + this._space);\n        this._emitExpression(symbol.value, Skew.Precedence.COMMA);\n      }\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._canRemoveSpaceBeforeKeyword = function(node) {\n    var kind = node.kind;\n    return Skew.in_NodeKind.isUnary(kind) && !Skew.in_NodeKind.isUnaryPostfix(kind) || node.isString() || node.isNumberLessThanZero() || Skew.in_NodeKind.isInitializer(kind) || (kind == Skew.NodeKind.HOOK || kind == Skew.NodeKind.SEQUENCE) && this._canRemoveSpaceBeforeKeyword(node.firstChild());\n  };\n\n  Skew.JavaScriptEmitter.prototype._emitSpaceBeforeKeyword = function(node) {\n    if (!this._minify || !this._canRemoveSpaceBeforeKeyword(node)) {\n      this._emit(' ');\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._emitStatement = function(node) {\n    switch (node.kind) {\n      case Skew.NodeKind.COMMENT_BLOCK: {\n        break;\n      }\n\n      case Skew.NodeKind.VARIABLES: {\n        this._emit(this._indent);\n        this._emitVariables(node);\n        this._emitSemicolonAfterStatement();\n        break;\n      }\n\n      case Skew.NodeKind.EXPRESSION: {\n        this._emit(this._indent);\n        this._emitExpression(node.expressionValue(), Skew.Precedence.LOWEST);\n        this._emitSemicolonAfterStatement();\n        break;\n      }\n\n      case Skew.NodeKind.BREAK: {\n        var label = in_IntMap.get(this._loopLabels, node.id, null);\n        this._emit(this._indent + 'break');\n\n        if (label != null) {\n          this._emit(' ' + Skew.JavaScriptEmitter._mangleName(label));\n        }\n\n        this._emitSemicolonAfterStatement();\n        break;\n      }\n\n      case Skew.NodeKind.CONTINUE: {\n        this._emit(this._indent + 'continue');\n        this._emitSemicolonAfterStatement();\n        break;\n      }\n\n      case Skew.NodeKind.RETURN: {\n        this._emit(this._indent + 'return');\n        var value = node.returnValue();\n\n        if (value != null) {\n          var comments = value.comments;\n\n          if (!this._minify && comments != null) {\n            // JavaScript needs parentheses here to avoid ASI issues\n            this._emit(' (\\n');\n            this._increaseIndent();\n            this._emitComments(comments);\n            this._emit(this._indent);\n            this._emitExpression(value, Skew.Precedence.LOWEST);\n            this._decreaseIndent();\n            this._emit(')');\n          }\n\n          else {\n            this._emitSpaceBeforeKeyword(value);\n            this._emitExpression(value, Skew.Precedence.LOWEST);\n          }\n        }\n\n        this._emitSemicolonAfterStatement();\n        break;\n      }\n\n      case Skew.NodeKind.THROW: {\n        var value1 = node.throwValue();\n        this._emit(this._indent + 'throw');\n        this._emitSpaceBeforeKeyword(value1);\n        this._emitExpression(value1, Skew.Precedence.LOWEST);\n        this._emitSemicolonAfterStatement();\n        break;\n      }\n\n      case Skew.NodeKind.FOR: {\n        var setup = node.forSetup();\n        var test = node.forTest();\n        var update = node.forUpdate();\n        this._emit(this._indent);\n        this._emitLoopLabel(node);\n        this._emit('for' + this._space + '(');\n\n        if (!setup.isEmptySequence()) {\n          this._parenthesizeInExpressions = this._parenthesizeInExpressions + 1 | 0;\n\n          if (setup.kind == Skew.NodeKind.VARIABLES) {\n            this._emitVariables(setup);\n          }\n\n          else {\n            this._emitExpression(setup, Skew.Precedence.LOWEST);\n          }\n\n          this._parenthesizeInExpressions = this._parenthesizeInExpressions - 1 | 0;\n        }\n\n        this._emit(';');\n\n        if (!test.isEmptySequence()) {\n          this._emit(this._space);\n          this._emitExpression(test, Skew.Precedence.LOWEST);\n        }\n\n        this._emit(';');\n\n        if (!update.isEmptySequence()) {\n          this._emit(this._space);\n          this._emitExpression(update, Skew.Precedence.LOWEST);\n        }\n\n        this._emit(')');\n        this._emitBlock(node.forBlock(), Skew.JavaScriptEmitter.AfterToken.AFTER_PARENTHESIS, Skew.JavaScriptEmitter.BracesMode.CAN_OMIT_BRACES);\n        this._emit(this._newline);\n        break;\n      }\n\n      case Skew.NodeKind.FOREACH: {\n        this._emit(this._indent);\n        this._emitLoopLabel(node);\n        this._emit('for' + this._space + '(var ' + Skew.JavaScriptEmitter._mangleName(node.symbol) + ' in ');\n        this._emitExpression(node.foreachValue(), Skew.Precedence.LOWEST);\n        this._emit(')');\n        this._emitBlock(node.foreachBlock(), Skew.JavaScriptEmitter.AfterToken.AFTER_PARENTHESIS, Skew.JavaScriptEmitter.BracesMode.CAN_OMIT_BRACES);\n        this._emit(this._newline);\n        break;\n      }\n\n      case Skew.NodeKind.IF: {\n        this._emit(this._indent);\n        this._emitIf(node);\n        this._emit(this._newline);\n        break;\n      }\n\n      case Skew.NodeKind.SWITCH: {\n        var switchValue = node.switchValue();\n        this._emit(this._indent + 'switch' + this._space + '(');\n        this._emitExpression(switchValue, Skew.Precedence.LOWEST);\n        this._emit(')' + this._space + '{' + this._newline);\n        this._increaseIndent();\n\n        for (var child = switchValue.nextSibling(); child != null; child = child.nextSibling()) {\n          var block = child.caseBlock();\n          this._emitSemicolonIfNeeded();\n\n          if (child.previousSibling() != switchValue) {\n            this._emit(this._newline);\n          }\n\n          this._emitComments(child.comments);\n\n          if (child.hasOneChild()) {\n            this._emit(this._indent + 'default:');\n          }\n\n          else {\n            for (var value2 = child.firstChild(); value2 != block; value2 = value2.nextSibling()) {\n              if (value2.previousSibling() != null) {\n                this._emit(this._newline);\n              }\n\n              this._emitComments(value2.comments);\n              this._emit(this._indent + 'case');\n              this._emitSpaceBeforeKeyword(value2);\n              this._emitExpression(value2, Skew.Precedence.LOWEST);\n              this._emit(':');\n            }\n          }\n\n          if (!this._minify) {\n            this._emit(' {\\n');\n            this._increaseIndent();\n          }\n\n          this._emitStatements(block);\n\n          if (block.hasControlFlowAtEnd()) {\n            this._emitSemicolonIfNeeded();\n            this._emit(this._indent + 'break');\n            this._emitSemicolonAfterStatement();\n          }\n\n          if (!this._minify) {\n            this._decreaseIndent();\n            this._emit(this._indent + '}\\n');\n          }\n        }\n\n        this._decreaseIndent();\n        this._emit(this._indent + '}' + this._newline);\n        this._needsSemicolon = false;\n        break;\n      }\n\n      case Skew.NodeKind.TRY: {\n        var tryBlock = node.tryBlock();\n        var finallyBlock = node.finallyBlock();\n        this._emit(this._indent + 'try');\n        this._emitBlock(tryBlock, Skew.JavaScriptEmitter.AfterToken.AFTER_KEYWORD, Skew.JavaScriptEmitter.BracesMode.MUST_KEEP_BRACES);\n        this._emit(this._newline);\n\n        for (var child1 = tryBlock.nextSibling(); child1 != finallyBlock; child1 = child1.nextSibling()) {\n          this._emit(this._newline);\n          this._emitComments(child1.comments);\n          this._emit(this._indent + 'catch' + this._space + '(' + Skew.JavaScriptEmitter._mangleName(child1.symbol) + ')');\n          this._emitBlock(child1.catchBlock(), Skew.JavaScriptEmitter.AfterToken.AFTER_KEYWORD, Skew.JavaScriptEmitter.BracesMode.MUST_KEEP_BRACES);\n          this._emit(this._newline);\n        }\n\n        if (finallyBlock != null) {\n          this._emit(this._newline);\n          this._emitComments(finallyBlock.comments);\n          this._emit(this._indent + 'finally');\n          this._emitBlock(finallyBlock, Skew.JavaScriptEmitter.AfterToken.AFTER_KEYWORD, Skew.JavaScriptEmitter.BracesMode.MUST_KEEP_BRACES);\n          this._emit(this._newline);\n        }\n        break;\n      }\n\n      case Skew.NodeKind.WHILE: {\n        this._emit(this._indent);\n        this._emitLoopLabel(node);\n        this._emit('while' + this._space + '(');\n        this._emitExpression(node.whileTest(), Skew.Precedence.LOWEST);\n        this._emit(')');\n        this._emitBlock(node.whileBlock(), Skew.JavaScriptEmitter.AfterToken.AFTER_PARENTHESIS, Skew.JavaScriptEmitter.BracesMode.CAN_OMIT_BRACES);\n        this._emit(this._newline);\n        break;\n      }\n\n      default: {\n        assert(false);\n        break;\n      }\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._emitLoopLabel = function(node) {\n    var label = in_IntMap.get(this._loopLabels, node.id, null);\n\n    if (label != null) {\n      this._emit(Skew.JavaScriptEmitter._mangleName(label) + ':' + this._space);\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._emitIf = function(node) {\n    var trueBlock = node.ifTrue();\n    var falseBlock = node.ifFalse();\n    this._emit('if' + this._space + '(');\n    this._emitExpression(node.ifTest(), Skew.Precedence.LOWEST);\n    this._emit(')');\n\n    // Make sure to always keep braces to avoid the dangling \"else\" case\n    // \"if (a) if (b) c; else d; else e;\"\n    // \"if (a) { if (b) if (c) d; else e; } else f;\"\n    // \"if (a) { if (b) c; else if (d) e; } else f;\"\n    // \"if (a) { while (true) if (b) break; } else c;\"\n    var braces = Skew.JavaScriptEmitter.BracesMode.CAN_OMIT_BRACES;\n\n    if (falseBlock != null) {\n      var statement = trueBlock.blockStatement();\n\n      if (statement != null && (statement.kind == Skew.NodeKind.IF || statement.kind == Skew.NodeKind.FOR && statement.forBlock().blockStatement() != null || statement.kind == Skew.NodeKind.FOREACH && statement.foreachBlock().blockStatement() != null || statement.kind == Skew.NodeKind.WHILE && statement.whileBlock().blockStatement() != null)) {\n        braces = Skew.JavaScriptEmitter.BracesMode.MUST_KEEP_BRACES;\n      }\n    }\n\n    this._emitBlock(node.ifTrue(), Skew.JavaScriptEmitter.AfterToken.AFTER_PARENTHESIS, braces);\n\n    if (falseBlock != null) {\n      var singleIf = Skew.JavaScriptEmitter._singleIf(falseBlock);\n      this._emitSemicolonIfNeeded();\n      this._emit(this._newline + this._newline);\n      this._emitComments(falseBlock.comments);\n\n      if (singleIf != null) {\n        this._emitComments(singleIf.comments);\n      }\n\n      this._emit(this._indent + 'else');\n\n      if (singleIf != null) {\n        this._emit(' ');\n        this._emitIf(singleIf);\n      }\n\n      else {\n        this._emitBlock(falseBlock, Skew.JavaScriptEmitter.AfterToken.AFTER_KEYWORD, Skew.JavaScriptEmitter.BracesMode.CAN_OMIT_BRACES);\n      }\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._emitContent = function(content) {\n    switch (content.kind()) {\n      case Skew.ContentKind.BOOL: {\n        this._emit(Skew.in_Content.asBool(content).toString());\n        break;\n      }\n\n      case Skew.ContentKind.INT: {\n        this._emit(Skew.in_Content.asInt(content).toString());\n        break;\n      }\n\n      case Skew.ContentKind.DOUBLE: {\n        var value = Skew.in_Content.asDouble(content);\n        var text = isNaN(value) ? 'NaN' : value == 1 / 0 ? 'Infinity' : value == -(1 / 0) ? '-Infinity' :\n          // The C# implementation of double.ToString() uses an uppercase \"E\"\n          TARGET == Target.CSHARP ? value.toString().toLowerCase() : value.toString();\n\n        // \"0.123\" => \".123\"\n        // \"-0.123\" => \"-.123\"\n        if (this._minify) {\n          if (text.startsWith('0.') && text != '0.') {\n            text = in_string.slice1(text, 1);\n          }\n\n          else if (text.startsWith('-0.') && text != '-0.') {\n            text = '-' + in_string.slice1(text, 2);\n          }\n        }\n\n        this._emit(text);\n        break;\n      }\n\n      case Skew.ContentKind.STRING: {\n        this._emit(Skew.quoteString(Skew.in_Content.asString(content), Skew.QuoteStyle.SHORTEST, Skew.QuoteOctal.OCTAL_WORKAROUND));\n        break;\n      }\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._emitCommaSeparatedExpressions = function(from, to) {\n    while (from != to) {\n      this._emitExpression(from, Skew.Precedence.COMMA);\n      from = from.nextSibling();\n\n      if (from != to) {\n        this._emit(',' + this._space);\n        this._maybeEmitMinifedNewline();\n      }\n    }\n  };\n\n  // Calling a function in an expression that starts with something like \"function(){}()\"\n  // must be wrapped in parentheses to avoid looking like a function statement\n  Skew.JavaScriptEmitter.prototype._lambdaMayNeedParentheses = function(node) {\n    var parent = node.parent();\n\n    if (parent == null) {\n      // Expression statements always have parents\n      return false;\n    }\n\n    switch (parent.kind) {\n      case Skew.NodeKind.CALL: {\n        return node == parent.callValue() && this._lambdaMayNeedParentheses(parent);\n      }\n\n      case Skew.NodeKind.DOT: {\n        return this._lambdaMayNeedParentheses(parent);\n      }\n\n      case Skew.NodeKind.INDEX: {\n        return node == parent.indexLeft() && this._lambdaMayNeedParentheses(parent);\n      }\n\n      case Skew.NodeKind.ASSIGN_INDEX: {\n        return node == parent.assignIndexLeft() && this._lambdaMayNeedParentheses(parent);\n      }\n\n      default: {\n        if (Skew.in_NodeKind.isBinary(parent.kind)) {\n          return node == parent.binaryLeft() && this._lambdaMayNeedParentheses(parent);\n        }\n\n        // Not sure, wrap to be safe\n        return true;\n      }\n    }\n  };\n\n  // Returns true if the provided call node must be parenthesized due to being inside a dot expression\n  Skew.JavaScriptEmitter.prototype._checkForDotParentOfCall = function(node) {\n    assert(node.kind == Skew.NodeKind.CALL);\n    var p = node.parent();\n\n    label: while (p != null) {\n      switch (p.kind) {\n        case Skew.NodeKind.CAST:\n        case Skew.NodeKind.PARAMETERIZE: {\n          p = p.parent();\n          break;\n        }\n\n        case Skew.NodeKind.DOT: {\n          return true;\n        }\n\n        default: {\n          break label;\n        }\n      }\n    }\n\n    return false;\n  };\n\n  Skew.JavaScriptEmitter.prototype._emitExpression = function(node, precedence) {\n    var kind = node.kind;\n    this._addMapping(node.range);\n\n    switch (kind) {\n      case Skew.NodeKind.TYPE: {\n        this._emit(Skew.JavaScriptEmitter._fullName(node.resolvedType.symbol));\n        break;\n      }\n\n      case Skew.NodeKind.NULL: {\n        this._emit('null');\n        break;\n      }\n\n      case Skew.NodeKind.NAME: {\n        var symbol = node.symbol;\n        this._emit(symbol != null ? Skew.JavaScriptEmitter._fullName(symbol) : node.asString());\n        break;\n      }\n\n      case Skew.NodeKind.DOT: {\n        this._emitExpression(node.dotTarget(), Skew.Precedence.MEMBER);\n        this._emit('.' + (node.symbol != null ? Skew.JavaScriptEmitter._mangleName(node.symbol) : node.asString()));\n        break;\n      }\n\n      case Skew.NodeKind.CONSTANT: {\n        var wrap = precedence == Skew.Precedence.MEMBER && (node.isInt() || node.isDouble() && (isFinite(node.asDouble()) || node.asDouble() < 0));\n\n        if (wrap) {\n          this._emit('(');\n        }\n\n        // Prevent \"x - -1\" from becoming \"x--1\"\n        if (this._minify && node.isNumberLessThanZero() && this._previousCodeUnit == 45) {\n          this._emit(' ');\n        }\n\n        this._emitContent(node.content);\n\n        if (wrap) {\n          this._emit(')');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.CALL: {\n        var value = node.callValue();\n        var call = value.kind == Skew.NodeKind.SUPER;\n        var isKeyword = value.kind == Skew.NodeKind.NAME && value.symbol == null && Skew.JavaScriptEmitter._keywordCallMap.has(value.asString());\n        var parenthesize = isKeyword && Skew.Precedence.UNARY_POSTFIX < precedence;\n        var wrap1 = value.kind == Skew.NodeKind.LAMBDA && this._lambdaMayNeedParentheses(node);\n        var isNew = false;\n\n        if (parenthesize) {\n          this._emit('(');\n        }\n\n        if (wrap1) {\n          this._emit('(');\n        }\n\n        if (!call && node.symbol != null && node.symbol.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n          this._emit('new ' + Skew.JavaScriptEmitter._fullName(node.symbol));\n          isNew = true;\n        }\n\n        else if (!call && value.kind == Skew.NodeKind.DOT && value.asString() == 'new') {\n          this._emit('new ');\n          this._emitExpression(value.dotTarget(), Skew.Precedence.MEMBER);\n          isNew = true;\n        }\n\n        else {\n          this._emitExpression(value, Skew.Precedence.UNARY_POSTFIX);\n\n          if (call) {\n            this._emit('.call');\n          }\n        }\n\n        if (wrap1) {\n          this._emit(')');\n        }\n\n        // Omit parentheses during mangling when possible\n        if (!isNew || !this._mangle || call || value.nextSibling() != null || this._checkForDotParentOfCall(node)) {\n          this._emit(isKeyword ? ' ' : '(');\n\n          if (call) {\n            this._emit(Skew.JavaScriptEmitter._mangleName(this._enclosingFunction.$this));\n          }\n\n          for (var child = value.nextSibling(); child != null; child = child.nextSibling()) {\n            if (call || child.previousSibling() != value) {\n              this._emit(',' + this._space);\n              this._maybeEmitMinifedNewline();\n            }\n\n            this._emitExpression(child, Skew.Precedence.COMMA);\n          }\n\n          if (!isKeyword) {\n            this._emit(')');\n          }\n        }\n\n        if (parenthesize) {\n          this._emit(')');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.INITIALIZER_LIST:\n      case Skew.NodeKind.INITIALIZER_MAP: {\n        var useBraces = kind == Skew.NodeKind.INITIALIZER_MAP;\n        var isIndented = false;\n\n        if (!this._minify) {\n          for (var child1 = node.firstChild(); child1 != null; child1 = child1.nextSibling()) {\n            if (child1.comments != null) {\n              isIndented = true;\n              break;\n            }\n          }\n        }\n\n        this._emit(useBraces ? '{' : '[');\n\n        if (isIndented) {\n          this._increaseIndent();\n        }\n\n        for (var child2 = node.firstChild(); child2 != null; child2 = child2.nextSibling()) {\n          if (child2.previousSibling() != null) {\n            this._emit(',' + (isIndented ? '' : this._space));\n            this._maybeEmitMinifedNewline();\n          }\n\n          if (isIndented) {\n            this._emit('\\n');\n            this._emitComments(child2.comments);\n            this._emit(this._indent);\n          }\n\n          this._emitExpression(child2, Skew.Precedence.COMMA);\n        }\n\n        if (isIndented) {\n          this._decreaseIndent();\n          this._emit('\\n' + this._indent);\n        }\n\n        this._emit(useBraces ? '}' : ']');\n        break;\n      }\n\n      case Skew.NodeKind.PAIR: {\n        this._emitExpression(node.firstValue(), Skew.Precedence.LOWEST);\n        this._emit(':' + this._space);\n        this._emitExpression(node.secondValue(), Skew.Precedence.LOWEST);\n        break;\n      }\n\n      case Skew.NodeKind.INDEX: {\n        this._emitExpression(node.indexLeft(), Skew.Precedence.UNARY_POSTFIX);\n        this._emit('[');\n        this._emitExpression(node.indexRight(), Skew.Precedence.LOWEST);\n        this._emit(']');\n        break;\n      }\n\n      case Skew.NodeKind.ASSIGN_INDEX: {\n        if (Skew.Precedence.ASSIGN < precedence) {\n          this._emit('(');\n        }\n\n        this._emitExpression(node.assignIndexLeft(), Skew.Precedence.UNARY_POSTFIX);\n        this._emit('[');\n        this._emitExpression(node.assignIndexCenter(), Skew.Precedence.LOWEST);\n        this._emit(']' + this._space + '=' + this._space + '');\n        this._emitExpression(node.assignIndexRight(), Skew.Precedence.ASSIGN);\n\n        if (Skew.Precedence.ASSIGN < precedence) {\n          this._emit(')');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.CAST: {\n        this._emitExpression(node.castValue(), precedence);\n        break;\n      }\n\n      case Skew.NodeKind.PARAMETERIZE: {\n        this._emitExpression(node.parameterizeValue(), precedence);\n        break;\n      }\n\n      case Skew.NodeKind.SEQUENCE: {\n        if (Skew.Precedence.COMMA <= precedence) {\n          this._emit('(');\n        }\n\n        this._emitCommaSeparatedExpressions(node.firstChild(), null);\n\n        if (Skew.Precedence.COMMA <= precedence) {\n          this._emit(')');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.SUPER: {\n        this._emit(Skew.JavaScriptEmitter._fullName(node.symbol));\n        break;\n      }\n\n      case Skew.NodeKind.HOOK: {\n        if (Skew.Precedence.ASSIGN < precedence) {\n          this._emit('(');\n        }\n\n        this._emitExpression(node.hookTest(), Skew.Precedence.LOGICAL_OR);\n        this._emit(this._space + '?');\n        var left = node.hookTrue();\n\n        if (left.comments != null) {\n          this._emit(this._newline);\n          this._increaseIndent();\n          this._emitComments(left.comments);\n          this._emit(this._indent);\n          this._emitExpression(left, Skew.Precedence.ASSIGN);\n          this._decreaseIndent();\n        }\n\n        else {\n          this._emit(this._space);\n          this._emitExpression(left, Skew.Precedence.ASSIGN);\n        }\n\n        this._emit(this._space + ':');\n        var right = node.hookFalse();\n\n        if (right.comments != null) {\n          this._emit(this._newline);\n          this._increaseIndent();\n          this._emitComments(right.comments);\n          this._emit(this._indent);\n          this._emitExpression(right, Skew.Precedence.ASSIGN);\n          this._decreaseIndent();\n        }\n\n        else {\n          this._emit(this._space);\n          this._emitExpression(right, Skew.Precedence.ASSIGN);\n        }\n\n        if (Skew.Precedence.ASSIGN < precedence) {\n          this._emit(')');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.LAMBDA: {\n        var symbol1 = node.symbol.asFunctionSymbol();\n        this._emit('function(');\n        this._emitArgumentList(symbol1.$arguments);\n        this._emit(')');\n        this._emitBlock(symbol1.block, Skew.JavaScriptEmitter.AfterToken.AFTER_PARENTHESIS, Skew.JavaScriptEmitter.BracesMode.MUST_KEEP_BRACES);\n        break;\n      }\n\n      case Skew.NodeKind.COMPLEMENT:\n      case Skew.NodeKind.NEGATIVE:\n      case Skew.NodeKind.NOT:\n      case Skew.NodeKind.POSITIVE:\n      case Skew.NodeKind.POSTFIX_DECREMENT:\n      case Skew.NodeKind.POSTFIX_INCREMENT:\n      case Skew.NodeKind.PREFIX_DECREMENT:\n      case Skew.NodeKind.PREFIX_INCREMENT: {\n        var value1 = node.unaryValue();\n        var info = in_IntMap.get1(Skew.operatorInfo, kind);\n\n        if (info.precedence < precedence) {\n          this._emit('(');\n        }\n\n        if (Skew.in_NodeKind.isUnaryPostfix(kind)) {\n          this._emitExpression(value1, info.precedence);\n          this._emit(info.text);\n        }\n\n        else {\n          // Prevent \"x - -1\" from becoming \"x--1\"\n          if (this._minify && (kind == Skew.NodeKind.POSITIVE || kind == Skew.NodeKind.NEGATIVE || kind == Skew.NodeKind.PREFIX_INCREMENT || kind == Skew.NodeKind.PREFIX_DECREMENT) && in_string.get1(info.text, 0) == this._previousCodeUnit) {\n            this._emit(' ');\n          }\n\n          this._emit(info.text);\n          this._emitExpression(value1, info.precedence);\n        }\n\n        if (info.precedence < precedence) {\n          this._emit(')');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.TYPE_CHECK: {\n        var type = node.typeCheckType();\n        var resolvedType = type.resolvedType;\n\n        if (resolvedType.isWrapped()) {\n          resolvedType = this._cache.unwrappedType(resolvedType);\n        }\n\n        if (resolvedType.kind == Skew.TypeKind.SYMBOL || type.kind != Skew.NodeKind.TYPE) {\n          if (Skew.Precedence.COMPARE < precedence) {\n            this._emit('(');\n          }\n\n          this._emitExpression(node.typeCheckValue(), Skew.Precedence.COMPARE);\n          this._emit(' instanceof ');\n\n          if (resolvedType.kind == Skew.TypeKind.SYMBOL) {\n            this._emit(Skew.JavaScriptEmitter._fullName(resolvedType.symbol));\n          }\n\n          else {\n            this._emitExpression(type, Skew.Precedence.COMPARE);\n          }\n\n          if (Skew.Precedence.COMPARE < precedence) {\n            this._emit(')');\n          }\n        }\n\n        else {\n          this._emitExpression(node.typeCheckValue(), precedence);\n        }\n        break;\n      }\n\n      default: {\n        if (Skew.in_NodeKind.isBinary(kind)) {\n          var info1 = in_IntMap.get1(Skew.operatorInfo, kind);\n          var left1 = node.binaryLeft();\n          var right1 = node.binaryRight();\n          var extraEquals = left1.resolvedType == Skew.Type.DYNAMIC || right1.resolvedType == Skew.Type.DYNAMIC ? '=' : '';\n          var needsParentheses = info1.precedence < precedence || kind == Skew.NodeKind.IN && this._parenthesizeInExpressions != 0;\n\n          if (needsParentheses) {\n            this._emit('(');\n          }\n\n          this._emitExpression(node.binaryLeft(), info1.precedence + (info1.associativity == Skew.Associativity.RIGHT | 0) | 0);\n\n          // Always emit spaces around keyword operators, even when minifying\n          var comments = this._minify ? null : right1.comments;\n          this._emit(kind == Skew.NodeKind.IN ? (left1.isString() ? this._space : ' ') + 'in' + (comments != null ? '' : ' ') : this._space + (kind == Skew.NodeKind.EQUAL ? '==' + extraEquals : kind == Skew.NodeKind.NOT_EQUAL ? '!=' + extraEquals : info1.text));\n\n          if (comments != null) {\n            this._emit(this._newline);\n            this._increaseIndent();\n            this._emitComments(comments);\n            this._emit(this._indent);\n            this._emitExpression(right1, info1.precedence + (info1.associativity == Skew.Associativity.LEFT | 0) | 0);\n            this._decreaseIndent();\n          }\n\n          else {\n            if (kind != Skew.NodeKind.IN) {\n              this._emit(this._space);\n            }\n\n            this._emitExpression(right1, info1.precedence + (info1.associativity == Skew.Associativity.LEFT | 0) | 0);\n          }\n\n          if (needsParentheses) {\n            this._emit(')');\n          }\n        }\n\n        else {\n          assert(false);\n        }\n        break;\n      }\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._patchObject = function(symbol) {\n    this._allocateNamingGroupIndex(symbol);\n\n    // Subclasses need the extension stub\n    if (!symbol.isImported() && (symbol.baseClass != null || symbol.kind == Skew.SymbolKind.OBJECT_CLASS && symbol.$extends != null)) {\n      this._specialVariable(Skew.JavaScriptEmitter.SpecialVariable.EXTENDS);\n      this._specialVariable(Skew.JavaScriptEmitter.SpecialVariable.CREATE);\n    }\n\n    // Scan over child objects\n    for (var i = 0, list = symbol.objects, count = list.length; i < count; i = i + 1 | 0) {\n      var object = in_List.get(list, i);\n      this._patchObject(object);\n\n      if (symbol == this._global && object.isExported()) {\n        this._symbolsToExport.push(object);\n      }\n    }\n\n    // Scan over child functions\n    var isPrimaryConstructor = true;\n    var prototypeCount = 0;\n\n    for (var i2 = 0, list2 = symbol.functions, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n      var $function = in_List.get(list2, i2);\n      var block = $function.block;\n      var $this = $function.$this;\n      this._allocateNamingGroupIndex($function);\n\n      // Check to see if we need an explicit \"self\" parameter while patching the block\n      this._needsSelf = false;\n      this._currentSelf = $this;\n      this._enclosingFunction = $function;\n      this._patchNode(block);\n      this._enclosingFunction = null;\n\n      // Only insert the \"self\" variable if required to handle capture inside lambdas\n      if (this._needsSelf) {\n        this._unionVariableWithFunction($this, $function);\n\n        if (block != null) {\n          $this.kind = Skew.SymbolKind.VARIABLE_LOCAL;\n          $this.value = new Skew.Node(Skew.NodeKind.NAME).withContent(new Skew.StringContent('this')).withType(Skew.Type.DYNAMIC);\n          var variable = Skew.Node.createVariable($this);\n          var merged = false;\n\n          // When mangling, add the \"self\" variable to an existing variable statement if present\n          if (this._mangle && block.hasChildren()) {\n            var firstChild = block.firstChild();\n\n            if (firstChild.kind == Skew.NodeKind.VARIABLES) {\n              firstChild.prependChild(variable);\n              merged = true;\n            }\n\n            else if (firstChild.kind == Skew.NodeKind.FOR) {\n              if (firstChild.forSetup().kind == Skew.NodeKind.VARIABLES) {\n                firstChild.forSetup().prependChild(variable);\n                merged = true;\n              }\n\n              else if (firstChild.forSetup().isEmptySequence()) {\n                firstChild.forSetup().replaceWith(new Skew.Node(Skew.NodeKind.VARIABLES).appendChild(variable));\n                merged = true;\n              }\n            }\n          }\n\n          if (!merged) {\n            block.prependChild(new Skew.Node(Skew.NodeKind.VARIABLES).appendChild(variable));\n          }\n        }\n      }\n\n      else if ($this != null) {\n        $this.name = 'this';\n        $this.flags |= Skew.SymbolFlags.IS_EXPORTED;\n      }\n\n      for (var i1 = 0, list1 = $function.$arguments, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n        var argument = in_List.get(list1, i1);\n        this._allocateNamingGroupIndex(argument);\n        this._unionVariableWithFunction(argument, $function);\n      }\n\n      // Rename extra constructors overloads so they don't conflict\n      if ($function.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR && isPrimaryConstructor) {\n        $function.flags |= Skew.SymbolFlags.IS_PRIMARY_CONSTRUCTOR;\n        isPrimaryConstructor = false;\n      }\n\n      // Mark the prototype variable as needed when the prototype is used\n      else if (this._mangle && ($function.kind == Skew.SymbolKind.FUNCTION_INSTANCE || $function.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR && !isPrimaryConstructor)) {\n        if ((prototypeCount = prototypeCount + 1 | 0) == 2) {\n          var variable1 = this._specialVariable(Skew.JavaScriptEmitter.SpecialVariable.PROTOTYPE);\n          in_IntMap.set(this._symbolCounts, variable1.id, in_IntMap.get(this._symbolCounts, variable1.id, 0) + 1 | 0);\n          symbol.flags |= Skew.SymbolFlags.USE_PROTOTYPE_CACHE;\n        }\n      }\n\n      if (symbol == this._global && $function.isExported()) {\n        this._symbolsToExport.push($function);\n      }\n    }\n\n    // Scan over child variables\n    for (var i3 = 0, list3 = symbol.variables, count3 = list3.length; i3 < count3; i3 = i3 + 1 | 0) {\n      var variable2 = in_List.get(list3, i3);\n      this._allocateNamingGroupIndex(variable2);\n      this._patchNode(variable2.value);\n\n      if (symbol == this._global && variable2.isExported()) {\n        this._symbolsToExport.push(variable2);\n      }\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._exportSymbols = function() {\n    if (this._symbolsToExport.length == 0) {\n      return;\n    }\n\n    this._exportsNamespace = new Skew.ObjectSymbol(Skew.SymbolKind.OBJECT_NAMESPACE, this._global.scope.generateName('exports'));\n    this._exportsNamespace.resolvedType = new Skew.Type(Skew.TypeKind.SYMBOL, this._exportsNamespace);\n    this._exportsNamespace.state = Skew.SymbolState.INITIALIZED;\n    this._exportsNamespace.scope = new Skew.ObjectScope(this._global.scope, this._exportsNamespace);\n    this._exportsNamespace.parent = this._global;\n    this._global.objects.push(this._exportsNamespace);\n    this._allocateNamingGroupIndex(this._exportsNamespace);\n\n    for (var i = 0, list = this._symbolsToExport, count = list.length; i < count; i = i + 1 | 0) {\n      var symbol = in_List.get(list, i);\n      assert(symbol.parent != null);\n      assert(Skew.in_SymbolKind.isObject(symbol.parent.kind));\n      var oldParent = symbol.parent.asObjectSymbol();\n      symbol.parent = this._exportsNamespace;\n\n      if (Skew.in_SymbolKind.isObject(symbol.kind)) {\n        in_List.removeOne(oldParent.objects, symbol.asObjectSymbol());\n        this._exportsNamespace.objects.push(symbol.asObjectSymbol());\n      }\n\n      else if (Skew.in_SymbolKind.isFunction(symbol.kind)) {\n        in_List.removeOne(oldParent.functions, symbol.asFunctionSymbol());\n        this._exportsNamespace.functions.push(symbol.asFunctionSymbol());\n      }\n\n      else if (Skew.in_SymbolKind.isVariable(symbol.kind)) {\n        in_List.removeOne(oldParent.variables, symbol.asVariableSymbol());\n        this._exportsNamespace.variables.push(symbol.asVariableSymbol());\n      }\n\n      else {\n        assert(false);\n      }\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._createIntBinary = function(kind, left, right) {\n    if (kind == Skew.NodeKind.MULTIPLY) {\n      return Skew.Node.createSymbolCall(this._specialVariable(Skew.JavaScriptEmitter.SpecialVariable.MULTIPLY)).appendChild(left).appendChild(right);\n    }\n\n    return this._wrapWithIntCast(Skew.Node.createBinary(kind, left, right).withType(this._cache.intType));\n  };\n\n  Skew.JavaScriptEmitter.prototype._wrapWithNot = function(node) {\n    return Skew.Node.createUnary(Skew.NodeKind.NOT, node).withType(this._cache.boolType).withRange(node.range);\n  };\n\n  Skew.JavaScriptEmitter.prototype._wrapWithIntCast = function(node) {\n    return Skew.Node.createBinary(Skew.NodeKind.BITWISE_OR, node, this._cache.createInt(0)).withType(this._cache.intType).withRange(node.range);\n  };\n\n  Skew.JavaScriptEmitter.prototype._removeIntCast = function(node) {\n    if (node.kind == Skew.NodeKind.BITWISE_OR && node.binaryRight().isInt() && node.binaryRight().asInt() == 0) {\n      node.replaceWith(node.binaryLeft().remove());\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._patchUnaryArithmetic = function(node) {\n    if (node.resolvedType == this._cache.intType && !Skew.JavaScriptEmitter._alwaysConvertsOperandsToInt(node.parent())) {\n      var value = node.unaryValue();\n\n      if (value.resolvedType == this._cache.intType) {\n        if (value.isInt()) {\n          value.content = new Skew.IntContent(-value.asInt() | 0);\n          node.become(value.remove());\n        }\n\n        else {\n          node.become(this._wrapWithIntCast(node.cloneAndStealChildren()));\n        }\n      }\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._patchBinaryArithmetic = function(node) {\n    // Make sure arithmetic integer operators don't emit doubles outside the\n    // integer range. Allowing this causes JIT slowdowns due to extra checks\n    // during compilation and potential deoptimizations during execution.\n    // Special-case the integer \"%\" operator where the right operand may be\n    // \"0\" since that generates \"NaN\" which is not representable as an int.\n    if (node.resolvedType == this._cache.intType && !Skew.JavaScriptEmitter._alwaysConvertsOperandsToInt(node.parent()) && (node.kind != Skew.NodeKind.REMAINDER && node.kind != Skew.NodeKind.UNSIGNED_SHIFT_RIGHT || !node.binaryRight().isInt() || node.binaryRight().asInt() == 0)) {\n      var left = node.binaryLeft();\n      var right = node.binaryRight();\n\n      if (left.resolvedType == this._cache.intType && right.resolvedType == this._cache.intType) {\n        node.become(this._createIntBinary(node.kind, left.remove(), right.remove()).withRange(node.range));\n      }\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._patchTypeCheck = function(node) {\n    var value = node.typeCheckValue();\n    var type = this._cache.unwrappedType(node.typeCheckType().resolvedType);\n\n    if (type == this._cache.boolType) {\n      node.become(Skew.Node.createSymbolCall(this._specialVariable(Skew.JavaScriptEmitter.SpecialVariable.IS_BOOL)).appendChild(value.remove()));\n    }\n\n    else if (this._cache.isInteger(type)) {\n      node.become(Skew.Node.createSymbolCall(this._specialVariable(Skew.JavaScriptEmitter.SpecialVariable.IS_INT)).appendChild(value.remove()));\n    }\n\n    else if (type == this._cache.doubleType) {\n      node.become(Skew.Node.createSymbolCall(this._specialVariable(Skew.JavaScriptEmitter.SpecialVariable.IS_DOUBLE)).appendChild(value.remove()));\n    }\n\n    else if (type == this._cache.stringType) {\n      node.become(Skew.Node.createSymbolCall(this._specialVariable(Skew.JavaScriptEmitter.SpecialVariable.IS_STRING)).appendChild(value.remove()));\n    }\n\n    else if (type.kind == Skew.TypeKind.LAMBDA) {\n      node.typeCheckType().replaceWith(new Skew.Node(Skew.NodeKind.NAME).withContent(new Skew.StringContent('Function')).withType(Skew.Type.DYNAMIC));\n    }\n  };\n\n  // Group each variable inside the function with the function itself so that\n  // they can be renamed together and won't cause any collisions inside the\n  // function\n  Skew.JavaScriptEmitter.prototype._unionVariableWithFunction = function(symbol, $function) {\n    if (this._mangle && $function != null) {\n      assert(this._namingGroupIndexForSymbol.has(symbol.id));\n      assert(this._namingGroupIndexForSymbol.has($function.id));\n      this._localVariableUnionFind.union(in_IntMap.get1(this._namingGroupIndexForSymbol, symbol.id), in_IntMap.get1(this._namingGroupIndexForSymbol, $function.id));\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._patchNode = function(node) {\n    if (node == null) {\n      return;\n    }\n\n    var oldEnclosingFunction = this._enclosingFunction;\n    var oldLoop = this._enclosingLoop;\n    var symbol = node.symbol;\n    var kind = node.kind;\n\n    if (this._mangle && symbol != null) {\n      this._allocateNamingGroupIndex(symbol);\n      in_IntMap.set(this._symbolCounts, symbol.id, in_IntMap.get(this._symbolCounts, symbol.id, 0) + 1 | 0);\n    }\n\n    if (kind == Skew.NodeKind.LAMBDA) {\n      this._enclosingFunction = symbol.asFunctionSymbol();\n    }\n\n    else if (Skew.in_NodeKind.isLoop(kind)) {\n      this._enclosingLoop = node;\n    }\n\n    if (kind == Skew.NodeKind.CAST) {\n      this._patchNode(node.castValue());\n    }\n\n    else {\n      for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n        this._patchNode(child);\n      }\n    }\n\n    if (kind == Skew.NodeKind.LAMBDA) {\n      this._enclosingFunction = oldEnclosingFunction;\n    }\n\n    else if (Skew.in_NodeKind.isLoop(kind)) {\n      this._enclosingLoop = oldLoop;\n    }\n\n    // Split this into a separate function because this function is hot and V8 doesn't\n    // optimize it otherwise (it's optimized \"too many times\" whatever that means)\n    this._patchNodeHelper(node);\n  };\n\n  Skew.JavaScriptEmitter.prototype._patchNodeHelper = function(node) {\n    switch (node.kind) {\n      case Skew.NodeKind.ADD:\n      case Skew.NodeKind.SUBTRACT:\n      case Skew.NodeKind.MULTIPLY:\n      case Skew.NodeKind.DIVIDE:\n      case Skew.NodeKind.REMAINDER:\n      case Skew.NodeKind.UNSIGNED_SHIFT_RIGHT: {\n        this._patchBinaryArithmetic(node);\n        break;\n      }\n\n      case Skew.NodeKind.BREAK: {\n        this._patchBreak(node);\n        break;\n      }\n\n      case Skew.NodeKind.CAST: {\n        this._patchCast(node);\n        break;\n      }\n\n      case Skew.NodeKind.FOREACH: {\n        this._unionVariableWithFunction(node.symbol, this._enclosingFunction);\n        break;\n      }\n\n      case Skew.NodeKind.LAMBDA: {\n        this._patchLambda(node);\n        break;\n      }\n\n      case Skew.NodeKind.NAME: {\n        this._patchName(node);\n        break;\n      }\n\n      case Skew.NodeKind.NEGATIVE: {\n        this._patchUnaryArithmetic(node);\n        break;\n      }\n\n      case Skew.NodeKind.TRY: {\n        this._patchTry(node);\n        break;\n      }\n\n      case Skew.NodeKind.TYPE_CHECK: {\n        this._patchTypeCheck(node);\n        break;\n      }\n\n      case Skew.NodeKind.VARIABLE: {\n        this._unionVariableWithFunction(node.symbol, this._enclosingFunction);\n        break;\n      }\n    }\n\n    if (this._mangle) {\n      switch (node.kind) {\n        case Skew.NodeKind.ASSIGN_INDEX: {\n          this._peepholeMangleAssignIndex(node);\n          break;\n        }\n\n        case Skew.NodeKind.BLOCK: {\n          this._peepholeMangleBlock(node);\n          break;\n        }\n\n        case Skew.NodeKind.CALL: {\n          this._peepholeMangleCall(node);\n          break;\n        }\n\n        case Skew.NodeKind.CONSTANT: {\n          this._peepholeMangleConstant(node);\n          break;\n        }\n\n        case Skew.NodeKind.FOR: {\n          this._peepholeMangleFor(node);\n          break;\n        }\n\n        case Skew.NodeKind.HOOK: {\n          this._peepholeMangleHook(node);\n          break;\n        }\n\n        case Skew.NodeKind.IF: {\n          this._peepholeMangleIf(node);\n          break;\n        }\n\n        case Skew.NodeKind.INDEX: {\n          this._peepholeMangleIndex(node);\n          break;\n        }\n\n        case Skew.NodeKind.PAIR: {\n          this._peepholeManglePair(node);\n          break;\n        }\n\n        case Skew.NodeKind.WHILE: {\n          this._peepholeMangleWhile(node);\n          break;\n        }\n\n        default: {\n          if (Skew.in_NodeKind.isBinary(node.kind)) {\n            this._peepholeMangleBinary(node);\n          }\n          break;\n        }\n      }\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._peepholeManglePair = function(node) {\n    if (Skew.JavaScriptEmitter._isIdentifierString(node.firstValue())) {\n      node.firstValue().kind = Skew.NodeKind.NAME;\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._peepholeMangleConstant = function(node) {\n    switch (node.content.kind()) {\n      case Skew.ContentKind.BOOL: {\n        node.become(this._wrapWithNot(this._cache.createInt(node.asBool() ? 0 : 1).withRange(node.range)));\n        break;\n      }\n\n      case Skew.ContentKind.INT: {\n        var value = node.asInt();\n\n        // \"-2147483648\" => \"1 << 31\"\n        if (value != 0) {\n          var count = value.toString().length;\n          var shift = 0;\n\n          // Count zero bits\n          while ((value & 1) == 0) {\n            value >>>= 1;\n            shift = shift + 1 | 0;\n          }\n\n          // Do the substitution if it makes sense\n          if (shift != 0 && ((value.toString().length + 2 | 0) + shift.toString().length | 0) < count) {\n            node.become(Skew.Node.createBinary(Skew.NodeKind.SHIFT_LEFT, this._cache.createInt(value), this._cache.createInt(shift)).withType(this._cache.intType).withRange(node.range));\n          }\n        }\n        break;\n      }\n\n      case Skew.ContentKind.DOUBLE: {\n        var value1 = node.asDouble();\n        var reciprocal = 1 / value1;\n\n        // Shorten long reciprocals (don't replace multiplication with division\n        // because that's not numerically identical). These should be constant-\n        // folded by the JIT at compile-time.\n        //\n        //   \"x * 0.3333333333333333\" => \"x * (1 / 3)\"\n        //\n        for (var i = 1; i < 10; i = i + 1 | 0) {\n          if (reciprocal * i == (reciprocal * i | 0) && value1.toString().length >= 10) {\n            node.become(Skew.Node.createBinary(Skew.NodeKind.DIVIDE, this._cache.createDouble(i), this._cache.createDouble(reciprocal * i)).withType(this._cache.doubleType).withRange(node.range));\n            break;\n          }\n        }\n        break;\n      }\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._patchName = function(node) {\n    if (node.symbol != null && node.symbol == this._currentSelf && this._enclosingFunction != null && this._enclosingFunction.kind == Skew.SymbolKind.FUNCTION_LOCAL) {\n      this._needsSelf = true;\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._peepholeMangleCall = function(node) {\n    var value = node.callValue();\n    var parent = node.parent();\n\n    // \"x + y.toString()\" => \"x + y\" where \"x\" is a string\n    // \"x.toString() + ''\" => \"x + ''\"\n    if (value.nextSibling() == null && value.kind == Skew.NodeKind.DOT && value.asString() == 'toString' && value.symbol != null && value.symbol.isImportedOrExported() && parent.kind == Skew.NodeKind.ADD && (node == parent.binaryRight() && this._cache.isEquivalentToString(parent.binaryLeft().resolvedType) || parent.binaryRight().isString())) {\n      node.become(value.dotTarget().remove());\n    }\n  };\n\n  // The \"break\" statement inside a switch should break out of the enclosing\n  // loop:\n  //\n  //   while true {\n  //     switch x {\n  //       case 0 {\n  //         break\n  //       }\n  //     }\n  //   }\n  //\n  // becomes:\n  //\n  //   label: while (true) {\n  //     switch (x) {\n  //       case 0: {\n  //         break label;\n  //       }\n  //     }\n  //   }\n  //\n  Skew.JavaScriptEmitter.prototype._patchBreak = function(node) {\n    var loop = this._enclosingLoop;\n\n    for (var parent = node.parent(); parent != loop; parent = parent.parent()) {\n      if (parent.kind == Skew.NodeKind.SWITCH) {\n        var label = in_IntMap.get(this._loopLabels, loop.id, null);\n\n        if (label == null) {\n          label = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_LOCAL, this._enclosingFunction.scope.generateName('label'));\n          this._allocateNamingGroupIndex(label);\n          this._unionVariableWithFunction(label, this._enclosingFunction);\n          in_IntMap.set(this._loopLabels, loop.id, label);\n        }\n\n        in_IntMap.set(this._loopLabels, node.id, label);\n        break;\n      }\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._patchLambda = function(node) {\n    var $function = node.symbol.asFunctionSymbol();\n\n    for (var i = 0, list = $function.$arguments, count = list.length; i < count; i = i + 1 | 0) {\n      var argument = in_List.get(list, i);\n      this._allocateNamingGroupIndex(argument);\n      this._unionVariableWithFunction(argument, $function);\n    }\n\n    this._unionVariableWithFunction($function, this._enclosingFunction);\n  };\n\n  Skew.JavaScriptEmitter.prototype._recursiveSubstituteSymbol = function(node, old, $new) {\n    if (node.symbol == old) {\n      node.symbol = $new;\n    }\n\n    for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n      this._recursiveSubstituteSymbol(child, old, $new);\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._patchTry = function(node) {\n    if (node.hasChildren() && !node.hasOneChild()) {\n      var tryBlock = node.tryBlock();\n      var finallyBlock = node.finallyBlock();\n      var firstCatch = finallyBlock != null ? finallyBlock.previousSibling() : node.lastChild();\n      var variable = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_LOCAL, firstCatch.kind == Skew.NodeKind.CATCH && firstCatch.symbol != null ? firstCatch.symbol.name : this._enclosingFunction.scope.generateName('e'));\n      variable.resolvedType = Skew.Type.DYNAMIC;\n      var block = new Skew.Node(Skew.NodeKind.BLOCK).appendChild(Skew.Node.createThrow(Skew.Node.createSymbolReference(variable)));\n\n      // Iterate backwards over the catch blocks\n      for (var child = firstCatch, previous = child.previousSibling(); child != tryBlock; child = previous, previous = child.previousSibling()) {\n        var catchBlock = child.remove().catchBlock().remove();\n\n        // Substitute the variable into the contents of the block\n        if (child.symbol != null) {\n          this._recursiveSubstituteSymbol(catchBlock, child.symbol, variable);\n        }\n\n        // Build up the chain of tests in reverse\n        if (child.symbol != null && child.symbol.resolvedType != Skew.Type.DYNAMIC) {\n          var test = Skew.Node.createTypeCheck(Skew.Node.createSymbolReference(variable), new Skew.Node(Skew.NodeKind.TYPE).withType(child.symbol.resolvedType)).withType(this._cache.boolType);\n          block = new Skew.Node(Skew.NodeKind.BLOCK).appendChild(catchBlock.hasChildren() ? Skew.Node.createIf(test, catchBlock, block) : Skew.Node.createIf(this._wrapWithNot(test), block, null));\n        }\n\n        else {\n          block = catchBlock;\n        }\n      }\n\n      node.insertChildAfter(tryBlock, Skew.Node.createCatch(variable, block));\n\n      // Make sure the new variable name is mangled\n      this._allocateNamingGroupIndex(variable);\n      this._unionVariableWithFunction(variable, this._enclosingFunction);\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._peepholeMangleBinary = function(node) {\n    var kind = node.kind;\n    var left = node.binaryLeft();\n    var right = node.binaryRight();\n\n    // \"(a, b) || c\" => \"a, b || c\"\n    // \"(a, b) && c\" => \"a, b && c\"\n    if ((kind == Skew.NodeKind.LOGICAL_OR || kind == Skew.NodeKind.LOGICAL_AND) && left.kind == Skew.NodeKind.SEQUENCE) {\n      var binary = Skew.Node.createBinary(kind, left.lastChild().cloneAndStealChildren(), right.remove()).withType(Skew.Type.DYNAMIC);\n      this._peepholeMangleBinary(binary);\n      left.lastChild().replaceWith(binary);\n      node.become(left.remove());\n    }\n\n    // \"a + (b + c)\" => \"(a + b) + c\"\n    else if (Skew.in_NodeKind.isBinaryAssociative(kind) && right.kind == kind) {\n      while (true) {\n        node.rotateBinaryRightToLeft();\n        node = node.binaryLeft();\n\n        if (!Skew.in_NodeKind.isBinaryAssociative(node.kind) || node.binaryRight().kind != node.kind) {\n          break;\n        }\n      }\n    }\n\n    else if ((kind == Skew.NodeKind.GREATER_THAN_OR_EQUAL || kind == Skew.NodeKind.LESS_THAN_OR_EQUAL) && this._cache.isEquivalentToInt(left.resolvedType) && this._cache.isEquivalentToInt(right.resolvedType)) {\n      if (left.isInt()) {\n        var value = left.asInt();\n\n        // \"2 >= a\" => \"3 > a\"\n        if (node.kind == Skew.NodeKind.GREATER_THAN_OR_EQUAL && value < 2147483647) {\n          left.content = new Skew.IntContent(value + 1 | 0);\n          node.kind = Skew.NodeKind.GREATER_THAN;\n        }\n\n        // \"2 <= a\" => \"1 < a\"\n        else if (node.kind == Skew.NodeKind.LESS_THAN_OR_EQUAL && value >= -2147483647) {\n          left.content = new Skew.IntContent(value - 1 | 0);\n          node.kind = Skew.NodeKind.LESS_THAN;\n        }\n      }\n\n      else if (right.isInt()) {\n        var value1 = right.asInt();\n\n        // \"a >= 2\" => \"a > 1\"\n        if (node.kind == Skew.NodeKind.GREATER_THAN_OR_EQUAL && value1 >= -2147483647) {\n          right.content = new Skew.IntContent(value1 - 1 | 0);\n          node.kind = Skew.NodeKind.GREATER_THAN;\n        }\n\n        // \"a <= 2\" => \"a < 3\"\n        else if (node.kind == Skew.NodeKind.LESS_THAN_OR_EQUAL && value1 < 2147483647) {\n          right.content = new Skew.IntContent(value1 + 1 | 0);\n          node.kind = Skew.NodeKind.LESS_THAN;\n        }\n      }\n    }\n  };\n\n  // Simplifies the node assuming it's used in a boolean context. Note that\n  // this may replace the passed-in node, which will then need to be queried\n  // again if it's needed for further stuff.\n  Skew.JavaScriptEmitter.prototype._peepholeMangleBoolean = function(node, canSwap) {\n    var kind = node.kind;\n\n    if (kind == Skew.NodeKind.EQUAL || kind == Skew.NodeKind.NOT_EQUAL) {\n      var left = node.binaryLeft();\n      var right = node.binaryRight();\n      var replacement = Skew.JavaScriptEmitter._isFalsy(right) ? left : Skew.JavaScriptEmitter._isFalsy(left) ? right : null;\n\n      // \"if (a != 0) b;\" => \"if (a) b;\"\n      if (replacement != null) {\n        // This minification is not valid for strings and doubles because\n        // they both have multiple falsy values (NaN and 0, null, and \"\")\n        if (left.resolvedType != null && left.resolvedType != Skew.Type.DYNAMIC && !this._cache.isEquivalentToDouble(left.resolvedType) && !this._cache.isEquivalentToString(left.resolvedType) && right.resolvedType != null && right.resolvedType != Skew.Type.DYNAMIC && !this._cache.isEquivalentToDouble(right.resolvedType) && !this._cache.isEquivalentToString(right.resolvedType)) {\n          replacement.remove();\n          node.become(kind == Skew.NodeKind.EQUAL ? this._wrapWithNot(replacement) : replacement);\n        }\n      }\n\n      else if (this._cache.isInteger(left.resolvedType) && this._cache.isInteger(right.resolvedType) && (kind == Skew.NodeKind.NOT_EQUAL || kind == Skew.NodeKind.EQUAL && canSwap == Skew.JavaScriptEmitter.BooleanSwap.SWAP)) {\n        // \"if (a != -1) c;\" => \"if (~a) c;\"\n        // \"if (a == -1) c; else d;\" => \"if (~a) d; else c;\"\n        if (right.isInt() && right.asInt() == -1) {\n          node.become(Skew.Node.createUnary(Skew.NodeKind.COMPLEMENT, left.remove()).withType(this._cache.intType));\n        }\n\n        // \"if (-1 != b) c;\" => \"if (~b) c;\"\n        // \"if (-1 == b) c; else d;\" => \"if (~b) d; else c;\"\n        else if (left.isInt() && left.asInt() == -1) {\n          node.become(Skew.Node.createUnary(Skew.NodeKind.COMPLEMENT, right.remove()).withType(this._cache.intType));\n        }\n\n        // \"if (a != b) c;\" => \"if (a ^ b) c;\"\n        // \"if (a == b) c; else d;\" => \"if (a ^ b) d; else c;\"\n        // \"if ((a + b | 0) != (c + d | 0)) e;\" => \"if (a + b ^ c + d) e;\"\n        else {\n          node.kind = Skew.NodeKind.BITWISE_XOR;\n          this._removeIntCast(node.binaryLeft());\n          this._removeIntCast(node.binaryRight());\n        }\n\n        return kind == Skew.NodeKind.EQUAL ? Skew.JavaScriptEmitter.BooleanSwap.SWAP : Skew.JavaScriptEmitter.BooleanSwap.NO_SWAP;\n      }\n    }\n\n    // \"if (a != 0 || b != 0) c;\" => \"if (a || b) c;\"\n    else if (kind == Skew.NodeKind.LOGICAL_AND || kind == Skew.NodeKind.LOGICAL_OR) {\n      this._peepholeMangleBoolean(node.binaryLeft(), Skew.JavaScriptEmitter.BooleanSwap.NO_SWAP);\n      this._peepholeMangleBoolean(node.binaryRight(), Skew.JavaScriptEmitter.BooleanSwap.NO_SWAP);\n    }\n\n    // \"if (!a) b; else c;\" => \"if (a) c; else b;\"\n    // \"a == 0 ? b : c;\" => \"a ? c : b;\"\n    // This is not an \"else if\" check since EQUAL may be turned into NOT above\n    if (node.kind == Skew.NodeKind.NOT && canSwap == Skew.JavaScriptEmitter.BooleanSwap.SWAP) {\n      node.become(node.unaryValue().remove());\n      return Skew.JavaScriptEmitter.BooleanSwap.SWAP;\n    }\n\n    // \"if (a, !b) c; else d;\" => \"if (a, b) d; else c;\"\n    if (node.kind == Skew.NodeKind.SEQUENCE) {\n      return this._peepholeMangleBoolean(node.lastChild(), canSwap);\n    }\n\n    return Skew.JavaScriptEmitter.BooleanSwap.NO_SWAP;\n  };\n\n  Skew.JavaScriptEmitter.prototype._peepholeMangleIf = function(node) {\n    var test = node.ifTest();\n    var trueBlock = node.ifTrue();\n    var falseBlock = node.ifFalse();\n    var trueStatement = trueBlock.blockStatement();\n    var swapped = this._peepholeMangleBoolean(test, falseBlock != null || trueStatement != null && trueStatement.kind == Skew.NodeKind.EXPRESSION ? Skew.JavaScriptEmitter.BooleanSwap.SWAP : Skew.JavaScriptEmitter.BooleanSwap.NO_SWAP);\n\n    // \"if (a) b; else ;\" => \"if (a) b;\"\n    if (falseBlock != null && !falseBlock.hasChildren()) {\n      falseBlock.remove();\n      falseBlock = null;\n    }\n\n    if (falseBlock != null) {\n      var falseStatement = falseBlock.blockStatement();\n\n      // \"if (!a) b; else c;\" => \"if (a) c; else b;\"\n      if (swapped == Skew.JavaScriptEmitter.BooleanSwap.SWAP) {\n        var block = trueBlock;\n        trueBlock = falseBlock;\n        falseBlock = block;\n        var statement = trueStatement;\n        trueStatement = falseStatement;\n        falseStatement = statement;\n        trueBlock.swapWith(falseBlock);\n      }\n\n      if (trueStatement != null && falseStatement != null) {\n        // \"if (a) b; else c;\" => \"a ? b : c;\"\n        if (trueStatement.kind == Skew.NodeKind.EXPRESSION && falseStatement.kind == Skew.NodeKind.EXPRESSION) {\n          var hook = Skew.Node.createHook(test.remove(), trueStatement.expressionValue().remove(), falseStatement.expressionValue().remove()).withType(Skew.Type.DYNAMIC);\n          this._peepholeMangleHook(hook);\n          node.become(Skew.Node.createExpression(hook));\n        }\n\n        // \"if (a) return b; else return c;\" => \"return a ? b : c;\"\n        else if (trueStatement.kind == Skew.NodeKind.RETURN && falseStatement.kind == Skew.NodeKind.RETURN) {\n          var trueValue = trueStatement.returnValue();\n          var falseValue = falseStatement.returnValue();\n\n          if (trueValue != null && falseValue != null) {\n            var hook1 = Skew.Node.createHook(test.remove(), trueValue.remove(), falseValue.remove()).withType(Skew.Type.DYNAMIC);\n            this._peepholeMangleHook(hook1);\n            node.become(Skew.Node.createReturn(hook1));\n          }\n        }\n      }\n    }\n\n    // \"if (a) b;\" => \"a && b;\"\n    // \"if (!a) b;\" => \"a || b;\"\n    else if (trueStatement != null && trueStatement.kind == Skew.NodeKind.EXPRESSION) {\n      var binary = Skew.Node.createBinary(swapped == Skew.JavaScriptEmitter.BooleanSwap.SWAP ? Skew.NodeKind.LOGICAL_OR : Skew.NodeKind.LOGICAL_AND, test.remove(), trueStatement.expressionValue().remove()).withType(Skew.Type.DYNAMIC);\n      this._peepholeMangleBinary(binary);\n      node.become(Skew.Node.createExpression(binary));\n    }\n\n    // \"if (a) if (b) c;\" => \"if (a && b) c;\"\n    else {\n      var singleIf = Skew.JavaScriptEmitter._singleIf(trueBlock);\n\n      if (singleIf != null && singleIf.ifFalse() == null) {\n        var block1 = singleIf.ifTrue();\n        test.replaceWith(Skew.Node.createBinary(Skew.NodeKind.LOGICAL_AND, test.cloneAndStealChildren(), singleIf.ifTest().remove()).withType(Skew.Type.DYNAMIC));\n        trueBlock.replaceWith(block1.remove());\n      }\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._peepholeMangleWhile = function(node) {\n    var test = node.whileTest();\n    var block = node.whileBlock();\n    this._peepholeMangleBoolean(test.remove(), Skew.JavaScriptEmitter.BooleanSwap.NO_SWAP);\n\n    // \"while (a) {}\" => \"for (; a;) {}\"\n    var loop = Skew.Node.createFor(new Skew.Node(Skew.NodeKind.SEQUENCE).withType(Skew.Type.DYNAMIC), test, new Skew.Node(Skew.NodeKind.SEQUENCE).withType(Skew.Type.DYNAMIC), block.remove()).withRange(node.range);\n    this._peepholeMangleFor(loop);\n    node.become(loop);\n  };\n\n  Skew.JavaScriptEmitter.prototype._peepholeMangleFor = function(node) {\n    var test = node.forTest();\n    this._peepholeMangleBoolean(test, Skew.JavaScriptEmitter.BooleanSwap.NO_SWAP);\n\n    // \"for (; true;) {}\" => \"for (;;) {}\"\n    if (test.kind == Skew.NodeKind.NOT && test.unaryValue().isInt() && test.unaryValue().asInt() == 0) {\n      var empty = new Skew.Node(Skew.NodeKind.SEQUENCE).withType(Skew.Type.DYNAMIC);\n      test.replaceWith(empty);\n      test = empty;\n    }\n\n    // \"for (a;;) if (b) break;\" => \"for (a; b;) {}\"\n    if (node.forUpdate().isEmptySequence()) {\n      var statement = node.forBlock().blockStatement();\n\n      if (statement != null && statement.kind == Skew.NodeKind.IF && statement.ifFalse() == null) {\n        var branch = statement.ifTrue().blockStatement();\n\n        if (branch != null && branch.kind == Skew.NodeKind.BREAK) {\n          var condition = statement.remove().ifTest().remove();\n          condition.invertBooleanCondition(this._cache);\n\n          if (test.isEmptySequence()) {\n            test.replaceWith(condition);\n          }\n\n          else {\n            condition = Skew.Node.createBinary(Skew.NodeKind.LOGICAL_AND, test.cloneAndStealChildren(), condition).withType(Skew.Type.DYNAMIC);\n            this._peepholeMangleBinary(condition);\n            test.become(condition);\n          }\n        }\n      }\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._peepholeMangleHook = function(node) {\n    var test = node.hookTest();\n    var trueValue = node.hookTrue();\n    var falseValue = node.hookFalse();\n    var swapped = this._peepholeMangleBoolean(test, Skew.JavaScriptEmitter.BooleanSwap.SWAP);\n\n    // \"!a ? b : c;\" => \"a ? c : b;\"\n    if (swapped == Skew.JavaScriptEmitter.BooleanSwap.SWAP) {\n      var temp = trueValue;\n      trueValue = falseValue;\n      falseValue = temp;\n      trueValue.swapWith(falseValue);\n    }\n\n    // \"a.b ? c : null\" => \"a.b && c\"\n    if (falseValue.kind == Skew.NodeKind.CAST && falseValue.castValue().kind == Skew.NodeKind.NULL && test.resolvedType != null && test.resolvedType != Skew.Type.DYNAMIC && test.resolvedType.isReference()) {\n      node.become(Skew.Node.createBinary(Skew.NodeKind.LOGICAL_AND, test.remove(), trueValue.remove()).withType(node.resolvedType));\n      return;\n    }\n\n    // \"a ? a : b\" => \"a || b\"\n    // \"a = b ? a : c\" => \"(a = b) || c\"\n    if (test.looksTheSameAs(trueValue) && test.hasNoSideEffects() || Skew.in_NodeKind.isBinaryAssign(test.kind) && test.binaryLeft().looksTheSameAs(trueValue) && test.binaryLeft().hasNoSideEffects()) {\n      node.become(Skew.Node.createBinary(Skew.NodeKind.LOGICAL_OR, test.remove(), falseValue.remove()).withType(node.resolvedType));\n      return;\n    }\n\n    // \"a ? b : a\" => \"a && b\"\n    if (test.looksTheSameAs(falseValue) && test.hasNoSideEffects()) {\n      node.become(Skew.Node.createBinary(Skew.NodeKind.LOGICAL_AND, test.remove(), trueValue.remove()).withType(node.resolvedType));\n      return;\n    }\n\n    // \"a ? b : b\" => \"a, b\"\n    if (trueValue.looksTheSameAs(falseValue)) {\n      node.become(test.hasNoSideEffects() ? trueValue.remove() : Skew.Node.createSequence2(test.remove(), trueValue.remove()));\n      return;\n    }\n\n    // Collapse partially-identical hook expressions\n    if (falseValue.kind == Skew.NodeKind.HOOK) {\n      var falseTest = falseValue.hookTest();\n      var falseTrueValue = falseValue.hookTrue();\n      var falseFalseValue = falseValue.hookFalse();\n\n      // \"a ? b : c ? b : d\" => \"a || c ? b : d\"\n      // \"a ? b : c || d ? b : e\" => \"a || c || d ? b : e\"\n      if (trueValue.looksTheSameAs(falseTrueValue)) {\n        var both = Skew.Node.createBinary(Skew.NodeKind.LOGICAL_OR, test.cloneAndStealChildren(), falseTest.remove()).withType(Skew.Type.DYNAMIC);\n        this._peepholeMangleBinary(both);\n        test.replaceWith(both);\n        falseValue.replaceWith(falseFalseValue.remove());\n        this._peepholeMangleHook(node);\n        return;\n      }\n    }\n\n    // Collapse partially-identical binary expressions\n    if (trueValue.kind == falseValue.kind && Skew.in_NodeKind.isBinary(trueValue.kind)) {\n      var trueLeft = trueValue.binaryLeft();\n      var trueRight = trueValue.binaryRight();\n      var falseLeft = falseValue.binaryLeft();\n      var falseRight = falseValue.binaryRight();\n\n      // \"a ? b = c : b = d;\" => \"b = a ? c : d;\"\n      if (trueLeft.looksTheSameAs(falseLeft)) {\n        var hook = Skew.Node.createHook(test.remove(), trueRight.remove(), falseRight.remove()).withType(Skew.Type.DYNAMIC);\n        this._peepholeMangleHook(hook);\n        node.become(Skew.Node.createBinary(trueValue.kind, trueLeft.remove(), hook).withType(node.resolvedType));\n      }\n\n      // \"a ? b + 100 : c + 100;\" => \"(a ? b + c) + 100;\"\n      else if (trueRight.looksTheSameAs(falseRight) && !Skew.in_NodeKind.isBinaryAssign(trueValue.kind)) {\n        var hook1 = Skew.Node.createHook(test.remove(), trueLeft.remove(), falseLeft.remove()).withType(Skew.Type.DYNAMIC);\n        this._peepholeMangleHook(hook1);\n        node.become(Skew.Node.createBinary(trueValue.kind, hook1, trueRight.remove()).withType(node.resolvedType));\n      }\n    }\n\n    // \"(a, b) ? c : d\" => \"a, b ? c : d\"\n    if (test.kind == Skew.NodeKind.SEQUENCE) {\n      node.prependChild(test.remove().lastChild().remove());\n      test.appendChild(node.cloneAndStealChildren());\n      node.become(test);\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._peepholeMangleAssignIndex = function(node) {\n    var left = node.assignIndexLeft();\n    var center = node.assignIndexCenter();\n    var right = node.assignIndexRight();\n\n    if (Skew.JavaScriptEmitter._isIdentifierString(center)) {\n      node.become(Skew.Node.createBinary(Skew.NodeKind.ASSIGN, new Skew.Node(Skew.NodeKind.DOT).withContent(new Skew.StringContent(center.asString())).appendChild(left.remove()).withRange(Skew.Range.span(left.range, center.range)).withType(Skew.Type.DYNAMIC), right.remove()).withRange(node.range).withType(node.resolvedType));\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._peepholeMangleIndex = function(node) {\n    var left = node.indexLeft();\n    var right = node.indexRight();\n\n    if (Skew.JavaScriptEmitter._isIdentifierString(right)) {\n      node.become(new Skew.Node(Skew.NodeKind.DOT).withContent(new Skew.StringContent(right.asString())).appendChild(left.remove()).withRange(node.range).withType(node.resolvedType));\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._peepholeMangleBlock = function(node) {\n    for (var child = node.firstChild(), next = null; child != null; child = next) {\n      var previous = child.previousSibling();\n      next = child.nextSibling();\n\n      switch (child.kind) {\n        // Make sure we entirely remove blocks only containing comment blocks\n        case Skew.NodeKind.COMMENT_BLOCK: {\n          child.remove();\n          break;\n        }\n\n        // \"var a; var b;\" => \"var a, b;\"\n        case Skew.NodeKind.VARIABLES: {\n          if (previous != null && previous.kind == Skew.NodeKind.VARIABLES) {\n            child.replaceWith(previous.remove().appendChildrenFrom(child));\n          }\n          break;\n        }\n\n        // \"a; b; c;\" => \"a, b, c;\"\n        case Skew.NodeKind.EXPRESSION: {\n          if (child.expressionValue().hasNoSideEffects()) {\n            child.remove();\n          }\n\n          else if (previous != null && previous.kind == Skew.NodeKind.EXPRESSION) {\n            var sequence = Skew.Node.createSequence2(previous.remove().expressionValue().remove(), child.expressionValue().remove());\n            child.become(Skew.Node.createExpression(sequence));\n          }\n          break;\n        }\n\n        case Skew.NodeKind.RETURN: {\n          while (previous != null) {\n            // \"if (a) return b; return c;\" => \"return a ? b : c;\"\n            if (child.returnValue() != null && previous.kind == Skew.NodeKind.IF && previous.ifFalse() == null) {\n              var statement = previous.ifTrue().blockStatement();\n\n              if (statement != null && statement.kind == Skew.NodeKind.RETURN && statement.returnValue() != null) {\n                var hook = Skew.Node.createHook(previous.remove().ifTest().remove(), statement.returnValue().remove(), child.returnValue().remove()).withType(Skew.Type.DYNAMIC);\n                this._peepholeMangleHook(hook);\n                child.become(Skew.Node.createReturn(hook));\n              }\n\n              else {\n                break;\n              }\n            }\n\n            // \"a; return b;\" => \"return a, b;\"\n            else if (child.returnValue() != null && previous.kind == Skew.NodeKind.EXPRESSION) {\n              var sequence1 = Skew.Node.createSequence2(previous.remove().expressionValue().remove(), child.returnValue().remove());\n              child.become(Skew.Node.createReturn(sequence1));\n            }\n\n            else {\n              break;\n            }\n\n            previous = child.previousSibling();\n          }\n          break;\n        }\n\n        case Skew.NodeKind.IF: {\n          while (previous != null) {\n            // \"if (a) b; if (c) b;\" => \"if (a || c) b;\"\n            if (child.ifFalse() == null && previous.kind == Skew.NodeKind.IF && previous.ifFalse() == null && previous.ifTrue().looksTheSameAs(child.ifTrue())) {\n              child.ifTest().replaceWith(Skew.Node.createBinary(Skew.NodeKind.LOGICAL_OR, previous.remove().ifTest().remove(), child.ifTest().cloneAndStealChildren()).withType(Skew.Type.DYNAMIC));\n            }\n\n            // \"a; if (b) c;\" => \"if (a, b) c;\"\n            else if (previous.kind == Skew.NodeKind.EXPRESSION) {\n              var sequence2 = Skew.Node.createSequence2(previous.remove().expressionValue().remove(), child.ifTest().cloneAndStealChildren());\n              child.ifTest().replaceWith(sequence2);\n            }\n\n            else {\n              break;\n            }\n\n            previous = child.previousSibling();\n          }\n\n          // \"void foo() { if (a) return; b(); c() }\" => \"void foo() { if (!a) { b(); c() } }\"\n          // \"while (a) { if (b) continue; c(); d() }\" => \"while (a) { if (!b) { c(); d() } }\"\n          if (child.ifFalse() == null) {\n            var trueBlock = child.ifTrue();\n\n            if (trueBlock.hasChildren()) {\n              var statement1 = trueBlock.lastChild();\n\n              if ((statement1.kind == Skew.NodeKind.RETURN && statement1.returnValue() == null || statement1.kind == Skew.NodeKind.CONTINUE) && Skew.JavaScriptEmitter._isJumpImplied(node, statement1.kind)) {\n                var block = null;\n\n                // If the if statement block without the jump is empty, then flip\n                // the condition of the if statement and reuse the block. Otherwise,\n                // create an else branch for the if statement and use that block.\n                statement1.remove();\n\n                if (!trueBlock.hasChildren()) {\n                  child.ifTest().invertBooleanCondition(this._cache);\n                  block = trueBlock;\n                }\n\n                else if (next != null) {\n                  block = new Skew.Node(Skew.NodeKind.BLOCK);\n                  child.appendChild(block);\n                  assert(block == child.ifFalse());\n                }\n\n                else {\n                  // Returning here is fine because this is the last child\n                  return;\n                }\n\n                // Move the rest of this block into the block for the if statement\n                while (child.nextSibling() != null) {\n                  block.appendChild(child.nextSibling().remove());\n                }\n\n                this._peepholeMangleBlock(block);\n                this._peepholeMangleIf(child);\n\n                // \"a(); if (b) return; c();\" => \"a(); if (!b) c();\" => \"a(); !b && c();\" => \"a(), !b && c();\"\n                if (child.kind == Skew.NodeKind.EXPRESSION && previous != null && previous.kind == Skew.NodeKind.EXPRESSION) {\n                  var sequence3 = Skew.Node.createSequence2(previous.remove().expressionValue().remove(), child.expressionValue().remove());\n                  child.become(Skew.Node.createExpression(sequence3));\n                }\n\n                return;\n              }\n            }\n          }\n          break;\n        }\n\n        case Skew.NodeKind.FOR: {\n          var setup = child.forSetup();\n\n          // \"var a; for (;;) {}\" => \"for (var a;;) {}\"\n          if (previous != null && setup.isEmptySequence() && previous.kind == Skew.NodeKind.VARIABLES) {\n            setup.replaceWith(previous.remove().appendChildrenFrom(setup));\n          }\n\n          // \"var a; for (var b;;) {}\" => \"for (var a, b;;) {}\"\n          else if (previous != null && setup.kind == Skew.NodeKind.VARIABLES && previous.kind == Skew.NodeKind.VARIABLES) {\n            setup.replaceWith(previous.remove().appendChildrenFrom(setup));\n          }\n\n          // \"a; for (b;;) {}\" => \"for (a, b;;) {}\"\n          else if (previous != null && Skew.in_NodeKind.isExpression(setup.kind) && previous.kind == Skew.NodeKind.EXPRESSION) {\n            setup.replaceWith(Skew.Node.createSequence2(previous.remove().expressionValue().remove(), setup.cloneAndStealChildren()));\n          }\n          break;\n        }\n\n        case Skew.NodeKind.SWITCH: {\n          var switchValue = child.switchValue();\n          var defaultCase = child.defaultCase();\n\n          if (defaultCase != null) {\n            var hasFlowAtEnd = false;\n\n            // See if any non-default case will flow past the end of the switch block\n            for (var caseChild = switchValue.nextSibling(); caseChild != defaultCase; caseChild = caseChild.nextSibling()) {\n              if (caseChild.caseBlock().hasControlFlowAtEnd()) {\n                hasFlowAtEnd = true;\n              }\n            }\n\n            // \"switch (a) { case b: return; default: c; break; }\" => \"switch (a) { case b: return; } c;\"\n            if (!hasFlowAtEnd) {\n              node.insertChildrenAfterFrom(defaultCase.caseBlock(), child);\n              next = child.nextSibling();\n              defaultCase.remove();\n              defaultCase = null;\n            }\n          }\n\n          // \"switch (a) {}\" => \"a;\"\n          if (child.hasOneChild()) {\n            next = Skew.Node.createExpression(switchValue.remove());\n            child.replaceWith(next);\n            continue;\n          }\n\n          // \"switch (a) { case b: c; break; }\" => \"if (a == b) c;\"\n          else if (child.hasTwoChildren()) {\n            var singleCase = child.lastChild();\n\n            if (singleCase.hasTwoChildren()) {\n              var value = singleCase.firstChild();\n              next = Skew.Node.createIf(Skew.Node.createBinary(Skew.NodeKind.EQUAL, switchValue.remove(), value.remove()).withType(this._cache.boolType), singleCase.caseBlock().remove(), null);\n              this._peepholeMangleIf(next);\n              child.replaceWith(next);\n              continue;\n            }\n          }\n\n          // \"switch (a) { case b: c; break; default: d; break; }\" => \"if (a == b) c; else d;\"\n          else if (child.hasThreeChildren()) {\n            var firstCase = switchValue.nextSibling();\n            var secondCase = child.lastChild();\n\n            if (firstCase.hasTwoChildren() && secondCase.hasOneChild()) {\n              var value1 = firstCase.firstChild();\n              next = Skew.Node.createIf(Skew.Node.createBinary(Skew.NodeKind.EQUAL, switchValue.remove(), value1.remove()).withType(this._cache.boolType), firstCase.caseBlock().remove(), secondCase.caseBlock().remove());\n              this._peepholeMangleIf(next);\n              child.replaceWith(next);\n              continue;\n            }\n          }\n\n          // Optimize specific patterns of switch statements\n          if (switchValue.kind == Skew.NodeKind.NAME && defaultCase == null) {\n            this._peepholeMangleSwitchCases(child);\n          }\n          break;\n        }\n      }\n    }\n  };\n\n  // \"switch (a) { case 0: return 0; case 1: return 1; case 2: return 2; }\" => \"if (a >= 0 && a <= 2) return a\"\n  // \"switch (a) { case 0: return 1; case 1: return 2; case 2: return 3; }\" => \"if (a >= 0 && a <= 2) return a + 1\"\n  Skew.JavaScriptEmitter.prototype._peepholeMangleSwitchCases = function(node) {\n    var switchValue = node.switchValue();\n    var firstCase = switchValue.nextSibling();\n\n    if (!this._cache.isEquivalentToInt(switchValue.resolvedType)) {\n      return;\n    }\n\n    var sharedDelta = 0;\n    var count = 0;\n    var min = 0;\n    var max = 0;\n\n    for (var child = firstCase; child != null; child = child.nextSibling()) {\n      var singleStatement = child.caseBlock().blockStatement();\n\n      if (!child.hasTwoChildren() || singleStatement == null || singleStatement.kind != Skew.NodeKind.RETURN) {\n        return;\n      }\n\n      var caseValue = child.firstChild();\n      var returnValue = singleStatement.returnValue();\n\n      if (!caseValue.isInt() || returnValue == null || !returnValue.isInt()) {\n        return;\n      }\n\n      var caseInt = caseValue.asInt();\n      var returnInt = returnValue.asInt();\n      var delta = returnInt - caseInt | 0;\n\n      if (count == 0) {\n        sharedDelta = delta;\n        min = caseInt;\n        max = caseInt;\n      }\n\n      else if (delta != sharedDelta) {\n        return;\n      }\n\n      else {\n        min = Math.min(min, caseInt);\n        max = Math.max(max, caseInt);\n      }\n\n      count = count + 1 | 0;\n    }\n\n    // Make sure the pattern is matched\n    if (count == 0) {\n      return;\n    }\n\n    var block = new Skew.Node(Skew.NodeKind.BLOCK).appendChild(Skew.Node.createReturn(sharedDelta > 0 ? this._createIntBinary(Skew.NodeKind.ADD, switchValue.remove(), this._cache.createInt(sharedDelta)) : sharedDelta < 0 ? this._createIntBinary(Skew.NodeKind.SUBTRACT, switchValue.remove(), this._cache.createInt(-sharedDelta | 0)) : switchValue.remove()));\n\n    // Replace the large \"switch\" statement with a smaller \"if\" statement if the entire range is covered\n    if ((max - min | 0) == (count - 1 | 0)) {\n      var lower = Skew.Node.createBinary(Skew.NodeKind.GREATER_THAN_OR_EQUAL, switchValue.clone(), this._cache.createInt(min)).withType(this._cache.boolType);\n      var upper = Skew.Node.createBinary(Skew.NodeKind.LESS_THAN_OR_EQUAL, switchValue.clone(), this._cache.createInt(max)).withType(this._cache.boolType);\n\n      // Convert \">=\" and \"<=\" to \">\" and \"<\" where possible\n      this._peepholeMangleBinary(lower);\n      this._peepholeMangleBinary(upper);\n      node.replaceWith(Skew.Node.createIf(Skew.Node.createBinary(Skew.NodeKind.LOGICAL_AND, lower, upper).withType(this._cache.boolType), block, null));\n    }\n\n    // Just combine everything into one case\n    else {\n      var combined = new Skew.Node(Skew.NodeKind.CASE);\n\n      for (var child1 = firstCase; child1 != null; child1 = child1.nextSibling()) {\n        combined.appendChild(child1.firstChild().remove());\n      }\n\n      node.replaceWith(Skew.Node.createSwitch(switchValue.clone()).appendChild(combined.appendChild(block)));\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._patchCast = function(node) {\n    var value = node.castValue();\n    var type = node.resolvedType;\n    var valueType = value.resolvedType;\n\n    // Wrapping should be transparent in the emitted code\n    if (type.isWrapped() || valueType.isWrapped()) {\n      return;\n    }\n\n    // Cast to bool\n    if (type == this._cache.boolType) {\n      if (valueType != this._cache.boolType) {\n        node.become(this._wrapWithNot(this._wrapWithNot(value.remove())));\n      }\n    }\n\n    // Cast to int\n    else if (this._cache.isInteger(type)) {\n      if (!this._cache.isInteger(valueType) && !Skew.JavaScriptEmitter._alwaysConvertsOperandsToInt(node.parent())) {\n        node.become(this._wrapWithIntCast(value.remove()));\n      }\n\n      else if (value.isInt()) {\n        node.become(value.remove().withType(node.resolvedType));\n      }\n    }\n\n    // Cast to double\n    else if (type == this._cache.doubleType) {\n      if (!this._cache.isNumeric(valueType)) {\n        node.become(Skew.Node.createUnary(Skew.NodeKind.POSITIVE, value.remove()).withRange(node.range).withType(this._cache.doubleType));\n      }\n    }\n\n    // Cast to string\n    else if (type == this._cache.stringType) {\n      if (valueType != this._cache.stringType && valueType != Skew.Type.NULL) {\n        node.become(Skew.Node.createSymbolCall(this._specialVariable(Skew.JavaScriptEmitter.SpecialVariable.AS_STRING)).appendChild(value.remove()));\n      }\n    }\n  };\n\n  Skew.JavaScriptEmitter.prototype._specialVariable = function(name) {\n    assert(this._specialVariables.has(name));\n    var variable = in_IntMap.get1(this._specialVariables, name);\n    in_IntMap.set(this._isSpecialVariableNeeded, variable.id, 0);\n    return variable;\n  };\n\n  Skew.JavaScriptEmitter._isReferenceTo = function(node, symbol) {\n    if (node.kind == Skew.NodeKind.CAST) {\n      node = node.castValue();\n    }\n\n    return node.kind == Skew.NodeKind.NAME && node.symbol == symbol;\n  };\n\n  Skew.JavaScriptEmitter._isJumpImplied = function(node, kind) {\n    assert(node.kind == Skew.NodeKind.BLOCK);\n    assert(kind == Skew.NodeKind.RETURN || kind == Skew.NodeKind.CONTINUE);\n    var parent = node.parent();\n\n    if (kind == Skew.NodeKind.RETURN && (parent == null || parent.kind == Skew.NodeKind.LAMBDA) || kind == Skew.NodeKind.CONTINUE && parent != null && Skew.in_NodeKind.isLoop(parent.kind)) {\n      return true;\n    }\n\n    if (parent != null && parent.kind == Skew.NodeKind.IF && parent.nextSibling() == null) {\n      return Skew.JavaScriptEmitter._isJumpImplied(parent.parent(), kind);\n    }\n\n    return false;\n  };\n\n  Skew.JavaScriptEmitter._isIdentifierString = function(node) {\n    if (node.isString()) {\n      var value = node.asString();\n\n      for (var i = 0, count = value.length; i < count; i = i + 1 | 0) {\n        var c = in_string.get1(value, i);\n\n        if ((c < 65 || c > 90) && (c < 97 || c > 122) && c != 95 && c != 36 && (i == 0 || c < 48 || c > 57)) {\n          return false;\n        }\n      }\n\n      return value != '' && !Skew.JavaScriptEmitter._isKeyword.has(value);\n    }\n\n    return false;\n  };\n\n  Skew.JavaScriptEmitter._singleIf = function(block) {\n    if (block == null) {\n      return null;\n    }\n\n    var statement = block.blockStatement();\n\n    if (statement != null && statement.kind == Skew.NodeKind.IF) {\n      return statement;\n    }\n\n    return null;\n  };\n\n  Skew.JavaScriptEmitter._numberToName = function(number) {\n    var name = in_string.get(Skew.JavaScriptEmitter._first, number % Skew.JavaScriptEmitter._first.length | 0);\n    number = number / Skew.JavaScriptEmitter._first.length | 0;\n\n    while (number > 0) {\n      number = number - 1 | 0;\n      name += in_string.get(Skew.JavaScriptEmitter._rest, number % Skew.JavaScriptEmitter._rest.length | 0);\n      number = number / Skew.JavaScriptEmitter._rest.length | 0;\n    }\n\n    return name;\n  };\n\n  Skew.JavaScriptEmitter._isCompactNodeKind = function(kind) {\n    return kind == Skew.NodeKind.EXPRESSION || kind == Skew.NodeKind.VARIABLES || Skew.in_NodeKind.isJump(kind);\n  };\n\n  Skew.JavaScriptEmitter._isFalsy = function(node) {\n    switch (node.kind) {\n      case Skew.NodeKind.NULL: {\n        return true;\n      }\n\n      case Skew.NodeKind.CAST: {\n        return Skew.JavaScriptEmitter._isFalsy(node.castValue());\n      }\n\n      case Skew.NodeKind.CONSTANT: {\n        var content = node.content;\n\n        switch (content.kind()) {\n          case Skew.ContentKind.INT: {\n            return Skew.in_Content.asInt(content) == 0;\n          }\n\n          case Skew.ContentKind.DOUBLE: {\n            return Skew.in_Content.asDouble(content) == 0 || isNaN(Skew.in_Content.asDouble(content));\n          }\n\n          case Skew.ContentKind.STRING: {\n            return Skew.in_Content.asString(content) == '';\n          }\n        }\n        break;\n      }\n    }\n\n    return false;\n  };\n\n  Skew.JavaScriptEmitter._fullName = function(symbol) {\n    var parent = symbol.parent;\n\n    if (parent != null && parent.kind != Skew.SymbolKind.OBJECT_GLOBAL) {\n      var enclosingName = Skew.JavaScriptEmitter._fullName(parent);\n\n      if (symbol.isPrimaryConstructor() || symbol.isImported() && symbol.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n        return enclosingName;\n      }\n\n      assert(symbol.kind != Skew.SymbolKind.OVERLOADED_INSTANCE);\n\n      if (symbol.kind == Skew.SymbolKind.FUNCTION_INSTANCE) {\n        enclosingName += '.prototype';\n      }\n\n      return enclosingName + '.' + Skew.JavaScriptEmitter._mangleName(symbol);\n    }\n\n    return Skew.JavaScriptEmitter._mangleName(symbol);\n  };\n\n  Skew.JavaScriptEmitter._shouldRenameSymbol = function(symbol) {\n    // Don't rename annotations since \"@rename\" is used for renaming and is identified by name\n    return !symbol.isImportedOrExported() && !symbol.isRenamed() && !symbol.isPrimaryConstructor() && symbol.kind != Skew.SymbolKind.FUNCTION_ANNOTATION && symbol.kind != Skew.SymbolKind.OBJECT_GLOBAL && symbol.kind != Skew.SymbolKind.FUNCTION_LOCAL;\n  };\n\n  Skew.JavaScriptEmitter._mangleName = function(symbol) {\n    symbol = symbol.forwarded();\n\n    if (symbol.isPrimaryConstructor()) {\n      symbol = symbol.parent;\n    }\n\n    if (!symbol.isImportedOrExported() && (Skew.JavaScriptEmitter._isKeyword.has(symbol.name) || symbol.parent != null && symbol.parent.kind == Skew.SymbolKind.OBJECT_CLASS && !Skew.in_SymbolKind.isOnInstances(symbol.kind) && Skew.JavaScriptEmitter._isFunctionProperty.has(symbol.name))) {\n      return '$' + symbol.name;\n    }\n\n    return symbol.name;\n  };\n\n  Skew.JavaScriptEmitter._computeNamespacePrefix = function(symbol) {\n    assert(Skew.in_SymbolKind.isObject(symbol.kind));\n    return symbol.kind == Skew.SymbolKind.OBJECT_GLOBAL ? '' : Skew.JavaScriptEmitter._computeNamespacePrefix(symbol.parent.asObjectSymbol()) + Skew.JavaScriptEmitter._mangleName(symbol) + '.';\n  };\n\n  Skew.JavaScriptEmitter._alwaysConvertsOperandsToInt = function(node) {\n    if (node != null) {\n      switch (node.kind) {\n        case Skew.NodeKind.ASSIGN_BITWISE_AND:\n        case Skew.NodeKind.ASSIGN_BITWISE_OR:\n        case Skew.NodeKind.ASSIGN_BITWISE_XOR:\n        case Skew.NodeKind.ASSIGN_SHIFT_LEFT:\n        case Skew.NodeKind.ASSIGN_SHIFT_RIGHT:\n        case Skew.NodeKind.BITWISE_AND:\n        case Skew.NodeKind.BITWISE_OR:\n        case Skew.NodeKind.BITWISE_XOR:\n        case Skew.NodeKind.COMPLEMENT:\n        case Skew.NodeKind.SHIFT_LEFT:\n        case Skew.NodeKind.SHIFT_RIGHT: {\n          return true;\n        }\n      }\n    }\n\n    return false;\n  };\n\n  Skew.JavaScriptEmitter.BooleanSwap = {\n    SWAP: 0,\n    NO_SWAP: 1\n  };\n\n  Skew.JavaScriptEmitter.ExtractGroupsMode = {\n    ALL_SYMBOLS: 0,\n    ONLY_LOCAL_VARIABLES: 1,\n    ONLY_INSTANCE_VARIABLES: 2\n  };\n\n  Skew.JavaScriptEmitter.SymbolGroup = function(symbols, count) {\n    this.symbols = symbols;\n    this.count = count;\n  };\n\n  Skew.JavaScriptEmitter.AfterToken = {\n    AFTER_KEYWORD: 0,\n    AFTER_PARENTHESIS: 1\n  };\n\n  Skew.JavaScriptEmitter.BracesMode = {\n    MUST_KEEP_BRACES: 0,\n    CAN_OMIT_BRACES: 1\n  };\n\n  Skew.JavaScriptEmitter.SpecialVariable = {\n    NONE: 0,\n    AS_STRING: 1,\n    CREATE: 2,\n    EXTENDS: 3,\n    IS_BOOL: 4,\n    IS_DOUBLE: 5,\n    IS_INT: 6,\n    IS_STRING: 7,\n    MULTIPLY: 8,\n    PROTOTYPE: 9\n  };\n\n  Skew.TypeScriptEmitter = function(_log, _options, _cache) {\n    Skew.Emitter.call(this);\n    this._log = _log;\n    this._options = _options;\n    this._cache = _cache;\n    this._specialVariables = new Map();\n    this._ctors = new Map();\n    this._enclosingNamespaces = [];\n    this._emittedComments = [];\n    this._previousNode = null;\n    this._previousSymbol = null;\n    this._symbolsCheckedForImport = new Map();\n    this._importedFiles = new Map();\n    this._loopLabels = new Map();\n    this._enclosingFunction = null;\n    this._expectedNextEnumValue = 0;\n    this._currentFile = '';\n  };\n\n  __extends(Skew.TypeScriptEmitter, Skew.Emitter);\n\n  Skew.TypeScriptEmitter.prototype.visit = function(global) {\n    var self = this;\n    self._indentAmount = '  ';\n\n    // Generate the entry point\n    var entryPoint = self._cache.entryPointSymbol;\n\n    if (entryPoint != null) {\n      entryPoint.name = 'main';\n    }\n\n    // Load special-cased variables\n    for (var i = 0, list = global.variables, count = list.length; i < count; i = i + 1 | 0) {\n      var variable = in_List.get(list, i);\n      var special = in_StringMap.get(Skew.TypeScriptEmitter._specialVariableMap, variable.name, Skew.TypeScriptEmitter.SpecialVariable.NONE);\n\n      if (special != Skew.TypeScriptEmitter.SpecialVariable.NONE) {\n        in_IntMap.set(self._specialVariables, special, variable);\n        variable.flags |= Skew.SymbolFlags.IS_EXPORTED;\n      }\n    }\n\n    assert(self._specialVariables.has(Skew.TypeScriptEmitter.SpecialVariable.AS_STRING));\n    assert(self._specialVariables.has(Skew.TypeScriptEmitter.SpecialVariable.IS_INT));\n\n    // Avoid emitting unnecessary stuff\n    Skew.shakingPass(global, entryPoint, Skew.ShakingMode.USE_TYPES);\n    self._markVirtualFunctions(global);\n    var emitIndividualFiles = self._options.outputDirectory != null;\n    var symbolsByFile = new Map();\n\n    // Bucket things by the source file they came from\n    var collisions = new Map();\n    var add = function(s) {\n      var name = '';\n\n      if (s.range != null) {\n        name = s.range.source.name;\n      }\n\n      if (!symbolsByFile.has(name)) {\n        in_StringMap.set(symbolsByFile, name, []);\n      }\n\n      in_StringMap.get1(symbolsByFile, name).push(s);\n\n      // Track collisions\n      if (!s.isImported()) {\n        var list = in_StringMap.get(collisions, s.name, []);\n        list.push(s);\n        in_StringMap.set(collisions, s.name, list);\n      }\n    };\n\n    // There can only be one constructor in TypeScript\n    var fixAllMultipleCtors = null;\n    fixAllMultipleCtors = function(p) {\n      for (var i1 = 0, list1 = p.objects, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n        var s = in_List.get(list1, i1);\n        fixAllMultipleCtors(s);\n\n        if (s.kind == Skew.SymbolKind.OBJECT_CLASS && !s.isImported()) {\n          var ctors = s.functions.filter(function(f) {\n            return f.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR;\n          });\n\n          if (ctors.length > 1) {\n            s.functions = s.functions.filter(function(f) {\n              return f.kind != Skew.SymbolKind.FUNCTION_CONSTRUCTOR;\n            });\n            var canUseArgumentCount = ctors.every(function(c1) {\n              return ctors.filter(function(c2) {\n                return c1.$arguments.length == c2.$arguments.length;\n              }).length == 1;\n            });\n            in_IntMap.set(self._ctors, s.id, new Skew.TypeScriptEmitter.MultipleCtors(ctors, canUseArgumentCount));\n          }\n        }\n      }\n    };\n    fixAllMultipleCtors(global);\n    var addAll = null;\n    addAll = function(p) {\n      // If this namespace has comments, move its comments to\n      // the first child of this namespace in the same file\n      if (p.comments != null) {\n        var all = [];\n\n        for (var i1 = 0, list1 = p.variables, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n          var s = in_List.get(list1, i1);\n          all.push(s);\n        }\n\n        for (var i2 = 0, list2 = p.functions, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n          var s1 = in_List.get(list2, i2);\n          all.push(s1);\n        }\n\n        for (var i3 = 0, list3 = p.objects, count3 = list3.length; i3 < count3; i3 = i3 + 1 | 0) {\n          var s2 = in_List.get(list3, i3);\n          all.push(s2);\n        }\n\n        // Iterate over the comments in reverse because we are prefixing\n        for (var i = 0, count5 = p.comments.length; i < count5; i = i + 1 | 0) {\n          var c = in_List.get(p.comments, (p.comments.length - i | 0) - 1 | 0);\n          var best = null;\n\n          for (var i4 = 0, list4 = all, count4 = list4.length; i4 < count4; i4 = i4 + 1 | 0) {\n            var s3 = in_List.get(list4, i4);\n\n            if (s3.range.source == c.range.source) {\n              if (best == null || best.range.start > s3.range.start) {\n                best = s3;\n              }\n            }\n          }\n\n          if (best != null) {\n            best.comments = Skew.Comment.concat([c], best.comments);\n          }\n\n          else if (self._options.warnAboutIgnoredComments) {\n            self._log.syntaxWarningIgnoredCommentInEmitter(c.range);\n          }\n        }\n      }\n\n      for (var i5 = 0, list5 = p.variables, count6 = list5.length; i5 < count6; i5 = i5 + 1 | 0) {\n        var s4 = in_List.get(list5, i5);\n        add(s4);\n      }\n\n      for (var i6 = 0, list6 = p.functions, count7 = list6.length; i6 < count7; i6 = i6 + 1 | 0) {\n        var s5 = in_List.get(list6, i6);\n        add(s5);\n      }\n\n      for (var i7 = 0, list7 = p.objects, count8 = list7.length; i7 < count8; i7 = i7 + 1 | 0) {\n        var s6 = in_List.get(list7, i7);\n\n        if (Skew.TypeScriptEmitter._shouldFlattenNamespace(s6)) {\n          addAll(s6);\n        }\n\n        else {\n          add(s6);\n        }\n      }\n    };\n    addAll(global);\n\n    // Rename all collisions\n    in_StringMap.each(collisions, function(name, list) {\n      if (list.length > 1) {\n        for (var i1 = 0, list1 = list, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n          var s = in_List.get(list1, i1);\n          var i = 1;\n\n          while (true) {\n            var rename = name + i.toString();\n\n            if (!collisions.has(rename)) {\n              in_StringMap.set(collisions, rename, []);\n              s.name = rename;\n              break;\n            }\n\n            i = i + 1 | 0;\n          }\n        }\n      }\n    });\n\n    // Emit each global object into a separate file\n    in_StringMap.each(symbolsByFile, function(file, symbols) {\n      self._currentFile = file;\n\n      for (var i1 = 0, list1 = symbols, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n        var s = in_List.get(list1, i1);\n\n        if (Skew.in_SymbolKind.isObject(s.kind)) {\n          self._emitObject(s);\n        }\n      }\n\n      for (var i2 = 0, list2 = symbols, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n        var s1 = in_List.get(list2, i2);\n\n        if (Skew.in_SymbolKind.isFunction(s1.kind)) {\n          self._emitFunction(s1);\n        }\n      }\n\n      for (var i3 = 0, list3 = symbols, count3 = list3.length; i3 < count3; i3 = i3 + 1 | 0) {\n        var s2 = in_List.get(list3, i3);\n\n        if (Skew.in_SymbolKind.isVariable(s2.kind)) {\n          self._emitVariable(s2);\n        }\n      }\n\n      // Emit each object into its own file if requested\n      if (emitIndividualFiles) {\n        self._finalizeEmittedFile();\n        self._createSource(self._options.outputDirectory + '/' + self._tsFileName(file), Skew.EmitMode.SKIP_IF_EMPTY);\n      }\n    });\n\n    // Emit a single file if requested\n    if (!emitIndividualFiles) {\n      self._finalizeEmittedFile();\n      self._createSource(self._options.outputFile, Skew.EmitMode.ALWAYS_EMIT);\n    }\n  };\n\n  Skew.TypeScriptEmitter.prototype._specialVariable = function(name) {\n    assert(this._specialVariables.has(name));\n    var variable = in_IntMap.get1(this._specialVariables, name);\n    this._handleSymbol(variable);\n    return variable;\n  };\n\n  Skew.TypeScriptEmitter.prototype._tsFileName = function(skewFile) {\n    skewFile = skewFile.split('<').join('');\n    skewFile = skewFile.split('>').join('');\n\n    if (skewFile.endsWith('.sk')) {\n      skewFile = in_string.slice2(skewFile, 0, skewFile.length - '.sk'.length | 0);\n    }\n\n    return skewFile + '.ts';\n  };\n\n  Skew.TypeScriptEmitter.prototype._relativeImport = function(file) {\n    var currentParts = this._currentFile.split('/');\n    var fileParts = file.split('/');\n    in_List.removeLast(currentParts);\n\n    while (!(currentParts.length == 0) && !(fileParts.length == 0) && in_List.first(currentParts) == in_List.first(fileParts)) {\n      in_List.removeFirst(currentParts);\n      in_List.removeFirst(fileParts);\n    }\n\n    if (currentParts.length == 0) {\n      fileParts.unshift('.');\n    }\n\n    else {\n      for (var i = 0, list = currentParts, count = list.length; i < count; i = i + 1 | 0) {\n        var _ = in_List.get(list, i);\n        fileParts.unshift('..');\n      }\n    }\n\n    return fileParts.join('/');\n  };\n\n  Skew.TypeScriptEmitter.prototype._finalizeEmittedFile = function() {\n    var importedFiles = Array.from(this._importedFiles.keys());\n\n    if (!(importedFiles.length == 0)) {\n      // Sort so the order is deterministic\n      importedFiles.sort(Skew.SORT_STRINGS);\n\n      for (var i = 0, list = importedFiles, count = list.length; i < count; i = i + 1 | 0) {\n        var file = in_List.get(list, i);\n        var importedNames = Array.from(in_StringMap.get1(this._importedFiles, file).keys());\n\n        // Sort so the order is deterministic\n        importedNames.sort(Skew.SORT_STRINGS);\n        var where = Skew.quoteString(this._relativeImport(file), Skew.QuoteStyle.DOUBLE, Skew.QuoteOctal.NORMAL);\n        this._emitPrefix('import { ' + importedNames.join(', ') + ' } from ' + where + ';\\n');\n      }\n\n      this._emitPrefix('\\n');\n    }\n\n    this._previousSymbol = null;\n    this._symbolsCheckedForImport = new Map();\n    this._importedFiles = new Map();\n  };\n\n  Skew.TypeScriptEmitter.prototype._handleSymbol = function(symbol) {\n    if (!Skew.in_SymbolKind.isLocal(symbol.kind) && !this._symbolsCheckedForImport.has(symbol.id)) {\n      in_IntMap.set(this._symbolsCheckedForImport, symbol.id, 0);\n      var parent = symbol.parent;\n\n      if (parent != null && (symbol.kind == Skew.SymbolKind.VARIABLE_ENUM_OR_FLAGS || parent.kind == Skew.SymbolKind.OBJECT_WRAPPED || parent.kind == Skew.SymbolKind.OBJECT_NAMESPACE && !Skew.TypeScriptEmitter._shouldFlattenNamespace(parent) || Skew.in_SymbolKind.isObject(symbol.kind) && parent.kind == Skew.SymbolKind.OBJECT_CLASS || symbol.kind == Skew.SymbolKind.FUNCTION_GLOBAL && parent.kind == Skew.SymbolKind.OBJECT_CLASS || symbol.kind == Skew.SymbolKind.VARIABLE_GLOBAL && parent.kind == Skew.SymbolKind.OBJECT_CLASS)) {\n        this._handleSymbol(parent);\n      }\n\n      else if (!symbol.isImported() && symbol.range != null && (symbol.kind == Skew.SymbolKind.OBJECT_CLASS || symbol.kind == Skew.SymbolKind.OBJECT_ENUM || symbol.kind == Skew.SymbolKind.OBJECT_FLAGS || symbol.kind == Skew.SymbolKind.OBJECT_WRAPPED || symbol.kind == Skew.SymbolKind.OBJECT_INTERFACE || symbol.kind == Skew.SymbolKind.OBJECT_NAMESPACE || symbol.kind == Skew.SymbolKind.FUNCTION_GLOBAL && parent.kind != Skew.SymbolKind.OBJECT_CLASS || symbol.kind == Skew.SymbolKind.VARIABLE_GLOBAL && parent.kind != Skew.SymbolKind.OBJECT_CLASS)) {\n        var file = symbol.range.source.name;\n\n        if (this._currentFile != file) {\n          file = this._tsFileName(file);\n          file = in_string.slice2(file, 0, file.length - '.ts'.length | 0);\n\n          if (!this._importedFiles.has(file)) {\n            in_StringMap.set(this._importedFiles, file, new Map());\n          }\n\n          in_StringMap.set(in_StringMap.get1(this._importedFiles, file), Skew.TypeScriptEmitter._mangleName(symbol), 0);\n        }\n      }\n    }\n  };\n\n  Skew.TypeScriptEmitter.prototype._emitNewlineBeforeSymbol = function(symbol) {\n    if (this._previousSymbol != null && (symbol.comments != null || (!Skew.in_SymbolKind.isVariable(this._previousSymbol.kind) || !Skew.in_SymbolKind.isVariable(symbol.kind)) && (!Skew.in_SymbolKind.isFunction(this._previousSymbol.kind) || this._previousSymbol.asFunctionSymbol().block != null || !Skew.in_SymbolKind.isFunction(symbol.kind) || symbol.asFunctionSymbol().block != null))) {\n      this._emit('\\n');\n    }\n\n    this._previousSymbol = null;\n  };\n\n  Skew.TypeScriptEmitter.prototype._emitNewlineAfterSymbol = function(symbol) {\n    this._previousSymbol = symbol;\n  };\n\n  Skew.TypeScriptEmitter.prototype._emitNewlineBeforeStatement = function(node) {\n    if (this._previousNode != null && (node.comments != null || !Skew.TypeScriptEmitter._isCompactNodeKind(this._previousNode.kind) || !Skew.TypeScriptEmitter._isCompactNodeKind(node.kind))) {\n      this._emit('\\n');\n    }\n\n    this._previousNode = null;\n  };\n\n  Skew.TypeScriptEmitter.prototype._emitNewlineAfterStatement = function(node) {\n    this._previousNode = node;\n  };\n\n  Skew.TypeScriptEmitter.prototype._emitComments = function(comments) {\n    if (comments != null) {\n      for (var i1 = 0, list1 = comments, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n        var comment = in_List.get(list1, i1);\n\n        for (var i = 0, list = comment.lines, count = list.length; i < count; i = i + 1 | 0) {\n          var line = in_List.get(list, i);\n          this._emit(this._indent + '//' + line + '\\n');\n        }\n\n        if (comment.hasGapBelow) {\n          this._emit('\\n');\n        }\n\n        if (this._options.warnAboutIgnoredComments) {\n          this._emittedComments.push(comment);\n        }\n      }\n    }\n  };\n\n  Skew.TypeScriptEmitter.prototype._emitTrailingComment = function(comment) {\n    if (comment != null) {\n      assert(comment.lines.length == 1);\n      this._emit(' //' + in_List.first(comment.lines));\n\n      if (this._options.warnAboutIgnoredComments) {\n        this._emittedComments.push(comment);\n      }\n    }\n  };\n\n  Skew.TypeScriptEmitter.prototype._emitObject = function(symbol) {\n    this._handleSymbol(symbol);\n\n    if (symbol.isImported() || symbol.kind == Skew.SymbolKind.OBJECT_GLOBAL) {\n      return;\n    }\n\n    this._emitNewlineBeforeSymbol(symbol);\n    this._emitComments(symbol.comments);\n    this._emit(this._indent);\n    this._emit('export ');\n\n    if (symbol.isAbstract()) {\n      this._emit('abstract ');\n    }\n\n    switch (symbol.kind) {\n      case Skew.SymbolKind.OBJECT_CLASS: {\n        this._emit('class ');\n        break;\n      }\n\n      case Skew.SymbolKind.OBJECT_ENUM:\n      case Skew.SymbolKind.OBJECT_FLAGS: {\n        var toString = in_StringMap.get(symbol.members, 'toString', null);\n\n        if (toString != null && Skew.in_SymbolKind.isFunction(toString.kind) && (Skew.SymbolFlags.IS_INLINING_FORCED & toString.flags) != 0 && (Skew.SymbolFlags.IS_AUTOMATICALLY_GENERATED & toString.flags) != 0 && toString.inlinedCount == 0) {\n          this._emit('const ');\n        }\n\n        this._emit('enum ');\n        break;\n      }\n\n      case Skew.SymbolKind.OBJECT_INTERFACE: {\n        this._emit('interface ');\n        break;\n      }\n\n      case Skew.SymbolKind.OBJECT_WRAPPED: {\n        this._emit('type ');\n        break;\n      }\n\n      case Skew.SymbolKind.OBJECT_NAMESPACE: {\n        this._emit('namespace ');\n        break;\n      }\n\n      default: {\n        assert(false);\n        break;\n      }\n    }\n\n    this._emit(Skew.TypeScriptEmitter._mangleName(symbol));\n    this._emitTypeParameters(symbol.parameters);\n\n    if (symbol.kind == Skew.SymbolKind.OBJECT_WRAPPED) {\n      this._emit(' = ');\n      this._emitExpressionOrType(symbol.$extends, symbol.wrappedType);\n      this._emit('\\n');\n      this._emitNewlineAfterSymbol(symbol);\n    }\n\n    else {\n      if (symbol.$extends != null || symbol.$implements != null) {\n        if (symbol.$extends != null) {\n          this._emit(' extends ');\n          this._emitExpressionOrType(symbol.$extends, symbol.baseType);\n        }\n\n        if (symbol.$implements != null) {\n          this._emit(' implements ');\n\n          for (var i = 0, list = symbol.$implements, count = list.length; i < count; i = i + 1 | 0) {\n            var node = in_List.get(list, i);\n\n            if (node != in_List.first(symbol.$implements)) {\n              this._emit(', ');\n            }\n\n            this._emitExpressionOrType(node, node.resolvedType);\n          }\n        }\n      }\n\n      this._emit(' {\\n');\n      this._increaseIndent();\n      this._expectedNextEnumValue = 0;\n\n      if (symbol.kind == Skew.SymbolKind.OBJECT_NAMESPACE) {\n        this._enclosingNamespaces.push(symbol);\n      }\n\n      var variablesComeFirst = symbol.kind == Skew.SymbolKind.OBJECT_CLASS;\n\n      if (variablesComeFirst) {\n        for (var i1 = 0, list1 = symbol.variables, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n          var variable = in_List.get(list1, i1);\n          this._emitVariable(variable);\n        }\n      }\n\n      var multiple = in_IntMap.get(this._ctors, symbol.id, null);\n\n      if (multiple != null) {\n        this._emitConstructor(symbol, multiple.ctors, multiple.canUseArgumentCount);\n      }\n\n      for (var i2 = 0, list2 = symbol.functions, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n        var $function = in_List.get(list2, i2);\n        this._emitFunction($function);\n      }\n\n      if (!variablesComeFirst) {\n        for (var i3 = 0, list3 = symbol.variables, count3 = list3.length; i3 < count3; i3 = i3 + 1 | 0) {\n          var variable1 = in_List.get(list3, i3);\n          this._emitVariable(variable1);\n        }\n      }\n\n      if (symbol.kind == Skew.SymbolKind.OBJECT_NAMESPACE) {\n        in_List.removeLast(this._enclosingNamespaces);\n      }\n\n      this._emitComments(symbol.commentsInsideEndOfBlock);\n      this._decreaseIndent();\n      this._emit(this._indent + '}\\n');\n      this._emitNewlineAfterSymbol(symbol);\n    }\n\n    if (symbol.objects.length > 0 || symbol.kind == Skew.SymbolKind.OBJECT_WRAPPED && (symbol.variables.length > 0 || symbol.functions.length > 0)) {\n      this._emitNewlineBeforeSymbol(symbol);\n      this._emit(this._indent + 'export namespace ');\n      this._emit(Skew.TypeScriptEmitter._mangleName(symbol));\n      this._emit(' {\\n');\n      this._increaseIndent();\n\n      if (symbol.kind == Skew.SymbolKind.OBJECT_WRAPPED) {\n        this._enclosingNamespaces.push(symbol);\n      }\n\n      for (var i4 = 0, list4 = symbol.objects, count4 = list4.length; i4 < count4; i4 = i4 + 1 | 0) {\n        var object = in_List.get(list4, i4);\n        this._emitObject(object);\n      }\n\n      if (symbol.kind == Skew.SymbolKind.OBJECT_WRAPPED) {\n        for (var i5 = 0, list5 = symbol.functions, count5 = list5.length; i5 < count5; i5 = i5 + 1 | 0) {\n          var function1 = in_List.get(list5, i5);\n          this._emitFunction(function1);\n        }\n\n        for (var i6 = 0, list6 = symbol.variables, count6 = list6.length; i6 < count6; i6 = i6 + 1 | 0) {\n          var variable2 = in_List.get(list6, i6);\n          this._emitVariable(variable2);\n        }\n      }\n\n      if (symbol.kind == Skew.SymbolKind.OBJECT_WRAPPED) {\n        in_List.removeLast(this._enclosingNamespaces);\n      }\n\n      this._decreaseIndent();\n      this._emit(this._indent + '}\\n');\n    }\n  };\n\n  Skew.TypeScriptEmitter.prototype._emitConstructor = function(object, ctors, canUseArgumentCount) {\n    // Optimize for standard TypeScript idioms if we can\n    if (canUseArgumentCount) {\n      // Forward-declare the function signatures\n      this._emitNewlineBeforeSymbol(in_List.first(ctors));\n\n      for (var i = 0, list = ctors, count = list.length; i < count; i = i + 1 | 0) {\n        var ctor = in_List.get(list, i);\n        this._emitComments(ctor.comments);\n        this._emit(this._indent);\n        this._emit('constructor');\n        this._emitTypeParameters(ctor.parameters);\n        this._emitArgumentList(ctor);\n        this._emit(';\\n');\n      }\n\n      this._emitNewlineAfterSymbol(in_List.first(ctors));\n\n      // Define the implementation\n      this._emitNewlineBeforeSymbol(in_List.first(ctors));\n      this._emit(this._indent);\n      this._emit('constructor() {\\n');\n      this._increaseIndent();\n\n      for (var i2 = 0, list2 = ctors, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n        var ctor1 = in_List.get(list2, i2);\n        var block = ctor1.block;\n        var prefix = ctor1 == in_List.first(ctors) ? this._indent : '\\n' + this._indent + 'else ';\n        assert(block != null);\n        assert(block.kind == Skew.NodeKind.BLOCK);\n\n        // JavaScript arrow functions have sane capture rules for \"this\" so no variable insertion is needed\n        if (ctor1.$this != null) {\n          ctor1.$this.name = 'this';\n          ctor1.$this.flags |= Skew.SymbolFlags.IS_EXPORTED;\n        }\n\n        this._enclosingFunction = ctor1;\n        this._emit(prefix + ('if (arguments.length == ' + ctor1.$arguments.length.toString() + ') {\\n'));\n        this._increaseIndent();\n\n        if (!(ctor1.$arguments.length == 0)) {\n          this._emit(this._indent + ('let [' + ctor1.$arguments.map(function(arg) {\n            return Skew.TypeScriptEmitter._mangleName(arg);\n          }).join(', ') + ']: ['));\n\n          for (var i1 = 0, list1 = ctor1.$arguments, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n            var arg = in_List.get(list1, i1);\n\n            if (arg != in_List.first(ctor1.$arguments)) {\n              this._emit(', ');\n            }\n\n            this._emitExpressionOrType(arg.type, arg.resolvedType);\n          }\n\n          this._emit('] = arguments as any;\\n');\n        }\n\n        this._emitStatements(block);\n        this._decreaseIndent();\n        this._emit(this._indent + '}\\n');\n        this._enclosingFunction = null;\n      }\n\n      this._decreaseIndent();\n      this._emit(this._indent);\n      this._emit('}\\n');\n      this._emitNewlineAfterSymbol(in_List.first(ctors));\n    }\n\n    // Otherwise, fall back to something that is still correct: disambiguating with an index\n    else {\n      // Forward-declare the function signatures\n      this._emitNewlineBeforeSymbol(in_List.first(ctors));\n\n      for (var i4 = 0, list4 = ctors, count4 = list4.length; i4 < count4; i4 = i4 + 1 | 0) {\n        var ctor2 = in_List.get(list4, i4);\n        this._emitComments(ctor2.comments);\n        this._emit(this._indent);\n        this._emit('constructor');\n        this._emitTypeParameters(ctor2.parameters);\n        this._emit('(_: ' + ctors.indexOf(ctor2).toString());\n\n        for (var i3 = 0, list3 = ctor2.$arguments, count3 = list3.length; i3 < count3; i3 = i3 + 1 | 0) {\n          var arg1 = in_List.get(list3, i3);\n          this._emit(', ' + Skew.TypeScriptEmitter._mangleName(arg1) + ': ');\n          this._emitExpressionOrType(arg1.type, arg1.resolvedType);\n        }\n\n        this._emit(');\\n');\n      }\n\n      this._emitNewlineAfterSymbol(in_List.first(ctors));\n\n      // Define the implementation\n      this._emitNewlineBeforeSymbol(in_List.first(ctors));\n      this._emit(this._indent);\n      this._emit('constructor() {\\n');\n      this._increaseIndent();\n\n      for (var i6 = 0, list6 = ctors, count6 = list6.length; i6 < count6; i6 = i6 + 1 | 0) {\n        var ctor3 = in_List.get(list6, i6);\n        var block1 = ctor3.block;\n        var prefix1 = ctor3 == in_List.first(ctors) ? this._indent : '\\n' + this._indent + 'else ';\n        assert(block1 != null);\n        assert(block1.kind == Skew.NodeKind.BLOCK);\n\n        // JavaScript arrow functions have sane capture rules for \"this\" so no variable insertion is needed\n        if (ctor3.$this != null) {\n          ctor3.$this.name = 'this';\n          ctor3.$this.flags |= Skew.SymbolFlags.IS_EXPORTED;\n        }\n\n        this._enclosingFunction = ctor3;\n        this._emit(prefix1 + ('if (arguments[0] == ' + ctors.indexOf(ctor3).toString() + ') {\\n'));\n        this._increaseIndent();\n\n        if (!(ctor3.$arguments.length == 0)) {\n          this._emit(this._indent + ('let [' + ctor3.$arguments.map(function(arg) {\n            return ', ' + Skew.TypeScriptEmitter._mangleName(arg);\n          }).join('') + ']: [number'));\n\n          for (var i5 = 0, list5 = ctor3.$arguments, count5 = list5.length; i5 < count5; i5 = i5 + 1 | 0) {\n            var arg2 = in_List.get(list5, i5);\n            this._emit(', ');\n            this._emitExpressionOrType(arg2.type, arg2.resolvedType);\n          }\n\n          this._emit('] = arguments as any;\\n');\n        }\n\n        this._emitStatements(block1);\n        this._decreaseIndent();\n        this._emit(this._indent + '}\\n');\n        this._enclosingFunction = null;\n      }\n\n      this._decreaseIndent();\n      this._emit(this._indent);\n      this._emit('}\\n');\n      this._emitNewlineAfterSymbol(in_List.first(ctors));\n    }\n  };\n\n  Skew.TypeScriptEmitter.prototype._emitTypeParameters = function(parameters) {\n    if (parameters != null) {\n      this._emit('<');\n\n      for (var i = 0, list = parameters, count = list.length; i < count; i = i + 1 | 0) {\n        var parameter = in_List.get(list, i);\n\n        if (parameter != in_List.first(parameters)) {\n          this._emit(', ');\n        }\n\n        this._emit(Skew.TypeScriptEmitter._mangleName(parameter));\n      }\n\n      this._emit('>');\n    }\n  };\n\n  Skew.TypeScriptEmitter.prototype._emitArgumentList = function(symbol) {\n    this._emit('(');\n\n    for (var i = 0, list = symbol.$arguments, count = list.length; i < count; i = i + 1 | 0) {\n      var argument = in_List.get(list, i);\n\n      if (argument != in_List.first(symbol.$arguments)) {\n        this._emit(', ');\n      }\n\n      this._emit(Skew.TypeScriptEmitter._mangleName(argument) + ': ');\n      this._emitExpressionOrType(argument.type, argument.resolvedType);\n    }\n\n    this._emit(')');\n  };\n\n  Skew.TypeScriptEmitter.prototype._emitVariable = function(symbol) {\n    this._handleSymbol(symbol);\n\n    if (symbol.isImported()) {\n      return;\n    }\n\n    var trailing = Skew.Comment.lastTrailingComment(symbol.comments);\n    var notTrailing = Skew.Comment.withoutLastTrailingComment(symbol.comments);\n    this._emitNewlineBeforeSymbol(symbol);\n    this._emitComments(notTrailing);\n    this._emit(this._indent);\n\n    if (symbol.kind == Skew.SymbolKind.VARIABLE_ENUM_OR_FLAGS) {\n      this._emit(Skew.TypeScriptEmitter._mangleName(symbol));\n\n      if (symbol.value != null) {\n        // Enum values are initialized with integers\n        symbol.value.resolvedType = this._cache.intType;\n\n        if (symbol.value.asInt() != this._expectedNextEnumValue) {\n          this._emit(' = ');\n          this._emitExpression(symbol.value, Skew.Precedence.COMMA);\n        }\n\n        this._expectedNextEnumValue = symbol.value.asInt() + 1 | 0;\n      }\n\n      this._emit(',');\n    }\n\n    else {\n      if (symbol.kind == Skew.SymbolKind.VARIABLE_GLOBAL && symbol.parent != null && symbol.parent.kind == Skew.SymbolKind.OBJECT_CLASS) {\n        this._emit('static ');\n      }\n\n      else if (symbol.kind != Skew.SymbolKind.VARIABLE_INSTANCE) {\n        this._emit('export ');\n        this._emit('let ');\n      }\n\n      var emitValue = symbol.value != null && symbol.kind != Skew.SymbolKind.VARIABLE_INSTANCE;\n\n      if (emitValue && this._canOmitTypeAnnotation(symbol.value)) {\n        this._emit(Skew.TypeScriptEmitter._mangleName(symbol));\n      }\n\n      else {\n        this._emit(Skew.TypeScriptEmitter._mangleName(symbol) + ': ');\n        this._emitExpressionOrType(symbol.type, symbol.resolvedType);\n      }\n\n      if (emitValue) {\n        this._emit(' = ');\n        this._emitExpression(symbol.value, Skew.Precedence.COMMA);\n      }\n\n      this._emit(';');\n    }\n\n    this._emitTrailingComment(trailing);\n    this._emit('\\n');\n    this._emitNewlineAfterSymbol(symbol);\n  };\n\n  // Various heuristics to make nicer-looking code without introducing too many type errors\n  Skew.TypeScriptEmitter.prototype._canOmitTypeAnnotation = function(value) {\n    var type = this._cache.unwrappedType(value.resolvedType);\n\n    if (type == Skew.Type.DYNAMIC) {\n      return false;\n    }\n\n    if (value.kind == Skew.NodeKind.CALL || value.kind == Skew.NodeKind.DOT) {\n      return true;\n    }\n\n    if (value.kind == Skew.NodeKind.NAME) {\n      return this._enclosingFunction == null || value.symbol != this._enclosingFunction.$this;\n    }\n\n    if (type == this._cache.boolType || this._cache.isNumeric(type)) {\n      return true;\n    }\n\n    if (type == this._cache.stringType && value.kind != Skew.NodeKind.NULL && (value.kind != Skew.NodeKind.CAST || value.castValue().kind != Skew.NodeKind.NULL)) {\n      return true;\n    }\n\n    return false;\n  };\n\n  Skew.TypeScriptEmitter.prototype._emitFunction = function(symbol) {\n    this._handleSymbol(symbol);\n\n    if (symbol.isImported()) {\n      return;\n    }\n\n    // JavaScript arrow functions have sane capture rules for \"this\" so no variable insertion is needed\n    if (symbol.$this != null) {\n      symbol.$this.name = 'this';\n      symbol.$this.flags |= Skew.SymbolFlags.IS_EXPORTED;\n    }\n\n    this._enclosingFunction = symbol;\n    this._emitNewlineBeforeSymbol(symbol);\n    this._emitComments(symbol.comments);\n    this._emit(this._indent);\n    var block = symbol.block;\n\n    if (block == null && symbol.parent != null && symbol.parent.kind == Skew.SymbolKind.OBJECT_CLASS) {\n      this._emit('abstract ');\n    }\n\n    if (symbol.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n      this._emit('constructor');\n    }\n\n    else {\n      if (symbol.kind == Skew.SymbolKind.FUNCTION_GLOBAL && symbol.parent != null && symbol.parent.kind == Skew.SymbolKind.OBJECT_CLASS) {\n        this._emit('static ');\n      }\n\n      else if (symbol.kind != Skew.SymbolKind.FUNCTION_INSTANCE) {\n        this._emit('export function ');\n      }\n\n      this._emit(Skew.TypeScriptEmitter._mangleName(symbol));\n    }\n\n    this._emitTypeParameters(symbol.parameters);\n    this._emitArgumentList(symbol);\n\n    if (symbol.kind != Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n      this._emit(': ');\n      this._emitExpressionOrType(symbol.returnType, symbol.resolvedType.returnType);\n    }\n\n    if (block == null) {\n      this._emit(';\\n');\n    }\n\n    else {\n      var comments = [];\n\n      if (this._options.warnAboutIgnoredComments) {\n        this._scanForComments(block, comments);\n        this._emittedComments = [];\n      }\n\n      this._emitBlock(block);\n\n      if (this._options.warnAboutIgnoredComments) {\n        for (var i = 0, list = comments, count = list.length; i < count; i = i + 1 | 0) {\n          var c = in_List.get(list, i);\n\n          if (!(this._emittedComments.indexOf(c) != -1)) {\n            this._log.syntaxWarningIgnoredCommentInEmitter(c.range);\n          }\n        }\n      }\n\n      this._emit('\\n');\n    }\n\n    this._emitNewlineAfterSymbol(symbol);\n    this._enclosingFunction = null;\n  };\n\n  Skew.TypeScriptEmitter.prototype._scanForComments = function(node, comments) {\n    if (node.comments != null) {\n      in_List.append1(comments, node.comments);\n    }\n\n    if (node.innerComments != null) {\n      in_List.append1(comments, node.innerComments);\n    }\n\n    for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n      this._scanForComments(child, comments);\n    }\n  };\n\n  Skew.TypeScriptEmitter.prototype._emitType = function(type) {\n    if (type == null) {\n      this._emit('void');\n      return;\n    }\n\n    if (type == Skew.Type.DYNAMIC) {\n      this._emit('any');\n    }\n\n    else if (type.kind == Skew.TypeKind.LAMBDA) {\n      var argumentTypes = type.argumentTypes;\n      var returnType = type.returnType;\n      this._emit('(');\n\n      for (var i = 0, count = argumentTypes.length; i < count; i = i + 1 | 0) {\n        if (i != 0) {\n          this._emit(', ');\n        }\n\n        this._emit('v' + i.toString() + ': ');\n        this._emitType(in_List.get(argumentTypes, i));\n      }\n\n      this._emit(') => ');\n\n      if (returnType != null) {\n        this._emitType(returnType);\n      }\n\n      else {\n        this._emit('void');\n      }\n    }\n\n    else if (this._cache.isIntMap(type) || this._cache.isStringMap(type)) {\n      this._emit('Map<');\n      this._emit(this._cache.isIntMap(type) ? 'number' : 'string');\n      this._emit(', ');\n      this._emitType(in_List.first(type.substitutions));\n      this._emit('>');\n    }\n\n    else {\n      assert(type.kind == Skew.TypeKind.SYMBOL);\n      this._handleSymbol(type.symbol);\n      this._emit(this._fullName(type.symbol));\n\n      if (type.isParameterized()) {\n        this._emit('<');\n\n        for (var i1 = 0, count1 = type.substitutions.length; i1 < count1; i1 = i1 + 1 | 0) {\n          if (i1 != 0) {\n            this._emit(', ');\n          }\n\n          this._emitType(in_List.get(type.substitutions, i1));\n        }\n\n        this._emit('>');\n      }\n    }\n  };\n\n  Skew.TypeScriptEmitter.prototype._emitExpressionOrType = function(node, type) {\n    if (node != null && (type == null || type == Skew.Type.DYNAMIC)) {\n      // Treat the type \"dynamic.Object\" as an alias for \"dynamic\" instead of what it actually means\n      if (type == Skew.Type.DYNAMIC && node.kind == Skew.NodeKind.NAME && node.asString() == 'Object') {\n        this._emitType(Skew.Type.DYNAMIC);\n      }\n\n      else {\n        this._emitExpression(node, Skew.Precedence.LOWEST);\n      }\n    }\n\n    else {\n      this._emitType(type);\n    }\n  };\n\n  Skew.TypeScriptEmitter.prototype._emitStatements = function(node) {\n    this._previousNode = null;\n\n    for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n      var trailing = Skew.Comment.lastTrailingComment(child.comments);\n      var notTrailing = Skew.Comment.withoutLastTrailingComment(child.comments);\n      this._emitNewlineBeforeStatement(child);\n      this._emitComments(notTrailing);\n      this._emitStatement(child, trailing);\n      this._emitNewlineAfterStatement(child);\n    }\n\n    this._previousNode = null;\n  };\n\n  Skew.TypeScriptEmitter.prototype._emitBlock = function(node) {\n    assert(node.kind == Skew.NodeKind.BLOCK);\n    this._emit(' {\\n');\n    this._increaseIndent();\n    this._emitStatements(node);\n    this._decreaseIndent();\n    this._emit(this._indent + '}');\n  };\n\n  Skew.TypeScriptEmitter.prototype._emitIf = function(node) {\n    this._emit('if (');\n    this._emitExpression(node.ifTest(), Skew.Precedence.LOWEST);\n    this._emit(')');\n    var then = node.ifTrue();\n    var thenComments = then.comments;\n\n    // Some people put comments before blocks in if statements\n    if (thenComments != null) {\n      this._emit('\\n');\n      this._emitComments(thenComments);\n      this._emit(this._indent + '{\\n');\n      this._increaseIndent();\n      this._emitStatements(then);\n      this._decreaseIndent();\n      this._emit(this._indent + '}');\n    }\n\n    else {\n      this._emitBlock(then);\n    }\n\n    var block = node.ifFalse();\n\n    if (block != null) {\n      var singleIf = block.hasOneChild() && block.firstChild().kind == Skew.NodeKind.IF ? block.firstChild() : null;\n\n      if (block.comments != null || singleIf != null && singleIf.comments != null) {\n        this._emit('\\n');\n        this._emit('\\n');\n        this._emitComments(block.comments);\n\n        if (singleIf != null) {\n          this._emitComments(singleIf.comments);\n        }\n\n        this._emit(this._indent + 'else');\n      }\n\n      else {\n        this._emit(' else');\n      }\n\n      if (singleIf != null) {\n        this._emit(' ');\n        this._emitIf(singleIf);\n      }\n\n      else {\n        this._emitBlock(block);\n        this._emit('\\n');\n      }\n    }\n\n    else {\n      this._emit('\\n');\n    }\n  };\n\n  Skew.TypeScriptEmitter.prototype._scanForSwitchBreak = function(node, loop) {\n    if (node.kind == Skew.NodeKind.BREAK) {\n      for (var parent = node.parent(); parent != loop; parent = parent.parent()) {\n        if (parent.kind == Skew.NodeKind.SWITCH) {\n          var label = in_IntMap.get(this._loopLabels, loop.id, null);\n\n          if (label == null) {\n            label = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_LOCAL, this._enclosingFunction.scope.generateName('label'));\n            in_IntMap.set(this._loopLabels, loop.id, label);\n          }\n\n          in_IntMap.set(this._loopLabels, node.id, label);\n          break;\n        }\n      }\n    }\n\n    // Stop at nested loops since those will be tested later\n    else if (node == loop || !Skew.in_NodeKind.isLoop(node.kind)) {\n      for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n        this._scanForSwitchBreak(child, loop);\n      }\n    }\n  };\n\n  Skew.TypeScriptEmitter.prototype._emitStatement = function(node, trailing) {\n    if (Skew.in_NodeKind.isLoop(node.kind)) {\n      this._scanForSwitchBreak(node, node);\n      var label = in_IntMap.get(this._loopLabels, node.id, null);\n\n      if (label != null) {\n        this._emit(this._indent + Skew.TypeScriptEmitter._mangleName(label) + (node.nextSibling() != null ? ':\\n' : ':;\\n'));\n      }\n    }\n\n    switch (node.kind) {\n      case Skew.NodeKind.COMMENT_BLOCK: {\n        break;\n      }\n\n      case Skew.NodeKind.VARIABLES: {\n        for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n          var symbol = child.symbol.asVariableSymbol();\n          var value = symbol.value;\n          this._emit(this._indent + 'let ');\n\n          if (value != null && this._canOmitTypeAnnotation(value)) {\n            this._emit(Skew.TypeScriptEmitter._mangleName(symbol));\n          }\n\n          else {\n            this._emit(Skew.TypeScriptEmitter._mangleName(symbol) + ': ');\n            this._emitExpressionOrType(symbol.type, symbol.resolvedType);\n          }\n\n          if (value != null) {\n            var comments = this._commentsFromExpression(value);\n\n            if (comments != null) {\n              this._emit(' =\\n');\n              this._increaseIndent();\n              this._emitComments(comments);\n              this._emit(this._indent);\n              this._emitExpression(value, Skew.Precedence.ASSIGN);\n              this._decreaseIndent();\n            }\n\n            else {\n              this._emit(' = ');\n              this._emitExpression(value, Skew.Precedence.ASSIGN);\n            }\n          }\n\n          this._emit(';');\n          this._emitTrailingComment(trailing);\n          this._emit('\\n');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.EXPRESSION: {\n        this._emit(this._indent);\n        this._emitExpression(node.expressionValue(), Skew.Precedence.LOWEST);\n        this._emit(';');\n        this._emitTrailingComment(trailing);\n        this._emit('\\n');\n        break;\n      }\n\n      case Skew.NodeKind.BREAK: {\n        var label1 = in_IntMap.get(this._loopLabels, node.id, null);\n\n        if (label1 != null) {\n          this._emit(this._indent + 'break ' + Skew.TypeScriptEmitter._mangleName(label1) + ';');\n        }\n\n        else {\n          this._emit(this._indent + 'break;');\n        }\n\n        this._emitTrailingComment(trailing);\n        this._emit('\\n');\n        break;\n      }\n\n      case Skew.NodeKind.CONTINUE: {\n        this._emit(this._indent + 'continue;');\n        this._emitTrailingComment(trailing);\n        this._emit('\\n');\n        break;\n      }\n\n      case Skew.NodeKind.IF: {\n        this._emit(this._indent);\n\n        if (trailing != null) {\n          this._emitComments([trailing]);\n        }\n\n        this._emitIf(node);\n        break;\n      }\n\n      case Skew.NodeKind.SWITCH: {\n        var switchValue = node.switchValue();\n        this._emit(this._indent + 'switch (');\n        this._emitExpression(switchValue, Skew.Precedence.LOWEST);\n        this._emit(') {\\n');\n        this._increaseIndent();\n\n        for (var child1 = switchValue.nextSibling(); child1 != null; child1 = child1.nextSibling()) {\n          var block = child1.caseBlock();\n          var blockComments = block.comments;\n\n          if (child1.previousSibling() != switchValue) {\n            this._emit('\\n');\n          }\n\n          this._emitComments(child1.comments);\n\n          if (child1.hasOneChild()) {\n            this._emit(this._indent + 'default:');\n          }\n\n          else {\n            for (var value1 = child1.firstChild(); value1 != block; value1 = value1.nextSibling()) {\n              if (value1.previousSibling() != null) {\n                this._emit('\\n');\n              }\n\n              this._emitComments(this._commentsFromExpression(value1));\n              this._emit(this._indent + 'case ');\n              this._emitExpression(value1, Skew.Precedence.LOWEST);\n              this._emit(':');\n            }\n          }\n\n          // Some people put comments before blocks in case statements\n          if (blockComments != null) {\n            this._emit('\\n');\n            this._emitComments(blockComments);\n            this._emit(this._indent + '{\\n');\n          }\n\n          else {\n            this._emit(' {\\n');\n          }\n\n          this._increaseIndent();\n          this._emitStatements(block);\n\n          if (block.hasControlFlowAtEnd()) {\n            this._emit(this._indent + 'break;\\n');\n          }\n\n          this._decreaseIndent();\n          this._emit(this._indent + '}\\n');\n        }\n\n        this._decreaseIndent();\n        this._emit(this._indent + '}');\n        this._emitTrailingComment(trailing);\n        this._emit('\\n');\n        break;\n      }\n\n      case Skew.NodeKind.RETURN: {\n        this._emit(this._indent + 'return');\n        var value2 = node.returnValue();\n\n        if (value2 != null) {\n          var comments1 = value2.comments;\n\n          if (comments1 != null) {\n            // JavaScript needs parentheses here to avoid ASI issues\n            this._emit(' (\\n');\n            this._increaseIndent();\n            this._emitComments(comments1);\n            this._emit(this._indent);\n            this._emitExpression(value2, Skew.Precedence.LOWEST);\n            this._decreaseIndent();\n            this._emit(')');\n          }\n\n          else {\n            this._emit(' ');\n            this._emitExpression(value2, Skew.Precedence.LOWEST);\n          }\n        }\n\n        this._emit(';');\n        this._emitTrailingComment(trailing);\n        this._emit('\\n');\n        break;\n      }\n\n      case Skew.NodeKind.THROW: {\n        this._emit(this._indent + 'throw ');\n        this._emitExpression(node.throwValue(), Skew.Precedence.LOWEST);\n        this._emit(';');\n        this._emitTrailingComment(trailing);\n        this._emit('\\n');\n        break;\n      }\n\n      case Skew.NodeKind.FOREACH: {\n        var value3 = node.foreachValue();\n        this._emit(this._indent + 'for (const ' + Skew.TypeScriptEmitter._mangleName(node.symbol));\n        this._emit(this._cache.isList(value3.resolvedType) ? ' of ' : ' in ');\n        this._emitExpression(value3, Skew.Precedence.LOWEST);\n        this._emit(')');\n        this._emitBlock(node.foreachBlock());\n        this._emitTrailingComment(trailing);\n        this._emit('\\n');\n        break;\n      }\n\n      case Skew.NodeKind.FOR: {\n        var setup = node.forSetup();\n        var test = node.forTest();\n        var update = node.forUpdate();\n        this._emit(this._indent + 'for (');\n\n        if (!setup.isEmptySequence()) {\n          if (setup.kind == Skew.NodeKind.VARIABLES) {\n            var symbol1 = setup.firstChild().symbol.asVariableSymbol();\n            this._emit('let ');\n\n            for (var child2 = setup.firstChild(); child2 != null; child2 = child2.nextSibling()) {\n              symbol1 = child2.symbol.asVariableSymbol();\n              assert(child2.kind == Skew.NodeKind.VARIABLE);\n\n              if (child2.previousSibling() != null) {\n                this._emit(', ');\n              }\n\n              if (this._canOmitTypeAnnotation(symbol1.value)) {\n                this._emit(Skew.TypeScriptEmitter._mangleName(symbol1));\n              }\n\n              else {\n                this._emit(Skew.TypeScriptEmitter._mangleName(symbol1) + ': ');\n                this._emitExpressionOrType(symbol1.type, symbol1.resolvedType);\n              }\n\n              this._emit(' = ');\n              this._emitExpression(symbol1.value, Skew.Precedence.COMMA);\n            }\n          }\n\n          else {\n            this._emitExpression(setup, Skew.Precedence.LOWEST);\n          }\n        }\n\n        this._emit('; ');\n\n        if (!test.isEmptySequence()) {\n          this._emitExpression(test, Skew.Precedence.LOWEST);\n        }\n\n        this._emit('; ');\n\n        if (!update.isEmptySequence()) {\n          this._emitExpression(update, Skew.Precedence.LOWEST);\n        }\n\n        this._emit(')');\n        this._emitBlock(node.forBlock());\n        this._emitTrailingComment(trailing);\n        this._emit('\\n');\n        break;\n      }\n\n      case Skew.NodeKind.TRY: {\n        var tryBlock = node.tryBlock();\n        var finallyBlock = node.finallyBlock();\n\n        if (trailing != null) {\n          this._emitComments([trailing]);\n        }\n\n        this._emit(this._indent + 'try');\n        this._emitBlock(tryBlock);\n        this._emit('\\n');\n\n        for (var child3 = tryBlock.nextSibling(); child3 != finallyBlock; child3 = child3.nextSibling()) {\n          if (child3.comments != null) {\n            this._emit('\\n');\n            this._emitComments(child3.comments);\n          }\n\n          this._emit(this._indent + 'catch');\n\n          if (child3.symbol != null) {\n            this._emit(' (' + Skew.TypeScriptEmitter._mangleName(child3.symbol) + ')');\n          }\n\n          this._emitBlock(child3.catchBlock());\n          this._emit('\\n');\n        }\n\n        if (finallyBlock != null) {\n          if (finallyBlock.comments != null) {\n            this._emit('\\n');\n            this._emitComments(finallyBlock.comments);\n          }\n\n          this._emit(this._indent + 'finally');\n          this._emitBlock(finallyBlock);\n          this._emit('\\n');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.WHILE: {\n        this._emit(this._indent + 'while (');\n        this._emitExpression(node.whileTest(), Skew.Precedence.LOWEST);\n        this._emit(')');\n        this._emitBlock(node.whileBlock());\n        this._emitTrailingComment(trailing);\n        this._emit('\\n');\n        break;\n      }\n\n      default: {\n        assert(false);\n        break;\n      }\n    }\n  };\n\n  Skew.TypeScriptEmitter.prototype._emitContent = function(content) {\n    switch (content.kind()) {\n      case Skew.ContentKind.BOOL: {\n        this._emit(Skew.in_Content.asBool(content).toString());\n        break;\n      }\n\n      case Skew.ContentKind.INT: {\n        this._emit(Skew.in_Content.asInt(content).toString());\n        break;\n      }\n\n      case Skew.ContentKind.DOUBLE: {\n        var value = Skew.in_Content.asDouble(content);\n        this._emit(isNaN(value) ? 'NaN' : value == 1 / 0 ? 'Infinity' : value == -(1 / 0) ? '-Infinity' : value.toString());\n        break;\n      }\n\n      case Skew.ContentKind.STRING: {\n        this._emit(Skew.quoteString(Skew.in_Content.asString(content), Skew.QuoteStyle.SHORTEST, Skew.QuoteOctal.NORMAL));\n        break;\n      }\n    }\n  };\n\n  Skew.TypeScriptEmitter.prototype._commentsFromExpression = function(node) {\n    var comments = node.comments;\n\n    switch (node.kind) {\n      case Skew.NodeKind.CAST: {\n        return Skew.Comment.concat(comments, node.castValue().comments);\n      }\n\n      case Skew.NodeKind.CALL: {\n        return Skew.Comment.concat(comments, node.callValue().comments);\n      }\n    }\n\n    return comments;\n  };\n\n  Skew.TypeScriptEmitter.prototype._emitCommaSeparatedExpressions = function(from, to) {\n    var isIndented = false;\n\n    for (var child = from; child != to; child = child.nextSibling()) {\n      if (this._commentsFromExpression(child) != null) {\n        isIndented = true;\n        break;\n      }\n    }\n\n    if (isIndented) {\n      this._increaseIndent();\n    }\n\n    while (from != to) {\n      var comments = this._commentsFromExpression(from);\n      var trailing = Skew.Comment.lastTrailingComment(comments);\n      var notTrailing = Skew.Comment.withoutLastTrailingComment(comments);\n\n      if (isIndented) {\n        this._emit('\\n');\n        this._emitComments(notTrailing);\n        this._emit(this._indent);\n      }\n\n      this._emitExpression(from, Skew.Precedence.COMMA);\n      from = from.nextSibling();\n\n      if (from != to) {\n        this._emit(isIndented ? ',' : ', ');\n      }\n\n      this._emitTrailingComment(trailing);\n    }\n\n    if (isIndented) {\n      this._decreaseIndent();\n      this._emit('\\n');\n      this._emit(this._indent);\n    }\n  };\n\n  Skew.TypeScriptEmitter.prototype._emitExpression = function(node, precedence) {\n    var kind = node.kind;\n    var symbol = node.symbol;\n\n    if (symbol != null) {\n      this._handleSymbol(symbol);\n    }\n\n    switch (kind) {\n      case Skew.NodeKind.TYPE:\n      case Skew.NodeKind.LAMBDA_TYPE: {\n        this._emitType(node.resolvedType);\n        break;\n      }\n\n      case Skew.NodeKind.NULL: {\n        this._emit('null');\n        break;\n      }\n\n      case Skew.NodeKind.NAME: {\n        this._emit(symbol != null ? this._fullName(symbol) : node.asString());\n        break;\n      }\n\n      case Skew.NodeKind.DOT: {\n        var innerComments = node.innerComments;\n        this._emitExpression(node.dotTarget(), Skew.Precedence.MEMBER);\n\n        if (innerComments != null) {\n          this._increaseIndent();\n          this._emit('\\n');\n          this._emitComments(innerComments);\n          this._emit(this._indent);\n          this._decreaseIndent();\n        }\n\n        this._emit('.' + (symbol != null ? Skew.TypeScriptEmitter._mangleName(symbol) : node.asString()));\n        break;\n      }\n\n      case Skew.NodeKind.STRING_INTERPOLATION: {\n        this._emit('`');\n        var isString = true;\n\n        for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n          if (isString) {\n            this._emit(Skew.quoteString(child.asString(), Skew.QuoteStyle.TYPESCRIPT_TEMPLATE, Skew.QuoteOctal.NORMAL));\n          }\n\n          else {\n            this._emit('${');\n            var value = child;\n\n            // Omit implied \".toString()\" calls on interpolated values\n            if (value.kind == Skew.NodeKind.CALL) {\n              var target = value.callValue();\n\n              if (target.nextSibling() == null && target.kind == Skew.NodeKind.DOT && target.asString() == 'toString') {\n                value = target.dotTarget();\n              }\n            }\n\n            this._emitExpression(value, Skew.Precedence.LOWEST);\n            this._emit('}');\n          }\n\n          isString = !isString;\n        }\n\n        this._emit('`');\n        break;\n      }\n\n      case Skew.NodeKind.CONSTANT: {\n        var wrap = precedence == Skew.Precedence.MEMBER && node.isNumberLessThanZero() && (!node.isDouble() || isFinite(node.asDouble()));\n\n        if (wrap) {\n          this._emit('(');\n        }\n\n        this._emitContent(node.content);\n\n        if (node.resolvedType.isEnumOrFlags()) {\n          this._emit(' as ');\n          this._emitType(node.resolvedType);\n        }\n\n        if (wrap) {\n          this._emit(')');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.CALL: {\n        var value1 = node.callValue();\n        var wrap1 = value1.kind == Skew.NodeKind.LAMBDA;\n\n        // Turn \"new Object\" into \"{}\"\n        if (value1.kind == Skew.NodeKind.DOT && value1.asString() == 'new' && value1.nextSibling() == null) {\n          var target1 = value1.dotTarget();\n\n          if (target1.kind == Skew.NodeKind.NAME && target1.asString() == 'Object') {\n            this._emit('{}');\n            return;\n          }\n        }\n\n        if (wrap1) {\n          this._emit('(');\n        }\n\n        if (value1.kind == Skew.NodeKind.SUPER) {\n          this._emit('super');\n\n          if (symbol.kind != Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n            this._emit('.');\n            this._emit(Skew.TypeScriptEmitter._mangleName(symbol));\n          }\n        }\n\n        else if (symbol != null && symbol.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n          this._emit('new ');\n          this._emitType(node.resolvedType);\n        }\n\n        else if (value1.kind == Skew.NodeKind.DOT && value1.asString() == 'new') {\n          this._emit('new ');\n          this._emitExpression(value1.dotTarget(), Skew.Precedence.MEMBER);\n        }\n\n        else {\n          this._emitExpression(value1, Skew.Precedence.UNARY_POSTFIX);\n        }\n\n        if (wrap1) {\n          this._emit(')');\n        }\n\n        this._emit('(');\n\n        if (symbol != null && symbol.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n          var multiple = in_IntMap.get(this._ctors, symbol.parent.id, null);\n\n          if (multiple != null && !multiple.canUseArgumentCount) {\n            this._emit(multiple.ctors.indexOf(symbol).toString());\n\n            if (value1.nextSibling() != null) {\n              this._emit(', ');\n            }\n          }\n        }\n\n        this._emitCommaSeparatedExpressions(value1.nextSibling(), null);\n        this._emit(')');\n        break;\n      }\n\n      case Skew.NodeKind.CAST: {\n        var type = node.castType();\n        var value2 = node.castValue();\n        var unwrappedSource = this._cache.unwrappedType(value2.resolvedType);\n        var unwrappedTarget = this._cache.unwrappedType(type.resolvedType);\n\n        // Skip the cast in certain cases\n        if (type.kind == Skew.NodeKind.TYPE && (type.resolvedType == Skew.Type.DYNAMIC || value2.kind == Skew.NodeKind.NULL)) {\n          this._emitExpression(value2, precedence);\n        }\n\n        // Conversion from integer to any numeric type can be ignored\n        else if (this._cache.isInteger(unwrappedSource) && this._cache.isNumeric(unwrappedTarget)) {\n          this._emitExpression(value2, precedence);\n        }\n\n        // Cast from bool to a number\n        else if (this._cache.isNumeric(unwrappedTarget) && value2.resolvedType == this._cache.boolType) {\n          this._emitExpression(Skew.Node.createHook(value2.remove(), this._cache.createInt(1), this._cache.createInt(0)).withType(this._cache.intType), precedence);\n        }\n\n        // Cast to bool\n        else if (unwrappedTarget == this._cache.boolType && unwrappedSource != this._cache.boolType) {\n          this._emitExpression(Skew.Node.createUnary(Skew.NodeKind.NOT, Skew.Node.createUnary(Skew.NodeKind.NOT, value2.remove()).withType(this._cache.boolType)).withType(this._cache.boolType), precedence);\n        }\n\n        // Cast to int\n        else if (this._cache.isInteger(unwrappedTarget) && !this._cache.isInteger(unwrappedSource)) {\n          this._emitExpression(Skew.Node.createBinary(Skew.NodeKind.BITWISE_OR, value2.remove(), new Skew.Node(Skew.NodeKind.CONSTANT).withContent(new Skew.IntContent(0)).withType(this._cache.intType)).withType(this._cache.intType), precedence);\n        }\n\n        // Cast to double\n        else if (unwrappedTarget == this._cache.doubleType && unwrappedSource != this._cache.doubleType) {\n          this._emitExpression(Skew.Node.createUnary(Skew.NodeKind.POSITIVE, value2.remove()).withType(this._cache.doubleType), precedence);\n        }\n\n        // Cast to string\n        else if (unwrappedTarget == this._cache.stringType && unwrappedSource != this._cache.stringType) {\n          this._emitExpression(Skew.Node.createSymbolCall(this._specialVariable(Skew.TypeScriptEmitter.SpecialVariable.AS_STRING)).appendChild(value2.remove()).withType(this._cache.stringType), precedence);\n        }\n\n        // Only emit a cast if the underlying types are different\n        else if (unwrappedSource != unwrappedTarget || type.resolvedType == Skew.Type.DYNAMIC) {\n          if (Skew.Precedence.ASSIGN < precedence) {\n            this._emit('(');\n          }\n\n          this._emitExpression(value2, Skew.Precedence.ASSIGN);\n          this._emit(' as ');\n          this._emitExpressionOrType(type, type.resolvedType);\n\n          if (Skew.Precedence.ASSIGN < precedence) {\n            this._emit(')');\n          }\n        }\n\n        // Otherwise, pretend the cast isn't there\n        else {\n          this._emitExpression(value2, precedence);\n        }\n        break;\n      }\n\n      case Skew.NodeKind.TYPE_CHECK: {\n        var value3 = node.typeCheckValue();\n        var type1 = node.typeCheckType();\n        var targetType = this._cache.unwrappedType(type1.resolvedType);\n\n        if (this._cache.isInteger(targetType)) {\n          this._emitExpression(Skew.Node.createSymbolCall(this._specialVariable(Skew.TypeScriptEmitter.SpecialVariable.IS_INT)).appendChild(value3.remove()).withType(this._cache.boolType), precedence);\n          return;\n        }\n\n        if (Skew.Precedence.COMPARE < precedence) {\n          this._emit('(');\n        }\n\n        if (targetType == this._cache.doubleType) {\n          this._emit('typeof ');\n          this._emitExpression(value3, Skew.Precedence.UNARY_PREFIX);\n          this._emit(\" === 'number'\");\n        }\n\n        else if (targetType == this._cache.stringType) {\n          this._emit('typeof ');\n          this._emitExpression(value3, Skew.Precedence.UNARY_PREFIX);\n          this._emit(\" === 'string'\");\n        }\n\n        else if (targetType == this._cache.boolType) {\n          this._emit('typeof ');\n          this._emitExpression(value3, Skew.Precedence.UNARY_PREFIX);\n          this._emit(\" === 'boolean'\");\n        }\n\n        else {\n          this._emitExpression(value3, Skew.Precedence.LOWEST);\n          this._emit(' instanceof ');\n\n          if (type1.resolvedType == Skew.Type.DYNAMIC) {\n            this._emitExpression(type1, Skew.Precedence.LOWEST);\n          }\n\n          else {\n            this._emitExpressionOrType(type1, type1.resolvedType);\n          }\n        }\n\n        if (Skew.Precedence.COMPARE < precedence) {\n          this._emit(')');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.INITIALIZER_LIST: {\n        this._emit('[');\n        this._emitCommaSeparatedExpressions(node.firstChild(), null);\n        this._emit(']');\n        break;\n      }\n\n      case Skew.NodeKind.INITIALIZER_MAP: {\n        if (!node.hasChildren()) {\n          this._emit('{}');\n        }\n\n        else {\n          this._emit('{\\n');\n          this._increaseIndent();\n\n          for (var child1 = node.firstChild(); child1 != null; child1 = child1.nextSibling()) {\n            this._emitComments(child1.comments);\n            this._emit(this._indent);\n            this._emitExpression(child1.firstValue(), Skew.Precedence.COMMA);\n            this._emit(': ');\n            this._emitExpression(child1.secondValue(), Skew.Precedence.COMMA);\n            this._emit(',\\n');\n          }\n\n          this._decreaseIndent();\n          this._emit(this._indent + '}');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.INDEX: {\n        this._emitExpression(node.indexLeft(), Skew.Precedence.UNARY_POSTFIX);\n        this._emit('[');\n        this._emitExpression(node.indexRight(), Skew.Precedence.LOWEST);\n        this._emit(']');\n        break;\n      }\n\n      case Skew.NodeKind.ASSIGN_INDEX: {\n        if (Skew.Precedence.ASSIGN < precedence) {\n          this._emit('(');\n        }\n\n        this._emitExpression(node.assignIndexLeft(), Skew.Precedence.UNARY_POSTFIX);\n        this._emit('[');\n        this._emitExpression(node.assignIndexCenter(), Skew.Precedence.LOWEST);\n        this._emit('] = ');\n        this._emitExpression(node.assignIndexRight(), Skew.Precedence.ASSIGN);\n\n        if (Skew.Precedence.ASSIGN < precedence) {\n          this._emit(')');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.PARAMETERIZE: {\n        var value4 = node.parameterizeValue();\n\n        if (value4.isType()) {\n          this._emitType(node.resolvedType);\n        }\n\n        else {\n          this._emitExpression(value4, precedence);\n          this._emit('<');\n          this._emitCommaSeparatedExpressions(value4.nextSibling(), null);\n          this._emit('>');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.SEQUENCE: {\n        if (Skew.Precedence.COMMA <= precedence) {\n          this._emit('(');\n        }\n\n        this._emitCommaSeparatedExpressions(node.firstChild(), null);\n\n        if (Skew.Precedence.COMMA <= precedence) {\n          this._emit(')');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.HOOK: {\n        if (Skew.Precedence.ASSIGN < precedence) {\n          this._emit('(');\n        }\n\n        this._emitExpression(node.hookTest(), Skew.Precedence.LOGICAL_OR);\n        this._emit(' ?');\n        var left = node.hookTrue();\n        var leftComments = this._commentsFromExpression(left);\n\n        if (leftComments != null) {\n          this._emit('\\n');\n          this._increaseIndent();\n          this._emitComments(leftComments);\n          this._emit(this._indent);\n          this._emitExpression(left, Skew.Precedence.ASSIGN);\n          this._decreaseIndent();\n        }\n\n        else {\n          this._emit(' ');\n          this._emitExpression(left, Skew.Precedence.ASSIGN);\n        }\n\n        this._emit(' :');\n        var right = node.hookFalse();\n        var rightComments = this._commentsFromExpression(right);\n\n        if (rightComments != null) {\n          this._emit('\\n');\n          this._increaseIndent();\n          this._emitComments(rightComments);\n          this._emit(this._indent);\n          this._emitExpression(right, Skew.Precedence.ASSIGN);\n          this._decreaseIndent();\n        }\n\n        else {\n          this._emit(' ');\n          this._emitExpression(right, Skew.Precedence.ASSIGN);\n        }\n\n        if (Skew.Precedence.ASSIGN < precedence) {\n          this._emit(')');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.LAMBDA: {\n        var oldEnclosingFunction = this._enclosingFunction;\n        this._enclosingFunction = symbol.asFunctionSymbol();\n        this._emitArgumentList(symbol.asFunctionSymbol());\n        this._emit(' =>');\n        this._emitBlock(symbol.asFunctionSymbol().block);\n        this._enclosingFunction = oldEnclosingFunction;\n        break;\n      }\n\n      case Skew.NodeKind.COMPLEMENT:\n      case Skew.NodeKind.NEGATIVE:\n      case Skew.NodeKind.NOT:\n      case Skew.NodeKind.POSITIVE:\n      case Skew.NodeKind.POSTFIX_DECREMENT:\n      case Skew.NodeKind.POSTFIX_INCREMENT:\n      case Skew.NodeKind.PREFIX_DECREMENT:\n      case Skew.NodeKind.PREFIX_INCREMENT: {\n        var value5 = node.unaryValue();\n        var info = in_IntMap.get1(Skew.operatorInfo, kind);\n        var sign = node.sign();\n\n        if (info.precedence < precedence) {\n          this._emit('(');\n        }\n\n        if (!Skew.in_NodeKind.isUnaryPostfix(kind)) {\n          this._emit(info.text);\n\n          // Prevent \"x - -1\" from becoming \"x--1\"\n          if (sign != Skew.NodeKind.NULL && sign == value5.sign()) {\n            this._emit(' ');\n          }\n        }\n\n        this._emitExpression(value5, info.precedence);\n\n        if (Skew.in_NodeKind.isUnaryPostfix(kind)) {\n          this._emit(info.text);\n        }\n\n        if (info.precedence < precedence) {\n          this._emit(')');\n        }\n        break;\n      }\n\n      default: {\n        if (Skew.in_NodeKind.isBinary(kind)) {\n          var left1 = node.binaryLeft();\n          var right1 = node.binaryRight();\n\n          // Handle truncating integer division\n          if (node.resolvedType == this._cache.intType && kind == Skew.NodeKind.DIVIDE && node.parent() != null && node.parent().kind != Skew.NodeKind.BITWISE_OR) {\n            var divide = Skew.Node.createBinary(Skew.NodeKind.DIVIDE, left1.remove(), right1.remove()).withType(this._cache.intType);\n            var zero = new Skew.Node(Skew.NodeKind.CONSTANT).withContent(new Skew.IntContent(0)).withType(this._cache.intType);\n            this._emitExpression(Skew.Node.createBinary(Skew.NodeKind.BITWISE_OR, divide, zero).withType(this._cache.intType), precedence);\n            return;\n          }\n\n          var info1 = in_IntMap.get1(Skew.operatorInfo, kind);\n\n          if (info1.precedence < precedence) {\n            this._emit('(');\n          }\n\n          this._emitExpression(left1, info1.precedence + (info1.associativity == Skew.Associativity.RIGHT | 0) | 0);\n          this._emit(' ' + info1.text + (kind == Skew.NodeKind.EQUAL || kind == Skew.NodeKind.NOT_EQUAL ? '=' : ''));\n          var comments = this._commentsFromExpression(right1);\n\n          if (comments != null) {\n            var leading = Skew.Comment.firstTrailingComment(comments);\n            var notLeading = Skew.Comment.withoutFirstTrailingComment(comments);\n            this._emitTrailingComment(leading);\n            this._emit('\\n');\n            this._increaseIndent();\n            this._emitComments(notLeading);\n            this._emit(this._indent);\n            this._emitExpression(right1, info1.precedence + (info1.associativity == Skew.Associativity.LEFT | 0) | 0);\n            this._decreaseIndent();\n          }\n\n          else {\n            this._emit(' ');\n            this._emitExpression(right1, info1.precedence + (info1.associativity == Skew.Associativity.LEFT | 0) | 0);\n          }\n\n          if (info1.precedence < precedence) {\n            this._emit(')');\n          }\n        }\n\n        else {\n          assert(false);\n        }\n        break;\n      }\n    }\n  };\n\n  Skew.TypeScriptEmitter.prototype._fullName = function(symbol) {\n    var parent = symbol.parent;\n\n    if (parent != null && parent.kind != Skew.SymbolKind.OBJECT_GLOBAL && (!Skew.TypeScriptEmitter._shouldFlattenNamespace(parent) || parent.isImported()) && !Skew.in_SymbolKind.isParameter(symbol.kind) && !(this._enclosingNamespaces.indexOf(parent) != -1)) {\n      var enclosingName = this._fullName(parent);\n\n      if (symbol.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n        return enclosingName;\n      }\n\n      return enclosingName + '.' + Skew.TypeScriptEmitter._mangleName(symbol);\n    }\n\n    return Skew.TypeScriptEmitter._mangleName(symbol);\n  };\n\n  Skew.TypeScriptEmitter._isInsideNamespaceOrGlobal = function(symbol) {\n    var parent = symbol.parent;\n    return parent != null && (parent.kind == Skew.SymbolKind.OBJECT_GLOBAL || parent.kind == Skew.SymbolKind.OBJECT_NAMESPACE && Skew.TypeScriptEmitter._isInsideNamespaceOrGlobal(parent));\n  };\n\n  Skew.TypeScriptEmitter._shouldFlattenNamespace = function(symbol) {\n    return symbol.kind == Skew.SymbolKind.OBJECT_NAMESPACE && Skew.TypeScriptEmitter._isInsideNamespaceOrGlobal(symbol);\n  };\n\n  Skew.TypeScriptEmitter._isCompactNodeKind = function(kind) {\n    return kind == Skew.NodeKind.EXPRESSION || kind == Skew.NodeKind.VARIABLES || Skew.in_NodeKind.isJump(kind);\n  };\n\n  Skew.TypeScriptEmitter._mangleName = function(symbol) {\n    symbol = symbol.forwarded();\n\n    if (symbol.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n      symbol = symbol.parent;\n    }\n\n    if (!symbol.isImportedOrExported() && Skew.TypeScriptEmitter._isKeyword.has(symbol.name)) {\n      return '_' + symbol.name;\n    }\n\n    var parent = symbol.parent;\n\n    if (parent != null && parent.kind == Skew.SymbolKind.OBJECT_NAMESPACE && parent.name.startsWith('in_')) {\n      var prefix = Skew.TypeScriptEmitter._mangleName(parent);\n\n      if (prefix.startsWith('in_')) {\n        prefix = in_string.slice1(prefix, 3);\n      }\n\n      return prefix + '_' + symbol.name;\n    }\n\n    return symbol.name;\n  };\n\n  Skew.TypeScriptEmitter.MultipleCtors = function(ctors, canUseArgumentCount) {\n    this.ctors = ctors;\n    this.canUseArgumentCount = canUseArgumentCount;\n  };\n\n  Skew.TypeScriptEmitter.SpecialVariable = {\n    NONE: 0,\n    AS_STRING: 1,\n    IS_INT: 2\n  };\n\n  Skew.QuoteStyle = {\n    DOUBLE: 0,\n    SINGLE: 1,\n    SHORTEST: 2,\n    TYPESCRIPT_TEMPLATE: 3\n  };\n\n  Skew.QuoteOctal = {\n    NORMAL: 0,\n    OCTAL_WORKAROUND: 1\n  };\n\n  Skew.Associativity = {\n    NONE: 0,\n    LEFT: 1,\n    RIGHT: 2\n  };\n\n  // The same operator precedence as C for the most part\n  Skew.Precedence = {\n    LOWEST: 0,\n    COMMA: 1,\n    ASSIGN: 2,\n    NULL_JOIN: 3,\n    LOGICAL_OR: 4,\n    LOGICAL_AND: 5,\n    BITWISE_OR: 6,\n    BITWISE_XOR: 7,\n    BITWISE_AND: 8,\n    EQUAL: 9,\n    COMPARE: 10,\n    SHIFT: 11,\n    ADD: 12,\n    MULTIPLY: 13,\n    UNARY_PREFIX: 14,\n    UNARY_POSTFIX: 15,\n    MEMBER: 16\n  };\n\n  Skew.CPlusPlusEmitter = function(_options, _cache) {\n    Skew.Emitter.call(this);\n    this._options = _options;\n    this._cache = _cache;\n    this._previousNode = null;\n    this._previousSymbol = null;\n    this._namespaceStack = [];\n    this._symbolsCheckedForInclude = new Map();\n    this._includeNames = new Map();\n    this._loopLabels = new Map();\n    this._enclosingFunction = null;\n    this._dummyFunction = new Skew.FunctionSymbol(Skew.SymbolKind.FUNCTION_INSTANCE, '<dummy>');\n  };\n\n  __extends(Skew.CPlusPlusEmitter, Skew.Emitter);\n\n  Skew.CPlusPlusEmitter.prototype.visit = function(global) {\n    // Generate the entry point\n    var entryPoint = this._cache.entryPointSymbol;\n\n    if (entryPoint != null) {\n      entryPoint.name = 'main';\n\n      // The entry point must not be in a namespace\n      if (entryPoint.parent != global) {\n        in_List.removeOne(entryPoint.parent.asObjectSymbol().functions, entryPoint);\n        entryPoint.parent = global;\n        global.functions.push(entryPoint);\n      }\n\n      // The entry point in C++ takes an array, not a list\n      if (entryPoint.$arguments.length == 1) {\n        var argument = in_List.first(entryPoint.$arguments);\n        var argc = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_ARGUMENT, entryPoint.scope.generateName('argc'));\n        var argv = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_ARGUMENT, entryPoint.scope.generateName('argv'));\n        argc.initializeWithType(this._cache.intType);\n        argv.type = new Skew.Node(Skew.NodeKind.NAME).withContent(new Skew.StringContent('char**')).withType(Skew.Type.DYNAMIC);\n        argv.resolvedType = Skew.Type.DYNAMIC;\n        argv.state = Skew.SymbolState.INITIALIZED;\n        entryPoint.$arguments = [argc, argv];\n        entryPoint.resolvedType.argumentTypes = [argc.resolvedType, argv.resolvedType];\n\n        // Create the list from the array\n        if (entryPoint.block != null) {\n          var advance = new Skew.Node(Skew.NodeKind.NAME).withContent(new Skew.StringContent('*' + argv.name + '++')).withType(Skew.Type.DYNAMIC);\n          var block = new Skew.Node(Skew.NodeKind.BLOCK).appendChild(Skew.Node.createExpression(Skew.Node.createCall(new Skew.Node(Skew.NodeKind.DOT).withContent(new Skew.StringContent('append')).appendChild(Skew.Node.createSymbolReference(argument)).withType(Skew.Type.DYNAMIC)).withType(Skew.Type.DYNAMIC).appendChild(advance)));\n          var check = Skew.Node.createIf(advance.clone(), new Skew.Node(Skew.NodeKind.BLOCK).appendChild(new Skew.Node(Skew.NodeKind.WHILE).appendChild(new Skew.Node(Skew.NodeKind.NAME).withContent(new Skew.StringContent('*' + argv.name)).withType(Skew.Type.DYNAMIC)).appendChild(block)), null);\n          argument.kind = Skew.SymbolKind.VARIABLE_LOCAL;\n          argument.value = Skew.Node.createCall(new Skew.Node(Skew.NodeKind.DOT).withContent(new Skew.StringContent('new')).appendChild(new Skew.Node(Skew.NodeKind.TYPE).withType(argument.resolvedType)).withType(Skew.Type.DYNAMIC)).withType(Skew.Type.DYNAMIC);\n          entryPoint.block.prependChild(check);\n          entryPoint.block.prependChild(new Skew.Node(Skew.NodeKind.VARIABLES).appendChild(Skew.Node.createVariable(argument)));\n        }\n      }\n    }\n\n    // Make sure strings reference the right namespace. This has to be set\n    // here instead of in the library code to avoid a cyclic definition.\n    this._cache.stringType.symbol.name = 'Skew::string';\n\n    // Avoid emitting unnecessary stuff\n    Skew.shakingPass(global, this._cache.entryPointSymbol, Skew.ShakingMode.USE_TYPES);\n    this._markVirtualFunctions(global);\n\n    // Nested types in C++ can't be forward declared\n    var sorted = this._sortedObjects(global);\n\n    for (var i = 0, list = sorted, count = list.length; i < count; i = i + 1 | 0) {\n      var symbol = in_List.get(list, i);\n      this._moveNestedObjectToEnclosingNamespace(symbol);\n    }\n\n    // Emit code in passes to deal with C++'s forward declarations\n    for (var i1 = 0, list1 = sorted, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n      var symbol1 = in_List.get(list1, i1);\n      this._declareObject(symbol1);\n    }\n\n    for (var i2 = 0, list2 = sorted, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n      var symbol2 = in_List.get(list2, i2);\n      this._defineObject(symbol2);\n    }\n\n    this._adjustNamespace(null);\n\n    for (var i4 = 0, list4 = sorted, count4 = list4.length; i4 < count4; i4 = i4 + 1 | 0) {\n      var symbol3 = in_List.get(list4, i4);\n\n      if (!symbol3.isImported()) {\n        for (var i3 = 0, list3 = symbol3.variables, count3 = list3.length; i3 < count3; i3 = i3 + 1 | 0) {\n          var variable = in_List.get(list3, i3);\n\n          if (variable.kind == Skew.SymbolKind.VARIABLE_GLOBAL) {\n            this._emitVariable(variable, Skew.CPlusPlusEmitter.CodeMode.IMPLEMENT);\n          }\n        }\n      }\n    }\n\n    this._adjustNamespace(null);\n\n    for (var i6 = 0, list6 = sorted, count6 = list6.length; i6 < count6; i6 = i6 + 1 | 0) {\n      var symbol4 = in_List.get(list6, i6);\n\n      if (!symbol4.isImported()) {\n        for (var i5 = 0, list5 = symbol4.functions, count5 = list5.length; i5 < count5; i5 = i5 + 1 | 0) {\n          var $function = in_List.get(list5, i5);\n          this._emitFunction($function, Skew.CPlusPlusEmitter.CodeMode.IMPLEMENT);\n        }\n\n        this._emitMarkFunction(symbol4, Skew.CPlusPlusEmitter.CodeMode.IMPLEMENT);\n      }\n    }\n\n    this._finalizeEmittedFile();\n    this._createSource(this._options.outputFile, Skew.EmitMode.ALWAYS_EMIT);\n  };\n\n  Skew.CPlusPlusEmitter.prototype._emitNewlineBeforeSymbol = function(symbol, mode) {\n    if (this._previousSymbol != null && (!Skew.in_SymbolKind.isVariable(this._previousSymbol.kind) || !Skew.in_SymbolKind.isVariable(symbol.kind) || symbol.comments != null) && (mode != Skew.CPlusPlusEmitter.CodeMode.DEFINE || !Skew.in_SymbolKind.isFunction(this._previousSymbol.kind) || !Skew.in_SymbolKind.isFunction(symbol.kind) || symbol.comments != null) && (mode != Skew.CPlusPlusEmitter.CodeMode.DECLARE || this._previousSymbol.kind != Skew.SymbolKind.OBJECT_CLASS || symbol.kind != Skew.SymbolKind.OBJECT_CLASS)) {\n      this._emit('\\n');\n    }\n\n    this._previousSymbol = null;\n  };\n\n  Skew.CPlusPlusEmitter.prototype._emitNewlineAfterSymbol = function(symbol) {\n    this._previousSymbol = symbol;\n  };\n\n  Skew.CPlusPlusEmitter.prototype._emitNewlineBeforeStatement = function(node) {\n    if (this._previousNode != null && (node.comments != null || !Skew.CPlusPlusEmitter._isCompactNodeKind(this._previousNode.kind) || !Skew.CPlusPlusEmitter._isCompactNodeKind(node.kind))) {\n      this._emit('\\n');\n    }\n\n    this._previousNode = null;\n  };\n\n  Skew.CPlusPlusEmitter.prototype._emitNewlineAfterStatement = function(node) {\n    this._previousNode = node;\n  };\n\n  Skew.CPlusPlusEmitter.prototype._adjustNamespace = function(symbol) {\n    // Get the namespace chain for this symbol\n    var symbols = [];\n\n    while (symbol != null && symbol.kind != Skew.SymbolKind.OBJECT_GLOBAL) {\n      if (symbol.kind == Skew.SymbolKind.OBJECT_NAMESPACE || symbol.kind == Skew.SymbolKind.OBJECT_WRAPPED) {\n        symbols.unshift(symbol);\n      }\n\n      symbol = symbol.parent;\n    }\n\n    // Find the intersection\n    var limit = Math.min(this._namespaceStack.length, symbols.length);\n    var i = 0;\n\n    while (i < limit) {\n      if (in_List.get(this._namespaceStack, i) != in_List.get(symbols, i)) {\n        break;\n      }\n\n      i = i + 1 | 0;\n    }\n\n    // Leave the old namespace\n    while (this._namespaceStack.length > i) {\n      var object = in_List.takeLast(this._namespaceStack);\n      this._decreaseIndent();\n      this._emit(this._indent + '}\\n');\n      this._emitNewlineAfterSymbol(object);\n    }\n\n    // Enter the new namespace\n    while (this._namespaceStack.length < symbols.length) {\n      var object1 = in_List.get(symbols, this._namespaceStack.length);\n      this._emitNewlineBeforeSymbol(object1, Skew.CPlusPlusEmitter.CodeMode.DEFINE);\n      this._emit(this._indent + 'namespace ' + Skew.CPlusPlusEmitter._mangleName(object1) + ' {\\n');\n      this._increaseIndent();\n      this._namespaceStack.push(object1);\n    }\n  };\n\n  Skew.CPlusPlusEmitter.prototype._emitComments = function(comments) {\n    if (comments != null) {\n      for (var i1 = 0, list1 = comments, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n        var comment = in_List.get(list1, i1);\n\n        for (var i = 0, list = comment.lines, count = list.length; i < count; i = i + 1 | 0) {\n          var line = in_List.get(list, i);\n          this._emit(this._indent + '//' + line + '\\n');\n        }\n\n        if (comment.hasGapBelow) {\n          this._emit('\\n');\n        }\n      }\n    }\n  };\n\n  Skew.CPlusPlusEmitter.prototype._moveNestedObjectToEnclosingNamespace = function(symbol) {\n    var parent = symbol.parent;\n\n    while (parent != null && parent.kind == Skew.SymbolKind.OBJECT_CLASS) {\n      parent = parent.parent;\n    }\n\n    if (symbol.parent != parent) {\n      in_List.removeOne(symbol.parent.asObjectSymbol().objects, symbol);\n      symbol.parent = parent;\n      parent.asObjectSymbol().objects.push(symbol);\n    }\n  };\n\n  Skew.CPlusPlusEmitter.prototype._declareObject = function(symbol) {\n    if (symbol.isImported()) {\n      return;\n    }\n\n    switch (symbol.kind) {\n      case Skew.SymbolKind.OBJECT_ENUM:\n      case Skew.SymbolKind.OBJECT_FLAGS: {\n        this._adjustNamespace(symbol);\n        this._emitNewlineBeforeSymbol(symbol, Skew.CPlusPlusEmitter.CodeMode.DECLARE);\n\n        if (symbol.kind == Skew.SymbolKind.OBJECT_FLAGS) {\n          this._emit(this._indent + 'namespace ' + Skew.CPlusPlusEmitter._mangleName(symbol) + ' {\\n');\n          this._increaseIndent();\n\n          if (!(symbol.variables.length == 0)) {\n            this._emit(this._indent + 'enum {\\n');\n          }\n        }\n\n        else {\n          this._emit(this._indent + 'enum struct ' + Skew.CPlusPlusEmitter._mangleName(symbol) + ' {\\n');\n        }\n\n        this._increaseIndent();\n\n        for (var i = 0, list = symbol.variables, count = list.length; i < count; i = i + 1 | 0) {\n          var variable = in_List.get(list, i);\n          this._emitVariable(variable, Skew.CPlusPlusEmitter.CodeMode.DECLARE);\n        }\n\n        this._decreaseIndent();\n\n        if (symbol.kind == Skew.SymbolKind.OBJECT_FLAGS) {\n          if (!(symbol.variables.length == 0)) {\n            this._emit(this._indent + '};\\n');\n          }\n\n          this._decreaseIndent();\n          this._emit(this._indent + '}\\n');\n        }\n\n        else {\n          this._emit(this._indent + '};\\n');\n        }\n\n        this._emitNewlineAfterSymbol(symbol);\n        break;\n      }\n\n      case Skew.SymbolKind.OBJECT_CLASS:\n      case Skew.SymbolKind.OBJECT_INTERFACE: {\n        this._adjustNamespace(symbol);\n        this._emitNewlineBeforeSymbol(symbol, Skew.CPlusPlusEmitter.CodeMode.DECLARE);\n        this._emitTypeParameters(symbol.parameters);\n        this._emit(this._indent + 'struct ' + Skew.CPlusPlusEmitter._mangleName(symbol) + ';\\n');\n        this._emitNewlineAfterSymbol(symbol);\n        break;\n      }\n    }\n  };\n\n  Skew.CPlusPlusEmitter.prototype._defineObject = function(symbol) {\n    if (symbol.isImported()) {\n      return;\n    }\n\n    switch (symbol.kind) {\n      case Skew.SymbolKind.OBJECT_CLASS:\n      case Skew.SymbolKind.OBJECT_INTERFACE: {\n        this._adjustNamespace(symbol);\n        this._emitNewlineBeforeSymbol(symbol, Skew.CPlusPlusEmitter.CodeMode.DEFINE);\n        this._emitComments(symbol.comments);\n        this._emitTypeParameters(symbol.parameters);\n        this._emit(this._indent + 'struct ' + Skew.CPlusPlusEmitter._mangleName(symbol));\n\n        if (symbol.$extends != null || symbol.$implements != null) {\n          this._emit(' : ');\n\n          if (symbol.$extends != null) {\n            this._emitExpressionOrType(symbol.$extends, symbol.baseType, Skew.CPlusPlusEmitter.CppEmitMode.BARE);\n          }\n\n          if (symbol.$implements != null) {\n            for (var i = 0, list = symbol.$implements, count = list.length; i < count; i = i + 1 | 0) {\n              var node = in_List.get(list, i);\n\n              if (node != in_List.first(symbol.$implements) || symbol.$extends != null) {\n                this._emit(', ');\n              }\n\n              this._emitExpressionOrType(node, node.resolvedType, Skew.CPlusPlusEmitter.CppEmitMode.BARE);\n            }\n          }\n        }\n\n        else {\n          this._emit(' : virtual Skew::Object');\n        }\n\n        this._emit(' {\\n');\n        this._increaseIndent();\n\n        for (var i1 = 0, list1 = symbol.functions, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n          var $function = in_List.get(list1, i1);\n          this._emitFunction($function, Skew.CPlusPlusEmitter.CodeMode.DEFINE);\n        }\n\n        for (var i2 = 0, list2 = symbol.variables, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n          var variable = in_List.get(list2, i2);\n          this._emitVariable(variable, Skew.CPlusPlusEmitter.CodeMode.DEFINE);\n        }\n\n        this._emitMarkFunction(symbol, Skew.CPlusPlusEmitter.CodeMode.DEFINE);\n        this._decreaseIndent();\n        this._emit(this._indent + '};\\n');\n        this._emitNewlineAfterSymbol(symbol);\n        break;\n      }\n\n      case Skew.SymbolKind.OBJECT_NAMESPACE:\n      case Skew.SymbolKind.OBJECT_WRAPPED: {\n        this._adjustNamespace(symbol);\n\n        for (var i3 = 0, list3 = symbol.functions, count3 = list3.length; i3 < count3; i3 = i3 + 1 | 0) {\n          var function1 = in_List.get(list3, i3);\n          this._emitFunction(function1, Skew.CPlusPlusEmitter.CodeMode.DEFINE);\n        }\n\n        for (var i4 = 0, list4 = symbol.variables, count4 = list4.length; i4 < count4; i4 = i4 + 1 | 0) {\n          var variable1 = in_List.get(list4, i4);\n          this._emitVariable(variable1, Skew.CPlusPlusEmitter.CodeMode.DEFINE);\n        }\n        break;\n      }\n    }\n  };\n\n  Skew.CPlusPlusEmitter.prototype._emitEnclosingSymbolPrefix = function(parent) {\n    this._emit(Skew.CPlusPlusEmitter._fullName(parent));\n\n    if (parent.parameters != null) {\n      this._emit('<');\n\n      for (var i = 0, list = parent.parameters, count = list.length; i < count; i = i + 1 | 0) {\n        var parameter = in_List.get(list, i);\n\n        if (parameter != in_List.first(parent.parameters)) {\n          this._emit(', ');\n        }\n\n        this._emit(Skew.CPlusPlusEmitter._mangleName(parameter));\n      }\n\n      this._emit('>');\n    }\n\n    this._emit('::');\n  };\n\n  Skew.CPlusPlusEmitter.prototype._emitFunction = function(symbol, mode) {\n    var parent = symbol.parent.asObjectSymbol();\n    var block = symbol.block;\n\n    if (symbol.isImported() || mode == Skew.CPlusPlusEmitter.CodeMode.IMPLEMENT && block == null) {\n      return;\n    }\n\n    // We can't use lambdas in C++ since they don't have the right semantics so no variable insertion is needed\n    if (symbol.$this != null) {\n      symbol.$this.name = 'this';\n      symbol.$this.flags |= Skew.SymbolFlags.IS_EXPORTED;\n    }\n\n    this._enclosingFunction = symbol;\n    this._emitNewlineBeforeSymbol(symbol, mode);\n    this._emitComments(symbol.comments);\n\n    if (mode == Skew.CPlusPlusEmitter.CodeMode.IMPLEMENT) {\n      // TODO: Merge these with the ones on the symbol when symbols have both\n      this._emitTypeParameters(parent.parameters);\n    }\n\n    this._emitTypeParameters(symbol.parameters);\n    this._emit(this._indent);\n\n    if (mode == Skew.CPlusPlusEmitter.CodeMode.DEFINE && symbol.kind == Skew.SymbolKind.FUNCTION_GLOBAL && symbol.parent.kind == Skew.SymbolKind.OBJECT_CLASS) {\n      this._emit('static ');\n    }\n\n    if (symbol.kind != Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n      if (mode == Skew.CPlusPlusEmitter.CodeMode.DEFINE && (symbol.isVirtual() || block == null)) {\n        this._emit('virtual ');\n      }\n\n      this._emitExpressionOrType(symbol.returnType, symbol.resolvedType.returnType, Skew.CPlusPlusEmitter.CppEmitMode.DECLARATION);\n    }\n\n    if (mode == Skew.CPlusPlusEmitter.CodeMode.IMPLEMENT && parent.kind != Skew.SymbolKind.OBJECT_GLOBAL) {\n      this._emitEnclosingSymbolPrefix(parent);\n    }\n\n    this._emit(Skew.CPlusPlusEmitter._mangleName(symbol));\n    this._emitArgumentList(symbol);\n\n    if (mode == Skew.CPlusPlusEmitter.CodeMode.IMPLEMENT) {\n      // Move the super constructor call out of the function body\n      if (symbol.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR && block.hasChildren()) {\n        var first = block.firstChild();\n\n        if (first.kind == Skew.NodeKind.EXPRESSION) {\n          var call = first.expressionValue();\n\n          if (call.kind == Skew.NodeKind.CALL && call.callValue().kind == Skew.NodeKind.SUPER) {\n            this._emit(' : ');\n            first.remove();\n            this._emitExpression(call, Skew.Precedence.LOWEST);\n          }\n        }\n      }\n\n      this._emitBlock(block);\n      this._emit('\\n');\n    }\n\n    else {\n      if (symbol.overridden != null && symbol.kind != Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n        this._emit(' override');\n      }\n\n      if (block == null) {\n        this._emit(' = 0');\n      }\n\n      this._emit(';\\n');\n    }\n\n    this._emitNewlineAfterSymbol(symbol);\n    this._enclosingFunction = null;\n  };\n\n  Skew.CPlusPlusEmitter.prototype._emitMarkFunction = function(symbol, mode) {\n    if (symbol.kind == Skew.SymbolKind.OBJECT_CLASS) {\n      if (mode == Skew.CPlusPlusEmitter.CodeMode.DEFINE) {\n        this._emit('\\n' + this._indent + '#ifdef SKEW_GC_MARK_AND_SWEEP\\n');\n        this._increaseIndent();\n        this._emit(this._indent + 'virtual void __gc_mark() override;\\n');\n        this._decreaseIndent();\n        this._emit(this._indent + '#endif\\n');\n      }\n\n      else if (mode == Skew.CPlusPlusEmitter.CodeMode.IMPLEMENT) {\n        this._emitNewlineBeforeSymbol(this._dummyFunction, mode);\n        this._emit(this._indent + '#ifdef SKEW_GC_MARK_AND_SWEEP\\n');\n        this._increaseIndent();\n        this._emitTypeParameters(symbol.parameters);\n        this._emit(this._indent + 'void ');\n        this._emitEnclosingSymbolPrefix(symbol);\n        this._emit('__gc_mark() {\\n');\n        this._increaseIndent();\n\n        if (symbol.baseClass != null) {\n          this._emit(this._indent + Skew.CPlusPlusEmitter._fullName(symbol.baseClass) + '::__gc_mark();\\n');\n        }\n\n        for (var i = 0, list = symbol.variables, count = list.length; i < count; i = i + 1 | 0) {\n          var variable = in_List.get(list, i);\n\n          if (variable.kind == Skew.SymbolKind.VARIABLE_INSTANCE && variable.parent == symbol && this._isReferenceType(variable.resolvedType)) {\n            this._emit(this._indent + 'Skew::GC::mark(' + Skew.CPlusPlusEmitter._mangleName(variable) + ');\\n');\n          }\n        }\n\n        this._decreaseIndent();\n        this._emit(this._indent + '}\\n');\n        this._decreaseIndent();\n        this._emit(this._indent + '#endif\\n');\n        this._emitNewlineAfterSymbol(this._dummyFunction);\n      }\n    }\n  };\n\n  Skew.CPlusPlusEmitter.prototype._emitTypeParameters = function(parameters) {\n    if (parameters != null) {\n      this._emit(this._indent + 'template <');\n\n      for (var i = 0, list = parameters, count = list.length; i < count; i = i + 1 | 0) {\n        var parameter = in_List.get(list, i);\n\n        if (parameter != in_List.first(parameters)) {\n          this._emit(', ');\n        }\n\n        this._emit('typename ' + Skew.CPlusPlusEmitter._mangleName(parameter));\n      }\n\n      this._emit('>\\n');\n    }\n  };\n\n  Skew.CPlusPlusEmitter.prototype._emitArgumentList = function(symbol) {\n    this._emit('(');\n\n    for (var i = 0, list = symbol.$arguments, count = list.length; i < count; i = i + 1 | 0) {\n      var argument = in_List.get(list, i);\n\n      if (argument != in_List.first(symbol.$arguments)) {\n        this._emit(', ');\n      }\n\n      this._emitExpressionOrType(argument.type, argument.resolvedType, Skew.CPlusPlusEmitter.CppEmitMode.DECLARATION);\n      this._emit(Skew.CPlusPlusEmitter._mangleName(argument));\n    }\n\n    this._emit(')');\n  };\n\n  Skew.CPlusPlusEmitter.prototype._emitVariable = function(symbol, mode) {\n    if (symbol.isImported()) {\n      return;\n    }\n\n    var avoidFullName = symbol.kind == Skew.SymbolKind.VARIABLE_GLOBAL && symbol.parent.kind != Skew.SymbolKind.OBJECT_CLASS;\n\n    if (mode == Skew.CPlusPlusEmitter.CodeMode.IMPLEMENT && symbol.kind != Skew.SymbolKind.VARIABLE_LOCAL) {\n      this._adjustNamespace(avoidFullName ? symbol.parent : null);\n    }\n\n    this._emitNewlineBeforeSymbol(symbol, mode);\n    this._emitComments(symbol.comments);\n\n    if (symbol.kind == Skew.SymbolKind.VARIABLE_ENUM_OR_FLAGS) {\n      // Enum values are initialized with integers, so avoid any casts\n      symbol.value.resolvedType = this._cache.intType;\n      this._emit(this._indent + Skew.CPlusPlusEmitter._mangleName(symbol) + ' = ');\n      this._emitExpression(symbol.value, Skew.Precedence.COMMA);\n      this._emit(',\\n');\n    }\n\n    else {\n      this._emit(this._indent);\n\n      if (mode == Skew.CPlusPlusEmitter.CodeMode.DEFINE && symbol.kind == Skew.SymbolKind.VARIABLE_GLOBAL) {\n        this._emit(symbol.parent.kind == Skew.SymbolKind.OBJECT_CLASS ? 'static ' : 'extern ');\n      }\n\n      // Global variables must be stored in roots to avoid accidental garbage collection\n      if (symbol.kind == Skew.SymbolKind.VARIABLE_GLOBAL && this._isReferenceType(symbol.resolvedType)) {\n        this._emit('Skew::Root<');\n        this._emitType(symbol.resolvedType, Skew.CPlusPlusEmitter.CppEmitMode.BARE);\n        this._emit('> ');\n      }\n\n      else {\n        this._emitType(symbol.resolvedType, Skew.CPlusPlusEmitter.CppEmitMode.DECLARATION);\n      }\n\n      if (mode == Skew.CPlusPlusEmitter.CodeMode.DEFINE) {\n        this._emit(Skew.CPlusPlusEmitter._mangleName(symbol));\n      }\n\n      else {\n        this._emit(avoidFullName ? Skew.CPlusPlusEmitter._mangleName(symbol) : Skew.CPlusPlusEmitter._fullName(symbol));\n\n        if (symbol.value != null) {\n          this._emit(' = ');\n          this._emitExpression(symbol.value, Skew.Precedence.ASSIGN);\n        }\n      }\n\n      this._emit(';\\n');\n    }\n\n    this._emitNewlineAfterSymbol(symbol);\n  };\n\n  Skew.CPlusPlusEmitter.prototype._emitStatements = function(node) {\n    this._previousNode = null;\n\n    for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n      this._emitNewlineBeforeStatement(child);\n      this._emitComments(child.comments);\n      this._emitStatement(child);\n      this._emitNewlineAfterStatement(child);\n    }\n\n    this._previousNode = null;\n  };\n\n  Skew.CPlusPlusEmitter.prototype._emitBlock = function(node) {\n    this._emit(' {\\n');\n    this._increaseIndent();\n    this._emitStatements(node);\n    this._decreaseIndent();\n    this._emit(this._indent + '}');\n  };\n\n  Skew.CPlusPlusEmitter.prototype._scanForSwitchBreak = function(node, loop) {\n    if (node.kind == Skew.NodeKind.BREAK) {\n      for (var parent = node.parent(); parent != loop; parent = parent.parent()) {\n        if (parent.kind == Skew.NodeKind.SWITCH) {\n          var label = in_IntMap.get(this._loopLabels, loop.id, null);\n\n          if (label == null) {\n            label = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_LOCAL, this._enclosingFunction.scope.generateName('label'));\n            in_IntMap.set(this._loopLabels, loop.id, label);\n          }\n\n          in_IntMap.set(this._loopLabels, node.id, label);\n          break;\n        }\n      }\n    }\n\n    // Stop at nested loops since those will be tested later\n    else if (node == loop || !Skew.in_NodeKind.isLoop(node.kind)) {\n      for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n        this._scanForSwitchBreak(child, loop);\n      }\n    }\n  };\n\n  Skew.CPlusPlusEmitter.prototype._emitStatement = function(node) {\n    if (Skew.in_NodeKind.isLoop(node.kind)) {\n      this._scanForSwitchBreak(node, node);\n    }\n\n    switch (node.kind) {\n      case Skew.NodeKind.COMMENT_BLOCK: {\n        break;\n      }\n\n      case Skew.NodeKind.VARIABLES: {\n        for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n          this._emitVariable(child.symbol.asVariableSymbol(), Skew.CPlusPlusEmitter.CodeMode.IMPLEMENT);\n        }\n        break;\n      }\n\n      case Skew.NodeKind.EXPRESSION: {\n        this._emit(this._indent);\n        this._emitExpression(node.expressionValue(), Skew.Precedence.LOWEST);\n        this._emit(';\\n');\n        break;\n      }\n\n      case Skew.NodeKind.BREAK: {\n        var label = in_IntMap.get(this._loopLabels, node.id, null);\n\n        if (label != null) {\n          this._emit(this._indent + 'goto ' + Skew.CPlusPlusEmitter._mangleName(label) + ';\\n');\n        }\n\n        else {\n          this._emit(this._indent + 'break;\\n');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.CONTINUE: {\n        this._emit(this._indent + 'continue;\\n');\n        break;\n      }\n\n      case Skew.NodeKind.IF: {\n        this._emit(this._indent);\n        this._emitIf(node);\n        this._emit('\\n');\n        break;\n      }\n\n      case Skew.NodeKind.SWITCH: {\n        var switchValue = node.switchValue();\n        this._emit(this._indent + 'switch (');\n        this._emitExpression(switchValue, Skew.Precedence.LOWEST);\n        this._emit(') {\\n');\n        this._increaseIndent();\n\n        for (var child1 = switchValue.nextSibling(); child1 != null; child1 = child1.nextSibling()) {\n          var block = child1.caseBlock();\n\n          if (child1.previousSibling() != switchValue) {\n            this._emit('\\n');\n          }\n\n          if (child1.hasOneChild()) {\n            this._emit(this._indent + 'default:');\n          }\n\n          else {\n            for (var value = child1.firstChild(); value != block; value = value.nextSibling()) {\n              if (value.previousSibling() != null) {\n                this._emit('\\n');\n              }\n\n              this._emit(this._indent + 'case ');\n              this._emitExpression(value, Skew.Precedence.LOWEST);\n              this._emit(':');\n            }\n          }\n\n          this._emit(' {\\n');\n          this._increaseIndent();\n          this._emitStatements(block);\n\n          if (block.hasControlFlowAtEnd()) {\n            this._emit(this._indent + 'break;\\n');\n          }\n\n          this._decreaseIndent();\n          this._emit(this._indent + '}\\n');\n        }\n\n        this._decreaseIndent();\n        this._emit(this._indent + '}\\n');\n        break;\n      }\n\n      case Skew.NodeKind.RETURN: {\n        this._emit(this._indent + 'return');\n        var value1 = node.returnValue();\n\n        if (value1 != null) {\n          this._emit(' ');\n          this._emitExpression(value1, Skew.Precedence.LOWEST);\n        }\n\n        this._emit(';\\n');\n        break;\n      }\n\n      case Skew.NodeKind.THROW: {\n        this._emit(this._indent + 'throw ');\n        this._emitExpression(node.throwValue(), Skew.Precedence.LOWEST);\n        this._emit(';\\n');\n        break;\n      }\n\n      case Skew.NodeKind.FOR: {\n        var setup = node.forSetup();\n        var test = node.forTest();\n        var update = node.forUpdate();\n        this._emit(this._indent + 'for (');\n\n        if (!setup.isEmptySequence()) {\n          if (setup.kind == Skew.NodeKind.VARIABLES) {\n            this._emitType(setup.firstChild().symbol.asVariableSymbol().resolvedType, Skew.CPlusPlusEmitter.CppEmitMode.DECLARATION);\n\n            for (var child2 = setup.firstChild(); child2 != null; child2 = child2.nextSibling()) {\n              var symbol = child2.symbol.asVariableSymbol();\n              assert(child2.kind == Skew.NodeKind.VARIABLE);\n\n              if (child2.previousSibling() != null) {\n                this._emit(', ');\n\n                if (this._isReferenceType(symbol.resolvedType)) {\n                  this._emit('*');\n                }\n              }\n\n              this._emit(Skew.CPlusPlusEmitter._mangleName(symbol) + ' = ');\n              this._emitExpression(symbol.value, Skew.Precedence.COMMA);\n            }\n          }\n\n          else {\n            this._emitExpression(setup, Skew.Precedence.LOWEST);\n          }\n        }\n\n        this._emit('; ');\n\n        if (!test.isEmptySequence()) {\n          this._emitExpression(test, Skew.Precedence.LOWEST);\n        }\n\n        this._emit('; ');\n\n        if (!update.isEmptySequence()) {\n          this._emitExpression(update, Skew.Precedence.LOWEST);\n        }\n\n        this._emit(')');\n        this._emitBlock(node.forBlock());\n        this._emit('\\n');\n        break;\n      }\n\n      case Skew.NodeKind.TRY: {\n        var tryBlock = node.tryBlock();\n        var finallyBlock = node.finallyBlock();\n        this._emit(this._indent + 'try');\n        this._emitBlock(tryBlock);\n        this._emit('\\n');\n\n        for (var child3 = tryBlock.nextSibling(); child3 != finallyBlock; child3 = child3.nextSibling()) {\n          if (child3.comments != null) {\n            this._emit('\\n');\n            this._emitComments(child3.comments);\n          }\n\n          this._emit(this._indent + 'catch');\n\n          if (child3.symbol != null) {\n            this._emit(' (');\n            this._emitType(child3.symbol.resolvedType, Skew.CPlusPlusEmitter.CppEmitMode.DECLARATION);\n            this._emit(Skew.CPlusPlusEmitter._mangleName(child3.symbol) + ')');\n          }\n\n          else {\n            this._emit(' (...)');\n          }\n\n          this._emitBlock(child3.catchBlock());\n          this._emit('\\n');\n        }\n\n        if (finallyBlock != null) {\n          if (finallyBlock.comments != null) {\n            this._emit('\\n');\n            this._emitComments(finallyBlock.comments);\n          }\n\n          this._emit(this._indent + 'finally');\n          this._emitBlock(finallyBlock);\n          this._emit('\\n');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.WHILE: {\n        this._emit(this._indent + 'while (');\n        this._emitExpression(node.whileTest(), Skew.Precedence.LOWEST);\n        this._emit(')');\n        this._emitBlock(node.whileBlock());\n        this._emit('\\n');\n        break;\n      }\n\n      case Skew.NodeKind.FOREACH: {\n        var symbol1 = node.symbol.asVariableSymbol();\n        var value2 = node.foreachValue();\n        this._emit(this._indent + 'for (');\n        this._emitType(symbol1.resolvedType, Skew.CPlusPlusEmitter.CppEmitMode.DECLARATION);\n        this._emit(Skew.CPlusPlusEmitter._mangleName(symbol1) + ' : ');\n\n        if (this._isReferenceType(value2.resolvedType)) {\n          this._emit('*');\n          this._emitExpression(value2, Skew.Precedence.UNARY_PREFIX);\n        }\n\n        else {\n          this._emitExpression(value2, Skew.Precedence.LOWEST);\n        }\n\n        this._emit(')');\n        this._emitBlock(node.foreachBlock());\n        this._emit('\\n');\n        break;\n      }\n\n      default: {\n        assert(false);\n        break;\n      }\n    }\n\n    if (Skew.in_NodeKind.isLoop(node.kind)) {\n      var label1 = in_IntMap.get(this._loopLabels, node.id, null);\n\n      if (label1 != null) {\n        this._emit(this._indent + Skew.CPlusPlusEmitter._mangleName(label1) + (node.nextSibling() != null ? ':\\n' : ':;\\n'));\n      }\n    }\n  };\n\n  Skew.CPlusPlusEmitter.prototype._emitIf = function(node) {\n    this._emit('if (');\n    this._emitExpression(node.ifTest(), Skew.Precedence.LOWEST);\n    this._emit(')');\n    this._emitBlock(node.ifTrue());\n    var block = node.ifFalse();\n\n    if (block != null) {\n      var singleIf = block.hasOneChild() && block.firstChild().kind == Skew.NodeKind.IF ? block.firstChild() : null;\n      this._emit('\\n\\n');\n      this._emitComments(block.comments);\n\n      if (singleIf != null) {\n        this._emitComments(singleIf.comments);\n      }\n\n      this._emit(this._indent + 'else');\n\n      if (singleIf != null) {\n        this._emit(' ');\n        this._emitIf(singleIf);\n      }\n\n      else {\n        this._emitBlock(block);\n      }\n    }\n  };\n\n  Skew.CPlusPlusEmitter.prototype._emitContent = function(content) {\n    switch (content.kind()) {\n      case Skew.ContentKind.BOOL: {\n        this._emit(Skew.in_Content.asBool(content).toString());\n        break;\n      }\n\n      case Skew.ContentKind.INT: {\n        this._emit(Skew.in_Content.asInt(content).toString());\n        break;\n      }\n\n      case Skew.ContentKind.DOUBLE: {\n        var value = Skew.in_Content.asDouble(content);\n\n        if (!isFinite(value)) {\n          in_StringMap.set(this._includeNames, '<math.h>', 0);\n        }\n\n        this._emit(isNaN(value) ? 'NAN' : value == 1 / 0 ? 'INFINITY' : value == -(1 / 0) ? '-INFINITY' : Skew.doubleToStringWithDot(value));\n        break;\n      }\n\n      case Skew.ContentKind.STRING: {\n        var text = Skew.in_Content.asString(content);\n        var quoted = Skew.quoteString(text, Skew.QuoteStyle.DOUBLE, Skew.QuoteOctal.OCTAL_WORKAROUND);\n\n        // TODO: This needs to work with UTF8\n        this._emit(text.indexOf('\\0') != -1 ? 'Skew::string(' + quoted + ', ' + text.length.toString() + ')' : quoted + '_s');\n        break;\n      }\n    }\n  };\n\n  Skew.CPlusPlusEmitter.prototype._emitCommaSeparatedExpressions = function(from, to) {\n    while (from != to) {\n      this._emitExpression(from, Skew.Precedence.COMMA);\n      from = from.nextSibling();\n\n      if (from != to) {\n        this._emit(', ');\n      }\n    }\n  };\n\n  Skew.CPlusPlusEmitter.prototype._emitExpression = function(node, precedence) {\n    var kind = node.kind;\n    var symbol = node.symbol;\n\n    if (symbol != null) {\n      this._handleSymbol(symbol);\n    }\n\n    switch (kind) {\n      case Skew.NodeKind.TYPE:\n      case Skew.NodeKind.LAMBDA_TYPE: {\n        this._emitType(node.resolvedType, Skew.CPlusPlusEmitter.CppEmitMode.BARE);\n        break;\n      }\n\n      case Skew.NodeKind.NULL: {\n        this._emit('nullptr');\n        break;\n      }\n\n      case Skew.NodeKind.NAME: {\n        this._emit(symbol != null ? Skew.CPlusPlusEmitter._fullName(symbol) : node.asString());\n\n        // Need to unwrap GC roots using \".get()\" when global variables are referenced\n        if (symbol != null && symbol.kind == Skew.SymbolKind.VARIABLE_GLOBAL && this._isReferenceType(symbol.resolvedType) && (node.parent() == null || node.parent().kind != Skew.NodeKind.DOT && (node.parent().kind != Skew.NodeKind.ASSIGN || node != node.parent().binaryLeft()))) {\n          this._emit('.get()');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.DOT: {\n        var target = node.dotTarget();\n        var type = target.resolvedType;\n        this._emitExpression(target, Skew.Precedence.MEMBER);\n        this._emit((type != null && this._isReferenceType(type) ? '->' : '.') + (symbol != null ? Skew.CPlusPlusEmitter._mangleName(symbol) : node.asString()));\n        break;\n      }\n\n      case Skew.NodeKind.CONSTANT: {\n        if (node.resolvedType.isEnumOrFlags()) {\n          this._emit('(');\n          this._emitType(node.resolvedType, Skew.CPlusPlusEmitter.CppEmitMode.NORMAL);\n          this._emit(')');\n        }\n\n        this._emitContent(node.content);\n        break;\n      }\n\n      case Skew.NodeKind.CALL: {\n        var value = node.callValue();\n        var wrap = false;\n\n        if (value.kind == Skew.NodeKind.SUPER) {\n          this._emit(Skew.CPlusPlusEmitter._fullName(symbol));\n        }\n\n        else if (symbol != null && symbol.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n          wrap = precedence == Skew.Precedence.MEMBER;\n\n          if (wrap) {\n            this._emit('(');\n          }\n\n          this._emit('new ');\n          this._emitType(node.resolvedType, Skew.CPlusPlusEmitter.CppEmitMode.BARE);\n        }\n\n        else if (value.kind == Skew.NodeKind.DOT && value.asString() == 'new') {\n          wrap = precedence == Skew.Precedence.MEMBER;\n\n          if (wrap) {\n            this._emit('(');\n          }\n\n          this._emit('new ');\n          this._emitExpression(value.dotTarget(), Skew.Precedence.MEMBER);\n        }\n\n        else {\n          this._emitExpression(value, Skew.Precedence.UNARY_POSTFIX);\n        }\n\n        this._emit('(');\n        this._emitCommaSeparatedExpressions(node.firstChild().nextSibling(), null);\n        this._emit(')');\n\n        if (wrap) {\n          this._emit(')');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.CAST: {\n        var resolvedType = node.resolvedType;\n        var type1 = node.castType();\n        var value1 = node.castValue();\n\n        if (value1.kind == Skew.NodeKind.NULL && node.resolvedType == this._cache.stringType) {\n          this._emitType(this._cache.stringType, Skew.CPlusPlusEmitter.CppEmitMode.BARE);\n          this._emit('()');\n        }\n\n        else if (type1.kind == Skew.NodeKind.TYPE && type1.resolvedType == Skew.Type.DYNAMIC) {\n          this._emitExpression(value1, precedence);\n        }\n\n        // Automatically promote integer literals to doubles instead of using a cast\n        else if (this._cache.isEquivalentToDouble(resolvedType) && value1.isInt()) {\n          this._emitExpression(this._cache.createDouble(value1.asInt()), precedence);\n        }\n\n        // Only emit a cast if the underlying types are different\n        else if (this._unwrappedType(value1.resolvedType) != this._unwrappedType(type1.resolvedType) || type1.resolvedType == Skew.Type.DYNAMIC) {\n          if (Skew.Precedence.UNARY_POSTFIX < precedence) {\n            this._emit('(');\n          }\n\n          this._emit('(');\n          this._emitExpressionOrType(type1, resolvedType, Skew.CPlusPlusEmitter.CppEmitMode.NORMAL);\n          this._emit(')');\n          this._emitExpression(value1, Skew.Precedence.UNARY_POSTFIX);\n\n          if (Skew.Precedence.UNARY_POSTFIX < precedence) {\n            this._emit(')');\n          }\n        }\n\n        // Otherwise, pretend the cast isn't there\n        else {\n          this._emitExpression(value1, precedence);\n        }\n        break;\n      }\n\n      case Skew.NodeKind.TYPE_CHECK: {\n        var value2 = node.typeCheckValue();\n        var type2 = node.typeCheckType();\n\n        if (Skew.Precedence.EQUAL < precedence) {\n          this._emit('(');\n        }\n\n        this._emit('dynamic_cast<');\n        this._emitExpressionOrType(type2, type2.resolvedType, Skew.CPlusPlusEmitter.CppEmitMode.NORMAL);\n        this._emit('>(');\n        this._emitExpression(value2, Skew.Precedence.LOWEST);\n        this._emit(') != nullptr');\n\n        if (Skew.Precedence.EQUAL < precedence) {\n          this._emit(')');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.INDEX: {\n        var left = node.indexLeft();\n\n        if (this._isReferenceType(left.resolvedType)) {\n          this._emit('(*');\n          this._emitExpression(left, Skew.Precedence.UNARY_PREFIX);\n          this._emit(')');\n        }\n\n        else {\n          this._emitExpression(left, Skew.Precedence.UNARY_POSTFIX);\n        }\n\n        this._emit('[');\n        this._emitExpression(node.indexRight(), Skew.Precedence.LOWEST);\n        this._emit(']');\n        break;\n      }\n\n      case Skew.NodeKind.ASSIGN_INDEX: {\n        var left1 = node.assignIndexLeft();\n\n        if (Skew.Precedence.ASSIGN < precedence) {\n          this._emit('(');\n        }\n\n        if (this._isReferenceType(left1.resolvedType)) {\n          this._emit('(*');\n          this._emitExpression(left1, Skew.Precedence.UNARY_PREFIX);\n          this._emit(')');\n        }\n\n        else {\n          this._emitExpression(left1, Skew.Precedence.UNARY_POSTFIX);\n        }\n\n        this._emit('[');\n        this._emitExpression(node.assignIndexCenter(), Skew.Precedence.LOWEST);\n        this._emit('] = ');\n        this._emitExpression(node.assignIndexRight(), Skew.Precedence.ASSIGN);\n\n        if (Skew.Precedence.ASSIGN < precedence) {\n          this._emit(')');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.PARAMETERIZE: {\n        var value3 = node.parameterizeValue();\n\n        if (value3.isType()) {\n          this._emitType(node.resolvedType, Skew.CPlusPlusEmitter.CppEmitMode.NORMAL);\n        }\n\n        else {\n          this._emitExpression(value3, precedence);\n          this._emit('<');\n\n          for (var child = value3.nextSibling(); child != null; child = child.nextSibling()) {\n            if (child.previousSibling() != value3) {\n              this._emit(', ');\n            }\n\n            this._emitExpressionOrType(child, child.resolvedType, Skew.CPlusPlusEmitter.CppEmitMode.NORMAL);\n          }\n\n          this._emit('>');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.SEQUENCE: {\n        if (Skew.Precedence.COMMA <= precedence) {\n          this._emit('(');\n        }\n\n        this._emitCommaSeparatedExpressions(node.firstChild(), null);\n\n        if (Skew.Precedence.COMMA <= precedence) {\n          this._emit(')');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.HOOK: {\n        if (Skew.Precedence.ASSIGN < precedence) {\n          this._emit('(');\n        }\n\n        this._emitExpression(node.hookTest(), Skew.Precedence.LOGICAL_OR);\n        this._emit(' ? ');\n        this._emitExpression(node.hookTrue(), Skew.Precedence.ASSIGN);\n        this._emit(' : ');\n        this._emitExpression(node.hookFalse(), Skew.Precedence.ASSIGN);\n\n        if (Skew.Precedence.ASSIGN < precedence) {\n          this._emit(')');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.INITIALIZER_LIST:\n      case Skew.NodeKind.INITIALIZER_MAP: {\n        var wrap1 = precedence == Skew.Precedence.MEMBER;\n\n        if (wrap1) {\n          this._emit('(');\n        }\n\n        this._emit('new ');\n        this._emitType(node.resolvedType, Skew.CPlusPlusEmitter.CppEmitMode.BARE);\n\n        if (node.hasChildren()) {\n          this._emit('({');\n          this._emitCommaSeparatedExpressions(node.firstChild(), null);\n          this._emit('})');\n        }\n\n        else {\n          this._emit('()');\n        }\n\n        if (wrap1) {\n          this._emit(')');\n        }\n        break;\n      }\n\n      case Skew.NodeKind.PAIR: {\n        in_StringMap.set(this._includeNames, '<utility>', 0);\n        this._emit('std::make_pair(');\n        this._emitCommaSeparatedExpressions(node.firstChild(), null);\n        this._emit(')');\n        break;\n      }\n\n      case Skew.NodeKind.COMPLEMENT:\n      case Skew.NodeKind.NEGATIVE:\n      case Skew.NodeKind.NOT:\n      case Skew.NodeKind.POSITIVE:\n      case Skew.NodeKind.POSTFIX_DECREMENT:\n      case Skew.NodeKind.POSTFIX_INCREMENT:\n      case Skew.NodeKind.PREFIX_DECREMENT:\n      case Skew.NodeKind.PREFIX_INCREMENT: {\n        var value4 = node.unaryValue();\n        var info = in_IntMap.get1(Skew.operatorInfo, kind);\n        var sign = node.sign();\n\n        if (info.precedence < precedence) {\n          this._emit('(');\n        }\n\n        if (!Skew.in_NodeKind.isUnaryPostfix(kind)) {\n          this._emit(info.text);\n\n          // Prevent \"x - -1\" from becoming \"x--1\"\n          if (sign != Skew.NodeKind.NULL && sign == value4.sign()) {\n            this._emit(' ');\n          }\n        }\n\n        this._emitExpression(value4, info.precedence);\n\n        if (Skew.in_NodeKind.isUnaryPostfix(kind)) {\n          this._emit(info.text);\n        }\n\n        if (info.precedence < precedence) {\n          this._emit(')');\n        }\n        break;\n      }\n\n      default: {\n        if (Skew.in_NodeKind.isBinary(kind)) {\n          var parent = node.parent();\n\n          if (parent != null &&\n            // Clang warns about \"&&\" inside \"||\" or \"&\" inside \"|\" without parentheses\n            (parent.kind == Skew.NodeKind.LOGICAL_OR && kind == Skew.NodeKind.LOGICAL_AND || parent.kind == Skew.NodeKind.BITWISE_OR && kind == Skew.NodeKind.BITWISE_AND ||\n              // Clang and GCC also warn about add/subtract inside bitwise operations and shifts without parentheses\n              (parent.kind == Skew.NodeKind.BITWISE_AND || parent.kind == Skew.NodeKind.BITWISE_OR || parent.kind == Skew.NodeKind.BITWISE_XOR || Skew.in_NodeKind.isShift(parent.kind)) && (kind == Skew.NodeKind.ADD || kind == Skew.NodeKind.SUBTRACT))) {\n            precedence = Skew.Precedence.MEMBER;\n          }\n\n          var info1 = in_IntMap.get1(Skew.operatorInfo, kind);\n\n          if (info1.precedence < precedence) {\n            this._emit('(');\n          }\n\n          this._emitExpression(node.binaryLeft(), info1.precedence + (info1.associativity == Skew.Associativity.RIGHT | 0) | 0);\n          this._emit(' ' + info1.text + ' ');\n          this._emitExpression(node.binaryRight(), info1.precedence + (info1.associativity == Skew.Associativity.LEFT | 0) | 0);\n\n          if (info1.precedence < precedence) {\n            this._emit(')');\n          }\n        }\n\n        else {\n          assert(false);\n        }\n        break;\n      }\n    }\n  };\n\n  Skew.CPlusPlusEmitter.prototype._emitExpressionOrType = function(node, type, mode) {\n    if (node != null && (type == null || type == Skew.Type.DYNAMIC)) {\n      this._emitExpression(node, Skew.Precedence.LOWEST);\n\n      if (mode == Skew.CPlusPlusEmitter.CppEmitMode.DECLARATION) {\n        this._emit(' ');\n      }\n    }\n\n    else {\n      this._emitType(type, mode);\n    }\n  };\n\n  Skew.CPlusPlusEmitter.prototype._emitType = function(type, mode) {\n    if (type == null) {\n      this._emit('void');\n    }\n\n    else {\n      type = this._unwrappedType(type);\n\n      if (type == Skew.Type.DYNAMIC) {\n        this._emit('void');\n      }\n\n      else if (type.kind == Skew.TypeKind.LAMBDA) {\n        var hasReturnType = type.returnType != null;\n        var argumentCount = type.argumentTypes.length;\n        this._emit((hasReturnType ? 'Skew::Fn' : 'Skew::FnVoid') + argumentCount.toString());\n\n        if (hasReturnType || argumentCount != 0) {\n          this._emit('<');\n\n          if (hasReturnType) {\n            this._emitType(type.returnType, Skew.CPlusPlusEmitter.CppEmitMode.NORMAL);\n          }\n\n          for (var i = 0, count = argumentCount; i < count; i = i + 1 | 0) {\n            if (i != 0 || hasReturnType) {\n              this._emit(', ');\n            }\n\n            this._emitType(in_List.get(type.argumentTypes, i), Skew.CPlusPlusEmitter.CppEmitMode.NORMAL);\n          }\n\n          this._emit('>');\n        }\n      }\n\n      else {\n        assert(type.kind == Skew.TypeKind.SYMBOL);\n        this._handleSymbol(type.symbol);\n        this._emit(Skew.CPlusPlusEmitter._fullName(type.symbol));\n\n        if (type.isParameterized()) {\n          this._emit('<');\n\n          for (var i1 = 0, count1 = type.substitutions.length; i1 < count1; i1 = i1 + 1 | 0) {\n            if (i1 != 0) {\n              this._emit(', ');\n            }\n\n            this._emitType(in_List.get(type.substitutions, i1), Skew.CPlusPlusEmitter.CppEmitMode.NORMAL);\n          }\n\n          this._emit('>');\n        }\n      }\n    }\n\n    if (type != null && this._isReferenceType(type) && mode != Skew.CPlusPlusEmitter.CppEmitMode.BARE) {\n      this._emit(' *');\n    }\n\n    else if (mode == Skew.CPlusPlusEmitter.CppEmitMode.DECLARATION) {\n      this._emit(' ');\n    }\n  };\n\n  Skew.CPlusPlusEmitter.prototype._unwrappedType = function(type) {\n    return type.isFlags() ? this._cache.intType : this._cache.unwrappedType(type);\n  };\n\n  Skew.CPlusPlusEmitter.prototype._isReferenceType = function(type) {\n    return type.isReference() && type != this._cache.stringType;\n  };\n\n  Skew.CPlusPlusEmitter.prototype._finalizeEmittedFile = function() {\n    var includes = Array.from(this._includeNames.keys());\n\n    if (!(includes.length == 0)) {\n      // Sort so the order is deterministic\n      includes.sort(Skew.SORT_STRINGS);\n\n      for (var i = 0, list = includes, count = list.length; i < count; i = i + 1 | 0) {\n        var include = in_List.get(list, i);\n        this._emitPrefix('#include ' + (include.startsWith('<') && include.endsWith('>') ? include : '\"' + include + '\"') + '\\n');\n      }\n\n      this._emitPrefix('\\n');\n    }\n\n    this._adjustNamespace(null);\n    this._previousSymbol = null;\n    this._symbolsCheckedForInclude = new Map();\n    this._includeNames = new Map();\n  };\n\n  Skew.CPlusPlusEmitter.prototype._handleSymbol = function(symbol) {\n    if (!Skew.in_SymbolKind.isLocal(symbol.kind) && !this._symbolsCheckedForInclude.has(symbol.id)) {\n      in_IntMap.set(this._symbolsCheckedForInclude, symbol.id, 0);\n\n      if (symbol.annotations != null) {\n        for (var i = 0, list = symbol.annotations, count = list.length; i < count; i = i + 1 | 0) {\n          var annotation = in_List.get(list, i);\n\n          if (annotation.symbol != null && annotation.symbol.fullName() == 'include') {\n            var value = annotation.annotationValue();\n\n            if (value.childCount() == 2) {\n              in_StringMap.set(this._includeNames, value.lastChild().asString(), 0);\n            }\n          }\n        }\n      }\n\n      if (symbol.parent != null) {\n        this._handleSymbol(symbol.parent);\n      }\n    }\n  };\n\n  Skew.CPlusPlusEmitter._isCompactNodeKind = function(kind) {\n    return kind == Skew.NodeKind.EXPRESSION || kind == Skew.NodeKind.VARIABLES || Skew.in_NodeKind.isJump(kind);\n  };\n\n  Skew.CPlusPlusEmitter._fullName = function(symbol) {\n    var parent = symbol.parent;\n\n    if (parent != null && parent.kind != Skew.SymbolKind.OBJECT_GLOBAL && !Skew.in_SymbolKind.isParameter(symbol.kind)) {\n      return Skew.CPlusPlusEmitter._fullName(parent) + '::' + Skew.CPlusPlusEmitter._mangleName(symbol);\n    }\n\n    return Skew.CPlusPlusEmitter._mangleName(symbol);\n  };\n\n  Skew.CPlusPlusEmitter._mangleName = function(symbol) {\n    symbol = symbol.forwarded();\n\n    if (symbol.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n      return Skew.CPlusPlusEmitter._mangleName(symbol.parent);\n    }\n\n    if (!symbol.isImportedOrExported() && Skew.CPlusPlusEmitter._isNative.has(symbol.name) || Skew.CPlusPlusEmitter._isKeyword.has(symbol.name)) {\n      return '_' + symbol.name;\n    }\n\n    return symbol.name;\n  };\n\n  Skew.CPlusPlusEmitter.CodeMode = {\n    DECLARE: 0,\n    DEFINE: 1,\n    IMPLEMENT: 2\n  };\n\n  Skew.CPlusPlusEmitter.CppEmitMode = {\n    BARE: 0,\n    NORMAL: 1,\n    DECLARATION: 2\n  };\n\n  Skew.SourceMapping = function(sourceIndex, originalLine, originalColumn, generatedLine, generatedColumn) {\n    this.sourceIndex = sourceIndex;\n    this.originalLine = originalLine;\n    this.originalColumn = originalColumn;\n    this.generatedLine = generatedLine;\n    this.generatedColumn = generatedColumn;\n  };\n\n  // Based on https://github.com/mozilla/source-map\n  Skew.SourceMapGenerator = function() {\n    this._mappings = [];\n    this._sources = [];\n  };\n\n  Skew.SourceMapGenerator.prototype.addMapping = function(source, originalLine, originalColumn, generatedLine, generatedColumn) {\n    var sourceIndex = this._sources.indexOf(source);\n\n    if (sourceIndex == -1) {\n      sourceIndex = this._sources.length;\n      this._sources.push(source);\n    }\n\n    this._mappings.push(new Skew.SourceMapping(sourceIndex, originalLine, originalColumn, generatedLine, generatedColumn));\n  };\n\n  Skew.SourceMapGenerator.prototype.toString = function() {\n    var sourceNames = [];\n    var sourceContents = [];\n\n    for (var i = 0, list = this._sources, count = list.length; i < count; i = i + 1 | 0) {\n      var source = in_List.get(list, i);\n      sourceNames.push(Skew.quoteString(source.name, Skew.QuoteStyle.DOUBLE, Skew.QuoteOctal.OCTAL_WORKAROUND));\n      sourceContents.push(Skew.quoteString(source.contents, Skew.QuoteStyle.DOUBLE, Skew.QuoteOctal.OCTAL_WORKAROUND));\n    }\n\n    var builder = new StringBuilder();\n    builder.buffer += '{\"version\":3,\"sources\":[';\n    builder.buffer += sourceNames.join(',');\n    builder.buffer += '],\"sourcesContent\":[';\n    builder.buffer += sourceContents.join(',');\n    builder.buffer += '],\"names\":[],\"mappings\":\"';\n\n    // Sort the mappings in increasing order by generated location\n    this._mappings.sort(function(a, b) {\n      var delta = in_int.compare(a.generatedLine, b.generatedLine);\n      return delta != 0 ? delta : in_int.compare(a.generatedColumn, b.generatedColumn);\n    });\n    var previousGeneratedColumn = 0;\n    var previousGeneratedLine = 0;\n    var previousOriginalColumn = 0;\n    var previousOriginalLine = 0;\n    var previousSourceIndex = 0;\n\n    // Generate the base64 VLQ encoded mappings\n    for (var i1 = 0, list1 = this._mappings, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n      var mapping = in_List.get(list1, i1);\n      var generatedLine = mapping.generatedLine;\n\n      // Insert ',' for the same line and ';' for a line\n      if (previousGeneratedLine == generatedLine) {\n        if (previousGeneratedColumn == mapping.generatedColumn && (previousGeneratedLine != 0 || previousGeneratedColumn != 0)) {\n          continue;\n        }\n\n        builder.buffer += ',';\n      }\n\n      else {\n        previousGeneratedColumn = 0;\n\n        while (previousGeneratedLine < generatedLine) {\n          builder.buffer += ';';\n          previousGeneratedLine = previousGeneratedLine + 1 | 0;\n        }\n      }\n\n      // Record the generated column (the line is recorded using ';' above)\n      builder.buffer += Skew.encodeVLQ(mapping.generatedColumn - previousGeneratedColumn | 0);\n      previousGeneratedColumn = mapping.generatedColumn;\n\n      // Record the generated source\n      builder.buffer += Skew.encodeVLQ(mapping.sourceIndex - previousSourceIndex | 0);\n      previousSourceIndex = mapping.sourceIndex;\n\n      // Record the original line\n      builder.buffer += Skew.encodeVLQ(mapping.originalLine - previousOriginalLine | 0);\n      previousOriginalLine = mapping.originalLine;\n\n      // Record the original column\n      builder.buffer += Skew.encodeVLQ(mapping.originalColumn - previousOriginalColumn | 0);\n      previousOriginalColumn = mapping.originalColumn;\n    }\n\n    builder.buffer += '\"}\\n';\n    return builder.buffer;\n  };\n\n  Skew.UnionFind = function() {\n    this.parents = [];\n  };\n\n  Skew.UnionFind.prototype.allocate1 = function() {\n    var index = this.parents.length;\n    this.parents.push(index);\n    return index;\n  };\n\n  Skew.UnionFind.prototype.allocate2 = function(count) {\n    for (var i = 0, count1 = count; i < count1; i = i + 1 | 0) {\n      this.parents.push(this.parents.length);\n    }\n\n    return this;\n  };\n\n  Skew.UnionFind.prototype.union = function(left, right) {\n    in_List.set(this.parents, this.find(left), this.find(right));\n  };\n\n  Skew.UnionFind.prototype.find = function(index) {\n    assert(index >= 0 && index < this.parents.length);\n    var parent = in_List.get(this.parents, index);\n\n    if (parent != index) {\n      parent = this.find(parent);\n      in_List.set(this.parents, index, parent);\n    }\n\n    return parent;\n  };\n\n  Skew.SplitPath = function(directory, entry) {\n    this.directory = directory;\n    this.entry = entry;\n  };\n\n  Skew.PrettyPrint = {};\n\n  Skew.PrettyPrint.plural1 = function(value, word) {\n    return value.toString() + ' ' + word + (value == 1 ? '' : 's');\n  };\n\n  Skew.PrettyPrint.joinQuoted = function(parts, trailing) {\n    return Skew.PrettyPrint.join(parts.map(function(part) {\n      return '\"' + part + '\"';\n    }), trailing);\n  };\n\n  Skew.PrettyPrint.join = function(parts, trailing) {\n    if (parts.length < 3) {\n      return parts.join(' ' + trailing + ' ');\n    }\n\n    var text = '';\n\n    for (var i = 0, count = parts.length; i < count; i = i + 1 | 0) {\n      if (i != 0) {\n        text += ', ';\n\n        if ((i + 1 | 0) == parts.length) {\n          text += trailing + ' ';\n        }\n      }\n\n      text += in_List.get(parts, i);\n    }\n\n    return text;\n  };\n\n  Skew.PrettyPrint.wrapWords = function(text, width) {\n    // An invalid length means wrapping is disabled\n    if (width < 1) {\n      return [text];\n    }\n\n    var words = text.split(' ');\n    var lines = [];\n    var line = '';\n\n    // Run the word wrapping algorithm\n    var i = 0;\n\n    while (i < words.length) {\n      var word = in_List.get(words, i);\n      var lineLength = line.length;\n      var wordLength = word.length;\n      var estimatedLength = (lineLength + 1 | 0) + wordLength | 0;\n      i = i + 1 | 0;\n\n      // Collapse adjacent spaces\n      if (word == '') {\n        continue;\n      }\n\n      // Start the line\n      if (line == '') {\n        while (word.length > width) {\n          lines.push(in_string.slice2(word, 0, width));\n          word = in_string.slice2(word, width, word.length);\n        }\n\n        line = word;\n      }\n\n      // Continue line\n      else if (estimatedLength < width) {\n        line += ' ' + word;\n      }\n\n      // Continue and wrap\n      else if (estimatedLength == width) {\n        lines.push(line + ' ' + word);\n        line = '';\n      }\n\n      // Wrap and try again\n      else {\n        lines.push(line);\n        line = '';\n        i = i - 1 | 0;\n      }\n    }\n\n    // Don't add an empty trailing line unless there are no other lines\n    if (line != '' || lines.length == 0) {\n      lines.push(line);\n    }\n\n    return lines;\n  };\n\n  Skew.SymbolKind = {\n    PARAMETER_FUNCTION: 0,\n    PARAMETER_OBJECT: 1,\n    OBJECT_CLASS: 2,\n    OBJECT_ENUM: 3,\n    OBJECT_FLAGS: 4,\n    OBJECT_GLOBAL: 5,\n    OBJECT_INTERFACE: 6,\n    OBJECT_NAMESPACE: 7,\n    OBJECT_WRAPPED: 8,\n    FUNCTION_ANNOTATION: 9,\n    FUNCTION_CONSTRUCTOR: 10,\n    FUNCTION_GLOBAL: 11,\n    FUNCTION_INSTANCE: 12,\n    FUNCTION_LOCAL: 13,\n    OVERLOADED_ANNOTATION: 14,\n    OVERLOADED_GLOBAL: 15,\n    OVERLOADED_INSTANCE: 16,\n    VARIABLE_ARGUMENT: 17,\n    VARIABLE_ENUM_OR_FLAGS: 18,\n    VARIABLE_GLOBAL: 19,\n    VARIABLE_INSTANCE: 20,\n    VARIABLE_LOCAL: 21\n  };\n\n  Skew.SymbolState = {\n    UNINITIALIZED: 0,\n    INITIALIZING: 1,\n    INITIALIZED: 2\n  };\n\n  Skew.SymbolFlags = {\n    // Internal\n    IS_AUTOMATICALLY_GENERATED: 1,\n    IS_CONST: 2,\n    IS_GETTER: 4,\n    IS_LOOP_VARIABLE: 8,\n    IS_OVER: 16,\n    IS_SETTER: 32,\n    IS_VALUE_TYPE: 64,\n    SHOULD_INFER_RETURN_TYPE: 128,\n\n    // Modifiers\n    IS_DEPRECATED: 256,\n    IS_ENTRY_POINT: 512,\n    IS_EXPORTED: 1024,\n    IS_IMPORTED: 2048,\n    IS_INLINING_FORCED: 4096,\n    IS_INLINING_PREVENTED: 8192,\n    IS_PREFERRED: 16384,\n    IS_PROTECTED: 32768,\n    IS_RENAMED: 65536,\n    IS_SKIPPED: 131072,\n    SHOULD_SPREAD: 262144,\n\n    // Pass-specific\n    IS_CSHARP_CONST: 524288,\n    IS_DYNAMIC_LAMBDA: 1048576,\n    IS_GUARD_CONDITIONAL: 2097152,\n    IS_OBSOLETE: 4194304,\n    IS_PRIMARY_CONSTRUCTOR: 8388608,\n    IS_VIRTUAL: 16777216,\n    USE_PROTOTYPE_CACHE: 33554432\n  };\n\n  Skew.Symbol = function(kind, name) {\n    this.id = Skew.Symbol._nextID = Skew.Symbol._nextID + 1 | 0;\n    this.kind = kind;\n    this.name = name;\n    this.rename = null;\n    this.range = null;\n    this.parent = null;\n    this.resolvedType = null;\n    this.scope = null;\n    this.state = Skew.SymbolState.UNINITIALIZED;\n    this.annotations = null;\n    this.comments = null;\n    this.forwardTo = null;\n    this.flags = 0;\n    this.nextMergedSymbol = null;\n  };\n\n  Skew.Symbol.prototype._cloneFrom = function(symbol) {\n    this.rename = symbol.rename;\n    this.range = symbol.range;\n    this.scope = symbol.scope;\n    this.state = symbol.state;\n    this.flags = symbol.flags;\n  };\n\n  // Flags\n  Skew.Symbol.prototype.isAutomaticallyGenerated = function() {\n    return (Skew.SymbolFlags.IS_AUTOMATICALLY_GENERATED & this.flags) != 0;\n  };\n\n  Skew.Symbol.prototype.isConst = function() {\n    return (Skew.SymbolFlags.IS_CONST & this.flags) != 0;\n  };\n\n  Skew.Symbol.prototype.isGetter = function() {\n    return (Skew.SymbolFlags.IS_GETTER & this.flags) != 0;\n  };\n\n  Skew.Symbol.prototype.isLoopVariable = function() {\n    return (Skew.SymbolFlags.IS_LOOP_VARIABLE & this.flags) != 0;\n  };\n\n  Skew.Symbol.prototype.isOver = function() {\n    return (Skew.SymbolFlags.IS_OVER & this.flags) != 0;\n  };\n\n  Skew.Symbol.prototype.isSetter = function() {\n    return (Skew.SymbolFlags.IS_SETTER & this.flags) != 0;\n  };\n\n  Skew.Symbol.prototype.isValueType = function() {\n    return (Skew.SymbolFlags.IS_VALUE_TYPE & this.flags) != 0;\n  };\n\n  Skew.Symbol.prototype.shouldInferReturnType = function() {\n    return (Skew.SymbolFlags.SHOULD_INFER_RETURN_TYPE & this.flags) != 0;\n  };\n\n  // Modifiers\n  Skew.Symbol.prototype.isDeprecated = function() {\n    return (Skew.SymbolFlags.IS_DEPRECATED & this.flags) != 0;\n  };\n\n  Skew.Symbol.prototype.isEntryPoint = function() {\n    return (Skew.SymbolFlags.IS_ENTRY_POINT & this.flags) != 0;\n  };\n\n  Skew.Symbol.prototype.isExported = function() {\n    return (Skew.SymbolFlags.IS_EXPORTED & this.flags) != 0;\n  };\n\n  Skew.Symbol.prototype.isImported = function() {\n    return (Skew.SymbolFlags.IS_IMPORTED & this.flags) != 0;\n  };\n\n  Skew.Symbol.prototype.isInliningForced = function() {\n    return (Skew.SymbolFlags.IS_INLINING_FORCED & this.flags) != 0;\n  };\n\n  Skew.Symbol.prototype.isInliningPrevented = function() {\n    return (Skew.SymbolFlags.IS_INLINING_PREVENTED & this.flags) != 0;\n  };\n\n  Skew.Symbol.prototype.isPreferred = function() {\n    return (Skew.SymbolFlags.IS_PREFERRED & this.flags) != 0;\n  };\n\n  Skew.Symbol.prototype.isProtected = function() {\n    return (Skew.SymbolFlags.IS_PROTECTED & this.flags) != 0;\n  };\n\n  Skew.Symbol.prototype.isRenamed = function() {\n    return (Skew.SymbolFlags.IS_RENAMED & this.flags) != 0;\n  };\n\n  Skew.Symbol.prototype.isSkipped = function() {\n    return (Skew.SymbolFlags.IS_SKIPPED & this.flags) != 0;\n  };\n\n  Skew.Symbol.prototype.shouldSpread = function() {\n    return (Skew.SymbolFlags.SHOULD_SPREAD & this.flags) != 0;\n  };\n\n  // Pass-specific flags\n  Skew.Symbol.prototype.isCSharpConst = function() {\n    return (Skew.SymbolFlags.IS_CSHARP_CONST & this.flags) != 0;\n  };\n\n  Skew.Symbol.prototype.isDynamicLambda = function() {\n    return (Skew.SymbolFlags.IS_DYNAMIC_LAMBDA & this.flags) != 0;\n  };\n\n  Skew.Symbol.prototype.isGuardConditional = function() {\n    return (Skew.SymbolFlags.IS_GUARD_CONDITIONAL & this.flags) != 0;\n  };\n\n  Skew.Symbol.prototype.isObsolete = function() {\n    return (Skew.SymbolFlags.IS_OBSOLETE & this.flags) != 0;\n  };\n\n  Skew.Symbol.prototype.isPrimaryConstructor = function() {\n    return (Skew.SymbolFlags.IS_PRIMARY_CONSTRUCTOR & this.flags) != 0;\n  };\n\n  Skew.Symbol.prototype.isVirtual = function() {\n    return (Skew.SymbolFlags.IS_VIRTUAL & this.flags) != 0;\n  };\n\n  Skew.Symbol.prototype.usePrototypeCache = function() {\n    return (Skew.SymbolFlags.USE_PROTOTYPE_CACHE & this.flags) != 0;\n  };\n\n  // Combinations\n  Skew.Symbol.prototype.isImportedOrExported = function() {\n    return ((Skew.SymbolFlags.IS_IMPORTED | Skew.SymbolFlags.IS_EXPORTED) & this.flags) != 0;\n  };\n\n  Skew.Symbol.prototype.asParameterSymbol = function() {\n    assert(Skew.in_SymbolKind.isParameter(this.kind));\n    return this;\n  };\n\n  Skew.Symbol.prototype.asObjectSymbol = function() {\n    assert(Skew.in_SymbolKind.isObject(this.kind));\n    return this;\n  };\n\n  Skew.Symbol.prototype.asFunctionSymbol = function() {\n    assert(Skew.in_SymbolKind.isFunction(this.kind));\n    return this;\n  };\n\n  Skew.Symbol.prototype.asOverloadedFunctionSymbol = function() {\n    assert(Skew.in_SymbolKind.isOverloadedFunction(this.kind));\n    return this;\n  };\n\n  Skew.Symbol.prototype.asVariableSymbol = function() {\n    assert(Skew.in_SymbolKind.isVariable(this.kind));\n    return this;\n  };\n\n  Skew.Symbol.prototype.fullName = function() {\n    if (this.parent != null && this.parent.kind != Skew.SymbolKind.OBJECT_GLOBAL && !Skew.in_SymbolKind.isParameter(this.kind)) {\n      return this.parent.fullName() + '.' + this.name;\n    }\n\n    return this.name;\n  };\n\n  Skew.Symbol.prototype.forwarded = function() {\n    var symbol = this;\n\n    while (symbol.forwardTo != null) {\n      symbol = symbol.forwardTo;\n    }\n\n    return symbol;\n  };\n\n  Skew.Symbol.prototype.spreadingAnnotations = function() {\n    var result = null;\n\n    if (this.annotations != null) {\n      for (var i = 0, list = this.annotations, count = list.length; i < count; i = i + 1 | 0) {\n        var annotation = in_List.get(list, i);\n\n        if (annotation.symbol != null && annotation.symbol.shouldSpread()) {\n          if (result == null) {\n            result = [];\n          }\n\n          result.push(annotation);\n        }\n      }\n    }\n\n    return result;\n  };\n\n  Skew.Symbol.prototype.mergeInformationFrom = function(symbol) {\n    // Link merged symbols together\n    var link = this;\n\n    while (link.nextMergedSymbol != null) {\n      link = link.nextMergedSymbol;\n    }\n\n    link.nextMergedSymbol = symbol;\n\n    // Combine annotations\n    if (this.annotations == null) {\n      this.annotations = symbol.annotations;\n    }\n\n    else if (symbol.annotations != null) {\n      in_List.append1(this.annotations, symbol.annotations);\n    }\n\n    // Combine comments\n    if (this.comments == null) {\n      this.comments = symbol.comments;\n    }\n\n    else if (symbol.comments != null) {\n      in_List.append1(this.comments, symbol.comments);\n    }\n\n    if (this.rename == null) {\n      this.rename = symbol.rename;\n    }\n  };\n\n  Skew.Symbol._substituteSymbols = function(node, symbols) {\n    if (node.symbol != null) {\n      node.symbol = in_IntMap.get(symbols, node.symbol.id, node.symbol);\n    }\n\n    for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n      Skew.Symbol._substituteSymbols(child, symbols);\n    }\n  };\n\n  Skew.Symbol.SORT_BY_ID = function(a, b) {\n    return in_int.compare(a.id, b.id);\n  };\n\n  Skew.Symbol.SORT_OBJECTS_BY_ID = function(a, b) {\n    return in_int.compare(a.id, b.id);\n  };\n\n  Skew.Symbol.SORT_VARIABLES_BY_ID = function(a, b) {\n    return in_int.compare(a.id, b.id);\n  };\n\n  Skew.ParameterSymbol = function(kind, name) {\n    Skew.Symbol.call(this, kind, name);\n  };\n\n  __extends(Skew.ParameterSymbol, Skew.Symbol);\n\n  Skew.ParameterSymbol.prototype.clone = function() {\n    var clone = new Skew.ParameterSymbol(this.kind, this.name);\n    clone._cloneFrom(this);\n    clone.resolvedType = new Skew.Type(Skew.TypeKind.SYMBOL, clone);\n    return clone;\n  };\n\n  Skew.Guard = function(parent, test, contents, elseGuard) {\n    this.parent = parent;\n    this.test = test;\n    this.contents = contents;\n    this.elseGuard = elseGuard;\n  };\n\n  Skew.ObjectSymbol = function(kind, name) {\n    Skew.Symbol.call(this, kind, name);\n    this.$extends = null;\n    this.$implements = null;\n    this.baseType = null;\n    this.baseClass = null;\n    this.interfaceTypes = null;\n    this.wrappedType = null;\n    this.members = new Map();\n    this.objects = [];\n    this.functions = [];\n    this.variables = [];\n    this.parameters = null;\n    this.guards = null;\n    this.hasCheckedInterfacesAndAbstractStatus = false;\n    this.isAbstractBecauseOf = null;\n    this.commentsInsideEndOfBlock = null;\n  };\n\n  __extends(Skew.ObjectSymbol, Skew.Symbol);\n\n  Skew.ObjectSymbol.prototype.isAbstract = function() {\n    return this.isAbstractBecauseOf != null;\n  };\n\n  Skew.ObjectSymbol.prototype.hasBaseClass = function(symbol) {\n    return this.baseClass != null && (this.baseClass == symbol || this.baseClass.hasBaseClass(symbol));\n  };\n\n  Skew.ObjectSymbol.prototype.hasInterface = function(symbol) {\n    return this.interfaceTypes != null && this.interfaceTypes.some(function(type) {\n      return type.symbol == symbol;\n    });\n  };\n\n  Skew.ObjectSymbol.prototype.isSameOrHasBaseClass = function(symbol) {\n    return this == symbol || this.hasBaseClass(symbol);\n  };\n\n  Skew.FunctionSymbol = function(kind, name) {\n    Skew.Symbol.call(this, kind, name);\n    this.overridden = null;\n    this.overloaded = null;\n    this.implementations = null;\n    this.parameters = null;\n    this.$arguments = [];\n    this.$this = null;\n    this.argumentOnlyType = null;\n    this.returnType = null;\n    this.block = null;\n    this.namingGroup = -1;\n    this.inlinedCount = 0;\n  };\n\n  __extends(Skew.FunctionSymbol, Skew.Symbol);\n\n  Skew.FunctionSymbol.prototype.clone = function() {\n    var clone = new Skew.FunctionSymbol(this.kind, this.name);\n    var symbols = new Map();\n    clone._cloneFrom(this);\n\n    if (this.state == Skew.SymbolState.INITIALIZED) {\n      clone.resolvedType = new Skew.Type(Skew.TypeKind.SYMBOL, clone);\n      clone.resolvedType.returnType = this.resolvedType.returnType;\n      clone.resolvedType.argumentTypes = this.resolvedType.argumentTypes.slice();\n      clone.argumentOnlyType = this.argumentOnlyType;\n    }\n\n    if (this.parameters != null) {\n      clone.parameters = [];\n\n      for (var i = 0, list = this.parameters, count = list.length; i < count; i = i + 1 | 0) {\n        var parameter = in_List.get(list, i);\n        var cloned = parameter.clone();\n        in_IntMap.set(symbols, parameter.id, cloned);\n        clone.parameters.push(cloned);\n      }\n    }\n\n    for (var i1 = 0, list1 = this.$arguments, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n      var argument = in_List.get(list1, i1);\n      var cloned1 = argument.clone();\n      in_IntMap.set(symbols, argument.id, cloned1);\n      clone.$arguments.push(cloned1);\n    }\n\n    if (this.returnType != null) {\n      clone.returnType = this.returnType.clone();\n    }\n\n    if (this.block != null) {\n      clone.block = this.block.clone();\n      Skew.Symbol._substituteSymbols(clone.block, symbols);\n    }\n\n    return clone;\n  };\n\n  Skew.VariableSymbol = function(kind, name) {\n    Skew.Symbol.call(this, kind, name);\n    this.type = null;\n    this.value = null;\n  };\n\n  __extends(Skew.VariableSymbol, Skew.Symbol);\n\n  Skew.VariableSymbol.prototype.clone = function() {\n    var clone = new Skew.VariableSymbol(this.kind, this.name);\n    clone._cloneFrom(this);\n    clone.resolvedType = this.resolvedType;\n\n    if (this.type != null) {\n      clone.type = this.type.clone();\n    }\n\n    if (this.value != null) {\n      clone.value = this.value.clone();\n      Skew.Symbol._substituteSymbols(clone.value, in_IntMap.insert(new Map(), this.id, clone));\n    }\n\n    return clone;\n  };\n\n  Skew.VariableSymbol.prototype.initializeWithType = function(target) {\n    assert(this.state == Skew.SymbolState.UNINITIALIZED);\n    assert(this.type == null);\n    assert(this.resolvedType == null);\n    this.state = Skew.SymbolState.INITIALIZED;\n    this.resolvedType = target;\n    this.type = new Skew.Node(Skew.NodeKind.TYPE).withType(target);\n  };\n\n  Skew.OverloadedFunctionSymbol = function(kind, name, symbols) {\n    Skew.Symbol.call(this, kind, name);\n    this.symbols = symbols;\n  };\n\n  __extends(Skew.OverloadedFunctionSymbol, Skew.Symbol);\n\n  Skew.FuzzySymbolKind = {\n    EVERYTHING: 0,\n    TYPE_ONLY: 1,\n    GLOBAL_ONLY: 2,\n    INSTANCE_ONLY: 3\n  };\n\n  Skew.FuzzySymbolMatcher = function(name, kind) {\n    this._name = null;\n    this._kind = 0;\n    this._bestScore = 0;\n    this._bestMatch = null;\n    this._name = name;\n    this._kind = kind;\n    this._bestScore = name.length * 0.5;\n    this._bestMatch = null;\n  };\n\n  Skew.FuzzySymbolMatcher.prototype._isBetterScore = function(score, match) {\n    if (score < this._bestScore) {\n      return true;\n    }\n\n    // Do tie-breaking using a consistent ordering so that language targets\n    // with unordered maps (C++ for example) can iterate over symbols in an\n    // unspecified order for speed and still deterministically arrive at the\n    // same result.\n    if (score == this._bestScore && (this._bestMatch == null || match.id < this._bestMatch.id)) {\n      return true;\n    }\n\n    return false;\n  };\n\n  Skew.FuzzySymbolMatcher.prototype.include = function(match) {\n    if (this._kind == Skew.FuzzySymbolKind.INSTANCE_ONLY && !Skew.in_SymbolKind.isOnInstances(match.kind) || this._kind == Skew.FuzzySymbolKind.GLOBAL_ONLY && Skew.in_SymbolKind.isOnInstances(match.kind) || this._kind == Skew.FuzzySymbolKind.TYPE_ONLY && !Skew.in_SymbolKind.isType(match.kind) || match.state == Skew.SymbolState.INITIALIZING) {\n      return;\n    }\n\n    var score = Skew.caseAwareLevenshteinEditDistance(this._name, match.name);\n\n    if (score <= match.name.length * 0.5 && this._isBetterScore(score, match)) {\n      this._bestScore = score;\n      this._bestMatch = match;\n    }\n  };\n\n  Skew.FuzzySymbolMatcher.prototype.bestSoFar = function() {\n    return this._bestMatch;\n  };\n\n  Skew.ContentKind = {\n    BOOL: 0,\n    INT: 1,\n    DOUBLE: 2,\n    STRING: 3\n  };\n\n  Skew.BoolContent = function(value) {\n    this.value = value;\n  };\n\n  Skew.BoolContent.prototype.kind = function() {\n    return Skew.ContentKind.BOOL;\n  };\n\n  Skew.IntContent = function(value) {\n    this.value = value;\n  };\n\n  Skew.IntContent.prototype.kind = function() {\n    return Skew.ContentKind.INT;\n  };\n\n  Skew.DoubleContent = function(value) {\n    this.value = value;\n  };\n\n  Skew.DoubleContent.prototype.kind = function() {\n    return Skew.ContentKind.DOUBLE;\n  };\n\n  Skew.StringContent = function(value) {\n    this.value = value;\n  };\n\n  Skew.StringContent.prototype.kind = function() {\n    return Skew.ContentKind.STRING;\n  };\n\n  Skew.OperatorInfo = function(text, precedence, associativity, kind, validArgumentCounts, assignKind) {\n    this.text = text;\n    this.precedence = precedence;\n    this.associativity = associativity;\n    this.kind = kind;\n    this.validArgumentCounts = validArgumentCounts;\n    this.assignKind = assignKind;\n  };\n\n  Skew.OperatorKind = {\n    FIXED: 0,\n    OVERRIDABLE: 1\n  };\n\n  Skew.NodeKind = {\n    // Other\n    ANNOTATION: 0,\n    BLOCK: 1,\n    CASE: 2,\n    CATCH: 3,\n    VARIABLE: 4,\n\n    // Statements\n    BREAK: 5,\n    COMMENT_BLOCK: 6,\n    CONTINUE: 7,\n    EXPRESSION: 8,\n    FOR: 9,\n    FOREACH: 10,\n    IF: 11,\n    RETURN: 12,\n    SWITCH: 13,\n    THROW: 14,\n    TRY: 15,\n    VARIABLES: 16,\n    WHILE: 17,\n\n    // Expressions\n    ASSIGN_INDEX: 18,\n    CALL: 19,\n    CAST: 20,\n    CONSTANT: 21,\n    DOT: 22,\n    HOOK: 23,\n    INDEX: 24,\n    INITIALIZER_LIST: 25,\n    INITIALIZER_MAP: 26,\n    LAMBDA: 27,\n    LAMBDA_TYPE: 28,\n    NAME: 29,\n    NULL: 30,\n    NULL_DOT: 31,\n    PAIR: 32,\n    PARAMETERIZE: 33,\n    PARSE_ERROR: 34,\n    SEQUENCE: 35,\n    STRING_INTERPOLATION: 36,\n    SUPER: 37,\n    TYPE: 38,\n    TYPE_CHECK: 39,\n    XML: 40,\n\n    // Unary operators\n    COMPLEMENT: 41,\n    NEGATIVE: 42,\n    NOT: 43,\n    POSITIVE: 44,\n    POSTFIX_DECREMENT: 45,\n    POSTFIX_INCREMENT: 46,\n    PREFIX_DECREMENT: 47,\n    PREFIX_INCREMENT: 48,\n\n    // Binary operators\n    ADD: 49,\n    BITWISE_AND: 50,\n    BITWISE_OR: 51,\n    BITWISE_XOR: 52,\n    COMPARE: 53,\n    DIVIDE: 54,\n    EQUAL: 55,\n    IN: 56,\n    LOGICAL_AND: 57,\n    LOGICAL_OR: 58,\n    MODULUS: 59,\n    MULTIPLY: 60,\n    NOT_EQUAL: 61,\n    NULL_JOIN: 62,\n    POWER: 63,\n    REMAINDER: 64,\n    SHIFT_LEFT: 65,\n    SHIFT_RIGHT: 66,\n    SUBTRACT: 67,\n    UNSIGNED_SHIFT_RIGHT: 68,\n\n    // Binary comparison operators\n    GREATER_THAN: 69,\n    GREATER_THAN_OR_EQUAL: 70,\n    LESS_THAN: 71,\n    LESS_THAN_OR_EQUAL: 72,\n\n    // Binary assigment operators\n    ASSIGN: 73,\n    ASSIGN_ADD: 74,\n    ASSIGN_BITWISE_AND: 75,\n    ASSIGN_BITWISE_OR: 76,\n    ASSIGN_BITWISE_XOR: 77,\n    ASSIGN_DIVIDE: 78,\n    ASSIGN_MODULUS: 79,\n    ASSIGN_MULTIPLY: 80,\n    ASSIGN_NULL: 81,\n    ASSIGN_POWER: 82,\n    ASSIGN_REMAINDER: 83,\n    ASSIGN_SHIFT_LEFT: 84,\n    ASSIGN_SHIFT_RIGHT: 85,\n    ASSIGN_SUBTRACT: 86,\n    ASSIGN_UNSIGNED_SHIFT_RIGHT: 87\n  };\n\n  Skew.NodeFlags = {\n    // This flag is only for blocks. A simple control flow analysis is run\n    // during code resolution and blocks where control flow reaches the end of\n    // the block have this flag set.\n    HAS_CONTROL_FLOW_AT_END: 1,\n\n    // Use this flag to tell the IDE support code to ignore this node. This is\n    // useful for compiler-generated nodes that are used for lowering and that\n    // need marked ranges for error reporting but that should not show up in\n    // tooltips.\n    IS_IGNORED_BY_IDE: 2,\n\n    // An implicit return is a return statement inside an expression lambda. For\n    // example, the lambda \"x => x\" is compiled into \"x => { return x }\" where\n    // the return statement has this flag set.\n    IS_IMPLICIT_RETURN: 4,\n\n    // This flag marks list nodes that help implement initializer expressions.\n    IS_INITIALIZER_EXPANSION: 8,\n\n    // This flag marks nodes that were wrapped in parentheses in the original\n    // source code. It's used for warnings about C-style syntax in conditional\n    // statements and to call a lambda returned from a getter.\n    IS_INSIDE_PARENTHESES: 16,\n\n    // This flag is set on nodes that are expected to be types.\n    SHOULD_EXPECT_TYPE: 32,\n\n    // This flag marks nodes that were converted from ASSIGN_NULL to ASSIGN nodes.\n    WAS_ASSIGN_NULL: 64,\n\n    // This flag marks nodes that were converted from NULL_JOIN to HOOK nodes.\n    WAS_NULL_JOIN: 128\n  };\n\n  // Nodes represent executable code (variable initializers and function bodies)\n  // Node-specific queries\n  // Factory functions\n  // Getters, most of which should be inlineable when asserts are skipped in release\n  Skew.Node = function(kind) {\n    this.id = Skew.Node._nextID = Skew.Node._nextID + 1 | 0;\n    this.kind = kind;\n    this.flags = 0;\n    this.range = null;\n    this.internalRange = null;\n    this.symbol = null;\n    this.content = null;\n    this.resolvedType = null;\n    this.comments = null;\n    this.innerComments = null;\n    this._parent = null;\n    this._firstChild = null;\n    this._lastChild = null;\n    this._previousSibling = null;\n    this._nextSibling = null;\n  };\n\n  Skew.Node.prototype._cloneWithoutChildren = function() {\n    var ref1;\n    var ref;\n    var clone = new Skew.Node(this.kind);\n    clone.flags = this.flags;\n    clone.range = this.range;\n    clone.internalRange = this.internalRange;\n    clone.symbol = this.symbol;\n    clone.content = this.content;\n    clone.resolvedType = this.resolvedType;\n    clone.comments = (ref = this.comments) != null ? ref.slice() : null;\n    clone.innerComments = (ref1 = this.innerComments) != null ? ref1.slice() : null;\n    return clone;\n  };\n\n  // When used with become(), this provides a convenient way to wrap a node in\n  // an operation without the caller needing to be aware of replaceWith():\n  //\n  //  node.become(Node.createUnary(.NOT, node.cloneAndStealChildren))\n  //\n  Skew.Node.prototype.cloneAndStealChildren = function() {\n    var clone = this._cloneWithoutChildren();\n\n    while (this.hasChildren()) {\n      clone.appendChild(this._firstChild.remove());\n    }\n\n    return clone;\n  };\n\n  Skew.Node.prototype.clone = function() {\n    var clone = this._cloneWithoutChildren();\n\n    if (this.kind == Skew.NodeKind.LAMBDA) {\n      clone.symbol = this.symbol.asFunctionSymbol().clone();\n      clone.appendChild(clone.symbol.asFunctionSymbol().block);\n    }\n\n    else if (this.kind == Skew.NodeKind.VARIABLE) {\n      clone.symbol = this.symbol.asVariableSymbol().clone();\n      clone.appendChild(clone.symbol.asVariableSymbol().value);\n    }\n\n    else {\n      for (var child = this._firstChild; child != null; child = child._nextSibling) {\n        clone.appendChild(child.clone());\n      }\n    }\n\n    return clone;\n  };\n\n  // Change self node in place to become the provided node. The parent node is\n  // not changed, so become() can be called within a nested method and does not\n  // need to report the updated node reference to the caller since the reference\n  // does not change.\n  Skew.Node.prototype.become = function(node) {\n    if (node == this) {\n      return;\n    }\n\n    assert(node._parent == null);\n    this.kind = node.kind;\n    this.flags = node.flags;\n    this.range = node.range;\n    this.internalRange = node.internalRange;\n    this.symbol = node.symbol;\n    this.content = node.content;\n    this.resolvedType = node.resolvedType;\n    this.comments = node.comments;\n    this.removeChildren();\n    this.appendChildrenFrom(node);\n  };\n\n  Skew.Node.prototype.parent = function() {\n    return this._parent;\n  };\n\n  Skew.Node.prototype.firstChild = function() {\n    return this._firstChild;\n  };\n\n  Skew.Node.prototype.lastChild = function() {\n    return this._lastChild;\n  };\n\n  Skew.Node.prototype.previousSibling = function() {\n    return this._previousSibling;\n  };\n\n  Skew.Node.prototype.nextSibling = function() {\n    return this._nextSibling;\n  };\n\n  Skew.Node.prototype.hasControlFlowAtEnd = function() {\n    return (Skew.NodeFlags.HAS_CONTROL_FLOW_AT_END & this.flags) != 0;\n  };\n\n  Skew.Node.prototype.isImplicitReturn = function() {\n    return (Skew.NodeFlags.IS_IMPLICIT_RETURN & this.flags) != 0;\n  };\n\n  Skew.Node.prototype.isInitializerExpansion = function() {\n    return (Skew.NodeFlags.IS_INITIALIZER_EXPANSION & this.flags) != 0;\n  };\n\n  Skew.Node.prototype.isInsideParentheses = function() {\n    return (Skew.NodeFlags.IS_INSIDE_PARENTHESES & this.flags) != 0;\n  };\n\n  Skew.Node.prototype.wasAssignNull = function() {\n    return (Skew.NodeFlags.WAS_ASSIGN_NULL & this.flags) != 0;\n  };\n\n  Skew.Node.prototype.wasNullJoin = function() {\n    return (Skew.NodeFlags.WAS_NULL_JOIN & this.flags) != 0;\n  };\n\n  Skew.Node.prototype.shouldExpectType = function() {\n    for (var node = this; node != null; node = node.parent()) {\n      if ((Skew.NodeFlags.SHOULD_EXPECT_TYPE & node.flags) != 0) {\n        return true;\n      }\n    }\n\n    return false;\n  };\n\n  // This is cheaper than childCount == 0\n  Skew.Node.prototype.hasChildren = function() {\n    return this._firstChild != null;\n  };\n\n  // This is cheaper than childCount == 1\n  Skew.Node.prototype.hasOneChild = function() {\n    return this.hasChildren() && this._firstChild == this._lastChild;\n  };\n\n  // This is cheaper than childCount == 2\n  Skew.Node.prototype.hasTwoChildren = function() {\n    return this.hasChildren() && this._firstChild.nextSibling() == this._lastChild;\n  };\n\n  // This is cheaper than childCount == 3\n  Skew.Node.prototype.hasThreeChildren = function() {\n    return this.hasChildren() && this._firstChild.nextSibling() == this._lastChild.previousSibling();\n  };\n\n  Skew.Node.prototype.childCount = function() {\n    var count = 0;\n\n    for (var child = this._firstChild; child != null; child = child._nextSibling) {\n      count = count + 1 | 0;\n    }\n\n    return count;\n  };\n\n  Skew.Node.prototype.withFlags = function(value) {\n    this.flags = value;\n    return this;\n  };\n\n  Skew.Node.prototype.withType = function(value) {\n    this.resolvedType = value;\n    return this;\n  };\n\n  Skew.Node.prototype.withSymbol = function(value) {\n    this.symbol = value;\n    return this;\n  };\n\n  Skew.Node.prototype.withContent = function(value) {\n    this.content = value;\n    return this;\n  };\n\n  Skew.Node.prototype.withRange = function(value) {\n    this.range = value;\n    return this;\n  };\n\n  Skew.Node.prototype.withInternalRange = function(value) {\n    this.internalRange = value;\n    return this;\n  };\n\n  Skew.Node.prototype.withComments = function(value) {\n    assert(this.comments == null);\n    this.comments = value;\n    return this;\n  };\n\n  Skew.Node.prototype.withInnerComments = function(value) {\n    assert(this.innerComments == null);\n    this.innerComments = value;\n    return this;\n  };\n\n  Skew.Node.prototype.internalRangeOrRange = function() {\n    return this.internalRange != null ? this.internalRange : this.range;\n  };\n\n  Skew.Node.prototype.prependChild = function(node) {\n    if (node == null) {\n      return this;\n    }\n\n    assert(node != this);\n    assert(node._parent == null);\n    assert(node._previousSibling == null);\n    assert(node._nextSibling == null);\n    node._parent = this;\n\n    if (this.hasChildren()) {\n      node._nextSibling = this._firstChild;\n      this._firstChild._previousSibling = node;\n      this._firstChild = node;\n    }\n\n    else {\n      this._lastChild = this._firstChild = node;\n    }\n\n    return this;\n  };\n\n  Skew.Node.prototype.appendChild = function(node) {\n    if (node == null) {\n      return this;\n    }\n\n    assert(node != this);\n    assert(node._parent == null);\n    assert(node._previousSibling == null);\n    assert(node._nextSibling == null);\n    node._parent = this;\n\n    if (this.hasChildren()) {\n      node._previousSibling = this._lastChild;\n      this._lastChild._nextSibling = node;\n      this._lastChild = node;\n    }\n\n    else {\n      this._lastChild = this._firstChild = node;\n    }\n\n    return this;\n  };\n\n  Skew.Node.prototype.appendChildrenFrom = function(node) {\n    assert(node != this);\n\n    while (node.hasChildren()) {\n      this.appendChild(node._firstChild.remove());\n    }\n\n    return this;\n  };\n\n  Skew.Node.prototype.insertChildBefore = function(after, before) {\n    if (before == null) {\n      return this;\n    }\n\n    assert(before != after);\n    assert(before._parent == null);\n    assert(before._previousSibling == null);\n    assert(before._nextSibling == null);\n    assert(after == null || after._parent == this);\n\n    if (after == null) {\n      return this.appendChild(before);\n    }\n\n    before._parent = this;\n    before._previousSibling = after._previousSibling;\n    before._nextSibling = after;\n\n    if (after._previousSibling != null) {\n      assert(after == after._previousSibling._nextSibling);\n      after._previousSibling._nextSibling = before;\n    }\n\n    else {\n      assert(after == this._firstChild);\n      this._firstChild = before;\n    }\n\n    after._previousSibling = before;\n    return this;\n  };\n\n  Skew.Node.prototype.insertChildAfter = function(before, after) {\n    if (after == null) {\n      return this;\n    }\n\n    assert(before != after);\n    assert(after._parent == null);\n    assert(after._previousSibling == null);\n    assert(after._nextSibling == null);\n    assert(before == null || before._parent == this);\n\n    if (before == null) {\n      return this.prependChild(after);\n    }\n\n    after._parent = this;\n    after._previousSibling = before;\n    after._nextSibling = before._nextSibling;\n\n    if (before._nextSibling != null) {\n      assert(before == before._nextSibling._previousSibling);\n      before._nextSibling._previousSibling = after;\n    }\n\n    else {\n      assert(before == this._lastChild);\n      this._lastChild = after;\n    }\n\n    before._nextSibling = after;\n    return this;\n  };\n\n  Skew.Node.prototype.insertChildrenAfterFrom = function(from, after) {\n    while (from.hasChildren()) {\n      this.insertChildAfter(after, from.lastChild().remove());\n    }\n  };\n\n  Skew.Node.prototype.remove = function() {\n    assert(this._parent != null);\n\n    if (this._previousSibling != null) {\n      assert(this._previousSibling._nextSibling == this);\n      this._previousSibling._nextSibling = this._nextSibling;\n    }\n\n    else {\n      assert(this._parent._firstChild == this);\n      this._parent._firstChild = this._nextSibling;\n    }\n\n    if (this._nextSibling != null) {\n      assert(this._nextSibling._previousSibling == this);\n      this._nextSibling._previousSibling = this._previousSibling;\n    }\n\n    else {\n      assert(this._parent._lastChild == this);\n      this._parent._lastChild = this._previousSibling;\n    }\n\n    this._parent = null;\n    this._previousSibling = null;\n    this._nextSibling = null;\n    return this;\n  };\n\n  Skew.Node.prototype.removeChildren = function() {\n    while (this.hasChildren()) {\n      this._firstChild.remove();\n    }\n  };\n\n  Skew.Node.prototype.replaceWith = function(node) {\n    assert(node != this);\n    assert(this._parent != null);\n    assert(node._parent == null);\n    assert(node._previousSibling == null);\n    assert(node._nextSibling == null);\n    node._parent = this._parent;\n    node._previousSibling = this._previousSibling;\n    node._nextSibling = this._nextSibling;\n\n    if (this._previousSibling != null) {\n      assert(this._previousSibling._nextSibling == this);\n      this._previousSibling._nextSibling = node;\n    }\n\n    else {\n      assert(this._parent._firstChild == this);\n      this._parent._firstChild = node;\n    }\n\n    if (this._nextSibling != null) {\n      assert(this._nextSibling._previousSibling == this);\n      this._nextSibling._previousSibling = node;\n    }\n\n    else {\n      assert(this._parent._lastChild == this);\n      this._parent._lastChild = node;\n    }\n\n    if (this._parent.kind == Skew.NodeKind.LAMBDA) {\n      assert(this == this._parent.symbol.asFunctionSymbol().block);\n      this._parent.symbol.asFunctionSymbol().block = node;\n    }\n\n    else if (this._parent.kind == Skew.NodeKind.VARIABLE) {\n      assert(this == this._parent.symbol.asVariableSymbol().value);\n      this._parent.symbol.asVariableSymbol().value = node;\n    }\n\n    this._parent = null;\n    this._previousSibling = null;\n    this._nextSibling = null;\n    return this;\n  };\n\n  Skew.Node.prototype.replaceWithChildrenFrom = function(node) {\n    assert(node != this);\n    var parent = this._parent;\n\n    while (node.hasChildren()) {\n      parent.insertChildBefore(this, node._firstChild.remove());\n    }\n\n    return this.remove();\n  };\n\n  Skew.Node.prototype.swapWith = function(node) {\n    assert(node != this);\n    assert(this._parent != null && this._parent == node._parent);\n    var parent = this._parent;\n    var nextSibling = this._nextSibling;\n\n    if (node == this._previousSibling) {\n      parent.insertChildBefore(node, this.remove());\n    }\n\n    else if (node == nextSibling) {\n      parent.insertChildAfter(node, this.remove());\n    }\n\n    else {\n      parent.insertChildBefore(node, this.remove());\n      parent.insertChildBefore(nextSibling, node.remove());\n    }\n  };\n\n  Skew.Node._symbolsOrStringsLookTheSame = function(left, right) {\n    return left.symbol != null && left.symbol == right.symbol || left.symbol == null && right.symbol == null && left.asString() == right.asString();\n  };\n\n  Skew.Node._childrenLookTheSame = function(left, right) {\n    var leftChild = left.firstChild();\n    var rightChild = right.firstChild();\n\n    while (leftChild != null && rightChild != null) {\n      if (!Skew.Node._looksTheSame(leftChild, rightChild)) {\n        return false;\n      }\n\n      leftChild = leftChild.nextSibling();\n      rightChild = rightChild.nextSibling();\n    }\n\n    return leftChild == null && rightChild == null;\n  };\n\n  Skew.Node._looksTheSame = function(left, right) {\n    if (left.kind == right.kind) {\n      switch (left.kind) {\n        case Skew.NodeKind.NULL: {\n          return true;\n        }\n\n        case Skew.NodeKind.NAME: {\n          return Skew.Node._symbolsOrStringsLookTheSame(left, right);\n        }\n\n        case Skew.NodeKind.DOT: {\n          return Skew.Node._symbolsOrStringsLookTheSame(left, right) && Skew.Node._looksTheSame(left.dotTarget(), right.dotTarget());\n        }\n\n        case Skew.NodeKind.CONSTANT: {\n          switch (left.content.kind()) {\n            case Skew.ContentKind.INT: {\n              return right.isInt() && left.asInt() == right.asInt();\n            }\n\n            case Skew.ContentKind.BOOL: {\n              return right.isBool() && left.asBool() == right.asBool();\n            }\n\n            case Skew.ContentKind.DOUBLE: {\n              return right.isDouble() && left.asDouble() == right.asDouble();\n            }\n\n            case Skew.ContentKind.STRING: {\n              return right.isString() && left.asString() == right.asString();\n            }\n          }\n          break;\n        }\n\n        case Skew.NodeKind.BLOCK:\n        case Skew.NodeKind.BREAK:\n        case Skew.NodeKind.CONTINUE:\n        case Skew.NodeKind.EXPRESSION:\n        case Skew.NodeKind.IF:\n        case Skew.NodeKind.RETURN:\n        case Skew.NodeKind.THROW:\n        case Skew.NodeKind.WHILE:\n        case Skew.NodeKind.ASSIGN_INDEX:\n        case Skew.NodeKind.CALL:\n        case Skew.NodeKind.HOOK:\n        case Skew.NodeKind.INDEX:\n        case Skew.NodeKind.INITIALIZER_LIST:\n        case Skew.NodeKind.INITIALIZER_MAP:\n        case Skew.NodeKind.PAIR:\n        case Skew.NodeKind.SEQUENCE:\n        case Skew.NodeKind.COMPLEMENT:\n        case Skew.NodeKind.NEGATIVE:\n        case Skew.NodeKind.NOT:\n        case Skew.NodeKind.POSITIVE:\n        case Skew.NodeKind.POSTFIX_DECREMENT:\n        case Skew.NodeKind.POSTFIX_INCREMENT:\n        case Skew.NodeKind.PREFIX_DECREMENT:\n        case Skew.NodeKind.PREFIX_INCREMENT: {\n          return Skew.Node._childrenLookTheSame(left, right);\n        }\n\n        default: {\n          if (Skew.in_NodeKind.isBinary(left.kind)) {\n            return Skew.Node._childrenLookTheSame(left, right);\n          }\n          break;\n        }\n      }\n    }\n\n    // Null literals are always implicitly casted, so unwrap implicit casts\n    if (left.kind == Skew.NodeKind.CAST) {\n      return Skew.Node._looksTheSame(left.castValue(), right);\n    }\n\n    if (right.kind == Skew.NodeKind.CAST) {\n      return Skew.Node._looksTheSame(left, right.castValue());\n    }\n\n    return false;\n  };\n\n  Skew.Node.prototype.isSuperCallStatement = function() {\n    return this.kind == Skew.NodeKind.EXPRESSION && (this.expressionValue().kind == Skew.NodeKind.SUPER || this.expressionValue().kind == Skew.NodeKind.CALL && this.expressionValue().callValue().kind == Skew.NodeKind.SUPER);\n  };\n\n  Skew.Node.prototype.isEmptySequence = function() {\n    return this.kind == Skew.NodeKind.SEQUENCE && !this.hasChildren();\n  };\n\n  Skew.Node.prototype.isTrue = function() {\n    return this.kind == Skew.NodeKind.CONSTANT && this.content.kind() == Skew.ContentKind.BOOL && Skew.in_Content.asBool(this.content);\n  };\n\n  Skew.Node.prototype.isFalse = function() {\n    return this.kind == Skew.NodeKind.CONSTANT && this.content.kind() == Skew.ContentKind.BOOL && !Skew.in_Content.asBool(this.content);\n  };\n\n  Skew.Node.prototype.isType = function() {\n    return this.kind == Skew.NodeKind.TYPE || this.kind == Skew.NodeKind.LAMBDA_TYPE || (this.kind == Skew.NodeKind.NAME || this.kind == Skew.NodeKind.DOT || this.kind == Skew.NodeKind.PARAMETERIZE) && this.symbol != null && Skew.in_SymbolKind.isType(this.symbol.kind);\n  };\n\n  Skew.Node.prototype.isAssignTarget = function() {\n    return this._parent != null && (Skew.in_NodeKind.isUnaryAssign(this._parent.kind) || Skew.in_NodeKind.isBinaryAssign(this._parent.kind) && this == this._parent.binaryLeft());\n  };\n\n  Skew.Node.prototype.isZero = function() {\n    return this.isInt() && this.asInt() == 0 || this.isDouble() && this.asDouble() == 0;\n  };\n\n  Skew.Node.prototype.isNumberLessThanZero = function() {\n    return this.isInt() && this.asInt() < 0 || this.isDouble() && this.asDouble() < 0;\n  };\n\n  Skew.Node.prototype.hasNoSideEffects = function() {\n    assert(Skew.in_NodeKind.isExpression(this.kind));\n\n    switch (this.kind) {\n      case Skew.NodeKind.CONSTANT:\n      case Skew.NodeKind.NAME:\n      case Skew.NodeKind.NULL:\n      case Skew.NodeKind.TYPE: {\n        return true;\n      }\n\n      case Skew.NodeKind.CAST: {\n        return this.castValue().hasNoSideEffects();\n      }\n\n      case Skew.NodeKind.HOOK: {\n        return this.hookTest().hasNoSideEffects() && this.hookTrue().hasNoSideEffects() && this.hookFalse().hasNoSideEffects();\n      }\n\n      case Skew.NodeKind.DOT: {\n        return this.dotTarget().hasNoSideEffects();\n      }\n\n      case Skew.NodeKind.COMPLEMENT:\n      case Skew.NodeKind.NEGATIVE:\n      case Skew.NodeKind.NOT:\n      case Skew.NodeKind.POSITIVE:\n      case Skew.NodeKind.POSTFIX_DECREMENT:\n      case Skew.NodeKind.POSTFIX_INCREMENT:\n      case Skew.NodeKind.PREFIX_DECREMENT:\n      case Skew.NodeKind.PREFIX_INCREMENT: {\n        return !Skew.in_NodeKind.isUnaryAssign(this.kind) && this.unaryValue().hasNoSideEffects();\n      }\n\n      default: {\n        if (Skew.in_NodeKind.isBinary(this.kind)) {\n          return !Skew.in_NodeKind.isBinaryAssign(this.kind) && this.binaryLeft().hasNoSideEffects() && this.binaryRight().hasNoSideEffects();\n        }\n        break;\n      }\n    }\n\n    return false;\n  };\n\n  Skew.Node.prototype.looksTheSameAs = function(node) {\n    return Skew.Node._looksTheSame(this, node);\n  };\n\n  Skew.Node.prototype.invertBooleanCondition = function(cache) {\n    assert(Skew.in_NodeKind.isExpression(this.kind));\n\n    switch (this.kind) {\n      case Skew.NodeKind.CONSTANT: {\n        if (this.content.kind() == Skew.ContentKind.BOOL) {\n          this.content = new Skew.BoolContent(!Skew.in_Content.asBool(this.content));\n        }\n\n        return;\n      }\n\n      case Skew.NodeKind.NOT: {\n        this.become(this.unaryValue().remove());\n        return;\n      }\n\n      case Skew.NodeKind.EQUAL: {\n        this.kind = Skew.NodeKind.NOT_EQUAL;\n        return;\n      }\n\n      case Skew.NodeKind.NOT_EQUAL: {\n        this.kind = Skew.NodeKind.EQUAL;\n        return;\n      }\n\n      case Skew.NodeKind.LOGICAL_OR: {\n        this.kind = Skew.NodeKind.LOGICAL_AND;\n        this.binaryLeft().invertBooleanCondition(cache);\n        this.binaryRight().invertBooleanCondition(cache);\n        return;\n      }\n\n      case Skew.NodeKind.LOGICAL_AND: {\n        this.kind = Skew.NodeKind.LOGICAL_OR;\n        this.binaryLeft().invertBooleanCondition(cache);\n        this.binaryRight().invertBooleanCondition(cache);\n        return;\n      }\n\n      // Non-equality comparison operators involving floating-point numbers\n      // can't be inverted because one or both of those values may be NAN.\n      // Equality comparisons still work fine because inverting the test\n      // inverts the result as expected:\n      //\n      //   Test        |  Result\n      // --------------+----------\n      //   0 == NAN    |  false\n      //   0 != NAN    |  true\n      //   0 < NAN     |  false\n      //   0 > NAN     |  false\n      //   0 <= NAN    |  false\n      //   0 >= NAN    |  false\n      //   NAN == NAN  |  false\n      //   NAN != NAN  |  true\n      //   NAN < NAN   |  false\n      //   NAN > NAN   |  false\n      //   NAN <= NAN  |  false\n      //   NAN >= NAN  |  false\n      //\n      case Skew.NodeKind.LESS_THAN:\n      case Skew.NodeKind.GREATER_THAN:\n      case Skew.NodeKind.LESS_THAN_OR_EQUAL:\n      case Skew.NodeKind.GREATER_THAN_OR_EQUAL: {\n        var commonType = cache.commonImplicitType(this.binaryLeft().resolvedType, this.binaryRight().resolvedType);\n\n        if (commonType != null && commonType != cache.doubleType) {\n          switch (this.kind) {\n            case Skew.NodeKind.LESS_THAN: {\n              this.kind = Skew.NodeKind.GREATER_THAN_OR_EQUAL;\n              break;\n            }\n\n            case Skew.NodeKind.GREATER_THAN: {\n              this.kind = Skew.NodeKind.LESS_THAN_OR_EQUAL;\n              break;\n            }\n\n            case Skew.NodeKind.LESS_THAN_OR_EQUAL: {\n              this.kind = Skew.NodeKind.GREATER_THAN;\n              break;\n            }\n\n            case Skew.NodeKind.GREATER_THAN_OR_EQUAL: {\n              this.kind = Skew.NodeKind.LESS_THAN;\n              break;\n            }\n          }\n\n          return;\n        }\n        break;\n      }\n\n      case Skew.NodeKind.SEQUENCE: {\n        this._lastChild.invertBooleanCondition(cache);\n        return;\n      }\n    }\n\n    this.become(Skew.Node.createUnary(Skew.NodeKind.NOT, this.cloneAndStealChildren()).withType(cache.boolType));\n  };\n\n  // \"a + (b + c)\" => \"(a + b) + c\"\n  Skew.Node.prototype.rotateBinaryRightToLeft = function() {\n    assert(this.kind == this.binaryRight().kind);\n    var left = this.binaryLeft();\n    var right = this.binaryRight();\n    var rightLeft = right.binaryLeft();\n    var rightRight = right.binaryRight();\n\n    // \"a + (b + c)\" => \"(b + c) + a\"\n    left.swapWith(right);\n\n    // \"a + (b + c)\" => \"(c + b) + a\"\n    rightLeft.swapWith(rightRight);\n\n    // \"a + (b + c)\" => \"(a + c + b)\"\n    right.prependChild(left.remove());\n\n    // \"a + (b + c)\" => \"(a + b) + c\"\n    this.appendChild(rightRight.remove());\n  };\n\n  // If a variable is inside a variable cluster, break up the variable cluster\n  // into separate clusters so that variable is in a cluster all by itself. That\n  // way the variable can easily be replaced by something else (an assigment,\n  // for example. This does not handle variables inside loop headers.\n  //\n  // \"var a, b, c, d, e\" => c.extractVariableFromVariables => \"var a, b; var c; var d, e\"\n  //\n  Skew.Node.prototype.extractVariableFromVariables = function() {\n    assert(this.kind == Skew.NodeKind.VARIABLE);\n    assert(this.parent() != null && this.parent().kind == Skew.NodeKind.VARIABLES);\n    assert(this.parent().parent() != null && this.parent().parent().kind == Skew.NodeKind.BLOCK);\n\n    // Split off variables before this one\n    if (this.previousSibling() != null) {\n      var variables = new Skew.Node(Skew.NodeKind.VARIABLES);\n\n      while (this.previousSibling() != null) {\n        variables.prependChild(this.previousSibling().remove());\n      }\n\n      this.parent().parent().insertChildBefore(this.parent(), variables);\n    }\n\n    // Split off variables after this one\n    if (this.nextSibling() != null) {\n      var variables1 = new Skew.Node(Skew.NodeKind.VARIABLES);\n\n      while (this.nextSibling() != null) {\n        variables1.appendChild(this.nextSibling().remove());\n      }\n\n      this.parent().parent().insertChildAfter(this.parent(), variables1);\n    }\n  };\n\n  Skew.Node.prototype.sign = function() {\n    if (this.kind == Skew.NodeKind.NEGATIVE || this.kind == Skew.NodeKind.PREFIX_DECREMENT || this.isNumberLessThanZero()) {\n      return Skew.NodeKind.NEGATIVE;\n    }\n\n    if (this.kind == Skew.NodeKind.POSITIVE || this.kind == Skew.NodeKind.PREFIX_INCREMENT) {\n      return Skew.NodeKind.POSITIVE;\n    }\n\n    return Skew.NodeKind.NULL;\n  };\n\n  Skew.Node.createAnnotation = function(value, test) {\n    assert(Skew.in_NodeKind.isExpression(value.kind));\n    assert(test == null || Skew.in_NodeKind.isExpression(test.kind));\n    return new Skew.Node(Skew.NodeKind.ANNOTATION).appendChild(value).appendChild(test);\n  };\n\n  Skew.Node.createCatch = function(symbol, block) {\n    assert(block.kind == Skew.NodeKind.BLOCK);\n    return new Skew.Node(Skew.NodeKind.CATCH).appendChild(block).withSymbol(symbol);\n  };\n\n  // This adds the initializer expression to the tree for ease of traversal\n  Skew.Node.createVariable = function(symbol) {\n    return new Skew.Node(Skew.NodeKind.VARIABLE).appendChild(symbol.value).withSymbol(symbol);\n  };\n\n  Skew.Node.createExpression = function(value) {\n    assert(Skew.in_NodeKind.isExpression(value.kind));\n    return new Skew.Node(Skew.NodeKind.EXPRESSION).appendChild(value);\n  };\n\n  Skew.Node.createFor = function(setup, test, update, block) {\n    assert(Skew.in_NodeKind.isExpression(setup.kind) || setup.kind == Skew.NodeKind.VARIABLES);\n    assert(Skew.in_NodeKind.isExpression(test.kind));\n    assert(Skew.in_NodeKind.isExpression(update.kind));\n    assert(block.kind == Skew.NodeKind.BLOCK);\n    return new Skew.Node(Skew.NodeKind.FOR).appendChild(setup).appendChild(test).appendChild(update).appendChild(block);\n  };\n\n  Skew.Node.createForeach = function(symbol, value, block) {\n    assert(Skew.in_NodeKind.isExpression(value.kind));\n    assert(block.kind == Skew.NodeKind.BLOCK);\n    return new Skew.Node(Skew.NodeKind.FOREACH).withSymbol(symbol).appendChild(value).appendChild(block);\n  };\n\n  Skew.Node.createIf = function(test, trueBlock, falseBlock) {\n    assert(Skew.in_NodeKind.isExpression(test.kind));\n    assert(trueBlock.kind == Skew.NodeKind.BLOCK);\n    assert(falseBlock == null || falseBlock.kind == Skew.NodeKind.BLOCK);\n    return new Skew.Node(Skew.NodeKind.IF).appendChild(test).appendChild(trueBlock).appendChild(falseBlock);\n  };\n\n  Skew.Node.createReturn = function(value) {\n    assert(value == null || Skew.in_NodeKind.isExpression(value.kind));\n    return new Skew.Node(Skew.NodeKind.RETURN).appendChild(value);\n  };\n\n  Skew.Node.createSwitch = function(value) {\n    assert(Skew.in_NodeKind.isExpression(value.kind));\n    return new Skew.Node(Skew.NodeKind.SWITCH).appendChild(value);\n  };\n\n  Skew.Node.createThrow = function(value) {\n    assert(Skew.in_NodeKind.isExpression(value.kind));\n    return new Skew.Node(Skew.NodeKind.THROW).appendChild(value);\n  };\n\n  Skew.Node.createTry = function(tryBlock) {\n    assert(tryBlock.kind == Skew.NodeKind.BLOCK);\n    return new Skew.Node(Skew.NodeKind.TRY).appendChild(tryBlock);\n  };\n\n  Skew.Node.createIndex = function(left, right) {\n    assert(Skew.in_NodeKind.isExpression(left.kind));\n    assert(Skew.in_NodeKind.isExpression(right.kind));\n    return new Skew.Node(Skew.NodeKind.INDEX).appendChild(left).appendChild(right);\n  };\n\n  Skew.Node.createCall = function(target) {\n    assert(Skew.in_NodeKind.isExpression(target.kind));\n    return new Skew.Node(Skew.NodeKind.CALL).appendChild(target);\n  };\n\n  Skew.Node.createCast = function(value, type) {\n    assert(Skew.in_NodeKind.isExpression(value.kind));\n    assert(Skew.in_NodeKind.isExpression(type.kind));\n    return new Skew.Node(Skew.NodeKind.CAST).appendChild(value).appendChild(type);\n  };\n\n  Skew.Node.createHook = function(test, trueValue, falseValue) {\n    assert(Skew.in_NodeKind.isExpression(test.kind));\n    assert(Skew.in_NodeKind.isExpression(trueValue.kind));\n    assert(Skew.in_NodeKind.isExpression(falseValue.kind));\n    return new Skew.Node(Skew.NodeKind.HOOK).appendChild(test).appendChild(trueValue).appendChild(falseValue);\n  };\n\n  Skew.Node.createInitializer = function(kind) {\n    assert(Skew.in_NodeKind.isInitializer(kind));\n    return new Skew.Node(kind);\n  };\n\n  // This adds the block to the tree for ease of traversal\n  Skew.Node.createLambda = function(symbol) {\n    return new Skew.Node(Skew.NodeKind.LAMBDA).appendChild(symbol.block).withSymbol(symbol);\n  };\n\n  Skew.Node.createPair = function(first, second) {\n    assert(Skew.in_NodeKind.isExpression(first.kind));\n    assert(Skew.in_NodeKind.isExpression(second.kind));\n    return new Skew.Node(Skew.NodeKind.PAIR).appendChild(first).appendChild(second);\n  };\n\n  Skew.Node.createParameterize = function(value) {\n    assert(Skew.in_NodeKind.isExpression(value.kind));\n    return new Skew.Node(Skew.NodeKind.PARAMETERIZE).appendChild(value);\n  };\n\n  Skew.Node.createSequence2 = function(before, after) {\n    assert(Skew.in_NodeKind.isExpression(before.kind));\n    assert(Skew.in_NodeKind.isExpression(after.kind));\n    assert(before.parent() == null);\n    assert(after.parent() == null);\n\n    if (before.kind == Skew.NodeKind.SEQUENCE) {\n      if (after.kind == Skew.NodeKind.SEQUENCE) {\n        return before.withType(after.resolvedType).appendChildrenFrom(after);\n      }\n\n      return before.withType(after.resolvedType).appendChild(after);\n    }\n\n    if (after.kind == Skew.NodeKind.SEQUENCE) {\n      return after.prependChild(before);\n    }\n\n    return new Skew.Node(Skew.NodeKind.SEQUENCE).withType(after.resolvedType).appendChild(before).appendChild(after);\n  };\n\n  Skew.Node.createTypeCheck = function(value, type) {\n    assert(Skew.in_NodeKind.isExpression(value.kind));\n    assert(Skew.in_NodeKind.isExpression(type.kind));\n    return new Skew.Node(Skew.NodeKind.TYPE_CHECK).appendChild(value).appendChild(type);\n  };\n\n  Skew.Node.createXML = function(tag, attributes, children, closingTag) {\n    assert(Skew.in_NodeKind.isExpression(tag.kind));\n    assert(attributes.kind == Skew.NodeKind.SEQUENCE);\n    assert(children.kind == Skew.NodeKind.BLOCK);\n    assert(closingTag == null || Skew.in_NodeKind.isExpression(closingTag.kind));\n    return new Skew.Node(Skew.NodeKind.XML).appendChild(tag).appendChild(attributes).appendChild(children).appendChild(closingTag);\n  };\n\n  Skew.Node.createUnary = function(kind, value) {\n    assert(Skew.in_NodeKind.isUnary(kind));\n    assert(Skew.in_NodeKind.isExpression(value.kind));\n    return new Skew.Node(kind).appendChild(value);\n  };\n\n  Skew.Node.createBinary = function(kind, left, right) {\n    assert(Skew.in_NodeKind.isBinary(kind));\n    assert(Skew.in_NodeKind.isExpression(left.kind));\n    assert(Skew.in_NodeKind.isExpression(right.kind));\n    return new Skew.Node(kind).appendChild(left).appendChild(right);\n  };\n\n  Skew.Node.createSymbolReference = function(symbol) {\n    return new Skew.Node(Skew.NodeKind.NAME).withContent(new Skew.StringContent(symbol.name)).withSymbol(symbol).withType(symbol.resolvedType);\n  };\n\n  Skew.Node.createMemberReference = function(target, member) {\n    return new Skew.Node(Skew.NodeKind.DOT).withContent(new Skew.StringContent(member.name)).appendChild(target).withSymbol(member).withType(member.resolvedType);\n  };\n\n  Skew.Node.createSymbolCall = function(symbol) {\n    return Skew.Node.createCall(Skew.Node.createSymbolReference(symbol)).withSymbol(symbol).withType(symbol.resolvedType.returnType);\n  };\n\n  Skew.Node.prototype.isInt = function() {\n    return this.kind == Skew.NodeKind.CONSTANT && this.content.kind() == Skew.ContentKind.INT;\n  };\n\n  Skew.Node.prototype.isBool = function() {\n    return this.kind == Skew.NodeKind.CONSTANT && this.content.kind() == Skew.ContentKind.BOOL;\n  };\n\n  Skew.Node.prototype.isDouble = function() {\n    return this.kind == Skew.NodeKind.CONSTANT && this.content.kind() == Skew.ContentKind.DOUBLE;\n  };\n\n  Skew.Node.prototype.isString = function() {\n    return this.kind == Skew.NodeKind.CONSTANT && this.content.kind() == Skew.ContentKind.STRING;\n  };\n\n  Skew.Node.prototype.asInt = function() {\n    assert(this.kind == Skew.NodeKind.CONSTANT);\n    return Skew.in_Content.asInt(this.content);\n  };\n\n  Skew.Node.prototype.asBool = function() {\n    assert(this.kind == Skew.NodeKind.CONSTANT);\n    return Skew.in_Content.asBool(this.content);\n  };\n\n  Skew.Node.prototype.asDouble = function() {\n    assert(this.kind == Skew.NodeKind.CONSTANT);\n    return Skew.in_Content.asDouble(this.content);\n  };\n\n  Skew.Node.prototype.asString = function() {\n    assert(this.kind == Skew.NodeKind.NAME || this.kind == Skew.NodeKind.DOT || this.kind == Skew.NodeKind.CONSTANT || this.kind == Skew.NodeKind.NULL_DOT);\n    return Skew.in_Content.asString(this.content);\n  };\n\n  Skew.Node.prototype.blockStatement = function() {\n    assert(this.kind == Skew.NodeKind.BLOCK);\n    return this.hasOneChild() ? this._firstChild : null;\n  };\n\n  Skew.Node.prototype.firstValue = function() {\n    assert(this.kind == Skew.NodeKind.PAIR);\n    assert(this.childCount() == 2);\n    assert(Skew.in_NodeKind.isExpression(this._firstChild.kind));\n    return this._firstChild;\n  };\n\n  Skew.Node.prototype.secondValue = function() {\n    assert(this.kind == Skew.NodeKind.PAIR);\n    assert(this.childCount() == 2);\n    assert(Skew.in_NodeKind.isExpression(this._lastChild.kind));\n    return this._lastChild;\n  };\n\n  Skew.Node.prototype.dotTarget = function() {\n    assert(this.kind == Skew.NodeKind.DOT || this.kind == Skew.NodeKind.NULL_DOT);\n    assert(this.childCount() <= 1);\n    assert(this._firstChild == null || Skew.in_NodeKind.isExpression(this._firstChild.kind));\n    return this._firstChild;\n  };\n\n  Skew.Node.prototype.annotationValue = function() {\n    assert(this.kind == Skew.NodeKind.ANNOTATION);\n    assert(this.childCount() == 1 || this.childCount() == 2);\n    assert(Skew.in_NodeKind.isExpression(this._firstChild.kind));\n    return this._firstChild;\n  };\n\n  Skew.Node.prototype.annotationTest = function() {\n    assert(this.kind == Skew.NodeKind.ANNOTATION);\n    assert(this.childCount() == 1 || this.childCount() == 2);\n    assert(this._firstChild._nextSibling == null || Skew.in_NodeKind.isExpression(this._firstChild._nextSibling.kind));\n    return this._firstChild._nextSibling;\n  };\n\n  Skew.Node.prototype.caseBlock = function() {\n    assert(this.kind == Skew.NodeKind.CASE);\n    assert(this.childCount() >= 1);\n    assert(this._lastChild.kind == Skew.NodeKind.BLOCK);\n    return this._lastChild;\n  };\n\n  Skew.Node.prototype.catchBlock = function() {\n    assert(this.kind == Skew.NodeKind.CATCH);\n    assert(this.childCount() == 1);\n    assert(this._firstChild.kind == Skew.NodeKind.BLOCK);\n    return this._firstChild;\n  };\n\n  Skew.Node.prototype.variableValue = function() {\n    assert(this.kind == Skew.NodeKind.VARIABLE);\n    assert(this.childCount() <= 1);\n    assert(this._firstChild == null || Skew.in_NodeKind.isExpression(this._firstChild.kind));\n    return this._firstChild;\n  };\n\n  Skew.Node.prototype.expressionValue = function() {\n    assert(this.kind == Skew.NodeKind.EXPRESSION);\n    assert(this.childCount() == 1);\n    assert(Skew.in_NodeKind.isExpression(this._firstChild.kind));\n    return this._firstChild;\n  };\n\n  Skew.Node.prototype.returnValue = function() {\n    assert(this.kind == Skew.NodeKind.RETURN);\n    assert(this.childCount() <= 1);\n    assert(this._firstChild == null || Skew.in_NodeKind.isExpression(this._firstChild.kind));\n    return this._firstChild;\n  };\n\n  Skew.Node.prototype.switchValue = function() {\n    assert(this.kind == Skew.NodeKind.SWITCH);\n    assert(this.childCount() >= 1);\n    assert(Skew.in_NodeKind.isExpression(this._firstChild.kind));\n    return this._firstChild;\n  };\n\n  Skew.Node.prototype.defaultCase = function() {\n    assert(this.kind == Skew.NodeKind.SWITCH);\n    assert(this.childCount() >= 1);\n\n    // The default case is always the last one\n    return !this.hasOneChild() && this._lastChild.hasOneChild() ? this._lastChild : null;\n  };\n\n  Skew.Node.prototype.parameterizeValue = function() {\n    assert(this.kind == Skew.NodeKind.PARAMETERIZE);\n    assert(this.childCount() >= 1);\n    assert(Skew.in_NodeKind.isExpression(this._firstChild.kind));\n    return this._firstChild;\n  };\n\n  Skew.Node.prototype.callValue = function() {\n    assert(this.kind == Skew.NodeKind.CALL);\n    assert(this.childCount() >= 1);\n    assert(Skew.in_NodeKind.isExpression(this._firstChild.kind));\n    return this._firstChild;\n  };\n\n  Skew.Node.prototype.castValue = function() {\n    assert(this.kind == Skew.NodeKind.CAST);\n    assert(this.childCount() == 2);\n    assert(Skew.in_NodeKind.isExpression(this._firstChild.kind));\n    return this._firstChild;\n  };\n\n  Skew.Node.prototype.castType = function() {\n    assert(this.kind == Skew.NodeKind.CAST);\n    assert(this.childCount() == 2);\n    assert(Skew.in_NodeKind.isExpression(this._lastChild.kind));\n    return this._lastChild;\n  };\n\n  Skew.Node.prototype.typeCheckValue = function() {\n    assert(this.kind == Skew.NodeKind.TYPE_CHECK);\n    assert(this.childCount() == 2);\n    assert(Skew.in_NodeKind.isExpression(this._firstChild.kind));\n    return this._firstChild;\n  };\n\n  Skew.Node.prototype.typeCheckType = function() {\n    assert(this.kind == Skew.NodeKind.TYPE_CHECK);\n    assert(this.childCount() == 2);\n    assert(Skew.in_NodeKind.isExpression(this._lastChild.kind));\n    return this._lastChild;\n  };\n\n  Skew.Node.prototype.xmlTag = function() {\n    assert(this.kind == Skew.NodeKind.XML);\n    assert(this.childCount() == 3 || this.childCount() == 4);\n    assert(Skew.in_NodeKind.isExpression(this._firstChild.kind));\n    return this._firstChild;\n  };\n\n  Skew.Node.prototype.xmlAttributes = function() {\n    assert(this.kind == Skew.NodeKind.XML);\n    assert(this.childCount() == 3 || this.childCount() == 4);\n    assert(this._firstChild._nextSibling.kind == Skew.NodeKind.SEQUENCE);\n    return this._firstChild._nextSibling;\n  };\n\n  Skew.Node.prototype.xmlChildren = function() {\n    assert(this.kind == Skew.NodeKind.XML);\n    assert(this.childCount() == 3 || this.childCount() == 4);\n    assert(this._firstChild._nextSibling._nextSibling.kind == Skew.NodeKind.BLOCK);\n    return this._firstChild._nextSibling._nextSibling;\n  };\n\n  Skew.Node.prototype.xmlClosingTag = function() {\n    assert(this.kind == Skew.NodeKind.XML);\n    assert(this.childCount() == 3 || this.childCount() == 4);\n    assert(this._firstChild._nextSibling._nextSibling._nextSibling == null || Skew.in_NodeKind.isExpression(this._firstChild._nextSibling._nextSibling._nextSibling.kind));\n    return this._firstChild._nextSibling._nextSibling._nextSibling;\n  };\n\n  Skew.Node.prototype.unaryValue = function() {\n    assert(Skew.in_NodeKind.isUnary(this.kind));\n    assert(this.childCount() == 1);\n    assert(Skew.in_NodeKind.isExpression(this._firstChild.kind));\n    return this._firstChild;\n  };\n\n  Skew.Node.prototype.binaryLeft = function() {\n    assert(Skew.in_NodeKind.isBinary(this.kind));\n    assert(this.childCount() == 2);\n    assert(Skew.in_NodeKind.isExpression(this._firstChild.kind));\n    return this._firstChild;\n  };\n\n  Skew.Node.prototype.binaryRight = function() {\n    assert(Skew.in_NodeKind.isBinary(this.kind));\n    assert(this.childCount() == 2);\n    assert(Skew.in_NodeKind.isExpression(this._lastChild.kind));\n    return this._lastChild;\n  };\n\n  Skew.Node.prototype.throwValue = function() {\n    assert(this.childCount() == 1);\n    assert(Skew.in_NodeKind.isExpression(this._firstChild.kind));\n    return this._firstChild;\n  };\n\n  Skew.Node.prototype.tryBlock = function() {\n    assert(this.kind == Skew.NodeKind.TRY);\n    assert(this.childCount() >= 1);\n    assert(this._firstChild.kind == Skew.NodeKind.BLOCK);\n    return this._firstChild;\n  };\n\n  Skew.Node.prototype.finallyBlock = function() {\n    assert(this.kind == Skew.NodeKind.TRY);\n    assert(this.childCount() >= 1);\n    var finallyBlock = this._lastChild;\n    return finallyBlock != this.tryBlock() && finallyBlock.kind == Skew.NodeKind.BLOCK ? finallyBlock : null;\n  };\n\n  Skew.Node.prototype.whileTest = function() {\n    assert(this.kind == Skew.NodeKind.WHILE);\n    assert(this.childCount() == 2);\n    assert(Skew.in_NodeKind.isExpression(this._firstChild.kind));\n    return this._firstChild;\n  };\n\n  Skew.Node.prototype.whileBlock = function() {\n    assert(this.kind == Skew.NodeKind.WHILE);\n    assert(this.childCount() == 2);\n    assert(this._lastChild.kind == Skew.NodeKind.BLOCK);\n    return this._lastChild;\n  };\n\n  Skew.Node.prototype.forSetup = function() {\n    assert(this.kind == Skew.NodeKind.FOR);\n    assert(this.childCount() == 4);\n    assert(Skew.in_NodeKind.isExpression(this._firstChild.kind) || this._firstChild.kind == Skew.NodeKind.VARIABLES);\n    return this._firstChild;\n  };\n\n  Skew.Node.prototype.forTest = function() {\n    assert(this.kind == Skew.NodeKind.FOR);\n    assert(this.childCount() == 4);\n    assert(Skew.in_NodeKind.isExpression(this._firstChild._nextSibling.kind));\n    return this._firstChild._nextSibling;\n  };\n\n  Skew.Node.prototype.forUpdate = function() {\n    assert(this.kind == Skew.NodeKind.FOR);\n    assert(this.childCount() == 4);\n    assert(Skew.in_NodeKind.isExpression(this._lastChild._previousSibling.kind));\n    return this._lastChild._previousSibling;\n  };\n\n  Skew.Node.prototype.forBlock = function() {\n    assert(this.kind == Skew.NodeKind.FOR);\n    assert(this.childCount() == 4);\n    assert(this._lastChild.kind == Skew.NodeKind.BLOCK);\n    return this._lastChild;\n  };\n\n  Skew.Node.prototype.foreachValue = function() {\n    assert(this.kind == Skew.NodeKind.FOREACH);\n    assert(this.childCount() == 2);\n    assert(Skew.in_NodeKind.isExpression(this._firstChild.kind));\n    return this._firstChild;\n  };\n\n  Skew.Node.prototype.foreachBlock = function() {\n    assert(this.kind == Skew.NodeKind.FOREACH);\n    assert(this.childCount() == 2);\n    assert(this._lastChild.kind == Skew.NodeKind.BLOCK);\n    return this._lastChild;\n  };\n\n  Skew.Node.prototype.ifTest = function() {\n    assert(this.kind == Skew.NodeKind.IF);\n    assert(this.childCount() == 2 || this.childCount() == 3);\n    assert(Skew.in_NodeKind.isExpression(this._firstChild.kind));\n    return this._firstChild;\n  };\n\n  Skew.Node.prototype.ifTrue = function() {\n    assert(this.kind == Skew.NodeKind.IF);\n    assert(this.childCount() == 2 || this.childCount() == 3);\n    assert(this._firstChild._nextSibling.kind == Skew.NodeKind.BLOCK);\n    return this._firstChild._nextSibling;\n  };\n\n  Skew.Node.prototype.ifFalse = function() {\n    assert(this.kind == Skew.NodeKind.IF);\n    assert(this.childCount() == 2 || this.childCount() == 3);\n    assert(this._firstChild._nextSibling._nextSibling == null || this._firstChild._nextSibling._nextSibling.kind == Skew.NodeKind.BLOCK);\n    return this._firstChild._nextSibling._nextSibling;\n  };\n\n  Skew.Node.prototype.hookTest = function() {\n    assert(this.kind == Skew.NodeKind.HOOK);\n    assert(this.childCount() == 3);\n    assert(Skew.in_NodeKind.isExpression(this._firstChild.kind));\n    return this._firstChild;\n  };\n\n  Skew.Node.prototype.hookTrue = function() {\n    assert(this.kind == Skew.NodeKind.HOOK);\n    assert(this.childCount() == 3);\n    assert(Skew.in_NodeKind.isExpression(this._firstChild._nextSibling.kind));\n    return this._firstChild._nextSibling;\n  };\n\n  Skew.Node.prototype.hookFalse = function() {\n    assert(this.kind == Skew.NodeKind.HOOK);\n    assert(this.childCount() == 3);\n    assert(Skew.in_NodeKind.isExpression(this._lastChild.kind));\n    return this._lastChild;\n  };\n\n  Skew.Node.prototype.indexLeft = function() {\n    assert(this.kind == Skew.NodeKind.INDEX);\n    assert(this.childCount() == 2);\n    assert(Skew.in_NodeKind.isExpression(this._firstChild.kind));\n    return this._firstChild;\n  };\n\n  Skew.Node.prototype.indexRight = function() {\n    assert(this.kind == Skew.NodeKind.INDEX);\n    assert(this.childCount() == 2);\n    assert(Skew.in_NodeKind.isExpression(this._firstChild._nextSibling.kind));\n    return this._firstChild._nextSibling;\n  };\n\n  Skew.Node.prototype.assignIndexLeft = function() {\n    assert(this.kind == Skew.NodeKind.ASSIGN_INDEX);\n    assert(this.childCount() == 3);\n    assert(Skew.in_NodeKind.isExpression(this._firstChild.kind));\n    return this._firstChild;\n  };\n\n  Skew.Node.prototype.assignIndexCenter = function() {\n    assert(this.kind == Skew.NodeKind.ASSIGN_INDEX);\n    assert(this.childCount() == 3);\n    assert(Skew.in_NodeKind.isExpression(this._firstChild._nextSibling.kind));\n    return this._firstChild._nextSibling;\n  };\n\n  Skew.Node.prototype.assignIndexRight = function() {\n    assert(this.kind == Skew.NodeKind.ASSIGN_INDEX);\n    assert(this.childCount() == 3);\n    assert(Skew.in_NodeKind.isExpression(this._lastChild.kind));\n    return this._lastChild;\n  };\n\n  Skew.Node.prototype.lambdaBlock = function() {\n    assert(this.kind == Skew.NodeKind.LAMBDA);\n    assert(this.childCount() == 1);\n    assert(this._firstChild.kind == Skew.NodeKind.BLOCK);\n    return this._firstChild;\n  };\n\n  Skew.Node.prototype.lambdaReturnType = function() {\n    assert(this.kind == Skew.NodeKind.LAMBDA_TYPE);\n    assert(this.childCount() >= 1);\n    assert(Skew.in_NodeKind.isExpression(this._lastChild.kind));\n    return this._lastChild;\n  };\n\n  // Syntax warnings can be thought of as linting\n  Skew.Log = function() {\n    this.diagnostics = [];\n    this.appendCallback = null;\n    this.warningsAreErrors = false;\n    this._warningCount = 0;\n    this._errorCount = 0;\n    this._wasWarningCount = 0;\n  };\n\n  Skew.Log.prototype.commandLineWarningDuplicateFlagValue = function(range, name, previous) {\n    this.append(this.newWarning(range, 'Multiple values are specified for \"' + name + '\", using the later value').withNote(previous, 'Ignoring the previous value'));\n  };\n\n  Skew.Log.prototype.commandLineErrorBadFlag = function(range, name) {\n    this.append(this.newError(range, 'Unknown command line flag \"' + name + '\"'));\n  };\n\n  Skew.Log.prototype.commandLineErrorMissingValue = function(range, text) {\n    this.append(this.newError(range, 'Use \"' + text + '\" to provide a value'));\n  };\n\n  Skew.Log.prototype.commandLineErrorExpectedToken = function(range, expected, found, text) {\n    this.append(this.newError(range, 'Expected \"' + expected + '\" but found \"' + found + '\" in \"' + text + '\"'));\n  };\n\n  Skew.Log.prototype.commandLineErrorNonBooleanValue = function(range, value, text) {\n    this.append(this.newError(range, 'Expected \"true\" or \"false\" but found \"' + value + '\" in \"' + text + '\"'));\n  };\n\n  Skew.Log.prototype.commandLineErrorNonIntegerValue = function(range, value, text) {\n    this.append(this.newError(range, 'Expected integer constant but found \"' + value + '\" in \"' + text + '\"'));\n  };\n\n  Skew.Log.prototype.commandLineErrorExpectedDefineValue = function(range, name) {\n    this.append(this.newError(range, 'Use \"--define:' + name + '=___\" to provide a value'));\n  };\n\n  Skew.Log.prototype.commandLineErrorMissingOutput = function(range, first, second) {\n    this.append(this.newError(range, 'Specify the output location using either \"' + first + '\" or \"' + second + '\"'));\n  };\n\n  Skew.Log.prototype.commandLineErrorDuplicateOutput = function(range, first, second) {\n    this.append(this.newError(range, 'Cannot specify both \"' + first + '\" and \"' + second + '\"'));\n  };\n\n  Skew.Log.prototype.commandLineErrorUnreadableFile = function(range, name) {\n    this.append(this.newError(range, 'Could not read from \"' + name + '\"'));\n  };\n\n  Skew.Log.prototype.commandLineErrorUnwritableFile = function(range, name) {\n    this.append(this.newError(range, 'Could not write to \"' + name + '\"'));\n  };\n\n  Skew.Log.prototype.commandLineErrorNoInputFiles = function(range) {\n    this.append(this.newError(range, 'Missing input files'));\n  };\n\n  Skew.Log.prototype.commandLineErrorMissingTarget = function(range) {\n    this.append(this.newError(range, 'Specify the target format using \"--target\"'));\n  };\n\n  Skew.Log.prototype.commandLineErrorInvalidEnum = function(range, name, found, expected) {\n    this.append(this.newError(range, 'Invalid ' + name + ' \"' + found + '\", must be either ' + Skew.PrettyPrint.joinQuoted(expected, 'or')));\n  };\n\n  Skew.Log.prototype.hasErrors = function() {\n    return this._errorCount != 0;\n  };\n\n  Skew.Log.prototype.hasWarnings = function() {\n    return this._warningCount != 0;\n  };\n\n  Skew.Log.prototype.warningCount = function() {\n    return this._warningCount;\n  };\n\n  Skew.Log.prototype.errorCount = function() {\n    return this._errorCount;\n  };\n\n  Skew.Log.prototype.wasWarningCount = function() {\n    return this._wasWarningCount;\n  };\n\n  Skew.Log.prototype.newError = function(range, text) {\n    return new Skew.Diagnostic(Skew.DiagnosticKind.ERROR, range, text, false);\n  };\n\n  Skew.Log.prototype.newWarning = function(range, text) {\n    return new Skew.Diagnostic(this.warningsAreErrors ? Skew.DiagnosticKind.ERROR : Skew.DiagnosticKind.WARNING, range, text, this.warningsAreErrors);\n  };\n\n  Skew.Log.prototype.append = function(diagnostic) {\n    this.diagnostics.push(diagnostic);\n\n    if (diagnostic.kind == Skew.DiagnosticKind.ERROR) {\n      this._errorCount = this._errorCount + 1 | 0;\n    }\n\n    else {\n      this._warningCount = this._warningCount + 1 | 0;\n    }\n\n    if (diagnostic.wasWarning) {\n      this._wasWarningCount = this._wasWarningCount + 1 | 0;\n    }\n\n    if (this.appendCallback != null) {\n      this.appendCallback(diagnostic);\n    }\n  };\n\n  Skew.Log.prototype.syntaxWarningIgnoredCommentInParser = function(range) {\n    this.append(this.newWarning(range, 'This comment was ignored by the parser'));\n  };\n\n  Skew.Log.prototype.syntaxWarningIgnoredCommentInEmitter = function(range) {\n    this.append(this.newWarning(range, 'This comment was ignored by the emitter'));\n  };\n\n  Skew.Log.prototype.syntaxWarningOctal = function(range) {\n    var text = range.toString();\n\n    while (text.startsWith('0')) {\n      text = in_string.slice1(text, 1);\n    }\n\n    this.append(this.newWarning(range, 'Number interpreted as decimal (use the prefix \"0o\" for octal numbers)').withFix(Skew.FixKind.OCTAL_REMOVE_ZEROS, range, 'Remove the leading zeros to avoid confusion', text).withFix(Skew.FixKind.OCTAL_ADD_PREFIX, range, 'Add the prefix \"0o\" to interpret the number as octal', '0o' + text));\n  };\n\n  Skew.Log.prototype.syntaxWarningExtraParentheses = function(range) {\n    var leftSpace = range.rangeIncludingLeftWhitespace().start == range.start ? ' ' : '';\n    var rightSpace = range.rangeIncludingRightWhitespace().end == range.end ? ' ' : '';\n    var text = range.toString();\n    this.append(this.newWarning(range, 'Unnecessary parentheses').withFix(Skew.FixKind.UNNECESSARY_PARENTHESES, range, 'Remove parentheses', leftSpace + in_string.slice2(text, 1, text.length - 1 | 0) + rightSpace));\n  };\n\n  Skew.Log.prototype.syntaxWarningExtraComma = function(range) {\n    this.append(this.newWarning(range, 'Unnecessary comma').withFix(Skew.FixKind.EXTRA_COMMA, range, 'Remove comma', ''));\n  };\n\n  Skew.Log.prototype.syntaxErrorInvalidEscapeSequence = function(range) {\n    this.append(this.newError(range, 'Invalid escape sequence'));\n  };\n\n  Skew.Log.prototype.syntaxErrorIntegerLiteralTooLarge = function(range) {\n    this.append(this.newError(range, 'Integer literal is too big to fit in 32 bits'));\n  };\n\n  Skew.Log.prototype.syntaxErrorInvalidCharacter = function(range) {\n    this.append(this.newError(range, 'Use double quotes for strings (single quotes are for character literals)').withFix(Skew.FixKind.SINGLE_QUOTES, range, 'Replace single quotes with double quotes', Skew.replaceSingleQuotesWithDoubleQuotes(range.toString())));\n  };\n\n  Skew.Log.prototype.syntaxErrorExtraData = function(range, text) {\n    this.append(this.newError(range, 'Syntax error \"' + (text == '\"' ? '\\\\\"' : text) + '\"'));\n  };\n\n  Skew.Log.prototype.syntaxErrorExtraColonBeforeType = function(range) {\n    this.append(this.newError(range, 'Do not use a colon before a type expression').withFix(Skew.FixKind.EXTRA_COLON, range, 'Remove the colon', ''));\n  };\n\n  Skew.Log.prototype.syntaxErrorNewOperator = function(range, correction) {\n    this.append(this.newError(range, 'There is no \"new\" operator, use \"' + correction + '\" instead').withFix(Skew.FixKind.NEW_OPERATOR, range, 'Replace with \"' + correction + '\"', correction));\n  };\n\n  Skew.Log.prototype.syntaxErrorExtendsKeyword = function(range) {\n    this.append(this.newError(range, 'Use \":\" instead of \"extends\" to indicate a base class').withFix(Skew.FixKind.EXTENDS_IMPLEMENTS, range, 'Replace \"extends\" with \":\"', ':'));\n  };\n\n  Skew.Log.prototype.syntaxErrorImplementsKeyword = function(range) {\n    this.append(this.newError(range, 'Use \"::\" instead of \"implements\" to indicate implemented interfaces').withFix(Skew.FixKind.EXTENDS_IMPLEMENTS, range, 'Replace \"implements\" with \"::\"', '::'));\n  };\n\n  Skew.Log.prototype.syntaxErrorMissingVar = function(range) {\n    this.append(this.newError(range, 'Use \"var\" before variable declarations').withFix(Skew.FixKind.MISSING_VAR, range, 'Insert \"var\"', 'var ' + range.toString()));\n  };\n\n  Skew.Log.prototype.syntaxErrorMissingDef = function(range) {\n    this.append(this.newError(range, 'Use \"def\" before function declarations').withFix(Skew.FixKind.MISSING_DEF, range, 'Insert \"def\"', 'def ' + range.toString()));\n  };\n\n  Skew.Log.prototype.syntaxErrorStaticKeyword = function(range, parentKind, parentName) {\n    this.append(this.newError(range, parentKind == Skew.SymbolKind.OBJECT_GLOBAL || parentKind == Skew.SymbolKind.OBJECT_NAMESPACE ? 'There is no \"static\" keyword' : 'There is no \"static\" keyword (declare this symbol in a namespace called \"' + parentName + '\" instead)'));\n  };\n\n  Skew.Log.prototype.syntaxErrorPublicKeyword = function(range) {\n    this.append(this.newError(range, 'There is no \"public\" keyword'));\n  };\n\n  Skew.Log.prototype.syntaxErrorPrivateOrProtected = function(range) {\n    this.append(this.newError(range, 'There is no \"' + range.toString() + '\" keyword (to give something protected access, use a name starting with \"_\" instead)'));\n  };\n\n  Skew.Log.prototype.syntaxErrorExpectedCommaBetweenCases = function(range) {\n    this.append(this.newError(range, 'Use a comma between multiple values in a case statement (example: \"case 1, 2, 3 { ... }\")').withFix(Skew.FixKind.CASE_COMMA, range, 'Replace this with a comma', ','));\n  };\n\n  Skew.Log.prototype.syntaxErrorColonAfterCaseOrDefault = function(range, breakRange) {\n    var diagnostic = this.newError(range, 'Surround the body of case and default statements with \"{\" and \"}\" instead of \":\" and \"break\"');\n\n    if (breakRange != null) {\n      assert(range.source == breakRange.source);\n      var start = range.source.indexToLineColumn(range.end);\n      var end = range.source.indexToLineColumn(breakRange.start);\n      var text = in_string.slice2(range.source.contents, range.end, breakRange.start);\n\n      // Use the indentation of the case statement for the \"}\"\n      if (start.line < end.line) {\n        text = in_string.slice2(text, 0, text.length - end.column | 0) + Skew.indentOfLine(range.source.contentsOfLine(start.line)) + Skew.lineWithoutIndent(in_string.slice2(range.source.contentsOfLine(end.line), 0, end.column));\n      }\n\n      diagnostic.withFix(Skew.FixKind.CASE_BRACES, Skew.Range.span(range.rangeIncludingLeftWhitespace(), breakRange), 'Replace \":\" and \"break\" with \"{\" and \"}\"', ' {' + text + '}');\n    }\n\n    this.append(diagnostic);\n  };\n\n  Skew.Log.prototype.syntaxErrorOperatorTypo = function(range, correction) {\n    this.append(this.newError(range, 'Use the \"' + correction + '\" operator instead').withFix(Skew.FixKind.OPERATOR_TYPO, range, 'Replace with \"' + correction + '\"', correction));\n  };\n\n  Skew.Log.prototype.syntaxErrorExtraVarInForLoop = function(range) {\n    this.append(this.newError(range, 'The \"var\" keyword is unnecessary here since for loops automatically declare their variables').withFix(Skew.FixKind.FOR_LOOP_VAR, range != null ? range.rangeIncludingRightWhitespace() : null, 'Remove \"var\"', ''));\n  };\n\n  Skew.Log.prototype.syntaxErrorWrongListSyntax = function(range, correction) {\n    this.append(this.newError(range, 'The array type is \"List<T>\"').withFix(Skew.FixKind.ARRAY_SYNTAX, range, 'Replace with \"' + correction + '\"', correction));\n  };\n\n  Skew.Log.prototype.syntaxErrorSlashComment = function(range) {\n    var text = range.toString();\n    var last = text.length - 1 | 0;\n    assert(text.startsWith('//'));\n\n    if (in_string.get1(text, last) == 10) {\n      text = in_string.slice2(text, 0, last);\n      range = range.fromStart(last);\n    }\n\n    // Change a run of \"////\" into \"####\"\n    var replacement = '';\n\n    for (var i = 1, count = text.length; i < count; i = i + 1 | 0) {\n      if (in_string.get1(text, i) == 47) {\n        replacement += '#';\n      }\n\n      else {\n        replacement += in_string.slice1(text, i);\n        break;\n      }\n    }\n\n    this.append(this.newError(range, 'Comments start with \"#\" instead of \"//\"').withFix(Skew.FixKind.SLASH_COMMENT, range, 'Replace \"//\" with \"#\"', replacement));\n  };\n\n  Skew.Log.prototype.syntaxErrorUnexpectedToken = function(token) {\n    this.append(this.newError(token.range, 'Unexpected ' + Skew.in_TokenKind.toString(token.kind)));\n  };\n\n  Skew.Log.prototype.syntaxErrorExpectedToken = function(range, found, expected) {\n    var diagnostic = this.newError(range, 'Expected ' + Skew.in_TokenKind.toString(expected) + ' but found ' + Skew.in_TokenKind.toString(found));\n\n    if (found == Skew.TokenKind.SEMICOLON && expected == Skew.TokenKind.NEWLINE) {\n      diagnostic.withFix(Skew.FixKind.EXTRA_SEMICOLON, range, 'Remove \";\"', '');\n    }\n\n    this.append(diagnostic);\n  };\n\n  Skew.Log.prototype.syntaxErrorEmptyFunctionParentheses = function(range) {\n    this.append(this.newError(range, 'Functions without arguments do not use parentheses').withFix(Skew.FixKind.EXTRA_DEF_PARENTHESES, range, 'Remove parentheses', ''));\n  };\n\n  Skew.Log.prototype.syntaxErrorBadDeclarationInsideType = function(range) {\n    this.append(this.newError(range, 'Cannot use this declaration here'));\n  };\n\n  Skew.Log.prototype.syntaxErrorBadOperatorCustomization = function(range, kind, why) {\n    this.append(this.newError(range, 'The ' + Skew.in_TokenKind.toString(kind) + ' operator is not customizable because ' + why));\n  };\n\n  Skew.Log.prototype.syntaxErrorVariableDeclarationNeedsVar = function(range, name) {\n    this.append(this.newError(range, 'Declare variables using \"var\" and put the type after the variable name').withFix(Skew.FixKind.NEED_VAR, Skew.Range.span(range, name), 'Declare \"' + name.toString() + '\" correctly', 'var ' + name.toString() + ' ' + range.toString()));\n  };\n\n  Skew.Log.prototype.syntaxErrorXMLClosingTagMismatch = function(range, found, expected, openingRange) {\n    this.append(this.newError(range, 'Expected \"' + expected + '\" but found \"' + found + '\" in XML literal').withNote(openingRange, 'Attempted to match opening tag here'));\n  };\n\n  Skew.Log.prototype.syntaxErrorOptionalArgument = function(range) {\n    this.append(this.newError(range, \"Optional arguments aren't supported yet\"));\n  };\n\n  Skew.Log._expectedCountText = function(singular, expected, found) {\n    return 'Expected ' + Skew.PrettyPrint.plural1(expected, singular) + ' but found ' + Skew.PrettyPrint.plural1(found, singular);\n  };\n\n  Skew.Log._formatArgumentTypes = function(types) {\n    if (types == null) {\n      return '';\n    }\n\n    var names = [];\n\n    for (var i = 0, list = types, count = list.length; i < count; i = i + 1 | 0) {\n      var type = in_List.get(list, i);\n      names.push(type.toString());\n    }\n\n    return ' of type' + (types.length == 1 ? '' : 's') + ' ' + Skew.PrettyPrint.join(names, 'and');\n  };\n\n  Skew.Log.prototype.semanticWarningInliningFailed = function(range, name) {\n    this.append(this.newWarning(range, 'Cannot inline function \"' + name + '\"'));\n  };\n\n  Skew.Log.prototype.semanticWarningIdenticalOperands = function(range, operator) {\n    this.append(this.newWarning(range, 'Both sides of \"' + operator + '\" are identical, is this a bug?'));\n  };\n\n  Skew.Log.prototype.semanticWarningSuspiciousAssignmentLocation = function(range) {\n    this.append(this.newWarning(range, 'Use of \"=\" here looks like a bug, did you mean to use \"==\"?'));\n  };\n\n  Skew.Log.prototype.semanticWarningShiftByZero = function(range) {\n    this.append(this.newWarning(range, \"Shifting an integer by zero doesn't do anything, is this a bug?\"));\n  };\n\n  Skew.Log.prototype.semanticWarningUnusedExpression = function(range) {\n    this.append(this.newWarning(range, 'Unused expression'));\n  };\n\n  Skew.Log.prototype.semanticErrorXMLMissingAppend = function(range, type) {\n    this.append(this.newError(range, 'Implement a function called \"<>...</>\" on type \"' + type.toString() + '\" to add support for child elements'));\n  };\n\n  Skew.Log.prototype.semanticErrorComparisonOperatorNotInt = function(range) {\n    this.append(this.newError(range, 'The comparison operator must have a return type of \"int\"'));\n  };\n\n  Skew.Log.prototype.semanticErrorDuplicateSymbol = function(range, name, previous) {\n    this.append(this.newError(range, '\"' + name + '\" is already declared').withNote(previous, 'The previous declaration is here'));\n  };\n\n  Skew.Log.prototype.semanticErrorShadowedSymbol = function(range, name, previous) {\n    this.append(this.newError(range, '\"' + name + '\" shadows a previous declaration').withNote(previous, 'The previous declaration is here'));\n  };\n\n  Skew.Log.prototype.semanticErrorDuplicateTypeParameters = function(range, name, previous) {\n    this.append(this.newError(range, '\"' + name + '\" already has type parameters').withNote(previous, 'Type parameters were previously declared here'));\n  };\n\n  Skew.Log.prototype.semanticErrorDuplicateBaseType = function(range, name, previous) {\n    this.append(this.newError(range, '\"' + name + '\" already has a base type').withNote(previous, 'The previous base type is here'));\n  };\n\n  Skew.Log.prototype.semanticErrorCyclicDeclaration = function(range, name) {\n    this.append(this.newError(range, 'Cyclic declaration of \"' + name + '\"'));\n  };\n\n  Skew.Log.prototype.semanticErrorUndeclaredSymbol = function(range, name, correction, correctionRange) {\n    var diagnostic = this.newError(range, '\"' + name + '\" is not declared' + (correction != null ? ', did you mean \"' + correction + '\"?' : ''));\n\n    if (correction != null && correctionRange != null) {\n      diagnostic.withNote(correctionRange, '\"' + correction + '\" is defined here').withFix(Skew.FixKind.SYMBOL_TYPO, range, 'Replace with \"' + correction + '\"', correction);\n    }\n\n    this.append(diagnostic);\n  };\n\n  Skew.Log.prototype.semanticErrorUndeclaredSelfSymbol = function(range, name) {\n    this.append(this.newError(range, '\"' + name + '\" is not declared (use \"self\" to refer to the object instance)').withFix(Skew.FixKind.SELF_VS_THIS, range, 'Replace \"' + name + '\" with \"self\"', 'self'));\n  };\n\n  Skew.Log.prototype.semanticErrorUnknownMemberSymbol = function(range, name, type, correction, correctionRange) {\n    var diagnostic = this.newError(range, '\"' + name + '\" is not declared on type \"' + type.toString() + '\"' + (correction != null ? ', did you mean \"' + correction + '\"?' : ''));\n\n    if (correction != null && correctionRange != null) {\n      diagnostic.withNote(correctionRange, '\"' + correction + '\" is defined here').withFix(Skew.FixKind.SYMBOL_TYPO, range, 'Replace with \"' + correction + '\"', correction);\n    }\n\n    this.append(diagnostic);\n  };\n\n  Skew.Log.prototype.semanticErrorVarMissingType = function(range, name) {\n    this.append(this.newError(range, 'Unable to determine the type of \"' + name + '\"'));\n  };\n\n  Skew.Log.prototype.semanticErrorVarMissingValue = function(range, name) {\n    this.append(this.newError(range, 'The implicitly typed variable \"' + name + '\" must be initialized'));\n  };\n\n  Skew.Log.prototype.semanticErrorConstMissingValue = function(range, name) {\n    this.append(this.newError(range, 'The constant \"' + name + '\" must be initialized'));\n  };\n\n  Skew.Log.prototype.semanticErrorInvalidCall = function(range, type) {\n    this.append(this.newError(range, 'Cannot call value of type \"' + type.toString() + '\"'));\n  };\n\n  Skew.Log.prototype.semanticErrorCannotParameterize = function(range, type) {\n    this.append(this.newError(range, 'Cannot parameterize \"' + type.toString() + '\"' + (type.isParameterized() ? ' because it is already parameterized' : ' because it has no type parameters')));\n  };\n\n  Skew.Log.prototype.semanticErrorParameterCount = function(range, expected, found) {\n    this.append(this.newError(range, Skew.Log._expectedCountText('type parameter', expected, found)));\n  };\n\n  Skew.Log.prototype.semanticErrorArgumentCount = function(range, expected, found, name, $function) {\n    this.append(this.newError(range, Skew.Log._expectedCountText('argument', expected, found) + (name != null ? ' when calling \"' + name + '\"' : '')).withNote($function, 'The function declaration is here'));\n  };\n\n  Skew.Log.prototype.semanticErrorGetterRequiresWrap = function(range, name, $function) {\n    this.append(this.newError(range, 'Wrap calls to the function \"' + name + '\" in parentheses to call the returned lambda').withNote($function, 'The function declaration is here'));\n  };\n\n  Skew.Log.prototype.semanticErrorGetterCalledTwice = function(range, name, $function) {\n    var diagnostic = this.newError(range, 'Cannot call the value returned from the function \"' + name + '\" (this function was called automatically because it takes no arguments)').withNote($function, 'The function declaration is here');\n\n    if (range.toString() == '()') {\n      diagnostic.withFix(Skew.FixKind.EXTRA_CALL_PARENTHESES, range, 'Remove the unnecessary \"()\"', '');\n    }\n\n    this.append(diagnostic);\n  };\n\n  Skew.Log.prototype.semanticErrorUseOfVoidFunction = function(range, name, $function) {\n    this.append(this.newError(range, 'The function \"' + name + '\" does not return a value').withNote($function, 'The function declaration is here'));\n  };\n\n  Skew.Log.prototype.semanticErrorUseOfVoidLambda = function(range) {\n    this.append(this.newError(range, 'This call does not return a value'));\n  };\n\n  Skew.Log.prototype.semanticErrorBadImplicitVariableType = function(range, type) {\n    this.append(this.newError(range, 'Implicitly typed variables cannot be of type \"' + type.toString() + '\"'));\n  };\n\n  Skew.Log.prototype.semanticErrorNoDefaultValue = function(range, type) {\n    this.append(this.newError(range, 'Cannot construct a default value of type \"' + type.toString() + '\"'));\n  };\n\n  Skew.Log.prototype.semanticErrorMemberUnexpectedGlobal = function(range, name) {\n    this.append(this.newError(range, 'Cannot access global member \"' + name + '\" from an instance context'));\n  };\n\n  Skew.Log.prototype.semanticErrorMemberUnexpectedInstance = function(range, name) {\n    this.append(this.newError(range, 'Cannot access instance member \"' + name + '\" from a global context'));\n  };\n\n  Skew.Log.prototype.semanticErrorMemberUnexpectedTypeParameter = function(range, name) {\n    this.append(this.newError(range, 'Cannot access type parameter \"' + name + '\" here'));\n  };\n\n  Skew.Log.prototype.semanticErrorConstructorReturnType = function(range) {\n    this.append(this.newError(range, 'Constructors cannot have a return type').withFix(Skew.FixKind.NEW_RETURN_TYPE, range != null ? range.rangeIncludingLeftWhitespace() : null, 'Remove the return type', ''));\n  };\n\n  Skew.Log.prototype.semanticErrorNoMatchingOverload = function(range, name, count, types) {\n    this.append(this.newError(range, 'No overload of \"' + name + '\" was found that takes ' + Skew.PrettyPrint.plural1(count, 'argument') + Skew.Log._formatArgumentTypes(types)));\n  };\n\n  Skew.Log.prototype.semanticErrorAmbiguousOverload = function(range, name, count, types) {\n    this.append(this.newError(range, 'Multiple matching overloads of \"' + name + '\" were found that can take ' + Skew.PrettyPrint.plural1(count, 'argument') + Skew.Log._formatArgumentTypes(types)));\n  };\n\n  Skew.Log.prototype.semanticErrorUnexpectedExpression = function(range, type) {\n    this.append(this.newError(range, 'Unexpected expression of type \"' + type.toString() + '\"'));\n  };\n\n  Skew.Log.prototype.semanticErrorUnexpectedType = function(range, type) {\n    this.append(this.newError(range, 'Unexpected type \"' + type.toString() + '\"'));\n  };\n\n  Skew.Log.prototype.semanticErrorIncompatibleTypes = function(range, from, to, isCastAllowed) {\n    this.append(this.newError(range, 'Cannot convert from type \"' + from.toString() + '\" to type \"' + to.toString() + '\"' + (isCastAllowed ? ' without a cast' : '')));\n  };\n\n  Skew.Log.prototype.semanticErrorInvalidDefine1 = function(range, value, type, name) {\n    this.append(this.newError(range, 'Cannot convert \"' + value + '\" to type \"' + type.toString() + '\" for variable \"' + name + '\"'));\n  };\n\n  Skew.Log.prototype.semanticWarningExtraCast = function(range, from, to) {\n    this.append(this.newWarning(range, 'Unnecessary cast from type \"' + from.toString() + '\" to type \"' + to.toString() + '\"').withFix(Skew.FixKind.EXTRA_CAST, range != null ? range.rangeIncludingLeftWhitespace() : null, 'Remove the cast', ''));\n  };\n\n  Skew.Log.prototype.semanticWarningExtraTypeCheck = function(range, from, to) {\n    this.append(this.newWarning(range, 'Unnecessary type check, type \"' + from.toString() + '\" is always type \"' + to.toString() + '\"'));\n  };\n\n  Skew.Log.prototype.semanticWarningBadTypeCheck = function(range, type) {\n    this.append(this.newError(range, 'Cannot check against interface type \"' + type.toString() + '\"'));\n  };\n\n  Skew.Log.prototype.semanticErrorWrongArgumentCount = function(range, name, count) {\n    this.append(this.newError(range, 'Expected \"' + name + '\" to take ' + Skew.PrettyPrint.plural1(count, 'argument')));\n  };\n\n  Skew.Log.prototype.semanticErrorWrongArgumentCountRange = function(range, name, values) {\n    assert(!(values.length == 0));\n    var first = in_List.first(values);\n    var count = values.length;\n\n    if (count == 1) {\n      this.semanticErrorWrongArgumentCount(range, name, first);\n    }\n\n    else {\n      var counts = [];\n      var min = first;\n      var max = first;\n      var text = null;\n\n      for (var i = 0, list = values, count1 = list.length; i < count1; i = i + 1 | 0) {\n        var value = in_List.get(list, i);\n        min = Math.min(min, value);\n        max = Math.max(max, value);\n        counts.push(value.toString());\n      }\n\n      // Assuming values are unique, this means all values form a continuous range\n      if (((max - min | 0) + 1 | 0) == count) {\n        if (min == 0) {\n          text = 'Expected \"' + name + '\" to take at most ' + Skew.PrettyPrint.plural1(max, 'argument');\n        }\n\n        else {\n          text = 'Expected \"' + name + '\" to take between ' + min.toString() + ' and ' + max.toString() + ' arguments';\n        }\n      }\n\n      // Otherwise, the values are disjoint\n      else {\n        text = 'Expected \"' + name + '\" to take either ' + Skew.PrettyPrint.join(counts, 'or') + ' arguments';\n      }\n\n      this.append(this.newError(range, text));\n    }\n  };\n\n  Skew.Log.prototype.semanticErrorExpectedList = function(range, name, type) {\n    this.append(this.newError(range, 'Expected argument \"' + name + '\" to be of type \"List<T>\" instead of type \"' + type.toString() + '\"'));\n  };\n\n  Skew.Log.prototype.semanticErrorUnexpectedReturnValue = function(range) {\n    this.append(this.newError(range, 'Cannot return a value inside a function without a return type'));\n  };\n\n  Skew.Log.prototype.semanticErrorBadReturnType = function(range, type) {\n    this.append(this.newError(range, 'Cannot create a function with a return type of \"' + type.toString() + '\"'));\n  };\n\n  Skew.Log.prototype.semanticErrorVoidReturnType = function(range) {\n    this.append(this.newError(range, 'There is no explicit \"void\" return type (to indicate that there\\'s nothing to return, just don\\'t put a return type)').withFix(Skew.FixKind.VOID_RETURN, range != null ? range.rangeIncludingLeftWhitespace() : null, 'Remove \"void\"', ''));\n  };\n\n  Skew.Log.prototype.semanticErrorExpectedReturnValue = function(range, type) {\n    this.append(this.newError(range, 'Must return a value of type \"' + type.toString() + '\"'));\n  };\n\n  Skew.Log.prototype.semanticErrorMissingReturn = function(range, name, type) {\n    this.append(this.newError(range, 'All control paths for \"' + name + '\" must return a value of type \"' + type.toString() + '\"'));\n  };\n\n  Skew.Log.prototype.semanticErrorBadStorage = function(range) {\n    this.append(this.newError(range, 'Cannot store to this location'));\n  };\n\n  Skew.Log.prototype.semanticErrorStorageToConstSymbol = function(range, name) {\n    this.append(this.newError(range, 'Cannot store to constant symbol \"' + name + '\"'));\n  };\n\n  Skew.Log.prototype.semanticErrorAccessViolation = function(range, name) {\n    this.append(this.newError(range, 'Cannot access protected symbol \"' + name + '\" here'));\n  };\n\n  Skew.Log.prototype.semanticWarningDeprecatedUsage = function(range, name) {\n    this.append(this.newWarning(range, 'Use of deprecated symbol \"' + name + '\"'));\n  };\n\n  Skew.Log.prototype.semanticErrorUnparameterizedType = function(range, type) {\n    this.append(this.newError(range, 'Cannot use unparameterized type \"' + type.toString() + '\" here'));\n  };\n\n  Skew.Log.prototype.semanticErrorParameterizedType = function(range, type) {\n    this.append(this.newError(range, 'Cannot use parameterized type \"' + type.toString() + '\" here'));\n  };\n\n  Skew.Log.prototype.semanticErrorNoCommonType = function(range, left, right) {\n    this.append(this.newError(range, 'No common type for \"' + left.toString() + '\" and \"' + right.toString() + '\"'));\n  };\n\n  Skew.Log.prototype.semanticErrorInvalidAnnotation = function(range, annotation, name) {\n    this.append(this.newError(range, 'Cannot use the annotation \"' + annotation + '\" on \"' + name + '\"'));\n  };\n\n  Skew.Log.prototype.semanticWarningDuplicateAnnotation = function(range, annotation, name) {\n    this.append(this.newWarning(range, 'Duplicate annotation \"' + annotation + '\" on \"' + name + '\"'));\n  };\n\n  Skew.Log.prototype.semanticWarningRedundantAnnotation = function(range, annotation, name, parent) {\n    this.append(this.newWarning(range, 'Redundant annotation \"' + annotation + '\" on \"' + name + '\" is already inherited from type \"' + parent + '\"'));\n  };\n\n  Skew.Log.prototype.semanticErrorBadForValue = function(range, type) {\n    this.append(this.newError(range, 'Cannot iterate over type \"' + type.toString() + '\"'));\n  };\n\n  Skew.Log.prototype.semanticWarningEmptyRange = function(range) {\n    this.append(this.newWarning(range, 'This range is empty'));\n  };\n\n  Skew.Log.prototype.semanticErrorMissingDotContext = function(range, name) {\n    this.append(this.newError(range, 'Cannot access \"' + name + '\" without type context'));\n  };\n\n  Skew.Log.prototype.semanticErrorInitializerTypeInferenceFailed = function(range) {\n    this.append(this.newError(range, 'Cannot infer a type for this literal'));\n  };\n\n  Skew.Log.prototype.semanticErrorInitializerRecursiveExpansion = function(range, newRange) {\n    this.append(this.newError(range, 'Attempting to resolve this literal led to recursive expansion').withNote(newRange, 'The constructor that was called recursively is here'));\n  };\n\n  Skew.Log.prototype.semanticErrorXMLCannotConstruct = function(range, type) {\n    this.append(this.newError(range, 'Cannot construct type \"' + type.toString() + '\"'));\n  };\n\n  Skew.Log.prototype.semanticErrorDuplicateOverload = function(range, name, previous) {\n    this.append(this.newError(range, 'Duplicate overloaded function \"' + name + '\"').withNote(previous, 'The previous declaration is here'));\n  };\n\n  Skew.Log.prototype.semanticErrorInvalidExtends = function(range, type) {\n    this.append(this.newError(range, 'Cannot extend type \"' + type.toString() + '\"'));\n  };\n\n  Skew.Log.prototype.semanticErrorInvalidImplements = function(range, type) {\n    this.append(this.newError(range, 'Cannot implement type \"' + type.toString() + '\"'));\n  };\n\n  Skew.Log.prototype.semanticErrorDuplicateImplements = function(range, type, previous) {\n    this.append(this.newError(range, 'Duplicate implemented type \"' + type.toString() + '\"').withNote(previous, 'The first occurrence is here'));\n  };\n\n  Skew.Log.prototype.semanticErrorBadInterfaceImplementation = function(range, classType, interfaceType, name, reason) {\n    this.append(this.newError(range, 'Type \"' + classType.toString() + '\" is missing an implementation of function \"' + name + '\" from interface \"' + interfaceType.toString() + '\"').withNote(reason, 'The function declaration is here'));\n  };\n\n  Skew.Log.prototype.semanticErrorBadInterfaceImplementationReturnType = function(range, name, found, expected, interfaceType, reason) {\n    this.append(this.newError(range, found != null && expected != null ? 'Function \"' + name + '\" has unexpected return type \"' + found.toString() + '\", expected return type \"' + expected.toString() + '\" ' + ('to match the function with the same name and argument types from interface \"' + interfaceType.toString() + '\"') : 'Expected the return type of function \"' + name + '\" to match the function with the same name and argument types from interface \"' + interfaceType.toString() + '\"').withNote(reason, 'The function declaration is here'));\n  };\n\n  Skew.Log.prototype.semanticErrorBadOverride = function(range, name, base, overridden) {\n    this.append(this.newError(range, '\"' + name + '\" overrides another declaration with the same name in base type \"' + base.toString() + '\"').withNote(overridden, 'The overridden declaration is here'));\n  };\n\n  Skew.Log.prototype.semanticErrorBadOverrideReturnType = function(range, name, base, overridden) {\n    this.append(this.newError(range, '\"' + name + '\" overrides another function with the same name and argument types but a different return type in base type \"' + base.toString() + '\"').withNote(overridden, 'The overridden function is here'));\n  };\n\n  Skew.Log.prototype.semanticErrorModifierMissingOverride = function(range, name, overridden) {\n    this.append(this.newError(range, '\"' + name + '\" overrides another symbol with the same name but is declared using \"def\" instead of \"over\"').withNote(overridden, 'The overridden declaration is here'));\n  };\n\n  Skew.Log.prototype.semanticErrorModifierUnusedOverride = function(range, name) {\n    this.append(this.newError(range, '\"' + name + '\" is declared using \"over\" instead of \"def\" but does not override anything'));\n  };\n\n  Skew.Log.prototype.semanticErrorBadSuper = function(range) {\n    this.append(this.newError(range, 'Cannot use \"super\" here'));\n  };\n\n  Skew.Log.prototype.semanticErrorBadJump = function(range, name) {\n    this.append(this.newError(range, 'Cannot use \"' + name + '\" outside a loop'));\n  };\n\n  Skew.Log.prototype.semanticErrorMustCallFunction = function(range, name, lower, upper) {\n    this.append(this.newError(range, lower == upper ? 'The function \"' + name + '\" takes ' + Skew.PrettyPrint.plural1(lower, 'argument') + ' and must be called' : 'The function \"' + name + '\" takes between ' + lower.toString() + ' and ' + upper.toString() + ' arguments and must be called'));\n  };\n\n  Skew.Log.prototype.semanticErrorDuplicateEntryPoint = function(range, previous) {\n    this.append(this.newError(range, 'Multiple entry points are declared').withNote(previous, 'The first entry point is here'));\n  };\n\n  Skew.Log.prototype.semanticErrorInvalidEntryPointArguments = function(range, name) {\n    this.append(this.newError(range, 'Entry point \"' + name + '\" must take either no arguments or one argument of type \"List<string>\"'));\n  };\n\n  Skew.Log.prototype.semanticErrorInvalidEntryPointReturnType = function(range, name) {\n    this.append(this.newError(range, 'Entry point \"' + name + '\" must return either nothing or a value of type \"int\"'));\n  };\n\n  Skew.Log.prototype.semanticErrorInvalidDefine2 = function(range, name) {\n    this.append(this.newError(range, 'Could not find a variable named \"' + name + '\" to override'));\n  };\n\n  Skew.Log.prototype.semanticErrorExpectedConstant = function(range) {\n    this.append(this.newError(range, 'This value must be a compile-time constant'));\n  };\n\n  Skew.Log.prototype.semanticWarningUnreadLocalVariable = function(range, name) {\n    this.append(this.newWarning(range, 'Local variable \"' + name + '\" is never read'));\n  };\n\n  Skew.Log.prototype.semanticErrorAbstractNew = function(range, type, reason, name) {\n    this.append(this.newError(range, 'Cannot construct abstract type \"' + type.toString() + '\"').withNote(reason, 'The type \"' + type.toString() + '\" is abstract due to member \"' + name + '\"'));\n  };\n\n  Skew.Log.prototype.semanticErrorUnimplementedFunction = function(range, name) {\n    this.append(this.newError(range, 'Non-imported function \"' + name + '\" is missing an implementation (use the \"@import\" annotation if it\\'s implemented externally)'));\n  };\n\n  Skew.Log.prototype.semanticErrorDefaultCaseNotLast = function(range) {\n    this.append(this.newError(range, 'The default case in a switch statement must come last'));\n  };\n\n  Skew.Log.prototype.semanticErrorForLoopDifferentType = function(range, name, found, expected) {\n    this.append(this.newError(range, 'Expected loop variable \"' + name + '\" to be of type \"' + expected.toString() + '\" instead of type \"' + found.toString() + '\"'));\n  };\n\n  Skew.Log.prototype.semanticErrorDuplicateCase = function(range, previous) {\n    this.append(this.newError(range, 'Duplicate case value').withNote(previous, 'The first occurrence is here'));\n  };\n\n  Skew.Log.prototype.semanticErrorMissingWrappedType = function(range, name) {\n    this.append(this.newError(range, 'Missing base type for wrapped type \"' + name + '\"'));\n  };\n\n  Skew.Log.prototype.semanticErrorDuplicateRename = function(range, name, optionA, optionB) {\n    this.append(this.newError(range, 'Cannot rename \"' + name + '\" to both \"' + optionA + '\" and \"' + optionB + '\"'));\n  };\n\n  Skew.Log.prototype.semanticErrorMissingSuper = function(range) {\n    this.append(this.newError(range, 'Constructors for derived types must start with a call to \"super\"'));\n  };\n\n  Skew.Log.prototype.semanticErrorTooManyFlags = function(range, name) {\n    this.append(this.newError(range, 'The type \"' + name + '\" cannot have more than 32 flags'));\n  };\n\n  Skew.Options = {};\n\n  Skew.Options.Type = {\n    BOOL: 0,\n    INT: 1,\n    STRING: 2,\n    STRING_LIST: 3\n  };\n\n  Skew.Options.Data = function(parser, type, option, name, description) {\n    this.parser = parser;\n    this.type = type;\n    this.option = option;\n    this.name = name;\n    this.description = description;\n  };\n\n  Skew.Options.Data.prototype.nameText = function() {\n    return this.name + (this.type == Skew.Options.Type.BOOL ? '' : this.type == Skew.Options.Type.STRING_LIST ? ':___' : '=___');\n  };\n\n  Skew.Options.Data.prototype.aliases = function(names) {\n    for (var i = 0, list = names, count = list.length; i < count; i = i + 1 | 0) {\n      var name = in_List.get(list, i);\n      in_StringMap.set(this.parser.map, name, this);\n    }\n\n    return this;\n  };\n\n  Skew.Options.Parser = function() {\n    this.options = [];\n    this.map = new Map();\n    this.optionalArguments = new Map();\n    this.normalArguments = [];\n    this.source = null;\n  };\n\n  Skew.Options.Parser.prototype.define = function(type, option, name, description) {\n    var data = new Skew.Options.Data(this, type, option, name, description);\n    in_StringMap.set(this.map, name, data);\n    this.options.push(data);\n    return data;\n  };\n\n  Skew.Options.Parser.prototype.nodeForOption = function(option) {\n    return in_IntMap.get(this.optionalArguments, option, null);\n  };\n\n  Skew.Options.Parser.prototype.boolForOption = function(option, defaultValue) {\n    var node = this.nodeForOption(option);\n    return node != null ? Skew.in_Content.asBool(node.content) : defaultValue;\n  };\n\n  Skew.Options.Parser.prototype.intForOption = function(option, defaultValue) {\n    var node = this.nodeForOption(option);\n    return node != null ? Skew.in_Content.asInt(node.content) : defaultValue;\n  };\n\n  Skew.Options.Parser.prototype.rangeForOption = function(option) {\n    var node = this.nodeForOption(option);\n    return node != null ? node.range : null;\n  };\n\n  Skew.Options.Parser.prototype.rangeListForOption = function(option) {\n    var node = this.nodeForOption(option);\n    var ranges = [];\n\n    if (node != null) {\n      for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n        ranges.push(child.range);\n      }\n    }\n\n    return ranges;\n  };\n\n  Skew.Options.Parser.prototype.parse = function(log, $arguments) {\n    this.source = new Skew.Source('<arguments>', '');\n    var ranges = [];\n\n    // Create a source for the arguments to work with the log system. The\n    // trailing space is needed to be able to point to the character after\n    // the last argument without wrapping onto the next line.\n    for (var i1 = 0, list = $arguments, count = list.length; i1 < count; i1 = i1 + 1 | 0) {\n      var argument = in_List.get(list, i1);\n      var needsQuotes = argument.indexOf(' ') != -1;\n      var start = this.source.contents.length + (needsQuotes | 0) | 0;\n      ranges.push(new Skew.Range(this.source, start, start + argument.length | 0));\n      this.source.contents += needsQuotes ? \"'\" + argument + \"' \" : argument + ' ';\n    }\n\n    // Parse each argument\n    for (var i = 0, count1 = $arguments.length; i < count1; i = i + 1 | 0) {\n      var argument1 = in_List.get($arguments, i);\n      var range = in_List.get(ranges, i);\n\n      // Track all normal arguments separately\n      if (argument1 == '' || in_string.get1(argument1, 0) != 45 && !this.map.has(argument1)) {\n        this.normalArguments.push(range);\n        continue;\n      }\n\n      // Parse a flag\n      var equals = argument1.indexOf('=');\n      var colon = argument1.indexOf(':');\n      var separator = equals >= 0 && (colon < 0 || equals < colon) ? equals : colon;\n      var name = separator >= 0 ? in_string.slice2(argument1, 0, separator) : argument1;\n      var data = in_StringMap.get(this.map, name, null);\n\n      // Check that the flag exists\n      if (data == null) {\n        log.commandLineErrorBadFlag(range.fromStart(name.length), name);\n        continue;\n      }\n\n      // Validate the flag data\n      var text = in_string.slice1(argument1, separator + 1 | 0);\n      var separatorRange = separator < 0 ? null : range.slice(separator, separator + 1 | 0);\n      var textRange = range.fromEnd(text.length);\n\n      switch (data.type) {\n        // Parse a single boolean value\n        case Skew.Options.Type.BOOL: {\n          if (separator < 0) {\n            text = 'true';\n          }\n\n          else if (in_string.get1(argument1, separator) != 61) {\n            log.commandLineErrorExpectedToken(separatorRange, '=', in_string.get(argument1, separator), argument1);\n            continue;\n          }\n\n          else if (text != 'true' && text != 'false') {\n            log.commandLineErrorNonBooleanValue(textRange, text, argument1);\n            continue;\n          }\n\n          if (this.optionalArguments.has(data.option)) {\n            log.commandLineWarningDuplicateFlagValue(textRange, name, in_IntMap.get1(this.optionalArguments, data.option).range);\n          }\n\n          in_IntMap.set(this.optionalArguments, data.option, new Skew.Node(Skew.NodeKind.CONSTANT).withContent(new Skew.BoolContent(text == 'true')).withRange(textRange));\n          break;\n        }\n\n        // Parse a single int value\n        case Skew.Options.Type.INT: {\n          if (separator < 0) {\n            log.commandLineErrorMissingValue(textRange, data.nameText());\n          }\n\n          else if (in_string.get1(argument1, separator) != 61) {\n            log.commandLineErrorExpectedToken(separatorRange, '=', in_string.get(argument1, separator), argument1);\n          }\n\n          else {\n            var box = Skew.Parsing.parseIntLiteral(log, textRange);\n\n            if (box == null) {\n              log.commandLineErrorNonIntegerValue(textRange, text, argument1);\n            }\n\n            else {\n              if (this.optionalArguments.has(data.option)) {\n                log.commandLineWarningDuplicateFlagValue(textRange, name, in_IntMap.get1(this.optionalArguments, data.option).range);\n              }\n\n              in_IntMap.set(this.optionalArguments, data.option, new Skew.Node(Skew.NodeKind.CONSTANT).withContent(new Skew.IntContent(box.value)).withRange(textRange));\n            }\n          }\n          break;\n        }\n\n        // Parse a single string value\n        case Skew.Options.Type.STRING: {\n          if (separator < 0) {\n            log.commandLineErrorMissingValue(textRange, data.nameText());\n          }\n\n          else if (in_string.get1(argument1, separator) != 61) {\n            log.commandLineErrorExpectedToken(separatorRange, '=', in_string.get(argument1, separator), argument1);\n          }\n\n          else {\n            if (this.optionalArguments.has(data.option)) {\n              log.commandLineWarningDuplicateFlagValue(textRange, name, in_IntMap.get1(this.optionalArguments, data.option).range);\n            }\n\n            in_IntMap.set(this.optionalArguments, data.option, new Skew.Node(Skew.NodeKind.CONSTANT).withContent(new Skew.StringContent(text)).withRange(textRange));\n          }\n          break;\n        }\n\n        // Parse an item in a list of string values\n        case Skew.Options.Type.STRING_LIST: {\n          if (separator < 0) {\n            log.commandLineErrorMissingValue(textRange, data.nameText());\n          }\n\n          else if (in_string.get1(argument1, separator) != 58) {\n            log.commandLineErrorExpectedToken(separatorRange, ':', in_string.get(argument1, separator), argument1);\n          }\n\n          else {\n            var node = null;\n\n            if (this.optionalArguments.has(data.option)) {\n              node = in_IntMap.get1(this.optionalArguments, data.option);\n            }\n\n            else {\n              node = Skew.Node.createInitializer(Skew.NodeKind.INITIALIZER_LIST);\n              in_IntMap.set(this.optionalArguments, data.option, node);\n            }\n\n            node.appendChild(new Skew.Node(Skew.NodeKind.CONSTANT).withContent(new Skew.StringContent(text)).withRange(textRange));\n          }\n          break;\n        }\n      }\n    }\n  };\n\n  Skew.Options.Parser.prototype.usageText = function(wrapWidth) {\n    var text = '';\n    var columnWidth = 0;\n\n    // Figure out the column width\n    for (var i = 0, list = this.options, count = list.length; i < count; i = i + 1 | 0) {\n      var option = in_List.get(list, i);\n      var width = option.nameText().length + 4 | 0;\n\n      if (columnWidth < width) {\n        columnWidth = width;\n      }\n    }\n\n    // Format the options\n    var columnText = in_string.repeat(' ', columnWidth);\n\n    for (var i2 = 0, list2 = this.options, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n      var option1 = in_List.get(list2, i2);\n      var nameText = option1.nameText();\n      var isFirst = true;\n      text += '\\n  ' + nameText + in_string.repeat(' ', (columnWidth - nameText.length | 0) - 2 | 0);\n\n      for (var i1 = 0, list1 = Skew.PrettyPrint.wrapWords(option1.description, wrapWidth - columnWidth | 0), count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n        var line = in_List.get(list1, i1);\n        text += (isFirst ? '' : columnText) + line + '\\n';\n        isFirst = false;\n      }\n    }\n\n    return text + '\\n';\n  };\n\n  Skew.Option = {\n    DEFINE: 0,\n    FIX_ALL: 1,\n    FOLD_CONSTANTS: 2,\n    GLOBALIZE_FUNCTIONS: 4,\n    HELP: 5,\n    IGNORED_COMMENT_WARNING: 6,\n    INLINE_FUNCTIONS: 7,\n    JS_MANGLE: 8,\n    JS_MINIFY: 9,\n    JS_SOURCE_MAP: 10,\n    MESSAGE_LIMIT: 11,\n    NO_OUTPUT: 12,\n    OUTPUT_DIRECTORY: 13,\n    OUTPUT_FILE: 14,\n    RELEASE: 15,\n    TARGET: 16,\n    VERBOSE: 17,\n    VERSION: 18,\n    WARNINGS_ARE_ERRORS: 19\n  };\n\n  Skew.DiagnosticKind = {\n    ERROR: 0,\n    WARNING: 1\n  };\n\n  Skew.Fix = function(kind, range, description, replacement) {\n    this.kind = kind;\n    this.range = range;\n    this.description = description;\n    this.replacement = replacement;\n  };\n\n  Skew.FixKind = {\n    ARRAY_SYNTAX: 0,\n    CASE_BRACES: 1,\n    CASE_COMMA: 2,\n    EXTENDS_IMPLEMENTS: 3,\n    EXTRA_CALL_PARENTHESES: 4,\n    EXTRA_CAST: 5,\n    EXTRA_COLON: 6,\n    EXTRA_COMMA: 7,\n    EXTRA_DEF_PARENTHESES: 8,\n    EXTRA_SEMICOLON: 9,\n    FOR_LOOP_VAR: 10,\n    MISSING_DEF: 11,\n    MISSING_VAR: 12,\n    NEED_VAR: 13,\n    NEW_OPERATOR: 14,\n    NEW_RETURN_TYPE: 15,\n    OCTAL_ADD_PREFIX: 16,\n    OCTAL_REMOVE_ZEROS: 17,\n    OPERATOR_TYPO: 18,\n    SELF_VS_THIS: 19,\n    SINGLE_QUOTES: 20,\n    SLASH_COMMENT: 21,\n    SYMBOL_TYPO: 22,\n    UNNECESSARY_PARENTHESES: 23,\n    VOID_RETURN: 24\n  };\n\n  Skew.Diagnostic = function(kind, range, text, wasWarning) {\n    this.kind = kind;\n    this.range = range;\n    this.text = text;\n    this.wasWarning = wasWarning;\n    this.noteRange = null;\n    this.noteText = '';\n    this.fixes = null;\n  };\n\n  Skew.Diagnostic.prototype.withFix = function(kind, range, description, replacement) {\n    if (range != null && replacement != null) {\n      (this.fixes != null ? this.fixes : this.fixes = []).push(new Skew.Fix(kind, range, description, replacement));\n    }\n\n    return this;\n  };\n\n  Skew.Diagnostic.prototype.withNote = function(range, text) {\n    if (range != null) {\n      this.noteRange = range;\n      this.noteText = text;\n    }\n\n    return this;\n  };\n\n  Skew.Comment = function(range, lines, hasGapBelow, isTrailing) {\n    this.range = range;\n    this.lines = lines;\n    this.hasGapBelow = hasGapBelow;\n    this.isTrailing = isTrailing;\n  };\n\n  Skew.Comment.concat = function(left, right) {\n    if (left == null) {\n      return right;\n    }\n\n    if (right == null) {\n      return left;\n    }\n\n    in_List.append1(left, right);\n    return left;\n  };\n\n  Skew.Comment.lastTrailingComment = function(comments) {\n    if (comments != null) {\n      var last = in_List.last(comments);\n\n      if (last.isTrailing && last.lines.length == 1) {\n        return last;\n      }\n    }\n\n    return null;\n  };\n\n  Skew.Comment.withoutLastTrailingComment = function(comments) {\n    if (comments != null) {\n      var last = in_List.last(comments);\n\n      if (last.isTrailing && last.lines.length == 1) {\n        return in_List.slice2(comments, 0, comments.length - 1 | 0);\n      }\n    }\n\n    return comments;\n  };\n\n  Skew.Comment.firstTrailingComment = function(comments) {\n    if (comments != null) {\n      var first = in_List.first(comments);\n\n      if (first.isTrailing && first.lines.length == 1) {\n        return first;\n      }\n    }\n\n    return null;\n  };\n\n  Skew.Comment.withoutFirstTrailingComment = function(comments) {\n    if (comments != null) {\n      var first = in_List.first(comments);\n\n      if (first.isTrailing && first.lines.length == 1) {\n        return in_List.slice1(comments, 1);\n      }\n    }\n\n    return comments;\n  };\n\n  Skew.Token = function(range, kind, comments) {\n    this.range = range;\n    this.kind = kind;\n    this.comments = comments;\n  };\n\n  Skew.TokenKind = {\n    // Type parameters are surrounded by \"<\" and \">\"\n    PARAMETER_LIST_END: 0,\n    PARAMETER_LIST_START: 1,\n\n    // XML entities are surrounded by \"<\" and \">\" (or \"</\" and \"/>\" but those are defined by flex)\n    XML_END: 2,\n    XML_START: 3,\n\n    // String interpolation looks like \"start\\( 1 )continue( 2 )end\"\n    STRING_INTERPOLATION_CONTINUE: 4,\n    STRING_INTERPOLATION_END: 5,\n    STRING_INTERPOLATION_START: 6,\n    ANNOTATION: 7,\n    ARROW: 8,\n    AS: 9,\n    ASSIGN: 10,\n    ASSIGN_BITWISE_AND: 11,\n    ASSIGN_BITWISE_OR: 12,\n    ASSIGN_BITWISE_XOR: 13,\n    ASSIGN_DIVIDE: 14,\n    ASSIGN_INDEX: 15,\n    ASSIGN_MINUS: 16,\n    ASSIGN_MODULUS: 17,\n    ASSIGN_MULTIPLY: 18,\n    ASSIGN_NULL: 19,\n    ASSIGN_PLUS: 20,\n    ASSIGN_POWER: 21,\n    ASSIGN_REMAINDER: 22,\n    ASSIGN_SHIFT_LEFT: 23,\n    ASSIGN_SHIFT_RIGHT: 24,\n    ASSIGN_UNSIGNED_SHIFT_RIGHT: 25,\n    BITWISE_AND: 26,\n    BITWISE_OR: 27,\n    BITWISE_XOR: 28,\n    BREAK: 29,\n    CASE: 30,\n    CATCH: 31,\n    CHARACTER: 32,\n    COLON: 33,\n    COMMA: 34,\n    COMMENT: 35,\n    COMMENT_ERROR: 36,\n    COMPARE: 37,\n    CONST: 38,\n    CONTINUE: 39,\n    DECREMENT: 40,\n    DEFAULT: 41,\n    DIVIDE: 42,\n    DOT: 43,\n    DOT_DOT: 44,\n    DOUBLE: 45,\n    DOUBLE_COLON: 46,\n    DYNAMIC: 47,\n    ELSE: 48,\n    END_OF_FILE: 49,\n    EQUAL: 50,\n    EQUAL_ERROR: 51,\n    ERROR: 52,\n    FALSE: 53,\n    FINALLY: 54,\n    FOR: 55,\n    GREATER_THAN: 56,\n    GREATER_THAN_OR_EQUAL: 57,\n    IDENTIFIER: 58,\n    IF: 59,\n    IN: 60,\n    INCREMENT: 61,\n    INDEX: 62,\n    INT: 63,\n    INT_BINARY: 64,\n    INT_HEX: 65,\n    INT_OCTAL: 66,\n    IS: 67,\n    LEFT_BRACE: 68,\n    LEFT_BRACKET: 69,\n    LEFT_PARENTHESIS: 70,\n    LESS_THAN: 71,\n    LESS_THAN_OR_EQUAL: 72,\n    LIST: 73,\n    LIST_NEW: 74,\n    LOGICAL_AND: 75,\n    LOGICAL_OR: 76,\n    MINUS: 77,\n    MODULUS: 78,\n    MULTIPLY: 79,\n    NEWLINE: 80,\n    NOT: 81,\n    NOT_EQUAL: 82,\n    NOT_EQUAL_ERROR: 83,\n    NULL: 84,\n    NULL_DOT: 85,\n    NULL_JOIN: 86,\n    PLUS: 87,\n    POWER: 88,\n    QUESTION_MARK: 89,\n    REMAINDER: 90,\n    RETURN: 91,\n    RIGHT_BRACE: 92,\n    RIGHT_BRACKET: 93,\n    RIGHT_PARENTHESIS: 94,\n    SEMICOLON: 95,\n    SET: 96,\n    SET_NEW: 97,\n    SHIFT_LEFT: 98,\n    SHIFT_RIGHT: 99,\n    STRING: 100,\n    SUPER: 101,\n    SWITCH: 102,\n    THROW: 103,\n    TILDE: 104,\n    TRUE: 105,\n    TRY: 106,\n    UNSIGNED_SHIFT_RIGHT: 107,\n    VAR: 108,\n    WHILE: 109,\n    WHITESPACE: 110,\n    XML_CHILD: 111,\n    XML_END_EMPTY: 112,\n    XML_START_CLOSE: 113,\n    YY_INVALID_ACTION: 114\n  };\n\n  Skew.FormattedRange = function(line, range) {\n    this.line = line;\n    this.range = range;\n  };\n\n  Skew.Range = function(source, start, end) {\n    this.source = source;\n    this.start = start;\n    this.end = end;\n  };\n\n  Skew.Range.prototype.toString = function() {\n    return in_string.slice2(this.source.contents, this.start, this.end);\n  };\n\n  Skew.Range.prototype.locationString = function() {\n    var location = this.source.indexToLineColumn(this.start);\n    return this.source.name + ':' + (location.line + 1 | 0).toString() + ':' + (location.column + 1 | 0).toString();\n  };\n\n  Skew.Range.prototype.touches = function(index) {\n    return this.start <= index && index <= this.end;\n  };\n\n  Skew.Range.prototype.format = function(maxLength) {\n    assert(this.source != null);\n    var start = this.source.indexToLineColumn(this.start);\n    var end = this.source.indexToLineColumn(this.end);\n    var line = this.source.contentsOfLine(start.line);\n    var startColumn = start.column;\n    var endColumn = end.line == start.line ? end.column : line.length;\n\n    // Use a unicode iterator to count the actual code points so they don't get sliced through the middle\n    var iterator = Unicode.StringIterator.INSTANCE.reset(line, 0);\n    var codePoints = [];\n    var a = 0;\n    var b = 0;\n\n    // Expand tabs into spaces\n    while (true) {\n      if (iterator.index == startColumn) {\n        a = codePoints.length;\n      }\n\n      if (iterator.index == endColumn) {\n        b = codePoints.length;\n      }\n\n      var codePoint = iterator.nextCodePoint();\n\n      if (codePoint < 0) {\n        break;\n      }\n\n      if (codePoint == 9) {\n        for (var space = 0, count1 = 8 - codePoints.length % 8 | 0; space < count1; space = space + 1 | 0) {\n          codePoints.push(32);\n        }\n      }\n\n      else {\n        codePoints.push(codePoint);\n      }\n    }\n\n    // Ensure the line length doesn't exceed maxLength\n    var count = codePoints.length;\n\n    if (maxLength > 0 && count > maxLength) {\n      var centeredWidth = Math.min(b - a | 0, maxLength / 2 | 0);\n      var centeredStart = Math.max((maxLength - centeredWidth | 0) / 2 | 0, 3);\n\n      // Left aligned\n      if (a < centeredStart) {\n        line = in_string.fromCodePoints(in_List.slice2(codePoints, 0, maxLength - 3 | 0)) + '...';\n\n        if (b > (maxLength - 3 | 0)) {\n          b = maxLength - 3 | 0;\n        }\n      }\n\n      // Right aligned\n      else if ((count - a | 0) < (maxLength - centeredStart | 0)) {\n        var offset = count - maxLength | 0;\n        line = '...' + in_string.fromCodePoints(in_List.slice2(codePoints, offset + 3 | 0, count));\n        a = a - offset | 0;\n        b = b - offset | 0;\n      }\n\n      // Center aligned\n      else {\n        var offset1 = a - centeredStart | 0;\n        line = '...' + in_string.fromCodePoints(in_List.slice2(codePoints, offset1 + 3 | 0, (offset1 + maxLength | 0) - 3 | 0)) + '...';\n        a = a - offset1 | 0;\n        b = b - offset1 | 0;\n\n        if (b > (maxLength - 3 | 0)) {\n          b = maxLength - 3 | 0;\n        }\n      }\n    }\n\n    else {\n      line = in_string.fromCodePoints(codePoints);\n    }\n\n    return new Skew.FormattedRange(line, in_string.repeat(' ', a) + ((b - a | 0) < 2 ? '^' : in_string.repeat('~', b - a | 0)));\n  };\n\n  Skew.Range.prototype.fromStart = function(count) {\n    assert(count >= 0 && count <= (this.end - this.start | 0));\n    return new Skew.Range(this.source, this.start, this.start + count | 0);\n  };\n\n  Skew.Range.prototype.fromEnd = function(count) {\n    assert(count >= 0 && count <= (this.end - this.start | 0));\n    return new Skew.Range(this.source, this.end - count | 0, this.end);\n  };\n\n  Skew.Range.prototype.slice = function(offsetStart, offsetEnd) {\n    assert(offsetStart >= 0 && offsetStart <= offsetEnd && offsetEnd <= (this.end - this.start | 0));\n    return new Skew.Range(this.source, this.start + offsetStart | 0, this.start + offsetEnd | 0);\n  };\n\n  Skew.Range.prototype.rangeIncludingLeftWhitespace = function() {\n    var index = this.start;\n    var contents = this.source.contents;\n\n    while (index > 0) {\n      var c = in_string.get1(contents, index - 1 | 0);\n\n      if (c != 32 && c != 9) {\n        break;\n      }\n\n      index = index - 1 | 0;\n    }\n\n    return new Skew.Range(this.source, index, this.end);\n  };\n\n  Skew.Range.prototype.rangeIncludingRightWhitespace = function() {\n    var index = this.end;\n    var contents = this.source.contents;\n\n    while (index < contents.length) {\n      var c = in_string.get1(contents, index);\n\n      if (c != 32 && c != 9) {\n        break;\n      }\n\n      index = index + 1 | 0;\n    }\n\n    return new Skew.Range(this.source, this.start, index);\n  };\n\n  Skew.Range.span = function(start, end) {\n    assert(start.source == end.source);\n    assert(start.start <= end.end);\n    return new Skew.Range(start.source, start.start, end.end);\n  };\n\n  Skew.Parsing = {};\n\n  // Parser recovery is done by skipping to the next closing token after an error\n  Skew.Parsing.scanForToken = function(context, kind) {\n    if (context.expect(kind)) {\n      return;\n    }\n\n    // Scan forward for the token\n    while (!context.peek1(Skew.TokenKind.END_OF_FILE)) {\n      if (context.eat(kind)) {\n        return;\n      }\n\n      switch (context.current().kind) {\n        // Stop at the next closing token\n        case Skew.TokenKind.RIGHT_PARENTHESIS:\n        case Skew.TokenKind.RIGHT_BRACKET:\n        case Skew.TokenKind.RIGHT_BRACE: {\n          return;\n        }\n\n        // Optionally recover parsing before the next statement if it's unambiguous\n        case Skew.TokenKind.BREAK:\n        case Skew.TokenKind.CATCH:\n        case Skew.TokenKind.CONST:\n        case Skew.TokenKind.CONTINUE:\n        case Skew.TokenKind.ELSE:\n        case Skew.TokenKind.FINALLY:\n        case Skew.TokenKind.FOR:\n        case Skew.TokenKind.IF:\n        case Skew.TokenKind.RETURN:\n        case Skew.TokenKind.TRY:\n        case Skew.TokenKind.VAR:\n        case Skew.TokenKind.WHILE: {\n          return;\n        }\n      }\n\n      context.next();\n    }\n  };\n\n  Skew.Parsing.parseIntLiteral = function(log, range) {\n    var text = range.toString();\n\n    // Parse negative signs for use with the \"--define\" flag\n    var isNegative = text.startsWith('-');\n    var start = isNegative | 0;\n    var count = text.length;\n    var doubleValue = 0;\n    var intValue = 0;\n    var base = 10;\n\n    // Parse the base\n    if ((start + 2 | 0) < count && in_string.get1(text, start) == 48) {\n      var c = in_string.get1(text, start + 1 | 0);\n\n      if (c == 98) {\n        base = 2;\n        start = start + 2 | 0;\n      }\n\n      else if (c == 111) {\n        base = 8;\n        start = start + 2 | 0;\n      }\n\n      else if (c == 120) {\n        base = 16;\n        start = start + 2 | 0;\n      }\n    }\n\n    // There must be numbers after the base\n    if (start == count) {\n      return null;\n    }\n\n    // Special-case hexadecimal since it's more complex\n    if (base == 16) {\n      for (var i = start, count1 = count; i < count1; i = i + 1 | 0) {\n        var c1 = in_string.get1(text, i);\n\n        if ((c1 < 48 || c1 > 57) && (c1 < 65 || c1 > 70) && (c1 < 97 || c1 > 102)) {\n          return null;\n        }\n\n        var delta = c1 - (c1 <= 57 ? 48 : c1 <= 70 ? 65 - 10 | 0 : 97 - 10 | 0) | 0;\n        doubleValue = doubleValue * 16 + delta;\n        intValue = __imul(intValue, 16) + delta | 0;\n      }\n    }\n\n    // All other bases are zero-relative\n    else {\n      for (var i1 = start, count2 = count; i1 < count2; i1 = i1 + 1 | 0) {\n        var delta1 = in_string.get1(text, i1) - 48 | 0;\n\n        if (delta1 < 0 || delta1 >= base) {\n          return null;\n        }\n\n        doubleValue = doubleValue * base + delta1;\n        intValue = __imul(intValue, base) + delta1 | 0;\n      }\n    }\n\n    // Integer literals are only an error if they are outside both the signed and\n    // unsigned 32-bit integer ranges. Integers here are 32-bit signed integers\n    // but it can be convenient to write literals using unsigned notation and\n    // have the compiler do the wrapping (for example, all Mach-O files use a\n    // magic number of 0xFEEDFACE).\n    if (doubleValue < -2147483648 || doubleValue > 4294967295) {\n      log.syntaxErrorIntegerLiteralTooLarge(range);\n      return new Box(intValue);\n    }\n\n    // Warn about decimal integers that start with \"0\" because other languages\n    // strangely treat these numbers as octal instead of decimal\n    if (base == 10 && intValue != 0 && in_string.get1(text, 0) == 48) {\n      log.syntaxWarningOctal(range);\n    }\n\n    return new Box(isNegative ? -intValue | 0 : intValue);\n  };\n\n  Skew.Parsing.checkExtraParentheses = function(context, node) {\n    if (node.isInsideParentheses()) {\n      context.log.syntaxWarningExtraParentheses(node.range);\n    }\n  };\n\n  Skew.Parsing._warnAboutIgnoredComments = function(context, comments) {\n    if (comments != null && context.warnAboutIgnoredComments) {\n      for (var i = 0, list = comments, count = list.length; i < count; i = i + 1 | 0) {\n        var comment = in_List.get(list, i);\n        context.log.syntaxWarningIgnoredCommentInParser(comment.range);\n      }\n    }\n  };\n\n  Skew.Parsing.parseTrailingComment = function(context) {\n    switch (context.current().kind) {\n      case Skew.TokenKind.NEWLINE:\n      case Skew.TokenKind.END_OF_FILE:\n      case Skew.TokenKind.RIGHT_PARENTHESIS:\n      case Skew.TokenKind.RIGHT_BRACE:\n      case Skew.TokenKind.RIGHT_BRACKET: {\n        return context.stealComments();\n      }\n    }\n\n    return null;\n  };\n\n  Skew.Parsing.parseAnnotations = function(context, annotations) {\n    while (context.peek1(Skew.TokenKind.ANNOTATION)) {\n      var range = context.next().range;\n      var value = new Skew.Node(Skew.NodeKind.NAME).withContent(new Skew.StringContent(range.toString())).withRange(range);\n\n      // Change \"@foo.bar.baz\" into \"foo.bar.@baz\"\n      if (context.peek1(Skew.TokenKind.DOT)) {\n        var root = value.asString();\n        value.content = new Skew.StringContent(in_string.slice1(root, 1));\n\n        while (context.eat(Skew.TokenKind.DOT)) {\n          var name = context.current().range;\n\n          if (!context.expect(Skew.TokenKind.IDENTIFIER)) {\n            break;\n          }\n\n          value = new Skew.Node(Skew.NodeKind.DOT).withContent(new Skew.StringContent(name.toString())).appendChild(value).withRange(context.spanSince(range)).withInternalRange(name);\n        }\n\n        value.content = new Skew.StringContent('@' + value.asString());\n      }\n\n      // Parse parentheses if present\n      var token = context.current();\n\n      if (context.eat(Skew.TokenKind.LEFT_PARENTHESIS)) {\n        var call = Skew.Node.createCall(value);\n        Skew.Parsing.parseCommaSeparatedList(context, call, Skew.TokenKind.RIGHT_PARENTHESIS);\n        value = call.withRange(context.spanSince(range)).withInternalRange(context.spanSince(token.range));\n      }\n\n      // Parse a trailing if condition\n      var test = null;\n\n      if (context.eat(Skew.TokenKind.IF)) {\n        test = Skew.Parsing.expressionParser.parse(context, Skew.Precedence.LOWEST);\n      }\n\n      // All annotations must end in a newline to avoid confusion with the trailing if\n      if (!context.peek1(Skew.TokenKind.LEFT_BRACE) && !context.expect(Skew.TokenKind.NEWLINE)) {\n        Skew.Parsing.scanForToken(context, Skew.TokenKind.NEWLINE);\n      }\n\n      annotations.push(Skew.Node.createAnnotation(value, test).withRange(context.spanSince(range)));\n    }\n\n    return annotations;\n  };\n\n  // When the type is present, this parses something like \"int x = 0\"\n  Skew.Parsing.parseVariables = function(context, type) {\n    var variables = new Skew.Node(Skew.NodeKind.VARIABLES);\n    var token = context.current();\n\n    // Skip \"var\" or \"const\" if present\n    if (type == null) {\n      context.next();\n    }\n\n    while (true) {\n      var range = context.current().range;\n\n      if (!context.expect(Skew.TokenKind.IDENTIFIER)) {\n        return null;\n      }\n\n      var symbol = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_LOCAL, range.toString());\n      symbol.range = range;\n\n      if (token.kind == Skew.TokenKind.CONST) {\n        symbol.flags |= Skew.SymbolFlags.IS_CONST;\n      }\n\n      if (type != null) {\n        symbol.type = type.clone();\n      }\n\n      else {\n        if (context.peek1(Skew.TokenKind.COLON)) {\n          context.log.syntaxErrorExtraColonBeforeType(context.next().range);\n        }\n\n        if (Skew.Parsing.peekType(context)) {\n          symbol.type = Skew.Parsing.typeParser.parse(context, Skew.Precedence.LOWEST);\n        }\n      }\n\n      if (context.eat(Skew.TokenKind.ASSIGN)) {\n        symbol.value = Skew.Parsing.expressionParser.parse(context, Skew.Precedence.LOWEST);\n      }\n\n      variables.appendChild(Skew.Node.createVariable(symbol).withRange(context.spanSince(range)));\n\n      if (!context.eat(Skew.TokenKind.COMMA)) {\n        break;\n      }\n    }\n\n    return variables.withRange(context.spanSince(type != null ? type.range : token.range));\n  };\n\n  Skew.Parsing.parseJump = function(context) {\n    var token = context.next();\n    return (token.kind == Skew.TokenKind.BREAK ? new Skew.Node(Skew.NodeKind.BREAK) : new Skew.Node(Skew.NodeKind.CONTINUE)).withRange(token.range);\n  };\n\n  Skew.Parsing.parseReturn = function(context) {\n    var token = context.next();\n    var value = null;\n\n    // Check for \"return;\" explicitly for a better error message\n    if (!context.skipSemicolon() && !context.peek1(Skew.TokenKind.NEWLINE) && !context.peek1(Skew.TokenKind.COMMENT) && !context.peek1(Skew.TokenKind.RIGHT_BRACE)) {\n      value = Skew.Parsing.expressionParser.parse(context, Skew.Precedence.LOWEST);\n      Skew.Parsing.checkExtraParentheses(context, value);\n    }\n\n    return Skew.Node.createReturn(value).withRange(context.spanSince(token.range));\n  };\n\n  Skew.Parsing.parseSwitch = function(context) {\n    var token = context.next();\n    var value = Skew.Parsing.expressionParser.parse(context, Skew.Precedence.LOWEST);\n    Skew.Parsing.checkExtraParentheses(context, value);\n    var node = Skew.Node.createSwitch(value);\n    context.skipWhitespace();\n\n    if (!context.expect(Skew.TokenKind.LEFT_BRACE)) {\n      return null;\n    }\n\n    context.eat(Skew.TokenKind.NEWLINE);\n\n    while (!context.peek1(Skew.TokenKind.RIGHT_BRACE)) {\n      var comments = context.stealComments();\n\n      // Ignore trailing comments\n      if (context.peek1(Skew.TokenKind.RIGHT_BRACE) || context.peek1(Skew.TokenKind.END_OF_FILE)) {\n        Skew.Parsing._warnAboutIgnoredComments(context, comments);\n        break;\n      }\n\n      // Parse a new case\n      var child = new Skew.Node(Skew.NodeKind.CASE);\n      var start = context.current();\n      var colon = null;\n\n      if (context.eat(Skew.TokenKind.CASE)) {\n        while (true) {\n          var constantComments = context.stealComments();\n          var constant = Skew.Parsing.expressionParser.parse(context, Skew.Precedence.LOWEST);\n          Skew.Parsing.checkExtraParentheses(context, constant);\n          child.appendChild(constant);\n          constant.comments = Skew.Comment.concat(constantComments, Skew.Parsing.parseTrailingComment(context));\n\n          // A colon isn't valid syntax here, but try to have a nice error message\n          if (context.peek1(Skew.TokenKind.COLON)) {\n            colon = context.next().range;\n            context.skipWhitespace();\n\n            if (context.eat(Skew.TokenKind.CASE)) {\n              context.log.syntaxErrorExpectedCommaBetweenCases(context.spanSince(colon));\n              colon = null;\n            }\n\n            else {\n              break;\n            }\n          }\n\n          // Commas separate multiple values\n          else if (!context.eat(Skew.TokenKind.COMMA)) {\n            break;\n          }\n\n          constant.comments = Skew.Comment.concat(constant.comments, Skew.Parsing.parseTrailingComment(context));\n        }\n      }\n\n      // Default cases have no values\n      else {\n        if (!context.eat(Skew.TokenKind.DEFAULT)) {\n          context.expect(Skew.TokenKind.CASE);\n          return null;\n        }\n\n        // A colon isn't valid syntax here, but try to have a nice error message\n        if (context.peek1(Skew.TokenKind.COLON)) {\n          colon = context.next().range;\n        }\n      }\n\n      var block = null;\n\n      // Use a block instead of requiring \"break\" at the end\n      if (colon == null) {\n        block = Skew.Parsing.parseBlock(context);\n\n        if (block == null) {\n          return null;\n        }\n      }\n\n      // If there was a syntax error, try to parse a C-style block\n      else {\n        var range = context.current().range;\n        block = new Skew.Node(Skew.NodeKind.BLOCK);\n\n        if (!Skew.Parsing.parseStatements(context, block, Skew.Parsing.StatementsMode.C_STYLE_SWITCH)) {\n          return null;\n        }\n\n        var breakRange = null;\n\n        if (context.peek1(Skew.TokenKind.BREAK)) {\n          breakRange = context.next().range;\n\n          if (context.skipSemicolon()) {\n            breakRange = context.spanSince(breakRange);\n          }\n        }\n\n        block.withRange(context.spanSince(range));\n        context.log.syntaxErrorColonAfterCaseOrDefault(colon, breakRange);\n        context.eat(Skew.TokenKind.NEWLINE);\n      }\n\n      // Create the case\n      node.appendChild(child.appendChild(block).withRange(context.spanSince(start.range)));\n\n      // Parse trailing comments and/or newline\n      child.comments = Skew.Comment.concat(comments, Skew.Parsing.parseTrailingComment(context));\n\n      if (context.peek1(Skew.TokenKind.RIGHT_BRACE) || colon == null && !context.expect(Skew.TokenKind.NEWLINE)) {\n        break;\n      }\n    }\n\n    if (!context.expect(Skew.TokenKind.RIGHT_BRACE)) {\n      return null;\n    }\n\n    return node.withRange(context.spanSince(token.range));\n  };\n\n  Skew.Parsing.parseFor = function(context) {\n    var token = context.next();\n    var parentheses = context.peek1(Skew.TokenKind.LEFT_PARENTHESIS) ? context.next() : null;\n\n    // Doing \"for var i = ...\" is an error\n    if (context.peek1(Skew.TokenKind.VAR)) {\n      context.log.syntaxErrorExtraVarInForLoop(context.next().range);\n    }\n\n    var initialNameRange = context.current().range;\n\n    if (!context.expect(Skew.TokenKind.IDENTIFIER)) {\n      return null;\n    }\n\n    // for a in b {}\n    if (context.eat(Skew.TokenKind.IN)) {\n      var symbol = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_LOCAL, initialNameRange.toString());\n      symbol.range = initialNameRange;\n      var value = Skew.Parsing.expressionParser.parse(context, Skew.Precedence.LOWEST);\n\n      if (context.eat(Skew.TokenKind.DOT_DOT)) {\n        var second = Skew.Parsing.expressionParser.parse(context, Skew.Precedence.LOWEST);\n        value = Skew.Node.createPair(value, second).withRange(Skew.Range.span(value.range, second.range));\n      }\n\n      Skew.Parsing.checkExtraParentheses(context, value);\n\n      // Allow parentheses around the loop header\n      if (parentheses != null) {\n        if (!context.expect(Skew.TokenKind.RIGHT_PARENTHESIS)) {\n          return null;\n        }\n\n        context.log.syntaxWarningExtraParentheses(context.spanSince(parentheses.range));\n      }\n\n      var block = Skew.Parsing.parseBlock(context);\n\n      if (block == null) {\n        return null;\n      }\n\n      return Skew.Node.createForeach(symbol, value, block).withRange(context.spanSince(token.range));\n    }\n\n    // for a = 0; a < 10; a++ {}\n    var setup = new Skew.Node(Skew.NodeKind.VARIABLES);\n    context.undo();\n\n    while (true) {\n      var nameRange = context.current().range;\n\n      if (!context.expect(Skew.TokenKind.IDENTIFIER)) {\n        return null;\n      }\n\n      var symbol1 = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_LOCAL, nameRange.toString());\n      symbol1.range = nameRange;\n\n      if (Skew.Parsing.peekType(context)) {\n        symbol1.type = Skew.Parsing.typeParser.parse(context, Skew.Precedence.LOWEST);\n      }\n\n      if (context.eat(Skew.TokenKind.ASSIGN)) {\n        symbol1.value = Skew.Parsing.expressionParser.parse(context, Skew.Precedence.LOWEST);\n        Skew.Parsing.checkExtraParentheses(context, symbol1.value);\n      }\n\n      setup.appendChild(Skew.Node.createVariable(symbol1).withRange(context.spanSince(nameRange)));\n\n      if (!context.eat(Skew.TokenKind.COMMA)) {\n        break;\n      }\n    }\n\n    setup.range = context.spanSince(initialNameRange);\n\n    if (!context.expect(Skew.TokenKind.SEMICOLON)) {\n      return null;\n    }\n\n    var test = Skew.Parsing.expressionParser.parse(context, Skew.Precedence.LOWEST);\n\n    if (!context.expect(Skew.TokenKind.SEMICOLON)) {\n      return null;\n    }\n\n    var update = Skew.Parsing.expressionParser.parse(context, Skew.Precedence.LOWEST);\n\n    // This is the one place in the grammar that sequence expressions are allowed\n    if (context.eat(Skew.TokenKind.COMMA)) {\n      update = new Skew.Node(Skew.NodeKind.SEQUENCE).appendChild(update);\n\n      while (true) {\n        var value1 = Skew.Parsing.expressionParser.parse(context, Skew.Precedence.LOWEST);\n        update.appendChild(value1);\n\n        if (!context.eat(Skew.TokenKind.COMMA)) {\n          break;\n        }\n      }\n    }\n\n    // Allow parentheses around the loop header\n    if (parentheses != null) {\n      if (!context.expect(Skew.TokenKind.RIGHT_PARENTHESIS)) {\n        return null;\n      }\n\n      context.log.syntaxWarningExtraParentheses(context.spanSince(parentheses.range));\n    }\n\n    var block1 = Skew.Parsing.parseBlock(context);\n\n    if (block1 == null) {\n      return null;\n    }\n\n    return Skew.Node.createFor(setup, test, update, block1).withRange(context.spanSince(token.range));\n  };\n\n  Skew.Parsing.parseIf = function(context) {\n    var token = context.next();\n    var test = Skew.Parsing.expressionParser.parse(context, Skew.Precedence.LOWEST);\n    Skew.Parsing.checkExtraParentheses(context, test);\n    var trueBlock = Skew.Parsing.parseBlock(context);\n\n    if (trueBlock == null) {\n      return null;\n    }\n\n    return Skew.Node.createIf(test, trueBlock, null).withRange(context.spanSince(token.range));\n  };\n\n  Skew.Parsing.parseThrow = function(context) {\n    var token = context.next();\n    var value = Skew.Parsing.expressionParser.parse(context, Skew.Precedence.LOWEST);\n    Skew.Parsing.checkExtraParentheses(context, value);\n    return Skew.Node.createThrow(value).withRange(context.spanSince(token.range));\n  };\n\n  Skew.Parsing.parseTry = function(context) {\n    var token = context.next();\n    var tryBlock = Skew.Parsing.parseBlock(context);\n\n    if (tryBlock == null) {\n      return null;\n    }\n\n    return Skew.Node.createTry(tryBlock).withRange(context.spanSince(token.range));\n  };\n\n  Skew.Parsing.parseWhile = function(context) {\n    var token = context.next();\n    var test = Skew.Parsing.expressionParser.parse(context, Skew.Precedence.LOWEST);\n    Skew.Parsing.checkExtraParentheses(context, test);\n    var block = Skew.Parsing.parseBlock(context);\n\n    if (block == null) {\n      return null;\n    }\n\n    return new Skew.Node(Skew.NodeKind.WHILE).appendChild(test).appendChild(block).withRange(context.spanSince(token.range));\n  };\n\n  Skew.Parsing.parseStatement = function(context) {\n    var token = context.current();\n\n    switch (token.kind) {\n      case Skew.TokenKind.BREAK:\n      case Skew.TokenKind.CONTINUE: {\n        return Skew.Parsing.parseJump(context);\n      }\n\n      case Skew.TokenKind.CONST:\n      case Skew.TokenKind.VAR: {\n        return Skew.Parsing.parseVariables(context, null);\n      }\n\n      case Skew.TokenKind.FOR: {\n        return Skew.Parsing.parseFor(context);\n      }\n\n      case Skew.TokenKind.IF: {\n        return Skew.Parsing.parseIf(context);\n      }\n\n      case Skew.TokenKind.RETURN: {\n        return Skew.Parsing.parseReturn(context);\n      }\n\n      case Skew.TokenKind.SWITCH: {\n        return Skew.Parsing.parseSwitch(context);\n      }\n\n      case Skew.TokenKind.THROW: {\n        return Skew.Parsing.parseThrow(context);\n      }\n\n      case Skew.TokenKind.TRY: {\n        return Skew.Parsing.parseTry(context);\n      }\n\n      case Skew.TokenKind.WHILE: {\n        return Skew.Parsing.parseWhile(context);\n      }\n    }\n\n    var value = Skew.Parsing.expressionParser.parse(context, Skew.Precedence.LOWEST);\n    Skew.Parsing.checkExtraParentheses(context, value);\n\n    // A special case for better errors when users try to use C-style variable declarations\n    if (!value.isInsideParentheses() && Skew.Parsing.looksLikeType(value) && context.peek1(Skew.TokenKind.IDENTIFIER) && context.canReportSyntaxError()) {\n      context.log.syntaxErrorVariableDeclarationNeedsVar(value.range, context.current().range);\n      return Skew.Parsing.parseVariables(context, value);\n    }\n\n    var node = Skew.Node.createExpression(value).withRange(value.range);\n    return node;\n  };\n\n  Skew.Parsing.looksLikeType = function(node) {\n    var kind = node.kind;\n    return kind == Skew.NodeKind.NAME || kind == Skew.NodeKind.TYPE || kind == Skew.NodeKind.LAMBDA_TYPE || kind == Skew.NodeKind.DOT && node.dotTarget() != null && Skew.Parsing.looksLikeType(node.dotTarget()) || kind == Skew.NodeKind.PARAMETERIZE && Skew.Parsing.looksLikeType(node.parameterizeValue());\n  };\n\n  Skew.Parsing.parseStatements = function(context, parent, mode) {\n    var previous = null;\n    var leading = Skew.Parsing.parseTrailingComment(context);\n    context.eat(Skew.TokenKind.NEWLINE);\n\n    while (!context.peek1(Skew.TokenKind.RIGHT_BRACE) && !context.peek1(Skew.TokenKind.XML_START_CLOSE) && !context.peek1(Skew.TokenKind.END_OF_FILE)) {\n      // The block may start with a trailing comment\n      var comments = Skew.Comment.concat(leading, context.stealComments());\n      leading = null;\n\n      // When parsing a C-style switch, stop if it looks like the end of the case\n      if (mode == Skew.Parsing.StatementsMode.C_STYLE_SWITCH && (context.peek1(Skew.TokenKind.CASE) || context.peek1(Skew.TokenKind.DEFAULT) || context.peek1(Skew.TokenKind.BREAK))) {\n        Skew.Parsing._warnAboutIgnoredComments(context, comments);\n        break;\n      }\n\n      // Merge \"else\" statements with the previous \"if\"\n      if (context.peek1(Skew.TokenKind.ELSE)) {\n        var isValid = previous != null && previous.kind == Skew.NodeKind.IF && previous.ifFalse() == null;\n\n        if (!isValid) {\n          context.unexpectedToken();\n        }\n\n        context.next();\n\n        // Match \"else if\"\n        if (context.peek1(Skew.TokenKind.IF)) {\n          var statement = Skew.Parsing.parseIf(context);\n\n          if (statement == null) {\n            return false;\n          }\n\n          // Append to the if statement\n          var falseBlock = new Skew.Node(Skew.NodeKind.BLOCK).withRange(statement.range).appendChild(statement);\n          falseBlock.comments = comments;\n\n          if (isValid) {\n            previous.appendChild(falseBlock);\n            previous = statement;\n          }\n\n          else {\n            previous = null;\n          }\n        }\n\n        // Match \"else\"\n        else {\n          var falseBlock1 = Skew.Parsing.parseBlock(context);\n\n          if (falseBlock1 == null) {\n            return false;\n          }\n\n          // Append to the if statement\n          falseBlock1.comments = comments;\n\n          if (isValid) {\n            previous.appendChild(falseBlock1);\n            previous = falseBlock1;\n          }\n\n          else {\n            previous = null;\n          }\n        }\n      }\n\n      // Merge \"catch\" statements with the previous \"try\"\n      else if (context.peek1(Skew.TokenKind.CATCH)) {\n        var isValid1 = previous != null && previous.kind == Skew.NodeKind.TRY && previous.finallyBlock() == null;\n\n        if (!isValid1) {\n          context.unexpectedToken();\n        }\n\n        var catchToken = context.next();\n        var symbol = null;\n        var nameRange = context.current().range;\n\n        // Optional typed variable\n        if (context.eat(Skew.TokenKind.IDENTIFIER)) {\n          symbol = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_LOCAL, nameRange.toString());\n          symbol.range = nameRange;\n          symbol.type = Skew.Parsing.typeParser.parse(context, Skew.Precedence.LOWEST);\n        }\n\n        // Parse the block\n        var catchBlock = Skew.Parsing.parseBlock(context);\n\n        if (catchBlock == null) {\n          return false;\n        }\n\n        // Append to the try statement\n        var child = Skew.Node.createCatch(symbol, catchBlock).withRange(context.spanSince(catchToken.range));\n        child.comments = comments;\n\n        if (isValid1) {\n          previous.appendChild(child);\n        }\n\n        else {\n          previous = null;\n        }\n      }\n\n      // Merge \"finally\" statements with the previous \"try\"\n      else if (context.peek1(Skew.TokenKind.FINALLY)) {\n        var isValid2 = previous != null && previous.kind == Skew.NodeKind.TRY && previous.finallyBlock() == null;\n\n        if (!isValid2) {\n          context.unexpectedToken();\n        }\n\n        context.next();\n\n        // Parse the block\n        var finallyBlock = Skew.Parsing.parseBlock(context);\n\n        if (finallyBlock == null) {\n          return false;\n        }\n\n        // Append to the try statement\n        finallyBlock.comments = comments;\n\n        if (isValid2) {\n          previous.appendChild(finallyBlock);\n        }\n\n        else {\n          previous = null;\n        }\n      }\n\n      // Parse a new statement\n      else {\n        var current = context.current();\n        var statement1 = Skew.Parsing.parseStatement(context);\n\n        if (statement1 == null) {\n          Skew.Parsing.scanForToken(context, Skew.TokenKind.NEWLINE);\n          continue;\n        }\n\n        // Prevent an infinite loop due to a syntax error at the start of an expression\n        if (context.current() == current) {\n          context.next();\n        }\n\n        previous = statement1;\n        statement1.comments = comments;\n        parent.appendChild(statement1);\n      }\n\n      // Special-case semicolons before comments for better parser recovery\n      var semicolon = context.skipSemicolon();\n\n      // Parse trailing comments and/or newline\n      var trailing = Skew.Parsing.parseTrailingComment(context);\n\n      if (trailing != null) {\n        if (previous != null) {\n          previous.comments = Skew.Comment.concat(previous.comments, trailing);\n        }\n\n        else {\n          Skew.Parsing._warnAboutIgnoredComments(context, trailing);\n        }\n      }\n\n      if (context.peek1(Skew.TokenKind.RIGHT_BRACE) || context.peek1(Skew.TokenKind.XML_START_CLOSE)) {\n        break;\n      }\n\n      else if (!context.peek1(Skew.TokenKind.ELSE) && !context.peek1(Skew.TokenKind.CATCH) && !context.peek1(Skew.TokenKind.FINALLY)) {\n        if (semicolon) {\n          context.eat(Skew.TokenKind.NEWLINE);\n        }\n\n        else {\n          context.expect(Skew.TokenKind.NEWLINE);\n        }\n      }\n    }\n\n    // Convert trailing comments to blocks\n    var comments1 = Skew.Comment.concat(leading, context.stealComments());\n\n    if (comments1 != null) {\n      parent.appendChild(new Skew.Node(Skew.NodeKind.COMMENT_BLOCK).withComments(comments1));\n    }\n\n    return true;\n  };\n\n  Skew.Parsing.parseBlock = function(context) {\n    context.skipWhitespace();\n    var comments = context.stealComments();\n    var token = context.current();\n\n    if (!context.expect(Skew.TokenKind.LEFT_BRACE)) {\n      // Return a block to try to recover and continue parsing\n      return new Skew.Node(Skew.NodeKind.BLOCK);\n    }\n\n    var block = new Skew.Node(Skew.NodeKind.BLOCK);\n\n    if (!Skew.Parsing.parseStatements(context, block, Skew.Parsing.StatementsMode.NORMAL) || !context.expect(Skew.TokenKind.RIGHT_BRACE)) {\n      return null;\n    }\n\n    return block.withRange(context.spanSince(token.range)).withComments(comments);\n  };\n\n  Skew.Parsing.peekType = function(context) {\n    return context.peek1(Skew.TokenKind.IDENTIFIER) || context.peek1(Skew.TokenKind.DYNAMIC);\n  };\n\n  Skew.Parsing.parseFunctionBlock = function(context, symbol) {\n    // \"=> x\" is the same as \"{ return x }\"\n    if (symbol.kind == Skew.SymbolKind.FUNCTION_LOCAL) {\n      if (!context.expect(Skew.TokenKind.ARROW)) {\n        return false;\n      }\n\n      if (context.peek1(Skew.TokenKind.LEFT_BRACE)) {\n        symbol.block = Skew.Parsing.parseBlock(context);\n\n        if (symbol.block == null) {\n          return false;\n        }\n      }\n\n      else {\n        var value = Skew.Parsing.expressionParser.parse(context, Skew.Precedence.LOWEST);\n        symbol.block = new Skew.Node(Skew.NodeKind.BLOCK).withRange(value.range).appendChild(Skew.Node.createReturn(value).withRange(value.range).withFlags(Skew.NodeFlags.IS_IMPLICIT_RETURN));\n      }\n    }\n\n    // Parse function body if present\n    else if (context.peek1(Skew.TokenKind.LEFT_BRACE)) {\n      symbol.block = Skew.Parsing.parseBlock(context);\n\n      if (symbol.block == null) {\n        return false;\n      }\n    }\n\n    return true;\n  };\n\n  Skew.Parsing.parseFunctionArguments = function(context, symbol) {\n    var leading = Skew.Parsing.parseTrailingComment(context);\n    var usingTypes = false;\n\n    while (!context.eat(Skew.TokenKind.RIGHT_PARENTHESIS)) {\n      context.skipWhitespace();\n      var comments = Skew.Comment.concat(leading, context.stealComments());\n      leading = null;\n      var range = context.current().range;\n\n      if (!context.expect(Skew.TokenKind.IDENTIFIER)) {\n        Skew.Parsing.scanForToken(context, Skew.TokenKind.RIGHT_PARENTHESIS);\n        break;\n      }\n\n      var arg = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_ARGUMENT, range.toString());\n      arg.range = range;\n\n      // Parse argument type\n      if (symbol.kind != Skew.SymbolKind.FUNCTION_LOCAL || (symbol.$arguments.length == 0 ? Skew.Parsing.peekType(context) || context.peek1(Skew.TokenKind.COLON) : usingTypes)) {\n        if (context.peek1(Skew.TokenKind.COLON)) {\n          context.log.syntaxErrorExtraColonBeforeType(context.next().range);\n        }\n\n        arg.type = Skew.Parsing.typeParser.parse(context, Skew.Precedence.LOWEST);\n        usingTypes = true;\n      }\n\n      // Optional arguments aren't supported yet\n      var assign = context.current().range;\n\n      if (context.eat(Skew.TokenKind.ASSIGN)) {\n        Skew.Parsing.expressionParser.parse(context, Skew.Precedence.LOWEST);\n        context.log.syntaxErrorOptionalArgument(context.spanSince(assign));\n      }\n\n      symbol.$arguments.push(arg);\n\n      if (!context.peek1(Skew.TokenKind.RIGHT_PARENTHESIS)) {\n        if (!context.expect(Skew.TokenKind.COMMA)) {\n          Skew.Parsing.scanForToken(context, Skew.TokenKind.RIGHT_PARENTHESIS);\n          break;\n        }\n      }\n\n      arg.comments = Skew.Comment.concat(comments, Skew.Parsing.parseTrailingComment(context));\n    }\n\n    return true;\n  };\n\n  Skew.Parsing.parseFunctionReturnTypeAndBlock = function(context, symbol) {\n    if (context.peek1(Skew.TokenKind.COLON)) {\n      context.log.syntaxErrorExtraColonBeforeType(context.next().range);\n    }\n\n    if (Skew.Parsing.peekType(context)) {\n      symbol.returnType = Skew.Parsing.typeParser.parse(context, Skew.Precedence.LOWEST);\n    }\n\n    if (context.peek1(Skew.TokenKind.NEWLINE) && context.peek2(Skew.TokenKind.LEFT_BRACE, 1)) {\n      context.next();\n    }\n\n    return Skew.Parsing.parseFunctionBlock(context, symbol);\n  };\n\n  Skew.Parsing.parseTypeParameters = function(context, kind) {\n    var parameters = [];\n\n    while (true) {\n      var range = context.current().range;\n      var name = range.toString();\n\n      if (!context.expect(Skew.TokenKind.IDENTIFIER)) {\n        return null;\n      }\n\n      var symbol = new Skew.ParameterSymbol(kind, name);\n      symbol.range = range;\n      parameters.push(symbol);\n\n      if (!context.eat(Skew.TokenKind.COMMA)) {\n        break;\n      }\n    }\n\n    if (!context.expect(Skew.TokenKind.PARAMETER_LIST_END)) {\n      return null;\n    }\n\n    return parameters;\n  };\n\n  Skew.Parsing.parseAfterBlock = function(context) {\n    // Check for  \";\" explicitly for a better error message\n    context.skipSemicolon();\n    return context.peek1(Skew.TokenKind.END_OF_FILE) || context.peek1(Skew.TokenKind.RIGHT_BRACE) || context.expect(Skew.TokenKind.NEWLINE);\n  };\n\n  Skew.Parsing.recursiveParseGuard = function(context, parent, annotations) {\n    var test = null;\n\n    if (context.eat(Skew.TokenKind.IF)) {\n      test = Skew.Parsing.expressionParser.parse(context, Skew.Precedence.LOWEST);\n    }\n\n    if (!context.expect(Skew.TokenKind.LEFT_BRACE)) {\n      return null;\n    }\n\n    var contents = new Skew.ObjectSymbol(parent.kind, '<conditional>');\n    contents.flags |= Skew.SymbolFlags.IS_GUARD_CONDITIONAL;\n    contents.parent = parent;\n    Skew.Parsing.parseSymbols(context, contents, annotations);\n\n    if (!context.expect(Skew.TokenKind.RIGHT_BRACE) || !context.peek1(Skew.TokenKind.ELSE) && !Skew.Parsing.parseAfterBlock(context)) {\n      return null;\n    }\n\n    var elseGuard = null;\n\n    if (context.eat(Skew.TokenKind.ELSE)) {\n      elseGuard = Skew.Parsing.recursiveParseGuard(context, parent, annotations);\n\n      if (elseGuard == null) {\n        return null;\n      }\n    }\n\n    return new Skew.Guard(parent, test, contents, elseGuard);\n  };\n\n  Skew.Parsing.parseSymbol = function(context, parent, annotations) {\n    // Parse comments before the symbol declaration\n    var comments = context.stealComments();\n\n    // Ignore trailing comments\n    if (context.peek1(Skew.TokenKind.RIGHT_BRACE) || context.peek1(Skew.TokenKind.END_OF_FILE)) {\n      Skew.Parsing._warnAboutIgnoredComments(context, comments);\n      return false;\n    }\n\n    // Parse a compile-time if statement\n    if (context.peek1(Skew.TokenKind.IF)) {\n      Skew.Parsing._warnAboutIgnoredComments(context, comments);\n      var guard = Skew.Parsing.recursiveParseGuard(context, parent, annotations);\n\n      if (guard == null) {\n        return false;\n      }\n\n      if (parent.guards == null) {\n        parent.guards = [];\n      }\n\n      parent.guards.push(guard);\n      return true;\n    }\n\n    // Parse annotations before the symbol declaration\n    if (context.peek1(Skew.TokenKind.ANNOTATION)) {\n      annotations = Skew.Parsing.parseAnnotations(context, annotations != null ? annotations.slice() : []);\n\n      // Parse an annotation block\n      if (context.eat(Skew.TokenKind.LEFT_BRACE)) {\n        Skew.Parsing._warnAboutIgnoredComments(context, comments);\n        Skew.Parsing.parseSymbols(context, parent, annotations);\n        return context.expect(Skew.TokenKind.RIGHT_BRACE) && Skew.Parsing.parseAfterBlock(context);\n      }\n    }\n\n    var token = context.current();\n    var tokenKind = token.kind;\n    var text = token.range.toString();\n    var wasCorrected = false;\n    var symbol = null;\n    var kind = in_StringMap.get(Skew.Parsing.identifierToSymbolKind, text, Skew.SymbolKind.OBJECT_GLOBAL);\n\n    // Skip extra identifiers such as \"public\" in \"public var x = 0\"\n    while (tokenKind == Skew.TokenKind.IDENTIFIER && kind == Skew.SymbolKind.OBJECT_GLOBAL && (context.peek2(Skew.TokenKind.IDENTIFIER, 1) || context.peek2(Skew.TokenKind.VAR, 1) || context.peek2(Skew.TokenKind.CONST, 1))) {\n      switch (text) {\n        case 'static': {\n          context.log.syntaxErrorStaticKeyword(token.range, parent.kind, parent.name);\n          break;\n        }\n\n        case 'public': {\n          context.log.syntaxErrorPublicKeyword(token.range);\n          break;\n        }\n\n        case 'protected':\n        case 'private': {\n          context.log.syntaxErrorPrivateOrProtected(token.range);\n          break;\n        }\n\n        default: {\n          context.unexpectedToken();\n          break;\n        }\n      }\n\n      context.next();\n      token = context.current();\n      tokenKind = token.kind;\n      text = token.range.toString();\n      kind = in_StringMap.get(Skew.Parsing.identifierToSymbolKind, text, Skew.SymbolKind.OBJECT_GLOBAL);\n    }\n\n    // Special-case a top-level \"x = 0\" and \"x: int = 0\" but avoid trying to make \"def =() {}\" into a variable\n    if (tokenKind == Skew.TokenKind.IDENTIFIER && (context.peek2(Skew.TokenKind.ASSIGN, 1) && (!context.peek2(Skew.TokenKind.LEFT_PARENTHESIS, 2) || text != 'def') || context.peek2(Skew.TokenKind.COLON, 1) && context.peek2(Skew.TokenKind.IDENTIFIER, 2))) {\n      context.log.syntaxErrorMissingVar(token.range);\n      tokenKind = Skew.TokenKind.VAR;\n      wasCorrected = true;\n    }\n\n    // Special-case a top-level \"x() {}\"\n    else if (tokenKind == Skew.TokenKind.IDENTIFIER && context.peek2(Skew.TokenKind.LEFT_PARENTHESIS, 1)) {\n      context.log.syntaxErrorMissingDef(token.range);\n      tokenKind = Skew.TokenKind.IDENTIFIER;\n      kind = Skew.SymbolKind.FUNCTION_GLOBAL;\n      text = 'def';\n      wasCorrected = true;\n    }\n\n    // Special-case enum and flags symbols\n    if (Skew.in_SymbolKind.isEnumOrFlags(parent.kind) && tokenKind == Skew.TokenKind.IDENTIFIER && kind == Skew.SymbolKind.OBJECT_GLOBAL) {\n      while (true) {\n        if (Skew.Parsing.identifierToSymbolKind.has(text) || !context.expect(Skew.TokenKind.IDENTIFIER)) {\n          break;\n        }\n\n        var variable = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_ENUM_OR_FLAGS, text);\n        variable.range = token.range;\n        variable.parent = parent;\n        variable.flags |= Skew.SymbolFlags.IS_CONST;\n        parent.variables.push(variable);\n        symbol = variable;\n        var comma = context.current();\n\n        if (!context.eat(Skew.TokenKind.COMMA)) {\n          break;\n        }\n\n        variable.annotations = annotations != null ? annotations.slice() : null;\n        variable.comments = comments;\n        token = context.current();\n        text = token.range.toString();\n\n        if (context.peek1(Skew.TokenKind.NEWLINE) || context.peek1(Skew.TokenKind.RIGHT_BRACE)) {\n          context.log.syntaxWarningExtraComma(comma.range);\n          break;\n        }\n      }\n    }\n\n    else {\n      // Parse the symbol kind\n      switch (tokenKind) {\n        case Skew.TokenKind.CONST:\n        case Skew.TokenKind.VAR: {\n          kind = Skew.in_SymbolKind.hasInstances(parent.kind) ? Skew.SymbolKind.VARIABLE_INSTANCE : Skew.SymbolKind.VARIABLE_GLOBAL;\n          break;\n        }\n\n        // For symbol kinds that can't live inside functions, use contextual\n        // keywords instead of special keyword tokens. This means these names\n        // are still available to be used as regular symbols:\n        //\n        //   class div {\n        //     var class = \"\"\n        //   }\n        //\n        //   var example = <div class=\"header\"/>\n        //\n        case Skew.TokenKind.IDENTIFIER: {\n          if (kind == Skew.SymbolKind.OBJECT_GLOBAL) {\n            context.unexpectedToken();\n            return false;\n          }\n\n          if (kind == Skew.SymbolKind.FUNCTION_GLOBAL && Skew.in_SymbolKind.hasInstances(parent.kind)) {\n            kind = Skew.SymbolKind.FUNCTION_INSTANCE;\n          }\n          break;\n        }\n\n        default: {\n          context.unexpectedToken();\n          return false;\n        }\n      }\n\n      if (!wasCorrected) {\n        context.next();\n      }\n\n      var nameToken = context.current();\n      var range = nameToken.range;\n      var name = range.toString();\n      var isOperator = false;\n\n      // Only check for custom operators for instance functions\n      if (kind == Skew.SymbolKind.FUNCTION_INSTANCE) {\n        if (Skew.Parsing.customOperators.has(nameToken.kind)) {\n          isOperator = true;\n        }\n\n        else if (Skew.Parsing.forbiddenCustomOperators.has(nameToken.kind)) {\n          context.log.syntaxErrorBadOperatorCustomization(range, nameToken.kind, in_IntMap.get1(Skew.Parsing.forbiddenGroupDescription, in_IntMap.get1(Skew.Parsing.forbiddenCustomOperators, nameToken.kind)));\n          isOperator = true;\n        }\n      }\n\n      // Parse the symbol name\n      if (isOperator) {\n        context.next();\n      }\n\n      else if (kind == Skew.SymbolKind.FUNCTION_GLOBAL && context.eat(Skew.TokenKind.ANNOTATION)) {\n        kind = Skew.SymbolKind.FUNCTION_ANNOTATION;\n      }\n\n      else if (context.eat(Skew.TokenKind.LIST_NEW) || context.eat(Skew.TokenKind.SET_NEW)) {\n        if (kind == Skew.SymbolKind.FUNCTION_INSTANCE) {\n          kind = Skew.SymbolKind.FUNCTION_CONSTRUCTOR;\n        }\n      }\n\n      else {\n        if (!context.expect(Skew.TokenKind.IDENTIFIER)) {\n          return false;\n        }\n\n        if (kind == Skew.SymbolKind.FUNCTION_INSTANCE && name == 'new') {\n          kind = Skew.SymbolKind.FUNCTION_CONSTRUCTOR;\n        }\n      }\n\n      // Parse shorthand nested namespace declarations\n      if (Skew.in_SymbolKind.isObject(kind)) {\n        while (context.eat(Skew.TokenKind.DOT)) {\n          var nextToken = context.current();\n\n          if (!context.expect(Skew.TokenKind.IDENTIFIER)) {\n            return false;\n          }\n\n          // Wrap this declaration in a namespace\n          var nextParent = new Skew.ObjectSymbol(Skew.SymbolKind.OBJECT_NAMESPACE, name);\n          nextParent.range = range;\n          nextParent.parent = parent;\n          parent.objects.push(nextParent);\n          parent = nextParent;\n\n          // Update the declaration token\n          nameToken = nextToken;\n          range = nextToken.range;\n          name = range.toString();\n        }\n      }\n\n      // Parse the symbol body\n      switch (kind) {\n        case Skew.SymbolKind.VARIABLE_GLOBAL:\n        case Skew.SymbolKind.VARIABLE_INSTANCE: {\n          while (true) {\n            var variable1 = new Skew.VariableSymbol(kind, name);\n            variable1.range = range;\n            variable1.parent = parent;\n\n            if (tokenKind == Skew.TokenKind.CONST) {\n              variable1.flags |= Skew.SymbolFlags.IS_CONST;\n            }\n\n            if (context.peek1(Skew.TokenKind.COLON)) {\n              context.log.syntaxErrorExtraColonBeforeType(context.next().range);\n            }\n\n            if (Skew.Parsing.peekType(context)) {\n              variable1.type = Skew.Parsing.typeParser.parse(context, Skew.Precedence.LOWEST);\n            }\n\n            if (context.eat(Skew.TokenKind.ASSIGN)) {\n              variable1.value = Skew.Parsing.expressionParser.parse(context, Skew.Precedence.LOWEST);\n              Skew.Parsing.checkExtraParentheses(context, variable1.value);\n            }\n\n            parent.variables.push(variable1);\n\n            if (!context.eat(Skew.TokenKind.COMMA)) {\n              symbol = variable1;\n              break;\n            }\n\n            variable1.annotations = annotations != null ? annotations.slice() : null;\n            variable1.comments = comments;\n            nameToken = context.current();\n            range = nameToken.range;\n            name = range.toString();\n\n            if (!context.expect(Skew.TokenKind.IDENTIFIER)) {\n              return false;\n            }\n          }\n          break;\n        }\n\n        case Skew.SymbolKind.FUNCTION_ANNOTATION:\n        case Skew.SymbolKind.FUNCTION_CONSTRUCTOR:\n        case Skew.SymbolKind.FUNCTION_GLOBAL:\n        case Skew.SymbolKind.FUNCTION_INSTANCE: {\n          var $function = new Skew.FunctionSymbol(kind, name);\n          $function.range = range;\n          $function.parent = parent;\n\n          if (text == 'over') {\n            $function.flags |= Skew.SymbolFlags.IS_OVER;\n          }\n\n          // Check for setters like \"def foo=(x int) {}\" but don't allow a space\n          // between the name and the assignment operator\n          if (kind != Skew.SymbolKind.FUNCTION_ANNOTATION && nameToken.kind == Skew.TokenKind.IDENTIFIER && context.peek1(Skew.TokenKind.ASSIGN) && context.current().range.start == nameToken.range.end) {\n            $function.range = Skew.Range.span($function.range, context.next().range);\n            $function.flags |= Skew.SymbolFlags.IS_SETTER;\n            $function.name += '=';\n          }\n\n          // Parse type parameters\n          if (context.eat(Skew.TokenKind.PARAMETER_LIST_START)) {\n            $function.parameters = Skew.Parsing.parseTypeParameters(context, Skew.SymbolKind.PARAMETER_FUNCTION);\n\n            if ($function.parameters == null) {\n              return false;\n            }\n          }\n\n          // Parse function arguments\n          var before = context.current();\n\n          if (context.eat(Skew.TokenKind.LEFT_PARENTHESIS)) {\n            if (!Skew.Parsing.parseFunctionArguments(context, $function)) {\n              return false;\n            }\n\n            // Functions without arguments are \"getters\" and don't use parentheses\n            if ($function.$arguments.length == 0) {\n              context.log.syntaxErrorEmptyFunctionParentheses(context.spanSince(before.range));\n            }\n          }\n\n          if (kind != Skew.SymbolKind.FUNCTION_ANNOTATION && !Skew.Parsing.parseFunctionReturnTypeAndBlock(context, $function)) {\n            return false;\n          }\n\n          // Don't mark operators as getters to avoid confusion with unary operators and compiler-generated call expressions\n          if (!isOperator && $function.$arguments.length == 0) {\n            $function.flags |= Skew.SymbolFlags.IS_GETTER;\n          }\n\n          parent.functions.push($function);\n          symbol = $function;\n          break;\n        }\n\n        case Skew.SymbolKind.OBJECT_CLASS:\n        case Skew.SymbolKind.OBJECT_ENUM:\n        case Skew.SymbolKind.OBJECT_FLAGS:\n        case Skew.SymbolKind.OBJECT_INTERFACE:\n        case Skew.SymbolKind.OBJECT_NAMESPACE:\n        case Skew.SymbolKind.OBJECT_WRAPPED: {\n          var object = new Skew.ObjectSymbol(kind, name);\n          object.range = range;\n          object.parent = parent;\n\n          if (kind != Skew.SymbolKind.OBJECT_NAMESPACE && context.eat(Skew.TokenKind.PARAMETER_LIST_START)) {\n            object.parameters = Skew.Parsing.parseTypeParameters(context, Skew.SymbolKind.PARAMETER_OBJECT);\n\n            if (object.parameters == null) {\n              return false;\n            }\n          }\n\n          // Allow \"type Foo = int\"\n          if (kind == Skew.SymbolKind.OBJECT_WRAPPED && context.eat(Skew.TokenKind.ASSIGN)) {\n            object.$extends = Skew.Parsing.typeParser.parse(context, Skew.Precedence.LOWEST);\n\n            if (object.$extends == null) {\n              return false;\n            }\n          }\n\n          // Regular block structure \"type Foo : int {}\"\n          else {\n            // Base class\n            var isExtends = context.peek1(Skew.TokenKind.IDENTIFIER) && context.current().range.toString() == 'extends';\n\n            if (isExtends) {\n              context.log.syntaxErrorExtendsKeyword(context.next().range);\n            }\n\n            if (isExtends || context.eat(Skew.TokenKind.COLON)) {\n              object.$extends = Skew.Parsing.typeParser.parse(context, Skew.Precedence.LOWEST);\n\n              if (object.$extends == null) {\n                return false;\n              }\n            }\n\n            // Interfaces\n            var isImplements = context.peek1(Skew.TokenKind.IDENTIFIER) && context.current().range.toString() == 'implements';\n\n            if (isImplements) {\n              context.log.syntaxErrorImplementsKeyword(context.next().range);\n            }\n\n            if (isImplements || context.eat(Skew.TokenKind.DOUBLE_COLON)) {\n              object.$implements = [];\n\n              while (true) {\n                var type = Skew.Parsing.typeParser.parse(context, Skew.Precedence.LOWEST);\n                object.$implements.push(type);\n\n                if (!context.eat(Skew.TokenKind.COMMA)) {\n                  break;\n                }\n              }\n            }\n\n            context.skipWhitespace();\n\n            if (!context.expect(Skew.TokenKind.LEFT_BRACE)) {\n              Skew.Parsing.scanForToken(context, Skew.TokenKind.LEFT_BRACE);\n            }\n\n            Skew.Parsing.parseSymbols(context, object, null);\n            object.commentsInsideEndOfBlock = context.stealComments();\n\n            if (!context.expect(Skew.TokenKind.RIGHT_BRACE)) {\n              return false;\n            }\n          }\n\n          parent.objects.push(object);\n          symbol = object;\n          break;\n        }\n\n        default: {\n          assert(false);\n          break;\n        }\n      }\n\n      // Forbid certain kinds of symbols inside certain object types\n      if ((Skew.in_SymbolKind.isEnumOrFlags(parent.kind) || parent.kind == Skew.SymbolKind.OBJECT_WRAPPED || parent.kind == Skew.SymbolKind.OBJECT_INTERFACE) && (kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR || kind == Skew.SymbolKind.VARIABLE_INSTANCE)) {\n        context.log.syntaxErrorBadDeclarationInsideType(context.spanSince(token.range));\n      }\n    }\n\n    symbol.annotations = annotations != null ? annotations.slice() : null;\n    symbol.comments = Skew.Comment.concat(comments, Skew.Parsing.parseTrailingComment(context));\n\n    if (!Skew.Parsing.parseAfterBlock(context)) {\n      return false;\n    }\n\n    return true;\n  };\n\n  Skew.Parsing.parseSymbols = function(context, parent, annotations) {\n    context.eat(Skew.TokenKind.NEWLINE);\n\n    while (!context.peek1(Skew.TokenKind.END_OF_FILE) && !context.peek1(Skew.TokenKind.RIGHT_BRACE)) {\n      if (!Skew.Parsing.parseSymbol(context, parent, annotations)) {\n        break;\n      }\n    }\n  };\n\n  Skew.Parsing.parseCommaSeparatedList = function(context, parent, stop) {\n    var isFirst = true;\n    var leading = Skew.Parsing.parseTrailingComment(context);\n    context.skipWhitespace();\n\n    while (true) {\n      var comments = Skew.Comment.concat(leading, context.stealComments());\n      leading = null;\n\n      if (isFirst && context.eat(stop)) {\n        Skew.Parsing._warnAboutIgnoredComments(context, comments);\n        break;\n      }\n\n      var value = Skew.Parsing.expressionParser.parse(context, Skew.Precedence.LOWEST);\n      value.comments = Skew.Comment.concat(comments, Skew.Parsing.parseTrailingComment(context));\n      context.skipWhitespace();\n      parent.appendChild(value);\n\n      if (context.eat(stop)) {\n        break;\n      }\n\n      if (!context.expect(Skew.TokenKind.COMMA)) {\n        Skew.Parsing.scanForToken(context, stop);\n        break;\n      }\n\n      value.comments = Skew.Comment.concat(value.comments, Skew.Parsing.parseTrailingComment(context));\n      context.skipWhitespace();\n      isFirst = false;\n    }\n  };\n\n  Skew.Parsing.parseHexCharacter = function(c) {\n    if (c >= 48 && c <= 57) {\n      return c - 48 | 0;\n    }\n\n    if (c >= 65 && c <= 70) {\n      return (c - 65 | 0) + 10 | 0;\n    }\n\n    if (c >= 97 && c <= 102) {\n      return (c - 97 | 0) + 10 | 0;\n    }\n\n    return -1;\n  };\n\n  Skew.Parsing.createStringNode = function(log, range) {\n    return new Skew.Node(Skew.NodeKind.CONSTANT).withContent(new Skew.StringContent(Skew.Parsing.parseStringLiteral(log, range))).withRange(range);\n  };\n\n  Skew.Parsing.parseStringLiteral = function(log, range) {\n    var text = range.toString();\n    var count = text.length;\n    assert(count >= 2);\n    assert(in_string.get1(text, 0) == 34 || in_string.get1(text, 0) == 39 || in_string.get1(text, 0) == 41);\n    assert(in_string.get1(text, count - 1 | 0) == 34 || in_string.get1(text, count - 1 | 0) == 39 || in_string.get1(text, count - 1 | 0) == 40);\n    var builder = new StringBuilder();\n    var start = 1;\n    var stop = count - (in_string.get1(text, count - 1 | 0) == 40 ? 2 : 1) | 0;\n    var i = start;\n\n    while (i < stop) {\n      var c = in_string.get1(text, (i = i + 1 | 0) + -1 | 0);\n\n      if (c == 92) {\n        var escape = i - 1 | 0;\n        builder.buffer += in_string.slice2(text, start, escape);\n\n        if (i < stop) {\n          c = in_string.get1(text, (i = i + 1 | 0) + -1 | 0);\n\n          if (c == 110) {\n            builder.buffer += '\\n';\n            start = i;\n          }\n\n          else if (c == 114) {\n            builder.buffer += '\\r';\n            start = i;\n          }\n\n          else if (c == 116) {\n            builder.buffer += '\\t';\n            start = i;\n          }\n\n          else if (c == 48) {\n            builder.buffer += '\\0';\n            start = i;\n          }\n\n          else if (c == 92 || c == 34 || c == 39) {\n            builder.buffer += String.fromCharCode(c);\n            start = i;\n          }\n\n          else if (c == 120) {\n            if (i < stop) {\n              var c0 = Skew.Parsing.parseHexCharacter(in_string.get1(text, (i = i + 1 | 0) + -1 | 0));\n\n              if (i < stop) {\n                var c1 = Skew.Parsing.parseHexCharacter(in_string.get1(text, (i = i + 1 | 0) + -1 | 0));\n\n                if (c0 != -1 && c1 != -1) {\n                  builder.buffer += String.fromCharCode(c0 << 4 | c1);\n                  start = i;\n                }\n              }\n            }\n          }\n        }\n\n        if (start < i) {\n          log.syntaxErrorInvalidEscapeSequence(new Skew.Range(range.source, range.start + escape | 0, range.start + i | 0));\n        }\n      }\n    }\n\n    builder.buffer += in_string.slice2(text, start, i);\n    return builder.buffer;\n  };\n\n  Skew.Parsing.boolLiteral = function(value) {\n    return function(context, token) {\n      return new Skew.Node(Skew.NodeKind.CONSTANT).withContent(new Skew.BoolContent(value)).withRange(token.range);\n    };\n  };\n\n  Skew.Parsing.tokenLiteral = function(kind) {\n    return function(context, token) {\n      return new Skew.Node(kind).withRange(token.range);\n    };\n  };\n\n  Skew.Parsing.unaryPrefix = function(kind) {\n    return function(context, token, value) {\n      return Skew.Node.createUnary(kind, value).withRange(Skew.Range.span(token.range, value.range)).withInternalRange(token.range);\n    };\n  };\n\n  Skew.Parsing.unaryPostfix = function(kind) {\n    return function(context, value, token) {\n      return Skew.Node.createUnary(kind, value).withRange(Skew.Range.span(value.range, token.range)).withInternalRange(token.range);\n    };\n  };\n\n  Skew.Parsing.binaryInfix = function(kind) {\n    return function(context, left, token, right) {\n      if (kind == Skew.NodeKind.ASSIGN && left.kind == Skew.NodeKind.INDEX) {\n        left.appendChild(right);\n        left.kind = Skew.NodeKind.ASSIGN_INDEX;\n        return left.withRange(Skew.Range.span(left.range, right.range)).withInternalRange(Skew.Range.span(left.internalRange, right.range));\n      }\n\n      return Skew.Node.createBinary(kind, left, right).withRange(Skew.Range.span(left.range, right.range)).withInternalRange(token.range);\n    };\n  };\n\n  Skew.Parsing.createExpressionParser = function() {\n    var pratt = new Skew.Pratt();\n\n    /////////////////////////////////////////\n    // Literals\n    /////////////////////////////////////////\n\n    pratt.literal(Skew.TokenKind.DOUBLE, function(context, token) {\n      return new Skew.Node(Skew.NodeKind.CONSTANT).withContent(new Skew.DoubleContent(+token.range.toString())).withRange(token.range);\n    });\n    pratt.literal(Skew.TokenKind.FALSE, Skew.Parsing.boolLiteral(false));\n    pratt.literal(Skew.TokenKind.INT, Skew.Parsing.intLiteral);\n    pratt.literal(Skew.TokenKind.INT_BINARY, Skew.Parsing.intLiteral);\n    pratt.literal(Skew.TokenKind.INT_HEX, Skew.Parsing.intLiteral);\n    pratt.literal(Skew.TokenKind.INT_OCTAL, Skew.Parsing.intLiteral);\n    pratt.literal(Skew.TokenKind.NULL, Skew.Parsing.tokenLiteral(Skew.NodeKind.NULL));\n    pratt.literal(Skew.TokenKind.STRING, Skew.Parsing.stringLiteral);\n    pratt.literal(Skew.TokenKind.SUPER, Skew.Parsing.tokenLiteral(Skew.NodeKind.SUPER));\n    pratt.literal(Skew.TokenKind.TRUE, Skew.Parsing.boolLiteral(true));\n    pratt.literal(Skew.TokenKind.CHARACTER, function(context, token) {\n      var result = Skew.Parsing.parseStringLiteral(context.log, token.range);\n      var codePoint = 0;\n\n      // There must be exactly one unicode code point\n      var iterator = Unicode.StringIterator.INSTANCE.reset(result, 0);\n      codePoint = iterator.nextCodePoint();\n\n      if (codePoint == -1 || iterator.nextCodePoint() != -1) {\n        context.log.syntaxErrorInvalidCharacter(token.range);\n      }\n\n      // Don't return null when there's an error because that\n      // error won't affect the rest of the compilation\n      return new Skew.Node(Skew.NodeKind.CONSTANT).withContent(new Skew.IntContent(codePoint)).withRange(token.range);\n    });\n\n    /////////////////////////////////////////\n    // Unary expressions\n    /////////////////////////////////////////\n\n    pratt.prefix(Skew.TokenKind.MINUS, Skew.Precedence.UNARY_PREFIX, Skew.Parsing.unaryPrefix(Skew.NodeKind.NEGATIVE));\n    pratt.prefix(Skew.TokenKind.NOT, Skew.Precedence.UNARY_PREFIX, Skew.Parsing.unaryPrefix(Skew.NodeKind.NOT));\n    pratt.prefix(Skew.TokenKind.PLUS, Skew.Precedence.UNARY_PREFIX, Skew.Parsing.unaryPrefix(Skew.NodeKind.POSITIVE));\n    pratt.prefix(Skew.TokenKind.TILDE, Skew.Precedence.UNARY_PREFIX, Skew.Parsing.unaryPrefix(Skew.NodeKind.COMPLEMENT));\n    pratt.prefix(Skew.TokenKind.INCREMENT, Skew.Precedence.UNARY_PREFIX, Skew.Parsing.unaryPrefix(Skew.NodeKind.PREFIX_INCREMENT));\n    pratt.prefix(Skew.TokenKind.DECREMENT, Skew.Precedence.UNARY_PREFIX, Skew.Parsing.unaryPrefix(Skew.NodeKind.PREFIX_DECREMENT));\n    pratt.postfix(Skew.TokenKind.INCREMENT, Skew.Precedence.UNARY_PREFIX, Skew.Parsing.unaryPostfix(Skew.NodeKind.POSTFIX_INCREMENT));\n    pratt.postfix(Skew.TokenKind.DECREMENT, Skew.Precedence.UNARY_PREFIX, Skew.Parsing.unaryPostfix(Skew.NodeKind.POSTFIX_DECREMENT));\n\n    /////////////////////////////////////////\n    // Binary expressions\n    /////////////////////////////////////////\n\n    pratt.infix(Skew.TokenKind.BITWISE_AND, Skew.Precedence.BITWISE_AND, Skew.Parsing.binaryInfix(Skew.NodeKind.BITWISE_AND));\n    pratt.infix(Skew.TokenKind.BITWISE_OR, Skew.Precedence.BITWISE_OR, Skew.Parsing.binaryInfix(Skew.NodeKind.BITWISE_OR));\n    pratt.infix(Skew.TokenKind.BITWISE_XOR, Skew.Precedence.BITWISE_XOR, Skew.Parsing.binaryInfix(Skew.NodeKind.BITWISE_XOR));\n    pratt.infix(Skew.TokenKind.COMPARE, Skew.Precedence.COMPARE, Skew.Parsing.binaryInfix(Skew.NodeKind.COMPARE));\n    pratt.infix(Skew.TokenKind.DIVIDE, Skew.Precedence.MULTIPLY, Skew.Parsing.binaryInfix(Skew.NodeKind.DIVIDE));\n    pratt.infix(Skew.TokenKind.EQUAL, Skew.Precedence.EQUAL, Skew.Parsing.binaryInfix(Skew.NodeKind.EQUAL));\n    pratt.infix(Skew.TokenKind.GREATER_THAN, Skew.Precedence.COMPARE, Skew.Parsing.binaryInfix(Skew.NodeKind.GREATER_THAN));\n    pratt.infix(Skew.TokenKind.GREATER_THAN_OR_EQUAL, Skew.Precedence.COMPARE, Skew.Parsing.binaryInfix(Skew.NodeKind.GREATER_THAN_OR_EQUAL));\n    pratt.infix(Skew.TokenKind.IN, Skew.Precedence.COMPARE, Skew.Parsing.binaryInfix(Skew.NodeKind.IN));\n    pratt.infix(Skew.TokenKind.LESS_THAN, Skew.Precedence.COMPARE, Skew.Parsing.binaryInfix(Skew.NodeKind.LESS_THAN));\n    pratt.infix(Skew.TokenKind.LESS_THAN_OR_EQUAL, Skew.Precedence.COMPARE, Skew.Parsing.binaryInfix(Skew.NodeKind.LESS_THAN_OR_EQUAL));\n    pratt.infix(Skew.TokenKind.LOGICAL_AND, Skew.Precedence.LOGICAL_AND, Skew.Parsing.binaryInfix(Skew.NodeKind.LOGICAL_AND));\n    pratt.infix(Skew.TokenKind.LOGICAL_OR, Skew.Precedence.LOGICAL_OR, Skew.Parsing.binaryInfix(Skew.NodeKind.LOGICAL_OR));\n    pratt.infix(Skew.TokenKind.MINUS, Skew.Precedence.ADD, Skew.Parsing.binaryInfix(Skew.NodeKind.SUBTRACT));\n    pratt.infix(Skew.TokenKind.MODULUS, Skew.Precedence.MULTIPLY, Skew.Parsing.binaryInfix(Skew.NodeKind.MODULUS));\n    pratt.infix(Skew.TokenKind.MULTIPLY, Skew.Precedence.MULTIPLY, Skew.Parsing.binaryInfix(Skew.NodeKind.MULTIPLY));\n    pratt.infix(Skew.TokenKind.NOT_EQUAL, Skew.Precedence.EQUAL, Skew.Parsing.binaryInfix(Skew.NodeKind.NOT_EQUAL));\n    pratt.infix(Skew.TokenKind.PLUS, Skew.Precedence.ADD, Skew.Parsing.binaryInfix(Skew.NodeKind.ADD));\n    pratt.infix(Skew.TokenKind.POWER, Skew.Precedence.UNARY_PREFIX, Skew.Parsing.binaryInfix(Skew.NodeKind.POWER));\n    pratt.infix(Skew.TokenKind.REMAINDER, Skew.Precedence.MULTIPLY, Skew.Parsing.binaryInfix(Skew.NodeKind.REMAINDER));\n    pratt.infix(Skew.TokenKind.SHIFT_LEFT, Skew.Precedence.SHIFT, Skew.Parsing.binaryInfix(Skew.NodeKind.SHIFT_LEFT));\n    pratt.infix(Skew.TokenKind.SHIFT_RIGHT, Skew.Precedence.SHIFT, Skew.Parsing.binaryInfix(Skew.NodeKind.SHIFT_RIGHT));\n    pratt.infix(Skew.TokenKind.UNSIGNED_SHIFT_RIGHT, Skew.Precedence.SHIFT, Skew.Parsing.binaryInfix(Skew.NodeKind.UNSIGNED_SHIFT_RIGHT));\n    pratt.infixRight(Skew.TokenKind.ASSIGN, Skew.Precedence.ASSIGN, Skew.Parsing.binaryInfix(Skew.NodeKind.ASSIGN));\n    pratt.infixRight(Skew.TokenKind.ASSIGN_BITWISE_AND, Skew.Precedence.ASSIGN, Skew.Parsing.binaryInfix(Skew.NodeKind.ASSIGN_BITWISE_AND));\n    pratt.infixRight(Skew.TokenKind.ASSIGN_BITWISE_OR, Skew.Precedence.ASSIGN, Skew.Parsing.binaryInfix(Skew.NodeKind.ASSIGN_BITWISE_OR));\n    pratt.infixRight(Skew.TokenKind.ASSIGN_BITWISE_XOR, Skew.Precedence.ASSIGN, Skew.Parsing.binaryInfix(Skew.NodeKind.ASSIGN_BITWISE_XOR));\n    pratt.infixRight(Skew.TokenKind.ASSIGN_DIVIDE, Skew.Precedence.ASSIGN, Skew.Parsing.binaryInfix(Skew.NodeKind.ASSIGN_DIVIDE));\n    pratt.infixRight(Skew.TokenKind.ASSIGN_MINUS, Skew.Precedence.ASSIGN, Skew.Parsing.binaryInfix(Skew.NodeKind.ASSIGN_SUBTRACT));\n    pratt.infixRight(Skew.TokenKind.ASSIGN_MODULUS, Skew.Precedence.ASSIGN, Skew.Parsing.binaryInfix(Skew.NodeKind.ASSIGN_MODULUS));\n    pratt.infixRight(Skew.TokenKind.ASSIGN_MULTIPLY, Skew.Precedence.ASSIGN, Skew.Parsing.binaryInfix(Skew.NodeKind.ASSIGN_MULTIPLY));\n    pratt.infixRight(Skew.TokenKind.ASSIGN_NULL, Skew.Precedence.ASSIGN, Skew.Parsing.binaryInfix(Skew.NodeKind.ASSIGN_NULL));\n    pratt.infixRight(Skew.TokenKind.ASSIGN_PLUS, Skew.Precedence.ASSIGN, Skew.Parsing.binaryInfix(Skew.NodeKind.ASSIGN_ADD));\n    pratt.infixRight(Skew.TokenKind.ASSIGN_POWER, Skew.Precedence.ASSIGN, Skew.Parsing.binaryInfix(Skew.NodeKind.ASSIGN_POWER));\n    pratt.infixRight(Skew.TokenKind.ASSIGN_REMAINDER, Skew.Precedence.ASSIGN, Skew.Parsing.binaryInfix(Skew.NodeKind.ASSIGN_REMAINDER));\n    pratt.infixRight(Skew.TokenKind.ASSIGN_SHIFT_LEFT, Skew.Precedence.ASSIGN, Skew.Parsing.binaryInfix(Skew.NodeKind.ASSIGN_SHIFT_LEFT));\n    pratt.infixRight(Skew.TokenKind.ASSIGN_SHIFT_RIGHT, Skew.Precedence.ASSIGN, Skew.Parsing.binaryInfix(Skew.NodeKind.ASSIGN_SHIFT_RIGHT));\n    pratt.infixRight(Skew.TokenKind.ASSIGN_UNSIGNED_SHIFT_RIGHT, Skew.Precedence.ASSIGN, Skew.Parsing.binaryInfix(Skew.NodeKind.ASSIGN_UNSIGNED_SHIFT_RIGHT));\n    pratt.infixRight(Skew.TokenKind.NULL_JOIN, Skew.Precedence.NULL_JOIN, Skew.Parsing.binaryInfix(Skew.NodeKind.NULL_JOIN));\n\n    /////////////////////////////////////////\n    // Other expressions\n    /////////////////////////////////////////\n\n    pratt.parselet(Skew.TokenKind.DOT, Skew.Precedence.MEMBER).infix = Skew.Parsing.dotInfixParselet;\n    pratt.parselet(Skew.TokenKind.INDEX, Skew.Precedence.LOWEST).prefix = Skew.Parsing.initializerParselet;\n    pratt.parselet(Skew.TokenKind.LEFT_BRACE, Skew.Precedence.LOWEST).prefix = Skew.Parsing.initializerParselet;\n    pratt.parselet(Skew.TokenKind.LEFT_BRACKET, Skew.Precedence.LOWEST).prefix = Skew.Parsing.initializerParselet;\n    pratt.parselet(Skew.TokenKind.LIST_NEW, Skew.Precedence.LOWEST).prefix = Skew.Parsing.initializerParselet;\n    pratt.parselet(Skew.TokenKind.SET_NEW, Skew.Precedence.LOWEST).prefix = Skew.Parsing.initializerParselet;\n    pratt.parselet(Skew.TokenKind.PARAMETER_LIST_START, Skew.Precedence.MEMBER).infix = Skew.Parsing.parameterizedParselet;\n\n    // String interpolation\n    pratt.parselet(Skew.TokenKind.STRING_INTERPOLATION_START, Skew.Precedence.LOWEST).prefix = function(context) {\n      var token = context.next();\n      var node = new Skew.Node(Skew.NodeKind.STRING_INTERPOLATION).appendChild(Skew.Parsing.createStringNode(context.log, token.range));\n\n      while (true) {\n        var value = Skew.Parsing.expressionParser.parse(context, Skew.Precedence.LOWEST);\n        node.appendChild(value);\n        context.skipWhitespace();\n        token = context.current();\n\n        if (!context.eat(Skew.TokenKind.STRING_INTERPOLATION_CONTINUE) && !context.expect(Skew.TokenKind.STRING_INTERPOLATION_END)) {\n          return context.createParseError();\n        }\n\n        node.appendChild(Skew.Parsing.createStringNode(context.log, token.range));\n\n        if (token.kind == Skew.TokenKind.STRING_INTERPOLATION_END) {\n          break;\n        }\n      }\n\n      return node.withRange(context.spanSince(node.firstChild().range));\n    };\n\n    // \"x?.y\"\n    pratt.parselet(Skew.TokenKind.NULL_DOT, Skew.Precedence.MEMBER).infix = function(context, left) {\n      context.next();\n      var range = context.current().range;\n\n      if (!context.expect(Skew.TokenKind.IDENTIFIER)) {\n        return context.createParseError();\n      }\n\n      return new Skew.Node(Skew.NodeKind.NULL_DOT).withContent(new Skew.StringContent(range.toString())).appendChild(left).withRange(context.spanSince(left.range)).withInternalRange(range);\n    };\n\n    // Lambda expressions like \"=> x\"\n    pratt.parselet(Skew.TokenKind.ARROW, Skew.Precedence.LOWEST).prefix = function(context) {\n      var token = context.current();\n      var symbol = new Skew.FunctionSymbol(Skew.SymbolKind.FUNCTION_LOCAL, '<lambda>');\n\n      if (!Skew.Parsing.parseFunctionBlock(context, symbol)) {\n        return context.createParseError();\n      }\n\n      symbol.range = context.spanSince(token.range);\n      return Skew.Node.createLambda(symbol).withRange(symbol.range);\n    };\n\n    // Cast expressions\n    pratt.parselet(Skew.TokenKind.AS, Skew.Precedence.UNARY_PREFIX).infix = function(context, left) {\n      var token = context.next();\n      var type = Skew.Parsing.typeParser.parse(context, Skew.Precedence.LOWEST);\n      return Skew.Node.createCast(left, type).withRange(context.spanSince(left.range)).withInternalRange(token.range);\n    };\n\n    // Using \".\" as a unary prefix operator accesses members off the inferred type\n    pratt.parselet(Skew.TokenKind.DOT, Skew.Precedence.MEMBER).prefix = function(context) {\n      var token = context.next();\n      var range = context.current().range;\n\n      if (!context.expect(Skew.TokenKind.IDENTIFIER)) {\n        return context.createParseError();\n      }\n\n      return new Skew.Node(Skew.NodeKind.DOT).withContent(new Skew.StringContent(range.toString())).appendChild(null).withRange(context.spanSince(token.range)).withInternalRange(range);\n    };\n\n    // Access members off of \"dynamic\" for untyped globals\n    pratt.parselet(Skew.TokenKind.DYNAMIC, Skew.Precedence.LOWEST).prefix = function(context) {\n      var token = context.next();\n\n      if (!context.expect(Skew.TokenKind.DOT)) {\n        return context.createParseError();\n      }\n\n      var range = context.current().range;\n\n      if (!context.expect(Skew.TokenKind.IDENTIFIER)) {\n        return context.createParseError();\n      }\n\n      return new Skew.Node(Skew.NodeKind.DOT).withContent(new Skew.StringContent(range.toString())).appendChild(new Skew.Node(Skew.NodeKind.TYPE).withType(Skew.Type.DYNAMIC)).withRange(context.spanSince(token.range)).withInternalRange(range);\n    };\n\n    // Name expressions and lambda expressions like \"x => x * x\"\n    pratt.parselet(Skew.TokenKind.IDENTIFIER, Skew.Precedence.LOWEST).prefix = function(context) {\n      var range = context.next().range;\n      var name = range.toString();\n\n      // Lambda expression\n      if (context.peek1(Skew.TokenKind.ARROW)) {\n        var symbol = new Skew.FunctionSymbol(Skew.SymbolKind.FUNCTION_LOCAL, '<lambda>');\n        var argument = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_ARGUMENT, name);\n        argument.range = range;\n        symbol.$arguments.push(argument);\n\n        if (!Skew.Parsing.parseFunctionBlock(context, symbol)) {\n          return context.createParseError();\n        }\n\n        symbol.range = context.spanSince(range);\n        return Skew.Node.createLambda(symbol).withRange(symbol.range);\n      }\n\n      // New expression (an error, but still parsed for a better error message)\n      if (context.peek1(Skew.TokenKind.IDENTIFIER) && name == 'new') {\n        var type = Skew.Parsing.typeParser.parse(context, Skew.Precedence.LOWEST);\n        context.log.syntaxErrorNewOperator(context.spanSince(range), type.range.toString() + '.new');\n        return new Skew.Node(Skew.NodeKind.PARSE_ERROR).withRange(context.spanSince(range));\n      }\n\n      return new Skew.Node(Skew.NodeKind.NAME).withContent(new Skew.StringContent(name)).withRange(range);\n    };\n\n    // Type check expressions\n    pratt.parselet(Skew.TokenKind.IS, Skew.Precedence.COMPARE).infix = function(context, left) {\n      var token = context.next();\n      var type = Skew.Parsing.typeParser.parse(context, Skew.Precedence.LOWEST);\n      return Skew.Node.createTypeCheck(left, type).withRange(context.spanSince(left.range)).withInternalRange(token.range);\n    };\n\n    // Index expressions\n    pratt.parselet(Skew.TokenKind.LEFT_BRACKET, Skew.Precedence.MEMBER).infix = function(context, left) {\n      var token = context.next();\n      var right = Skew.Parsing.expressionParser.parse(context, Skew.Precedence.LOWEST);\n      Skew.Parsing.scanForToken(context, Skew.TokenKind.RIGHT_BRACKET);\n      return Skew.Node.createIndex(left, right).withRange(context.spanSince(left.range)).withInternalRange(context.spanSince(token.range));\n    };\n\n    // Parenthetic groups and lambda expressions like \"() => x\"\n    pratt.parselet(Skew.TokenKind.LEFT_PARENTHESIS, Skew.Precedence.LOWEST).prefix = function(context) {\n      var token = context.next();\n\n      // Try to parse a group\n      if (!context.peek1(Skew.TokenKind.RIGHT_PARENTHESIS)) {\n        var value = pratt.parse(context, Skew.Precedence.LOWEST);\n\n        if ((value.kind != Skew.NodeKind.NAME || !Skew.Parsing.peekType(context)) && context.eat(Skew.TokenKind.RIGHT_PARENTHESIS)) {\n          if (value.kind != Skew.NodeKind.NAME || !context.peek1(Skew.TokenKind.ARROW)) {\n            return value.withRange(context.spanSince(token.range)).withFlags(Skew.NodeFlags.IS_INSIDE_PARENTHESES);\n          }\n\n          context.undo();\n        }\n\n        context.undo();\n      }\n\n      // Parse a lambda instead\n      var symbol = new Skew.FunctionSymbol(Skew.SymbolKind.FUNCTION_LOCAL, '<lambda>');\n\n      if (!Skew.Parsing.parseFunctionArguments(context, symbol) || !Skew.Parsing.parseFunctionReturnTypeAndBlock(context, symbol)) {\n        return context.createParseError();\n      }\n\n      symbol.range = context.spanSince(token.range);\n      return Skew.Node.createLambda(symbol).withRange(symbol.range);\n    };\n\n    // Call expressions\n    pratt.parselet(Skew.TokenKind.LEFT_PARENTHESIS, Skew.Precedence.UNARY_POSTFIX).infix = function(context, left) {\n      var node = Skew.Node.createCall(left);\n      var token = context.next();\n      Skew.Parsing.parseCommaSeparatedList(context, node, Skew.TokenKind.RIGHT_PARENTHESIS);\n      return node.withRange(context.spanSince(left.range)).withInternalRange(context.spanSince(token.range));\n    };\n\n    // Hook expressions\n    pratt.parselet(Skew.TokenKind.QUESTION_MARK, Skew.Precedence.ASSIGN).infix = function(context, left) {\n      context.next();\n      var middle = pratt.parse(context, Skew.Precedence.ASSIGN - 1 | 0);\n\n      if (!context.expect(Skew.TokenKind.COLON)) {\n        return context.createParseError();\n      }\n\n      var right = pratt.parse(context, Skew.Precedence.ASSIGN - 1 | 0);\n      return Skew.Node.createHook(left, middle, right).withRange(context.spanSince(left.range));\n    };\n\n    // XML literals\n    pratt.parselet(Skew.TokenKind.XML_START, Skew.Precedence.LOWEST).prefix = function(context) {\n      var token = context.next();\n      var tag = Skew.Parsing.parseDotChain(context);\n\n      if (tag == null) {\n        Skew.Parsing.scanForToken(context, Skew.TokenKind.XML_END);\n        return context.createParseError();\n      }\n\n      var attributes = new Skew.Node(Skew.NodeKind.SEQUENCE);\n\n      // Parse attributes\n      context.skipWhitespace();\n\n      while (context.peek1(Skew.TokenKind.IDENTIFIER)) {\n        var name = Skew.Parsing.parseDotChain(context);\n        var assignment = context.current();\n        var kind = in_IntMap.get(Skew.Parsing.assignmentOperators, assignment.kind, Skew.NodeKind.NULL);\n\n        if (kind == Skew.NodeKind.NULL) {\n          context.expect(Skew.TokenKind.ASSIGN);\n          Skew.Parsing.scanForToken(context, Skew.TokenKind.XML_END);\n          return context.createParseError();\n        }\n\n        context.next();\n        var value = Skew.Parsing.expressionParser.parse(context, Skew.Precedence.UNARY_PREFIX - 1 | 0);\n        attributes.appendChild(Skew.Node.createBinary(kind, name, value).withRange(context.spanSince(name.range)).withInternalRange(assignment.range));\n        context.skipWhitespace();\n      }\n\n      // Parse end of tag\n      var block = new Skew.Node(Skew.NodeKind.BLOCK);\n      var closingTag = null;\n      context.skipWhitespace();\n\n      // Check for children\n      if (!context.eat(Skew.TokenKind.XML_END_EMPTY)) {\n        if (!context.expect(Skew.TokenKind.XML_END)) {\n          Skew.Parsing.scanForToken(context, Skew.TokenKind.XML_END);\n          return context.createParseError();\n        }\n\n        // Parse children\n        context.skipWhitespace();\n\n        if (!Skew.Parsing.parseStatements(context, block, Skew.Parsing.StatementsMode.NORMAL) || !context.expect(Skew.TokenKind.XML_START_CLOSE)) {\n          return context.createParseError();\n        }\n\n        block.withRange(context.spanSince(token.range));\n\n        // Parse closing tag\n        closingTag = Skew.Parsing.parseDotChain(context);\n\n        if (closingTag == null) {\n          Skew.Parsing.scanForToken(context, Skew.TokenKind.XML_END);\n          return context.createParseError();\n        }\n\n        context.skipWhitespace();\n\n        if (!context.expect(Skew.TokenKind.XML_END)) {\n          Skew.Parsing.scanForToken(context, Skew.TokenKind.XML_END);\n          return context.createParseError();\n        }\n\n        // Validate closing tag (not a fatal error)\n        if (!tag.looksTheSameAs(closingTag)) {\n          context.log.syntaxErrorXMLClosingTagMismatch(closingTag.range, Skew.Parsing.dotChainToString(closingTag), Skew.Parsing.dotChainToString(tag), tag.range);\n        }\n      }\n\n      return Skew.Node.createXML(tag, attributes, block, closingTag).withRange(context.spanSince(token.range));\n    };\n    return pratt;\n  };\n\n  Skew.Parsing.dotChainToString = function(node) {\n    assert(node.kind == Skew.NodeKind.NAME || node.kind == Skew.NodeKind.DOT);\n\n    if (node.kind == Skew.NodeKind.NAME) {\n      return node.asString();\n    }\n\n    return Skew.Parsing.dotChainToString(node.dotTarget()) + '.' + node.asString();\n  };\n\n  Skew.Parsing.parseDotChain = function(context) {\n    var current = context.current();\n\n    if (!context.expect(Skew.TokenKind.IDENTIFIER)) {\n      return null;\n    }\n\n    var chain = new Skew.Node(Skew.NodeKind.NAME).withContent(new Skew.StringContent(current.range.toString())).withRange(current.range);\n\n    while (context.eat(Skew.TokenKind.DOT)) {\n      current = context.current();\n\n      if (!context.expect(Skew.TokenKind.IDENTIFIER)) {\n        return null;\n      }\n\n      chain = new Skew.Node(Skew.NodeKind.DOT).withContent(new Skew.StringContent(current.range.toString())).appendChild(chain).withRange(context.spanSince(chain.range)).withInternalRange(current.range);\n    }\n\n    return chain;\n  };\n\n  Skew.Parsing.createTypeParser = function() {\n    var pratt = new Skew.Pratt();\n    pratt.literal(Skew.TokenKind.DYNAMIC, function(context, token) {\n      return new Skew.Node(Skew.NodeKind.TYPE).withType(Skew.Type.DYNAMIC).withRange(token.range);\n    });\n    pratt.parselet(Skew.TokenKind.DOT, Skew.Precedence.MEMBER).infix = Skew.Parsing.dotInfixParselet;\n    pratt.parselet(Skew.TokenKind.PARAMETER_LIST_START, Skew.Precedence.MEMBER).infix = Skew.Parsing.parameterizedParselet;\n\n    // Name expressions or lambda type expressions like \"fn(int) int\"\n    pratt.parselet(Skew.TokenKind.IDENTIFIER, Skew.Precedence.LOWEST).prefix = function(context) {\n      var node = new Skew.Node(Skew.NodeKind.LAMBDA_TYPE).appendChild(new Skew.Node(Skew.NodeKind.TYPE).withType(Skew.Type.NULL));\n      var returnType = node.lambdaReturnType();\n      var token = context.next();\n      var name = token.range.toString();\n      var isFirst = true;\n\n      if (name != 'fn' || !context.eat(Skew.TokenKind.LEFT_PARENTHESIS)) {\n        return new Skew.Node(Skew.NodeKind.NAME).withContent(new Skew.StringContent(name)).withRange(token.range);\n      }\n\n      // Parse argument types\n      while (!context.eat(Skew.TokenKind.RIGHT_PARENTHESIS)) {\n        if (!isFirst && !context.expect(Skew.TokenKind.COMMA)) {\n          Skew.Parsing.scanForToken(context, Skew.TokenKind.RIGHT_PARENTHESIS);\n          return context.createParseError();\n        }\n\n        node.insertChildBefore(returnType, Skew.Parsing.typeParser.parse(context, Skew.Precedence.LOWEST));\n        isFirst = false;\n      }\n\n      // Parse return type if present\n      if (Skew.Parsing.peekType(context)) {\n        returnType.replaceWith(Skew.Parsing.typeParser.parse(context, Skew.Precedence.LOWEST));\n      }\n\n      return node.withRange(context.spanSince(token.range));\n    };\n\n    // The \"Foo[]\" syntax is an error but parse it anyway\n    pratt.parselet(Skew.TokenKind.INDEX, Skew.Precedence.MEMBER).infix = function(context, left) {\n      context.next();\n      var range = context.spanSince(left.range);\n      context.log.syntaxErrorWrongListSyntax(range, 'List<' + left.range.toString() + '>');\n      return new Skew.Node(Skew.NodeKind.PARSE_ERROR).withRange(range);\n    };\n    return pratt;\n  };\n\n  Skew.Parsing.parseFile = function(log, tokens, global, warnAboutIgnoredComments) {\n    if (Skew.Parsing.expressionParser == null) {\n      Skew.Parsing.expressionParser = Skew.Parsing.createExpressionParser();\n    }\n\n    if (Skew.Parsing.typeParser == null) {\n      Skew.Parsing.typeParser = Skew.Parsing.createTypeParser();\n    }\n\n    var context = new Skew.ParserContext(log, tokens, warnAboutIgnoredComments);\n    Skew.Parsing.parseSymbols(context, global, null);\n    context.expect(Skew.TokenKind.END_OF_FILE);\n  };\n\n  Skew.Parsing.intLiteral = function(context, token) {\n    return new Skew.Node(Skew.NodeKind.CONSTANT).withContent(new Skew.IntContent(Skew.Parsing.parseIntLiteral(context.log, token.range).value)).withRange(token.range);\n  };\n\n  Skew.Parsing.stringLiteral = function(context, token) {\n    return Skew.Parsing.createStringNode(context.log, token.range);\n  };\n\n  Skew.Parsing.StatementsMode = {\n    NORMAL: 0,\n    C_STYLE_SWITCH: 1\n  };\n\n  Skew.Parsing.ForbiddenGroup = {\n    ASSIGN: 0,\n    COMPARE: 1,\n    EQUAL: 2,\n    LOGICAL: 3\n  };\n\n  Skew.ParserContext = function(log, _tokens, warnAboutIgnoredComments) {\n    this.log = log;\n    this.inNonVoidFunction = false;\n    this._tokens = _tokens;\n    this._index = 0;\n    this.warnAboutIgnoredComments = warnAboutIgnoredComments;\n    this._previousSyntaxError = -1;\n  };\n\n  Skew.ParserContext.prototype.current = function() {\n    return in_List.get(this._tokens, this._index);\n  };\n\n  Skew.ParserContext.prototype.stealComments = function() {\n    var token = this.current();\n    var comments = token.comments;\n    token.comments = null;\n    return comments;\n  };\n\n  Skew.ParserContext.prototype.next = function() {\n    var token = this.current();\n\n    if (this.warnAboutIgnoredComments && token.comments != null) {\n      this.log.syntaxWarningIgnoredCommentInParser(in_List.first(token.comments).range);\n    }\n\n    if ((this._index + 1 | 0) < this._tokens.length) {\n      this._index = this._index + 1 | 0;\n    }\n\n    return token;\n  };\n\n  Skew.ParserContext.prototype.spanSince = function(range) {\n    var previous = in_List.get(this._tokens, this._index > 0 ? this._index - 1 | 0 : 0);\n    return previous.range.end < range.start ? range : Skew.Range.span(range, previous.range);\n  };\n\n  Skew.ParserContext.prototype.peek1 = function(kind) {\n    return this.current().kind == kind;\n  };\n\n  Skew.ParserContext.prototype.peek2 = function(kind, skip) {\n    assert(skip >= 1);\n    return in_List.get(this._tokens, Math.min(this._index + skip | 0, this._tokens.length - 1 | 0)).kind == kind;\n  };\n\n  Skew.ParserContext.prototype.eat = function(kind) {\n    if (this.peek1(kind)) {\n      this.next();\n      return true;\n    }\n\n    return false;\n  };\n\n  Skew.ParserContext.prototype.skipWhitespace = function() {\n    this.eat(Skew.TokenKind.NEWLINE);\n  };\n\n  Skew.ParserContext.prototype.skipSemicolon = function() {\n    if (this.peek1(Skew.TokenKind.SEMICOLON)) {\n      this.expect(Skew.TokenKind.NEWLINE);\n      this.next();\n      return true;\n    }\n\n    return false;\n  };\n\n  Skew.ParserContext.prototype.undo = function() {\n    assert(this._index > 0);\n    this._index = this._index - 1 | 0;\n  };\n\n  Skew.ParserContext.prototype.expect = function(kind) {\n    if (!this.eat(kind)) {\n      if (this.canReportSyntaxError()) {\n        this.log.syntaxErrorExpectedToken(this.current().range, this.current().kind, kind);\n      }\n\n      return false;\n    }\n\n    return true;\n  };\n\n  Skew.ParserContext.prototype.unexpectedToken = function() {\n    if (this.canReportSyntaxError()) {\n      this.log.syntaxErrorUnexpectedToken(this.current());\n    }\n  };\n\n  Skew.ParserContext.prototype.createParseError = function() {\n    return new Skew.Node(Skew.NodeKind.PARSE_ERROR).withRange(this.current().range);\n  };\n\n  Skew.ParserContext.prototype.canReportSyntaxError = function() {\n    if (this._previousSyntaxError != this._index) {\n      this._previousSyntaxError = this._index;\n      return true;\n    }\n\n    return false;\n  };\n\n  Skew.Parselet = function(precedence) {\n    this.precedence = precedence;\n    this.prefix = null;\n    this.infix = null;\n  };\n\n  // A Pratt parser is a parser that associates up to two operations per token,\n  // each with its own precedence. Pratt parsers excel at parsing expression\n  // trees with deeply nested precedence levels. For an excellent writeup, see:\n  //\n  //   http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/\n  //\n  Skew.Pratt = function() {\n    this._table = new Map();\n  };\n\n  Skew.Pratt.prototype.parselet = function(kind, precedence) {\n    var parselet = in_IntMap.get(this._table, kind, null);\n\n    if (parselet == null) {\n      var created = new Skew.Parselet(precedence);\n      parselet = created;\n      in_IntMap.set(this._table, kind, created);\n    }\n\n    else if (precedence > parselet.precedence) {\n      parselet.precedence = precedence;\n    }\n\n    return parselet;\n  };\n\n  Skew.Pratt.prototype.parse = function(context, precedence) {\n    context.skipWhitespace();\n    var comments = context.stealComments();\n    var token = context.current();\n    var parselet = in_IntMap.get(this._table, token.kind, null);\n\n    if (parselet == null || parselet.prefix == null) {\n      context.unexpectedToken();\n      return context.createParseError();\n    }\n\n    var node = this.resume(context, precedence, parselet.prefix(context));\n\n    // Parselets must set the range of every node\n    assert(node != null && node.range != null);\n    node.comments = Skew.Comment.concat(comments, node.comments);\n    return node;\n  };\n\n  Skew.Pratt.prototype.resume = function(context, precedence, left) {\n    while (true) {\n      var kind = context.current().kind;\n      var parselet = in_IntMap.get(this._table, kind, null);\n\n      if (parselet == null || parselet.infix == null || parselet.precedence <= precedence) {\n        break;\n      }\n\n      left = parselet.infix(context, left);\n\n      // Parselets must set the range of every node\n      assert(left != null && left.range != null);\n    }\n\n    return left;\n  };\n\n  Skew.Pratt.prototype.literal = function(kind, callback) {\n    this.parselet(kind, Skew.Precedence.LOWEST).prefix = function(context) {\n      return callback(context, context.next());\n    };\n  };\n\n  Skew.Pratt.prototype.prefix = function(kind, precedence, callback) {\n    var self = this;\n    self.parselet(kind, Skew.Precedence.LOWEST).prefix = function(context) {\n      var token = context.next();\n      return callback(context, token, self.parse(context, precedence));\n    };\n  };\n\n  Skew.Pratt.prototype.postfix = function(kind, precedence, callback) {\n    this.parselet(kind, precedence).infix = function(context, left) {\n      return callback(context, left, context.next());\n    };\n  };\n\n  Skew.Pratt.prototype.infix = function(kind, precedence, callback) {\n    var self = this;\n    self.parselet(kind, precedence).infix = function(context, left) {\n      var token = context.next();\n      var comments = context.stealComments();\n      var right = self.parse(context, precedence);\n      right.comments = Skew.Comment.concat(comments, right.comments);\n      return callback(context, left, token, right);\n    };\n  };\n\n  Skew.Pratt.prototype.infixRight = function(kind, precedence, callback) {\n    var self = this;\n    self.parselet(kind, precedence).infix = function(context, left) {\n      var token = context.next();\n\n      // Subtract 1 for right-associativity\n      return callback(context, left, token, self.parse(context, precedence - 1 | 0));\n    };\n  };\n\n  Skew.LineColumn = function(line, column) {\n    this.line = line;\n    this.column = column;\n  };\n\n  Skew.Source = function(name, contents) {\n    this.name = name;\n    this.contents = contents;\n    this._lineOffsets = null;\n  };\n\n  Skew.Source.prototype.entireRange = function() {\n    return new Skew.Range(this, 0, this.contents.length);\n  };\n\n  Skew.Source.prototype.lineCount = function() {\n    this._computeLineOffsets();\n\n    // Ignore the line offset at 0\n    return this._lineOffsets.length - 1 | 0;\n  };\n\n  Skew.Source.prototype.contentsOfLine = function(line) {\n    this._computeLineOffsets();\n\n    if (line < 0 || line >= this._lineOffsets.length) {\n      return '';\n    }\n\n    var start = in_List.get(this._lineOffsets, line);\n    var end = (line + 1 | 0) < this._lineOffsets.length ? in_List.get(this._lineOffsets, line + 1 | 0) - 1 | 0 : this.contents.length;\n    return in_string.slice2(this.contents, start, end);\n  };\n\n  Skew.Source.prototype.indexToLineColumn = function(index) {\n    this._computeLineOffsets();\n\n    // Binary search to find the line\n    var count = this._lineOffsets.length;\n    var line = 0;\n\n    while (count > 0) {\n      var step = count / 2 | 0;\n      var i = line + step | 0;\n\n      if (in_List.get(this._lineOffsets, i) <= index) {\n        line = i + 1 | 0;\n        count = (count - step | 0) - 1 | 0;\n      }\n\n      else {\n        count = step;\n      }\n    }\n\n    // Use the line to compute the column\n    var column = line > 0 ? index - in_List.get(this._lineOffsets, line - 1 | 0) | 0 : index;\n    return new Skew.LineColumn(line - 1 | 0, column);\n  };\n\n  Skew.Source.prototype._computeLineOffsets = function() {\n    if (this._lineOffsets == null) {\n      this._lineOffsets = [0];\n\n      for (var i = 0, count = this.contents.length; i < count; i = i + 1 | 0) {\n        if (in_string.get1(this.contents, i) == 10) {\n          this._lineOffsets.push(i + 1 | 0);\n        }\n      }\n    }\n  };\n\n  Skew.ShakingMode = {\n    USE_TYPES: 0,\n    IGNORE_TYPES: 1\n  };\n\n  // This stores a mapping from every symbol to its immediate dependencies and\n  // uses that to provide a mapping from a subset of symbols to their complete\n  // dependencies. This is useful for dead code elimination.\n  Skew.UsageGraph = function(global, mode) {\n    this._mode = 0;\n    this.context = null;\n    this._currentUsages = null;\n    this._overridesForSymbol = new Map();\n    this._usages = new Map();\n    this._allSymbols = new Map();\n    this._mode = mode;\n    this._visitObject(global);\n    this._changeContext(null);\n  };\n\n  Skew.UsageGraph.prototype.usagesForSymbols = function(symbols) {\n    var overridesToCheck = new Map();\n    var combinedUsages = new Map();\n    var stack = [];\n    in_List.append1(stack, symbols);\n\n    // Iterate until a fixed point is reached\n    while (!(stack.length == 0)) {\n      var symbol = in_List.takeLast(stack);\n\n      if (!combinedUsages.has(symbol.id)) {\n        in_IntMap.set(combinedUsages, symbol.id, symbol);\n        var symbolUsages = in_IntMap.get(this._usages, symbol.id, null);\n\n        if (symbolUsages != null) {\n          in_List.append1(stack, symbolUsages);\n        }\n\n        // Handle function overrides\n        if (Skew.in_SymbolKind.isFunction(symbol.kind)) {\n          var overridden = symbol.asFunctionSymbol().overridden;\n          var symbolOverrides = in_IntMap.get(this._overridesForSymbol, symbol.id, null);\n\n          // Automatically include all overridden functions in case the use\n          // of this type is polymorphic, which is a conservative estimate\n          if (overridden != null) {\n            stack.push(overridden);\n          }\n\n          // Check function overrides too\n          if (symbolOverrides != null) {\n            for (var i = 0, list = symbolOverrides, count = list.length; i < count; i = i + 1 | 0) {\n              var override = in_List.get(list, i);\n              var key = override.parent.id;\n\n              // Queue this override immediately if the parent type is used\n              if (combinedUsages.has(key)) {\n                stack.push(override);\n              }\n\n              // Otherwise, remember this override for later if the parent type ends up being used\n              else {\n                var overrides = in_IntMap.get(overridesToCheck, key, null);\n\n                if (overrides == null) {\n                  overrides = [];\n                  in_IntMap.set(overridesToCheck, key, overrides);\n                }\n\n                overrides.push(override);\n              }\n            }\n          }\n        }\n\n        // Handle overrides dependent on this type\n        else if (Skew.in_SymbolKind.isType(symbol.kind)) {\n          var overrides1 = in_IntMap.get(overridesToCheck, symbol.id, null);\n\n          if (overrides1 != null) {\n            in_List.append1(stack, overrides1);\n          }\n        }\n      }\n    }\n\n    return combinedUsages;\n  };\n\n  Skew.UsageGraph.prototype._changeContext = function(symbol) {\n    if (this.context != null) {\n      var values = Array.from(this._currentUsages.values());\n\n      // Sort so the order is deterministic\n      values.sort(Skew.Symbol.SORT_BY_ID);\n      in_IntMap.set(this._usages, this.context.id, values);\n    }\n\n    this._currentUsages = new Map();\n\n    if (symbol != null) {\n      this._includeSymbol(symbol);\n      in_IntMap.set(this._currentUsages, symbol.id, symbol);\n    }\n\n    this.context = symbol;\n  };\n\n  Skew.UsageGraph.prototype._recordOverride = function(base, derived) {\n    var overrides = in_IntMap.get(this._overridesForSymbol, base.id, null);\n\n    if (overrides == null) {\n      overrides = [];\n      in_IntMap.set(this._overridesForSymbol, base.id, overrides);\n    }\n\n    overrides.push(derived);\n  };\n\n  Skew.UsageGraph.prototype._recordUsage = function(symbol) {\n    this._includeSymbol(symbol);\n\n    if (!Skew.in_SymbolKind.isLocal(symbol.kind)) {\n      in_IntMap.set(this._currentUsages, symbol.id, symbol);\n    }\n  };\n\n  Skew.UsageGraph.prototype._visitObject = function(symbol) {\n    for (var i3 = 0, list3 = symbol.objects, count3 = list3.length; i3 < count3; i3 = i3 + 1 | 0) {\n      var object = in_List.get(list3, i3);\n      this._changeContext(object);\n      this._recordUsage(symbol);\n\n      // Always pull the base class in\n      if (object.baseClass != null) {\n        this._recordUsage(object.baseClass);\n      }\n\n      // Only pull interfaces in for typed targets (interfaces disappear entirely for untyped targets)\n      if (this._mode != Skew.ShakingMode.IGNORE_TYPES && object.interfaceTypes != null) {\n        for (var i = 0, list = object.interfaceTypes, count = list.length; i < count; i = i + 1 | 0) {\n          var type = in_List.get(list, i);\n\n          if (type.symbol != null) {\n            this._recordUsage(type.symbol);\n          }\n        }\n      }\n\n      // If an imported type is used, automatically assume all functions and\n      // variables for that type are used too\n      if (object.isImported()) {\n        for (var i1 = 0, list1 = object.functions, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n          var $function = in_List.get(list1, i1);\n          this._recordUsage($function);\n        }\n\n        for (var i2 = 0, list2 = object.functions, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n          var variable = in_List.get(list2, i2);\n          this._recordUsage(variable);\n        }\n      }\n\n      this._visitObject(object);\n    }\n\n    for (var i4 = 0, list4 = symbol.functions, count4 = list4.length; i4 < count4; i4 = i4 + 1 | 0) {\n      var function1 = in_List.get(list4, i4);\n      this._changeContext(function1);\n\n      // Instance functions shouldn't cause their instance type to be emitted for dynamically-typed targets\n      if (this._mode != Skew.ShakingMode.IGNORE_TYPES || function1.kind != Skew.SymbolKind.FUNCTION_INSTANCE) {\n        this._recordUsage(symbol);\n      }\n\n      this._visitFunction(function1);\n    }\n\n    for (var i5 = 0, list5 = symbol.variables, count5 = list5.length; i5 < count5; i5 = i5 + 1 | 0) {\n      var variable1 = in_List.get(list5, i5);\n      this._changeContext(variable1);\n\n      // Instance variables shouldn't require the class to be present because\n      // accessing an instance variable already requires a constructed instance\n      if (variable1.kind != Skew.SymbolKind.VARIABLE_INSTANCE) {\n        this._recordUsage(symbol);\n      }\n\n      this._visitVariable(variable1);\n    }\n  };\n\n  Skew.UsageGraph.prototype._visitFunction = function(symbol) {\n    for (var i = 0, list = symbol.$arguments, count = list.length; i < count; i = i + 1 | 0) {\n      var argument = in_List.get(list, i);\n      this._visitVariable(argument);\n    }\n\n    this._visitType(symbol.resolvedType.returnType);\n    this._visitNode(symbol.block);\n\n    // Remember which functions are overridden for later\n    if (symbol.overridden != null) {\n      this._recordOverride(symbol.overridden, symbol);\n    }\n\n    // Remember which functions are overridden for later\n    if (symbol.implementations != null) {\n      for (var i1 = 0, list1 = symbol.implementations, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n        var $function = in_List.get(list1, i1);\n        this._recordOverride(symbol, $function);\n        this._recordOverride($function, symbol);\n      }\n    }\n  };\n\n  Skew.UsageGraph.prototype._visitVariable = function(symbol) {\n    this._visitType(symbol.resolvedType);\n    this._visitNode(symbol.value);\n  };\n\n  Skew.UsageGraph.prototype._visitNode = function(node) {\n    if (node == null) {\n      return;\n    }\n\n    if (node.kind == Skew.NodeKind.CAST) {\n      this._visitNode(node.castValue());\n      this._visitType(node.castType().resolvedType);\n    }\n\n    // This is necessary to preserve the types of constant-folded enums in typed languages\n    else if (node.kind == Skew.NodeKind.CONSTANT && this._mode == Skew.ShakingMode.USE_TYPES) {\n      this._visitType(node.resolvedType);\n    }\n\n    else {\n      for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n        this._visitNode(child);\n      }\n    }\n\n    if (node.symbol != null) {\n      this._recordUsage(node.symbol);\n    }\n\n    switch (node.kind) {\n      // The function block is a child node and has already been visited\n      case Skew.NodeKind.LAMBDA: {\n        var $function = node.symbol.asFunctionSymbol();\n\n        for (var i = 0, list = $function.$arguments, count = list.length; i < count; i = i + 1 | 0) {\n          var argument = in_List.get(list, i);\n          this._visitVariable(argument);\n        }\n\n        this._visitType($function.resolvedType.returnType);\n        break;\n      }\n\n      // The variable value is a child node and has already been visited\n      case Skew.NodeKind.VARIABLE: {\n        this._visitType(node.symbol.asVariableSymbol().resolvedType);\n        break;\n      }\n    }\n  };\n\n  Skew.UsageGraph.prototype._visitType = function(type) {\n    if (this._mode == Skew.ShakingMode.USE_TYPES && type != null && type.symbol != null) {\n      this._recordUsage(type.symbol);\n\n      // This should be a tree too, so infinite loops should not happen\n      if (type.isParameterized()) {\n        for (var i = 0, list = type.substitutions, count = list.length; i < count; i = i + 1 | 0) {\n          var substitution = in_List.get(list, i);\n          this._visitType(substitution);\n        }\n      }\n    }\n  };\n\n  Skew.UsageGraph.prototype._includeSymbol = function(symbol) {\n    in_IntMap.set(this._allSymbols, symbol.id, symbol);\n  };\n\n  Skew.Shaking = {};\n\n  Skew.Shaking.collectExportedSymbols = function(symbol, symbols, entryPoint) {\n    for (var i = 0, list = symbol.objects, count = list.length; i < count; i = i + 1 | 0) {\n      var object = in_List.get(list, i);\n      Skew.Shaking.collectExportedSymbols(object, symbols, entryPoint);\n\n      if (object.isExported()) {\n        symbols.push(object);\n      }\n    }\n\n    for (var i1 = 0, list1 = symbol.functions, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n      var $function = in_List.get(list1, i1);\n\n      if ($function.isExported() || $function == entryPoint) {\n        symbols.push($function);\n      }\n    }\n\n    for (var i2 = 0, list2 = symbol.variables, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n      var variable = in_List.get(list2, i2);\n\n      if (variable.isExported()) {\n        symbols.push(variable);\n      }\n    }\n  };\n\n  Skew.Shaking.removeUnusedSymbols = function(symbol, usages) {\n    in_List.removeIf(symbol.objects, function(object) {\n      return !usages.has(object.id);\n    });\n    in_List.removeIf(symbol.functions, function($function) {\n      return !usages.has($function.id);\n    });\n    in_List.removeIf(symbol.variables, function(variable) {\n      return !usages.has(variable.id);\n    });\n\n    for (var i = 0, list = symbol.objects, count = list.length; i < count; i = i + 1 | 0) {\n      var object = in_List.get(list, i);\n      Skew.Shaking.removeUnusedSymbols(object, usages);\n    }\n  };\n\n  Skew.Resolving = {};\n\n  Skew.Resolving.ConversionKind = {\n    IMPLICIT: 0,\n    EXPLICIT: 1\n  };\n\n  Skew.Resolving.SymbolStatistic = {\n    READ: 0,\n    WRITE: 1\n  };\n\n  Skew.Resolving.LocalVariableStatistics = function(symbol) {\n    this.symbol = symbol;\n    this.readCount = 0;\n    this.writeCount = 0;\n  };\n\n  Skew.Resolving.LocalVariableStatistics.SORT_BY_ID = function(a, b) {\n    return in_int.compare(a.symbol.id, b.symbol.id);\n  };\n\n  Skew.Resolving.Resolver = function(_global, _options, _defines, _cache, _log) {\n    this._global = _global;\n    this._options = _options;\n    this._defines = _defines;\n    this._cache = _cache;\n    this._log = _log;\n    this._foreachLoops = [];\n    this._localVariableStatistics = new Map();\n    this._controlFlow = new Skew.ControlFlowAnalyzer();\n    this._generatedGlobalVariables = [];\n    this._constantFolder = null;\n    this._isMergingGuards = true;\n  };\n\n  Skew.Resolving.Resolver.prototype.resolve = function() {\n    var self = this;\n    self._constantFolder = new Skew.Folding.ConstantFolder(self._cache, self._options, function(symbol) {\n      self._initializeSymbol(symbol);\n    });\n    self._initializeGlobals();\n    self._iterativelyMergeGuards();\n    self._resolveGlobal();\n    self._removeObsoleteFunctions(self._global);\n    in_List.insert1(self._global.variables, 0, self._generatedGlobalVariables);\n  };\n\n  // Put the guts of the function inside another function because V8 doesn't\n  // optimize functions with try-catch statements\n  Skew.Resolving.Resolver.prototype._initializeSymbolSwitch = function(symbol) {\n    switch (symbol.kind) {\n      case Skew.SymbolKind.OBJECT_CLASS:\n      case Skew.SymbolKind.OBJECT_ENUM:\n      case Skew.SymbolKind.OBJECT_FLAGS:\n      case Skew.SymbolKind.OBJECT_GLOBAL:\n      case Skew.SymbolKind.OBJECT_INTERFACE:\n      case Skew.SymbolKind.OBJECT_NAMESPACE:\n      case Skew.SymbolKind.OBJECT_WRAPPED: {\n        this._initializeObject(symbol.asObjectSymbol());\n        break;\n      }\n\n      case Skew.SymbolKind.FUNCTION_ANNOTATION:\n      case Skew.SymbolKind.FUNCTION_CONSTRUCTOR:\n      case Skew.SymbolKind.FUNCTION_GLOBAL:\n      case Skew.SymbolKind.FUNCTION_INSTANCE:\n      case Skew.SymbolKind.FUNCTION_LOCAL: {\n        this._initializeFunction(symbol.asFunctionSymbol());\n        break;\n      }\n\n      case Skew.SymbolKind.VARIABLE_ARGUMENT:\n      case Skew.SymbolKind.VARIABLE_ENUM_OR_FLAGS:\n      case Skew.SymbolKind.VARIABLE_GLOBAL:\n      case Skew.SymbolKind.VARIABLE_INSTANCE:\n      case Skew.SymbolKind.VARIABLE_LOCAL: {\n        this._initializeVariable(symbol.asVariableSymbol());\n        break;\n      }\n\n      case Skew.SymbolKind.PARAMETER_FUNCTION:\n      case Skew.SymbolKind.PARAMETER_OBJECT: {\n        this._initializeParameter(symbol.asParameterSymbol());\n        break;\n      }\n\n      case Skew.SymbolKind.OVERLOADED_ANNOTATION:\n      case Skew.SymbolKind.OVERLOADED_GLOBAL:\n      case Skew.SymbolKind.OVERLOADED_INSTANCE: {\n        this._initializeOverloadedFunction(symbol.asOverloadedFunctionSymbol());\n        break;\n      }\n\n      default: {\n        assert(false);\n        break;\n      }\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._initializeSymbol = function(symbol) {\n    // The scope should have been set by the merging pass (or by this pass for local variables)\n    assert(symbol.scope != null);\n\n    // Only initialize the symbol once\n    if (symbol.state == Skew.SymbolState.UNINITIALIZED) {\n      symbol.state = Skew.SymbolState.INITIALIZING;\n\n      try {\n        this._initializeSymbolSwitch(symbol);\n      }\n\n      catch (failure) {\n        if (failure instanceof Skew.Resolving.Resolver.GuardMergingFailure) {\n          symbol.state = Skew.SymbolState.UNINITIALIZED;\n\n          throw failure;\n        }\n\n        else {\n          throw failure;\n        }\n      }\n\n      assert(symbol.resolvedType != null);\n      symbol.state = Skew.SymbolState.INITIALIZED;\n\n      if (Skew.in_SymbolKind.isFunction(symbol.kind)) {\n        var $function = symbol.asFunctionSymbol();\n        var overloaded = $function.overloaded;\n\n        // After initializing a function symbol, ensure the entire overload set is initialized\n        if (overloaded != null && overloaded.state == Skew.SymbolState.UNINITIALIZED) {\n          this._initializeSymbol(overloaded);\n        }\n      }\n    }\n\n    // Detect cyclic symbol references such as \"foo foo;\"\n    else if (symbol.state == Skew.SymbolState.INITIALIZING) {\n      this._log.semanticErrorCyclicDeclaration(symbol.range, symbol.name);\n      symbol.resolvedType = Skew.Type.DYNAMIC;\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._validateEntryPoint = function(symbol) {\n    // Detect duplicate entry points\n    if (this._cache.entryPointSymbol != null) {\n      this._log.semanticErrorDuplicateEntryPoint(symbol.range, this._cache.entryPointSymbol.range);\n      return;\n    }\n\n    this._cache.entryPointSymbol = symbol;\n\n    // Only recognize a few entry point types\n    var type = symbol.resolvedType;\n\n    if (type != Skew.Type.DYNAMIC) {\n      var argumentTypes = type.argumentTypes;\n\n      // The argument list must be empty or one argument of type \"List<string>\"\n      if (argumentTypes.length > 1 || argumentTypes.length == 1 && in_List.first(argumentTypes) != this._cache.createListType(this._cache.stringType)) {\n        this._log.semanticErrorInvalidEntryPointArguments(Skew.Range.span(in_List.first(symbol.$arguments).range, in_List.last(symbol.$arguments).type.range), symbol.name);\n      }\n\n      // The return type must be nothing or \"int\"\n      else if (type.returnType != null && type.returnType != this._cache.intType) {\n        this._log.semanticErrorInvalidEntryPointReturnType(symbol.returnType.range, symbol.name);\n      }\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveDefines = function(symbol) {\n    var key = symbol.fullName();\n    var define = in_StringMap.get(this._defines, key, null);\n\n    if (define == null) {\n      return;\n    }\n\n    // Remove the define so we can tell what defines weren't used later on\n    this._defines.delete(key);\n    var type = symbol.resolvedType;\n    var range = define.value;\n    var value = range.toString();\n    var node = null;\n\n    // Special-case booleans\n    if (type == this._cache.boolType) {\n      if (value == 'true' || value == 'false') {\n        node = new Skew.Node(Skew.NodeKind.CONSTANT).withContent(new Skew.BoolContent(value == 'true'));\n      }\n    }\n\n    // Special-case doubles\n    else if (type == this._cache.doubleType) {\n      var number = +value;\n\n      if (!isNaN(number)) {\n        node = new Skew.Node(Skew.NodeKind.CONSTANT).withContent(new Skew.DoubleContent(number));\n      }\n    }\n\n    // Special-case strings\n    else if (type == this._cache.stringType) {\n      node = new Skew.Node(Skew.NodeKind.CONSTANT).withContent(new Skew.StringContent(value));\n    }\n\n    // Special-case enums\n    else if (type.isEnumOrFlags()) {\n      node = new Skew.Node(Skew.NodeKind.DOT).withContent(new Skew.StringContent(value)).appendChild(null);\n    }\n\n    // Integers can also apply to doubles\n    if (node == null && this._cache.isNumeric(type)) {\n      var box = Skew.Parsing.parseIntLiteral(this._log, range);\n\n      if (box != null) {\n        node = new Skew.Node(Skew.NodeKind.CONSTANT).withContent(new Skew.IntContent(box.value));\n      }\n    }\n\n    // Stop if anything failed above\n    if (node == null) {\n      this._log.semanticErrorInvalidDefine1(range, value, type, key);\n      return;\n    }\n\n    this._resolveAsParameterizedExpressionWithConversion(node.withRange(range), this._global.scope, type);\n    symbol.value = node;\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveAnnotations = function(symbol) {\n    var self = this;\n    var parent = symbol.parent;\n    var annotations = symbol.annotations;\n\n    // The import/export annotations are inherited, except import isn't inherited for implemented functions\n    if (parent != null) {\n      symbol.flags |= parent.flags & (Skew.in_SymbolKind.isFunction(symbol.kind) && symbol.asFunctionSymbol().block != null ? Skew.SymbolFlags.IS_EXPORTED : Skew.SymbolFlags.IS_IMPORTED | Skew.SymbolFlags.IS_EXPORTED);\n    }\n\n    // Resolve annotations on this symbol after annotation inheritance. Don't\n    // use removeIf() since this annotation list may be shared elsewhere.\n    if (annotations != null) {\n      symbol.annotations = annotations.filter(function(annotation) {\n        return self._resolveAnnotation(annotation, symbol);\n      });\n    }\n\n    // Protected access used to be an annotation. It's now indicated with just\n    // a leading underscore.\n    if (symbol.name.startsWith('_') && !Skew.in_SymbolKind.isLocal(symbol.kind)) {\n      symbol.flags |= Skew.SymbolFlags.IS_PROTECTED;\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveParameters = function(parameters) {\n    if (parameters != null) {\n      for (var i = 0, list = parameters, count = list.length; i < count; i = i + 1 | 0) {\n        var parameter = in_List.get(list, i);\n        this._resolveParameter(parameter);\n      }\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._initializeParameter = function(symbol) {\n    if (symbol.resolvedType == null) {\n      symbol.resolvedType = new Skew.Type(Skew.TypeKind.SYMBOL, symbol);\n    }\n\n    this._resolveAnnotations(symbol);\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveParameter = function(symbol) {\n    this._initializeSymbol(symbol);\n  };\n\n  Skew.Resolving.Resolver.prototype._initializeObject = function(symbol) {\n    var ref;\n    var kind = symbol.kind;\n    var $extends = symbol.$extends;\n    var $implements = symbol.$implements;\n\n    if (symbol.resolvedType == null) {\n      symbol.resolvedType = new Skew.Type(Skew.TypeKind.SYMBOL, symbol);\n    }\n\n    this._resolveParameters(symbol.parameters);\n\n    // Resolve the base type (only for classes and wrapped types)\n    if ($extends != null) {\n      this._resolveAsParameterizedType($extends, symbol.scope);\n      var baseType = $extends.resolvedType;\n\n      if (kind == Skew.SymbolKind.OBJECT_WRAPPED) {\n        symbol.wrappedType = baseType;\n\n        // Don't lose the type parameters from the base type\n        symbol.resolvedType.environment = baseType.environment;\n      }\n\n      else if (kind != Skew.SymbolKind.OBJECT_CLASS || baseType != Skew.Type.DYNAMIC && (!baseType.isClass() || baseType.symbol.isValueType())) {\n        this._log.semanticErrorInvalidExtends($extends.range, baseType);\n      }\n\n      else if (baseType != Skew.Type.DYNAMIC) {\n        symbol.baseType = baseType;\n        symbol.baseClass = baseType.symbol.asObjectSymbol();\n\n        // Don't lose the type parameters from the base type\n        symbol.resolvedType.environment = baseType.environment;\n\n        // Copy members from the base type\n        var functions = [];\n        var members = Array.from(symbol.baseClass.members.values());\n\n        // Sort so the order is deterministic\n        members.sort(Skew.Symbol.SORT_BY_ID);\n\n        for (var i2 = 0, list1 = members, count1 = list1.length; i2 < count1; i2 = i2 + 1 | 0) {\n          var member = in_List.get(list1, i2);\n          var memberKind = member.kind;\n\n          // Separate out functions\n          if (Skew.in_SymbolKind.isFunction(memberKind)) {\n            if (memberKind != Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n              functions.push(member.asFunctionSymbol());\n            }\n          }\n\n          // Include overloaded functions individually\n          else if (Skew.in_SymbolKind.isOverloadedFunction(memberKind)) {\n            for (var i1 = 0, list = member.asOverloadedFunctionSymbol().symbols, count = list.length; i1 < count; i1 = i1 + 1 | 0) {\n              var $function = in_List.get(list, i1);\n\n              if ($function.kind != Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n                functions.push($function);\n              }\n            }\n          }\n\n          // Other kinds\n          else if (!Skew.in_SymbolKind.isParameter(memberKind)) {\n            var other = in_StringMap.get(symbol.members, member.name, null);\n\n            if (other != null) {\n              this._log.semanticErrorBadOverride(other.range, other.name, baseType, member.range);\n            }\n\n            else {\n              in_StringMap.set(symbol.members, member.name, member);\n            }\n          }\n        }\n\n        Skew.Merging.mergeFunctions(this._log, symbol, functions, Skew.Merging.MergeBehavior.INTO_DERIVED_CLASS);\n      }\n    }\n\n    // Wrapped types without something to wrap don't make sense\n    else if (kind == Skew.SymbolKind.OBJECT_WRAPPED) {\n      this._log.semanticErrorMissingWrappedType(symbol.range, symbol.fullName());\n\n      // Make sure to fill out the wrapped type anyway so code that tries to\n      // access it doesn't crash. The dynamic type should ignore further errors.\n      symbol.wrappedType = Skew.Type.DYNAMIC;\n    }\n\n    // Resolve the base interface types\n    if ($implements != null) {\n      symbol.interfaceTypes = [];\n\n      for (var i = 0, count2 = $implements.length; i < count2; i = i + 1 | 0) {\n        var type = in_List.get($implements, i);\n        this._resolveAsParameterizedType(type, symbol.scope);\n\n        // Ignore the dynamic type, which will be from errors and dynamic expressions used for exports\n        var interfaceType = type.resolvedType;\n\n        if (interfaceType == Skew.Type.DYNAMIC) {\n          continue;\n        }\n\n        // Only classes can derive from interfaces\n        if (kind != Skew.SymbolKind.OBJECT_CLASS || !interfaceType.isInterface()) {\n          this._log.semanticErrorInvalidImplements(type.range, interfaceType);\n          continue;\n        }\n\n        // An interface can only be implemented once\n        for (var j = 0; j < i; j = j + 1 | 0) {\n          var other1 = in_List.get($implements, j);\n\n          if (other1.resolvedType == interfaceType) {\n            this._log.semanticErrorDuplicateImplements(type.range, interfaceType, other1.range);\n            break;\n          }\n        }\n\n        symbol.interfaceTypes.push(interfaceType);\n      }\n    }\n\n    // Assign values for all enums and flags before they are initialized\n    if (Skew.in_SymbolKind.isEnumOrFlags(kind)) {\n      var nextValue = 0;\n\n      for (var i3 = 0, list2 = symbol.variables, count3 = list2.length; i3 < count3; i3 = i3 + 1 | 0) {\n        var variable = in_List.get(list2, i3);\n\n        if (variable.kind == Skew.SymbolKind.VARIABLE_ENUM_OR_FLAGS) {\n          if (nextValue >= 32 && kind == Skew.SymbolKind.OBJECT_FLAGS) {\n            this._log.semanticErrorTooManyFlags(variable.range, symbol.name);\n          }\n\n          variable.value = new Skew.Node(Skew.NodeKind.CONSTANT).withContent(new Skew.IntContent(kind == Skew.SymbolKind.OBJECT_FLAGS ? 1 << nextValue : nextValue)).withType(symbol.resolvedType).withRange(variable.range);\n          nextValue = nextValue + 1 | 0;\n        }\n      }\n\n      symbol.flags |= Skew.SymbolFlags.IS_VALUE_TYPE;\n    }\n\n    this._resolveAnnotations(symbol);\n\n    // Create a default constructor if one doesn't exist\n    var $constructor = in_StringMap.get(symbol.members, 'new', null);\n\n    if (kind == Skew.SymbolKind.OBJECT_CLASS && !symbol.isImported() && $constructor == null) {\n      var baseConstructor = (ref = symbol.baseClass) != null ? in_StringMap.get(ref.members, 'new', null) : null;\n\n      // Unwrap the overload group if present\n      if (baseConstructor != null && baseConstructor.kind == Skew.SymbolKind.OVERLOADED_GLOBAL) {\n        var overloaded = baseConstructor.asOverloadedFunctionSymbol();\n\n        for (var i4 = 0, list3 = overloaded.symbols, count4 = list3.length; i4 < count4; i4 = i4 + 1 | 0) {\n          var overload = in_List.get(list3, i4);\n\n          if (overload.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n            if (baseConstructor.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n              // Signal that there isn't a single base constructor\n              baseConstructor = null;\n              break;\n            }\n\n            baseConstructor = overload;\n          }\n        }\n      }\n\n      // A default constructor can only be created if the base class has a single constructor\n      if (symbol.baseClass == null || baseConstructor != null && baseConstructor.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n        var generated = new Skew.FunctionSymbol(Skew.SymbolKind.FUNCTION_CONSTRUCTOR, 'new');\n        generated.scope = new Skew.FunctionScope(symbol.scope, generated);\n        generated.flags |= Skew.SymbolFlags.IS_AUTOMATICALLY_GENERATED;\n        generated.parent = symbol;\n        generated.range = symbol.range;\n        generated.overridden = baseConstructor != null ? baseConstructor.asFunctionSymbol() : null;\n        symbol.functions.push(generated);\n        in_StringMap.set(symbol.members, generated.name, generated);\n      }\n    }\n\n    // Create a default toString if one doesn't exist\n    if (kind == Skew.SymbolKind.OBJECT_ENUM && !symbol.isImported() && !symbol.members.has('toString')) {\n      var generated1 = new Skew.FunctionSymbol(Skew.SymbolKind.FUNCTION_INSTANCE, 'toString');\n      generated1.scope = new Skew.FunctionScope(symbol.scope, generated1);\n      generated1.flags |= Skew.SymbolFlags.IS_AUTOMATICALLY_GENERATED | Skew.SymbolFlags.IS_INLINING_FORCED;\n      this._options.isAlwaysInlinePresent = true;\n      generated1.parent = symbol;\n      generated1.range = symbol.range;\n      symbol.functions.push(generated1);\n      in_StringMap.set(symbol.members, generated1.name, generated1);\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._checkInterfacesAndAbstractStatus1 = function(object, $function) {\n    assert($function.kind == Skew.SymbolKind.FUNCTION_INSTANCE);\n    assert($function.state == Skew.SymbolState.INITIALIZED);\n\n    if (!object.isAbstract() && !$function.isImported() && !$function.isObsolete() && $function.block == null) {\n      object.isAbstractBecauseOf = $function;\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._checkInterfacesAndAbstractStatus2 = function(symbol) {\n    assert(symbol.state == Skew.SymbolState.INITIALIZED);\n\n    if (symbol.hasCheckedInterfacesAndAbstractStatus || symbol.kind != Skew.SymbolKind.OBJECT_CLASS) {\n      return;\n    }\n\n    symbol.hasCheckedInterfacesAndAbstractStatus = true;\n\n    // Check to see if this class is abstract (has unimplemented members)\n    var members = Array.from(symbol.members.values());\n\n    // Sort so the order is deterministic\n    members.sort(Skew.Symbol.SORT_BY_ID);\n\n    for (var i1 = 0, list1 = members, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n      var member = in_List.get(list1, i1);\n\n      if (member.kind == Skew.SymbolKind.OVERLOADED_INSTANCE) {\n        this._initializeSymbol(member);\n\n        for (var i = 0, list = member.asOverloadedFunctionSymbol().symbols, count = list.length; i < count; i = i + 1 | 0) {\n          var $function = in_List.get(list, i);\n          this._checkInterfacesAndAbstractStatus1(symbol, $function);\n        }\n      }\n\n      else if (member.kind == Skew.SymbolKind.FUNCTION_INSTANCE) {\n        this._initializeSymbol(member);\n        this._checkInterfacesAndAbstractStatus1(symbol, member.asFunctionSymbol());\n      }\n\n      if (symbol.isAbstract()) {\n        break;\n      }\n    }\n\n    // Check interfaces for missing implementations\n    if (symbol.interfaceTypes != null) {\n      for (var i4 = 0, list4 = symbol.interfaceTypes, count4 = list4.length; i4 < count4; i4 = i4 + 1 | 0) {\n        var interfaceType = in_List.get(list4, i4);\n\n        for (var i3 = 0, list3 = interfaceType.symbol.asObjectSymbol().functions, count3 = list3.length; i3 < count3; i3 = i3 + 1 | 0) {\n          var function1 = in_List.get(list3, i3);\n\n          if (function1.kind != Skew.SymbolKind.FUNCTION_INSTANCE || function1.block != null) {\n            continue;\n          }\n\n          this._initializeSymbol(function1);\n          var member1 = in_StringMap.get(symbol.members, function1.name, null);\n          var match = null;\n          var equivalence = Skew.TypeCache.Equivalence.NOT_EQUIVALENT;\n\n          // Search for a matching function\n          if (member1 != null) {\n            this._initializeSymbol(member1);\n\n            if (member1.kind == Skew.SymbolKind.OVERLOADED_INSTANCE) {\n              for (var i2 = 0, list2 = member1.asOverloadedFunctionSymbol().symbols, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n                var other = in_List.get(list2, i2);\n                equivalence = this._cache.areFunctionSymbolsEquivalent(function1, interfaceType.environment, other, null);\n\n                if (equivalence != Skew.TypeCache.Equivalence.NOT_EQUIVALENT) {\n                  match = other;\n                  break;\n                }\n              }\n            }\n\n            else if (member1.kind == Skew.SymbolKind.FUNCTION_INSTANCE) {\n              equivalence = this._cache.areFunctionSymbolsEquivalent(function1, interfaceType.environment, member1.asFunctionSymbol(), null);\n\n              if (equivalence != Skew.TypeCache.Equivalence.NOT_EQUIVALENT) {\n                match = member1.asFunctionSymbol();\n              }\n            }\n          }\n\n          // Validate use of the interface\n          if (match == null) {\n            this._log.semanticErrorBadInterfaceImplementation(symbol.range, symbol.resolvedType, interfaceType, function1.name, function1.range);\n          }\n\n          else if (equivalence == Skew.TypeCache.Equivalence.EQUIVALENT_EXCEPT_RETURN_TYPE) {\n            var returnType = function1.resolvedType.returnType;\n\n            if (returnType != null) {\n              returnType = this._cache.substitute(returnType, interfaceType.environment);\n            }\n\n            this._log.semanticErrorBadInterfaceImplementationReturnType(match.range, match.name, match.resolvedType.returnType, this._cache.substituteFunctionParameters(returnType, match, function1), interfaceType, function1.range);\n          }\n\n          else {\n            if (function1.implementations == null) {\n              function1.implementations = [];\n            }\n\n            function1.implementations.push(match);\n          }\n        }\n      }\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._initializeGlobals = function() {\n    this._initializeSymbol(this._cache.boolType.symbol);\n    this._initializeSymbol(this._cache.doubleType.symbol);\n    this._initializeSymbol(this._cache.intMapType.symbol);\n    this._initializeSymbol(this._cache.intType.symbol);\n    this._initializeSymbol(this._cache.listType.symbol);\n    this._initializeSymbol(this._cache.stringMapType.symbol);\n    this._initializeSymbol(this._cache.stringType.symbol);\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveGlobal = function() {\n    this._resolveObject(this._global);\n    this._scanLocalVariables();\n    this._convertForeachLoops();\n    this._discardUnusedDefines();\n  };\n\n  // An obsolete function is one without an implementation that was dropped in\n  // favor of one with an implementation:\n  //\n  //   namespace Foo {\n  //     def foo {}\n  //\n  //     # This will be marked as obsolete\n  //     def foo\n  //   }\n  //\n  Skew.Resolving.Resolver.prototype._removeObsoleteFunctions = function(symbol) {\n    for (var i = 0, list = symbol.objects, count = list.length; i < count; i = i + 1 | 0) {\n      var object = in_List.get(list, i);\n      this._removeObsoleteFunctions(object);\n    }\n\n    in_List.removeIf(symbol.functions, function($function) {\n      return $function.isObsolete();\n    });\n  };\n\n  Skew.Resolving.Resolver.prototype._iterativelyMergeGuards = function() {\n    var guards = null;\n\n    // Iterate until a fixed point is reached\n    while (true) {\n      guards = [];\n      this._scanForGuards(this._global, guards);\n\n      if (guards.length == 0) {\n        break;\n      }\n\n      // Each iteration must remove at least one guard to continue\n      if (!this._processGuards(guards)) {\n        break;\n      }\n    }\n\n    this._isMergingGuards = false;\n\n    // All remaining guards are errors\n    for (var i = 0, list = guards, count1 = list.length; i < count1; i = i + 1 | 0) {\n      var guard = in_List.get(list, i);\n      var count = this._log.errorCount();\n      this._resolveAsParameterizedExpressionWithConversion(guard.test, guard.parent.scope, this._cache.boolType);\n\n      if (this._log.errorCount() == count) {\n        this._log.semanticErrorExpectedConstant(guard.test.range);\n      }\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._scanForGuards = function(symbol, guards) {\n    if (symbol.guards != null) {\n      in_List.append1(guards, symbol.guards);\n    }\n\n    for (var i = 0, list = symbol.objects, count = list.length; i < count; i = i + 1 | 0) {\n      var object = in_List.get(list, i);\n      this._scanForGuards(object, guards);\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._reportGuardMergingFailure = function(node) {\n    if (this._isMergingGuards) {\n      throw new Skew.Resolving.Resolver.GuardMergingFailure();\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._attemptToResolveGuardConstant = function(node, scope) {\n    assert(scope != null);\n\n    try {\n      this._resolveAsParameterizedExpressionWithConversion(node, scope, this._cache.boolType);\n      this._constantFolder.foldConstants(node);\n      return true;\n    }\n\n    catch (failure) {\n      if (!(failure instanceof Skew.Resolving.Resolver.GuardMergingFailure)) {\n        throw failure;\n      }\n    }\n\n    return false;\n  };\n\n  Skew.Resolving.Resolver.prototype._processGuards = function(guards) {\n    var wasGuardRemoved = false;\n\n    for (var i = 0, list = guards, count = list.length; i < count; i = i + 1 | 0) {\n      var guard = in_List.get(list, i);\n      var test = guard.test;\n      var parent = guard.parent;\n\n      // If it's not a constant, we'll just try again in the next iteration\n      if (!this._attemptToResolveGuardConstant(test, parent.scope)) {\n        continue;\n      }\n\n      if (test.isBool()) {\n        in_List.removeOne(parent.guards, guard);\n        wasGuardRemoved = true;\n\n        if (test.isTrue()) {\n          this._mergeGuardIntoObject(guard, parent);\n        }\n\n        else {\n          var elseGuard = guard.elseGuard;\n\n          if (elseGuard != null) {\n            if (elseGuard.test != null) {\n              elseGuard.parent = parent;\n              parent.guards.push(elseGuard);\n            }\n\n            else {\n              this._mergeGuardIntoObject(elseGuard, parent);\n            }\n          }\n        }\n      }\n    }\n\n    return wasGuardRemoved;\n  };\n\n  Skew.Resolving.Resolver.prototype._mergeGuardIntoObject = function(guard, object) {\n    var symbol = guard.contents;\n    Skew.Merging.mergeObjects(this._log, object, symbol.objects);\n    Skew.Merging.mergeFunctions(this._log, object, symbol.functions, Skew.Merging.MergeBehavior.NORMAL);\n    Skew.Merging.mergeVariables(this._log, object, symbol.variables);\n    in_List.append1(object.objects, symbol.objects);\n    in_List.append1(object.functions, symbol.functions);\n    in_List.append1(object.variables, symbol.variables);\n\n    // Handle nested guard clauses like this:\n    //\n    //   if true {\n    //     if true {\n    //       var foo = 0\n    //     }\n    //   }\n    //\n    if (symbol.guards != null) {\n      for (var i = 0, list = symbol.guards, count = list.length; i < count; i = i + 1 | 0) {\n        var nested = in_List.get(list, i);\n        object.guards.push(nested);\n\n        for (var g = nested; g != null; g = g.elseGuard) {\n          g.parent = object;\n          g.contents.parent = object;\n        }\n      }\n    }\n  };\n\n  // Foreach loops are converted to for loops after everything is resolved\n  // because that process needs to generate symbol names and it's much easier\n  // to generate non-conflicting symbol names after all local variables have\n  // been defined.\n  Skew.Resolving.Resolver.prototype._convertForeachLoops = function() {\n    for (var i = 0, list1 = this._foreachLoops, count2 = list1.length; i < count2; i = i + 1 | 0) {\n      var node = in_List.get(list1, i);\n      var symbol = node.symbol.asVariableSymbol();\n\n      // Generate names at the function level to avoid conflicts with local scopes\n      var scope = symbol.scope.findEnclosingFunctionOrLambda();\n      var value = node.foreachValue();\n      var block = node.foreachBlock();\n\n      // Handle \"for i in 0..10\"\n      if (value.kind == Skew.NodeKind.PAIR) {\n        var first = value.firstValue();\n        var second = value.secondValue();\n        symbol.flags &= ~Skew.SymbolFlags.IS_CONST;\n        symbol.value = first.remove();\n        var setup = new Skew.Node(Skew.NodeKind.VARIABLES).appendChild(Skew.Node.createVariable(symbol));\n        var symbolName = Skew.Node.createSymbolReference(symbol);\n        var update = Skew.Node.createUnary(Skew.NodeKind.PREFIX_INCREMENT, symbolName);\n        var test = null;\n\n        // Special-case constant iteration limits to generate simpler code\n        if (second.kind == Skew.NodeKind.CONSTANT || second.kind == Skew.NodeKind.NAME && second.symbol != null && second.symbol.isConst()) {\n          test = Skew.Node.createBinary(Skew.NodeKind.LESS_THAN, symbolName.clone(), second.remove());\n        }\n\n        // Otherwise, save the iteration limit in case it changes during iteration\n        else {\n          var count = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_LOCAL, scope.generateName('count'));\n          count.initializeWithType(this._cache.intType);\n          count.value = second.remove();\n          setup.appendChild(Skew.Node.createVariable(count));\n          test = Skew.Node.createBinary(Skew.NodeKind.LESS_THAN, symbolName.clone(), Skew.Node.createSymbolReference(count));\n        }\n\n        // Use a C-style for loop to implement this foreach loop\n        node.become(Skew.Node.createFor(setup, test, update, block.remove()).withComments(node.comments).withRange(node.range));\n\n        // Make sure the new expressions are resolved\n        this._resolveNode(test, symbol.scope, null);\n        this._resolveNode(update, symbol.scope, null);\n      }\n\n      else if (this._cache.isList(value.resolvedType) && !this._options.target.supportsListForeach()) {\n        // Create the index variable\n        var index = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_LOCAL, scope.generateName('i'));\n        index.initializeWithType(this._cache.intType);\n        index.value = this._cache.createInt(0);\n        var setup1 = new Skew.Node(Skew.NodeKind.VARIABLES).appendChild(Skew.Node.createVariable(index));\n        var indexName = Skew.Node.createSymbolReference(index);\n\n        // Create the list variable\n        var list = null;\n\n        if (value.kind == Skew.NodeKind.NAME && value.symbol != null && Skew.in_SymbolKind.isVariable(value.symbol.kind) && value.symbol.isConst()) {\n          list = value.symbol.asVariableSymbol();\n        }\n\n        else {\n          list = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_LOCAL, scope.generateName('list'));\n          list.initializeWithType(value.resolvedType);\n          list.value = value.remove();\n          setup1.appendChild(Skew.Node.createVariable(list));\n        }\n\n        var listName = Skew.Node.createSymbolReference(list);\n\n        // Create the count variable\n        var count1 = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_LOCAL, scope.generateName('count'));\n        count1.initializeWithType(this._cache.intType);\n        count1.value = new Skew.Node(Skew.NodeKind.DOT).withContent(new Skew.StringContent('count')).appendChild(listName);\n        setup1.appendChild(Skew.Node.createVariable(count1));\n        var countName = Skew.Node.createSymbolReference(count1);\n\n        // Move the loop variable into the loop body\n        symbol.value = Skew.Node.createIndex(listName.clone(), indexName);\n        block.prependChild(new Skew.Node(Skew.NodeKind.VARIABLES).appendChild(Skew.Node.createVariable(symbol)));\n\n        // Use a C-style for loop to implement this foreach loop\n        var test1 = Skew.Node.createBinary(Skew.NodeKind.LESS_THAN, indexName.clone(), countName);\n        var update1 = Skew.Node.createUnary(Skew.NodeKind.PREFIX_INCREMENT, indexName.clone());\n        node.become(Skew.Node.createFor(setup1, test1, update1, block.remove()).withComments(node.comments).withRange(node.range));\n\n        // Make sure the new expressions are resolved\n        this._resolveNode(symbol.value, symbol.scope, null);\n        this._resolveNode(count1.value, symbol.scope, null);\n        this._resolveNode(test1, symbol.scope, null);\n        this._resolveNode(update1, symbol.scope, null);\n      }\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._scanLocalVariables = function() {\n    var values = Array.from(this._localVariableStatistics.values());\n\n    // Sort so the order is deterministic\n    values.sort(Skew.Resolving.LocalVariableStatistics.SORT_BY_ID);\n\n    for (var i = 0, list = values, count = list.length; i < count; i = i + 1 | 0) {\n      var info = in_List.get(list, i);\n      var symbol = info.symbol;\n\n      // Variables that are never re-assigned can safely be considered constants for constant folding\n      if (info.writeCount == 0 && this._options.foldAllConstants) {\n        symbol.flags |= Skew.SymbolFlags.IS_CONST;\n      }\n\n      // Unused local variables can safely be removed, but don't warn about \"for i in 0..10 {}\"\n      if (info.readCount == 0 && !symbol.isLoopVariable() && symbol.kind == Skew.SymbolKind.VARIABLE_LOCAL) {\n        this._log.semanticWarningUnreadLocalVariable(symbol.range, symbol.name);\n      }\n\n      // Rename local variables that conflict\n      var scope = symbol.scope;\n\n      while (scope.kind() == Skew.ScopeKind.LOCAL) {\n        scope = scope.parent;\n      }\n\n      if (scope.used != null && in_StringMap.get(scope.used, symbol.name, null) != symbol) {\n        symbol.name = scope.generateName(symbol.name);\n      }\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._discardUnusedDefines = function() {\n    var keys = Array.from(this._defines.keys());\n\n    // Sort so the order is deterministic\n    keys.sort(function(a, b) {\n      return in_string.compare(a, b);\n    });\n\n    for (var i = 0, list = keys, count = list.length; i < count; i = i + 1 | 0) {\n      var key = in_List.get(list, i);\n      this._log.semanticErrorInvalidDefine2(in_StringMap.get1(this._defines, key).name, key);\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveObject = function(symbol) {\n    this._initializeSymbol(symbol);\n\n    for (var i = 0, list = symbol.objects, count = list.length; i < count; i = i + 1 | 0) {\n      var object = in_List.get(list, i);\n      this._resolveObject(object);\n    }\n\n    for (var i1 = 0, list1 = symbol.functions, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n      var $function = in_List.get(list1, i1);\n      this._resolveFunction($function);\n    }\n\n    for (var i2 = 0, list2 = symbol.variables, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n      var variable = in_List.get(list2, i2);\n      this._resolveVariable1(variable);\n    }\n\n    this._checkInterfacesAndAbstractStatus2(symbol);\n  };\n\n  Skew.Resolving.Resolver.prototype._initializeFunction = function(symbol) {\n    if (symbol.resolvedType == null) {\n      symbol.resolvedType = new Skew.Type(Skew.TypeKind.SYMBOL, symbol);\n    }\n\n    // Referencing a normal variable instead of a special node kind for \"this\"\n    // makes many things much easier including lambda capture and devirtualization\n    if (symbol.kind == Skew.SymbolKind.FUNCTION_INSTANCE || symbol.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n      var $this = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_ARGUMENT, 'self');\n      $this.initializeWithType(this._cache.parameterize(symbol.parent.resolvedType));\n      $this.flags |= Skew.SymbolFlags.IS_CONST;\n      symbol.$this = $this;\n    }\n\n    // Lazily-initialize automatically generated functions\n    if (symbol.isAutomaticallyGenerated()) {\n      if (symbol.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n        assert(symbol.name == 'new');\n        this._automaticallyGenerateClassConstructor(symbol);\n      }\n\n      else if (symbol.kind == Skew.SymbolKind.FUNCTION_INSTANCE) {\n        assert(symbol.name == 'toString');\n        this._automaticallyGenerateEnumToString(symbol);\n      }\n    }\n\n    this._resolveParameters(symbol.parameters);\n\n    // Resolve the argument variables\n    symbol.resolvedType.argumentTypes = [];\n\n    for (var i = 0, list = symbol.$arguments, count1 = list.length; i < count1; i = i + 1 | 0) {\n      var argument = in_List.get(list, i);\n      argument.scope = symbol.scope;\n      this._resolveVariable1(argument);\n      symbol.resolvedType.argumentTypes.push(argument.resolvedType);\n    }\n\n    symbol.argumentOnlyType = this._cache.createLambdaType(symbol.resolvedType.argumentTypes, null);\n\n    // Resolve the return type if present (no return type means \"void\")\n    var returnType = null;\n\n    if (symbol.returnType != null) {\n      if (symbol.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n        this._log.semanticErrorConstructorReturnType(symbol.returnType.range);\n      }\n\n      // Explicitly handle a \"void\" return type for better error messages\n      else if (symbol.returnType.kind == Skew.NodeKind.NAME && symbol.returnType.asString() == 'void' && symbol.scope.find('void', Skew.ScopeSearch.NORMAL) == null) {\n        this._log.semanticErrorVoidReturnType(symbol.returnType.range);\n      }\n\n      else {\n        this._resolveAsParameterizedType(symbol.returnType, symbol.scope);\n        returnType = symbol.returnType.resolvedType;\n      }\n    }\n\n    // Constructors always return the type they construct\n    if (symbol.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n      returnType = this._cache.parameterize(symbol.parent.resolvedType);\n      symbol.returnType = new Skew.Node(Skew.NodeKind.TYPE).withType(returnType);\n    }\n\n    // The \"<=>\" operator must return a numeric value for comparison with zero\n    var count = symbol.$arguments.length;\n\n    if (symbol.name == '<=>') {\n      if (returnType == null || returnType != this._cache.intType) {\n        this._log.semanticErrorComparisonOperatorNotInt(symbol.returnType != null ? symbol.returnType.range : symbol.range);\n        returnType = Skew.Type.DYNAMIC;\n      }\n\n      else if (count != 1) {\n        this._log.semanticErrorWrongArgumentCount(symbol.range, symbol.name, 1);\n      }\n    }\n\n    // Setters must have one argument\n    else if (symbol.isSetter() && count != 1) {\n      this._log.semanticErrorWrongArgumentCount(symbol.range, symbol.name, 1);\n      symbol.flags &= ~Skew.SymbolFlags.IS_SETTER;\n    }\n\n    // Validate argument count\n    else {\n      var argumentCount = Skew.argumentCountForOperator(symbol.name);\n\n      if (argumentCount != null && !(argumentCount.indexOf(count) != -1)) {\n        this._log.semanticErrorWrongArgumentCountRange(symbol.range, symbol.name, argumentCount);\n      }\n\n      // Enforce that the initializer constructor operators take lists of\n      // values to avoid confusing error messages inside the code generated\n      // for initializer expressions\n      else if (symbol.name == '{new}' || symbol.name == '[new]') {\n        for (var i1 = 0, list1 = symbol.$arguments, count2 = list1.length; i1 < count2; i1 = i1 + 1 | 0) {\n          var argument1 = in_List.get(list1, i1);\n\n          if (argument1.resolvedType != Skew.Type.DYNAMIC && !this._cache.isList(argument1.resolvedType)) {\n            this._log.semanticErrorExpectedList(argument1.range, argument1.name, argument1.resolvedType);\n          }\n        }\n      }\n    }\n\n    symbol.resolvedType.returnType = returnType;\n    this._resolveAnnotations(symbol);\n\n    // Validate the entry point after this symbol has a type\n    if (symbol.isEntryPoint()) {\n      this._validateEntryPoint(symbol);\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._automaticallyGenerateClassConstructor = function(symbol) {\n    // Create the function body\n    var block = new Skew.Node(Skew.NodeKind.BLOCK);\n    symbol.block = block;\n\n    // Mirror the base constructor's arguments\n    if (symbol.overridden != null) {\n      this._initializeSymbol(symbol.overridden);\n      var $arguments = symbol.overridden.$arguments;\n      var base = new Skew.Node(Skew.NodeKind.SUPER).withRange(symbol.overridden.range);\n\n      if ($arguments.length == 0) {\n        block.appendChild(Skew.Node.createExpression(base));\n      }\n\n      else {\n        var call = Skew.Node.createCall(base);\n\n        for (var i = 0, list = $arguments, count = list.length; i < count; i = i + 1 | 0) {\n          var variable = in_List.get(list, i);\n          var argument = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_ARGUMENT, variable.name);\n          argument.range = variable.range;\n          argument.initializeWithType(variable.resolvedType);\n          symbol.$arguments.push(argument);\n          call.appendChild(Skew.Node.createSymbolReference(argument));\n        }\n\n        block.prependChild(Skew.Node.createExpression(call));\n      }\n    }\n\n    // Add an argument for every uninitialized variable\n    var parent = symbol.parent.asObjectSymbol();\n    this._initializeSymbol(parent);\n\n    for (var i1 = 0, list1 = parent.variables, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n      var variable1 = in_List.get(list1, i1);\n\n      if (variable1.kind == Skew.SymbolKind.VARIABLE_INSTANCE) {\n        this._initializeSymbol(variable1);\n\n        if (variable1.value == null) {\n          var argument1 = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_ARGUMENT, variable1.name);\n          argument1.initializeWithType(variable1.resolvedType);\n          argument1.range = variable1.range;\n          symbol.$arguments.push(argument1);\n          block.appendChild(Skew.Node.createExpression(Skew.Node.createBinary(Skew.NodeKind.ASSIGN, Skew.Node.createMemberReference(Skew.Node.createSymbolReference(symbol.$this), variable1), Skew.Node.createSymbolReference(argument1)).withRange(variable1.range)));\n        }\n\n        else {\n          block.appendChild(Skew.Node.createExpression(Skew.Node.createBinary(Skew.NodeKind.ASSIGN, Skew.Node.createMemberReference(Skew.Node.createSymbolReference(symbol.$this), variable1), variable1.value.clone()).withRange(variable1.range)));\n        }\n      }\n    }\n\n    // Make constructors without arguments into getters\n    if (symbol.$arguments.length == 0) {\n      symbol.flags |= Skew.SymbolFlags.IS_GETTER;\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._automaticallyGenerateEnumToString = function(symbol) {\n    var parent = symbol.parent.asObjectSymbol();\n    var names = new Skew.Node(Skew.NodeKind.INITIALIZER_LIST);\n    this._initializeSymbol(parent);\n    symbol.returnType = new Skew.Node(Skew.NodeKind.TYPE).withType(this._cache.stringType);\n    symbol.flags |= Skew.SymbolFlags.IS_GETTER;\n\n    // TypeScript has special enum-to-string support that we can use instead\n    if (this._options.target instanceof Skew.TypeScriptTarget) {\n      var target = new Skew.Node(Skew.NodeKind.NAME).withContent(new Skew.StringContent(parent.name)).withSymbol(parent).withType(Skew.Type.DYNAMIC);\n      symbol.block = new Skew.Node(Skew.NodeKind.BLOCK).appendChild(Skew.Node.createReturn(Skew.Node.createIndex(target, new Skew.Node(Skew.NodeKind.NAME).withContent(new Skew.StringContent('self')))));\n      return;\n    }\n\n    for (var i = 0, list = parent.variables, count = list.length; i < count; i = i + 1 | 0) {\n      var variable = in_List.get(list, i);\n\n      if (variable.kind == Skew.SymbolKind.VARIABLE_ENUM_OR_FLAGS) {\n        assert(variable.value.asInt() == names.childCount());\n        names.appendChild(new Skew.Node(Skew.NodeKind.CONSTANT).withContent(new Skew.StringContent(variable.name)));\n      }\n    }\n\n    var strings = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_GLOBAL, parent.scope.generateName('_strings'));\n    strings.range = parent.range;\n    strings.initializeWithType(this._cache.createListType(this._cache.stringType));\n    strings.value = names;\n    strings.flags |= Skew.SymbolFlags.IS_PROTECTED | Skew.SymbolFlags.IS_CONST | Skew.SymbolFlags.IS_AUTOMATICALLY_GENERATED;\n    strings.parent = parent;\n    strings.scope = parent.scope;\n    parent.variables.push(strings);\n    this._resolveAsParameterizedExpressionWithConversion(strings.value, strings.scope, strings.resolvedType);\n    symbol.block = new Skew.Node(Skew.NodeKind.BLOCK).appendChild(Skew.Node.createReturn(Skew.Node.createIndex(Skew.Node.createSymbolReference(strings), new Skew.Node(Skew.NodeKind.NAME).withContent(new Skew.StringContent('self')))));\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveFunction = function(symbol) {\n    this._initializeSymbol(symbol);\n\n    // Validate use of \"def\" vs \"over\"\n    if (!symbol.isObsolete()) {\n      if (symbol.overridden != null && symbol.kind == Skew.SymbolKind.FUNCTION_INSTANCE) {\n        if (!symbol.isOver()) {\n          this._log.semanticErrorModifierMissingOverride(symbol.range, symbol.name, symbol.overridden.range);\n        }\n      }\n\n      else if (symbol.isOver()) {\n        this._log.semanticErrorModifierUnusedOverride(symbol.range, symbol.name);\n      }\n    }\n\n    var scope = new Skew.LocalScope(symbol.scope, Skew.LocalType.NORMAL);\n\n    if (symbol.$this != null) {\n      scope.define(symbol.$this, this._log);\n    }\n\n    // Default values for argument variables aren't resolved with this local\n    // scope since they are evaluated at the call site, not inside the\n    // function body, and shouldn't have access to other arguments\n    for (var i = 0, list = symbol.$arguments, count = list.length; i < count; i = i + 1 | 0) {\n      var argument = in_List.get(list, i);\n      scope.define(argument, this._log);\n      in_IntMap.set(this._localVariableStatistics, argument.id, new Skew.Resolving.LocalVariableStatistics(argument));\n    }\n\n    // The function is considered abstract if the body is missing\n    var block = symbol.block;\n\n    if (block != null) {\n      var firstStatement = block.firstChild();\n\n      if (firstStatement != null && firstStatement.isSuperCallStatement()) {\n        firstStatement = firstStatement.nextSibling();\n      }\n\n      // User-specified constructors have variable initializers automatically inserted\n      if (symbol.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR && !symbol.isAutomaticallyGenerated()) {\n        for (var i1 = 0, list1 = symbol.parent.asObjectSymbol().variables, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n          var variable = in_List.get(list1, i1);\n\n          if (variable.kind == Skew.SymbolKind.VARIABLE_INSTANCE) {\n            this._resolveVariable1(variable);\n\n            // Attempt to create a default value if absent. Right now this\n            // avoids the problem of initializing type parameters:\n            //\n            //   class Foo<T> {\n            //     var foo T\n            //     def new {}\n            //     def use T { return foo }\n            //   }\n            //\n            // This should be fixed at some point.\n            if (variable.value == null && !variable.resolvedType.isParameter()) {\n              variable.value = this._createDefaultValueForType(variable.resolvedType, variable.range);\n            }\n\n            if (variable.value != null) {\n              block.insertChildBefore(firstStatement, Skew.Node.createExpression(Skew.Node.createBinary(Skew.NodeKind.ASSIGN, Skew.Node.createMemberReference(Skew.Node.createSymbolReference(symbol.$this), variable), variable.value.clone())));\n            }\n          }\n        }\n      }\n\n      // Skip resolving irrelevant function bodies to speed up code completion\n      var context = this._options.completionContext;\n\n      if (context != null && block.range != null && block.range.source != context.source) {\n        return;\n      }\n\n      this._resolveNode(block, scope, null);\n\n      // Missing a return statement is an error\n      if (symbol.kind != Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {\n        var returnType = symbol.resolvedType.returnType;\n\n        if (returnType != null && !symbol.isDynamicLambda() && block.hasControlFlowAtEnd()) {\n          this._log.semanticErrorMissingReturn(symbol.range, symbol.name, returnType);\n        }\n      }\n\n      // Derived class constructors must start with a call to \"super\"\n      else if (symbol.parent.asObjectSymbol().baseClass != null) {\n        var first = block.firstChild();\n\n        if (first == null || !first.isSuperCallStatement()) {\n          this._log.semanticErrorMissingSuper(firstStatement == null ? symbol.range : firstStatement.range);\n        }\n      }\n    }\n\n    // Global functions and functions on non-virtual types can't be abstract\n    else if (!symbol.isImported() && !symbol.isObsolete() && (symbol.kind == Skew.SymbolKind.FUNCTION_GLOBAL || symbol.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR || symbol.kind == Skew.SymbolKind.FUNCTION_INSTANCE && symbol.parent.kind != Skew.SymbolKind.OBJECT_CLASS && symbol.parent.kind != Skew.SymbolKind.OBJECT_INTERFACE)) {\n      this._log.semanticErrorUnimplementedFunction(symbol.range, symbol.name);\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._recordStatistic = function(symbol, statistic) {\n    if (symbol != null && (symbol.kind == Skew.SymbolKind.VARIABLE_LOCAL || symbol.kind == Skew.SymbolKind.VARIABLE_ARGUMENT)) {\n      var info = in_IntMap.get(this._localVariableStatistics, symbol.id, null);\n\n      if (info != null) {\n        switch (statistic) {\n          case Skew.Resolving.SymbolStatistic.READ: {\n            info.readCount = info.readCount + 1 | 0;\n            break;\n          }\n\n          case Skew.Resolving.SymbolStatistic.WRITE: {\n            info.writeCount = info.writeCount + 1 | 0;\n            break;\n          }\n        }\n      }\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._initializeVariable = function(symbol) {\n    var value = symbol.value;\n\n    // Normal variables may omit the initializer if the type is present\n    if (symbol.type != null) {\n      this._resolveAsParameterizedType(symbol.type, symbol.scope);\n      symbol.resolvedType = symbol.type.resolvedType;\n      symbol.state = Skew.SymbolState.INITIALIZED;\n\n      // Resolve the constant now so initialized constants always have a value\n      if (symbol.isConst() && value != null) {\n        this._resolveAsParameterizedExpressionWithConversion(value, symbol.scope, symbol.resolvedType);\n      }\n    }\n\n    // Enums take their type from their parent\n    else if (symbol.kind == Skew.SymbolKind.VARIABLE_ENUM_OR_FLAGS) {\n      symbol.resolvedType = symbol.parent.resolvedType;\n    }\n\n    // Implicitly-typed variables take their type from their initializer\n    else if (value != null) {\n      this._resolveAsParameterizedExpression(value, symbol.scope);\n      var type = value.resolvedType;\n      symbol.resolvedType = type;\n\n      // Forbid certain types\n      if (!Skew.Resolving.Resolver._isValidVariableType(type)) {\n        this._log.semanticErrorBadImplicitVariableType(symbol.range, type);\n        symbol.resolvedType = Skew.Type.DYNAMIC;\n      }\n    }\n\n    // Use a different error for constants which must have a type and lambda arguments which cannot have an initializer\n    else if (symbol.isConst() || symbol.scope.kind() == Skew.ScopeKind.FUNCTION && symbol.scope.asFunctionScope().symbol.kind == Skew.SymbolKind.FUNCTION_LOCAL) {\n      this._log.semanticErrorVarMissingType(symbol.range, symbol.name);\n      symbol.resolvedType = Skew.Type.DYNAMIC;\n    }\n\n    // Variables without a type are an error\n    else {\n      this._log.semanticErrorVarMissingValue(symbol.range, symbol.name);\n      symbol.resolvedType = Skew.Type.DYNAMIC;\n    }\n\n    // Make sure the symbol has a type node\n    if (symbol.type == null) {\n      symbol.type = new Skew.Node(Skew.NodeKind.TYPE).withType(symbol.resolvedType);\n    }\n\n    this._resolveDefines(symbol);\n    this._resolveAnnotations(symbol);\n\n    // Run post-annotation checks\n    if (symbol.resolvedType != Skew.Type.DYNAMIC && symbol.isConst() && !symbol.isImported() && value == null && symbol.kind != Skew.SymbolKind.VARIABLE_ENUM_OR_FLAGS && symbol.kind != Skew.SymbolKind.VARIABLE_INSTANCE) {\n      this._log.semanticErrorConstMissingValue(symbol.range, symbol.name);\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveVariable1 = function(symbol) {\n    this._initializeSymbol(symbol);\n\n    if (symbol.value != null) {\n      this._resolveAsParameterizedExpressionWithConversion(symbol.value, symbol.scope, symbol.resolvedType);\n    }\n\n    // Default-initialize variables\n    else if (symbol.kind != Skew.SymbolKind.VARIABLE_ARGUMENT && symbol.kind != Skew.SymbolKind.VARIABLE_INSTANCE && symbol.kind != Skew.SymbolKind.VARIABLE_ENUM_OR_FLAGS) {\n      symbol.value = this._createDefaultValueForType(symbol.resolvedType, symbol.range);\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._createDefaultValueForType = function(type, range) {\n    var unwrapped = this._cache.unwrappedType(type);\n\n    if (unwrapped == this._cache.intType) {\n      return new Skew.Node(Skew.NodeKind.CONSTANT).withContent(new Skew.IntContent(0)).withType(type);\n    }\n\n    if (unwrapped == this._cache.doubleType) {\n      return new Skew.Node(Skew.NodeKind.CONSTANT).withContent(new Skew.DoubleContent(0)).withType(type);\n    }\n\n    if (unwrapped == this._cache.boolType) {\n      return new Skew.Node(Skew.NodeKind.CONSTANT).withContent(new Skew.BoolContent(false)).withType(type);\n    }\n\n    if (unwrapped.isEnumOrFlags()) {\n      return Skew.Node.createCast(this._cache.createInt(0), new Skew.Node(Skew.NodeKind.TYPE).withType(type)).withType(type);\n    }\n\n    if (unwrapped.isParameter()) {\n      this._log.semanticErrorNoDefaultValue(range, type);\n      return null;\n    }\n\n    assert(unwrapped.isReference());\n    return new Skew.Node(Skew.NodeKind.NULL).withType(type);\n  };\n\n  Skew.Resolving.Resolver.prototype._initializeOverloadedFunction = function(symbol) {\n    var symbols = symbol.symbols;\n\n    if (symbol.resolvedType == null) {\n      symbol.resolvedType = new Skew.Type(Skew.TypeKind.SYMBOL, symbol);\n    }\n\n    // Ensure no two overloads have the same argument types\n    var i = 0;\n\n    while (i < symbols.length) {\n      var $function = in_List.get(symbols, i);\n      this._initializeSymbol($function);\n      symbol.flags |= $function.flags & Skew.SymbolFlags.IS_SETTER;\n      var equivalence = Skew.TypeCache.Equivalence.NOT_EQUIVALENT;\n      var index = -1;\n\n      for (var j = 0, count = i; j < count; j = j + 1 | 0) {\n        equivalence = this._cache.areFunctionSymbolsEquivalent($function, null, in_List.get(symbols, j), null);\n\n        if (equivalence != Skew.TypeCache.Equivalence.NOT_EQUIVALENT) {\n          index = j;\n          break;\n        }\n      }\n\n      if (index == -1) {\n        i = i + 1 | 0;\n        continue;\n      }\n\n      var other = in_List.get(symbols, index);\n      var parent = symbol.parent.asObjectSymbol();\n      var isFromSameObject = $function.parent == other.parent;\n      var areReturnTypesDifferent = equivalence == Skew.TypeCache.Equivalence.EQUIVALENT_EXCEPT_RETURN_TYPE && (isFromSameObject || symbol.kind == Skew.SymbolKind.OVERLOADED_INSTANCE);\n\n      // Symbols should be in the base type chain\n      assert(parent.isSameOrHasBaseClass($function.parent));\n      assert(parent.isSameOrHasBaseClass(other.parent));\n\n      // Forbid overloading by return type\n      if (!isFromSameObject && areReturnTypesDifferent) {\n        var derived = $function.parent == parent ? $function : other;\n        var base = derived == $function ? other : $function;\n        this._log.semanticErrorBadOverrideReturnType(derived.range, derived.name, parent.baseType, base.range);\n\n        if (isFromSameObject) {\n          $function.flags |= Skew.SymbolFlags.IS_OBSOLETE;\n        }\n      }\n\n      // Allow duplicate function declarations with the same type to merge\n      // as long as there are not two declarations that provide implementations.\n      // Mark the obsolete function as obsolete instead of removing it so it\n      // doesn't potentially mess up iteration in a parent call stack.\n      else if (areReturnTypesDifferent || isFromSameObject && $function.block != null && other.block != null) {\n        this._log.semanticErrorDuplicateOverload($function.range, symbol.name, other.range);\n\n        if (isFromSameObject) {\n          $function.flags |= Skew.SymbolFlags.IS_OBSOLETE;\n        }\n      }\n\n      // Keep \"function\"\n      else if (isFromSameObject ? $function.block != null : $function.parent.asObjectSymbol().hasBaseClass(other.parent)) {\n        if ($function.parent == parent && other.parent == parent) {\n          $function.mergeInformationFrom(other);\n          $function.flags |= $function.block != null ? other.flags & ~Skew.SymbolFlags.IS_IMPORTED : other.flags;\n          other.flags |= Skew.SymbolFlags.IS_OBSOLETE;\n        }\n\n        else if (!isFromSameObject) {\n          $function.overridden = other;\n        }\n\n        in_List.set(symbols, index, $function);\n      }\n\n      // Keep \"other\"\n      else if ($function.parent == parent && other.parent == parent) {\n        other.flags |= other.block != null ? $function.flags & ~Skew.SymbolFlags.IS_IMPORTED : $function.flags;\n        other.mergeInformationFrom($function);\n        $function.flags |= Skew.SymbolFlags.IS_OBSOLETE;\n      }\n\n      else if (!isFromSameObject) {\n        other.overridden = $function;\n      }\n\n      // Remove the symbol after the merge\n      in_List.removeAt(symbols, i);\n    }\n  };\n\n  // Put the guts of the function inside another function because V8 doesn't\n  // optimize functions with try-catch statements\n  Skew.Resolving.Resolver.prototype._resolveNodeSwitch = function(node, scope, context) {\n    switch (node.kind) {\n      case Skew.NodeKind.BLOCK: {\n        this._resolveBlock(node, scope);\n        break;\n      }\n\n      case Skew.NodeKind.PAIR: {\n        this._resolvePair(node, scope, context);\n        break;\n      }\n\n      // Statements\n      case Skew.NodeKind.BREAK:\n      case Skew.NodeKind.CONTINUE: {\n        this._resolveJump(node, scope);\n        break;\n      }\n\n      case Skew.NodeKind.COMMENT_BLOCK: {\n        break;\n      }\n\n      case Skew.NodeKind.EXPRESSION: {\n        this._resolveExpression(node, scope);\n        break;\n      }\n\n      case Skew.NodeKind.FOR: {\n        this._resolveFor(node, scope);\n        break;\n      }\n\n      case Skew.NodeKind.FOREACH: {\n        this._resolveForeach(node, scope);\n        break;\n      }\n\n      case Skew.NodeKind.IF: {\n        this._resolveIf(node, scope);\n        break;\n      }\n\n      case Skew.NodeKind.RETURN: {\n        this._resolveReturn(node, scope);\n        break;\n      }\n\n      case Skew.NodeKind.SWITCH: {\n        this._resolveSwitch(node, scope);\n        break;\n      }\n\n      case Skew.NodeKind.THROW: {\n        this._resolveThrow(node, scope);\n        break;\n      }\n\n      case Skew.NodeKind.TRY: {\n        this._resolveTry(node, scope);\n        break;\n      }\n\n      case Skew.NodeKind.VARIABLE: {\n        this._resolveVariable2(node, scope);\n        break;\n      }\n\n      case Skew.NodeKind.VARIABLES: {\n        this._resolveVariables(node, scope);\n        break;\n      }\n\n      case Skew.NodeKind.WHILE: {\n        this._resolveWhile(node, scope);\n        break;\n      }\n\n      // Expressions\n      case Skew.NodeKind.ASSIGN_INDEX: {\n        this._resolveOperatorOverload(node, scope, context);\n        break;\n      }\n\n      case Skew.NodeKind.CALL: {\n        this._resolveCall(node, scope, context);\n        break;\n      }\n\n      case Skew.NodeKind.CAST: {\n        this._resolveCast(node, scope, context);\n        break;\n      }\n\n      case Skew.NodeKind.COMPLEMENT:\n      case Skew.NodeKind.NEGATIVE:\n      case Skew.NodeKind.NOT:\n      case Skew.NodeKind.POSITIVE:\n      case Skew.NodeKind.POSTFIX_DECREMENT:\n      case Skew.NodeKind.POSTFIX_INCREMENT:\n      case Skew.NodeKind.PREFIX_DECREMENT:\n      case Skew.NodeKind.PREFIX_INCREMENT: {\n        this._resolveOperatorOverload(node, scope, context);\n        break;\n      }\n\n      case Skew.NodeKind.CONSTANT: {\n        this._resolveConstant(node, scope, context);\n        break;\n      }\n\n      case Skew.NodeKind.DOT: {\n        this._resolveDot(node, scope, context);\n        break;\n      }\n\n      case Skew.NodeKind.HOOK: {\n        this._resolveHook(node, scope, context);\n        break;\n      }\n\n      case Skew.NodeKind.INDEX: {\n        this._resolveOperatorOverload(node, scope, context);\n        break;\n      }\n\n      case Skew.NodeKind.INITIALIZER_LIST:\n      case Skew.NodeKind.INITIALIZER_MAP: {\n        this._resolveInitializer(node, scope, context);\n        break;\n      }\n\n      case Skew.NodeKind.LAMBDA: {\n        this._resolveLambda(node, scope, context);\n        break;\n      }\n\n      case Skew.NodeKind.LAMBDA_TYPE: {\n        this._resolveLambdaType(node, scope);\n        break;\n      }\n\n      case Skew.NodeKind.NAME: {\n        this._resolveName(node, scope);\n        break;\n      }\n\n      case Skew.NodeKind.NULL: {\n        node.resolvedType = Skew.Type.NULL;\n        break;\n      }\n\n      case Skew.NodeKind.NULL_DOT: {\n        this._resolveNullDot(node, scope);\n        break;\n      }\n\n      case Skew.NodeKind.PARAMETERIZE: {\n        this._resolveParameterize(node, scope);\n        break;\n      }\n\n      case Skew.NodeKind.PARSE_ERROR: {\n        node.resolvedType = Skew.Type.DYNAMIC;\n        break;\n      }\n\n      case Skew.NodeKind.SEQUENCE: {\n        this._resolveSequence(node, scope, context);\n        break;\n      }\n\n      case Skew.NodeKind.STRING_INTERPOLATION: {\n        this._resolveStringInterpolation(node, scope);\n        break;\n      }\n\n      case Skew.NodeKind.SUPER: {\n        this._resolveSuper(node, scope);\n        break;\n      }\n\n      case Skew.NodeKind.TYPE: {\n        break;\n      }\n\n      case Skew.NodeKind.TYPE_CHECK: {\n        this._resolveTypeCheck(node, scope);\n        break;\n      }\n\n      case Skew.NodeKind.XML: {\n        this._resolveXML(node, scope);\n        break;\n      }\n\n      default: {\n        if (Skew.in_NodeKind.isBinary(node.kind)) {\n          this._resolveBinary(node, scope, context);\n        }\n\n        else {\n          assert(false);\n        }\n        break;\n      }\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveNode = function(node, scope, context) {\n    if (node.resolvedType != null) {\n      // Only resolve once\n      return;\n    }\n\n    node.resolvedType = Skew.Type.DYNAMIC;\n\n    try {\n      this._resolveNodeSwitch(node, scope, context);\n    }\n\n    catch (failure) {\n      if (failure instanceof Skew.Resolving.Resolver.GuardMergingFailure) {\n        node.resolvedType = null;\n\n        throw failure;\n      }\n\n      else {\n        throw failure;\n      }\n    }\n\n    assert(node.resolvedType != null);\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveAsParameterizedType = function(node, scope) {\n    assert(Skew.in_NodeKind.isExpression(node.kind));\n    node.flags |= Skew.NodeFlags.SHOULD_EXPECT_TYPE;\n    this._resolveNode(node, scope, null);\n    this._checkIsType(node);\n    this._checkIsParameterized(node);\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveAsParameterizedExpression = function(node, scope) {\n    assert(Skew.in_NodeKind.isExpression(node.kind));\n    this._resolveNode(node, scope, null);\n    this._checkIsInstance(node);\n    this._checkIsParameterized(node);\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveAsParameterizedExpressionWithTypeContext = function(node, scope, type) {\n    assert(Skew.in_NodeKind.isExpression(node.kind));\n    this._resolveNode(node, scope, type);\n    this._checkIsInstance(node);\n    this._checkIsParameterized(node);\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveAsParameterizedExpressionWithConversion = function(node, scope, type) {\n    this._resolveAsParameterizedExpressionWithTypeContext(node, scope, type);\n    this._checkConversion(node, type, Skew.Resolving.ConversionKind.IMPLICIT);\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveChildrenAsParameterizedExpressions = function(node, scope) {\n    for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n      this._resolveAsParameterizedExpression(child, scope);\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveChildrenAsParameterizedExpressionsWithDynamicTypeContext = function(node, scope) {\n    for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n      this._resolveAsParameterizedExpressionWithTypeContext(child, scope, Skew.Type.DYNAMIC);\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._checkUnusedExpression = function(node) {\n    var kind = node.kind;\n\n    if (kind == Skew.NodeKind.HOOK) {\n      this._checkUnusedExpression(node.hookTrue());\n      this._checkUnusedExpression(node.hookFalse());\n    }\n\n    else if (node.range != null && node.resolvedType != Skew.Type.DYNAMIC && kind != Skew.NodeKind.CALL && !Skew.in_NodeKind.isAssign(kind)) {\n      this._log.semanticWarningUnusedExpression(node.range);\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._checkIsInstance = function(node) {\n    if (node.resolvedType != Skew.Type.DYNAMIC && node.isType()) {\n      this._log.semanticErrorUnexpectedType(node.range, node.resolvedType);\n      node.resolvedType = Skew.Type.DYNAMIC;\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._checkIsType = function(node) {\n    if (node.resolvedType != Skew.Type.DYNAMIC && !node.isType()) {\n      this._log.semanticErrorUnexpectedExpression(node.range, node.resolvedType);\n      node.resolvedType = Skew.Type.DYNAMIC;\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._checkIsParameterized = function(node) {\n    if (node.resolvedType.parameters() != null && !node.resolvedType.isParameterized()) {\n      this._log.semanticErrorUnparameterizedType(node.range, node.resolvedType);\n      node.resolvedType = Skew.Type.DYNAMIC;\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._checkStorage = function(node, scope) {\n    var symbol = node.symbol;\n\n    // Only allow storage to variables\n    if (node.kind != Skew.NodeKind.NAME && node.kind != Skew.NodeKind.DOT && (node.kind != Skew.NodeKind.INDEX || node.resolvedType != Skew.Type.DYNAMIC) || symbol != null && !Skew.in_SymbolKind.isVariable(symbol.kind)) {\n      this._log.semanticErrorBadStorage(node.range);\n    }\n\n    // Forbid storage to constants\n    else if (symbol != null && symbol.isConst()) {\n      var $function = scope.findEnclosingFunction();\n\n      // Allow assignments to constants inside constructors\n      if ($function == null || $function.symbol.kind != Skew.SymbolKind.FUNCTION_CONSTRUCTOR || $function.symbol.parent != symbol.parent || symbol.kind != Skew.SymbolKind.VARIABLE_INSTANCE) {\n        this._log.semanticErrorStorageToConstSymbol(node.internalRangeOrRange(), symbol.name);\n      }\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._checkAccess = function(node, range, scope) {\n    var symbol = node.symbol;\n\n    if (symbol == null) {\n      return;\n    }\n\n    // Check access control\n    if (symbol.isProtected()) {\n      while (scope != null) {\n        if (scope.kind() == Skew.ScopeKind.OBJECT) {\n          var object = scope.asObjectScope().symbol;\n\n          if (object.isSameOrHasBaseClass(symbol.parent)) {\n            return;\n          }\n        }\n\n        scope = scope.parent;\n      }\n\n      this._log.semanticErrorAccessViolation(range, symbol.name);\n    }\n\n    // Deprecation annotations optionally provide a warning message\n    if (symbol.isDeprecated()) {\n      for (var i = 0, list = symbol.annotations, count = list.length; i < count; i = i + 1 | 0) {\n        var annotation = in_List.get(list, i);\n\n        if (annotation.symbol != null && annotation.symbol.fullName() == '@deprecated') {\n          var value = annotation.annotationValue();\n\n          if (value.kind == Skew.NodeKind.CALL && value.hasTwoChildren()) {\n            var last = value.lastChild();\n\n            if (last.kind == Skew.NodeKind.CONSTANT && last.content.kind() == Skew.ContentKind.STRING) {\n              this._log.append(this._log.newWarning(range, Skew.in_Content.asString(last.content)));\n              return;\n            }\n          }\n        }\n      }\n\n      this._log.semanticWarningDeprecatedUsage(range, symbol.name);\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._checkConversion = function(node, to, kind) {\n    var from = node.resolvedType;\n    assert(from != null);\n    assert(to != null);\n\n    // The \"dynamic\" type is a hole in the type system\n    if (from == Skew.Type.DYNAMIC || to == Skew.Type.DYNAMIC) {\n      return;\n    }\n\n    // No conversion is needed for identical types\n    if (from == to) {\n      return;\n    }\n\n    // The implicit conversion must be valid\n    if (kind == Skew.Resolving.ConversionKind.IMPLICIT && !this._cache.canImplicitlyConvert(from, to) || kind == Skew.Resolving.ConversionKind.EXPLICIT && !this._cache.canExplicitlyConvert(from, to)) {\n      this._log.semanticErrorIncompatibleTypes(node.range, from, to, this._cache.canExplicitlyConvert(from, to));\n      node.resolvedType = Skew.Type.DYNAMIC;\n      return;\n    }\n\n    // Make the implicit conversion explicit for convenience later on\n    if (kind == Skew.Resolving.ConversionKind.IMPLICIT) {\n      node.become(Skew.Node.createCast(node.cloneAndStealChildren(), new Skew.Node(Skew.NodeKind.TYPE).withType(to)).withType(to).withRange(node.range));\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveAnnotation = function(node, symbol) {\n    var value = node.annotationValue();\n    var test = node.annotationTest();\n    this._resolveNode(value, symbol.scope, null);\n\n    if (test != null) {\n      this._resolveAsParameterizedExpressionWithConversion(test, symbol.scope, this._cache.boolType);\n    }\n\n    // Terminate early when there were errors\n    if (value.symbol == null) {\n      return false;\n    }\n\n    // Make sure annotations have the arguments they need\n    if (value.kind != Skew.NodeKind.CALL) {\n      this._log.semanticErrorArgumentCount(value.range, value.symbol.resolvedType.argumentTypes.length, 0, value.symbol.name, value.symbol.range);\n      return false;\n    }\n\n    // Ensure all arguments are constants\n    var isValid = true;\n\n    for (var child = value.callValue().nextSibling(); child != null; child = child.nextSibling()) {\n      isValid = isValid && this._recursivelyResolveAsConstant(child);\n    }\n\n    if (!isValid) {\n      return false;\n    }\n\n    // Only store symbols for annotations with the correct arguments for ease of use\n    node.symbol = value.symbol;\n\n    // Apply built-in annotation logic\n    var flag = in_StringMap.get(Skew.Resolving.Resolver._annotationSymbolFlags, value.symbol.fullName(), 0);\n\n    if (flag != 0) {\n      switch (flag) {\n        case Skew.SymbolFlags.IS_DEPRECATED: {\n          break;\n        }\n\n        case Skew.SymbolFlags.IS_ENTRY_POINT: {\n          isValid = symbol.kind == Skew.SymbolKind.FUNCTION_GLOBAL;\n          break;\n        }\n\n        case Skew.SymbolFlags.IS_EXPORTED: {\n          isValid = !symbol.isImported();\n          break;\n        }\n\n        case Skew.SymbolFlags.IS_IMPORTED: {\n          isValid = !symbol.isExported() && (!Skew.in_SymbolKind.isFunction(symbol.kind) || symbol.asFunctionSymbol().block == null);\n          break;\n        }\n\n        case Skew.SymbolFlags.IS_INLINING_FORCED:\n        case Skew.SymbolFlags.IS_INLINING_PREVENTED:\n        case Skew.SymbolFlags.IS_PREFERRED: {\n          isValid = Skew.in_SymbolKind.isFunction(symbol.kind);\n          break;\n        }\n\n        case Skew.SymbolFlags.IS_RENAMED: {\n          break;\n        }\n\n        case Skew.SymbolFlags.IS_SKIPPED: {\n          isValid = Skew.in_SymbolKind.isFunction(symbol.kind) && symbol.resolvedType.returnType == null;\n          break;\n        }\n\n        case Skew.SymbolFlags.SHOULD_SPREAD: {\n          isValid = symbol.kind == Skew.SymbolKind.FUNCTION_ANNOTATION;\n          break;\n        }\n      }\n\n      if (flag == Skew.SymbolFlags.IS_INLINING_FORCED) {\n        this._options.isAlwaysInlinePresent = true;\n      }\n\n      if (!isValid) {\n        this._log.semanticErrorInvalidAnnotation(value.range, value.symbol.name, symbol.name);\n        return false;\n      }\n\n      // Don't add an annotation when the test expression is false\n      if (test != null && this._recursivelyResolveAsConstant(test) && test.isFalse()) {\n        return false;\n      }\n\n      // Only warn about duplicate annotations after checking the test expression\n      if ((symbol.flags & flag) != 0) {\n        if ((symbol.parent.flags & flag & (Skew.SymbolFlags.IS_IMPORTED | Skew.SymbolFlags.IS_EXPORTED)) != 0) {\n          this._log.semanticWarningRedundantAnnotation(value.range, value.symbol.name, symbol.name, symbol.parent.name);\n        }\n\n        else {\n          this._log.semanticWarningDuplicateAnnotation(value.range, value.symbol.name, symbol.name);\n        }\n      }\n\n      symbol.flags |= flag;\n\n      // Store the new name for later\n      if (flag == Skew.SymbolFlags.IS_RENAMED && value.hasTwoChildren()) {\n        symbol.rename = value.lastChild().asString();\n      }\n    }\n\n    return true;\n  };\n\n  Skew.Resolving.Resolver.prototype._recursivelyResolveAsConstant = function(node) {\n    this._constantFolder.foldConstants(node);\n\n    if (node.kind != Skew.NodeKind.CONSTANT) {\n      this._log.semanticErrorExpectedConstant(node.range);\n      return false;\n    }\n\n    return true;\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveBlock = function(node, scope) {\n    assert(node.kind == Skew.NodeKind.BLOCK);\n    this._controlFlow.pushBlock(node);\n\n    for (var child = node.firstChild(), next = null; child != null; child = next) {\n      var prev = child.previousSibling();\n      next = child.nextSibling();\n\n      // There is a well-known ambiguity in languages like JavaScript where\n      // a return statement followed by a newline and a value can either be\n      // parsed as a single return statement with a value or as two\n      // statements, a return statement without a value and an expression\n      // statement. Luckily, we're better off than JavaScript since we know\n      // the type of the function. Parse a single statement in a non-void\n      // function but two statements in a void function.\n      if (child.kind == Skew.NodeKind.RETURN && next != null && child.returnValue() == null && next.kind == Skew.NodeKind.EXPRESSION) {\n        var $function = scope.findEnclosingFunctionOrLambda().symbol;\n\n        if ($function.kind != Skew.SymbolKind.FUNCTION_CONSTRUCTOR && $function.resolvedType.returnType != null) {\n          var statement = next.remove();\n          var value = statement.expressionValue().remove();\n          child.appendChild(value);\n          var trailing = Skew.Comment.lastTrailingComment(statement.comments);\n          var notTrailing = Skew.Comment.withoutLastTrailingComment(statement.comments);\n\n          if (trailing != null) {\n            child.comments = Skew.Comment.concat(child.comments, [trailing]);\n          }\n\n          value.comments = Skew.Comment.concat(notTrailing, value.comments);\n          next = child.nextSibling();\n          assert(child.returnValue() != null);\n        }\n      }\n\n      this._resolveNode(child, scope, null);\n\n      // Visit control flow from the previous node to the next node, which\n      // should handle the case where this node was replaced with something\n      for (var n = prev != null ? prev.nextSibling() : node.firstChild(); n != next; n = n.nextSibling()) {\n        this._controlFlow.visitStatementInPostOrder(n);\n      }\n\n      // Stop now if the child was removed\n      if (child.parent() == null) {\n        continue;\n      }\n\n      // The \"@skip\" annotation removes function calls after type checking\n      if (child.kind == Skew.NodeKind.EXPRESSION) {\n        var value1 = child.expressionValue();\n\n        if (value1.kind == Skew.NodeKind.CALL && value1.symbol != null && value1.symbol.isSkipped()) {\n          child.remove();\n        }\n      }\n    }\n\n    this._controlFlow.popBlock(node);\n  };\n\n  Skew.Resolving.Resolver.prototype._resolvePair = function(node, scope, context) {\n    // Allow resolving a pair with a type context of \"dynamic\" to\n    // deliberately silence errors around needing type context\n    if (context == Skew.Type.DYNAMIC) {\n      this._resolveAsParameterizedExpressionWithConversion(node.firstValue(), scope, context);\n      this._resolveAsParameterizedExpressionWithConversion(node.secondValue(), scope, context);\n      return;\n    }\n\n    this._resolveAsParameterizedExpression(node.firstValue(), scope);\n    this._resolveAsParameterizedExpression(node.secondValue(), scope);\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveJump = function(node, scope) {\n    if (scope.findEnclosingLoop() == null) {\n      this._log.semanticErrorBadJump(node.range, node.kind == Skew.NodeKind.BREAK ? 'break' : 'continue');\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveExpressionOrImplicitReturn = function(node, value, scope) {\n    var hook = this._sinkNullDotIntoHook(value, scope, null);\n\n    // Turn top-level \"?.\" expressions into if statements\n    if (hook != null) {\n      var test = hook.hookTest();\n      var yes = hook.hookTrue();\n      var block = new Skew.Node(Skew.NodeKind.BLOCK).appendChild(Skew.Node.createExpression(yes.remove()).withRange(yes.range)).withRange(yes.range);\n      node.become(Skew.Node.createIf(test.remove(), block, null).withRange(node.range).withComments(node.comments));\n      this._resolveNode(node, scope, null);\n    }\n\n    // Turn top-level \"?=\" expressions into if statements\n    else if (value.kind == Skew.NodeKind.ASSIGN_NULL) {\n      var left = value.binaryLeft();\n      var right = value.binaryRight();\n      this._resolveAsParameterizedExpressionWithTypeContext(left, scope, null);\n      this._checkStorage(left, scope);\n      var test1 = Skew.Node.createBinary(Skew.NodeKind.EQUAL, this._extractExpressionForAssignment(left, scope), new Skew.Node(Skew.NodeKind.NULL)).withRange(left.range);\n      var assign = Skew.Node.createBinary(Skew.NodeKind.ASSIGN, left.remove(), right.remove()).withRange(node.range).withFlags(Skew.NodeFlags.WAS_ASSIGN_NULL);\n      var block1 = new Skew.Node(Skew.NodeKind.BLOCK).appendChild(Skew.Node.createExpression(assign).withRange(node.range)).withRange(node.range);\n      node.become(Skew.Node.createIf(test1, block1, null).withRange(node.range).withComments(node.comments));\n      this._resolveNode(node, scope, null);\n    }\n\n    // Normal expression statement\n    else {\n      this._resolveAsParameterizedExpression(value, scope);\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveExpression = function(node, scope) {\n    var value = node.expressionValue();\n    this._resolveExpressionOrImplicitReturn(node, value, scope);\n\n    // Only continue this didn't get turned into an if statement due to a top-level \"?.\" or \"?=\" expression\n    if (node.kind == Skew.NodeKind.EXPRESSION) {\n      this._checkUnusedExpression(value);\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveFor = function(node, scope) {\n    var setup = node.forSetup();\n    var update = node.forUpdate();\n    scope = new Skew.LocalScope(scope, Skew.LocalType.LOOP);\n\n    if (setup.kind == Skew.NodeKind.VARIABLES) {\n      this._resolveNode(setup, scope, null);\n\n      // All for loop variables must have the same type. This is a requirement\n      // for one-to-one code emission in the languages we want to target.\n      var type = setup.firstChild().symbol.resolvedType;\n\n      for (var child = setup.firstChild().nextSibling(); child != null; child = child.nextSibling()) {\n        var symbol = child.symbol;\n\n        if (symbol.resolvedType != type) {\n          this._log.semanticErrorForLoopDifferentType(symbol.range, symbol.name, symbol.resolvedType, type);\n          break;\n        }\n      }\n    }\n\n    else {\n      this._resolveAsParameterizedExpression(setup, scope);\n    }\n\n    this._resolveAsParameterizedExpressionWithConversion(node.forTest(), scope, this._cache.boolType);\n    this._resolveAsParameterizedExpression(update, scope);\n\n    if (update.kind == Skew.NodeKind.SEQUENCE) {\n      for (var child1 = update.firstChild(); child1 != null; child1 = child1.nextSibling()) {\n        this._checkUnusedExpression(child1);\n      }\n    }\n\n    this._resolveBlock(node.forBlock(), scope);\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveForeach = function(node, scope) {\n    var type = Skew.Type.DYNAMIC;\n    scope = new Skew.LocalScope(scope, Skew.LocalType.LOOP);\n    var value = node.foreachValue();\n    this._resolveAsParameterizedExpression(value, scope);\n\n    // Support \"for i in 0..10\"\n    if (value.kind == Skew.NodeKind.PAIR) {\n      var first = value.firstValue();\n      var second = value.secondValue();\n      type = this._cache.intType;\n      this._checkConversion(first, this._cache.intType, Skew.Resolving.ConversionKind.IMPLICIT);\n      this._checkConversion(second, this._cache.intType, Skew.Resolving.ConversionKind.IMPLICIT);\n\n      // The \"..\" syntax only counts up, unlike CoffeeScript\n      if (first.isInt() && second.isInt() && first.asInt() >= second.asInt()) {\n        this._log.semanticWarningEmptyRange(value.range);\n      }\n    }\n\n    // Support \"for i in [1, 2, 3]\"\n    else if (this._cache.isList(value.resolvedType)) {\n      type = in_List.get(value.resolvedType.substitutions, 0);\n    }\n\n    // Anything else is an error\n    else if (value.resolvedType != Skew.Type.DYNAMIC) {\n      this._log.semanticErrorBadForValue(value.range, value.resolvedType);\n    }\n\n    // Special-case symbol initialization with the type\n    var symbol = node.symbol.asVariableSymbol();\n    scope.asLocalScope().define(symbol, this._log);\n    in_IntMap.set(this._localVariableStatistics, symbol.id, new Skew.Resolving.LocalVariableStatistics(symbol));\n    symbol.initializeWithType(type);\n    symbol.flags |= Skew.SymbolFlags.IS_CONST | Skew.SymbolFlags.IS_LOOP_VARIABLE;\n    this._resolveBlock(node.foreachBlock(), scope);\n\n    // Collect foreach loops and convert them in another pass\n    this._foreachLoops.push(node);\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveIf = function(node, scope) {\n    var test = node.ifTest();\n    var ifFalse = node.ifFalse();\n    this._resolveAsParameterizedExpressionWithConversion(test, scope, this._cache.boolType);\n    this._resolveBlock(node.ifTrue(), new Skew.LocalScope(scope, Skew.LocalType.NORMAL));\n\n    if (ifFalse != null) {\n      this._resolveBlock(ifFalse, new Skew.LocalScope(scope, Skew.LocalType.NORMAL));\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveReturn = function(node, scope) {\n    var value = node.returnValue();\n    var $function = scope.findEnclosingFunctionOrLambda().symbol;\n    var returnType = $function.kind != Skew.SymbolKind.FUNCTION_CONSTRUCTOR ? $function.resolvedType.returnType : null;\n\n    // Check for a returned value\n    if (value == null) {\n      if (returnType != null && !$function.isDynamicLambda()) {\n        this._log.semanticErrorExpectedReturnValue(node.range, returnType);\n      }\n\n      return;\n    }\n\n    // Check the type of the returned value\n    if (returnType != null) {\n      this._resolveAsParameterizedExpressionWithConversion(value, scope, returnType);\n\n      if ($function.shouldInferReturnType() && Skew.Resolving.Resolver._isCallReturningVoid(value)) {\n        node.kind = Skew.NodeKind.EXPRESSION;\n      }\n\n      return;\n    }\n\n    // If there's no return type, still check for other errors\n    if (node.isImplicitReturn()) {\n      this._resolveExpressionOrImplicitReturn(node, value, scope);\n\n      // Stop now if this got turned into an if statement due to a top-level \"?.\" or \"?=\" expression\n      if (node.kind != Skew.NodeKind.RETURN) {\n        return;\n      }\n    }\n\n    else {\n      this._resolveAsParameterizedExpression(value, scope);\n    }\n\n    // Lambdas without a return type or an explicit \"return\" statement get special treatment\n    if (!node.isImplicitReturn()) {\n      this._log.semanticErrorUnexpectedReturnValue(value.range);\n      return;\n    }\n\n    // Check for a return value of type \"void\"\n    if (!$function.shouldInferReturnType() || Skew.Resolving.Resolver._isCallReturningVoid(value)) {\n      this._checkUnusedExpression(value);\n      node.kind = Skew.NodeKind.EXPRESSION;\n      return;\n    }\n\n    // Check for an invalid return type\n    var type = value.resolvedType;\n\n    if (!Skew.Resolving.Resolver._isValidVariableType(type)) {\n      this._log.semanticErrorBadReturnType(value.range, type);\n      node.kind = Skew.NodeKind.EXPRESSION;\n      return;\n    }\n\n    // Mutate the return type to the type from the returned value\n    $function.returnType = new Skew.Node(Skew.NodeKind.TYPE).withType(type);\n    $function.resolvedType.returnType = type;\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveSwitch = function(node, scope) {\n    var duplicateCases = new Map();\n    var mustEnsureConstantIntegers = this._options.target.requiresIntegerSwitchStatements();\n    var allValuesAreIntegers = true;\n    var value = node.switchValue();\n    this._resolveAsParameterizedExpression(value, scope);\n\n    for (var child = value.nextSibling(); child != null; child = child.nextSibling()) {\n      var block = child.caseBlock();\n\n      // Resolve all case values\n      for (var caseValue = child.firstChild(); caseValue != block; caseValue = caseValue.nextSibling()) {\n        this._resolveAsParameterizedExpressionWithConversion(caseValue, scope, value.resolvedType);\n        var symbol = caseValue.symbol;\n        var integer = 0;\n\n        // Check for a constant variable, which may just be read-only with a\n        // value determined at runtime\n        if (symbol != null && (mustEnsureConstantIntegers ? symbol.kind == Skew.SymbolKind.VARIABLE_ENUM_OR_FLAGS : Skew.in_SymbolKind.isVariable(symbol.kind) && symbol.isConst())) {\n          var constant = this._constantFolder.constantForSymbol(symbol.asVariableSymbol());\n\n          if (constant == null || constant.kind() != Skew.ContentKind.INT) {\n            allValuesAreIntegers = false;\n            continue;\n          }\n\n          integer = Skew.in_Content.asInt(constant);\n        }\n\n        // Fall back to the constant folder only as a last resort because it\n        // mutates the syntax tree and harms readability\n        else {\n          this._constantFolder.foldConstants(caseValue);\n\n          if (!caseValue.isInt()) {\n            allValuesAreIntegers = false;\n            continue;\n          }\n\n          integer = caseValue.asInt();\n        }\n\n        // Duplicate case detection\n        var previous = in_IntMap.get(duplicateCases, integer, null);\n\n        if (previous != null) {\n          this._log.semanticErrorDuplicateCase(caseValue.range, previous);\n        }\n\n        else {\n          in_IntMap.set(duplicateCases, integer, caseValue.range);\n        }\n      }\n\n      // The default case must be last, makes changing into an if chain easier later\n      if (child.hasOneChild() && child.nextSibling() != null) {\n        this._log.semanticErrorDefaultCaseNotLast(child.range);\n      }\n\n      this._resolveBlock(block, new Skew.LocalScope(scope, Skew.LocalType.NORMAL));\n    }\n\n    // Fall back to an if statement if the case values aren't compile-time\n    // integer constants, which is requried by many language targets\n    if (!allValuesAreIntegers && mustEnsureConstantIntegers) {\n      this._convertSwitchToIfChain(node, scope);\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveThrow = function(node, scope) {\n    var value = node.throwValue();\n    this._resolveAsParameterizedExpression(value, scope);\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveVariable2 = function(node, scope) {\n    var symbol = node.symbol.asVariableSymbol();\n    scope.asLocalScope().define(symbol, this._log);\n    in_IntMap.set(this._localVariableStatistics, symbol.id, new Skew.Resolving.LocalVariableStatistics(symbol));\n    this._resolveVariable1(symbol);\n\n    // Make sure to parent any created values under the variable node\n    if (!node.hasChildren() && symbol.value != null) {\n      node.appendChild(symbol.value);\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveVariables = function(node, scope) {\n    for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n      this._resolveVariable2(child, scope);\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveTry = function(node, scope) {\n    var tryBlock = node.tryBlock();\n    var finallyBlock = node.finallyBlock();\n    this._resolveBlock(tryBlock, new Skew.LocalScope(scope, Skew.LocalType.NORMAL));\n\n    // Bare try statements catch all thrown values\n    if (node.hasOneChild()) {\n      node.appendChild(Skew.Node.createCatch(null, new Skew.Node(Skew.NodeKind.BLOCK)));\n    }\n\n    // Check catch statements\n    for (var child = tryBlock.nextSibling(); child != finallyBlock; child = child.nextSibling()) {\n      var childScope = new Skew.LocalScope(scope, Skew.LocalType.NORMAL);\n\n      if (child.symbol != null) {\n        var symbol = child.symbol.asVariableSymbol();\n        childScope.define(symbol, this._log);\n        this._resolveVariable1(symbol);\n      }\n\n      this._resolveBlock(child.catchBlock(), childScope);\n    }\n\n    // Check finally block\n    if (finallyBlock != null) {\n      this._resolveBlock(finallyBlock, new Skew.LocalScope(scope, Skew.LocalType.NORMAL));\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveWhile = function(node, scope) {\n    this._resolveAsParameterizedExpressionWithConversion(node.whileTest(), scope, this._cache.boolType);\n    this._resolveBlock(node.whileBlock(), new Skew.LocalScope(scope, Skew.LocalType.LOOP));\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveCall = function(node, scope, context) {\n    var hook = this._sinkNullDotIntoHook(node, scope, context);\n\n    if (hook != null) {\n      node.become(hook);\n      this._resolveAsParameterizedExpressionWithTypeContext(node, scope, context);\n      return;\n    }\n\n    var value = node.callValue();\n\n    // Take argument types from call argument values for immediately-invoked\n    // function expressions:\n    //\n    //   var foo = ((a, b) => a + b)(1, 2)\n    //   var bar int = ((a, b) => { return a + b })(1, 2)\n    //\n    if (value.kind == Skew.NodeKind.LAMBDA) {\n      var symbol = value.symbol.asFunctionSymbol();\n      var $arguments = symbol.$arguments;\n\n      if (node.childCount() == ($arguments.length + 1 | 0)) {\n        var child = value.nextSibling();\n\n        for (var i = 0, count = $arguments.length; i < count; i = i + 1 | 0) {\n          var argument = in_List.get($arguments, i);\n\n          if (argument.type == null) {\n            this._resolveAsParameterizedExpression(child, scope);\n            argument.type = new Skew.Node(Skew.NodeKind.TYPE).withType(child.resolvedType);\n          }\n\n          child = child.nextSibling();\n        }\n\n        if (context != null && symbol.returnType == null) {\n          symbol.returnType = new Skew.Node(Skew.NodeKind.TYPE).withType(context);\n        }\n      }\n    }\n\n    this._resolveAsParameterizedExpression(value, scope);\n    var type = value.resolvedType;\n\n    switch (type.kind) {\n      // Each function has its own type for simplicity\n      case Skew.TypeKind.SYMBOL: {\n        if (this._resolveSymbolCall(node, scope, type)) {\n          return;\n        }\n        break;\n      }\n\n      // Lambda types look like \"fn(int, int) int\"\n      case Skew.TypeKind.LAMBDA: {\n        if (this._resolveFunctionCall(node, scope, type)) {\n          return;\n        }\n        break;\n      }\n\n      // Can't call other types (the null type, for example)\n      default: {\n        if (type != Skew.Type.DYNAMIC) {\n          this._log.semanticErrorInvalidCall(node.internalRangeOrRange(), value.resolvedType);\n        }\n        break;\n      }\n    }\n\n    // If there was an error, resolve the arguments to check for further\n    // errors but use a dynamic type context to avoid introducing errors\n    for (var child1 = value.nextSibling(); child1 != null; child1 = child1.nextSibling()) {\n      this._resolveAsParameterizedExpressionWithConversion(child1, scope, Skew.Type.DYNAMIC);\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveSymbolCall = function(node, scope, type) {\n    var symbol = type.symbol;\n\n    // Getters are called implicitly, so explicitly calling one is an error.\n    // This error prevents a getter returning a lambda which is then called.\n    // To overcome this, wrap the call in parentheses:\n    //\n    //   def foo fn()\n    //\n    //   def bar {\n    //     foo()   # Error\n    //     (foo)() # Correct\n    //   }\n    //\n    if (symbol.isGetter() && Skew.Resolving.Resolver._isCallValue(node) && !node.callValue().isInsideParentheses()) {\n      if (symbol.resolvedType.returnType != null && symbol.resolvedType.returnType.kind == Skew.TypeKind.LAMBDA) {\n        this._log.semanticErrorGetterRequiresWrap(node.range, symbol.name, symbol.range);\n      }\n\n      else {\n        this._log.semanticErrorGetterCalledTwice(node.parent().internalRangeOrRange(), symbol.name, symbol.range);\n      }\n\n      this._resolveChildrenAsParameterizedExpressionsWithDynamicTypeContext(node, scope);\n      return false;\n    }\n\n    // Check for calling a function directly\n    if (Skew.in_SymbolKind.isFunction(symbol.kind)) {\n      return this._resolveFunctionCall(node, scope, type);\n    }\n\n    // Check for calling a set of functions, must not be ambiguous\n    if (Skew.in_SymbolKind.isOverloadedFunction(symbol.kind)) {\n      return this._resolveOverloadedFunctionCall(node, scope, type);\n    }\n\n    // Can't call other symbols\n    this._log.semanticErrorInvalidCall(node.internalRangeOrRange(), node.callValue().resolvedType);\n    return false;\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveFunctionCall = function(node, scope, type) {\n    var ref;\n    var $function = (ref = type.symbol) != null ? ref.asFunctionSymbol() : null;\n    var expected = type.argumentTypes.length;\n    var count = node.childCount() - 1 | 0;\n    node.symbol = $function;\n\n    // Use the return type even if there were errors\n    if (type.returnType != null) {\n      node.resolvedType = type.returnType;\n    }\n\n    // There is no \"void\" type, so make sure this return value isn't used\n    else if (Skew.Resolving.Resolver._isExpressionUsed(node)) {\n      if ($function != null) {\n        this._log.semanticErrorUseOfVoidFunction(node.range, $function.name, $function.range);\n      }\n\n      else {\n        this._log.semanticErrorUseOfVoidLambda(node.range);\n      }\n    }\n\n    // Check argument count\n    if (expected != count) {\n      this._log.semanticErrorArgumentCount(node.internalRangeOrRange(), expected, count, $function != null ? $function.name : null, $function != null ? $function.range : null);\n      this._resolveChildrenAsParameterizedExpressionsWithDynamicTypeContext(node, scope);\n      return false;\n    }\n\n    // Check argument types\n    var value = node.firstChild();\n    var child = value.nextSibling();\n\n    for (var i = 0, list = type.argumentTypes, count1 = list.length; i < count1; i = i + 1 | 0) {\n      var argumentType = in_List.get(list, i);\n      this._resolveAsParameterizedExpressionWithConversion(child, scope, argumentType);\n      child = child.nextSibling();\n    }\n\n    // Forbid constructing an abstract type\n    if ($function != null && $function.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR && value.kind != Skew.NodeKind.SUPER) {\n      this._checkInterfacesAndAbstractStatus2($function.parent.asObjectSymbol());\n      var reason = $function.parent.asObjectSymbol().isAbstractBecauseOf;\n\n      if (reason != null) {\n        this._log.semanticErrorAbstractNew(node.internalRangeOrRange(), $function.parent.resolvedType, reason.range, reason.name);\n      }\n    }\n\n    // Replace overloaded symbols with the chosen overload\n    if (value.kind == Skew.NodeKind.PARAMETERIZE) {\n      value = value.parameterizeValue();\n    }\n\n    if ($function != null && value.symbol != null && Skew.in_SymbolKind.isOverloadedFunction(value.symbol.kind) && value.symbol.asOverloadedFunctionSymbol().symbols.indexOf($function) != -1) {\n      value.symbol = $function;\n      value.resolvedType = type;\n    }\n\n    return true;\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveOverloadedFunction = function(range, node, scope, symbolType) {\n    var overloaded = symbolType.symbol.asOverloadedFunctionSymbol();\n    var firstArgument = node.firstChild().nextSibling();\n    var count = node.childCount() - 1 | 0;\n    var candidates = [];\n\n    // Filter by argument length and substitute using the current type environment\n    for (var i1 = 0, list = overloaded.symbols, count1 = list.length; i1 < count1; i1 = i1 + 1 | 0) {\n      var symbol = in_List.get(list, i1);\n\n      if (symbol.$arguments.length == count || overloaded.symbols.length == 1) {\n        candidates.push(this._cache.substitute(symbol.resolvedType, symbolType.environment));\n      }\n    }\n\n    // Check for matches\n    if (candidates.length == 0) {\n      this._log.semanticErrorNoMatchingOverload(range, overloaded.name, count, null);\n      return null;\n    }\n\n    // Check for an unambiguous match\n    if (candidates.length == 1) {\n      return in_List.get(candidates, 0);\n    }\n\n    // First filter by syntactic structure impossibilities. This helps break\n    // the chicken-and-egg problem of needing to resolve argument types to\n    // get a match and needing a match to resolve argument types. For example,\n    // a list literal needs type context to resolve correctly.\n    var index = 0;\n\n    while (index < candidates.length) {\n      var child = firstArgument;\n\n      for (var i2 = 0, list1 = in_List.get(candidates, index).argumentTypes, count2 = list1.length; i2 < count2; i2 = i2 + 1 | 0) {\n        var type = in_List.get(list1, i2);\n        var kind = child.kind;\n\n        if (kind == Skew.NodeKind.NULL && !type.isReference() || kind == Skew.NodeKind.INITIALIZER_LIST && this._findMember(type, '[new]') == null && this._findMember(type, '[...]') == null || kind == Skew.NodeKind.INITIALIZER_MAP && this._findMember(type, '{new}') == null && this._findMember(type, '{...}') == null || kind == Skew.NodeKind.LAMBDA && (type.kind != Skew.TypeKind.LAMBDA || type.argumentTypes.length != child.symbol.asFunctionSymbol().$arguments.length)) {\n          in_List.removeAt(candidates, index);\n          index = index - 1 | 0;\n          break;\n        }\n\n        child = child.nextSibling();\n      }\n\n      index = index + 1 | 0;\n    }\n\n    // Check for an unambiguous match\n    if (candidates.length == 1) {\n      return in_List.get(candidates, 0);\n    }\n\n    // If that still didn't work, resolve the arguments without type context\n    for (var child1 = firstArgument; child1 != null; child1 = child1.nextSibling()) {\n      this._resolveAsParameterizedExpression(child1, scope);\n    }\n\n    // Try again, this time discarding all implicit conversion failures\n    index = 0;\n\n    while (index < candidates.length) {\n      var child2 = firstArgument;\n\n      for (var i3 = 0, list2 = in_List.get(candidates, index).argumentTypes, count3 = list2.length; i3 < count3; i3 = i3 + 1 | 0) {\n        var type1 = in_List.get(list2, i3);\n\n        if (!this._cache.canImplicitlyConvert(child2.resolvedType, type1)) {\n          in_List.removeAt(candidates, index);\n          index = index - 1 | 0;\n          break;\n        }\n\n        child2 = child2.nextSibling();\n      }\n\n      index = index + 1 | 0;\n    }\n\n    // Check for an unambiguous match\n    if (candidates.length == 1) {\n      return in_List.get(candidates, 0);\n    }\n\n    // Extract argument types for an error if there is one\n    var childTypes = [];\n\n    for (var child3 = firstArgument; child3 != null; child3 = child3.nextSibling()) {\n      childTypes.push(child3.resolvedType);\n    }\n\n    // Give up without a match\n    if (candidates.length == 0) {\n      this._log.semanticErrorNoMatchingOverload(range, overloaded.name, count, childTypes);\n      return null;\n    }\n\n    // If that still didn't work, try type equality\n    for (var i4 = 0, list3 = candidates, count5 = list3.length; i4 < count5; i4 = i4 + 1 | 0) {\n      var type2 = in_List.get(list3, i4);\n      var isMatch = true;\n\n      for (var i = 0, count4 = count; i < count4; i = i + 1 | 0) {\n        if (in_List.get(childTypes, i) != in_List.get(type2.argumentTypes, i)) {\n          isMatch = false;\n          break;\n        }\n      }\n\n      if (isMatch) {\n        return type2;\n      }\n    }\n\n    // If that still didn't work, try picking the preferred overload\n    var firstPreferred = null;\n    var secondPreferred = null;\n\n    for (var i5 = 0, list4 = candidates, count6 = list4.length; i5 < count6; i5 = i5 + 1 | 0) {\n      var type3 = in_List.get(list4, i5);\n\n      if (type3.symbol.isPreferred()) {\n        secondPreferred = firstPreferred;\n        firstPreferred = type3;\n      }\n    }\n\n    // Check for a single preferred overload\n    if (firstPreferred != null && secondPreferred == null) {\n      return firstPreferred;\n    }\n\n    // Give up since the overload is ambiguous\n    this._log.semanticErrorAmbiguousOverload(range, overloaded.name, count, childTypes);\n    return null;\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveOverloadedFunctionCall = function(node, scope, type) {\n    var match = this._resolveOverloadedFunction(node.callValue().range, node, scope, type);\n\n    if (match != null && this._resolveFunctionCall(node, scope, match)) {\n      this._checkAccess(node, node.callValue().internalRangeOrRange(), scope);\n      return true;\n    }\n\n    return false;\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveCast = function(node, scope, context) {\n    var value = node.castValue();\n    var type = node.castType();\n    var neededTypeContext = Skew.Resolving.Resolver._needsTypeContext(value);\n    this._resolveAsParameterizedType(type, scope);\n    this._resolveAsParameterizedExpressionWithTypeContext(value, scope, type.resolvedType);\n    this._checkConversion(value, type.resolvedType, Skew.Resolving.ConversionKind.EXPLICIT);\n    node.resolvedType = type.resolvedType;\n\n    // Warn about unnecessary casts\n    var range = node.internalRangeOrRange();\n\n    if (range != null && type.resolvedType != Skew.Type.DYNAMIC && value.resolvedType != Skew.Type.DYNAMIC && !neededTypeContext && (value.resolvedType == type.resolvedType || context == type.resolvedType && this._cache.canImplicitlyConvert(value.resolvedType, type.resolvedType))) {\n      this._log.semanticWarningExtraCast(Skew.Range.span(range, type.range), value.resolvedType, type.resolvedType);\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveConstant = function(node, scope, context) {\n    switch (node.content.kind()) {\n      case Skew.ContentKind.BOOL: {\n        node.resolvedType = this._cache.boolType;\n        break;\n      }\n\n      case Skew.ContentKind.DOUBLE: {\n        node.resolvedType = this._cache.doubleType;\n        break;\n      }\n\n      case Skew.ContentKind.STRING: {\n        node.resolvedType = this._cache.stringType;\n        break;\n      }\n\n      // The literal \"0\" represents the empty set for \"flags\" types\n      case Skew.ContentKind.INT: {\n        node.resolvedType = context != null && context.isFlags() && node.asInt() == 0 ? context : this._cache.intType;\n        break;\n      }\n\n      default: {\n        assert(false);\n        break;\n      }\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._findMember = function(type, name) {\n    if (type.kind == Skew.TypeKind.SYMBOL) {\n      var symbol = type.symbol;\n\n      if (Skew.in_SymbolKind.isObject(symbol.kind)) {\n        var member = in_StringMap.get(symbol.asObjectSymbol().members, name, null);\n\n        if (member != null) {\n          this._initializeSymbol(member);\n          return member;\n        }\n      }\n    }\n\n    return null;\n  };\n\n  Skew.Resolving.Resolver.prototype._sinkNullDotIntoHook = function(node, scope, context) {\n    var nullDot = node;\n\n    // Search down the chain of dot accesses and calls for \"?.\" expression\n    while (true) {\n      if (nullDot.kind == Skew.NodeKind.DOT && nullDot.dotTarget() != null) {\n        nullDot = nullDot.dotTarget();\n      }\n\n      else if (nullDot.kind == Skew.NodeKind.CALL) {\n        nullDot = nullDot.callValue();\n      }\n\n      else {\n        break;\n      }\n    }\n\n    // Stop if this isn't a \"?.\" expression after all\n    if (nullDot.kind != Skew.NodeKind.NULL_DOT) {\n      return null;\n    }\n\n    // Wrap everything in a null check\n    var target = nullDot.dotTarget().remove();\n    this._resolveAsParameterizedExpression(target, scope);\n    var test = Skew.Node.createBinary(Skew.NodeKind.NOT_EQUAL, this._extractExpression(target, scope), new Skew.Node(Skew.NodeKind.NULL).withRange(nullDot.internalRange)).withRange(target.range);\n    var dot = new Skew.Node(Skew.NodeKind.DOT).withContent(new Skew.StringContent(nullDot.asString())).appendChild(target).withRange(nullDot.range).withInternalRange(nullDot.internalRange);\n    var hook = Skew.Node.createHook(test, dot, new Skew.Node(Skew.NodeKind.NULL).withRange(nullDot.internalRangeOrRange())).withRange(nullDot.range);\n    nullDot.become(hook.hookTrue().clone());\n\n    // This is necessary to trigger the resolve below\n    node.resolvedType = null;\n    hook.hookTrue().become(node.cloneAndStealChildren());\n    return hook;\n  };\n\n  Skew.Resolving.Resolver.prototype._checkForMemberCompletions = function(type, range, name, check) {\n    assert(type != null);\n    var completionContext = this._options.completionContext;\n\n    if (completionContext != null && range != null && range.source == completionContext.source && range.touches(completionContext.index) && type.kind == Skew.TypeKind.SYMBOL && Skew.in_SymbolKind.isObject(type.symbol.kind)) {\n      var prefix = in_string.slice2(name, 0, completionContext.index - range.start | 0);\n      var object = type.symbol.asObjectSymbol();\n      this._initializeSymbol(object);\n      completionContext.range = range;\n\n      for (var i = 0, list = Array.from(object.members.values()), count = list.length; i < count; i = i + 1 | 0) {\n        var member = in_List.get(list, i);\n        var isOnInstances = Skew.in_SymbolKind.isOnInstances(member.kind);\n\n        if ((check == Skew.Resolving.Resolver.CompletionCheck.INSTANCE_ONLY ? isOnInstances : check == Skew.Resolving.Resolver.CompletionCheck.GLOBAL_ONLY ? !isOnInstances : true) && Skew.Resolving.Resolver._matchCompletion(member, prefix)) {\n          this._initializeSymbol(member);\n          completionContext.addCompletion(member);\n        }\n      }\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._checkForScopeCompletions = function(scope, range, name, thisObject) {\n    var completionContext = this._options.completionContext;\n\n    if (completionContext != null && range != null && range.source == completionContext.source && range.touches(completionContext.index)) {\n      var prefix = in_string.slice2(name, 0, completionContext.index - range.start | 0);\n      completionContext.range = range;\n\n      while (scope != null) {\n        switch (scope.kind()) {\n          case Skew.ScopeKind.OBJECT: {\n            var object = scope.asObjectScope().symbol;\n\n            for (var i = 0, list = Array.from(object.members.values()), count = list.length; i < count; i = i + 1 | 0) {\n              var symbol = in_List.get(list, i);\n\n              if (Skew.Resolving.Resolver._matchCompletion(symbol, prefix) && (!Skew.in_SymbolKind.isOnInstances(symbol.kind) || object == thisObject)) {\n                this._initializeSymbol(symbol);\n                completionContext.addCompletion(symbol);\n              }\n            }\n            break;\n          }\n\n          case Skew.ScopeKind.FUNCTION: {\n            for (var i1 = 0, list1 = Array.from(scope.asFunctionScope().parameters.values()), count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n              var symbol1 = in_List.get(list1, i1);\n\n              if (Skew.Resolving.Resolver._matchCompletion(symbol1, prefix)) {\n                this._initializeSymbol(symbol1);\n                completionContext.addCompletion(symbol1);\n              }\n            }\n            break;\n          }\n\n          case Skew.ScopeKind.LOCAL: {\n            for (var i2 = 0, list2 = Array.from(scope.asLocalScope().locals.values()), count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n              var symbol2 = in_List.get(list2, i2);\n\n              if (Skew.Resolving.Resolver._matchCompletion(symbol2, prefix)) {\n                this._initializeSymbol(symbol2);\n                completionContext.addCompletion(symbol2);\n              }\n            }\n            break;\n          }\n        }\n\n        scope = scope.parent;\n      }\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveDot = function(node, scope, context) {\n    var hook = this._sinkNullDotIntoHook(node, scope, context);\n\n    if (hook != null) {\n      node.become(hook);\n      this._resolveAsParameterizedExpressionWithTypeContext(node, scope, context);\n      return;\n    }\n\n    var target = node.dotTarget();\n    var name = node.asString();\n\n    // Resolve the target if present\n    if (target != null) {\n      this._resolveNode(target, scope, null);\n\n      // Support IDE code completion\n      this._checkForMemberCompletions(target.resolvedType, node.internalRange, name, target.isType() ? Skew.Resolving.Resolver.CompletionCheck.GLOBAL_ONLY : Skew.Resolving.Resolver.CompletionCheck.INSTANCE_ONLY);\n    }\n\n    // Ignore parse errors (the syntax tree is kept around for code completion)\n    if (name == '') {\n      return;\n    }\n\n    // Infer the target from the type context if it's omitted\n    if (target == null) {\n      if (context == null) {\n        this._log.semanticErrorMissingDotContext(node.range, name);\n        return;\n      }\n\n      target = new Skew.Node(Skew.NodeKind.TYPE).withType(context);\n      node.appendChild(target);\n      assert(node.dotTarget() == target);\n\n      // Support IDE code completion\n      this._checkForMemberCompletions(target.resolvedType, node.internalRange, name, target.isType() ? Skew.Resolving.Resolver.CompletionCheck.GLOBAL_ONLY : Skew.Resolving.Resolver.CompletionCheck.INSTANCE_ONLY);\n    }\n\n    // Search for a setter first, then search for a normal member\n    var symbol = null;\n\n    if (Skew.Resolving.Resolver._shouldCheckForSetter(node)) {\n      symbol = this._findMember(target.resolvedType, name + '=');\n    }\n\n    if (symbol == null) {\n      symbol = this._findMember(target.resolvedType, name);\n\n      if (symbol == null) {\n        // Symbol lookup failure\n        if (target.resolvedType != Skew.Type.DYNAMIC) {\n          var type = target.resolvedType;\n          var correction = type.kind != Skew.TypeKind.SYMBOL || !Skew.in_SymbolKind.isObject(type.symbol.kind) ? null : type.symbol.asObjectSymbol().scope.findWithFuzzyMatching(name, target.isType() ? Skew.FuzzySymbolKind.GLOBAL_ONLY : Skew.FuzzySymbolKind.INSTANCE_ONLY, Skew.FuzzyScopeSearch.SELF_ONLY);\n          this._reportGuardMergingFailure(node);\n          this._log.semanticErrorUnknownMemberSymbol(node.internalRangeOrRange(), name, target.resolvedType, correction != null ? correction.name : null, correction != null ? correction.range : null);\n        }\n\n        // Dynamic symbol access\n        else {\n          // Make sure to warn when accessing a symbol at statement level without using it\n          if (node.parent() != null && node.parent().kind == Skew.NodeKind.EXPRESSION) {\n            this._log.semanticWarningUnusedExpression(node.range);\n          }\n\n          // \"dynamic.foo\" => \"foo\"\n          if (target.kind == Skew.NodeKind.TYPE) {\n            node.kind = Skew.NodeKind.NAME;\n            node.removeChildren();\n          }\n\n          // \"Foo.new\" => \"Foo.new()\"\n          // \"Foo.new()\" => \"Foo.new()\"\n          else if (name == 'new' && !Skew.Resolving.Resolver._isCallValue(node)) {\n            node.become(Skew.Node.createCall(node.cloneAndStealChildren()).withType(Skew.Type.DYNAMIC).withRange(node.range));\n          }\n        }\n\n        return;\n      }\n    }\n\n    // Forbid referencing a base class global or constructor function from a derived class\n    if (Skew.Resolving.Resolver._isBaseGlobalReference(target.resolvedType.symbol, symbol)) {\n      this._log.semanticErrorUnknownMemberSymbol(node.range, name, target.resolvedType, symbol.fullName(), symbol.range);\n      return;\n    }\n\n    var isType = target.isType();\n    var needsType = !Skew.in_SymbolKind.isOnInstances(symbol.kind);\n\n    // Make sure the global/instance context matches the intended usage\n    if (isType) {\n      if (!needsType) {\n        this._log.semanticErrorMemberUnexpectedInstance(node.internalRangeOrRange(), symbol.name);\n      }\n\n      else if (Skew.in_SymbolKind.isFunctionOrOverloadedFunction(symbol.kind)) {\n        this._checkIsParameterized(target);\n      }\n\n      else if (target.resolvedType.isParameterized()) {\n        this._log.semanticErrorParameterizedType(target.range, target.resolvedType);\n      }\n    }\n\n    else if (needsType) {\n      this._log.semanticErrorMemberUnexpectedGlobal(node.internalRangeOrRange(), symbol.name);\n    }\n\n    // Always access referenced globals directly\n    if (!this._options.stopAfterResolve && Skew.in_SymbolKind.isGlobalReference(symbol.kind)) {\n      node.kind = Skew.NodeKind.NAME;\n      node.removeChildren();\n    }\n\n    node.symbol = symbol;\n    node.resolvedType = this._cache.substitute(symbol.resolvedType, target.resolvedType.environment);\n    this._automaticallyCallGetter(node, scope);\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveHook = function(node, scope, context) {\n    this._resolveAsParameterizedExpressionWithConversion(node.hookTest(), scope, this._cache.boolType);\n    var trueValue = node.hookTrue();\n    var falseValue = node.hookFalse();\n\n    // Use the type context from the parent\n    if (context != null) {\n      this._resolveAsParameterizedExpressionWithConversion(trueValue, scope, context);\n      this._resolveAsParameterizedExpressionWithConversion(falseValue, scope, context);\n      node.resolvedType = context;\n    }\n\n    // Find the common type from both branches\n    else {\n      this._resolveAsParameterizedExpression(trueValue, scope);\n      this._resolveAsParameterizedExpression(falseValue, scope);\n      var commonType = this._cache.commonImplicitType(trueValue.resolvedType, falseValue.resolvedType);\n\n      // Insert casts if needed since some targets can't perform this type inference\n      if (commonType != null) {\n        this._checkConversion(trueValue, commonType, Skew.Resolving.ConversionKind.IMPLICIT);\n        this._checkConversion(falseValue, commonType, Skew.Resolving.ConversionKind.IMPLICIT);\n        node.resolvedType = commonType;\n      }\n\n      else {\n        this._log.semanticErrorNoCommonType(Skew.Range.span(trueValue.range, falseValue.range), trueValue.resolvedType, falseValue.resolvedType);\n      }\n    }\n\n    // Check for likely bugs where both branches look the same\n    if (trueValue.looksTheSameAs(falseValue)) {\n      this._log.semanticWarningIdenticalOperands(Skew.Range.span(trueValue.range, falseValue.range), node.wasNullJoin() ? '??' : ':');\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveInitializer = function(node, scope, context) {\n    // Make sure to resolve the children even if the initializer is invalid\n    if (context != null) {\n      if (context == Skew.Type.DYNAMIC || !this._resolveInitializerWithContext(node, scope, context)) {\n        this._resolveChildrenAsParameterizedExpressionsWithDynamicTypeContext(node, scope);\n      }\n\n      return;\n    }\n\n    // First pass: only children with type context, second pass: all children\n    for (var pass = 0; pass < 2; pass = pass + 1 | 0) {\n      switch (node.kind) {\n        case Skew.NodeKind.INITIALIZER_LIST: {\n          var type = null;\n\n          // Resolve all children for this pass\n          for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n            if (pass != 0 || !Skew.Resolving.Resolver._needsTypeContext(child)) {\n              this._resolveAsParameterizedExpression(child, scope);\n              type = this._mergeCommonType(type, child);\n            }\n          }\n\n          // Resolve remaining children using the type context if valid\n          if (type != null && Skew.Resolving.Resolver._isValidVariableType(type)) {\n            this._resolveInitializerWithContext(node, scope, this._cache.createListType(type));\n            return;\n          }\n          break;\n        }\n\n        case Skew.NodeKind.INITIALIZER_MAP: {\n          var keyType = null;\n          var valueType = null;\n\n          // Resolve all children for this pass\n          for (var child1 = node.firstChild(); child1 != null; child1 = child1.nextSibling()) {\n            var key = child1.firstValue();\n            var value = child1.secondValue();\n\n            if (pass != 0 || !Skew.Resolving.Resolver._needsTypeContext(key)) {\n              this._resolveAsParameterizedExpression(key, scope);\n              keyType = this._mergeCommonType(keyType, key);\n            }\n\n            if (pass != 0 || !Skew.Resolving.Resolver._needsTypeContext(value)) {\n              this._resolveAsParameterizedExpression(value, scope);\n              valueType = this._mergeCommonType(valueType, value);\n            }\n          }\n\n          // Resolve remaining children using the type context if valid\n          if (keyType != null && valueType != null && Skew.Resolving.Resolver._isValidVariableType(valueType)) {\n            assert(!this._cache.isEquivalentToInt(keyType) || !this._cache.isEquivalentToString(keyType));\n\n            if (this._cache.isEquivalentToInt(keyType)) {\n              this._resolveInitializerWithContext(node, scope, this._cache.createIntMapType(valueType));\n              return;\n            }\n\n            if (this._cache.isEquivalentToString(keyType)) {\n              this._resolveInitializerWithContext(node, scope, this._cache.createStringMapType(valueType));\n              return;\n            }\n          }\n          break;\n        }\n      }\n    }\n\n    this._log.semanticErrorInitializerTypeInferenceFailed(node.range);\n    this._resolveChildrenAsParameterizedExpressionsWithDynamicTypeContext(node, scope);\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveInitializerWithContext = function(node, scope, context) {\n    var isList = node.kind == Skew.NodeKind.INITIALIZER_LIST;\n    var $new = this._findMember(context, isList ? '[new]' : '{new}');\n    var add = this._findMember(context, isList ? '[...]' : '{...}');\n\n    // Special-case imported literals to prevent an infinite loop for list literals\n    if (add != null && add.isImported()) {\n      var $function = add.asFunctionSymbol();\n\n      if ($function.$arguments.length == (isList ? 1 : 2)) {\n        var functionType = this._cache.substitute($function.resolvedType, context.environment);\n\n        for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n          if (child.kind == Skew.NodeKind.PAIR) {\n            this._resolveAsParameterizedExpressionWithConversion(child.firstValue(), scope, in_List.get(functionType.argumentTypes, 0));\n            this._resolveAsParameterizedExpressionWithConversion(child.secondValue(), scope, in_List.get(functionType.argumentTypes, 1));\n            child.resolvedType = Skew.Type.DYNAMIC;\n          }\n\n          else {\n            this._resolveAsParameterizedExpressionWithConversion(child, scope, in_List.get(functionType.argumentTypes, 0));\n          }\n        }\n\n        node.resolvedType = context;\n        return true;\n      }\n    }\n\n    // Use simple call chaining when there's an add operator present\n    if (add != null) {\n      var type = new Skew.Node(Skew.NodeKind.TYPE).withType(context).withRange(node.range).withFlags(Skew.NodeFlags.IS_IGNORED_BY_IDE);\n      var chain = new Skew.Node(Skew.NodeKind.DOT).withContent(new Skew.StringContent($new != null ? $new.name : 'new')).appendChild(type).withRange(node.range).withFlags(Skew.NodeFlags.IS_IGNORED_BY_IDE);\n\n      while (node.hasChildren()) {\n        var child1 = node.firstChild().remove();\n        var dot = new Skew.Node(Skew.NodeKind.DOT).withContent(new Skew.StringContent(add.name)).appendChild(chain).withRange(child1.range).withFlags(Skew.NodeFlags.IS_IGNORED_BY_IDE);\n        chain = Skew.Node.createCall(dot).withRange(child1.range).withFlags(Skew.NodeFlags.IS_IGNORED_BY_IDE);\n\n        if (child1.kind == Skew.NodeKind.PAIR) {\n          chain.appendChildrenFrom(child1);\n        }\n\n        else {\n          chain.appendChild(child1);\n        }\n      }\n\n      node.become(chain);\n      this._resolveAsParameterizedExpressionWithConversion(node, scope, context);\n      return true;\n    }\n\n    // Make sure there's a constructor to call\n    if ($new == null) {\n      // Avoid emitting an extra error when the constructor doesn't have the right type:\n      //\n      //   def main Foo {\n      //     return []\n      //   }\n      //\n      //   class Foo {\n      //     def [new](x int) {}\n      //   }\n      //\n      if (!node.isInitializerExpansion()) {\n        this._log.semanticErrorInitializerTypeInferenceFailed(node.range);\n      }\n\n      return false;\n    }\n\n    // Avoid infinite expansion\n    if (node.isInitializerExpansion()) {\n      this._log.semanticErrorInitializerRecursiveExpansion(node.range, $new.range);\n      return false;\n    }\n\n    var dot1 = new Skew.Node(Skew.NodeKind.DOT).withContent(new Skew.StringContent($new.name)).appendChild(new Skew.Node(Skew.NodeKind.TYPE).withType(context).withRange(node.range)).withRange(node.range);\n\n    // Call the initializer constructor\n    if (node.kind == Skew.NodeKind.INITIALIZER_MAP) {\n      var firstValues = new Skew.Node(Skew.NodeKind.INITIALIZER_LIST).withFlags(Skew.NodeFlags.IS_INITIALIZER_EXPANSION).withRange(node.range);\n      var secondValues = new Skew.Node(Skew.NodeKind.INITIALIZER_LIST).withFlags(Skew.NodeFlags.IS_INITIALIZER_EXPANSION).withRange(node.range);\n\n      for (var child2 = node.firstChild(); child2 != null; child2 = child2.nextSibling()) {\n        var first = child2.firstValue();\n        var second = child2.secondValue();\n        firstValues.appendChild(first.remove());\n        secondValues.appendChild(second.remove());\n      }\n\n      node.become(Skew.Node.createCall(dot1).withRange(node.range).appendChild(firstValues).appendChild(secondValues));\n    }\n\n    else {\n      var values = new Skew.Node(Skew.NodeKind.INITIALIZER_LIST).withFlags(Skew.NodeFlags.IS_INITIALIZER_EXPANSION).withRange(node.range);\n      node.become(Skew.Node.createCall(dot1).withRange(node.range).appendChild(values.appendChildrenFrom(node)));\n    }\n\n    this._resolveAsParameterizedExpressionWithConversion(node, scope, context);\n    return true;\n  };\n\n  Skew.Resolving.Resolver.prototype._mergeCommonType = function(commonType, child) {\n    if (commonType == null || child.resolvedType == Skew.Type.DYNAMIC) {\n      return child.resolvedType;\n    }\n\n    var result = this._cache.commonImplicitType(commonType, child.resolvedType);\n\n    if (result != null) {\n      return result;\n    }\n\n    this._log.semanticErrorNoCommonType(child.range, commonType, child.resolvedType);\n    return Skew.Type.DYNAMIC;\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveLambda = function(node, scope, context) {\n    var ref;\n    var symbol = node.symbol.asFunctionSymbol();\n    symbol.scope = new Skew.FunctionScope(scope, symbol);\n\n    // Use type context to implicitly set missing types\n    if (context != null && context.kind == Skew.TypeKind.LAMBDA) {\n      // Copy over the argument types if they line up\n      if (context.argumentTypes.length == symbol.$arguments.length) {\n        for (var i = 0, count = symbol.$arguments.length; i < count; i = i + 1 | 0) {\n          if ((ref = in_List.get(symbol.$arguments, i)).type == null) {\n            ref.type = new Skew.Node(Skew.NodeKind.TYPE).withType(in_List.get(context.argumentTypes, i));\n          }\n        }\n      }\n\n      // Copy over the return type\n      if (symbol.returnType == null && context.returnType != null) {\n        symbol.returnType = new Skew.Node(Skew.NodeKind.TYPE).withType(context.returnType);\n      }\n    }\n\n    else {\n      // Only infer non-void return types if there's no type context\n      if (symbol.returnType == null) {\n        symbol.flags |= Skew.SymbolFlags.SHOULD_INFER_RETURN_TYPE;\n      }\n\n      // If there's dynamic type context, treat all arguments as dynamic\n      if (context == Skew.Type.DYNAMIC) {\n        for (var i1 = 0, list = symbol.$arguments, count1 = list.length; i1 < count1; i1 = i1 + 1 | 0) {\n          var argument = in_List.get(list, i1);\n\n          if (argument.type == null) {\n            argument.type = new Skew.Node(Skew.NodeKind.TYPE).withType(Skew.Type.DYNAMIC);\n          }\n        }\n\n        if (symbol.returnType == null) {\n          symbol.returnType = new Skew.Node(Skew.NodeKind.TYPE).withType(Skew.Type.DYNAMIC);\n        }\n\n        symbol.flags |= Skew.SymbolFlags.IS_DYNAMIC_LAMBDA;\n      }\n    }\n\n    this._resolveFunction(symbol);\n\n    // Use a LambdaType instead of a SymbolType for the node\n    var argumentTypes = [];\n    var returnType = symbol.returnType;\n\n    for (var i2 = 0, list1 = symbol.$arguments, count2 = list1.length; i2 < count2; i2 = i2 + 1 | 0) {\n      var argument1 = in_List.get(list1, i2);\n      argumentTypes.push(argument1.resolvedType);\n    }\n\n    node.resolvedType = this._cache.createLambdaType(argumentTypes, returnType != null ? returnType.resolvedType : null);\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveLambdaType = function(node, scope) {\n    var lambdaReturnType = node.lambdaReturnType();\n    var argumentTypes = [];\n    var returnType = null;\n\n    for (var child = node.firstChild(); child != lambdaReturnType; child = child.nextSibling()) {\n      this._resolveAsParameterizedType(child, scope);\n      argumentTypes.push(child.resolvedType);\n    }\n\n    // An empty return type is signaled by the type \"null\"\n    if (lambdaReturnType.kind != Skew.NodeKind.TYPE || lambdaReturnType.resolvedType != Skew.Type.NULL) {\n      this._resolveAsParameterizedType(lambdaReturnType, scope);\n      returnType = lambdaReturnType.resolvedType;\n    }\n\n    node.resolvedType = this._cache.createLambdaType(argumentTypes, returnType);\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveName = function(node, scope) {\n    var enclosingFunction = scope.findEnclosingFunction();\n    var thisVariable = enclosingFunction != null ? enclosingFunction.symbol.$this : null;\n    var name = node.asString();\n\n    // Support IDE code completion\n    this._checkForScopeCompletions(scope, node.range, name, thisVariable != null ? enclosingFunction.symbol.parent.asObjectSymbol() : null);\n\n    if (thisVariable != null) {\n      this._checkForMemberCompletions(thisVariable.resolvedType, node.range, name, Skew.Resolving.Resolver.CompletionCheck.NORMAL);\n    }\n\n    var symbol = scope.find(name, Skew.Resolving.Resolver._shouldCheckForSetter(node) ? Skew.ScopeSearch.ALSO_CHECK_FOR_SETTER : Skew.ScopeSearch.NORMAL);\n\n    if (symbol == null) {\n      this._reportGuardMergingFailure(node);\n\n      if (name == 'this' && thisVariable != null) {\n        this._log.semanticErrorUndeclaredSelfSymbol(node.range, name);\n      }\n\n      else {\n        var correction = scope.findWithFuzzyMatching(name, node.shouldExpectType() ? Skew.FuzzySymbolKind.TYPE_ONLY : thisVariable != null ? Skew.FuzzySymbolKind.EVERYTHING : Skew.FuzzySymbolKind.GLOBAL_ONLY, Skew.FuzzyScopeSearch.SELF_AND_PARENTS);\n        this._log.semanticErrorUndeclaredSymbol(node.range, name, correction == null ? null : enclosingFunction != null && Skew.Resolving.Resolver._isBaseGlobalReference(enclosingFunction.symbol.parent, correction) ? correction.fullName() : correction.name, correction != null ? correction.range : null);\n      }\n\n      return;\n    }\n\n    this._initializeSymbol(symbol);\n\n    // Track reads and writes of local variables for later use\n    if (node.isAssignTarget()) {\n      this._recordStatistic(symbol, Skew.Resolving.SymbolStatistic.WRITE);\n\n      // Also track reads for assignments\n      if (Skew.Resolving.Resolver._isExpressionUsed(node.parent())) {\n        this._recordStatistic(symbol, Skew.Resolving.SymbolStatistic.READ);\n      }\n    }\n\n    else {\n      this._recordStatistic(symbol, Skew.Resolving.SymbolStatistic.READ);\n    }\n\n    // Forbid referencing a base class global or constructor function from a derived class\n    if (enclosingFunction != null && Skew.Resolving.Resolver._isBaseGlobalReference(enclosingFunction.symbol.parent, symbol)) {\n      this._log.semanticErrorUndeclaredSymbol(node.range, name, symbol.fullName(), symbol.range);\n      return;\n    }\n\n    // Automatically insert \"self.\" before instance symbols\n    var resolvedType = symbol.resolvedType;\n\n    if (Skew.in_SymbolKind.isOnInstances(symbol.kind)) {\n      if (thisVariable != null && enclosingFunction.symbol.parent.asObjectSymbol().isSameOrHasBaseClass(symbol.parent)) {\n        node.become(new Skew.Node(Skew.NodeKind.DOT).withContent(new Skew.StringContent(name)).appendChild(Skew.Node.createSymbolReference(thisVariable)).withRange(node.range).withInternalRange(node.range));\n        resolvedType = this._cache.substitute(resolvedType, thisVariable.resolvedType.environment);\n      }\n\n      else {\n        this._log.semanticErrorMemberUnexpectedInstance(node.range, symbol.name);\n      }\n    }\n\n    // Type parameters for objects may only be used in certain circumstances\n    else if (symbol.kind == Skew.SymbolKind.PARAMETER_OBJECT) {\n      var parent = scope;\n      var isValid = false;\n\n      label: while (parent != null) {\n        switch (parent.kind()) {\n          case Skew.ScopeKind.OBJECT: {\n            isValid = parent.asObjectScope().symbol == symbol.parent;\n            break label;\n          }\n\n          case Skew.ScopeKind.FUNCTION: {\n            var $function = parent.asFunctionScope().symbol;\n\n            if ($function.kind != Skew.SymbolKind.FUNCTION_LOCAL) {\n              isValid = $function.parent == symbol.parent;\n              break label;\n            }\n            break;\n          }\n\n          case Skew.ScopeKind.VARIABLE: {\n            var variable = parent.asVariableScope().symbol;\n            isValid = variable.kind == Skew.SymbolKind.VARIABLE_INSTANCE && variable.parent == symbol.parent;\n            break label;\n          }\n        }\n\n        parent = parent.parent;\n      }\n\n      if (!isValid) {\n        this._log.semanticErrorMemberUnexpectedTypeParameter(node.range, symbol.name);\n      }\n    }\n\n    node.symbol = symbol;\n    node.resolvedType = resolvedType;\n    this._automaticallyCallGetter(node, scope);\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveNullDot = function(node, scope) {\n    node.become(this._sinkNullDotIntoHook(node, scope, null));\n    this._resolveAsParameterizedExpression(node, scope);\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveParameterize = function(node, scope) {\n    var value = node.parameterizeValue();\n    this._resolveNode(value, scope, null);\n\n    // Resolve parameter types\n    var substitutions = [];\n    var count = 0;\n\n    for (var child = value.nextSibling(); child != null; child = child.nextSibling()) {\n      this._resolveAsParameterizedType(child, scope);\n      substitutions.push(child.resolvedType);\n      count = count + 1 | 0;\n    }\n\n    var type = value.resolvedType;\n    var parameters = type.parameters();\n\n    // If this is an overloaded symbol, try to pick an overload just using the parameter count\n    if (parameters == null && type.kind == Skew.TypeKind.SYMBOL && Skew.in_SymbolKind.isOverloadedFunction(type.symbol.kind)) {\n      var match = null;\n\n      for (var i = 0, list = type.symbol.asOverloadedFunctionSymbol().symbols, count1 = list.length; i < count1; i = i + 1 | 0) {\n        var candidate = in_List.get(list, i);\n\n        if (candidate.parameters != null && candidate.parameters.length == count) {\n          if (match != null) {\n            match = null;\n            break;\n          }\n\n          match = candidate;\n        }\n      }\n\n      if (match != null) {\n        type = this._cache.substitute(match.resolvedType, type.environment);\n        parameters = type.parameters();\n      }\n    }\n\n    // Check for type parameters\n    if (parameters == null || type.isParameterized()) {\n      if (type != Skew.Type.DYNAMIC) {\n        this._log.semanticErrorCannotParameterize(node.range, type);\n      }\n\n      value.resolvedType = Skew.Type.DYNAMIC;\n      return;\n    }\n\n    // Check parameter count\n    var expected = parameters.length;\n\n    if (count != expected) {\n      this._log.semanticErrorParameterCount(node.internalRangeOrRange(), expected, count);\n      value.resolvedType = Skew.Type.DYNAMIC;\n      return;\n    }\n\n    // Make sure all parameters have types\n    for (var i1 = 0, list1 = parameters, count2 = list1.length; i1 < count2; i1 = i1 + 1 | 0) {\n      var parameter = in_List.get(list1, i1);\n      this._initializeSymbol(parameter);\n    }\n\n    // Include the symbol for use with Node.isType\n    node.resolvedType = this._cache.substitute(type, this._cache.mergeEnvironments(type.environment, this._cache.createEnvironment(parameters, substitutions), null));\n    node.symbol = value.symbol;\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveSequence = function(node, scope, context) {\n    for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n      this._resolveAsParameterizedExpressionWithTypeContext(child, scope, child.nextSibling() == null ? context : null);\n    }\n\n    if (node.hasChildren()) {\n      node.resolvedType = node.lastChild().resolvedType;\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveStringInterpolation = function(node, scope) {\n    assert(node.childCount() % 2 == 1);\n    this._resolveChildrenAsParameterizedExpressions(node, scope);\n\n    // TypeScript supports string interpolation natively\n    if (this._options.target instanceof Skew.TypeScriptTarget) {\n      for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n        if (child.resolvedType != Skew.Type.DYNAMIC && child.resolvedType != this._cache.stringType) {\n          var temp = new Skew.Node(Skew.NodeKind.NULL);\n          child.replaceWith(temp);\n          child = new Skew.Node(Skew.NodeKind.DOT).withContent(new Skew.StringContent('toString')).appendChild(child).withRange(child.range).withFlags(Skew.NodeFlags.IS_IGNORED_BY_IDE);\n          temp.replaceWith(child);\n        }\n\n        this._resolveAsParameterizedExpressionWithConversion(child, scope, this._cache.stringType);\n      }\n\n      node.resolvedType = this._cache.stringType;\n      return;\n    }\n\n    // Convert the string interpolation into a series of string concatenations\n    var joined = null;\n\n    while (node.hasChildren()) {\n      var child1 = node.firstChild().remove();\n\n      if (child1.isString() && child1.asString() == '') {\n        continue;\n      }\n\n      else if (child1.resolvedType != Skew.Type.DYNAMIC && child1.resolvedType != this._cache.stringType) {\n        child1 = new Skew.Node(Skew.NodeKind.DOT).withContent(new Skew.StringContent('toString')).appendChild(child1).withRange(child1.range).withFlags(Skew.NodeFlags.IS_IGNORED_BY_IDE);\n        this._resolveAsParameterizedExpressionWithConversion(child1, scope, this._cache.stringType);\n      }\n\n      joined = joined != null ? Skew.Node.createBinary(Skew.NodeKind.ADD, joined, child1).withRange(Skew.Range.span(joined.range, child1.range)).withFlags(Skew.NodeFlags.IS_IGNORED_BY_IDE) : child1;\n      this._resolveAsParameterizedExpressionWithConversion(joined, scope, this._cache.stringType);\n    }\n\n    node.become(joined != null ? joined : new Skew.Node(Skew.NodeKind.CONSTANT).withContent(new Skew.StringContent('')));\n    this._resolveAsParameterizedExpressionWithConversion(node, scope, this._cache.stringType);\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveSuper = function(node, scope) {\n    var $function = scope.findEnclosingFunction();\n    var symbol = $function != null ? $function.symbol : null;\n    var baseType = symbol != null ? symbol.parent.asObjectSymbol().baseType : null;\n    var overridden = baseType == null ? null : this._findMember(baseType, symbol.name);\n\n    if (overridden == null) {\n      this._log.semanticErrorBadSuper(node.range);\n      return;\n    }\n\n    // Calling a static method doesn't need special handling\n    if (overridden.kind == Skew.SymbolKind.FUNCTION_GLOBAL) {\n      node.kind = Skew.NodeKind.NAME;\n    }\n\n    node.resolvedType = overridden.resolvedType;\n    node.symbol = overridden;\n    this._automaticallyCallGetter(node, scope);\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveTypeCheck = function(node, scope) {\n    var value = node.typeCheckValue();\n    var type = node.typeCheckType();\n    this._resolveAsParameterizedExpression(value, scope);\n    this._resolveAsParameterizedType(type, scope);\n    this._checkConversion(value, type.resolvedType, Skew.Resolving.ConversionKind.EXPLICIT);\n    node.resolvedType = this._cache.boolType;\n\n    // Type checks don't work against interfaces\n    if (type.resolvedType.isInterface()) {\n      this._log.semanticWarningBadTypeCheck(type.range, type.resolvedType);\n    }\n\n    // Warn about unnecessary type checks\n    else if (value.resolvedType != Skew.Type.DYNAMIC && this._cache.canImplicitlyConvert(value.resolvedType, type.resolvedType) && (type.resolvedType != Skew.Type.DYNAMIC || type.kind == Skew.NodeKind.TYPE)) {\n      this._log.semanticWarningExtraTypeCheck(node.range, value.resolvedType, type.resolvedType);\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveXML = function(node, scope) {\n    var ref;\n    var tag = node.xmlTag();\n    var attributes = node.xmlAttributes();\n    var children = node.xmlChildren();\n    var closingTag = (ref = node.xmlClosingTag()) != null ? ref.remove() : null;\n    var initialErrorCount = this._log.errorCount();\n    this._resolveAsParameterizedType(tag, scope);\n\n    // Make sure there's a constructor to call\n    if (this._findMember(tag.resolvedType, 'new') == null) {\n      attributes.removeChildren();\n      children.removeChildren();\n      attributes.resolvedType = Skew.Type.DYNAMIC;\n\n      // Only report an error if there isn't one already\n      if (this._log.errorCount() == initialErrorCount) {\n        this._log.semanticErrorXMLCannotConstruct(node.range, tag.resolvedType);\n      }\n\n      return;\n    }\n\n    // Call the constructor\n    var value = new Skew.Node(Skew.NodeKind.DOT).withContent(new Skew.StringContent('new')).appendChild(tag.clone()).withRange(node.range).withFlags(Skew.NodeFlags.IS_IGNORED_BY_IDE);\n    var needsSequence = attributes.hasChildren() || children.hasChildren();\n    var result = value;\n    this._resolveAsParameterizedExpression(value, scope);\n\n    if (needsSequence) {\n      result = new Skew.Node(Skew.NodeKind.SEQUENCE).withRange(node.range).appendChild(this._extractExpression(value, scope).withFlags(Skew.NodeFlags.IS_IGNORED_BY_IDE));\n    }\n\n    // Assign to attributes if necessary\n    while (attributes.hasChildren()) {\n      var child = attributes.firstChild().remove();\n      var name = child.binaryLeft();\n\n      while (name.kind == Skew.NodeKind.DOT) {\n        name = name.dotTarget();\n      }\n\n      assert(name.kind == Skew.NodeKind.NAME);\n      name.replaceWith(new Skew.Node(Skew.NodeKind.DOT).withContent(new Skew.StringContent(name.asString())).appendChild(value.clone()).withRange(name.range));\n      result.appendChild(child);\n    }\n\n    // Make sure there's an append function to call if needed\n    if (children.hasChildren() && this._findMember(tag.resolvedType, '<>...</>') == null) {\n      this._log.semanticErrorXMLMissingAppend(children.firstChild().range, tag.resolvedType);\n      children.removeChildren();\n    }\n\n    // Append children\n    else {\n      // Don't need a closure if all children are expressions\n      var isJustExpressions = true;\n\n      for (var child1 = children.firstChild(); child1 != null; child1 = child1.nextSibling()) {\n        if (child1.kind != Skew.NodeKind.EXPRESSION) {\n          isJustExpressions = false;\n          break;\n        }\n      }\n\n      // All expression statements get passed as arguments to \"<>...</>\"\n      this._recursivelyReplaceExpressionsInXML(children, value);\n\n      // Add to the sequence\n      if (isJustExpressions) {\n        for (var child2 = children.firstChild(); child2 != null; child2 = child2.nextSibling()) {\n          result.appendChild(child2.expressionValue().remove());\n        }\n      }\n\n      // Wrap in a closure\n      else {\n        var symbol = new Skew.FunctionSymbol(Skew.SymbolKind.FUNCTION_LOCAL, '<lambda>');\n        symbol.range = children.range;\n        symbol.block = children.remove();\n        result.appendChild(Skew.Node.createCall(Skew.Node.createLambda(symbol).withRange(symbol.range)).withRange(symbol.range));\n      }\n    }\n\n    // Resolve the closing tag for IDE tooltips\n    if (closingTag != null) {\n      this._resolveAsParameterizedType(closingTag, scope);\n      value = Skew.Node.createCast(value, closingTag);\n    }\n\n    // Resolve the value\n    node.become(needsSequence ? result.appendChild(value) : value);\n    this._resolveAsParameterizedExpression(node, scope);\n  };\n\n  Skew.Resolving.Resolver.prototype._recursivelyReplaceExpressionsInXML = function(node, reference) {\n    assert(node.kind == Skew.NodeKind.BLOCK);\n\n    for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n      switch (child.kind) {\n        case Skew.NodeKind.EXPRESSION: {\n          child.appendChild(Skew.Node.createCall(new Skew.Node(Skew.NodeKind.DOT).withContent(new Skew.StringContent('<>...</>')).appendChild(reference.clone()).withRange(child.range).withFlags(Skew.NodeFlags.IS_IGNORED_BY_IDE)).appendChild(child.expressionValue().remove()).withRange(child.range));\n          break;\n        }\n\n        case Skew.NodeKind.FOR: {\n          this._recursivelyReplaceExpressionsInXML(child.forBlock(), reference);\n          break;\n        }\n\n        case Skew.NodeKind.FOREACH: {\n          this._recursivelyReplaceExpressionsInXML(child.foreachBlock(), reference);\n          break;\n        }\n\n        case Skew.NodeKind.IF: {\n          this._recursivelyReplaceExpressionsInXML(child.ifTrue(), reference);\n\n          if (child.ifFalse() != null) {\n            this._recursivelyReplaceExpressionsInXML(child.ifFalse(), reference);\n          }\n          break;\n        }\n\n        case Skew.NodeKind.SWITCH: {\n          for (var nested = child.switchValue().nextSibling(); nested != null; nested = nested.nextSibling()) {\n            this._recursivelyReplaceExpressionsInXML(nested.caseBlock(), reference);\n          }\n          break;\n        }\n\n        case Skew.NodeKind.TRY: {\n          var tryBlock = child.tryBlock();\n          var finallyBlock = child.finallyBlock();\n          this._recursivelyReplaceExpressionsInXML(tryBlock, reference);\n\n          for (var nested1 = tryBlock.nextSibling(); nested1 != finallyBlock; nested1 = nested1.nextSibling()) {\n            this._recursivelyReplaceExpressionsInXML(nested1.catchBlock(), reference);\n          }\n\n          if (finallyBlock != null) {\n            this._recursivelyReplaceExpressionsInXML(finallyBlock, reference);\n          }\n          break;\n        }\n\n        case Skew.NodeKind.WHILE: {\n          this._recursivelyReplaceExpressionsInXML(child.whileBlock(), reference);\n          break;\n        }\n      }\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveBinary = function(node, scope, context) {\n    var kind = node.kind;\n    var left = node.binaryLeft();\n    var right = node.binaryRight();\n\n    // Special-case the \"??\" operator\n    if (kind == Skew.NodeKind.NULL_JOIN) {\n      this._resolveAsParameterizedExpressionWithTypeContext(left, scope, context);\n      this._resolveAsParameterizedExpressionWithTypeContext(right, scope, context != null ? context : left.resolvedType);\n      var test = Skew.Node.createBinary(Skew.NodeKind.NOT_EQUAL, this._extractExpressionForAssignment(left, scope), new Skew.Node(Skew.NodeKind.NULL)).withRange(left.range);\n      node.become(Skew.Node.createHook(test, left.remove(), right.remove()).withRange(node.range).withFlags(Skew.NodeFlags.WAS_NULL_JOIN));\n      this._resolveAsParameterizedExpressionWithTypeContext(node, scope, context);\n      return;\n    }\n\n    // Special-case the \"?=\" operator\n    if (kind == Skew.NodeKind.ASSIGN_NULL) {\n      this._resolveAsParameterizedExpressionWithTypeContext(left, scope, context);\n      this._checkStorage(left, scope);\n      var test1 = Skew.Node.createBinary(Skew.NodeKind.NOT_EQUAL, this._extractExpressionForAssignment(left, scope), new Skew.Node(Skew.NodeKind.NULL)).withRange(left.range);\n      var assign = Skew.Node.createBinary(Skew.NodeKind.ASSIGN, left.remove(), right.remove()).withRange(node.range).withFlags(Skew.NodeFlags.WAS_ASSIGN_NULL);\n      node.become(Skew.Node.createHook(test1, left.clone(), assign).withRange(node.range));\n      this._resolveAsParameterizedExpressionWithTypeContext(node, scope, context);\n      return;\n    }\n\n    // Special-case the equality operators\n    if (kind == Skew.NodeKind.EQUAL || kind == Skew.NodeKind.NOT_EQUAL) {\n      if (Skew.Resolving.Resolver._needsTypeContext(left)) {\n        this._resolveAsParameterizedExpression(right, scope);\n        this._resolveAsParameterizedExpressionWithTypeContext(left, scope, right.resolvedType);\n      }\n\n      else if (Skew.Resolving.Resolver._needsTypeContext(right)) {\n        this._resolveAsParameterizedExpression(left, scope);\n        this._resolveAsParameterizedExpressionWithTypeContext(right, scope, left.resolvedType);\n      }\n\n      else {\n        this._resolveAsParameterizedExpression(left, scope);\n        this._resolveAsParameterizedExpression(right, scope);\n      }\n\n      // Check for likely bugs \"x == x\" or \"x != x\", except when this is used to test for NaN\n      if (left.looksTheSameAs(right) && left.hasNoSideEffects() && right.hasNoSideEffects() && !this._cache.isEquivalentToDouble(left.resolvedType) && left.resolvedType != Skew.Type.DYNAMIC) {\n        this._log.semanticWarningIdenticalOperands(node.range, kind == Skew.NodeKind.EQUAL ? '==' : '!=');\n      }\n\n      // The two types must be compatible\n      var commonType = this._cache.commonImplicitType(left.resolvedType, right.resolvedType);\n\n      if (commonType == null) {\n        this._log.semanticErrorNoCommonType(node.range, left.resolvedType, right.resolvedType);\n      }\n\n      else {\n        node.resolvedType = this._cache.boolType;\n\n        // Make sure type casts are inserted\n        this._checkConversion(left, commonType, Skew.Resolving.ConversionKind.IMPLICIT);\n        this._checkConversion(right, commonType, Skew.Resolving.ConversionKind.IMPLICIT);\n      }\n\n      return;\n    }\n\n    // Special-case assignment since it's not overridable\n    if (kind == Skew.NodeKind.ASSIGN) {\n      this._resolveAsParameterizedExpression(left, scope);\n\n      // Automatically call setters\n      if (left.symbol != null && left.symbol.isSetter()) {\n        node.become(Skew.Node.createCall(left.remove()).withRange(node.range).withInternalRange(right.range).appendChild(right.remove()));\n        this._resolveAsParameterizedExpression(node, scope);\n      }\n\n      // Resolve the right side using type context from the left side\n      else {\n        this._resolveAsParameterizedExpressionWithConversion(right, scope, left.resolvedType);\n        node.resolvedType = left.resolvedType;\n        this._checkStorage(left, scope);\n\n        // Check for likely bugs \"x = x\"\n        if (left.looksTheSameAs(right) && left.hasNoSideEffects() && right.hasNoSideEffects()) {\n          this._log.semanticWarningIdenticalOperands(node.range, node.wasAssignNull() ? '?=' : '=');\n        }\n\n        // Check for likely bugs \"x = y\" instead of \"x == y\" based on type context\n        else if (node.internalRange != null && context != null && context != Skew.Type.DYNAMIC && left.resolvedType == Skew.Type.DYNAMIC && right.resolvedType != Skew.Type.DYNAMIC && !this._cache.canImplicitlyConvert(right.resolvedType, context)) {\n          this._log.semanticWarningSuspiciousAssignmentLocation(node.internalRangeOrRange());\n        }\n\n        // Check for likely bugs \"x = y\" instead of \"x == y\" based on expression context\n        else if (node.internalRange != null && node.parent() != null) {\n          var parent = node.parent();\n          var parentKind = parent.kind;\n\n          if (parentKind == Skew.NodeKind.IF || parentKind == Skew.NodeKind.WHILE || parentKind == Skew.NodeKind.LOGICAL_AND || parentKind == Skew.NodeKind.LOGICAL_OR || parentKind == Skew.NodeKind.NOT || parentKind == Skew.NodeKind.RETURN && !parent.isImplicitReturn() || parentKind == Skew.NodeKind.HOOK && node == parent.hookTest()) {\n            this._log.semanticWarningSuspiciousAssignmentLocation(node.internalRangeOrRange());\n          }\n        }\n      }\n\n      return;\n    }\n\n    // Special-case short-circuit logical operators since they aren't overridable\n    if (kind == Skew.NodeKind.LOGICAL_AND || kind == Skew.NodeKind.LOGICAL_OR) {\n      this._resolveAsParameterizedExpressionWithConversion(left, scope, this._cache.boolType);\n      this._resolveAsParameterizedExpressionWithConversion(right, scope, this._cache.boolType);\n      node.resolvedType = this._cache.boolType;\n\n      // Check for likely bugs \"x && x\" or \"x || x\"\n      if (left.looksTheSameAs(right) && left.hasNoSideEffects() && right.hasNoSideEffects() && (!left.isBool() || !right.isBool())) {\n        this._log.semanticWarningIdenticalOperands(node.range, kind == Skew.NodeKind.LOGICAL_AND ? '&&' : '||');\n      }\n\n      return;\n    }\n\n    this._resolveOperatorOverload(node, scope, context);\n  };\n\n  Skew.Resolving.Resolver.prototype._generateReference = function(scope, type) {\n    var enclosingFunction = scope.findEnclosingFunctionOrLambda();\n    var symbol = null;\n\n    // Add a local variable\n    if (enclosingFunction != null) {\n      var block = enclosingFunction.symbol.block;\n\n      // Make sure the call to \"super\" is still the first statement\n      var after = block.firstChild();\n\n      if (after.isSuperCallStatement()) {\n        after = after.nextSibling();\n      }\n\n      // Add the new variable to the top of the function\n      symbol = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_LOCAL, enclosingFunction.generateName('ref'));\n      block.insertChildBefore(after, new Skew.Node(Skew.NodeKind.VARIABLES).appendChild(Skew.Node.createVariable(symbol)));\n    }\n\n    // Otherwise, add a global variable\n    else {\n      symbol = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_GLOBAL, this._global.scope.generateName('ref'));\n      symbol.parent = this._global;\n      this._generatedGlobalVariables.push(symbol);\n    }\n\n    // Force-initialize the symbol\n    symbol.initializeWithType(type);\n    return Skew.Node.createSymbolReference(symbol);\n  };\n\n  Skew.Resolving.Resolver.prototype._extractExpression = function(node, scope) {\n    assert(node.resolvedType != null);\n\n    if (node.kind == Skew.NodeKind.NAME || node.kind == Skew.NodeKind.CONSTANT) {\n      return node.clone();\n    }\n\n    // Replace the original expression with a reference\n    var reference = this._generateReference(scope, node.resolvedType).withRange(node.range).withFlags(Skew.NodeFlags.IS_IGNORED_BY_IDE);\n    var setup = node.cloneAndStealChildren();\n    node.become(reference);\n    return Skew.Node.createBinary(Skew.NodeKind.ASSIGN, reference, setup).withType(node.resolvedType).withRange(node.range);\n  };\n\n  // Expressions with side effects must be stored to temporary variables\n  // if they need to be duplicated in an expression. This does the variable\n  // allocation and storage and returns a partial assigment.\n  //\n  // Examples:\n  //\n  //    \"a\" stays \"a\" and returns \"a\"\n  //    \"a.b\" stays \"a.b\" and returns \"a.b\"\n  //    \"a[0]\" stays \"a[0]\" and returns \"a[0]\"\n  //    \"a().b\" becomes \"ref.b\" and returns \"(ref = a()).b\"\n  //    \"a()[0]\" becomes \"ref[0]\" and returns \"(ref = a())[0]\"\n  //    \"a()[b()]\" becomes \"ref[ref2]\" and returns \"(ref = a())[ref2 = b()]\"\n  //\n  Skew.Resolving.Resolver.prototype._extractExpressionForAssignment = function(node, scope) {\n    assert(node.resolvedType != null);\n\n    // Handle dot expressions\n    if (node.kind == Skew.NodeKind.DOT && node.symbol != null) {\n      return new Skew.Node(Skew.NodeKind.DOT).withContent(new Skew.StringContent(node.asString())).appendChild(this._extractExpression(node.dotTarget(), scope)).withSymbol(node.symbol).withType(node.resolvedType).withRange(node.range).withInternalRange(node.internalRange);\n    }\n\n    // Handle index expressions\n    if (node.kind == Skew.NodeKind.INDEX) {\n      var left = this._extractExpression(node.indexLeft(), scope);\n      return Skew.Node.createIndex(left, this._extractExpression(node.indexRight(), scope)).withRange(node.range);\n    }\n\n    // Handle name expressions\n    if (node.kind == Skew.NodeKind.NAME) {\n      return node.clone();\n    }\n\n    // Handle everything else\n    return this._extractExpression(node, scope);\n  };\n\n  Skew.Resolving.Resolver.prototype._resolveOperatorOverload = function(node, scope, context) {\n    // The order of operands are reversed for the \"in\" operator\n    var kind = node.kind;\n    var reverseBinaryOrder = kind == Skew.NodeKind.IN;\n    var first = node.firstChild();\n    var second = first.nextSibling();\n    var target = reverseBinaryOrder ? second : first;\n    var other = Skew.in_NodeKind.isBinary(kind) ? reverseBinaryOrder ? first : second : null;\n    var isBitOperation = Skew.in_NodeKind.isBitOperation(kind);\n    var bitContext = isBitOperation && context != null && context.isFlags() ? context : null;\n\n    // Allow \"foo in [.FOO, .BAR]\"\n    if (kind == Skew.NodeKind.IN && target.kind == Skew.NodeKind.INITIALIZER_LIST && !Skew.Resolving.Resolver._needsTypeContext(other)) {\n      this._resolveAsParameterizedExpression(other, scope);\n      this._resolveAsParameterizedExpressionWithTypeContext(target, scope, other.resolvedType != Skew.Type.DYNAMIC ? this._cache.createListType(other.resolvedType) : null);\n    }\n\n    // Resolve just the target since the other arguments may need type context from overload resolution\n    else {\n      this._resolveAsParameterizedExpressionWithTypeContext(target, scope, bitContext);\n    }\n\n    // Warn about shifting by 0 in the original source code, since that doesn't\n    // do anything when the arguments are integers and so is likely a mistake\n    if (Skew.in_NodeKind.isShift(kind) && this._cache.isEquivalentToInt(target.resolvedType) && other.isInt() && other.asInt() == 0) {\n      this._log.semanticWarningShiftByZero(node.range);\n    }\n\n    // Can't do overload resolution on the dynamic type\n    var type = target.resolvedType;\n\n    if (type == Skew.Type.DYNAMIC) {\n      if (Skew.in_NodeKind.isAssign(kind) && kind != Skew.NodeKind.ASSIGN_INDEX) {\n        this._checkStorage(target, scope);\n      }\n\n      this._resolveChildrenAsParameterizedExpressions(node, scope);\n      return;\n    }\n\n    // Check if the operator can be overridden at all\n    var info = in_IntMap.get1(Skew.operatorInfo, kind);\n\n    if (info.kind != Skew.OperatorKind.OVERRIDABLE) {\n      this._log.semanticErrorUnknownMemberSymbol(node.internalRangeOrRange(), info.text, type, null, null);\n      this._resolveChildrenAsParameterizedExpressions(node, scope);\n      return;\n    }\n\n    // Numeric conversions\n    var enumFlagsType = null;\n\n    // Binary operations\n    if (other != null) {\n      // Assignment operations aren't symmetric\n      if (!Skew.in_NodeKind.isBinaryAssign(kind)) {\n        if (type == this._cache.intType) {\n          this._resolveAsParameterizedExpression(other, scope);\n\n          // Auto-convert doubles to ints\n          if (other.resolvedType == this._cache.doubleType) {\n            this._checkConversion(target, this._cache.doubleType, Skew.Resolving.ConversionKind.IMPLICIT);\n            type = this._cache.doubleType;\n          }\n        }\n\n        // Check if the target is an enum\n        else if (type.isEnumOrFlags()) {\n          this._resolveAsParameterizedExpressionWithTypeContext(other, scope, bitContext != null ? bitContext : (isBitOperation || kind == Skew.NodeKind.IN) && type.isFlags() ? type : null);\n\n          // Auto-convert enums to ints when both operands can be converted\n          if (this._cache.isNumeric(other.resolvedType)) {\n            type = this._cache.commonImplicitType(type, other.resolvedType);\n            assert(type != null);\n\n            if (type.isEnumOrFlags()) {\n              if (type.isFlags()) {\n                enumFlagsType = type;\n              }\n\n              type = this._cache.intType;\n            }\n\n            this._checkConversion(target, type, Skew.Resolving.ConversionKind.IMPLICIT);\n            this._checkConversion(other, type, Skew.Resolving.ConversionKind.IMPLICIT);\n          }\n        }\n      }\n\n      // Allow certain operations on \"flags\" types\n      else if (isBitOperation && type.isFlags()) {\n        this._resolveAsParameterizedExpressionWithTypeContext(other, scope, type);\n        enumFlagsType = type;\n        type = this._cache.intType;\n        this._checkConversion(other, type, Skew.Resolving.ConversionKind.IMPLICIT);\n      }\n    }\n\n    // Allow \"~x\" on \"flags\" types\n    else if (kind == Skew.NodeKind.COMPLEMENT && type.isEnumOrFlags()) {\n      if (type.isFlags()) {\n        enumFlagsType = type;\n      }\n\n      type = this._cache.intType;\n      this._checkConversion(target, type, Skew.Resolving.ConversionKind.IMPLICIT);\n    }\n\n    // Find the operator method\n    var isComparison = Skew.in_NodeKind.isBinaryComparison(kind);\n    var name = isComparison ? '<=>' : info.text;\n    var symbol = this._findMember(type, name);\n    var extracted = null;\n    var wasUnaryPostfix = false;\n\n    // Convert operators like \"+=\" to a \"+\" inside a \"=\"\n    if (symbol == null && info.assignKind != Skew.NodeKind.NULL) {\n      symbol = this._findMember(type, in_IntMap.get1(Skew.operatorInfo, info.assignKind).text);\n\n      if (symbol != null) {\n        extracted = this._extractExpressionForAssignment(target, scope);\n\n        if (kind == Skew.NodeKind.PREFIX_INCREMENT || kind == Skew.NodeKind.PREFIX_DECREMENT || kind == Skew.NodeKind.POSTFIX_INCREMENT || kind == Skew.NodeKind.POSTFIX_DECREMENT) {\n          node.appendChild(this._cache.createInt(1).withRange(node.internalRangeOrRange()));\n\n          // This no longer makes sense\n          node.internalRange = null;\n        }\n\n        wasUnaryPostfix = Skew.in_NodeKind.isUnaryPostfix(kind) && Skew.Resolving.Resolver._isExpressionUsed(node);\n        kind = info.assignKind;\n        node.kind = kind;\n      }\n    }\n\n    // Special-case the \"in\" operator on \"flags\" types\n    if (symbol == null && kind == Skew.NodeKind.IN && enumFlagsType != null) {\n      node.become(Skew.Node.createBinary(Skew.NodeKind.NOT_EQUAL, Skew.Node.createBinary(Skew.NodeKind.BITWISE_AND, other.remove(), target.remove()).withRange(node.range), this._cache.createInt(0)).withRange(node.range));\n      this._resolveAsParameterizedExpression(node, scope);\n      return;\n    }\n\n    // Fail if the operator wasn't found\n    if (symbol == null) {\n      this._log.semanticErrorUnknownMemberSymbol(node.internalRangeOrRange(), name, type, null, null);\n      this._resolveChildrenAsParameterizedExpressions(node, scope);\n      return;\n    }\n\n    var symbolType = this._cache.substitute(symbol.resolvedType, type.environment);\n\n    // Resolve the overload now so the symbol's properties can be inspected\n    if (Skew.in_SymbolKind.isOverloadedFunction(symbol.kind)) {\n      if (reverseBinaryOrder) {\n        first.swapWith(second);\n      }\n\n      symbolType = this._resolveOverloadedFunction(node.internalRangeOrRange(), node, scope, symbolType);\n\n      if (reverseBinaryOrder) {\n        first.swapWith(second);\n      }\n\n      if (symbolType == null) {\n        this._resolveChildrenAsParameterizedExpressions(node, scope);\n        return;\n      }\n\n      symbol = symbolType.symbol;\n    }\n\n    var isRawImport = symbol.isImported() && !symbol.isRenamed();\n    node.symbol = symbol;\n    this._checkAccess(node, node.internalRangeOrRange(), scope);\n\n    // Check for a valid storage location for imported operators\n    if (Skew.in_NodeKind.isAssign(kind) && kind != Skew.NodeKind.ASSIGN_INDEX && symbol.isImported() && extracted == null) {\n      this._checkStorage(target, scope);\n    }\n\n    // \"<\", \">\", \"<=\", or \">=\"\n    if (isComparison && (isRawImport || type == this._cache.intType || type == this._cache.doubleType)) {\n      this._resolveChildrenAsParameterizedExpressions(node, scope);\n      node.resolvedType = this._cache.boolType;\n      node.symbol = null;\n    }\n\n    // Don't replace the operator with a call if it's just used for type checking\n    else if (isRawImport) {\n      if (reverseBinaryOrder) {\n        first.swapWith(second);\n      }\n\n      if (!this._resolveFunctionCall(node, scope, symbolType)) {\n        this._resolveChildrenAsParameterizedExpressions(node, scope);\n      }\n\n      if (reverseBinaryOrder) {\n        first.swapWith(second);\n      }\n\n      // Handle \"flags\" types\n      if (isBitOperation && enumFlagsType != null) {\n        node.resolvedType = enumFlagsType;\n      }\n    }\n\n    else {\n      // Resolve the method call\n      if (reverseBinaryOrder) {\n        first.swapWith(second);\n      }\n\n      node.prependChild(Skew.Node.createMemberReference(target.remove(), symbol).withRange(node.internalRangeOrRange()));\n\n      // Implement the logic for the \"<=>\" operator\n      if (isComparison) {\n        var call = new Skew.Node(Skew.NodeKind.CALL).appendChildrenFrom(node).withRange(node.range);\n        node.appendChild(call);\n        node.appendChild(this._cache.createInt(0));\n        node.resolvedType = this._cache.boolType;\n        this._resolveFunctionCall(call, scope, symbolType);\n      }\n\n      // All other operators are just normal method calls\n      else {\n        node.kind = Skew.NodeKind.CALL;\n        this._resolveFunctionCall(node, scope, symbolType);\n      }\n    }\n\n    if (extracted != null) {\n      // The expression used to initialize the assignment must return a value\n      if (symbolType.returnType == null) {\n        this._log.semanticErrorUseOfVoidFunction(node.range, symbol.name, symbol.range);\n      }\n\n      // Wrap everything in an assignment if the assignment target was extracted\n      this._promoteToAssignment(node, extracted);\n      this._resolveAsParameterizedExpression(node, scope);\n\n      // Handle custom unary postfix operators\n      if (wasUnaryPostfix) {\n        node.become(Skew.Node.createBinary(kind, node.cloneAndStealChildren(), this._cache.createInt(-1).withRange(node.internalRangeOrRange())).withRange(node.range));\n        this._resolveAsParameterizedExpression(node, scope);\n      }\n    }\n\n    // Handle custom unary assignment operators\n    else if (Skew.in_NodeKind.isUnaryAssign(kind) && !isRawImport) {\n      // \"foo(x++)\" => \"foo((ref = x, x = ref.increment(), ref))\"\n      if (Skew.in_NodeKind.isUnaryPostfix(kind) && Skew.Resolving.Resolver._isExpressionUsed(node)) {\n        var reference = this._generateReference(scope, target.resolvedType).withRange(target.range);\n        var original = this._extractExpressionForAssignment(target, scope);\n        target.replaceWith(reference);\n        this._promoteToAssignment(node, target);\n        node.become(new Skew.Node(Skew.NodeKind.SEQUENCE).appendChild(Skew.Node.createBinary(Skew.NodeKind.ASSIGN, reference.clone(), original).withRange(node.range)).appendChild(node.cloneAndStealChildren()).appendChild(reference.clone()).withRange(node.range));\n        this._resolveAsParameterizedExpression(node, scope);\n      }\n\n      // \"foo(++x)\" => \"foo(x = x.increment())\"\n      else {\n        this._promoteToAssignment(node, this._extractExpressionForAssignment(target, scope));\n        this._resolveAsParameterizedExpression(node, scope);\n      }\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._promoteToAssignment = function(node, extracted) {\n    assert(extracted.parent() == null);\n\n    if (extracted.kind == Skew.NodeKind.INDEX) {\n      extracted.kind = Skew.NodeKind.ASSIGN_INDEX;\n      extracted.appendChild(node.cloneAndStealChildren());\n      node.become(extracted);\n    }\n\n    else {\n      node.become(Skew.Node.createBinary(Skew.NodeKind.ASSIGN, extracted, node.cloneAndStealChildren()).withRange(node.range));\n    }\n  };\n\n  Skew.Resolving.Resolver.prototype._automaticallyCallGetter = function(node, scope) {\n    var symbol = node.symbol;\n\n    if (symbol == null) {\n      return false;\n    }\n\n    var kind = symbol.kind;\n    var parent = node.parent();\n\n    // Never call a getter if type parameters are present\n    if (parent != null && parent.kind == Skew.NodeKind.PARAMETERIZE && Skew.Resolving.Resolver._isCallValue(parent)) {\n      return false;\n    }\n\n    // The check for getters is complicated by overloaded functions\n    if (!symbol.isGetter() && Skew.in_SymbolKind.isOverloadedFunction(kind) && (!Skew.Resolving.Resolver._isCallValue(node) || parent.hasOneChild())) {\n      var overloaded = symbol.asOverloadedFunctionSymbol();\n\n      for (var i = 0, list = overloaded.symbols, count1 = list.length; i < count1; i = i + 1 | 0) {\n        var getter = in_List.get(list, i);\n\n        // Just return the first getter assuming errors for duplicate getters\n        // were already logged when the overloaded symbol was initialized\n        if (getter.isGetter()) {\n          node.resolvedType = this._cache.substitute(getter.resolvedType, node.resolvedType.environment);\n          node.symbol = getter;\n          symbol = getter;\n          break;\n        }\n      }\n    }\n\n    this._checkAccess(node, node.internalRangeOrRange(), scope);\n\n    // Automatically wrap the getter in a call expression\n    if (symbol.isGetter()) {\n      node.become(Skew.Node.createCall(node.cloneAndStealChildren()).withRange(node.range));\n      this._resolveAsParameterizedExpression(node, scope);\n      return true;\n    }\n\n    // Forbid bare function references\n    if (!symbol.isSetter() && node.resolvedType != Skew.Type.DYNAMIC && Skew.in_SymbolKind.isFunctionOrOverloadedFunction(kind) && kind != Skew.SymbolKind.FUNCTION_ANNOTATION && !Skew.Resolving.Resolver._isCallValue(node) && (parent == null || parent.kind != Skew.NodeKind.PARAMETERIZE || !Skew.Resolving.Resolver._isCallValue(parent))) {\n      var lower = 2147483647;\n      var upper = -1;\n\n      if (Skew.in_SymbolKind.isFunction(kind)) {\n        lower = upper = symbol.asFunctionSymbol().$arguments.length;\n      }\n\n      else {\n        for (var i1 = 0, list1 = symbol.asOverloadedFunctionSymbol().symbols, count2 = list1.length; i1 < count2; i1 = i1 + 1 | 0) {\n          var $function = in_List.get(list1, i1);\n          var count = $function.$arguments.length;\n\n          if (count < lower) {\n            lower = count;\n          }\n\n          if (count > upper) {\n            upper = count;\n          }\n        }\n      }\n\n      this._log.semanticErrorMustCallFunction(node.internalRangeOrRange(), symbol.name, lower, upper);\n      node.resolvedType = Skew.Type.DYNAMIC;\n    }\n\n    return false;\n  };\n\n  Skew.Resolving.Resolver.prototype._convertSwitchToIfChain = function(node, scope) {\n    var variable = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_LOCAL, scope.generateName('value'));\n    var value = node.switchValue().remove();\n    var block = null;\n\n    // Stash the variable being switched over so it's only evaluated once\n    variable.initializeWithType(value.resolvedType);\n    variable.value = value;\n    node.parent().insertChildBefore(node, new Skew.Node(Skew.NodeKind.VARIABLES).appendChild(Skew.Node.createVariable(variable)));\n\n    // Build the chain in reverse starting with the last case\n    for (var child = node.lastChild(); child != null; child = child.previousSibling()) {\n      var caseBlock = child.caseBlock().remove();\n      var test = null;\n\n      // Combine adjacent cases in a \"||\" chain\n      while (child.hasChildren()) {\n        var caseValue = Skew.Node.createBinary(Skew.NodeKind.EQUAL, Skew.Node.createSymbolReference(variable), child.firstChild().remove()).withType(this._cache.boolType);\n        test = test != null ? Skew.Node.createBinary(Skew.NodeKind.LOGICAL_OR, test, caseValue).withType(this._cache.boolType) : caseValue;\n      }\n\n      // Chain if-else statements together\n      block = test != null ? new Skew.Node(Skew.NodeKind.BLOCK).appendChild(Skew.Node.createIf(test, caseBlock, block)) : caseBlock;\n    }\n\n    // Replace the switch statement with the if chain\n    if (block != null) {\n      node.replaceWithChildrenFrom(block);\n    }\n\n    else {\n      node.remove();\n    }\n  };\n\n  Skew.Resolving.Resolver._shouldCheckForSetter = function(node) {\n    return node.parent() != null && node.parent().kind == Skew.NodeKind.ASSIGN && node == node.parent().binaryLeft();\n  };\n\n  Skew.Resolving.Resolver._isExpressionUsed = function(node) {\n    // Check for a null parent to handle variable initializers\n    var parent = node.parent();\n    return parent == null || parent.kind != Skew.NodeKind.EXPRESSION && !parent.isImplicitReturn() && (parent.kind != Skew.NodeKind.ANNOTATION || node != parent.annotationValue()) && (parent.kind != Skew.NodeKind.FOR || node != parent.forUpdate()) && parent.kind != Skew.NodeKind.SEQUENCE;\n  };\n\n  Skew.Resolving.Resolver._isValidVariableType = function(type) {\n    return type != Skew.Type.NULL && (type.kind != Skew.TypeKind.SYMBOL || !Skew.in_SymbolKind.isFunctionOrOverloadedFunction(type.symbol.kind));\n  };\n\n  Skew.Resolving.Resolver._isBaseGlobalReference = function(parent, member) {\n    return parent != null && parent.kind == Skew.SymbolKind.OBJECT_CLASS && Skew.in_SymbolKind.isGlobalReference(member.kind) && member.parent != parent && member.parent.kind == Skew.SymbolKind.OBJECT_CLASS && parent.asObjectSymbol().hasBaseClass(member.parent);\n  };\n\n  Skew.Resolving.Resolver._isCallValue = function(node) {\n    var parent = node.parent();\n    return parent != null && parent.kind == Skew.NodeKind.CALL && node == parent.callValue();\n  };\n\n  Skew.Resolving.Resolver._isCallReturningVoid = function(node) {\n    return node.kind == Skew.NodeKind.CALL && (node.symbol != null && node.symbol.resolvedType.returnType == null || node.callValue().resolvedType.kind == Skew.TypeKind.LAMBDA && node.callValue().resolvedType.returnType == null);\n  };\n\n  Skew.Resolving.Resolver._needsTypeContext = function(node) {\n    return node.kind == Skew.NodeKind.DOT && node.dotTarget() == null || node.kind == Skew.NodeKind.HOOK && Skew.Resolving.Resolver._needsTypeContext(node.hookTrue()) && Skew.Resolving.Resolver._needsTypeContext(node.hookFalse()) || Skew.in_NodeKind.isInitializer(node.kind);\n  };\n\n  Skew.Resolving.Resolver._matchCompletion = function(symbol, prefix) {\n    if (symbol.state == Skew.SymbolState.INITIALIZING) {\n      return false;\n    }\n\n    var name = symbol.name.toLowerCase();\n\n    if (in_string.get1(name, 0) == 95 && in_string.get1(prefix, 0) != 95) {\n      name = in_string.slice1(name, 1);\n    }\n\n    return name.startsWith(prefix.toLowerCase());\n  };\n\n  Skew.Resolving.Resolver.CompletionCheck = {\n    NORMAL: 0,\n    INSTANCE_ONLY: 1,\n    GLOBAL_ONLY: 2\n  };\n\n  Skew.Resolving.Resolver.GuardMergingFailure = function() {\n  };\n\n  Skew.LambdaConversion = {};\n\n  Skew.LambdaConversion.CaptureKind = {\n    FUNCTION: 0,\n    LAMBDA: 1,\n    LOOP: 2\n  };\n\n  Skew.LambdaConversion.Definition = function(symbol, node, scope) {\n    this.symbol = symbol;\n    this.node = node;\n    this.scope = scope;\n    this.isCaptured = false;\n    this.member = null;\n  };\n\n  Skew.LambdaConversion.Use = function(definition, node) {\n    this.definition = definition;\n    this.node = node;\n  };\n\n  Skew.LambdaConversion.Copy = function(scope) {\n    this.scope = scope;\n    this.member = null;\n  };\n\n  Skew.LambdaConversion.Scope = function(kind, node, enclosingFunction, parent) {\n    this.id = Skew.LambdaConversion.Scope._nextID = Skew.LambdaConversion.Scope._nextID + 1 | 0;\n    this.kind = kind;\n    this.node = node;\n    this.enclosingFunction = enclosingFunction;\n    this.parent = parent;\n    this.hasCapturedDefinitions = false;\n    this.hasCapturingUses = false;\n    this.environmentObject = null;\n    this.environmentVariable = null;\n    this.environmentConstructor = null;\n    this.environmentConstructorCall = null;\n    this.definitions = [];\n    this.uses = [];\n    this.copies = [];\n    this.definitionLookup = new Map();\n    this.copyLookup = new Map();\n  };\n\n  Skew.LambdaConversion.Scope.prototype.recordDefinition = function(symbol, node) {\n    assert(!this.definitionLookup.has(symbol.id));\n    var definition = new Skew.LambdaConversion.Definition(symbol, node, this);\n    this.definitions.push(definition);\n    in_IntMap.set(this.definitionLookup, symbol.id, definition);\n  };\n\n  Skew.LambdaConversion.Scope.prototype.recordUse = function(symbol, node) {\n    var isCaptured = false;\n\n    // Walk up the scope chain\n    for (var scope = this; scope != null; scope = scope.parent) {\n      var definition = in_IntMap.get(scope.definitionLookup, symbol.id, null);\n\n      // Stop once the definition is found\n      if (definition != null) {\n        this.uses.push(new Skew.LambdaConversion.Use(definition, node));\n\n        if (isCaptured) {\n          definition.isCaptured = true;\n          scope.hasCapturedDefinitions = true;\n          this.hasCapturingUses = true;\n        }\n\n        break;\n      }\n\n      // Variables are captured if a lambda is in the scope chain\n      if (scope.kind == Skew.LambdaConversion.CaptureKind.LAMBDA) {\n        isCaptured = true;\n      }\n    }\n  };\n\n  Skew.LambdaConversion.Scope.prototype.createReferenceToScope = function(scope) {\n    // Skip to the enclosing scope with an environment\n    var target = this;\n\n    while (target.environmentObject == null) {\n      assert(!target.hasCapturedDefinitions && target.kind != Skew.LambdaConversion.CaptureKind.LAMBDA);\n      target = target.parent;\n    }\n\n    // Reference this scope\n    if (scope == target) {\n      return Skew.Node.createSymbolReference(target.environmentVariable);\n    }\n\n    // Reference a parent scope\n    var copy = in_IntMap.get1(target.copyLookup, scope.id);\n    return Skew.Node.createMemberReference(Skew.Node.createSymbolReference(target.environmentVariable), copy.member);\n  };\n\n  Skew.LambdaConversion.Converter = function(_global, _cache) {\n    this._global = _global;\n    this._cache = _cache;\n    this._scopes = [];\n    this._stack = [];\n    this._interfaces = new Map();\n    this._calls = [];\n    this._skewNamespace = null;\n    this._enclosingFunction = null;\n  };\n\n  Skew.LambdaConversion.Converter.prototype.run = function() {\n    this._visitObject(this._global);\n    this._convertCalls();\n    this._convertLambdas();\n  };\n\n  Skew.LambdaConversion.Converter.prototype._convertCalls = function() {\n    var swap = new Skew.Node(Skew.NodeKind.NULL);\n\n    for (var i = 0, list = this._calls, count = list.length; i < count; i = i + 1 | 0) {\n      var node = in_List.get(list, i);\n      var value = node.callValue();\n      var resolvedType = value.resolvedType;\n\n      if (resolvedType.kind == Skew.TypeKind.LAMBDA) {\n        var interfaceType = this._interfaceTypeForLambdaType(resolvedType);\n        var interfaceRun = in_List.first(interfaceType.symbol.asObjectSymbol().functions);\n        assert(interfaceRun.name == 'run');\n        value.replaceWith(swap);\n        swap.replaceWith(Skew.Node.createMemberReference(value, interfaceRun));\n      }\n    }\n  };\n\n  Skew.LambdaConversion.Converter.prototype._convertLambdas = function() {\n    // Propagate required environment copies up the scope chain\n    for (var i1 = 0, list1 = this._scopes, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n      var scope = in_List.get(list1, i1);\n\n      if (scope.hasCapturingUses) {\n        for (var i = 0, list = scope.uses, count = list.length; i < count; i = i + 1 | 0) {\n          var use = in_List.get(list, i);\n\n          if (use.definition.isCaptured) {\n            var definingScope = use.definition.scope;\n\n            for (var s = scope; s != definingScope; s = s.parent) {\n              if (!s.copyLookup.has(definingScope.id)) {\n                var copy = new Skew.LambdaConversion.Copy(definingScope);\n                s.copies.push(copy);\n                in_IntMap.set(s.copyLookup, definingScope.id, copy);\n              }\n            }\n          }\n        }\n      }\n    }\n\n    for (var i5 = 0, list5 = this._scopes, count5 = list5.length; i5 < count5; i5 = i5 + 1 | 0) {\n      var scope1 = in_List.get(list5, i5);\n\n      if (scope1.hasCapturedDefinitions || scope1.kind == Skew.LambdaConversion.CaptureKind.LAMBDA) {\n        // Create an object to store the environment\n        var object = this._createObject(Skew.SymbolKind.OBJECT_CLASS, Skew.LambdaConversion.Converter._generateEnvironmentName(scope1), this._global);\n        var $constructor = Skew.LambdaConversion.Converter._createConstructor(object);\n        var constructorCall = Skew.Node.createCall(Skew.Node.createMemberReference(Skew.Node.createSymbolReference(object), $constructor)).withType(object.resolvedType);\n\n        // The environment must store all captured variables\n        for (var i2 = 0, list2 = scope1.definitions, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n          var definition = in_List.get(list2, i2);\n\n          if (definition.isCaptured) {\n            definition.member = Skew.LambdaConversion.Converter._createInstanceVariable(object.scope.generateName(definition.symbol.name), definition.symbol.resolvedType, object);\n          }\n        }\n\n        // Insert the constructor call declaration\n        switch (scope1.kind) {\n          case Skew.LambdaConversion.CaptureKind.FUNCTION: {\n            // Store the environment instance in a variable\n            var variable = Skew.LambdaConversion.Converter._createVariable(Skew.SymbolKind.VARIABLE_LOCAL, scope1.enclosingFunction.scope.generateName('env'), object.resolvedType);\n            variable.value = constructorCall;\n            scope1.environmentVariable = variable;\n\n            // Define the variable at the top of the function body\n            var variables = new Skew.Node(Skew.NodeKind.VARIABLES).appendChild(Skew.Node.createVariable(variable));\n\n            // TODO: Insert this after the call to \"super\"\n            scope1.node.prependChild(variables);\n\n            // Assign captured arguments and \"self\" to the environment\n            // TODO: Remove the extra indirection to \"self\", copy it directly into environments instead\n            var previous = variables;\n\n            for (var i3 = 0, list3 = scope1.definitions, count3 = list3.length; i3 < count3; i3 = i3 + 1 | 0) {\n              var definition1 = in_List.get(list3, i3);\n\n              if (definition1.isCaptured && (definition1.symbol.kind == Skew.SymbolKind.VARIABLE_ARGUMENT || definition1.symbol == scope1.enclosingFunction.$this)) {\n                var assignment = Skew.LambdaConversion.Converter._createAssignment(variable, definition1.member, definition1.symbol);\n                scope1.node.insertChildAfter(previous, assignment);\n                previous = assignment;\n              }\n            }\n            break;\n          }\n\n          case Skew.LambdaConversion.CaptureKind.LAMBDA: {\n            var $function = scope1.node.symbol.asFunctionSymbol();\n            $function.kind = Skew.SymbolKind.FUNCTION_INSTANCE;\n            $function.name = 'run';\n            $function.$this = Skew.LambdaConversion.Converter._createVariable(Skew.SymbolKind.VARIABLE_LOCAL, 'self', object.resolvedType);\n            $function.parent = object;\n            object.functions.push($function);\n            scope1.node.become(constructorCall);\n            scope1.environmentVariable = $function.$this;\n            constructorCall = scope1.node;\n\n            // Lambdas introduce two scopes instead of one. All captured\n            // definitions for that lambda have to be in the nested scope,\n            // even lambda function arguments, because that nested scope\n            // needs to be different for each invocation of the lambda.\n            assert(!scope1.hasCapturedDefinitions);\n\n            // Implement the lambda interface with the right type parameters\n            var interfaceType = this._interfaceTypeForLambdaType($function.resolvedType);\n            var interfaceFunction = in_List.first(interfaceType.symbol.asObjectSymbol().functions);\n            assert(interfaceFunction.name == 'run');\n            object.$implements = [new Skew.Node(Skew.NodeKind.TYPE).withType(interfaceType)];\n            object.interfaceTypes = [interfaceType];\n\n            if (interfaceFunction.implementations == null) {\n              interfaceFunction.implementations = [];\n            }\n\n            interfaceFunction.implementations.push($function);\n            break;\n          }\n\n          case Skew.LambdaConversion.CaptureKind.LOOP: {\n            // Store the environment instance in a variable\n            var variable1 = Skew.LambdaConversion.Converter._createVariable(Skew.SymbolKind.VARIABLE_LOCAL, scope1.enclosingFunction.scope.generateName('env'), object.resolvedType);\n            variable1.value = constructorCall;\n            scope1.environmentVariable = variable1;\n\n            // Define the variable at the top of the function body\n            var variables1 = new Skew.Node(Skew.NodeKind.VARIABLES).appendChild(Skew.Node.createVariable(variable1));\n            var node = scope1.node;\n            var block = node.kind == Skew.NodeKind.FOR ? node.forBlock() : node.kind == Skew.NodeKind.FOREACH ? node.foreachBlock() : node.kind == Skew.NodeKind.WHILE ? node.whileBlock() : null;\n            block.prependChild(variables1);\n\n            // Assign captured loop variables\n            var previous1 = variables1;\n\n            for (var i4 = 0, list4 = scope1.definitions, count4 = list4.length; i4 < count4; i4 = i4 + 1 | 0) {\n              var definition2 = in_List.get(list4, i4);\n\n              if (definition2.isCaptured && definition2.symbol.isLoopVariable()) {\n                var assignment1 = Skew.LambdaConversion.Converter._createAssignment(variable1, definition2.member, definition2.symbol);\n                block.insertChildAfter(previous1, assignment1);\n                previous1 = assignment1;\n              }\n            }\n            break;\n          }\n\n          default: {\n            assert(false);\n            break;\n          }\n        }\n\n        // These will be referenced later\n        scope1.environmentObject = object;\n        scope1.environmentConstructor = $constructor;\n        scope1.environmentConstructorCall = constructorCall;\n      }\n\n      // Mutate the parent scope pointer to skip past irrelevant scopes\n      // (those without environments). This means everything necessary to\n      // access captured symbols can be found on the environment associated\n      // with the parent scope without needing to look at grandparent scopes.\n      //\n      // All parent scopes that need environments should already have them\n      // because scopes are iterated over using a pre-order traversal.\n      while (scope1.parent != null && scope1.parent.environmentObject == null) {\n        assert(!scope1.parent.hasCapturedDefinitions && scope1.parent.kind != Skew.LambdaConversion.CaptureKind.LAMBDA);\n        scope1.parent = scope1.parent.parent;\n      }\n    }\n\n    // Make sure each environment has a copy of each parent environment that it or its children needs\n    for (var i7 = 0, list7 = this._scopes, count7 = list7.length; i7 < count7; i7 = i7 + 1 | 0) {\n      var scope2 = in_List.get(list7, i7);\n      var object1 = scope2.environmentObject;\n      var constructor1 = scope2.environmentConstructor;\n      var constructorCall1 = scope2.environmentConstructorCall;\n\n      if (object1 != null) {\n        for (var i6 = 0, list6 = scope2.copies, count6 = list6.length; i6 < count6; i6 = i6 + 1 | 0) {\n          var copy1 = in_List.get(list6, i6);\n          var name = object1.scope.generateName(copy1.scope.kind == Skew.LambdaConversion.CaptureKind.LAMBDA ? 'lambda' : 'env');\n          var member = Skew.LambdaConversion.Converter._createInstanceVariable(name, copy1.scope.environmentObject.resolvedType, object1);\n          var argument = Skew.LambdaConversion.Converter._createVariable(Skew.SymbolKind.VARIABLE_ARGUMENT, name, member.resolvedType);\n          copy1.member = member;\n          constructor1.$arguments.push(argument);\n          constructor1.resolvedType.argumentTypes.push(argument.resolvedType);\n          constructor1.block.appendChild(Skew.LambdaConversion.Converter._createAssignment(constructor1.$this, member, argument));\n          constructorCall1.appendChild(scope2.parent.createReferenceToScope(copy1.scope));\n        }\n      }\n    }\n\n    for (var i10 = 0, list10 = this._scopes, count10 = list10.length; i10 < count10; i10 = i10 + 1 | 0) {\n      var scope3 = in_List.get(list10, i10);\n\n      // Replace variable definitions of captured symbols with assignments to their environment\n      if (scope3.hasCapturedDefinitions) {\n        for (var i8 = 0, list8 = scope3.definitions, count8 = list8.length; i8 < count8; i8 = i8 + 1 | 0) {\n          var definition3 = in_List.get(list8, i8);\n\n          if (definition3.isCaptured && definition3.node != null) {\n            assert(definition3.node.kind == Skew.NodeKind.VARIABLE);\n            assert(definition3.node.parent().kind == Skew.NodeKind.VARIABLES);\n            definition3.node.extractVariableFromVariables();\n            definition3.node.parent().replaceWith(Skew.Node.createExpression(Skew.Node.createBinary(Skew.NodeKind.ASSIGN, Skew.Node.createMemberReference(Skew.Node.createSymbolReference(scope3.environmentVariable), definition3.member), definition3.symbol.value.remove()).withType(definition3.member.resolvedType)));\n          }\n        }\n      }\n\n      // Replace all references to captured variables with a member access from the appropriate environment\n      for (var i9 = 0, list9 = scope3.uses, count9 = list9.length; i9 < count9; i9 = i9 + 1 | 0) {\n        var use1 = in_List.get(list9, i9);\n\n        if (use1.definition.isCaptured) {\n          use1.node.become(Skew.Node.createMemberReference(scope3.createReferenceToScope(use1.definition.scope), use1.definition.member));\n        }\n      }\n    }\n  };\n\n  Skew.LambdaConversion.Converter.prototype._visitObject = function(symbol) {\n    for (var i = 0, list = symbol.objects, count = list.length; i < count; i = i + 1 | 0) {\n      var object = in_List.get(list, i);\n      this._visitObject(object);\n    }\n\n    for (var i1 = 0, list1 = symbol.functions, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n      var $function = in_List.get(list1, i1);\n      this._visitFunction($function);\n    }\n\n    for (var i2 = 0, list2 = symbol.variables, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n      var variable = in_List.get(list2, i2);\n      this._visitVariable(variable);\n    }\n  };\n\n  Skew.LambdaConversion.Converter.prototype._visitFunction = function(symbol) {\n    if (symbol.block != null) {\n      this._enclosingFunction = symbol;\n      var scope = this._pushScope(Skew.LambdaConversion.CaptureKind.FUNCTION, symbol.block, null);\n\n      if (symbol.$this != null) {\n        scope.recordDefinition(symbol.$this, null);\n      }\n\n      for (var i = 0, list = symbol.$arguments, count = list.length; i < count; i = i + 1 | 0) {\n        var argument = in_List.get(list, i);\n        scope.recordDefinition(argument, null);\n      }\n\n      this._visit(symbol.block);\n      in_List.removeLast(this._stack);\n      this._enclosingFunction = null;\n    }\n  };\n\n  Skew.LambdaConversion.Converter.prototype._visitVariable = function(symbol) {\n    if (symbol.value != null) {\n      this._visit(symbol.value);\n    }\n  };\n\n  Skew.LambdaConversion.Converter.prototype._visit = function(node) {\n    var kind = node.kind;\n    var symbol = node.symbol;\n    var oldEnclosingFunction = this._enclosingFunction;\n\n    if (kind == Skew.NodeKind.LAMBDA) {\n      this._enclosingFunction = symbol.asFunctionSymbol();\n      var lambdaScope = this._pushScope(Skew.LambdaConversion.CaptureKind.LAMBDA, node, this._stack.length == 0 ? null : in_List.last(this._stack));\n      var scope = this._pushScope(Skew.LambdaConversion.CaptureKind.FUNCTION, node.lambdaBlock(), lambdaScope);\n\n      for (var i = 0, list = symbol.asFunctionSymbol().$arguments, count = list.length; i < count; i = i + 1 | 0) {\n        var argument = in_List.get(list, i);\n        scope.recordDefinition(argument, null);\n      }\n    }\n\n    else if (kind == Skew.NodeKind.FOREACH) {\n      // Visit loop header\n      this._visit(node.foreachValue());\n\n      // Visit loop body\n      var scope1 = this._pushScope(Skew.LambdaConversion.CaptureKind.LOOP, node, in_List.last(this._stack));\n      scope1.recordDefinition(symbol.asVariableSymbol(), null);\n      this._visit(node.foreachBlock());\n      in_List.removeLast(this._stack);\n      return;\n    }\n\n    else if (kind == Skew.NodeKind.FOR || kind == Skew.NodeKind.WHILE) {\n      this._pushScope(Skew.LambdaConversion.CaptureKind.LOOP, node, in_List.last(this._stack));\n    }\n\n    else if (kind == Skew.NodeKind.VARIABLE) {\n      in_List.last(this._stack).recordDefinition(symbol.asVariableSymbol(), node);\n    }\n\n    else if (kind == Skew.NodeKind.CATCH) {\n      // TODO\n    }\n\n    else if (kind == Skew.NodeKind.CALL) {\n      this._calls.push(node);\n    }\n\n    else if (kind == Skew.NodeKind.NAME && symbol != null && (symbol.kind == Skew.SymbolKind.VARIABLE_ARGUMENT || symbol.kind == Skew.SymbolKind.VARIABLE_LOCAL)) {\n      in_List.last(this._stack).recordUse(symbol.asVariableSymbol(), node);\n    }\n\n    for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n      this._visit(child);\n    }\n\n    if (kind == Skew.NodeKind.LAMBDA) {\n      in_List.removeLast(this._stack);\n      in_List.removeLast(this._stack);\n      this._enclosingFunction = oldEnclosingFunction;\n    }\n\n    else if (Skew.in_NodeKind.isLoop(kind)) {\n      in_List.removeLast(this._stack);\n    }\n  };\n\n  Skew.LambdaConversion.Converter.prototype._pushScope = function(kind, node, parent) {\n    var scope = new Skew.LambdaConversion.Scope(kind, node, this._enclosingFunction, parent);\n    this._scopes.push(scope);\n    this._stack.push(scope);\n    return scope;\n  };\n\n  Skew.LambdaConversion.Converter.prototype._createObject = function(kind, name, parent) {\n    var object = new Skew.ObjectSymbol(kind, parent.scope.generateName(name));\n    object.scope = new Skew.ObjectScope(parent.scope, object);\n    object.resolvedType = new Skew.Type(Skew.TypeKind.SYMBOL, object);\n    object.state = Skew.SymbolState.INITIALIZED;\n    object.parent = parent;\n    parent.objects.push(object);\n    return object;\n  };\n\n  Skew.LambdaConversion.Converter.prototype._ensureSkewNamespaceExists = function() {\n    if (this._skewNamespace == null) {\n      var symbol = this._global.scope.find('Skew', Skew.ScopeSearch.NORMAL);\n\n      // Did the user's code define the namespace?\n      if (symbol != null && Skew.in_SymbolKind.isObject(symbol.kind)) {\n        this._skewNamespace = symbol.asObjectSymbol();\n      }\n\n      // It's missing or there's a conflict, define one ourselves\n      else {\n        this._skewNamespace = this._createObject(Skew.SymbolKind.OBJECT_NAMESPACE, 'Skew', this._global);\n        this._skewNamespace.flags |= Skew.SymbolFlags.IS_IMPORTED;\n      }\n    }\n  };\n\n  Skew.LambdaConversion.Converter.prototype._createInterface = function(count, hasReturnType) {\n    var key = count << 1 | hasReturnType;\n    var object = in_IntMap.get(this._interfaces, key, null);\n\n    if (object == null) {\n      this._ensureSkewNamespaceExists();\n      object = this._createObject(Skew.SymbolKind.OBJECT_INTERFACE, (hasReturnType ? 'Fn' : 'FnVoid') + count.toString(), this._skewNamespace);\n      object.flags |= Skew.SymbolFlags.IS_IMPORTED;\n      in_IntMap.set(this._interfaces, key, object);\n      var $function = Skew.LambdaConversion.Converter._createFunction(object, Skew.SymbolKind.FUNCTION_INSTANCE, 'run', Skew.LambdaConversion.Converter.Body.ABSTRACT);\n      $function.flags |= Skew.SymbolFlags.IS_IMPORTED;\n      $function.resolvedType.argumentTypes = [];\n\n      if (hasReturnType) {\n        var returnType = Skew.LambdaConversion.Converter._createParameter(object, 'R').resolvedType;\n        $function.resolvedType.returnType = returnType;\n        $function.returnType = new Skew.Node(Skew.NodeKind.TYPE).withType(returnType);\n      }\n\n      for (var i = 0, count1 = count; i < count1; i = i + 1 | 0) {\n        var parameter = Skew.LambdaConversion.Converter._createParameter(object, 'A' + (i + 1 | 0).toString());\n        $function.$arguments.push(Skew.LambdaConversion.Converter._createVariable(Skew.SymbolKind.VARIABLE_ARGUMENT, 'a' + (i + 1 | 0).toString(), parameter.resolvedType));\n        $function.resolvedType.argumentTypes.push(parameter.resolvedType);\n      }\n    }\n\n    return object;\n  };\n\n  Skew.LambdaConversion.Converter.prototype._interfaceTypeForLambdaType = function(lambdaType) {\n    var $interface = this._createInterface(lambdaType.argumentTypes.length, lambdaType.returnType != null);\n    var interfaceType = $interface.resolvedType;\n    var substitutions = [];\n\n    if (lambdaType.returnType != null) {\n      substitutions.push(lambdaType.returnType);\n    }\n\n    in_List.append1(substitutions, lambdaType.argumentTypes);\n\n    if (!(substitutions.length == 0)) {\n      interfaceType = this._cache.substitute(interfaceType, this._cache.createEnvironment($interface.parameters, substitutions));\n    }\n\n    return interfaceType;\n  };\n\n  Skew.LambdaConversion.Converter._generateEnvironmentName = function(scope) {\n    var name = '';\n    var root = scope;\n\n    while (root.parent != null) {\n      root = root.parent;\n    }\n\n    for (var symbol = root.enclosingFunction; symbol != null && symbol.kind != Skew.SymbolKind.OBJECT_GLOBAL; symbol = symbol.parent) {\n      if (symbol.kind != Skew.SymbolKind.OBJECT_GLOBAL && !Skew.Renaming.isInvalidIdentifier(symbol.name)) {\n        name = Skew.withUppercaseFirstLetter(symbol.name) + name;\n      }\n    }\n\n    name += scope.kind == Skew.LambdaConversion.CaptureKind.LAMBDA ? 'Lambda' : 'Env';\n    return name;\n  };\n\n  Skew.LambdaConversion.Converter._createConstructor = function(object) {\n    var $function = Skew.LambdaConversion.Converter._createFunction(object, Skew.SymbolKind.FUNCTION_CONSTRUCTOR, 'new', Skew.LambdaConversion.Converter.Body.IMPLEMENTED);\n    $function.resolvedType.returnType = object.resolvedType;\n    $function.returnType = new Skew.Node(Skew.NodeKind.TYPE).withType(object.resolvedType);\n    return $function;\n  };\n\n  Skew.LambdaConversion.Converter._createFunction = function(object, kind, name, body) {\n    var $function = new Skew.FunctionSymbol(kind, name);\n    $function.scope = new Skew.FunctionScope(object.scope, $function);\n    $function.resolvedType = new Skew.Type(Skew.TypeKind.SYMBOL, $function);\n    $function.resolvedType.argumentTypes = [];\n    $function.state = Skew.SymbolState.INITIALIZED;\n    $function.parent = object;\n\n    if (body == Skew.LambdaConversion.Converter.Body.IMPLEMENTED) {\n      $function.block = new Skew.Node(Skew.NodeKind.BLOCK);\n      $function.$this = Skew.LambdaConversion.Converter._createVariable(Skew.SymbolKind.VARIABLE_LOCAL, 'self', object.resolvedType);\n    }\n\n    object.functions.push($function);\n    return $function;\n  };\n\n  Skew.LambdaConversion.Converter._createInstanceVariable = function(name, type, object) {\n    var variable = Skew.LambdaConversion.Converter._createVariable(Skew.SymbolKind.VARIABLE_INSTANCE, name, type);\n    variable.parent = object;\n    object.variables.push(variable);\n    return variable;\n  };\n\n  Skew.LambdaConversion.Converter._createVariable = function(kind, name, type) {\n    var variable = new Skew.VariableSymbol(kind, name);\n    variable.initializeWithType(type);\n    return variable;\n  };\n\n  Skew.LambdaConversion.Converter._createParameter = function(parent, name) {\n    var parameter = new Skew.ParameterSymbol(Skew.SymbolKind.PARAMETER_OBJECT, name);\n    parameter.resolvedType = new Skew.Type(Skew.TypeKind.SYMBOL, parameter);\n    parameter.state = Skew.SymbolState.INITIALIZED;\n\n    if (parent.parameters == null) {\n      parent.parameters = [];\n    }\n\n    parent.parameters.push(parameter);\n    return parameter;\n  };\n\n  Skew.LambdaConversion.Converter._createAssignment = function(object, member, variable) {\n    return Skew.Node.createExpression(Skew.Node.createBinary(Skew.NodeKind.ASSIGN, Skew.Node.createMemberReference(Skew.Node.createSymbolReference(object), member), Skew.Node.createSymbolReference(variable)).withType(member.resolvedType));\n  };\n\n  Skew.LambdaConversion.Converter.Body = {\n    ABSTRACT: 0,\n    IMPLEMENTED: 1\n  };\n\n  Skew.CompilerTarget = function() {\n  };\n\n  Skew.CompilerTarget.prototype.stopAfterResolve = function() {\n    return true;\n  };\n\n  Skew.CompilerTarget.prototype.requiresIntegerSwitchStatements = function() {\n    return false;\n  };\n\n  Skew.CompilerTarget.prototype.supportsListForeach = function() {\n    return false;\n  };\n\n  Skew.CompilerTarget.prototype.supportsNestedTypes = function() {\n    return false;\n  };\n\n  Skew.CompilerTarget.prototype.needsLambdaLifting = function() {\n    return false;\n  };\n\n  Skew.CompilerTarget.prototype.removeSingletonInterfaces = function() {\n    return false;\n  };\n\n  Skew.CompilerTarget.prototype.stringEncoding = function() {\n    return Unicode.Encoding.UTF32;\n  };\n\n  Skew.CompilerTarget.prototype.editOptions = function(options) {\n  };\n\n  Skew.CompilerTarget.prototype.includeSources = function(sources) {\n  };\n\n  Skew.CompilerTarget.prototype.createEmitter = function(context) {\n    return null;\n  };\n\n  Skew.JavaScriptTarget = function() {\n    Skew.CompilerTarget.call(this);\n  };\n\n  __extends(Skew.JavaScriptTarget, Skew.CompilerTarget);\n\n  Skew.JavaScriptTarget.prototype.stopAfterResolve = function() {\n    return false;\n  };\n\n  Skew.JavaScriptTarget.prototype.supportsNestedTypes = function() {\n    return true;\n  };\n\n  Skew.JavaScriptTarget.prototype.removeSingletonInterfaces = function() {\n    return true;\n  };\n\n  Skew.JavaScriptTarget.prototype.stringEncoding = function() {\n    return Unicode.Encoding.UTF16;\n  };\n\n  Skew.JavaScriptTarget.prototype.editOptions = function(options) {\n    options.define('TARGET', 'JAVASCRIPT');\n  };\n\n  Skew.JavaScriptTarget.prototype.includeSources = function(sources) {\n    sources.unshift(new Skew.Source('<native-js>', Skew.NATIVE_LIBRARY_JS));\n  };\n\n  Skew.JavaScriptTarget.prototype.createEmitter = function(context) {\n    return new Skew.JavaScriptEmitter(context, context.options, context.cache);\n  };\n\n  Skew.CPlusPlusTarget = function() {\n    Skew.CompilerTarget.call(this);\n  };\n\n  __extends(Skew.CPlusPlusTarget, Skew.CompilerTarget);\n\n  Skew.CPlusPlusTarget.prototype.stopAfterResolve = function() {\n    return false;\n  };\n\n  Skew.CPlusPlusTarget.prototype.requiresIntegerSwitchStatements = function() {\n    return true;\n  };\n\n  Skew.CPlusPlusTarget.prototype.supportsListForeach = function() {\n    return true;\n  };\n\n  Skew.CPlusPlusTarget.prototype.needsLambdaLifting = function() {\n    return true;\n  };\n\n  Skew.CPlusPlusTarget.prototype.stringEncoding = function() {\n    return Unicode.Encoding.UTF8;\n  };\n\n  Skew.CPlusPlusTarget.prototype.editOptions = function(options) {\n    options.define('TARGET', 'CPLUSPLUS');\n  };\n\n  Skew.CPlusPlusTarget.prototype.includeSources = function(sources) {\n    sources.unshift(new Skew.Source('<native-cpp>', Skew.NATIVE_LIBRARY_CPP));\n  };\n\n  Skew.CPlusPlusTarget.prototype.createEmitter = function(context) {\n    return new Skew.CPlusPlusEmitter(context.options, context.cache);\n  };\n\n  Skew.CSharpTarget = function() {\n    Skew.CompilerTarget.call(this);\n  };\n\n  __extends(Skew.CSharpTarget, Skew.CompilerTarget);\n\n  Skew.CSharpTarget.prototype.stopAfterResolve = function() {\n    return false;\n  };\n\n  Skew.CSharpTarget.prototype.requiresIntegerSwitchStatements = function() {\n    return true;\n  };\n\n  Skew.CSharpTarget.prototype.supportsListForeach = function() {\n    return true;\n  };\n\n  Skew.CSharpTarget.prototype.supportsNestedTypes = function() {\n    return true;\n  };\n\n  Skew.CSharpTarget.prototype.stringEncoding = function() {\n    return Unicode.Encoding.UTF16;\n  };\n\n  Skew.CSharpTarget.prototype.editOptions = function(options) {\n    options.define('TARGET', 'CSHARP');\n  };\n\n  Skew.CSharpTarget.prototype.includeSources = function(sources) {\n    sources.unshift(new Skew.Source('<native-cs>', Skew.NATIVE_LIBRARY_CS));\n  };\n\n  Skew.CSharpTarget.prototype.createEmitter = function(context) {\n    return new Skew.CSharpEmitter(context.options, context.cache);\n  };\n\n  Skew.LispTreeTarget = function() {\n    Skew.CompilerTarget.call(this);\n  };\n\n  __extends(Skew.LispTreeTarget, Skew.CompilerTarget);\n\n  Skew.LispTreeTarget.prototype.createEmitter = function(context) {\n    return new Skew.LispTreeEmitter(context.options);\n  };\n\n  Skew.TypeScriptTarget = function() {\n    Skew.CompilerTarget.call(this);\n  };\n\n  __extends(Skew.TypeScriptTarget, Skew.CompilerTarget);\n\n  Skew.TypeScriptTarget.prototype.stopAfterResolve = function() {\n    return false;\n  };\n\n  Skew.TypeScriptTarget.prototype.requiresIntegerSwitchStatements = function() {\n    return true;\n  };\n\n  Skew.TypeScriptTarget.prototype.supportsListForeach = function() {\n    return true;\n  };\n\n  Skew.TypeScriptTarget.prototype.supportsNestedTypes = function() {\n    return true;\n  };\n\n  Skew.TypeScriptTarget.prototype.removeSingletonInterfaces = function() {\n    return true;\n  };\n\n  Skew.TypeScriptTarget.prototype.stringEncoding = function() {\n    return Unicode.Encoding.UTF16;\n  };\n\n  Skew.TypeScriptTarget.prototype.editOptions = function(options) {\n    options.define('TARGET', 'JAVASCRIPT');\n  };\n\n  Skew.TypeScriptTarget.prototype.includeSources = function(sources) {\n    sources.unshift(new Skew.Source('<native-js>', Skew.NATIVE_LIBRARY_JS));\n  };\n\n  Skew.TypeScriptTarget.prototype.createEmitter = function(context) {\n    return new Skew.TypeScriptEmitter(context.log, context.options, context.cache);\n  };\n\n  Skew.Define = function(name, value) {\n    this.name = name;\n    this.value = value;\n  };\n\n  Skew.CompilerOptions = function() {\n    var self = this;\n    self.completionContext = null;\n    self.defines = new Map();\n    self.foldAllConstants = false;\n    self.globalizeAllFunctions = false;\n    self.inlineAllFunctions = false;\n    self.isAlwaysInlinePresent = false;\n    self.jsMangle = false;\n    self.jsMinify = false;\n    self.jsSourceMap = false;\n    self.outputDirectory = null;\n    self.outputFile = null;\n    self.passes = null;\n    self.stopAfterResolve = false;\n    self.target = new Skew.CompilerTarget();\n    self.verbose = false;\n    self.warnAboutIgnoredComments = false;\n    self.warningsAreErrors = false;\n    self.passes = [\n      new Skew.LexingPass(),\n      new Skew.ParsingPass(),\n      new Skew.MergingPass(),\n      new Skew.ResolvingPass(),\n      new Skew.LambdaConversionPass().onlyRunWhen(function() {\n        return self._continueAfterResolve() && self.target.needsLambdaLifting();\n      }),\n      new Skew.InterfaceRemovalPass().onlyRunWhen(function() {\n        return self._continueAfterResolve() && self.target.removeSingletonInterfaces() && self.globalizeAllFunctions;\n      }),\n      // The call graph is used as a shortcut so the tree only needs to be scanned once for all call-based optimizations\n      new Skew.CallGraphPass().onlyRunWhen(function() {\n        return self._continueAfterResolve();\n      }),\n      new Skew.GlobalizingPass().onlyRunWhen(function() {\n        return self._continueAfterResolve();\n      }),\n      new Skew.MotionPass().onlyRunWhen(function() {\n        return self._continueAfterResolve();\n      }),\n      new Skew.RenamingPass().onlyRunWhen(function() {\n        return self._continueAfterResolve();\n      }),\n      new Skew.FoldingPass().onlyRunWhen(function() {\n        return self._continueAfterResolve() && self.foldAllConstants;\n      }),\n      new Skew.InliningPass().onlyRunWhen(function() {\n        return self._continueAfterResolve() && (self.inlineAllFunctions || self.isAlwaysInlinePresent);\n      }),\n      new Skew.FoldingPass().onlyRunWhen(function() {\n        return self._continueAfterResolve() && (self.inlineAllFunctions || self.isAlwaysInlinePresent) && self.foldAllConstants;\n      }),\n      new Skew.EmittingPass().onlyRunWhen(function() {\n        return !self.stopAfterResolve;\n      })\n    ];\n  };\n\n  Skew.CompilerOptions.prototype.define = function(name, value) {\n    var range = new Skew.Source('<internal>', '--define:' + name + '=' + value).entireRange();\n    in_StringMap.set(this.defines, name, new Skew.Define(range.slice(9, 9 + name.length | 0), range.fromEnd(value.length)));\n  };\n\n  Skew.CompilerOptions.prototype._continueAfterResolve = function() {\n    return !this.stopAfterResolve && !this.target.stopAfterResolve();\n  };\n\n  Skew.CompilerOptions.prototype.createTargetFromExtension = function() {\n    if (this.outputFile != null) {\n      var dot = this.outputFile.lastIndexOf('.');\n\n      if (dot != -1) {\n        switch (in_string.slice1(this.outputFile, dot + 1 | 0)) {\n          case 'cpp':\n          case 'cxx':\n          case 'cc': {\n            this.target = new Skew.CPlusPlusTarget();\n            break;\n          }\n\n          case 'cs': {\n            this.target = new Skew.CSharpTarget();\n            break;\n          }\n\n          case 'ts': {\n            this.target = new Skew.TypeScriptTarget();\n            break;\n          }\n\n          case 'js': {\n            this.target = new Skew.JavaScriptTarget();\n            break;\n          }\n\n          default: {\n            return false;\n          }\n        }\n\n        return true;\n      }\n    }\n\n    return false;\n  };\n\n  Skew.Timer = function() {\n    this._isStarted = false;\n    this._startTime = 0;\n    this._totalSeconds = 0;\n  };\n\n  Skew.Timer.prototype.start = function() {\n    assert(!this._isStarted);\n    this._isStarted = true;\n    this._startTime = (typeof performance !== 'undefined' && performance.now ? performance.now() : Date.now()) / 1000;\n  };\n\n  Skew.Timer.prototype.stop = function() {\n    assert(this._isStarted);\n    this._isStarted = false;\n    this._totalSeconds += (typeof performance !== 'undefined' && performance.now ? performance.now() : Date.now()) / 1000 - this._startTime;\n  };\n\n  Skew.Timer.prototype.elapsedSeconds = function() {\n    return this._totalSeconds;\n  };\n\n  Skew.Timer.prototype.elapsedMilliseconds = function() {\n    return (Math.round(this._totalSeconds * 1000 * 10) / 10).toString() + 'ms';\n  };\n\n  Skew.PassContext = function(log, options, inputs) {\n    this.log = log;\n    this.options = options;\n    this.inputs = inputs;\n    this.cache = new Skew.TypeCache();\n    this.global = new Skew.ObjectSymbol(Skew.SymbolKind.OBJECT_GLOBAL, '<global>');\n    this.callGraph = null;\n    this.tokens = [];\n    this.outputs = [];\n    this.isResolvePassComplete = false;\n  };\n\n  Skew.PassContext.prototype.verify = function() {\n    this._verifyHierarchy1(this.global);\n  };\n\n  Skew.PassContext.prototype._verifySymbol = function(symbol) {\n    var ref;\n\n    if (!this.isResolvePassComplete) {\n      return;\n    }\n\n    // Special-case nested guards that aren't initialized when the outer guard has errors\n    if (symbol.state != Skew.SymbolState.INITIALIZED) {\n      assert(Skew.in_SymbolKind.isObject(symbol.kind));\n      assert(symbol.isGuardConditional());\n      assert(this.log.errorCount() > 0);\n      return;\n    }\n\n    assert(symbol.state == Skew.SymbolState.INITIALIZED);\n    assert(symbol.resolvedType != null);\n\n    if (Skew.in_SymbolKind.isObject(symbol.kind) || Skew.in_SymbolKind.isFunction(symbol.kind) || Skew.in_SymbolKind.isParameter(symbol.kind)) {\n      if (symbol.resolvedType == Skew.Type.DYNAMIC) {\n        // Ignore errors due to cyclic declarations\n        assert(this.log.errorCount() > 0);\n      }\n\n      else {\n        assert(symbol.resolvedType.kind == Skew.TypeKind.SYMBOL);\n        assert(symbol.resolvedType.symbol == symbol);\n      }\n    }\n\n    if (Skew.in_SymbolKind.isFunction(symbol.kind) && symbol.resolvedType.kind == Skew.TypeKind.SYMBOL) {\n      var $function = symbol.asFunctionSymbol();\n      assert(symbol.resolvedType.returnType == ((ref = $function.returnType) != null ? ref.resolvedType : null));\n      assert(symbol.resolvedType.argumentTypes.length == $function.$arguments.length);\n\n      for (var i = 0, count = $function.$arguments.length; i < count; i = i + 1 | 0) {\n        assert(in_List.get(symbol.resolvedType.argumentTypes, i) == in_List.get($function.$arguments, i).resolvedType);\n      }\n    }\n\n    if (Skew.in_SymbolKind.isVariable(symbol.kind)) {\n      assert(symbol.resolvedType == symbol.asVariableSymbol().type.resolvedType);\n    }\n  };\n\n  Skew.PassContext.prototype._verifyHierarchy1 = function(symbol) {\n    this._verifySymbol(symbol);\n\n    for (var i1 = 0, list1 = symbol.objects, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n      var object = in_List.get(list1, i1);\n      assert(object.parent == symbol);\n      this._verifyHierarchy1(object);\n\n      if (object.$extends != null) {\n        this._verifyHierarchy2(object.$extends, null);\n      }\n\n      if (object.$implements != null) {\n        for (var i = 0, list = object.$implements, count = list.length; i < count; i = i + 1 | 0) {\n          var node = in_List.get(list, i);\n          this._verifyHierarchy2(node, null);\n        }\n      }\n    }\n\n    for (var i2 = 0, list2 = symbol.functions, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n      var $function = in_List.get(list2, i2);\n      assert($function.parent == symbol);\n      this._verifySymbol($function);\n\n      if ($function.block != null) {\n        this._verifyHierarchy2($function.block, null);\n      }\n    }\n\n    for (var i3 = 0, list3 = symbol.variables, count3 = list3.length; i3 < count3; i3 = i3 + 1 | 0) {\n      var variable = in_List.get(list3, i3);\n      assert(variable.parent == symbol);\n      this._verifySymbol(variable);\n      assert(variable.state != Skew.SymbolState.INITIALIZED || variable.type != null);\n\n      if (variable.type != null) {\n        this._verifyHierarchy2(variable.type, null);\n      }\n\n      if (variable.value != null) {\n        this._verifyHierarchy2(variable.value, null);\n      }\n    }\n\n    if (symbol.guards != null) {\n      for (var i4 = 0, list4 = symbol.guards, count4 = list4.length; i4 < count4; i4 = i4 + 1 | 0) {\n        var guard = in_List.get(list4, i4);\n        this._verifyHierarchy3(guard, symbol);\n      }\n    }\n  };\n\n  Skew.PassContext.prototype._verifyHierarchy2 = function(node, parent) {\n    assert(node.parent() == parent);\n\n    // All expressions must have a type after the type resolution pass\n    if (this.isResolvePassComplete && Skew.in_NodeKind.isExpression(node.kind)) {\n      assert(node.resolvedType != null);\n    }\n\n    if (node.kind == Skew.NodeKind.VARIABLE) {\n      assert(node.symbol != null);\n      assert(node.symbol.kind == Skew.SymbolKind.VARIABLE_LOCAL);\n      var variable = node.symbol.asVariableSymbol();\n      assert(variable.value == node.variableValue());\n      this._verifySymbol(variable);\n      assert(variable.state != Skew.SymbolState.INITIALIZED || variable.type != null);\n\n      if (variable.type != null) {\n        this._verifyHierarchy2(variable.type, null);\n      }\n    }\n\n    else if (node.kind == Skew.NodeKind.LAMBDA) {\n      assert(node.symbol != null);\n      assert(node.symbol.kind == Skew.SymbolKind.FUNCTION_LOCAL);\n      assert(node.symbol.asFunctionSymbol().block == node.lambdaBlock());\n      this._verifySymbol(node.symbol);\n    }\n\n    for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n      this._verifyHierarchy2(child, node);\n    }\n  };\n\n  Skew.PassContext.prototype._verifyHierarchy3 = function(guard, parent) {\n    assert(guard.parent == parent);\n    assert(guard.contents.parent == parent);\n\n    if (guard.test != null) {\n      this._verifyHierarchy2(guard.test, null);\n    }\n\n    this._verifyHierarchy1(guard.contents);\n\n    if (guard.elseGuard != null) {\n      this._verifyHierarchy3(guard.elseGuard, parent);\n    }\n  };\n\n  Skew.Pass = function() {\n    this._shouldRun = null;\n  };\n\n  Skew.Pass.prototype.shouldRun = function() {\n    return this._shouldRun != null ? this._shouldRun() : true;\n  };\n\n  Skew.Pass.prototype.onlyRunWhen = function(callback) {\n    this._shouldRun = callback;\n    return this;\n  };\n\n  Skew.LambdaConversionPass = function() {\n    Skew.Pass.call(this);\n  };\n\n  __extends(Skew.LambdaConversionPass, Skew.Pass);\n\n  Skew.LambdaConversionPass.prototype.kind = function() {\n    return Skew.PassKind.LAMBDA_CONVERSION;\n  };\n\n  Skew.LambdaConversionPass.prototype.run = function(context) {\n    new Skew.LambdaConversion.Converter(context.global, context.cache).run();\n  };\n\n  Skew.ResolvingPass = function() {\n    Skew.Pass.call(this);\n  };\n\n  __extends(Skew.ResolvingPass, Skew.Pass);\n\n  Skew.ResolvingPass.prototype.kind = function() {\n    return Skew.PassKind.RESOLVING;\n  };\n\n  Skew.ResolvingPass.prototype.run = function(context) {\n    context.cache.loadGlobals(context.log, context.global);\n    new Skew.Resolving.Resolver(context.global, context.options, new Map(context.options.defines), context.cache, context.log).resolve();\n\n    // The tree isn't fully resolved for speed reasons if code completion is requested\n    if (context.options.completionContext == null) {\n      context.isResolvePassComplete = true;\n    }\n  };\n\n  Skew.ParsingPass = function() {\n    Skew.Pass.call(this);\n  };\n\n  __extends(Skew.ParsingPass, Skew.Pass);\n\n  Skew.ParsingPass.prototype.kind = function() {\n    return Skew.PassKind.PARSING;\n  };\n\n  Skew.ParsingPass.prototype.run = function(context) {\n    for (var i = 0, list = context.tokens, count = list.length; i < count; i = i + 1 | 0) {\n      var tokens = in_List.get(list, i);\n      Skew.Parsing.parseFile(context.log, tokens, context.global, context.options.warnAboutIgnoredComments);\n    }\n  };\n\n  Skew.EmittingPass = function() {\n    Skew.Pass.call(this);\n  };\n\n  __extends(Skew.EmittingPass, Skew.Pass);\n\n  Skew.EmittingPass.prototype.kind = function() {\n    return Skew.PassKind.EMITTING;\n  };\n\n  Skew.EmittingPass.prototype.run = function(context) {\n    var emitter = context.options.target.createEmitter(context);\n\n    if (emitter != null) {\n      emitter.visit(context.global);\n      context.outputs = emitter.sources();\n    }\n  };\n\n  Skew.LexingPass = function() {\n    Skew.Pass.call(this);\n  };\n\n  __extends(Skew.LexingPass, Skew.Pass);\n\n  Skew.LexingPass.prototype.kind = function() {\n    return Skew.PassKind.LEXING;\n  };\n\n  Skew.LexingPass.prototype.run = function(context) {\n    for (var i = 0, list = context.inputs, count = list.length; i < count; i = i + 1 | 0) {\n      var source = in_List.get(list, i);\n      context.tokens.push(Skew.tokenize(context.log, source));\n    }\n  };\n\n  Skew.PassTimer = function(kind) {\n    this.kind = kind;\n    this.timer = new Skew.Timer();\n  };\n\n  Skew.StatisticsKind = {\n    SHORT: 0,\n    LONG: 1\n  };\n\n  Skew.CompilerResult = function(cache, global, outputs, passTimers, totalTimer) {\n    this.cache = cache;\n    this.global = global;\n    this.outputs = outputs;\n    this.passTimers = passTimers;\n    this.totalTimer = totalTimer;\n  };\n\n  Skew.CompilerResult.prototype.statistics = function(inputs, kind) {\n    var builder = new StringBuilder();\n    var totalTime = this.totalTimer.elapsedSeconds();\n    var sourceStatistics = function(name, sources) {\n      var totalBytes = 0;\n      var totalLines = 0;\n\n      for (var i = 0, list = sources, count = list.length; i < count; i = i + 1 | 0) {\n        var source = in_List.get(list, i);\n        totalBytes = totalBytes + source.contents.length | 0;\n\n        if (kind == Skew.StatisticsKind.LONG) {\n          totalLines = totalLines + source.lineCount() | 0;\n        }\n      }\n\n      builder.buffer += name + (sources.length == 1 ? '' : 's') + ': ';\n      builder.buffer += sources.length == 1 ? in_List.first(sources).name : sources.length.toString() + ' files';\n      builder.buffer += ' (' + Skew.bytesToString(totalBytes);\n      builder.buffer += ', ' + Skew.bytesToString(Math.round(totalBytes / totalTime) | 0) + '/s';\n\n      if (kind == Skew.StatisticsKind.LONG) {\n        builder.buffer += ', ' + Skew.PrettyPrint.plural1(totalLines, 'line');\n        builder.buffer += ', ' + Skew.PrettyPrint.plural1(Math.round(totalLines / totalTime) | 0, 'line') + '/s';\n      }\n\n      builder.buffer += ')\\n';\n    };\n\n    // Sources\n    sourceStatistics('input', inputs);\n    sourceStatistics('output', this.outputs);\n\n    // Compilation time\n    builder.buffer += 'time: ' + this.totalTimer.elapsedMilliseconds();\n\n    if (kind == Skew.StatisticsKind.LONG) {\n      for (var i = 0, list = this.passTimers, count = list.length; i < count; i = i + 1 | 0) {\n        var passTimer = in_List.get(list, i);\n        builder.buffer += '\\n  ' + in_List.get(Skew.in_PassKind._strings, passTimer.kind) + ': ' + passTimer.timer.elapsedMilliseconds();\n      }\n    }\n\n    return builder.buffer;\n  };\n\n  Skew.CallGraphPass = function() {\n    Skew.Pass.call(this);\n  };\n\n  __extends(Skew.CallGraphPass, Skew.Pass);\n\n  Skew.CallGraphPass.prototype.kind = function() {\n    return Skew.PassKind.CALL_GRAPH;\n  };\n\n  Skew.CallGraphPass.prototype.run = function(context) {\n    context.callGraph = new Skew.CallGraph(context.global);\n  };\n\n  Skew.CallSite = function(callNode, enclosingSymbol) {\n    this.callNode = callNode;\n    this.enclosingSymbol = enclosingSymbol;\n  };\n\n  Skew.CallInfo = function(symbol) {\n    this.symbol = symbol;\n    this.callSites = [];\n  };\n\n  Skew.CallGraph = function(global) {\n    this.callInfo = [];\n    this.symbolToInfoIndex = new Map();\n    this._visitObject(global);\n  };\n\n  Skew.CallGraph.prototype.callInfoForSymbol = function(symbol) {\n    assert(this.symbolToInfoIndex.has(symbol.id));\n    return in_List.get(this.callInfo, in_IntMap.get1(this.symbolToInfoIndex, symbol.id));\n  };\n\n  Skew.CallGraph.prototype._visitObject = function(symbol) {\n    for (var i = 0, list = symbol.objects, count = list.length; i < count; i = i + 1 | 0) {\n      var object = in_List.get(list, i);\n      this._visitObject(object);\n    }\n\n    for (var i1 = 0, list1 = symbol.functions, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n      var $function = in_List.get(list1, i1);\n      this._recordCallSite($function, null, null);\n      this._visitNode($function.block, $function);\n    }\n\n    for (var i2 = 0, list2 = symbol.variables, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n      var variable = in_List.get(list2, i2);\n      this._visitNode(variable.value, variable);\n    }\n  };\n\n  Skew.CallGraph.prototype._visitNode = function(node, context) {\n    if (node != null) {\n      for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n        this._visitNode(child, context);\n      }\n\n      if (node.kind == Skew.NodeKind.CALL && node.symbol != null) {\n        assert(Skew.in_SymbolKind.isFunction(node.symbol.kind));\n        this._recordCallSite(node.symbol.forwarded().asFunctionSymbol(), node, context);\n      }\n    }\n  };\n\n  Skew.CallGraph.prototype._recordCallSite = function(symbol, node, context) {\n    var index = in_IntMap.get(this.symbolToInfoIndex, symbol.id, -1);\n    var info = index < 0 ? new Skew.CallInfo(symbol) : in_List.get(this.callInfo, index);\n\n    if (index < 0) {\n      in_IntMap.set(this.symbolToInfoIndex, symbol.id, this.callInfo.length);\n      this.callInfo.push(info);\n    }\n\n    if (node != null) {\n      info.callSites.push(new Skew.CallSite(node, context));\n    }\n  };\n\n  Skew.InliningPass = function() {\n    Skew.Pass.call(this);\n  };\n\n  __extends(Skew.InliningPass, Skew.Pass);\n\n  Skew.InliningPass.prototype.kind = function() {\n    return Skew.PassKind.INLINING;\n  };\n\n  Skew.InliningPass.prototype.run = function(context) {\n    var graph = new Skew.Inlining.InliningGraph(context.callGraph, context.log, context.options.inlineAllFunctions);\n\n    for (var i = 0, list = graph.inliningInfo, count = list.length; i < count; i = i + 1 | 0) {\n      var info = in_List.get(list, i);\n      Skew.Inlining.inlineSymbol(graph, info);\n    }\n  };\n\n  Skew.Inlining = {};\n\n  Skew.Inlining.inlineSymbol = function(graph, info) {\n    var ref;\n\n    if (!info.shouldInline) {\n      return;\n    }\n\n    // Inlining nested functions first is more efficient because it results in\n    // fewer inlining operations. This won't enter an infinite loop because\n    // inlining for all such functions has already been disabled.\n    for (var i1 = 0, list = info.bodyCalls, count = list.length; i1 < count; i1 = i1 + 1 | 0) {\n      var bodyCall = in_List.get(list, i1);\n      Skew.Inlining.inlineSymbol(graph, bodyCall);\n    }\n\n    var spreadingAnnotations = info.symbol.spreadingAnnotations();\n\n    for (var i = 0, count2 = info.callSites.length; i < count2; i = i + 1 | 0) {\n      var callSite = in_List.get(info.callSites, i);\n\n      // Some calls may be reused for other node types during constant folding\n      if (callSite == null || callSite.callNode.kind != Skew.NodeKind.CALL) {\n        continue;\n      }\n\n      // Make sure the call site hasn't been tampered with. An example of where\n      // this can happen is constant folding \"false ? 0 : foo.foo\" to \"foo.foo\".\n      // The children of \"foo.foo\" are stolen and parented under the hook\n      // expression as part of a become() call. Skipping inlining in this case\n      // just means we lose out on those inlining opportunities. This isn't the\n      // end of the world and is a pretty rare occurrence.\n      var node = callSite.callNode;\n\n      if (node.childCount() != (info.symbol.$arguments.length + 1 | 0)) {\n        continue;\n      }\n\n      // Propagate spreading annotations that must be preserved through inlining\n      if (spreadingAnnotations != null) {\n        var annotations = callSite.enclosingSymbol.annotations;\n\n        if (annotations == null) {\n          annotations = [];\n          callSite.enclosingSymbol.annotations = annotations;\n        }\n\n        for (var i2 = 0, list1 = spreadingAnnotations, count1 = list1.length; i2 < count1; i2 = i2 + 1 | 0) {\n          var annotation = in_List.get(list1, i2);\n          in_List.appendOne(annotations, annotation);\n        }\n      }\n\n      // Make sure each call site is inlined once by setting the call site to\n      // null. The call site isn't removed from the list since we don't want\n      // to mess up the indices of another call to inlineSymbol further up\n      // the call stack.\n      in_List.set(info.callSites, i, null);\n\n      // If there are unused arguments, drop those expressions entirely if\n      // they don't have side effects:\n      //\n      //   def bar(a int, b int) int {\n      //     return a\n      //   }\n      //\n      //   def test int {\n      //     return bar(0, foo(0)) + bar(1, 2)\n      //   }\n      //\n      // This should compile to:\n      //\n      //   def test int {\n      //     return bar(0, foo(0)) + 2\n      //   }\n      //\n      if (!(info.unusedArguments.length == 0)) {\n        var hasSideEffects = false;\n\n        for (var child = node.callValue().nextSibling(); child != null; child = child.nextSibling()) {\n          if (!child.hasNoSideEffects()) {\n            hasSideEffects = true;\n            break;\n          }\n        }\n\n        if (hasSideEffects) {\n          continue;\n        }\n      }\n\n      (ref = info.symbol).inlinedCount = ref.inlinedCount + 1 | 0;\n      var clone = info.inlineValue.clone();\n      var value = node.firstChild().remove();\n      var values = [];\n\n      while (node.hasChildren()) {\n        assert(node.firstChild().resolvedType != null);\n        values.push(node.firstChild().remove());\n      }\n\n      // Make sure not to update the type if the function dynamic because the\n      // expression inside the function may have a more specific type that is\n      // necessary during code generation\n      if (node.resolvedType != Skew.Type.DYNAMIC) {\n        clone.resolvedType = node.resolvedType;\n      }\n\n      assert((value.kind == Skew.NodeKind.PARAMETERIZE ? value.parameterizeValue() : value).kind == Skew.NodeKind.NAME && value.symbol == info.symbol);\n      assert(clone.resolvedType != null);\n      node.become(clone);\n      Skew.Inlining.recursivelySubstituteArguments(node, node, info.symbol.$arguments, values);\n\n      // Remove the inlined result entirely if appropriate\n      var parent = node.parent();\n\n      if (parent != null && parent.kind == Skew.NodeKind.EXPRESSION && node.hasNoSideEffects()) {\n        parent.remove();\n      }\n    }\n  };\n\n  Skew.Inlining.recursivelySubstituteArguments = function(root, node, $arguments, values) {\n    // Substitute the argument if this is an argument name\n    var symbol = node.symbol;\n\n    if (symbol != null && Skew.in_SymbolKind.isVariable(symbol.kind)) {\n      var index = $arguments.indexOf(symbol.asVariableSymbol());\n\n      if (index != -1) {\n        var parent = node.parent();\n\n        // If we're in a wrapped type cast, replace the cast itself\n        if (parent.kind == Skew.NodeKind.CAST) {\n          var valueType = parent.castValue().resolvedType;\n          var targetType = parent.castType().resolvedType;\n\n          if (valueType.isWrapped() && targetType.symbol != null && valueType.symbol.asObjectSymbol().wrappedType.symbol == targetType.symbol) {\n            node = parent;\n          }\n        }\n\n        if (node == root) {\n          node.become(in_List.get(values, index));\n        }\n\n        else {\n          node.replaceWith(in_List.get(values, index));\n        }\n\n        return;\n      }\n    }\n\n    // Otherwise, recursively search for substitutions in all child nodes\n    for (var child = node.firstChild(), next = null; child != null; child = next) {\n      next = child.nextSibling();\n      Skew.Inlining.recursivelySubstituteArguments(root, child, $arguments, values);\n    }\n  };\n\n  Skew.Inlining.InliningInfo = function(symbol, inlineValue, callSites, unusedArguments) {\n    this.symbol = symbol;\n    this.inlineValue = inlineValue;\n    this.callSites = callSites;\n    this.unusedArguments = unusedArguments;\n    this.shouldInline = true;\n    this.bodyCalls = [];\n  };\n\n  // Each node in the inlining graph is a symbol of an inlineable function and\n  // each directional edge is from a first function to a second function that is\n  // called directly within the body of the first function. Indirect function\n  // calls that may become direct calls through inlining can be discovered by\n  // traversing edges of this graph.\n  Skew.Inlining.InliningGraph = function(graph, log, inlineAllFunctions) {\n    this.inliningInfo = [];\n    this.symbolToInfoIndex = new Map();\n\n    // Create the nodes in the graph\n    for (var i = 0, list = graph.callInfo, count = list.length; i < count; i = i + 1 | 0) {\n      var callInfo = in_List.get(list, i);\n      var symbol = callInfo.symbol;\n\n      if (symbol.isInliningPrevented()) {\n        continue;\n      }\n\n      var info = Skew.Inlining.InliningGraph._createInliningInfo(callInfo);\n\n      if (info != null) {\n        if (inlineAllFunctions || symbol.isInliningForced()) {\n          in_IntMap.set(this.symbolToInfoIndex, symbol.id, this.inliningInfo.length);\n          this.inliningInfo.push(info);\n        }\n      }\n\n      else if (symbol.isInliningForced()) {\n        log.semanticWarningInliningFailed(symbol.range, symbol.name);\n      }\n    }\n\n    // Create the edges in the graph\n    for (var i2 = 0, list2 = this.inliningInfo, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n      var info1 = in_List.get(list2, i2);\n\n      for (var i1 = 0, list1 = graph.callInfoForSymbol(info1.symbol).callSites, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n        var callSite = in_List.get(list1, i1);\n\n        if (callSite.enclosingSymbol.kind == Skew.SymbolKind.FUNCTION_GLOBAL) {\n          var index = in_IntMap.get(this.symbolToInfoIndex, callSite.enclosingSymbol.id, -1);\n\n          if (index != -1) {\n            in_List.get(this.inliningInfo, index).bodyCalls.push(info1);\n          }\n        }\n      }\n    }\n\n    // Detect and disable infinitely expanding inline operations\n    for (var i3 = 0, list3 = this.inliningInfo, count3 = list3.length; i3 < count3; i3 = i3 + 1 | 0) {\n      var info2 = in_List.get(list3, i3);\n      info2.shouldInline = !Skew.Inlining.InliningGraph._containsInfiniteExpansion(info2, []);\n    }\n  };\n\n  Skew.Inlining.InliningGraph._containsInfiniteExpansion = function(info, symbols) {\n    // This shouldn't get very long in normal programs so O(n) here is fine\n    if (symbols.indexOf(info.symbol) != -1) {\n      return true;\n    }\n\n    // Do a depth-first search on the graph and check for cycles\n    symbols.push(info.symbol);\n\n    for (var i = 0, list = info.bodyCalls, count = list.length; i < count; i = i + 1 | 0) {\n      var bodyCall = in_List.get(list, i);\n\n      if (Skew.Inlining.InliningGraph._containsInfiniteExpansion(bodyCall, symbols)) {\n        return true;\n      }\n    }\n\n    in_List.removeLast(symbols);\n    return false;\n  };\n\n  Skew.Inlining.InliningGraph._createInliningInfo = function(info) {\n    var symbol = info.symbol;\n\n    // Inline functions consisting of a single return statement\n    if (symbol.kind == Skew.SymbolKind.FUNCTION_GLOBAL) {\n      var block = symbol.block;\n\n      if (block == null) {\n        return null;\n      }\n\n      // Replace functions with empty bodies with null\n      if (!block.hasChildren()) {\n        var unusedArguments = [];\n\n        for (var i = 0, count1 = symbol.$arguments.length; i < count1; i = i + 1 | 0) {\n          unusedArguments.push(i);\n        }\n\n        return new Skew.Inlining.InliningInfo(symbol, new Skew.Node(Skew.NodeKind.NULL).withType(Skew.Type.NULL), info.callSites, unusedArguments);\n      }\n\n      var first = block.firstChild();\n      var inlineValue = null;\n\n      // If the first value in the function is a return statement, then the\n      // function body doesn't need to only have one statement. Subsequent\n      // statements are just dead code and will never be executed anyway.\n      if (first.kind == Skew.NodeKind.RETURN) {\n        inlineValue = first.returnValue();\n      }\n\n      // Otherwise, this statement must be a lone expression statement\n      else if (first.kind == Skew.NodeKind.EXPRESSION && first.nextSibling() == null) {\n        inlineValue = first.expressionValue();\n      }\n\n      if (inlineValue != null) {\n        // Count the number of times each symbol is observed. Argument\n        // variables that are used more than once may need a let statement\n        // to avoid changing the semantics of the call site. For now, just\n        // only inline functions where each argument is used exactly once.\n        var argumentCounts = new Map();\n\n        for (var i2 = 0, list = symbol.$arguments, count2 = list.length; i2 < count2; i2 = i2 + 1 | 0) {\n          var argument = in_List.get(list, i2);\n          in_IntMap.set(argumentCounts, argument.id, 0);\n        }\n\n        if (Skew.Inlining.InliningGraph._recursivelyCountArgumentUses(inlineValue, argumentCounts)) {\n          var unusedArguments1 = [];\n          var isSimpleSubstitution = true;\n\n          for (var i1 = 0, count3 = symbol.$arguments.length; i1 < count3; i1 = i1 + 1 | 0) {\n            var count = in_IntMap.get1(argumentCounts, in_List.get(symbol.$arguments, i1).id);\n\n            if (count == 0) {\n              unusedArguments1.push(i1);\n            }\n\n            else if (count != 1) {\n              isSimpleSubstitution = false;\n              break;\n            }\n          }\n\n          if (isSimpleSubstitution) {\n            return new Skew.Inlining.InliningInfo(symbol, inlineValue, info.callSites, unusedArguments1);\n          }\n        }\n      }\n    }\n\n    return null;\n  };\n\n  // This returns false if inlining is impossible\n  Skew.Inlining.InliningGraph._recursivelyCountArgumentUses = function(node, argumentCounts) {\n    // Prevent inlining of lambda expressions. They have their own function\n    // symbols that reference the original block and won't work with cloning.\n    // Plus inlining lambdas leads to code bloat.\n    if (node.kind == Skew.NodeKind.LAMBDA) {\n      return false;\n    }\n\n    // Inlining is impossible at this node if it's impossible for any child node\n    for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n      if (!Skew.Inlining.InliningGraph._recursivelyCountArgumentUses(child, argumentCounts)) {\n        return false;\n      }\n    }\n\n    var symbol = node.symbol;\n\n    if (symbol != null) {\n      var count = in_IntMap.get(argumentCounts, symbol.id, -1);\n\n      if (count != -1) {\n        in_IntMap.set(argumentCounts, symbol.id, count + 1 | 0);\n\n        // Prevent inlining of functions that modify their arguments locally. For\n        // example, inlining this would lead to incorrect code:\n        //\n        //   def foo(x int, y int) {\n        //     x += y\n        //   }\n        //\n        //   def test {\n        //     foo(1, 2)\n        //   }\n        //\n        if (node.isAssignTarget()) {\n          return false;\n        }\n      }\n    }\n\n    return true;\n  };\n\n  Skew.TypeKind = {\n    LAMBDA: 0,\n    SPECIAL: 1,\n    SYMBOL: 2\n  };\n\n  Skew.Type = function(kind, symbol) {\n    this.id = Skew.Type._nextID = Skew.Type._nextID + 1 | 0;\n    this.kind = kind;\n    this.symbol = symbol;\n    this.environment = null;\n    this.substitutions = null;\n    this.argumentTypes = null;\n    this.returnType = null;\n    this.substitutionCache = null;\n  };\n\n  Skew.Type.prototype.parameters = function() {\n    return this.symbol == null ? null : Skew.in_SymbolKind.isObject(this.symbol.kind) ? this.symbol.asObjectSymbol().parameters : Skew.in_SymbolKind.isFunction(this.symbol.kind) ? this.symbol.asFunctionSymbol().parameters : null;\n  };\n\n  Skew.Type.prototype.isParameterized = function() {\n    return this.substitutions != null;\n  };\n\n  Skew.Type.prototype.isWrapped = function() {\n    return this.symbol != null && this.symbol.kind == Skew.SymbolKind.OBJECT_WRAPPED;\n  };\n\n  Skew.Type.prototype.isClass = function() {\n    return this.symbol != null && this.symbol.kind == Skew.SymbolKind.OBJECT_CLASS;\n  };\n\n  Skew.Type.prototype.isInterface = function() {\n    return this.symbol != null && this.symbol.kind == Skew.SymbolKind.OBJECT_INTERFACE;\n  };\n\n  Skew.Type.prototype.isEnumOrFlags = function() {\n    return this.symbol != null && Skew.in_SymbolKind.isEnumOrFlags(this.symbol.kind);\n  };\n\n  Skew.Type.prototype.isFlags = function() {\n    return this.symbol != null && this.symbol.kind == Skew.SymbolKind.OBJECT_FLAGS;\n  };\n\n  Skew.Type.prototype.isParameter = function() {\n    return this.symbol != null && Skew.in_SymbolKind.isParameter(this.symbol.kind);\n  };\n\n  // Type parameters are not guaranteed to be nullable since generics are\n  // implemented through type erasure and the substituted type may be \"int\"\n  Skew.Type.prototype.isReference = function() {\n    return this.symbol == null || !this.symbol.isValueType() && !Skew.in_SymbolKind.isParameter(this.symbol.kind) && (this.symbol.kind != Skew.SymbolKind.OBJECT_WRAPPED || this.symbol.asObjectSymbol().wrappedType.isReference());\n  };\n\n  Skew.Type.prototype.toString = function() {\n    if (this.kind == Skew.TypeKind.SYMBOL) {\n      if (this.isParameterized()) {\n        var name = this.symbol.fullName() + '<';\n\n        for (var i = 0, count = this.substitutions.length; i < count; i = i + 1 | 0) {\n          if (i != 0) {\n            name += ', ';\n          }\n\n          name += in_List.get(this.substitutions, i).toString();\n        }\n\n        return name + '>';\n      }\n\n      return this.symbol.fullName();\n    }\n\n    if (this.kind == Skew.TypeKind.LAMBDA) {\n      var result = 'fn(';\n\n      for (var i1 = 0, count1 = this.argumentTypes.length; i1 < count1; i1 = i1 + 1 | 0) {\n        if (i1 != 0) {\n          result += ', ';\n        }\n\n        result += in_List.get(this.argumentTypes, i1).toString();\n      }\n\n      return result + (this.returnType != null ? ') ' + this.returnType.toString() : ')');\n    }\n\n    return this == Skew.Type.DYNAMIC ? 'dynamic' : 'null';\n  };\n\n  Skew.Type.prototype.baseType = function() {\n    return this.isClass() ? this.symbol.asObjectSymbol().baseType : null;\n  };\n\n  Skew.Type.prototype.interfaceTypes = function() {\n    return this.isClass() ? this.symbol.asObjectSymbol().interfaceTypes : null;\n  };\n\n  Skew.Environment = function(parameters, substitutions) {\n    this.id = Skew.Environment._nextID = Skew.Environment._nextID + 1 | 0;\n    this.parameters = parameters;\n    this.substitutions = substitutions;\n    this.mergeCache = null;\n  };\n\n  Skew.TypeCache = function() {\n    this.boolType = null;\n    this.boxType = null;\n    this.doubleType = null;\n    this.intMapType = null;\n    this.intType = null;\n    this.listType = null;\n    this.mathType = null;\n    this.stringMapType = null;\n    this.stringType = null;\n    this.boolToStringSymbol = null;\n    this.doublePowerSymbol = null;\n    this.doubleToStringSymbol = null;\n    this.intPowerSymbol = null;\n    this.intToStringSymbol = null;\n    this.mathPowSymbol = null;\n    this.stringCountSymbol = null;\n    this.stringFromCodePointsSymbol = null;\n    this.stringFromCodePointSymbol = null;\n    this.stringFromCodeUnitsSymbol = null;\n    this.stringFromCodeUnitSymbol = null;\n    this.entryPointSymbol = null;\n    this._environments = new Map();\n    this._lambdaTypes = new Map();\n    this._parameters = [];\n  };\n\n  Skew.TypeCache.prototype.loadGlobals = function(log, global) {\n    this.boolType = Skew.TypeCache._loadGlobalObject(global, 'bool', Skew.SymbolKind.OBJECT_CLASS, Skew.SymbolFlags.IS_VALUE_TYPE);\n    this.boxType = Skew.TypeCache._loadGlobalObject(global, 'Box', Skew.SymbolKind.OBJECT_CLASS, 0);\n    this.doubleType = Skew.TypeCache._loadGlobalObject(global, 'double', Skew.SymbolKind.OBJECT_CLASS, Skew.SymbolFlags.IS_VALUE_TYPE);\n    this.intMapType = Skew.TypeCache._loadGlobalObject(global, 'IntMap', Skew.SymbolKind.OBJECT_CLASS, 0);\n    this.intType = Skew.TypeCache._loadGlobalObject(global, 'int', Skew.SymbolKind.OBJECT_CLASS, Skew.SymbolFlags.IS_VALUE_TYPE);\n    this.listType = Skew.TypeCache._loadGlobalObject(global, 'List', Skew.SymbolKind.OBJECT_CLASS, 0);\n    this.mathType = Skew.TypeCache._loadGlobalObject(global, 'Math', Skew.SymbolKind.OBJECT_NAMESPACE, 0);\n    this.stringMapType = Skew.TypeCache._loadGlobalObject(global, 'StringMap', Skew.SymbolKind.OBJECT_CLASS, 0);\n    this.stringType = Skew.TypeCache._loadGlobalObject(global, 'string', Skew.SymbolKind.OBJECT_CLASS, 0);\n    this.boolToStringSymbol = Skew.TypeCache._loadInstanceFunction(this.boolType, 'toString');\n    this.doublePowerSymbol = Skew.TypeCache._loadInstanceFunction(this.doubleType, '**');\n    this.doubleToStringSymbol = Skew.TypeCache._loadInstanceFunction(this.doubleType, 'toString');\n    this.intPowerSymbol = Skew.TypeCache._loadInstanceFunction(this.intType, '**');\n    this.intToStringSymbol = Skew.TypeCache._loadInstanceFunction(this.intType, 'toString');\n    this.mathPowSymbol = Skew.TypeCache._loadGlobalFunction(this.mathType, 'pow');\n    this.stringCountSymbol = Skew.TypeCache._loadInstanceFunction(this.stringType, 'count');\n    this.stringFromCodePointsSymbol = Skew.TypeCache._loadGlobalFunction(this.stringType, 'fromCodePoints');\n    this.stringFromCodePointSymbol = Skew.TypeCache._loadGlobalFunction(this.stringType, 'fromCodePoint');\n    this.stringFromCodeUnitsSymbol = Skew.TypeCache._loadGlobalFunction(this.stringType, 'fromCodeUnits');\n    this.stringFromCodeUnitSymbol = Skew.TypeCache._loadGlobalFunction(this.stringType, 'fromCodeUnit');\n  };\n\n  Skew.TypeCache.prototype.isEquivalentToBool = function(type) {\n    return this.unwrappedType(type) == this.boolType;\n  };\n\n  Skew.TypeCache.prototype.isEquivalentToInt = function(type) {\n    return this.isInteger(this.unwrappedType(type));\n  };\n\n  Skew.TypeCache.prototype.isEquivalentToDouble = function(type) {\n    return this.unwrappedType(type) == this.doubleType;\n  };\n\n  Skew.TypeCache.prototype.isEquivalentToString = function(type) {\n    return this.unwrappedType(type) == this.stringType;\n  };\n\n  Skew.TypeCache.prototype.isInteger = function(type) {\n    return type == this.intType || type.isEnumOrFlags();\n  };\n\n  Skew.TypeCache.prototype.isNumeric = function(type) {\n    return this.isInteger(type) || type == this.doubleType;\n  };\n\n  Skew.TypeCache.prototype.isList = function(type) {\n    return type.symbol == this.listType.symbol;\n  };\n\n  Skew.TypeCache.prototype.isIntMap = function(type) {\n    return type.symbol == this.intMapType.symbol;\n  };\n\n  Skew.TypeCache.prototype.isStringMap = function(type) {\n    return type.symbol == this.stringMapType.symbol;\n  };\n\n  Skew.TypeCache.prototype.isBaseType = function(derived, base) {\n    if (derived.isClass() && base.isClass()) {\n      while (true) {\n        var baseType = derived.baseType();\n\n        if (baseType == null) {\n          break;\n        }\n\n        derived = this.substitute(baseType, derived.environment);\n\n        if (derived == base) {\n          return true;\n        }\n      }\n    }\n\n    return false;\n  };\n\n  Skew.TypeCache.prototype.isImplementedInterface = function(classType, interfaceType) {\n    if (classType.isClass() && interfaceType.isInterface()) {\n      while (classType != null) {\n        var interfaceTypes = classType.interfaceTypes();\n\n        if (interfaceTypes != null) {\n          for (var i = 0, list = interfaceTypes, count = list.length; i < count; i = i + 1 | 0) {\n            var type = in_List.get(list, i);\n\n            if (this.substitute(type, classType.environment) == interfaceType) {\n              return true;\n            }\n          }\n        }\n\n        var baseType = classType.baseType();\n\n        if (baseType == null) {\n          break;\n        }\n\n        classType = this.substitute(baseType, classType.environment);\n      }\n    }\n\n    return false;\n  };\n\n  Skew.TypeCache.prototype.unwrappedType = function(type) {\n    if (type.isWrapped()) {\n      var inner = type.symbol.asObjectSymbol().wrappedType;\n\n      if (inner != null) {\n        return this.unwrappedType(this.substitute(inner, type.environment));\n      }\n    }\n\n    return type;\n  };\n\n  Skew.TypeCache.prototype.canImplicitlyConvert = function(from, to) {\n    if (from == to) {\n      return true;\n    }\n\n    if (from == Skew.Type.DYNAMIC || to == Skew.Type.DYNAMIC) {\n      return true;\n    }\n\n    if (from == Skew.Type.NULL && to.isReference()) {\n      return true;\n    }\n\n    if (from == this.intType && to == this.doubleType) {\n      return true;\n    }\n\n    if (this.isBaseType(from, to)) {\n      return true;\n    }\n\n    if (this.isImplementedInterface(from, to)) {\n      return true;\n    }\n\n    if (from.isEnumOrFlags() && !to.isEnumOrFlags() && this.isNumeric(to)) {\n      return true;\n    }\n\n    return false;\n  };\n\n  Skew.TypeCache.prototype.canExplicitlyConvert = function(from, to) {\n    from = this.unwrappedType(from);\n    to = this.unwrappedType(to);\n\n    if (this.canImplicitlyConvert(from, to)) {\n      return true;\n    }\n\n    if (this._canCastToNumeric(from) && this._canCastToNumeric(to)) {\n      return true;\n    }\n\n    if (this.isBaseType(to, from)) {\n      return true;\n    }\n\n    if (this.isImplementedInterface(to, from)) {\n      return true;\n    }\n\n    if (to.isEnumOrFlags() && this.isNumeric(from)) {\n      return true;\n    }\n\n    return false;\n  };\n\n  Skew.TypeCache.prototype.commonImplicitType = function(left, right) {\n    // Short-circuit early for identical types\n    if (left == right) {\n      return left;\n    }\n\n    // Dynamic is a hole in the type system\n    if (left == Skew.Type.DYNAMIC || right == Skew.Type.DYNAMIC) {\n      return Skew.Type.DYNAMIC;\n    }\n\n    // Check implicit conversions\n    if (this.canImplicitlyConvert(left, right)) {\n      return right;\n    }\n\n    if (this.canImplicitlyConvert(right, left)) {\n      return left;\n    }\n\n    // Implement common implicit types for numeric types\n    if (this.isNumeric(left) && this.isNumeric(right)) {\n      return this.isInteger(left) && this.isInteger(right) ? this.intType : this.doubleType;\n    }\n\n    // Check for a common base class\n    if (left.isClass() && right.isClass()) {\n      return Skew.TypeCache._commonBaseType(left, right);\n    }\n\n    return null;\n  };\n\n  Skew.TypeCache.prototype.createInt = function(value) {\n    return new Skew.Node(Skew.NodeKind.CONSTANT).withContent(new Skew.IntContent(value)).withType(this.intType);\n  };\n\n  Skew.TypeCache.prototype.createDouble = function(value) {\n    return new Skew.Node(Skew.NodeKind.CONSTANT).withContent(new Skew.DoubleContent(value)).withType(this.doubleType);\n  };\n\n  Skew.TypeCache.prototype.createListType = function(itemType) {\n    return this.substitute(this.listType, this.createEnvironment(this.listType.parameters(), [itemType]));\n  };\n\n  Skew.TypeCache.prototype.createIntMapType = function(valueType) {\n    return this.substitute(this.intMapType, this.createEnvironment(this.intMapType.parameters(), [valueType]));\n  };\n\n  Skew.TypeCache.prototype.createStringMapType = function(valueType) {\n    return this.substitute(this.stringMapType, this.createEnvironment(this.stringMapType.parameters(), [valueType]));\n  };\n\n  Skew.TypeCache.prototype.createEnvironment = function(parameters, substitutions) {\n    assert(parameters.length == substitutions.length);\n\n    // Hash the inputs\n    var hash = Skew.TypeCache._hashTypes(Skew.TypeCache._hashParameters(parameters), substitutions);\n    var bucket = in_IntMap.get(this._environments, hash, null);\n\n    // Check existing environments in the bucket for a match\n    if (bucket != null) {\n      for (var i = 0, list = bucket, count = list.length; i < count; i = i + 1 | 0) {\n        var existing = in_List.get(list, i);\n\n        if (in_List.equals(parameters, existing.parameters) && in_List.equals(substitutions, existing.substitutions)) {\n          return existing;\n        }\n      }\n    }\n\n    // Make a new bucket\n    else {\n      bucket = [];\n      in_IntMap.set(this._environments, hash, bucket);\n    }\n\n    // Make a new environment\n    var environment = new Skew.Environment(parameters, substitutions);\n    bucket.push(environment);\n    return environment;\n  };\n\n  Skew.TypeCache.prototype.createLambdaType = function(argumentTypes, returnType) {\n    // This is used as a sentinel on LAMBDA_TYPE nodes\n    assert(returnType != Skew.Type.NULL);\n    var hash = Skew.TypeCache._hashTypes(returnType != null ? returnType.id : -1, argumentTypes);\n    var bucket = in_IntMap.get(this._lambdaTypes, hash, null);\n\n    // Check existing types in the bucket for a match\n    if (bucket != null) {\n      for (var i = 0, list = bucket, count = list.length; i < count; i = i + 1 | 0) {\n        var existing = in_List.get(list, i);\n\n        if (in_List.equals(argumentTypes, existing.argumentTypes) && returnType == existing.returnType) {\n          return existing;\n        }\n      }\n    }\n\n    // Make a new bucket\n    else {\n      bucket = [];\n      in_IntMap.set(this._lambdaTypes, hash, bucket);\n    }\n\n    // Make a new lambda type\n    var type = new Skew.Type(Skew.TypeKind.LAMBDA, null);\n\n    // Make a copy in case the caller mutates this later\n    type.argumentTypes = argumentTypes.slice();\n    type.returnType = returnType;\n    bucket.push(type);\n    return type;\n  };\n\n  Skew.TypeCache.prototype.mergeEnvironments = function(a, b, restrictions) {\n    if (a == null) {\n      return b;\n    }\n\n    if (b == null) {\n      return a;\n    }\n\n    var parameters = a.parameters.slice();\n    var substitutions = this.substituteAll(a.substitutions, b);\n\n    for (var i = 0, count = b.parameters.length; i < count; i = i + 1 | 0) {\n      var parameter = in_List.get(b.parameters, i);\n      var substitution = in_List.get(b.substitutions, i);\n\n      if (!(parameters.indexOf(parameter) != -1) && (restrictions == null || restrictions.indexOf(parameter) != -1)) {\n        parameters.push(parameter);\n        substitutions.push(substitution);\n      }\n    }\n\n    return this.createEnvironment(parameters, substitutions);\n  };\n\n  Skew.TypeCache.prototype.parameterize = function(type) {\n    var parameters = type.parameters();\n\n    if (parameters == null) {\n      return type;\n    }\n\n    assert(!type.isParameterized());\n    var substitutions = [];\n\n    for (var i = 0, list = parameters, count = list.length; i < count; i = i + 1 | 0) {\n      var parameter = in_List.get(list, i);\n      substitutions.push(parameter.resolvedType);\n    }\n\n    return this.substitute(type, this.createEnvironment(parameters, substitutions));\n  };\n\n  Skew.TypeCache.prototype.substituteAll = function(types, environment) {\n    var substitutions = [];\n\n    for (var i = 0, list = types, count = list.length; i < count; i = i + 1 | 0) {\n      var type = in_List.get(list, i);\n      substitutions.push(this.substitute(type, environment));\n    }\n\n    return substitutions;\n  };\n\n  Skew.TypeCache.prototype.substitute = function(type, environment) {\n    var existing = type.environment;\n\n    if (environment == null || environment == existing) {\n      return type;\n    }\n\n    // Merge the type environments (this matters for nested generics). For\n    // object types, limit the parameters in the environment to just those\n    // on this type and the base type.\n    var parameters = type.parameters();\n\n    if (existing != null) {\n      environment = this.mergeEnvironments(existing, environment, type.kind == Skew.TypeKind.SYMBOL && Skew.in_SymbolKind.isFunctionOrOverloadedFunction(type.symbol.kind) ? null : parameters);\n    }\n\n    // Check to see if this has been computed before\n    var rootType = type.kind == Skew.TypeKind.SYMBOL ? type.symbol.resolvedType : type;\n\n    if (rootType.substitutionCache == null) {\n      rootType.substitutionCache = new Map();\n    }\n\n    var substituted = in_IntMap.get(rootType.substitutionCache, environment.id, null);\n\n    if (substituted != null) {\n      return substituted;\n    }\n\n    substituted = type;\n\n    if (type.kind == Skew.TypeKind.LAMBDA) {\n      var argumentTypes = [];\n      var returnType = null;\n\n      // Substitute function arguments\n      for (var i = 0, list = type.argumentTypes, count = list.length; i < count; i = i + 1 | 0) {\n        var argumentType = in_List.get(list, i);\n        argumentTypes.push(this.substitute(argumentType, environment));\n      }\n\n      // Substitute return type\n      if (type.returnType != null) {\n        returnType = this.substitute(type.returnType, environment);\n      }\n\n      substituted = this.createLambdaType(argumentTypes, returnType);\n    }\n\n    else if (type.kind == Skew.TypeKind.SYMBOL) {\n      var symbol = type.symbol;\n\n      // Parameters just need simple substitution\n      if (Skew.in_SymbolKind.isParameter(symbol.kind)) {\n        var index = environment.parameters.indexOf(symbol.asParameterSymbol());\n\n        if (index != -1) {\n          substituted = in_List.get(environment.substitutions, index);\n        }\n      }\n\n      // Symbols with type parameters are more complicated\n      // Overloaded functions are also included even though they don't have\n      // type parameters because the type environment needs to be bundled\n      // for later substitution into individual matched overloads\n      else if (parameters != null || Skew.in_SymbolKind.isFunctionOrOverloadedFunction(symbol.kind)) {\n        substituted = new Skew.Type(Skew.TypeKind.SYMBOL, symbol);\n        substituted.environment = environment;\n\n        // Generate type substitutions\n        if (parameters != null) {\n          var found = true;\n\n          for (var i1 = 0, list1 = parameters, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n            var parameter = in_List.get(list1, i1);\n            found = environment.parameters.indexOf(parameter) != -1;\n\n            if (!found) {\n              break;\n            }\n          }\n\n          if (found) {\n            substituted.substitutions = [];\n\n            for (var i2 = 0, list2 = parameters, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n              var parameter1 = in_List.get(list2, i2);\n              substituted.substitutions.push(this.substitute(parameter1.resolvedType, environment));\n            }\n          }\n        }\n\n        // Substitute function arguments\n        if (type.argumentTypes != null) {\n          substituted.argumentTypes = [];\n\n          for (var i3 = 0, list3 = type.argumentTypes, count3 = list3.length; i3 < count3; i3 = i3 + 1 | 0) {\n            var argumentType1 = in_List.get(list3, i3);\n            substituted.argumentTypes.push(this.substitute(argumentType1, environment));\n          }\n        }\n\n        // Substitute return type\n        if (type.returnType != null) {\n          substituted.returnType = this.substitute(type.returnType, environment);\n        }\n      }\n    }\n\n    in_IntMap.set(rootType.substitutionCache, environment.id, substituted);\n    return substituted;\n  };\n\n  // Substitute the type parameters from one function into the other\n  Skew.TypeCache.prototype.substituteFunctionParameters = function(type, from, to) {\n    if (from.parameters != null && to.parameters != null && from.parameters.length == to.parameters.length) {\n      var substitutions = [];\n\n      for (var i = 0, list = from.parameters, count = list.length; i < count; i = i + 1 | 0) {\n        var parameter = in_List.get(list, i);\n        substitutions.push(parameter.resolvedType);\n      }\n\n      type = this.substitute(type, this.createEnvironment(to.parameters, substitutions));\n    }\n\n    return type;\n  };\n\n  Skew.TypeCache.prototype.areFunctionSymbolsEquivalent = function(left, leftEnvironment, right, rightEnvironment) {\n    var leftType = left.resolvedType;\n    var rightType = right.resolvedType;\n    var leftReturn = leftType.returnType;\n    var rightReturn = rightType.returnType;\n\n    // Account for return types of functions from generic base types\n    if (leftReturn != null) {\n      leftReturn = this.substitute(leftReturn, leftEnvironment);\n    }\n\n    if (rightReturn != null) {\n      rightReturn = this.substitute(rightReturn, rightEnvironment);\n    }\n\n    // Overloading by return type is not allowed, so only compare argument types\n    if (this.substitute(left.argumentOnlyType, leftEnvironment) == this.substitute(right.argumentOnlyType, rightEnvironment)) {\n      return leftReturn == rightReturn ? Skew.TypeCache.Equivalence.EQUIVALENT : Skew.TypeCache.Equivalence.EQUIVALENT_EXCEPT_RETURN_TYPE;\n    }\n\n    // For generic functions, substitute dummy type parameters into both\n    // functions and then compare. For example, these are equivalent:\n    //\n    //   def foo<X>(bar X)\n    //   def foo<Y>(baz Y)\n    //\n    if (left.parameters != null && right.parameters != null) {\n      var leftArguments = leftType.argumentTypes;\n      var rightArguments = rightType.argumentTypes;\n      var argumentCount = leftArguments.length;\n      var parameterCount = left.parameters.length;\n\n      if (argumentCount == rightArguments.length && parameterCount == right.parameters.length) {\n        // Generate enough dummy type parameters\n        for (var i = this._parameters.length, count = parameterCount; i < count; i = i + 1 | 0) {\n          var symbol = new Skew.ParameterSymbol(Skew.SymbolKind.PARAMETER_FUNCTION, 'T' + i.toString());\n          symbol.resolvedType = new Skew.Type(Skew.TypeKind.SYMBOL, symbol);\n          symbol.state = Skew.SymbolState.INITIALIZED;\n          this._parameters.push(symbol.resolvedType);\n        }\n\n        // Substitute the same type parameters into both functions\n        var parameters = this._parameters.length == parameterCount ? this._parameters : in_List.slice2(this._parameters, 0, parameterCount);\n        var leftParametersEnvironment = this.createEnvironment(left.parameters, parameters);\n        var rightParametersEnvironment = this.createEnvironment(right.parameters, parameters);\n\n        // Compare each argument\n        for (var i1 = 0, count1 = argumentCount; i1 < count1; i1 = i1 + 1 | 0) {\n          if (this.substitute(this.substitute(in_List.get(leftArguments, i1), leftEnvironment), leftParametersEnvironment) != this.substitute(this.substitute(in_List.get(rightArguments, i1), rightEnvironment), rightParametersEnvironment)) {\n            return Skew.TypeCache.Equivalence.NOT_EQUIVALENT;\n          }\n        }\n\n        return leftReturn == null && rightReturn == null || leftReturn != null && rightReturn != null && this.substitute(leftReturn, leftParametersEnvironment) == this.substitute(rightReturn, rightParametersEnvironment) ? Skew.TypeCache.Equivalence.EQUIVALENT : Skew.TypeCache.Equivalence.EQUIVALENT_EXCEPT_RETURN_TYPE;\n      }\n    }\n\n    return Skew.TypeCache.Equivalence.NOT_EQUIVALENT;\n  };\n\n  Skew.TypeCache.prototype._canCastToNumeric = function(type) {\n    return type == this.intType || type == this.doubleType || type == this.boolType;\n  };\n\n  Skew.TypeCache._loadGlobalObject = function(global, name, kind, flags) {\n    assert(Skew.in_SymbolKind.isObject(kind));\n    var symbol = in_StringMap.get(global.members, name, null);\n    assert(symbol != null);\n    assert(symbol.kind == kind);\n    var type = new Skew.Type(Skew.TypeKind.SYMBOL, symbol.asObjectSymbol());\n    symbol.resolvedType = type;\n    symbol.flags |= flags;\n    return type;\n  };\n\n  Skew.TypeCache._loadInstanceFunction = function(type, name) {\n    var symbol = in_StringMap.get(type.symbol.asObjectSymbol().members, name, null);\n    assert(symbol != null);\n    assert(symbol.kind == Skew.SymbolKind.FUNCTION_INSTANCE || symbol.kind == Skew.SymbolKind.OVERLOADED_INSTANCE);\n    return symbol;\n  };\n\n  Skew.TypeCache._loadGlobalFunction = function(type, name) {\n    var symbol = in_StringMap.get(type.symbol.asObjectSymbol().members, name, null);\n    assert(symbol != null);\n    assert(symbol.kind == Skew.SymbolKind.FUNCTION_GLOBAL || symbol.kind == Skew.SymbolKind.OVERLOADED_GLOBAL);\n    return symbol;\n  };\n\n  Skew.TypeCache._hashParameters = function(parameters) {\n    var hash = 0;\n\n    for (var i = 0, list = parameters, count = list.length; i < count; i = i + 1 | 0) {\n      var parameter = in_List.get(list, i);\n      hash = Skew.hashCombine(hash, parameter.id);\n    }\n\n    return hash;\n  };\n\n  Skew.TypeCache._hashTypes = function(hash, types) {\n    for (var i = 0, list = types, count = list.length; i < count; i = i + 1 | 0) {\n      var type = in_List.get(list, i);\n      hash = Skew.hashCombine(hash, type.id);\n    }\n\n    return hash;\n  };\n\n  Skew.TypeCache._commonBaseType = function(left, right) {\n    var a = left;\n\n    while (a != null) {\n      var b = right;\n\n      while (b != null) {\n        if (a == b) {\n          return a;\n        }\n\n        b = b.baseType();\n      }\n\n      a = a.baseType();\n    }\n\n    return null;\n  };\n\n  Skew.TypeCache.Equivalence = {\n    EQUIVALENT: 0,\n    EQUIVALENT_EXCEPT_RETURN_TYPE: 1,\n    NOT_EQUIVALENT: 2\n  };\n\n  Skew.FoldingPass = function() {\n    Skew.Pass.call(this);\n  };\n\n  __extends(Skew.FoldingPass, Skew.Pass);\n\n  Skew.FoldingPass.prototype.kind = function() {\n    return Skew.PassKind.FOLDING;\n  };\n\n  Skew.FoldingPass.prototype.run = function(context) {\n    new Skew.Folding.ConstantFolder(context.cache, context.options, null).visitObject(context.global);\n  };\n\n  Skew.Folding = {};\n\n  Skew.Folding.ConstantFolder = function(_cache, _options, _prepareSymbol) {\n    this._cache = _cache;\n    this._options = _options;\n    this._prepareSymbol = _prepareSymbol;\n    this._constantCache = new Map();\n  };\n\n  Skew.Folding.ConstantFolder.prototype.visitObject = function(symbol) {\n    for (var i = 0, list = symbol.objects, count = list.length; i < count; i = i + 1 | 0) {\n      var object = in_List.get(list, i);\n      this.visitObject(object);\n    }\n\n    for (var i1 = 0, list1 = symbol.functions, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n      var $function = in_List.get(list1, i1);\n\n      if ($function.block != null) {\n        this.foldConstants($function.block);\n      }\n    }\n\n    for (var i2 = 0, list2 = symbol.variables, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n      var variable = in_List.get(list2, i2);\n\n      if (variable.value != null) {\n        this.foldConstants(variable.value);\n      }\n    }\n  };\n\n  // Use this instead of node.become(Node.createConstant(content)) to avoid more GC\n  Skew.Folding.ConstantFolder.prototype._flatten = function(node, content) {\n    node.removeChildren();\n    node.kind = Skew.NodeKind.CONSTANT;\n    node.content = content;\n    node.symbol = null;\n  };\n\n  // Use this instead of node.become(Node.createBool(value)) to avoid more GC\n  Skew.Folding.ConstantFolder.prototype._flattenBool = function(node, value) {\n    assert(this._cache.isEquivalentToBool(node.resolvedType) || node.resolvedType == Skew.Type.DYNAMIC);\n    this._flatten(node, new Skew.BoolContent(value));\n  };\n\n  // Use this instead of node.become(Node.createInt(value)) to avoid more GC\n  Skew.Folding.ConstantFolder.prototype._flattenInt = function(node, value) {\n    assert(this._cache.isEquivalentToInt(node.resolvedType) || node.resolvedType == Skew.Type.DYNAMIC);\n    this._flatten(node, new Skew.IntContent(value));\n  };\n\n  // Use this instead of node.become(Node.createDouble(value)) to avoid more GC\n  Skew.Folding.ConstantFolder.prototype._flattenDouble = function(node, value) {\n    assert(this._cache.isEquivalentToDouble(node.resolvedType) || node.resolvedType == Skew.Type.DYNAMIC);\n    this._flatten(node, new Skew.DoubleContent(value));\n  };\n\n  // Use this instead of node.become(Node.createString(value)) to avoid more GC\n  Skew.Folding.ConstantFolder.prototype._flattenString = function(node, value) {\n    assert(this._cache.isEquivalentToString(node.resolvedType) || node.resolvedType == Skew.Type.DYNAMIC);\n    this._flatten(node, new Skew.StringContent(value));\n  };\n\n  Skew.Folding.ConstantFolder.prototype.foldConstants = function(node) {\n    var kind = node.kind;\n\n    // Transform \"a + (b + c)\" => \"(a + b) + c\" before operands are folded\n    if (kind == Skew.NodeKind.ADD && node.resolvedType == this._cache.stringType && node.binaryLeft().resolvedType == this._cache.stringType && node.binaryRight().resolvedType == this._cache.stringType) {\n      this._rotateStringConcatenation(node);\n    }\n\n    // Fold operands before folding this node\n    for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n      this.foldConstants(child);\n    }\n\n    // Separating the case bodies into separate functions makes the JavaScript JIT go faster\n    switch (kind) {\n      case Skew.NodeKind.BLOCK: {\n        this._foldBlock(node);\n        break;\n      }\n\n      case Skew.NodeKind.CALL: {\n        this._foldCall(node);\n        break;\n      }\n\n      case Skew.NodeKind.CAST: {\n        this._foldCast(node);\n        break;\n      }\n\n      case Skew.NodeKind.DOT: {\n        this._foldDot(node);\n        break;\n      }\n\n      case Skew.NodeKind.HOOK: {\n        this._foldHook(node);\n        break;\n      }\n\n      case Skew.NodeKind.NAME: {\n        this._foldName(node);\n        break;\n      }\n\n      case Skew.NodeKind.COMPLEMENT:\n      case Skew.NodeKind.NEGATIVE:\n      case Skew.NodeKind.NOT:\n      case Skew.NodeKind.POSITIVE: {\n        this._foldUnary(node);\n        break;\n      }\n\n      default: {\n        if (Skew.in_NodeKind.isBinary(kind)) {\n          this._foldBinary(node);\n        }\n        break;\n      }\n    }\n  };\n\n  Skew.Folding.ConstantFolder.prototype._rotateStringConcatenation = function(node) {\n    var left = node.binaryLeft();\n    var right = node.binaryRight();\n    assert(node.kind == Skew.NodeKind.ADD);\n    assert(left.resolvedType == this._cache.stringType || left.resolvedType == Skew.Type.DYNAMIC);\n    assert(right.resolvedType == this._cache.stringType || right.resolvedType == Skew.Type.DYNAMIC);\n\n    // \"a + (b + c)\" => \"(a + b) + c\"\n    if (right.kind == Skew.NodeKind.ADD) {\n      assert(right.binaryLeft().resolvedType == this._cache.stringType || right.binaryLeft().resolvedType == Skew.Type.DYNAMIC);\n      assert(right.binaryRight().resolvedType == this._cache.stringType || right.binaryRight().resolvedType == Skew.Type.DYNAMIC);\n      node.rotateBinaryRightToLeft();\n    }\n  };\n\n  Skew.Folding.ConstantFolder.prototype._foldStringConcatenation = function(node) {\n    var left = node.binaryLeft();\n    var right = node.binaryRight();\n    assert(left.resolvedType == this._cache.stringType || left.resolvedType == Skew.Type.DYNAMIC);\n    assert(right.resolvedType == this._cache.stringType || right.resolvedType == Skew.Type.DYNAMIC);\n\n    if (right.isString()) {\n      // \"a\" + \"b\" => \"ab\"\n      if (left.isString()) {\n        this._flattenString(node, left.asString() + right.asString());\n      }\n\n      else if (left.kind == Skew.NodeKind.ADD) {\n        var leftLeft = left.binaryLeft();\n        var leftRight = left.binaryRight();\n        assert(leftLeft.resolvedType == this._cache.stringType || leftLeft.resolvedType == Skew.Type.DYNAMIC);\n        assert(leftRight.resolvedType == this._cache.stringType || leftRight.resolvedType == Skew.Type.DYNAMIC);\n\n        // (a + \"b\") + \"c\" => a + \"bc\"\n        if (leftRight.isString()) {\n          this._flattenString(leftRight, leftRight.asString() + right.asString());\n          node.become(left.remove());\n        }\n      }\n    }\n  };\n\n  Skew.Folding.ConstantFolder.prototype._foldTry = function(node) {\n    var tryBlock = node.tryBlock();\n\n    // var finallyBlock = node.finallyBlock\n\n    // A try block without any statements cannot possibly throw\n    if (!tryBlock.hasChildren()) {\n      node.remove();\n      return -1;\n    }\n\n    return 0;\n  };\n\n  Skew.Folding.ConstantFolder.prototype._foldIf = function(node) {\n    var test = node.ifTest();\n    var trueBlock = node.ifTrue();\n    var falseBlock = node.ifFalse();\n\n    // No reason to keep an empty \"else\" block\n    if (falseBlock != null && !falseBlock.hasChildren()) {\n      falseBlock.remove();\n      falseBlock = null;\n    }\n\n    // Always true if statement\n    if (test.isTrue()) {\n      // Inline the contents of the true block\n      node.replaceWithChildrenFrom(trueBlock);\n    }\n\n    // Always false if statement\n    else if (test.isFalse()) {\n      // Remove entirely\n      if (falseBlock == null) {\n        node.remove();\n      }\n\n      // Inline the contents of the false block\n      else {\n        node.replaceWithChildrenFrom(falseBlock);\n      }\n    }\n\n    // Remove if statements with empty true blocks\n    else if (!trueBlock.hasChildren()) {\n      // \"if (a) {} else b;\" => \"if (!a) b;\"\n      if (falseBlock != null && falseBlock.hasChildren()) {\n        test.invertBooleanCondition(this._cache);\n        trueBlock.remove();\n      }\n\n      // \"if (a) {}\" => \"\"\n      else if (test.hasNoSideEffects()) {\n        node.remove();\n      }\n\n      // \"if (a) {}\" => \"a;\"\n      else {\n        node.become(Skew.Node.createExpression(test.remove()));\n      }\n    }\n  };\n\n  Skew.Folding.ConstantFolder.prototype._foldSwitch = function(node) {\n    var value = node.switchValue();\n    var defaultCase = null;\n\n    // Check for a default case\n    for (var child = value.nextSibling(); child != null; child = child.nextSibling()) {\n      if (child.hasOneChild()) {\n        defaultCase = child;\n        break;\n      }\n    }\n\n    // Remove the default case if it's empty\n    if (defaultCase != null && !defaultCase.caseBlock().hasChildren()) {\n      defaultCase.remove();\n      defaultCase = null;\n    }\n\n    // Check for a constant value and inline the corresponding case block\n    if (value.kind == Skew.NodeKind.CONSTANT) {\n      var hasNonConstant = false;\n\n      // Search all case blocks for a match\n      for (var child1 = value.nextSibling(), nextChild = null; child1 != null; child1 = nextChild) {\n        nextChild = child1.nextSibling();\n        var block = child1.caseBlock();\n\n        for (var caseValue = child1.firstChild(), nextCase = null; caseValue != block; caseValue = nextCase) {\n          nextCase = caseValue.nextSibling();\n\n          // If there's a non-constant value, we can't tell if it's taken or not\n          if (caseValue.kind != Skew.NodeKind.CONSTANT) {\n            hasNonConstant = true;\n          }\n\n          // Remove cases that definitely don't apply\n          else if (!Skew.in_Content.equals(value.content, caseValue.content)) {\n            caseValue.remove();\n          }\n\n          // Only inline this case if all previous values have been constants,\n          // otherwise we can't be sure that none of those would have matched\n          else if (!hasNonConstant) {\n            node.replaceWithChildrenFrom(block);\n            return;\n          }\n        }\n\n        // Remove the case entirely if all values were trimmed\n        if (child1.hasOneChild() && child1 != defaultCase) {\n          child1.remove();\n        }\n      }\n\n      // Inline the default case if it's present and it can be proven to be taken\n      if (!hasNonConstant) {\n        if (defaultCase != null) {\n          node.replaceWithChildrenFrom(defaultCase.caseBlock());\n        }\n\n        else {\n          node.remove();\n        }\n\n        return;\n      }\n    }\n\n    // If the default case is missing, all other empty cases can be removed too\n    if (defaultCase == null) {\n      for (var child2 = node.lastChild(), previous = null; child2 != value; child2 = previous) {\n        previous = child2.previousSibling();\n\n        if (!child2.caseBlock().hasChildren()) {\n          child2.remove();\n        }\n      }\n    }\n\n    // Replace \"switch (foo) {}\" with \"foo;\"\n    if (node.hasOneChild()) {\n      node.become(Skew.Node.createExpression(value.remove()).withRange(node.range));\n    }\n  };\n\n  Skew.Folding.ConstantFolder.prototype._foldVariables = function(node) {\n    // Remove symbols entirely that are being inlined everywhere\n    for (var child = node.firstChild(), next = null; child != null; child = next) {\n      assert(child.kind == Skew.NodeKind.VARIABLE);\n      next = child.nextSibling();\n      var symbol = child.symbol.asVariableSymbol();\n\n      if (symbol.isConst() && this.constantForSymbol(symbol) != null) {\n        child.remove();\n      }\n    }\n\n    // Empty variable statements are not allowed\n    if (!node.hasChildren()) {\n      node.remove();\n    }\n  };\n\n  Skew.Folding.ConstantFolder.prototype._foldBlock = function(node) {\n    for (var child = node.firstChild(), next = null; child != null; child = next) {\n      next = child.nextSibling();\n      var kind = child.kind;\n\n      // Remove everything after a jump\n      if (Skew.in_NodeKind.isJump(kind)) {\n        while (child.nextSibling() != null) {\n          child.nextSibling().remove();\n        }\n\n        break;\n      }\n\n      // Remove constants and \"while false { ... }\" entirely\n      if (kind == Skew.NodeKind.EXPRESSION && child.expressionValue().hasNoSideEffects() || kind == Skew.NodeKind.WHILE && child.whileTest().isFalse()) {\n        child.remove();\n      }\n\n      // Remove dead assignments\n      else if (kind == Skew.NodeKind.EXPRESSION && child.expressionValue().kind == Skew.NodeKind.ASSIGN) {\n        this._foldAssignment(child);\n      }\n\n      else if (kind == Skew.NodeKind.VARIABLES) {\n        this._foldVariables(child);\n      }\n\n      // Remove unused try statements since they can cause deoptimizations\n      else if (kind == Skew.NodeKind.TRY) {\n        this._foldTry(child);\n      }\n\n      // Statically evaluate if statements where possible\n      else if (kind == Skew.NodeKind.IF) {\n        this._foldIf(child);\n      }\n\n      // Fold switch statements\n      else if (kind == Skew.NodeKind.SWITCH) {\n        this._foldSwitch(child);\n      }\n    }\n  };\n\n  // \"a = 0; b = 0; a = 1;\" => \"b = 0; a = 1;\"\n  Skew.Folding.ConstantFolder.prototype._foldAssignment = function(node) {\n    assert(node.kind == Skew.NodeKind.EXPRESSION && node.expressionValue().kind == Skew.NodeKind.ASSIGN);\n    var value = node.expressionValue();\n    var left = value.binaryLeft();\n    var right = value.binaryRight();\n\n    // Only do this for simple variable assignments\n    var dotVariable = left.kind == Skew.NodeKind.DOT && Skew.Folding.ConstantFolder._isVariableReference(left.dotTarget()) ? left.dotTarget().symbol : null;\n    var variable = Skew.Folding.ConstantFolder._isVariableReference(left) || dotVariable != null ? left.symbol : null;\n\n    if (variable == null) {\n      return;\n    }\n\n    // Make sure the assigned value doesn't need the previous value. We bail\n    // on expressions with side effects like function calls and on expressions\n    // that reference the variable.\n    if (!right.hasNoSideEffects() || Skew.Folding.ConstantFolder._hasNestedReference(right, variable)) {\n      return;\n    }\n\n    // Scan backward over previous statements\n    var previous = node.previousSibling();\n\n    while (previous != null) {\n      // Only pattern-match expressions\n      if (previous.kind == Skew.NodeKind.EXPRESSION) {\n        var previousValue = previous.expressionValue();\n\n        // Remove duplicate assignments\n        if (previousValue.kind == Skew.NodeKind.ASSIGN) {\n          var previousLeft = previousValue.binaryLeft();\n          var previousRight = previousValue.binaryRight();\n          var previousDotVariable = previousLeft.kind == Skew.NodeKind.DOT && Skew.Folding.ConstantFolder._isVariableReference(previousLeft.dotTarget()) ? previousLeft.dotTarget().symbol : null;\n          var previousVariable = Skew.Folding.ConstantFolder._isVariableReference(previousLeft) || previousDotVariable != null && previousDotVariable == dotVariable ? previousLeft.symbol : null;\n\n          // Check for assignment to the same variable and remove the assignment\n          // if it's a match. Make sure to keep the assigned value around if it\n          // has side effects.\n          if (previousVariable == variable) {\n            if (previousRight.hasNoSideEffects()) {\n              previous.remove();\n            }\n\n            else {\n              previousValue.replaceWith(previousRight.remove());\n            }\n\n            break;\n          }\n\n          // Stop if we can't determine that this statement doesn't involve\n          // this variable's value. If it does involve this variable's value,\n          // then it isn't safe to remove duplicate assignments past this\n          // statement.\n          if (!previousRight.hasNoSideEffects() || Skew.Folding.ConstantFolder._hasNestedReference(previousRight, variable)) {\n            break;\n          }\n        }\n\n        // Also stop here if we can't determine that this statement doesn't\n        // involve this variable's value\n        else if (!previousValue.hasNoSideEffects()) {\n          break;\n        }\n      }\n\n      // Also stop here if we can't determine that this statement doesn't\n      // involve this variable's value\n      else {\n        break;\n      }\n\n      previous = previous.previousSibling();\n    }\n  };\n\n  Skew.Folding.ConstantFolder.prototype._foldDot = function(node) {\n    var symbol = node.symbol;\n\n    // Only replace this with a constant if the target has no side effects.\n    // This catches constants declared on imported types.\n    if (Skew.Folding.ConstantFolder._shouldFoldSymbol(symbol) && !node.isAssignTarget() && (node.dotTarget() == null || node.dotTarget().hasNoSideEffects())) {\n      var content = this.constantForSymbol(symbol.asVariableSymbol());\n\n      if (content != null) {\n        this._flatten(node, content);\n      }\n    }\n  };\n\n  Skew.Folding.ConstantFolder.prototype._foldName = function(node) {\n    var symbol = node.symbol;\n\n    // Don't fold loop variables since they aren't actually constant across loop iterations\n    if (Skew.Folding.ConstantFolder._shouldFoldSymbol(symbol) && !node.isAssignTarget() && !symbol.isLoopVariable()) {\n      var content = this.constantForSymbol(symbol.asVariableSymbol());\n\n      if (content != null) {\n        this._flatten(node, content);\n      }\n    }\n  };\n\n  Skew.Folding.ConstantFolder.prototype._foldCall = function(node) {\n    var value = node.callValue();\n    var symbol = value.symbol;\n\n    // Fold instance function calls\n    if (value.kind == Skew.NodeKind.DOT) {\n      var target = value.dotTarget();\n\n      // Folding of double.toString can't be done in a platform-independent\n      // manner. The obvious cases are NaN and infinity, but even fractions\n      // are emitted differently on different platforms. Instead of having\n      // constant folding change how the code behaves, just don't fold double\n      // toString calls.\n      //\n      // \"bool.toString\"\n      // \"int.toString\"\n      //\n      if (target != null && target.kind == Skew.NodeKind.CONSTANT) {\n        if (Skew.Folding.ConstantFolder._isKnownCall(symbol, this._cache.boolToStringSymbol)) {\n          this._flattenString(node, target.asBool().toString());\n        }\n\n        else if (Skew.Folding.ConstantFolder._isKnownCall(symbol, this._cache.intToStringSymbol)) {\n          this._flattenString(node, target.asInt().toString());\n        }\n      }\n    }\n\n    // Fold global function calls\n    else if (value.kind == Skew.NodeKind.NAME) {\n      // \"\\\"abc\\\".count\" => \"3\"\n      if (Skew.Folding.ConstantFolder._isKnownCall(symbol, this._cache.stringCountSymbol) && node.lastChild().isString()) {\n        this._flattenInt(node, Unicode.codeUnitCountForCodePoints(in_string.codePoints(node.lastChild().asString()), this._options.target.stringEncoding()));\n      }\n\n      // \"3 ** 2\" => \"9\"\n      else if (Skew.Folding.ConstantFolder._isKnownCall(symbol, this._cache.intPowerSymbol) && node.lastChild().isInt() && value.nextSibling().isInt()) {\n        this._flattenInt(node, in_int.power(value.nextSibling().asInt(), node.lastChild().asInt()));\n      }\n\n      // \"0.0625 ** 0.25\" => \"0.5\"\n      // \"Math.pow(0.0625, 0.25)\" => \"0.5\"\n      else if ((Skew.Folding.ConstantFolder._isKnownCall(symbol, this._cache.doublePowerSymbol) || Skew.Folding.ConstantFolder._isKnownCall(symbol, this._cache.mathPowSymbol)) && node.lastChild().isDouble() && value.nextSibling().isDouble()) {\n        this._flattenDouble(node, Math.pow(value.nextSibling().asDouble(), node.lastChild().asDouble()));\n      }\n\n      // \"string.fromCodePoint(100)\" => \"\\\"d\\\"\"\n      // \"string.fromCodeUnit(100)\" => \"\\\"d\\\"\"\n      else if ((Skew.Folding.ConstantFolder._isKnownCall(symbol, this._cache.stringFromCodePointSymbol) || Skew.Folding.ConstantFolder._isKnownCall(symbol, this._cache.stringFromCodeUnitSymbol)) && node.lastChild().isInt()) {\n        // \"fromCodePoint\" is a superset of \"fromCodeUnit\"\n        this._flattenString(node, in_string.fromCodePoint(node.lastChild().asInt()));\n      }\n\n      // \"string.fromCodePoints([97, 98, 99])\" => \"\\\"abc\\\"\"\n      // \"string.fromCodeUnits([97, 98, 99])\" => \"\\\"abc\\\"\"\n      else if ((Skew.Folding.ConstantFolder._isKnownCall(symbol, this._cache.stringFromCodePointsSymbol) || Skew.Folding.ConstantFolder._isKnownCall(symbol, this._cache.stringFromCodeUnitsSymbol)) && node.lastChild().kind == Skew.NodeKind.INITIALIZER_LIST) {\n        var codePoints = [];\n\n        for (var child = node.lastChild().firstChild(); child != null; child = child.nextSibling()) {\n          if (!child.isInt()) {\n            return;\n          }\n\n          codePoints.push(child.asInt());\n        }\n\n        // \"fromCodePoints\" is a superset of \"fromCodeUnits\"\n        this._flattenString(node, in_string.fromCodePoints(codePoints));\n      }\n    }\n  };\n\n  Skew.Folding.ConstantFolder.prototype._foldCast = function(node) {\n    var type = node.castType().resolvedType;\n    var value = node.castValue();\n\n    if (value.kind == Skew.NodeKind.CONSTANT) {\n      var content = value.content;\n      var kind = content.kind();\n\n      // Cast \"bool\" values\n      if (kind == Skew.ContentKind.BOOL) {\n        if (this._cache.isEquivalentToBool(type)) {\n          this._flattenBool(node, value.asBool());\n        }\n\n        else if (this._cache.isEquivalentToInt(type)) {\n          this._flattenInt(node, value.asBool() | 0);\n        }\n\n        else if (this._cache.isEquivalentToDouble(type)) {\n          this._flattenDouble(node, +value.asBool());\n        }\n      }\n\n      // Cast \"int\" values\n      else if (kind == Skew.ContentKind.INT) {\n        if (this._cache.isEquivalentToBool(type)) {\n          this._flattenBool(node, !!value.asInt());\n        }\n\n        else if (this._cache.isEquivalentToInt(type)) {\n          this._flattenInt(node, value.asInt());\n        }\n\n        else if (this._cache.isEquivalentToDouble(type)) {\n          this._flattenDouble(node, value.asInt());\n        }\n      }\n\n      // Cast \"double\" values\n      else if (kind == Skew.ContentKind.DOUBLE) {\n        if (this._cache.isEquivalentToBool(type)) {\n          this._flattenBool(node, !!value.asDouble());\n        }\n\n        else if (this._cache.isEquivalentToInt(type)) {\n          this._flattenInt(node, value.asDouble() | 0);\n        }\n\n        else if (this._cache.isEquivalentToDouble(type)) {\n          this._flattenDouble(node, value.asDouble());\n        }\n      }\n    }\n  };\n\n  Skew.Folding.ConstantFolder.prototype._foldUnary = function(node) {\n    var value = node.unaryValue();\n    var kind = node.kind;\n\n    if (value.kind == Skew.NodeKind.CONSTANT) {\n      var content = value.content;\n      var contentKind = content.kind();\n\n      // Fold \"bool\" values\n      if (contentKind == Skew.ContentKind.BOOL) {\n        if (kind == Skew.NodeKind.NOT) {\n          this._flattenBool(node, !value.asBool());\n        }\n      }\n\n      // Fold \"int\" values\n      else if (contentKind == Skew.ContentKind.INT) {\n        if (kind == Skew.NodeKind.POSITIVE) {\n          this._flattenInt(node, +value.asInt());\n        }\n\n        else if (kind == Skew.NodeKind.NEGATIVE) {\n          this._flattenInt(node, -value.asInt() | 0);\n        }\n\n        else if (kind == Skew.NodeKind.COMPLEMENT) {\n          this._flattenInt(node, ~value.asInt());\n        }\n      }\n\n      // Fold \"float\" or \"double\" values\n      else if (contentKind == Skew.ContentKind.DOUBLE) {\n        if (kind == Skew.NodeKind.POSITIVE) {\n          this._flattenDouble(node, +value.asDouble());\n        }\n\n        else if (kind == Skew.NodeKind.NEGATIVE) {\n          this._flattenDouble(node, -value.asDouble());\n        }\n      }\n    }\n\n    // Partial evaluation (\"!!x\" isn't necessarily \"x\" if we don't know the type)\n    else if (kind == Skew.NodeKind.NOT && value.resolvedType != Skew.Type.DYNAMIC) {\n      switch (value.kind) {\n        case Skew.NodeKind.NOT:\n        case Skew.NodeKind.EQUAL:\n        case Skew.NodeKind.NOT_EQUAL:\n        case Skew.NodeKind.LOGICAL_OR:\n        case Skew.NodeKind.LOGICAL_AND:\n        case Skew.NodeKind.LESS_THAN:\n        case Skew.NodeKind.GREATER_THAN:\n        case Skew.NodeKind.LESS_THAN_OR_EQUAL:\n        case Skew.NodeKind.GREATER_THAN_OR_EQUAL: {\n          value.invertBooleanCondition(this._cache);\n          node.become(value.remove());\n          break;\n        }\n      }\n    }\n  };\n\n  Skew.Folding.ConstantFolder.prototype._foldConstantIntegerAddOrSubtract = function(node, variable, constant, delta) {\n    var isAdd = node.kind == Skew.NodeKind.ADD;\n    var needsContentUpdate = delta != 0;\n    var isRightConstant = constant == node.binaryRight();\n    var shouldNegateConstant = !isAdd && isRightConstant;\n    var value = constant.asInt();\n\n    // Make this an add for simplicity\n    if (shouldNegateConstant) {\n      value = -value | 0;\n    }\n\n    // Include the delta from the parent node if present\n    value = value + delta | 0;\n\n    // 0 + a => a\n    // 0 - a => -a\n    // a + 0 => a\n    // a - 0 => a\n    if (value == 0) {\n      node.become(isAdd || isRightConstant ? variable.remove() : Skew.Node.createUnary(Skew.NodeKind.NEGATIVE, variable.remove()).withType(node.resolvedType));\n      return;\n    }\n\n    // Check for nested addition or subtraction\n    if (variable.kind == Skew.NodeKind.ADD || variable.kind == Skew.NodeKind.SUBTRACT) {\n      var left = variable.binaryLeft();\n      var right = variable.binaryRight();\n      assert(left.resolvedType == this._cache.intType || left.resolvedType == Skew.Type.DYNAMIC);\n      assert(right.resolvedType == this._cache.intType || right.resolvedType == Skew.Type.DYNAMIC);\n\n      // (a + 1) + 2 => a + 3\n      var isLeftConstant = left.isInt();\n\n      if (isLeftConstant || right.isInt()) {\n        this._foldConstantIntegerAddOrSubtract(variable, isLeftConstant ? right : left, isLeftConstant ? left : right, value);\n        node.become(variable.remove());\n        return;\n      }\n    }\n\n    // Adjust the value so it has the correct sign\n    if (shouldNegateConstant) {\n      value = -value | 0;\n    }\n\n    // The negative sign can often be removed by code transformation\n    if (value < 0) {\n      // a + -1 => a - 1\n      // a - -1 => a + 1\n      if (isRightConstant) {\n        node.kind = isAdd ? Skew.NodeKind.SUBTRACT : Skew.NodeKind.ADD;\n        value = -value | 0;\n        needsContentUpdate = true;\n      }\n\n      // -1 + a => a - 1\n      else if (isAdd) {\n        node.kind = Skew.NodeKind.SUBTRACT;\n        value = -value | 0;\n        variable.swapWith(constant);\n        needsContentUpdate = true;\n      }\n    }\n\n    // Avoid extra allocations\n    if (needsContentUpdate) {\n      constant.content = new Skew.IntContent(value);\n    }\n\n    // Also handle unary negation on \"variable\"\n    this._foldAddOrSubtract(node);\n  };\n\n  Skew.Folding.ConstantFolder.prototype._foldAddOrSubtract = function(node) {\n    var isAdd = node.kind == Skew.NodeKind.ADD;\n    var left = node.binaryLeft();\n    var right = node.binaryRight();\n\n    // -a + b => b - a\n    if (left.kind == Skew.NodeKind.NEGATIVE && isAdd) {\n      left.become(left.unaryValue().remove());\n      left.swapWith(right);\n      node.kind = Skew.NodeKind.SUBTRACT;\n    }\n\n    // a + -b => a - b\n    // a - -b => a + b\n    else if (right.kind == Skew.NodeKind.NEGATIVE) {\n      right.become(right.unaryValue().remove());\n      node.kind = isAdd ? Skew.NodeKind.SUBTRACT : Skew.NodeKind.ADD;\n    }\n\n    // 0 + a => a\n    // 0 - a => -a\n    else if (left.isZero()) {\n      node.become(isAdd ? right.remove() : Skew.Node.createUnary(Skew.NodeKind.NEGATIVE, right.remove()).withType(node.resolvedType));\n    }\n\n    // a + 0 => a\n    // a - 0 => a\n    else if (right.isZero()) {\n      node.become(left.remove());\n    }\n  };\n\n  Skew.Folding.ConstantFolder.prototype._foldConstantIntegerMultiply = function(node, variable, constant) {\n    assert(constant.isInt());\n\n    // Apply identities\n    var variableIsInt = variable.resolvedType == this._cache.intType;\n    var value = constant.asInt();\n\n    // Replacing values with 0 only works for integers. Doubles can be NaN and\n    // NaN times anything is NaN, zero included.\n    if (value == 0 && variableIsInt) {\n      if (variable.hasNoSideEffects()) {\n        node.become(constant.remove());\n      }\n\n      return;\n    }\n\n    // This identity works even with NaN\n    if (value == 1) {\n      node.become(variable.remove());\n      return;\n    }\n\n    // Multiply by a power of 2 should be a left-shift operation, which is\n    // more concise and always faster (or at least never slower) than the\n    // alternative. Division can't be replaced by a right-shift operation\n    // because that would lead to incorrect results for negative numbers.\n    if (variableIsInt) {\n      var shift = Skew.Folding.ConstantFolder._logBase2(value);\n\n      if (shift != -1) {\n        // \"x * 2 * 4\" => \"x << 3\"\n        if (variable.kind == Skew.NodeKind.SHIFT_LEFT && variable.binaryRight().isInt()) {\n          shift = shift + variable.binaryRight().asInt() | 0;\n          variable.replaceWith(variable.binaryLeft().remove());\n        }\n\n        constant.content = new Skew.IntContent(shift);\n        node.kind = Skew.NodeKind.SHIFT_LEFT;\n      }\n    }\n  };\n\n  // \"((a >> 8) & 255) << 8\" => \"a & (255 << 8)\"\n  // \"((a >>> 8) & 255) << 8\" => \"a & (255 << 8)\"\n  // \"((a >> 7) & 255) << 8\" => \"(a << 1) & (255 << 8)\"\n  // \"((a >>> 7) & 255) << 8\" => \"(a << 1) & (255 << 8)\"\n  // \"((a >> 8) & 255) << 7\" => \"(a >> 1) & (255 << 7)\"\n  // \"((a >>> 8) & 255) << 7\" => \"(a >>> 1) & (255 << 7)\"\n  Skew.Folding.ConstantFolder.prototype._foldConstantBitwiseAndInsideShift = function(node, andLeft, andRight) {\n    assert(node.kind == Skew.NodeKind.SHIFT_LEFT && node.binaryRight().isInt());\n\n    if (andRight.isInt() && (andLeft.kind == Skew.NodeKind.SHIFT_RIGHT || andLeft.kind == Skew.NodeKind.UNSIGNED_SHIFT_RIGHT) && andLeft.binaryRight().isInt()) {\n      var mask = andRight.asInt();\n      var leftShift = node.binaryRight().asInt();\n      var rightShift = andLeft.binaryRight().asInt();\n      var value = andLeft.binaryLeft().remove();\n\n      if (leftShift < rightShift) {\n        value = Skew.Node.createBinary(andLeft.kind, value, this._cache.createInt(rightShift - leftShift | 0)).withType(this._cache.intType);\n      }\n\n      else if (leftShift > rightShift) {\n        value = Skew.Node.createBinary(Skew.NodeKind.SHIFT_LEFT, value, this._cache.createInt(leftShift - rightShift | 0)).withType(this._cache.intType);\n      }\n\n      node.become(Skew.Node.createBinary(Skew.NodeKind.BITWISE_AND, value, this._cache.createInt(mask << leftShift)).withType(node.resolvedType));\n    }\n  };\n\n  Skew.Folding.ConstantFolder.prototype._foldConstantBitwiseAndInsideBitwiseOr = function(node) {\n    assert(node.kind == Skew.NodeKind.BITWISE_OR && node.binaryLeft().kind == Skew.NodeKind.BITWISE_AND);\n    var left = node.binaryLeft();\n    var right = node.binaryRight();\n    var leftLeft = left.binaryLeft();\n    var leftRight = left.binaryRight();\n\n    // \"(a & b) | (a & c)\" => \"a & (b | c)\"\n    if (right.kind == Skew.NodeKind.BITWISE_AND) {\n      var rightLeft = right.binaryLeft();\n      var rightRight = right.binaryRight();\n\n      if (leftRight.isInt() && rightRight.isInt() && Skew.Folding.ConstantFolder._isSameVariableReference(leftLeft, rightLeft)) {\n        var mask = leftRight.asInt() | rightRight.asInt();\n        node.become(Skew.Node.createBinary(Skew.NodeKind.BITWISE_AND, leftLeft.remove(), this._cache.createInt(mask)).withType(node.resolvedType));\n      }\n    }\n\n    // \"(a & b) | c\" => \"a | c\" when \"(a | b) == ~0\"\n    else if (right.isInt() && leftRight.isInt() && (leftRight.asInt() | right.asInt()) == ~0) {\n      left.become(leftLeft.remove());\n    }\n  };\n\n  Skew.Folding.ConstantFolder.prototype._foldBinaryWithConstant = function(node, left, right) {\n    // There are lots of other folding opportunities for most binary operators\n    // here but those usually have a negligible performance and/or size impact\n    // on the generated code and instead slow the compiler down. Only certain\n    // ones are implemented below.\n    switch (node.kind) {\n      // These are important for dead code elimination\n      case Skew.NodeKind.LOGICAL_AND: {\n        if (left.isFalse() || right.isTrue()) {\n          node.become(left.remove());\n        }\n\n        else if (left.isTrue()) {\n          node.become(right.remove());\n        }\n        break;\n      }\n\n      case Skew.NodeKind.LOGICAL_OR: {\n        if (left.isTrue() || right.isFalse()) {\n          node.become(left.remove());\n        }\n\n        else if (left.isFalse()) {\n          node.become(right.remove());\n        }\n        break;\n      }\n\n      // Constants are often added up in compound expressions. Folding\n      // addition/subtraction improves minification in JavaScript and often\n      // helps with readability.\n      case Skew.NodeKind.ADD:\n      case Skew.NodeKind.SUBTRACT: {\n        if (left.isInt()) {\n          this._foldConstantIntegerAddOrSubtract(node, right, left, 0);\n        }\n\n        else if (right.isInt()) {\n          this._foldConstantIntegerAddOrSubtract(node, left, right, 0);\n        }\n\n        else {\n          this._foldAddOrSubtract(node);\n        }\n        break;\n      }\n\n      // Multiplication is special-cased here because in JavaScript, optimizing\n      // away the general-purpose Math.imul function may result in large\n      // speedups when it's implemented with a polyfill.\n      case Skew.NodeKind.MULTIPLY: {\n        if (right.isInt()) {\n          this._foldConstantIntegerMultiply(node, left, right);\n        }\n        break;\n      }\n\n      // This improves generated code for inlined bit packing functions\n      case Skew.NodeKind.SHIFT_LEFT:\n      case Skew.NodeKind.SHIFT_RIGHT:\n      case Skew.NodeKind.UNSIGNED_SHIFT_RIGHT: {\n        // \"x << 0\" => \"x\"\n        // \"x >> 0\" => \"x\"\n        // \"x >>> 0\" => \"x\"\n        if (this._cache.isEquivalentToInt(left.resolvedType) && right.isInt() && right.asInt() == 0) {\n          node.become(left.remove());\n        }\n\n        // Handle special cases of \"&\" nested inside \"<<\"\n        else if (node.kind == Skew.NodeKind.SHIFT_LEFT && left.kind == Skew.NodeKind.BITWISE_AND && right.isInt()) {\n          this._foldConstantBitwiseAndInsideShift(node, left.binaryLeft(), left.binaryRight());\n        }\n\n        // \"x << 1 << 2\" => \"x << 3\"\n        // \"x >> 1 >> 2\" => \"x >> 3\"\n        // \"x >>> 1 >>> 2\" => \"x >>> 3\"\n        else if (node.kind == left.kind && left.binaryRight().isInt() && right.isInt()) {\n          this._flattenInt(right, left.binaryRight().asInt() + right.asInt() | 0);\n          left.replaceWith(left.binaryLeft().remove());\n        }\n        break;\n      }\n\n      case Skew.NodeKind.BITWISE_AND: {\n        if (right.isInt() && this._cache.isEquivalentToInt(left.resolvedType)) {\n          var value = right.asInt();\n\n          // \"x & ~0\" => \"x\"\n          if (value == ~0) {\n            node.become(left.remove());\n          }\n\n          // \"x & 0\" => \"0\"\n          else if (value == 0 && left.hasNoSideEffects()) {\n            node.become(right.remove());\n          }\n        }\n        break;\n      }\n\n      case Skew.NodeKind.BITWISE_OR: {\n        if (right.isInt() && this._cache.isEquivalentToInt(left.resolvedType)) {\n          var value1 = right.asInt();\n\n          // \"x | 0\" => \"x\"\n          if (value1 == 0) {\n            node.become(left.remove());\n            return;\n          }\n\n          // \"x | ~0\" => \"~0\"\n          else if (value1 == ~0 && left.hasNoSideEffects()) {\n            node.become(right.remove());\n            return;\n          }\n        }\n\n        if (left.kind == Skew.NodeKind.BITWISE_AND) {\n          this._foldConstantBitwiseAndInsideBitwiseOr(node);\n        }\n        break;\n      }\n    }\n  };\n\n  Skew.Folding.ConstantFolder.prototype._foldBinary = function(node) {\n    var kind = node.kind;\n\n    if (kind == Skew.NodeKind.ADD && node.resolvedType == this._cache.stringType) {\n      this._foldStringConcatenation(node);\n      return;\n    }\n\n    var left = node.binaryLeft();\n    var right = node.binaryRight();\n\n    // Canonicalize the order of commutative operators\n    if ((kind == Skew.NodeKind.MULTIPLY || kind == Skew.NodeKind.BITWISE_AND || kind == Skew.NodeKind.BITWISE_OR) && left.kind == Skew.NodeKind.CONSTANT && right.kind != Skew.NodeKind.CONSTANT) {\n      var temp = left;\n      left = right;\n      right = temp;\n      left.swapWith(right);\n    }\n\n    if (left.kind == Skew.NodeKind.CONSTANT && right.kind == Skew.NodeKind.CONSTANT) {\n      var leftContent = left.content;\n      var rightContent = right.content;\n      var leftKind = leftContent.kind();\n      var rightKind = rightContent.kind();\n\n      // Fold equality operators\n      if (leftKind == Skew.ContentKind.STRING && rightKind == Skew.ContentKind.STRING) {\n        switch (kind) {\n          case Skew.NodeKind.EQUAL: {\n            this._flattenBool(node, Skew.in_Content.asString(leftContent) == Skew.in_Content.asString(rightContent));\n            break;\n          }\n\n          case Skew.NodeKind.NOT_EQUAL: {\n            this._flattenBool(node, Skew.in_Content.asString(leftContent) != Skew.in_Content.asString(rightContent));\n            break;\n          }\n\n          case Skew.NodeKind.LESS_THAN: {\n            this._flattenBool(node, in_string.compare(Skew.in_Content.asString(leftContent), Skew.in_Content.asString(rightContent)) < 0);\n            break;\n          }\n\n          case Skew.NodeKind.GREATER_THAN: {\n            this._flattenBool(node, in_string.compare(Skew.in_Content.asString(leftContent), Skew.in_Content.asString(rightContent)) > 0);\n            break;\n          }\n\n          case Skew.NodeKind.LESS_THAN_OR_EQUAL: {\n            this._flattenBool(node, in_string.compare(Skew.in_Content.asString(leftContent), Skew.in_Content.asString(rightContent)) <= 0);\n            break;\n          }\n\n          case Skew.NodeKind.GREATER_THAN_OR_EQUAL: {\n            this._flattenBool(node, in_string.compare(Skew.in_Content.asString(leftContent), Skew.in_Content.asString(rightContent)) >= 0);\n            break;\n          }\n        }\n\n        return;\n      }\n\n      // Fold \"bool\" values\n      else if (leftKind == Skew.ContentKind.BOOL && rightKind == Skew.ContentKind.BOOL) {\n        switch (kind) {\n          case Skew.NodeKind.LOGICAL_AND: {\n            this._flattenBool(node, Skew.in_Content.asBool(leftContent) && Skew.in_Content.asBool(rightContent));\n            break;\n          }\n\n          case Skew.NodeKind.LOGICAL_OR: {\n            this._flattenBool(node, Skew.in_Content.asBool(leftContent) || Skew.in_Content.asBool(rightContent));\n            break;\n          }\n\n          case Skew.NodeKind.EQUAL: {\n            this._flattenBool(node, Skew.in_Content.asBool(leftContent) == Skew.in_Content.asBool(rightContent));\n            break;\n          }\n\n          case Skew.NodeKind.NOT_EQUAL: {\n            this._flattenBool(node, Skew.in_Content.asBool(leftContent) != Skew.in_Content.asBool(rightContent));\n            break;\n          }\n        }\n\n        return;\n      }\n\n      // Fold \"int\" values\n      else if (leftKind == Skew.ContentKind.INT && rightKind == Skew.ContentKind.INT) {\n        switch (kind) {\n          case Skew.NodeKind.ADD: {\n            this._flattenInt(node, Skew.in_Content.asInt(leftContent) + Skew.in_Content.asInt(rightContent) | 0);\n            break;\n          }\n\n          case Skew.NodeKind.BITWISE_AND: {\n            this._flattenInt(node, Skew.in_Content.asInt(leftContent) & Skew.in_Content.asInt(rightContent));\n            break;\n          }\n\n          case Skew.NodeKind.BITWISE_OR: {\n            this._flattenInt(node, Skew.in_Content.asInt(leftContent) | Skew.in_Content.asInt(rightContent));\n            break;\n          }\n\n          case Skew.NodeKind.BITWISE_XOR: {\n            this._flattenInt(node, Skew.in_Content.asInt(leftContent) ^ Skew.in_Content.asInt(rightContent));\n            break;\n          }\n\n          case Skew.NodeKind.DIVIDE: {\n            this._flattenInt(node, Skew.in_Content.asInt(leftContent) / Skew.in_Content.asInt(rightContent) | 0);\n            break;\n          }\n\n          case Skew.NodeKind.EQUAL: {\n            this._flattenBool(node, Skew.in_Content.asInt(leftContent) == Skew.in_Content.asInt(rightContent));\n            break;\n          }\n\n          case Skew.NodeKind.GREATER_THAN: {\n            this._flattenBool(node, Skew.in_Content.asInt(leftContent) > Skew.in_Content.asInt(rightContent));\n            break;\n          }\n\n          case Skew.NodeKind.GREATER_THAN_OR_EQUAL: {\n            this._flattenBool(node, Skew.in_Content.asInt(leftContent) >= Skew.in_Content.asInt(rightContent));\n            break;\n          }\n\n          case Skew.NodeKind.LESS_THAN: {\n            this._flattenBool(node, Skew.in_Content.asInt(leftContent) < Skew.in_Content.asInt(rightContent));\n            break;\n          }\n\n          case Skew.NodeKind.LESS_THAN_OR_EQUAL: {\n            this._flattenBool(node, Skew.in_Content.asInt(leftContent) <= Skew.in_Content.asInt(rightContent));\n            break;\n          }\n\n          case Skew.NodeKind.MULTIPLY: {\n            this._flattenInt(node, __imul(Skew.in_Content.asInt(leftContent), Skew.in_Content.asInt(rightContent)));\n            break;\n          }\n\n          case Skew.NodeKind.NOT_EQUAL: {\n            this._flattenBool(node, Skew.in_Content.asInt(leftContent) != Skew.in_Content.asInt(rightContent));\n            break;\n          }\n\n          case Skew.NodeKind.REMAINDER: {\n            this._flattenInt(node, Skew.in_Content.asInt(leftContent) % Skew.in_Content.asInt(rightContent) | 0);\n            break;\n          }\n\n          case Skew.NodeKind.SHIFT_LEFT: {\n            this._flattenInt(node, Skew.in_Content.asInt(leftContent) << Skew.in_Content.asInt(rightContent));\n            break;\n          }\n\n          case Skew.NodeKind.SHIFT_RIGHT: {\n            this._flattenInt(node, Skew.in_Content.asInt(leftContent) >> Skew.in_Content.asInt(rightContent));\n            break;\n          }\n\n          case Skew.NodeKind.SUBTRACT: {\n            this._flattenInt(node, Skew.in_Content.asInt(leftContent) - Skew.in_Content.asInt(rightContent) | 0);\n            break;\n          }\n\n          case Skew.NodeKind.UNSIGNED_SHIFT_RIGHT: {\n            this._flattenInt(node, Skew.in_Content.asInt(leftContent) >>> Skew.in_Content.asInt(rightContent) | 0);\n            break;\n          }\n        }\n\n        return;\n      }\n\n      // Fold \"double\" values\n      else if (leftKind == Skew.ContentKind.DOUBLE && rightKind == Skew.ContentKind.DOUBLE) {\n        switch (kind) {\n          case Skew.NodeKind.ADD: {\n            this._flattenDouble(node, Skew.in_Content.asDouble(leftContent) + Skew.in_Content.asDouble(rightContent));\n            break;\n          }\n\n          case Skew.NodeKind.SUBTRACT: {\n            this._flattenDouble(node, Skew.in_Content.asDouble(leftContent) - Skew.in_Content.asDouble(rightContent));\n            break;\n          }\n\n          case Skew.NodeKind.MULTIPLY: {\n            this._flattenDouble(node, Skew.in_Content.asDouble(leftContent) * Skew.in_Content.asDouble(rightContent));\n            break;\n          }\n\n          case Skew.NodeKind.DIVIDE: {\n            this._flattenDouble(node, Skew.in_Content.asDouble(leftContent) / Skew.in_Content.asDouble(rightContent));\n            break;\n          }\n\n          case Skew.NodeKind.EQUAL: {\n            this._flattenBool(node, Skew.in_Content.asDouble(leftContent) == Skew.in_Content.asDouble(rightContent));\n            break;\n          }\n\n          case Skew.NodeKind.NOT_EQUAL: {\n            this._flattenBool(node, Skew.in_Content.asDouble(leftContent) != Skew.in_Content.asDouble(rightContent));\n            break;\n          }\n\n          case Skew.NodeKind.LESS_THAN: {\n            this._flattenBool(node, Skew.in_Content.asDouble(leftContent) < Skew.in_Content.asDouble(rightContent));\n            break;\n          }\n\n          case Skew.NodeKind.GREATER_THAN: {\n            this._flattenBool(node, Skew.in_Content.asDouble(leftContent) > Skew.in_Content.asDouble(rightContent));\n            break;\n          }\n\n          case Skew.NodeKind.LESS_THAN_OR_EQUAL: {\n            this._flattenBool(node, Skew.in_Content.asDouble(leftContent) <= Skew.in_Content.asDouble(rightContent));\n            break;\n          }\n\n          case Skew.NodeKind.GREATER_THAN_OR_EQUAL: {\n            this._flattenBool(node, Skew.in_Content.asDouble(leftContent) >= Skew.in_Content.asDouble(rightContent));\n            break;\n          }\n        }\n\n        return;\n      }\n    }\n\n    this._foldBinaryWithConstant(node, left, right);\n  };\n\n  Skew.Folding.ConstantFolder.prototype._foldHook = function(node) {\n    var test = node.hookTest();\n\n    if (test.isTrue()) {\n      node.become(node.hookTrue().remove());\n    }\n\n    else if (test.isFalse()) {\n      node.become(node.hookFalse().remove());\n    }\n  };\n\n  Skew.Folding.ConstantFolder.prototype.constantForSymbol = function(symbol) {\n    if (this._constantCache.has(symbol.id)) {\n      return in_IntMap.get1(this._constantCache, symbol.id);\n    }\n\n    if (this._prepareSymbol != null) {\n      this._prepareSymbol(symbol);\n    }\n\n    var constant = null;\n    var value = symbol.value;\n\n    if (symbol.isConst() && value != null) {\n      in_IntMap.set(this._constantCache, symbol.id, null);\n      value = value.clone();\n      this.foldConstants(value);\n\n      if (value.kind == Skew.NodeKind.CONSTANT) {\n        constant = value.content;\n      }\n    }\n\n    in_IntMap.set(this._constantCache, symbol.id, constant);\n    return constant;\n  };\n\n  Skew.Folding.ConstantFolder._isVariableReference = function(node) {\n    return node.kind == Skew.NodeKind.NAME && node.symbol != null && Skew.in_SymbolKind.isVariable(node.symbol.kind);\n  };\n\n  Skew.Folding.ConstantFolder._isSameVariableReference = function(a, b) {\n    return Skew.Folding.ConstantFolder._isVariableReference(a) && Skew.Folding.ConstantFolder._isVariableReference(b) && a.symbol == b.symbol || a.kind == Skew.NodeKind.CAST && b.kind == Skew.NodeKind.CAST && Skew.Folding.ConstantFolder._isSameVariableReference(a.castValue(), b.castValue());\n  };\n\n  Skew.Folding.ConstantFolder._hasNestedReference = function(node, symbol) {\n    assert(symbol != null);\n\n    if (node.symbol == symbol) {\n      return true;\n    }\n\n    for (var child = node.firstChild(); child != null; child = child.nextSibling()) {\n      if (Skew.Folding.ConstantFolder._hasNestedReference(child, symbol)) {\n        return true;\n      }\n    }\n\n    return false;\n  };\n\n  Skew.Folding.ConstantFolder._shouldFoldSymbol = function(symbol) {\n    return symbol != null && symbol.isConst() && (symbol.kind != Skew.SymbolKind.VARIABLE_INSTANCE || symbol.isImported());\n  };\n\n  Skew.Folding.ConstantFolder._isKnownCall = function(symbol, knownSymbol) {\n    return symbol == knownSymbol || symbol != null && Skew.in_SymbolKind.isFunction(symbol.kind) && (symbol.asFunctionSymbol().overloaded == knownSymbol || Skew.in_SymbolKind.isFunction(knownSymbol.kind) && symbol.asFunctionSymbol().overloaded != null && symbol.asFunctionSymbol().overloaded == knownSymbol.asFunctionSymbol().overloaded && symbol.asFunctionSymbol().argumentOnlyType == knownSymbol.asFunctionSymbol().argumentOnlyType);\n  };\n\n  // Returns the log2(value) or -1 if log2(value) is not an integer\n  Skew.Folding.ConstantFolder._logBase2 = function(value) {\n    if (value < 1 || (value & value - 1) != 0) {\n      return -1;\n    }\n\n    var result = 0;\n\n    while (value > 1) {\n      value >>= 1;\n      result = result + 1 | 0;\n    }\n\n    return result;\n  };\n\n  Skew.MotionPass = function() {\n    Skew.Pass.call(this);\n  };\n\n  __extends(Skew.MotionPass, Skew.Pass);\n\n  Skew.MotionPass.prototype.kind = function() {\n    return Skew.PassKind.MOTION;\n  };\n\n  Skew.MotionPass.prototype.run = function(context) {\n    var motionContext = new Skew.Motion.Context();\n    Skew.Motion.symbolMotion(context.global, context.options, motionContext);\n    motionContext.finish();\n  };\n\n  Skew.Motion = {};\n\n  Skew.Motion.symbolMotion = function(symbol, options, context) {\n    // Move non-imported objects off imported objects\n    in_List.removeIf(symbol.objects, function(object) {\n      Skew.Motion.symbolMotion(object, options, context);\n\n      if (symbol.isImported() && !object.isImported() || !options.target.supportsNestedTypes() && !Skew.in_SymbolKind.isNamespaceOrGlobal(symbol.kind)) {\n        context.moveSymbolIntoNewNamespace(object);\n        return true;\n      }\n\n      return false;\n    });\n\n    // Move global functions with implementations off of imported objects and interfaces\n    in_List.removeIf(symbol.functions, function($function) {\n      if ($function.kind == Skew.SymbolKind.FUNCTION_GLOBAL && (symbol.isImported() && !$function.isImported() || symbol.kind == Skew.SymbolKind.OBJECT_INTERFACE)) {\n        context.moveSymbolIntoNewNamespace($function);\n        return true;\n      }\n\n      return false;\n    });\n\n    // Move stuff off of enums and flags\n    if (Skew.in_SymbolKind.isEnumOrFlags(symbol.kind)) {\n      symbol.objects.forEach(function(object) {\n        context.moveSymbolIntoNewNamespace(object);\n      });\n      symbol.functions.forEach(function($function) {\n        context.moveSymbolIntoNewNamespace($function);\n      });\n      in_List.removeIf(symbol.variables, function(variable) {\n        if (variable.kind != Skew.SymbolKind.VARIABLE_ENUM_OR_FLAGS) {\n          context.moveSymbolIntoNewNamespace(variable);\n          return true;\n        }\n\n        return false;\n      });\n      symbol.objects = [];\n      symbol.functions = [];\n    }\n\n    // Move variables off of interfaces\n    else if (symbol.kind == Skew.SymbolKind.OBJECT_INTERFACE) {\n      symbol.variables.forEach(function(variable) {\n        context.moveSymbolIntoNewNamespace(variable);\n      });\n      symbol.variables = [];\n    }\n  };\n\n  Skew.Motion.Context = function() {\n    this._namespaces = new Map();\n  };\n\n  // Avoid mutation during iteration\n  Skew.Motion.Context.prototype.finish = function() {\n    var values = Array.from(this._namespaces.values());\n\n    // Sort so the order is deterministic\n    values.sort(Skew.Symbol.SORT_OBJECTS_BY_ID);\n\n    for (var i = 0, list = values, count = list.length; i < count; i = i + 1 | 0) {\n      var object = in_List.get(list, i);\n      object.parent.asObjectSymbol().objects.push(object);\n    }\n  };\n\n  Skew.Motion.Context.prototype.moveSymbolIntoNewNamespace = function(symbol) {\n    var parent = symbol.parent;\n    var namespace = in_IntMap.get(this._namespaces, parent.id, null);\n    var object = namespace != null ? namespace.asObjectSymbol() : null;\n\n    // Create a parallel namespace next to the parent\n    if (namespace == null) {\n      var common = parent.parent.asObjectSymbol();\n      var name = 'in_' + parent.name;\n      var candidate = in_StringMap.get(common.members, name, null);\n\n      if (candidate != null && candidate.kind == Skew.SymbolKind.OBJECT_NAMESPACE) {\n        object = candidate.asObjectSymbol();\n      }\n\n      else {\n        object = new Skew.ObjectSymbol(Skew.SymbolKind.OBJECT_NAMESPACE, common.scope.generateName(name));\n        object.range = parent.range;\n        object.resolvedType = new Skew.Type(Skew.TypeKind.SYMBOL, object);\n        object.state = Skew.SymbolState.INITIALIZED;\n        object.scope = new Skew.ObjectScope(common.scope, object);\n        object.parent = common;\n        in_StringMap.set(common.members, name, object);\n        in_IntMap.set(this._namespaces, parent.id, object);\n      }\n    }\n\n    // Move this function into that parallel namespace\n    symbol.parent = object;\n\n    if (Skew.in_SymbolKind.isObject(symbol.kind)) {\n      object.objects.push(symbol.asObjectSymbol());\n    }\n\n    else if (Skew.in_SymbolKind.isFunction(symbol.kind)) {\n      object.functions.push(symbol.asFunctionSymbol());\n\n      // Inflate functions with type parameters from the parent (TODO: Need to inflate call sites too)\n      if (parent.asObjectSymbol().parameters != null) {\n        var $function = symbol.asFunctionSymbol();\n\n        if ($function.parameters == null) {\n          $function.parameters = [];\n        }\n\n        in_List.prepend1($function.parameters, parent.asObjectSymbol().parameters);\n      }\n    }\n\n    else if (Skew.in_SymbolKind.isVariable(symbol.kind)) {\n      object.variables.push(symbol.asVariableSymbol());\n    }\n  };\n\n  Skew.GlobalizingPass = function() {\n    Skew.Pass.call(this);\n  };\n\n  __extends(Skew.GlobalizingPass, Skew.Pass);\n\n  Skew.GlobalizingPass.prototype.kind = function() {\n    return Skew.PassKind.GLOBALIZING;\n  };\n\n  Skew.GlobalizingPass.prototype.run = function(context) {\n    var globalizeAllFunctions = context.options.globalizeAllFunctions;\n    var virtualLookup = globalizeAllFunctions || context.options.isAlwaysInlinePresent ? new Skew.VirtualLookup(context.global) : null;\n    var motionContext = new Skew.Motion.Context();\n\n    for (var i1 = 0, list1 = context.callGraph.callInfo, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n      var info = in_List.get(list1, i1);\n      var symbol = info.symbol;\n\n      // Turn certain instance functions into global functions\n      if (symbol.kind == Skew.SymbolKind.FUNCTION_INSTANCE && (Skew.in_SymbolKind.isEnumOrFlags(symbol.parent.kind) || symbol.parent.kind == Skew.SymbolKind.OBJECT_WRAPPED || symbol.parent.kind == Skew.SymbolKind.OBJECT_INTERFACE && symbol.block != null || symbol.parent.isImported() && !symbol.isImported() || (globalizeAllFunctions || symbol.isInliningForced()) && !symbol.isImportedOrExported() && !virtualLookup.isVirtual(symbol))) {\n        var $function = symbol.asFunctionSymbol();\n        $function.kind = Skew.SymbolKind.FUNCTION_GLOBAL;\n        $function.$arguments.unshift($function.$this);\n        $function.resolvedType.argumentTypes.unshift($function.$this.resolvedType);\n        $function.$this = null;\n\n        // The globalized function needs instance type parameters\n        if ($function.parent.asObjectSymbol().parameters != null) {\n          in_List.removeOne($function.parent.asObjectSymbol().functions, $function);\n          motionContext.moveSymbolIntoNewNamespace($function);\n        }\n\n        // Update all call sites\n        for (var i = 0, list = info.callSites, count = list.length; i < count; i = i + 1 | 0) {\n          var callSite = in_List.get(list, i);\n          var value = callSite.callNode.callValue();\n\n          // Rewrite \"super(foo)\" to \"bar(self, foo)\"\n          if (value.kind == Skew.NodeKind.SUPER) {\n            var $this = callSite.enclosingSymbol.asFunctionSymbol().$this;\n            value.replaceWith(Skew.Node.createSymbolReference($this));\n          }\n\n          // Rewrite \"self.foo(bar)\" to \"foo(self, bar)\"\n          else {\n            value.replaceWith((value.kind == Skew.NodeKind.PARAMETERIZE ? value.parameterizeValue() : value).dotTarget().remove());\n          }\n\n          callSite.callNode.prependChild(Skew.Node.createSymbolReference($function));\n        }\n      }\n    }\n\n    motionContext.finish();\n  };\n\n  Skew.VirtualLookup = function(global) {\n    this._map = new Map();\n    this._visitObject(global);\n  };\n\n  Skew.VirtualLookup.prototype.isVirtual = function(symbol) {\n    return this._map.has(symbol.id);\n  };\n\n  Skew.VirtualLookup.prototype._visitObject = function(symbol) {\n    for (var i = 0, list = symbol.objects, count = list.length; i < count; i = i + 1 | 0) {\n      var object = in_List.get(list, i);\n      this._visitObject(object);\n    }\n\n    for (var i2 = 0, list2 = symbol.functions, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n      var $function = in_List.get(list2, i2);\n\n      if ($function.overridden != null) {\n        in_IntMap.set(this._map, $function.overridden.id, 0);\n        in_IntMap.set(this._map, $function.id, 0);\n      }\n\n      if (symbol.kind == Skew.SymbolKind.OBJECT_INTERFACE && $function.kind == Skew.SymbolKind.FUNCTION_INSTANCE && $function.forwardTo == null) {\n        if ($function.implementations != null) {\n          for (var i1 = 0, list1 = $function.implementations, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n            var implementation = in_List.get(list1, i1);\n            in_IntMap.set(this._map, implementation.id, 0);\n          }\n        }\n\n        in_IntMap.set(this._map, $function.id, 0);\n      }\n    }\n  };\n\n  Skew.MergingPass = function() {\n    Skew.Pass.call(this);\n  };\n\n  __extends(Skew.MergingPass, Skew.Pass);\n\n  Skew.MergingPass.prototype.kind = function() {\n    return Skew.PassKind.MERGING;\n  };\n\n  Skew.MergingPass.prototype.run = function(context) {\n    Skew.Merging.mergeObject(context.log, null, context.global, context.global);\n  };\n\n  Skew.Merging = {};\n\n  Skew.Merging.mergeObject = function(log, parent, target, symbol) {\n    target.scope = new Skew.ObjectScope(parent != null ? parent.scope : null, target);\n    symbol.scope = target.scope;\n    symbol.parent = parent;\n\n    // This is a heuristic for getting the range to be from the primary definition\n    if (symbol.kind == target.kind && symbol.variables.length > target.variables.length) {\n      target.range = symbol.range;\n    }\n\n    if (symbol.parameters != null) {\n      for (var i = 0, list = symbol.parameters, count = list.length; i < count; i = i + 1 | 0) {\n        var parameter = in_List.get(list, i);\n        parameter.scope = parent.scope;\n        parameter.parent = target;\n\n        // Type parameters cannot merge with any members\n        var other = in_StringMap.get(target.members, parameter.name, null);\n\n        if (other != null) {\n          log.semanticErrorDuplicateSymbol(parameter.range, parameter.name, other.range);\n          continue;\n        }\n\n        in_StringMap.set(target.members, parameter.name, parameter);\n      }\n    }\n\n    Skew.Merging.mergeObjects(log, target, symbol.objects);\n    Skew.Merging.mergeFunctions(log, target, symbol.functions, Skew.Merging.MergeBehavior.NORMAL);\n    Skew.Merging.mergeVariables(log, target, symbol.variables);\n  };\n\n  Skew.Merging.mergeObjects = function(log, parent, children) {\n    var members = parent.members;\n    in_List.removeIf(children, function(child) {\n      var other = in_StringMap.get(members, child.name, null);\n\n      // Simple case: no merging\n      if (other == null) {\n        in_StringMap.set(members, child.name, child);\n        Skew.Merging.mergeObject(log, parent, child, child);\n        return false;\n      }\n\n      // Can only merge with another of the same kind or with a namespace\n      if (other.kind == Skew.SymbolKind.OBJECT_NAMESPACE) {\n        var swap = other.range;\n        other.range = child.range;\n        child.range = swap;\n        other.kind = child.kind;\n      }\n\n      else if (child.kind == Skew.SymbolKind.OBJECT_NAMESPACE) {\n        child.kind = other.kind;\n      }\n\n      else if (child.kind != other.kind) {\n        log.semanticErrorDuplicateSymbol(child.range, child.name, other.range);\n        return true;\n      }\n\n      // Classes can only have one base type\n      var object = other.asObjectSymbol();\n\n      if (child.$extends != null) {\n        if (object.$extends != null) {\n          log.semanticErrorDuplicateBaseType(child.$extends.range, child.name, object.$extends.range);\n          return true;\n        }\n\n        object.$extends = child.$extends;\n      }\n\n      // Merge base interfaces\n      if (child.$implements != null) {\n        if (object.$implements != null) {\n          in_List.append1(object.$implements, child.$implements);\n        }\n\n        else {\n          object.$implements = child.$implements;\n        }\n      }\n\n      // Cannot merge two objects that both have type parameters\n      if (child.parameters != null && object.parameters != null) {\n        log.semanticErrorDuplicateTypeParameters(Skew.Merging.rangeOfParameters(child.parameters), child.name, Skew.Merging.rangeOfParameters(object.parameters));\n        return true;\n      }\n\n      // Merge \"child\" into \"other\"\n      Skew.Merging.mergeObject(log, parent, object, child);\n      object.mergeInformationFrom(child);\n      in_List.append1(object.objects, child.objects);\n      in_List.append1(object.functions, child.functions);\n      in_List.append1(object.variables, child.variables);\n\n      if (child.parameters != null) {\n        object.parameters = child.parameters;\n      }\n\n      if (child.guards != null) {\n        if (object.guards == null) {\n          object.guards = [];\n        }\n\n        for (var i = 0, list = child.guards, count = list.length; i < count; i = i + 1 | 0) {\n          var guard = in_List.get(list, i);\n\n          for (var g = guard; g != null; g = g.elseGuard) {\n            g.parent = object;\n            g.contents.parent = object;\n          }\n\n          object.guards.push(guard);\n        }\n      }\n\n      return true;\n    });\n  };\n\n  Skew.Merging.mergeFunctions = function(log, parent, children, behavior) {\n    var members = parent.members;\n\n    for (var i1 = 0, list1 = children, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n      var child = in_List.get(list1, i1);\n      var other = in_StringMap.get(members, child.name, null);\n\n      // Create a scope for this function's type parameters\n      if (behavior == Skew.Merging.MergeBehavior.NORMAL) {\n        var scope = new Skew.FunctionScope(parent.scope, child);\n        child.scope = scope;\n        child.parent = parent;\n\n        if (child.parameters != null) {\n          for (var i = 0, list = child.parameters, count = list.length; i < count; i = i + 1 | 0) {\n            var parameter = in_List.get(list, i);\n            parameter.scope = scope;\n            parameter.parent = child;\n\n            // Type parameters cannot merge with other parameters on this function\n            var previous = in_StringMap.get(scope.parameters, parameter.name, null);\n\n            if (previous != null) {\n              log.semanticErrorDuplicateSymbol(parameter.range, parameter.name, previous.range);\n              continue;\n            }\n\n            in_StringMap.set(scope.parameters, parameter.name, parameter);\n          }\n        }\n      }\n\n      // Simple case: no merging\n      if (other == null) {\n        in_StringMap.set(members, child.name, child);\n        continue;\n      }\n\n      var childKind = Skew.Merging.overloadedKind(child.kind);\n      var otherKind = Skew.Merging.overloadedKind(other.kind);\n\n      // Merge with another symbol of the same overloaded group type\n      if (childKind != otherKind || !Skew.in_SymbolKind.isOverloadedFunction(childKind)) {\n        if (behavior == Skew.Merging.MergeBehavior.NORMAL) {\n          log.semanticErrorDuplicateSymbol(child.range, child.name, other.range);\n        }\n\n        else {\n          log.semanticErrorBadOverride(other.range, other.name, parent.baseType, child.range);\n        }\n\n        continue;\n      }\n\n      // Merge with a group of overloaded functions\n      if (Skew.in_SymbolKind.isOverloadedFunction(other.kind)) {\n        other.asOverloadedFunctionSymbol().symbols.push(child);\n\n        if (behavior == Skew.Merging.MergeBehavior.NORMAL) {\n          child.overloaded = other.asOverloadedFunctionSymbol();\n        }\n\n        continue;\n      }\n\n      // Create an overload group\n      var overloaded = new Skew.OverloadedFunctionSymbol(childKind, child.name, [other.asFunctionSymbol(), child]);\n      in_StringMap.set(members, child.name, overloaded);\n      other.asFunctionSymbol().overloaded = overloaded;\n\n      if (behavior == Skew.Merging.MergeBehavior.NORMAL) {\n        child.overloaded = overloaded;\n      }\n\n      overloaded.scope = parent.scope;\n      overloaded.parent = parent;\n    }\n  };\n\n  Skew.Merging.overloadedKind = function(kind) {\n    return kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR || kind == Skew.SymbolKind.FUNCTION_GLOBAL ? Skew.SymbolKind.OVERLOADED_GLOBAL : kind == Skew.SymbolKind.FUNCTION_ANNOTATION ? Skew.SymbolKind.OVERLOADED_ANNOTATION : kind == Skew.SymbolKind.FUNCTION_INSTANCE ? Skew.SymbolKind.OVERLOADED_INSTANCE : kind;\n  };\n\n  Skew.Merging.mergeVariables = function(log, parent, children) {\n    var members = parent.members;\n\n    for (var i = 0, list = children, count = list.length; i < count; i = i + 1 | 0) {\n      var child = in_List.get(list, i);\n      var other = in_StringMap.get(members, child.name, null);\n      child.scope = new Skew.VariableScope(parent.scope, child);\n      child.parent = parent;\n\n      // Variables never merge\n      if (other != null) {\n        log.semanticErrorDuplicateSymbol(child.range, child.name, other.range);\n        continue;\n      }\n\n      in_StringMap.set(members, child.name, child);\n    }\n  };\n\n  Skew.Merging.rangeOfParameters = function(parameters) {\n    return Skew.Range.span(in_List.first(parameters).range, in_List.last(parameters).range);\n  };\n\n  Skew.Merging.MergeBehavior = {\n    NORMAL: 0,\n    INTO_DERIVED_CLASS: 1\n  };\n\n  Skew.InterfaceRemovalPass = function() {\n    Skew.Pass.call(this);\n    this._interfaceImplementations = new Map();\n    this._interfaces = [];\n  };\n\n  __extends(Skew.InterfaceRemovalPass, Skew.Pass);\n\n  Skew.InterfaceRemovalPass.prototype.kind = function() {\n    return Skew.PassKind.INTERFACE_REMOVAL;\n  };\n\n  Skew.InterfaceRemovalPass.prototype.run = function(context) {\n    this._scanForInterfaces(context.global);\n\n    for (var i2 = 0, list2 = this._interfaces, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n      var symbol = in_List.get(list2, i2);\n\n      if (symbol.isImportedOrExported()) {\n        continue;\n      }\n\n      var implementations = in_IntMap.get(this._interfaceImplementations, symbol.id, null);\n\n      if (implementations == null || implementations.length == 1) {\n        symbol.kind = Skew.SymbolKind.OBJECT_NAMESPACE;\n\n        // Remove this interface from its implementation\n        if (implementations != null) {\n          var object = in_List.first(implementations);\n\n          for (var i = 0, list = object.interfaceTypes, count = list.length; i < count; i = i + 1 | 0) {\n            var type = in_List.get(list, i);\n\n            if (type.symbol == symbol) {\n              in_List.removeOne(object.interfaceTypes, type);\n              break;\n            }\n          }\n\n          // Mark these symbols as forwarded, which is used by the globalization\n          // pass and the JavaScript emitter to ignore this interface\n          for (var i1 = 0, list1 = symbol.functions, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n            var $function = in_List.get(list1, i1);\n\n            if ($function.implementations != null) {\n              $function.forwardTo = in_List.first($function.implementations);\n            }\n          }\n\n          symbol.forwardTo = object;\n        }\n      }\n    }\n  };\n\n  Skew.InterfaceRemovalPass.prototype._scanForInterfaces = function(symbol) {\n    for (var i = 0, list = symbol.objects, count = list.length; i < count; i = i + 1 | 0) {\n      var object = in_List.get(list, i);\n      this._scanForInterfaces(object);\n    }\n\n    if (symbol.kind == Skew.SymbolKind.OBJECT_INTERFACE) {\n      this._interfaces.push(symbol);\n    }\n\n    if (symbol.interfaceTypes != null) {\n      for (var i1 = 0, list1 = symbol.interfaceTypes, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n        var type = in_List.get(list1, i1);\n        var key = type.symbol.id;\n        var implementations = in_IntMap.get(this._interfaceImplementations, key, null);\n\n        if (implementations == null) {\n          implementations = [];\n          in_IntMap.set(this._interfaceImplementations, key, implementations);\n        }\n\n        implementations.push(symbol);\n      }\n    }\n  };\n\n  Skew.RenamingPass = function() {\n    Skew.Pass.call(this);\n  };\n\n  __extends(Skew.RenamingPass, Skew.Pass);\n\n  Skew.RenamingPass.prototype.kind = function() {\n    return Skew.PassKind.RENAMING;\n  };\n\n  Skew.RenamingPass.prototype.run = function(context) {\n    Skew.Renaming.renameGlobal(context.log, context.global);\n  };\n\n  Skew.Renaming = {};\n\n  Skew.Renaming.renameGlobal = function(log, global) {\n    // Collect all functions\n    var functions = [];\n    Skew.Renaming.collectFunctionAndRenameObjectsAndVariables(global, functions);\n\n    // Compute naming groups\n    var labels = new Skew.UnionFind().allocate2(functions.length);\n    var groups = [];\n    var firstScopeForObject = new Map();\n\n    for (var i = 0, count1 = functions.length; i < count1; i = i + 1 | 0) {\n      in_List.get(functions, i).namingGroup = i;\n      groups.push(null);\n    }\n\n    for (var i2 = 0, list1 = functions, count3 = list1.length; i2 < count3; i2 = i2 + 1 | 0) {\n      var $function = in_List.get(list1, i2);\n\n      if ($function.overridden != null) {\n        labels.union($function.namingGroup, $function.overridden.namingGroup);\n      }\n\n      if ($function.implementations != null) {\n        for (var i1 = 0, list = $function.implementations, count2 = list.length; i1 < count2; i1 = i1 + 1 | 0) {\n          var implementation = in_List.get(list, i1);\n          labels.union($function.namingGroup, implementation.namingGroup);\n        }\n      }\n    }\n\n    for (var i3 = 0, list2 = functions, count4 = list2.length; i3 < count4; i3 = i3 + 1 | 0) {\n      var function1 = in_List.get(list2, i3);\n      var label = labels.find(function1.namingGroup);\n      var group = in_List.get(groups, label);\n      function1.namingGroup = label;\n\n      if (group == null) {\n        group = [];\n        in_List.set(groups, label, group);\n      }\n\n      else {\n        assert(function1.name == in_List.first(group).name);\n      }\n\n      group.push(function1);\n\n      // Certain parent objects such as namespaces may have multiple scopes.\n      // However, we want to resolve name collisions in the same scope to detect\n      // collisions across all scopes. Do this by using the first scope.\n      if (!firstScopeForObject.has(function1.parent.id)) {\n        in_IntMap.set(firstScopeForObject, function1.parent.id, function1.scope.parent);\n      }\n    }\n\n    // Rename stuff\n    for (var i7 = 0, list3 = groups, count8 = list3.length; i7 < count8; i7 = i7 + 1 | 0) {\n      var group1 = in_List.get(list3, i7);\n\n      if (group1 == null) {\n        continue;\n      }\n\n      var isImportedOrExported = false;\n      var shouldRename = false;\n      var isInvalid = false;\n      var rename = null;\n\n      for (var i4 = 0, count5 = group1.length; i4 < count5; i4 = i4 + 1 | 0) {\n        var function2 = in_List.get(group1, i4);\n\n        if (function2.isImportedOrExported()) {\n          isImportedOrExported = true;\n        }\n\n        // Make sure there isn't more than one renamed symbol\n        if (function2.rename != null) {\n          if (rename != null && rename != function2.rename) {\n            log.semanticErrorDuplicateRename(function2.range, function2.name, rename, function2.rename);\n          }\n\n          rename = function2.rename;\n        }\n\n        // Rename functions with unusual names and make sure overloaded functions have unique names\n        if (!shouldRename) {\n          if (Skew.Renaming.isInvalidIdentifier(function2.name)) {\n            isInvalid = true;\n            shouldRename = true;\n          }\n\n          else if (function2.overloaded != null && function2.overloaded.symbols.length > 1) {\n            shouldRename = true;\n          }\n        }\n      }\n\n      // Bake in the rename annotation now\n      if (rename != null) {\n        for (var i5 = 0, count6 = group1.length; i5 < count6; i5 = i5 + 1 | 0) {\n          var function3 = in_List.get(group1, i5);\n          function3.flags |= Skew.SymbolFlags.IS_RENAMED;\n          function3.name = rename;\n          function3.rename = null;\n        }\n\n        continue;\n      }\n\n      // One function with a pinned name causes the whole group to avoid renaming\n      if (!shouldRename || isImportedOrExported && !isInvalid) {\n        continue;\n      }\n\n      var first = in_List.first(group1);\n      var $arguments = first.$arguments.length;\n      var count = 0;\n      var start = first.name;\n\n      if (($arguments == 0 || $arguments == 1 && first.kind == Skew.SymbolKind.FUNCTION_GLOBAL) && Skew.Renaming.unaryPrefixes.has(start)) {\n        start = in_StringMap.get1(Skew.Renaming.unaryPrefixes, start);\n      }\n\n      else if (Skew.Renaming.prefixes.has(start)) {\n        start = in_StringMap.get1(Skew.Renaming.prefixes, start);\n      }\n\n      else {\n        if (start.startsWith('@')) {\n          start = in_string.slice1(start, 1);\n        }\n\n        if (Skew.Renaming.isInvalidIdentifier(start)) {\n          start = Skew.Renaming.generateValidIdentifier(start);\n        }\n      }\n\n      // Generate a new name\n      var name = start;\n\n      while (group1.some(function($function) {\n        return in_IntMap.get1(firstScopeForObject, $function.parent.id).isNameUsed(name);\n      })) {\n        count = count + 1 | 0;\n        name = start + count.toString();\n      }\n\n      for (var i6 = 0, count7 = group1.length; i6 < count7; i6 = i6 + 1 | 0) {\n        var function4 = in_List.get(group1, i6);\n        in_IntMap.get1(firstScopeForObject, function4.parent.id).reserveName(name, null);\n        function4.name = name;\n      }\n    }\n  };\n\n  Skew.Renaming.collectFunctionAndRenameObjectsAndVariables = function(symbol, functions) {\n    for (var i = 0, list = symbol.objects, count = list.length; i < count; i = i + 1 | 0) {\n      var object = in_List.get(list, i);\n\n      if (object.rename != null) {\n        object.name = object.rename;\n        object.rename = null;\n      }\n\n      Skew.Renaming.collectFunctionAndRenameObjectsAndVariables(object, functions);\n    }\n\n    for (var i1 = 0, list1 = symbol.functions, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {\n      var $function = in_List.get(list1, i1);\n      functions.push($function);\n    }\n\n    for (var i2 = 0, list2 = symbol.variables, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {\n      var variable = in_List.get(list2, i2);\n\n      if (variable.rename != null) {\n        variable.name = variable.rename;\n        variable.rename = null;\n      }\n    }\n  };\n\n  Skew.Renaming.isAlpha = function(c) {\n    return c >= 97 && c <= 122 || c >= 65 && c <= 90 || c == 95;\n  };\n\n  Skew.Renaming.isNumber = function(c) {\n    return c >= 48 && c <= 57;\n  };\n\n  Skew.Renaming.isInvalidIdentifier = function(name) {\n    for (var i = 0, count = name.length; i < count; i = i + 1 | 0) {\n      var c = in_string.get1(name, i);\n\n      if (!Skew.Renaming.isAlpha(c) && (i == 0 || !Skew.Renaming.isNumber(c))) {\n        return true;\n      }\n    }\n\n    return false;\n  };\n\n  Skew.Renaming.generateValidIdentifier = function(name) {\n    var text = '';\n\n    for (var i = 0, count = name.length; i < count; i = i + 1 | 0) {\n      var c = in_string.get1(name, i);\n\n      if (Skew.Renaming.isAlpha(c) || Skew.Renaming.isNumber(c)) {\n        text += in_string.get(name, i);\n      }\n    }\n\n    if (text != '' && name.endsWith('=')) {\n      return 'set' + Skew.withUppercaseFirstLetter(text);\n    }\n\n    return text == '' || !Skew.Renaming.isAlpha(in_string.get1(text, 0)) ? '_' + text : text;\n  };\n\n  Skew.ScopeKind = {\n    FUNCTION: 0,\n    LOCAL: 1,\n    OBJECT: 2,\n    VARIABLE: 3\n  };\n\n  Skew.ScopeSearch = {\n    NORMAL: 0,\n    ALSO_CHECK_FOR_SETTER: 1\n  };\n\n  Skew.FuzzyScopeSearch = {\n    SELF_ONLY: 0,\n    SELF_AND_PARENTS: 1\n  };\n\n  Skew.Scope = function(parent) {\n    this.parent = parent;\n    this.used = null;\n    this._enclosingFunctionOrLambda = null;\n    this._enclosingFunction = null;\n    this._enclosingLoop = null;\n  };\n\n  Skew.Scope.prototype._find = function(name) {\n    return null;\n  };\n\n  Skew.Scope.prototype._findWithFuzzyMatching = function(matcher) {\n  };\n\n  // Need to check for a setter at the same time as for a normal symbol\n  // because the one in the closer scope must be picked. If both are in\n  // the same scope, pick the setter.\n  Skew.Scope.prototype.find = function(name, search) {\n    var symbol = null;\n    var setterName = search == Skew.ScopeSearch.ALSO_CHECK_FOR_SETTER ? name + '=' : null;\n\n    for (var scope = this; scope != null && symbol == null; scope = scope.parent) {\n      if (setterName != null) {\n        symbol = scope._find(setterName);\n      }\n\n      if (symbol == null) {\n        symbol = scope._find(name);\n      }\n    }\n\n    return symbol;\n  };\n\n  Skew.Scope.prototype.findWithFuzzyMatching = function(name, kind, search) {\n    var matcher = new Skew.FuzzySymbolMatcher(name, kind);\n\n    for (var scope = this; scope != null; scope = scope.parent) {\n      scope._findWithFuzzyMatching(matcher);\n\n      if (search == Skew.FuzzyScopeSearch.SELF_ONLY) {\n        break;\n      }\n    }\n\n    return matcher.bestSoFar();\n  };\n\n  Skew.Scope.prototype.asObjectScope = function() {\n    assert(this.kind() == Skew.ScopeKind.OBJECT);\n    return this;\n  };\n\n  Skew.Scope.prototype.asFunctionScope = function() {\n    assert(this.kind() == Skew.ScopeKind.FUNCTION);\n    return this;\n  };\n\n  Skew.Scope.prototype.asVariableScope = function() {\n    assert(this.kind() == Skew.ScopeKind.VARIABLE);\n    return this;\n  };\n\n  Skew.Scope.prototype.asLocalScope = function() {\n    assert(this.kind() == Skew.ScopeKind.LOCAL);\n    return this;\n  };\n\n  Skew.Scope.prototype.findEnclosingFunctionOrLambda = function() {\n    if (this._enclosingFunctionOrLambda != null) {\n      return this._enclosingFunctionOrLambda;\n    }\n\n    var scope = this;\n\n    while (scope != null) {\n      if (scope.kind() == Skew.ScopeKind.FUNCTION) {\n        this._enclosingFunctionOrLambda = scope.asFunctionScope();\n        return this._enclosingFunctionOrLambda;\n      }\n\n      scope = scope.parent;\n    }\n\n    return null;\n  };\n\n  Skew.Scope.prototype.findEnclosingFunction = function() {\n    if (this._enclosingFunction != null) {\n      return this._enclosingFunction;\n    }\n\n    var scope = this.findEnclosingFunctionOrLambda();\n\n    while (scope != null) {\n      if (scope.kind() == Skew.ScopeKind.FUNCTION && scope.asFunctionScope().symbol.kind != Skew.SymbolKind.FUNCTION_LOCAL) {\n        this._enclosingFunction = scope.asFunctionScope();\n        return this._enclosingFunction;\n      }\n\n      scope = scope.parent;\n    }\n\n    return null;\n  };\n\n  Skew.Scope.prototype.findEnclosingLoop = function() {\n    if (this._enclosingLoop != null) {\n      return this._enclosingLoop;\n    }\n\n    var scope = this;\n\n    while (scope != null && scope.kind() == Skew.ScopeKind.LOCAL) {\n      if (scope.asLocalScope().type == Skew.LocalType.LOOP) {\n        this._enclosingLoop = scope.asLocalScope();\n        return this._enclosingLoop;\n      }\n\n      scope = scope.parent;\n    }\n\n    return null;\n  };\n\n  Skew.Scope.prototype.generateName = function(prefix) {\n    var count = 0;\n    var name = prefix;\n\n    while (this.isNameUsed(name)) {\n      name = prefix + (count = count + 1 | 0).toString();\n    }\n\n    this.reserveName(name, null);\n    return name;\n  };\n\n  Skew.Scope.prototype.reserveName = function(name, symbol) {\n    if (this.used == null) {\n      this.used = new Map();\n    }\n\n    if (!this.used.has(name)) {\n      in_StringMap.set(this.used, name, symbol);\n    }\n  };\n\n  Skew.Scope.prototype.isNameUsed = function(name) {\n    if (this.find(name, Skew.ScopeSearch.NORMAL) != null) {\n      return true;\n    }\n\n    for (var scope = this; scope != null; scope = scope.parent) {\n      if (scope.used != null && scope.used.has(name)) {\n        return true;\n      }\n    }\n\n    return false;\n  };\n\n  Skew.ObjectScope = function(parent, symbol) {\n    Skew.Scope.call(this, parent);\n    this.symbol = symbol;\n  };\n\n  __extends(Skew.ObjectScope, Skew.Scope);\n\n  Skew.ObjectScope.prototype.kind = function() {\n    return Skew.ScopeKind.OBJECT;\n  };\n\n  Skew.ObjectScope.prototype._find = function(name) {\n    return in_StringMap.get(this.symbol.members, name, null);\n  };\n\n  Skew.ObjectScope.prototype._findWithFuzzyMatching = function(matcher) {\n    in_StringMap.each(this.symbol.members, function(name, member) {\n      matcher.include(member);\n    });\n  };\n\n  Skew.FunctionScope = function(parent, symbol) {\n    Skew.Scope.call(this, parent);\n    this.symbol = symbol;\n    this.parameters = new Map();\n  };\n\n  __extends(Skew.FunctionScope, Skew.Scope);\n\n  Skew.FunctionScope.prototype.kind = function() {\n    return Skew.ScopeKind.FUNCTION;\n  };\n\n  Skew.FunctionScope.prototype._find = function(name) {\n    return in_StringMap.get(this.parameters, name, null);\n  };\n\n  Skew.FunctionScope.prototype._findWithFuzzyMatching = function(matcher) {\n    in_StringMap.each(this.parameters, function(name, parameter) {\n      matcher.include(parameter);\n    });\n  };\n\n  Skew.VariableScope = function(parent, symbol) {\n    Skew.Scope.call(this, parent);\n    this.symbol = symbol;\n  };\n\n  __extends(Skew.VariableScope, Skew.Scope);\n\n  Skew.VariableScope.prototype.kind = function() {\n    return Skew.ScopeKind.VARIABLE;\n  };\n\n  Skew.LocalType = {\n    LOOP: 0,\n    NORMAL: 1\n  };\n\n  Skew.LocalScope = function(parent, type) {\n    Skew.Scope.call(this, parent);\n    this.locals = new Map();\n    this.type = type;\n  };\n\n  __extends(Skew.LocalScope, Skew.Scope);\n\n  Skew.LocalScope.prototype.kind = function() {\n    return Skew.ScopeKind.LOCAL;\n  };\n\n  Skew.LocalScope.prototype._find = function(name) {\n    return in_StringMap.get(this.locals, name, null);\n  };\n\n  Skew.LocalScope.prototype._findWithFuzzyMatching = function(matcher) {\n    in_StringMap.each(this.locals, function(name, local) {\n      matcher.include(local);\n    });\n  };\n\n  Skew.LocalScope.prototype.define = function(symbol, log) {\n    symbol.scope = this;\n\n    // Check for duplicates\n    var other = in_StringMap.get(this.locals, symbol.name, null);\n\n    if (other != null) {\n      log.semanticErrorDuplicateSymbol(symbol.range, symbol.name, other.range);\n      return;\n    }\n\n    // Check for shadowing\n    var scope = this.parent;\n\n    while (scope.kind() == Skew.ScopeKind.LOCAL) {\n      var local = in_StringMap.get(scope.asLocalScope().locals, symbol.name, null);\n\n      if (local != null) {\n        log.semanticErrorShadowedSymbol(symbol.range, symbol.name, local.range);\n        return;\n      }\n\n      scope = scope.parent;\n    }\n\n    scope.reserveName(symbol.name, symbol);\n    in_StringMap.set(this.locals, symbol.name, symbol);\n  };\n\n  // This does a simple control flow analysis without constructing a full\n  // control flow graph. The result of this analysis is setting the flag\n  // HAS_CONTROL_FLOW_AT_END on all blocks where control flow reaches the end.\n  //\n  // It makes a few assumptions around exceptions to make life easier. Normal\n  // code without throw statements is assumed not to throw. For example, all\n  // property accesses are assumed to succeed and not throw null pointer errors.\n  // This is mostly consistent with how C++ operates for better or worse, and\n  // is also consistent with how people read code. It also assumes flow always\n  // can enter every catch block. Otherwise, why is it there?\n  Skew.ControlFlowAnalyzer = function() {\n    this._isLoopBreakTarget = [];\n    this._isControlFlowLive = [];\n  };\n\n  Skew.ControlFlowAnalyzer.prototype.pushBlock = function(node) {\n    var parent = node.parent();\n\n    // Push control flow\n    this._isControlFlowLive.push(this._isControlFlowLive.length == 0 || in_List.last(this._isControlFlowLive));\n\n    // Push loop info\n    if (parent != null && Skew.in_NodeKind.isLoop(parent.kind)) {\n      this._isLoopBreakTarget.push(false);\n    }\n  };\n\n  Skew.ControlFlowAnalyzer.prototype.popBlock = function(node) {\n    var parent = node.parent();\n\n    // Pop control flow\n    var isLive = in_List.takeLast(this._isControlFlowLive);\n\n    if (isLive) {\n      node.flags |= Skew.NodeFlags.HAS_CONTROL_FLOW_AT_END;\n    }\n\n    // Pop loop info\n    if (parent != null && Skew.in_NodeKind.isLoop(parent.kind) && !in_List.takeLast(this._isLoopBreakTarget) && (parent.kind == Skew.NodeKind.WHILE && parent.whileTest().isTrue() || parent.kind == Skew.NodeKind.FOR && parent.forTest().isTrue())) {\n      in_List.setLast(this._isControlFlowLive, false);\n    }\n  };\n\n  Skew.ControlFlowAnalyzer.prototype.visitStatementInPostOrder = function(node) {\n    if (!in_List.last(this._isControlFlowLive)) {\n      return;\n    }\n\n    switch (node.kind) {\n      case Skew.NodeKind.BREAK: {\n        if (!(this._isLoopBreakTarget.length == 0)) {\n          in_List.setLast(this._isLoopBreakTarget, true);\n        }\n\n        in_List.setLast(this._isControlFlowLive, false);\n        break;\n      }\n\n      case Skew.NodeKind.RETURN:\n      case Skew.NodeKind.THROW:\n      case Skew.NodeKind.CONTINUE: {\n        in_List.setLast(this._isControlFlowLive, false);\n        break;\n      }\n\n      case Skew.NodeKind.IF: {\n        var test = node.ifTest();\n        var trueBlock = node.ifTrue();\n        var falseBlock = node.ifFalse();\n\n        if (test.isTrue()) {\n          if (!trueBlock.hasControlFlowAtEnd()) {\n            in_List.setLast(this._isControlFlowLive, false);\n          }\n        }\n\n        else if (test.isFalse() && falseBlock != null) {\n          if (!falseBlock.hasControlFlowAtEnd()) {\n            in_List.setLast(this._isControlFlowLive, false);\n          }\n        }\n\n        else if (trueBlock != null && falseBlock != null) {\n          if (!trueBlock.hasControlFlowAtEnd() && !falseBlock.hasControlFlowAtEnd()) {\n            in_List.setLast(this._isControlFlowLive, false);\n          }\n        }\n        break;\n      }\n\n      case Skew.NodeKind.SWITCH: {\n        var child = node.switchValue().nextSibling();\n        var foundDefaultCase = false;\n\n        while (child != null && !child.caseBlock().hasControlFlowAtEnd()) {\n          if (child.hasOneChild()) {\n            foundDefaultCase = true;\n          }\n\n          child = child.nextSibling();\n        }\n\n        if (child == null && foundDefaultCase) {\n          in_List.setLast(this._isControlFlowLive, false);\n        }\n        break;\n      }\n    }\n  };\n\n  Skew.in_PassKind = {};\n  Skew.in_SymbolKind = {};\n\n  Skew.in_SymbolKind.isType = function(self) {\n    return self >= Skew.SymbolKind.PARAMETER_FUNCTION && self <= Skew.SymbolKind.OBJECT_WRAPPED;\n  };\n\n  Skew.in_SymbolKind.isParameter = function(self) {\n    return self >= Skew.SymbolKind.PARAMETER_FUNCTION && self <= Skew.SymbolKind.PARAMETER_OBJECT;\n  };\n\n  Skew.in_SymbolKind.isObject = function(self) {\n    return self >= Skew.SymbolKind.OBJECT_CLASS && self <= Skew.SymbolKind.OBJECT_WRAPPED;\n  };\n\n  Skew.in_SymbolKind.isEnumOrFlags = function(self) {\n    return self == Skew.SymbolKind.OBJECT_ENUM || self == Skew.SymbolKind.OBJECT_FLAGS;\n  };\n\n  Skew.in_SymbolKind.isFunction = function(self) {\n    return self >= Skew.SymbolKind.FUNCTION_ANNOTATION && self <= Skew.SymbolKind.FUNCTION_LOCAL;\n  };\n\n  Skew.in_SymbolKind.isOverloadedFunction = function(self) {\n    return self >= Skew.SymbolKind.OVERLOADED_ANNOTATION && self <= Skew.SymbolKind.OVERLOADED_INSTANCE;\n  };\n\n  Skew.in_SymbolKind.isFunctionOrOverloadedFunction = function(self) {\n    return self >= Skew.SymbolKind.FUNCTION_ANNOTATION && self <= Skew.SymbolKind.OVERLOADED_INSTANCE;\n  };\n\n  Skew.in_SymbolKind.isVariable = function(self) {\n    return self >= Skew.SymbolKind.VARIABLE_ARGUMENT && self <= Skew.SymbolKind.VARIABLE_LOCAL;\n  };\n\n  Skew.in_SymbolKind.isLocalOrArgumentVariable = function(self) {\n    return self == Skew.SymbolKind.VARIABLE_ARGUMENT || self == Skew.SymbolKind.VARIABLE_LOCAL;\n  };\n\n  Skew.in_SymbolKind.isNamespaceOrGlobal = function(self) {\n    return self == Skew.SymbolKind.OBJECT_NAMESPACE || self == Skew.SymbolKind.OBJECT_GLOBAL;\n  };\n\n  Skew.in_SymbolKind.isGlobalReference = function(self) {\n    return self == Skew.SymbolKind.VARIABLE_ENUM_OR_FLAGS || self == Skew.SymbolKind.VARIABLE_GLOBAL || self == Skew.SymbolKind.FUNCTION_GLOBAL || self == Skew.SymbolKind.FUNCTION_CONSTRUCTOR || self == Skew.SymbolKind.OVERLOADED_GLOBAL || Skew.in_SymbolKind.isType(self);\n  };\n\n  Skew.in_SymbolKind.hasInstances = function(self) {\n    return self == Skew.SymbolKind.OBJECT_CLASS || self == Skew.SymbolKind.OBJECT_ENUM || self == Skew.SymbolKind.OBJECT_FLAGS || self == Skew.SymbolKind.OBJECT_INTERFACE || self == Skew.SymbolKind.OBJECT_WRAPPED;\n  };\n\n  Skew.in_SymbolKind.isOnInstances = function(self) {\n    return self == Skew.SymbolKind.FUNCTION_INSTANCE || self == Skew.SymbolKind.VARIABLE_INSTANCE || self == Skew.SymbolKind.OVERLOADED_INSTANCE;\n  };\n\n  Skew.in_SymbolKind.isLocal = function(self) {\n    return self == Skew.SymbolKind.FUNCTION_LOCAL || self == Skew.SymbolKind.VARIABLE_LOCAL || self == Skew.SymbolKind.VARIABLE_ARGUMENT;\n  };\n\n  Skew.in_Content = {};\n\n  Skew.in_Content.asBool = function(self) {\n    assert(self.kind() == Skew.ContentKind.BOOL);\n    return self.value;\n  };\n\n  Skew.in_Content.asInt = function(self) {\n    assert(self.kind() == Skew.ContentKind.INT);\n    return self.value;\n  };\n\n  Skew.in_Content.asDouble = function(self) {\n    assert(self.kind() == Skew.ContentKind.DOUBLE);\n    return self.value;\n  };\n\n  Skew.in_Content.asString = function(self) {\n    assert(self.kind() == Skew.ContentKind.STRING);\n    return self.value;\n  };\n\n  Skew.in_Content.equals = function(self, other) {\n    if (self.kind() == other.kind()) {\n      switch (self.kind()) {\n        case Skew.ContentKind.BOOL: {\n          return Skew.in_Content.asBool(self) == Skew.in_Content.asBool(other);\n        }\n\n        case Skew.ContentKind.INT: {\n          return Skew.in_Content.asInt(self) == Skew.in_Content.asInt(other);\n        }\n\n        case Skew.ContentKind.DOUBLE: {\n          return Skew.in_Content.asDouble(self) == Skew.in_Content.asDouble(other);\n        }\n\n        case Skew.ContentKind.STRING: {\n          return Skew.in_Content.asString(self) == Skew.in_Content.asString(other);\n        }\n      }\n    }\n\n    return false;\n  };\n\n  Skew.in_NodeKind = {};\n\n  Skew.in_NodeKind.isBitOperation = function(self) {\n    return self == Skew.NodeKind.COMPLEMENT || self >= Skew.NodeKind.BITWISE_AND && self <= Skew.NodeKind.BITWISE_XOR || self >= Skew.NodeKind.ASSIGN_BITWISE_AND && self <= Skew.NodeKind.ASSIGN_BITWISE_XOR;\n  };\n\n  Skew.in_NodeKind.isLoop = function(self) {\n    return self == Skew.NodeKind.FOR || self == Skew.NodeKind.FOREACH || self == Skew.NodeKind.WHILE;\n  };\n\n  Skew.in_NodeKind.isExpression = function(self) {\n    return self >= Skew.NodeKind.ASSIGN_INDEX && self <= Skew.NodeKind.ASSIGN_UNSIGNED_SHIFT_RIGHT;\n  };\n\n  Skew.in_NodeKind.isInitializer = function(self) {\n    return self == Skew.NodeKind.INITIALIZER_LIST || self == Skew.NodeKind.INITIALIZER_MAP;\n  };\n\n  Skew.in_NodeKind.isUnary = function(self) {\n    return self >= Skew.NodeKind.COMPLEMENT && self <= Skew.NodeKind.PREFIX_INCREMENT;\n  };\n\n  Skew.in_NodeKind.isUnaryAssign = function(self) {\n    return self >= Skew.NodeKind.POSTFIX_DECREMENT && self <= Skew.NodeKind.PREFIX_INCREMENT;\n  };\n\n  Skew.in_NodeKind.isUnaryPostfix = function(self) {\n    return self == Skew.NodeKind.POSTFIX_DECREMENT || self == Skew.NodeKind.POSTFIX_INCREMENT;\n  };\n\n  Skew.in_NodeKind.isBinary = function(self) {\n    return self >= Skew.NodeKind.ADD && self <= Skew.NodeKind.ASSIGN_UNSIGNED_SHIFT_RIGHT;\n  };\n\n  Skew.in_NodeKind.isBinaryAssign = function(self) {\n    return self >= Skew.NodeKind.ASSIGN && self <= Skew.NodeKind.ASSIGN_UNSIGNED_SHIFT_RIGHT;\n  };\n\n  // Note that add and multiply are NOT associative in finite-precision arithmetic\n  Skew.in_NodeKind.isBinaryAssociative = function(self) {\n    switch (self) {\n      case Skew.NodeKind.BITWISE_AND:\n      case Skew.NodeKind.BITWISE_OR:\n      case Skew.NodeKind.BITWISE_XOR:\n      case Skew.NodeKind.LOGICAL_AND:\n      case Skew.NodeKind.LOGICAL_OR: {\n        return true;\n      }\n    }\n\n    return false;\n  };\n\n  Skew.in_NodeKind.isBinaryComparison = function(self) {\n    return self >= Skew.NodeKind.GREATER_THAN && self <= Skew.NodeKind.LESS_THAN_OR_EQUAL;\n  };\n\n  Skew.in_NodeKind.isShift = function(self) {\n    return self == Skew.NodeKind.SHIFT_LEFT || self == Skew.NodeKind.SHIFT_RIGHT || self == Skew.NodeKind.UNSIGNED_SHIFT_RIGHT;\n  };\n\n  Skew.in_NodeKind.isJump = function(self) {\n    return self == Skew.NodeKind.BREAK || self == Skew.NodeKind.CONTINUE || self == Skew.NodeKind.RETURN;\n  };\n\n  Skew.in_NodeKind.isAssign = function(self) {\n    return Skew.in_NodeKind.isUnaryAssign(self) || Skew.in_NodeKind.isBinaryAssign(self) || self == Skew.NodeKind.ASSIGN_INDEX;\n  };\n\n  Skew.in_TokenKind = {};\n\n  Skew.in_TokenKind.toString = function(self) {\n    assert(Skew.in_TokenKind._toString.has(self));\n    return in_IntMap.get1(Skew.in_TokenKind._toString, self);\n  };\n\n  var Terminal = {};\n\n  Terminal.setColor = function(color) {\n    if (process.stdout.isTTY) {\n      process.stdout.write('\\x1B[0;' + in_IntMap.get1(Terminal.colorToEscapeCode, color).toString() + 'm');\n    }\n  };\n\n  Terminal.Color = {\n    DEFAULT: 0,\n    BOLD: 1,\n    GRAY: 2,\n    RED: 3,\n    GREEN: 4,\n    YELLOW: 5,\n    BLUE: 6,\n    MAGENTA: 7,\n    CYAN: 8\n  };\n\n  var IO = {};\n\n  IO.isDirectory = function(path) {\n    try {\n      return require('fs').statSync(path).isDirectory();\n    }\n\n    catch (e) {\n    }\n\n    return false;\n  };\n\n  IO.readDirectory = function(path) {\n    try {\n      var entries = require('fs').readdirSync(path);\n      entries.sort(function(a, b) {\n        return in_string.compare(a, b);\n      });\n      return entries;\n    }\n\n    catch (e) {\n    }\n\n    return null;\n  };\n\n  IO.readFile = function(path) {\n    try {\n      var contents = require('fs').readFileSync(path, 'utf8');\n      return contents.split('\\r\\n').join('\\n');\n    }\n\n    catch (e) {\n    }\n\n    return null;\n  };\n\n  IO.writeFile = function(path, contents) {\n    var fs = require('fs');\n    var p = require('path');\n    var mkdir_p = null;\n    mkdir_p = function(dir) {\n      if (dir !== p.dirname(dir)) {\n        mkdir_p(p.dirname(dir));\n\n        try {\n          fs.mkdirSync(dir);\n        }\n\n        catch (e) {\n        }\n      }\n    };\n    mkdir_p(p.dirname(path));\n\n    try {\n      fs.writeFileSync(path, contents);\n      return true;\n    }\n\n    catch (e) {\n    }\n\n    return false;\n  };\n\n  var in_List = {};\n\n  in_List.get = function(self, index) {\n    assert(0 <= index && index < self.length);\n    return self[index];\n  };\n\n  in_List.set = function(self, index, value) {\n    assert(0 <= index && index < self.length);\n    return self[index] = value;\n  };\n\n  in_List.setLast = function(self, x) {\n    return in_List.set(self, self.length - 1 | 0, x);\n  };\n\n  in_List.removeLast = function(self) {\n    assert(!(self.length == 0));\n    self.pop();\n  };\n\n  in_List.swap = function(self, i, j) {\n    assert(0 <= i && i < self.length);\n    assert(0 <= j && j < self.length);\n    var temp = in_List.get(self, i);\n    in_List.set(self, i, in_List.get(self, j));\n    in_List.set(self, j, temp);\n  };\n\n  in_List.last = function(self) {\n    assert(!(self.length == 0));\n    return in_List.get(self, self.length - 1 | 0);\n  };\n\n  in_List.prepend1 = function(self, values) {\n    assert(values != self);\n    var count = values.length;\n\n    for (var i = 0, count1 = count; i < count1; i = i + 1 | 0) {\n      self.unshift(in_List.get(values, (count - i | 0) - 1 | 0));\n    }\n  };\n\n  in_List.append1 = function(self, values) {\n    assert(values != self);\n\n    for (var i = 0, list = values, count1 = list.length; i < count1; i = i + 1 | 0) {\n      var value = in_List.get(list, i);\n      self.push(value);\n    }\n  };\n\n  in_List.insert1 = function(self, index, values) {\n    assert(values != self);\n\n    for (var i = 0, list = values, count1 = list.length; i < count1; i = i + 1 | 0) {\n      var value = in_List.get(list, i);\n      in_List.insert2(self, index, value);\n      index = index + 1 | 0;\n    }\n  };\n\n  in_List.insert2 = function(self, index, value) {\n    assert(0 <= index && index <= self.length);\n    self.splice(index, 0, value);\n  };\n\n  in_List.removeFirst = function(self) {\n    assert(!(self.length == 0));\n    self.shift();\n  };\n\n  in_List.removeAt = function(self, index) {\n    assert(0 <= index && index < self.length);\n    self.splice(index, 1);\n  };\n\n  in_List.appendOne = function(self, value) {\n    if (!(self.indexOf(value) != -1)) {\n      self.push(value);\n    }\n  };\n\n  in_List.removeOne = function(self, value) {\n    var index = self.indexOf(value);\n\n    if (index >= 0) {\n      in_List.removeAt(self, index);\n    }\n  };\n\n  in_List.removeIf = function(self, callback) {\n    var index = 0;\n\n    // Remove elements in place\n    for (var i = 0, count1 = self.length; i < count1; i = i + 1 | 0) {\n      if (!callback(in_List.get(self, i))) {\n        if (index < i) {\n          in_List.set(self, index, in_List.get(self, i));\n        }\n\n        index = index + 1 | 0;\n      }\n    }\n\n    // Shrink the array to the correct size\n    while (index < self.length) {\n      in_List.removeLast(self);\n    }\n  };\n\n  in_List.equals = function(self, other) {\n    if (self.length != other.length) {\n      return false;\n    }\n\n    for (var i = 0, count1 = self.length; i < count1; i = i + 1 | 0) {\n      if (in_List.get(self, i) != in_List.get(other, i)) {\n        return false;\n      }\n    }\n\n    return true;\n  };\n\n  in_List.slice1 = function(self, start) {\n    assert(0 <= start && start <= self.length);\n    return self.slice(start);\n  };\n\n  in_List.slice2 = function(self, start, end) {\n    assert(0 <= start && start <= end && end <= self.length);\n    return self.slice(start, end);\n  };\n\n  in_List.first = function(self) {\n    assert(!(self.length == 0));\n    return in_List.get(self, 0);\n  };\n\n  in_List.takeLast = function(self) {\n    assert(!(self.length == 0));\n    return self.pop();\n  };\n\n  var in_StringMap = {};\n\n  in_StringMap.set = function(self, key, value) {\n    self.set(key, value);\n    return value;\n  };\n\n  in_StringMap.insert = function(self, key, value) {\n    self.set(key, value);\n    return self;\n  };\n\n  in_StringMap.get = function(self, key, defaultValue) {\n    var value = self.get(key);\n\n    // Compare against undefined so the key is only hashed once for speed\n    return value !== void 0 ? value : defaultValue;\n  };\n\n  in_StringMap.each = function(self, x) {\n    self.forEach(function(value, key) {\n      x(key, value);\n    });\n  };\n\n  in_StringMap.get1 = function(self, key) {\n    assert(self.has(key));\n    return self.get(key);\n  };\n\n  var in_IntMap = {};\n\n  in_IntMap.set = function(self, key, value) {\n    self.set(key, value);\n    return value;\n  };\n\n  in_IntMap.insert = function(self, key, value) {\n    self.set(key, value);\n    return self;\n  };\n\n  in_IntMap.get = function(self, key, defaultValue) {\n    var value = self.get(key);\n\n    // Compare against undefined so the key is only hashed once for speed\n    return value !== void 0 ? value : defaultValue;\n  };\n\n  in_IntMap.get1 = function(self, key) {\n    assert(self.has(key));\n    return self.get(key);\n  };\n\n  var in_int = {};\n\n  in_int.power = function(self, x) {\n    var y = self;\n    var z = x < 0 ? 0 : 1;\n\n    while (x > 0) {\n      if ((x & 1) != 0) {\n        z = __imul(z, y);\n      }\n\n      x >>= 1;\n      y = __imul(y, y);\n    }\n\n    return z;\n  };\n\n  in_int.compare = function(self, x) {\n    return (x < self | 0) - (x > self | 0) | 0;\n  };\n\n  var in_string = {};\n\n  in_string.fromCodePoints = function(codePoints) {\n    var builder = new StringBuilder();\n\n    for (var i = 0, list = codePoints, count1 = list.length; i < count1; i = i + 1 | 0) {\n      var codePoint = in_List.get(list, i);\n      builder.buffer += in_string.fromCodePoint(codePoint);\n    }\n\n    return builder.buffer;\n  };\n\n  in_string.compare = function(self, x) {\n    return (x < self | 0) - (x > self | 0) | 0;\n  };\n\n  in_string.repeat = function(self, times) {\n    var result = '';\n\n    for (var i = 0, count1 = times; i < count1; i = i + 1 | 0) {\n      result += self;\n    }\n\n    return result;\n  };\n\n  in_string.codePoints = function(self) {\n    var codePoints = [];\n    var instance = Unicode.StringIterator.INSTANCE;\n    instance.reset(self, 0);\n\n    while (true) {\n      var codePoint = instance.nextCodePoint();\n\n      if (codePoint < 0) {\n        return codePoints;\n      }\n\n      codePoints.push(codePoint);\n    }\n  };\n\n  in_string.slice1 = function(self, start) {\n    assert(0 <= start && start <= self.length);\n    return self.slice(start);\n  };\n\n  in_string.slice2 = function(self, start, end) {\n    assert(0 <= start && start <= end && end <= self.length);\n    return self.slice(start, end);\n  };\n\n  in_string.get1 = function(self, index) {\n    assert(0 <= index && index < self.length);\n    return self.charCodeAt(index);\n  };\n\n  in_string.get = function(self, index) {\n    assert(0 <= index && index < self.length);\n    return self[index];\n  };\n\n  in_string.fromCodePoint = function(codePoint) {\n    return codePoint < 65536 ? String.fromCharCode(codePoint) : String.fromCharCode((codePoint - 65536 >> 10) + 55296 | 0) + String.fromCharCode((codePoint - 65536 & (1 << 10) - 1) + 56320 | 0);\n  };\n\n  var TARGET = Target.JAVASCRIPT;\n  Unicode.StringIterator.INSTANCE = new Unicode.StringIterator();\n  Skew.HEX = '0123456789ABCDEF';\n  Skew.BASE64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n  Skew.operatorInfo = in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(new Map(), Skew.NodeKind.COMPLEMENT, new Skew.OperatorInfo('~', Skew.Precedence.UNARY_PREFIX, Skew.Associativity.NONE, Skew.OperatorKind.OVERRIDABLE, [0], Skew.NodeKind.NULL)), Skew.NodeKind.NEGATIVE, new Skew.OperatorInfo('-', Skew.Precedence.UNARY_PREFIX, Skew.Associativity.NONE, Skew.OperatorKind.OVERRIDABLE, [0, 1], Skew.NodeKind.NULL)), Skew.NodeKind.NOT, new Skew.OperatorInfo('!', Skew.Precedence.UNARY_PREFIX, Skew.Associativity.NONE, Skew.OperatorKind.OVERRIDABLE, [0], Skew.NodeKind.NULL)), Skew.NodeKind.POSITIVE, new Skew.OperatorInfo('+', Skew.Precedence.UNARY_PREFIX, Skew.Associativity.NONE, Skew.OperatorKind.OVERRIDABLE, [0, 1], Skew.NodeKind.NULL)), Skew.NodeKind.POSTFIX_DECREMENT, new Skew.OperatorInfo('--', Skew.Precedence.UNARY_POSTFIX, Skew.Associativity.NONE, Skew.OperatorKind.OVERRIDABLE, [0], Skew.NodeKind.SUBTRACT)), Skew.NodeKind.POSTFIX_INCREMENT, new Skew.OperatorInfo('++', Skew.Precedence.UNARY_POSTFIX, Skew.Associativity.NONE, Skew.OperatorKind.OVERRIDABLE, [0], Skew.NodeKind.ADD)), Skew.NodeKind.PREFIX_DECREMENT, new Skew.OperatorInfo('--', Skew.Precedence.UNARY_PREFIX, Skew.Associativity.NONE, Skew.OperatorKind.OVERRIDABLE, [0], Skew.NodeKind.SUBTRACT)), Skew.NodeKind.PREFIX_INCREMENT, new Skew.OperatorInfo('++', Skew.Precedence.UNARY_PREFIX, Skew.Associativity.NONE, Skew.OperatorKind.OVERRIDABLE, [0], Skew.NodeKind.ADD)), Skew.NodeKind.ADD, new Skew.OperatorInfo('+', Skew.Precedence.ADD, Skew.Associativity.LEFT, Skew.OperatorKind.OVERRIDABLE, [0, 1], Skew.NodeKind.NULL)), Skew.NodeKind.BITWISE_AND, new Skew.OperatorInfo('&', Skew.Precedence.BITWISE_AND, Skew.Associativity.LEFT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.NULL)), Skew.NodeKind.BITWISE_OR, new Skew.OperatorInfo('|', Skew.Precedence.BITWISE_OR, Skew.Associativity.LEFT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.NULL)), Skew.NodeKind.BITWISE_XOR, new Skew.OperatorInfo('^', Skew.Precedence.BITWISE_XOR, Skew.Associativity.LEFT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.NULL)), Skew.NodeKind.COMPARE, new Skew.OperatorInfo('<=>', Skew.Precedence.COMPARE, Skew.Associativity.LEFT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.NULL)), Skew.NodeKind.DIVIDE, new Skew.OperatorInfo('/', Skew.Precedence.MULTIPLY, Skew.Associativity.LEFT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.NULL)), Skew.NodeKind.EQUAL, new Skew.OperatorInfo('==', Skew.Precedence.EQUAL, Skew.Associativity.LEFT, Skew.OperatorKind.FIXED, [1], Skew.NodeKind.NULL)), Skew.NodeKind.GREATER_THAN, new Skew.OperatorInfo('>', Skew.Precedence.COMPARE, Skew.Associativity.LEFT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.NULL)), Skew.NodeKind.GREATER_THAN_OR_EQUAL, new Skew.OperatorInfo('>=', Skew.Precedence.COMPARE, Skew.Associativity.LEFT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.NULL)), Skew.NodeKind.IN, new Skew.OperatorInfo('in', Skew.Precedence.COMPARE, Skew.Associativity.LEFT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.NULL)), Skew.NodeKind.LESS_THAN, new Skew.OperatorInfo('<', Skew.Precedence.COMPARE, Skew.Associativity.LEFT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.NULL)), Skew.NodeKind.LESS_THAN_OR_EQUAL, new Skew.OperatorInfo('<=', Skew.Precedence.COMPARE, Skew.Associativity.LEFT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.NULL)), Skew.NodeKind.LOGICAL_AND, new Skew.OperatorInfo('&&', Skew.Precedence.LOGICAL_AND, Skew.Associativity.LEFT, Skew.OperatorKind.FIXED, [1], Skew.NodeKind.NULL)), Skew.NodeKind.LOGICAL_OR, new Skew.OperatorInfo('||', Skew.Precedence.LOGICAL_OR, Skew.Associativity.LEFT, Skew.OperatorKind.FIXED, [1], Skew.NodeKind.NULL)), Skew.NodeKind.MODULUS, new Skew.OperatorInfo('%%', Skew.Precedence.MULTIPLY, Skew.Associativity.LEFT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.NULL)), Skew.NodeKind.MULTIPLY, new Skew.OperatorInfo('*', Skew.Precedence.MULTIPLY, Skew.Associativity.LEFT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.NULL)), Skew.NodeKind.NOT_EQUAL, new Skew.OperatorInfo('!=', Skew.Precedence.EQUAL, Skew.Associativity.LEFT, Skew.OperatorKind.FIXED, [1], Skew.NodeKind.NULL)), Skew.NodeKind.POWER, new Skew.OperatorInfo('**', Skew.Precedence.UNARY_PREFIX, Skew.Associativity.RIGHT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.NULL)), Skew.NodeKind.REMAINDER, new Skew.OperatorInfo('%', Skew.Precedence.MULTIPLY, Skew.Associativity.LEFT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.NULL)), Skew.NodeKind.SHIFT_LEFT, new Skew.OperatorInfo('<<', Skew.Precedence.SHIFT, Skew.Associativity.LEFT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.NULL)), Skew.NodeKind.SHIFT_RIGHT, new Skew.OperatorInfo('>>', Skew.Precedence.SHIFT, Skew.Associativity.LEFT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.NULL)), Skew.NodeKind.SUBTRACT, new Skew.OperatorInfo('-', Skew.Precedence.ADD, Skew.Associativity.LEFT, Skew.OperatorKind.OVERRIDABLE, [0, 1], Skew.NodeKind.NULL)), Skew.NodeKind.UNSIGNED_SHIFT_RIGHT, new Skew.OperatorInfo('>>>', Skew.Precedence.SHIFT, Skew.Associativity.LEFT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.NULL)), Skew.NodeKind.ASSIGN, new Skew.OperatorInfo('=', Skew.Precedence.ASSIGN, Skew.Associativity.RIGHT, Skew.OperatorKind.FIXED, [1], Skew.NodeKind.NULL)), Skew.NodeKind.ASSIGN_ADD, new Skew.OperatorInfo('+=', Skew.Precedence.ASSIGN, Skew.Associativity.RIGHT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.ADD)), Skew.NodeKind.ASSIGN_BITWISE_AND, new Skew.OperatorInfo('&=', Skew.Precedence.ASSIGN, Skew.Associativity.RIGHT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.BITWISE_AND)), Skew.NodeKind.ASSIGN_BITWISE_OR, new Skew.OperatorInfo('|=', Skew.Precedence.ASSIGN, Skew.Associativity.RIGHT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.BITWISE_OR)), Skew.NodeKind.ASSIGN_BITWISE_XOR, new Skew.OperatorInfo('^=', Skew.Precedence.ASSIGN, Skew.Associativity.RIGHT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.BITWISE_XOR)), Skew.NodeKind.ASSIGN_DIVIDE, new Skew.OperatorInfo('/=', Skew.Precedence.ASSIGN, Skew.Associativity.RIGHT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.DIVIDE)), Skew.NodeKind.ASSIGN_MODULUS, new Skew.OperatorInfo('%%=', Skew.Precedence.ASSIGN, Skew.Associativity.RIGHT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.MODULUS)), Skew.NodeKind.ASSIGN_MULTIPLY, new Skew.OperatorInfo('*=', Skew.Precedence.ASSIGN, Skew.Associativity.RIGHT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.MULTIPLY)), Skew.NodeKind.ASSIGN_POWER, new Skew.OperatorInfo('**=', Skew.Precedence.ASSIGN, Skew.Associativity.RIGHT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.POWER)), Skew.NodeKind.ASSIGN_REMAINDER, new Skew.OperatorInfo('%=', Skew.Precedence.ASSIGN, Skew.Associativity.RIGHT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.REMAINDER)), Skew.NodeKind.ASSIGN_SHIFT_LEFT, new Skew.OperatorInfo('<<=', Skew.Precedence.ASSIGN, Skew.Associativity.RIGHT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.SHIFT_LEFT)), Skew.NodeKind.ASSIGN_SHIFT_RIGHT, new Skew.OperatorInfo('>>=', Skew.Precedence.ASSIGN, Skew.Associativity.RIGHT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.SHIFT_RIGHT)), Skew.NodeKind.ASSIGN_SUBTRACT, new Skew.OperatorInfo('-=', Skew.Precedence.ASSIGN, Skew.Associativity.RIGHT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.SUBTRACT)), Skew.NodeKind.ASSIGN_UNSIGNED_SHIFT_RIGHT, new Skew.OperatorInfo('>>>=', Skew.Precedence.ASSIGN, Skew.Associativity.RIGHT, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.UNSIGNED_SHIFT_RIGHT)), Skew.NodeKind.ASSIGN_INDEX, new Skew.OperatorInfo('[]=', Skew.Precedence.MEMBER, Skew.Associativity.NONE, Skew.OperatorKind.OVERRIDABLE, [2], Skew.NodeKind.NULL)), Skew.NodeKind.INDEX, new Skew.OperatorInfo('[]', Skew.Precedence.MEMBER, Skew.Associativity.NONE, Skew.OperatorKind.OVERRIDABLE, [1], Skew.NodeKind.NULL));\n  Skew.validArgumentCounts = null;\n  Skew.DEFAULT_MESSAGE_LIMIT = 10;\n  Skew.VALID_TARGETS = in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(new Map(), 'cpp', new Skew.CPlusPlusTarget()), 'cs', new Skew.CSharpTarget()), 'ts', new Skew.TypeScriptTarget()), 'js', new Skew.JavaScriptTarget()), 'lisp-tree', new Skew.LispTreeTarget());\n  Skew.VERSION = '0.9.19';\n  Skew.REMOVE_WHITESPACE_BEFORE = in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(new Map(), Skew.TokenKind.COLON, 0), Skew.TokenKind.COMMA, 0), Skew.TokenKind.DOT, 0), Skew.TokenKind.QUESTION_MARK, 0), Skew.TokenKind.RIGHT_PARENTHESIS, 0);\n  Skew.FORBID_XML_AFTER = in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(new Map(), Skew.TokenKind.CHARACTER, 0), Skew.TokenKind.DECREMENT, 0), Skew.TokenKind.DOUBLE, 0), Skew.TokenKind.DYNAMIC, 0), Skew.TokenKind.STRING_INTERPOLATION_END, 0), Skew.TokenKind.FALSE, 0), Skew.TokenKind.IDENTIFIER, 0), Skew.TokenKind.INCREMENT, 0), Skew.TokenKind.INT, 0), Skew.TokenKind.INT_BINARY, 0), Skew.TokenKind.INT_HEX, 0), Skew.TokenKind.INT_OCTAL, 0), Skew.TokenKind.NULL, 0), Skew.TokenKind.RIGHT_BRACE, 0), Skew.TokenKind.RIGHT_BRACKET, 0), Skew.TokenKind.RIGHT_PARENTHESIS, 0), Skew.TokenKind.STRING, 0), Skew.TokenKind.SUPER, 0), Skew.TokenKind.TRUE, 0);\n  Skew.yy_accept = [Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.END_OF_FILE, Skew.TokenKind.ERROR, Skew.TokenKind.WHITESPACE, Skew.TokenKind.NEWLINE, Skew.TokenKind.NOT, Skew.TokenKind.ERROR, Skew.TokenKind.COMMENT, Skew.TokenKind.REMAINDER, Skew.TokenKind.BITWISE_AND, Skew.TokenKind.ERROR, Skew.TokenKind.LEFT_PARENTHESIS, Skew.TokenKind.RIGHT_PARENTHESIS, Skew.TokenKind.MULTIPLY, Skew.TokenKind.PLUS, Skew.TokenKind.COMMA, Skew.TokenKind.MINUS, Skew.TokenKind.DOT, Skew.TokenKind.DIVIDE, Skew.TokenKind.INT, Skew.TokenKind.INT, Skew.TokenKind.COLON, Skew.TokenKind.SEMICOLON, Skew.TokenKind.LESS_THAN, Skew.TokenKind.ASSIGN, Skew.TokenKind.GREATER_THAN, Skew.TokenKind.QUESTION_MARK, Skew.TokenKind.ERROR, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.LEFT_BRACKET, Skew.TokenKind.RIGHT_BRACKET, Skew.TokenKind.BITWISE_XOR, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.LEFT_BRACE, Skew.TokenKind.BITWISE_OR, Skew.TokenKind.RIGHT_BRACE, Skew.TokenKind.TILDE, Skew.TokenKind.WHITESPACE, Skew.TokenKind.NEWLINE, Skew.TokenKind.NOT_EQUAL, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.STRING, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.COMMENT, Skew.TokenKind.MODULUS, Skew.TokenKind.ASSIGN_REMAINDER, Skew.TokenKind.LOGICAL_AND, Skew.TokenKind.ASSIGN_BITWISE_AND, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.CHARACTER, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.POWER, Skew.TokenKind.ASSIGN_MULTIPLY, Skew.TokenKind.INCREMENT, Skew.TokenKind.ASSIGN_PLUS, Skew.TokenKind.DECREMENT, Skew.TokenKind.ASSIGN_MINUS, Skew.TokenKind.DOT_DOT, Skew.TokenKind.COMMENT_ERROR, Skew.TokenKind.ASSIGN_DIVIDE, Skew.TokenKind.XML_END_EMPTY, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.INT, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.DOUBLE_COLON, Skew.TokenKind.XML_START_CLOSE, Skew.TokenKind.SHIFT_LEFT, Skew.TokenKind.LESS_THAN_OR_EQUAL, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.EQUAL, Skew.TokenKind.ARROW, Skew.TokenKind.GREATER_THAN_OR_EQUAL, Skew.TokenKind.SHIFT_RIGHT, Skew.TokenKind.NULL_DOT, Skew.TokenKind.ASSIGN_NULL, Skew.TokenKind.NULL_JOIN, Skew.TokenKind.ANNOTATION, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.INDEX, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.ASSIGN_BITWISE_XOR, Skew.TokenKind.AS, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IF, Skew.TokenKind.IN, Skew.TokenKind.IS, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.ASSIGN_BITWISE_OR, Skew.TokenKind.LOGICAL_OR, Skew.TokenKind.NOT_EQUAL_ERROR, Skew.TokenKind.ASSIGN_MODULUS, Skew.TokenKind.ASSIGN_POWER, Skew.TokenKind.COMMENT_ERROR, Skew.TokenKind.DOUBLE, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.DOUBLE, Skew.TokenKind.INT_BINARY, Skew.TokenKind.INT_OCTAL, Skew.TokenKind.INT_HEX, Skew.TokenKind.ASSIGN_SHIFT_LEFT, Skew.TokenKind.COMPARE, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.EQUAL_ERROR, Skew.TokenKind.ASSIGN_SHIFT_RIGHT, Skew.TokenKind.UNSIGNED_SHIFT_RIGHT, Skew.TokenKind.ANNOTATION, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.ASSIGN_INDEX, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.FOR, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.TRY, Skew.TokenKind.VAR, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.ASSIGN_UNSIGNED_SHIFT_RIGHT, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.CASE, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.ELSE, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.NULL, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.TRUE, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.DOUBLE, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.LIST, Skew.TokenKind.LIST_NEW, Skew.TokenKind.BREAK, Skew.TokenKind.CATCH, Skew.TokenKind.CONST, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.FALSE, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.SUPER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.THROW, Skew.TokenKind.WHILE, Skew.TokenKind.SET, Skew.TokenKind.SET_NEW, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.RETURN, Skew.TokenKind.SWITCH, Skew.TokenKind.YY_INVALID_ACTION, Skew.TokenKind.IDENTIFIER, Skew.TokenKind.DEFAULT, Skew.TokenKind.DYNAMIC, Skew.TokenKind.FINALLY, Skew.TokenKind.XML_CHILD, Skew.TokenKind.CONTINUE, Skew.TokenKind.YY_INVALID_ACTION];\n  Skew.yy_ec = [0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 5, 6, 1, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 20, 20, 20, 20, 20, 21, 21, 22, 23, 24, 25, 26, 27, 28, 29, 29, 29, 29, 30, 29, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 32, 33, 34, 35, 31, 1, 36, 37, 38, 39, 40, 41, 31, 42, 43, 31, 44, 45, 46, 47, 48, 49, 31, 50, 51, 52, 53, 54, 55, 56, 57, 31, 58, 59, 60, 61, 1];\n  Skew.yy_meta = [0, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 4, 4, 5, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1];\n  Skew.yy_base = [0, 0, 0, 320, 321, 317, 316, 292, 57, 0, 56, 57, 55, 321, 321, 54, 55, 321, 52, 300, 58, 75, 81, 293, 321, 61, 44, 46, 82, 0, 0, 88, 321, 289, 262, 262, 70, 63, 266, 81, 85, 257, 269, 21, 66, 272, 265, 94, 88, 321, 321, 304, 303, 279, 109, 321, 300, 0, 277, 321, 321, 321, 110, 321, 298, 275, 321, 321, 321, 321, 321, 321, 0, 321, 321, 119, 130, 143, 109, 134, 0, 321, 321, 274, 272, 281, 271, 321, 321, 108, 321, 321, 321, 0, 0, 279, 269, 253, 321, 0, 252, 93, 244, 249, 242, 237, 242, 239, 235, 0, 0, 0, 239, 231, 233, 238, 230, 102, 229, 235, 261, 236, 321, 321, 321, 321, 321, 0, 147, 153, 160, 157, 164, 0, 321, 321, 259, 321, 321, 249, 0, 257, 321, 217, 235, 230, 231, 134, 232, 231, 226, 214, 228, 0, 218, 209, 221, 208, 211, 218, 0, 0, 212, 240, 200, 175, 238, 321, 219, 218, 207, 0, 208, 197, 205, 194, 200, 0, 205, 199, 0, 193, 192, 203, 185, 0, 199, 178, 177, 179, 183, 212, 321, 321, 0, 0, 0, 188, 181, 168, 0, 147, 144, 0, 147, 0, 0, 321, 321, 152, 104, 78, 87, 35, 0, 0, 63, 33, 0, 0, 0, 321, 0, 321, 204, 209, 214, 216, 219, 224, 227, 229];\n  Skew.yy_def = [0, 223, 1, 223, 223, 223, 223, 223, 224, 225, 223, 223, 226, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 227, 228, 223, 223, 223, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 223, 223, 223, 223, 223, 223, 223, 224, 223, 224, 225, 223, 223, 223, 223, 226, 223, 226, 223, 223, 223, 223, 223, 223, 223, 229, 223, 223, 223, 223, 223, 223, 223, 230, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 231, 228, 223, 223, 223, 223, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 223, 223, 223, 223, 223, 223, 223, 229, 223, 223, 223, 223, 223, 230, 223, 223, 223, 223, 223, 223, 231, 223, 223, 223, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 223, 223, 223, 223, 223, 223, 223, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 223, 223, 223, 223, 223, 223, 223, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 223, 223, 223, 228, 228, 228, 228, 228, 228, 223, 228, 228, 228, 228, 223, 228, 0, 223, 223, 223, 223, 223, 223, 223, 223];\n  Skew.yy_nxt = [0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 22, 22, 23, 24, 25, 26, 27, 28, 29, 30, 30, 30, 31, 4, 32, 33, 34, 35, 36, 37, 38, 39, 30, 40, 30, 30, 30, 41, 30, 30, 42, 43, 44, 30, 45, 46, 30, 30, 47, 48, 49, 50, 55, 58, 63, 60, 65, 69, 67, 86, 87, 88, 89, 222, 114, 72, 115, 70, 82, 66, 68, 59, 61, 73, 74, 83, 84, 85, 64, 221, 56, 75, 220, 76, 76, 76, 76, 75, 90, 76, 76, 76, 76, 103, 95, 77, 101, 91, 116, 92, 120, 77, 78, 122, 55, 77, 117, 106, 102, 63, 104, 77, 96, 79, 107, 219, 109, 131, 131, 108, 218, 80, 110, 138, 139, 97, 111, 128, 128, 128, 128, 121, 56, 64, 145, 146, 75, 123, 76, 76, 76, 76, 132, 132, 132, 159, 129, 217, 129, 160, 77, 130, 130, 130, 130, 128, 128, 128, 128, 216, 77, 130, 130, 130, 130, 131, 131, 165, 130, 130, 130, 130, 132, 132, 132, 173, 174, 165, 189, 215, 189, 214, 213, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 54, 54, 54, 54, 54, 57, 212, 57, 57, 57, 62, 62, 62, 62, 62, 93, 93, 94, 94, 94, 127, 211, 127, 127, 127, 133, 133, 140, 140, 140, 210, 209, 208, 207, 206, 205, 204, 203, 202, 201, 200, 199, 198, 197, 196, 195, 194, 193, 192, 191, 188, 187, 186, 185, 184, 183, 182, 181, 180, 179, 178, 177, 176, 175, 172, 171, 170, 169, 168, 167, 166, 164, 163, 162, 161, 158, 157, 156, 155, 154, 153, 152, 151, 150, 149, 148, 147, 144, 143, 142, 141, 137, 136, 135, 134, 126, 223, 125, 223, 124, 52, 51, 119, 118, 113, 112, 105, 100, 99, 98, 81, 71, 53, 52, 51, 223, 3, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223];\n  Skew.yy_chk = [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 10, 12, 11, 15, 18, 16, 26, 26, 27, 27, 217, 43, 20, 43, 18, 25, 15, 16, 10, 11, 20, 20, 25, 25, 25, 12, 216, 8, 21, 213, 21, 21, 21, 21, 22, 28, 22, 22, 22, 22, 37, 31, 21, 36, 28, 44, 28, 47, 22, 21, 48, 54, 21, 44, 39, 36, 62, 37, 22, 31, 21, 39, 212, 40, 78, 78, 39, 211, 21, 40, 89, 89, 31, 40, 75, 75, 75, 75, 47, 54, 62, 101, 101, 76, 48, 76, 76, 76, 76, 79, 79, 79, 117, 77, 210, 77, 117, 76, 77, 77, 77, 77, 128, 128, 128, 128, 209, 76, 129, 129, 129, 129, 131, 131, 128, 130, 130, 130, 130, 132, 132, 132, 147, 147, 128, 165, 204, 165, 202, 201, 165, 165, 165, 165, 189, 189, 189, 189, 190, 190, 190, 190, 224, 224, 224, 224, 224, 225, 199, 225, 225, 225, 226, 226, 226, 226, 226, 227, 227, 228, 228, 228, 229, 198, 229, 229, 229, 230, 230, 231, 231, 231, 197, 191, 188, 187, 186, 184, 183, 182, 181, 179, 178, 176, 175, 174, 173, 172, 170, 169, 168, 166, 164, 163, 162, 159, 158, 157, 156, 155, 154, 152, 151, 150, 149, 148, 146, 145, 144, 143, 141, 139, 136, 121, 120, 119, 118, 116, 115, 114, 113, 112, 108, 107, 106, 105, 104, 103, 102, 100, 97, 96, 95, 86, 85, 84, 83, 65, 64, 58, 56, 53, 52, 51, 46, 45, 42, 41, 38, 35, 34, 33, 23, 19, 7, 6, 5, 3, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223];\n  Skew.YY_JAM_STATE = 223;\n  Skew.YY_ACCEPT_LENGTH = 224;\n  Skew.NATIVE_LIBRARY_CPP = '\\n@import {\\n  def __doubleToString(x double) string\\n  def __intToString(x int) string\\n\\n  @rename(\"std::isnan\")\\n  def __doubleIsNaN(x double) bool\\n\\n  @rename(\"std::isfinite\")\\n  def __doubleIsFinite(x double) bool\\n}\\n\\nclass bool {\\n  def toString string {\\n    return self ? \"true\" : \"false\"\\n  }\\n}\\n\\nclass int {\\n  def toString string {\\n    return __intToString(self)\\n  }\\n\\n  def >>>(x int) int {\\n    return (self as dynamic.unsigned >> x) as int\\n  }\\n}\\n\\nclass double {\\n  def toString string {\\n    return __doubleToString(self)\\n  }\\n\\n  def isNaN bool {\\n    return __doubleIsNaN(self)\\n  }\\n\\n  def isFinite bool {\\n    return __doubleIsFinite(self)\\n  }\\n}\\n\\nclass string {\\n  @rename(\"compare\")\\n  def <=>(x string) int\\n\\n  @rename(\"contains\")\\n  def in(x string) bool\\n}\\n\\n@rename(\"Skew::List\")\\nclass List {\\n  @rename(\"contains\")\\n  def in(x T) bool\\n}\\n\\n@rename(\"Skew::StringMap\")\\nclass StringMap {\\n  @rename(\"contains\")\\n  def in(x string) bool\\n}\\n\\n@rename(\"Skew::IntMap\")\\nclass IntMap {\\n  @rename(\"contains\")\\n  def in(x int) bool\\n}\\n\\n@import\\n@rename(\"Skew::StringBuilder\")\\nclass StringBuilder {\\n}\\n\\n@import\\n@rename(\"Skew::Math\")\\nnamespace Math {\\n}\\n\\n@import\\ndef assert(truth bool)\\n';\n  Skew.UNICODE_LIBRARY = '\\nnamespace Unicode {\\n  enum Encoding {\\n    UTF8\\n    UTF16\\n    UTF32\\n  }\\n\\n  const STRING_ENCODING Encoding =\\n    TARGET == .CPLUSPLUS ? .UTF8 :\\n    TARGET == .CSHARP || TARGET == .JAVASCRIPT ? .UTF16 :\\n    .UTF32\\n\\n  class StringIterator {\\n    var value = \"\"\\n    var index = 0\\n    var stop = 0\\n\\n    def reset(text string, start int) StringIterator {\\n      value = text\\n      index = start\\n      stop = text.count\\n      return self\\n    }\\n\\n    def countCodePointsUntil(stop int) int {\\n      var count = 0\\n      while index < stop && nextCodePoint >= 0 {\\n        count++\\n      }\\n      return count\\n    }\\n\\n    def previousCodePoint int\\n    def nextCodePoint int\\n\\n    if STRING_ENCODING == .UTF8 {\\n      def previousCodePoint int {\\n        if index <= 0 { return -1 }\\n        var a = value[--index]\\n        if (a & 0xC0) != 0x80 { return a }\\n        if index <= 0 { return -1 }\\n        var b = value[--index]\\n        if (b & 0xC0) != 0x80 { return ((b & 0x1F) << 6) | (a & 0x3F) }\\n        if index <= 0 { return -1 }\\n        var c = value[--index]\\n        if (c & 0xC0) != 0x80 { return ((c & 0x0F) << 12) | ((b & 0x3F) << 6) | (a & 0x3F) }\\n        if index >= stop { return -1 }\\n        var d = value[--index]\\n        return ((d & 0x07) << 18) | ((c & 0x3F) << 12) | ((b & 0x3F) << 6) | (a & 0x3F)\\n      }\\n\\n      def nextCodePoint int {\\n        if index >= stop { return -1 }\\n        var a = value[index++]\\n        if a < 0xC0 { return a }\\n        if index >= stop { return -1 }\\n        var b = value[index++]\\n        if a < 0xE0 { return ((a & 0x1F) << 6) | (b & 0x3F) }\\n        if index >= stop { return -1 }\\n        var c = value[index++]\\n        if a < 0xF0 { return ((a & 0x0F) << 12) | ((b & 0x3F) << 6) | (c & 0x3F) }\\n        if index >= stop { return -1 }\\n        var d = value[index++]\\n        return ((a & 0x07) << 18) | ((b & 0x3F) << 12) | ((c & 0x3F) << 6) | (d & 0x3F)\\n      }\\n    }\\n\\n    else if STRING_ENCODING == .UTF16 {\\n      def previousCodePoint int {\\n        if index <= 0 { return -1 }\\n        var a = value[--index]\\n        if (a & 0xFC00) != 0xDC00 { return a }\\n        if index <= 0 { return -1 }\\n        var b = value[--index]\\n        return (b << 10) + a + (0x10000 - (0xD800 << 10) - 0xDC00)\\n      }\\n\\n      def nextCodePoint int {\\n        if index >= stop { return -1 }\\n        var a = value[index++]\\n        if (a & 0xFC00) != 0xD800 { return a }\\n        if index >= stop { return -1 }\\n        var b = value[index++]\\n        return (a << 10) + b + (0x10000 - (0xD800 << 10) - 0xDC00)\\n      }\\n    }\\n\\n    else {\\n      def previousCodePoint int {\\n        if index <= 0 { return -1 }\\n        return value[--index]\\n      }\\n\\n      def nextCodePoint int {\\n        if index >= stop { return -1 }\\n        return value[index++]\\n      }\\n    }\\n  }\\n\\n  namespace StringIterator {\\n    const INSTANCE = StringIterator.new\\n  }\\n\\n  def codeUnitCountForCodePoints(codePoints List<int>, encoding Encoding) int {\\n    var count = 0\\n\\n    switch encoding {\\n      case .UTF8 {\\n        for codePoint in codePoints {\\n          if codePoint < 0x80 { count++ }\\n          else if codePoint < 0x800 { count += 2 }\\n          else if codePoint < 0x10000 { count += 3 }\\n          else { count += 4 }\\n        }\\n      }\\n\\n      case .UTF16 {\\n        for codePoint in codePoints {\\n          if codePoint < 0x10000 { count++ }\\n          else { count += 2 }\\n        }\\n      }\\n\\n      case .UTF32 {\\n        count = codePoints.count\\n      }\\n    }\\n\\n    return count\\n  }\\n}\\n\\nclass string {\\n  if Unicode.STRING_ENCODING == .UTF32 {\\n    def codePoints List<int> {\\n      return codeUnits\\n    }\\n  }\\n\\n  else {\\n    def codePoints List<int> {\\n      var codePoints List<int> = []\\n      var instance = Unicode.StringIterator.INSTANCE\\n      instance.reset(self, 0)\\n\\n      while true {\\n        var codePoint = instance.nextCodePoint\\n        if codePoint < 0 {\\n          return codePoints\\n        }\\n        codePoints.append(codePoint)\\n      }\\n    }\\n  }\\n}\\n\\nnamespace string {\\n  def fromCodePoints(codePoints List<int>) string {\\n    var builder = StringBuilder.new\\n    for codePoint in codePoints {\\n      builder.append(fromCodePoint(codePoint))\\n    }\\n    return builder.toString\\n  }\\n\\n  if Unicode.STRING_ENCODING == .UTF8 {\\n    def fromCodePoint(codePoint int) string {\\n      return\\n        codePoint < 0x80 ? fromCodeUnit(codePoint) : (\\n          codePoint < 0x800 ? fromCodeUnit(((codePoint >> 6) & 0x1F) | 0xC0) : (\\n            codePoint < 0x10000 ? fromCodeUnit(((codePoint >> 12) & 0x0F) | 0xE0) : (\\n              fromCodeUnit(((codePoint >> 18) & 0x07) | 0xF0)\\n            ) + fromCodeUnit(((codePoint >> 12) & 0x3F) | 0x80)\\n          ) + fromCodeUnit(((codePoint >> 6) & 0x3F) | 0x80)\\n        ) + fromCodeUnit((codePoint & 0x3F) | 0x80)\\n    }\\n  }\\n\\n  else if Unicode.STRING_ENCODING == .UTF16 {\\n    def fromCodePoint(codePoint int) string {\\n      return codePoint < 0x10000 ? fromCodeUnit(codePoint) :\\n        fromCodeUnit(((codePoint - 0x10000) >> 10) + 0xD800) +\\n        fromCodeUnit(((codePoint - 0x10000) & ((1 << 10) - 1)) + 0xDC00)\\n    }\\n  }\\n\\n  else {\\n    def fromCodePoint(codePoint int) string {\\n      return fromCodeUnit(codePoint)\\n    }\\n  }\\n}\\n';\n  Skew.NATIVE_LIBRARY_JS = '\\nconst __create fn(dynamic) dynamic = dynamic.Object.create ? dynamic.Object.create : prototype => {\\n  return {\"__proto__\": prototype}\\n}\\n\\nconst __extends = (derived dynamic, base dynamic) => {\\n  derived.prototype = __create(base.prototype)\\n  derived.prototype.constructor = derived\\n}\\n\\nconst __imul fn(int, int) int = dynamic.Math.imul ? dynamic.Math.imul : (a, b) => {\\n  return ((a as dynamic) * (b >>> 16) << 16) + (a as dynamic) * (b & 65535) | 0\\n}\\n\\nconst __prototype dynamic\\nconst __isInt = (value dynamic) => value == (value | 0)\\nconst __isBool = (value dynamic) => value == !!value\\nconst __isDouble = (value dynamic) => dynamic.typeof(value) == \"number\"\\nconst __isString = (value dynamic) => dynamic.typeof(value) == \"string\"\\nconst __asString = (value dynamic) => value == null ? value : value + \"\"\\n\\ndef assert(truth bool) {\\n  if !truth {\\n    throw dynamic.Error(\"Assertion failed\")\\n  }\\n}\\n\\n# Override this to true to remove asserts from many of the functions below so that they may be inlined\\nconst JS_INLINE_NATIVE = false\\n\\n@import\\nnamespace Math {}\\n\\n@rename(\"boolean\")\\nclass bool {}\\n\\n@rename(\"number\")\\nclass int {}\\n\\n@rename(\"number\")\\nclass double {\\n  @alwaysinline\\n  def isFinite bool {\\n    return dynamic.isFinite(self)\\n  }\\n\\n  @alwaysinline\\n  def isNaN bool {\\n    return dynamic.isNaN(self)\\n  }\\n}\\n\\nclass string {\\n  def <=>(x string) int {\\n    return ((x as dynamic < self) as int) - ((x as dynamic > self) as int)\\n  }\\n\\n  if JS_INLINE_NATIVE {\\n    @alwaysinline\\n    def slice(start int) string {\\n      return (self as dynamic).slice(start)\\n    }\\n  } else {\\n    def slice(start int) string {\\n      assert(0 <= start && start <= count)\\n      return (self as dynamic).slice(start)\\n    }\\n  }\\n\\n  if JS_INLINE_NATIVE {\\n    @alwaysinline\\n    def slice(start int, end int) string {\\n      return (self as dynamic).slice(start, end)\\n    }\\n  } else {\\n    def slice(start int, end int) string {\\n      assert(0 <= start && start <= end && end <= count)\\n      return (self as dynamic).slice(start, end)\\n    }\\n  }\\n\\n  @alwaysinline\\n  def startsWith(text string) bool {\\n    return (self as dynamic).startsWith(text)\\n  }\\n\\n  @alwaysinline\\n  def endsWith(text string) bool {\\n    return (self as dynamic).endsWith(text)\\n  }\\n\\n  @alwaysinline\\n  def replaceAll(before string, after string) string {\\n    return after.join(self.split(before))\\n  }\\n\\n  @alwaysinline\\n  def in(value string) bool {\\n    return indexOf(value) != -1\\n  }\\n\\n  @alwaysinline\\n  def count int {\\n    return (self as dynamic).length\\n  }\\n\\n  if JS_INLINE_NATIVE {\\n    @alwaysinline\\n    def [](index int) int {\\n      return (self as dynamic).charCodeAt(index)\\n    }\\n  } else {\\n    def [](index int) int {\\n      assert(0 <= index && index < count)\\n      return (self as dynamic).charCodeAt(index)\\n    }\\n  }\\n\\n  if JS_INLINE_NATIVE {\\n    @alwaysinline\\n    def get(index int) string {\\n      return (self as dynamic)[index]\\n    }\\n  } else {\\n    def get(index int) string {\\n      assert(0 <= index && index < count)\\n      return (self as dynamic)[index]\\n    }\\n  }\\n\\n  def repeat(times int) string {\\n    var result = \"\"\\n    for i in 0..times {\\n      result += self\\n    }\\n    return result\\n  }\\n\\n  @alwaysinline\\n  def join(parts List<string>) string {\\n    return (parts as dynamic).join(self)\\n  }\\n\\n  def codeUnits List<int> {\\n    var result List<int> = []\\n    for i in 0..count {\\n      result.append(self[i])\\n    }\\n    return result\\n  }\\n}\\n\\nnamespace string {\\n  @alwaysinline\\n  def fromCodeUnit(codeUnit int) string {\\n    return dynamic.String.fromCharCode(codeUnit)\\n  }\\n\\n  def fromCodeUnits(codeUnits List<int>) string {\\n    var result = \"\"\\n    for codeUnit in codeUnits {\\n      result += string.fromCodeUnit(codeUnit)\\n    }\\n    return result\\n  }\\n}\\n\\nclass StringBuilder {\\n  var buffer = \"\"\\n\\n  def new {\\n  }\\n\\n  @alwaysinline\\n  def append(x string) {\\n    buffer += x\\n  }\\n\\n  @alwaysinline\\n  def toString string {\\n    return buffer\\n  }\\n}\\n\\n@rename(\"Array\")\\nclass List {\\n  @rename(\"unshift\")\\n  def prepend(x T)\\n\\n  @rename(\"push\")\\n  def append(x T)\\n\\n  @rename(\"every\")\\n  def all(x fn(T) bool) bool\\n\\n  @rename(\"some\")\\n  def any(x fn(T) bool) bool\\n\\n  @rename(\"slice\")\\n  def clone List<T>\\n\\n  @rename(\"forEach\")\\n  def each(x fn(T))\\n\\n  if JS_INLINE_NATIVE {\\n    @alwaysinline\\n    def slice(start int) List<T> {\\n      return (self as dynamic).slice(start)\\n    }\\n  } else {\\n    def slice(start int) List<T> {\\n      assert(0 <= start && start <= count)\\n      return (self as dynamic).slice(start)\\n    }\\n  }\\n\\n  if JS_INLINE_NATIVE {\\n    @alwaysinline\\n    def slice(start int, end int) List<T> {\\n      return (self as dynamic).slice(start, end)\\n    }\\n  } else {\\n    def slice(start int, end int) List<T> {\\n      assert(0 <= start && start <= end && end <= count)\\n      return (self as dynamic).slice(start, end)\\n    }\\n  }\\n\\n  if JS_INLINE_NATIVE {\\n    @alwaysinline\\n    def [](index int) T {\\n      return (self as dynamic)[index]\\n    }\\n  } else {\\n    def [](index int) T {\\n      assert(0 <= index && index < count)\\n      return (self as dynamic)[index]\\n    }\\n  }\\n\\n  if JS_INLINE_NATIVE {\\n    @alwaysinline\\n    def []=(index int, value T) T {\\n      return (self as dynamic)[index] = value\\n    }\\n  } else {\\n    def []=(index int, value T) T {\\n      assert(0 <= index && index < count)\\n      return (self as dynamic)[index] = value\\n    }\\n  }\\n\\n  @alwaysinline\\n  def in(value T) bool {\\n    return indexOf(value) != -1\\n  }\\n\\n  @alwaysinline\\n  def isEmpty bool {\\n    return count == 0\\n  }\\n\\n  @alwaysinline\\n  def count int {\\n    return (self as dynamic).length\\n  }\\n\\n  if JS_INLINE_NATIVE {\\n    @alwaysinline\\n    def first T {\\n      return self[0]\\n    }\\n  } else {\\n    def first T {\\n      assert(!isEmpty)\\n      return self[0]\\n    }\\n  }\\n\\n  def last T {\\n    assert(!isEmpty)\\n    return self[count - 1]\\n  }\\n\\n  def prepend(values List<T>) {\\n    assert(values != self)\\n    var count = values.count\\n    for i in 0..count {\\n      prepend(values[count - i - 1])\\n    }\\n  }\\n\\n  def append(values List<T>) {\\n    assert(values != self)\\n    for value in values {\\n      append(value)\\n    }\\n  }\\n\\n  def insert(index int, values List<T>) {\\n    assert(values != self)\\n    for value in values {\\n      insert(index, value)\\n      index++\\n    }\\n  }\\n\\n  def insert(index int, value T) {\\n    assert(0 <= index && index <= count)\\n    (self as dynamic).splice(index, 0, value)\\n  }\\n\\n  def removeFirst {\\n    assert(!isEmpty)\\n    (self as dynamic).shift()\\n  }\\n\\n  if JS_INLINE_NATIVE {\\n    @alwaysinline\\n    def takeFirst T {\\n      return (self as dynamic).shift()\\n    }\\n  } else {\\n    def takeFirst T {\\n      assert(!isEmpty)\\n      return (self as dynamic).shift()\\n    }\\n  }\\n\\n  def removeLast {\\n    assert(!isEmpty)\\n    (self as dynamic).pop()\\n  }\\n\\n  if JS_INLINE_NATIVE {\\n    @alwaysinline\\n    def takeLast T {\\n      return (self as dynamic).pop()\\n    }\\n  } else {\\n    def takeLast T {\\n      assert(!isEmpty)\\n      return (self as dynamic).pop()\\n    }\\n  }\\n\\n  def removeAt(index int) {\\n    assert(0 <= index && index < count)\\n    (self as dynamic).splice(index, 1)\\n  }\\n\\n  if JS_INLINE_NATIVE {\\n    @alwaysinline\\n    def takeAt(index int) T {\\n      return (self as dynamic).splice(index, 1)[0]\\n    }\\n  } else {\\n    def takeAt(index int) T {\\n      assert(0 <= index && index < count)\\n      return (self as dynamic).splice(index, 1)[0]\\n    }\\n  }\\n\\n  def takeRange(start int, end int) List<T> {\\n    assert(0 <= start && start <= end && end <= count)\\n    return (self as dynamic).splice(start, end - start)\\n  }\\n\\n  def appendOne(value T) {\\n    if !(value in self) {\\n      append(value)\\n    }\\n  }\\n\\n  def removeOne(value T) {\\n    var index = indexOf(value)\\n    if index >= 0 {\\n      removeAt(index)\\n    }\\n  }\\n\\n  def removeRange(start int, end int) {\\n    assert(0 <= start && start <= end && end <= count)\\n    (self as dynamic).splice(start, end - start)\\n  }\\n\\n  def removeIf(callback fn(T) bool) {\\n    var index = 0\\n\\n    # Remove elements in place\\n    for i in 0..count {\\n      if !callback(self[i]) {\\n        if index < i {\\n          self[index] = self[i]\\n        }\\n        index++\\n      }\\n    }\\n\\n    # Shrink the array to the correct size\\n    while index < count {\\n      removeLast\\n    }\\n  }\\n\\n  def equals(other List<T>) bool {\\n    if count != other.count {\\n      return false\\n    }\\n    for i in 0..count {\\n      if self[i] != other[i] {\\n        return false\\n      }\\n    }\\n    return true\\n  }\\n}\\n\\nnamespace List {\\n  @alwaysinline\\n  def new List<T> {\\n    return [] as dynamic\\n  }\\n}\\n\\nnamespace StringMap {\\n  @alwaysinline\\n  def new StringMap<T> {\\n    return dynamic.Map.new\\n  }\\n}\\n\\nclass StringMap {\\n  if JS_INLINE_NATIVE {\\n    @alwaysinline\\n    def [](key string) T {\\n      return (self as dynamic).get(key)\\n    }\\n  } else {\\n    def [](key string) T {\\n      assert(key in self)\\n      return (self as dynamic).get(key)\\n    }\\n  }\\n\\n  def []=(key string, value T) T {\\n    (self as dynamic).set(key, value)\\n    return value\\n  }\\n\\n  def {...}(key string, value T) StringMap<T> {\\n    (self as dynamic).set(key, value)\\n    return self\\n  }\\n\\n  @alwaysinline\\n  def in(key string) bool {\\n    return (self as dynamic).has(key)\\n  }\\n\\n  @alwaysinline\\n  def count int {\\n    return (self as dynamic).size\\n  }\\n\\n  @alwaysinline\\n  def isEmpty bool {\\n    return count == 0\\n  }\\n\\n  def get(key string, defaultValue T) T {\\n    const value = (self as dynamic).get(key)\\n    return value != dynamic.void(0) ? value : defaultValue # Compare against undefined so the key is only hashed once for speed\\n  }\\n\\n  @alwaysinline\\n  def keys List<string> {\\n    return dynamic.Array.from((self as dynamic).keys())\\n  }\\n\\n  @alwaysinline\\n  def values List<T> {\\n    return dynamic.Array.from((self as dynamic).values())\\n  }\\n\\n  @alwaysinline\\n  def clone StringMap<T> {\\n    return dynamic.Map.new(self)\\n  }\\n\\n  @alwaysinline\\n  def remove(key string) {\\n    (self as dynamic).delete(key)\\n  }\\n\\n  def each(x fn(string, T)) {\\n    (self as dynamic).forEach((value, key) => {\\n      x(key, value)\\n    })\\n  }\\n}\\n\\nnamespace IntMap {\\n  @alwaysinline\\n  def new IntMap<T> {\\n    return dynamic.Map.new\\n  }\\n}\\n\\nclass IntMap {\\n  if JS_INLINE_NATIVE {\\n    @alwaysinline\\n    def [](key int) T {\\n      return (self as dynamic).get(key)\\n    }\\n  } else {\\n    def [](key int) T {\\n      assert(key in self)\\n      return (self as dynamic).get(key)\\n    }\\n  }\\n\\n  def []=(key int, value T) T {\\n    (self as dynamic).set(key, value)\\n    return value\\n  }\\n\\n  def {...}(key int, value T) IntMap<T> {\\n    (self as dynamic).set(key, value)\\n    return self\\n  }\\n\\n  @alwaysinline\\n  def in(key int) bool {\\n    return (self as dynamic).has(key)\\n  }\\n\\n  @alwaysinline\\n  def count int {\\n    return (self as dynamic).size\\n  }\\n\\n  @alwaysinline\\n  def isEmpty bool {\\n    return count == 0\\n  }\\n\\n  def get(key int, defaultValue T) T {\\n    const value = (self as dynamic).get(key)\\n    return value != dynamic.void(0) ? value : defaultValue # Compare against undefined so the key is only hashed once for speed\\n  }\\n\\n  @alwaysinline\\n  def keys List<int> {\\n    return dynamic.Array.from((self as dynamic).keys())\\n  }\\n\\n  @alwaysinline\\n  def values List<T> {\\n    return dynamic.Array.from((self as dynamic).values())\\n  }\\n\\n  @alwaysinline\\n  def clone IntMap<T> {\\n    return dynamic.Map.new(self)\\n  }\\n\\n  @alwaysinline\\n  def remove(key int) {\\n    (self as dynamic).delete(key)\\n  }\\n\\n  def each(x fn(int, T)) {\\n    (self as dynamic).forEach((value, key) => {\\n      x(key, value)\\n    })\\n  }\\n}\\n';\n  Skew.NATIVE_LIBRARY = '\\nconst RELEASE = false\\nconst ASSERTS = !RELEASE\\n\\nenum Target {\\n  NONE\\n  CPLUSPLUS\\n  CSHARP\\n  JAVASCRIPT\\n}\\n\\nconst TARGET Target = .NONE\\n\\ndef @alwaysinline\\ndef @deprecated\\ndef @deprecated(message string)\\ndef @entry\\ndef @export\\ndef @import\\ndef @neverinline\\ndef @prefer\\ndef @rename(name string)\\ndef @skip\\ndef @spreads\\n\\n@spreads {\\n  def @using(name string) # For use with C#\\n  def @include(name string) # For use with C++\\n}\\n\\n@import if TARGET == .NONE\\n@skip if !ASSERTS\\ndef assert(truth bool)\\n\\n@import if TARGET == .NONE\\nnamespace Math {\\n  @prefer\\n  def abs(x double) double\\n  def abs(x int) int\\n\\n  def acos(x double) double\\n  def asin(x double) double\\n  def atan(x double) double\\n  def atan2(x double, y double) double\\n\\n  def sin(x double) double\\n  def cos(x double) double\\n  def tan(x double) double\\n\\n  def floor(x double) double\\n  def ceil(x double) double\\n  def round(x double) double\\n\\n  def exp(x double) double\\n  def log(x double) double\\n  def pow(x double, y double) double\\n  def random double\\n  def randomInRange(min double, max double) double\\n  def randomInRange(minInclusive int, maxExclusive int) int\\n  def sqrt(x double) double\\n\\n  @prefer {\\n    def max(x double, y double) double\\n    def min(x double, y double) double\\n    def max(x double, y double, z double) double\\n    def min(x double, y double, z double) double\\n    def max(x double, y double, z double, w double) double\\n    def min(x double, y double, z double, w double) double\\n    def clamp(x double, min double, max double) double\\n  }\\n\\n  def max(x int, y int) int\\n  def min(x int, y int) int\\n  def max(x int, y int, z int) int\\n  def min(x int, y int, z int) int\\n  def max(x int, y int, z int, w int) int\\n  def min(x int, y int, z int, w int) int\\n  def clamp(x int, min int, max int) int\\n\\n  def E double        { return 2.718281828459045 }\\n  def INFINITY double { return 1 / 0.0 }\\n  def NAN double      { return 0 / 0.0 }\\n  def PI double       { return 3.141592653589793 }\\n  def SQRT_2 double   { return 2 ** 0.5 }\\n}\\n\\n@import\\nclass bool {\\n  def ! bool\\n  def toString string\\n}\\n\\n@import\\nclass int {\\n  def + int\\n  def - int\\n  def ~ int\\n\\n  def +(x int) int\\n  def -(x int) int\\n  def *(x int) int\\n  def /(x int) int\\n  def %(x int) int\\n  def **(x int) int\\n  def <=>(x int) int\\n  def <<(x int) int\\n  def >>(x int) int\\n  def >>>(x int) int\\n  def &(x int) int\\n  def |(x int) int\\n  def ^(x int) int\\n\\n  def %%(x int) int {\\n    return ((self % x) + x) % x\\n  }\\n\\n  def <<=(x int) int\\n  def >>=(x int) int\\n  def &=(x int) int\\n  def |=(x int) int\\n  def ^=(x int) int\\n\\n  if TARGET != .CSHARP && TARGET != .CPLUSPLUS {\\n    def >>>=(x int)\\n  }\\n\\n  if TARGET != .JAVASCRIPT {\\n    def ++ int\\n    def -- int\\n\\n    def %=(x int) int\\n    def +=(x int) int\\n    def -=(x int) int\\n    def *=(x int) int\\n    def /=(x int) int\\n  }\\n\\n  def toString string\\n}\\n\\nnamespace int {\\n  def MIN int { return -0x7FFFFFFF - 1 }\\n  def MAX int { return 0x7FFFFFFF }\\n}\\n\\n@import\\nclass double {\\n  def + double\\n  def ++ double\\n  def - double\\n  def -- double\\n\\n  def *(x double) double\\n  def +(x double) double\\n  def -(x double) double\\n  def /(x double) double\\n  def **(x double) double\\n  def <=>(x double) int\\n\\n  def %%(x double) double {\\n    return self - Math.floor(self / x) * x\\n  }\\n\\n  def *=(x double) double\\n  def +=(x double) double\\n  def -=(x double) double\\n  def /=(x double) double\\n\\n  def isFinite bool\\n  def isNaN bool\\n\\n  def toString string\\n}\\n\\n@import\\nclass string {\\n  def +(x string) string\\n  def +=(x string) string\\n  def <=>(x string) int\\n\\n  def count int\\n  def in(x string) bool\\n  def indexOf(x string) int\\n  def lastIndexOf(x string) int\\n  def startsWith(x string) bool\\n  def endsWith(x string) bool\\n\\n  def [](x int) int\\n  def get(x int) string\\n  def slice(start int) string\\n  def slice(start int, end int) string\\n  def codePoints List<int>\\n  def codeUnits List<int>\\n\\n  def split(x string) List<string>\\n  def join(x List<string>) string\\n  def repeat(x int) string\\n  def replaceAll(before string, after string) string\\n\\n  def toLowerCase string\\n  def toUpperCase string\\n  def toString string { return self }\\n}\\n\\nnamespace string {\\n  def fromCodePoint(x int) string\\n  def fromCodePoints(x List<int>) string\\n  def fromCodeUnit(x int) string\\n  def fromCodeUnits(x List<int>) string\\n}\\n\\n@import if TARGET == .NONE\\nclass StringBuilder {\\n  def new\\n  def append(x string)\\n  def toString string\\n}\\n\\n@import\\nclass List<T> {\\n  def new\\n  def [...](x T) List<T>\\n\\n  def [](x int) T\\n  def []=(x int, y T) T\\n\\n  def count int\\n  def isEmpty bool\\n  def resize(count int, defaultValue T)\\n\\n  @prefer\\n  def append(x T)\\n  def append(x List<T>)\\n  def appendOne(x T)\\n\\n  @prefer\\n  def prepend(x T)\\n  def prepend(x List<T>)\\n\\n  @prefer\\n  def insert(x int, value T)\\n  def insert(x int, values List<T>)\\n\\n  def removeAll(x T)\\n  def removeAt(x int)\\n  def removeDuplicates\\n  def removeFirst\\n  def removeIf(x fn(T) bool)\\n  def removeLast\\n  def removeOne(x T)\\n  def removeRange(start int, end int)\\n\\n  def takeFirst T\\n  def takeLast T\\n  def takeAt(x int) T\\n  def takeRange(start int, end int) List<T>\\n\\n  def first T\\n  def first=(x T) T { return self[0] = x }\\n  def last T\\n  def last=(x T) T { return self[count - 1] = x }\\n\\n  def in(x T) bool\\n  def indexOf(x T) int\\n  def lastIndexOf(x T) int\\n\\n  def all(x fn(T) bool) bool\\n  def any(x fn(T) bool) bool\\n  def clone List<T>\\n  def each(x fn(T))\\n  def equals(x List<T>) bool\\n  def filter(x fn(T) bool) List<T>\\n  def map<R>(x fn(T) R) List<R>\\n  def reverse\\n  def shuffle\\n  def slice(start int) List<T>\\n  def slice(start int, end int) List<T>\\n  def sort(x fn(T, T) int)\\n  def swap(x int, y int)\\n}\\n\\n@import\\nclass StringMap<T> {\\n  def new\\n  def {...}(key string, value T) StringMap<T>\\n\\n  def [](key string) T\\n  def []=(key string, value T) T\\n\\n  def count int\\n  def isEmpty bool\\n  def keys List<string>\\n  def values List<T>\\n\\n  def clone StringMap<T>\\n  def each(x fn(string, T))\\n  def get(key string, defaultValue T) T\\n  def in(key string) bool\\n  def remove(key string)\\n}\\n\\n@import\\nclass IntMap<T> {\\n  def new\\n  def {...}(key int, value T) IntMap<T>\\n\\n  def [](key int) T\\n  def []=(key int, value T) T\\n\\n  def count int\\n  def isEmpty bool\\n  def keys List<int>\\n  def values List<T>\\n\\n  def clone IntMap<T>\\n  def each(x fn(int, T))\\n  def get(key int, defaultValue T) T\\n  def in(key int) bool\\n  def remove(key int)\\n}\\n\\nclass Box<T> {\\n  var value T\\n}\\n\\n################################################################################\\n# Implementations\\n\\nclass int {\\n  def **(x int) int {\\n    var y = self\\n    var z = x < 0 ? 0 : 1\\n    while x > 0 {\\n      if (x & 1) != 0 { z *= y }\\n      x >>= 1\\n      y *= y\\n    }\\n    return z\\n  }\\n\\n  def <=>(x int) int {\\n    return ((x < self) as int) - ((x > self) as int)\\n  }\\n}\\n\\nclass double {\\n  @alwaysinline\\n  def **(x double) double {\\n    return Math.pow(self, x)\\n  }\\n\\n  def <=>(x double) int {\\n    return ((x < self) as int) - ((x > self) as int)\\n  }\\n}\\n\\nclass List {\\n  def resize(count int, defaultValue T) {\\n    assert(count >= 0)\\n    while self.count < count { append(defaultValue) }\\n    while self.count > count { removeLast }\\n  }\\n\\n  def removeAll(value T) {\\n    var index = 0\\n\\n    # Remove elements in place\\n    for i in 0..count {\\n      if self[i] != value {\\n        if index < i {\\n          self[index] = self[i]\\n        }\\n        index++\\n      }\\n    }\\n\\n    # Shrink the array to the correct size\\n    while index < count {\\n      removeLast\\n    }\\n  }\\n\\n  def removeDuplicates {\\n    var index = 0\\n\\n    # Remove elements in place\\n    for i in 0..count {\\n      var found = false\\n      var value = self[i]\\n      for j in 0..i {\\n        if value == self[j] {\\n          found = true\\n          break\\n        }\\n      }\\n      if !found {\\n        if index < i {\\n          self[index] = self[i]\\n        }\\n        index++\\n      }\\n    }\\n\\n    # Shrink the array to the correct size\\n    while index < count {\\n      removeLast\\n    }\\n  }\\n\\n  def shuffle {\\n    var n = count\\n    for i in 0..n - 1 {\\n      swap(i, i + ((Math.random * (n - i)) as int))\\n    }\\n  }\\n\\n  def swap(i int, j int) {\\n    assert(0 <= i && i < count)\\n    assert(0 <= j && j < count)\\n    var temp = self[i]\\n    self[i] = self[j]\\n    self[j] = temp\\n  }\\n}\\n\\nnamespace Math {\\n  def randomInRange(min double, max double) double {\\n    assert(min <= max)\\n    var value = min + (max - min) * random\\n    assert(min <= value && value <= max)\\n    return value\\n  }\\n\\n  def randomInRange(minInclusive int, maxExclusive int) int {\\n    assert(minInclusive <= maxExclusive)\\n    var value = minInclusive + ((maxExclusive - minInclusive) * random) as int\\n    assert(minInclusive <= value && (minInclusive != maxExclusive ? value < maxExclusive : value == maxExclusive))\\n    return value\\n  }\\n\\n  if TARGET != .JAVASCRIPT {\\n    def max(x double, y double, z double) double {\\n      return max(max(x, y), z)\\n    }\\n\\n    def min(x double, y double, z double) double {\\n      return min(min(x, y), z)\\n    }\\n\\n    def max(x int, y int, z int) int {\\n      return max(max(x, y), z)\\n    }\\n\\n    def min(x int, y int, z int) int {\\n      return min(min(x, y), z)\\n    }\\n\\n    def max(x double, y double, z double, w double) double {\\n      return max(max(x, y), max(z, w))\\n    }\\n\\n    def min(x double, y double, z double, w double) double {\\n      return min(min(x, y), min(z, w))\\n    }\\n\\n    def max(x int, y int, z int, w int) int {\\n      return max(max(x, y), max(z, w))\\n    }\\n\\n    def min(x int, y int, z int, w int) int {\\n      return min(min(x, y), min(z, w))\\n    }\\n  }\\n\\n  def clamp(x double, min double, max double) double {\\n    return x < min ? min : x > max ? max : x\\n  }\\n\\n  def clamp(x int, min int, max int) int {\\n    return x < min ? min : x > max ? max : x\\n  }\\n}\\n';\n  Skew.NATIVE_LIBRARY_CS = '\\n@using(\"System.Diagnostics\")\\ndef assert(truth bool) {\\n  dynamic.Debug.Assert(truth)\\n}\\n\\n@using(\"System\")\\nvar __random dynamic.Random = null\\n\\n@using(\"System\")\\n@import\\nnamespace Math {\\n  @rename(\"Abs\") if TARGET == .CSHARP\\n  def abs(x double) double\\n  @rename(\"Abs\") if TARGET == .CSHARP\\n  def abs(x int) int\\n\\n  @rename(\"Acos\") if TARGET == .CSHARP\\n  def acos(x double) double\\n  @rename(\"Asin\") if TARGET == .CSHARP\\n  def asin(x double) double\\n  @rename(\"Atan\") if TARGET == .CSHARP\\n  def atan(x double) double\\n  @rename(\"Atan2\") if TARGET == .CSHARP\\n  def atan2(x double, y double) double\\n\\n  @rename(\"Sin\") if TARGET == .CSHARP\\n  def sin(x double) double\\n  @rename(\"Cos\") if TARGET == .CSHARP\\n  def cos(x double) double\\n  @rename(\"Tan\") if TARGET == .CSHARP\\n  def tan(x double) double\\n\\n  @rename(\"Floor\") if TARGET == .CSHARP\\n  def floor(x double) double\\n  @rename(\"Ceiling\") if TARGET == .CSHARP\\n  def ceil(x double) double\\n  @rename(\"Round\") if TARGET == .CSHARP\\n  def round(x double) double\\n\\n  @rename(\"Exp\") if TARGET == .CSHARP\\n  def exp(x double) double\\n  @rename(\"Log\") if TARGET == .CSHARP\\n  def log(x double) double\\n  @rename(\"Pow\") if TARGET == .CSHARP\\n  def pow(x double, y double) double\\n  @rename(\"Sqrt\") if TARGET == .CSHARP\\n  def sqrt(x double) double\\n\\n  @rename(\"Max\") if TARGET == .CSHARP\\n  def max(x double, y double) double\\n  @rename(\"Max\") if TARGET == .CSHARP\\n  def max(x int, y int) int\\n\\n  @rename(\"Min\") if TARGET == .CSHARP\\n  def min(x double, y double) double\\n  @rename(\"Min\") if TARGET == .CSHARP\\n  def min(x int, y int) int\\n\\n  def random double {\\n    __random ?= dynamic.Random.new()\\n    return __random.NextDouble()\\n  }\\n}\\n\\nclass double {\\n  def isFinite bool {\\n    return !isNaN && !dynamic.double.IsInfinity(self)\\n  }\\n\\n  def isNaN bool {\\n    return dynamic.double.IsNaN(self)\\n  }\\n}\\n\\n@using(\"System.Text\")\\n@import\\nclass StringBuilder {\\n  @rename(\"Append\")\\n  def append(x string)\\n\\n  @rename(\"ToString\")\\n  def toString string\\n}\\n\\nclass bool {\\n  @rename(\"ToString\")\\n  def toString string {\\n    return self ? \"true\" : \"false\"\\n  }\\n}\\n\\nclass int {\\n  @rename(\"ToString\")\\n  def toString string\\n\\n  def >>>(x int) int {\\n    return dynamic.unchecked(self as dynamic.uint >> x) as int\\n  }\\n}\\n\\nclass double {\\n  @rename(\"ToString\")\\n  def toString string\\n}\\n\\nclass string {\\n  @rename(\"CompareTo\")\\n  def <=>(x string) int\\n\\n  @rename(\"StartsWith\")\\n  def startsWith(x string) bool\\n\\n  @rename(\"EndsWith\")\\n  def endsWith(x string) bool\\n\\n  @rename(\"Contains\")\\n  def in(x string) bool\\n\\n  @rename(\"IndexOf\")\\n  def indexOf(x string) int\\n\\n  @rename(\"LastIndexOf\")\\n  def lastIndexOf(x string) int\\n\\n  @rename(\"Replace\")\\n  def replaceAll(before string, after string) string\\n\\n  @rename(\"Substring\") {\\n    def slice(start int) string\\n    def slice(start int, end int) string\\n  }\\n\\n  @rename(\"ToLower\")\\n  def toLowerCase string\\n\\n  @rename(\"ToUpper\")\\n  def toUpperCase string\\n\\n  def count int {\\n    return (self as dynamic).Length\\n  }\\n\\n  def get(index int) string {\\n    return fromCodeUnit(self[index])\\n  }\\n\\n  def repeat(times int) string {\\n    var result = \"\"\\n    for i in 0..times {\\n      result += self\\n    }\\n    return result\\n  }\\n\\n  @using(\"System.Linq\")\\n  @using(\"System\")\\n  def split(separator string) List<string> {\\n    var separators = [separator]\\n    return dynamic.Enumerable.ToList((self as dynamic).Split(dynamic.Enumerable.ToArray(separators as dynamic), dynamic.StringSplitOptions.None))\\n  }\\n\\n  def join(parts List<string>) string {\\n    return dynamic.string.Join(self, parts)\\n  }\\n\\n  def slice(start int, end int) string {\\n    return (self as dynamic).Substring(start, end - start)\\n  }\\n\\n  def codeUnits List<int> {\\n    var result List<int> = []\\n    for i in 0..count {\\n      result.append(self[i])\\n    }\\n    return result\\n  }\\n}\\n\\nnamespace string {\\n  def fromCodeUnit(codeUnit int) string {\\n    return dynamic.string.new(codeUnit as dynamic.char, 1)\\n  }\\n\\n  def fromCodeUnits(codeUnits List<int>) string {\\n    var builder = StringBuilder.new\\n    for codeUnit in codeUnits {\\n      builder.append(codeUnit as dynamic.char)\\n    }\\n    return builder.toString\\n  }\\n}\\n\\n@using(\"System.Collections.Generic\")\\nclass List {\\n  @rename(\"Contains\")\\n  def in(x T) bool\\n\\n  @rename(\"Add\")\\n  def append(value T)\\n\\n  @rename(\"AddRange\")\\n  def append(value List<T>)\\n\\n  def sort(x fn(T, T) int) {\\n    # C# doesn\\'t allow an anonymous function to be passed directly\\n    (self as dynamic).Sort((a T, b T) => x(a, b))\\n  }\\n\\n  @rename(\"Reverse\")\\n  def reverse\\n\\n  @rename(\"RemoveAll\")\\n  def removeIf(x fn(T) bool)\\n\\n  @rename(\"RemoveAt\")\\n  def removeAt(x int)\\n\\n  @rename(\"Remove\")\\n  def removeOne(x T)\\n\\n  @rename(\"TrueForAll\")\\n  def all(x fn(T) bool) bool\\n\\n  @rename(\"ForEach\")\\n  def each(x fn(T))\\n\\n  @rename(\"FindAll\")\\n  def filter(x fn(T) bool) List<T>\\n\\n  @rename(\"ConvertAll\")\\n  def map<R>(x fn(T) R) List<R>\\n\\n  @rename(\"IndexOf\")\\n  def indexOf(x T) int\\n\\n  @rename(\"LastIndexOf\")\\n  def lastIndexOf(x T) int\\n\\n  @rename(\"Insert\")\\n  def insert(x int, value T)\\n\\n  @rename(\"InsertRange\")\\n  def insert(x int, value List<T>)\\n\\n  def appendOne(x T) {\\n    if !(x in self) {\\n      append(x)\\n    }\\n  }\\n\\n  def removeRange(start int, end int) {\\n    (self as dynamic).RemoveRange(start, end - start)\\n  }\\n\\n  @using(\"System.Linq\") {\\n    @rename(\"SequenceEqual\")\\n    def equals(x List<T>) bool\\n\\n    @rename(\"First\")\\n    def first T\\n\\n    @rename(\"Last\")\\n    def last T\\n  }\\n\\n  def any(callback fn(T) bool) bool {\\n    return !all(x => !callback(x))\\n  }\\n\\n  def isEmpty bool {\\n    return count == 0\\n  }\\n\\n  def count int {\\n    return (self as dynamic).Count\\n  }\\n\\n  def prepend(value T) {\\n    insert(0, value)\\n  }\\n\\n  def prepend(values List<T>) {\\n    var count = values.count\\n    for i in 0..count {\\n      prepend(values[count - i - 1])\\n    }\\n  }\\n\\n  def removeFirst {\\n    removeAt(0)\\n  }\\n\\n  def removeLast {\\n    removeAt(count - 1)\\n  }\\n\\n  def takeFirst T {\\n    var value = first\\n    removeFirst\\n    return value\\n  }\\n\\n  def takeLast T {\\n    var value = last\\n    removeLast\\n    return value\\n  }\\n\\n  def takeAt(x int) T {\\n    var value = self[x]\\n    removeAt(x)\\n    return value\\n  }\\n\\n  def takeRange(start int, end int) List<T> {\\n    var value = slice(start, end)\\n    removeRange(start, end)\\n    return value\\n  }\\n\\n  def slice(start int) List<T> {\\n    return slice(start, count)\\n  }\\n\\n  def slice(start int, end int) List<T> {\\n    return (self as dynamic).GetRange(start, end - start)\\n  }\\n\\n  def clone List<T> {\\n    var clone = new\\n    clone.append(self)\\n    return clone\\n  }\\n}\\n\\n@using(\"System.Collections.Generic\")\\n@rename(\"Dictionary\")\\nclass StringMap {\\n  def count int {\\n    return (self as dynamic).Count\\n  }\\n\\n  @rename(\"ContainsKey\")\\n  def in(key string) bool\\n\\n  @rename(\"Remove\")\\n  def remove(key string)\\n\\n  def isEmpty bool {\\n    return count == 0\\n  }\\n\\n  def {...}(key string, value T) StringMap<T> {\\n    (self as dynamic).Add(key, value)\\n    return self\\n  }\\n\\n  def get(key string, value T) T {\\n    return key in self ? self[key] : value\\n  }\\n\\n  def keys List<string> {\\n    return dynamic.System.Linq.Enumerable.ToList((self as dynamic).Keys)\\n  }\\n\\n  def values List<T> {\\n    return dynamic.System.Linq.Enumerable.ToList((self as dynamic).Values)\\n  }\\n\\n  def clone StringMap<T> {\\n    var clone = new\\n    for key in keys {\\n      clone[key] = self[key]\\n    }\\n    return clone\\n  }\\n\\n  def each(x fn(string, T)) {\\n    for pair in self as dynamic {\\n      x(pair.Key, pair.Value)\\n    }\\n  }\\n}\\n\\n@using(\"System.Collections.Generic\")\\n@rename(\"Dictionary\")\\nclass IntMap {\\n  def count int {\\n    return (self as dynamic).Count\\n  }\\n\\n  @rename(\"ContainsKey\")\\n  def in(key int) bool\\n\\n  @rename(\"Remove\")\\n  def remove(key int)\\n\\n  def isEmpty bool {\\n    return count == 0\\n  }\\n\\n  def {...}(key int, value T) IntMap<T> {\\n    (self as dynamic).Add(key, value)\\n    return self\\n  }\\n\\n  def get(key int, value T) T {\\n    return key in self ? self[key] : value\\n  }\\n\\n  def keys List<int> {\\n    return dynamic.System.Linq.Enumerable.ToList((self as dynamic).Keys)\\n  }\\n\\n  def values List<T> {\\n    return dynamic.System.Linq.Enumerable.ToList((self as dynamic).Values)\\n  }\\n\\n  def clone IntMap<T> {\\n    var clone = new\\n    for key in keys {\\n      clone[key] = self[key]\\n    }\\n    return clone\\n  }\\n\\n  def each(x fn(int, T)) {\\n    for pair in self as dynamic {\\n      x(pair.Key, pair.Value)\\n    }\\n  }\\n}\\n';\n  Skew.CSharpEmitter._isKeyword = in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(new Map(), 'abstract', 0), 'as', 0), 'base', 0), 'bool', 0), 'break', 0), 'byte', 0), 'case', 0), 'catch', 0), 'char', 0), 'checked', 0), 'class', 0), 'const', 0), 'continue', 0), 'decimal', 0), 'default', 0), 'delegate', 0), 'do', 0), 'double', 0), 'else', 0), 'enum', 0), 'event', 0), 'explicit', 0), 'extern', 0), 'false', 0), 'finally', 0), 'fixed', 0), 'float', 0), 'for', 0), 'foreach', 0), 'goto', 0), 'if', 0), 'implicit', 0), 'in', 0), 'int', 0), 'interface', 0), 'internal', 0), 'is', 0), 'lock', 0), 'long', 0), 'namespace', 0), 'new', 0), 'null', 0), 'object', 0), 'operator', 0), 'out', 0), 'override', 0), 'params', 0), 'private', 0), 'protected', 0), 'public', 0), 'readonly', 0), 'ref', 0), 'return', 0), 'sbyte', 0), 'sealed', 0), 'short', 0), 'sizeof', 0), 'stackalloc', 0), 'static', 0), 'string', 0), 'struct', 0), 'switch', 0), 'this', 0), 'throw', 0), 'true', 0), 'try', 0), 'typeof', 0), 'uint', 0), 'ulong', 0), 'unchecked', 0), 'unsafe', 0), 'ushort', 0), 'using', 0), 'virtual', 0), 'void', 0), 'volatile', 0), 'while', 0);\n  Skew.JavaScriptEmitter._first = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$';\n  Skew.JavaScriptEmitter._rest = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$0123456789';\n  Skew.JavaScriptEmitter._isFunctionProperty = in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(new Map(), 'apply', 0), 'call', 0), 'length', 0), 'name', 0);\n  Skew.JavaScriptEmitter._isKeyword = in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(new Map(), 'arguments', 0), 'await', 0), 'Boolean', 0), 'break', 0), 'case', 0), 'catch', 0), 'class', 0), 'const', 0), 'constructor', 0), 'continue', 0), 'Date', 0), 'debugger', 0), 'default', 0), 'delete', 0), 'do', 0), 'double', 0), 'else', 0), 'enum', 0), 'eval', 0), 'export', 0), 'extends', 0), 'false', 0), 'finally', 0), 'float', 0), 'for', 0), 'function', 0), 'Function', 0), 'if', 0), 'implements', 0), 'import', 0), 'in', 0), 'instanceof', 0), 'int', 0), 'interface', 0), 'let', 0), 'new', 0), 'null', 0), 'Number', 0), 'Object', 0), 'package', 0), 'private', 0), 'protected', 0), 'public', 0), 'return', 0), 'static', 0), 'String', 0), 'super', 0), 'switch', 0), 'this', 0), 'throw', 0), 'true', 0), 'try', 0), 'typeof', 0), 'var', 0), 'void', 0), 'while', 0), 'with', 0), 'yield', 0);\n  Skew.JavaScriptEmitter._keywordCallMap = in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(new Map(), 'delete', 0), 'typeof', 0), 'void', 0);\n  Skew.JavaScriptEmitter._specialVariableMap = in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(new Map(), '__asString', Skew.JavaScriptEmitter.SpecialVariable.AS_STRING), '__create', Skew.JavaScriptEmitter.SpecialVariable.CREATE), '__extends', Skew.JavaScriptEmitter.SpecialVariable.EXTENDS), '__imul', Skew.JavaScriptEmitter.SpecialVariable.MULTIPLY), '__isBool', Skew.JavaScriptEmitter.SpecialVariable.IS_BOOL), '__isDouble', Skew.JavaScriptEmitter.SpecialVariable.IS_DOUBLE), '__isInt', Skew.JavaScriptEmitter.SpecialVariable.IS_INT), '__isString', Skew.JavaScriptEmitter.SpecialVariable.IS_STRING), '__prototype', Skew.JavaScriptEmitter.SpecialVariable.PROTOTYPE);\n\n  // https://github.com/Microsoft/TypeScript/issues/2536\n  Skew.TypeScriptEmitter._isKeyword = in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(new Map(), 'break', 0), 'case', 0), 'catch', 0), 'class', 0), 'const', 0), 'continue', 0), 'debugger', 0), 'default', 0), 'delete', 0), 'do', 0), 'else', 0), 'enum', 0), 'export', 0), 'extends', 0), 'false', 0), 'finally', 0), 'for', 0), 'function', 0), 'if', 0), 'implements', 0), 'import', 0), 'in', 0), 'instanceof', 0), 'interface', 0), 'namespace', 0), 'new', 0), 'null', 0), 'return', 0), 'super', 0), 'switch', 0), 'this', 0), 'throw', 0), 'true', 0), 'try', 0), 'typeof', 0), 'var', 0), 'void', 0), 'while', 0), 'with', 0), 'as', 0), 'implements', 0), 'interface', 0), 'let', 0), 'package', 0), 'private', 0), 'protected', 0), 'public', 0), 'static', 0), 'yield', 0), 'arguments', 0), 'Symbol', 0);\n  Skew.TypeScriptEmitter._specialVariableMap = in_StringMap.insert(in_StringMap.insert(new Map(), '__asString', Skew.TypeScriptEmitter.SpecialVariable.AS_STRING), '__isInt', Skew.TypeScriptEmitter.SpecialVariable.IS_INT);\n  Skew.CPlusPlusEmitter._isNative = in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(new Map(), 'auto', 0), 'bool', 0), 'char', 0), 'char16_t', 0), 'char32_t', 0), 'const_cast', 0), 'double', 0), 'dynamic_cast', 0), 'false', 0), 'float', 0), 'INFINITY', 0), 'int', 0), 'long', 0), 'NAN', 0), 'NULL', 0), 'nullptr', 0), 'reinterpret_cast', 0), 'short', 0), 'signed', 0), 'static_assert', 0), 'static_cast', 0), 'this', 0), 'true', 0), 'unsigned', 0), 'void', 0), 'wchar_t', 0);\n  Skew.CPlusPlusEmitter._isKeyword = in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(new Map(), 'alignas', 0), 'alignof', 0), 'and', 0), 'and_eq', 0), 'asm', 0), 'bitand', 0), 'bitor', 0), 'break', 0), 'case', 0), 'catch', 0), 'class', 0), 'compl', 0), 'const', 0), 'constexpr', 0), 'continue', 0), 'decltype', 0), 'default', 0), 'delete', 0), 'do', 0), 'else', 0), 'enum', 0), 'explicit', 0), 'export', 0), 'extern', 0), 'for', 0), 'friend', 0), 'goto', 0), 'if', 0), 'inline', 0), 'mutable', 0), 'namespace', 0), 'new', 0), 'noexcept', 0), 'not', 0), 'not_eq', 0), 'operator', 0), 'or', 0), 'or_eq', 0), 'private', 0), 'protected', 0), 'public', 0), 'register', 0), 'return', 0), 'sizeof', 0), 'static', 0), 'struct', 0), 'switch', 0), 'template', 0), 'thread_local', 0), 'throw', 0), 'try', 0), 'typedef', 0), 'typeid', 0), 'typename', 0), 'union', 0), 'using', 0), 'virtual', 0), 'volatile', 0), 'while', 0), 'xor', 0), 'xor_eq', 0);\n  Skew.Symbol._nextID = 0;\n  Skew.Node._nextID = 0;\n  Skew.Parsing.expressionParser = null;\n  Skew.Parsing.typeParser = null;\n  Skew.Parsing.identifierToSymbolKind = in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(new Map(), 'class', Skew.SymbolKind.OBJECT_CLASS), 'def', Skew.SymbolKind.FUNCTION_GLOBAL), 'enum', Skew.SymbolKind.OBJECT_ENUM), 'flags', Skew.SymbolKind.OBJECT_FLAGS), 'interface', Skew.SymbolKind.OBJECT_INTERFACE), 'namespace', Skew.SymbolKind.OBJECT_NAMESPACE), 'over', Skew.SymbolKind.FUNCTION_GLOBAL), 'type', Skew.SymbolKind.OBJECT_WRAPPED);\n  Skew.Parsing.customOperators = in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(new Map(), Skew.TokenKind.ASSIGN_BITWISE_AND, 0), Skew.TokenKind.ASSIGN_BITWISE_OR, 0), Skew.TokenKind.ASSIGN_BITWISE_XOR, 0), Skew.TokenKind.ASSIGN_DIVIDE, 0), Skew.TokenKind.ASSIGN_INDEX, 0), Skew.TokenKind.ASSIGN_MINUS, 0), Skew.TokenKind.ASSIGN_MODULUS, 0), Skew.TokenKind.ASSIGN_MULTIPLY, 0), Skew.TokenKind.ASSIGN_PLUS, 0), Skew.TokenKind.ASSIGN_POWER, 0), Skew.TokenKind.ASSIGN_REMAINDER, 0), Skew.TokenKind.ASSIGN_SHIFT_LEFT, 0), Skew.TokenKind.ASSIGN_SHIFT_RIGHT, 0), Skew.TokenKind.ASSIGN_UNSIGNED_SHIFT_RIGHT, 0), Skew.TokenKind.BITWISE_AND, 0), Skew.TokenKind.BITWISE_OR, 0), Skew.TokenKind.BITWISE_XOR, 0), Skew.TokenKind.COMPARE, 0), Skew.TokenKind.DECREMENT, 0), Skew.TokenKind.DIVIDE, 0), Skew.TokenKind.IN, 0), Skew.TokenKind.INCREMENT, 0), Skew.TokenKind.INDEX, 0), Skew.TokenKind.LIST, 0), Skew.TokenKind.MINUS, 0), Skew.TokenKind.MODULUS, 0), Skew.TokenKind.MULTIPLY, 0), Skew.TokenKind.NOT, 0), Skew.TokenKind.PLUS, 0), Skew.TokenKind.POWER, 0), Skew.TokenKind.REMAINDER, 0), Skew.TokenKind.SET, 0), Skew.TokenKind.SHIFT_LEFT, 0), Skew.TokenKind.SHIFT_RIGHT, 0), Skew.TokenKind.TILDE, 0), Skew.TokenKind.UNSIGNED_SHIFT_RIGHT, 0), Skew.TokenKind.XML_CHILD, 0);\n  Skew.Parsing.forbiddenCustomOperators = in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(new Map(), Skew.TokenKind.ASSIGN, Skew.Parsing.ForbiddenGroup.ASSIGN), Skew.TokenKind.EQUAL, Skew.Parsing.ForbiddenGroup.EQUAL), Skew.TokenKind.GREATER_THAN, Skew.Parsing.ForbiddenGroup.COMPARE), Skew.TokenKind.GREATER_THAN_OR_EQUAL, Skew.Parsing.ForbiddenGroup.COMPARE), Skew.TokenKind.LESS_THAN, Skew.Parsing.ForbiddenGroup.COMPARE), Skew.TokenKind.LESS_THAN_OR_EQUAL, Skew.Parsing.ForbiddenGroup.COMPARE), Skew.TokenKind.LOGICAL_AND, Skew.Parsing.ForbiddenGroup.LOGICAL), Skew.TokenKind.LOGICAL_OR, Skew.Parsing.ForbiddenGroup.LOGICAL), Skew.TokenKind.NOT_EQUAL, Skew.Parsing.ForbiddenGroup.EQUAL);\n\n  // These are prefixed with \"the operator \\\"...\\\" is not customizable because \"\n  Skew.Parsing.forbiddenGroupDescription = in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(new Map(), Skew.Parsing.ForbiddenGroup.ASSIGN, 'value types are not supported by the language'), Skew.Parsing.ForbiddenGroup.COMPARE, 'it\\'s automatically implemented using the \"<=>\" operator (customize the \"<=>\" operator instead)'), Skew.Parsing.ForbiddenGroup.EQUAL, \"that wouldn't work with generics, which are implemented with type erasure\"), Skew.Parsing.ForbiddenGroup.LOGICAL, 'of its special short-circuit evaluation behavior');\n  Skew.Parsing.assignmentOperators = in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(new Map(), Skew.TokenKind.ASSIGN, Skew.NodeKind.ASSIGN), Skew.TokenKind.ASSIGN_BITWISE_AND, Skew.NodeKind.ASSIGN_BITWISE_AND), Skew.TokenKind.ASSIGN_BITWISE_OR, Skew.NodeKind.ASSIGN_BITWISE_OR), Skew.TokenKind.ASSIGN_BITWISE_XOR, Skew.NodeKind.ASSIGN_BITWISE_XOR), Skew.TokenKind.ASSIGN_DIVIDE, Skew.NodeKind.ASSIGN_DIVIDE), Skew.TokenKind.ASSIGN_MINUS, Skew.NodeKind.ASSIGN_SUBTRACT), Skew.TokenKind.ASSIGN_MODULUS, Skew.NodeKind.ASSIGN_MODULUS), Skew.TokenKind.ASSIGN_MULTIPLY, Skew.NodeKind.ASSIGN_MULTIPLY), Skew.TokenKind.ASSIGN_PLUS, Skew.NodeKind.ASSIGN_ADD), Skew.TokenKind.ASSIGN_POWER, Skew.NodeKind.ASSIGN_POWER), Skew.TokenKind.ASSIGN_REMAINDER, Skew.NodeKind.ASSIGN_REMAINDER), Skew.TokenKind.ASSIGN_SHIFT_LEFT, Skew.NodeKind.ASSIGN_SHIFT_LEFT), Skew.TokenKind.ASSIGN_SHIFT_RIGHT, Skew.NodeKind.ASSIGN_SHIFT_RIGHT), Skew.TokenKind.ASSIGN_UNSIGNED_SHIFT_RIGHT, Skew.NodeKind.ASSIGN_UNSIGNED_SHIFT_RIGHT);\n  Skew.Parsing.dotInfixParselet = function(context, left) {\n    var innerComments = context.stealComments();\n    var token = context.next();\n    var range = context.current().range;\n\n    if (!context.expect(Skew.TokenKind.IDENTIFIER)) {\n      // Create a empty range instead of using createParseError so IDE code completion still works\n      range = new Skew.Range(token.range.source, token.range.end, token.range.end);\n    }\n\n    return new Skew.Node(Skew.NodeKind.DOT).withContent(new Skew.StringContent(range.toString())).appendChild(left).withRange(context.spanSince(left.range)).withInternalRange(range).withInnerComments(innerComments);\n  };\n  Skew.Parsing.initializerParselet = function(context) {\n    var token = context.next();\n    var kind = token.kind == Skew.TokenKind.LEFT_BRACE ? Skew.NodeKind.INITIALIZER_MAP : Skew.NodeKind.INITIALIZER_LIST;\n    var node = Skew.Node.createInitializer(kind);\n\n    if (token.kind == Skew.TokenKind.LEFT_BRACE || token.kind == Skew.TokenKind.LEFT_BRACKET) {\n      var expectColon = kind != Skew.NodeKind.INITIALIZER_LIST;\n      var end = expectColon ? Skew.TokenKind.RIGHT_BRACE : Skew.TokenKind.RIGHT_BRACKET;\n\n      while (true) {\n        context.eat(Skew.TokenKind.NEWLINE);\n        var comments = context.stealComments();\n\n        if (context.peek1(end)) {\n          Skew.Parsing._warnAboutIgnoredComments(context, comments);\n          break;\n        }\n\n        var first = Skew.Parsing.expressionParser.parse(context, Skew.Precedence.LOWEST);\n        var colon = context.current();\n\n        if (!expectColon) {\n          node.appendChild(first);\n        }\n\n        else {\n          if (!context.expect(Skew.TokenKind.COLON)) {\n            break;\n          }\n\n          var second = Skew.Parsing.expressionParser.parse(context, Skew.Precedence.LOWEST);\n          first = Skew.Node.createPair(first, second).withRange(Skew.Range.span(first.range, second.range)).withInternalRange(colon.range);\n          node.appendChild(first);\n        }\n\n        first.comments = Skew.Comment.concat(comments, Skew.Parsing.parseTrailingComment(context));\n\n        if (!context.eat(Skew.TokenKind.COMMA)) {\n          break;\n        }\n\n        first.comments = Skew.Comment.concat(first.comments, Skew.Parsing.parseTrailingComment(context));\n      }\n\n      context.skipWhitespace();\n      Skew.Parsing.scanForToken(context, end);\n    }\n\n    else if (token.kind == Skew.TokenKind.LIST_NEW || token.kind == Skew.TokenKind.SET_NEW) {\n      node.appendChild(new Skew.Node(Skew.NodeKind.NAME).withContent(new Skew.StringContent('new')).withRange(new Skew.Range(token.range.source, token.range.start + 1 | 0, token.range.end - 1 | 0)));\n    }\n\n    return node.withRange(context.spanSince(token.range));\n  };\n  Skew.Parsing.parameterizedParselet = function(context, left) {\n    var value = Skew.Node.createParameterize(left);\n    var token = context.next();\n\n    while (true) {\n      var type = Skew.Parsing.typeParser.parse(context, Skew.Precedence.LOWEST);\n      value.appendChild(type);\n\n      if (!context.eat(Skew.TokenKind.COMMA)) {\n        break;\n      }\n    }\n\n    Skew.Parsing.scanForToken(context, Skew.TokenKind.PARAMETER_LIST_END);\n    return value.withRange(context.spanSince(left.range)).withInternalRange(context.spanSince(token.range));\n  };\n  Skew.Resolving.Resolver._annotationSymbolFlags = in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(new Map(), '@alwaysinline', Skew.SymbolFlags.IS_INLINING_FORCED), '@deprecated', Skew.SymbolFlags.IS_DEPRECATED), '@entry', Skew.SymbolFlags.IS_ENTRY_POINT), '@export', Skew.SymbolFlags.IS_EXPORTED), '@import', Skew.SymbolFlags.IS_IMPORTED), '@neverinline', Skew.SymbolFlags.IS_INLINING_PREVENTED), '@prefer', Skew.SymbolFlags.IS_PREFERRED), '@rename', Skew.SymbolFlags.IS_RENAMED), '@skip', Skew.SymbolFlags.IS_SKIPPED), '@spreads', Skew.SymbolFlags.SHOULD_SPREAD);\n  Skew.LambdaConversion.Scope._nextID = 0;\n  Skew.Type.DYNAMIC = new Skew.Type(Skew.TypeKind.SPECIAL, null);\n  Skew.Type.NULL = new Skew.Type(Skew.TypeKind.SPECIAL, null);\n  Skew.Type._nextID = 0;\n  Skew.Environment._nextID = 0;\n  Skew.Renaming.unaryPrefixes = in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(new Map(), '!', 'not'), '+', 'positive'), '++', 'increment'), '-', 'negative'), '--', 'decrement'), '~', 'complement');\n  Skew.Renaming.prefixes = in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(in_StringMap.insert(new Map(), '%', 'remainder'), '%%', 'modulus'), '&', 'and'), '*', 'multiply'), '**', 'power'), '+', 'add'), '-', 'subtract'), '/', 'divide'), '<<', 'leftShift'), '<=>', 'compare'), '>>', 'rightShift'), '>>>', 'unsignedRightShift'), '^', 'xor'), 'in', 'contains'), '|', 'or'), '%%=', 'modulusUpdate'), '%=', 'remainderUpdate'), '&=', 'andUpdate'), '**=', 'powerUpdate'), '*=', 'multiplyUpdate'), '+=', 'addUpdate'), '-=', 'subtractUpdate'), '/=', 'divideUpdate'), '<<=', 'leftShiftUpdate'), '>>=', 'rightShiftUpdate'), '^=', 'xorUpdate'), '|=', 'orUpdate'), '[]', 'get'), '[]=', 'set'), '<>...</>', 'append'), '[...]', 'append'), '[new]', 'new'), '{...}', 'insert'), '{new}', 'new');\n  Skew.in_PassKind._strings = ['EMITTING', 'LEXING', 'PARSING', 'RESOLVING', 'LAMBDA_CONVERSION', 'CALL_GRAPH', 'INLINING', 'FOLDING', 'MOTION', 'GLOBALIZING', 'MERGING', 'INTERFACE_REMOVAL', 'RENAMING'];\n  Skew.in_SymbolKind._strings = ['PARAMETER_FUNCTION', 'PARAMETER_OBJECT', 'OBJECT_CLASS', 'OBJECT_ENUM', 'OBJECT_FLAGS', 'OBJECT_GLOBAL', 'OBJECT_INTERFACE', 'OBJECT_NAMESPACE', 'OBJECT_WRAPPED', 'FUNCTION_ANNOTATION', 'FUNCTION_CONSTRUCTOR', 'FUNCTION_GLOBAL', 'FUNCTION_INSTANCE', 'FUNCTION_LOCAL', 'OVERLOADED_ANNOTATION', 'OVERLOADED_GLOBAL', 'OVERLOADED_INSTANCE', 'VARIABLE_ARGUMENT', 'VARIABLE_ENUM_OR_FLAGS', 'VARIABLE_GLOBAL', 'VARIABLE_INSTANCE', 'VARIABLE_LOCAL'];\n  Skew.in_NodeKind._strings = ['ANNOTATION', 'BLOCK', 'CASE', 'CATCH', 'VARIABLE', 'BREAK', 'COMMENT_BLOCK', 'CONTINUE', 'EXPRESSION', 'FOR', 'FOREACH', 'IF', 'RETURN', 'SWITCH', 'THROW', 'TRY', 'VARIABLES', 'WHILE', 'ASSIGN_INDEX', 'CALL', 'CAST', 'CONSTANT', 'DOT', 'HOOK', 'INDEX', 'INITIALIZER_LIST', 'INITIALIZER_MAP', 'LAMBDA', 'LAMBDA_TYPE', 'NAME', 'NULL', 'NULL_DOT', 'PAIR', 'PARAMETERIZE', 'PARSE_ERROR', 'SEQUENCE', 'STRING_INTERPOLATION', 'SUPER', 'TYPE', 'TYPE_CHECK', 'XML', 'COMPLEMENT', 'NEGATIVE', 'NOT', 'POSITIVE', 'POSTFIX_DECREMENT', 'POSTFIX_INCREMENT', 'PREFIX_DECREMENT', 'PREFIX_INCREMENT', 'ADD', 'BITWISE_AND', 'BITWISE_OR', 'BITWISE_XOR', 'COMPARE', 'DIVIDE', 'EQUAL', 'IN', 'LOGICAL_AND', 'LOGICAL_OR', 'MODULUS', 'MULTIPLY', 'NOT_EQUAL', 'NULL_JOIN', 'POWER', 'REMAINDER', 'SHIFT_LEFT', 'SHIFT_RIGHT', 'SUBTRACT', 'UNSIGNED_SHIFT_RIGHT', 'GREATER_THAN', 'GREATER_THAN_OR_EQUAL', 'LESS_THAN', 'LESS_THAN_OR_EQUAL', 'ASSIGN', 'ASSIGN_ADD', 'ASSIGN_BITWISE_AND', 'ASSIGN_BITWISE_OR', 'ASSIGN_BITWISE_XOR', 'ASSIGN_DIVIDE', 'ASSIGN_MODULUS', 'ASSIGN_MULTIPLY', 'ASSIGN_NULL', 'ASSIGN_POWER', 'ASSIGN_REMAINDER', 'ASSIGN_SHIFT_LEFT', 'ASSIGN_SHIFT_RIGHT', 'ASSIGN_SUBTRACT', 'ASSIGN_UNSIGNED_SHIFT_RIGHT', 'A', 'B', 'C', 'D', 'E', 'F', 'G'];\n  Skew.in_TokenKind._toString = in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(new Map(), Skew.TokenKind.COMMENT, 'comment'), Skew.TokenKind.NEWLINE, 'newline'), Skew.TokenKind.WHITESPACE, 'whitespace'), Skew.TokenKind.AS, '\"as\"'), Skew.TokenKind.BREAK, '\"break\"'), Skew.TokenKind.CASE, '\"case\"'), Skew.TokenKind.CATCH, '\"catch\"'), Skew.TokenKind.CONST, '\"const\"'), Skew.TokenKind.CONTINUE, '\"continue\"'), Skew.TokenKind.DEFAULT, '\"default\"'), Skew.TokenKind.DYNAMIC, '\"dynamic\"'), Skew.TokenKind.ELSE, '\"else\"'), Skew.TokenKind.FALSE, '\"false\"'), Skew.TokenKind.FINALLY, '\"finally\"'), Skew.TokenKind.FOR, '\"for\"'), Skew.TokenKind.IF, '\"if\"'), Skew.TokenKind.IN, '\"in\"'), Skew.TokenKind.IS, '\"is\"'), Skew.TokenKind.NULL, '\"null\"'), Skew.TokenKind.RETURN, '\"return\"'), Skew.TokenKind.SUPER, '\"super\"'), Skew.TokenKind.SWITCH, '\"switch\"'), Skew.TokenKind.THROW, '\"throw\"'), Skew.TokenKind.TRUE, '\"true\"'), Skew.TokenKind.TRY, '\"try\"'), Skew.TokenKind.VAR, '\"var\"'), Skew.TokenKind.WHILE, '\"while\"'), Skew.TokenKind.ARROW, '\"=>\"'), Skew.TokenKind.ASSIGN, '\"=\"'), Skew.TokenKind.ASSIGN_BITWISE_AND, '\"&=\"'), Skew.TokenKind.ASSIGN_BITWISE_OR, '\"|=\"'), Skew.TokenKind.ASSIGN_BITWISE_XOR, '\"^=\"'), Skew.TokenKind.ASSIGN_DIVIDE, '\"/=\"'), Skew.TokenKind.ASSIGN_INDEX, '\"[]=\"'), Skew.TokenKind.ASSIGN_MINUS, '\"-=\"'), Skew.TokenKind.ASSIGN_MODULUS, '\"%%=\"'), Skew.TokenKind.ASSIGN_MULTIPLY, '\"*=\"'), Skew.TokenKind.ASSIGN_PLUS, '\"+=\"'), Skew.TokenKind.ASSIGN_POWER, '\"**=\"'), Skew.TokenKind.ASSIGN_REMAINDER, '\"%=\"'), Skew.TokenKind.ASSIGN_SHIFT_LEFT, '\"<<=\"'), Skew.TokenKind.ASSIGN_SHIFT_RIGHT, '\">>=\"'), Skew.TokenKind.ASSIGN_UNSIGNED_SHIFT_RIGHT, '\">>>=\"'), Skew.TokenKind.BITWISE_AND, '\"&\"'), Skew.TokenKind.BITWISE_OR, '\"|\"'), Skew.TokenKind.BITWISE_XOR, '\"^\"'), Skew.TokenKind.COLON, '\":\"'), Skew.TokenKind.COMMA, '\",\"'), Skew.TokenKind.COMPARE, '\"<=>\"'), Skew.TokenKind.DECREMENT, '\"--\"'), Skew.TokenKind.DIVIDE, '\"/\"'), Skew.TokenKind.DOT, '\".\"'), Skew.TokenKind.DOT_DOT, '\"..\"'), Skew.TokenKind.DOUBLE_COLON, '\"::\"'), Skew.TokenKind.EQUAL, '\"==\"'), Skew.TokenKind.GREATER_THAN, '\">\"'), Skew.TokenKind.GREATER_THAN_OR_EQUAL, '\">=\"'), Skew.TokenKind.INCREMENT, '\"++\"'), Skew.TokenKind.INDEX, '\"[]\"'), Skew.TokenKind.LEFT_BRACE, '\"{\"'), Skew.TokenKind.LEFT_BRACKET, '\"[\"'), Skew.TokenKind.LEFT_PARENTHESIS, '\"(\"'), Skew.TokenKind.LESS_THAN, '\"<\"'), Skew.TokenKind.LESS_THAN_OR_EQUAL, '\"<=\"'), Skew.TokenKind.LIST, '\"[...]\"'), Skew.TokenKind.LIST_NEW, '\"[new]\"'), Skew.TokenKind.LOGICAL_AND, '\"&&\"'), Skew.TokenKind.LOGICAL_OR, '\"||\"'), Skew.TokenKind.MINUS, '\"-\"'), Skew.TokenKind.MODULUS, '\"%%\"'), Skew.TokenKind.MULTIPLY, '\"*\"'), Skew.TokenKind.NOT, '\"!\"'), Skew.TokenKind.NOT_EQUAL, '\"!=\"'), Skew.TokenKind.NULL_DOT, '\"?.\"'), Skew.TokenKind.NULL_JOIN, '\"??\"'), Skew.TokenKind.PLUS, '\"+\"'), Skew.TokenKind.POWER, '\"**\"'), Skew.TokenKind.QUESTION_MARK, '\"?\"'), Skew.TokenKind.REMAINDER, '\"%\"'), Skew.TokenKind.RIGHT_BRACE, '\"}\"'), Skew.TokenKind.RIGHT_BRACKET, '\"]\"'), Skew.TokenKind.RIGHT_PARENTHESIS, '\")\"'), Skew.TokenKind.SEMICOLON, '\";\"'), Skew.TokenKind.SET, '\"{...}\"'), Skew.TokenKind.SET_NEW, '\"{new}\"'), Skew.TokenKind.SHIFT_LEFT, '\"<<\"'), Skew.TokenKind.SHIFT_RIGHT, '\">>\"'), Skew.TokenKind.TILDE, '\"~\"'), Skew.TokenKind.UNSIGNED_SHIFT_RIGHT, '\">>>\"'), Skew.TokenKind.ANNOTATION, 'annotation'), Skew.TokenKind.CHARACTER, 'character'), Skew.TokenKind.DOUBLE, 'double'), Skew.TokenKind.END_OF_FILE, 'end of input'), Skew.TokenKind.IDENTIFIER, 'identifier'), Skew.TokenKind.INT, 'integer'), Skew.TokenKind.INT_BINARY, 'integer'), Skew.TokenKind.INT_HEX, 'integer'), Skew.TokenKind.INT_OCTAL, 'integer'), Skew.TokenKind.STRING, 'string'), Skew.TokenKind.PARAMETER_LIST_END, '\">\"'), Skew.TokenKind.PARAMETER_LIST_START, '\"<\"'), Skew.TokenKind.XML_CHILD, '\"<>...</>\"'), Skew.TokenKind.XML_END, '\">\"'), Skew.TokenKind.XML_END_EMPTY, '\"/>\"'), Skew.TokenKind.XML_START, '\"<\"'), Skew.TokenKind.XML_START_CLOSE, '\"</\"'), Skew.TokenKind.STRING_INTERPOLATION_CONTINUE, 'string interpolation'), Skew.TokenKind.STRING_INTERPOLATION_END, 'string interpolation'), Skew.TokenKind.STRING_INTERPOLATION_START, 'string interpolation');\n  Terminal.colorToEscapeCode = in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(in_IntMap.insert(new Map(), Terminal.Color.DEFAULT, 0), Terminal.Color.BOLD, 1), Terminal.Color.GRAY, 90), Terminal.Color.RED, 91), Terminal.Color.GREEN, 92), Terminal.Color.YELLOW, 93), Terminal.Color.BLUE, 94), Terminal.Color.MAGENTA, 95), Terminal.Color.CYAN, 96);\n\n  process.exit(Skew.skewcMain(process.argv.slice(2)));\n})();\n"
  },
  {
    "path": "src/backend/cplusplus.sk",
    "content": "namespace Skew {\n  class CPlusPlusTarget : CompilerTarget {\n    over name string { return \"C++\" }\n    over extension string { return \"cpp\" }\n    over stopAfterResolve bool { return false }\n    over requiresIntegerSwitchStatements bool { return true }\n    over supportsListForeach bool { return true }\n    over needsLambdaLifting bool { return true }\n    over stringEncoding Unicode.Encoding { return .UTF8 }\n    over editOptions(options CompilerOptions) { options.define(\"TARGET\", \"CPLUSPLUS\") }\n    over includeSources(sources List<Source>) { sources.prepend(Source.new(\"<native-cpp>\", NATIVE_LIBRARY_CPP)) }\n    over createEmitter(context PassContext) Emitter { return CPlusPlusEmitter.new(context.options, context.cache) }\n  }\n\n  class CPlusPlusEmitter : Emitter {\n    const _options CompilerOptions\n    const _cache TypeCache\n    var _previousNode Node = null\n    var _previousSymbol Symbol = null\n    var _namespaceStack List<Symbol> = []\n    var _symbolsCheckedForInclude IntMap<int> = {}\n    var _includeNames StringMap<int> = {}\n    var _loopLabels IntMap<VariableSymbol> = {}\n    var _enclosingFunction FunctionSymbol = null\n    var _dummyFunction = FunctionSymbol.new(.FUNCTION_INSTANCE, \"<dummy>\")\n\n    over visit(global ObjectSymbol) {\n      # Generate the entry point\n      var entryPoint = _cache.entryPointSymbol\n      if entryPoint != null {\n        entryPoint.name = \"main\"\n\n        # The entry point must not be in a namespace\n        if entryPoint.parent != global {\n          entryPoint.parent.asObjectSymbol.functions.removeOne(entryPoint)\n          entryPoint.parent = global\n          global.functions.append(entryPoint)\n        }\n\n        # The entry point in C++ takes an array, not a list\n        if entryPoint.arguments.count == 1 {\n          var argument = entryPoint.arguments.first\n          var argc = VariableSymbol.new(.VARIABLE_ARGUMENT, entryPoint.scope.generateName(\"argc\"))\n          var argv = VariableSymbol.new(.VARIABLE_ARGUMENT, entryPoint.scope.generateName(\"argv\"))\n          argc.initializeWithType(_cache.intType)\n          argv.type = Node.createName(\"char**\").withType(.DYNAMIC)\n          argv.resolvedType = .DYNAMIC\n          argv.state = .INITIALIZED\n          entryPoint.arguments = [argc, argv]\n          entryPoint.resolvedType.argumentTypes = [argc.resolvedType, argv.resolvedType]\n\n          # Create the list from the array\n          if entryPoint.block != null {\n            var advance = Node.createName(\"*\\(argv.name)++\").withType(.DYNAMIC)\n            var block = Node.createBlock.appendChild(Node.createExpression(Node.createCall(Node.createDot(\n              Node.createSymbolReference(argument), \"append\").withType(.DYNAMIC)).withType(.DYNAMIC).appendChild(advance)))\n            var check = Node.createIf(advance.clone, Node.createBlock.appendChild(\n              Node.createWhile(Node.createName(\"*\\(argv.name)\").withType(.DYNAMIC), block)), null)\n            argument.kind = .VARIABLE_LOCAL\n            argument.value = Node.createCall(Node.createDot(Node.createType(argument.resolvedType), \"new\").withType(.DYNAMIC)).withType(.DYNAMIC)\n            entryPoint.block.prependChild(check)\n            entryPoint.block.prependChild(Node.createVariables.appendChild(Node.createVariable(argument)))\n          }\n        }\n      }\n\n      # Make sure strings reference the right namespace. This has to be set\n      # here instead of in the library code to avoid a cyclic definition.\n      _cache.stringType.symbol.name = \"Skew::string\"\n\n      # Avoid emitting unnecessary stuff\n      shakingPass(global, _cache.entryPointSymbol, .USE_TYPES)\n      _markVirtualFunctions(global)\n\n      # Nested types in C++ can't be forward declared\n      var sorted = _sortedObjects(global)\n      for symbol in sorted {\n        _moveNestedObjectToEnclosingNamespace(symbol)\n      }\n\n      # Emit code in passes to deal with C++'s forward declarations\n      for symbol in sorted {\n        _declareObject(symbol)\n      }\n      for symbol in sorted {\n        _defineObject(symbol)\n      }\n      _adjustNamespace(null)\n      for symbol in sorted {\n        if !symbol.isImported {\n          for variable in symbol.variables {\n            if variable.kind == .VARIABLE_GLOBAL {\n              _emitVariable(variable, .IMPLEMENT)\n            }\n          }\n        }\n      }\n      _adjustNamespace(null)\n      for symbol in sorted {\n        if !symbol.isImported {\n          for function in symbol.functions {\n            _emitFunction(function, .IMPLEMENT)\n          }\n          _emitMarkFunction(symbol, .IMPLEMENT)\n        }\n      }\n      _finalizeEmittedFile\n      _createSource(_options.outputFile, .ALWAYS_EMIT)\n    }\n\n    enum CodeMode {\n      DECLARE\n      DEFINE\n      IMPLEMENT\n    }\n\n    def _emitNewlineBeforeSymbol(symbol Symbol, mode CodeMode) {\n      if _previousSymbol != null &&\n          (!_previousSymbol.kind.isVariable || !symbol.kind.isVariable || symbol.comments != null) &&\n          (mode != .DEFINE || !_previousSymbol.kind.isFunction || !symbol.kind.isFunction || symbol.comments != null) &&\n          (mode != .DECLARE || _previousSymbol.kind != .OBJECT_CLASS || symbol.kind != .OBJECT_CLASS) {\n        _emit(\"\\n\")\n      }\n      _previousSymbol = null\n    }\n\n    def _emitNewlineAfterSymbol(symbol Symbol) {\n      _previousSymbol = symbol\n    }\n\n    def _emitNewlineBeforeStatement(node Node) {\n      if _previousNode != null && (node.comments != null || !_isCompactNodeKind(_previousNode.kind) || !_isCompactNodeKind(node.kind)) {\n        _emit(\"\\n\")\n      }\n      _previousNode = null\n    }\n\n    def _emitNewlineAfterStatement(node Node) {\n      _previousNode = node\n    }\n\n    def _adjustNamespace(symbol Symbol) {\n      # Get the namespace chain for this symbol\n      var symbols List<Symbol> = []\n      while symbol != null && symbol.kind != .OBJECT_GLOBAL {\n        if symbol.kind == .OBJECT_NAMESPACE || symbol.kind == .OBJECT_WRAPPED {\n          symbols.prepend(symbol)\n        }\n        symbol = symbol.parent\n      }\n\n      # Find the intersection\n      var limit = Math.min(_namespaceStack.count, symbols.count)\n      var i = 0\n      while i < limit {\n        if _namespaceStack[i] != symbols[i] {\n          break\n        }\n        i++\n      }\n\n      # Leave the old namespace\n      while _namespaceStack.count > i {\n        var object = _namespaceStack.takeLast\n        _decreaseIndent\n        _emit(_indent + \"}\\n\")\n        _emitNewlineAfterSymbol(object)\n      }\n\n      # Enter the new namespace\n      while _namespaceStack.count < symbols.count {\n        var object = symbols[_namespaceStack.count]\n        _emitNewlineBeforeSymbol(object, .DEFINE)\n        _emit(_indent + \"namespace \" + _mangleName(object) + \" {\\n\")\n        _increaseIndent\n        _namespaceStack.append(object)\n      }\n    }\n\n    def _emitComments(comments List<Comment>) {\n      if comments != null {\n        for comment in comments {\n          for line in comment.lines {\n            _emit(_indent + \"//\" + line + \"\\n\")\n          }\n          if comment.hasGapBelow {\n            _emit(\"\\n\")\n          }\n        }\n      }\n    }\n\n    def _moveNestedObjectToEnclosingNamespace(symbol ObjectSymbol) {\n      var parent = symbol.parent\n      while parent != null && parent.kind == .OBJECT_CLASS {\n        parent = parent.parent\n      }\n      if symbol.parent != parent {\n        symbol.parent.asObjectSymbol.objects.removeOne(symbol)\n        symbol.parent = parent\n        parent.asObjectSymbol.objects.append(symbol)\n      }\n    }\n\n    def _declareObject(symbol ObjectSymbol) {\n      if symbol.isImported {\n        return\n      }\n\n      switch symbol.kind {\n        case .OBJECT_ENUM, .OBJECT_FLAGS {\n          _adjustNamespace(symbol)\n          _emitNewlineBeforeSymbol(symbol, .DECLARE)\n          if symbol.kind == .OBJECT_FLAGS {\n            _emit(_indent + \"namespace \" + _mangleName(symbol) + \" {\\n\")\n            _increaseIndent\n            if !symbol.variables.isEmpty {\n              _emit(_indent + \"enum {\\n\")\n            }\n          } else {\n            _emit(_indent + \"enum struct \" + _mangleName(symbol) + \" {\\n\")\n          }\n          _increaseIndent\n          for variable in symbol.variables {\n            _emitVariable(variable, .DECLARE)\n          }\n          _decreaseIndent\n          if symbol.kind == .OBJECT_FLAGS {\n            if !symbol.variables.isEmpty {\n              _emit(_indent + \"};\\n\")\n            }\n            _decreaseIndent\n            _emit(_indent + \"}\\n\")\n          } else {\n            _emit(_indent + \"};\\n\")\n          }\n          _emitNewlineAfterSymbol(symbol)\n        }\n\n        case .OBJECT_CLASS, .OBJECT_INTERFACE {\n          _adjustNamespace(symbol)\n          _emitNewlineBeforeSymbol(symbol, .DECLARE)\n          _emitTypeParameters(symbol.parameters)\n          _emit(_indent + \"struct \" + _mangleName(symbol) + \";\\n\")\n          _emitNewlineAfterSymbol(symbol)\n        }\n      }\n    }\n\n    def _defineObject(symbol ObjectSymbol) {\n      if symbol.isImported {\n        return\n      }\n\n      switch symbol.kind {\n        case .OBJECT_CLASS, .OBJECT_INTERFACE {\n          _adjustNamespace(symbol)\n          _emitNewlineBeforeSymbol(symbol, .DEFINE)\n          _emitComments(symbol.comments)\n          _emitTypeParameters(symbol.parameters)\n          _emit(_indent + \"struct \" + _mangleName(symbol))\n          if symbol.extends != null || symbol.implements != null {\n            _emit(\" : \")\n            if symbol.extends != null {\n              _emitExpressionOrType(symbol.extends, symbol.baseType, .BARE)\n            }\n            if symbol.implements != null {\n              for node in symbol.implements {\n                if node != symbol.implements.first || symbol.extends != null {\n                  _emit(\", \")\n                }\n                _emitExpressionOrType(node, node.resolvedType, .BARE)\n              }\n            }\n          } else {\n            _emit(\" : virtual Skew::Object\")\n          }\n          _emit(\" {\\n\")\n          _increaseIndent\n          for function in symbol.functions {\n            _emitFunction(function, .DEFINE)\n          }\n          for variable in symbol.variables {\n            _emitVariable(variable, .DEFINE)\n          }\n          _emitMarkFunction(symbol, .DEFINE)\n          _decreaseIndent\n          _emit(_indent + \"};\\n\")\n          _emitNewlineAfterSymbol(symbol)\n        }\n\n        case .OBJECT_NAMESPACE, .OBJECT_WRAPPED {\n          _adjustNamespace(symbol)\n          for function in symbol.functions {\n            _emitFunction(function, .DEFINE)\n          }\n          for variable in symbol.variables {\n            _emitVariable(variable, .DEFINE)\n          }\n        }\n      }\n    }\n\n    def _emitEnclosingSymbolPrefix(parent ObjectSymbol) {\n      _emit(_fullName(parent))\n      if parent.parameters != null {\n        _emit(\"<\")\n        for parameter in parent.parameters {\n          if parameter != parent.parameters.first {\n            _emit(\", \")\n          }\n          _emit(_mangleName(parameter))\n        }\n        _emit(\">\")\n      }\n      _emit(\"::\")\n    }\n\n    def _emitFunction(symbol FunctionSymbol, mode CodeMode) {\n      var parent = symbol.parent.asObjectSymbol\n      var block = symbol.block\n\n      if symbol.isImported || mode == .IMPLEMENT && block == null {\n        return\n      }\n\n      # We can't use lambdas in C++ since they don't have the right semantics so no variable insertion is needed\n      if symbol.this != null {\n        symbol.this.name = \"this\"\n        symbol.this.flags |= .IS_EXPORTED\n      }\n\n      _enclosingFunction = symbol\n      _emitNewlineBeforeSymbol(symbol, mode)\n      _emitComments(symbol.comments)\n      if mode == .IMPLEMENT {\n        _emitTypeParameters(parent.parameters) # TODO: Merge these with the ones on the symbol when symbols have both\n      }\n      _emitTypeParameters(symbol.parameters)\n      _emit(_indent)\n      if mode == .DEFINE && symbol.kind == .FUNCTION_GLOBAL && symbol.parent.kind == .OBJECT_CLASS {\n        _emit(\"static \")\n      }\n      if symbol.kind != .FUNCTION_CONSTRUCTOR {\n        if mode == .DEFINE && (symbol.isVirtual || block == null) {\n          _emit(\"virtual \")\n        }\n        _emitExpressionOrType(symbol.returnType, symbol.resolvedType.returnType, .DECLARATION)\n      }\n      if mode == .IMPLEMENT && parent.kind != .OBJECT_GLOBAL {\n        _emitEnclosingSymbolPrefix(parent)\n      }\n      _emit(_mangleName(symbol))\n      _emitArgumentList(symbol)\n\n      if mode == .IMPLEMENT {\n        # Move the super constructor call out of the function body\n        if symbol.kind == .FUNCTION_CONSTRUCTOR && block.hasChildren {\n          var first = block.firstChild\n          if first.kind == .EXPRESSION {\n            var call = first.expressionValue\n            if call.kind == .CALL && call.callValue.kind == .SUPER {\n              _emit(\" : \")\n              first.remove\n              _emitExpression(call, .LOWEST)\n            }\n          }\n        }\n\n        _emitBlock(block)\n        _emit(\"\\n\")\n      }\n\n      else {\n        if symbol.overridden != null && symbol.kind != .FUNCTION_CONSTRUCTOR {\n          _emit(\" override\")\n        }\n        if block == null {\n          _emit(\" = 0\")\n        }\n        _emit(\";\\n\")\n      }\n\n      _emitNewlineAfterSymbol(symbol)\n      _enclosingFunction = null\n    }\n\n    def _emitMarkFunction(symbol ObjectSymbol, mode CodeMode) {\n      if symbol.kind == .OBJECT_CLASS {\n        if mode == .DEFINE {\n          _emit(\"\\n\" + _indent + \"#ifdef SKEW_GC_MARK_AND_SWEEP\\n\")\n          _increaseIndent\n          _emit(_indent + \"virtual void __gc_mark() override;\\n\")\n          _decreaseIndent\n          _emit(_indent + \"#endif\\n\")\n        }\n\n        else if mode == .IMPLEMENT {\n          _emitNewlineBeforeSymbol(_dummyFunction, mode)\n          _emit(_indent + \"#ifdef SKEW_GC_MARK_AND_SWEEP\\n\")\n          _increaseIndent\n          _emitTypeParameters(symbol.parameters)\n          _emit(_indent + \"void \")\n          _emitEnclosingSymbolPrefix(symbol)\n          _emit(\"__gc_mark() {\\n\")\n          _increaseIndent\n\n          if symbol.baseClass != null {\n            _emit(_indent + _fullName(symbol.baseClass) + \"::__gc_mark();\\n\")\n          }\n\n          for variable in symbol.variables {\n            if variable.kind == .VARIABLE_INSTANCE && variable.parent == symbol && _isReferenceType(variable.resolvedType) {\n              _emit(_indent + \"Skew::GC::mark(\" + _mangleName(variable) + \");\\n\")\n            }\n          }\n\n          _decreaseIndent\n          _emit(_indent + \"}\\n\")\n          _decreaseIndent\n          _emit(_indent + \"#endif\\n\")\n          _emitNewlineAfterSymbol(_dummyFunction)\n        }\n      }\n    }\n\n    def _emitTypeParameters(parameters List<ParameterSymbol>) {\n      if parameters != null {\n        _emit(_indent + \"template <\")\n        for parameter in parameters {\n          if parameter != parameters.first {\n            _emit(\", \")\n          }\n          _emit(\"typename \" + _mangleName(parameter))\n        }\n        _emit(\">\\n\")\n      }\n    }\n\n    def _emitArgumentList(symbol FunctionSymbol) {\n      _emit(\"(\")\n      for argument in symbol.arguments {\n        if argument != symbol.arguments.first {\n          _emit(\", \")\n        }\n        _emitExpressionOrType(argument.type, argument.resolvedType, .DECLARATION)\n        _emit(_mangleName(argument))\n      }\n      _emit(\")\")\n    }\n\n    def _emitVariable(symbol VariableSymbol, mode CodeMode) {\n      if symbol.isImported {\n        return\n      }\n\n      var avoidFullName = symbol.kind == .VARIABLE_GLOBAL && symbol.parent.kind != .OBJECT_CLASS\n      if mode == .IMPLEMENT && symbol.kind != .VARIABLE_LOCAL {\n        _adjustNamespace(avoidFullName ? symbol.parent : null)\n      }\n\n      _emitNewlineBeforeSymbol(symbol, mode)\n      _emitComments(symbol.comments)\n\n      if symbol.kind == .VARIABLE_ENUM_OR_FLAGS {\n        symbol.value.resolvedType = _cache.intType # Enum values are initialized with integers, so avoid any casts\n        _emit(_indent + _mangleName(symbol) + \" = \")\n        _emitExpression(symbol.value, .COMMA)\n        _emit(\",\\n\")\n      }\n\n      else {\n        _emit(_indent)\n        if mode == .DEFINE && symbol.kind == .VARIABLE_GLOBAL {\n          _emit(symbol.parent.kind == .OBJECT_CLASS ? \"static \" : \"extern \")\n        }\n\n        # Global variables must be stored in roots to avoid accidental garbage collection\n        if symbol.kind == .VARIABLE_GLOBAL && _isReferenceType(symbol.resolvedType) {\n          _emit(\"Skew::Root<\")\n          _emitType(symbol.resolvedType, .BARE)\n          _emit(\"> \")\n        } else {\n          _emitType(symbol.resolvedType, .DECLARATION)\n        }\n\n        if mode == .DEFINE {\n          _emit(_mangleName(symbol))\n        } else {\n          _emit(avoidFullName ? _mangleName(symbol) : _fullName(symbol))\n          if symbol.value != null {\n            _emit(\" = \")\n            _emitExpression(symbol.value, .ASSIGN)\n          }\n        }\n        _emit(\";\\n\")\n      }\n\n      _emitNewlineAfterSymbol(symbol)\n    }\n\n    def _emitStatements(node Node) {\n      _previousNode = null\n\n      for child = node.firstChild; child != null; child = child.nextSibling {\n        _emitNewlineBeforeStatement(child)\n        _emitComments(child.comments)\n        _emitStatement(child)\n        _emitNewlineAfterStatement(child)\n      }\n\n      _previousNode = null\n    }\n\n    def _emitBlock(node Node) {\n      _emit(\" {\\n\")\n      _increaseIndent\n      _emitStatements(node)\n      _decreaseIndent\n      _emit(_indent + \"}\")\n    }\n\n    def _scanForSwitchBreak(node Node, loop Node) {\n      if node.kind == .BREAK {\n        for parent = node.parent; parent != loop; parent = parent.parent {\n          if parent.kind == .SWITCH {\n            var label = _loopLabels.get(loop.id, null)\n            if label == null {\n              label = VariableSymbol.new(.VARIABLE_LOCAL, _enclosingFunction.scope.generateName(\"label\"))\n              _loopLabels[loop.id] = label\n            }\n            _loopLabels[node.id] = label\n            break\n          }\n        }\n      }\n\n      # Stop at nested loops since those will be tested later\n      else if node == loop || !node.kind.isLoop {\n        for child = node.firstChild; child != null; child = child.nextSibling {\n          _scanForSwitchBreak(child, loop)\n        }\n      }\n    }\n\n    def _emitStatement(node Node) {\n      if node.kind.isLoop {\n        _scanForSwitchBreak(node, node)\n      }\n\n      switch node.kind {\n        case .COMMENT_BLOCK {}\n\n        case .VARIABLES {\n          for child = node.firstChild; child != null; child = child.nextSibling {\n            _emitVariable(child.symbol.asVariableSymbol, .IMPLEMENT)\n          }\n        }\n\n        case .EXPRESSION {\n          _emit(_indent)\n          _emitExpression(node.expressionValue, .LOWEST)\n          _emit(\";\\n\")\n        }\n\n        case .BREAK {\n          var label = _loopLabels.get(node.id, null)\n          if label != null {\n            _emit(_indent + \"goto \" + _mangleName(label) + \";\\n\")\n          } else {\n            _emit(_indent + \"break;\\n\")\n          }\n        }\n\n        case .CONTINUE {\n          _emit(_indent + \"continue;\\n\")\n        }\n\n        case .IF {\n          _emit(_indent)\n          _emitIf(node)\n          _emit(\"\\n\")\n        }\n\n        case .SWITCH {\n          var switchValue = node.switchValue\n          _emit(_indent + \"switch (\")\n          _emitExpression(switchValue, .LOWEST)\n          _emit(\") {\\n\")\n          _increaseIndent\n          for child = switchValue.nextSibling; child != null; child = child.nextSibling {\n            var block = child.caseBlock\n            if child.previousSibling != switchValue {\n              _emit(\"\\n\")\n            }\n            if child.hasOneChild {\n              _emit(_indent + \"default:\")\n            } else {\n              for value = child.firstChild; value != block; value = value.nextSibling {\n                if value.previousSibling != null {\n                  _emit(\"\\n\")\n                }\n                _emit(_indent + \"case \")\n                _emitExpression(value, .LOWEST)\n                _emit(\":\")\n              }\n            }\n            _emit(\" {\\n\")\n            _increaseIndent\n            _emitStatements(block)\n            if block.hasControlFlowAtEnd {\n              _emit(_indent + \"break;\\n\")\n            }\n            _decreaseIndent\n            _emit(_indent + \"}\\n\")\n          }\n          _decreaseIndent\n          _emit(_indent + \"}\\n\")\n        }\n\n        case .RETURN {\n          _emit(_indent + \"return\")\n          var value = node.returnValue\n          if value != null {\n            _emit(\" \")\n            _emitExpression(value, .LOWEST)\n          }\n          _emit(\";\\n\")\n        }\n\n        case .THROW {\n          _emit(_indent + \"throw \")\n          _emitExpression(node.throwValue, .LOWEST)\n          _emit(\";\\n\")\n        }\n\n        case .FOR {\n          var setup = node.forSetup\n          var test = node.forTest\n          var update = node.forUpdate\n          _emit(_indent + \"for (\")\n          if !setup.isEmptySequence {\n            if setup.kind == .VARIABLES {\n              _emitType(setup.firstChild.symbol.asVariableSymbol.resolvedType, .DECLARATION)\n              for child = setup.firstChild; child != null; child = child.nextSibling {\n                var symbol = child.symbol.asVariableSymbol\n                assert(child.kind == .VARIABLE)\n                if child.previousSibling != null {\n                  _emit(\", \")\n                  if _isReferenceType(symbol.resolvedType) {\n                    _emit(\"*\")\n                  }\n                }\n                _emit(_mangleName(symbol) + \" = \")\n                _emitExpression(symbol.value, .COMMA)\n              }\n            } else {\n              _emitExpression(setup, .LOWEST)\n            }\n          }\n          _emit(\"; \")\n          if !test.isEmptySequence {\n            _emitExpression(test, .LOWEST)\n          }\n          _emit(\"; \")\n          if !update.isEmptySequence {\n            _emitExpression(update, .LOWEST)\n          }\n          _emit(\")\")\n          _emitBlock(node.forBlock)\n          _emit(\"\\n\")\n        }\n\n        case .TRY {\n          var tryBlock = node.tryBlock\n          var finallyBlock = node.finallyBlock\n          _emit(_indent + \"try\")\n          _emitBlock(tryBlock)\n          _emit(\"\\n\")\n\n          for child = tryBlock.nextSibling; child != finallyBlock; child = child.nextSibling {\n            if child.comments != null {\n              _emit(\"\\n\")\n              _emitComments(child.comments)\n            }\n            _emit(_indent + \"catch\")\n            if child.symbol != null {\n              _emit(\" (\")\n              _emitType(child.symbol.resolvedType, .DECLARATION)\n              _emit(_mangleName(child.symbol) + \")\")\n            } else {\n              _emit(\" (...)\")\n            }\n            _emitBlock(child.catchBlock)\n            _emit(\"\\n\")\n          }\n\n          if finallyBlock != null {\n            if finallyBlock.comments != null {\n              _emit(\"\\n\")\n              _emitComments(finallyBlock.comments)\n            }\n            _emit(_indent + \"finally\")\n            _emitBlock(finallyBlock)\n            _emit(\"\\n\")\n          }\n        }\n\n        case .WHILE {\n          _emit(_indent + \"while (\")\n          _emitExpression(node.whileTest, .LOWEST)\n          _emit(\")\")\n          _emitBlock(node.whileBlock)\n          _emit(\"\\n\")\n        }\n\n        case .FOREACH {\n          var symbol = node.symbol.asVariableSymbol\n          var value = node.foreachValue\n          _emit(_indent + \"for (\")\n          _emitType(symbol.resolvedType, .DECLARATION)\n          _emit(_mangleName(symbol) + \" : \")\n          if _isReferenceType(value.resolvedType) {\n            _emit(\"*\")\n            _emitExpression(value, .UNARY_PREFIX)\n          } else {\n            _emitExpression(value, .LOWEST)\n          }\n          _emit(\")\")\n          _emitBlock(node.foreachBlock)\n          _emit(\"\\n\")\n        }\n\n        default {\n          assert(false)\n        }\n      }\n\n      if node.kind.isLoop {\n        var label = _loopLabels.get(node.id, null)\n        if label != null {\n          _emit(_indent + _mangleName(label) + (node.nextSibling != null ? \":\\n\" : \":;\\n\"))\n        }\n      }\n    }\n\n    def _emitIf(node Node) {\n      _emit(\"if (\")\n      _emitExpression(node.ifTest, .LOWEST)\n      _emit(\")\")\n      _emitBlock(node.ifTrue)\n\n      var block = node.ifFalse\n      if block != null {\n        var singleIf = block.hasOneChild && block.firstChild.kind == .IF ? block.firstChild : null\n        _emit(\"\\n\\n\")\n        _emitComments(block.comments)\n        if singleIf != null {\n          _emitComments(singleIf.comments)\n        }\n        _emit(_indent + \"else\")\n\n        if singleIf != null {\n          _emit(\" \")\n          _emitIf(singleIf)\n        } else {\n          _emitBlock(block)\n        }\n      }\n    }\n\n    def _emitContent(content Content) {\n      switch content.kind {\n        case .BOOL { _emit(content.asBool.toString) }\n        case .INT { _emit(content.asInt.toString) }\n        case .DOUBLE {\n          var value = content.asDouble\n          if !value.isFinite {\n            _includeNames[\"<math.h>\"] = 0\n          }\n          _emit(\n            value.isNaN ? \"NAN\" :\n            value == Math.INFINITY ? \"INFINITY\" :\n            value == -Math.INFINITY ? \"-INFINITY\" :\n            doubleToStringWithDot(value))\n        }\n        case .STRING {\n          var text = content.asString\n          var quoted = quoteString(text, .DOUBLE, .OCTAL_WORKAROUND)\n          _emit(\"\\0\" in text ? \"Skew::string(\\(quoted), \\(text.count))\" : quoted + \"_s\") # TODO: This needs to work with UTF8\n        }\n      }\n    }\n\n    def _emitCommaSeparatedExpressions(from Node, to Node) {\n      while from != to {\n        _emitExpression(from, .COMMA)\n        from = from.nextSibling\n        if from != to {\n          _emit(\", \")\n        }\n      }\n    }\n\n    def _emitExpression(node Node, precedence Precedence) {\n      var kind = node.kind\n      var symbol = node.symbol\n\n      if symbol != null {\n        _handleSymbol(symbol)\n      }\n\n      switch kind {\n        case .TYPE, .LAMBDA_TYPE {\n          _emitType(node.resolvedType, .BARE)\n        }\n\n        case .NULL {\n          _emit(\"nullptr\")\n        }\n\n        case .NAME {\n          _emit(symbol != null ? _fullName(symbol) : node.asString)\n\n          # Need to unwrap GC roots using \".get()\" when global variables are referenced\n          if symbol != null && symbol.kind == .VARIABLE_GLOBAL && _isReferenceType(symbol.resolvedType) && (\n              node.parent == null || node.parent.kind != .DOT && (node.parent.kind != .ASSIGN || node != node.parent.binaryLeft)) {\n            _emit(\".get()\")\n          }\n        }\n\n        case .DOT {\n          var target = node.dotTarget\n          var type = target.resolvedType\n          _emitExpression(target, .MEMBER)\n          _emit((type != null && _isReferenceType(type) ? \"->\" : \".\") + (symbol != null ? _mangleName(symbol) : node.asString))\n        }\n\n        case .CONSTANT {\n          if node.resolvedType.isEnumOrFlags {\n            _emit(\"(\")\n            _emitType(node.resolvedType, .NORMAL)\n            _emit(\")\")\n          }\n          _emitContent(node.content)\n        }\n\n        case .CALL {\n          var value = node.callValue\n          var wrap = false\n\n          if value.kind == .SUPER {\n            _emit(_fullName(symbol))\n          }\n\n          else if symbol != null && symbol.kind == .FUNCTION_CONSTRUCTOR {\n            wrap = precedence == Precedence.MEMBER\n            if wrap {\n              _emit(\"(\")\n            }\n            _emit(\"new \")\n            _emitType(node.resolvedType, .BARE)\n          }\n\n          else if value.kind == .DOT && value.asString == \"new\" {\n            wrap = precedence == Precedence.MEMBER\n            if wrap {\n              _emit(\"(\")\n            }\n            _emit(\"new \")\n            _emitExpression(value.dotTarget, .MEMBER)\n          }\n\n          else {\n            _emitExpression(value, .UNARY_POSTFIX)\n          }\n\n          _emit(\"(\")\n          _emitCommaSeparatedExpressions(node.firstChild.nextSibling, null)\n          _emit(\")\")\n\n          if wrap {\n            _emit(\")\")\n          }\n        }\n\n        case .CAST {\n          var resolvedType = node.resolvedType\n          var type = node.castType\n          var value = node.castValue\n\n          if value.kind == .NULL && node.resolvedType == _cache.stringType {\n            _emitType(_cache.stringType, .BARE)\n            _emit(\"()\")\n          }\n\n          else if type.kind == .TYPE && type.resolvedType == .DYNAMIC {\n            _emitExpression(value, precedence)\n          }\n\n          # Automatically promote integer literals to doubles instead of using a cast\n          else if _cache.isEquivalentToDouble(resolvedType) && value.isInt {\n            _emitExpression(_cache.createDouble(value.asInt), precedence)\n          }\n\n          # Only emit a cast if the underlying types are different\n          else if _unwrappedType(value.resolvedType) != _unwrappedType(type.resolvedType) || type.resolvedType == .DYNAMIC {\n            if Precedence.UNARY_POSTFIX < precedence {\n              _emit(\"(\")\n            }\n            _emit(\"(\")\n            _emitExpressionOrType(type, resolvedType, .NORMAL)\n            _emit(\")\")\n            _emitExpression(value, .UNARY_POSTFIX)\n            if Precedence.UNARY_POSTFIX < precedence {\n              _emit(\")\")\n            }\n          }\n\n          # Otherwise, pretend the cast isn't there\n          else {\n            _emitExpression(value, precedence)\n          }\n        }\n\n        case .TYPE_CHECK {\n          var value = node.typeCheckValue\n          var type = node.typeCheckType\n\n          if Precedence.EQUAL < precedence {\n            _emit(\"(\")\n          }\n          _emit(\"dynamic_cast<\")\n          _emitExpressionOrType(type, type.resolvedType, .NORMAL)\n          _emit(\">(\")\n          _emitExpression(value, .LOWEST)\n          _emit(\") != nullptr\")\n          if Precedence.EQUAL < precedence {\n            _emit(\")\")\n          }\n        }\n\n        case .INDEX {\n          var left = node.indexLeft\n          if _isReferenceType(left.resolvedType) {\n            _emit(\"(*\")\n            _emitExpression(left, .UNARY_PREFIX)\n            _emit(\")\")\n          } else {\n            _emitExpression(left, .UNARY_POSTFIX)\n          }\n          _emit(\"[\")\n          _emitExpression(node.indexRight, .LOWEST)\n          _emit(\"]\")\n        }\n\n        case .ASSIGN_INDEX {\n          var left = node.assignIndexLeft\n          if Precedence.ASSIGN < precedence {\n            _emit(\"(\")\n          }\n          if _isReferenceType(left.resolvedType) {\n            _emit(\"(*\")\n            _emitExpression(left, .UNARY_PREFIX)\n            _emit(\")\")\n          } else {\n            _emitExpression(left, .UNARY_POSTFIX)\n          }\n          _emit(\"[\")\n          _emitExpression(node.assignIndexCenter, .LOWEST)\n          _emit(\"] = \")\n          _emitExpression(node.assignIndexRight, .ASSIGN)\n          if Precedence.ASSIGN < precedence {\n            _emit(\")\")\n          }\n        }\n\n        case .PARAMETERIZE {\n          var value = node.parameterizeValue\n          if value.isType {\n            _emitType(node.resolvedType, .NORMAL)\n          } else {\n            _emitExpression(value, precedence)\n            _emit(\"<\")\n            for child = value.nextSibling; child != null; child = child.nextSibling {\n              if child.previousSibling != value {\n                _emit(\", \")\n              }\n              _emitExpressionOrType(child, child.resolvedType, .NORMAL)\n            }\n            _emit(\">\")\n          }\n        }\n\n        case .SEQUENCE {\n          if Precedence.COMMA <= precedence {\n            _emit(\"(\")\n          }\n          _emitCommaSeparatedExpressions(node.firstChild, null)\n          if Precedence.COMMA <= precedence {\n            _emit(\")\")\n          }\n        }\n\n        case .HOOK {\n          if Precedence.ASSIGN < precedence {\n            _emit(\"(\")\n          }\n          _emitExpression(node.hookTest, .LOGICAL_OR)\n          _emit(\" ? \")\n          _emitExpression(node.hookTrue, .ASSIGN)\n          _emit(\" : \")\n          _emitExpression(node.hookFalse, .ASSIGN)\n          if Precedence.ASSIGN < precedence {\n            _emit(\")\")\n          }\n        }\n\n        case .INITIALIZER_LIST, .INITIALIZER_MAP {\n          var wrap = precedence == Precedence.MEMBER\n          if wrap {\n            _emit(\"(\")\n          }\n          _emit(\"new \")\n          _emitType(node.resolvedType, .BARE)\n          if node.hasChildren {\n            _emit(\"({\")\n            _emitCommaSeparatedExpressions(node.firstChild, null)\n            _emit(\"})\")\n          } else {\n            _emit(\"()\")\n          }\n          if wrap {\n            _emit(\")\")\n          }\n        }\n\n        case .PAIR {\n          _includeNames[\"<utility>\"] = 0\n          _emit(\"std::make_pair(\")\n          _emitCommaSeparatedExpressions(node.firstChild, null)\n          _emit(\")\")\n        }\n\n        case .COMPLEMENT, .NEGATIVE, .NOT, .POSITIVE, .POSTFIX_DECREMENT, .POSTFIX_INCREMENT, .PREFIX_DECREMENT, .PREFIX_INCREMENT {\n          var value = node.unaryValue\n          var info = operatorInfo[kind]\n          var sign = node.sign\n          if info.precedence < precedence {\n            _emit(\"(\")\n          }\n          if !kind.isUnaryPostfix {\n            _emit(info.text)\n\n            # Prevent \"x - -1\" from becoming \"x--1\"\n            if sign != .NULL && sign == value.sign {\n              _emit(\" \")\n            }\n          }\n          _emitExpression(value, info.precedence)\n          if kind.isUnaryPostfix {\n            _emit(info.text)\n          }\n          if info.precedence < precedence {\n            _emit(\")\")\n          }\n        }\n\n        default {\n          if kind.isBinary {\n            var parent = node.parent\n            if parent != null && (\n                # Clang warns about \"&&\" inside \"||\" or \"&\" inside \"|\" without parentheses\n                parent.kind == .LOGICAL_OR && kind == .LOGICAL_AND ||\n                parent.kind == .BITWISE_OR && kind == .BITWISE_AND ||\n\n                # Clang and GCC also warn about add/subtract inside bitwise operations and shifts without parentheses\n                (parent.kind == .BITWISE_AND || parent.kind == .BITWISE_OR || parent.kind == .BITWISE_XOR || parent.kind.isShift) && (kind == .ADD || kind == .SUBTRACT)) {\n\n              precedence = .MEMBER\n            }\n\n            var info = operatorInfo[kind]\n            if info.precedence < precedence {\n              _emit(\"(\")\n            }\n            _emitExpression(node.binaryLeft, info.precedence.incrementIfRightAssociative(info.associativity))\n            _emit(\" \" + info.text + \" \")\n            _emitExpression(node.binaryRight, info.precedence.incrementIfLeftAssociative(info.associativity))\n            if info.precedence < precedence {\n              _emit(\")\")\n            }\n          }\n\n          else {\n            assert(false)\n          }\n        }\n      }\n    }\n\n    enum CppEmitMode {\n      BARE\n      NORMAL\n      DECLARATION\n    }\n\n    def _emitExpressionOrType(node Node, type Type, mode CppEmitMode) {\n      if node != null && (type == null || type == .DYNAMIC) {\n        _emitExpression(node, .LOWEST)\n        if mode == .DECLARATION {\n          _emit(\" \")\n        }\n      } else {\n        _emitType(type, mode)\n      }\n    }\n\n    def _emitType(type Type, mode CppEmitMode) {\n      if type == null {\n        _emit(\"void\")\n      }\n\n      else {\n        type = _unwrappedType(type)\n\n        if type == .DYNAMIC {\n          _emit(\"void\")\n        }\n\n        else if type.kind == .LAMBDA {\n          var hasReturnType = type.returnType != null\n          var argumentCount = type.argumentTypes.count\n          _emit((hasReturnType ? \"Skew::Fn\" : \"Skew::FnVoid\") + \"\\(argumentCount)\")\n          if hasReturnType || argumentCount != 0 {\n            _emit(\"<\")\n            if hasReturnType {\n              _emitType(type.returnType, .NORMAL)\n            }\n            for i in 0..argumentCount {\n              if i != 0 || hasReturnType {\n                _emit(\", \")\n              }\n              _emitType(type.argumentTypes[i], .NORMAL)\n            }\n            _emit(\">\")\n          }\n        }\n\n        else {\n          assert(type.kind == .SYMBOL)\n          _handleSymbol(type.symbol)\n          _emit(_fullName(type.symbol))\n\n          if type.isParameterized {\n            _emit(\"<\")\n            for i in 0..type.substitutions.count {\n              if i != 0 {\n                _emit(\", \")\n              }\n              _emitType(type.substitutions[i], .NORMAL)\n            }\n            _emit(\">\")\n          }\n        }\n      }\n\n      if type != null && _isReferenceType(type) && mode != .BARE {\n        _emit(\" *\")\n      } else if mode == .DECLARATION {\n        _emit(\" \")\n      }\n    }\n\n    def _unwrappedType(type Type) Type {\n      return type.isFlags ? _cache.intType : _cache.unwrappedType(type)\n    }\n\n    def _isReferenceType(type Type) bool {\n      return type.isReference && type != _cache.stringType\n    }\n\n    def _finalizeEmittedFile {\n      var includes = _includeNames.keys\n\n      if !includes.isEmpty {\n        includes.sort(SORT_STRINGS) # Sort so the order is deterministic\n        for include in includes {\n          _emitPrefix(\"#include \" + (include.startsWith(\"<\") && include.endsWith(\">\") ? include : \"\\\"\" + include + \"\\\"\") + \"\\n\")\n        }\n        _emitPrefix(\"\\n\")\n      }\n\n      _adjustNamespace(null)\n      _previousSymbol = null\n      _symbolsCheckedForInclude = {}\n      _includeNames = {}\n    }\n\n    def _handleSymbol(symbol Symbol) {\n      if !symbol.kind.isLocal && !(symbol.id in _symbolsCheckedForInclude) {\n        _symbolsCheckedForInclude[symbol.id] = 0\n\n        if symbol.annotations != null {\n          for annotation in symbol.annotations {\n            if annotation.symbol != null && annotation.symbol.fullName == \"include\" {\n              var value = annotation.annotationValue\n              if value.childCount == 2 {\n                _includeNames[value.lastChild.asString] = 0\n              }\n            }\n          }\n        }\n\n        if symbol.parent != null {\n          _handleSymbol(symbol.parent)\n        }\n      }\n    }\n  }\n\n  namespace CPlusPlusEmitter {\n    def _isCompactNodeKind(kind NodeKind) bool {\n      return kind == .EXPRESSION || kind == .VARIABLES || kind.isJump\n    }\n\n    def _fullName(symbol Symbol) string {\n      var parent = symbol.parent\n      if parent != null && parent.kind != .OBJECT_GLOBAL && !symbol.kind.isParameter {\n        return _fullName(parent) + \"::\" + _mangleName(symbol)\n      }\n      return _mangleName(symbol)\n    }\n\n    def _mangleName(symbol Symbol) string {\n      symbol = symbol.forwarded\n      if symbol.kind == .FUNCTION_CONSTRUCTOR {\n        return _mangleName(symbol.parent)\n      }\n      if !symbol.isImportedOrExported && symbol.name in _isNative || symbol.name in _isKeyword {\n        return \"_\" + symbol.name\n      }\n      return symbol.name\n    }\n\n    const _isNative = {\n      \"auto\": 0,\n      \"bool\": 0,\n      \"char\": 0,\n      \"char16_t\": 0,\n      \"char32_t\": 0,\n      \"const_cast\": 0,\n      \"double\": 0,\n      \"dynamic_cast\": 0,\n      \"false\": 0,\n      \"float\": 0,\n      \"INFINITY\": 0,\n      \"int\": 0,\n      \"long\": 0,\n      \"NAN\": 0,\n      \"NULL\": 0,\n      \"nullptr\": 0,\n      \"reinterpret_cast\": 0,\n      \"short\": 0,\n      \"signed\": 0,\n      \"static_assert\": 0,\n      \"static_cast\": 0,\n      \"this\": 0,\n      \"true\": 0,\n      \"unsigned\": 0,\n      \"void\": 0,\n      \"wchar_t\": 0,\n    }\n\n    const _isKeyword = {\n      \"alignas\": 0,\n      \"alignof\": 0,\n      \"and\": 0,\n      \"and_eq\": 0,\n      \"asm\": 0,\n      \"bitand\": 0,\n      \"bitor\": 0,\n      \"break\": 0,\n      \"case\": 0,\n      \"catch\": 0,\n      \"class\": 0,\n      \"compl\": 0,\n      \"const\": 0,\n      \"constexpr\": 0,\n      \"continue\": 0,\n      \"decltype\": 0,\n      \"default\": 0,\n      \"delete\": 0,\n      \"do\": 0,\n      \"else\": 0,\n      \"enum\": 0,\n      \"explicit\": 0,\n      \"export\": 0,\n      \"extern\": 0,\n      \"for\": 0,\n      \"friend\": 0,\n      \"goto\": 0,\n      \"if\": 0,\n      \"inline\": 0,\n      \"mutable\": 0,\n      \"namespace\": 0,\n      \"new\": 0,\n      \"noexcept\": 0,\n      \"not\": 0,\n      \"not_eq\": 0,\n      \"operator\": 0,\n      \"or\": 0,\n      \"or_eq\": 0,\n      \"private\": 0,\n      \"protected\": 0,\n      \"public\": 0,\n      \"register\": 0,\n      \"return\": 0,\n      \"sizeof\": 0,\n      \"static\": 0,\n      \"struct\": 0,\n      \"switch\": 0,\n      \"template\": 0,\n      \"thread_local\": 0,\n      \"throw\": 0,\n      \"try\": 0,\n      \"typedef\": 0,\n      \"typeid\": 0,\n      \"typename\": 0,\n      \"union\": 0,\n      \"using\": 0,\n      \"virtual\": 0,\n      \"volatile\": 0,\n      \"while\": 0,\n      \"xor\": 0,\n      \"xor_eq\": 0,\n    }\n  }\n}\n"
  },
  {
    "path": "src/backend/csharp.sk",
    "content": "namespace Skew {\n  class CSharpTarget : CompilerTarget {\n    over name string { return \"C#\" }\n    over extension string { return \"cs\" }\n    over stopAfterResolve bool { return false }\n    over requiresIntegerSwitchStatements bool { return true }\n    over supportsListForeach bool { return true }\n    over supportsNestedTypes bool { return true }\n    over stringEncoding Unicode.Encoding { return .UTF16 }\n    over editOptions(options CompilerOptions) { options.define(\"TARGET\", \"CSHARP\") }\n    over includeSources(sources List<Source>) { sources.prepend(Source.new(\"<native-cs>\", NATIVE_LIBRARY_CS)) }\n    over createEmitter(context PassContext) Emitter { return CSharpEmitter.new(context.options, context.cache) }\n  }\n\n  class CSharpEmitter : Emitter {\n    const _options CompilerOptions\n    const _cache TypeCache\n    var _previousNode Node = null\n    var _previousSymbol Symbol = null\n    var _namespaceStack List<Symbol> = []\n    var _symbolsCheckedForUsing IntMap<int> = {}\n    var _usingNames StringMap<int> = {}\n    var _loopLabels IntMap<VariableSymbol> = {}\n    var _enclosingFunction FunctionSymbol = null\n\n    over visit(global ObjectSymbol) {\n      _indentAmount = \"    \"\n      _moveGlobalsIntoClasses(global)\n\n      # Generate the entry point\n      var entryPoint = _cache.entryPointSymbol\n      if entryPoint != null {\n        entryPoint.name = \"Main\"\n\n        # The entry point in C# takes an array, not a list\n        if entryPoint.arguments.count == 1 {\n          var argument = entryPoint.arguments.first\n          var array = VariableSymbol.new(.VARIABLE_ARGUMENT, argument.name)\n          array.type = Node.createName(\"string[]\").withType(.DYNAMIC)\n          array.resolvedType = .DYNAMIC\n          entryPoint.arguments = [array]\n          entryPoint.resolvedType.argumentTypes = [array.resolvedType]\n\n          # Create the list from the array\n          if entryPoint.block != null {\n            array.name = entryPoint.scope.generateName(array.name)\n            argument.kind = .VARIABLE_LOCAL\n            argument.value = Node.createCall(Node.createDot(Node.createType(argument.resolvedType), \"new\").withType(.DYNAMIC))\n              .withType(.DYNAMIC).appendChild(Node.createSymbolReference(array))\n            entryPoint.block.prependChild(Node.createVariables.appendChild(Node.createVariable(argument)))\n          }\n        }\n      }\n\n      # Avoid emitting unnecessary stuff\n      shakingPass(global, entryPoint, .USE_TYPES)\n      _markVirtualFunctions(global)\n\n      var emitIndividualFiles = _options.outputDirectory != null\n      var objects = _collectObjects(global)\n\n      for object in objects {\n        # Convert \"flags\" types to wrapped types\n        if object.kind == .OBJECT_FLAGS {\n          object.kind = .OBJECT_WRAPPED\n          object.wrappedType = _cache.intType\n\n          # Enum values become normal global variables\n          for variable in object.variables {\n            if variable.kind == .VARIABLE_ENUM_OR_FLAGS {\n              variable.kind = .VARIABLE_GLOBAL\n              variable.flags |= .IS_CSHARP_CONST\n            }\n          }\n        }\n      }\n\n      # All code in C# is inside objects, so just emit objects recursively\n      for object in objects {\n        # Nested objects will be emitted by their parent\n        if object.parent != null && object.parent.kind == .OBJECT_CLASS {\n          continue\n        }\n\n        _emitObject(object)\n\n        # Emit each object into its own file if requested\n        if emitIndividualFiles {\n          _finalizeEmittedFile\n          _createSource(_options.outputDirectory + \"/\" + _fullName(object) + \".cs\", .SKIP_IF_EMPTY)\n        }\n      }\n\n      # Emit a single file if requested\n      if !emitIndividualFiles {\n        _finalizeEmittedFile\n        _createSource(_options.outputFile, .ALWAYS_EMIT)\n      }\n    }\n\n    def _moveGlobalsIntoClasses(symbol ObjectSymbol) {\n      if !symbol.kind.isNamespaceOrGlobal {\n        return\n      }\n\n      # Just change namespaces into classes if there aren't nested objects\n      if symbol.kind == .OBJECT_NAMESPACE && symbol.objects.isEmpty && (!symbol.functions.isEmpty || !symbol.variables.isEmpty) {\n        symbol.kind = .OBJECT_CLASS\n        return\n      }\n\n      var globals ObjectSymbol = null\n      var lazilyCreateGlobals = => {\n        if globals == null {\n          globals = ObjectSymbol.new(.OBJECT_CLASS, symbol.scope.generateName(symbol.kind == .OBJECT_NAMESPACE ? symbol.name + \"Globals\" : \"Globals\"))\n          globals.resolvedType = Type.new(.SYMBOL, globals)\n          globals.state = .INITIALIZED\n          globals.parent = symbol\n          symbol.objects.append(globals)\n        }\n      }\n\n      for object in symbol.objects {\n        _moveGlobalsIntoClasses(object)\n      }\n\n      symbol.functions.removeIf(function => {\n        if function.kind != .FUNCTION_ANNOTATION && !function.isImported {\n          lazilyCreateGlobals()\n          function.parent = globals\n          globals.functions.append(function)\n          return true\n        }\n        return false\n      })\n\n      symbol.variables.removeIf(variable => {\n        if variable.kind == .VARIABLE_GLOBAL && !variable.isImported {\n          lazilyCreateGlobals()\n          variable.parent = globals\n          globals.variables.append(variable)\n          return true\n        }\n        return false\n      })\n    }\n\n    def _adjustNamespace(symbol Symbol) {\n      # Get the namespace chain for this symbol\n      var symbols List<Symbol> = []\n      while symbol != null && symbol.kind != .OBJECT_GLOBAL {\n        if symbol.kind == .OBJECT_NAMESPACE {\n          symbols.prepend(symbol)\n        }\n        symbol = symbol.parent\n      }\n\n      # Find the intersection\n      var limit = Math.min(_namespaceStack.count, symbols.count)\n      var i = 0\n      while i < limit {\n        if _namespaceStack[i] != symbols[i] {\n          break\n        }\n        i++\n      }\n\n      # Leave the old namespace\n      while _namespaceStack.count > i {\n        var object = _namespaceStack.takeLast\n        _decreaseIndent\n        _emit(_indent + \"}\\n\")\n        _emitNewlineAfterSymbol(object)\n      }\n\n      # Enter the new namespace\n      while _namespaceStack.count < symbols.count {\n        var object = symbols[_namespaceStack.count]\n        _emitNewlineBeforeSymbol(object)\n        _emit(_indent + \"namespace \" + _mangleName(object) + \"\\n\")\n        _emit(_indent + \"{\\n\")\n        _increaseIndent\n        _namespaceStack.append(object)\n      }\n    }\n\n    def _finalizeEmittedFile {\n      var usings = _usingNames.keys\n\n      if !usings.isEmpty {\n        usings.sort(SORT_STRINGS) # Sort so the order is deterministic\n        for using in usings {\n          _emitPrefix(\"using \" + using + \";\\n\")\n        }\n        _emitPrefix(\"\\n\")\n      }\n\n      _adjustNamespace(null)\n      _previousSymbol = null\n      _symbolsCheckedForUsing = {}\n      _usingNames = {}\n    }\n\n    def _handleSymbol(symbol Symbol) {\n      if !symbol.kind.isLocal && !(symbol.id in _symbolsCheckedForUsing) {\n        _symbolsCheckedForUsing[symbol.id] = 0\n\n        if symbol.annotations != null {\n          for annotation in symbol.annotations {\n            if annotation.symbol != null && annotation.symbol.fullName == \"using\" {\n              var value = annotation.annotationValue\n              if value.childCount == 2 {\n                _usingNames[value.lastChild.asString] = 0\n              }\n            }\n          }\n        }\n\n        if symbol.parent != null {\n          _handleSymbol(symbol.parent)\n        }\n      }\n    }\n\n    def _emitNewlineBeforeSymbol(symbol Symbol) {\n      if _previousSymbol != null && (!_previousSymbol.kind.isVariable || !symbol.kind.isVariable || symbol.comments != null) {\n        _emit(\"\\n\")\n      }\n      _previousSymbol = null\n    }\n\n    def _emitNewlineAfterSymbol(symbol Symbol) {\n      _previousSymbol = symbol\n    }\n\n    def _emitNewlineBeforeStatement(node Node) {\n      if _previousNode != null && (node.comments != null || !_isCompactNodeKind(_previousNode.kind) || !_isCompactNodeKind(node.kind)) {\n        _emit(\"\\n\")\n      }\n      _previousNode = null\n    }\n\n    def _emitNewlineAfterStatement(node Node) {\n      _previousNode = node\n    }\n\n    def _emitComments(comments List<Comment>) {\n      if comments != null {\n        for comment in comments {\n          for line in comment.lines {\n            _emit(_indent + \"//\" + line + \"\\n\")\n          }\n          if comment.hasGapBelow {\n            _emit(\"\\n\")\n          }\n        }\n      }\n    }\n\n    def _emitObject(symbol ObjectSymbol) {\n      _handleSymbol(symbol)\n\n      if symbol.isImported || symbol.kind.isNamespaceOrGlobal {\n        return\n      }\n\n      _adjustNamespace(symbol)\n      _emitNewlineBeforeSymbol(symbol)\n      _emitComments(symbol.comments)\n      _emit(_indent + \"public \")\n      if symbol.isAbstract {\n        _emit(\"abstract \")\n      }\n      switch symbol.kind {\n        case .OBJECT_CLASS { _emit(\"class \") }\n        case .OBJECT_ENUM, .OBJECT_FLAGS { _emit(\"enum \") }\n        case .OBJECT_INTERFACE { _emit(\"interface \") }\n        case .OBJECT_WRAPPED, .OBJECT_NAMESPACE { _emit(\"static class \") }\n        default { assert(false) }\n      }\n      _emit(_mangleName(symbol))\n      _emitTypeParameters(symbol.parameters)\n      if (symbol.extends != null || symbol.implements != null) && symbol.kind != .OBJECT_WRAPPED {\n        _emit(\" : \")\n        if symbol.extends != null {\n          _emitExpressionOrType(symbol.extends, symbol.baseType)\n        }\n        if symbol.implements != null {\n          for node in symbol.implements {\n            if node != symbol.implements.first || symbol.extends != null {\n              _emit(\", \")\n            }\n            _emitExpressionOrType(node, node.resolvedType)\n          }\n        }\n      }\n      _emit(\"\\n\" + _indent + \"{\\n\")\n      _increaseIndent\n      for object in symbol.objects {\n        _emitObject(object)\n      }\n      for variable in symbol.variables {\n        _emitVariable(variable)\n      }\n      for function in symbol.functions {\n        _emitFunction(function)\n      }\n      _decreaseIndent\n      _emit(_indent + \"}\\n\")\n      _emitNewlineAfterSymbol(symbol)\n    }\n\n    def _emitTypeParameters(parameters List<ParameterSymbol>) {\n      if parameters != null {\n        _emit(\"<\")\n        for parameter in parameters {\n          if parameter != parameters.first {\n            _emit(\", \")\n          }\n          _emit(_mangleName(parameter))\n        }\n        _emit(\">\")\n      }\n    }\n\n    def _emitArgumentList(symbol FunctionSymbol) {\n      _emit(\"(\")\n      for argument in symbol.arguments {\n        if argument != symbol.arguments.first {\n          _emit(\", \")\n        }\n        _emitExpressionOrType(argument.type, argument.resolvedType)\n        _emit(\" \" + _mangleName(argument))\n      }\n      _emit(\")\")\n    }\n\n    def _emitVariable(symbol VariableSymbol) {\n      _handleSymbol(symbol)\n\n      if symbol.isImported {\n        return\n      }\n\n      _emitNewlineBeforeSymbol(symbol)\n      _emitComments(symbol.comments)\n      if symbol.kind == .VARIABLE_ENUM_OR_FLAGS {\n        _emit(_indent + _mangleName(symbol))\n        if symbol.value != null {\n          symbol.value.resolvedType = _cache.intType # Enum values are initialized with integers\n          _emit(\" = \")\n          _emitExpression(symbol.value, .COMMA)\n        }\n        _emit(\",\\n\")\n      } else {\n        _emit(_indent + \"public \")\n        if symbol.kind == .VARIABLE_GLOBAL {\n          _emit(symbol.isCSharpConst ? \"const \" : \"static \")\n        }\n        _emitExpressionOrType(symbol.type, symbol.resolvedType)\n        _emit(\" \" + _mangleName(symbol))\n        if symbol.value != null {\n          _emit(\" = \")\n          _emitExpression(symbol.value, .COMMA)\n        }\n        _emit(\";\\n\")\n      }\n      _emitNewlineAfterSymbol(symbol)\n    }\n\n    def _emitFunction(symbol FunctionSymbol) {\n      _handleSymbol(symbol)\n\n      if symbol.isImported {\n        return\n      }\n\n      # C# has sane capture rules for \"this\" so no variable insertion is needed\n      if symbol.this != null {\n        symbol.this.name = \"this\"\n        symbol.this.flags |= .IS_EXPORTED\n      }\n\n      _enclosingFunction = symbol\n      _emitNewlineBeforeSymbol(symbol)\n      _emitComments(symbol.comments)\n      _emit(_indent)\n      if symbol.parent.kind != .OBJECT_INTERFACE {\n        _emit(\"public \")\n      }\n      if symbol.kind == .FUNCTION_GLOBAL {\n        _emit(\"static \")\n      }\n      if symbol.kind != .FUNCTION_CONSTRUCTOR {\n        if symbol.parent.kind != .OBJECT_INTERFACE {\n          if symbol.block == null {\n            _emit(\"abstract \")\n          } else if symbol.overridden != null {\n            _emit(\"override \")\n          } else if symbol.isVirtual {\n            _emit(\"virtual \")\n          }\n        }\n        _emitExpressionOrType(symbol.returnType, symbol.resolvedType.returnType)\n        _emit(\" \")\n      }\n      _emit(_mangleName(symbol))\n      _emitTypeParameters(symbol.parameters)\n      _emitArgumentList(symbol)\n\n      var block = symbol.block\n      if block == null {\n        _emit(\";\\n\")\n      }\n\n      else {\n        # Move the super constructor call out of the function body\n        if symbol.kind == .FUNCTION_CONSTRUCTOR && block.hasChildren {\n          var first = block.firstChild\n          if first.kind == .EXPRESSION {\n            var call = first.expressionValue\n            if call.kind == .CALL && call.callValue.kind == .SUPER {\n              _emit(\" : \")\n              first.remove\n              _emitExpression(call, .LOWEST)\n            }\n          }\n        }\n\n        _emit(\"\\n\")\n        _emitBlock(block)\n        _emit(\"\\n\")\n      }\n\n      _emitNewlineAfterSymbol(symbol)\n      _enclosingFunction = null\n    }\n\n    def _emitType(type Type) {\n      if type == null {\n        _emit(\"void\")\n        return\n      }\n\n      type = _cache.unwrappedType(type)\n\n      if type == .DYNAMIC {\n        _emit(\"dynamic\")\n      }\n\n      else if type.kind == .LAMBDA {\n        var argumentTypes = type.argumentTypes\n        var returnType = type.returnType\n        _emit(returnType != null ? \"System.Func\" : \"System.Action\")\n        if !argumentTypes.isEmpty || returnType != null {\n          _emit(\"<\")\n          for i in 0..argumentTypes.count {\n            if i != 0 {\n              _emit(\", \")\n            }\n            _emitType(argumentTypes[i])\n          }\n          if returnType != null {\n            if !argumentTypes.isEmpty {\n              _emit(\", \")\n            }\n            _emitType(returnType)\n          }\n          _emit(\">\")\n        }\n      }\n\n      else {\n        assert(type.kind == .SYMBOL)\n        _handleSymbol(type.symbol)\n        _emit(_fullName(type.symbol))\n\n        if type.isParameterized {\n          _emit(\"<\")\n\n          if _cache.isIntMap(type) || _cache.isStringMap(type) {\n            _emit(_cache.isIntMap(type) ? \"int\" : \"string\")\n            _emit(\", \")\n            _emitType(type.substitutions.first)\n          }\n\n          else {\n            for i in 0..type.substitutions.count {\n              if i != 0 {\n                _emit(\", \")\n              }\n              _emitType(type.substitutions[i])\n            }\n          }\n\n          _emit(\">\")\n        }\n      }\n    }\n\n    def _emitExpressionOrType(node Node, type Type) {\n      if node != null && (type == null || type == .DYNAMIC) {\n        _emitExpression(node, .LOWEST)\n      } else {\n        _emitType(type)\n      }\n    }\n\n    def _emitStatements(node Node) {\n      _previousNode = null\n\n      for child = node.firstChild; child != null; child = child.nextSibling {\n        _emitNewlineBeforeStatement(child)\n        _emitComments(child.comments)\n        _emitStatement(child)\n        _emitNewlineAfterStatement(child)\n      }\n\n      _previousNode = null\n    }\n\n    def _emitBlock(node Node) {\n      assert(node.kind == .BLOCK)\n      _emit(_indent + \"{\\n\")\n      _increaseIndent\n      _emitStatements(node)\n      _decreaseIndent\n      _emit(_indent + \"}\")\n    }\n\n    def _emitIf(node Node) {\n      _emit(\"if (\")\n      _emitExpression(node.ifTest, .LOWEST)\n      _emit(\")\\n\")\n      _emitBlock(node.ifTrue)\n      _emit(\"\\n\")\n\n      var block = node.ifFalse\n      if block != null {\n        var singleIf = block.hasOneChild && block.firstChild.kind == .IF ? block.firstChild : null\n        if block.comments != null || singleIf != null && singleIf.comments != null {\n          _emit(\"\\n\")\n          _emitComments(block.comments)\n          if singleIf != null {\n            _emitComments(singleIf.comments)\n          }\n        }\n        _emit(_indent + \"else\")\n\n        if singleIf != null {\n          _emit(\" \")\n          _emitIf(singleIf)\n        } else {\n          _emit(\"\\n\")\n          _emitBlock(block)\n          _emit(\"\\n\")\n        }\n      }\n    }\n\n    def _scanForSwitchBreak(node Node, loop Node) {\n      if node.kind == .BREAK {\n        for parent = node.parent; parent != loop; parent = parent.parent {\n          if parent.kind == .SWITCH {\n            var label = _loopLabels.get(loop.id, null)\n            if label == null {\n              label = VariableSymbol.new(.VARIABLE_LOCAL, _enclosingFunction.scope.generateName(\"label\"))\n              _loopLabels[loop.id] = label\n            }\n            _loopLabels[node.id] = label\n            break\n          }\n        }\n      }\n\n      # Stop at nested loops since those will be tested later\n      else if node == loop || !node.kind.isLoop {\n        for child = node.firstChild; child != null; child = child.nextSibling {\n          _scanForSwitchBreak(child, loop)\n        }\n      }\n    }\n\n    def _emitStatement(node Node) {\n      if node.kind.isLoop {\n        _scanForSwitchBreak(node, node)\n      }\n\n      switch node.kind {\n        case .COMMENT_BLOCK {}\n\n        case .VARIABLES {\n          for child = node.firstChild; child != null; child = child.nextSibling {\n            var symbol = child.symbol.asVariableSymbol\n            _emit(_indent)\n            _emitExpressionOrType(symbol.type, symbol.resolvedType)\n            _emit(\" \" + _mangleName(symbol))\n            if symbol.value != null {\n              _emit(\" = \")\n              _emitExpression(symbol.value, .ASSIGN)\n            }\n            _emit(\";\\n\")\n          }\n        }\n\n        case .EXPRESSION {\n          _emit(_indent)\n          _emitExpression(node.expressionValue, .LOWEST)\n          _emit(\";\\n\")\n        }\n\n        case .BREAK {\n          var label = _loopLabels.get(node.id, null)\n          if label != null {\n            _emit(_indent + \"goto \" + _mangleName(label) + \";\\n\")\n          } else {\n            _emit(_indent + \"break;\\n\")\n          }\n        }\n\n        case .CONTINUE {\n          _emit(_indent + \"continue;\\n\")\n        }\n\n        case .IF {\n          _emit(_indent)\n          _emitIf(node)\n        }\n\n        case .SWITCH {\n          var switchValue = node.switchValue\n          _emit(_indent + \"switch (\")\n          _emitExpression(switchValue, .LOWEST)\n          _emit(\")\\n\" + _indent + \"{\\n\")\n          _increaseIndent\n          for child = switchValue.nextSibling; child != null; child = child.nextSibling {\n            var block = child.caseBlock\n            if child.previousSibling != switchValue {\n              _emit(\"\\n\")\n            }\n            if child.hasOneChild {\n              _emit(_indent + \"default:\")\n            } else {\n              for value = child.firstChild; value != block; value = value.nextSibling {\n                if value.previousSibling != null {\n                  _emit(\"\\n\")\n                }\n                _emit(_indent + \"case \")\n                _emitExpression(value, .LOWEST)\n                _emit(\":\")\n              }\n            }\n            _emit(\"\\n\" + _indent + \"{\\n\")\n            _increaseIndent\n            _emitStatements(block)\n            if block.hasControlFlowAtEnd {\n              _emit(_indent + \"break;\\n\")\n            }\n            _decreaseIndent\n            _emit(_indent + \"}\\n\")\n          }\n          _decreaseIndent\n          _emit(_indent + \"}\\n\")\n        }\n\n        case .RETURN {\n          _emit(_indent + \"return\")\n          var value = node.returnValue\n          if value != null {\n            _emit(\" \")\n            _emitExpression(value, .LOWEST)\n          }\n          _emit(\";\\n\")\n        }\n\n        case .THROW {\n          _emit(_indent + \"throw \")\n          _emitExpression(node.throwValue, .LOWEST)\n          _emit(\";\\n\")\n        }\n\n        case .FOREACH {\n          _emit(_indent + \"foreach (var \" + _mangleName(node.symbol) + \" in \")\n          _emitExpression(node.foreachValue, .LOWEST)\n          _emit(\")\\n\")\n          _emitBlock(node.foreachBlock)\n          _emit(\"\\n\")\n        }\n\n        case .FOR {\n          var setup = node.forSetup\n          var test = node.forTest\n          var update = node.forUpdate\n          _emit(_indent + \"for (\")\n          if !setup.isEmptySequence {\n            if setup.kind == .VARIABLES {\n              var symbol = setup.firstChild.symbol.asVariableSymbol\n              _emitExpressionOrType(symbol.type, symbol.resolvedType)\n              _emit(\" \")\n              for child = setup.firstChild; child != null; child = child.nextSibling {\n                symbol = child.symbol.asVariableSymbol\n                assert(child.kind == .VARIABLE)\n                if child.previousSibling != null {\n                  _emit(\", \")\n                }\n                _emit(_mangleName(symbol) + \" = \")\n                _emitExpression(symbol.value, .COMMA)\n              }\n            } else {\n              _emitExpression(setup, .LOWEST)\n            }\n          }\n          _emit(\"; \")\n          if !test.isEmptySequence {\n            _emitExpression(test, .LOWEST)\n          }\n          _emit(\"; \")\n          if !update.isEmptySequence {\n            _emitExpression(update, .LOWEST)\n          }\n          _emit(\")\\n\")\n          _emitBlock(node.forBlock)\n          _emit(\"\\n\")\n        }\n\n        case .TRY {\n          var tryBlock = node.tryBlock\n          var finallyBlock = node.finallyBlock\n          _emit(_indent + \"try\\n\")\n          _emitBlock(tryBlock)\n          _emit(\"\\n\")\n\n          for child = tryBlock.nextSibling; child != finallyBlock; child = child.nextSibling {\n            if child.comments != null {\n              _emit(\"\\n\")\n              _emitComments(child.comments)\n            }\n            _emit(_indent + \"catch\")\n            if child.symbol != null {\n              _emit(\" (\")\n              _emitExpressionOrType(child.symbol.asVariableSymbol.type, child.symbol.resolvedType)\n              _emit(\" \" + _mangleName(child.symbol) + \")\")\n            }\n            _emit(\"\\n\")\n            _emitBlock(child.catchBlock)\n            _emit(\"\\n\")\n          }\n\n          if finallyBlock != null {\n            if finallyBlock.comments != null {\n              _emit(\"\\n\")\n              _emitComments(finallyBlock.comments)\n            }\n            _emit(_indent + \"finally\\n\")\n            _emitBlock(finallyBlock)\n            _emit(\"\\n\")\n          }\n        }\n\n        case .WHILE {\n          _emit(_indent + \"while (\")\n          _emitExpression(node.whileTest, .LOWEST)\n          _emit(\")\\n\")\n          _emitBlock(node.whileBlock)\n          _emit(\"\\n\")\n        }\n\n        default {\n          assert(false)\n        }\n      }\n\n      if node.kind.isLoop {\n        var label = _loopLabels.get(node.id, null)\n        if label != null {\n          _emit(_indent + _mangleName(label) + (node.nextSibling != null ? \":\\n\" : \":;\\n\"))\n        }\n      }\n    }\n\n    def _emitContent(content Content) {\n      switch content.kind {\n        case .BOOL { _emit(content.asBool.toString) }\n        case .INT { _emit(content.asInt.toString) }\n        case .DOUBLE {\n          var value = content.asDouble\n          if !value.isFinite {\n            _usingNames[\"System\"] = 0\n          }\n          _emit(\n            value.isNaN ? \"Double.NaN\" :\n            value == Math.INFINITY ? \"Double.PositiveInfinity\" :\n            value == -Math.INFINITY ? \"Double.NegativeInfinity\" :\n            doubleToStringWithDot(value))\n        }\n        case .STRING { _emit(quoteString(content.asString, .DOUBLE, .NORMAL)) }\n      }\n    }\n\n    def _emitCommaSeparatedExpressions(from Node, to Node) {\n      while from != to {\n        _emitExpression(from, .COMMA)\n        from = from.nextSibling\n        if from != to {\n          _emit(\", \")\n        }\n      }\n    }\n\n    def _emitExpression(node Node, precedence Precedence) {\n      var kind = node.kind\n      var symbol = node.symbol\n\n      if symbol != null {\n        _handleSymbol(symbol)\n      }\n\n      switch kind {\n        case .TYPE, .LAMBDA_TYPE {\n          _emitType(node.resolvedType)\n        }\n\n        case .NULL {\n          _emit(\"null\")\n        }\n\n        case .NAME {\n          _emit(symbol != null ? _fullName(symbol) : node.asString)\n        }\n\n        case .DOT {\n          _emitExpression(node.dotTarget, .MEMBER)\n          _emit(\".\" + (symbol != null ? _mangleName(symbol) : node.asString))\n        }\n\n        case .CONSTANT {\n          var wrap = precedence == .MEMBER && node.isNumberLessThanZero && (!node.isDouble || node.asDouble.isFinite)\n          if wrap {\n            _emit(\"(\")\n          }\n\n          if node.resolvedType.isEnumOrFlags {\n            _emit(\"(\")\n            _emitType(node.resolvedType)\n            _emit(\")\")\n          }\n          _emitContent(node.content)\n\n          if wrap {\n            _emit(\")\")\n          }\n        }\n\n        case .CALL {\n          var value = node.callValue\n          var wrap = value.kind == .LAMBDA\n\n          if wrap {\n            _emit(\"new \")\n            _emitType(value.resolvedType)\n            _emit(\"(\")\n          }\n\n          if value.kind == .SUPER {\n            _emit(\"base\")\n            if symbol.kind != .FUNCTION_CONSTRUCTOR {\n              _emit(\".\")\n              _emit(_mangleName(symbol))\n            }\n          }\n\n          else if symbol != null && symbol.kind == .FUNCTION_CONSTRUCTOR {\n            _emit(\"new \")\n            _emitType(node.resolvedType)\n          }\n\n          else if value.kind == .DOT && value.asString == \"new\" {\n            _emit(\"new \")\n            _emitExpression(value.dotTarget, .MEMBER)\n          }\n\n          else {\n            _emitExpression(value, .UNARY_POSTFIX)\n          }\n\n          if wrap {\n            _emit(\")\")\n          }\n\n          _emit(\"(\")\n          _emitCommaSeparatedExpressions(value.nextSibling, null)\n          _emit(\")\")\n        }\n\n        case .CAST {\n          var resolvedType = node.resolvedType\n          var type = node.castType\n          var value = node.castValue\n\n          if type.kind == .TYPE && type.resolvedType == .DYNAMIC {\n            _emitExpression(value, precedence)\n          }\n\n          # Automatically promote integer literals to doubles instead of using a cast\n          else if _cache.isEquivalentToDouble(resolvedType) && value.isInt {\n            _emitExpression(_cache.createDouble(value.asInt), precedence)\n          }\n\n          # C# doesn't have a cast from bool to int\n          else if _cache.isNumeric(resolvedType) && value.resolvedType == _cache.boolType {\n            _emitExpression(Node.createHook(value.remove, _cache.createInt(1), _cache.createInt(0)).withType(_cache.intType), precedence)\n          }\n\n          # C# doesn't have a cast from int to bool\n          else if resolvedType == _cache.boolType && _cache.isNumeric(value.resolvedType) {\n            _emitExpression(Node.createBinary(.NOT_EQUAL, value.remove, _cache.createInt(0)).withType(_cache.boolType), precedence)\n          }\n\n          # Only emit a cast if the underlying types are different\n          else if _cache.unwrappedType(value.resolvedType) != _cache.unwrappedType(type.resolvedType) || type.resolvedType == .DYNAMIC {\n            if Precedence.UNARY_POSTFIX < precedence {\n              _emit(\"(\")\n            }\n            _emit(\"(\")\n            _emitExpressionOrType(type, type.resolvedType)\n            _emit(\")\")\n            _emitExpression(value, .UNARY_POSTFIX)\n            if Precedence.UNARY_POSTFIX < precedence {\n              _emit(\")\")\n            }\n          }\n\n          # Otherwise, pretend the cast isn't there\n          else {\n            _emitExpression(value, precedence)\n          }\n        }\n\n        case .TYPE_CHECK {\n          var value = node.typeCheckValue\n          var type = node.typeCheckType\n\n          if Precedence.COMPARE < precedence {\n            _emit(\"(\")\n          }\n          _emitExpression(value, .LOWEST)\n          _emit(\" is \")\n          _emitExpressionOrType(type, type.resolvedType)\n          if Precedence.COMPARE < precedence {\n            _emit(\")\")\n          }\n        }\n\n        case .INITIALIZER_LIST {\n          _emit(\"new \")\n          _emitType(node.resolvedType)\n          if node.hasChildren {\n            _emit(\" { \")\n            _emitCommaSeparatedExpressions(node.firstChild, null)\n            _emit(\" }\")\n          } else {\n            _emit(\"()\")\n          }\n        }\n\n        case .INDEX {\n          _emitExpression(node.indexLeft, .UNARY_POSTFIX)\n          _emit(\"[\")\n          _emitExpression(node.indexRight, .LOWEST)\n          _emit(\"]\")\n        }\n\n        case .ASSIGN_INDEX {\n          if Precedence.ASSIGN < precedence {\n            _emit(\"(\")\n          }\n          _emitExpression(node.assignIndexLeft, .UNARY_POSTFIX)\n          _emit(\"[\")\n          _emitExpression(node.assignIndexCenter, .LOWEST)\n          _emit(\"] = \")\n          _emitExpression(node.assignIndexRight, .ASSIGN)\n          if Precedence.ASSIGN < precedence {\n            _emit(\")\")\n          }\n        }\n\n        case .PARAMETERIZE {\n          var value = node.parameterizeValue\n          if value.isType {\n            _emitType(node.resolvedType)\n          } else {\n            _emitExpression(value, precedence)\n            _emit(\"<\")\n            _emitCommaSeparatedExpressions(value.nextSibling, null)\n            _emit(\">\")\n          }\n        }\n\n        case .SEQUENCE {\n          if Precedence.COMMA <= precedence {\n            _emit(\"(\")\n          }\n          _emitCommaSeparatedExpressions(node.firstChild, null)\n          if Precedence.COMMA <= precedence {\n            _emit(\")\")\n          }\n        }\n\n        case .HOOK {\n          if Precedence.ASSIGN < precedence {\n            _emit(\"(\")\n          }\n          _emitExpression(node.hookTest, .LOGICAL_OR)\n          _emit(\" ? \")\n          _emitExpression(node.hookTrue, .ASSIGN)\n          _emit(\" : \")\n          _emitExpression(node.hookFalse, .ASSIGN)\n          if Precedence.ASSIGN < precedence {\n            _emit(\")\")\n          }\n        }\n\n        case .LAMBDA {\n          var oldEnclosingFunction = _enclosingFunction\n          _enclosingFunction = symbol.asFunctionSymbol\n          _emitArgumentList(symbol.asFunctionSymbol)\n          _emit(\" =>\\n\")\n          _emitBlock(symbol.asFunctionSymbol.block)\n          _enclosingFunction = oldEnclosingFunction\n        }\n\n        case .COMPLEMENT, .NEGATIVE, .NOT, .POSITIVE, .POSTFIX_DECREMENT, .POSTFIX_INCREMENT, .PREFIX_DECREMENT, .PREFIX_INCREMENT {\n          var value = node.unaryValue\n          var info = operatorInfo[kind]\n          var sign = node.sign\n          if info.precedence < precedence {\n            _emit(\"(\")\n          }\n          if !kind.isUnaryPostfix {\n            _emit(info.text)\n\n            # Prevent \"x - -1\" from becoming \"x--1\"\n            if sign != .NULL && sign == value.sign {\n              _emit(\" \")\n            }\n          }\n          _emitExpression(value, info.precedence)\n          if kind.isUnaryPostfix {\n            _emit(info.text)\n          }\n          if info.precedence < precedence {\n            _emit(\")\")\n          }\n        }\n\n        default {\n          if kind.isBinary {\n            var left = node.binaryLeft\n            var right = node.binaryRight\n\n            # Some types stupidly don't implement operator \"==\"\n            if (kind == .EQUAL || kind == .NOT_EQUAL) && left.resolvedType.isParameter && right.resolvedType.isParameter {\n              if kind == .NOT_EQUAL {\n                _emit(\"!\")\n              }\n              _emit(\"EqualityComparer<\")\n              _emitType(left.resolvedType)\n              _emit(\">.Default.Equals(\")\n              _emitExpression(left, .COMMA)\n              _emit(\", \")\n              _emitExpression(right, .COMMA)\n              _emit(\")\")\n              _usingNames[\"System.Collections.Generic\"] = 0\n            }\n\n            else {\n              var info = operatorInfo[kind]\n              if info.precedence < precedence {\n                _emit(\"(\")\n              }\n              _emitExpression(left, info.precedence.incrementIfRightAssociative(info.associativity))\n              _emit(\" \" + info.text + \" \")\n              _emitExpression(right, info.precedence.incrementIfLeftAssociative(info.associativity))\n              if info.precedence < precedence {\n                _emit(\")\")\n              }\n            }\n          }\n\n          else {\n            assert(false)\n          }\n        }\n      }\n    }\n  }\n\n  namespace CSharpEmitter {\n    def _isCompactNodeKind(kind NodeKind) bool {\n      return kind == .EXPRESSION || kind == .VARIABLES || kind.isJump\n    }\n\n    def _fullName(symbol Symbol) string {\n      var parent = symbol.parent\n      if parent != null && parent.kind != .OBJECT_GLOBAL && !symbol.kind.isParameter {\n        var enclosingName = _fullName(parent)\n        if symbol.kind == .FUNCTION_CONSTRUCTOR {\n          return enclosingName\n        }\n        return enclosingName + \".\" + _mangleName(symbol)\n      }\n      return _mangleName(symbol)\n    }\n\n    def _mangleName(symbol Symbol) string {\n      symbol = symbol.forwarded\n      if symbol.kind == .FUNCTION_CONSTRUCTOR {\n        symbol = symbol.parent\n      }\n      if !symbol.isImportedOrExported && symbol.name in _isKeyword {\n        return \"_\" + symbol.name\n      }\n      return symbol.name\n    }\n\n    const _isKeyword = {\n      \"abstract\": 0,\n      \"as\": 0,\n      \"base\": 0,\n      \"bool\": 0,\n      \"break\": 0,\n      \"byte\": 0,\n      \"case\": 0,\n      \"catch\": 0,\n      \"char\": 0,\n      \"checked\": 0,\n      \"class\": 0,\n      \"const\": 0,\n      \"continue\": 0,\n      \"decimal\": 0,\n      \"default\": 0,\n      \"delegate\": 0,\n      \"do\": 0,\n      \"double\": 0,\n      \"else\": 0,\n      \"enum\": 0,\n      \"event\": 0,\n      \"explicit\": 0,\n      \"extern\": 0,\n      \"false\": 0,\n      \"finally\": 0,\n      \"fixed\": 0,\n      \"float\": 0,\n      \"for\": 0,\n      \"foreach\": 0,\n      \"goto\": 0,\n      \"if\": 0,\n      \"implicit\": 0,\n      \"in\": 0,\n      \"int\": 0,\n      \"interface\": 0,\n      \"internal\": 0,\n      \"is\": 0,\n      \"lock\": 0,\n      \"long\": 0,\n      \"namespace\": 0,\n      \"new\": 0,\n      \"null\": 0,\n      \"object\": 0,\n      \"operator\": 0,\n      \"out\": 0,\n      \"override\": 0,\n      \"params\": 0,\n      \"private\": 0,\n      \"protected\": 0,\n      \"public\": 0,\n      \"readonly\": 0,\n      \"ref\": 0,\n      \"return\": 0,\n      \"sbyte\": 0,\n      \"sealed\": 0,\n      \"short\": 0,\n      \"sizeof\": 0,\n      \"stackalloc\": 0,\n      \"static\": 0,\n      \"string\": 0,\n      \"struct\": 0,\n      \"switch\": 0,\n      \"this\": 0,\n      \"throw\": 0,\n      \"true\": 0,\n      \"try\": 0,\n      \"typeof\": 0,\n      \"uint\": 0,\n      \"ulong\": 0,\n      \"unchecked\": 0,\n      \"unsafe\": 0,\n      \"ushort\": 0,\n      \"using\": 0,\n      \"virtual\": 0,\n      \"void\": 0,\n      \"volatile\": 0,\n      \"while\": 0,\n    }\n  }\n}\n"
  },
  {
    "path": "src/backend/emitter.sk",
    "content": "namespace Skew {\n  enum PassKind {\n    EMITTING\n  }\n\n  class EmittingPass : Pass {\n    over kind PassKind {\n      return .EMITTING\n    }\n\n    over run(context PassContext) {\n      var emitter = context.options.target.createEmitter(context)\n      if emitter != null {\n        emitter.visit(context.global)\n        context.outputs = emitter.sources\n      }\n    }\n  }\n\n  enum EmitMode {\n    ALWAYS_EMIT\n    SKIP_IF_EMPTY\n  }\n\n  class Emitter {\n    var _sources List<Source> = []\n    var _prefix = StringBuilder.new\n    var _code = StringBuilder.new\n    var _indentAmount = \"  \"\n    var _indent = \"\"\n\n    def sources List<Source> {\n      return _sources\n    }\n\n    def visit(global ObjectSymbol)\n\n    def _increaseIndent {\n      _indent += _indentAmount\n    }\n\n    def _decreaseIndent {\n      _indent = _indent.slice(_indentAmount.count)\n    }\n\n    def _emit(text string) {\n      _code.append(text)\n    }\n\n    def _emitPrefix(text string) {\n      _prefix.append(text)\n    }\n\n    def _createSource(name string, mode EmitMode) {\n      var code = _code.toString\n\n      if mode == .ALWAYS_EMIT || code != \"\" {\n        _prefix.append(code)\n        _sources.append(Source.new(name, _prefix.toString))\n      }\n\n      _prefix = StringBuilder.new\n      _code = StringBuilder.new\n    }\n\n    def _collectObjects(global ObjectSymbol) List<ObjectSymbol> {\n      var objects List<ObjectSymbol> = []\n      _findObjects(objects, global)\n      return objects\n    }\n\n    def _sortedObjects(global ObjectSymbol) List<ObjectSymbol> {\n      var objects = _collectObjects(global)\n\n      # Sort by inheritance and containment\n      for i in 0..objects.count {\n        var j = i\n\n        # Select an object that comes before all other types\n        while j < objects.count {\n          var object = objects[j]\n          var k = i\n\n          # Check to see if this comes before all other types\n          while k < objects.count {\n            if j != k && _objectComesBefore(objects[k], object) {\n              break\n            }\n            k++\n          }\n          if k == objects.count {\n            break\n          }\n          j++\n        }\n\n        # Swap the object into the correct order\n        if j < objects.count {\n          objects.swap(i, j)\n        }\n      }\n\n      return objects\n    }\n\n    def _markVirtualFunctions(symbol ObjectSymbol) {\n      for object in symbol.objects {\n        _markVirtualFunctions(object)\n      }\n\n      for function in symbol.functions {\n        if function.overridden != null {\n          function.overridden.flags |= .IS_VIRTUAL\n          function.flags |= .IS_VIRTUAL\n        }\n        if function.implementations != null {\n          for other in function.implementations {\n            other.flags |= .IS_VIRTUAL\n            function.flags |= .IS_VIRTUAL\n          }\n        }\n      }\n    }\n\n    def _findObjects(objects List<ObjectSymbol>, object ObjectSymbol) {\n      objects.append(object)\n      for o in object.objects {\n        _findObjects(objects, o)\n      }\n    }\n  }\n\n  namespace Emitter {\n    def _isContainedBy(inner ObjectSymbol, outer ObjectSymbol) bool {\n      if inner.parent == null {\n        return false\n      }\n      if inner.parent == outer {\n        return true\n      }\n      return _isContainedBy(inner.parent.asObjectSymbol, outer)\n    }\n\n    def _objectComesBefore(before ObjectSymbol, after ObjectSymbol) bool {\n      return\n        after.hasBaseClass(before) ||\n        after.hasInterface(before) ||\n        _isContainedBy(after, before) ||\n        after.forwardTo == before\n    }\n  }\n\n  const HEX = \"0123456789ABCDEF\"\n\n  enum QuoteStyle {\n    DOUBLE\n    SINGLE\n    SHORTEST\n    TYPESCRIPT_TEMPLATE\n  }\n\n  enum QuoteOctal {\n    NORMAL\n    OCTAL_WORKAROUND\n  }\n\n  def quoteString(text string, style QuoteStyle, octal QuoteOctal) string {\n    var count = text.count\n\n    # Use whichever quote character is less frequent\n    if style == .SHORTEST {\n      var singleQuotes = 0\n      var doubleQuotes = 0\n      for i in 0..count {\n        var c = text[i]\n        if c == '\"' { doubleQuotes++ }\n        else if c == '\\'' { singleQuotes++ }\n      }\n      style = singleQuotes <= doubleQuotes ? .SINGLE : .DOUBLE\n    }\n\n    var builder = StringBuilder.new\n    var quoteString = style == .SINGLE ? \"'\" : \"\\\"\"\n    var quote = style == .TYPESCRIPT_TEMPLATE ? '`' : style == .SINGLE ? '\\'' : '\"'\n    var escaped = \"\"\n    var start = 0 # Append long runs of unescaped characters using a single slice for speed\n    if style != .TYPESCRIPT_TEMPLATE { builder.append(quoteString) }\n    for i in 0..count {\n      var c = text[i]\n      if c == quote { escaped = \"\\\\\" + quoteString }\n      else if c == '\\n' { escaped = \"\\\\n\" }\n      else if c == '\\r' { escaped = \"\\\\r\" }\n      else if c == '\\t' { escaped = \"\\\\t\" }\n      else if c == '\\0' {\n        # Avoid issues around accidental octal encoding\n        var next = i + 1 < count ? text[i + 1] : '\\0'\n        escaped = octal == .OCTAL_WORKAROUND && next >= '0' && next <= '9' ? \"\\\\000\" : \"\\\\0\"\n      }\n      else if c == '\\\\' { escaped = \"\\\\\\\\\" }\n      else if c == '$' && style == .TYPESCRIPT_TEMPLATE { escaped = \"\\\\$\" }\n      else if c < ' ' { escaped = \"\\\\x\" + HEX.get(c >> 4) + HEX.get(c & 15) }\n      else { continue }\n      builder.append(text.slice(start, i))\n      builder.append(escaped)\n      start = i + 1\n    }\n    builder.append(text.slice(start, count))\n    if style != .TYPESCRIPT_TEMPLATE { builder.append(quoteString) }\n    return builder.toString\n  }\n\n  enum Associativity {\n    NONE\n    LEFT\n    RIGHT\n  }\n\n  enum Precedence {\n    def incrementIfLeftAssociative(associativity Associativity) Precedence {\n      return (self + ((associativity == .LEFT) as int)) as Precedence\n    }\n\n    def incrementIfRightAssociative(associativity Associativity) Precedence {\n      return (self + ((associativity == .RIGHT) as int)) as Precedence\n    }\n  }\n}\n"
  },
  {
    "path": "src/backend/javascript.sk",
    "content": "namespace Skew {\n  class JavaScriptTarget : CompilerTarget {\n    over name string { return \"JavaScript\" }\n    over extension string { return \"js\" }\n    over stopAfterResolve bool { return false }\n    over supportsNestedTypes bool { return true }\n    over removeSingletonInterfaces bool { return true }\n    over stringEncoding Unicode.Encoding { return .UTF16 }\n    over editOptions(options CompilerOptions) { options.define(\"TARGET\", \"JAVASCRIPT\") }\n    over includeSources(sources List<Source>) { sources.prepend(Source.new(\"<native-js>\", NATIVE_LIBRARY_JS)) }\n    over createEmitter(context PassContext) Emitter { return JavaScriptEmitter.new(context, context.options, context.cache) }\n  }\n\n  class JavaScriptEmitter : Emitter {\n    enum BooleanSwap {\n      SWAP\n      NO_SWAP\n    }\n\n    enum ExtractGroupsMode {\n      ALL_SYMBOLS\n      ONLY_LOCAL_VARIABLES\n      ONLY_INSTANCE_VARIABLES\n    }\n\n    class SymbolGroup {\n      const symbols List<Symbol>\n      const count int\n    }\n\n    enum AfterToken {\n      AFTER_KEYWORD\n      AFTER_PARENTHESIS\n    }\n\n    enum BracesMode {\n      MUST_KEEP_BRACES\n      CAN_OMIT_BRACES\n    }\n\n    enum SpecialVariable {\n      NONE\n      AS_STRING\n      CREATE\n      EXTENDS\n      IS_BOOL\n      IS_DOUBLE\n      IS_INT\n      IS_STRING\n      MULTIPLY\n      PROTOTYPE\n    }\n\n    const _context PassContext\n    const _options CompilerOptions\n    const _cache TypeCache\n    const _isSpecialVariableNeeded IntMap<int> = {}\n    const _loopLabels IntMap<VariableSymbol> = {}\n    const _specialVariables IntMap<VariableSymbol> = {}\n    var _global ObjectSymbol = null\n    var _symbolsToExport List<Symbol> = []\n    var _allSpecialVariables List<VariableSymbol> = null\n    var _exportsNamespace ObjectSymbol = null\n    var _enclosingFunction FunctionSymbol = null # This includes lambdas during patching but not during emission\n    var _enclosingLoop Node = null\n    var _namespacePrefix = \"\"\n    var _previousNode Node = null\n    var _previousSymbol Symbol = null\n\n    # There's this stupid corner case in JavaScript syntax where a for-in loop\n    # allows the variable to be initialized. That looks like this:\n    #\n    #   // This is valid JavaScript\n    #   for (var x = 'y' in z) {}\n    #\n    # This means that the variable initializer in the for-in loop cannot be\n    # initialized using an \"in\" expression without parenthesizing it first:\n    #\n    #   // This is invalid JavaScript\n    #   for (var x = 'y' in z; x; x = !x) {}\n    #\n    #   // The initializer must be parenthesized to be valid JavaScript\n    #   for (var x = ('y' in z); x; x = !x) {}\n    #\n    # Rather than parenthesizing all \"in\" expressions, this variable tracks\n    # whether the current state is nested inside a for-in initializer and\n    # only parenthesizes then.\n    var _parenthesizeInExpressions = 0\n\n    # Source map support\n    var _currentColumn = 0\n    var _currentLine = 0\n    var _generator = SourceMapGenerator.new\n    var _previousSource Source = null\n    var _previousStart = 0\n    var _sourceMap = false\n\n    # A union-find data structure is used to quickly merge symbols into\n    # groups. All local variables inside a function are merged with that\n    # function. The map create a quick way of getting from a symbol to its\n    # union/find index.\n    const _allSymbols List<Symbol> = []\n    const _localVariableUnionFind = UnionFind.new\n    const _namingGroupIndexForSymbol IntMap<int> = {}\n    const _symbolCounts IntMap<int> = {}\n    var _nextSymbolName = 0\n\n    # For minification\n    var _mangle = false\n    var _minify = false\n    var _needsSemicolon = false\n    var _newline = \"\\n\"\n    var _space = \" \"\n    var _previousCodeUnit = '\\0'\n\n    # For tracking \"this\" vs \"self\"\n    var _currentSelf VariableSymbol = null\n    var _needsSelf = false\n\n    over visit(global ObjectSymbol) {\n      _mangle = _options.jsMangle\n      _minify = _options.jsMinify\n      _sourceMap = _options.jsSourceMap\n      _global = global\n\n      if _minify {\n        _indentAmount = \"\"\n        _newline = \"\"\n        _space = \"\"\n      }\n\n      # Load special-cased variables\n      for variable in global.variables {\n        var special = _specialVariableMap.get(variable.name, .NONE)\n        if special != .NONE {\n          _specialVariables[special] = variable\n        }\n      }\n      assert(SpecialVariable.AS_STRING in _specialVariables)\n      assert(SpecialVariable.CREATE in _specialVariables)\n      assert(SpecialVariable.EXTENDS in _specialVariables)\n      assert(SpecialVariable.IS_BOOL in _specialVariables)\n      assert(SpecialVariable.IS_DOUBLE in _specialVariables)\n      assert(SpecialVariable.IS_INT in _specialVariables)\n      assert(SpecialVariable.IS_STRING in _specialVariables)\n      assert(SpecialVariable.MULTIPLY in _specialVariables)\n      assert(SpecialVariable.PROTOTYPE in _specialVariables)\n\n      # These don't need to be initialized\n      _specialVariables[SpecialVariable.PROTOTYPE].value = null\n\n      # Sort these so their order is deterministic\n      _allSpecialVariables = _specialVariables.values\n      _allSpecialVariables.sort(Symbol.SORT_VARIABLES_BY_ID)\n\n      # Preprocess the code\n      if _mangle {\n        _liftGlobals(global)\n      }\n      if _options.inlineAllFunctions {\n        _maybeInlineFunctions(global)\n      }\n      shakingPass(global, _cache.entryPointSymbol, .IGNORE_TYPES)\n      _prepareGlobal(global)\n      _convertLambdasToFunctions(global)\n      var objects = _sortedObjects(global)\n\n      # Make sure the \"__create\" variable is inserted when used even if \"__extends\" isn't used\n      var create = _specialVariables[SpecialVariable.CREATE]\n      if create in global.variables {\n        _isSpecialVariableNeeded[create.id] = 0\n      }\n\n      # The entire body of code is wrapped in a closure for safety\n      _emit(_indent + \"(function(\" + (_exportsNamespace != null ? _mangleName(_exportsNamespace) : \"\") + \")\" + _space + \"{\" + _newline + \"\")\n      _increaseIndent\n\n      # Emit special-cased variables that must come first\n      for variable in _allSpecialVariables {\n        if variable.id in _isSpecialVariableNeeded {\n          if variable.value != null && variable.value.kind == .LAMBDA {\n            _emitFunction(_convertLambdaToFunction(variable))\n          } else {\n            _emitVariable(variable)\n          }\n        }\n      }\n\n      # Emit objects and functions\n      for object in objects {\n        _emitObject(object)\n      }\n\n      # Emit variables\n      var statement = Node.createVariables\n      for object in objects {\n        _namespacePrefix = \"\"\n        for o = object; o.kind != .OBJECT_GLOBAL; o = o.parent.asObjectSymbol {\n          _namespacePrefix = _mangleName(o) + \".\" + _namespacePrefix\n        }\n        for variable in object.variables {\n          if !(variable in _allSpecialVariables) {\n            if _mangle && _namespacePrefix == \"\" && !variable.isImportedOrExported {\n              statement.appendChild(Node.createVariable(variable))\n            } else {\n              _emitVariable(variable)\n            }\n          }\n        }\n      }\n      _namespacePrefix = \"\"\n\n      # Group adjacent variables into a single statement during mangling\n      if statement.hasChildren {\n        _emitNewlineBeforeSymbol(statement.firstChild.symbol)\n        _emitStatement(statement)\n        _emitNewlineAfterSymbol(statement.firstChild.symbol)\n        for child = statement.firstChild; child != null; child = child.nextSibling {\n          child.removeChildren\n        }\n      }\n\n      # Emit entry point\n      var entryPointSymbol = _cache.entryPointSymbol\n      if entryPointSymbol != null {\n        var type = entryPointSymbol.resolvedType\n        var callText = _fullName(entryPointSymbol) + (type.argumentTypes.isEmpty ? \"()\" : \"(process.argv.slice(2))\")\n        _emitSemicolonIfNeeded\n        _emit(_newline + _indent + (type.returnType == _cache.intType ? \"process.exit(\" + callText + \")\" : callText))\n        _emitSemicolonAfterStatement\n      }\n\n      # End the closure wrapping everything\n      _decreaseIndent\n      _emit(_indent + \"})(\" + (_exportsNamespace != null ? \"this\" : \"\") + \");\\n\")\n\n      var codeName = _options.outputDirectory != null ? _options.outputDirectory + \"/compiled.js\" : _options.outputFile\n      var mapName = codeName != null ? codeName + \".map\" : null\n\n      # Obfuscate the sourceMappingURL so it's not incorrectly picked up as the\n      # sourceMappingURL for the compiled JavaScript compiler file\n      if _sourceMap {\n        _emit(\"/\")\n        _emit(\"/# sourceMappingURL=\" + splitPath(mapName).entry + \"\\n\")\n      }\n\n      _createSource(codeName, .ALWAYS_EMIT)\n\n      # Create the source map\n      if _sourceMap {\n        _emit(_generator.toString)\n        _createSource(mapName, .ALWAYS_EMIT)\n      }\n    }\n\n    over _emit(text string) {\n      if _minify || _sourceMap {\n        var n = text.count\n        for i in 0..n {\n          if text[i] == '\\n' {\n            _currentColumn = 0\n            _currentLine++\n          } else {\n            _currentColumn++\n          }\n        }\n        if n != 0 {\n          _previousCodeUnit = text[n - 1]\n        }\n      }\n      _code.append(text)\n    }\n\n    def _liftGlobals(global ObjectSymbol) {\n      var globalObjects List<ObjectSymbol> = []\n      var globalFunctions List<FunctionSymbol> = []\n      var globalVariables List<VariableSymbol> = []\n\n      _liftGlobals(global, globalObjects, globalFunctions, globalVariables)\n\n      for object in globalObjects { object.parent = global }\n      for function in globalFunctions { function.parent = global }\n      for variable in globalVariables { variable.parent = global }\n\n      global.objects.append(globalObjects)\n      global.functions.append(globalFunctions)\n      global.variables.append(globalVariables)\n    }\n\n    def _liftGlobals(symbol ObjectSymbol, globalObjects List<ObjectSymbol>, globalFunctions List<FunctionSymbol>, globalVariables List<VariableSymbol>) {\n      var shouldLiftGlobals = symbol.parent != null\n\n      # Scan over child objects\n      symbol.objects.removeIf(object => {\n        _liftGlobals(object, globalObjects, globalFunctions, globalVariables)\n        if shouldLiftGlobals && !object.isImportedOrExported {\n          globalObjects.append(object)\n          return true\n        }\n        return false\n      })\n\n      symbol.functions.removeIf(function => {\n        if shouldLiftGlobals && function.kind == .FUNCTION_GLOBAL && !function.isImportedOrExported {\n          globalFunctions.append(function)\n          return true\n        }\n        return false\n      })\n\n      # Scan over child variables\n      symbol.variables.removeIf(variable => {\n        if shouldLiftGlobals && variable.kind == .VARIABLE_GLOBAL && !variable.isImportedOrExported {\n          globalVariables.append(variable)\n          return true\n        }\n        return false\n      })\n    }\n\n    def _collectInlineableFunctions(symbol ObjectSymbol, listAppends List<Node>, mapInserts List<Node>) {\n      for object in symbol.objects {\n        _collectInlineableFunctions(object, listAppends, mapInserts)\n      }\n\n      for function in symbol.functions {\n        if function.block == null || !function.block.hasTwoChildren {\n          continue\n        }\n\n        var arguments = function.arguments\n\n        # \"foo([], 0)\" => \"[0]\" where \"foo\" is \"def foo(a, b) { a.push(b); return a }\"\n        if arguments.count == 2 {\n          var first = function.block.firstChild\n          var second = function.block.lastChild\n          if first.kind == .EXPRESSION && first.expressionValue.kind == .CALL &&\n              second.kind == .RETURN && second.returnValue != null {\n            var call = first.expressionValue\n            var callValue = call.callValue\n            if call.hasTwoChildren && callValue.kind == .DOT && callValue.asString == \"push\" &&\n                _isReferenceTo(callValue.dotTarget, arguments[0]) &&\n                _isReferenceTo(call.lastChild, arguments[1]) &&\n                _isReferenceTo(second.returnValue, arguments[0]) {\n              for callSite in _context.callGraph.callInfoForSymbol(function).callSites {\n                if callSite != null && callSite.callNode.kind == .CALL {\n                  assert(callSite.callNode.symbol == function)\n                  listAppends.append(callSite.callNode)\n                }\n              }\n            }\n          }\n        }\n\n        # \"foo({}, 0, 1)\" => \"{0: 1}\" where \"foo\" is \"def foo(a, b, c) { a[b] = c; return a }\"\n        else if arguments.count == 3 {\n          var keyType = arguments[1].resolvedType\n          var first = function.block.firstChild\n          var second = function.block.lastChild\n          if (keyType == .DYNAMIC || _cache.isEquivalentToInt(keyType) || _cache.isEquivalentToString(keyType)) &&\n              first.kind == .EXPRESSION && first.expressionValue.kind == .ASSIGN_INDEX &&\n              second.kind == .RETURN && second.returnValue != null {\n            var assign = first.expressionValue\n            if _isReferenceTo(assign.assignIndexLeft, arguments[0]) &&\n                _isReferenceTo(assign.assignIndexCenter, arguments[1]) &&\n                _isReferenceTo(assign.assignIndexRight, arguments[2]) &&\n                _isReferenceTo(second.returnValue, arguments[0]) {\n              for callSite in _context.callGraph.callInfoForSymbol(function).callSites {\n                if callSite != null && callSite.callNode.kind == .CALL {\n                  assert(callSite.callNode.symbol == function)\n                  mapInserts.append(callSite.callNode)\n                }\n              }\n            }\n          }\n        }\n      }\n    }\n\n    # This uses iteration until fixed point to avoid dependence on inlining order\n    def _maybeInlineFunctions(global ObjectSymbol) {\n      var listAppends List<Node> = []\n      var mapInserts List<Node> = []\n      _collectInlineableFunctions(global, listAppends, mapInserts)\n\n      # List append fixed point\n      var changed = true\n      while changed {\n        changed = false\n        for i in 0..listAppends.count {\n          var node = listAppends[i]\n\n          # This will be null if it was already inlined\n          if node == null {\n            continue\n          }\n\n          var firstArgument = node.callValue.nextSibling\n          var secondArgument = firstArgument.nextSibling\n\n          # List expressions are sometimes casted\n          if firstArgument.kind == .CAST {\n            firstArgument = firstArgument.castValue\n          }\n\n          # Only check when the inputs are constants\n          if firstArgument.kind == .INITIALIZER_LIST {\n            node.become(firstArgument.remove.appendChild(secondArgument.remove))\n            listAppends[i] = null\n            changed = true\n          }\n        }\n      }\n\n      # Map insert fixed point\n      changed = true\n      while changed {\n        changed = false\n        for i in 0..mapInserts.count {\n          var node = mapInserts[i]\n\n          # This will be null if it was already inlined\n          if node == null {\n            continue\n          }\n\n          var firstArgument = node.callValue.nextSibling\n          var secondArgument = firstArgument.nextSibling\n          var thirdArgument = secondArgument.nextSibling\n\n          # Map expressions are sometimes casted\n          if firstArgument.kind == .CAST {\n            firstArgument = firstArgument.castValue\n          }\n\n          # Only check when the inputs are constants\n          if firstArgument.kind == .INITIALIZER_MAP && (secondArgument.isInt || secondArgument.isString) {\n            node.become(firstArgument.remove.appendChild(Node.createPair(secondArgument.remove, thirdArgument.remove).withType(.DYNAMIC)))\n            mapInserts[i] = null\n            changed = true\n          }\n        }\n      }\n    }\n\n    def _prepareGlobal(global ObjectSymbol) {\n      # Lower certain stuff into JavaScript (for example, \"x as bool\" becomes \"!!x\")\n      _patchObject(global)\n      _exportSymbols\n\n      # Skip everything below if we aren't mangling\n      if !_mangle {\n        return\n      }\n\n      # These will be culled by tree shaking regardless of whether they are needed\n      for variable in _allSpecialVariables {\n        if variable.id in _isSpecialVariableNeeded {\n          _allocateNamingGroupIndex(variable)\n          _patchNode(variable.value)\n        }\n      }\n\n      # Rename symbols based on frequency for better compression\n      _renameSymbols\n    }\n\n    def _convertLambdaToFunction(variable VariableSymbol) FunctionSymbol {\n      var function = variable.value.symbol.asFunctionSymbol\n      function.kind = .FUNCTION_GLOBAL\n      function.parent = variable.parent\n      function.name = variable.name\n      if function.block.parent != null {\n        function.block.remove\n      }\n      return function\n    }\n\n    def _convertLambdasToFunctions(symbol ObjectSymbol) {\n      for object in symbol.objects {\n        _convertLambdasToFunctions(object)\n      }\n\n      symbol.variables.removeIf(variable => {\n        if variable.kind == .VARIABLE_GLOBAL && variable.isConst && !variable.isExported && variable.value != null && variable.value.kind == .LAMBDA {\n          symbol.functions.append(_convertLambdaToFunction(variable))\n          return true\n        }\n        return false\n      })\n    }\n\n    def _allocateNamingGroupIndex(symbol Symbol) {\n      if _mangle && !(symbol.id in _namingGroupIndexForSymbol) {\n        var index = _localVariableUnionFind.allocate\n        _namingGroupIndexForSymbol[symbol.id] = index\n        _allSymbols.append(symbol)\n\n        # Explicitly add function arguments since they won't be reached by\n        # normal tree traversal\n        if symbol.kind.isFunction {\n          var this = symbol.asFunctionSymbol.this\n          if this != null {\n            _allocateNamingGroupIndex(this)\n          }\n          for argument in symbol.asFunctionSymbol.arguments {\n            _allocateNamingGroupIndex(argument)\n          }\n        }\n      }\n    }\n\n    def _renameSymbols {\n      # This holds the groups used for naming. Unioning two labels using\n      # this object will cause both groups of symbols to have the same name.\n      var namingGroupsUnionFind = UnionFind.new.allocate(_allSymbols.count)\n\n      # These are optional and only reduce the number of generated names\n      var order List<int> = []\n      _aliasLocalVariables(namingGroupsUnionFind, order)\n      _aliasUnrelatedProperties(namingGroupsUnionFind, order)\n\n      # Ensure all overridden symbols have the same generated name. This is\n      # manditory for correctness, otherwise virtual functions break.\n      var namingGroupMap IntMap<int> = {}\n      for symbol in _allSymbols {\n        if symbol.kind.isFunction {\n          var function = symbol.asFunctionSymbol\n          assert(function.id in _namingGroupIndexForSymbol)\n          var id = namingGroupMap.get(function.namingGroup, -1)\n          if id == -1 {\n            namingGroupMap[function.namingGroup] = _namingGroupIndexForSymbol[function.id]\n          } else {\n            namingGroupsUnionFind.union(id, _namingGroupIndexForSymbol[function.id])\n          }\n        }\n      }\n\n      # Collect all reserved names together into one big set for querying\n      var reservedNames StringMap<int> = _isKeyword.clone\n      for symbol in _allSymbols {\n        if !_shouldRenameSymbol(symbol) {\n          reservedNames[symbol.name] = 0\n        }\n      }\n\n      # Everything that should have the same name is now grouped together.\n      # Generate and assign names to all internal symbols, but use shorter\n      # names for more frequently used symbols.\n      var sortedGroups List<SymbolGroup> = []\n      for group in _extractGroups(namingGroupsUnionFind, .ALL_SYMBOLS) {\n        var count = 0\n        for symbol in group {\n          if _shouldRenameSymbol(symbol) {\n            count += _symbolCounts.get(symbol.id, 0)\n          }\n        }\n        sortedGroups.append(SymbolGroup.new(group, count))\n      }\n\n      # Create a total order to make builds deterministic when maps use hashing\n      sortedGroups.sort((a, b) => {\n        var difference = b.count <=> a.count\n        if difference == 0 {\n          difference = b.symbols.count <=> a.symbols.count\n          for i = 0; difference == 0 && i < a.symbols.count; i++ {\n            difference = a.symbols[i].id <=> b.symbols[i].id\n          }\n        }\n        return difference\n      })\n\n      for group in sortedGroups {\n        var name = \"\"\n        for symbol in group.symbols {\n          if _shouldRenameSymbol(symbol) {\n            if name == \"\" {\n              name = _generateSymbolName(reservedNames)\n            }\n            symbol.name = name\n          }\n        }\n      }\n    }\n\n    # Merge local variables from different functions together in the order\n    # they were declared. This will cause every argument list to use the same\n    # variables in the same order, which should offer better gzip:\n    #\n    #   function d(a, b) {}\n    #   function e(a, b, c) {}\n    #\n    def _aliasLocalVariables(unionFind UnionFind, order List<int>) {\n      _zipTogetherInOrder(unionFind, order, _extractGroups(_localVariableUnionFind, .ONLY_LOCAL_VARIABLES))\n    }\n\n    # Merge all related types together into naming groups. This ensures names\n    # will be unique within a subclass hierarchy allowing names to be\n    # duplicated in separate subclass hierarchies.\n    def _aliasUnrelatedProperties(unionFind UnionFind, order List<int>) {\n      var relatedTypesUnionFind = UnionFind.new.allocate(_allSymbols.count)\n      for i in 0.._allSymbols.count {\n        var symbol = _allSymbols[i]\n        if symbol.kind == .OBJECT_CLASS {\n          var baseClass = symbol.asObjectSymbol.baseClass\n          if baseClass != null {\n            relatedTypesUnionFind.union(i, _namingGroupIndexForSymbol[baseClass.id])\n          }\n          for variable in symbol.asObjectSymbol.variables {\n            relatedTypesUnionFind.union(i, _namingGroupIndexForSymbol[variable.id])\n          }\n        }\n      }\n      _zipTogetherInOrder(unionFind, order, _extractGroups(relatedTypesUnionFind, .ONLY_INSTANCE_VARIABLES))\n    }\n\n    def _zipTogetherInOrder(unionFind UnionFind, order List<int>, groups List<List<Symbol>>) {\n      for group in groups {\n        for i in 0..group.count {\n          var symbol = group[i]\n          var index = _namingGroupIndexForSymbol[symbol.id]\n          if i >= order.count {\n            order.append(index)\n          } else {\n            unionFind.union(index, order[i])\n          }\n        }\n      }\n    }\n\n    def _generateSymbolName(reservedNames StringMap<int>) string {\n      while true {\n        var name = _numberToName(_nextSymbolName)\n        _nextSymbolName++\n        if !(name in reservedNames) {\n          return name\n        }\n      }\n    }\n\n    def _extractGroups(unionFind UnionFind, mode ExtractGroupsMode) List<List<Symbol>> {\n      var labelToGroup IntMap<List<Symbol>> = {}\n      for symbol in _allSymbols {\n        if mode == .ONLY_LOCAL_VARIABLES && !symbol.kind.isLocalOrArgumentVariable ||\n            mode == .ONLY_INSTANCE_VARIABLES && symbol.kind != .VARIABLE_INSTANCE {\n          continue\n        }\n        assert(symbol.id in _namingGroupIndexForSymbol)\n        var label = unionFind.find(_namingGroupIndexForSymbol[symbol.id])\n        var group = labelToGroup.get(label, null)\n        if group == null {\n          group = []\n          labelToGroup[label] = group\n        }\n        group.append(symbol)\n      }\n\n      # Sort each resulting group to make builds deterministic when maps use hashing\n      var groups = labelToGroup.values\n      for group in groups {\n        group.sort(Symbol.SORT_BY_ID)\n      }\n      return groups\n    }\n\n    def _addMapping(range Range) {\n      if _sourceMap && range != null {\n        var source = range.source\n        var start = range.start\n\n        if _previousSource != source || _previousStart != start {\n          var location = source.indexToLineColumn(start)\n          _generator.addMapping(source, location.line, location.column, _currentLine, _currentColumn)\n          _previousStart = start\n          _previousSource = source\n        }\n      }\n    }\n\n    def _emitSemicolonAfterStatement {\n      if !_minify {\n        _emit(\";\\n\")\n      } else {\n        _needsSemicolon = true\n      }\n    }\n\n    def _emitSemicolonIfNeeded {\n      if _needsSemicolon {\n        _emit(\";\")\n        _needsSemicolon = false\n      }\n      _maybeEmitMinifedNewline\n    }\n\n    # Lots of text editors choke up on long lines, so add a newline every now\n    # and then for usability's sake\n    def _maybeEmitMinifedNewline {\n      if _minify && _currentColumn > 1024 {\n        _emit(\"\\n\")\n      }\n    }\n\n    def _emitNewlineBeforeSymbol(symbol Symbol) {\n      _emitSemicolonIfNeeded\n      if !_minify && _previousSymbol != null &&\n          (!_previousSymbol.kind.isObject || !symbol.kind.isObject || symbol.comments != null || _previousSymbol.kind.isEnumOrFlags || symbol.kind.isEnumOrFlags) &&\n          (!_previousSymbol.kind.isVariable || !symbol.kind.isVariable || symbol.comments != null) {\n        _emit(\"\\n\")\n      }\n      _previousSymbol = null\n      _addMapping(symbol.range)\n    }\n\n    def _emitNewlineAfterSymbol(symbol Symbol) {\n      _previousSymbol = symbol\n    }\n\n    def _emitNewlineBeforeStatement(node Node) {\n      if !_minify && _previousNode != null && (node.comments != null || !_isCompactNodeKind(_previousNode.kind) || !_isCompactNodeKind(node.kind)) {\n        _emit(\"\\n\")\n      } else {\n        _maybeEmitMinifedNewline\n      }\n      _previousNode = null\n    }\n\n    def _emitNewlineAfterStatement(node Node) {\n      _previousNode = node\n    }\n\n    def _emitComments(comments List<Comment>) {\n      if comments != null && !_minify {\n        for comment in comments {\n          for line in comment.lines {\n            _emit(_indent + \"//\" + line + \"\\n\")\n          }\n          if comment.hasGapBelow {\n            _emit(\"\\n\")\n          }\n        }\n      }\n    }\n\n    def _emitObject(symbol ObjectSymbol) {\n      if symbol.isImported {\n        return\n      }\n\n      var foundPrimaryConstructor = false\n      _namespacePrefix = symbol.parent != null ? _computeNamespacePrefix(symbol.parent.asObjectSymbol) : \"\"\n\n      switch symbol.kind {\n        case .OBJECT_NAMESPACE, .OBJECT_INTERFACE, .OBJECT_WRAPPED {\n          if symbol.forwardTo == null && symbol != _exportsNamespace {\n            _emitNewlineBeforeSymbol(symbol)\n            _emitComments(symbol.comments)\n            _emit(_indent + (_namespacePrefix == \"\" ? \"var \" : _namespacePrefix) + _mangleName(symbol) + _space + \"=\" + _space + \"{}\")\n            _emitSemicolonAfterStatement\n            _emitNewlineAfterSymbol(symbol)\n          }\n        }\n\n        case .OBJECT_ENUM, .OBJECT_FLAGS {\n          _emitNewlineBeforeSymbol(symbol)\n          _emitComments(symbol.comments)\n          _emit(_indent + (_namespacePrefix == \"\" ? \"var \" : _namespacePrefix) + _mangleName(symbol) + _space + \"=\" + _space + \"{\")\n          _increaseIndent\n          var isFirst = true\n          for variable in symbol.variables {\n            if variable.kind == .VARIABLE_ENUM_OR_FLAGS {\n              if isFirst {\n                isFirst = false\n              } else {\n                _emit(\",\")\n              }\n              _emit(_newline)\n              _emitNewlineBeforeSymbol(variable)\n              _emitComments(variable.comments)\n              _emit(_indent + _mangleName(variable) + \":\" + _space)\n              _emitExpression(variable.value, .COMMA)\n              _emitNewlineAfterSymbol(variable)\n            }\n          }\n          _decreaseIndent\n          if !isFirst && !_minify {\n            _emit(\"\\n\" + _indent)\n          }\n          _emit(\"}\")\n          _emitSemicolonAfterStatement\n          _emitNewlineAfterSymbol(symbol)\n        }\n\n        case .OBJECT_CLASS {\n          var variable = _specialVariables[SpecialVariable.EXTENDS]\n          for function in symbol.functions {\n            if function.isPrimaryConstructor {\n              if function.comments == null && symbol.comments != null {\n                function.comments = symbol.comments\n              }\n              _emitFunction(function)\n              if symbol.baseClass != null || symbol.kind == .OBJECT_CLASS && symbol.extends != null {\n                if !_minify {\n                  _emit(\"\\n\" + _indent)\n                }\n                _emitSemicolonIfNeeded\n                _addMapping(variable.range)\n                _emit(_mangleName(variable) + \"(\" + _fullName(symbol) + \",\" + _space)\n                if symbol.baseClass != null {\n                  _emit(_fullName(symbol.baseClass))\n                } else {\n                  assert(symbol.kind == .OBJECT_CLASS && symbol.extends != null)\n                  _emitExpression(symbol.extends, .LOWEST)\n                }\n                _emit(\")\")\n                _emitSemicolonAfterStatement\n              }\n              foundPrimaryConstructor = true\n              break\n            }\n          }\n\n          # Emit a namespace if the class is never constructed\n          if !foundPrimaryConstructor {\n            _emitNewlineBeforeSymbol(symbol)\n            _emit(_indent + (_namespacePrefix == \"\" && !symbol.isExported ? \"var \" : _namespacePrefix) + _mangleName(symbol) + _space + \"=\" + _space + \"{}\")\n            _emitSemicolonAfterStatement\n          }\n        }\n      }\n\n      if symbol.kind != .OBJECT_GLOBAL {\n        _namespacePrefix += _mangleName(symbol) + \".\"\n      }\n\n      if symbol.usePrototypeCache {\n        _emitSemicolonIfNeeded\n        _emit(_newline + _indent + _mangleName(_specialVariables[SpecialVariable.PROTOTYPE]) + _space + \"=\" + _space + _fullName(symbol) + \".prototype\")\n        _emitSemicolonAfterStatement\n      }\n\n      # Ignore instance functions if the class is never constructed\n      for function in symbol.functions {\n        if foundPrimaryConstructor ? !function.isPrimaryConstructor : function.kind == .FUNCTION_GLOBAL {\n          _emitFunction(function)\n        }\n      }\n    }\n\n    def _emitArgumentList(arguments List<VariableSymbol>) {\n      for argument in arguments {\n        if argument != arguments.first {\n          _emit(\",\" + _space)\n        }\n        _addMapping(argument.range)\n        _emit(_mangleName(argument))\n      }\n    }\n\n    def _emitFunction(symbol FunctionSymbol) {\n      if symbol.block == null {\n        return\n      }\n\n      _emitNewlineBeforeSymbol(symbol)\n      _emitComments(symbol.comments)\n\n      var isExpression = _namespacePrefix != \"\" || symbol.isExported\n      var name = _mangleName(symbol.isPrimaryConstructor ? symbol.parent : symbol)\n\n      if isExpression {\n        _emit(_indent + (\n          symbol.kind != .FUNCTION_INSTANCE ? _namespacePrefix :\n          symbol.parent.usePrototypeCache ? _mangleName(_specialVariables[SpecialVariable.PROTOTYPE]) + \".\" :\n          _namespacePrefix + \"prototype.\") + name + _space + \"=\" + _space + \"function(\")\n      } else {\n        _emit(_indent + \"function \" + name + \"(\")\n      }\n\n      _emitArgumentList(symbol.arguments)\n      _emit(\")\" + _space + \"{\" + _newline)\n      _increaseIndent\n      _enclosingFunction = symbol\n      _emitStatements(symbol.block)\n      _enclosingFunction = null\n      _decreaseIndent\n      _emit(_indent + \"}\")\n      if isExpression {\n        _emitSemicolonAfterStatement\n      } else {\n        _needsSemicolon = false\n        _emit(_newline)\n      }\n      _emitNewlineAfterSymbol(symbol)\n\n      # Secondary constructors need the same prototype as the primary constructor\n      if symbol.kind == .FUNCTION_CONSTRUCTOR && !symbol.isPrimaryConstructor {\n        _emitSemicolonIfNeeded\n        _emit(_newline + _indent + _fullName(symbol) + \".prototype\" + _space + \"=\" + _space + (\n          symbol.parent.usePrototypeCache ? _mangleName(_specialVariables[SpecialVariable.PROTOTYPE]) :\n          _fullName(symbol.parent) + \".prototype\"))\n        _emitSemicolonAfterStatement\n      }\n    }\n\n    def _emitVariable(symbol VariableSymbol) {\n      if symbol.isImported {\n        return\n      }\n\n      if symbol.kind != .VARIABLE_INSTANCE && symbol.kind != .VARIABLE_ENUM_OR_FLAGS && (symbol.value != null || _namespacePrefix == \"\" || symbol.kind.isLocalOrArgumentVariable) {\n        _emitNewlineBeforeSymbol(symbol)\n        _emitComments(symbol.comments)\n        _emit(_indent + (_namespacePrefix == \"\" || symbol.kind.isLocalOrArgumentVariable ? \"var \" : _namespacePrefix) + _mangleName(symbol))\n\n        if symbol.value != null {\n          _emit(_space + \"=\" + _space)\n          _emitExpression(symbol.value, .COMMA)\n        }\n\n        _emitSemicolonAfterStatement\n        _emitNewlineAfterSymbol(symbol)\n      }\n    }\n\n    def _emitStatements(node Node) {\n      _previousNode = null\n\n      for child = node.firstChild; child != null; child = child.nextSibling {\n        _emitSemicolonIfNeeded\n        _emitNewlineBeforeStatement(child)\n        _addMapping(child.range)\n        _emitComments(child.comments)\n        _emitStatement(child)\n        _emitNewlineAfterStatement(child)\n      }\n\n      _previousNode = null\n    }\n\n    def _emitBlock(node Node, after AfterToken, mode BracesMode) {\n      var shouldMinify = mode == .CAN_OMIT_BRACES && _minify\n      _addMapping(node.range)\n      if shouldMinify && !node.hasChildren {\n        _emit(\";\")\n      } else if shouldMinify && node.hasOneChild && node.firstChild.kind != .COMMENT_BLOCK {\n        if after == .AFTER_KEYWORD {\n          _emit(\" \")\n        }\n        _emitStatement(node.firstChild)\n      } else {\n        _emit(_space + \"{\" + _newline)\n        if node.hasChildren {\n          _increaseIndent\n          _emitStatements(node)\n          _decreaseIndent\n        }\n        _emit(_indent + \"}\")\n        _needsSemicolon = false\n      }\n    }\n\n    def _emitVariables(node Node) {\n      _emit(\"var \")\n      for child = node.firstChild; child != null; child = child.nextSibling {\n        if child.previousSibling != null {\n          _emit(\",\" + _space)\n        }\n        var symbol = child.symbol.asVariableSymbol\n        _emit(_mangleName(symbol))\n        if symbol.value != null {\n          _emit(_space + \"=\" + _space)\n          _emitExpression(symbol.value, .COMMA)\n        }\n      }\n    }\n\n    def _canRemoveSpaceBeforeKeyword(node Node) bool {\n      var kind = node.kind\n      return\n        kind.isUnary && !kind.isUnaryPostfix ||\n        node.isString ||\n        node.isNumberLessThanZero ||\n        kind.isInitializer ||\n        (kind == .HOOK || kind == .SEQUENCE) && _canRemoveSpaceBeforeKeyword(node.firstChild)\n    }\n\n    def _emitSpaceBeforeKeyword(node Node) {\n      if !_minify || !_canRemoveSpaceBeforeKeyword(node) {\n        _emit(\" \")\n      }\n    }\n\n    def _emitStatement(node Node) {\n      switch node.kind {\n        case .COMMENT_BLOCK {}\n\n        case .VARIABLES {\n          _emit(_indent)\n          _emitVariables(node)\n          _emitSemicolonAfterStatement\n        }\n\n        case .EXPRESSION {\n          _emit(_indent)\n          _emitExpression(node.expressionValue, .LOWEST)\n          _emitSemicolonAfterStatement\n        }\n\n        case .BREAK {\n          var label = _loopLabels.get(node.id, null)\n          _emit(_indent + \"break\")\n          if label != null {\n            _emit(\" \" + _mangleName(label))\n          }\n          _emitSemicolonAfterStatement\n        }\n\n        case .CONTINUE {\n          _emit(_indent + \"continue\")\n          _emitSemicolonAfterStatement\n        }\n\n        case .RETURN {\n          _emit(_indent + \"return\")\n          var value = node.returnValue\n          if value != null {\n            var comments = value.comments\n            if !_minify && comments != null {\n              # JavaScript needs parentheses here to avoid ASI issues\n              _emit(\" (\\n\")\n              _increaseIndent\n              _emitComments(comments)\n              _emit(_indent)\n              _emitExpression(value, .LOWEST)\n              _decreaseIndent\n              _emit(\")\")\n            } else {\n              _emitSpaceBeforeKeyword(value)\n              _emitExpression(value, .LOWEST)\n            }\n          }\n          _emitSemicolonAfterStatement\n        }\n\n        case .THROW {\n          var value = node.throwValue\n          _emit(_indent + \"throw\")\n          _emitSpaceBeforeKeyword(value)\n          _emitExpression(value, .LOWEST)\n          _emitSemicolonAfterStatement\n        }\n\n        case .FOR {\n          var setup = node.forSetup\n          var test = node.forTest\n          var update = node.forUpdate\n          _emit(_indent)\n          _emitLoopLabel(node)\n          _emit(\"for\" + _space + \"(\")\n          if !setup.isEmptySequence {\n            _parenthesizeInExpressions++\n            if setup.kind == .VARIABLES {\n              _emitVariables(setup)\n            } else {\n              _emitExpression(setup, .LOWEST)\n            }\n            _parenthesizeInExpressions--\n          }\n          _emit(\";\")\n          if !test.isEmptySequence {\n            _emit(_space)\n            _emitExpression(test, .LOWEST)\n          }\n          _emit(\";\")\n          if !update.isEmptySequence {\n            _emit(_space)\n            _emitExpression(update, .LOWEST)\n          }\n          _emit(\")\")\n          _emitBlock(node.forBlock, .AFTER_PARENTHESIS, .CAN_OMIT_BRACES)\n          _emit(_newline)\n        }\n\n        case .FOREACH {\n          _emit(_indent)\n          _emitLoopLabel(node)\n          _emit(\"for\" + _space + \"(var \" + _mangleName(node.symbol) + \" in \")\n          _emitExpression(node.foreachValue, .LOWEST)\n          _emit(\")\")\n          _emitBlock(node.foreachBlock, .AFTER_PARENTHESIS, .CAN_OMIT_BRACES)\n          _emit(_newline)\n        }\n\n        case .IF {\n          _emit(_indent)\n          _emitIf(node)\n          _emit(_newline)\n        }\n\n        case .SWITCH {\n          var switchValue = node.switchValue\n          _emit(_indent + \"switch\" + _space + \"(\")\n          _emitExpression(switchValue, .LOWEST)\n          _emit(\")\" + _space + \"{\" + _newline)\n          _increaseIndent\n          for child = switchValue.nextSibling; child != null; child = child.nextSibling {\n            var block = child.caseBlock\n            _emitSemicolonIfNeeded\n            if child.previousSibling != switchValue {\n              _emit(_newline)\n            }\n            _emitComments(child.comments)\n            if child.hasOneChild {\n              _emit(_indent + \"default:\")\n            } else {\n              for value = child.firstChild; value != block; value = value.nextSibling {\n                if value.previousSibling != null {\n                  _emit(_newline)\n                }\n                _emitComments(value.comments)\n                _emit(_indent + \"case\")\n                _emitSpaceBeforeKeyword(value)\n                _emitExpression(value, .LOWEST)\n                _emit(\":\")\n              }\n            }\n            if !_minify {\n              _emit(\" {\\n\")\n              _increaseIndent\n            }\n            _emitStatements(block)\n            if block.hasControlFlowAtEnd {\n              _emitSemicolonIfNeeded\n              _emit(_indent + \"break\")\n              _emitSemicolonAfterStatement\n            }\n            if !_minify {\n              _decreaseIndent\n              _emit(_indent + \"}\\n\")\n            }\n          }\n          _decreaseIndent\n          _emit(_indent + \"}\" + _newline)\n          _needsSemicolon = false\n        }\n\n        case .TRY {\n          var tryBlock = node.tryBlock\n          var finallyBlock = node.finallyBlock\n          _emit(_indent + \"try\")\n          _emitBlock(tryBlock, .AFTER_KEYWORD, .MUST_KEEP_BRACES)\n          _emit(_newline)\n          for child = tryBlock.nextSibling; child != finallyBlock; child = child.nextSibling {\n            _emit(_newline)\n            _emitComments(child.comments)\n            _emit(_indent + \"catch\" + _space + \"(\" + _mangleName(child.symbol) + \")\")\n            _emitBlock(child.catchBlock, .AFTER_KEYWORD, .MUST_KEEP_BRACES)\n            _emit(_newline)\n          }\n          if finallyBlock != null {\n            _emit(_newline)\n            _emitComments(finallyBlock.comments)\n            _emit(_indent + \"finally\")\n            _emitBlock(finallyBlock, .AFTER_KEYWORD, .MUST_KEEP_BRACES)\n            _emit(_newline)\n          }\n        }\n\n        case .WHILE {\n          _emit(_indent)\n          _emitLoopLabel(node)\n          _emit(\"while\" + _space + \"(\")\n          _emitExpression(node.whileTest, .LOWEST)\n          _emit(\")\")\n          _emitBlock(node.whileBlock, .AFTER_PARENTHESIS, .CAN_OMIT_BRACES)\n          _emit(_newline)\n        }\n\n        default {\n          assert(false)\n        }\n      }\n    }\n\n    def _emitLoopLabel(node Node) {\n      var label = _loopLabels.get(node.id, null)\n      if label != null {\n        _emit(_mangleName(label) + \":\" + _space)\n      }\n    }\n\n    def _emitIf(node Node) {\n      var trueBlock = node.ifTrue\n      var falseBlock = node.ifFalse\n      _emit(\"if\" + _space + \"(\")\n      _emitExpression(node.ifTest, .LOWEST)\n      _emit(\")\")\n\n      # Make sure to always keep braces to avoid the dangling \"else\" case\n      # \"if (a) if (b) c; else d; else e;\"\n      # \"if (a) { if (b) if (c) d; else e; } else f;\"\n      # \"if (a) { if (b) c; else if (d) e; } else f;\"\n      # \"if (a) { while (true) if (b) break; } else c;\"\n      var braces = BracesMode.CAN_OMIT_BRACES\n      if falseBlock != null {\n        var statement = trueBlock.blockStatement\n        if statement != null && (statement.kind == .IF ||\n            statement.kind == .FOR && statement.forBlock.blockStatement != null ||\n            statement.kind == .FOREACH && statement.foreachBlock.blockStatement != null ||\n            statement.kind == .WHILE && statement.whileBlock.blockStatement != null) {\n          braces = .MUST_KEEP_BRACES\n        }\n      }\n      _emitBlock(node.ifTrue, .AFTER_PARENTHESIS, braces)\n\n      if falseBlock != null {\n        var singleIf = _singleIf(falseBlock)\n        _emitSemicolonIfNeeded\n        _emit(_newline + _newline)\n        _emitComments(falseBlock.comments)\n        if singleIf != null {\n          _emitComments(singleIf.comments)\n        }\n        _emit(_indent + \"else\")\n\n        if singleIf != null {\n          _emit(\" \")\n          _emitIf(singleIf)\n        } else {\n          _emitBlock(falseBlock, .AFTER_KEYWORD, .CAN_OMIT_BRACES)\n        }\n      }\n    }\n\n    def _emitContent(content Content) {\n      switch content.kind {\n        case .BOOL { _emit(content.asBool.toString) }\n        case .INT { _emit(content.asInt.toString) }\n        case .DOUBLE {\n          var value = content.asDouble\n          var text =\n            value.isNaN ? \"NaN\" :\n            value == Math.INFINITY ? \"Infinity\" :\n            value == -Math.INFINITY ? \"-Infinity\" :\n\n            # The C# implementation of double.ToString() uses an uppercase \"E\"\n            TARGET == .CSHARP ? value.toString.toLowerCase :\n            value.toString\n\n          # \"0.123\" => \".123\"\n          # \"-0.123\" => \"-.123\"\n          if _minify {\n            if text.startsWith(\"0.\") && text != \"0.\" {\n              text = text.slice(1)\n            } else if text.startsWith(\"-0.\") && text != \"-0.\" {\n              text = \"-\" + text.slice(2)\n            }\n          }\n\n          _emit(text)\n        }\n        case .STRING { _emit(quoteString(content.asString, .SHORTEST, .OCTAL_WORKAROUND)) }\n      }\n    }\n\n    def _emitCommaSeparatedExpressions(from Node, to Node) {\n      while from != to {\n        _emitExpression(from, .COMMA)\n        from = from.nextSibling\n        if from != to {\n          _emit(\",\" + _space)\n          _maybeEmitMinifedNewline\n        }\n      }\n    }\n\n    # Calling a function in an expression that starts with something like \"function(){}()\"\n    # must be wrapped in parentheses to avoid looking like a function statement\n    def _lambdaMayNeedParentheses(node Node) bool {\n      var parent = node.parent\n      if parent == null {\n        return false # Expression statements always have parents\n      }\n      switch parent.kind {\n        case .CALL { return node == parent.callValue && _lambdaMayNeedParentheses(parent) }\n        case .DOT { return _lambdaMayNeedParentheses(parent) }\n        case .INDEX { return node == parent.indexLeft && _lambdaMayNeedParentheses(parent) }\n        case .ASSIGN_INDEX { return node == parent.assignIndexLeft && _lambdaMayNeedParentheses(parent) }\n        default {\n          if parent.kind.isBinary { return node == parent.binaryLeft && _lambdaMayNeedParentheses(parent) }\n          return true # Not sure, wrap to be safe\n        }\n      }\n    }\n\n    # Returns true if the provided call node must be parenthesized due to being inside a dot expression\n    def _checkForDotParentOfCall(node Node) bool {\n      assert(node.kind == .CALL)\n      var p = node.parent\n      while p != null {\n        switch p.kind {\n          case .CAST, .PARAMETERIZE { p = p.parent }\n          case .DOT { return true }\n          default { break }\n        }\n      }\n      return false\n    }\n\n    def _emitExpression(node Node, precedence Precedence) {\n      var kind = node.kind\n      _addMapping(node.range)\n\n      switch kind {\n        case .TYPE {\n          _emit(_fullName(node.resolvedType.symbol))\n        }\n\n        case .NULL {\n          _emit(\"null\")\n        }\n\n        case .NAME {\n          var symbol = node.symbol\n          _emit(symbol != null ? _fullName(symbol) : node.asString)\n        }\n\n        case .DOT {\n          _emitExpression(node.dotTarget, .MEMBER)\n          _emit(\".\" + (node.symbol != null ? _mangleName(node.symbol) : node.asString))\n        }\n\n        case .CONSTANT {\n          var wrap = precedence == .MEMBER && (node.isInt || node.isDouble && (node.asDouble.isFinite || node.asDouble < 0))\n          if wrap {\n            _emit(\"(\")\n          }\n\n          # Prevent \"x - -1\" from becoming \"x--1\"\n          if _minify && node.isNumberLessThanZero && _previousCodeUnit == '-' {\n            _emit(\" \")\n          }\n\n          _emitContent(node.content)\n\n          if wrap {\n            _emit(\")\")\n          }\n        }\n\n        case .CALL {\n          var value = node.callValue\n          var call = value.kind == .SUPER\n          var isKeyword = value.kind == .NAME && value.symbol == null && value.asString in _keywordCallMap\n          var parenthesize = isKeyword && Precedence.UNARY_POSTFIX < precedence\n          var wrap = value.kind == .LAMBDA && _lambdaMayNeedParentheses(node)\n          var isNew = false\n\n          if parenthesize {\n            _emit(\"(\")\n          }\n\n          if wrap {\n            _emit(\"(\")\n          }\n\n          if !call && node.symbol != null && node.symbol.kind == .FUNCTION_CONSTRUCTOR {\n            _emit(\"new \" + _fullName(node.symbol))\n            isNew = true\n          } else if !call && value.kind == .DOT && value.asString == \"new\" {\n            _emit(\"new \")\n            _emitExpression(value.dotTarget, .MEMBER)\n            isNew = true\n          } else {\n            _emitExpression(value, .UNARY_POSTFIX)\n            if call {\n              _emit(\".call\")\n            }\n          }\n\n          if wrap {\n            _emit(\")\")\n          }\n\n          # Omit parentheses during mangling when possible\n          if !isNew || !_mangle || call || value.nextSibling != null || _checkForDotParentOfCall(node) {\n            _emit(isKeyword ? \" \" : \"(\")\n\n            if call {\n              _emit(_mangleName(_enclosingFunction.this))\n            }\n\n            for child = value.nextSibling; child != null; child = child.nextSibling {\n              if call || child.previousSibling != value {\n                _emit(\",\" + _space)\n                _maybeEmitMinifedNewline\n              }\n              _emitExpression(child, .COMMA)\n            }\n\n            if !isKeyword {\n              _emit(\")\")\n            }\n          }\n\n          if parenthesize {\n            _emit(\")\")\n          }\n        }\n\n        case .INITIALIZER_LIST, .INITIALIZER_MAP {\n          var useBraces = kind == .INITIALIZER_MAP\n          var isIndented = false\n\n          if !_minify {\n            for child = node.firstChild; child != null; child = child.nextSibling {\n              if child.comments != null {\n                isIndented = true\n                break\n              }\n            }\n          }\n\n          _emit(useBraces ? \"{\" : \"[\")\n          if isIndented {\n            _increaseIndent\n          }\n\n          for child = node.firstChild; child != null; child = child.nextSibling {\n            if child.previousSibling != null {\n              _emit(\",\" + (isIndented ? \"\" : _space))\n              _maybeEmitMinifedNewline\n            }\n            if isIndented {\n              _emit(\"\\n\")\n              _emitComments(child.comments)\n              _emit(_indent)\n            }\n            _emitExpression(child, .COMMA)\n          }\n\n          if isIndented {\n            _decreaseIndent\n            _emit(\"\\n\" + _indent)\n          }\n          _emit(useBraces ? \"}\" : \"]\")\n        }\n\n        case .PAIR {\n          _emitExpression(node.firstValue, .LOWEST)\n          _emit(\":\" + _space)\n          _emitExpression(node.secondValue, .LOWEST)\n        }\n\n        case .INDEX {\n          _emitExpression(node.indexLeft, .UNARY_POSTFIX)\n          _emit(\"[\")\n          _emitExpression(node.indexRight, .LOWEST)\n          _emit(\"]\")\n        }\n\n        case .ASSIGN_INDEX {\n          if Precedence.ASSIGN < precedence {\n            _emit(\"(\")\n          }\n          _emitExpression(node.assignIndexLeft, .UNARY_POSTFIX)\n          _emit(\"[\")\n          _emitExpression(node.assignIndexCenter, .LOWEST)\n          _emit(\"]\" + _space + \"=\" + _space + \"\")\n          _emitExpression(node.assignIndexRight, .ASSIGN)\n          if Precedence.ASSIGN < precedence {\n            _emit(\")\")\n          }\n        }\n\n        case .CAST {\n          _emitExpression(node.castValue, precedence)\n        }\n\n        case .PARAMETERIZE {\n          _emitExpression(node.parameterizeValue, precedence)\n        }\n\n        case .SEQUENCE {\n          if Precedence.COMMA <= precedence {\n            _emit(\"(\")\n          }\n          _emitCommaSeparatedExpressions(node.firstChild, null)\n          if Precedence.COMMA <= precedence {\n            _emit(\")\")\n          }\n        }\n\n        case .SUPER {\n          _emit(_fullName(node.symbol))\n        }\n\n        case .HOOK {\n          if Precedence.ASSIGN < precedence {\n            _emit(\"(\")\n          }\n\n          _emitExpression(node.hookTest, .LOGICAL_OR)\n          _emit(_space + \"?\")\n\n          var left = node.hookTrue\n          if left.comments != null {\n            _emit(_newline)\n            _increaseIndent\n            _emitComments(left.comments)\n            _emit(_indent)\n            _emitExpression(left, .ASSIGN)\n            _decreaseIndent\n          } else {\n            _emit(_space)\n            _emitExpression(left, .ASSIGN)\n          }\n\n          _emit(_space + \":\")\n\n          var right = node.hookFalse\n          if right.comments != null {\n            _emit(_newline)\n            _increaseIndent\n            _emitComments(right.comments)\n            _emit(_indent)\n            _emitExpression(right, .ASSIGN)\n            _decreaseIndent\n          } else {\n            _emit(_space)\n            _emitExpression(right, .ASSIGN)\n          }\n\n          if Precedence.ASSIGN < precedence {\n            _emit(\")\")\n          }\n        }\n\n        case .LAMBDA {\n          var symbol = node.symbol.asFunctionSymbol\n          _emit(\"function(\")\n          _emitArgumentList(symbol.arguments)\n          _emit(\")\")\n          _emitBlock(symbol.block, .AFTER_PARENTHESIS, .MUST_KEEP_BRACES)\n        }\n\n        case .COMPLEMENT, .NEGATIVE, .NOT, .POSITIVE, .POSTFIX_DECREMENT, .POSTFIX_INCREMENT, .PREFIX_DECREMENT, .PREFIX_INCREMENT {\n          var value = node.unaryValue\n          var info = operatorInfo[kind]\n          if info.precedence < precedence {\n            _emit(\"(\")\n          }\n\n          if kind.isUnaryPostfix {\n            _emitExpression(value, info.precedence)\n            _emit(info.text)\n          }\n\n          else {\n            # Prevent \"x - -1\" from becoming \"x--1\"\n            if _minify && (kind == .POSITIVE || kind == .NEGATIVE || kind == .PREFIX_INCREMENT || kind == .PREFIX_DECREMENT) && info.text[0] == _previousCodeUnit {\n              _emit(\" \")\n            }\n\n            _emit(info.text)\n            _emitExpression(value, info.precedence)\n          }\n\n          if info.precedence < precedence {\n            _emit(\")\")\n          }\n        }\n\n        case .TYPE_CHECK {\n          var type = node.typeCheckType\n          var resolvedType = type.resolvedType\n          if resolvedType.isWrapped {\n            resolvedType = _cache.unwrappedType(resolvedType)\n          }\n          if resolvedType.kind == .SYMBOL || type.kind != .TYPE {\n            if Precedence.COMPARE < precedence {\n              _emit(\"(\")\n            }\n            _emitExpression(node.typeCheckValue, Precedence.COMPARE)\n            _emit(\" instanceof \")\n            if resolvedType.kind == .SYMBOL {\n              _emit(_fullName(resolvedType.symbol))\n            } else {\n              _emitExpression(type, Precedence.COMPARE)\n            }\n            if Precedence.COMPARE < precedence {\n              _emit(\")\")\n            }\n          } else {\n            _emitExpression(node.typeCheckValue, precedence)\n          }\n        }\n\n        default {\n          if kind.isBinary {\n            var info = operatorInfo[kind]\n            var left = node.binaryLeft\n            var right = node.binaryRight\n            var extraEquals = left.resolvedType == .DYNAMIC || right.resolvedType == .DYNAMIC ? \"=\" : \"\"\n            var needsParentheses = info.precedence < precedence || kind == .IN && _parenthesizeInExpressions != 0\n\n            if needsParentheses {\n              _emit(\"(\")\n            }\n            _emitExpression(node.binaryLeft, info.precedence.incrementIfRightAssociative(info.associativity))\n\n            # Always emit spaces around keyword operators, even when minifying\n            var comments = _minify ? null : right.comments\n            _emit(kind == .IN ? (left.isString ? _space : \" \") + \"in\" + (comments != null ? \"\" : \" \") :\n              _space + (kind == .EQUAL ? \"==\" + extraEquals : kind == .NOT_EQUAL ? \"!=\" + extraEquals : info.text))\n\n            if comments != null {\n              _emit(_newline)\n              _increaseIndent\n              _emitComments(comments)\n              _emit(_indent)\n              _emitExpression(right, info.precedence.incrementIfLeftAssociative(info.associativity))\n              _decreaseIndent\n            } else {\n              if kind != .IN { _emit(_space) }\n              _emitExpression(right, info.precedence.incrementIfLeftAssociative(info.associativity))\n            }\n\n            if needsParentheses {\n              _emit(\")\")\n            }\n          }\n\n          else {\n            assert(false)\n          }\n        }\n      }\n    }\n\n    def _patchObject(symbol ObjectSymbol) {\n      _allocateNamingGroupIndex(symbol)\n\n      # Subclasses need the extension stub\n      if !symbol.isImported && (symbol.baseClass != null || symbol.kind == .OBJECT_CLASS && symbol.extends != null) {\n        _specialVariable(.EXTENDS)\n        _specialVariable(.CREATE)\n      }\n\n      # Scan over child objects\n      for object in symbol.objects {\n        _patchObject(object)\n\n        if symbol == _global && object.isExported {\n          _symbolsToExport.append(object)\n        }\n      }\n\n      # Scan over child functions\n      var isPrimaryConstructor = true\n      var prototypeCount = 0\n      for function in symbol.functions {\n        var block = function.block\n        var this = function.this\n        _allocateNamingGroupIndex(function)\n\n        # Check to see if we need an explicit \"self\" parameter while patching the block\n        _needsSelf = false\n        _currentSelf = this\n        _enclosingFunction = function\n        _patchNode(block)\n        _enclosingFunction = null\n\n        # Only insert the \"self\" variable if required to handle capture inside lambdas\n        if _needsSelf {\n          _unionVariableWithFunction(this, function)\n          if block != null {\n            this.kind = .VARIABLE_LOCAL\n            this.value = Node.createName(\"this\").withType(.DYNAMIC)\n            var variable = Node.createVariable(this)\n            var merged = false\n\n            # When mangling, add the \"self\" variable to an existing variable statement if present\n            if _mangle && block.hasChildren {\n              var firstChild = block.firstChild\n              if firstChild.kind == .VARIABLES {\n                firstChild.prependChild(variable)\n                merged = true\n              } else if firstChild.kind == .FOR {\n                if firstChild.forSetup.kind == .VARIABLES {\n                  firstChild.forSetup.prependChild(variable)\n                  merged = true\n                } else if firstChild.forSetup.isEmptySequence {\n                  firstChild.forSetup.replaceWith(Node.createVariables.appendChild(variable))\n                  merged = true\n                }\n              }\n            }\n\n            if !merged {\n              block.prependChild(Node.createVariables.appendChild(variable))\n            }\n          }\n        } else if this != null {\n          this.name = \"this\"\n          this.flags |= .IS_EXPORTED\n        }\n\n        for argument in function.arguments {\n          _allocateNamingGroupIndex(argument)\n          _unionVariableWithFunction(argument, function)\n        }\n\n        # Rename extra constructors overloads so they don't conflict\n        if function.kind == .FUNCTION_CONSTRUCTOR && isPrimaryConstructor {\n          function.flags |= .IS_PRIMARY_CONSTRUCTOR\n          isPrimaryConstructor = false\n        }\n\n        # Mark the prototype variable as needed when the prototype is used\n        else if _mangle && (function.kind == .FUNCTION_INSTANCE || function.kind == .FUNCTION_CONSTRUCTOR && !isPrimaryConstructor) {\n          if ++prototypeCount == 2 {\n            var variable = _specialVariable(.PROTOTYPE)\n            _symbolCounts[variable.id] = _symbolCounts.get(variable.id, 0) + 1\n            symbol.flags |= .USE_PROTOTYPE_CACHE\n          }\n        }\n\n        if symbol == _global && function.isExported {\n          _symbolsToExport.append(function)\n        }\n      }\n\n      # Scan over child variables\n      for variable in symbol.variables {\n        _allocateNamingGroupIndex(variable)\n        _patchNode(variable.value)\n\n        if symbol == _global && variable.isExported {\n          _symbolsToExport.append(variable)\n        }\n      }\n    }\n\n    def _exportSymbols {\n      if _symbolsToExport.isEmpty {\n        return\n      }\n\n      _exportsNamespace = ObjectSymbol.new(.OBJECT_NAMESPACE, _global.scope.generateName(\"exports\"))\n      _exportsNamespace.resolvedType = Type.new(.SYMBOL, _exportsNamespace)\n      _exportsNamespace.state = .INITIALIZED\n      _exportsNamespace.scope = ObjectScope.new(_global.scope, _exportsNamespace)\n      _exportsNamespace.parent = _global\n      _global.objects.append(_exportsNamespace)\n      _allocateNamingGroupIndex(_exportsNamespace)\n\n      for symbol in _symbolsToExport {\n        assert(symbol.parent != null)\n        assert(symbol.parent.kind.isObject)\n\n        var oldParent = symbol.parent.asObjectSymbol\n        symbol.parent = _exportsNamespace\n\n        if symbol.kind.isObject {\n          oldParent.objects.removeOne(symbol.asObjectSymbol)\n          _exportsNamespace.objects.append(symbol.asObjectSymbol)\n        }\n\n        else if symbol.kind.isFunction {\n          oldParent.functions.removeOne(symbol.asFunctionSymbol)\n          _exportsNamespace.functions.append(symbol.asFunctionSymbol)\n        }\n\n        else if symbol.kind.isVariable {\n          oldParent.variables.removeOne(symbol.asVariableSymbol)\n          _exportsNamespace.variables.append(symbol.asVariableSymbol)\n        }\n\n        else {\n          assert(false)\n        }\n      }\n    }\n\n    def _createIntBinary(kind NodeKind, left Node, right Node) Node {\n      if kind == .MULTIPLY {\n        return Node.createSymbolCall(_specialVariable(.MULTIPLY)).appendChild(left).appendChild(right)\n      }\n      return _wrapWithIntCast(Node.createBinary(kind, left, right).withType(_cache.intType))\n    }\n\n    def _wrapWithNot(node Node) Node {\n      return Node.createUnary(.NOT, node).withType(_cache.boolType).withRange(node.range)\n    }\n\n    def _wrapWithIntCast(node Node) Node {\n      return Node.createBinary(.BITWISE_OR, node, _cache.createInt(0)).withType(_cache.intType).withRange(node.range)\n    }\n\n    def _removeIntCast(node Node) {\n      if node.kind == .BITWISE_OR && node.binaryRight.isInt && node.binaryRight.asInt == 0 {\n        node.replaceWith(node.binaryLeft.remove)\n      }\n    }\n\n    def _patchUnaryArithmetic(node Node) {\n      if node.resolvedType == _cache.intType && !_alwaysConvertsOperandsToInt(node.parent) {\n        var value = node.unaryValue\n        if value.resolvedType == _cache.intType {\n          if value.isInt {\n            value.content = IntContent.new(-value.asInt)\n            node.become(value.remove)\n          } else {\n            node.become(_wrapWithIntCast(node.cloneAndStealChildren))\n          }\n        }\n      }\n    }\n\n    def _patchBinaryArithmetic(node Node) {\n      # Make sure arithmetic integer operators don't emit doubles outside the\n      # integer range. Allowing this causes JIT slowdowns due to extra checks\n      # during compilation and potential deoptimizations during execution.\n      # Special-case the integer \"%\" operator where the right operand may be\n      # \"0\" since that generates \"NaN\" which is not representable as an int.\n      if node.resolvedType == _cache.intType && !_alwaysConvertsOperandsToInt(node.parent) && (\n          node.kind != .REMAINDER && node.kind != .UNSIGNED_SHIFT_RIGHT || !node.binaryRight.isInt || node.binaryRight.asInt == 0) {\n        var left = node.binaryLeft\n        var right = node.binaryRight\n        if left.resolvedType == _cache.intType && right.resolvedType == _cache.intType {\n          node.become(_createIntBinary(node.kind, left.remove, right.remove).withRange(node.range))\n        }\n      }\n    }\n\n    def _patchTypeCheck(node Node) {\n      var value = node.typeCheckValue\n      var type = _cache.unwrappedType(node.typeCheckType.resolvedType)\n\n      if type == _cache.boolType {\n        node.become(Node.createSymbolCall(_specialVariable(.IS_BOOL)).appendChild(value.remove))\n      }\n\n      else if _cache.isInteger(type) {\n        node.become(Node.createSymbolCall(_specialVariable(.IS_INT)).appendChild(value.remove))\n      }\n\n      else if type == _cache.doubleType {\n        node.become(Node.createSymbolCall(_specialVariable(.IS_DOUBLE)).appendChild(value.remove))\n      }\n\n      else if type == _cache.stringType {\n        node.become(Node.createSymbolCall(_specialVariable(.IS_STRING)).appendChild(value.remove))\n      }\n\n      else if type.kind == .LAMBDA {\n        node.typeCheckType.replaceWith(Node.createName(\"Function\").withType(.DYNAMIC))\n      }\n    }\n\n    # Group each variable inside the function with the function itself so that\n    # they can be renamed together and won't cause any collisions inside the\n    # function\n    def _unionVariableWithFunction(symbol Symbol, function Symbol) {\n      if _mangle && function != null {\n        assert(symbol.id in _namingGroupIndexForSymbol)\n        assert(function.id in _namingGroupIndexForSymbol)\n        _localVariableUnionFind.union(\n          _namingGroupIndexForSymbol[symbol.id],\n          _namingGroupIndexForSymbol[function.id])\n      }\n    }\n\n    def _patchNode(node Node) {\n      if node == null {\n        return\n      }\n\n      var oldEnclosingFunction = _enclosingFunction\n      var oldLoop = _enclosingLoop\n      var symbol = node.symbol\n      var kind = node.kind\n\n      if _mangle && symbol != null {\n        _allocateNamingGroupIndex(symbol)\n        _symbolCounts[symbol.id] = _symbolCounts.get(symbol.id, 0) + 1\n      }\n\n      if kind == .LAMBDA {\n        _enclosingFunction = symbol.asFunctionSymbol\n      } else if kind.isLoop {\n        _enclosingLoop = node\n      }\n\n      if kind == .CAST {\n        _patchNode(node.castValue)\n      } else {\n        for child = node.firstChild; child != null; child = child.nextSibling {\n          _patchNode(child)\n        }\n      }\n\n      if kind == .LAMBDA {\n        _enclosingFunction = oldEnclosingFunction\n      } else if kind.isLoop {\n        _enclosingLoop = oldLoop\n      }\n\n      # Split this into a separate function because this function is hot and V8 doesn't\n      # optimize it otherwise (it's optimized \"too many times\" whatever that means)\n      _patchNodeHelper(node)\n    }\n\n    def _patchNodeHelper(node Node) {\n      switch node.kind {\n        case .ADD, .SUBTRACT, .MULTIPLY, .DIVIDE, .REMAINDER, .UNSIGNED_SHIFT_RIGHT { _patchBinaryArithmetic(node) }\n        case .BREAK { _patchBreak(node) }\n        case .CAST { _patchCast(node) }\n        case .FOREACH { _unionVariableWithFunction(node.symbol, _enclosingFunction) }\n        case .LAMBDA { _patchLambda(node) }\n        case .NAME { _patchName(node) }\n        case .NEGATIVE { _patchUnaryArithmetic(node) }\n        case .TRY { _patchTry(node) }\n        case .TYPE_CHECK { _patchTypeCheck(node) }\n        case .VARIABLE { _unionVariableWithFunction(node.symbol, _enclosingFunction) }\n      }\n\n      if _mangle {\n        switch node.kind {\n          case .ASSIGN_INDEX { _peepholeMangleAssignIndex(node) }\n          case .BLOCK { _peepholeMangleBlock(node) }\n          case .CALL { _peepholeMangleCall(node) }\n          case .CONSTANT { _peepholeMangleConstant(node) }\n          case .FOR { _peepholeMangleFor(node) }\n          case .HOOK { _peepholeMangleHook(node) }\n          case .IF { _peepholeMangleIf(node) }\n          case .INDEX { _peepholeMangleIndex(node) }\n          case .PAIR { _peepholeManglePair(node) }\n          case .WHILE { _peepholeMangleWhile(node) }\n          default { if node.kind.isBinary { _peepholeMangleBinary(node) } }\n        }\n      }\n    }\n\n    def _peepholeManglePair(node Node) {\n      if _isIdentifierString(node.firstValue) {\n        node.firstValue.kind = .NAME\n      }\n    }\n\n    def _peepholeMangleConstant(node Node) {\n      switch node.content.kind {\n        case .BOOL {\n          node.become(_wrapWithNot(_cache.createInt(node.asBool ? 0 : 1).withRange(node.range)))\n        }\n\n        case .INT {\n          var value = node.asInt\n\n          # \"-2147483648\" => \"1 << 31\"\n          if value != 0 {\n            var count = value.toString.count\n            var shift = 0\n\n            # Count zero bits\n            while (value & 1) == 0 {\n              value >>>= 1\n              shift++\n            }\n\n            # Do the substitution if it makes sense\n            if shift != 0 && value.toString.count + 2 + shift.toString.count < count {\n              node.become(Node.createBinary(.SHIFT_LEFT, _cache.createInt(value), _cache.createInt(shift)).withType(_cache.intType).withRange(node.range))\n            }\n          }\n        }\n\n        case .DOUBLE {\n          var value = node.asDouble\n          var reciprocal = 1 / value\n\n          # Shorten long reciprocals (don't replace multiplication with division\n          # because that's not numerically identical). These should be constant-\n          # folded by the JIT at compile-time.\n          #\n          #   \"x * 0.3333333333333333\" => \"x * (1 / 3)\"\n          #\n          for i in 1..10 {\n            if reciprocal * i == ((reciprocal * i) as int) && value.toString.count >= 10 {\n              node.become(Node.createBinary(.DIVIDE, _cache.createDouble(i), _cache.createDouble(reciprocal * i)).withType(_cache.doubleType).withRange(node.range))\n              break\n            }\n          }\n        }\n      }\n    }\n\n    def _patchName(node Node) {\n      if node.symbol != null && node.symbol == _currentSelf && _enclosingFunction != null && _enclosingFunction.kind == .FUNCTION_LOCAL {\n        _needsSelf = true\n      }\n    }\n\n    def _peepholeMangleCall(node Node) {\n      var value = node.callValue\n      var parent = node.parent\n\n      # \"x + y.toString()\" => \"x + y\" where \"x\" is a string\n      # \"x.toString() + ''\" => \"x + ''\"\n      if value.nextSibling == null && value.kind == .DOT && value.asString == \"toString\" &&\n          value.symbol != null && value.symbol.isImportedOrExported && parent.kind == .ADD && (\n            node == parent.binaryRight && _cache.isEquivalentToString(parent.binaryLeft.resolvedType) || parent.binaryRight.isString) {\n        node.become(value.dotTarget.remove)\n      }\n    }\n\n    # The \"break\" statement inside a switch should break out of the enclosing\n    # loop:\n    #\n    #   while true {\n    #     switch x {\n    #       case 0 {\n    #         break\n    #       }\n    #     }\n    #   }\n    #\n    # becomes:\n    #\n    #   label: while (true) {\n    #     switch (x) {\n    #       case 0: {\n    #         break label;\n    #       }\n    #     }\n    #   }\n    #\n    def _patchBreak(node Node) {\n      var loop = _enclosingLoop\n      for parent = node.parent; parent != loop; parent = parent.parent {\n        if parent.kind == .SWITCH {\n          var label = _loopLabels.get(loop.id, null)\n          if label == null {\n            label = VariableSymbol.new(.VARIABLE_LOCAL, _enclosingFunction.scope.generateName(\"label\"))\n            _allocateNamingGroupIndex(label)\n            _unionVariableWithFunction(label, _enclosingFunction)\n            _loopLabels[loop.id] = label\n          }\n          _loopLabels[node.id] = label\n          break\n        }\n      }\n    }\n\n    def _patchLambda(node Node) {\n      var function = node.symbol.asFunctionSymbol\n      for argument in function.arguments {\n        _allocateNamingGroupIndex(argument)\n        _unionVariableWithFunction(argument, function)\n      }\n      _unionVariableWithFunction(function, _enclosingFunction)\n    }\n\n    def _recursiveSubstituteSymbol(node Node, old Symbol, new Symbol) {\n      if node.symbol == old {\n        node.symbol = new\n      }\n\n      for child = node.firstChild; child != null; child = child.nextSibling {\n        _recursiveSubstituteSymbol(child, old, new)\n      }\n    }\n\n    def _patchTry(node Node) {\n      if node.hasChildren && !node.hasOneChild {\n        var tryBlock = node.tryBlock\n        var finallyBlock = node.finallyBlock\n        var firstCatch = finallyBlock != null ? finallyBlock.previousSibling : node.lastChild\n        var variable = VariableSymbol.new(.VARIABLE_LOCAL, firstCatch.kind == .CATCH && firstCatch.symbol != null ?\n          firstCatch.symbol.name : _enclosingFunction.scope.generateName(\"e\"))\n        variable.resolvedType = .DYNAMIC\n        var block = Node.createBlock.appendChild(Node.createThrow(Node.createSymbolReference(variable)))\n\n        # Iterate backwards over the catch blocks\n        for child = firstCatch, previous = child.previousSibling; child != tryBlock; child = previous, previous = child.previousSibling {\n          var catchBlock = child.remove.catchBlock.remove\n\n          # Substitute the variable into the contents of the block\n          if child.symbol != null {\n            _recursiveSubstituteSymbol(catchBlock, child.symbol, variable)\n          }\n\n          # Build up the chain of tests in reverse\n          if child.symbol != null && child.symbol.resolvedType != .DYNAMIC {\n            var test = Node.createTypeCheck(Node.createSymbolReference(variable), Node.createType(child.symbol.resolvedType)).withType(_cache.boolType)\n            block = Node.createBlock.appendChild(catchBlock.hasChildren\n              ? Node.createIf(test, catchBlock, block)\n              : Node.createIf(_wrapWithNot(test), block, null))\n          } else {\n            block = catchBlock\n          }\n        }\n\n        node.insertChildAfter(tryBlock, Node.createCatch(variable, block))\n\n        # Make sure the new variable name is mangled\n        _allocateNamingGroupIndex(variable)\n        _unionVariableWithFunction(variable, _enclosingFunction)\n      }\n    }\n\n    def _peepholeMangleBinary(node Node) {\n      var kind = node.kind\n      var left = node.binaryLeft\n      var right = node.binaryRight\n\n      # \"(a, b) || c\" => \"a, b || c\"\n      # \"(a, b) && c\" => \"a, b && c\"\n      if (kind == .LOGICAL_OR || kind == .LOGICAL_AND) && left.kind == .SEQUENCE {\n        var binary = Node.createBinary(kind, left.lastChild.cloneAndStealChildren, right.remove).withType(.DYNAMIC)\n        _peepholeMangleBinary(binary)\n        left.lastChild.replaceWith(binary)\n        node.become(left.remove)\n      }\n\n      # \"a + (b + c)\" => \"(a + b) + c\"\n      else if kind.isBinaryAssociative && right.kind == kind {\n        while true {\n          node.rotateBinaryRightToLeft\n          node = node.binaryLeft\n          if !node.kind.isBinaryAssociative || node.binaryRight.kind != node.kind {\n            break\n          }\n        }\n      }\n\n      else if (kind == .GREATER_THAN_OR_EQUAL || kind == .LESS_THAN_OR_EQUAL) && _cache.isEquivalentToInt(left.resolvedType) && _cache.isEquivalentToInt(right.resolvedType) {\n        if left.isInt {\n          var value = left.asInt\n\n          # \"2 >= a\" => \"3 > a\"\n          if node.kind == .GREATER_THAN_OR_EQUAL && _canIncrement(value) {\n            left.content = IntContent.new(value + 1)\n            node.kind = .GREATER_THAN\n          }\n\n          # \"2 <= a\" => \"1 < a\"\n          else if node.kind == .LESS_THAN_OR_EQUAL && _canDecrement(value) {\n            left.content = IntContent.new(value - 1)\n            node.kind = .LESS_THAN\n          }\n        } else if right.isInt {\n          var value = right.asInt\n\n          # \"a >= 2\" => \"a > 1\"\n          if node.kind == .GREATER_THAN_OR_EQUAL && _canDecrement(value) {\n            right.content = IntContent.new(value - 1)\n            node.kind = .GREATER_THAN\n          }\n\n          # \"a <= 2\" => \"a < 3\"\n          else if node.kind == .LESS_THAN_OR_EQUAL && _canIncrement(value) {\n            right.content = IntContent.new(value + 1)\n            node.kind = .LESS_THAN\n          }\n        }\n      }\n    }\n\n    # Simplifies the node assuming it's used in a boolean context. Note that\n    # this may replace the passed-in node, which will then need to be queried\n    # again if it's needed for further stuff.\n    def _peepholeMangleBoolean(node Node, canSwap BooleanSwap) BooleanSwap {\n      var kind = node.kind\n\n      if kind == .EQUAL || kind == .NOT_EQUAL {\n        var left = node.binaryLeft\n        var right = node.binaryRight\n        var replacement = _isFalsy(right) ? left : _isFalsy(left) ? right : null\n\n        # \"if (a != 0) b;\" => \"if (a) b;\"\n        if replacement != null {\n\n          # This minification is not valid for strings and doubles because\n          # they both have multiple falsy values (NaN and 0, null, and \"\")\n          if left.resolvedType != null && left.resolvedType != .DYNAMIC && !_cache.isEquivalentToDouble(left.resolvedType) && !_cache.isEquivalentToString(left.resolvedType) &&\n              right.resolvedType != null && right.resolvedType != .DYNAMIC && !_cache.isEquivalentToDouble(right.resolvedType) && !_cache.isEquivalentToString(right.resolvedType) {\n            replacement.remove\n            node.become(kind == .EQUAL ? _wrapWithNot(replacement) : replacement)\n          }\n        }\n\n        else if _cache.isInteger(left.resolvedType) && _cache.isInteger(right.resolvedType) && (kind == .NOT_EQUAL || kind == .EQUAL && canSwap == .SWAP) {\n\n          # \"if (a != -1) c;\" => \"if (~a) c;\"\n          # \"if (a == -1) c; else d;\" => \"if (~a) d; else c;\"\n          if right.isInt && right.asInt == -1 {\n            node.become(Node.createUnary(.COMPLEMENT, left.remove).withType(_cache.intType))\n          }\n\n          # \"if (-1 != b) c;\" => \"if (~b) c;\"\n          # \"if (-1 == b) c; else d;\" => \"if (~b) d; else c;\"\n          else if left.isInt && left.asInt == -1 {\n            node.become(Node.createUnary(.COMPLEMENT, right.remove).withType(_cache.intType))\n          }\n\n          # \"if (a != b) c;\" => \"if (a ^ b) c;\"\n          # \"if (a == b) c; else d;\" => \"if (a ^ b) d; else c;\"\n          # \"if ((a + b | 0) != (c + d | 0)) e;\" => \"if (a + b ^ c + d) e;\"\n          else {\n            node.kind = .BITWISE_XOR\n            _removeIntCast(node.binaryLeft)\n            _removeIntCast(node.binaryRight)\n          }\n\n          return kind == .EQUAL ? .SWAP : .NO_SWAP\n        }\n      }\n\n      # \"if (a != 0 || b != 0) c;\" => \"if (a || b) c;\"\n      else if kind == .LOGICAL_AND || kind == .LOGICAL_OR {\n        _peepholeMangleBoolean(node.binaryLeft, .NO_SWAP)\n        _peepholeMangleBoolean(node.binaryRight, .NO_SWAP)\n      }\n\n      # \"if (!a) b; else c;\" => \"if (a) c; else b;\"\n      # \"a == 0 ? b : c;\" => \"a ? c : b;\"\n      # This is not an \"else if\" check since EQUAL may be turned into NOT above\n      if node.kind == .NOT && canSwap == .SWAP {\n        node.become(node.unaryValue.remove)\n        return .SWAP\n      }\n\n      # \"if (a, !b) c; else d;\" => \"if (a, b) d; else c;\"\n      if node.kind == .SEQUENCE {\n        return _peepholeMangleBoolean(node.lastChild, canSwap)\n      }\n\n      return .NO_SWAP\n    }\n\n    def _peepholeMangleIf(node Node) {\n      var test = node.ifTest\n      var trueBlock = node.ifTrue\n      var falseBlock = node.ifFalse\n      var trueStatement = trueBlock.blockStatement\n      var swapped = _peepholeMangleBoolean(test, falseBlock != null || trueStatement != null && trueStatement.kind == .EXPRESSION ? .SWAP : .NO_SWAP)\n\n      # \"if (a) b; else ;\" => \"if (a) b;\"\n      if falseBlock != null && !falseBlock.hasChildren {\n        falseBlock.remove\n        falseBlock = null\n      }\n\n      if falseBlock != null {\n        var falseStatement = falseBlock.blockStatement\n\n        # \"if (!a) b; else c;\" => \"if (a) c; else b;\"\n        if swapped == .SWAP {\n          var block = trueBlock\n          trueBlock = falseBlock\n          falseBlock = block\n          var statement = trueStatement\n          trueStatement = falseStatement\n          falseStatement = statement\n          trueBlock.swapWith(falseBlock)\n        }\n\n        if trueStatement != null && falseStatement != null {\n\n          # \"if (a) b; else c;\" => \"a ? b : c;\"\n          if trueStatement.kind == .EXPRESSION && falseStatement.kind == .EXPRESSION {\n            var hook = Node.createHook(test.remove, trueStatement.expressionValue.remove, falseStatement.expressionValue.remove).withType(.DYNAMIC)\n            _peepholeMangleHook(hook)\n            node.become(Node.createExpression(hook))\n          }\n\n          # \"if (a) return b; else return c;\" => \"return a ? b : c;\"\n          else if trueStatement.kind == .RETURN && falseStatement.kind == .RETURN {\n            var trueValue = trueStatement.returnValue\n            var falseValue = falseStatement.returnValue\n            if trueValue != null && falseValue != null {\n              var hook = Node.createHook(test.remove, trueValue.remove, falseValue.remove).withType(.DYNAMIC)\n              _peepholeMangleHook(hook)\n              node.become(Node.createReturn(hook))\n            }\n          }\n        }\n      }\n\n      # \"if (a) b;\" => \"a && b;\"\n      # \"if (!a) b;\" => \"a || b;\"\n      else if trueStatement != null && trueStatement.kind == .EXPRESSION {\n        var binary = Node.createBinary(swapped == .SWAP ? .LOGICAL_OR : .LOGICAL_AND, test.remove, trueStatement.expressionValue.remove).withType(.DYNAMIC)\n        _peepholeMangleBinary(binary)\n        node.become(Node.createExpression(binary))\n      }\n\n      # \"if (a) if (b) c;\" => \"if (a && b) c;\"\n      else {\n        var singleIf = _singleIf(trueBlock)\n        if singleIf != null && singleIf.ifFalse == null {\n          var block = singleIf.ifTrue\n          test.replaceWith(Node.createBinary(.LOGICAL_AND, test.cloneAndStealChildren, singleIf.ifTest.remove).withType(.DYNAMIC))\n          trueBlock.replaceWith(block.remove)\n        }\n      }\n    }\n\n    def _peepholeMangleWhile(node Node) {\n      var test = node.whileTest\n      var block = node.whileBlock\n      _peepholeMangleBoolean(test.remove, .NO_SWAP)\n\n      # \"while (a) {}\" => \"for (; a;) {}\"\n      var loop = Node.createFor(Node.createSequence.withType(.DYNAMIC), test, Node.createSequence.withType(.DYNAMIC), block.remove).withRange(node.range)\n      _peepholeMangleFor(loop)\n      node.become(loop)\n    }\n\n    def _peepholeMangleFor(node Node) {\n      var test = node.forTest\n      _peepholeMangleBoolean(test, .NO_SWAP)\n\n      # \"for (; true;) {}\" => \"for (;;) {}\"\n      if test.kind == .NOT && test.unaryValue.isInt && test.unaryValue.asInt == 0 {\n        var empty = Node.createSequence.withType(.DYNAMIC)\n        test.replaceWith(empty)\n        test = empty\n      }\n\n      # \"for (a;;) if (b) break;\" => \"for (a; b;) {}\"\n      if node.forUpdate.isEmptySequence {\n        var statement = node.forBlock.blockStatement\n        if statement != null && statement.kind == .IF && statement.ifFalse == null {\n          var branch = statement.ifTrue.blockStatement\n          if branch != null && branch.kind == .BREAK {\n            var condition = statement.remove.ifTest.remove\n            condition.invertBooleanCondition(_cache)\n            if test.isEmptySequence {\n              test.replaceWith(condition)\n            } else {\n              condition = Node.createBinary(.LOGICAL_AND, test.cloneAndStealChildren, condition).withType(.DYNAMIC)\n              _peepholeMangleBinary(condition)\n              test.become(condition)\n            }\n          }\n        }\n      }\n    }\n\n    def _peepholeMangleHook(node Node) {\n      var test = node.hookTest\n      var trueValue = node.hookTrue\n      var falseValue = node.hookFalse\n      var swapped = _peepholeMangleBoolean(test, .SWAP)\n\n      # \"!a ? b : c;\" => \"a ? c : b;\"\n      if swapped == .SWAP {\n        var temp = trueValue\n        trueValue = falseValue\n        falseValue = temp\n        trueValue.swapWith(falseValue)\n      }\n\n      # \"a.b ? c : null\" => \"a.b && c\"\n      if falseValue.kind == .CAST && falseValue.castValue.kind == .NULL && test.resolvedType != null && test.resolvedType != .DYNAMIC && test.resolvedType.isReference {\n        node.become(Node.createBinary(.LOGICAL_AND, test.remove, trueValue.remove).withType(node.resolvedType))\n        return\n      }\n\n      # \"a ? a : b\" => \"a || b\"\n      # \"a = b ? a : c\" => \"(a = b) || c\"\n      if test.looksTheSameAs(trueValue) && test.hasNoSideEffects ||\n          test.kind.isBinaryAssign && test.binaryLeft.looksTheSameAs(trueValue) && test.binaryLeft.hasNoSideEffects {\n        node.become(Node.createBinary(.LOGICAL_OR, test.remove, falseValue.remove).withType(node.resolvedType))\n        return\n      }\n\n      # \"a ? b : a\" => \"a && b\"\n      if test.looksTheSameAs(falseValue) && test.hasNoSideEffects {\n        node.become(Node.createBinary(.LOGICAL_AND, test.remove, trueValue.remove).withType(node.resolvedType))\n        return\n      }\n\n      # \"a ? b : b\" => \"a, b\"\n      if trueValue.looksTheSameAs(falseValue) {\n        node.become(test.hasNoSideEffects ? trueValue.remove : Node.createSequence(test.remove, trueValue.remove))\n        return\n      }\n\n      # Collapse partially-identical hook expressions\n      if falseValue.kind == .HOOK {\n        var falseTest = falseValue.hookTest\n        var falseTrueValue = falseValue.hookTrue\n        var falseFalseValue = falseValue.hookFalse\n\n        # \"a ? b : c ? b : d\" => \"a || c ? b : d\"\n        # \"a ? b : c || d ? b : e\" => \"a || c || d ? b : e\"\n        if trueValue.looksTheSameAs(falseTrueValue) {\n          var both = Node.createBinary(.LOGICAL_OR, test.cloneAndStealChildren, falseTest.remove).withType(.DYNAMIC)\n          _peepholeMangleBinary(both)\n          test.replaceWith(both)\n          falseValue.replaceWith(falseFalseValue.remove)\n          _peepholeMangleHook(node)\n          return\n        }\n      }\n\n      # Collapse partially-identical binary expressions\n      if trueValue.kind == falseValue.kind && trueValue.kind.isBinary {\n        var trueLeft = trueValue.binaryLeft\n        var trueRight = trueValue.binaryRight\n        var falseLeft = falseValue.binaryLeft\n        var falseRight = falseValue.binaryRight\n\n        # \"a ? b = c : b = d;\" => \"b = a ? c : d;\"\n        if trueLeft.looksTheSameAs(falseLeft) {\n          var hook = Node.createHook(test.remove, trueRight.remove, falseRight.remove).withType(.DYNAMIC)\n          _peepholeMangleHook(hook)\n          node.become(Node.createBinary(trueValue.kind, trueLeft.remove, hook).withType(node.resolvedType))\n        }\n\n        # \"a ? b + 100 : c + 100;\" => \"(a ? b + c) + 100;\"\n        else if trueRight.looksTheSameAs(falseRight) && !trueValue.kind.isBinaryAssign {\n          var hook = Node.createHook(test.remove, trueLeft.remove, falseLeft.remove).withType(.DYNAMIC)\n          _peepholeMangleHook(hook)\n          node.become(Node.createBinary(trueValue.kind, hook, trueRight.remove).withType(node.resolvedType))\n        }\n      }\n\n      # \"(a, b) ? c : d\" => \"a, b ? c : d\"\n      if test.kind == .SEQUENCE {\n        node.prependChild(test.remove.lastChild.remove)\n        test.appendChild(node.cloneAndStealChildren)\n        node.become(test)\n      }\n    }\n\n    def _peepholeMangleAssignIndex(node Node) {\n      var left = node.assignIndexLeft\n      var center = node.assignIndexCenter\n      var right = node.assignIndexRight\n\n      if _isIdentifierString(center) {\n        node.become(Node.createBinary(.ASSIGN, Node.createDot(left.remove, center.asString)\n            .withRange(Range.span(left.range, center.range)).withType(.DYNAMIC), right.remove)\n          .withRange(node.range).withType(node.resolvedType))\n      }\n    }\n\n    def _peepholeMangleIndex(node Node) {\n      var left = node.indexLeft\n      var right = node.indexRight\n\n      if _isIdentifierString(right) {\n        node.become(Node.createDot(left.remove, right.asString).withRange(node.range).withType(node.resolvedType))\n      }\n    }\n\n    def _peepholeMangleBlock(node Node) {\n      for child = node.firstChild, next Node = null; child != null; child = next {\n        var previous = child.previousSibling\n        next = child.nextSibling\n\n        switch child.kind {\n          # Make sure we entirely remove blocks only containing comment blocks\n          case .COMMENT_BLOCK {\n            child.remove\n          }\n\n          # \"var a; var b;\" => \"var a, b;\"\n          case .VARIABLES {\n            if previous != null && previous.kind == .VARIABLES {\n              child.replaceWith(previous.remove.appendChildrenFrom(child))\n            }\n          }\n\n          # \"a; b; c;\" => \"a, b, c;\"\n          case .EXPRESSION {\n            if child.expressionValue.hasNoSideEffects {\n              child.remove\n            } else if previous != null && previous.kind == .EXPRESSION {\n              var sequence = Node.createSequence(previous.remove.expressionValue.remove, child.expressionValue.remove)\n              child.become(Node.createExpression(sequence))\n            }\n          }\n\n          case .RETURN {\n            while previous != null {\n              # \"if (a) return b; return c;\" => \"return a ? b : c;\"\n              if child.returnValue != null && previous.kind == .IF && previous.ifFalse == null {\n                var statement = previous.ifTrue.blockStatement\n                if statement != null && statement.kind == .RETURN && statement.returnValue != null {\n                  var hook = Node.createHook(previous.remove.ifTest.remove, statement.returnValue.remove, child.returnValue.remove).withType(.DYNAMIC)\n                  _peepholeMangleHook(hook)\n                  child.become(Node.createReturn(hook))\n                } else {\n                  break\n                }\n              }\n\n              # \"a; return b;\" => \"return a, b;\"\n              else if child.returnValue != null && previous.kind == .EXPRESSION {\n                var sequence = Node.createSequence(previous.remove.expressionValue.remove, child.returnValue.remove)\n                child.become(Node.createReturn(sequence))\n              }\n\n              else {\n                break\n              }\n\n              previous = child.previousSibling\n            }\n          }\n\n          case .IF {\n            while previous != null {\n              # \"if (a) b; if (c) b;\" => \"if (a || c) b;\"\n              if child.ifFalse == null && previous.kind == .IF && previous.ifFalse == null && previous.ifTrue.looksTheSameAs(child.ifTrue) {\n                child.ifTest.replaceWith(Node.createBinary(.LOGICAL_OR, previous.remove.ifTest.remove, child.ifTest.cloneAndStealChildren).withType(.DYNAMIC))\n              }\n\n              # \"a; if (b) c;\" => \"if (a, b) c;\"\n              else if previous.kind == .EXPRESSION {\n                var sequence = Node.createSequence(previous.remove.expressionValue.remove, child.ifTest.cloneAndStealChildren)\n                child.ifTest.replaceWith(sequence)\n              }\n\n              else {\n                break\n              }\n\n              previous = child.previousSibling\n            }\n\n            # \"void foo() { if (a) return; b(); c() }\" => \"void foo() { if (!a) { b(); c() } }\"\n            # \"while (a) { if (b) continue; c(); d() }\" => \"while (a) { if (!b) { c(); d() } }\"\n            if child.ifFalse == null {\n              var trueBlock = child.ifTrue\n              if trueBlock.hasChildren {\n                var statement = trueBlock.lastChild\n                if (statement.kind == .RETURN && statement.returnValue == null || statement.kind == .CONTINUE) && _isJumpImplied(node, statement.kind) {\n                  var block Node\n\n                  # If the if statement block without the jump is empty, then flip\n                  # the condition of the if statement and reuse the block. Otherwise,\n                  # create an else branch for the if statement and use that block.\n                  statement.remove\n                  if !trueBlock.hasChildren {\n                    child.ifTest.invertBooleanCondition(_cache)\n                    block = trueBlock\n                  } else if next != null {\n                    block = Node.createBlock\n                    child.appendChild(block)\n                    assert(block == child.ifFalse)\n                  } else {\n                    return # Returning here is fine because this is the last child\n                  }\n\n                  # Move the rest of this block into the block for the if statement\n                  while child.nextSibling != null {\n                    block.appendChild(child.nextSibling.remove)\n                  }\n                  _peepholeMangleBlock(block)\n                  _peepholeMangleIf(child)\n\n                  # \"a(); if (b) return; c();\" => \"a(); if (!b) c();\" => \"a(); !b && c();\" => \"a(), !b && c();\"\n                  if child.kind == .EXPRESSION && previous != null && previous.kind == .EXPRESSION {\n                    var sequence = Node.createSequence(previous.remove.expressionValue.remove, child.expressionValue.remove)\n                    child.become(Node.createExpression(sequence))\n                  }\n                  return\n                }\n              }\n            }\n          }\n\n          case .FOR {\n            var setup = child.forSetup\n\n            # \"var a; for (;;) {}\" => \"for (var a;;) {}\"\n            if previous != null && setup.isEmptySequence && previous.kind == .VARIABLES {\n              setup.replaceWith(previous.remove.appendChildrenFrom(setup))\n            }\n\n            # \"var a; for (var b;;) {}\" => \"for (var a, b;;) {}\"\n            else if previous != null && setup.kind == .VARIABLES && previous.kind == .VARIABLES {\n              setup.replaceWith(previous.remove.appendChildrenFrom(setup))\n            }\n\n            # \"a; for (b;;) {}\" => \"for (a, b;;) {}\"\n            else if previous != null && setup.kind.isExpression && previous.kind == .EXPRESSION {\n              setup.replaceWith(Node.createSequence(previous.remove.expressionValue.remove, setup.cloneAndStealChildren))\n            }\n          }\n\n          case .SWITCH {\n            var switchValue = child.switchValue\n            var defaultCase = child.defaultCase\n\n            if defaultCase != null {\n              var hasFlowAtEnd = false\n\n              # See if any non-default case will flow past the end of the switch block\n              for caseChild = switchValue.nextSibling; caseChild != defaultCase; caseChild = caseChild.nextSibling {\n                if caseChild.caseBlock.hasControlFlowAtEnd {\n                  hasFlowAtEnd = true\n                }\n              }\n\n              # \"switch (a) { case b: return; default: c; break; }\" => \"switch (a) { case b: return; } c;\"\n              if !hasFlowAtEnd {\n                node.insertChildrenAfterFrom(defaultCase.caseBlock, child)\n                next = child.nextSibling\n                defaultCase.remove\n                defaultCase = null\n              }\n            }\n\n            # \"switch (a) {}\" => \"a;\"\n            if child.hasOneChild {\n              next = Node.createExpression(switchValue.remove)\n              child.replaceWith(next)\n              continue\n            }\n\n            # \"switch (a) { case b: c; break; }\" => \"if (a == b) c;\"\n            else if child.hasTwoChildren {\n              var singleCase = child.lastChild\n              if singleCase.hasTwoChildren {\n                var value = singleCase.firstChild\n                next = Node.createIf(Node.createBinary(.EQUAL, switchValue.remove, value.remove).withType(_cache.boolType), singleCase.caseBlock.remove, null)\n                _peepholeMangleIf(next)\n                child.replaceWith(next)\n                continue\n              }\n            }\n\n            # \"switch (a) { case b: c; break; default: d; break; }\" => \"if (a == b) c; else d;\"\n            else if child.hasThreeChildren {\n              var firstCase = switchValue.nextSibling\n              var secondCase = child.lastChild\n              if firstCase.hasTwoChildren && secondCase.hasOneChild {\n                var value = firstCase.firstChild\n                next = Node.createIf(Node.createBinary(.EQUAL, switchValue.remove, value.remove).withType(_cache.boolType), firstCase.caseBlock.remove, secondCase.caseBlock.remove)\n                _peepholeMangleIf(next)\n                child.replaceWith(next)\n                continue\n              }\n            }\n\n            # Optimize specific patterns of switch statements\n            if switchValue.kind == .NAME && defaultCase == null {\n              _peepholeMangleSwitchCases(child)\n            }\n          }\n        }\n      }\n    }\n\n    # \"switch (a) { case 0: return 0; case 1: return 1; case 2: return 2; }\" => \"if (a >= 0 && a <= 2) return a\"\n    # \"switch (a) { case 0: return 1; case 1: return 2; case 2: return 3; }\" => \"if (a >= 0 && a <= 2) return a + 1\"\n    def _peepholeMangleSwitchCases(node Node) {\n      var switchValue = node.switchValue\n      var firstCase = switchValue.nextSibling\n      if !_cache.isEquivalentToInt(switchValue.resolvedType) {\n        return\n      }\n\n      var sharedDelta = 0\n      var count = 0\n      var min = 0\n      var max = 0\n\n      for child = firstCase; child != null; child = child.nextSibling {\n        var singleStatement = child.caseBlock.blockStatement\n        if !child.hasTwoChildren || singleStatement == null || singleStatement.kind != .RETURN {\n          return\n        }\n\n        var caseValue = child.firstChild\n        var returnValue = singleStatement.returnValue\n        if !caseValue.isInt || returnValue == null || !returnValue.isInt {\n          return\n        }\n\n        var caseInt = caseValue.asInt\n        var returnInt = returnValue.asInt\n        var delta = returnInt - caseInt\n        if count == 0 {\n          sharedDelta = delta\n          min = caseInt\n          max = caseInt\n        } else if delta != sharedDelta {\n          return\n        } else {\n          min = Math.min(min, caseInt)\n          max = Math.max(max, caseInt)\n        }\n\n        count++\n      }\n\n      # Make sure the pattern is matched\n      if count == 0 {\n        return\n      }\n\n      var block = Node.createBlock.appendChild(Node.createReturn(\n        sharedDelta > 0 ? _createIntBinary(.ADD, switchValue.remove, _cache.createInt(sharedDelta)) :\n        sharedDelta < 0 ? _createIntBinary(.SUBTRACT, switchValue.remove, _cache.createInt(-sharedDelta)) :\n        switchValue.remove))\n\n      # Replace the large \"switch\" statement with a smaller \"if\" statement if the entire range is covered\n      if max - min == count - 1 {\n        var lower = Node.createBinary(.GREATER_THAN_OR_EQUAL, switchValue.clone, _cache.createInt(min)).withType(_cache.boolType)\n        var upper = Node.createBinary(.LESS_THAN_OR_EQUAL, switchValue.clone, _cache.createInt(max)).withType(_cache.boolType)\n\n        # Convert \">=\" and \"<=\" to \">\" and \"<\" where possible\n        _peepholeMangleBinary(lower)\n        _peepholeMangleBinary(upper)\n\n        node.replaceWith(Node.createIf(Node.createBinary(.LOGICAL_AND, lower, upper).withType(_cache.boolType), block, null))\n      }\n\n      # Just combine everything into one case\n      else {\n        var combined = Node.createCase\n        for child = firstCase; child != null; child = child.nextSibling {\n          combined.appendChild(child.firstChild.remove)\n        }\n        node.replaceWith(Node.createSwitch(switchValue.clone).appendChild(combined.appendChild(block)))\n      }\n    }\n\n    def _patchCast(node Node) {\n      var value = node.castValue\n      var type = node.resolvedType\n      var valueType = value.resolvedType\n\n      # Wrapping should be transparent in the emitted code\n      if type.isWrapped || valueType.isWrapped {\n        return\n      }\n\n      # Cast to bool\n      if type == _cache.boolType {\n        if valueType != _cache.boolType {\n          node.become(_wrapWithNot(_wrapWithNot(value.remove)))\n        }\n      }\n\n      # Cast to int\n      else if _cache.isInteger(type) {\n        if !_cache.isInteger(valueType) && !_alwaysConvertsOperandsToInt(node.parent) {\n          node.become(_wrapWithIntCast(value.remove))\n        } else if value.isInt {\n          node.become(value.remove.withType(node.resolvedType))\n        }\n      }\n\n      # Cast to double\n      else if type == _cache.doubleType {\n        if !_cache.isNumeric(valueType) {\n          node.become(Node.createUnary(.POSITIVE, value.remove).withRange(node.range).withType(_cache.doubleType))\n        }\n      }\n\n      # Cast to string\n      else if type == _cache.stringType {\n        if valueType != _cache.stringType && valueType != .NULL {\n          node.become(Node.createSymbolCall(_specialVariable(.AS_STRING)).appendChild(value.remove))\n        }\n      }\n    }\n\n    def _specialVariable(name SpecialVariable) VariableSymbol {\n      assert(name in _specialVariables)\n      var variable = _specialVariables[name]\n      _isSpecialVariableNeeded[variable.id] = 0\n      return variable\n    }\n  }\n\n  namespace JavaScriptEmitter {\n    def _isReferenceTo(node Node, symbol Symbol) bool {\n      if node.kind == .CAST {\n        node = node.castValue\n      }\n      return node.kind == .NAME && node.symbol == symbol\n    }\n\n    def _isJumpImplied(node Node, kind NodeKind) bool {\n      assert(node.kind == .BLOCK)\n      assert(kind == .RETURN || kind == .CONTINUE)\n      var parent = node.parent\n      if kind == .RETURN && (parent == null || parent.kind == .LAMBDA) || kind == .CONTINUE && parent != null && parent.kind.isLoop {\n        return true\n      }\n      if parent != null && parent.kind == .IF && parent.nextSibling == null {\n        return _isJumpImplied(parent.parent, kind)\n      }\n      return false\n    }\n\n    def _canIncrement(value int) bool {\n      return value < 0x7FFFFFFF\n    }\n\n    def _canDecrement(value int) bool {\n      return value >= -0x7FFFFFFF\n    }\n\n    def _isIdentifierString(node Node) bool {\n      if node.isString {\n        var value = node.asString\n        for i in 0..value.count {\n          var c = value[i]\n          if (c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && c != '_' && c != '$' && (i == 0 || c < '0' || c > '9') {\n            return false\n          }\n        }\n        return value != \"\" && !(value in _isKeyword)\n      }\n      return false\n    }\n\n    def _singleIf(block Node) Node {\n      if block == null {\n        return null\n      }\n      var statement = block.blockStatement\n      if statement != null && statement.kind == .IF {\n        return statement\n      }\n      return null\n    }\n\n    const _first = \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$\"\n    const _rest = \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$0123456789\"\n\n    def _numberToName(number int) string {\n      var name = _first.get(number % _first.count)\n      number = number / _first.count\n      while number > 0 {\n        number--\n        name += _rest.get(number % _rest.count)\n        number = number / _rest.count\n      }\n      return name\n    }\n\n    def _isCompactNodeKind(kind NodeKind) bool {\n      return kind == .EXPRESSION || kind == .VARIABLES || kind.isJump\n    }\n\n    def _isFalsy(node Node) bool {\n      switch node.kind {\n        case .NULL { return true }\n        case .CAST { return _isFalsy(node.castValue) }\n        case .CONSTANT {\n          var content = node.content\n          switch content.kind {\n            case .INT { return content.asInt == 0 }\n            case .DOUBLE { return content.asDouble == 0 || content.asDouble.isNaN }\n            case .STRING { return content.asString == \"\" }\n          }\n        }\n      }\n      return false\n    }\n\n    def _fullName(symbol Symbol) string {\n      var parent = symbol.parent\n      if parent != null && parent.kind != .OBJECT_GLOBAL {\n        var enclosingName = _fullName(parent)\n        if symbol.isPrimaryConstructor || symbol.isImported && symbol.kind == .FUNCTION_CONSTRUCTOR {\n          return enclosingName\n        }\n        assert(symbol.kind != .OVERLOADED_INSTANCE)\n        if symbol.kind == .FUNCTION_INSTANCE {\n          enclosingName += \".prototype\"\n        }\n        return enclosingName + \".\" + _mangleName(symbol)\n      }\n      return _mangleName(symbol)\n    }\n\n    def _shouldRenameSymbol(symbol Symbol) bool {\n      # Don't rename annotations since \"@rename\" is used for renaming and is identified by name\n      return !symbol.isImportedOrExported && !symbol.isRenamed && !symbol.isPrimaryConstructor &&\n        symbol.kind != .FUNCTION_ANNOTATION && symbol.kind != .OBJECT_GLOBAL && symbol.kind != .FUNCTION_LOCAL\n    }\n\n    def _mangleName(symbol Symbol) string {\n      symbol = symbol.forwarded\n\n      if symbol.isPrimaryConstructor {\n        symbol = symbol.parent\n      }\n      if !symbol.isImportedOrExported && (symbol.name in _isKeyword ||\n          symbol.parent != null && symbol.parent.kind == .OBJECT_CLASS && !symbol.kind.isOnInstances && symbol.name in _isFunctionProperty) {\n        return \"$\" + symbol.name\n      }\n      return symbol.name\n    }\n\n    def _computeNamespacePrefix(symbol ObjectSymbol) string {\n      assert(symbol.kind.isObject)\n      return symbol.kind == .OBJECT_GLOBAL ? \"\" : _computeNamespacePrefix(symbol.parent.asObjectSymbol) + _mangleName(symbol) + \".\"\n    }\n\n    def _alwaysConvertsOperandsToInt(node Node) bool {\n      if node != null {\n        switch node.kind {\n          case\n            .ASSIGN_BITWISE_AND, .ASSIGN_BITWISE_OR, .ASSIGN_BITWISE_XOR,\n            .ASSIGN_SHIFT_LEFT, .ASSIGN_SHIFT_RIGHT, .BITWISE_AND, .BITWISE_OR,\n            .BITWISE_XOR, .COMPLEMENT, .SHIFT_LEFT, .SHIFT_RIGHT {\n            return true\n          }\n        }\n      }\n      return false\n    }\n\n    const _isFunctionProperty = {\n      \"apply\": 0,\n      \"call\": 0,\n      \"length\": 0,\n      \"name\": 0,\n    }\n\n    const _isKeyword = {\n      \"arguments\": 0,\n      \"await\": 0,\n      \"Boolean\": 0,\n      \"break\": 0,\n      \"case\": 0,\n      \"catch\": 0,\n      \"class\": 0,\n      \"const\": 0,\n      \"constructor\": 0,\n      \"continue\": 0,\n      \"Date\": 0,\n      \"debugger\": 0,\n      \"default\": 0,\n      \"delete\": 0,\n      \"do\": 0,\n      \"double\": 0,\n      \"else\": 0,\n      \"enum\": 0,\n      \"eval\": 0,\n      \"export\": 0,\n      \"extends\": 0,\n      \"false\": 0,\n      \"finally\": 0,\n      \"float\": 0,\n      \"for\": 0,\n      \"function\": 0,\n      \"Function\": 0,\n      \"if\": 0,\n      \"implements\": 0,\n      \"import\": 0,\n      \"in\": 0,\n      \"instanceof\": 0,\n      \"int\": 0,\n      \"interface\": 0,\n      \"let\": 0,\n      \"new\": 0,\n      \"null\": 0,\n      \"Number\": 0,\n      \"Object\": 0,\n      \"package\": 0,\n      \"private\": 0,\n      \"protected\": 0,\n      \"public\": 0,\n      \"return\": 0,\n      \"static\": 0,\n      \"String\": 0,\n      \"super\": 0,\n      \"switch\": 0,\n      \"this\": 0,\n      \"throw\": 0,\n      \"true\": 0,\n      \"try\": 0,\n      \"typeof\": 0,\n      \"var\": 0,\n      \"void\": 0,\n      \"while\": 0,\n      \"with\": 0,\n      \"yield\": 0,\n    }\n\n    const _keywordCallMap = {\n      \"delete\": 0,\n      \"typeof\": 0,\n      \"void\": 0,\n    }\n\n    const _specialVariableMap = {\n      \"__asString\": SpecialVariable.AS_STRING,\n      \"__create\": SpecialVariable.CREATE,\n      \"__extends\": SpecialVariable.EXTENDS,\n      \"__imul\": SpecialVariable.MULTIPLY,\n      \"__isBool\": SpecialVariable.IS_BOOL,\n      \"__isDouble\": SpecialVariable.IS_DOUBLE,\n      \"__isInt\": SpecialVariable.IS_INT,\n      \"__isString\": SpecialVariable.IS_STRING,\n      \"__prototype\": SpecialVariable.PROTOTYPE,\n    }\n  }\n}\n"
  },
  {
    "path": "src/backend/lisptree.sk",
    "content": "namespace Skew {\n  class LispTreeTarget : CompilerTarget {\n    over name string { return \"S-expression\" }\n    over extension string { return \"lisp\" }\n    over createEmitter(context PassContext) Emitter { return LispTreeEmitter.new(context.options) }\n  }\n\n  class LispTreeEmitter : Emitter {\n    const _options CompilerOptions\n\n    over visit(global ObjectSymbol) {\n      _visitObject(global)\n      _emit(\"\\n\")\n      _createSource(_options.outputDirectory != null ? _options.outputDirectory + \"/compiled.lisp\" : _options.outputFile, .ALWAYS_EMIT)\n    }\n\n    def _visitObject(symbol ObjectSymbol) {\n      _emit(\"(\" + _mangleKind(symbol.kind.toString) + \" \" + quoteString(symbol.name, .DOUBLE, .OCTAL_WORKAROUND))\n      _increaseIndent\n\n      for object in symbol.objects {\n        _emit(\"\\n\" + _indent)\n        _visitObject(object)\n      }\n\n      for function in symbol.functions {\n        _emit(\"\\n\" + _indent)\n        _visitFunction(function)\n      }\n\n      for variable in symbol.variables {\n        _emit(\"\\n\" + _indent)\n        _visitVariable(variable)\n      }\n\n      _decreaseIndent\n      _emit(\")\")\n    }\n\n    def _visitFunction(symbol FunctionSymbol) {\n      _emit(\"(\" + _mangleKind(symbol.kind.toString) + \" \" + quoteString(symbol.name, .DOUBLE, .OCTAL_WORKAROUND))\n      _increaseIndent\n\n      for argument in symbol.arguments {\n        _emit(\"\\n\" + _indent)\n        _visitVariable(argument)\n      }\n\n      _emit(\"\\n\" + _indent)\n      _visitNode(symbol.returnType)\n      _emit(\"\\n\" + _indent)\n      _visitNode(symbol.block)\n      _decreaseIndent\n      _emit(\")\")\n    }\n\n    def _visitVariable(symbol VariableSymbol) {\n      _emit(\"(\" + _mangleKind(symbol.kind.toString) + \" \" + quoteString(symbol.name, .DOUBLE, .OCTAL_WORKAROUND) + \" \")\n      _visitNode(symbol.type)\n      _emit(\" \")\n      _visitNode(symbol.value)\n      _emit(\")\")\n    }\n\n    def _visitNode(node Node) {\n      if node == null {\n        _emit(\"nil\")\n        return\n      }\n\n      _emit(\"(\" + _mangleKind(node.kind.toString))\n\n      var content = node.content\n      if content != null {\n        switch content.kind {\n          case .INT { _emit(\" \" + content.asInt.toString) }\n          case .BOOL { _emit(\" \" + content.asBool.toString) }\n          case .DOUBLE { _emit(\" \" + content.asDouble.toString) }\n          case .STRING { _emit(\" \" + quoteString(content.asString, .DOUBLE, .OCTAL_WORKAROUND)) }\n        }\n      }\n\n      if node.kind == .VARIABLE {\n        _emit(\" \")\n        _visitVariable(node.symbol.asVariableSymbol)\n      }\n\n      else if node.kind == .LAMBDA {\n        _emit(\" \")\n        _visitFunction(node.symbol.asFunctionSymbol)\n      }\n\n      else if node.hasChildren {\n        _increaseIndent\n        for child = node.firstChild; child != null; child = child.nextSibling {\n          _emit(\"\\n\" + _indent)\n          _visitNode(child)\n        }\n        _decreaseIndent\n      }\n\n      _emit(\")\")\n    }\n\n    def _mangleKind(kind string) string {\n      return kind.toLowerCase.replaceAll(\"_\", \"-\")\n    }\n  }\n\n  # These dump() functions are helpful for debugging syntax trees\n  namespace LispTreeEmitter {\n    def dump(global ObjectSymbol) string {\n      var emitter = LispTreeEmitter.new(CompilerOptions.new)\n      emitter.visit(global)\n      emitter._createSource(null, .ALWAYS_EMIT)\n      return emitter.sources.first.contents\n    }\n\n    def dump(node Node) string {\n      var emitter = LispTreeEmitter.new(CompilerOptions.new)\n      emitter._visitNode(node)\n      emitter._createSource(null, .ALWAYS_EMIT)\n      return emitter.sources.first.contents\n    }\n  }\n}\n"
  },
  {
    "path": "src/backend/sourcemap.sk",
    "content": "namespace Skew {\n  class SourceMapping {\n    const sourceIndex int\n    const originalLine int # 0-based\n    const originalColumn int # 0-based\n    const generatedLine int # 0-based\n    const generatedColumn int # 0-based\n  }\n\n  # Based on https://github.com/mozilla/source-map\n  class SourceMapGenerator {\n    var _mappings List<SourceMapping> = []\n    var _sources List<Source> = []\n\n    def addMapping(source Source, originalLine int, originalColumn int, generatedLine int, generatedColumn int) {\n      var sourceIndex = _sources.indexOf(source)\n      if sourceIndex == -1 {\n        sourceIndex = _sources.count\n        _sources.append(source)\n      }\n      _mappings.append(SourceMapping.new(sourceIndex, originalLine, originalColumn, generatedLine, generatedColumn))\n    }\n\n    def toString string {\n      var sourceNames List<string> = []\n      var sourceContents List<string> = []\n\n      for source in _sources {\n        sourceNames.append(quoteString(source.name, .DOUBLE, .OCTAL_WORKAROUND))\n        sourceContents.append(quoteString(source.contents, .DOUBLE, .OCTAL_WORKAROUND))\n      }\n\n      var builder = StringBuilder.new\n      builder.append(\"{\\\"version\\\":3,\\\"sources\\\":[\")\n      builder.append(\",\".join(sourceNames))\n      builder.append(\"],\\\"sourcesContent\\\":[\")\n      builder.append(\",\".join(sourceContents))\n      builder.append(\"],\\\"names\\\":[],\\\"mappings\\\":\\\"\")\n\n      # Sort the mappings in increasing order by generated location\n      _mappings.sort((a, b) => {\n        var delta = a.generatedLine <=> b.generatedLine\n        return delta != 0 ? delta : a.generatedColumn <=> b.generatedColumn\n      })\n\n      var previousGeneratedColumn = 0\n      var previousGeneratedLine = 0\n      var previousOriginalColumn = 0\n      var previousOriginalLine = 0\n      var previousSourceIndex = 0\n\n      # Generate the base64 VLQ encoded mappings\n      for mapping in _mappings {\n        var generatedLine = mapping.generatedLine\n\n        # Insert ',' for the same line and ';' for a line\n        if previousGeneratedLine == generatedLine {\n          if previousGeneratedColumn == mapping.generatedColumn && (previousGeneratedLine != 0 || previousGeneratedColumn != 0) {\n            continue\n          }\n          builder.append(\",\")\n        } else {\n          previousGeneratedColumn = 0\n          while previousGeneratedLine < generatedLine {\n            builder.append(\";\")\n            previousGeneratedLine++\n          }\n        }\n\n        # Record the generated column (the line is recorded using ';' above)\n        builder.append(encodeVLQ(mapping.generatedColumn - previousGeneratedColumn))\n        previousGeneratedColumn = mapping.generatedColumn\n\n        # Record the generated source\n        builder.append(encodeVLQ(mapping.sourceIndex - previousSourceIndex))\n        previousSourceIndex = mapping.sourceIndex\n\n        # Record the original line\n        builder.append(encodeVLQ(mapping.originalLine - previousOriginalLine))\n        previousOriginalLine = mapping.originalLine\n\n        # Record the original column\n        builder.append(encodeVLQ(mapping.originalColumn - previousOriginalColumn))\n        previousOriginalColumn = mapping.originalColumn\n      }\n\n      builder.append(\"\\\"}\\n\")\n      return builder.toString\n    }\n  }\n\n  # A single base 64 digit can contain 6 bits of data. For the base 64 variable\n  # length quantities we use in the source map spec, the first bit is the sign,\n  # the next four bits are the actual value, and the 6th bit is the continuation\n  # bit. The continuation bit tells us whether there are more digits in this\n  # value following this digit.\n  #\n  #   Continuation\n  #   |    Sign\n  #   |    |\n  #   V    V\n  #   101011\n  #\n  def encodeVLQ(value int) string {\n    var vlq = value < 0 ? -value << 1 | 1 : value << 1\n    var encoded = \"\"\n\n    while true {\n      var digit = vlq & 31\n      vlq >>= 5\n\n      # If there are still more digits in this value, we must make sure the\n      # continuation bit is marked\n      if vlq != 0 {\n        digit |= 32\n      }\n\n      encoded += BASE64.get(digit)\n\n      if vlq == 0 {\n        break\n      }\n    }\n\n    return encoded\n  }\n\n  const BASE64 = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\"\n}\n"
  },
  {
    "path": "src/backend/typescript.sk",
    "content": "namespace Skew {\n  class TypeScriptTarget : CompilerTarget {\n    over name string { return \"TypeScript\" }\n    over extension string { return \"ts\" }\n    over stopAfterResolve bool { return false }\n    over requiresIntegerSwitchStatements bool { return true }\n    over supportsListForeach bool { return true }\n    over supportsNestedTypes bool { return true }\n    over removeSingletonInterfaces bool { return true }\n    over stringEncoding Unicode.Encoding { return .UTF16 }\n    over editOptions(options CompilerOptions) { options.define(\"TARGET\", \"JAVASCRIPT\") }\n    over includeSources(sources List<Source>) { sources.prepend(Source.new(\"<native-js>\", NATIVE_LIBRARY_JS)) }\n    over createEmitter(context PassContext) Emitter { return TypeScriptEmitter.new(context.log, context.options, context.cache) }\n  }\n\n  class TypeScriptEmitter : Emitter {\n    enum SpecialVariable {\n      NONE\n      AS_STRING\n      IS_INT\n    }\n\n    class MultipleCtors {\n      const ctors List<FunctionSymbol>\n      const canUseArgumentCount bool\n    }\n\n    const _log Log\n    const _options CompilerOptions\n    const _cache TypeCache\n    const _specialVariables IntMap<VariableSymbol> = {}\n    const _ctors IntMap<MultipleCtors> = {}\n    const _enclosingNamespaces List<Symbol> = []\n    var _emittedComments List<Comment> = []\n    var _previousNode Node = null\n    var _previousSymbol Symbol = null\n    var _symbolsCheckedForImport IntMap<int> = {}\n    var _importedFiles StringMap<StringMap<int>> = {}\n    var _loopLabels IntMap<VariableSymbol> = {}\n    var _enclosingFunction FunctionSymbol = null\n    var _expectedNextEnumValue = 0\n    var _currentFile = \"\"\n\n    over visit(global ObjectSymbol) {\n      _indentAmount = \"  \"\n\n      # Generate the entry point\n      const entryPoint = _cache.entryPointSymbol\n      if entryPoint != null {\n        entryPoint.name = \"main\"\n      }\n\n      # Load special-cased variables\n      for variable in global.variables {\n        var special = _specialVariableMap.get(variable.name, .NONE)\n        if special != .NONE {\n          _specialVariables[special] = variable\n          variable.flags |= .IS_EXPORTED\n        }\n      }\n      assert(SpecialVariable.AS_STRING in _specialVariables)\n      assert(SpecialVariable.IS_INT in _specialVariables)\n\n      # Avoid emitting unnecessary stuff\n      shakingPass(global, entryPoint, .USE_TYPES)\n      _markVirtualFunctions(global)\n\n      const emitIndividualFiles = _options.outputDirectory != null\n      const symbolsByFile = StringMap<List<Symbol>>.new\n\n      # Bucket things by the source file they came from\n      const collisions = StringMap<List<Symbol>>.new\n      const add = (s Symbol) => {\n        var name = \"\"\n        if s.range != null {\n          name = s.range.source.name\n        }\n        if !(name in symbolsByFile) {\n          symbolsByFile[name] =  []\n        }\n        symbolsByFile[name].append(s)\n\n        # Track collisions\n        if !s.isImported {\n          var list = collisions.get(s.name, [])\n          list.append(s)\n          collisions[s.name] = list\n        }\n      }\n\n      # There can only be one constructor in TypeScript\n      var fixAllMultipleCtors fn(ObjectSymbol)\n      fixAllMultipleCtors = (p ObjectSymbol) => {\n        for s in p.objects {\n          fixAllMultipleCtors(s)\n          if s.kind == .OBJECT_CLASS && !s.isImported {\n            var ctors = s.functions.filter(f => f.kind == .FUNCTION_CONSTRUCTOR)\n            if ctors.count > 1 {\n              s.functions = s.functions.filter(f => f.kind != .FUNCTION_CONSTRUCTOR)\n              const canUseArgumentCount = ctors.all(c1 => ctors.filter(c2 => c1.arguments.count == c2.arguments.count).count == 1)\n              _ctors[s.id] = MultipleCtors.new(ctors, canUseArgumentCount)\n            }\n          }\n        }\n      }\n      fixAllMultipleCtors(global)\n\n      var addAll fn(ObjectSymbol)\n      addAll = (p ObjectSymbol) => {\n        # If this namespace has comments, move its comments to\n        # the first child of this namespace in the same file\n        if p.comments != null {\n          var all List<Symbol> = []\n          for s in p.variables { all.append(s) }\n          for s in p.functions { all.append(s) }\n          for s in p.objects { all.append(s) }\n\n          # Iterate over the comments in reverse because we are prefixing\n          for i in 0..p.comments.count {\n            var c = p.comments[p.comments.count - i - 1]\n            var best Symbol = null\n            for s in all {\n              if s.range.source == c.range.source {\n                if best == null || best.range.start > s.range.start {\n                  best = s\n                }\n              }\n            }\n            if best != null {\n              best.comments = Comment.concat([c], best.comments)\n            } else if _options.warnAboutIgnoredComments {\n              _log.syntaxWarningIgnoredCommentInEmitter(c.range)\n            }\n          }\n        }\n\n        for s in p.variables {\n          add(s)\n        }\n\n        for s in p.functions {\n          add(s)\n        }\n\n        for s in p.objects {\n          if _shouldFlattenNamespace(s) {\n            addAll(s)\n          } else {\n            add(s)\n          }\n        }\n      }\n\n      addAll(global)\n\n      # Rename all collisions\n      collisions.each((name, list) => {\n        if list.count > 1 {\n          for s in list {\n            var i = 1\n            while true {\n              var rename = \"\\(name)\\(i)\"\n              if !(rename in collisions) {\n                collisions[rename] = []\n                s.name = rename\n                break\n              }\n              i++\n            }\n          }\n        }\n      })\n\n      # Emit each global object into a separate file\n      symbolsByFile.each((file, symbols) => {\n        _currentFile = file\n\n        for s in symbols {\n          if s.kind.isObject {\n            _emitObject(s as ObjectSymbol)\n          }\n        }\n\n        for s in symbols {\n          if s.kind.isFunction {\n            _emitFunction(s as FunctionSymbol)\n          }\n        }\n\n        for s in symbols {\n          if s.kind.isVariable {\n            _emitVariable(s as VariableSymbol)\n          }\n        }\n\n        # Emit each object into its own file if requested\n        if emitIndividualFiles {\n          _finalizeEmittedFile\n          _createSource(_options.outputDirectory + \"/\" + _tsFileName(file), .SKIP_IF_EMPTY)\n        }\n      })\n\n      # Emit a single file if requested\n      if !emitIndividualFiles {\n        _finalizeEmittedFile\n        _createSource(_options.outputFile, .ALWAYS_EMIT)\n      }\n    }\n\n    def _specialVariable(name SpecialVariable) VariableSymbol {\n      assert(name in _specialVariables)\n      var variable = _specialVariables[name]\n      _handleSymbol(variable)\n      return variable\n    }\n\n    def _replaceReturnsWithVariable(node Node, variable VariableSymbol) {\n      if node.kind == .RETURN {\n        node.become(Node.createReturn(Node.createSymbolReference(variable)))\n      }\n\n      for child = node.firstChild; child != null; child = child.nextSibling {\n        _replaceReturnsWithVariable(child, variable)\n      }\n    }\n\n    def _tsFileName(skewFile string) string {\n      skewFile = skewFile.replaceAll(\"<\", \"\")\n      skewFile = skewFile.replaceAll(\">\", \"\")\n\n      if skewFile.endsWith(\".sk\") {\n        skewFile = skewFile.slice(0, skewFile.count - \".sk\".count)\n      }\n\n      return skewFile + \".ts\"\n    }\n\n    def _relativeImport(file string) string {\n      var currentParts = _currentFile.split(\"/\")\n      var fileParts = file.split(\"/\")\n      currentParts.removeLast\n\n      while !currentParts.isEmpty && !fileParts.isEmpty && currentParts.first == fileParts.first {\n        currentParts.removeFirst\n        fileParts.removeFirst\n      }\n\n      if currentParts.isEmpty {\n        fileParts.prepend(\".\")\n      } else {\n        for _ in currentParts {\n          fileParts.prepend(\"..\")\n        }\n      }\n\n      return \"/\".join(fileParts)\n    }\n\n    def _finalizeEmittedFile {\n      var importedFiles = _importedFiles.keys\n\n      if !importedFiles.isEmpty {\n        importedFiles.sort(SORT_STRINGS) # Sort so the order is deterministic\n        for file in importedFiles {\n          var importedNames = _importedFiles[file].keys\n          importedNames.sort(SORT_STRINGS) # Sort so the order is deterministic\n          var where = quoteString(_relativeImport(file), .DOUBLE, .NORMAL)\n          _emitPrefix(\"import { \\(\", \".join(importedNames)) } from \\(where);\\n\")\n        }\n        _emitPrefix(\"\\n\")\n      }\n\n      _previousSymbol = null\n      _symbolsCheckedForImport = {}\n      _importedFiles = {}\n    }\n\n    def _handleSymbol(symbol Symbol) {\n      if !symbol.kind.isLocal && !(symbol.id in _symbolsCheckedForImport) {\n        _symbolsCheckedForImport[symbol.id] = 0\n        var parent = symbol.parent\n\n        if parent != null && (\n            symbol.kind == .VARIABLE_ENUM_OR_FLAGS ||\n            parent.kind == .OBJECT_WRAPPED ||\n            (parent.kind == .OBJECT_NAMESPACE && !_shouldFlattenNamespace(parent)) ||\n            (symbol.kind.isObject && parent.kind == .OBJECT_CLASS) ||\n            (symbol.kind == .FUNCTION_GLOBAL && parent.kind == .OBJECT_CLASS) ||\n            (symbol.kind == .VARIABLE_GLOBAL && parent.kind == .OBJECT_CLASS)) {\n          _handleSymbol(parent)\n        }\n\n        else if !symbol.isImported && symbol.range != null && (\n          symbol.kind == .OBJECT_CLASS ||\n          symbol.kind == .OBJECT_ENUM ||\n          symbol.kind == .OBJECT_FLAGS ||\n          symbol.kind == .OBJECT_WRAPPED ||\n          symbol.kind == .OBJECT_INTERFACE ||\n          symbol.kind == .OBJECT_NAMESPACE ||\n          (symbol.kind == .FUNCTION_GLOBAL && parent.kind != .OBJECT_CLASS) ||\n          (symbol.kind == .VARIABLE_GLOBAL && parent.kind != .OBJECT_CLASS)) {\n          var file = symbol.range.source.name\n          if _currentFile != file {\n            file = _tsFileName(file)\n            file = file.slice(0, file.count - \".ts\".count)\n            if !(file in _importedFiles) {\n              _importedFiles[file] = {}\n            }\n            _importedFiles[file][_mangleName(symbol)] = 0\n          }\n        }\n      }\n    }\n\n    def _emitNewlineBeforeSymbol(symbol Symbol) {\n      if _previousSymbol != null && (\n          symbol.comments != null ||\n          (!_previousSymbol.kind.isVariable || !symbol.kind.isVariable) &&\n          (!_previousSymbol.kind.isFunction || _previousSymbol.asFunctionSymbol.block != null ||\n            !symbol.kind.isFunction || symbol.asFunctionSymbol.block != null)) {\n        _emit(\"\\n\")\n      }\n      _previousSymbol = null\n    }\n\n    def _emitNewlineAfterSymbol(symbol Symbol) {\n      _previousSymbol = symbol\n    }\n\n    def _emitNewlineBeforeStatement(node Node) {\n      if _previousNode != null && (node.comments != null || !_isCompactNodeKind(_previousNode.kind) || !_isCompactNodeKind(node.kind)) {\n        _emit(\"\\n\")\n      }\n      _previousNode = null\n    }\n\n    def _emitNewlineAfterStatement(node Node) {\n      _previousNode = node\n    }\n\n    def _emitComments(comments List<Comment>) {\n      if comments != null {\n        for comment in comments {\n          for line in comment.lines {\n            _emit(_indent + \"//\" + line + \"\\n\")\n          }\n          if comment.hasGapBelow {\n            _emit(\"\\n\")\n          }\n          if _options.warnAboutIgnoredComments {\n            _emittedComments.append(comment)\n          }\n        }\n      }\n    }\n\n    def _emitTrailingComment(comment Comment) {\n      if comment != null {\n        assert(comment.lines.count == 1)\n        _emit(\" //\" + comment.lines.first)\n        if _options.warnAboutIgnoredComments {\n          _emittedComments.append(comment)\n        }\n      }\n    }\n\n    def _emitObject(symbol ObjectSymbol) {\n      _handleSymbol(symbol)\n\n      if symbol.isImported || symbol.kind == .OBJECT_GLOBAL {\n        return\n      }\n\n      _emitNewlineBeforeSymbol(symbol)\n      _emitComments(symbol.comments)\n      _emit(_indent)\n      _emit(\"export \")\n      if symbol.isAbstract {\n        _emit(\"abstract \")\n      }\n      switch symbol.kind {\n        case .OBJECT_CLASS { _emit(\"class \") }\n        case .OBJECT_ENUM, .OBJECT_FLAGS {\n          var toString = symbol.members.get(\"toString\", null)\n          if toString != null &&\n              toString.kind.isFunction &&\n              .IS_INLINING_FORCED in toString.flags &&\n              .IS_AUTOMATICALLY_GENERATED in toString.flags &&\n              (toString as FunctionSymbol).inlinedCount == 0 {\n            _emit(\"const \")\n          }\n          _emit(\"enum \")\n        }\n        case .OBJECT_INTERFACE { _emit(\"interface \") }\n        case .OBJECT_WRAPPED { _emit(\"type \") }\n        case .OBJECT_NAMESPACE { _emit(\"namespace \") }\n        default { assert(false) }\n      }\n      _emit(_mangleName(symbol))\n      _emitTypeParameters(symbol.parameters)\n\n      if symbol.kind == .OBJECT_WRAPPED {\n        _emit(\" = \")\n        _emitExpressionOrType(symbol.extends, symbol.wrappedType)\n        _emit(\"\\n\")\n        _emitNewlineAfterSymbol(symbol)\n      }\n\n      else {\n        if symbol.extends != null || symbol.implements != null {\n          if symbol.extends != null {\n            _emit(\" extends \")\n            _emitExpressionOrType(symbol.extends, symbol.baseType)\n          }\n          if symbol.implements != null {\n            _emit(\" implements \")\n            for node in symbol.implements {\n              if node != symbol.implements.first {\n                _emit(\", \")\n              }\n              _emitExpressionOrType(node, node.resolvedType)\n            }\n          }\n        }\n\n        _emit(\" {\\n\")\n        _increaseIndent\n        _expectedNextEnumValue = 0\n        if symbol.kind == .OBJECT_NAMESPACE {\n          _enclosingNamespaces.append(symbol)\n        }\n\n        var variablesComeFirst = symbol.kind == .OBJECT_CLASS\n\n        if variablesComeFirst {\n          for variable in symbol.variables {\n            _emitVariable(variable)\n          }\n        }\n\n        var multiple = _ctors.get(symbol.id, null)\n        if multiple != null {\n          _emitConstructor(symbol, multiple.ctors, multiple.canUseArgumentCount)\n        }\n\n        for function in symbol.functions {\n          _emitFunction(function)\n        }\n\n        if !variablesComeFirst {\n          for variable in symbol.variables {\n            _emitVariable(variable)\n          }\n        }\n\n        if symbol.kind == .OBJECT_NAMESPACE {\n          _enclosingNamespaces.removeLast\n        }\n        _emitComments(symbol.commentsInsideEndOfBlock)\n        _decreaseIndent\n        _emit(_indent + \"}\\n\")\n        _emitNewlineAfterSymbol(symbol)\n      }\n\n      if symbol.objects.count > 0 || (symbol.kind == .OBJECT_WRAPPED && (symbol.variables.count > 0 || symbol.functions.count > 0)) {\n        _emitNewlineBeforeSymbol(symbol)\n        _emit(_indent + \"export namespace \")\n        _emit(_mangleName(symbol))\n        _emit(\" {\\n\")\n        _increaseIndent\n        if symbol.kind == .OBJECT_WRAPPED {\n          _enclosingNamespaces.append(symbol)\n        }\n\n        for object in symbol.objects {\n          _emitObject(object)\n        }\n\n        if symbol.kind == .OBJECT_WRAPPED {\n          for function in symbol.functions {\n            _emitFunction(function)\n          }\n\n          for variable in symbol.variables {\n            _emitVariable(variable)\n          }\n        }\n\n        if symbol.kind == .OBJECT_WRAPPED {\n          _enclosingNamespaces.removeLast\n        }\n        _decreaseIndent\n        _emit(_indent + \"}\\n\")\n      }\n    }\n\n    def _emitConstructor(object ObjectSymbol, ctors List<FunctionSymbol>, canUseArgumentCount bool) {\n      # Optimize for standard TypeScript idioms if we can\n      if canUseArgumentCount {\n        # Forward-declare the function signatures\n        _emitNewlineBeforeSymbol(ctors.first)\n        for ctor in ctors {\n          _emitComments(ctor.comments)\n          _emit(_indent)\n          _emit(\"constructor\")\n          _emitTypeParameters(ctor.parameters)\n          _emitArgumentList(ctor)\n          _emit(\";\\n\")\n        }\n        _emitNewlineAfterSymbol(ctors.first)\n\n        # Define the implementation\n        _emitNewlineBeforeSymbol(ctors.first)\n        _emit(_indent)\n        _emit(\"constructor() {\\n\")\n        _increaseIndent\n\n        for ctor in ctors {\n          var block = ctor.block\n          var prefix = ctor == ctors.first ? _indent : \"\\n\\(_indent)else \"\n          assert(block != null)\n          assert(block.kind == .BLOCK)\n\n          # JavaScript arrow functions have sane capture rules for \"this\" so no variable insertion is needed\n          if ctor.this != null {\n            ctor.this.name = \"this\"\n            ctor.this.flags |= .IS_EXPORTED\n          }\n\n          _enclosingFunction = ctor\n          _emit(prefix + \"if (arguments.length == \\(ctor.arguments.count)) {\\n\")\n\n          _increaseIndent\n          if !ctor.arguments.isEmpty {\n            _emit(_indent + \"let [\\(\", \".join(ctor.arguments.map<string>(arg => _mangleName(arg))))]: [\")\n            for arg in ctor.arguments {\n              if arg != ctor.arguments.first {\n                _emit(\", \")\n              }\n              _emitExpressionOrType(arg.type, arg.resolvedType)\n            }\n            _emit(\"] = arguments as any;\\n\")\n          }\n          _emitStatements(block)\n          _decreaseIndent\n\n          _emit(_indent + \"}\\n\")\n          _enclosingFunction = null\n        }\n\n        _decreaseIndent\n        _emit(_indent)\n        _emit(\"}\\n\")\n        _emitNewlineAfterSymbol(ctors.first)\n      }\n\n      # Otherwise, fall back to something that is still correct: disambiguating with an index\n      else {\n        # Forward-declare the function signatures\n        _emitNewlineBeforeSymbol(ctors.first)\n        for ctor in ctors {\n          _emitComments(ctor.comments)\n          _emit(_indent)\n          _emit(\"constructor\")\n          _emitTypeParameters(ctor.parameters)\n          _emit(\"(_: \\(ctors.indexOf(ctor))\")\n          for arg in ctor.arguments {\n            _emit(\", \\(_mangleName(arg)): \")\n            _emitExpressionOrType(arg.type, arg.resolvedType)\n          }\n          _emit(\");\\n\")\n        }\n        _emitNewlineAfterSymbol(ctors.first)\n\n        # Define the implementation\n        _emitNewlineBeforeSymbol(ctors.first)\n        _emit(_indent)\n        _emit(\"constructor() {\\n\")\n        _increaseIndent\n\n        for ctor in ctors {\n          var block = ctor.block\n          var prefix = ctor == ctors.first ? _indent : \"\\n\\(_indent)else \"\n          assert(block != null)\n          assert(block.kind == .BLOCK)\n\n          # JavaScript arrow functions have sane capture rules for \"this\" so no variable insertion is needed\n          if ctor.this != null {\n            ctor.this.name = \"this\"\n            ctor.this.flags |= .IS_EXPORTED\n          }\n\n          _enclosingFunction = ctor\n          _emit(prefix + \"if (arguments[0] == \\(ctors.indexOf(ctor))) {\\n\")\n\n          _increaseIndent\n          if !ctor.arguments.isEmpty {\n            _emit(_indent + \"let [\\(\"\".join(ctor.arguments.map<string>(arg => \", \" + _mangleName(arg))))]: [number\")\n            for arg in ctor.arguments {\n              _emit(\", \")\n              _emitExpressionOrType(arg.type, arg.resolvedType)\n            }\n            _emit(\"] = arguments as any;\\n\")\n          }\n          _emitStatements(block)\n          _decreaseIndent\n\n          _emit(_indent + \"}\\n\")\n          _enclosingFunction = null\n        }\n\n        _decreaseIndent\n        _emit(_indent)\n        _emit(\"}\\n\")\n        _emitNewlineAfterSymbol(ctors.first)\n      }\n    }\n\n    def _emitTypeParameters(parameters List<ParameterSymbol>) {\n      if parameters != null {\n        _emit(\"<\")\n        for parameter in parameters {\n          if parameter != parameters.first {\n            _emit(\", \")\n          }\n          _emit(_mangleName(parameter))\n        }\n        _emit(\">\")\n      }\n    }\n\n    def _emitArgumentList(symbol FunctionSymbol) {\n      _emit(\"(\")\n      for argument in symbol.arguments {\n        if argument != symbol.arguments.first {\n          _emit(\", \")\n        }\n        _emit(_mangleName(argument) + \": \")\n        _emitExpressionOrType(argument.type, argument.resolvedType)\n      }\n      _emit(\")\")\n    }\n\n    def _emitVariable(symbol VariableSymbol) {\n      _handleSymbol(symbol)\n\n      if symbol.isImported {\n        return\n      }\n\n      var trailing = Comment.lastTrailingComment(symbol.comments)\n      var notTrailing = Comment.withoutLastTrailingComment(symbol.comments)\n\n      _emitNewlineBeforeSymbol(symbol)\n      _emitComments(notTrailing)\n      _emit(_indent)\n\n      if symbol.kind == .VARIABLE_ENUM_OR_FLAGS {\n        _emit(_mangleName(symbol))\n        if symbol.value != null {\n          symbol.value.resolvedType = _cache.intType # Enum values are initialized with integers\n          if symbol.value.asInt != _expectedNextEnumValue {\n            _emit(\" = \")\n            _emitExpression(symbol.value, .COMMA)\n          }\n          _expectedNextEnumValue = symbol.value.asInt + 1\n        }\n        _emit(\",\")\n      }\n\n      else {\n        if symbol.kind == .VARIABLE_GLOBAL && symbol.parent != null && symbol.parent.kind == .OBJECT_CLASS {\n          _emit(\"static \")\n        } else if symbol.kind != .VARIABLE_INSTANCE {\n          _emit(\"export \")\n          _emit(\"let \")\n        }\n\n        var emitValue = symbol.value != null && symbol.kind != .VARIABLE_INSTANCE\n\n        if emitValue && _canOmitTypeAnnotation(symbol.value) {\n          _emit(_mangleName(symbol))\n        } else {\n          _emit(_mangleName(symbol) + \": \")\n          _emitExpressionOrType(symbol.type, symbol.resolvedType)\n        }\n\n        if emitValue {\n          _emit(\" = \")\n          _emitExpression(symbol.value, .COMMA)\n        }\n        _emit(\";\")\n      }\n\n      _emitTrailingComment(trailing)\n      _emit(\"\\n\")\n      _emitNewlineAfterSymbol(symbol)\n    }\n\n    # Various heuristics to make nicer-looking code without introducing too many type errors\n    def _canOmitTypeAnnotation(value Node) bool {\n      var type = _cache.unwrappedType(value.resolvedType)\n      if type == .DYNAMIC { return false }\n      if value.kind == .CALL || value.kind == .DOT { return true }\n      if value.kind == .NAME { return _enclosingFunction == null || value.symbol != _enclosingFunction.this }\n      if type == _cache.boolType || _cache.isNumeric(type) { return true }\n      if type == _cache.stringType && value.kind != .NULL && (value.kind != .CAST || value.castValue.kind != .NULL) { return true }\n      return false\n    }\n\n    def _emitFunction(symbol FunctionSymbol) {\n      _handleSymbol(symbol)\n\n      if symbol.isImported {\n        return\n      }\n\n      # JavaScript arrow functions have sane capture rules for \"this\" so no variable insertion is needed\n      if symbol.this != null {\n        symbol.this.name = \"this\"\n        symbol.this.flags |= .IS_EXPORTED\n      }\n\n      _enclosingFunction = symbol\n      _emitNewlineBeforeSymbol(symbol)\n      _emitComments(symbol.comments)\n      _emit(_indent)\n\n      var block = symbol.block\n      if block == null && symbol.parent != null && symbol.parent.kind == .OBJECT_CLASS {\n        _emit(\"abstract \")\n      }\n\n      if symbol.kind == .FUNCTION_CONSTRUCTOR {\n        _emit(\"constructor\")\n      } else {\n        if symbol.kind == .FUNCTION_GLOBAL && symbol.parent != null && symbol.parent.kind == .OBJECT_CLASS {\n          _emit(\"static \")\n        } else if symbol.kind != .FUNCTION_INSTANCE {\n          _emit(\"export function \")\n        }\n        _emit(_mangleName(symbol))\n      }\n\n      _emitTypeParameters(symbol.parameters)\n      _emitArgumentList(symbol)\n      if symbol.kind != .FUNCTION_CONSTRUCTOR {\n        _emit(\": \")\n        _emitExpressionOrType(symbol.returnType, symbol.resolvedType.returnType)\n      }\n\n      if block == null {\n        _emit(\";\\n\")\n      }\n\n      else {\n        var comments List<Comment> = []\n        if _options.warnAboutIgnoredComments {\n          _scanForComments(block, comments)\n          _emittedComments = []\n        }\n\n        _emitBlock(block)\n\n        if _options.warnAboutIgnoredComments {\n          for c in comments {\n            if !(c in _emittedComments) {\n              _log.syntaxWarningIgnoredCommentInEmitter(c.range)\n            }\n          }\n        }\n\n        _emit(\"\\n\")\n      }\n\n      _emitNewlineAfterSymbol(symbol)\n      _enclosingFunction = null\n    }\n\n    def _scanForComments(node Node, comments List<Comment>) {\n      if node.comments != null {\n        comments.append(node.comments)\n      }\n      if node.innerComments != null {\n        comments.append(node.innerComments)\n      }\n      for child = node.firstChild; child != null; child = child.nextSibling {\n        _scanForComments(child, comments)\n      }\n    }\n\n    def _emitType(type Type) {\n      if type == null {\n        _emit(\"void\")\n        return\n      }\n\n      if type == .DYNAMIC {\n        _emit(\"any\")\n      }\n\n      else if type.kind == .LAMBDA {\n        var argumentTypes = type.argumentTypes\n        var returnType = type.returnType\n        _emit(\"(\")\n        for i in 0..argumentTypes.count {\n          if i != 0 {\n            _emit(\", \")\n          }\n          _emit(\"v\\(i): \")\n          _emitType(argumentTypes[i])\n        }\n        _emit(\") => \")\n        if returnType != null {\n          _emitType(returnType)\n        } else {\n          _emit(\"void\")\n        }\n      }\n\n      else if _cache.isIntMap(type) || _cache.isStringMap(type) {\n        _emit(\"Map<\")\n        _emit(_cache.isIntMap(type) ? \"number\" : \"string\")\n        _emit(\", \")\n        _emitType(type.substitutions.first)\n        _emit(\">\")\n      }\n\n      else {\n        assert(type.kind == .SYMBOL)\n        _handleSymbol(type.symbol)\n        _emit(_fullName(type.symbol))\n\n        if type.isParameterized {\n          _emit(\"<\")\n\n          for i in 0..type.substitutions.count {\n            if i != 0 {\n              _emit(\", \")\n            }\n            _emitType(type.substitutions[i])\n          }\n\n          _emit(\">\")\n        }\n      }\n    }\n\n    def _emitExpressionOrType(node Node, type Type) {\n      if node != null && (type == null || type == .DYNAMIC) {\n        # Treat the type \"dynamic.Object\" as an alias for \"dynamic\" instead of what it actually means\n        if type == .DYNAMIC && node.kind == .NAME && node.asString == \"Object\" {\n          _emitType(.DYNAMIC)\n        } else {\n          _emitExpression(node, .LOWEST)\n        }\n      } else {\n        _emitType(type)\n      }\n    }\n\n    def _emitStatements(node Node) {\n      _previousNode = null\n\n      for child = node.firstChild; child != null; child = child.nextSibling {\n        var trailing = Comment.lastTrailingComment(child.comments)\n        var notTrailing = Comment.withoutLastTrailingComment(child.comments)\n        _emitNewlineBeforeStatement(child)\n        _emitComments(notTrailing)\n        _emitStatement(child, trailing)\n        _emitNewlineAfterStatement(child)\n      }\n\n      _previousNode = null\n    }\n\n    def _emitBlock(node Node) {\n      assert(node.kind == .BLOCK)\n      _emit(\" {\\n\")\n      _increaseIndent\n      _emitStatements(node)\n      _decreaseIndent\n      _emit(_indent + \"}\")\n    }\n\n    def _emitIf(node Node) {\n      _emit(\"if (\")\n      _emitExpression(node.ifTest, .LOWEST)\n      _emit(\")\")\n\n      var then = node.ifTrue\n      var thenComments = then.comments\n\n      # Some people put comments before blocks in if statements\n      if thenComments != null {\n        _emit(\"\\n\")\n        _emitComments(thenComments)\n        _emit(_indent + \"{\\n\")\n        _increaseIndent\n        _emitStatements(then)\n        _decreaseIndent\n        _emit(_indent + \"}\")\n      } else {\n        _emitBlock(then)\n      }\n\n      var block = node.ifFalse\n      if block != null {\n        var singleIf = block.hasOneChild && block.firstChild.kind == .IF ? block.firstChild : null\n        if block.comments != null || singleIf != null && singleIf.comments != null {\n          _emit(\"\\n\")\n          _emit(\"\\n\")\n          _emitComments(block.comments)\n          if singleIf != null {\n            _emitComments(singleIf.comments)\n          }\n          _emit(_indent + \"else\")\n        } else {\n          _emit(\" else\")\n        }\n\n        if singleIf != null {\n          _emit(\" \")\n          _emitIf(singleIf)\n        } else {\n          _emitBlock(block)\n          _emit(\"\\n\")\n        }\n      } else {\n        _emit(\"\\n\")\n      }\n    }\n\n    def _scanForSwitchBreak(node Node, loop Node) {\n      if node.kind == .BREAK {\n        for parent = node.parent; parent != loop; parent = parent.parent {\n          if parent.kind == .SWITCH {\n            var label = _loopLabels.get(loop.id, null)\n            if label == null {\n              label = VariableSymbol.new(.VARIABLE_LOCAL, _enclosingFunction.scope.generateName(\"label\"))\n              _loopLabels[loop.id] = label\n            }\n            _loopLabels[node.id] = label\n            break\n          }\n        }\n      }\n\n      # Stop at nested loops since those will be tested later\n      else if node == loop || !node.kind.isLoop {\n        for child = node.firstChild; child != null; child = child.nextSibling {\n          _scanForSwitchBreak(child, loop)\n        }\n      }\n    }\n\n    def _emitStatement(node Node, trailing Comment) {\n      if node.kind.isLoop {\n        _scanForSwitchBreak(node, node)\n\n        var label = _loopLabels.get(node.id, null)\n        if label != null {\n          _emit(_indent + _mangleName(label) + (node.nextSibling != null ? \":\\n\" : \":;\\n\"))\n        }\n      }\n\n      switch node.kind {\n        case .COMMENT_BLOCK {}\n\n        case .VARIABLES {\n          for child = node.firstChild; child != null; child = child.nextSibling {\n            var symbol = child.symbol.asVariableSymbol\n            var value = symbol.value\n            _emit(_indent + \"let \")\n            if value != null && _canOmitTypeAnnotation(value) {\n              _emit(_mangleName(symbol))\n            } else {\n              _emit(_mangleName(symbol) + \": \")\n              _emitExpressionOrType(symbol.type, symbol.resolvedType)\n            }\n            if value != null {\n              var comments = _commentsFromExpression(value)\n              if comments != null {\n                _emit(\" =\\n\")\n                _increaseIndent\n                _emitComments(comments)\n                _emit(_indent)\n                _emitExpression(value, .ASSIGN)\n                _decreaseIndent\n              } else {\n                _emit(\" = \")\n                _emitExpression(value, .ASSIGN)\n              }\n            }\n            _emit(\";\")\n            _emitTrailingComment(trailing)\n            _emit(\"\\n\")\n          }\n        }\n\n        case .EXPRESSION {\n          _emit(_indent)\n          _emitExpression(node.expressionValue, .LOWEST)\n          _emit(\";\")\n          _emitTrailingComment(trailing)\n          _emit(\"\\n\")\n        }\n\n        case .BREAK {\n          var label = _loopLabels.get(node.id, null)\n          if label != null {\n            _emit(_indent + \"break \" + _mangleName(label) + \";\")\n          } else {\n            _emit(_indent + \"break;\")\n          }\n          _emitTrailingComment(trailing)\n          _emit(\"\\n\")\n        }\n\n        case .CONTINUE {\n          _emit(_indent + \"continue;\")\n          _emitTrailingComment(trailing)\n          _emit(\"\\n\")\n        }\n\n        case .IF {\n          _emit(_indent)\n          if trailing != null {\n            _emitComments([trailing])\n          }\n          _emitIf(node)\n        }\n\n        case .SWITCH {\n          var switchValue = node.switchValue\n          _emit(_indent + \"switch (\")\n          _emitExpression(switchValue, .LOWEST)\n          _emit(\") {\\n\")\n          _increaseIndent\n          for child = switchValue.nextSibling; child != null; child = child.nextSibling {\n            var block = child.caseBlock\n            var blockComments = block.comments\n            if child.previousSibling != switchValue {\n              _emit(\"\\n\")\n            }\n            _emitComments(child.comments)\n            if child.hasOneChild {\n              _emit(_indent + \"default:\")\n            } else {\n              for value = child.firstChild; value != block; value = value.nextSibling {\n                if value.previousSibling != null {\n                  _emit(\"\\n\")\n                }\n                _emitComments(_commentsFromExpression(value))\n                _emit(_indent + \"case \")\n                _emitExpression(value, .LOWEST)\n                _emit(\":\")\n              }\n            }\n\n            # Some people put comments before blocks in case statements\n            if blockComments != null {\n              _emit(\"\\n\")\n              _emitComments(blockComments)\n              _emit(_indent + \"{\\n\")\n            } else {\n              _emit(\" {\\n\")\n            }\n\n            _increaseIndent\n            _emitStatements(block)\n            if block.hasControlFlowAtEnd {\n              _emit(_indent + \"break;\\n\")\n            }\n            _decreaseIndent\n            _emit(_indent + \"}\\n\")\n          }\n          _decreaseIndent\n          _emit(_indent + \"}\")\n          _emitTrailingComment(trailing)\n          _emit(\"\\n\")\n        }\n\n        case .RETURN {\n          _emit(_indent + \"return\")\n          var value = node.returnValue\n          if value != null {\n            var comments = value.comments\n            if comments != null {\n              # JavaScript needs parentheses here to avoid ASI issues\n              _emit(\" (\\n\")\n              _increaseIndent\n              _emitComments(comments)\n              _emit(_indent)\n              _emitExpression(value, .LOWEST)\n              _decreaseIndent\n              _emit(\")\")\n            } else {\n              _emit(\" \")\n              _emitExpression(value, .LOWEST)\n            }\n          }\n          _emit(\";\")\n          _emitTrailingComment(trailing)\n          _emit(\"\\n\")\n        }\n\n        case .THROW {\n          _emit(_indent + \"throw \")\n          _emitExpression(node.throwValue, .LOWEST)\n          _emit(\";\")\n          _emitTrailingComment(trailing)\n          _emit(\"\\n\")\n        }\n\n        case .FOREACH {\n          var value = node.foreachValue\n          _emit(_indent + \"for (const \" + _mangleName(node.symbol))\n          _emit(_cache.isList(value.resolvedType)  ? \" of \" : \" in \")\n          _emitExpression(value, .LOWEST)\n          _emit(\")\")\n          _emitBlock(node.foreachBlock)\n          _emitTrailingComment(trailing)\n          _emit(\"\\n\")\n        }\n\n        case .FOR {\n          var setup = node.forSetup\n          var test = node.forTest\n          var update = node.forUpdate\n          _emit(_indent + \"for (\")\n          if !setup.isEmptySequence {\n            if setup.kind == .VARIABLES {\n              var symbol = setup.firstChild.symbol.asVariableSymbol\n              _emit(\"let \")\n              for child = setup.firstChild; child != null; child = child.nextSibling {\n                symbol = child.symbol.asVariableSymbol\n                assert(child.kind == .VARIABLE)\n                if child.previousSibling != null {\n                  _emit(\", \")\n                }\n                if _canOmitTypeAnnotation(symbol.value) {\n                  _emit(_mangleName(symbol))\n                } else {\n                  _emit(_mangleName(symbol) + \": \")\n                  _emitExpressionOrType(symbol.type, symbol.resolvedType)\n                }\n                _emit(\" = \")\n                _emitExpression(symbol.value, .COMMA)\n              }\n            } else {\n              _emitExpression(setup, .LOWEST)\n            }\n          }\n          _emit(\"; \")\n          if !test.isEmptySequence {\n            _emitExpression(test, .LOWEST)\n          }\n          _emit(\"; \")\n          if !update.isEmptySequence {\n            _emitExpression(update, .LOWEST)\n          }\n          _emit(\")\")\n          _emitBlock(node.forBlock)\n          _emitTrailingComment(trailing)\n          _emit(\"\\n\")\n        }\n\n        case .TRY {\n          var tryBlock = node.tryBlock\n          var finallyBlock = node.finallyBlock\n\n          if trailing != null {\n            _emitComments([trailing])\n          }\n\n          _emit(_indent + \"try\")\n          _emitBlock(tryBlock)\n          _emit(\"\\n\")\n\n          for child = tryBlock.nextSibling; child != finallyBlock; child = child.nextSibling {\n            if child.comments != null {\n              _emit(\"\\n\")\n              _emitComments(child.comments)\n            }\n            _emit(_indent + \"catch\")\n            if child.symbol != null {\n              _emit(\" (\" + _mangleName(child.symbol) + \")\")\n            }\n            _emitBlock(child.catchBlock)\n            _emit(\"\\n\")\n          }\n\n          if finallyBlock != null {\n            if finallyBlock.comments != null {\n              _emit(\"\\n\")\n              _emitComments(finallyBlock.comments)\n            }\n            _emit(_indent + \"finally\")\n            _emitBlock(finallyBlock)\n            _emit(\"\\n\")\n          }\n        }\n\n        case .WHILE {\n          _emit(_indent + \"while (\")\n          _emitExpression(node.whileTest, .LOWEST)\n          _emit(\")\")\n          _emitBlock(node.whileBlock)\n          _emitTrailingComment(trailing)\n          _emit(\"\\n\")\n        }\n\n        default {\n          assert(false)\n        }\n      }\n    }\n\n    def _emitContent(content Content) {\n      switch content.kind {\n        case .BOOL { _emit(content.asBool.toString) }\n        case .INT { _emit(content.asInt.toString) }\n        case .DOUBLE {\n          var value = content.asDouble\n          _emit(\n            value.isNaN ? \"NaN\" :\n            value == Math.INFINITY ? \"Infinity\" :\n            value == -Math.INFINITY ? \"-Infinity\" :\n            value.toString)\n        }\n        case .STRING { _emit(quoteString(content.asString, .SHORTEST, .NORMAL)) }\n      }\n    }\n\n    def _commentsFromExpression(node Node) List<Comment> {\n      var comments = node.comments\n      switch node.kind {\n        case .CAST { return Comment.concat(comments, node.castValue.comments) }\n        case .CALL { return Comment.concat(comments, node.callValue.comments) }\n      }\n      return comments\n    }\n\n    def _emitCommaSeparatedExpressions(from Node, to Node) {\n      var isIndented = false\n\n      for child = from; child != to; child = child.nextSibling {\n        if _commentsFromExpression(child) != null {\n          isIndented = true\n          break\n        }\n      }\n\n      if isIndented {\n        _increaseIndent\n      }\n\n      while from != to {\n        var comments = _commentsFromExpression(from)\n        var trailing = Comment.lastTrailingComment(comments)\n        var notTrailing = Comment.withoutLastTrailingComment(comments)\n\n        if isIndented {\n          _emit(\"\\n\")\n          _emitComments(notTrailing)\n          _emit(_indent)\n        }\n\n        _emitExpression(from, .COMMA)\n        from = from.nextSibling\n        if from != to {\n          _emit(isIndented ? \",\" : \", \")\n        }\n\n        _emitTrailingComment(trailing)\n      }\n\n      if isIndented {\n        _decreaseIndent\n        _emit(\"\\n\")\n        _emit(_indent)\n      }\n    }\n\n    def _emitExpression(node Node, precedence Precedence) {\n      var kind = node.kind\n      var symbol = node.symbol\n\n      if symbol != null {\n        _handleSymbol(symbol)\n      }\n\n      switch kind {\n        case .TYPE, .LAMBDA_TYPE {\n          _emitType(node.resolvedType)\n        }\n\n        case .NULL {\n          _emit(\"null\")\n        }\n\n        case .NAME {\n          _emit(symbol != null ? _fullName(symbol) : node.asString)\n        }\n\n        case .DOT {\n          var innerComments = node.innerComments\n          _emitExpression(node.dotTarget, .MEMBER)\n          if innerComments != null {\n            _increaseIndent\n            _emit(\"\\n\")\n            _emitComments(innerComments)\n            _emit(_indent)\n            _decreaseIndent\n          }\n          _emit(\".\" + (symbol != null ? _mangleName(symbol) : node.asString))\n        }\n\n        case .STRING_INTERPOLATION {\n          _emit(\"`\")\n          var isString = true\n          for child = node.firstChild; child != null; child = child.nextSibling {\n            if isString {\n              _emit(quoteString(child.asString, .TYPESCRIPT_TEMPLATE, .NORMAL))\n            } else {\n              _emit(\"${\")\n              var value = child\n\n              # Omit implied \".toString()\" calls on interpolated values\n              if value.kind == .CALL {\n                var target = value.callValue\n                if target.nextSibling == null && target.kind == .DOT && target.asString == \"toString\" {\n                  value = target.dotTarget\n                }\n              }\n\n              _emitExpression(value, .LOWEST)\n              _emit(\"}\")\n            }\n            isString = !isString\n          }\n          _emit(\"`\")\n        }\n\n        case .CONSTANT {\n          var wrap = precedence == .MEMBER && node.isNumberLessThanZero && (!node.isDouble || node.asDouble.isFinite)\n          if wrap {\n            _emit(\"(\")\n          }\n\n          _emitContent(node.content)\n\n          if node.resolvedType.isEnumOrFlags {\n            _emit(\" as \")\n            _emitType(node.resolvedType)\n          }\n\n          if wrap {\n            _emit(\")\")\n          }\n        }\n\n        case .CALL {\n          var value = node.callValue\n          var wrap = value.kind == .LAMBDA\n\n          # Turn \"new Object\" into \"{}\"\n          if value.kind == .DOT && value.asString == \"new\" && value.nextSibling == null {\n            var target = value.dotTarget\n            if target.kind == .NAME && target.asString == \"Object\" {\n              _emit(\"{}\")\n              return\n            }\n          }\n\n          if wrap {\n            _emit(\"(\")\n          }\n\n          if value.kind == .SUPER {\n            _emit(\"super\")\n            if symbol.kind != .FUNCTION_CONSTRUCTOR {\n              _emit(\".\")\n              _emit(_mangleName(symbol))\n            }\n          }\n\n          else if symbol != null && symbol.kind == .FUNCTION_CONSTRUCTOR {\n            _emit(\"new \")\n            _emitType(node.resolvedType)\n          }\n\n          else if value.kind == .DOT && value.asString == \"new\" {\n            _emit(\"new \")\n            _emitExpression(value.dotTarget, .MEMBER)\n          }\n\n          else {\n            _emitExpression(value, .UNARY_POSTFIX)\n          }\n\n          if wrap {\n            _emit(\")\")\n          }\n\n          _emit(\"(\")\n          if symbol != null && symbol.kind == .FUNCTION_CONSTRUCTOR {\n            var multiple = _ctors.get(symbol.parent.id, null)\n            if multiple != null && !multiple.canUseArgumentCount {\n              _emit(\"\\(multiple.ctors.indexOf(symbol as FunctionSymbol))\")\n              if value.nextSibling != null {\n                _emit(\", \")\n              }\n            }\n          }\n          _emitCommaSeparatedExpressions(value.nextSibling, null)\n          _emit(\")\")\n        }\n\n        case .CAST {\n          var type = node.castType\n          var value = node.castValue\n          var unwrappedSource = _cache.unwrappedType(value.resolvedType)\n          var unwrappedTarget = _cache.unwrappedType(type.resolvedType)\n\n          # Skip the cast in certain cases\n          if type.kind == .TYPE && (type.resolvedType == .DYNAMIC || value.kind == .NULL) {\n            _emitExpression(value, precedence)\n          }\n\n          # Conversion from integer to any numeric type can be ignored\n          else if _cache.isInteger(unwrappedSource) && _cache.isNumeric(unwrappedTarget) {\n            _emitExpression(value, precedence)\n          }\n\n          # Cast from bool to a number\n          else if _cache.isNumeric(unwrappedTarget) && value.resolvedType == _cache.boolType {\n            _emitExpression(Node.createHook(value.remove, _cache.createInt(1), _cache.createInt(0)).withType(_cache.intType), precedence)\n          }\n\n          # Cast to bool\n          else if unwrappedTarget == _cache.boolType && unwrappedSource != _cache.boolType {\n            _emitExpression(Node.createUnary(.NOT, Node.createUnary(.NOT, value.remove).withType(_cache.boolType)).withType(_cache.boolType), precedence)\n          }\n\n          # Cast to int\n          else if _cache.isInteger(unwrappedTarget) && !_cache.isInteger(unwrappedSource) {\n            _emitExpression(Node.createBinary(.BITWISE_OR, value.remove, Node.createInt(0).withType(_cache.intType)).withType(_cache.intType), precedence)\n          }\n\n          # Cast to double\n          else if unwrappedTarget == _cache.doubleType && unwrappedSource != _cache.doubleType {\n            _emitExpression(Node.createUnary(.POSITIVE, value.remove).withType(_cache.doubleType), precedence)\n          }\n\n          # Cast to string\n          else if unwrappedTarget == _cache.stringType && unwrappedSource != _cache.stringType {\n            _emitExpression(Node.createSymbolCall(_specialVariable(.AS_STRING)).appendChild(value.remove).withType(_cache.stringType), precedence)\n          }\n\n          # Only emit a cast if the underlying types are different\n          else if unwrappedSource != unwrappedTarget || type.resolvedType == .DYNAMIC {\n            if Precedence.ASSIGN < precedence {\n              _emit(\"(\")\n            }\n            _emitExpression(value, .ASSIGN)\n            _emit(\" as \")\n            _emitExpressionOrType(type, type.resolvedType)\n            if Precedence.ASSIGN < precedence {\n              _emit(\")\")\n            }\n          }\n\n          # Otherwise, pretend the cast isn't there\n          else {\n            _emitExpression(value, precedence)\n          }\n        }\n\n        case .TYPE_CHECK {\n          var value = node.typeCheckValue\n          var type = node.typeCheckType\n          var targetType = _cache.unwrappedType(type.resolvedType)\n\n          if _cache.isInteger(targetType) {\n            _emitExpression(Node.createSymbolCall(_specialVariable(.IS_INT)).appendChild(value.remove).withType(_cache.boolType), precedence)\n            return\n          }\n\n          if Precedence.COMPARE < precedence {\n            _emit(\"(\")\n          }\n\n          if targetType == _cache.doubleType {\n            _emit(\"typeof \")\n            _emitExpression(value, .UNARY_PREFIX)\n            _emit(\" === 'number'\")\n          }\n\n          else if targetType == _cache.stringType {\n            _emit(\"typeof \")\n            _emitExpression(value, .UNARY_PREFIX)\n            _emit(\" === 'string'\")\n          }\n\n          else if targetType == _cache.boolType {\n            _emit(\"typeof \")\n            _emitExpression(value, .UNARY_PREFIX)\n            _emit(\" === 'boolean'\")\n          }\n\n          else {\n            _emitExpression(value, .LOWEST)\n            _emit(\" instanceof \")\n            if type.resolvedType == .DYNAMIC {\n              _emitExpression(type, .LOWEST)\n            } else {\n              _emitExpressionOrType(type, type.resolvedType)\n            }\n          }\n\n          if Precedence.COMPARE < precedence {\n            _emit(\")\")\n          }\n        }\n\n        case .INITIALIZER_LIST {\n          _emit(\"[\")\n          _emitCommaSeparatedExpressions(node.firstChild, null)\n          _emit(\"]\")\n        }\n\n        case .INITIALIZER_MAP {\n          if !node.hasChildren {\n            _emit(\"{}\")\n          } else {\n            _emit(\"{\\n\")\n            _increaseIndent\n            for child = node.firstChild; child != null; child = child.nextSibling {\n              _emitComments(child.comments)\n              _emit(_indent)\n              _emitExpression(child.firstValue, .COMMA)\n              _emit(\": \")\n              _emitExpression(child.secondValue, .COMMA)\n              _emit(\",\\n\")\n            }\n            _decreaseIndent\n            _emit(_indent + \"}\")\n          }\n        }\n\n        case .INDEX {\n          _emitExpression(node.indexLeft, .UNARY_POSTFIX)\n          _emit(\"[\")\n          _emitExpression(node.indexRight, .LOWEST)\n          _emit(\"]\")\n        }\n\n        case .ASSIGN_INDEX {\n          if Precedence.ASSIGN < precedence {\n            _emit(\"(\")\n          }\n          _emitExpression(node.assignIndexLeft, .UNARY_POSTFIX)\n          _emit(\"[\")\n          _emitExpression(node.assignIndexCenter, .LOWEST)\n          _emit(\"] = \")\n          _emitExpression(node.assignIndexRight, .ASSIGN)\n          if Precedence.ASSIGN < precedence {\n            _emit(\")\")\n          }\n        }\n\n        case .PARAMETERIZE {\n          var value = node.parameterizeValue\n          if value.isType {\n            _emitType(node.resolvedType)\n          } else {\n            _emitExpression(value, precedence)\n            _emit(\"<\")\n            _emitCommaSeparatedExpressions(value.nextSibling, null)\n            _emit(\">\")\n          }\n        }\n\n        case .SEQUENCE {\n          if Precedence.COMMA <= precedence {\n            _emit(\"(\")\n          }\n          _emitCommaSeparatedExpressions(node.firstChild, null)\n          if Precedence.COMMA <= precedence {\n            _emit(\")\")\n          }\n        }\n\n        case .HOOK {\n          if Precedence.ASSIGN < precedence {\n            _emit(\"(\")\n          }\n\n          _emitExpression(node.hookTest, .LOGICAL_OR)\n          _emit(\" ?\")\n\n          var left = node.hookTrue\n          var leftComments = _commentsFromExpression(left)\n          if leftComments != null {\n            _emit(\"\\n\")\n            _increaseIndent\n            _emitComments(leftComments)\n            _emit(_indent)\n            _emitExpression(left, .ASSIGN)\n            _decreaseIndent\n          } else {\n            _emit(\" \")\n            _emitExpression(left, .ASSIGN)\n          }\n\n          _emit(\" :\")\n\n          var right = node.hookFalse\n          var rightComments = _commentsFromExpression(right)\n          if rightComments != null {\n            _emit(\"\\n\")\n            _increaseIndent\n            _emitComments(rightComments)\n            _emit(_indent)\n            _emitExpression(right, .ASSIGN)\n            _decreaseIndent\n          } else {\n            _emit(\" \")\n            _emitExpression(right, .ASSIGN)\n          }\n\n          if Precedence.ASSIGN < precedence {\n            _emit(\")\")\n          }\n        }\n\n        case .LAMBDA {\n          var oldEnclosingFunction = _enclosingFunction\n          _enclosingFunction = symbol.asFunctionSymbol\n          _emitArgumentList(symbol.asFunctionSymbol)\n          _emit(\" =>\")\n          _emitBlock(symbol.asFunctionSymbol.block)\n          _enclosingFunction = oldEnclosingFunction\n        }\n\n        case .COMPLEMENT, .NEGATIVE, .NOT, .POSITIVE, .POSTFIX_DECREMENT, .POSTFIX_INCREMENT, .PREFIX_DECREMENT, .PREFIX_INCREMENT {\n          var value = node.unaryValue\n          var info = operatorInfo[kind]\n          var sign = node.sign\n          if info.precedence < precedence {\n            _emit(\"(\")\n          }\n          if !kind.isUnaryPostfix {\n            _emit(info.text)\n\n            # Prevent \"x - -1\" from becoming \"x--1\"\n            if sign != .NULL && sign == value.sign {\n              _emit(\" \")\n            }\n          }\n          _emitExpression(value, info.precedence)\n          if kind.isUnaryPostfix {\n            _emit(info.text)\n          }\n          if info.precedence < precedence {\n            _emit(\")\")\n          }\n        }\n\n        default {\n          if kind.isBinary {\n            var left = node.binaryLeft\n            var right = node.binaryRight\n\n            # Handle truncating integer division\n            if node.resolvedType == _cache.intType && kind == .DIVIDE && node.parent != null && node.parent.kind != .BITWISE_OR {\n              const divide = Node.createBinary(.DIVIDE, left.remove, right.remove).withType(_cache.intType)\n              const zero = Node.createInt(0).withType(_cache.intType)\n              _emitExpression(Node.createBinary(.BITWISE_OR, divide, zero).withType(_cache.intType), precedence)\n              return\n            }\n\n            var info = operatorInfo[kind]\n            if info.precedence < precedence {\n              _emit(\"(\")\n            }\n            _emitExpression(left, info.precedence.incrementIfRightAssociative(info.associativity))\n            _emit(\" \" + info.text + (kind == .EQUAL || kind == .NOT_EQUAL ? \"=\" : \"\"))\n\n            var comments = _commentsFromExpression(right)\n            if comments != null {\n              var leading = Comment.firstTrailingComment(comments)\n              var notLeading = Comment.withoutFirstTrailingComment(comments)\n              _emitTrailingComment(leading)\n              _emit(\"\\n\")\n              _increaseIndent\n              _emitComments(notLeading)\n              _emit(_indent)\n              _emitExpression(right, info.precedence.incrementIfLeftAssociative(info.associativity))\n              _decreaseIndent\n            } else {\n              _emit(\" \")\n              _emitExpression(right, info.precedence.incrementIfLeftAssociative(info.associativity))\n            }\n\n            if info.precedence < precedence {\n              _emit(\")\")\n            }\n          }\n\n          else {\n            assert(false)\n          }\n        }\n      }\n    }\n\n    def _fullName(symbol Symbol) string {\n      var parent = symbol.parent\n      if parent != null && parent.kind != .OBJECT_GLOBAL &&\n          (!_shouldFlattenNamespace(parent) || parent.isImported) && !symbol.kind.isParameter &&\n          !(parent in _enclosingNamespaces) {\n        var enclosingName = _fullName(parent)\n        if symbol.kind == .FUNCTION_CONSTRUCTOR {\n          return enclosingName\n        }\n        return enclosingName + \".\" + _mangleName(symbol)\n      }\n      return _mangleName(symbol)\n    }\n  }\n\n  namespace TypeScriptEmitter {\n    def _isInsideNamespaceOrGlobal(symbol Symbol) bool {\n      var parent = symbol.parent\n      return parent != null && (parent.kind == .OBJECT_GLOBAL || parent.kind == .OBJECT_NAMESPACE && _isInsideNamespaceOrGlobal(parent))\n    }\n\n    def _shouldFlattenNamespace(symbol Symbol) bool {\n      return symbol.kind == .OBJECT_NAMESPACE && _isInsideNamespaceOrGlobal(symbol)\n    }\n\n    def _isCompactNodeKind(kind NodeKind) bool {\n      return kind == .EXPRESSION || kind == .VARIABLES || kind.isJump\n    }\n\n    def _mangleName(symbol Symbol) string {\n      symbol = symbol.forwarded\n      if symbol.kind == .FUNCTION_CONSTRUCTOR {\n        symbol = symbol.parent\n      }\n      if !symbol.isImportedOrExported && symbol.name in _isKeyword {\n        return \"_\" + symbol.name\n      }\n      var parent = symbol.parent\n      if parent != null && parent.kind == .OBJECT_NAMESPACE && parent.name.startsWith(\"in_\") {\n        var prefix = _mangleName(parent)\n        if prefix.startsWith(\"in_\") {\n          prefix = prefix.slice(3)\n        }\n        return prefix + \"_\" + symbol.name\n      }\n      return symbol.name\n    }\n\n    # https://github.com/Microsoft/TypeScript/issues/2536\n    const _isKeyword = {\n      # Reserved Words\n      \"break\": 0,\n      \"case\": 0,\n      \"catch\": 0,\n      \"class\": 0,\n      \"const\": 0,\n      \"continue\": 0,\n      \"debugger\": 0,\n      \"default\": 0,\n      \"delete\": 0,\n      \"do\": 0,\n      \"else\": 0,\n      \"enum\": 0,\n      \"export\": 0,\n      \"extends\": 0,\n      \"false\": 0,\n      \"finally\": 0,\n      \"for\": 0,\n      \"function\": 0,\n      \"if\": 0,\n      \"implements\": 0,\n      \"import\": 0,\n      \"in\": 0,\n      \"instanceof\": 0,\n      \"interface\": 0,\n      \"namespace\": 0,\n      \"new\": 0,\n      \"null\": 0,\n      \"return\": 0,\n      \"super\": 0,\n      \"switch\": 0,\n      \"this\": 0,\n      \"throw\": 0,\n      \"true\": 0,\n      \"try\": 0,\n      \"typeof\": 0,\n      \"var\": 0,\n      \"void\": 0,\n      \"while\": 0,\n      \"with\": 0,\n\n      # Strict mode reserved words\n      \"as\": 0,\n      \"implements\": 0,\n      \"interface\": 0,\n      \"let\": 0,\n      \"package\": 0,\n      \"private\": 0,\n      \"protected\": 0,\n      \"public\": 0,\n      \"static\": 0,\n      \"yield\": 0,\n\n      # Other special names that must be avoided\n      \"arguments\": 0,\n      \"Symbol\": 0,\n    }\n\n    const _specialVariableMap = {\n      \"__asString\": SpecialVariable.AS_STRING,\n      \"__isInt\": SpecialVariable.IS_INT,\n    }\n  }\n}\n"
  },
  {
    "path": "src/core/content.sk",
    "content": "namespace Skew {\n  enum ContentKind {\n    BOOL\n    INT\n    DOUBLE\n    STRING\n  }\n\n  interface Content {\n    def kind ContentKind\n\n    def asBool bool {\n      assert(kind == .BOOL)\n      return (self as BoolContent).value\n    }\n\n    def asInt int {\n      assert(kind == .INT)\n      return (self as IntContent).value\n    }\n\n    def asDouble double {\n      assert(kind == .DOUBLE)\n      return (self as DoubleContent).value\n    }\n\n    def asString string {\n      assert(kind == .STRING)\n      return (self as StringContent).value\n    }\n\n    def equals(other Content) bool {\n      if kind == other.kind {\n        switch kind {\n          case .BOOL { return asBool == other.asBool }\n          case .INT { return asInt == other.asInt }\n          case .DOUBLE { return asDouble == other.asDouble }\n          case .STRING { return asString == other.asString }\n        }\n      }\n      return false\n    }\n  }\n\n  class BoolContent :: Content {\n    const value bool\n\n    def kind ContentKind {\n      return .BOOL\n    }\n  }\n\n  class IntContent :: Content {\n    const value int\n\n    def kind ContentKind {\n      return .INT\n    }\n  }\n\n  class DoubleContent :: Content {\n    const value double\n\n    def kind ContentKind {\n      return .DOUBLE\n    }\n  }\n\n  class StringContent :: Content {\n    const value string\n\n    def kind ContentKind {\n      return .STRING\n    }\n  }\n}\n"
  },
  {
    "path": "src/core/node.sk",
    "content": "namespace Skew {\n  enum NodeKind {\n    # Other\n    ANNOTATION\n    BLOCK\n    CASE\n    CATCH\n    VARIABLE\n\n    # Statements\n    BREAK\n    COMMENT_BLOCK\n    CONTINUE\n    EXPRESSION\n    FOR\n    FOREACH\n    IF\n    RETURN\n    SWITCH\n    THROW\n    TRY\n    VARIABLES\n    WHILE\n\n    # Expressions\n    ASSIGN_INDEX\n    CALL\n    CAST\n    CONSTANT\n    DOT\n    HOOK\n    INDEX\n    INITIALIZER_LIST\n    INITIALIZER_MAP\n    LAMBDA\n    LAMBDA_TYPE\n    NAME\n    NULL\n    NULL_DOT\n    PAIR\n    PARAMETERIZE\n    PARSE_ERROR\n    SEQUENCE\n    STRING_INTERPOLATION\n    SUPER\n    TYPE\n    TYPE_CHECK\n    XML\n\n    # Unary operators\n    COMPLEMENT\n    NEGATIVE\n    NOT\n    POSITIVE\n    POSTFIX_DECREMENT\n    POSTFIX_INCREMENT\n    PREFIX_DECREMENT\n    PREFIX_INCREMENT\n\n    # Binary operators\n    ADD\n    BITWISE_AND\n    BITWISE_OR\n    BITWISE_XOR\n    COMPARE\n    DIVIDE\n    EQUAL\n    IN\n    LOGICAL_AND\n    LOGICAL_OR\n    MODULUS\n    MULTIPLY\n    NOT_EQUAL\n    NULL_JOIN\n    POWER\n    REMAINDER\n    SHIFT_LEFT\n    SHIFT_RIGHT\n    SUBTRACT\n    UNSIGNED_SHIFT_RIGHT\n\n    # Binary comparison operators\n    GREATER_THAN\n    GREATER_THAN_OR_EQUAL\n    LESS_THAN\n    LESS_THAN_OR_EQUAL\n\n    # Binary assigment operators\n    ASSIGN\n    ASSIGN_ADD\n    ASSIGN_BITWISE_AND\n    ASSIGN_BITWISE_OR\n    ASSIGN_BITWISE_XOR\n    ASSIGN_DIVIDE\n    ASSIGN_MODULUS\n    ASSIGN_MULTIPLY\n    ASSIGN_NULL\n    ASSIGN_POWER\n    ASSIGN_REMAINDER\n    ASSIGN_SHIFT_LEFT\n    ASSIGN_SHIFT_RIGHT\n    ASSIGN_SUBTRACT\n    ASSIGN_UNSIGNED_SHIFT_RIGHT\n\n    def isStatement bool {\n      return self >= ASSIGN && self <= WHILE\n    }\n\n    def isBitOperation bool {\n      return\n        self == COMPLEMENT ||\n        self >= BITWISE_AND && self <= BITWISE_XOR ||\n        self >= ASSIGN_BITWISE_AND && self <= ASSIGN_BITWISE_XOR\n    }\n\n    def isLoop bool {\n      return self == FOR || self == FOREACH || self == WHILE\n    }\n\n    def isExpression bool {\n      return self >= ASSIGN_INDEX && self <= ASSIGN_UNSIGNED_SHIFT_RIGHT\n    }\n\n    def isInitializer bool {\n      return self == INITIALIZER_LIST || self == INITIALIZER_MAP\n    }\n\n    def isUnary bool {\n      return self >= COMPLEMENT && self <= PREFIX_INCREMENT\n    }\n\n    def isUnaryAssign bool {\n      return self >= POSTFIX_DECREMENT && self <= PREFIX_INCREMENT\n    }\n\n    def isUnaryPostfix bool {\n      return self == POSTFIX_DECREMENT || self == POSTFIX_INCREMENT\n    }\n\n    def isBinary bool {\n      return self >= ADD && self <= ASSIGN_UNSIGNED_SHIFT_RIGHT\n    }\n\n    def isBinaryAssign bool {\n      return self >= ASSIGN && self <= ASSIGN_UNSIGNED_SHIFT_RIGHT\n    }\n\n    # Note that add and multiply are NOT associative in finite-precision arithmetic\n    def isBinaryAssociative bool {\n      switch self {\n        case BITWISE_AND, BITWISE_OR, BITWISE_XOR, LOGICAL_AND, LOGICAL_OR {\n          return true\n        }\n      }\n      return false\n    }\n\n    def isBinaryComparison bool {\n      return self >= GREATER_THAN && self <= LESS_THAN_OR_EQUAL\n    }\n\n    def isShift bool {\n      return self == SHIFT_LEFT || self == SHIFT_RIGHT || self == UNSIGNED_SHIFT_RIGHT\n    }\n\n    def isJump bool {\n      return self == BREAK || self == CONTINUE || self == RETURN\n    }\n\n    def isAssign bool {\n      return isUnaryAssign || isBinaryAssign || self == ASSIGN_INDEX\n    }\n  }\n\n  flags NodeFlags {\n    # This flag is only for blocks. A simple control flow analysis is run\n    # during code resolution and blocks where control flow reaches the end of\n    # the block have this flag set.\n    HAS_CONTROL_FLOW_AT_END\n\n    # Use this flag to tell the IDE support code to ignore this node. This is\n    # useful for compiler-generated nodes that are used for lowering and that\n    # need marked ranges for error reporting but that should not show up in\n    # tooltips.\n    IS_IGNORED_BY_IDE\n\n    # An implicit return is a return statement inside an expression lambda. For\n    # example, the lambda \"x => x\" is compiled into \"x => { return x }\" where\n    # the return statement has this flag set.\n    IS_IMPLICIT_RETURN\n\n    # This flag marks list nodes that help implement initializer expressions.\n    IS_INITIALIZER_EXPANSION\n\n    # This flag marks nodes that were wrapped in parentheses in the original\n    # source code. It's used for warnings about C-style syntax in conditional\n    # statements and to call a lambda returned from a getter.\n    IS_INSIDE_PARENTHESES\n\n    # This flag is set on nodes that are expected to be types.\n    SHOULD_EXPECT_TYPE\n\n    # This flag marks nodes that were converted from ASSIGN_NULL to ASSIGN nodes.\n    WAS_ASSIGN_NULL\n\n    # This flag marks nodes that were converted from NULL_JOIN to HOOK nodes.\n    WAS_NULL_JOIN\n  }\n\n  # Nodes represent executable code (variable initializers and function bodies)\n  class Node {\n    const id = _createID\n    var kind NodeKind\n    var flags NodeFlags = 0\n    var range Range = null\n    var internalRange Range = null\n    var symbol Symbol = null\n    var content Content = null\n    var resolvedType Type = null\n    var comments List<Comment> = null\n    var innerComments List<Comment> = null\n    var _parent Node = null\n    var _firstChild Node = null\n    var _lastChild Node = null\n    var _previousSibling Node = null\n    var _nextSibling Node = null\n\n    def _cloneWithoutChildren Node {\n      var clone = new(kind)\n      clone.flags = flags\n      clone.range = range\n      clone.internalRange = internalRange\n      clone.symbol = symbol\n      clone.content = content\n      clone.resolvedType = resolvedType\n      clone.comments = comments?.clone\n      clone.innerComments = innerComments?.clone\n      return clone\n    }\n\n    # When used with become(), this provides a convenient way to wrap a node in\n    # an operation without the caller needing to be aware of replaceWith():\n    #\n    #  node.become(Node.createUnary(.NOT, node.cloneAndStealChildren))\n    #\n    def cloneAndStealChildren Node {\n      var clone = _cloneWithoutChildren\n      while hasChildren {\n        clone.appendChild(_firstChild.remove)\n      }\n      return clone\n    }\n\n    def clone Node {\n      var clone = _cloneWithoutChildren\n      if kind == .LAMBDA {\n        clone.symbol = symbol.asFunctionSymbol.clone\n        clone.appendChild(clone.symbol.asFunctionSymbol.block)\n      } else if kind == .VARIABLE {\n        clone.symbol = symbol.asVariableSymbol.clone\n        clone.appendChild(clone.symbol.asVariableSymbol.value)\n      } else {\n        for child = _firstChild; child != null; child = child._nextSibling {\n          clone.appendChild(child.clone)\n        }\n      }\n      return clone\n    }\n\n    # Change self node in place to become the provided node. The parent node is\n    # not changed, so become() can be called within a nested method and does not\n    # need to report the updated node reference to the caller since the reference\n    # does not change.\n    def become(node Node) {\n      if node == self {\n        return\n      }\n      assert(node._parent == null)\n      kind = node.kind\n      flags = node.flags\n      range = node.range\n      internalRange = node.internalRange\n      symbol = node.symbol\n      content = node.content\n      resolvedType = node.resolvedType\n      comments = node.comments\n      removeChildren\n      appendChildrenFrom(node)\n    }\n\n    def parent Node          { return _parent }\n    def firstChild Node      { return _firstChild }\n    def lastChild Node       { return _lastChild }\n    def previousSibling Node { return _previousSibling }\n    def nextSibling Node     { return _nextSibling }\n\n    def hasControlFlowAtEnd bool    { return .HAS_CONTROL_FLOW_AT_END in flags }\n    def isIgnoredByIDE bool         { return .IS_IGNORED_BY_IDE in flags }\n    def isImplicitReturn bool       { return .IS_IMPLICIT_RETURN in flags }\n    def isInitializerExpansion bool { return .IS_INITIALIZER_EXPANSION in flags }\n    def isInsideParentheses bool    { return .IS_INSIDE_PARENTHESES in flags }\n    def wasAssignNull bool          { return .WAS_ASSIGN_NULL in flags }\n    def wasNullJoin bool            { return .WAS_NULL_JOIN in flags }\n\n    def shouldExpectType bool {\n      for node = self; node != null; node = node.parent {\n        if .SHOULD_EXPECT_TYPE in node.flags {\n          return true\n        }\n      }\n      return false\n    }\n\n    # This is cheaper than childCount == 0\n    def hasChildren bool {\n      return _firstChild != null\n    }\n\n    # This is cheaper than childCount == 1\n    def hasOneChild bool {\n      return hasChildren && _firstChild == _lastChild\n    }\n\n    # This is cheaper than childCount == 2\n    def hasTwoChildren bool {\n      return hasChildren && _firstChild.nextSibling == _lastChild\n    }\n\n    # This is cheaper than childCount == 3\n    def hasThreeChildren bool {\n      return hasChildren && _firstChild.nextSibling == _lastChild.previousSibling\n    }\n\n    # This is cheaper than childCount == 4\n    def hasFourChildren bool {\n      return hasChildren && _firstChild.nextSibling != null && _firstChild.nextSibling.nextSibling == _lastChild.previousSibling\n    }\n\n    def childCount int {\n      var count = 0\n      for child = _firstChild; child != null; child = child._nextSibling {\n        count++\n      }\n      return count\n    }\n\n    def withFlags(value NodeFlags) Node {\n      flags = value\n      return self\n    }\n\n    def withType(value Type) Node {\n      resolvedType = value\n      return self\n    }\n\n    def withSymbol(value Symbol) Node {\n      symbol = value\n      return self\n    }\n\n    def withContent(value Content) Node {\n      content = value\n      return self\n    }\n\n    def withRange(value Range) Node {\n      range = value\n      return self\n    }\n\n    def withInternalRange(value Range) Node {\n      internalRange = value\n      return self\n    }\n\n    def withComments(value List<Comment>) Node {\n      assert(comments == null)\n      comments = value\n      return self\n    }\n\n    def withInnerComments(value List<Comment>) Node {\n      assert(innerComments == null)\n      innerComments = value\n      return self\n    }\n\n    def internalRangeOrRange Range {\n      return internalRange ?? range\n    }\n\n    def prependChild(node Node) Node {\n      if node == null {\n        return self\n      }\n\n      assert(node != self)\n      assert(node._parent == null)\n      assert(node._previousSibling == null)\n      assert(node._nextSibling == null)\n      node._parent = self\n\n      if hasChildren {\n        node._nextSibling = _firstChild\n        _firstChild._previousSibling = node\n        _firstChild = node\n      } else {\n        _lastChild = _firstChild = node\n      }\n\n      return self\n    }\n\n    def appendChild(node Node) Node {\n      if node == null {\n        return self\n      }\n\n      assert(node != self)\n      assert(node._parent == null)\n      assert(node._previousSibling == null)\n      assert(node._nextSibling == null)\n      node._parent = self\n\n      if hasChildren {\n        node._previousSibling = _lastChild\n        _lastChild._nextSibling = node\n        _lastChild = node\n      } else {\n        _lastChild = _firstChild = node\n      }\n\n      return self\n    }\n\n    def appendChildrenFrom(node Node) Node {\n      assert(node != self)\n      while node.hasChildren {\n        appendChild(node._firstChild.remove)\n      }\n      return self\n    }\n\n    def insertChildBefore(after Node, before Node) Node {\n      if before == null {\n        return self\n      }\n\n      assert(before != after)\n      assert(before._parent == null)\n      assert(before._previousSibling == null)\n      assert(before._nextSibling == null)\n      assert(after == null || after._parent == self)\n\n      if after == null {\n        return appendChild(before)\n      }\n\n      before._parent = self\n      before._previousSibling = after._previousSibling\n      before._nextSibling = after\n\n      if after._previousSibling != null {\n        assert(after == after._previousSibling._nextSibling)\n        after._previousSibling._nextSibling = before\n      } else {\n        assert(after == _firstChild)\n        _firstChild = before\n      }\n\n      after._previousSibling = before\n      return self\n    }\n\n    def insertChildAfter(before Node, after Node) Node {\n      if after == null {\n        return self\n      }\n\n      assert(before != after)\n      assert(after._parent == null)\n      assert(after._previousSibling == null)\n      assert(after._nextSibling == null)\n      assert(before == null || before._parent == self)\n\n      if before == null {\n        return prependChild(after)\n      }\n\n      after._parent = self\n      after._previousSibling = before\n      after._nextSibling = before._nextSibling\n\n      if before._nextSibling != null {\n        assert(before == before._nextSibling._previousSibling)\n        before._nextSibling._previousSibling = after\n      } else {\n        assert(before == _lastChild)\n        _lastChild = after\n      }\n\n      before._nextSibling = after\n      return self\n    }\n\n    def insertChildrenAfterFrom(from Node, after Node) {\n      while from.hasChildren {\n        insertChildAfter(after, from.lastChild.remove)\n      }\n    }\n\n    def remove Node {\n      assert(_parent != null)\n\n      if _previousSibling != null {\n        assert(_previousSibling._nextSibling == self)\n        _previousSibling._nextSibling = _nextSibling\n      } else {\n        assert(_parent._firstChild == self)\n        _parent._firstChild = _nextSibling\n      }\n\n      if _nextSibling != null {\n        assert(_nextSibling._previousSibling == self)\n        _nextSibling._previousSibling = _previousSibling\n      } else {\n        assert(_parent._lastChild == self)\n        _parent._lastChild = _previousSibling\n      }\n\n      _parent = null\n      _previousSibling = null\n      _nextSibling = null\n      return self\n    }\n\n    def removeChildren {\n      while hasChildren {\n        _firstChild.remove\n      }\n    }\n\n    def replaceWith(node Node) Node {\n      assert(node != self)\n      assert(_parent != null)\n      assert(node._parent == null)\n      assert(node._previousSibling == null)\n      assert(node._nextSibling == null)\n\n      node._parent = _parent\n      node._previousSibling = _previousSibling\n      node._nextSibling = _nextSibling\n\n      if _previousSibling != null {\n        assert(_previousSibling._nextSibling == self)\n        _previousSibling._nextSibling = node\n      } else {\n        assert(_parent._firstChild == self)\n        _parent._firstChild = node\n      }\n\n      if _nextSibling != null {\n        assert(_nextSibling._previousSibling == self)\n        _nextSibling._previousSibling = node\n      } else {\n        assert(_parent._lastChild == self)\n        _parent._lastChild = node\n      }\n\n      if _parent.kind == .LAMBDA {\n        assert(self == _parent.symbol.asFunctionSymbol.block)\n        _parent.symbol.asFunctionSymbol.block = node\n      }\n\n      else if _parent.kind == .VARIABLE {\n        assert(self == _parent.symbol.asVariableSymbol.value)\n        _parent.symbol.asVariableSymbol.value = node\n      }\n\n      _parent = null\n      _previousSibling = null\n      _nextSibling = null\n      return self\n    }\n\n    def replaceWithChildrenFrom(node Node) Node {\n      assert(node != self)\n      var parent = _parent\n      while node.hasChildren {\n        parent.insertChildBefore(self, node._firstChild.remove)\n      }\n      return remove\n    }\n\n    def swapWith(node Node) {\n      assert(node != self)\n      assert(_parent != null && _parent == node._parent)\n\n      var parent = _parent\n      var nextSibling = _nextSibling\n\n      if node == _previousSibling {\n        parent.insertChildBefore(node, remove)\n      } else if node == nextSibling {\n        parent.insertChildAfter(node, remove)\n      } else {\n        parent.insertChildBefore(node, remove)\n        parent.insertChildBefore(nextSibling, node.remove)\n      }\n    }\n  }\n\n  namespace Node {\n    def _createID int {\n      return ++_nextID\n    }\n\n    var _nextID = 0\n\n    def _symbolsOrStringsLookTheSame(left Node, right Node) bool {\n      return\n        left.symbol != null && left.symbol == right.symbol ||\n        left.symbol == null && right.symbol == null && left.asString == right.asString\n    }\n\n    def _childrenLookTheSame(left Node, right Node) bool {\n      var leftChild = left.firstChild\n      var rightChild = right.firstChild\n\n      while leftChild != null && rightChild != null {\n        if !_looksTheSame(leftChild, rightChild) {\n          return false\n        }\n\n        leftChild = leftChild.nextSibling\n        rightChild = rightChild.nextSibling\n      }\n\n      return leftChild == null && rightChild == null\n    }\n\n    def _looksTheSame(left Node, right Node) bool {\n      if left.kind == right.kind {\n        switch left.kind {\n          case .NULL { return true }\n          case .NAME { return _symbolsOrStringsLookTheSame(left, right) }\n          case .DOT { return _symbolsOrStringsLookTheSame(left, right) && _looksTheSame(left.dotTarget, right.dotTarget) }\n\n          case .CONSTANT {\n            switch left.content.kind {\n              case .INT { return right.isInt && left.asInt == right.asInt }\n              case .BOOL { return right.isBool && left.asBool == right.asBool }\n              case .DOUBLE { return right.isDouble && left.asDouble == right.asDouble }\n              case .STRING { return right.isString && left.asString == right.asString }\n            }\n          }\n\n          case\n            .BLOCK, .BREAK, .CONTINUE, .EXPRESSION, .IF, .RETURN, .THROW, .WHILE,\n            .ASSIGN_INDEX, .CALL, .HOOK, .INDEX, .INITIALIZER_LIST, .INITIALIZER_MAP, .PAIR, .SEQUENCE,\n            .COMPLEMENT, .NEGATIVE, .NOT, .POSITIVE, .POSTFIX_DECREMENT, .POSTFIX_INCREMENT, .PREFIX_DECREMENT, .PREFIX_INCREMENT {\n            return _childrenLookTheSame(left, right)\n          }\n\n          default {\n            if left.kind.isBinary { return _childrenLookTheSame(left, right) }\n          }\n        }\n      }\n\n      # Null literals are always implicitly casted, so unwrap implicit casts\n      if left.kind == .CAST { return _looksTheSame(left.castValue, right) }\n      if right.kind == .CAST { return _looksTheSame(left, right.castValue) }\n      return false\n    }\n  }\n\n  # Node-specific queries\n  class Node {\n    def isSuperCallStatement bool {\n      return kind == .EXPRESSION && (expressionValue.kind == .SUPER || expressionValue.kind == .CALL && expressionValue.callValue.kind == .SUPER)\n    }\n\n    def isEmptySequence bool {\n      return kind == .SEQUENCE && !hasChildren\n    }\n\n    def isTrue bool {\n      return kind == .CONSTANT && content.kind == .BOOL && content.asBool\n    }\n\n    def isFalse bool {\n      return kind == .CONSTANT && content.kind == .BOOL && !content.asBool\n    }\n\n    def isType bool {\n      return kind == .TYPE || kind == .LAMBDA_TYPE || (kind == .NAME || kind == .DOT || kind == .PARAMETERIZE) && symbol != null && symbol.kind.isType\n    }\n\n    def isAssignTarget bool {\n      return _parent != null && (_parent.kind.isUnaryAssign || _parent.kind.isBinaryAssign && self == _parent.binaryLeft)\n    }\n\n    def isZero bool {\n      return isInt && asInt == 0 || isDouble && asDouble == 0\n    }\n\n    def isNumberLessThanZero bool {\n      return isInt && asInt < 0 || isDouble && asDouble < 0\n    }\n\n    def hasNoSideEffects bool {\n      assert(kind.isExpression)\n      switch kind {\n        case .CONSTANT, .NAME, .NULL, .TYPE { return true }\n        case .CAST { return castValue.hasNoSideEffects }\n        case .HOOK { return hookTest.hasNoSideEffects && hookTrue.hasNoSideEffects && hookFalse.hasNoSideEffects }\n        case .DOT { return dotTarget.hasNoSideEffects }\n        case .COMPLEMENT, .NEGATIVE, .NOT, .POSITIVE, .POSTFIX_DECREMENT, .POSTFIX_INCREMENT, .PREFIX_DECREMENT, .PREFIX_INCREMENT {\n          return !kind.isUnaryAssign && unaryValue.hasNoSideEffects\n        }\n        default {\n          if kind.isBinary { return !kind.isBinaryAssign && binaryLeft.hasNoSideEffects && binaryRight.hasNoSideEffects }\n        }\n      }\n      return false\n    }\n\n    def looksTheSameAs(node Node) bool {\n      return _looksTheSame(self, node)\n    }\n\n    def invertBooleanCondition(cache TypeCache) {\n      assert(kind.isExpression)\n      switch kind {\n        case .CONSTANT {\n          if content.kind == .BOOL {\n            content = BoolContent.new(!content.asBool)\n          }\n          return\n        }\n\n        case .NOT {\n          become(unaryValue.remove)\n          return\n        }\n\n        case .EQUAL {\n          kind = .NOT_EQUAL\n          return\n        }\n\n        case .NOT_EQUAL {\n          kind = .EQUAL\n          return\n        }\n\n        case .LOGICAL_OR {\n          kind = .LOGICAL_AND\n          binaryLeft.invertBooleanCondition(cache)\n          binaryRight.invertBooleanCondition(cache)\n          return\n        }\n\n        case .LOGICAL_AND {\n          kind = .LOGICAL_OR\n          binaryLeft.invertBooleanCondition(cache)\n          binaryRight.invertBooleanCondition(cache)\n          return\n        }\n\n        # Non-equality comparison operators involving floating-point numbers\n        # can't be inverted because one or both of those values may be NAN.\n        # Equality comparisons still work fine because inverting the test\n        # inverts the result as expected:\n        #\n        #   Test        |  Result\n        # --------------+----------\n        #   0 == NAN    |  false\n        #   0 != NAN    |  true\n        #   0 < NAN     |  false\n        #   0 > NAN     |  false\n        #   0 <= NAN    |  false\n        #   0 >= NAN    |  false\n        #   NAN == NAN  |  false\n        #   NAN != NAN  |  true\n        #   NAN < NAN   |  false\n        #   NAN > NAN   |  false\n        #   NAN <= NAN  |  false\n        #   NAN >= NAN  |  false\n        #\n        case .LESS_THAN, .GREATER_THAN, .LESS_THAN_OR_EQUAL, .GREATER_THAN_OR_EQUAL {\n          var commonType = cache.commonImplicitType(binaryLeft.resolvedType, binaryRight.resolvedType)\n          if commonType != null && commonType != cache.doubleType {\n            switch kind {\n              case .LESS_THAN { kind = .GREATER_THAN_OR_EQUAL }\n              case .GREATER_THAN { kind = .LESS_THAN_OR_EQUAL }\n              case .LESS_THAN_OR_EQUAL { kind = .GREATER_THAN }\n              case .GREATER_THAN_OR_EQUAL { kind = .LESS_THAN }\n            }\n            return\n          }\n        }\n\n        case .SEQUENCE {\n          _lastChild.invertBooleanCondition(cache)\n          return\n        }\n      }\n\n      become(createUnary(.NOT, cloneAndStealChildren).withType(cache.boolType))\n    }\n\n    def replaceVariableWith(node Node) Node {\n      assert(kind == .VARIABLE)\n      assert(parent != null)\n      assert(parent.kind == .VARIABLES)\n\n      # \"var x = 0\" becomes \"node\"\n      if _previousSibling == null && _nextSibling == null {\n        parent.replaceWith(node)\n      }\n\n      # \"var x = 0, y = 0\" becomes \"node; var y = 0\"\n      else if _previousSibling == null {\n        parent._parent.insertChildBefore(parent, node)\n      }\n\n      # \"var x = 0, y = 0\" becomes \"var x = 0; node\"\n      else if _nextSibling == null {\n        parent._parent.insertChildAfter(parent, node)\n      }\n\n      # \"var x = 0, y = 0, z = 0\" becomes \"var x = 0; node; var z = 0\"\n      else {\n        var variables = Node.createVariables\n        parent._parent.insertChildAfter(parent, node)\n        parent._parent.insertChildAfter(node, variables)\n        while _nextSibling != null {\n          variables.appendChild(_nextSibling.remove)\n        }\n      }\n\n      return remove\n    }\n\n    # \"a + (b + c)\" => \"(a + b) + c\"\n    def rotateBinaryRightToLeft {\n      assert(kind == binaryRight.kind)\n\n      var left = binaryLeft\n      var right = binaryRight\n      var rightLeft = right.binaryLeft\n      var rightRight = right.binaryRight\n\n      # \"a + (b + c)\" => \"(b + c) + a\"\n      left.swapWith(right)\n\n      # \"a + (b + c)\" => \"(c + b) + a\"\n      rightLeft.swapWith(rightRight)\n\n      # \"a + (b + c)\" => \"(a + c + b)\"\n      right.prependChild(left.remove)\n\n      # \"a + (b + c)\" => \"(a + b) + c\"\n      appendChild(rightRight.remove)\n    }\n\n    # If a variable is inside a variable cluster, break up the variable cluster\n    # into separate clusters so that variable is in a cluster all by itself. That\n    # way the variable can easily be replaced by something else (an assigment,\n    # for example. This does not handle variables inside loop headers.\n    #\n    # \"var a, b, c, d, e\" => c.extractVariableFromVariables => \"var a, b; var c; var d, e\"\n    #\n    def extractVariableFromVariables {\n      assert(kind == .VARIABLE)\n      assert(parent != null && parent.kind == .VARIABLES)\n      assert(parent.parent != null && parent.parent.kind == .BLOCK)\n\n      # Split off variables before this one\n      if previousSibling != null {\n        var variables = Node.createVariables\n        while previousSibling != null {\n          variables.prependChild(previousSibling.remove)\n        }\n        parent.parent.insertChildBefore(parent, variables)\n      }\n\n      # Split off variables after this one\n      if nextSibling != null {\n        var variables = Node.createVariables\n        while nextSibling != null {\n          variables.appendChild(nextSibling.remove)\n        }\n        parent.parent.insertChildAfter(parent, variables)\n      }\n    }\n\n    def sign NodeKind {\n      if kind == .NEGATIVE || kind == .PREFIX_DECREMENT || isNumberLessThanZero { return .NEGATIVE }\n      if kind == .POSITIVE || kind == .PREFIX_INCREMENT { return .POSITIVE }\n      return .NULL\n    }\n  }\n\n  # Factory functions\n  namespace Node {\n    def createAnnotation(value Node, test Node) Node {\n      assert(value.kind.isExpression)\n      assert(test == null || test.kind.isExpression)\n      return new(.ANNOTATION).appendChild(value).appendChild(test)\n    }\n\n    def createBlock Node {\n      return new(.BLOCK)\n    }\n\n    def createCase Node {\n      return new(.CASE)\n    }\n\n    def createCatch(symbol VariableSymbol, block Node) Node {\n      assert(block.kind == .BLOCK)\n      return new(.CATCH).appendChild(block).withSymbol(symbol)\n    }\n\n    # This adds the initializer expression to the tree for ease of traversal\n    def createVariable(symbol VariableSymbol) Node {\n      return new(.VARIABLE).appendChild(symbol.value).withSymbol(symbol)\n    }\n\n    def createBreak Node {\n      return new(.BREAK)\n    }\n\n    def createCommentBlock Node {\n      return new(.COMMENT_BLOCK)\n    }\n\n    def createContinue Node {\n      return new(.CONTINUE)\n    }\n\n    def createExpression(value Node) Node {\n      assert(value.kind.isExpression)\n      return new(.EXPRESSION).appendChild(value)\n    }\n\n    def createFor(setup Node, test Node, update Node, block Node) Node {\n      assert(setup.kind.isExpression || setup.kind == .VARIABLES)\n      assert(test.kind.isExpression)\n      assert(update.kind.isExpression)\n      assert(block.kind == .BLOCK)\n      return new(.FOR).appendChild(setup).appendChild(test).appendChild(update).appendChild(block)\n    }\n\n    def createForeach(symbol VariableSymbol, value Node, block Node) Node {\n      assert(value.kind.isExpression)\n      assert(block.kind == .BLOCK)\n      return new(.FOREACH).withSymbol(symbol).appendChild(value).appendChild(block)\n    }\n\n    def createIf(test Node, trueBlock Node, falseBlock Node) Node {\n      assert(test.kind.isExpression)\n      assert(trueBlock.kind == .BLOCK)\n      assert(falseBlock == null || falseBlock.kind == .BLOCK)\n      return new(.IF).appendChild(test).appendChild(trueBlock).appendChild(falseBlock)\n    }\n\n    def createReturn(value Node) Node {\n      assert(value == null || value.kind.isExpression)\n      return new(.RETURN).appendChild(value)\n    }\n\n    def createSwitch(value Node) Node {\n      assert(value.kind.isExpression)\n      return new(.SWITCH).appendChild(value)\n    }\n\n    def createThrow(value Node) Node {\n      assert(value.kind.isExpression)\n      return new(.THROW).appendChild(value)\n    }\n\n    def createTry(tryBlock Node) Node {\n      assert(tryBlock.kind == .BLOCK)\n      return new(.TRY).appendChild(tryBlock)\n    }\n\n    def createVariables Node {\n      return new(.VARIABLES)\n    }\n\n    def createWhile(test Node, block Node) Node {\n      return new(.WHILE).appendChild(test).appendChild(block)\n    }\n\n    def createAssignIndex(left Node, center Node, right Node) Node {\n      assert(left.kind.isExpression)\n      assert(center.kind.isExpression)\n      assert(right.kind.isExpression)\n      return new(.ASSIGN_INDEX).appendChild(left).appendChild(center).appendChild(right)\n    }\n\n    def createIndex(left Node, right Node) Node {\n      assert(left.kind.isExpression)\n      assert(right.kind.isExpression)\n      return new(.INDEX).appendChild(left).appendChild(right)\n    }\n\n    def createCall(target Node) Node {\n      assert(target.kind.isExpression)\n      return new(.CALL).appendChild(target)\n    }\n\n    def createCast(value Node, type Node) Node {\n      assert(value.kind.isExpression)\n      assert(type.kind.isExpression)\n      return new(.CAST).appendChild(value).appendChild(type)\n    }\n\n    def createBool(value bool) Node {\n      return createConstant(BoolContent.new(value))\n    }\n\n    def createInt(value int) Node {\n      return createConstant(IntContent.new(value))\n    }\n\n    def createDouble(value double) Node {\n      return createConstant(DoubleContent.new(value))\n    }\n\n    def createString(value string) Node {\n      return createConstant(StringContent.new(value))\n    }\n\n    def createConstant(value Content) Node {\n      return new(.CONSTANT).withContent(value)\n    }\n\n    def createDot(target Node, name string) Node {\n      return new(.DOT).withContent(StringContent.new(name)).appendChild(target)\n    }\n\n    def createHook(test Node, trueValue Node, falseValue Node) Node {\n      assert(test.kind.isExpression)\n      assert(trueValue.kind.isExpression)\n      assert(falseValue.kind.isExpression)\n      return new(.HOOK).appendChild(test).appendChild(trueValue).appendChild(falseValue)\n    }\n\n    def createList Node {\n      return new(.INITIALIZER_LIST)\n    }\n\n    def createInitializer(kind NodeKind) Node {\n      assert(kind.isInitializer)\n      return new(kind)\n    }\n\n    # This adds the block to the tree for ease of traversal\n    def createLambda(symbol FunctionSymbol) Node {\n      return new(.LAMBDA).appendChild(symbol.block).withSymbol(symbol)\n    }\n\n    def createName(text string) Node {\n      return new(.NAME).withContent(StringContent.new(text))\n    }\n\n    def createNull Node {\n      return new(.NULL)\n    }\n\n    def createNullDot(target Node, name string) Node {\n      return new(.NULL_DOT).withContent(StringContent.new(name)).appendChild(target)\n    }\n\n    def createPair(first Node, second Node) Node {\n      assert(first.kind.isExpression)\n      assert(second.kind.isExpression)\n      return new(.PAIR).appendChild(first).appendChild(second)\n    }\n\n    def createParameterize(value Node) Node {\n      assert(value.kind.isExpression)\n      return new(.PARAMETERIZE).appendChild(value)\n    }\n\n    def createParseError Node {\n      return new(.PARSE_ERROR)\n    }\n\n    def createSequence Node {\n      return new(.SEQUENCE)\n    }\n\n    def createSequence(before Node, after Node) Node {\n      assert(before.kind.isExpression)\n      assert(after.kind.isExpression)\n      assert(before.parent == null)\n      assert(after.parent == null)\n\n      if before.kind == .SEQUENCE {\n        if after.kind == .SEQUENCE {\n          return before.withType(after.resolvedType).appendChildrenFrom(after)\n        }\n        return before.withType(after.resolvedType).appendChild(after)\n      }\n      if after.kind == .SEQUENCE {\n        return after.prependChild(before)\n      }\n      return createSequence.withType(after.resolvedType).appendChild(before).appendChild(after)\n    }\n\n    def createStringInterpolation Node {\n      return new(.STRING_INTERPOLATION)\n    }\n\n    def createSuper Node {\n      return new(.SUPER)\n    }\n\n    def createType(type Type) Node {\n      return new(.TYPE).withType(type)\n    }\n\n    def createTypeCheck(value Node, type Node) Node {\n      assert(value.kind.isExpression)\n      assert(type.kind.isExpression)\n      return new(.TYPE_CHECK).appendChild(value).appendChild(type)\n    }\n\n    def createXML(tag Node, attributes Node, children Node, closingTag Node) Node {\n      assert(tag.kind.isExpression)\n      assert(attributes.kind == .SEQUENCE)\n      assert(children.kind == .BLOCK)\n      assert(closingTag == null || closingTag.kind.isExpression)\n      return new(.XML).appendChild(tag).appendChild(attributes).appendChild(children).appendChild(closingTag)\n    }\n\n    def createUnary(kind NodeKind, value Node) Node {\n      assert(kind.isUnary)\n      assert(value.kind.isExpression)\n      return new(kind).appendChild(value)\n    }\n\n    def createBinary(kind NodeKind, left Node, right Node) Node {\n      assert(kind.isBinary)\n      assert(left.kind.isExpression)\n      assert(right.kind.isExpression)\n      return new(kind).appendChild(left).appendChild(right)\n    }\n\n    def createLambdaType Node {\n      return new(.LAMBDA_TYPE).appendChild(createType(.NULL))\n    }\n\n    def createSymbolReference(symbol Symbol) Node {\n      return createName(symbol.name).withSymbol(symbol).withType(symbol.resolvedType)\n    }\n\n    def createMemberReference(target Node, member Symbol) Node {\n      return createDot(target, member.name).withSymbol(member).withType(member.resolvedType)\n    }\n\n    def createSymbolCall(symbol Symbol) Node {\n      return createCall(createSymbolReference(symbol)).withSymbol(symbol).withType(symbol.resolvedType.returnType)\n    }\n  }\n\n  # Getters, most of which should be inlineable when asserts are skipped in release\n  class Node {\n    def isInt bool {\n      return kind == .CONSTANT && content.kind == .INT\n    }\n\n    def isBool bool {\n      return kind == .CONSTANT && content.kind == .BOOL\n    }\n\n    def isDouble bool {\n      return kind == .CONSTANT && content.kind == .DOUBLE\n    }\n\n    def isString bool {\n      return kind == .CONSTANT && content.kind == .STRING\n    }\n\n    def asInt int {\n      assert(kind == .CONSTANT)\n      return content.asInt\n    }\n\n    def asBool bool {\n      assert(kind == .CONSTANT)\n      return content.asBool\n    }\n\n    def asDouble double {\n      assert(kind == .CONSTANT)\n      return content.asDouble\n    }\n\n    def asString string {\n      assert(kind == .NAME || kind == .DOT || kind == .CONSTANT || kind == .NULL_DOT)\n      return content.asString\n    }\n\n    def blockStatement Node {\n      assert(kind == .BLOCK)\n      return hasOneChild ? _firstChild : null\n    }\n\n    def firstValue Node {\n      assert(kind == .PAIR)\n      assert(childCount == 2)\n      assert(_firstChild.kind.isExpression)\n      return _firstChild\n    }\n\n    def secondValue Node {\n      assert(kind == .PAIR)\n      assert(childCount == 2)\n      assert(_lastChild.kind.isExpression)\n      return _lastChild\n    }\n\n    def dotTarget Node {\n      assert(kind == .DOT || kind == .NULL_DOT)\n      assert(childCount <= 1)\n      assert(_firstChild == null || _firstChild.kind.isExpression)\n      return _firstChild\n    }\n\n    def annotationValue Node {\n      assert(kind == .ANNOTATION)\n      assert(childCount == 1 || childCount == 2)\n      assert(_firstChild.kind.isExpression)\n      return _firstChild\n    }\n\n    def annotationTest Node {\n      assert(kind == .ANNOTATION)\n      assert(childCount == 1 || childCount == 2)\n      assert(_firstChild._nextSibling == null || _firstChild._nextSibling.kind.isExpression)\n      return _firstChild._nextSibling\n    }\n\n    def caseBlock Node {\n      assert(kind == .CASE)\n      assert(childCount >= 1)\n      assert(_lastChild.kind == .BLOCK)\n      return _lastChild\n    }\n\n    def catchBlock Node {\n      assert(kind == .CATCH)\n      assert(childCount == 1)\n      assert(_firstChild.kind == .BLOCK)\n      return _firstChild\n    }\n\n    def variableValue Node {\n      assert(kind == .VARIABLE)\n      assert(childCount <= 1)\n      assert(_firstChild == null || _firstChild.kind.isExpression)\n      return _firstChild\n    }\n\n    def expressionValue Node {\n      assert(kind == .EXPRESSION)\n      assert(childCount == 1)\n      assert(_firstChild.kind.isExpression)\n      return _firstChild\n    }\n\n    def returnValue Node {\n      assert(kind == .RETURN)\n      assert(childCount <= 1)\n      assert(_firstChild == null || _firstChild.kind.isExpression)\n      return _firstChild\n    }\n\n    def switchValue Node {\n      assert(kind == .SWITCH)\n      assert(childCount >= 1)\n      assert(_firstChild.kind.isExpression)\n      return _firstChild\n    }\n\n    def defaultCase Node {\n      assert(kind == .SWITCH)\n      assert(childCount >= 1)\n      return !hasOneChild && _lastChild.hasOneChild ? _lastChild : null # The default case is always the last one\n    }\n\n    def parameterizeValue Node {\n      assert(kind == .PARAMETERIZE)\n      assert(childCount >= 1)\n      assert(_firstChild.kind.isExpression)\n      return _firstChild\n    }\n\n    def callValue Node {\n      assert(kind == .CALL)\n      assert(childCount >= 1)\n      assert(_firstChild.kind.isExpression)\n      return _firstChild\n    }\n\n    def castValue Node {\n      assert(kind == .CAST)\n      assert(childCount == 2)\n      assert(_firstChild.kind.isExpression)\n      return _firstChild\n    }\n\n    def castType Node {\n      assert(kind == .CAST)\n      assert(childCount == 2)\n      assert(_lastChild.kind.isExpression)\n      return _lastChild\n    }\n\n    def typeCheckValue Node {\n      assert(kind == .TYPE_CHECK)\n      assert(childCount == 2)\n      assert(_firstChild.kind.isExpression)\n      return _firstChild\n    }\n\n    def typeCheckType Node {\n      assert(kind == .TYPE_CHECK)\n      assert(childCount == 2)\n      assert(_lastChild.kind.isExpression)\n      return _lastChild\n    }\n\n    def xmlTag Node {\n      assert(kind == .XML)\n      assert(childCount == 3 || childCount == 4)\n      assert(_firstChild.kind.isExpression)\n      return _firstChild\n    }\n\n    def xmlAttributes Node {\n      assert(kind == .XML)\n      assert(childCount == 3 || childCount == 4)\n      assert(_firstChild._nextSibling.kind == .SEQUENCE)\n      return _firstChild._nextSibling\n    }\n\n    def xmlChildren Node {\n      assert(kind == .XML)\n      assert(childCount == 3 || childCount == 4)\n      assert(_firstChild._nextSibling._nextSibling.kind == .BLOCK)\n      return _firstChild._nextSibling._nextSibling\n    }\n\n    def xmlClosingTag Node {\n      assert(kind == .XML)\n      assert(childCount == 3 || childCount == 4)\n      assert(\n        _firstChild._nextSibling._nextSibling._nextSibling == null ||\n        _firstChild._nextSibling._nextSibling._nextSibling.kind.isExpression)\n      return _firstChild._nextSibling._nextSibling._nextSibling\n    }\n\n    def unaryValue Node {\n      assert(kind.isUnary)\n      assert(childCount == 1)\n      assert(_firstChild.kind.isExpression)\n      return _firstChild\n    }\n\n    def binaryLeft Node {\n      assert(kind.isBinary)\n      assert(childCount == 2)\n      assert(_firstChild.kind.isExpression)\n      return _firstChild\n    }\n\n    def binaryRight Node {\n      assert(kind.isBinary)\n      assert(childCount == 2)\n      assert(_lastChild.kind.isExpression)\n      return _lastChild\n    }\n\n    def throwValue Node {\n      assert(childCount == 1)\n      assert(_firstChild.kind.isExpression)\n      return _firstChild\n    }\n\n    def tryBlock Node {\n      assert(kind == .TRY)\n      assert(childCount >= 1)\n      assert(_firstChild.kind == .BLOCK)\n      return _firstChild\n    }\n\n    def finallyBlock Node {\n      assert(kind == .TRY)\n      assert(childCount >= 1)\n      var finallyBlock = _lastChild\n      return finallyBlock != tryBlock && finallyBlock.kind == .BLOCK ? finallyBlock : null\n    }\n\n    def whileTest Node {\n      assert(kind == .WHILE)\n      assert(childCount == 2)\n      assert(_firstChild.kind.isExpression)\n      return _firstChild\n    }\n\n    def whileBlock Node {\n      assert(kind == .WHILE)\n      assert(childCount == 2)\n      assert(_lastChild.kind == .BLOCK)\n      return _lastChild\n    }\n\n    def forSetup Node {\n      assert(kind == .FOR)\n      assert(childCount == 4)\n      assert(_firstChild.kind.isExpression || _firstChild.kind == .VARIABLES)\n      return _firstChild\n    }\n\n    def forTest Node {\n      assert(kind == .FOR)\n      assert(childCount == 4)\n      assert(_firstChild._nextSibling.kind.isExpression)\n      return _firstChild._nextSibling\n    }\n\n    def forUpdate Node {\n      assert(kind == .FOR)\n      assert(childCount == 4)\n      assert(_lastChild._previousSibling.kind.isExpression)\n      return _lastChild._previousSibling\n    }\n\n    def forBlock Node {\n      assert(kind == .FOR)\n      assert(childCount == 4)\n      assert(_lastChild.kind == .BLOCK)\n      return _lastChild\n    }\n\n    def foreachValue Node {\n      assert(kind == .FOREACH)\n      assert(childCount == 2)\n      assert(_firstChild.kind.isExpression)\n      return _firstChild\n    }\n\n    def foreachBlock Node {\n      assert(kind == .FOREACH)\n      assert(childCount == 2)\n      assert(_lastChild.kind == .BLOCK)\n      return _lastChild\n    }\n\n    def ifTest Node {\n      assert(kind == .IF)\n      assert(childCount == 2 || childCount == 3)\n      assert(_firstChild.kind.isExpression)\n      return _firstChild\n    }\n\n    def ifTrue Node {\n      assert(kind == .IF)\n      assert(childCount == 2 || childCount == 3)\n      assert(_firstChild._nextSibling.kind == .BLOCK)\n      return _firstChild._nextSibling\n    }\n\n    def ifFalse Node {\n      assert(kind == .IF)\n      assert(childCount == 2 || childCount == 3)\n      assert(_firstChild._nextSibling._nextSibling == null || _firstChild._nextSibling._nextSibling.kind == .BLOCK)\n      return _firstChild._nextSibling._nextSibling\n    }\n\n    def hookTest Node {\n      assert(kind == .HOOK)\n      assert(childCount == 3)\n      assert(_firstChild.kind.isExpression)\n      return _firstChild\n    }\n\n    def hookTrue Node {\n      assert(kind == .HOOK)\n      assert(childCount == 3)\n      assert(_firstChild._nextSibling.kind.isExpression)\n      return _firstChild._nextSibling\n    }\n\n    def hookFalse Node {\n      assert(kind == .HOOK)\n      assert(childCount == 3)\n      assert(_lastChild.kind.isExpression)\n      return _lastChild\n    }\n\n    def indexLeft Node {\n      assert(kind == .INDEX)\n      assert(childCount == 2)\n      assert(_firstChild.kind.isExpression)\n      return _firstChild\n    }\n\n    def indexRight Node {\n      assert(kind == .INDEX)\n      assert(childCount == 2)\n      assert(_firstChild._nextSibling.kind.isExpression)\n      return _firstChild._nextSibling\n    }\n\n    def assignIndexLeft Node {\n      assert(kind == .ASSIGN_INDEX)\n      assert(childCount == 3)\n      assert(_firstChild.kind.isExpression)\n      return _firstChild\n    }\n\n    def assignIndexCenter Node {\n      assert(kind == .ASSIGN_INDEX)\n      assert(childCount == 3)\n      assert(_firstChild._nextSibling.kind.isExpression)\n      return _firstChild._nextSibling\n    }\n\n    def assignIndexRight Node {\n      assert(kind == .ASSIGN_INDEX)\n      assert(childCount == 3)\n      assert(_lastChild.kind.isExpression)\n      return _lastChild\n    }\n\n    def lambdaBlock Node {\n      assert(kind == .LAMBDA)\n      assert(childCount == 1)\n      assert(_firstChild.kind == .BLOCK)\n      return _firstChild\n    }\n\n    def lambdaReturnType Node {\n      assert(kind == .LAMBDA_TYPE)\n      assert(childCount >= 1)\n      assert(_lastChild.kind.isExpression)\n      return _lastChild\n    }\n  }\n}\n"
  },
  {
    "path": "src/core/operators.sk",
    "content": "namespace Skew {\n  class OperatorInfo {\n    const text string\n    const precedence Precedence\n    const associativity Associativity\n    const kind OperatorKind\n    const validArgumentCounts List<int>\n    const assignKind NodeKind\n  }\n\n  enum OperatorKind {\n    FIXED\n    OVERRIDABLE\n  }\n\n  var operatorInfo = {\n    # Unary operators\n    NodeKind.COMPLEMENT:                  OperatorInfo.new(\"~\", .UNARY_PREFIX, .NONE, .OVERRIDABLE, [0], .NULL),\n    NodeKind.NEGATIVE:                    OperatorInfo.new(\"-\", .UNARY_PREFIX, .NONE, .OVERRIDABLE, [0, 1], .NULL),\n    NodeKind.NOT:                         OperatorInfo.new(\"!\", .UNARY_PREFIX, .NONE, .OVERRIDABLE, [0], .NULL),\n    NodeKind.POSITIVE:                    OperatorInfo.new(\"+\", .UNARY_PREFIX, .NONE, .OVERRIDABLE, [0, 1], .NULL),\n    NodeKind.POSTFIX_DECREMENT:           OperatorInfo.new(\"--\", .UNARY_POSTFIX, .NONE, .OVERRIDABLE, [0], .SUBTRACT),\n    NodeKind.POSTFIX_INCREMENT:           OperatorInfo.new(\"++\", .UNARY_POSTFIX, .NONE, .OVERRIDABLE, [0], .ADD),\n    NodeKind.PREFIX_DECREMENT:            OperatorInfo.new(\"--\", .UNARY_PREFIX, .NONE, .OVERRIDABLE, [0], .SUBTRACT),\n    NodeKind.PREFIX_INCREMENT:            OperatorInfo.new(\"++\", .UNARY_PREFIX, .NONE, .OVERRIDABLE, [0], .ADD),\n\n    # Binary operators\n    NodeKind.ADD:                         OperatorInfo.new(\"+\", .ADD, .LEFT, .OVERRIDABLE, [0, 1], .NULL),\n    NodeKind.BITWISE_AND:                 OperatorInfo.new(\"&\", .BITWISE_AND, .LEFT, .OVERRIDABLE, [1], .NULL),\n    NodeKind.BITWISE_OR:                  OperatorInfo.new(\"|\", .BITWISE_OR, .LEFT, .OVERRIDABLE, [1], .NULL),\n    NodeKind.BITWISE_XOR:                 OperatorInfo.new(\"^\", .BITWISE_XOR, .LEFT, .OVERRIDABLE, [1], .NULL),\n    NodeKind.COMPARE:                     OperatorInfo.new(\"<=>\", .COMPARE, .LEFT, .OVERRIDABLE, [1], .NULL),\n    NodeKind.DIVIDE:                      OperatorInfo.new(\"/\", .MULTIPLY, .LEFT, .OVERRIDABLE, [1], .NULL),\n    NodeKind.EQUAL:                       OperatorInfo.new(\"==\", .EQUAL, .LEFT, .FIXED, [1], .NULL),\n    NodeKind.GREATER_THAN:                OperatorInfo.new(\">\", .COMPARE, .LEFT, .OVERRIDABLE, [1], .NULL),\n    NodeKind.GREATER_THAN_OR_EQUAL:       OperatorInfo.new(\">=\", .COMPARE, .LEFT, .OVERRIDABLE, [1], .NULL),\n    NodeKind.IN:                          OperatorInfo.new(\"in\", .COMPARE, .LEFT, .OVERRIDABLE, [1], .NULL),\n    NodeKind.LESS_THAN:                   OperatorInfo.new(\"<\", .COMPARE, .LEFT, .OVERRIDABLE, [1], .NULL),\n    NodeKind.LESS_THAN_OR_EQUAL:          OperatorInfo.new(\"<=\", .COMPARE, .LEFT, .OVERRIDABLE, [1], .NULL),\n    NodeKind.LOGICAL_AND:                 OperatorInfo.new(\"&&\", .LOGICAL_AND, .LEFT, .FIXED, [1], .NULL),\n    NodeKind.LOGICAL_OR:                  OperatorInfo.new(\"||\", .LOGICAL_OR, .LEFT, .FIXED, [1], .NULL),\n    NodeKind.MODULUS:                     OperatorInfo.new(\"%%\", .MULTIPLY, .LEFT, .OVERRIDABLE, [1], .NULL),\n    NodeKind.MULTIPLY:                    OperatorInfo.new(\"*\", .MULTIPLY, .LEFT, .OVERRIDABLE, [1], .NULL),\n    NodeKind.NOT_EQUAL:                   OperatorInfo.new(\"!=\", .EQUAL, .LEFT, .FIXED, [1], .NULL),\n    NodeKind.POWER:                       OperatorInfo.new(\"**\", .UNARY_PREFIX, .RIGHT, .OVERRIDABLE, [1], .NULL),\n    NodeKind.REMAINDER:                   OperatorInfo.new(\"%\", .MULTIPLY, .LEFT, .OVERRIDABLE, [1], .NULL),\n    NodeKind.SHIFT_LEFT:                  OperatorInfo.new(\"<<\", .SHIFT, .LEFT, .OVERRIDABLE, [1], .NULL),\n    NodeKind.SHIFT_RIGHT:                 OperatorInfo.new(\">>\", .SHIFT, .LEFT, .OVERRIDABLE, [1], .NULL),\n    NodeKind.SUBTRACT:                    OperatorInfo.new(\"-\", .ADD, .LEFT, .OVERRIDABLE, [0, 1], .NULL),\n    NodeKind.UNSIGNED_SHIFT_RIGHT:        OperatorInfo.new(\">>>\", .SHIFT, .LEFT, .OVERRIDABLE, [1], .NULL),\n\n    # Binary assignment operators\n    NodeKind.ASSIGN:                      OperatorInfo.new(\"=\", .ASSIGN, .RIGHT, .FIXED, [1], .NULL),\n    NodeKind.ASSIGN_ADD:                  OperatorInfo.new(\"+=\", .ASSIGN, .RIGHT, .OVERRIDABLE, [1], .ADD),\n    NodeKind.ASSIGN_BITWISE_AND:          OperatorInfo.new(\"&=\", .ASSIGN, .RIGHT, .OVERRIDABLE, [1], .BITWISE_AND),\n    NodeKind.ASSIGN_BITWISE_OR:           OperatorInfo.new(\"|=\", .ASSIGN, .RIGHT, .OVERRIDABLE, [1], .BITWISE_OR),\n    NodeKind.ASSIGN_BITWISE_XOR:          OperatorInfo.new(\"^=\", .ASSIGN, .RIGHT, .OVERRIDABLE, [1], .BITWISE_XOR),\n    NodeKind.ASSIGN_DIVIDE:               OperatorInfo.new(\"/=\", .ASSIGN, .RIGHT, .OVERRIDABLE, [1], .DIVIDE),\n    NodeKind.ASSIGN_MODULUS:              OperatorInfo.new(\"%%=\", .ASSIGN, .RIGHT, .OVERRIDABLE, [1], .MODULUS),\n    NodeKind.ASSIGN_MULTIPLY:             OperatorInfo.new(\"*=\", .ASSIGN, .RIGHT, .OVERRIDABLE, [1], .MULTIPLY),\n    NodeKind.ASSIGN_POWER:                OperatorInfo.new(\"**=\", .ASSIGN, .RIGHT, .OVERRIDABLE, [1], .POWER),\n    NodeKind.ASSIGN_REMAINDER:            OperatorInfo.new(\"%=\", .ASSIGN, .RIGHT, .OVERRIDABLE, [1], .REMAINDER),\n    NodeKind.ASSIGN_SHIFT_LEFT:           OperatorInfo.new(\"<<=\", .ASSIGN, .RIGHT, .OVERRIDABLE, [1], .SHIFT_LEFT),\n    NodeKind.ASSIGN_SHIFT_RIGHT:          OperatorInfo.new(\">>=\", .ASSIGN, .RIGHT, .OVERRIDABLE, [1], .SHIFT_RIGHT),\n    NodeKind.ASSIGN_SUBTRACT:             OperatorInfo.new(\"-=\", .ASSIGN, .RIGHT, .OVERRIDABLE, [1], .SUBTRACT),\n    NodeKind.ASSIGN_UNSIGNED_SHIFT_RIGHT: OperatorInfo.new(\">>>=\", .ASSIGN, .RIGHT, .OVERRIDABLE, [1], .UNSIGNED_SHIFT_RIGHT),\n\n    # Index operators\n    NodeKind.ASSIGN_INDEX:                OperatorInfo.new(\"[]=\", .MEMBER, .NONE, .OVERRIDABLE, [2], .NULL),\n    NodeKind.INDEX:                       OperatorInfo.new(\"[]\", .MEMBER, .NONE, .OVERRIDABLE, [1], .NULL),\n  }\n\n  var validArgumentCounts StringMap<List<int>> = null\n\n  def argumentCountForOperator(text string) List<int> {\n    if validArgumentCounts == null {\n      validArgumentCounts = {}\n      for value in operatorInfo.values {\n        validArgumentCounts[value.text] = value.validArgumentCounts\n      }\n      validArgumentCounts[\"<>...</>\"] = [1]\n      validArgumentCounts[\"[...]\"] = [1]\n      validArgumentCounts[\"[new]\"] = [0, 1]\n      validArgumentCounts[\"{...}\"] = [2]\n      validArgumentCounts[\"{new}\"] = [0, 2]\n    }\n    return validArgumentCounts.get(text, null)\n  }\n}\n"
  },
  {
    "path": "src/core/support.sk",
    "content": "namespace Skew {\n  const SORT_STRINGS = (a string, b string) => a <=> b\n\n  def hashCombine(left int, right int) int {\n    return left ^ right - 0x61c88647 + (left << 6) + (left >> 2)\n  }\n\n  class UnionFind {\n    var parents List<int> = []\n\n    def allocate int {\n      var index = parents.count\n      parents.append(index)\n      return index\n    }\n\n    def allocate(count int) UnionFind {\n      for i in 0..count {\n        parents.append(parents.count)\n      }\n      return self\n    }\n\n    def union(left int, right int) {\n      parents[find(left)] = find(right)\n    }\n\n    def find(index int) int {\n      assert(index >= 0 && index < parents.count)\n      var parent = parents[index]\n      if parent != index {\n        parent = find(parent)\n        parents[index] = parent\n      }\n      return parent\n    }\n  }\n\n  class SplitPath {\n    const directory string\n    const entry string\n  }\n\n  def splitPath(path string) SplitPath {\n    var slashIndex = Math.max(path.lastIndexOf(\"/\"), path.lastIndexOf(\"\\\\\"))\n    return slashIndex == -1\n      ? SplitPath.new(\".\", path)\n      : SplitPath.new(path.slice(0, slashIndex), path.slice(slashIndex + 1))\n  }\n\n  def withUppercaseFirstLetter(text string) string {\n    return text == \"\" ? text : text.get(0).toUpperCase + text.slice(1)\n  }\n\n  def indentIndex(text string) int {\n    var i = 0\n    while i < text.count && (text[i] == ' ' || text[i] == '\\t') {\n      i++\n    }\n    return i\n  }\n\n  def indentOfLine(line string) string {\n    return line.slice(0, indentIndex(line))\n  }\n\n  def lineWithoutIndent(line string) string {\n    return line.slice(indentIndex(line))\n  }\n\n  def formatNumber(number double) string {\n    return (Math.round(number * 10) / 10).toString\n  }\n\n  def bytesToString(bytes int) string {\n    const KB = 1 << 10\n    const MB = 1 << 20\n    const GB = 1 << 30\n    if bytes == 1 { return \"1 byte\" }\n    if bytes < KB { return \"\\(bytes) bytes\" }\n    if bytes < MB { return \"\\(formatNumber(bytes / (KB as double)))kb\" }\n    if bytes < GB { return \"\\(formatNumber(bytes / (MB as double)))mb\" }\n    return \"\\(formatNumber(bytes / (GB as double)))gb\"\n  }\n\n  def doubleToStringWithDot(value double) string {\n    assert(value.isFinite) # These cases are different for each language target and must be handled before this\n    var text = value.toString\n\n    # The C# implementation of double.ToString() uses an uppercase \"E\"\n    if TARGET == .CSHARP {\n      text = text.toLowerCase\n    }\n\n    # \"1\" => \"1.0\"\n    # \"1.5\" => \"1.5\"\n    # \"1e+100\" => \"1.0e+100\"\n    # \"1.5e+100\" => \"1.5e+100\"\n    if !(\".\" in text) {\n      var e = text.indexOf(\"e\")\n      if e != -1 {\n        text = text.slice(0, e) + \".0\" + text.slice(e)\n      } else {\n        text += \".0\"\n      }\n    }\n\n    return text\n  }\n\n  # The cost of changing the case of a letter is 0.5 instead of 1\n  def caseAwareLevenshteinEditDistance(a string, b string) double {\n    var an = a.count\n    var bn = b.count\n\n    var v0 List<double> = []\n    var v1 List<double> = []\n\n    for i in 0..bn + 1 {\n      v0.append(i)\n      v1.append(i)\n    }\n\n    for i in 0..an {\n      var ca = a[i]\n      v1[0] = i + 1\n\n      for j in 0..bn {\n        var cb = b[j]\n        v1[j + 1] = Math.min(\n          v0[j] + (ca == cb ? 0 : toLowerCase(ca) == toLowerCase(cb) ? 0.5 : 1),\n          Math.min(v1[j], v0[j + 1]) + 1)\n      }\n\n      for j in 0..bn + 1 {\n        v0[j] = v1[j]\n      }\n    }\n\n    return v1[bn]\n  }\n\n  def toLowerCase(c int) int {\n    return c >= 'A' && c <= 'Z' ? 'a' - 'A' + c : c\n  }\n\n  def replaceSingleQuotesWithDoubleQuotes(text string) string {\n    assert(text.startsWith(\"'\"))\n    assert(text.endsWith(\"'\"))\n\n    var builder = StringBuilder.new\n    var start = 1\n    var limit = text.count - 1\n\n    builder.append(\"\\\"\")\n\n    for i = start; i < limit; i++ {\n      var c = text[i]\n\n      if c == '\\\"' {\n        builder.append(text.slice(start, i))\n        builder.append(\"\\\\\\\"\")\n        start = i + 1\n      }\n\n      else if c == '\\\\' {\n        if text[i + 1] == '\\'' {\n          builder.append(text.slice(start, i))\n          builder.append(\"'\")\n          start = i + 2\n        }\n        i++\n      }\n    }\n\n    builder.append(text.slice(start, limit))\n    builder.append(\"\\\"\")\n\n    return builder.toString\n  }\n}\n\nnamespace Skew.PrettyPrint {\n  def plural(value int, word string) string {\n    return \"\\(value) \\(word)\\(plural(value))\"\n  }\n\n  def plural(value int) string {\n    return value == 1 ? \"\" : \"s\"\n  }\n\n  def joinQuoted(parts List<string>, trailing string) string {\n    return join(parts.map<string>(part => \"\\\"\\(part)\\\"\"), trailing)\n  }\n\n  def join(parts List<string>, trailing string) string {\n    if parts.count < 3 {\n      return \" \\(trailing) \".join(parts)\n    }\n    var text = \"\"\n    for i in 0..parts.count {\n      if i != 0 {\n        text += \", \"\n        if i + 1 == parts.count {\n          text += trailing + \" \"\n        }\n      }\n      text += parts[i]\n    }\n    return text\n  }\n\n  def wrapWords(text string, width int) List<string> {\n    # An invalid length means wrapping is disabled\n    if width < 1 {\n      return [text]\n    }\n\n    var words = text.split(\" \")\n    var lines List<string> = []\n    var line = \"\"\n\n    # Run the word wrapping algorithm\n    var i = 0\n    while i < words.count {\n      var word = words[i]\n      var lineLength = line.count\n      var wordLength = word.count\n      var estimatedLength = lineLength + 1 + wordLength\n      i++\n\n      # Collapse adjacent spaces\n      if word == \"\" {\n        continue\n      }\n\n      # Start the line\n      if line == \"\" {\n        while word.count > width {\n          lines.append(word.slice(0, width))\n          word = word.slice(width, word.count)\n        }\n        line = word\n      }\n\n      # Continue line\n      else if estimatedLength < width {\n        line += \" \" + word\n      }\n\n      # Continue and wrap\n      else if estimatedLength == width {\n        lines.append(line + \" \" + word)\n        line = \"\"\n      }\n\n      # Wrap and try again\n      else {\n        lines.append(line)\n        line = \"\"\n        i--\n      }\n    }\n\n    # Don't add an empty trailing line unless there are no other lines\n    if line != \"\" || lines.isEmpty {\n      lines.append(line)\n    }\n\n    return lines\n  }\n}\n\n# Language-specific stuff\n\nif TARGET == .JAVASCRIPT {\n  def parseDoubleLiteral(text string) double {\n    return +(text as dynamic)\n  }\n}\n\nelse if TARGET == .CSHARP {\n  def parseDoubleLiteral(text string) double {\n    return dynamic.double.Parse(text)\n  }\n}\n\nelse {\n  @import\n  def parseDoubleLiteral(text string) double\n}\n"
  },
  {
    "path": "src/core/symbol.sk",
    "content": "namespace Skew {\n  enum SymbolKind {\n    PARAMETER_FUNCTION\n    PARAMETER_OBJECT\n\n    OBJECT_CLASS\n    OBJECT_ENUM\n    OBJECT_FLAGS\n    OBJECT_GLOBAL\n    OBJECT_INTERFACE\n    OBJECT_NAMESPACE\n    OBJECT_WRAPPED\n\n    FUNCTION_ANNOTATION\n    FUNCTION_CONSTRUCTOR\n    FUNCTION_GLOBAL\n    FUNCTION_INSTANCE\n    FUNCTION_LOCAL\n\n    OVERLOADED_ANNOTATION\n    OVERLOADED_GLOBAL\n    OVERLOADED_INSTANCE\n\n    VARIABLE_ARGUMENT\n    VARIABLE_ENUM_OR_FLAGS\n    VARIABLE_GLOBAL\n    VARIABLE_INSTANCE\n    VARIABLE_LOCAL\n\n    def isType bool {\n      return self >= PARAMETER_FUNCTION && self <= OBJECT_WRAPPED\n    }\n\n    def isParameter bool {\n      return self >= PARAMETER_FUNCTION && self <= PARAMETER_OBJECT\n    }\n\n    def isObject bool {\n      return self >= OBJECT_CLASS && self <= OBJECT_WRAPPED\n    }\n\n    def isEnumOrFlags bool {\n      return self == OBJECT_ENUM || self == OBJECT_FLAGS\n    }\n\n    def isFunction bool {\n      return self >= FUNCTION_ANNOTATION && self <= FUNCTION_LOCAL\n    }\n\n    def isOverloadedFunction bool {\n      return self >= OVERLOADED_ANNOTATION && self <= OVERLOADED_INSTANCE\n    }\n\n    def isFunctionOrOverloadedFunction bool {\n      return self >= FUNCTION_ANNOTATION && self <= OVERLOADED_INSTANCE\n    }\n\n    def isVariable bool {\n      return self >= VARIABLE_ARGUMENT && self <= VARIABLE_LOCAL\n    }\n\n    def isLocalOrArgumentVariable bool {\n      return self == VARIABLE_ARGUMENT || self == VARIABLE_LOCAL\n    }\n\n    def isNamespaceOrGlobal bool {\n      return self == OBJECT_NAMESPACE || self == OBJECT_GLOBAL\n    }\n\n    def isGlobalReference bool {\n      return\n        self == VARIABLE_ENUM_OR_FLAGS || self == VARIABLE_GLOBAL ||\n        self == FUNCTION_GLOBAL || self == FUNCTION_CONSTRUCTOR ||\n        self == OVERLOADED_GLOBAL || isType\n    }\n\n    def hasInstances bool {\n      return self == OBJECT_CLASS || self == OBJECT_ENUM || self == OBJECT_FLAGS || self == OBJECT_INTERFACE || self == OBJECT_WRAPPED\n    }\n\n    def isOnInstances bool {\n      return self == FUNCTION_INSTANCE || self == VARIABLE_INSTANCE || self == OVERLOADED_INSTANCE\n    }\n\n    def isLocal bool {\n      return self == FUNCTION_LOCAL || self == VARIABLE_LOCAL || self == VARIABLE_ARGUMENT\n    }\n  }\n\n  enum SymbolState {\n    UNINITIALIZED\n    INITIALIZING\n    INITIALIZED\n  }\n\n  flags SymbolFlags {\n    # Internal\n    IS_AUTOMATICALLY_GENERATED\n    IS_CONST\n    IS_GETTER\n    IS_LOOP_VARIABLE\n    IS_OVER\n    IS_SETTER\n    IS_VALUE_TYPE\n    SHOULD_INFER_RETURN_TYPE\n\n    # Modifiers\n    IS_DEPRECATED\n    IS_ENTRY_POINT\n    IS_EXPORTED\n    IS_IMPORTED\n    IS_INLINING_FORCED\n    IS_INLINING_PREVENTED\n    IS_PREFERRED\n    IS_PROTECTED\n    IS_RENAMED\n    IS_SKIPPED\n    SHOULD_SPREAD\n\n    # Pass-specific\n    IS_CSHARP_CONST\n    IS_DYNAMIC_LAMBDA\n    IS_GUARD_CONDITIONAL\n    IS_OBSOLETE\n    IS_PRIMARY_CONSTRUCTOR\n    IS_VIRTUAL\n    USE_PROTOTYPE_CACHE\n  }\n\n  class Symbol {\n    const id = _createID\n    var kind SymbolKind\n    var name string\n    var rename string = null\n    var range Range = null # The location of the name in the source code\n    var parent Symbol = null # Automatically set by the merging step\n    var resolvedType Type = null # Automatically set by the resolving step\n    var scope Scope = null # Automatically set by the merging step (resolving step for local variables)\n    var state SymbolState = .UNINITIALIZED\n    var annotations List<Node> = null\n    var comments List<Comment> = null\n    var forwardTo Symbol = null # Set by the interface removal step\n    var flags SymbolFlags = 0\n    var nextMergedSymbol Symbol = null # This allows traversal of all declarations for IDE tooltips\n\n    def _cloneFrom(symbol Symbol) {\n      rename = symbol.rename\n      range = symbol.range\n      scope = symbol.scope\n      state = symbol.state\n      flags = symbol.flags\n    }\n\n    # Flags\n    def isAutomaticallyGenerated bool { return .IS_AUTOMATICALLY_GENERATED in flags }\n    def isConst bool                  { return .IS_CONST in flags }\n    def isGetter bool                 { return .IS_GETTER in flags }\n    def isLoopVariable bool           { return .IS_LOOP_VARIABLE in flags }\n    def isOver bool                   { return .IS_OVER in flags }\n    def isSetter bool                 { return .IS_SETTER in flags }\n    def isValueType bool              { return .IS_VALUE_TYPE in flags }\n    def shouldInferReturnType bool    { return .SHOULD_INFER_RETURN_TYPE in flags }\n\n    # Modifiers\n    def isDeprecated bool        { return .IS_DEPRECATED in flags }\n    def isEntryPoint bool        { return .IS_ENTRY_POINT in flags }\n    def isExported bool          { return .IS_EXPORTED in flags }\n    def isImported bool          { return .IS_IMPORTED in flags }\n    def isInliningForced bool    { return .IS_INLINING_FORCED in flags }\n    def isInliningPrevented bool { return .IS_INLINING_PREVENTED in flags }\n    def isPreferred bool         { return .IS_PREFERRED in flags }\n    def isProtected bool         { return .IS_PROTECTED in flags }\n    def isRenamed bool           { return .IS_RENAMED in flags }\n    def isSkipped bool           { return .IS_SKIPPED in flags }\n    def shouldSpread bool        { return .SHOULD_SPREAD in flags }\n\n    # Pass-specific flags\n    def isCSharpConst bool        { return .IS_CSHARP_CONST in flags }\n    def isDynamicLambda bool      { return .IS_DYNAMIC_LAMBDA in flags }\n    def isGuardConditional bool   { return .IS_GUARD_CONDITIONAL in flags }\n    def isObsolete bool           { return .IS_OBSOLETE in flags }\n    def isPrimaryConstructor bool { return .IS_PRIMARY_CONSTRUCTOR in flags }\n    def isVirtual bool            { return .IS_VIRTUAL in flags }\n    def usePrototypeCache bool    { return .USE_PROTOTYPE_CACHE in flags }\n\n    # Combinations\n    def isImportedOrExported bool { return (.IS_IMPORTED | .IS_EXPORTED) in flags }\n\n    def asParameterSymbol ParameterSymbol {\n      assert(kind.isParameter)\n      return self as ParameterSymbol\n    }\n\n    def asObjectSymbol ObjectSymbol {\n      assert(kind.isObject)\n      return self as ObjectSymbol\n    }\n\n    def asFunctionSymbol FunctionSymbol {\n      assert(kind.isFunction)\n      return self as FunctionSymbol\n    }\n\n    def asOverloadedFunctionSymbol OverloadedFunctionSymbol {\n      assert(kind.isOverloadedFunction)\n      return self as OverloadedFunctionSymbol\n    }\n\n    def asVariableSymbol VariableSymbol {\n      assert(kind.isVariable)\n      return self as VariableSymbol\n    }\n\n    def fullName string {\n      if parent != null && parent.kind != .OBJECT_GLOBAL && !kind.isParameter {\n        return parent.fullName + \".\" + name\n      }\n      return name\n    }\n\n    def forwarded Symbol {\n      var symbol = self\n      while symbol.forwardTo != null {\n        symbol = symbol.forwardTo\n      }\n      return symbol\n    }\n\n    def spreadingAnnotations List<Node> {\n      var result List<Node> = null\n      if annotations != null {\n        for annotation in annotations {\n          if annotation.symbol != null && annotation.symbol.shouldSpread {\n            result ?= []\n            result.append(annotation)\n          }\n        }\n      }\n      return result\n    }\n\n    def mergeInformationFrom(symbol Symbol) {\n      # Link merged symbols together\n      var link = self\n      while link.nextMergedSymbol != null {\n        link = link.nextMergedSymbol\n      }\n      link.nextMergedSymbol = symbol\n\n      # Combine annotations\n      if annotations == null {\n        annotations = symbol.annotations\n      } else if symbol.annotations != null {\n        annotations.append(symbol.annotations)\n      }\n\n      # Combine comments\n      if comments == null {\n        comments = symbol.comments\n      } else if symbol.comments != null {\n        comments.append(symbol.comments)\n      }\n\n      rename ?= symbol.rename\n    }\n  }\n\n  namespace Symbol {\n    var _nextID = 0\n\n    const SORT_BY_ID = (a Symbol, b Symbol) => a.id <=> b.id\n    const SORT_OBJECTS_BY_ID = (a ObjectSymbol, b ObjectSymbol) => a.id <=> b.id\n    const SORT_VARIABLES_BY_ID = (a VariableSymbol, b VariableSymbol) => a.id <=> b.id\n\n    const SORT_BY_NAME = (a Symbol, b Symbol) int => {\n      var an = a.name\n      var bn = b.name\n      var ac = an.count\n      var bc = bn.count\n      for i = 0, c = Math.max(ac, bc); i < c; i++ {\n        var ai = i < ac ? an[i] : -1\n        var bi = i < bc ? bn[i] : -1\n        if ai < bi { return -1 }\n        if ai > bi { return 1 }\n      }\n      return a.id <=> b.id\n    }\n\n    def _createID int {\n      return ++_nextID\n    }\n\n    def _substituteSymbols(node Node, symbols IntMap<Symbol>) {\n      if node.symbol != null {\n        node.symbol = symbols.get(node.symbol.id, node.symbol)\n      }\n\n      for child = node.firstChild; child != null; child = child.nextSibling {\n        _substituteSymbols(child, symbols)\n      }\n    }\n  }\n\n  class ParameterSymbol : Symbol {\n    def clone ParameterSymbol {\n      var clone = new(kind, name)\n      clone._cloneFrom(self)\n      clone.resolvedType = Type.new(.SYMBOL, clone)\n      return clone\n    }\n  }\n\n  class Guard {\n    var parent ObjectSymbol\n    var test Node\n    var contents ObjectSymbol\n    var elseGuard Guard\n  }\n\n  class ObjectSymbol : Symbol {\n    var extends Node = null\n    var implements List<Node> = null\n    var baseType Type = null\n    var baseClass ObjectSymbol = null\n    var interfaceTypes List<Type> = null\n    var wrappedType Type = null\n    var members StringMap<Symbol> = {} # Automatically expanded to include members from the base class by the resolving step\n    var objects List<ObjectSymbol> = []\n    var functions List<FunctionSymbol> = []\n    var variables List<VariableSymbol> = []\n    var parameters List<ParameterSymbol> = null\n    var guards List<Guard> = null # Compile-time if statements\n    var hasCheckedInterfacesAndAbstractStatus = false\n    var isAbstractBecauseOf FunctionSymbol = null # Used for diagnostics\n    var commentsInsideEndOfBlock List<Comment> = null # These have nowhere else to go right now\n\n    def isAbstract bool {\n      return isAbstractBecauseOf != null\n    }\n\n    def hasBaseClass(symbol Symbol) bool {\n      return baseClass != null && (baseClass == symbol || baseClass.hasBaseClass(symbol))\n    }\n\n    def hasInterface(symbol Symbol) bool {\n      return interfaceTypes != null && interfaceTypes.any(type => type.symbol == symbol)\n    }\n\n    def isSameOrHasBaseClass(symbol Symbol) bool {\n      return self == symbol || hasBaseClass(symbol)\n    }\n  }\n\n  class FunctionSymbol : Symbol {\n    var overridden FunctionSymbol = null # For derived class functions\n    var overloaded OverloadedFunctionSymbol = null # Links overloaded functions to the other overloads on that type (not on derived types)\n    var implementations List<FunctionSymbol> = null # For interface functions\n    var parameters List<ParameterSymbol> = null\n    var arguments List<VariableSymbol> = []\n    var this VariableSymbol = null # For instance functions and constructors\n    var argumentOnlyType Type = null # For quickly comparing the argument types of two function symbols\n    var returnType Node = null\n    var block Node = null\n    var namingGroup = -1 # Automatically filled out by the renaming step\n    var inlinedCount = 0\n\n    def clone FunctionSymbol {\n      var clone = new(kind, name)\n      var symbols IntMap<Symbol> = {}\n\n      clone._cloneFrom(self)\n\n      if state == .INITIALIZED {\n        clone.resolvedType = Type.new(.SYMBOL, clone)\n        clone.resolvedType.returnType = resolvedType.returnType\n        clone.resolvedType.argumentTypes = resolvedType.argumentTypes.clone\n        clone.argumentOnlyType = argumentOnlyType\n      }\n\n      if parameters != null {\n        clone.parameters = []\n        for parameter in parameters {\n          var cloned = parameter.clone\n          symbols[parameter.id] = cloned\n          clone.parameters.append(cloned)\n        }\n      }\n\n      for argument in arguments {\n        var cloned = argument.clone\n        symbols[argument.id] = cloned\n        clone.arguments.append(cloned)\n      }\n\n      if returnType != null {\n        clone.returnType = returnType.clone\n      }\n\n      if block != null {\n        clone.block = block.clone\n        Symbol._substituteSymbols(clone.block, symbols)\n      }\n\n      return clone\n    }\n  }\n\n  class VariableSymbol : Symbol {\n    var type Node = null\n    var value Node = null\n\n    def clone VariableSymbol {\n      var clone = new(kind, name)\n      clone._cloneFrom(self)\n      clone.resolvedType = resolvedType\n\n      if type != null {\n        clone.type = type.clone\n      }\n\n      if value != null {\n        clone.value = value.clone\n        Symbol._substituteSymbols(clone.value, {id: clone})\n      }\n\n      return clone\n    }\n\n    def initializeWithType(target Type) {\n      assert(state == .UNINITIALIZED)\n      assert(type == null)\n      assert(resolvedType == null)\n\n      state = .INITIALIZED\n      resolvedType = target\n      type = Node.createType(target)\n    }\n  }\n\n  class OverloadedFunctionSymbol : Symbol {\n    var symbols List<FunctionSymbol>\n  }\n\n  enum FuzzySymbolKind {\n    EVERYTHING\n    TYPE_ONLY\n    GLOBAL_ONLY\n    INSTANCE_ONLY\n  }\n\n  class FuzzySymbolMatcher {\n    var _name string\n    var _kind FuzzySymbolKind\n    var _bestScore double\n    var _bestMatch Symbol\n\n    def new(name string, kind FuzzySymbolKind) {\n      _name = name\n      _kind = kind\n      _bestScore = name.count * 0.5\n      _bestMatch = null\n    }\n\n    def _isBetterScore(score double, match Symbol) bool {\n      if score < _bestScore {\n        return true\n      }\n\n      # Do tie-breaking using a consistent ordering so that language targets\n      # with unordered maps (C++ for example) can iterate over symbols in an\n      # unspecified order for speed and still deterministically arrive at the\n      # same result.\n      if score == _bestScore && (_bestMatch == null || match.id < _bestMatch.id) {\n        return true\n      }\n\n      return false\n    }\n\n    def include(match Symbol) {\n      if _kind == .INSTANCE_ONLY && !match.kind.isOnInstances ||\n          _kind == .GLOBAL_ONLY && match.kind.isOnInstances ||\n          _kind == .TYPE_ONLY && !match.kind.isType ||\n          match.state == .INITIALIZING {\n        return\n      }\n\n      var score = caseAwareLevenshteinEditDistance(_name, match.name)\n      if score <= match.name.count * 0.5 && _isBetterScore(score, match) {\n        _bestScore = score\n        _bestMatch = match\n      }\n    }\n\n    def bestSoFar Symbol {\n      return _bestMatch\n    }\n  }\n}\n"
  },
  {
    "path": "src/cpp/fast.cpp",
    "content": "#include <assert.h>\n\n#if _WIN32\n  #include <windows.h>\n#else\n  #include <sys/mman.h>\n#endif\n\nstatic void *__fast_next;\nstatic size_t __fast_available;\n\nstatic void *__fast_allocate(size_t size) {\n  enum {\n    CHUNK_SIZE = 1 << 20,\n    ALIGN = 8,\n  };\n\n  // Always allocate a multiple of the alignment size\n  size = (size + ALIGN - 1) & ~(ALIGN - 1);\n\n  // Grow if needed\n  if (__fast_available < size) {\n    size_t chunk = (size + CHUNK_SIZE - 1) & ~(CHUNK_SIZE - 1);\n    assert(size <= chunk);\n\n    // Ignore the remaining memory in the old chunk and grab a new chunk instead\n    #if _WIN32\n      __fast_next = VirtualAlloc(nullptr, chunk, MEM_COMMIT, PAGE_READWRITE);\n      assert(__fast_next != nullptr);\n    #else\n      __fast_next = mmap(nullptr, chunk, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);\n      assert(__fast_next != MAP_FAILED);\n    #endif\n\n    __fast_available = chunk;\n  }\n\n  // Just use a simple bump allocator\n  void *data = __fast_next;\n  __fast_next = (char *)__fast_next + size;\n  __fast_available -= size;\n  return data;\n}\n\nvoid *operator new (size_t size) { return __fast_allocate(size); }\nvoid *operator new [] (size_t size) { return __fast_allocate(size); }\nvoid operator delete (void *data) throw() {}\nvoid operator delete [] (void *data) throw() {}\n\n// Overriding malloc() and free() is really hard on Windows for some reason\n#if !_WIN32\n  extern \"C\" void *malloc(size_t size) { return __fast_allocate(size); }\n  extern \"C\" void free(void *data) {}\n#endif\n"
  },
  {
    "path": "src/cpp/skew.cpp",
    "content": "#include <math.h>\n#include <string.h>\n\n#if _WIN32\n  #include <windows.h>\n  #undef max\n  #undef min\n#else\n  #include <sys/time.h>\n#endif\n\n////////////////////////////////////////////////////////////////////////////////\n\nSkew::string::string() : _isNull(true) {\n}\n\nSkew::string::string(const char *x) : _data(x ? x : \"\"), _isNull(!x) {\n}\n\nSkew::string::string(const char *x, int count) : _data(x, x + count), _isNull(false) {\n}\n\nSkew::string::string(const std::string &x) : _data(x), _isNull(false) {\n}\n\nbool Skew::string::operator == (const string &x) const {\n  return _isNull == x._isNull && _data == x._data;\n}\n\nbool Skew::string::operator != (const string &x) const {\n  return _isNull != x._isNull || _data != x._data;\n}\n\nconst char *Skew::string::c_str() const {\n  return _isNull ? nullptr : _data.c_str();\n}\n\nconst std::string &Skew::string::std_str() const {\n  return _data;\n}\n\nSkew::string Skew::string::operator + (const string &x) const {\n  assert(!_isNull);\n  assert(!x._isNull);\n  return _data + x._data;\n}\n\nSkew::string &Skew::string::operator += (const string &x) {\n  assert(!_isNull);\n  assert(!x._isNull);\n  _data += x._data;\n  return *this;\n}\n\nint Skew::string::compare(const string &x) const {\n  assert(!_isNull);\n  assert(!x._isNull);\n  return (_data > x._data) - (_data < x._data);\n}\n\nint Skew::string::count() const {\n  return (int)_data.size();\n}\n\nbool Skew::string::contains(const string &x) const {\n  assert(!_isNull);\n  assert(!x._isNull);\n  return _data.find(x._data) != std::string::npos;\n}\n\nint Skew::string::indexOf(const string &x) const {\n  assert(!_isNull);\n  assert(!x._isNull);\n  auto it = _data.find(x._data);\n  return it != std::string::npos ? (int)it : -1;\n}\n\nint Skew::string::lastIndexOf(const string &x) const {\n  assert(!_isNull);\n  assert(!x._isNull);\n  auto it = _data.rfind(x._data);\n  return it != std::string::npos ? (int)it : -1;\n}\n\nbool Skew::string::startsWith(const string &x) const {\n  assert(!_isNull);\n  assert(!x._isNull);\n  return _data.size() >= x._data.size() && !memcmp(_data.data(), x._data.data(), x._data.size());\n}\n\nbool Skew::string::endsWith(const string &x) const {\n  assert(!_isNull);\n  assert(!x._isNull);\n  return _data.size() >= x._data.size() && !memcmp(_data.data() + _data.size() - x._data.size(), x._data.data(), x._data.size());\n}\n\nint Skew::string::operator [] (int x) const {\n  assert(0 <= x && x < count());\n  return (int)(unsigned char)_data[x]; // Code units should not be negative\n}\n\nSkew::string Skew::string::get(int x) const {\n  assert(0 <= x && x < count());\n  return std::string(1, _data[x]);\n}\n\nSkew::string Skew::string::slice(int start) const {\n  assert(0 <= start && start <= count());\n  return _data.substr(start);\n}\n\nSkew::string Skew::string::slice(int start, int end) const {\n  assert(0 <= start && start <= end && end <= count());\n  return _data.substr(start, end - start);\n}\n\nSkew::List<int> *Skew::string::codeUnits() const {\n  auto result = new List<int>;\n  for (unsigned char x : _data) {\n    result->append(x);\n  }\n  return result;\n}\n\nSkew::List<Skew::string> *Skew::string::split(const string &x) const {\n  assert(!_isNull);\n  assert(!x._isNull);\n  auto result = new List<string>;\n  size_t start = 0;\n  while (true) {\n    auto it = _data.find(x._data, start);\n    if (it == std::string::npos) {\n      break;\n    }\n    result->append(_data.substr(start, it - start));\n    start = it + x._data.size();\n  }\n  result->append(_data.substr(start));\n  return result;\n}\n\nSkew::string Skew::string::join(const List<Skew::string> *x) const {\n  assert(!_isNull);\n  std::string result(\"\");\n  for (auto b = x->begin(), e = x->end(), it = b; it != e; it++) {\n    if (it != b) {\n      result += _data;\n    }\n    assert(!it->_isNull);\n    result += it->_data;\n  }\n  return result;\n}\n\nSkew::string Skew::string::repeat(int x) const {\n  assert(x >= 0);\n  std::string result(\"\");\n  result.reserve(_data.size() * x);\n  while (x-- > 0) {\n    result += _data;\n  }\n  return result;\n}\n\nSkew::string Skew::string::replaceAll(const string &before, const string &after) const {\n  assert(!_isNull);\n  assert(!before._isNull);\n  assert(!after._isNull);\n  string result(\"\");\n  size_t start = 0;\n  while (true) {\n    auto it = _data.find(before._data, start);\n    if (it == std::string::npos) {\n      break;\n    }\n    result._data += _data.substr(start, it - start);\n    result._data += after._data;\n    start = it + before._data.size();\n  }\n  result._data += _data.substr(start);\n  return result;\n}\n\nSkew::string Skew::string::toLowerCase() const {\n  auto result = _data;\n  std::transform(_data.begin(), _data.end(), result.begin(), ::tolower);\n  return result;\n}\n\nSkew::string Skew::string::toUpperCase() const {\n  auto result = _data;\n  std::transform(_data.begin(), _data.end(), result.begin(), ::toupper);\n  return result;\n}\n\nSkew::string Skew::string::fromCodeUnit(int x) {\n  return std::string(1, x);\n}\n\nSkew::string Skew::string::fromCodeUnits(const List<int> *x) {\n  std::string result(\"\");\n  result.reserve(x->count());\n  for (char y : *x) {\n    result += y;\n  }\n  return result;\n}\n\nSkew::string operator \"\" _s (const char *data, size_t count) {\n  return Skew::string(data, (int)count);\n}\n\n////////////////////////////////////////////////////////////////////////////////\n\nSkew::StringBuilder::StringBuilder() {\n}\n\nvoid Skew::StringBuilder::append(const string &x) {\n  _data += x.std_str();\n}\n\nSkew::string Skew::StringBuilder::toString() const {\n  return _data;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n\ndouble Skew::Math::abs(double x) {\n  return ::fabs(x);\n}\n\nint Skew::Math::abs(int x) {\n  return ::abs(x);\n}\n\ndouble Skew::Math::acos(double x) {\n  return ::acos(x);\n}\n\ndouble Skew::Math::asin(double x) {\n  return ::asin(x);\n}\n\ndouble Skew::Math::atan(double x) {\n  return ::atan(x);\n}\n\ndouble Skew::Math::atan2(double x, double y) {\n  return ::atan2(x, y);\n}\n\ndouble Skew::Math::sin(double x) {\n  return ::sin(x);\n}\n\ndouble Skew::Math::cos(double x) {\n  return ::cos(x);\n}\n\ndouble Skew::Math::tan(double x) {\n  return ::tan(x);\n}\n\ndouble Skew::Math::floor(double x) {\n  return ::floor(x);\n}\n\ndouble Skew::Math::ceil(double x) {\n  return ::ceil(x);\n}\n\ndouble Skew::Math::round(double x) {\n  return ::round(x);\n}\n\ndouble Skew::Math::exp(double x) {\n  return ::exp(x);\n}\n\ndouble Skew::Math::log(double x) {\n  return ::log(x);\n}\n\ndouble Skew::Math::pow(double x, double y) {\n  return ::pow(x, y);\n}\n\nstatic uint64_t __MurmurHash3(uint64_t h) {\n  h ^= h >> 33;\n  h *= 0xFF51AFD7ED558CCDull;\n  h ^= h >> 33;\n  h *= 0xC4CEB9FE1A85EC53ull;\n  h ^= h >> 33;\n  return h;\n}\n\n// This implementation is from V8: http://v8project.blogspot.com/2015/12/theres-mathrandom-and-then-theres.html\ndouble Skew::Math::random() {\n  static uint64_t state0;\n  static uint64_t state1;\n  static bool setup;\n\n  if (!setup) {\n    #ifdef _WIN32\n      LARGE_INTEGER counter;\n      QueryPerformanceCounter(&counter);\n      state0 = __MurmurHash3(counter.QuadPart);\n    #else\n      timeval data;\n      gettimeofday(&data, nullptr);\n      state0 = __MurmurHash3(((uint64_t)data.tv_sec << 32) | (uint64_t)data.tv_usec);\n    #endif\n    state1 = __MurmurHash3(state0);\n    setup = true;\n  }\n\n  uint64_t s1 = state0;\n  uint64_t s0 = state1;\n  state0 = s0;\n  s1 ^= s1 << 23;\n  s1 ^= s1 >> 17;\n  s1 ^= s0;\n  s1 ^= s0 >> 26;\n  state1 = s1;\n\n  // Exponent for double values for [1.0 .. 2.0)\n  static const uint64_t kExponentBits = 0x3FF0000000000000ull;\n  static const uint64_t kMantissaMask = 0x000FFFFFFFFFFFFFull;\n  uint64_t random = ((state0 + state1) & kMantissaMask) | kExponentBits;\n  double result = 0;\n  static_assert(sizeof(result) == sizeof(random), \"\");\n  memcpy(&result, &random, sizeof(result)); // Use this instead of reinterpret_cast to avoid type-punning\n  return result - 1;\n}\n\ndouble Skew::Math::sqrt(double x) {\n  return ::sqrt(x);\n}\n\ndouble Skew::Math::max(double x, double y) {\n  return x > y ? x : y;\n}\n\nint Skew::Math::max(int x, int y) {\n  return x > y ? x : y;\n}\n\ndouble Skew::Math::min(double x, double y) {\n  return x < y ? x : y;\n}\n\nint Skew::Math::min(int x, int y) {\n  return x < y ? x : y;\n}\n\n// Try shorter strings first. Good test cases: 0.1, 9.8, 0.00000000001, 1.1 - 1.0\nSkew::string __doubleToString(double value) {\n  char buffer[64];\n  std::snprintf(&buffer[0], sizeof(buffer), \"%.15g\", value);\n\n  if (std::stod(&buffer[0]) != value) {\n    std::snprintf(&buffer[0], sizeof(buffer), \"%.16g\", value);\n\n    if (std::stod(&buffer[0]) != value) {\n      std::snprintf(&buffer[0], sizeof(buffer), \"%.17g\", value);\n    }\n  }\n\n  if (!strcmp(buffer, \"-0\")) {\n    return \"0\";\n  }\n\n  return buffer;\n}\n\nSkew::string __intToString(int x) {\n  return std::to_string(x);\n}\n\n////////////////////////////////////////////////////////////////////////////////\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n\n  #include <stack>\n  #include <unordered_set>\n\n  static std::unordered_set<Skew::Object *> marked;\n  static std::stack<Skew::Object *> stack;\n  static Skew::Object *latest;\n\n  enum class Delete {\n    NOW,\n    LATER,\n  };\n\n  // Skew::Internal is a friend of Skew::Object so it can access private variables\n  namespace Skew {\n    struct Internal {\n      static UntypedRoot *start();\n      static void mark();\n      static void sweep(Delete mode);\n      static Object *next(Object *object) { return object->__gc_next; }\n    };\n  }\n\n  #ifdef SKEW_GC_PARALLEL\n    #include <sys/fcntl.h>\n    #include <sys/wait.h>\n    #include <unistd.h>\n\n    struct DeleteLater {\n      Skew::Object *object;\n      Skew::Object **previous;\n    };\n\n    enum { READ, WRITE };\n    static int fd[2];\n    static pid_t childProcess;\n    static size_t liveObjectCount;\n    static size_t nextCollectionThreshold;\n    static std::vector<DeleteLater> deleteLater;\n    static Skew::Root<Skew::Object> parallelHead;\n\n    static void startParallelCollection() {\n      if (childProcess) {\n        return;\n      }\n\n      pipe(fd);\n      fcntl(fd[READ], F_SETFL, fcntl(fd[READ], F_GETFL) | O_NONBLOCK);\n\n      // Make sure the collection is always started with the latest object as\n      // a known object that is guaranteed not to be collected in this\n      // collection. That way the previous pointer for every collected object\n      // should be valid and we don't have to worry about collecting the\n      // latest object and not knowing which previous pointer to patch up.\n      parallelHead = new Skew::Object();\n\n      // Child process\n      if (!(childProcess = fork())) {\n        close(fd[READ]);\n        Skew::Internal::mark();\n        Skew::Internal::sweep(Delete::LATER);\n        write(fd[WRITE], deleteLater.data(), deleteLater.size() * sizeof(DeleteLater));\n        close(fd[WRITE]);\n        _exit(0);\n      }\n\n      // Parent process\n      close(fd[WRITE]);\n    }\n\n    enum class Check {\n      DO_NOT_BLOCK,\n      BLOCK_UNTIL_DONE,\n    };\n\n    static void checkParallelCollection(Check mode) {\n      static uint8_t *buffer[1 << 16];\n      static size_t offset;\n      ssize_t count;\n\n      if (!childProcess) {\n        return;\n      }\n\n      if (mode == Check::BLOCK_UNTIL_DONE) {\n        fcntl(fd[READ], F_SETFL, fcntl(fd[READ], F_GETFL) & ~O_NONBLOCK);\n      }\n\n      // Read some data\n      while ((count = read(fd[READ], buffer + offset, sizeof(buffer) - offset)) > 0) {\n        size_t totalSize = offset + count;\n        size_t objectCount = totalSize / sizeof(DeleteLater);\n        size_t usedSize = objectCount * sizeof(DeleteLater);\n        DeleteLater *records = reinterpret_cast<DeleteLater *>(buffer);\n\n        // Delete all complete records we received\n        for (size_t i = 0; i < objectCount; i++) {\n          const DeleteLater &record = records[i];\n\n          // Skew objects form a singly-linked list. Deleting an object\n          // involves unlinking that object from the list, which involves\n          // changing the next pointer of the previous link to the next link.\n          // This is easy with a doubly-linked list but with a singly-linked\n          // list we don't have the address of the previous link. To get around\n          // this, the collection process sends the address of the previous\n          // link's next pointer. Every object being deleted is guaranteed to\n          // have a previous link because of the \"parallelHead\" object that was\n          // created right before the collection started. The \"parallelHead\"\n          // object is guaranteed not to be collected in this collection.\n          *record.previous = Skew::Internal::next(record.object);\n\n          delete record.object;\n        }\n\n        // Preserve any remaining bytes left over\n        offset = totalSize - usedSize;\n        memmove(buffer, buffer + usedSize, offset);\n\n        if (mode == Check::DO_NOT_BLOCK) {\n          break;\n        }\n      }\n\n      // Check for exit\n      if (waitpid(childProcess, nullptr, mode == Check::BLOCK_UNTIL_DONE ? 0 : WNOHANG)) {\n        close(fd[READ]);\n        childProcess = 0;\n\n        // Set a threshold for the next collection so the garbage collector\n        // only kicks in when there's a decent number of objects to collect\n        nextCollectionThreshold = liveObjectCount + 1024;\n      }\n    }\n\n    void Skew::GC::parallelCollect() {\n      if (liveObjectCount > nextCollectionThreshold) {\n        startParallelCollection();\n      }\n\n      checkParallelCollection(Check::DO_NOT_BLOCK);\n    }\n  #endif\n\n  void Skew::GC::blockingCollect() {\n    #ifdef SKEW_GC_PARALLEL\n      checkParallelCollection(Check::BLOCK_UNTIL_DONE);\n    #endif\n\n    Skew::Internal::mark();\n    Skew::Internal::sweep(Delete::NOW);\n    marked.clear();\n  }\n\n  void Skew::GC::mark(Object *object) {\n    if (object && !marked.count(object)) {\n      marked.insert(object);\n      stack.push(object);\n    }\n  }\n\n  Skew::UntypedRoot::UntypedRoot(Object *object) : _previous(Internal::start()), _next(_previous->_next), _object(object) {\n    _previous->_next = this;\n    _next->_previous = this;\n  }\n\n  Skew::UntypedRoot::~UntypedRoot() {\n    _previous->_next = _next;\n    _next->_previous = _previous;\n  }\n\n  Skew::Object::Object() : __gc_next(latest) {\n    latest = this;\n\n    #ifdef SKEW_GC_PARALLEL\n      liveObjectCount++;\n    #endif\n  }\n\n  Skew::Object::~Object() {\n    #ifdef SKEW_GC_PARALLEL\n      liveObjectCount--;\n    #endif\n  }\n\n  // The first root is the start of a doubly-linked list of roots. It's returned as\n  // a static local variable to avoid trouble from C++ initialization order. Roots\n  // are global variables and initialization order of global variables is undefined.\n  Skew::UntypedRoot *Skew::Internal::start() {\n    static UntypedRoot start;\n    return &start;\n  }\n\n  // Marking must be done with an explicit stack to avoid call stack overflow\n  void Skew::Internal::mark() {\n    for (auto end = start(), root = end->_next; root != end; root = root->_next) {\n      GC::mark(root->_object);\n    }\n\n    while (!stack.empty()) {\n      auto object = stack.top();\n      stack.pop();\n      object->__gc_mark();\n    }\n  }\n\n  // Sweeping removes unmarked objects from the linked list and deletes them\n  void Skew::Internal::sweep(Delete mode) {\n    for (Object *previous = nullptr, *current = latest, *next; current; current = next) {\n      next = current->__gc_next;\n\n      if (!marked.count(current)) {\n        switch (mode) {\n          case Delete::NOW: {\n            (previous ? previous->__gc_next : latest) = next;\n            delete current;\n            break;\n          }\n\n          case Delete::LATER: {\n            #ifdef SKEW_GC_PARALLEL\n              deleteLater.push_back({current, previous ? &previous->__gc_next : nullptr});\n            #endif\n            break;\n          }\n        }\n      }\n\n      else {\n        previous = current;\n      }\n    }\n  }\n\n#endif\n"
  },
  {
    "path": "src/cpp/skew.h",
    "content": "#ifdef SKEW_GC_MARK_AND_SWEEP\n\n  #include <type_traits>\n\n  namespace Skew {\n    struct Internal;\n\n    struct Object {\n      Object(); // Adds this object to the global linked list of objects\n      virtual ~Object();\n\n    protected:\n      virtual void __gc_mark() {} // Recursively marks all child objects\n\n    private:\n      friend Internal;\n      Object *__gc_next = nullptr; // GC space overhead is one pointer per object\n      Object(const Object &); // Prevent copying\n      Object &operator = (const Object &); // Prevent copying\n    };\n\n    struct UntypedRoot {\n      ~UntypedRoot();\n\n    protected:\n      friend Internal;\n      UntypedRoot &operator = (const UntypedRoot &root) { _object = root._object; return *this; }\n      UntypedRoot(const UntypedRoot &root) : UntypedRoot(root._object) {}\n      UntypedRoot() : _previous(this), _next(this), _object() {} // Only used for the first root\n      UntypedRoot(Object *object); // Adds this root to the circular doubly-linked list of roots\n      UntypedRoot *_previous;\n      UntypedRoot *_next;\n      Object *_object;\n    };\n\n    template <typename T>\n    struct Root : UntypedRoot {\n      Root(T *object = nullptr) : UntypedRoot(object) {}\n      T *get() const { return dynamic_cast<T *>(_object); }\n      operator T * () const { return dynamic_cast<T *>(_object); }\n      T *operator -> () const { return dynamic_cast<T *>(_object); }\n      Root<T> &operator = (T *value) { _object = value; return *this; }\n    };\n\n    template <typename T>\n    using VoidIfNotObject = typename std::enable_if<!std::is_base_of<Object, typename std::remove_pointer<T>::type>::value, void>::type;\n\n    namespace GC {\n      void blockingCollect();\n      void mark(Object *object);\n\n      #ifdef SKEW_GC_PARALLEL\n        void parallelCollect();\n      #endif\n\n      template <typename T>\n      inline VoidIfNotObject<T> mark(const T &value) {} // Don't mark anything that's not an object\n    }\n  }\n\n#else\n\n  namespace Skew {\n    struct Object {\n      virtual ~Object() {}\n    };\n\n    template <typename T>\n    struct Root {\n      Root(T *object = nullptr) : _object(object) {}\n      T *get() const { return _object; }\n      operator T * () const { return _object; }\n      T *operator -> () const { return _object; }\n      Root<T> &operator = (T *value) { _object = value; return *this; }\n\n    private:\n      T *_object;\n    };\n  }\n\n#endif\n\n#include <algorithm>\n#include <assert.h>\n#include <initializer_list>\n#include <string>\n#include <unordered_map>\n#include <utility>\n#include <vector>\n#include <cmath>\n\n////////////////////////////////////////////////////////////////////////////////\n\nnamespace Skew {\n  struct FnVoid0 : virtual Skew::Object {\n    virtual void run() = 0;\n  };\n\n  template <typename R>\n  struct Fn0 : virtual Skew::Object {\n    virtual R run() = 0;\n  };\n\n  template <typename A1>\n  struct FnVoid1 : virtual Skew::Object {\n    virtual void run(A1 a1) = 0;\n  };\n\n  template <typename R, typename A1>\n  struct Fn1 : virtual Skew::Object {\n    virtual R run(A1 a1) = 0;\n  };\n\n  template <typename A1, typename A2>\n  struct FnVoid2 : virtual Skew::Object {\n    virtual void run(A1 a1, A2 a2) = 0;\n  };\n\n  template <typename R, typename A1, typename A2>\n  struct Fn2 : virtual Skew::Object {\n    virtual R run(A1 a1, A2 a2) = 0;\n  };\n\n  template <typename A1, typename A2, typename A3>\n  struct FnVoid3 : virtual Skew::Object {\n    virtual void run(A1 a1, A2 a2, A3 a3) = 0;\n  };\n\n  template <typename R, typename A1, typename A2, typename A3>\n  struct Fn3 : virtual Skew::Object {\n    virtual R run(A1 a1, A2 a2, A3 a3) = 0;\n  };\n\n  template <typename A1, typename A2, typename A3, typename A4>\n  struct FnVoid4 : virtual Skew::Object {\n    virtual void run(A1 a1, A2 a2, A3 a3, A4 a4) = 0;\n  };\n\n  template <typename R, typename A1, typename A2, typename A3, typename A4>\n  struct Fn4 : virtual Skew::Object {\n    virtual R run(A1 a1, A2 a2, A3 a3, A4 a4) = 0;\n  };\n\n  template <typename A1, typename A2, typename A3, typename A4, typename A5>\n  struct FnVoid5 : virtual Skew::Object {\n    virtual void run(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) = 0;\n  };\n\n  template <typename R, typename A1, typename A2, typename A3, typename A4, typename A5>\n  struct Fn5 : virtual Skew::Object {\n    virtual R run(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) = 0;\n  };\n\n  template <typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>\n  struct FnVoid6 : virtual Skew::Object {\n    virtual void run(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) = 0;\n  };\n\n  template <typename R, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>\n  struct Fn6 : virtual Skew::Object {\n    virtual R run(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) = 0;\n  };\n\n  template <typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7>\n  struct FnVoid7 : virtual Skew::Object {\n    virtual void run(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) = 0;\n  };\n\n  template <typename R, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7>\n  struct Fn7 : virtual Skew::Object {\n    virtual R run(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) = 0;\n  };\n\n  template <typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8>\n  struct FnVoid8 : virtual Skew::Object {\n    virtual void run(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) = 0;\n  };\n\n  template <typename R, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8>\n  struct Fn8 : virtual Skew::Object {\n    virtual R run(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) = 0;\n  };\n\n  template <typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9>\n  struct FnVoid9 : virtual Skew::Object {\n    virtual void run(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) = 0;\n  };\n\n  template <typename R, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9>\n  struct Fn9 : virtual Skew::Object {\n    virtual R run(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) = 0;\n  };\n\n  template <typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10>\n  struct FnVoid10 : virtual Skew::Object {\n    virtual void run(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) = 0;\n  };\n\n  template <typename R, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10>\n  struct Fn10 : virtual Skew::Object {\n    virtual R run(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) = 0;\n  };\n}\n\n////////////////////////////////////////////////////////////////////////////////\n\nnamespace Skew {\n  template <typename T>\n  struct List;\n\n  struct string {\n    string();\n    string(const char *x);\n    string(const char *x, int count);\n    string(const std::string &x);\n\n    bool operator == (const string &x) const;\n    bool operator != (const string &x) const;\n    const char *c_str() const;\n    const std::string &std_str() const;\n\n    string operator + (const string &x) const;\n    string &operator += (const string &x);\n    int compare(const string &x) const;\n\n    int count() const;\n    bool contains(const string &x) const;\n    int indexOf(const string &x) const;\n    int lastIndexOf(const string &x) const;\n    bool startsWith(const string &x) const;\n    bool endsWith(const string &x) const;\n\n    int operator [] (int x) const;\n    string get(int x) const;\n    string slice(int start) const;\n    string slice(int start, int end) const;\n    List<int> *codeUnits() const;\n\n    List<Skew::string> *split(const string &x) const;\n    string join(const List<Skew::string> *x) const;\n    string repeat(int x) const;\n    string replaceAll(const string &before, const string &after) const;\n\n    string toLowerCase() const;\n    string toUpperCase() const;\n\n    static string fromCodeUnit(int x);\n    static string fromCodeUnits(const List<int> *x);\n\n  private:\n    friend struct std::hash<string>;\n\n    std::string _data;\n    bool _isNull;\n  };\n}\n\nSkew::string operator \"\" _s (const char *data, size_t count);\n\nnamespace std {\n  template <>\n  struct hash<Skew::string> {\n    size_t operator () (const Skew::string &x) const {\n      return hash<std::string>()(x._data);\n    }\n  };\n}\n\n////////////////////////////////////////////////////////////////////////////////\n\nnamespace Skew {\n  struct StringBuilder : virtual Skew::Object {\n    StringBuilder();\n\n    #ifdef SKEW_GC_MARK_AND_SWEEP\n      virtual void __gc_mark() override {}\n    #endif\n\n    void append(const string &x);\n    string toString() const;\n\n  private:\n    std::string _data;\n  };\n}\n\n////////////////////////////////////////////////////////////////////////////////\n\nnamespace Skew {\n  template <typename T>\n  struct CharInsteadOfBool {\n    using Type = T;\n    static T &cast(T &x) { return x; }\n    static const T &cast(const T &x) { return x; }\n  };\n\n  template <>\n  struct CharInsteadOfBool<bool> {\n    static_assert(sizeof(bool) == sizeof(char), \"\");\n    using Type = char;\n    static bool &cast(char &x) { return reinterpret_cast<bool &>(x); }\n    static const bool &cast(const char &x) { return reinterpret_cast<const bool &>(x); }\n  };\n\n  template <typename T>\n  struct List : virtual Skew::Object {\n    List();\n    List(const std::initializer_list<T> &x);\n\n    const T *begin() const;\n    const T *end() const;\n\n    T *begin();\n    T *end();\n\n    const T &operator [] (int x) const;\n    T &operator [] (int x);\n\n    int count() const;\n    bool isEmpty() const;\n\n    void append(const T &x);\n    void append(const List<T> *x);\n    void appendOne(const T &x);\n\n    void prepend(const T &x);\n    void prepend(const List<T> *x);\n\n    void insert(int x, const T &value);\n    void insert(int x, const List<T> *values);\n\n    void removeAt(int x);\n    void removeFirst();\n    void removeIf(Fn1<bool, T> *x);\n    void removeLast();\n    void removeOne(const T &x);\n    void removeRange(int start, int end);\n\n    T takeFirst();\n    T takeLast();\n    T takeAt(int x);\n    List<T> *takeRange(int start, int end);\n\n    #ifdef SKEW_GC_MARK_AND_SWEEP\n      virtual void __gc_mark() override;\n    #endif\n\n    const T &first() const;\n    const T &last() const;\n    T &setFirst(const T &x);\n    T &setLast(const T &x);\n\n    bool contains(const T &x) const;\n    int indexOf(const T &x) const;\n    int lastIndexOf(const T &x) const;\n\n    bool all(Fn1<bool, T> *x) const;\n    bool any(Fn1<bool, T> *x) const;\n    List<T> *clone() const;\n    void each(FnVoid1<T> *x) const;\n    bool equals(const List<T> *x) const;\n    List<T> *filter(Fn1<bool, T> *x) const;\n    template <typename R>\n    List<R> *map(Fn1<R, T> *x) const;\n    void reverse();\n    List<T> *slice(int start) const;\n    List<T> *slice(int start, int end) const;\n    void sort(Fn2<int, T, T> *x);\n\n  private:\n    std::vector<typename CharInsteadOfBool<T>::Type> _data;\n  };\n}\n\n////////////////////////////////////////////////////////////////////////////////\n\nnamespace Skew {\n  template <typename T>\n  struct StringMap : virtual Skew::Object {\n    StringMap();\n    StringMap(const std::initializer_list<std::pair<string, T>> &x);\n\n    #ifdef SKEW_GC_MARK_AND_SWEEP\n      virtual void __gc_mark() override;\n    #endif\n\n    const T &operator [] (const string &x) const;\n    T &operator [] (const string &x);\n\n    int count() const;\n    bool isEmpty() const;\n    List<Skew::string> *keys() const;\n    List<T> *values() const;\n\n    StringMap<T> *clone() const;\n    void each(FnVoid2<string, T> *x) const;\n    T get(const string &key, const T &defaultValue) const;\n    bool contains(const string &key) const;\n    void remove(const string &key);\n\n  private:\n    std::unordered_map<string, T> _data;\n  };\n}\n\n////////////////////////////////////////////////////////////////////////////////\n\nnamespace Skew {\n  template <typename T>\n  struct IntMap : virtual Skew::Object {\n    IntMap();\n    IntMap(const std::initializer_list<std::pair<int, T>> &x);\n\n    #ifdef SKEW_GC_MARK_AND_SWEEP\n      virtual void __gc_mark() override;\n    #endif\n\n    const T &operator [] (int x) const;\n    T &operator [] (int x);\n\n    int count() const;\n    bool isEmpty() const;\n    List<int> *keys() const;\n    List<T> *values() const;\n\n    IntMap<T> *clone() const;\n    void each(FnVoid2<int, T> *x) const;\n    T get(int key, const T &defaultValue) const;\n    bool contains(int key) const;\n    void remove(int key);\n\n  private:\n    std::unordered_map<int, T> _data;\n  };\n}\n\n////////////////////////////////////////////////////////////////////////////////\n\nnamespace Skew {\n  namespace Math {\n    double abs(double x);\n    int abs(int x);\n\n    double acos(double x);\n    double asin(double x);\n    double atan(double x);\n    double atan2(double x, double y);\n\n    double sin(double x);\n    double cos(double x);\n    double tan(double x);\n\n    double floor(double x);\n    double ceil(double x);\n    double round(double x);\n\n    double exp(double x);\n    double log(double x);\n    double pow(double x, double y);\n    double random();\n    double sqrt(double x);\n\n    double max(double x, double y);\n    int max(int x, int y);\n\n    double min(double x, double y);\n    int min(int x, int y);\n  }\n}\n\nSkew::string __doubleToString(double x);\nSkew::string __intToString(int x);\n\n////////////////////////////////////////////////////////////////////////////////\n\ntemplate <typename T>\nSkew::List<T>::List() {\n}\n\ntemplate <typename T>\nSkew::List<T>::List(const std::initializer_list<T> &x) : _data{x} {\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  template <typename T>\n  void Skew::List<T>::__gc_mark() {\n    for (const auto &value : _data) {\n      Skew::GC::mark(value);\n    }\n  }\n#endif\n\ntemplate <typename T>\nconst T *Skew::List<T>::begin() const {\n  return _data.data();\n}\n\ntemplate <typename T>\nconst T *Skew::List<T>::end() const {\n  return _data.data() + _data.size();\n}\n\ntemplate <typename T>\nT *Skew::List<T>::begin() {\n  return _data.data();\n}\n\ntemplate <typename T>\nT *Skew::List<T>::end() {\n  return _data.data() + _data.size();\n}\n\ntemplate <typename T>\nconst T &Skew::List<T>::operator [] (int x) const {\n  assert(0 <= x && x < count());\n  return CharInsteadOfBool<T>::cast(_data[x]);\n}\n\ntemplate <typename T>\nT &Skew::List<T>::operator [] (int x) {\n  assert(0 <= x && x < count());\n  return CharInsteadOfBool<T>::cast(_data[x]);\n}\n\ntemplate <typename T>\nint Skew::List<T>::count() const {\n  return (int)_data.size();\n}\n\ntemplate <typename T>\nbool Skew::List<T>::isEmpty() const {\n  return _data.empty();\n}\n\ntemplate <typename T>\nvoid Skew::List<T>::append(const T &x) {\n  _data.push_back(x);\n}\n\ntemplate <typename T>\nvoid Skew::List<T>::append(const List<T> *x) {\n  assert(x != this);\n  _data.insert(_data.end(), x->_data.begin(), x->_data.end());\n}\n\ntemplate <typename T>\nvoid Skew::List<T>::appendOne(const T &x) {\n  auto it = std::find(_data.begin(), _data.end(), x);\n  if (it == _data.end()) {\n    _data.push_back(x);\n  }\n}\n\ntemplate <typename T>\nvoid Skew::List<T>::prepend(const T &x) {\n  _data.insert(_data.begin(), x);\n}\n\ntemplate <typename T>\nvoid Skew::List<T>::prepend(const List<T> *x) {\n  assert(x != this);\n  _data.insert(_data.begin(), x->_data.begin(), x->_data.end());\n}\n\ntemplate <typename T>\nvoid Skew::List<T>::insert(int x, const T &value) {\n  assert(x >= 0 && x <= count());\n  _data.insert(_data.begin() + x, value);\n}\n\ntemplate <typename T>\nvoid Skew::List<T>::insert(int x, const List<T> *values) {\n  assert(x >= 0 && x <= count());\n  assert(values != this);\n  _data.insert(_data.begin() + x, values->_data.begin(), values->_data.end());\n}\n\ntemplate <typename T>\nvoid Skew::List<T>::removeAt(int x) {\n  assert(x >= 0 && x < count());\n  _data.erase(_data.begin() + x);\n}\n\ntemplate <typename T>\nvoid Skew::List<T>::removeFirst() {\n  assert(!isEmpty());\n  _data.erase(_data.begin());\n}\n\ntemplate <typename T>\nvoid Skew::List<T>::removeIf(Fn1<bool, T> *x) {\n  _data.erase(std::remove_if(_data.begin(), _data.end(), [&](const T &y) {\n    return x->run(y);\n  }), _data.end());\n}\n\ntemplate <typename T>\nvoid Skew::List<T>::removeLast() {\n  assert(!isEmpty());\n  _data.pop_back();\n}\n\ntemplate <typename T>\nvoid Skew::List<T>::removeOne(const T &x) {\n  auto it = std::find(_data.begin(), _data.end(), x);\n  if (it != _data.end()) {\n    _data.erase(it);\n  }\n}\n\ntemplate <typename T>\nvoid Skew::List<T>::removeRange(int start, int end) {\n  assert(0 <= start && start <= end && end <= count());\n  _data.erase(_data.begin() + start, _data.begin() + end);\n}\n\ntemplate <typename T>\nT Skew::List<T>::takeFirst() {\n  assert(!isEmpty());\n  T result = std::move(_data.front());\n  _data.erase(_data.begin());\n  return result;\n}\n\ntemplate <typename T>\nT Skew::List<T>::takeLast() {\n  assert(!isEmpty());\n  T result = std::move(_data.back());\n  _data.pop_back();\n  return result;\n}\n\ntemplate <typename T>\nT Skew::List<T>::takeAt(int x) {\n  assert(0 <= x && x < count());\n  T result = std::move(_data[x]);\n  _data.erase(_data.begin() + x);\n  return result;\n}\n\ntemplate <typename T>\nSkew::List<T> *Skew::List<T>::takeRange(int start, int end) {\n  assert(0 <= start && start <= end && end <= count());\n  auto result = new List<T>;\n  result->_data.reserve(end - start);\n  for (int i = start; i < end; i++) {\n    result->_data.emplace_back(std::move(_data[i]));\n  }\n  _data.erase(_data.begin() + start, _data.begin() + end);\n  return result;\n}\n\ntemplate <typename T>\nconst T &Skew::List<T>::first() const {\n  assert(!isEmpty());\n  return CharInsteadOfBool<T>::cast(_data.front());\n}\n\ntemplate <typename T>\nconst T &Skew::List<T>::last() const {\n  assert(!isEmpty());\n  return CharInsteadOfBool<T>::cast(_data.back());\n}\n\ntemplate <typename T>\nT &Skew::List<T>::setFirst(const T &x) {\n  assert(!isEmpty());\n  return CharInsteadOfBool<T>::cast(_data.front()) = x;\n}\n\ntemplate <typename T>\nT &Skew::List<T>::setLast(const T &x) {\n  assert(!isEmpty());\n  return CharInsteadOfBool<T>::cast(_data.back()) = x;\n}\n\ntemplate <typename T>\nbool Skew::List<T>::contains(const T &x) const {\n  return std::find(begin(), end(), x) != end();\n}\n\ntemplate <typename T>\nint Skew::List<T>::indexOf(const T &x) const {\n  auto it = std::find(begin(), end(), x);\n  return it == end() ? -1 : (int)(it - begin());\n}\n\ntemplate <typename T>\nint Skew::List<T>::lastIndexOf(const T &x) const {\n  auto it = std::find(_data.rbegin(), _data.rend(), x);\n  return it == _data.rend() ? -1 : count() - 1 - (int)(it - _data.rbegin());\n}\n\ntemplate <typename T>\nbool Skew::List<T>::all(Fn1<bool, T> *x) const {\n  for (const auto &it : _data) {\n    if (!x->run(it)) {\n      return false;\n    }\n  }\n  return true;\n}\n\ntemplate <typename T>\nbool Skew::List<T>::any(Fn1<bool, T> *x) const {\n  for (const auto &it : _data) {\n    if (x->run(it)) {\n      return true;\n    }\n  }\n  return false;\n}\n\ntemplate <typename T>\nSkew::List<T> *Skew::List<T>::clone() const {\n  auto result = new List<T>;\n  result->_data = _data;\n  return result;\n}\n\ntemplate <typename T>\nvoid Skew::List<T>::each(FnVoid1<T> *x) const {\n  for (const auto &it : _data) {\n    x->run(it);\n  }\n}\n\ntemplate <typename T>\nbool Skew::List<T>::equals(const List<T> *x) const {\n  if (count() != x->count()) {\n    return false;\n  }\n  for (int i = count() - 1; i >= 0; i--) {\n    if ((*this)[i] != (*x)[i]) {\n      return false;\n    }\n  }\n  return true;\n}\n\ntemplate <typename T>\nSkew::List<T> *Skew::List<T>::filter(Fn1<bool, T> *x) const {\n  auto result = new List<T>;\n  for (const auto &it : _data) {\n    if (x->run(it)) {\n      result->append(it);\n    }\n  }\n  return result;\n}\n\ntemplate <typename T>\ntemplate <typename R>\nSkew::List<R> *Skew::List<T>::map(Fn1<R, T> *x) const {\n  auto result = new List<R>;\n  for (const auto &it : _data) {\n    result->append(x->run(it));\n  }\n  return result;\n}\n\ntemplate <typename T>\nvoid Skew::List<T>::reverse() {\n  std::reverse(begin(), end());\n}\n\ntemplate <typename T>\nSkew::List<T> *Skew::List<T>::slice(int start) const {\n  assert(0 <= start && start <= count());\n  auto result = new List<T>;\n  result->_data.insert(result->_data.begin(), _data.begin() + start, _data.end());\n  return result;\n}\n\ntemplate <typename T>\nSkew::List<T> *Skew::List<T>::slice(int start, int end) const {\n  assert(0 <= start && start <= end && end <= count());\n  auto result = new List<T>;\n  result->_data.insert(result->_data.begin(), _data.begin() + start, _data.begin() + end);\n  return result;\n}\n\ntemplate <typename T>\nvoid Skew::List<T>::sort(Fn2<int, T, T> *x) {\n  std::sort(_data.begin(), _data.end(), [&x](const T &a, const T &b) {\n    return x->run(a, b) < 0;\n  });\n}\n\n////////////////////////////////////////////////////////////////////////////////\n\ntemplate <typename T>\nSkew::StringMap<T>::StringMap() {\n}\n\ntemplate <typename T>\nSkew::StringMap<T>::StringMap(const std::initializer_list<std::pair<string, T>> &x) {\n  _data.reserve(x.size());\n  for (const auto &it : x) {\n    _data.insert(it);\n  }\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  template <typename T>\n  void Skew::StringMap<T>::__gc_mark() {\n    for (const auto &value : _data) {\n      Skew::GC::mark(value.second);\n    }\n  }\n#endif\n\ntemplate <typename T>\nconst T &Skew::StringMap<T>::operator [] (const string &x) const {\n  assert(contains(x));\n  return _data[x];\n}\n\ntemplate <typename T>\nT &Skew::StringMap<T>::operator [] (const string &x) {\n  return _data[x];\n}\n\ntemplate <typename T>\nint Skew::StringMap<T>::count() const {\n  return (int)_data.size();\n}\n\ntemplate <typename T>\nbool Skew::StringMap<T>::isEmpty() const {\n  return _data.empty();\n}\n\ntemplate <typename T>\nSkew::List<Skew::string> *Skew::StringMap<T>::keys() const {\n  auto result = new List<string>;\n  for (const auto &it : _data) {\n    result->append(it.first);\n  }\n  return result;\n}\n\ntemplate <typename T>\nSkew::List<T> *Skew::StringMap<T>::values() const {\n  auto result = new List<T>;\n  for (const auto &it : _data) {\n    result->append(it.second);\n  }\n  return result;\n}\n\ntemplate <typename T>\nSkew::StringMap<T> *Skew::StringMap<T>::clone() const {\n  auto result = new StringMap<T>;\n  result->_data = _data;\n  return result;\n}\n\ntemplate <typename T>\nvoid Skew::StringMap<T>::each(FnVoid2<string, T> *x) const {\n  for (const auto &it : _data) {\n    x->run(it.first, it.second);\n  }\n}\n\ntemplate <typename T>\nT Skew::StringMap<T>::get(const string &key, const T &defaultValue) const {\n  auto it = _data.find(key);\n  return it != _data.end() ? it->second : defaultValue;\n}\n\ntemplate <typename T>\nbool Skew::StringMap<T>::contains(const string &key) const {\n  return _data.count(key);\n}\n\ntemplate <typename T>\nvoid Skew::StringMap<T>::remove(const string &key) {\n  _data.erase(key);\n}\n\n////////////////////////////////////////////////////////////////////////////////\n\ntemplate <typename T>\nSkew::IntMap<T>::IntMap() {\n}\n\ntemplate <typename T>\nSkew::IntMap<T>::IntMap(const std::initializer_list<std::pair<int, T>> &x) {\n  _data.reserve(x.size());\n  for (const auto &it : x) {\n    _data.insert(it);\n  }\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  template <typename T>\n  void Skew::IntMap<T>::__gc_mark() {\n    for (const auto &value : _data) {\n      Skew::GC::mark(value.second);\n    }\n  }\n#endif\n\ntemplate <typename T>\nconst T &Skew::IntMap<T>::operator [] (int x) const {\n  assert(contains(x));\n  return _data[x];\n}\n\ntemplate <typename T>\nT &Skew::IntMap<T>::operator [] (int x) {\n  return _data[x];\n}\n\ntemplate <typename T>\nint Skew::IntMap<T>::count() const {\n  return (int)_data.size();\n}\n\ntemplate <typename T>\nbool Skew::IntMap<T>::isEmpty() const {\n  return _data.empty();\n}\n\ntemplate <typename T>\nSkew::List<int> *Skew::IntMap<T>::keys() const {\n  auto result = new List<int>;\n  for (const auto &it : _data) {\n    result->append(it.first);\n  }\n  return result;\n}\n\ntemplate <typename T>\nSkew::List<T> *Skew::IntMap<T>::values() const {\n  auto result = new List<T>;\n  for (const auto &it : _data) {\n    result->append(it.second);\n  }\n  return result;\n}\n\ntemplate <typename T>\nSkew::IntMap<T> *Skew::IntMap<T>::clone() const {\n  auto result = new IntMap<T>;\n  result->_data = _data;\n  return result;\n}\n\ntemplate <typename T>\nvoid Skew::IntMap<T>::each(FnVoid2<int, T> *x) const {\n  for (const auto &it : _data) {\n    x->run(it.first, it.second);\n  }\n}\n\ntemplate <typename T>\nT Skew::IntMap<T>::get(int key, const T &defaultValue) const {\n  auto it = _data.find(key);\n  return it != _data.end() ? it->second : defaultValue;\n}\n\ntemplate <typename T>\nbool Skew::IntMap<T>::contains(int key) const {\n  return _data.count(key);\n}\n\ntemplate <typename T>\nvoid Skew::IntMap<T>::remove(int key) {\n  _data.erase(key);\n}\n"
  },
  {
    "path": "src/cpp/support.cpp",
    "content": "#include <fstream>\n#include <iostream>\n#include <sstream>\n\n#ifdef _WIN32\n  #include <windows.h>\n#else\n  #include <dirent.h>\n  #include <sys/ioctl.h>\n  #include <sys/stat.h>\n  #include <sys/time.h>\n  #include <unistd.h>\n#endif\n\n////////////////////////////////////////////////////////////////////////////////\n\nSkew::string IO::readFile(const Skew::string &path) {\n  std::ifstream file(path.c_str());\n  if (!file) return Skew::string();\n  std::string contents((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());\n  return Skew::string(contents).replaceAll(\"\\r\\n\", \"\\n\");\n}\n\nbool IO::writeFile(const Skew::string &path, const Skew::string &contents) {\n  std::ofstream file(path.c_str());\n  if (!file) return false;\n  file << contents.c_str();\n  return true;\n}\n\nbool IO::isDirectory(const Skew::string &path) {\n  #ifdef _WIN32\n    auto attributes = GetFileAttributesA(path.c_str());\n    return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;\n  #else\n    struct stat info;\n    return stat(path.c_str(), &info) == 0 && info.st_mode & S_IFDIR;\n  #endif\n}\n\nSkew::List<Skew::string> *IO::readDirectory(const Skew::string &path) {\n  #ifdef _WIN32\n    WIN32_FIND_DATA data;\n    auto handle = FindFirstFileA(path.c_str(), &data);\n    if (handle != INVALID_HANDLE_VALUE) {\n      auto entries = new Skew::List<Skew::string>();\n      do {\n        entries->append(data.cFileName);\n      } while (FindNextFile(handle, &data));\n      FindClose(handle);\n      return entries;\n    }\n  #else\n    if (auto dir = opendir(path.c_str())) {\n      auto entries = new Skew::List<Skew::string>();\n      while (auto entry = readdir(dir)) {\n        entries->append(entry->d_name);\n      }\n      return entries;\n    }\n  #endif\n  return nullptr;\n}\n\n////////////////////////////////////////////////////////////////////////////////\n\nstruct __TerminalInfo {\n  int width;\n  int height;\n  bool isValid;\n\n  #ifdef _WIN32\n    HANDLE handle = INVALID_HANDLE_VALUE;\n    CONSOLE_SCREEN_BUFFER_INFO buffer;\n  #else\n    bool isTTY;\n  #endif\n};\n\nstatic __TerminalInfo &__getTerminalInfo() {\n  static __TerminalInfo info;\n\n  if (!info.isValid) {\n    #ifdef _WIN32\n      info.handle = GetStdHandle(STD_OUTPUT_HANDLE);\n      GetConsoleScreenBufferInfo(info.handle, &info.buffer);\n      info.width = info.buffer.dwSize.X;\n      info.height = info.buffer.dwSize.Y;\n    #else\n      winsize size;\n      if (!ioctl(2, TIOCGWINSZ, &size)) {\n        info.width = size.ws_col;\n        info.height = size.ws_row;\n      }\n      info.isTTY = isatty(STDOUT_FILENO);\n    #endif\n\n    info.isValid = true;\n  }\n\n  return info;\n}\n\nvoid Terminal::_setColor(int escapeCode) {\n  #ifdef _WIN32\n    auto &info = __getTerminalInfo();\n    int attributes = info.buffer.wAttributes;\n    switch (escapeCode) {\n      case 1:  attributes |= FOREGROUND_INTENSITY; break;\n      case 90: attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break;\n      case 91: attributes = FOREGROUND_RED | FOREGROUND_INTENSITY; break;\n      case 92: attributes = FOREGROUND_GREEN | FOREGROUND_INTENSITY; break;\n      case 93: attributes = FOREGROUND_BLUE | FOREGROUND_INTENSITY; break;\n      case 94: attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; break;\n      case 95: attributes = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY; break;\n      case 96: attributes = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; break;\n    }\n    SetConsoleTextAttribute(info.handle, attributes);\n  #else\n    if (__getTerminalInfo().isTTY) {\n      std::cout << \"\\x1B[0;\" << escapeCode << 'm';\n    }\n  #endif\n}\n\nint Terminal::width() {\n  return __getTerminalInfo().width;\n}\n\nint Terminal::height() {\n  return __getTerminalInfo().height;\n}\n\nvoid Terminal::print(const Skew::string &text) {\n  static Skew::string newline(\"\\n\");\n  write(text);\n  write(newline);\n}\n\nvoid Terminal::flush() {\n  #ifndef _WIN32\n    std::cout.flush();\n  #endif\n}\n\nvoid Terminal::write(const Skew::string &text) {\n  #ifdef _WIN32\n    auto converted = text.replaceAll(\"\\n\", \"\\r\\n\");\n\n    // Use WriteConsoleA() instead of std::cout for a huge performance boost\n    WriteConsoleA(__getTerminalInfo().handle, converted.c_str(), converted.count(), nullptr, nullptr);\n  #else\n    std::cout << text.c_str();\n  #endif\n}\n\n////////////////////////////////////////////////////////////////////////////////\n\ndouble Timestamp::seconds() {\n  #ifdef _WIN32\n    static LARGE_INTEGER frequency;\n    LARGE_INTEGER counter;\n    if (!frequency.QuadPart) QueryPerformanceFrequency(&frequency);\n    QueryPerformanceCounter(&counter);\n    return counter.QuadPart / (double)frequency.QuadPart;\n  #else\n    timeval data;\n    gettimeofday(&data, nullptr);\n    return data.tv_sec + data.tv_usec / 1.0e6;\n  #endif\n}\n\n////////////////////////////////////////////////////////////////////////////////\n\ndouble parseDoubleLiteral(const Skew::string &x) {\n  double y = NAN;\n  std::stringstream(x.c_str()) >> y;\n  return y;\n}\n"
  },
  {
    "path": "src/cpp/support.h",
    "content": "namespace Skew {\n  struct string;\n\n  template <typename T>\n  struct List;\n}\n\nnamespace IO {\n  Skew::string readFile(const Skew::string &path);\n  bool writeFile(const Skew::string &path, const Skew::string &contents);\n  bool isDirectory(const Skew::string &path);\n  Skew::List<Skew::string> *readDirectory(const Skew::string &path);\n}\n\nnamespace Terminal {\n  void _setColor(int escapeCode);\n  int width();\n  int height();\n  void print(const Skew::string &text);\n  void flush();\n  void write(const Skew::string &text);\n}\n\nnamespace Timestamp {\n  double seconds();\n}\n\ndouble parseDoubleLiteral(const Skew::string &x);\n"
  },
  {
    "path": "src/driver/jsapi.d.ts",
    "content": "declare module \"skew\" {\n  export type SymbolKind =\n    | \"PARAMETER_FUNCTION\"\n    | \"PARAMETER_OBJECT\"\n\n    | \"OBJECT_CLASS\"\n    | \"OBJECT_ENUM\"\n    | \"OBJECT_FLAGS\"\n    | \"OBJECT_GLOBAL\"\n    | \"OBJECT_INTERFACE\"\n    | \"OBJECT_NAMESPACE\"\n    | \"OBJECT_WRAPPED\"\n\n    | \"FUNCTION_ANNOTATION\"\n    | \"FUNCTION_CONSTRUCTOR\"\n    | \"FUNCTION_GLOBAL\"\n    | \"FUNCTION_INSTANCE\"\n    | \"FUNCTION_LOCAL\"\n\n    | \"OVERLOADED_ANNOTATION\"\n    | \"OVERLOADED_GLOBAL\"\n    | \"OVERLOADED_INSTANCE\"\n\n    | \"VARIABLE_ARGUMENT\"\n    | \"VARIABLE_ENUM_OR_FLAGS\"\n    | \"VARIABLE_GLOBAL\"\n    | \"VARIABLE_INSTANCE\"\n    | \"VARIABLE_LOCAL\"\n\n  export interface Source {\n    name: string\n    contents: string\n  }\n\n  export interface Range {\n    source: string\n    start: Location\n    end: Location\n  }\n\n  export interface Location {\n    line: number\n    column: number\n  }\n\n  export interface CompilerOptions {\n    release?: boolean\n    foldAllConstants?: boolean\n    globalizeAllFunctions?: boolean\n    inlineAllFunctions?: boolean\n    jsMangle?: boolean\n    jsMinify?: boolean\n    jsSourceMap?: boolean\n    outputDirectory?: string\n    outputFile?: string\n    stopAfterResolve?: boolean\n    defines?: { readonly [name: string]: string }\n    target: \"c#\" | \"ts\" | \"c++\" | \"js\" | \"lisp-tree\"\n    inputs: readonly Source[]\n  }\n\n  ////////////////////////////////////////////////////////////////////////////////\n\n  export interface CompileReq extends CompilerOptions {\n    type?: \"compile\"\n    id?: any\n  }\n\n  export interface CompileRes {\n    type: \"compile\"\n    id: any\n    outputs: Source[]\n    log: Log\n  }\n\n  export interface Log {\n    text: string\n    diagnostics: Diagnostic[]\n  }\n\n  export interface Diagnostic {\n    kind: \"error\" | \"warning\"\n    range: Range\n    text: string\n    fixes: Fix[]\n  }\n\n  export interface Fix {\n    kind: number // Only useful for telling which fixes are related\n    range: Range\n    expected: string\n    description: string\n    replacement: string\n  }\n\n  ////////////////////////////////////////////////////////////////////////////////\n\n  export interface TooltipReq {\n    type?: \"tooltip-query\"\n    id?: any\n    source: string\n    line: number\n    column: number\n    ignoreDiagnostics: boolean\n  }\n\n  export interface TooltipRes {\n    type: \"tooltip-query\"\n    id: any\n    source: string\n    tooltip: string | null\n    range: Range | null\n    symbol: string | null\n  }\n\n  ////////////////////////////////////////////////////////////////////////////////\n\n  export interface DefinitionQueryReq {\n    type?: \"definition-query\"\n    id?: any\n    source: string\n    line: number\n    column: number\n  }\n\n  export interface DefinitionQueryRes {\n    type: \"definition-query\"\n    id: any\n    source: string\n    definition: Range | null\n    range: Range | null\n    symbol: string | null\n  }\n\n  ////////////////////////////////////////////////////////////////////////////////\n\n  export interface SymbolsQueryReq {\n    type?: \"symbols-query\",\n    id?: any\n    source?: string\n    fuzzyName?: string\n  }\n\n  export interface SymbolsQueryRes {\n    type: \"symbols-query\",\n    id: any\n    symbols: Symbol[] | null\n  }\n\n  export interface Symbol {\n    name: string\n    kind: SymbolKind\n    parent: number // This is an index into the symbols array or -1\n    fullName: string\n    range: Range\n  }\n\n  ////////////////////////////////////////////////////////////////////////////////\n\n  export interface RenameQueryReq {\n    type?: \"rename-query\"\n    id?: any\n    source: string\n    line: number\n    column: number\n  }\n\n  export interface RenameQueryRes {\n    type: \"rename-query\"\n    id: any\n    source: string\n    ranges: Range[] | null\n  }\n\n  ////////////////////////////////////////////////////////////////////////////////\n\n  export interface CompletionQueryReq extends CompilerOptions {\n    type?: \"completion-query\"\n    id?: any\n    source: string\n    line: number\n    column: number\n  }\n\n  export interface CompletionQueryRes {\n    type: \"completion-query\"\n    id: any\n    source: string\n    range: Range | null\n    completions: Completion[] | null\n  }\n\n  export interface Completion {\n    name: string\n    kind: SymbolKind\n    type: string\n    comments: string[] | null\n  }\n\n  ////////////////////////////////////////////////////////////////////////////////\n\n  export interface SignatureQueryReq {\n    type?: \"signature-query\"\n    id?: any\n    source: string\n    line: number\n    column: number\n  }\n\n  export interface SignatureQueryRes {\n    type: \"signature-query\"\n    id: any\n    source: string\n    signature: string | null\n    arguments: string[] | null\n    argumentIndex: number\n  }\n\n  ////////////////////////////////////////////////////////////////////////////////\n\n  export interface Compiler {\n    compile(req: CompileReq): CompileRes\n    tooltipQuery(req: TooltipReq): TooltipRes\n    definitionQuery(req: DefinitionQueryReq): DefinitionQueryRes\n    symbolsQuery(req: SymbolsQueryReq): SymbolsQueryRes\n    renameQuery(req: RenameQueryReq): RenameQueryRes\n    completionQuery(req: CompletionQueryReq): CompletionQueryRes\n    signatureQuery(req: SignatureQueryReq): SignatureQueryRes\n    message(req: Req): Res\n  }\n\n  export type Req =\n    | CompileReq\n    | TooltipReq\n    | DefinitionQueryReq\n    | SymbolsQueryReq\n    | RenameQueryReq\n    | CompletionQueryReq\n    | SignatureQueryReq\n\n  export type Res =\n    | CompileRes\n    | TooltipRes\n    | DefinitionQueryRes\n    | SymbolsQueryRes\n    | RenameQueryRes\n    | CompletionQueryRes\n    | SignatureQueryRes\n\n  export const VERSION: string\n  export function create(): Compiler\n}\n"
  },
  {
    "path": "src/driver/jsapi.sk",
    "content": "namespace Skew.API {\n  def sourcesToJSON(sources List<Source>) dynamic {\n    return sources.map<dynamic>(source => {\n      return {\n        \"name\": source.name,\n        \"contents\": source.contents,\n      }\n    })\n  }\n\n  def diagnosticsToJSON(diagnostics List<Diagnostic>) dynamic {\n    return diagnostics.map<dynamic>(diagnostic => {\n      return {\n        \"kind\": diagnostic.kind.toString.toLowerCase,\n        \"range\": rangeToJSON(diagnostic.range),\n        \"text\": diagnostic.text,\n        \"fixes\": diagnostic.fixes == null ? [] : diagnostic.fixes.map<dynamic>(fix => ({\n          \"kind\": fix.kind, # Only useful for telling which fixes are related\n          \"range\": rangeToJSON(fix.range),\n          \"expected\": fix.range.toString,\n          \"description\": fix.description,\n          \"replacement\": fix.replacement,\n        }))\n      }\n    })\n  }\n\n  var rangeToJSON = (range Range) dynamic => {\n    if range == null {\n      return null\n    }\n\n    var source = range.source\n    var start = source.indexToLineColumn(range.start)\n    var end = source.indexToLineColumn(range.end)\n\n    return {\n      \"source\": source.name,\n      \"start\": {\n        \"line\": start.line,\n        \"column\": start.column,\n      },\n      \"end\": {\n        \"line\": end.line,\n        \"column\": end.column,\n      },\n    }\n  }\n\n  def parseOptions(args dynamic, inputs List<Source>) CompilerOptions {\n    if !(args.inputs is List<dynamic>) {\n      throw dynamic.Error.new(\"Missing the required 'inputs' array\")\n    }\n\n    var options = CompilerOptions.new\n    var release = !!args.release\n    options.foldAllConstants = !!args.foldAllConstants || release\n    options.globalizeAllFunctions = !!args.globalizeAllFunctions || release\n    options.inlineAllFunctions = !!args.inlineAllFunctions || release\n    options.jsMangle = !!args.jsMangle || release\n    options.jsMinify = !!args.jsMinify || release\n    options.jsSourceMap = !!args.jsSourceMap\n    options.outputDirectory = args.outputDirectory ? args.outputDirectory + \"\" : null\n    options.outputFile = args.outputFile ? args.outputFile + \"\" : null\n    options.stopAfterResolve = !!args.stopAfterResolve\n\n    if args.defines {\n      var defines = args.defines\n      for key in dynamic.Object.keys(defines) as List<string> {\n        options.define(key, defines[key] + \"\")\n      }\n    }\n\n    if release {\n      options.define(\"RELEASE\", \"true\")\n    }\n\n    switch args.target {\n      case \"c#\" { options.target = CSharpTarget.new }\n      case \"ts\" { options.target = TypeScriptTarget.new }\n      case \"c++\" { options.target = CPlusPlusTarget.new }\n      case \"js\" { options.target = JavaScriptTarget.new }\n      case \"lisp-tree\" { options.target = LispTreeTarget.new }\n      default {\n        if !options.createTargetFromExtension {\n          throw dynamic.Error.new(\"Invalid target '\\(args.target)'\")\n        }\n      }\n    }\n\n    for i in 0..args.inputs.length {\n      var input = args.inputs[i]\n      inputs.append(Source.new(input.name + \"\", input.contents + \"\"))\n    }\n\n    return options\n  }\n\n  var createCompilerInstance fn() dynamic = => {\n    var result CompilerResult = null\n    var inputs List<Source> = null\n    var log Log = null\n\n    var handleCompile = (message dynamic) dynamic => {\n      inputs = []\n      log = Log.new\n      result = compile(log, parseOptions(message, inputs), inputs)\n\n      return {\n        \"type\": \"compile\",\n        \"id\": message.id,\n        \"outputs\": sourcesToJSON(result.outputs),\n        \"log\": {\n          \"text\": log.toString,\n          \"diagnostics\": diagnosticsToJSON(log.diagnostics),\n        },\n      }\n    }\n\n    var handleTooltipQuery = (message dynamic) dynamic => {\n      var name string = message.source + \"\"\n      var line int = message.line | 0\n      var column int = message.column | 0\n      var ignoreDiagnostics bool = !!message.ignoreDiagnostics\n      var range Range = null\n      var tooltip string = null\n      var symbol string = null\n\n      if inputs != null {\n        for source in inputs {\n          if source.name == name {\n            var index = source.lineColumnToIndex(line, column)\n            if index != -1 {\n              # Search diagnostics first\n              if !ignoreDiagnostics && log != null {\n                for diagnostic in log.diagnostics {\n                  if diagnostic.range != null && diagnostic.range.source == source && diagnostic.range.touches(index) {\n                    tooltip = diagnostic.text\n                    range = diagnostic.range\n                    break\n                  }\n                }\n              }\n\n              # Search the syntax tree next\n              if tooltip == null && result != null && result.global != null {\n                var query = IDE.SymbolQuery.new(source, index)\n                query.run(result.global)\n                if query.symbol != null {\n                  tooltip = query.generateTooltip\n                  range = query.range\n                  symbol = query.symbol.fullName\n                }\n              }\n            }\n            break\n          }\n        }\n      }\n\n      return {\n        \"type\": \"tooltip-query\",\n        \"id\": message.id,\n        \"source\": name,\n        \"tooltip\": tooltip,\n        \"range\": rangeToJSON(range),\n        \"symbol\": symbol,\n      }\n    }\n\n    var handleDefinitionQuery = (message dynamic) dynamic => {\n      var name string = message.source + \"\"\n      var line int = message.line | 0\n      var column int = message.column | 0\n      var range Range = null\n      var definition Range = null\n      var symbol string = null\n\n      if inputs != null {\n        for source in inputs {\n          if source.name == name {\n            var index = source.lineColumnToIndex(line, column)\n            if index != -1 && result != null && result.global != null {\n              var query = IDE.SymbolQuery.new(source, index)\n              query.run(result.global)\n              if query.symbol != null {\n                definition = query.symbol.range\n                range = query.range\n                symbol = query.symbol.fullName\n              }\n            }\n            break\n          }\n        }\n      }\n\n      return {\n        \"type\": \"definition-query\",\n        \"id\": message.id,\n        \"source\": name,\n        \"definition\": rangeToJSON(definition),\n        \"range\": rangeToJSON(range),\n        \"symbol\": symbol,\n      }\n    }\n\n    var handleSymbolsQuery = (message dynamic) dynamic => {\n      var symbols List<Symbol> = []\n\n      # List all symbols in a given source file\n      if message.source {\n        var name string = message.source + \"\"\n        if inputs != null {\n          for source in inputs {\n            if source.name == name {\n              if result != null && result.global != null {\n                var query = IDE.SymbolsQuery.new(source)\n                query.run(result.global)\n                symbols = query.symbols\n              }\n              break\n            }\n          }\n        }\n      }\n\n      # List all symbols matching a given substring\n      else if message.fuzzyName {\n        var nameSubstring string = message.fuzzyName + \"\"\n        nameSubstring = nameSubstring.toLowerCase\n        if inputs != null && result != null && result.global != null {\n          var query = IDE.SymbolsQuery.new(null)\n          query.run(result.global)\n          for symbol in query.symbols {\n            if symbol.name.toLowerCase.indexOf(nameSubstring) >= 0 {\n              symbols.append(symbol)\n            }\n          }\n        }\n      }\n\n      return {\n        \"type\": \"symbols-query\",\n        \"id\": message.id,\n        \"symbols\": symbols.isEmpty ? null : symbols.map<dynamic>(symbol => ({\n          \"name\": symbol.name,\n          \"kind\": symbol.kind.toString,\n          \"parent\": symbol.parent == null || symbol == result.global ? -1 : symbols.indexOf(symbol.parent),\n          \"fullName\": symbol.fullName,\n          \"range\": rangeToJSON(symbol.range),\n        })),\n      }\n    }\n\n    var handleRenameQuery = (message dynamic) dynamic => {\n      var name string = message.source + \"\"\n      var line int = message.line | 0\n      var column int = message.column | 0\n      var ranges List<Range> = null\n\n      if inputs != null {\n        for source in inputs {\n          if source.name == name {\n            var index = source.lineColumnToIndex(line, column)\n            if index != -1 && result != null && result.global != null {\n              var query = IDE.RenameQuery.new(source, index)\n              query.run(result.global)\n              ranges = query.ranges\n            }\n            break\n          }\n        }\n      }\n\n      return {\n        \"type\": \"rename-query\",\n        \"id\": message.id,\n        \"source\": name,\n        \"ranges\": ranges == null ? null : ranges.map<dynamic>(rangeToJSON),\n      }\n    }\n\n    var handleCompletionQuery = (message dynamic) dynamic => {\n      var name string = message.source + \"\"\n      var line int = message.line | 0\n      var column int = message.column | 0\n      var range Range = null\n      var completions List<Symbol> = null\n      var inputs List<Source> = []\n      var log = Log.new\n      var options = parseOptions(message, inputs)\n\n      # Completion queries involve compiling the source code again because it requires scope information\n      for input in inputs {\n        if input.name == name {\n          var index = input.lineColumnToIndex(line, column)\n          if index != -1 {\n            options.stopAfterResolve = true\n            options.completionContext = CompletionContext.new(input, index)\n            compile(log, options, inputs)\n            range = options.completionContext.range\n            completions = options.completionContext.completions\n          }\n          break\n        }\n      }\n\n      return {\n        \"type\": \"completion-query\",\n        \"id\": message.id,\n        \"source\": name,\n        \"range\": rangeToJSON(range),\n        \"completions\": completions == null ? null : completions.map<dynamic>(symbol => ({\n          \"name\": symbol.name,\n          \"kind\": symbol.kind.toString,\n          \"type\": IDE.completionType(symbol),\n          \"comments\": symbol.comments == null ? null : symbol.comments.map<string>(comment => \"\\n\".join(comment.lines)),\n        })),\n      }\n    }\n\n    var handleSignatureQuery = (message dynamic) dynamic => {\n      var name string = message.source + \"\"\n      var line int = message.line | 0\n      var column int = message.column | 0\n      var signature string = null\n      var arguments List<string> = null\n      var argumentIndex = -1\n\n      if inputs != null {\n        for source in inputs {\n          if source.name == name {\n            var index = source.lineColumnToIndex(line, column)\n            if index != -1 && result != null && result.global != null {\n              var query = IDE.SignatureQuery.new(source, index)\n              query.run(result.global)\n              if query.signature != null {\n                signature = query.signatureString\n                arguments = query.argumentStrings\n                argumentIndex = query.argumentIndex\n              }\n            }\n            break\n          }\n        }\n      }\n\n      return {\n        \"type\": \"signature-query\",\n        \"id\": message.id,\n        \"source\": name,\n        \"signature\": signature,\n        \"arguments\": arguments,\n        \"argumentIndex\": argumentIndex,\n      }\n    }\n\n    var handleMessage = (message dynamic) dynamic => {\n      switch message.type {\n        case \"compile\" { return handleCompile(message) }\n        case \"tooltip-query\" { return handleTooltipQuery(message) }\n        case \"definition-query\" { return handleDefinitionQuery(message) }\n        case \"symbols-query\" { return handleSymbolsQuery(message) }\n        case \"rename-query\" { return handleRenameQuery(message) }\n        case \"completion-query\" { return handleCompletionQuery(message) }\n        case \"signature-query\" { return handleSignatureQuery(message) }\n        default { throw dynamic.Error.new(\"Unexpected message type '\\(message.type)'\") }\n      }\n    }\n\n    return {\n      \"compile\": handleCompile,\n      \"tooltipQuery\": handleTooltipQuery,\n      \"definitionQuery\": handleDefinitionQuery,\n      \"symbolsQuery\": handleSymbolsQuery,\n      \"renameQuery\": handleRenameQuery,\n      \"completionQuery\": handleCompletionQuery,\n      \"signatureQuery\": handleSignatureQuery,\n      \"message\": handleMessage,\n    }\n  }\n\n  @entry if BUILD == .API\n  def apiMain {\n    # JavaScript API\n    var this = (=> dynamic.this)()\n    var api = dynamic.typeof(dynamic.exports) != \"undefined\" ? dynamic.exports : this.Skew ? this.Skew : this.Skew = {}\n    api.VERSION = VERSION\n    api.create = createCompilerInstance\n\n    # Web Worker API (only installed if no other code in the worker sets \"Skew.handleWorkerMessages\" to false first)\n    if dynamic.typeof(dynamic.WorkerGlobalScope) != \"undefined\" && this is dynamic.WorkerGlobalScope && api.handleWorkerMessages != true {\n      var instance = createCompilerInstance()\n      dynamic.onmessage = (event dynamic) => {\n        dynamic.postMessage(instance.message(event.data))\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/driver/options.sk",
    "content": "namespace Skew {\n  class Log {\n    def commandLineWarningDuplicateFlagValue(range Range, name string, previous Range) {\n      append(\n        newWarning(range, \"Multiple values are specified for \\\"\\(name)\\\", using the later value\")\n        .withNote(previous, \"Ignoring the previous value\"))\n    }\n\n    def commandLineErrorBadFlag(range Range, name string) {\n      append(newError(range, \"Unknown command line flag \\\"\\(name)\\\"\"))\n    }\n\n    def commandLineErrorMissingValue(range Range, text string) {\n      append(newError(range, \"Use \\\"\\(text)\\\" to provide a value\"))\n    }\n\n    def commandLineErrorExpectedToken(range Range, expected string, found string, text string) {\n      append(newError(range, \"Expected \\\"\\(expected)\\\" but found \\\"\\(found)\\\" in \\\"\\(text)\\\"\"))\n    }\n\n    def commandLineErrorNonBooleanValue(range Range, value string, text string) {\n      append(newError(range, \"Expected \\\"true\\\" or \\\"false\\\" but found \\\"\\(value)\\\" in \\\"\\(text)\\\"\"))\n    }\n\n    def commandLineErrorNonIntegerValue(range Range, value string, text string) {\n      append(newError(range, \"Expected integer constant but found \\\"\\(value)\\\" in \\\"\\(text)\\\"\"))\n    }\n  }\n}\n\nnamespace Skew.Options {\n  enum Type {\n    BOOL\n    INT\n    STRING\n    STRING_LIST\n  }\n\n  class Data {\n    var parser Parser\n    var type Type\n    var option Option\n    var name string\n    var description string\n\n    def nameText string {\n      return name + (type == .BOOL ? \"\" : type == .STRING_LIST ? \":___\" : \"=___\")\n    }\n\n    def aliases(names List<string>) Data {\n      for name in names {\n        parser.map[name] = self\n      }\n      return self\n    }\n  }\n\n  class Parser {\n    var options List<Data> = []\n    var map StringMap<Data> = {}\n    var optionalArguments IntMap<Node> = {}\n    var normalArguments List<Range> = []\n    var source Source = null\n\n    def define(type Type, option Option, name string, description string) Data {\n      var data = Data.new(self, type, option, name, description)\n      map[name] = data\n      options.append(data)\n      return data\n    }\n\n    def nodeForOption(option Option) Node {\n      return optionalArguments.get(option, null)\n    }\n\n    def boolForOption(option Option, defaultValue bool) bool {\n      var node = nodeForOption(option)\n      return node != null ? node.content.asBool : defaultValue\n    }\n\n    def intForOption(option Option, defaultValue int) int {\n      var node = nodeForOption(option)\n      return node != null ? node.content.asInt : defaultValue\n    }\n\n    def rangeForOption(option Option) Range {\n      var node = nodeForOption(option)\n      return node?.range\n    }\n\n    def rangeListForOption(option Option) List<Range> {\n      var node = nodeForOption(option)\n      var ranges List<Range> = []\n      if node != null {\n        for child = node.firstChild; child != null; child = child.nextSibling {\n          ranges.append(child.range)\n        }\n      }\n      return ranges\n    }\n\n    def parse(log Log, arguments List<string>) {\n      source = Source.new(\"<arguments>\", \"\")\n      var ranges List<Range> = []\n\n      # Create a source for the arguments to work with the log system. The\n      # trailing space is needed to be able to point to the character after\n      # the last argument without wrapping onto the next line.\n      for argument in arguments {\n        var needsQuotes = \" \" in argument\n        var start = source.contents.count + (needsQuotes as int)\n        ranges.append(Range.new(source, start, start + argument.count))\n        source.contents += needsQuotes ? \"'\\(argument)' \" : argument + \" \"\n      }\n\n      # Parse each argument\n      for i in 0..arguments.count {\n        var argument = arguments[i]\n        var range = ranges[i]\n\n        # Track all normal arguments separately\n        if argument == \"\" || argument[0] != '-' && !(argument in map) {\n          normalArguments.append(range)\n          continue\n        }\n\n        # Parse a flag\n        var equals = argument.indexOf(\"=\")\n        var colon = argument.indexOf(\":\")\n        var separator = equals >= 0 && (colon < 0 || equals < colon) ? equals : colon\n        var name = separator >= 0 ? argument.slice(0, separator) : argument\n        var data = map.get(name, null)\n\n        # Check that the flag exists\n        if data == null {\n          log.commandLineErrorBadFlag(range.fromStart(name.count), name)\n          continue\n        }\n\n        # Validate the flag data\n        var text = argument.slice(separator + 1)\n        var separatorRange = separator < 0 ? null : range.slice(separator, separator + 1)\n        var textRange = range.fromEnd(text.count)\n        switch data.type {\n\n          # Parse a single boolean value\n          case .BOOL {\n            if separator < 0 {\n              text = \"true\"\n            } else if argument[separator] != '=' {\n              log.commandLineErrorExpectedToken(separatorRange, \"=\", argument.get(separator), argument)\n              continue\n            } else if text != \"true\" && text != \"false\" {\n              log.commandLineErrorNonBooleanValue(textRange, text, argument)\n              continue\n            }\n            if data.option in optionalArguments {\n              log.commandLineWarningDuplicateFlagValue(textRange, name, optionalArguments[data.option].range)\n            }\n            optionalArguments[data.option] = Node.createBool(text == \"true\").withRange(textRange)\n          }\n\n          # Parse a single int value\n          case .INT {\n            if separator < 0 {\n              log.commandLineErrorMissingValue(textRange, data.nameText)\n            } else if argument[separator] != '=' {\n              log.commandLineErrorExpectedToken(separatorRange, \"=\", argument.get(separator), argument)\n            } else {\n              var box = Parsing.parseIntLiteral(log, textRange)\n              if box == null {\n                log.commandLineErrorNonIntegerValue(textRange, text, argument)\n              } else {\n                if data.option in optionalArguments {\n                  log.commandLineWarningDuplicateFlagValue(textRange, name, optionalArguments[data.option].range)\n                }\n                optionalArguments[data.option] = Node.createInt(box.value).withRange(textRange)\n              }\n            }\n          }\n\n          # Parse a single string value\n          case .STRING {\n            if separator < 0 {\n              log.commandLineErrorMissingValue(textRange, data.nameText)\n            } else if argument[separator] != '=' {\n              log.commandLineErrorExpectedToken(separatorRange, \"=\", argument.get(separator), argument)\n            } else {\n              if data.option in optionalArguments {\n                log.commandLineWarningDuplicateFlagValue(textRange, name, optionalArguments[data.option].range)\n              }\n              optionalArguments[data.option] = Node.createString(text).withRange(textRange)\n            }\n          }\n\n          # Parse an item in a list of string values\n          case .STRING_LIST {\n            if separator < 0 {\n              log.commandLineErrorMissingValue(textRange, data.nameText)\n            } else if argument[separator] != ':' {\n              log.commandLineErrorExpectedToken(separatorRange, \":\", argument.get(separator), argument)\n            } else {\n              var node Node\n              if data.option in optionalArguments {\n                node = optionalArguments[data.option]\n              } else {\n                node = Node.createInitializer(.INITIALIZER_LIST)\n                optionalArguments[data.option] = node\n              }\n              node.appendChild(Node.createString(text).withRange(textRange))\n            }\n          }\n        }\n      }\n    }\n\n    def usageText(wrapWidth int) string {\n      var text = \"\"\n      var columnWidth = 0\n\n      # Figure out the column width\n      for option in options {\n        var width = option.nameText.count + 4\n        if columnWidth < width {\n          columnWidth = width\n        }\n      }\n\n      # Format the options\n      var columnText = \" \".repeat(columnWidth)\n      for option in options {\n        var nameText = option.nameText\n        var isFirst = true\n        text += \"\\n  \" + nameText + \" \".repeat(columnWidth - nameText.count - 2)\n        for line in PrettyPrint.wrapWords(option.description, wrapWidth - columnWidth) {\n          text += (isFirst ? \"\" : columnText) + line + \"\\n\"\n          isFirst = false\n        }\n      }\n\n      return text + \"\\n\"\n    }\n  }\n}\n"
  },
  {
    "path": "src/driver/terminal.sk",
    "content": "namespace Skew {\n  enum Option {\n    DEFINE\n    FIX_ALL\n    FOLD_CONSTANTS\n    GC_STRATEGY\n    GLOBALIZE_FUNCTIONS\n    HELP\n    IGNORED_COMMENT_WARNING\n    INLINE_FUNCTIONS\n    JS_MANGLE\n    JS_MINIFY\n    JS_SOURCE_MAP\n    MESSAGE_LIMIT\n    NO_OUTPUT\n    OUTPUT_DIRECTORY\n    OUTPUT_FILE\n    RELEASE\n    TARGET\n    VERBOSE\n    VERSION\n    WARNINGS_ARE_ERRORS\n  }\n\n  const DEFAULT_MESSAGE_LIMIT = 10\n\n  @entry if BUILD == .SKEWC\n  def skewcMain(arguments List<string>) int {\n    var log = Log.new\n    var diagnosticLimit = 0\n    var printDiagnostic = (diagnostic Diagnostic) => {\n      var terminalWidth = Terminal.width\n      if diagnosticLimit > 0 && log.diagnostics.count >= diagnosticLimit {\n        return\n      }\n      if diagnostic.range != null {\n        printWithColor(.BOLD, diagnostic.range.locationString + \": \")\n      }\n      switch diagnostic.kind {\n        case .WARNING { printWarning(diagnostic.text) }\n        case .ERROR { printError(diagnostic.text) }\n      }\n      if diagnostic.range != null {\n        var formatted = diagnostic.range.format(terminalWidth)\n        Terminal.print(formatted.line)\n        printWithColor(.GREEN, formatted.range + \"\\n\")\n      }\n      if diagnostic.noteRange != null {\n        var formatted = diagnostic.noteRange.format(terminalWidth)\n        printWithColor(.BOLD, diagnostic.noteRange.locationString + \": \")\n        printNote(diagnostic.noteText)\n        Terminal.print(formatted.line)\n        printWithColor(.GREEN, formatted.range + \"\\n\")\n      }\n    }\n\n    # Print diagnostics immediately when generated to improve perceived speed\n    log.appendCallback = printDiagnostic\n\n    # Translate frontend flags to compiler options\n    var parser = Options.Parser.new\n    var options = parseOptions(log, parser, arguments)\n    diagnosticLimit = parser.intForOption(.MESSAGE_LIMIT, DEFAULT_MESSAGE_LIMIT)\n    var fixAll = parser.boolForOption(.FIX_ALL, false)\n    var fixCount = 0\n\n    # Optionally have the log transform warnings into errors\n    if options != null {\n      log.warningsAreErrors = options.warningsAreErrors\n    }\n\n    # Suppress logging during fixes\n    if fixAll {\n      log = Log.new\n    }\n\n    # Iterate until fixed point when applying fixes\n    while true {\n      var inputs List<Source> = []\n      var inputRanges List<Range> = []\n      readSources(log, parser.normalArguments, inputs, inputRanges)\n\n      # Run the compilation\n      if !log.hasErrors && options != null {\n        var result = compile(log, options, inputs)\n\n        # Write all outputs\n        if !log.hasErrors {\n          for output in result.outputs {\n            if output.name != null && !IO.writeFile(output.name, output.contents) {\n              var outputFile = parser.rangeForOption(.OUTPUT_FILE)\n              var outputDirectory = parser.rangeForOption(.OUTPUT_DIRECTORY)\n              log.commandLineErrorUnwritableFile(outputFile ?? outputDirectory, output.name)\n              break\n            }\n          }\n\n          # Print compilation statistics\n          if !log.hasErrors {\n            printWithColor(.GRAY, result.statistics(inputs, options.verbose ? .LONG : .SHORT) + \"\\n\")\n          }\n        }\n      }\n\n      if !fixAll {\n        break\n      }\n\n      # Attempt to automatically fix warnings and errors\n      var applyLog = Log.new\n      var count = applyFixes(log, applyLog, source => {\n        for i in 0..inputs.count {\n          if source.name == inputs[i].name {\n            return inputRanges[i]\n          }\n        }\n        return parser.rangeForOption(.FIX_ALL)\n      })\n\n      fixCount += count\n      log = applyLog\n\n      if count == 0 || applyLog.hasErrors {\n        break\n      }\n    }\n\n    # Print diagnostics afterward when applying fixes since they aren't printed earlier\n    if fixAll {\n      for diagnostic in log.diagnostics {\n        printDiagnostic(diagnostic)\n      }\n      Terminal.print(\"\\(fixCount) \\(fixCount == 1 ? \"fix\" : \"fixes\") applied\")\n    }\n\n    # Print any errors and warnings\n    printLogSummary(log, diagnosticLimit)\n\n    # Optionally report a failure if any warnings were found\n    if options != null && options.warningsAreErrors {\n      return log.hasErrors || log.hasWarnings ? 1 : 0\n    } else {\n      return log.hasErrors ? 1 : 0\n    }\n  }\n\n  def printWithColor(color Terminal.Color, text string) {\n    Terminal.setColor(color)\n    Terminal.write(text)\n    Terminal.setColor(.DEFAULT)\n  }\n\n  def printError(text string) {\n    printWithColor(.RED, \"error: \")\n    printWithColor(.BOLD, text + \"\\n\")\n  }\n\n  def printNote(text string) {\n    printWithColor(.GRAY, \"note: \")\n    printWithColor(.BOLD, text + \"\\n\")\n  }\n\n  def printWarning(text string) {\n    printWithColor(.MAGENTA, \"warning: \")\n    printWithColor(.BOLD, text + \"\\n\")\n  }\n\n  def printUsage(parser Options.Parser) {\n    printWithColor(.GREEN, \"\\nusage: \")\n    printWithColor(.BOLD, \"skewc [flags] [inputs]\\n\")\n    Terminal.write(parser.usageText(Math.min(Terminal.width, 80)))\n  }\n\n  def printLogSummary(log Log, diagnosticLimit int) {\n    var hasErrors = log.hasErrors\n    var hasWarnings = log.hasWarnings\n    var summary = \"\"\n    if hasWarnings {\n      summary += PrettyPrint.plural(log.warningCount, \"warning\")\n      if hasErrors {\n        summary += \" and \"\n      }\n    }\n    if hasErrors {\n      summary += PrettyPrint.plural(log.errorCount, \"error\")\n    }\n    if hasWarnings || hasErrors {\n      Terminal.write(summary + \" generated\")\n      if log.wasWarningCount > 0 {\n        Terminal.write(\" (warnings are being treated as errors due to \\\"--warnings-are-errors\\\")\")\n      }\n      if diagnosticLimit > 0 && log.diagnostics.count > diagnosticLimit {\n        printWithColor(.GRAY, \" (only showing \\(PrettyPrint.plural(diagnosticLimit, \"message\")), use \\\"--message-limit=0\\\" to see all)\")\n      }\n      Terminal.write(\"\\n\")\n    }\n  }\n\n  def readSources(log Log, normalArguments List<Range>, inputs List<Source>, inputRanges List<Range>) {\n    var visit fn(Range, string, bool)\n\n    visit = (range, path, isExplicit) => {\n      if splitPath(path).entry.startsWith(\".\") {\n        return\n      }\n\n      # Directories\n      if IO.isDirectory(path) {\n        var entries = IO.readDirectory(path)\n        if entries == null {\n          log.commandLineErrorUnreadableFile(range, path)\n        }\n        for entry in entries {\n          if !entry.startsWith(\".\") {\n            visit(range, path + \"/\" + entry, false)\n          }\n        }\n      }\n\n      # Files (ignore non-skew files that aren't explicitly specified)\n      else if isExplicit || path.endsWith(\".sk\") {\n        var contents = IO.readFile(path)\n        if contents == null {\n          log.commandLineErrorUnreadableFile(range, path)\n        } else {\n          inputs.append(Source.new(path, contents))\n          inputRanges.append(range)\n        }\n      }\n    }\n\n    # Recursively visit input directories\n    for range in normalArguments {\n      visit(range, range.toString, true)\n    }\n  }\n\n  def parseOptions(log Log, parser Options.Parser, arguments List<string>) CompilerOptions {\n    # Configure the parser\n    parser.define(.BOOL, .HELP, \"--help\", \"Prints this message.\").aliases([\"-help\", \"?\", \"-?\", \"-h\", \"-H\", \"/?\", \"/h\", \"/H\"])\n    parser.define(.STRING, .TARGET, \"--target\", \"Sets the target format. Valid targets are \\(joinKeys(VALID_TARGETS.keys)).\")\n    parser.define(.STRING, .OUTPUT_FILE, \"--output-file\", \"Combines all output into a single file. Mutually exclusive with --output-dir.\")\n    parser.define(.STRING, .OUTPUT_DIRECTORY, \"--output-dir\", \"Places all output files in the specified directory. Mutually exclusive with --output-file.\")\n    parser.define(.BOOL, .NO_OUTPUT, \"--no-output\", \"Stops after the type checking pass and does not generate any output.\")\n    parser.define(.BOOL, .RELEASE, \"--release\", \"Implies --js-mangle, --js-minify, --fold-constants, --inline-functions, --globalize-functions, and --define:RELEASE=true.\")\n    parser.define(.BOOL, .VERBOSE, \"--verbose\", \"Prints out information about the compilation.\")\n    parser.define(.BOOL, .VERSION, \"--version\", \"Prints the current compiler version (\\(VERSION)) and exits.\")\n    parser.define(.INT, .MESSAGE_LIMIT, \"--message-limit\", \"Sets the maximum number of messages to report. \" +\n      \"Pass 0 to disable the message limit. The default is \\(DEFAULT_MESSAGE_LIMIT).\")\n    parser.define(.STRING_LIST, .DEFINE, \"--define\", \"Override variable values at compile time.\")\n    parser.define(.BOOL, .JS_MANGLE, \"--js-mangle\", \"Transforms emitted JavaScript to be as small as possible. The \\\"@export\\\" annotation prevents renaming a symbol.\")\n    parser.define(.BOOL, .JS_MINIFY, \"--js-minify\", \"Remove whitespace when compiling to JavaScript.\")\n    parser.define(.BOOL, .JS_SOURCE_MAP, \"--js-source-map\", \"Generates a source map when targeting JavaScript. \" +\n      \"The source map is saved with the \\\".map\\\" extension in the same directory as the main output file.\")\n    parser.define(.BOOL, .FOLD_CONSTANTS, \"--fold-constants\", \"Evaluates constants at compile time and removes dead code inside functions.\")\n    parser.define(.BOOL, .INLINE_FUNCTIONS, \"--inline-functions\", \"Uses heuristics to automatically inline simple global functions.\")\n    parser.define(.BOOL, .GLOBALIZE_FUNCTIONS, \"--globalize-functions\", \"Convert instance functions to global functions for better inlining.\")\n    parser.define(.BOOL, .FIX_ALL, \"--fix-all\", \"Attempt to automatically fix as many errors and warnings as possible. \" +\n      \"THIS WILL WRITE OVER YOUR SOURCE CODE. Make sure you know what you're doing.\")\n    parser.define(.BOOL, .IGNORED_COMMENT_WARNING, \"--ignored-comment-warning\", \"Warn when the compiler doesn't store a comment in the parse tree.\")\n    parser.define(.BOOL, .WARNINGS_ARE_ERRORS, \"--warnings-are-errors\", \"Turns warnings into errors.\")\n\n    # Parse the command line arguments\n    parser.parse(log, arguments)\n    if log.hasErrors {\n      return null\n    }\n\n    # Early-out when printing the usage text\n    if parser.boolForOption(.HELP, arguments.isEmpty) {\n      printUsage(parser)\n      return null\n    }\n\n    # Early-out when printing the version\n    if parser.boolForOption(.VERSION, false) {\n      Terminal.print(VERSION)\n      return null\n    }\n\n    # Set up the options for the compiler\n    var options = CompilerOptions.new\n    var releaseFlag = parser.boolForOption(.RELEASE, false)\n    options.foldAllConstants = parser.boolForOption(.FOLD_CONSTANTS, releaseFlag)\n    options.globalizeAllFunctions = parser.boolForOption(.GLOBALIZE_FUNCTIONS, releaseFlag)\n    options.inlineAllFunctions = parser.boolForOption(.INLINE_FUNCTIONS, releaseFlag)\n    options.jsMangle = parser.boolForOption(.JS_MANGLE, releaseFlag)\n    options.jsMinify = parser.boolForOption(.JS_MINIFY, releaseFlag)\n    options.jsSourceMap = parser.boolForOption(.JS_SOURCE_MAP, false)\n    options.stopAfterResolve = parser.boolForOption(.NO_OUTPUT, false)\n    options.verbose = parser.boolForOption(.VERBOSE, false)\n    options.warnAboutIgnoredComments = parser.boolForOption(.IGNORED_COMMENT_WARNING, false)\n    options.warningsAreErrors = parser.boolForOption(.WARNINGS_ARE_ERRORS, false)\n\n    # Prepare the defines\n    if releaseFlag {\n      options.define(\"RELEASE\", \"true\")\n    }\n    for range in parser.rangeListForOption(.DEFINE) {\n      var name = range.toString\n      var equals = name.indexOf(\"=\")\n      if equals < 0 {\n        log.commandLineErrorExpectedDefineValue(range, name)\n        continue\n      }\n      options.defines[name.slice(0, equals)] = Define.new(range.fromStart(equals), range.fromEnd(name.count - equals - 1))\n    }\n\n    # There must be at least one source file\n    var end = parser.source.contents.count\n    var trailingSpace = Range.new(parser.source, end - 1, end)\n    if parser.normalArguments.isEmpty && !options.stopAfterResolve {\n      log.commandLineErrorNoInputFiles(trailingSpace)\n    }\n\n    # Parse the output location\n    if !options.stopAfterResolve {\n      var outputFile = parser.rangeForOption(.OUTPUT_FILE)\n      var outputDirectory = parser.rangeForOption(.OUTPUT_DIRECTORY)\n      if outputFile == null && outputDirectory == null {\n        log.commandLineErrorMissingOutput(trailingSpace, \"--output-file\", \"--output-dir\")\n      } else if outputFile != null && outputDirectory != null {\n        log.commandLineErrorDuplicateOutput(outputFile.start > outputDirectory.start ? outputFile : outputDirectory, \"--output-file\", \"--output-dir\")\n      } else if outputFile != null {\n        options.outputFile = outputFile.toString\n      } else {\n        options.outputDirectory = outputDirectory.toString\n      }\n    }\n\n    # Check the target format\n    var target = parser.rangeForOption(.TARGET)\n    if target != null {\n      options.target = parseEnum<CompilerTarget>(log, \"target\", VALID_TARGETS, target, null)\n    } else if !options.createTargetFromExtension {\n      log.commandLineErrorMissingTarget(trailingSpace)\n    }\n\n    return options\n  }\n\n  def applyFixes(log Log, applyLog Log, rangeForSource fn(Source) Range) int {\n    var fixCount = 0\n\n    # Collect diagnostics by source file\n    var map StringMap<List<Diagnostic>> = {}\n    for diagnostic in log.diagnostics {\n      if diagnostic.range != null && diagnostic.fixes != null && diagnostic.fixes.count == 1 {\n        var name = diagnostic.range.source.name\n        var diagnostics = map.get(name, null)\n        if diagnostics == null {\n          map[name] = diagnostics = []\n        }\n        diagnostics.append(diagnostic)\n      }\n    }\n\n    # Apply for each source file\n    for diagnostics in map.values {\n      var source = diagnostics.first.range.source\n      var contents = source.contents\n      diagnostics.sort((a, b) => b.range.start <=> a.range.start)\n\n      # Apply fixes in reverse to avoid issues with changing offsets\n      var last = contents.count\n      for i in 0..diagnostics.count {\n        var fix = diagnostics[i].fixes.first\n\n        # Typo correction isn't robust enough right now to fix automatically\n        if fix.kind == .SYMBOL_TYPO || fix.range.end > last {\n          continue\n        }\n        contents = contents.slice(0, fix.range.start) + fix.replacement + contents.slice(fix.range.end)\n        last = fix.range.start\n        fixCount++\n      }\n\n      # Write over the source file in place\n      if !IO.writeFile(source.name, contents) {\n        applyLog.commandLineErrorUnwritableFile(rangeForSource(source), source.name)\n      }\n    }\n\n    return fixCount\n  }\n\n  class Log {\n    def commandLineErrorExpectedDefineValue(range Range, name string) {\n      append(newError(range, \"Use \\\"--define:\\(name)=___\\\" to provide a value\"))\n    }\n\n    def commandLineErrorMissingOutput(range Range, first string, second string) {\n      append(newError(range, \"Specify the output location using either \\\"\\(first)\\\" or \\\"\\(second)\\\"\"))\n    }\n\n    def commandLineErrorDuplicateOutput(range Range, first string, second string) {\n      append(newError(range, \"Cannot specify both \\\"\\(first)\\\" and \\\"\\(second)\\\"\"))\n    }\n\n    def commandLineErrorUnreadableFile(range Range, name string) {\n      append(newError(range, \"Could not read from \\\"\\(name)\\\"\"))\n    }\n\n    def commandLineErrorUnwritableFile(range Range, name string) {\n      append(newError(range, \"Could not write to \\\"\\(name)\\\"\"))\n    }\n\n    def commandLineErrorNoInputFiles(range Range) {\n      append(newError(range, \"Missing input files\"))\n    }\n\n    def commandLineErrorMissingTarget(range Range) {\n      append(newError(range, \"Specify the target format using \\\"--target\\\"\"))\n    }\n\n    def commandLineErrorInvalidEnum(range Range, name string, found string, expected List<string>) {\n      append(newError(range, \"Invalid \\(name) \\\"\\(found)\\\", must be either \\(PrettyPrint.joinQuoted(expected, \"or\"))\"))\n    }\n  }\n\n  def joinKeys(keys List<string>) string {\n    keys.sort(SORT_STRINGS)\n    return PrettyPrint.joinQuoted(keys, \"and\")\n  }\n\n  def parseEnum<T>(log Log, name string, map StringMap<T>, range Range, defaultValue T) T {\n    if range != null {\n      var key = range.toString\n      if key in map {\n        return map[key]\n      }\n      var keys = map.keys\n      keys.sort(SORT_STRINGS) # Sort so the order is deterministic\n      log.commandLineErrorInvalidEnum(range, name, key, keys)\n    }\n    return defaultValue\n  }\n\n  const VALID_TARGETS = {\n    \"cpp\": CPlusPlusTarget.new,\n    \"cs\": CSharpTarget.new,\n    \"ts\": TypeScriptTarget.new,\n    \"js\": JavaScriptTarget.new,\n    \"lisp-tree\": LispTreeTarget.new,\n  }\n}\n"
  },
  {
    "path": "src/driver/tests.sk",
    "content": "namespace Skew.Tests {\n  class CompilerTest : Unit.Test {\n    var _input string\n    var _expected string\n    var _options = CompilerOptions.new\n\n    over run {\n      rename(compactWhitespace(_input))\n      var log = Log.new\n      var result = compile(log, _options, [Source.new(\"<stdin>\", _input)])\n      var output string\n\n      if result.outputs.isEmpty {\n        output = log.toString + log.fixesToString\n      } else {\n        output = \"\\n\".join(result.outputs.map<string>(source => (source.name == null ? \"\" : \"[\\(source.name)]\\n\") + source.contents))\n      }\n\n      expectString(trimNewlines(_expected), trimNewlines(output))\n    }\n\n    def cpp CompilerTest {\n      _options.target = CPlusPlusTarget.new\n      return self\n    }\n\n    def csharp CompilerTest {\n      _options.target = CSharpTarget.new\n      return self\n    }\n\n    def ts CompilerTest {\n      _options.target = TypeScriptTarget.new\n      return self\n    }\n\n    def js CompilerTest {\n      _options.target = JavaScriptTarget.new\n      return self\n    }\n\n    def jsMangle CompilerTest {\n      _options.target = JavaScriptTarget.new\n      _options.jsMangle = true\n      _options.define(\"RELEASE\", \"true\")\n      return self\n    }\n\n    def jsMinify CompilerTest {\n      _options.target = JavaScriptTarget.new\n      _options.jsMinify = true\n      return self\n    }\n\n    def foldAllConstants CompilerTest {\n      _options.foldAllConstants = true\n      return self\n    }\n\n    def globalizeAllFunctions CompilerTest {\n      _options.globalizeAllFunctions = true\n      return self\n    }\n\n    def inlineAllFunctions CompilerTest {\n      _options.inlineAllFunctions = true\n      return self\n    }\n  }\n\n  class IDETest : Unit.Test {\n    var _input string\n    var _callback fn(IDETest, fn(string, string))\n    var _source Source = null\n    var _result CompilerResult = null\n\n    over run {\n      rename(compactWhitespace(_input))\n      var log = Log.new\n      var options = CompilerOptions.new\n      options.stopAfterResolve = true\n      _source = Source.new(\"<stdin>\", _input)\n      _result = compile(log, options, [_source])\n      expectString(\"\", log.toString)\n      _callback(self, (a, b) => expectString(a, b))\n    }\n\n    def tooltipQuery(line int, column int) string {\n      var index = _source.lineColumnToIndex(line, column)\n      if index == -1 {\n        return \"error: The location \\\"\\(line):\\(column)\\\" could not be found in the input\"\n      }\n\n      var query = IDE.SymbolQuery.new(_source, index)\n      query.run(_result.global)\n      if query.symbol != null {\n        return query.generateTooltip\n      }\n\n      return \"\"\n    }\n\n    def definitionQuery(line int, column int) string {\n      var index = _source.lineColumnToIndex(line, column)\n      if index == -1 {\n        return \"error: The location \\\"\\(line):\\(column)\\\" could not be found in the input\"\n      }\n\n      var query = IDE.SymbolQuery.new(_source, index)\n      query.run(_result.global)\n      if query.symbol != null {\n        return query.symbol.range.locationString\n      }\n\n      return \"\"\n    }\n\n    def renameQuery(line int, column int) string {\n      var index = _source.lineColumnToIndex(line, column)\n      if index == -1 {\n        return \"error: The location \\\"\\(line):\\(column)\\\" could not be found in the input\"\n      }\n\n      var query = IDE.RenameQuery.new(_source, index)\n      query.run(_result.global)\n      if query.ranges != null {\n        return \", \".join(query.ranges.map<string>(range => range.locationString))\n      }\n\n      return \"\"\n    }\n\n    def signatureQuery(line int, column int) string {\n      var index = _source.lineColumnToIndex(line, column)\n      if index == -1 {\n        return \"error: The location \\\"\\(line):\\(column)\\\" could not be found in the input\"\n      }\n\n      var query = IDE.SignatureQuery.new(_source, index)\n      query.run(_result.global)\n      if query.signature != null {\n        var signature = query.signatureString\n        var argument = query.argumentStrings[query.argumentIndex]\n        var position = signature.indexOf(argument)\n        if position != -1 {\n          return \"\\(signature.slice(0, position))[\\(argument)]\\(signature.slice(position + argument.count))\"\n        }\n      }\n\n      return \"\"\n    }\n  }\n\n  class CompletionTest : Unit.Test {\n    var _input string\n    var _line int\n    var _column int\n    var _expected string\n\n    over run {\n      rename(compactWhitespace(_input))\n      var log = Log.new\n      var source = Source.new(\"<stdin>\", _input)\n      var index = source.lineColumnToIndex(_line, _column)\n\n      if index == -1 {\n        expectString(trimNewlines(_expected), \"error: The location \\\"\\(_line):\\(_column)\\\" could not be found in the input\")\n      }\n\n      else {\n        var options = CompilerOptions.new\n        options.stopAfterResolve = true\n        options.completionContext = CompletionContext.new(source, index)\n        compile(log, options, [source])\n\n        var builder = StringBuilder.new\n        var range = options.completionContext.range\n        builder.append(trimNewlines(log.toString))\n\n        if range != null {\n          var formatted = range.format(0)\n          var lastSpace = formatted.range.lastIndexOf(\" \")\n          var indent = lastSpace != -1 ? formatted.range.slice(0, lastSpace + 1) : \"\"\n          builder.append(\"\\n\\(range.locationString): completions:\\n\\(formatted.line)\\n\\(formatted.range)\")\n\n          for symbol in options.completionContext.completions {\n            builder.append(\"\\n\\(indent)[\\(symbol.name)]\")\n\n            var type = IDE.completionType(symbol)\n            if type != null {\n              builder.append(\" # \\\"\\(IDE.completionType(symbol))\\\"\")\n            }\n\n            if symbol.comments != null {\n              var nested = \"\\n\" + indent + \" \".repeat(symbol.name.count + 2) + \" #\"\n              for comment in symbol.comments {\n                if !comment.hasGapBelow {\n                  for line in comment.lines {\n                    builder.append(nested + (line.endsWith(\"\\n\") ? line.slice(0, line.count - 1) : line))\n                  }\n                }\n              }\n            }\n          }\n        }\n\n        expectString(trimNewlines(_expected), builder.toString)\n      }\n    }\n  }\n\n  class FormatTest : Unit.Test {\n    over run {\n      rename(compactWhitespace(_input))\n      var formatted = Range.new(Source.new(\"<stdin>\", _input), _start, _end).format(_maxLength)\n      expectString(trimNewlines(_expected), trimNewlines(formatted.line + \"\\n\" + formatted.range))\n    }\n\n    const _input string\n    const _expected string\n    const _start int\n    const _end int\n    const _maxLength int\n  }\n\n  class SimpleTest : Unit.Test {\n    over run {\n      _callback((a, b) => expectString(a, b))\n    }\n\n    const _callback fn(fn(string, string))\n  }\n\n  def trimNewlines(text string) string {\n    var length = text.count\n    var start = 0\n    var end = length\n    while start < length && text[start] == '\\n' {\n      start++\n    }\n    while start < end && text[end - 1] == '\\n' {\n      end--\n    }\n    return text.slice(start, end)\n  }\n\n  def compactWhitespace(text string) string {\n    var wasSpace = false\n    var result = \"\"\n    for i in 0..text.count {\n      var c = text[i]\n      if c != '\\n' && c != ' ' && c != '\\t' {\n        result += text.get(i)\n        wasSpace = false\n      } else if !wasSpace {\n        result += \" \"\n        wasSpace = true\n      }\n    }\n    return result\n  }\n\n  def test(input string, expected string) CompilerTest {\n    return CompilerTest.new(trimNewlines(input), expected)\n  }\n\n  def testFormat(input string, expected string, start int, end int, maxLength int) FormatTest {\n    return FormatTest.new(trimNewlines(input), expected, start, end, maxLength)\n  }\n\n  def testIDE(input string, callback fn(IDETest, fn(string, string))) IDETest {\n    return IDETest.new(trimNewlines(input), callback)\n  }\n\n  def testCompletion(input string, line int, column int, expected string) CompletionTest {\n    return CompletionTest.new(trimNewlines(input), line, column, expected)\n  }\n\n  def test(name string, callback fn(fn(string, string))) SimpleTest {\n    var test = SimpleTest.new(callback)\n    test.rename(name)\n    return test\n  }\n\n  def testExpect(text string, answer fn() bool, expected bool) Unit.Test {\n    return test(text, expectString => expectString(answer().toString, expected.toString))\n  }\n\n  def testExpect(text string, answer fn() int, expected int) Unit.Test {\n    return test(text, expectString => expectString(answer().toString, expected.toString))\n  }\n\n  def testExpect(text string, answer fn() double, expected double) Unit.Test {\n    return test(text, expectString => expectString(answer().toString, expected.toString))\n  }\n\n  def testExpect(text string, answer fn() string, expected string) Unit.Test {\n    return test(text, expectString => expectString(answer(), expected))\n  }\n\n  def testExpect(text string, answer fn() List<int>, expected List<int>) Unit.Test {\n    return test(text, expectString => expectString(toString(answer()), toString(expected)))\n  }\n\n  def testExpect(text string, answer fn() List<double>, expected List<double>) Unit.Test {\n    return test(text, expectString => expectString(toString(answer()), toString(expected)))\n  }\n\n  def testExpect(text string, answer fn() List<string>, expected List<string>) Unit.Test {\n    return test(text, expectString => expectString(toString(answer()), toString(expected)))\n  }\n\n  def testExpect(text string, answer fn() IntMap<double>, expected IntMap<double>) Unit.Test {\n    return test(text, expectString => expectString(toString(answer()), toString(expected)))\n  }\n\n  def testExpect(text string, answer fn() StringMap<double>, expected StringMap<double>) Unit.Test {\n    return test(text, expectString => expectString(toString(answer()), toString(expected)))\n  }\n\n  def toString(values List<int>) string {\n    return toString(values.map<string>(x => x.toString))\n  }\n\n  def toString(values List<double>) string {\n    return toString(values.map<string>(x => x.toString))\n  }\n\n  def toString(values List<string>) string {\n    return \"[\" + \", \".join(values) + \"]\"\n  }\n\n  def toString(node Node) string {\n    if node == null {\n      return \"null\"\n    }\n    var parts = [node.kind.toString]\n    for child = node.firstChild; child != null; child = child.nextSibling {\n      parts.append(toString(child))\n    }\n    return toString(parts)\n  }\n\n  def toString(value IntMap<double>) string {\n    var keys = value.keys\n    keys.sort((a, b) => a <=> b) # Sort so the order is deterministic\n    return toString(keys.map<string>(k => k.toString), keys.map<string>(k => value[k].toString))\n  }\n\n  def toString(value StringMap<double>) string {\n    var keys = value.keys\n    keys.sort((a, b) => a <=> b) # Sort so the order is deterministic\n    return toString(keys, keys.map<string>(k => value[k].toString))\n  }\n\n  def toString(keys List<string>, values List<string>) string {\n    assert(keys.count == values.count)\n    var parts List<string> = []\n    for i in 0..keys.count {\n      parts.append(keys[i] + \": \" + values[i])\n    }\n    return \"{\" + \", \".join(parts) + \"}\"\n  }\n\n  if TARGET == .JAVASCRIPT {\n    def fixRuntime {\n      dynamic.Error.stackTraceLimit = Math.INFINITY\n    }\n  } else {\n    def fixRuntime {\n    }\n  }\n\n  @entry if BUILD == .TEST\n  def testMain int {\n    fixRuntime\n\n    # End-to-end tests\n    testCPlusPlus\n    testCSharp\n    testIDE\n    testJavaScript\n    testJavaScriptMangle\n    testJavaScriptMinify\n    testParsing\n    testSimple\n\n    # Unit tests\n    testFormatting\n    testLevenshteinEditDistance\n    testLibrary\n    testNode\n    testQuoteReplacement\n    testRanges\n    testRuntime\n    testUnicode\n\n    var report = Unit.TerminalReport.new\n    Unit.Test.runAll(report)\n    return report.failedCount\n  }\n}\n"
  },
  {
    "path": "src/frontend/flex.l",
    "content": "%%\n\n\\n[ \\t\\r]*                        NEWLINE;\n[ \\t\\r]+                          WHITESPACE;\n#.*?                              COMMENT;\n\\/\\/.*?                           COMMENT_ERROR;\n\n\"as\"                              AS;\n\"break\"                           BREAK;\n\"case\"                            CASE;\n\"catch\"                           CATCH;\n\"const\"                           CONST;\n\"continue\"                        CONTINUE;\n\"default\"                         DEFAULT;\n\"dynamic\"                         DYNAMIC;\n\"else\"                            ELSE;\n\"false\"                           FALSE;\n\"finally\"                         FINALLY;\n\"for\"                             FOR;\n\"if\"                              IF;\n\"in\"                              IN;\n\"is\"                              IS;\n\"null\"                            NULL;\n\"return\"                          RETURN;\n\"super\"                           SUPER;\n\"switch\"                          SWITCH;\n\"throw\"                           THROW;\n\"true\"                            TRUE;\n\"try\"                             TRY;\n\"var\"                             VAR;\n\"while\"                           WHILE;\n\n\"[...]\"                           LIST;\n\"[new]\"                           LIST_NEW;\n\"{...}\"                           SET;\n\"{new}\"                           SET_NEW;\n\"[]=\"                             ASSIGN_INDEX;\n\"[]\"                              INDEX;\n\"(\"                               LEFT_PARENTHESIS;\n\")\"                               RIGHT_PARENTHESIS;\n\"{\"                               LEFT_BRACE;\n\"}\"                               RIGHT_BRACE;\n\"[\"                               LEFT_BRACKET;\n\"]\"                               RIGHT_BRACKET;\n\"=>\"                              ARROW;\n\"~\"                               TILDE;\n\"..\"                              DOT_DOT;\n\".\"                               DOT;\n\",\"                               COMMA;\n\"?=\"                              ASSIGN_NULL;\n\"??\"                              NULL_JOIN;\n\"?.\"                              NULL_DOT;\n\"?\"                               QUESTION_MARK;\n\"::\"                              DOUBLE_COLON;\n\":\"                               COLON;\n\";\"                               SEMICOLON;\n\"<>...</>\"                        XML_CHILD;\n\"</\"                              XML_START_CLOSE;\n\"/>\"                              XML_END_EMPTY;\n\"**=\"                             ASSIGN_POWER;\n\"+=\"                              ASSIGN_PLUS;\n\"-=\"                              ASSIGN_MINUS;\n\"*=\"                              ASSIGN_MULTIPLY;\n\"/=\"                              ASSIGN_DIVIDE;\n\"%%=\"                             ASSIGN_MODULUS;\n\"%=\"                              ASSIGN_REMAINDER;\n\"&=\"                              ASSIGN_BITWISE_AND;\n\"|=\"                              ASSIGN_BITWISE_OR;\n\"^=\"                              ASSIGN_BITWISE_XOR;\n\"<<=\"                             ASSIGN_SHIFT_LEFT;\n\">>>=\"                            ASSIGN_UNSIGNED_SHIFT_RIGHT;\n\">>=\"                             ASSIGN_SHIFT_RIGHT;\n\"**\"                              POWER;\n\"++\"                              INCREMENT;\n\"--\"                              DECREMENT;\n\"+\"                               PLUS;\n\"-\"                               MINUS;\n\"*\"                               MULTIPLY;\n\"/\"                               DIVIDE;\n\"%%\"                              MODULUS;\n\"%\"                               REMAINDER;\n\"||\"                              LOGICAL_OR;\n\"&&\"                              LOGICAL_AND;\n\"&\"                               BITWISE_AND;\n\"|\"                               BITWISE_OR;\n\"^\"                               BITWISE_XOR;\n\"<<\"                              SHIFT_LEFT;\n\">>>\"                             UNSIGNED_SHIFT_RIGHT;\n\">>\"                              SHIFT_RIGHT;\n\"!==\"                             NOT_EQUAL_ERROR;\n\"===\"                             EQUAL_ERROR;\n\"!=\"                              NOT_EQUAL;\n\"==\"                              EQUAL;\n\"<=>\"                             COMPARE;\n\"<=\"                              LESS_THAN_OR_EQUAL;\n\">=\"                              GREATER_THAN_OR_EQUAL;\n\"<\"                               LESS_THAN;\n\">\"                               GREATER_THAN;\n\"!\"                               NOT;\n\"=\"                               ASSIGN;\n\n['](\\\\.|[^\\\\'])*[']               CHARACTER;\n[\"](\\\\.|[^\\\\\"])*[\"]               STRING;\n@[A-Za-z_][A-Za-z0-9_]*           ANNOTATION;\n[A-Za-z_][A-Za-z0-9_]*            IDENTIFIER;\n[0-9]+\\.[0-9]+[eE][-+]?[0-9]+     DOUBLE;\n[0-9]+\\.[0-9]+                    DOUBLE;\n0b[0-1]+                          INT_BINARY;\n0o[0-7]+                          INT_OCTAL;\n0x[A-Fa-f0-9]+                    INT_HEX;\n[0-9]+[eE][-+]?[0-9]+             DOUBLE;\n[0-9]+                            INT;\n"
  },
  {
    "path": "src/frontend/flex.py",
    "content": "import os\nimport re\nimport sys\nimport tempfile\nimport subprocess\n\ndef _run_flex(source):\n  fd, path = tempfile.mkstemp()\n  os.close(fd)\n  flex = subprocess.Popen(['flex', '-B', '-7', '-o', path], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n  stdout, stderr = flex.communicate(input=source)\n  sys.stdout.write(stdout)\n  sys.stderr.write(stderr)\n  if flex.returncode:\n    raise Exception('flex failed to run')\n  output = open(path).read()\n  os.remove(path)\n  return output\n\ndef _find_array(source, name):\n  match = re.search(name + r'\\[\\d+\\]\\s*=[^{]*\\{([^}]*)\\}', source)\n  return map(int, match.groups(1)[0].split(','))\n\ndef _find_magic_number(source, pattern):\n  match = re.search(pattern, source)\n  return int(match.groups(1)[0])\n\ndef _find_actions(source):\n  matches = re.findall(r'case\\s+(\\d+)\\s*:\\s*(?:/\\*[^*]*\\*/)?\\s*YY_RULE_SETUP[^\\0]*?\\n(.*);\\s*YY_BREAK', source)\n  return [(int(m[0]), m[1]) for m in matches]\n\ndef compile(source):\n  output = _run_flex(source)\n  result = {}\n\n  # Comments from https://github.com/gobo-eiffel/gobo/blob/master/library/lexical/scanner/lx_compressed_tables.e\n  result['yy_accept'] = _find_array(output, 'yy_accept') # Accepting id list\n  result['yy_ec']     = _find_array(output, 'yy_ec') # ASCII to equivalence class\n  result['yy_meta']   = _find_array(output, 'yy_meta') # Meta equivalence classes which are sets of classes with identical transitions out of templates\n  result['yy_base']   = _find_array(output, 'yy_base') # Offsets into 'yy_nxt' for given states\n  result['yy_def']    = _find_array(output, 'yy_def') # Where to go if 'yy_chk' disallows 'yy_nxt' entry\n  result['yy_nxt']    = _find_array(output, 'yy_nxt') # States to enter upon reading symbol\n  result['yy_chk']    = _find_array(output, 'yy_chk') # Check value to see if 'yy_nxt' applies\n\n  result['yy_end_of_buffer'] = _find_magic_number(output, r'#define\\s+YY_END_OF_BUFFER\\s+(\\d+)')\n  result['jamstate'] = _find_magic_number(output, r'while\\s*\\(\\s*yy_current_state\\s*!=\\s*(\\d+)')\n  result['actions'] = _find_actions(output)\n\n  return result\n"
  },
  {
    "path": "src/frontend/lexer.py",
    "content": "import os\nimport flex\n\ntemplate = '''\n################################################################################\n#\n# This is a generated file, all edits will be lost!\n#\n################################################################################\n\nnamespace Skew {\n  enum TokenKind {\n%(actions)s\n  }\n\n  %(yy_accept)s\n  %(yy_ec)s\n  %(yy_meta)s\n  %(yy_base)s\n  %(yy_def)s\n  %(yy_nxt)s\n  %(yy_chk)s\n  %(jamstate)s\n  %(yy_accept_length)s\n}\n'''\n\ndef create_table(result, name, type=None):\n  return 'const %(name)s%(type)s = [%(entries)s]' % {\n    'type': ' ' + type if type else '',\n    'name': name,\n    'entries': ', '.join('%s' % x for x in result[name]),\n  }\n\n# Read and compile the input\npath = os.path.dirname(__file__)\nsource = open(os.path.join(path, 'flex.l')).read()\nresult = flex.compile(source)\n\n# Assume all actions are sequential and start at 1\nif [k for k, v in result['actions']] != range(1, len(result['actions']) + 1):\n  raise Exception('all actions are not sequential')\n\n# Assume ECHO is the last action\nif result['actions'][-1][1] != 'ECHO':\n  raise Exception('ECHO is not after the last action')\n\n# Assume yy_end_of_buffer is after the last action\nif result['yy_end_of_buffer'] != len(result['actions']) + 1:\n  raise Exception('yy_end_of_buffer is not after the last action')\n\n# Patch the results\nresult['actions'] = dict((k, v if v != 'ECHO' else 'ERROR') for k, v in result['actions'] + [(0, 'YY_INVALID_ACTION'), (result['yy_end_of_buffer'], 'END_OF_FILE')])\nresult['yy_accept'] = ['.%s' % result['actions'][x] for x in result['yy_accept']]\nresult['actions'] = '\\n'.join('    %s' % x for x in sorted(set(result['actions'].values())))\nresult['yy_accept_length'] = len(result['yy_accept'])\nresult['yy_accept'] = create_table(result, 'yy_accept', type='List<TokenKind>')\nresult['yy_ec'] = create_table(result, 'yy_ec')\nresult['yy_meta'] = create_table(result, 'yy_meta')\nresult['yy_base'] = create_table(result, 'yy_base')\nresult['yy_def'] = create_table(result, 'yy_def')\nresult['yy_nxt'] = create_table(result, 'yy_nxt')\nresult['yy_chk'] = create_table(result, 'yy_chk')\nresult['jamstate'] = 'const YY_JAM_STATE = %s' % result['jamstate']\nresult['yy_accept_length'] = 'const YY_ACCEPT_LENGTH = %s' % result['yy_accept_length']\n\n# Write the output\nopen(os.path.join(path, 'lexer.sk'), 'w').write(template.strip() % result + '\\n')\n"
  },
  {
    "path": "src/frontend/lexer.sk",
    "content": "################################################################################\n#\n# This is a generated file, all edits will be lost!\n#\n################################################################################\n\nnamespace Skew {\n  enum TokenKind {\n    ANNOTATION\n    ARROW\n    AS\n    ASSIGN\n    ASSIGN_BITWISE_AND\n    ASSIGN_BITWISE_OR\n    ASSIGN_BITWISE_XOR\n    ASSIGN_DIVIDE\n    ASSIGN_INDEX\n    ASSIGN_MINUS\n    ASSIGN_MODULUS\n    ASSIGN_MULTIPLY\n    ASSIGN_NULL\n    ASSIGN_PLUS\n    ASSIGN_POWER\n    ASSIGN_REMAINDER\n    ASSIGN_SHIFT_LEFT\n    ASSIGN_SHIFT_RIGHT\n    ASSIGN_UNSIGNED_SHIFT_RIGHT\n    BITWISE_AND\n    BITWISE_OR\n    BITWISE_XOR\n    BREAK\n    CASE\n    CATCH\n    CHARACTER\n    COLON\n    COMMA\n    COMMENT\n    COMMENT_ERROR\n    COMPARE\n    CONST\n    CONTINUE\n    DECREMENT\n    DEFAULT\n    DIVIDE\n    DOT\n    DOT_DOT\n    DOUBLE\n    DOUBLE_COLON\n    DYNAMIC\n    ELSE\n    END_OF_FILE\n    EQUAL\n    EQUAL_ERROR\n    ERROR\n    FALSE\n    FINALLY\n    FOR\n    GREATER_THAN\n    GREATER_THAN_OR_EQUAL\n    IDENTIFIER\n    IF\n    IN\n    INCREMENT\n    INDEX\n    INT\n    INT_BINARY\n    INT_HEX\n    INT_OCTAL\n    IS\n    LEFT_BRACE\n    LEFT_BRACKET\n    LEFT_PARENTHESIS\n    LESS_THAN\n    LESS_THAN_OR_EQUAL\n    LIST\n    LIST_NEW\n    LOGICAL_AND\n    LOGICAL_OR\n    MINUS\n    MODULUS\n    MULTIPLY\n    NEWLINE\n    NOT\n    NOT_EQUAL\n    NOT_EQUAL_ERROR\n    NULL\n    NULL_DOT\n    NULL_JOIN\n    PLUS\n    POWER\n    QUESTION_MARK\n    REMAINDER\n    RETURN\n    RIGHT_BRACE\n    RIGHT_BRACKET\n    RIGHT_PARENTHESIS\n    SEMICOLON\n    SET\n    SET_NEW\n    SHIFT_LEFT\n    SHIFT_RIGHT\n    STRING\n    SUPER\n    SWITCH\n    THROW\n    TILDE\n    TRUE\n    TRY\n    UNSIGNED_SHIFT_RIGHT\n    VAR\n    WHILE\n    WHITESPACE\n    XML_CHILD\n    XML_END_EMPTY\n    XML_START_CLOSE\n    YY_INVALID_ACTION\n  }\n\n  const yy_accept List<TokenKind> = [.YY_INVALID_ACTION, .YY_INVALID_ACTION, .YY_INVALID_ACTION, .END_OF_FILE, .ERROR, .WHITESPACE, .NEWLINE, .NOT, .ERROR, .COMMENT, .REMAINDER, .BITWISE_AND, .ERROR, .LEFT_PARENTHESIS, .RIGHT_PARENTHESIS, .MULTIPLY, .PLUS, .COMMA, .MINUS, .DOT, .DIVIDE, .INT, .INT, .COLON, .SEMICOLON, .LESS_THAN, .ASSIGN, .GREATER_THAN, .QUESTION_MARK, .ERROR, .IDENTIFIER, .LEFT_BRACKET, .RIGHT_BRACKET, .BITWISE_XOR, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .LEFT_BRACE, .BITWISE_OR, .RIGHT_BRACE, .TILDE, .WHITESPACE, .NEWLINE, .NOT_EQUAL, .YY_INVALID_ACTION, .STRING, .YY_INVALID_ACTION, .COMMENT, .MODULUS, .ASSIGN_REMAINDER, .LOGICAL_AND, .ASSIGN_BITWISE_AND, .YY_INVALID_ACTION, .CHARACTER, .YY_INVALID_ACTION, .POWER, .ASSIGN_MULTIPLY, .INCREMENT, .ASSIGN_PLUS, .DECREMENT, .ASSIGN_MINUS, .DOT_DOT, .COMMENT_ERROR, .ASSIGN_DIVIDE, .XML_END_EMPTY, .YY_INVALID_ACTION, .INT, .YY_INVALID_ACTION, .YY_INVALID_ACTION, .YY_INVALID_ACTION, .YY_INVALID_ACTION, .DOUBLE_COLON, .XML_START_CLOSE, .SHIFT_LEFT, .LESS_THAN_OR_EQUAL, .YY_INVALID_ACTION, .EQUAL, .ARROW, .GREATER_THAN_OR_EQUAL, .SHIFT_RIGHT, .NULL_DOT, .ASSIGN_NULL, .NULL_JOIN, .ANNOTATION, .IDENTIFIER, .YY_INVALID_ACTION, .INDEX, .YY_INVALID_ACTION, .ASSIGN_BITWISE_XOR, .AS, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IF, .IN, .IS, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .YY_INVALID_ACTION, .YY_INVALID_ACTION, .ASSIGN_BITWISE_OR, .LOGICAL_OR, .NOT_EQUAL_ERROR, .ASSIGN_MODULUS, .ASSIGN_POWER, .COMMENT_ERROR, .DOUBLE, .YY_INVALID_ACTION, .DOUBLE, .INT_BINARY, .INT_OCTAL, .INT_HEX, .ASSIGN_SHIFT_LEFT, .COMPARE, .YY_INVALID_ACTION, .EQUAL_ERROR, .ASSIGN_SHIFT_RIGHT, .UNSIGNED_SHIFT_RIGHT, .ANNOTATION, .YY_INVALID_ACTION, .ASSIGN_INDEX, .YY_INVALID_ACTION, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .FOR, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .TRY, .VAR, .IDENTIFIER, .YY_INVALID_ACTION, .YY_INVALID_ACTION, .YY_INVALID_ACTION, .YY_INVALID_ACTION, .ASSIGN_UNSIGNED_SHIFT_RIGHT, .YY_INVALID_ACTION, .YY_INVALID_ACTION, .IDENTIFIER, .CASE, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .ELSE, .IDENTIFIER, .IDENTIFIER, .NULL, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .TRUE, .IDENTIFIER, .YY_INVALID_ACTION, .YY_INVALID_ACTION, .YY_INVALID_ACTION, .DOUBLE, .YY_INVALID_ACTION, .LIST, .LIST_NEW, .BREAK, .CATCH, .CONST, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .FALSE, .IDENTIFIER, .IDENTIFIER, .SUPER, .IDENTIFIER, .THROW, .WHILE, .SET, .SET_NEW, .YY_INVALID_ACTION, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .IDENTIFIER, .RETURN, .SWITCH, .YY_INVALID_ACTION, .IDENTIFIER, .DEFAULT, .DYNAMIC, .FINALLY, .XML_CHILD, .CONTINUE, .YY_INVALID_ACTION]\n  const yy_ec = [0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 5, 6, 1, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 20, 20, 20, 20, 20, 21, 21, 22, 23, 24, 25, 26, 27, 28, 29, 29, 29, 29, 30, 29, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 32, 33, 34, 35, 31, 1, 36, 37, 38, 39, 40, 41, 31, 42, 43, 31, 44, 45, 46, 47, 48, 49, 31, 50, 51, 52, 53, 54, 55, 56, 57, 31, 58, 59, 60, 61, 1]\n  const yy_meta = [0, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 4, 4, 5, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1]\n  const yy_base = [0, 0, 0, 320, 321, 317, 316, 292, 57, 0, 56, 57, 55, 321, 321, 54, 55, 321, 52, 300, 58, 75, 81, 293, 321, 61, 44, 46, 82, 0, 0, 88, 321, 289, 262, 262, 70, 63, 266, 81, 85, 257, 269, 21, 66, 272, 265, 94, 88, 321, 321, 304, 303, 279, 109, 321, 300, 0, 277, 321, 321, 321, 110, 321, 298, 275, 321, 321, 321, 321, 321, 321, 0, 321, 321, 119, 130, 143, 109, 134, 0, 321, 321, 274, 272, 281, 271, 321, 321, 108, 321, 321, 321, 0, 0, 279, 269, 253, 321, 0, 252, 93, 244, 249, 242, 237, 242, 239, 235, 0, 0, 0, 239, 231, 233, 238, 230, 102, 229, 235, 261, 236, 321, 321, 321, 321, 321, 0, 147, 153, 160, 157, 164, 0, 321, 321, 259, 321, 321, 249, 0, 257, 321, 217, 235, 230, 231, 134, 232, 231, 226, 214, 228, 0, 218, 209, 221, 208, 211, 218, 0, 0, 212, 240, 200, 175, 238, 321, 219, 218, 207, 0, 208, 197, 205, 194, 200, 0, 205, 199, 0, 193, 192, 203, 185, 0, 199, 178, 177, 179, 183, 212, 321, 321, 0, 0, 0, 188, 181, 168, 0, 147, 144, 0, 147, 0, 0, 321, 321, 152, 104, 78, 87, 35, 0, 0, 63, 33, 0, 0, 0, 321, 0, 321, 204, 209, 214, 216, 219, 224, 227, 229]\n  const yy_def = [0, 223, 1, 223, 223, 223, 223, 223, 224, 225, 223, 223, 226, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 227, 228, 223, 223, 223, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 223, 223, 223, 223, 223, 223, 223, 224, 223, 224, 225, 223, 223, 223, 223, 226, 223, 226, 223, 223, 223, 223, 223, 223, 223, 229, 223, 223, 223, 223, 223, 223, 223, 230, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 231, 228, 223, 223, 223, 223, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 223, 223, 223, 223, 223, 223, 223, 229, 223, 223, 223, 223, 223, 230, 223, 223, 223, 223, 223, 223, 231, 223, 223, 223, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 223, 223, 223, 223, 223, 223, 223, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 223, 223, 223, 223, 223, 223, 223, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 223, 223, 223, 228, 228, 228, 228, 228, 228, 223, 228, 228, 228, 228, 223, 228, 0, 223, 223, 223, 223, 223, 223, 223, 223]\n  const yy_nxt = [0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 22, 22, 23, 24, 25, 26, 27, 28, 29, 30, 30, 30, 31, 4, 32, 33, 34, 35, 36, 37, 38, 39, 30, 40, 30, 30, 30, 41, 30, 30, 42, 43, 44, 30, 45, 46, 30, 30, 47, 48, 49, 50, 55, 58, 63, 60, 65, 69, 67, 86, 87, 88, 89, 222, 114, 72, 115, 70, 82, 66, 68, 59, 61, 73, 74, 83, 84, 85, 64, 221, 56, 75, 220, 76, 76, 76, 76, 75, 90, 76, 76, 76, 76, 103, 95, 77, 101, 91, 116, 92, 120, 77, 78, 122, 55, 77, 117, 106, 102, 63, 104, 77, 96, 79, 107, 219, 109, 131, 131, 108, 218, 80, 110, 138, 139, 97, 111, 128, 128, 128, 128, 121, 56, 64, 145, 146, 75, 123, 76, 76, 76, 76, 132, 132, 132, 159, 129, 217, 129, 160, 77, 130, 130, 130, 130, 128, 128, 128, 128, 216, 77, 130, 130, 130, 130, 131, 131, 165, 130, 130, 130, 130, 132, 132, 132, 173, 174, 165, 189, 215, 189, 214, 213, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 54, 54, 54, 54, 54, 57, 212, 57, 57, 57, 62, 62, 62, 62, 62, 93, 93, 94, 94, 94, 127, 211, 127, 127, 127, 133, 133, 140, 140, 140, 210, 209, 208, 207, 206, 205, 204, 203, 202, 201, 200, 199, 198, 197, 196, 195, 194, 193, 192, 191, 188, 187, 186, 185, 184, 183, 182, 181, 180, 179, 178, 177, 176, 175, 172, 171, 170, 169, 168, 167, 166, 164, 163, 162, 161, 158, 157, 156, 155, 154, 153, 152, 151, 150, 149, 148, 147, 144, 143, 142, 141, 137, 136, 135, 134, 126, 223, 125, 223, 124, 52, 51, 119, 118, 113, 112, 105, 100, 99, 98, 81, 71, 53, 52, 51, 223, 3, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223]\n  const yy_chk = [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 10, 12, 11, 15, 18, 16, 26, 26, 27, 27, 217, 43, 20, 43, 18, 25, 15, 16, 10, 11, 20, 20, 25, 25, 25, 12, 216, 8, 21, 213, 21, 21, 21, 21, 22, 28, 22, 22, 22, 22, 37, 31, 21, 36, 28, 44, 28, 47, 22, 21, 48, 54, 21, 44, 39, 36, 62, 37, 22, 31, 21, 39, 212, 40, 78, 78, 39, 211, 21, 40, 89, 89, 31, 40, 75, 75, 75, 75, 47, 54, 62, 101, 101, 76, 48, 76, 76, 76, 76, 79, 79, 79, 117, 77, 210, 77, 117, 76, 77, 77, 77, 77, 128, 128, 128, 128, 209, 76, 129, 129, 129, 129, 131, 131, 128, 130, 130, 130, 130, 132, 132, 132, 147, 147, 128, 165, 204, 165, 202, 201, 165, 165, 165, 165, 189, 189, 189, 189, 190, 190, 190, 190, 224, 224, 224, 224, 224, 225, 199, 225, 225, 225, 226, 226, 226, 226, 226, 227, 227, 228, 228, 228, 229, 198, 229, 229, 229, 230, 230, 231, 231, 231, 197, 191, 188, 187, 186, 184, 183, 182, 181, 179, 178, 176, 175, 174, 173, 172, 170, 169, 168, 166, 164, 163, 162, 159, 158, 157, 156, 155, 154, 152, 151, 150, 149, 148, 146, 145, 144, 143, 141, 139, 136, 121, 120, 119, 118, 116, 115, 114, 113, 112, 108, 107, 106, 105, 104, 103, 102, 100, 97, 96, 95, 86, 85, 84, 83, 65, 64, 58, 56, 53, 52, 51, 46, 45, 42, 41, 38, 35, 34, 33, 23, 19, 7, 6, 5, 3, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223]\n  const YY_JAM_STATE = 223\n  const YY_ACCEPT_LENGTH = 224\n}\n"
  },
  {
    "path": "src/frontend/log.sk",
    "content": "namespace Skew {\n  enum DiagnosticKind {\n    ERROR\n    WARNING\n  }\n\n  class Fix {\n    const kind FixKind\n    const range Range\n    const description string\n    const replacement string\n  }\n\n  enum FixKind {\n    ARRAY_SYNTAX\n    CASE_BRACES\n    CASE_COMMA\n    EXTENDS_IMPLEMENTS\n    EXTRA_CALL_PARENTHESES\n    EXTRA_CAST\n    EXTRA_COLON\n    EXTRA_COMMA\n    EXTRA_DEF_PARENTHESES\n    EXTRA_SEMICOLON\n    FOR_LOOP_VAR\n    MISSING_DEF\n    MISSING_VAR\n    NEED_VAR\n    NEW_OPERATOR\n    NEW_RETURN_TYPE\n    OCTAL_ADD_PREFIX\n    OCTAL_REMOVE_ZEROS\n    OPERATOR_TYPO\n    SELF_VS_THIS\n    SINGLE_QUOTES\n    SLASH_COMMENT\n    SYMBOL_TYPO\n    UNNECESSARY_PARENTHESES\n    VOID_RETURN\n  }\n\n  class Diagnostic {\n    const kind DiagnosticKind\n    const range Range\n    const text string\n    const wasWarning bool\n    var noteRange Range = null\n    var noteText = \"\"\n    var fixes List<Fix> = null\n\n    def withFix(kind FixKind, range Range, description string, replacement string) Diagnostic {\n      if range != null && replacement != null {\n        (fixes ?= []).append(Fix.new(kind, range, description, replacement))\n      }\n      return self\n    }\n\n    def withNote(range Range, text string) Diagnostic {\n      if range != null {\n        noteRange = range\n        noteText = text\n      }\n      return self\n    }\n  }\n\n  namespace Diagnostic {\n    def format(kind string, range Range, text string) string {\n      if range == null {\n        return \"\\(kind): \\(text)\\n\"\n      }\n      var formatted = range.format(0)\n      return \"\\(range.locationString): \\(kind): \\(text)\\n\\(formatted.line)\\n\\(formatted.range)\\n\"\n    }\n  }\n\n  class Log {\n    var diagnostics List<Diagnostic> = []\n    var appendCallback fn(Diagnostic) = null\n    var warningsAreErrors = false\n    var _warningCount = 0\n    var _errorCount = 0\n    var _wasWarningCount = 0\n\n    def isEmpty bool {\n      return diagnostics.isEmpty\n    }\n\n    def hasErrors bool {\n      return _errorCount != 0\n    }\n\n    def hasWarnings bool {\n      return _warningCount != 0\n    }\n\n    def warningCount int {\n      return _warningCount\n    }\n\n    def errorCount int {\n      return _errorCount\n    }\n\n    def wasWarningCount int {\n      return _wasWarningCount\n    }\n\n    def newError(range Range, text string) Diagnostic {\n      return Diagnostic.new(.ERROR, range, text, false)\n    }\n\n    def newWarning(range Range, text string) Diagnostic {\n      return Diagnostic.new(warningsAreErrors ? .ERROR : .WARNING, range, text, warningsAreErrors)\n    }\n\n    def toString string {\n      var builder = StringBuilder.new\n\n      # Emit the log assuming an infinite terminal width\n      for diagnostic in diagnostics {\n        builder.append(Diagnostic.format(diagnostic.kind == .ERROR ? \"error\" : \"warning\", diagnostic.range, diagnostic.text))\n\n        # Append notes after the diagnostic they apply to\n        if diagnostic.noteRange != null {\n          builder.append(Diagnostic.format(\"note\", diagnostic.noteRange, diagnostic.noteText))\n        }\n      }\n\n      return builder.toString\n    }\n\n    # This is useful for visualizing the diagnostic fixes\n    def fixesToString string {\n      var builder = StringBuilder.new\n\n      for diagnostic in diagnostics {\n        if diagnostic.fixes != null {\n          for fix in diagnostic.fixes {\n            var formatted = fix.range.format(0)\n            var index = formatted.range.lastIndexOf(\" \")\n            var indent = index != -1 ? formatted.range.slice(0, index + 1) : \"\"\n            builder.append(fix.range.locationString + \": fix: \" + fix.description + \"\\n\")\n            builder.append(\"\\(formatted.line)\\n\\(formatted.range)\\n\\(indent)[\\(fix.replacement)]\\n\")\n          }\n        }\n      }\n\n      return builder.toString\n    }\n\n    def append(diagnostic Diagnostic) {\n      diagnostics.append(diagnostic)\n      if diagnostic.kind == .ERROR {\n        _errorCount++\n      } else {\n        _warningCount++\n      }\n      if diagnostic.wasWarning {\n        _wasWarningCount++\n      }\n      if appendCallback != null {\n        appendCallback(diagnostic)\n      }\n    }\n  }\n\n  # Syntax warnings can be thought of as linting\n  class Log {\n    def syntaxWarningIgnoredCommentInParser(range Range) {\n      append(newWarning(range, \"This comment was ignored by the parser\"))\n    }\n\n    def syntaxWarningIgnoredCommentInEmitter(range Range) {\n      append(newWarning(range, \"This comment was ignored by the emitter\"))\n    }\n\n    def syntaxWarningOctal(range Range) {\n      var text = range.toString\n      while text.startsWith(\"0\") {\n        text = text.slice(1)\n      }\n      append(newWarning(range, \"Number interpreted as decimal (use the prefix \\\"0o\\\" for octal numbers)\")\n        .withFix(.OCTAL_REMOVE_ZEROS, range, \"Remove the leading zeros to avoid confusion\", text)\n        .withFix(.OCTAL_ADD_PREFIX, range, \"Add the prefix \\\"0o\\\" to interpret the number as octal\", \"0o\" + text))\n    }\n\n    def syntaxWarningExtraParentheses(range Range) {\n      var leftSpace = range.rangeIncludingLeftWhitespace.start == range.start ? \" \" : \"\"\n      var rightSpace = range.rangeIncludingRightWhitespace.end == range.end ? \" \" : \"\"\n      var text = range.toString\n      append(\n        newWarning(range, \"Unnecessary parentheses\")\n        .withFix(.UNNECESSARY_PARENTHESES, range, \"Remove parentheses\", leftSpace + text.slice(1, text.count - 1) + rightSpace))\n    }\n\n    def syntaxWarningExtraComma(range Range) {\n      append(\n        newWarning(range, \"Unnecessary comma\")\n        .withFix(.EXTRA_COMMA, range, \"Remove comma\", \"\"))\n    }\n  }\n\n  class Log {\n    def syntaxErrorInvalidEscapeSequence(range Range) {\n      append(newError(range, \"Invalid escape sequence\"))\n    }\n\n    def syntaxErrorIntegerLiteralTooLarge(range Range) {\n      append(newError(range, \"Integer literal is too big to fit in 32 bits\"))\n    }\n\n    def syntaxErrorInvalidCharacter(range Range) {\n      append(\n        newError(range, \"Use double quotes for strings (single quotes are for character literals)\")\n        .withFix(.SINGLE_QUOTES, range, \"Replace single quotes with double quotes\", replaceSingleQuotesWithDoubleQuotes(range.toString)))\n    }\n\n    def syntaxErrorExtraData(range Range, text string) {\n      append(newError(range, \"Syntax error \\\"\\(text == \"\\\"\" ? \"\\\\\\\"\": text)\\\"\"))\n    }\n\n    def syntaxErrorExtraColonBeforeType(range Range) {\n      append(\n        newError(range, \"Do not use a colon before a type expression\")\n        .withFix(.EXTRA_COLON, range, \"Remove the colon\", \"\"))\n    }\n\n    def syntaxErrorNewOperator(range Range, correction string) {\n      append(\n        newError(range, \"There is no \\\"new\\\" operator, use \\\"\\(correction)\\\" instead\")\n        .withFix(.NEW_OPERATOR, range, \"Replace with \\\"\\(correction)\\\"\", correction))\n    }\n\n    def syntaxErrorExtendsKeyword(range Range) {\n      append(\n        newError(range, \"Use \\\":\\\" instead of \\\"extends\\\" to indicate a base class\")\n        .withFix(.EXTENDS_IMPLEMENTS, range, \"Replace \\\"extends\\\" with \\\":\\\"\", \":\"))\n    }\n\n    def syntaxErrorImplementsKeyword(range Range) {\n      append(\n        newError(range, \"Use \\\"::\\\" instead of \\\"implements\\\" to indicate implemented interfaces\")\n        .withFix(.EXTENDS_IMPLEMENTS, range, \"Replace \\\"implements\\\" with \\\"::\\\"\", \"::\"))\n    }\n\n    def syntaxErrorMissingVar(range Range) {\n      append(\n        newError(range, \"Use \\\"var\\\" before variable declarations\")\n        .withFix(.MISSING_VAR, range, \"Insert \\\"var\\\"\", \"var \\(range)\"))\n    }\n\n    def syntaxErrorMissingDef(range Range) {\n      append(\n        newError(range, \"Use \\\"def\\\" before function declarations\")\n        .withFix(.MISSING_DEF, range, \"Insert \\\"def\\\"\", \"def \\(range)\"))\n    }\n\n    def syntaxErrorStaticKeyword(range Range, parentKind SymbolKind, parentName string) {\n      append(\n        newError(range, parentKind == .OBJECT_GLOBAL || parentKind == .OBJECT_NAMESPACE\n          ? \"There is no \\\"static\\\" keyword\"\n          : \"There is no \\\"static\\\" keyword (declare this symbol in a namespace called \\\"\\(parentName)\\\" instead)\"))\n    }\n\n    def syntaxErrorPublicKeyword(range Range) {\n      append(newError(range, \"There is no \\\"public\\\" keyword\"))\n    }\n\n    def syntaxErrorPrivateOrProtected(range Range) {\n      append(newError(range, \"There is no \\\"\\(range)\\\" keyword (to give something protected access, use a name starting with \\\"_\\\" instead)\"))\n    }\n\n    def syntaxErrorExpectedCommaBetweenCases(range Range) {\n      append(\n        newError(range, \"Use a comma between multiple values in a case statement (example: \\\"case 1, 2, 3 { ... }\\\")\")\n        .withFix(.CASE_COMMA, range, \"Replace this with a comma\", \",\"))\n    }\n\n    def syntaxErrorColonAfterCaseOrDefault(range Range, breakRange Range) {\n      var diagnostic = newError(range, \"Surround the body of case and default statements with \\\"{\\\" and \\\"}\\\" instead of \\\":\\\" and \\\"break\\\"\")\n\n      if breakRange != null {\n        assert(range.source == breakRange.source)\n\n        var start = range.source.indexToLineColumn(range.end)\n        var end = range.source.indexToLineColumn(breakRange.start)\n        var text = range.source.contents.slice(range.end, breakRange.start)\n\n        # Use the indentation of the case statement for the \"}\"\n        if start.line < end.line {\n          text = text.slice(0, text.count - end.column) +\n            indentOfLine(range.source.contentsOfLine(start.line)) +\n            lineWithoutIndent(range.source.contentsOfLine(end.line).slice(0, end.column))\n        }\n\n        diagnostic.withFix(.CASE_BRACES, Range.span(range.rangeIncludingLeftWhitespace, breakRange),\n          \"Replace \\\":\\\" and \\\"break\\\" with \\\"{\\\" and \\\"}\\\"\", \" {\" + text + \"}\")\n      }\n\n      append(diagnostic)\n    }\n\n    def syntaxErrorOperatorTypo(range Range, correction string) {\n      append(\n        newError(range, \"Use the \\\"\\(correction)\\\" operator instead\")\n        .withFix(.OPERATOR_TYPO, range, \"Replace with \\\"\\(correction)\\\"\", correction))\n    }\n\n    def syntaxErrorExtraVarInForLoop(range Range) {\n      append(\n        newError(range, \"The \\\"var\\\" keyword is unnecessary here since for loops automatically declare their variables\")\n        .withFix(.FOR_LOOP_VAR, range?.rangeIncludingRightWhitespace, \"Remove \\\"var\\\"\", \"\"))\n    }\n\n    def syntaxErrorWrongListSyntax(range Range, correction string) {\n      append(\n        newError(range, \"The array type is \\\"List<T>\\\"\")\n        .withFix(.ARRAY_SYNTAX, range, \"Replace with \\\"\\(correction)\\\"\", correction))\n    }\n\n    def syntaxErrorSlashComment(range Range) {\n      var text = range.toString\n      var last = text.count - 1\n      assert(text.startsWith(\"//\"))\n      if text[last] == '\\n' {\n        text = text.slice(0, last)\n        range = range.fromStart(last)\n      }\n\n      # Change a run of \"////\" into \"####\"\n      var replacement = \"\"\n      for i in 1..text.count {\n        if text[i] == '/' {\n          replacement += \"#\"\n        } else {\n          replacement += text.slice(i)\n          break\n        }\n      }\n\n      append(\n        newError(range, \"Comments start with \\\"#\\\" instead of \\\"//\\\"\")\n        .withFix(.SLASH_COMMENT, range, \"Replace \\\"//\\\" with \\\"#\\\"\", replacement))\n    }\n\n    def syntaxErrorUnexpectedToken(token Token) {\n      append(newError(token.range, \"Unexpected \\(token.kind)\"))\n    }\n\n    def syntaxErrorExpectedToken(range Range, found TokenKind, expected TokenKind) {\n      var diagnostic = newError(range, \"Expected \\(expected) but found \\(found)\")\n      if found == .SEMICOLON && expected == .NEWLINE {\n        diagnostic.withFix(.EXTRA_SEMICOLON, range, \"Remove \\\";\\\"\", \"\")\n      }\n      append(diagnostic)\n    }\n\n    def syntaxErrorEmptyFunctionParentheses(range Range) {\n      append(\n        newError(range, \"Functions without arguments do not use parentheses\")\n        .withFix(.EXTRA_DEF_PARENTHESES, range, \"Remove parentheses\", \"\"))\n    }\n\n    def syntaxErrorBadDeclarationInsideType(range Range) {\n      append(newError(range, \"Cannot use this declaration here\"))\n    }\n\n    def syntaxErrorBadOperatorCustomization(range Range, kind TokenKind, why string) {\n      append(newError(range, \"The \\(kind) operator is not customizable because \\(why)\"))\n    }\n\n    def syntaxErrorVariableDeclarationNeedsVar(range Range, name Range) {\n      append(\n        newError(range, \"Declare variables using \\\"var\\\" and put the type after the variable name\")\n        .withFix(.NEED_VAR, Range.span(range, name), \"Declare \\\"\\(name)\\\" correctly\", \"var \\(name) \\(range)\"))\n    }\n\n    def syntaxErrorXMLClosingTagMismatch(range Range, found string, expected string, openingRange Range) {\n      append(\n        newError(range, \"Expected \\\"\\(expected)\\\" but found \\\"\\(found)\\\" in XML literal\")\n        .withNote(openingRange, \"Attempted to match opening tag here\"))\n    }\n\n    def syntaxErrorOptionalArgument(range Range) {\n      append(newError(range, \"Optional arguments aren't supported yet\"))\n    }\n  }\n\n  namespace Log {\n    def _expectedCountText(singular string, expected int, found int) string {\n      return \"Expected \\(PrettyPrint.plural(expected, singular)) but found \\(PrettyPrint.plural(found, singular))\"\n    }\n\n    def _formatArgumentTypes(types List<Type>) string {\n      if types == null {\n        return \"\"\n      }\n      var names List<string> = []\n      for type in types {\n        names.append(type.toString)\n      }\n      return \" of type\\(PrettyPrint.plural(types.count)) \\(PrettyPrint.join(names, \"and\"))\"\n    }\n  }\n\n  class Log {\n    def semanticWarningInliningFailed(range Range, name string) {\n      append(newWarning(range, \"Cannot inline function \\\"\\(name)\\\"\"))\n    }\n\n    def semanticWarningIdenticalOperands(range Range, operator string) {\n      append(newWarning(range, \"Both sides of \\\"\\(operator)\\\" are identical, is this a bug?\"))\n    }\n\n    def semanticWarningSuspiciousAssignmentLocation(range Range) {\n      append(newWarning(range, \"Use of \\\"=\\\" here looks like a bug, did you mean to use \\\"==\\\"?\"))\n    }\n\n    def semanticWarningShiftByZero(range Range) {\n      append(newWarning(range, \"Shifting an integer by zero doesn't do anything, is this a bug?\"))\n    }\n\n    def semanticWarningUnusedExpression(range Range) {\n      append(newWarning(range, \"Unused expression\"))\n    }\n\n    def semanticErrorXMLMissingAppend(range Range, type Type) {\n      append(newError(range, \"Implement a function called \\\"<>...</>\\\" on type \\\"\\(type)\\\" to add support for child elements\"))\n    }\n\n    def semanticErrorComparisonOperatorNotInt(range Range) {\n      append(newError(range, \"The comparison operator must have a return type of \\\"int\\\"\"))\n    }\n\n    def semanticErrorDuplicateSymbol(range Range, name string, previous Range) {\n      append(\n        newError(range, \"\\\"\\(name)\\\" is already declared\")\n        .withNote(previous, \"The previous declaration is here\"))\n    }\n\n    def semanticErrorShadowedSymbol(range Range, name string, previous Range) {\n      append(\n        newError(range, \"\\\"\\(name)\\\" shadows a previous declaration\")\n        .withNote(previous, \"The previous declaration is here\"))\n    }\n\n    def semanticErrorDuplicateTypeParameters(range Range, name string, previous Range) {\n      append(\n        newError(range, \"\\\"\\(name)\\\" already has type parameters\")\n        .withNote(previous, \"Type parameters were previously declared here\"))\n    }\n\n    def semanticErrorDuplicateBaseType(range Range, name string, previous Range) {\n      append(\n        newError(range, \"\\\"\\(name)\\\" already has a base type\")\n        .withNote(previous, \"The previous base type is here\"))\n    }\n\n    def semanticErrorCyclicDeclaration(range Range, name string) {\n      append(newError(range, \"Cyclic declaration of \\\"\\(name)\\\"\"))\n    }\n\n    def semanticErrorUndeclaredSymbol(range Range, name string, correction string, correctionRange Range) {\n      var diagnostic = newError(range, \"\\\"\\(name)\\\" is not declared\" + (correction != null ? \", did you mean \\\"\\(correction)\\\"?\" : \"\"))\n      if correction != null && correctionRange != null {\n        diagnostic\n          .withNote(correctionRange, \"\\\"\\(correction)\\\" is defined here\")\n          .withFix(.SYMBOL_TYPO, range, \"Replace with \\\"\\(correction)\\\"\", correction)\n      }\n      append(diagnostic)\n    }\n\n    def semanticErrorUndeclaredSelfSymbol(range Range, name string) {\n      append(\n        newError(range, \"\\\"\\(name)\\\" is not declared (use \\\"self\\\" to refer to the object instance)\")\n        .withFix(.SELF_VS_THIS, range, \"Replace \\\"\\(name)\\\" with \\\"self\\\"\", \"self\"))\n    }\n\n    def semanticErrorUnknownMemberSymbol(range Range, name string, type Type, correction string, correctionRange Range) {\n      var diagnostic = newError(range, \"\\\"\\(name)\\\" is not declared on type \\\"\\(type)\\\"\" + (correction != null ? \", did you mean \\\"\\(correction)\\\"?\" : \"\"))\n      if correction != null && correctionRange != null {\n        diagnostic\n          .withNote(correctionRange, \"\\\"\\(correction)\\\" is defined here\")\n          .withFix(.SYMBOL_TYPO, range, \"Replace with \\\"\\(correction)\\\"\", correction)\n      }\n      append(diagnostic)\n    }\n\n    def semanticErrorVarMissingType(range Range, name string) {\n      append(newError(range, \"Unable to determine the type of \\\"\\(name)\\\"\"))\n    }\n\n    def semanticErrorVarMissingValue(range Range, name string) {\n      append(newError(range, \"The implicitly typed variable \\\"\\(name)\\\" must be initialized\"))\n    }\n\n    def semanticErrorConstMissingValue(range Range, name string) {\n      append(newError(range, \"The constant \\\"\\(name)\\\" must be initialized\"))\n    }\n\n    def semanticErrorInvalidCall(range Range, type Type) {\n      append(newError(range, \"Cannot call value of type \\\"\\(type)\\\"\"))\n    }\n\n    def semanticErrorCannotParameterize(range Range, type Type) {\n      append(newError(range, \"Cannot parameterize \\\"\\(type)\\\"\" + (\n        type.isParameterized ? \" because it is already parameterized\" : \" because it has no type parameters\")))\n    }\n\n    def semanticErrorParameterCount(range Range, expected int, found int) {\n      append(newError(range, _expectedCountText(\"type parameter\", expected, found)))\n    }\n\n    def semanticErrorArgumentCount(range Range, expected int, found int, name string, function Range) {\n      append(\n        newError(range, _expectedCountText(\"argument\", expected, found) + (name != null ? \" when calling \\\"\\(name)\\\"\" : \"\"))\n        .withNote(function, \"The function declaration is here\"))\n    }\n\n    def semanticErrorGetterRequiresWrap(range Range, name string, function Range) {\n      append(\n        newError(range, \"Wrap calls to the function \\\"\\(name)\\\" in parentheses to call the returned lambda\")\n        .withNote(function, \"The function declaration is here\"))\n    }\n\n    def semanticErrorGetterCalledTwice(range Range, name string, function Range) {\n      var diagnostic =\n        newError(range, \"Cannot call the value returned from the function \\\"\\(name)\\\" (this function was called automatically because it takes no arguments)\")\n        .withNote(function, \"The function declaration is here\")\n      if range.toString == \"()\" {\n        diagnostic.withFix(.EXTRA_CALL_PARENTHESES, range, \"Remove the unnecessary \\\"()\\\"\", \"\")\n      }\n      append(diagnostic)\n    }\n\n    def semanticErrorUseOfVoidFunction(range Range, name string, function Range) {\n      append(\n        newError(range, \"The function \\\"\\(name)\\\" does not return a value\")\n        .withNote(function, \"The function declaration is here\"))\n    }\n\n    def semanticErrorUseOfVoidLambda(range Range) {\n      append(newError(range, \"This call does not return a value\"))\n    }\n\n    def semanticErrorBadImplicitVariableType(range Range, type Type) {\n      append(newError(range, \"Implicitly typed variables cannot be of type \\\"\\(type)\\\"\"))\n    }\n\n    def semanticErrorNoDefaultValue(range Range, type Type) {\n      append(newError(range, \"Cannot construct a default value of type \\\"\\(type)\\\"\"))\n    }\n\n    def semanticErrorMemberUnexpectedGlobal(range Range, name string) {\n      append(newError(range, \"Cannot access global member \\\"\\(name)\\\" from an instance context\"))\n    }\n\n    def semanticErrorMemberUnexpectedInstance(range Range, name string) {\n      append(newError(range, \"Cannot access instance member \\\"\\(name)\\\" from a global context\"))\n    }\n\n    def semanticErrorMemberUnexpectedTypeParameter(range Range, name string) {\n      append(newError(range, \"Cannot access type parameter \\\"\\(name)\\\" here\"))\n    }\n\n    def semanticErrorConstructorReturnType(range Range) {\n      append(\n        newError(range, \"Constructors cannot have a return type\")\n        .withFix(.NEW_RETURN_TYPE, range?.rangeIncludingLeftWhitespace, \"Remove the return type\", \"\"))\n    }\n\n    def semanticErrorNoMatchingOverload(range Range, name string, count int, types List<Type>) {\n      append(newError(range, \"No overload of \\\"\\(name)\\\" was found that takes \\(PrettyPrint.plural(count, \"argument\"))\\(_formatArgumentTypes(types))\"))\n    }\n\n    def semanticErrorAmbiguousOverload(range Range, name string, count int, types List<Type>) {\n      append(newError(range, \"Multiple matching overloads of \\\"\\(name)\\\" were found that can take \\(PrettyPrint.plural(count, \"argument\"))\\(_formatArgumentTypes(types))\"))\n    }\n\n    def semanticErrorUnexpectedExpression(range Range, type Type) {\n      append(newError(range, \"Unexpected expression of type \\\"\\(type)\\\"\"))\n    }\n\n    def semanticErrorUnexpectedType(range Range, type Type) {\n      append(newError(range, \"Unexpected type \\\"\\(type)\\\"\"))\n    }\n\n    def semanticErrorIncompatibleTypes(range Range, from Type, to Type, isCastAllowed bool) {\n      append(newError(range, \"Cannot convert from type \\\"\\(from)\\\" to type \\\"\\(to)\\\"\\(isCastAllowed ? \" without a cast\" : \"\")\"))\n    }\n\n    def semanticErrorInvalidDefine(range Range, value string, type Type, name string) {\n      append(newError(range, \"Cannot convert \\\"\\(value)\\\" to type \\\"\\(type)\\\" for variable \\\"\\(name)\\\"\"))\n    }\n\n    def semanticWarningExtraCast(range Range, from Type, to Type) {\n      append(\n        newWarning(range, \"Unnecessary cast from type \\\"\\(from)\\\" to type \\\"\\(to)\\\"\")\n        .withFix(.EXTRA_CAST, range?.rangeIncludingLeftWhitespace, \"Remove the cast\", \"\"))\n    }\n\n    def semanticWarningExtraTypeCheck(range Range, from Type, to Type) {\n      append(newWarning(range, \"Unnecessary type check, type \\\"\\(from)\\\" is always type \\\"\\(to)\\\"\"))\n    }\n\n    def semanticWarningBadTypeCheck(range Range, type Type) {\n      append(newError(range, \"Cannot check against interface type \\\"\\(type)\\\"\"))\n    }\n\n    def semanticErrorWrongArgumentCount(range Range, name string, count int) {\n      append(newError(range, \"Expected \\\"\\(name)\\\" to take \\(PrettyPrint.plural(count, \"argument\"))\"))\n    }\n\n    def semanticErrorWrongArgumentCountRange(range Range, name string, values List<int>) {\n      assert(!values.isEmpty)\n\n      var first = values.first\n      var count = values.count\n\n      if count == 1 {\n        semanticErrorWrongArgumentCount(range, name, first)\n      }\n\n      else {\n        var counts List<string> = []\n        var min = first\n        var max = first\n        var text string\n\n        for value in values {\n          min = Math.min(min, value)\n          max = Math.max(max, value)\n          counts.append(value.toString)\n        }\n\n        # Assuming values are unique, this means all values form a continuous range\n        if max - min + 1 == count {\n          if min == 0 {\n            text = \"Expected \\\"\\(name)\\\" to take at most \\(PrettyPrint.plural(max, \"argument\"))\"\n          } else {\n            text = \"Expected \\\"\\(name)\\\" to take between \\(min) and \\(max) arguments\"\n          }\n        }\n\n        # Otherwise, the values are disjoint\n        else {\n          text = \"Expected \\\"\\(name)\\\" to take either \\(PrettyPrint.join(counts, \"or\")) arguments\"\n        }\n\n        append(newError(range, text))\n      }\n    }\n\n    def semanticErrorExpectedList(range Range, name string, type Type) {\n      append(newError(range, \"Expected argument \\\"\\(name)\\\" to be of type \\\"List<T>\\\" instead of type \\\"\\(type)\\\"\"))\n    }\n\n    def semanticErrorUnexpectedReturnValue(range Range) {\n      append(newError(range, \"Cannot return a value inside a function without a return type\"))\n    }\n\n    def semanticErrorBadReturnType(range Range, type Type) {\n      append(newError(range, \"Cannot create a function with a return type of \\\"\\(type)\\\"\"))\n    }\n\n    def semanticErrorVoidReturnType(range Range) {\n      append(\n        newError(range, \"There is no explicit \\\"void\\\" return type (to indicate that there's nothing to return, just don't put a return type)\")\n        .withFix(.VOID_RETURN, range?.rangeIncludingLeftWhitespace, \"Remove \\\"void\\\"\", \"\"))\n    }\n\n    def semanticErrorExpectedReturnValue(range Range, type Type) {\n      append(newError(range, \"Must return a value of type \\\"\\(type)\\\"\"))\n    }\n\n    def semanticErrorMissingReturn(range Range, name string, type Type) {\n      append(newError(range, \"All control paths for \\\"\\(name)\\\" must return a value of type \\\"\\(type)\\\"\"))\n    }\n\n    def semanticErrorBadStorage(range Range) {\n      append(newError(range, \"Cannot store to this location\"))\n    }\n\n    def semanticErrorStorageToConstSymbol(range Range, name string) {\n      append(newError(range, \"Cannot store to constant symbol \\\"\\(name)\\\"\"))\n    }\n\n    def semanticErrorAccessViolation(range Range, name string) {\n      append(newError(range, \"Cannot access protected symbol \\\"\\(name)\\\" here\"))\n    }\n\n    def semanticWarningDeprecatedUsage(range Range, name string) {\n      append(newWarning(range, \"Use of deprecated symbol \\\"\\(name)\\\"\"))\n    }\n\n    def semanticErrorUnparameterizedType(range Range, type Type) {\n      append(newError(range, \"Cannot use unparameterized type \\\"\\(type)\\\" here\"))\n    }\n\n    def semanticErrorParameterizedType(range Range, type Type) {\n      append(newError(range, \"Cannot use parameterized type \\\"\\(type)\\\" here\"))\n    }\n\n    def semanticErrorNoCommonType(range Range, left Type, right Type) {\n      append(newError(range, \"No common type for \\\"\\(left)\\\" and \\\"\\(right)\\\"\"))\n    }\n\n    def semanticErrorInvalidAnnotation(range Range, annotation string, name string) {\n      append(newError(range, \"Cannot use the annotation \\\"\\(annotation)\\\" on \\\"\\(name)\\\"\"))\n    }\n\n    def semanticWarningDuplicateAnnotation(range Range, annotation string, name string) {\n      append(newWarning(range, \"Duplicate annotation \\\"\\(annotation)\\\" on \\\"\\(name)\\\"\"))\n    }\n\n    def semanticWarningRedundantAnnotation(range Range, annotation string, name string, parent string) {\n      append(newWarning(range, \"Redundant annotation \\\"\\(annotation)\\\" on \\\"\\(name)\\\" is already inherited from type \\\"\\(parent)\\\"\"))\n    }\n\n    def semanticErrorBadForValue(range Range, type Type) {\n      append(newError(range, \"Cannot iterate over type \\\"\\(type)\\\"\"))\n    }\n\n    def semanticWarningEmptyRange(range Range) {\n      append(newWarning(range, \"This range is empty\"))\n    }\n\n    def semanticErrorMissingDotContext(range Range, name string) {\n      append(newError(range, \"Cannot access \\\"\\(name)\\\" without type context\"))\n    }\n\n    def semanticErrorInitializerTypeInferenceFailed(range Range) {\n      append(newError(range, \"Cannot infer a type for this literal\"))\n    }\n\n    def semanticErrorInitializerRecursiveExpansion(range Range, newRange Range) {\n      append(\n        newError(range, \"Attempting to resolve this literal led to recursive expansion\")\n        .withNote(newRange, \"The constructor that was called recursively is here\"))\n    }\n\n    def semanticErrorXMLCannotConstruct(range Range, type Type) {\n      append(newError(range, \"Cannot construct type \\\"\\(type)\\\"\"))\n    }\n\n    def semanticErrorDuplicateOverload(range Range, name string, previous Range) {\n      append(\n        newError(range, \"Duplicate overloaded function \\\"\\(name)\\\"\")\n        .withNote(previous, \"The previous declaration is here\"))\n    }\n\n    def semanticErrorInvalidExtends(range Range, type Type) {\n      append(newError(range, \"Cannot extend type \\\"\\(type)\\\"\"))\n    }\n\n    def semanticErrorInvalidImplements(range Range, type Type) {\n      append(newError(range, \"Cannot implement type \\\"\\(type)\\\"\"))\n    }\n\n    def semanticErrorDuplicateImplements(range Range, type Type, previous Range) {\n      append(\n        newError(range, \"Duplicate implemented type \\\"\\(type)\\\"\")\n        .withNote(previous, \"The first occurrence is here\"))\n    }\n\n    def semanticErrorBadInterfaceImplementation(range Range, classType Type, interfaceType Type, name string, reason Range) {\n      append(\n        newError(range, \"Type \\\"\\(classType)\\\" is missing an implementation of function \\\"\\(name)\\\" from interface \\\"\\(interfaceType)\\\"\")\n        .withNote(reason, \"The function declaration is here\"))\n    }\n\n    def semanticErrorBadInterfaceImplementationReturnType(range Range, name string, found Type, expected Type, interfaceType Type, reason Range) {\n      append(\n        newError(range, found != null && expected != null\n          ? \"Function \\\"\\(name)\\\" has unexpected return type \\\"\\(found)\\\", expected return type \\\"\\(expected)\\\" \" +\n            \"to match the function with the same name and argument types from interface \\\"\\(interfaceType)\\\"\"\n          : \"Expected the return type of function \\\"\\(name)\\\" to match the function with the same name and argument types from interface \\\"\\(interfaceType)\\\"\")\n        .withNote(reason, \"The function declaration is here\"))\n    }\n\n    def semanticErrorBadOverride(range Range, name string, base Type, overridden Range) {\n      append(\n        newError(range, \"\\\"\\(name)\\\" overrides another declaration with the same name in base type \\\"\\(base)\\\"\")\n        .withNote(overridden, \"The overridden declaration is here\"))\n    }\n\n    def semanticErrorBadOverrideReturnType(range Range, name string, base Type, overridden Range) {\n      append(\n        newError(range, \"\\\"\\(name)\\\" overrides another function with the same name and argument types but a different return type in base type \\\"\\(base)\\\"\")\n        .withNote(overridden, \"The overridden function is here\"))\n    }\n\n    def semanticErrorModifierMissingOverride(range Range, name string, overridden Range) {\n      append(\n        newError(range, \"\\\"\\(name)\\\" overrides another symbol with the same name but is declared using \\\"def\\\" instead of \\\"over\\\"\")\n        .withNote(overridden, \"The overridden declaration is here\"))\n    }\n\n    def semanticErrorModifierUnusedOverride(range Range, name string) {\n      append(newError(range, \"\\\"\\(name)\\\" is declared using \\\"over\\\" instead of \\\"def\\\" but does not override anything\"))\n    }\n\n    def semanticErrorBadSuper(range Range) {\n      append(newError(range, \"Cannot use \\\"super\\\" here\"))\n    }\n\n    def semanticErrorBadJump(range Range, name string) {\n      append(newError(range, \"Cannot use \\\"\\(name)\\\" outside a loop\"))\n    }\n\n    def semanticErrorMustCallFunction(range Range, name string, lower int, upper int) {\n      append(newError(range, lower == upper\n        ? \"The function \\\"\\(name)\\\" takes \\(PrettyPrint.plural(lower, \"argument\")) and must be called\"\n        : \"The function \\\"\\(name)\\\" takes between \\(lower) and \\(upper) arguments and must be called\"))\n    }\n\n    def semanticErrorDuplicateEntryPoint(range Range, previous Range) {\n      append(\n        newError(range, \"Multiple entry points are declared\")\n        .withNote(previous, \"The first entry point is here\"))\n    }\n\n    def semanticErrorInvalidEntryPointArguments(range Range, name string) {\n      append(newError(range, \"Entry point \\\"\\(name)\\\" must take either no arguments or one argument of type \\\"List<string>\\\"\"))\n    }\n\n    def semanticErrorInvalidEntryPointReturnType(range Range, name string) {\n      append(newError(range, \"Entry point \\\"\\(name)\\\" must return either nothing or a value of type \\\"int\\\"\"))\n    }\n\n    def semanticErrorInvalidDefine(range Range, name string) {\n      append(newError(range, \"Could not find a variable named \\\"\\(name)\\\" to override\"))\n    }\n\n    def semanticErrorExpectedConstant(range Range) {\n      append(newError(range, \"This value must be a compile-time constant\"))\n    }\n\n    def semanticWarningUnreadLocalVariable(range Range, name string) {\n      append(newWarning(range, \"Local variable \\\"\\(name)\\\" is never read\"))\n    }\n\n    def semanticErrorAbstractNew(range Range, type Type, reason Range, name string) {\n      append(\n        newError(range, \"Cannot construct abstract type \\\"\\(type)\\\"\")\n        .withNote(reason, \"The type \\\"\\(type)\\\" is abstract due to member \\\"\\(name)\\\"\"))\n    }\n\n    def semanticErrorUnimplementedFunction(range Range, name string) {\n      append(newError(range, \"Non-imported function \\\"\\(name)\\\" is missing an implementation (use the \\\"@import\\\" annotation if it's implemented externally)\"))\n    }\n\n    def semanticErrorDefaultCaseNotLast(range Range) {\n      append(newError(range, \"The default case in a switch statement must come last\"))\n    }\n\n    def semanticErrorForLoopDifferentType(range Range, name string, found Type, expected Type) {\n      append(newError(range, \"Expected loop variable \\\"\\(name)\\\" to be of type \\\"\\(expected)\\\" instead of type \\\"\\(found)\\\"\"))\n    }\n\n    def semanticErrorDuplicateCase(range Range, previous Range) {\n      append(\n        newError(range, \"Duplicate case value\")\n        .withNote(previous, \"The first occurrence is here\"))\n    }\n\n    def semanticErrorMissingWrappedType(range Range, name string) {\n      append(newError(range, \"Missing base type for wrapped type \\\"\\(name)\\\"\"))\n    }\n\n    def semanticErrorDuplicateRename(range Range, name string, optionA string, optionB string) {\n      append(newError(range, \"Cannot rename \\\"\\(name)\\\" to both \\\"\\(optionA)\\\" and \\\"\\(optionB)\\\"\"))\n    }\n\n    def semanticErrorMissingSuper(range Range) {\n      append(newError(range, \"Constructors for derived types must start with a call to \\\"super\\\"\"))\n    }\n\n    def semanticErrorTooManyFlags(range Range, name string) {\n      append(newError(range, \"The type \\\"\\(name)\\\" cannot have more than 32 flags\"))\n    }\n  }\n}\n"
  },
  {
    "path": "src/frontend/parser.sk",
    "content": "namespace Skew {\n  enum PassKind {\n    PARSING\n  }\n\n  class ParsingPass : Pass {\n    over kind PassKind {\n      return .PARSING\n    }\n\n    over run(context PassContext) {\n      for tokens in context.tokens {\n        Parsing.parseFile(context.log, tokens, context.global, context.options.warnAboutIgnoredComments)\n      }\n    }\n  }\n}\n\nnamespace Skew.Parsing {\n  var expressionParser Pratt\n  var typeParser Pratt\n\n  # Parser recovery is done by skipping to the next closing token after an error\n  def scanForToken(context ParserContext, kind TokenKind) {\n    if context.expect(kind) {\n      return\n    }\n\n    # Scan forward for the token\n    while !context.peek(.END_OF_FILE) {\n      if context.eat(kind) {\n        return\n      }\n\n      switch context.current.kind {\n        # Stop at the next closing token\n        case .RIGHT_PARENTHESIS, .RIGHT_BRACKET, .RIGHT_BRACE {\n          return\n        }\n\n        # Optionally recover parsing before the next statement if it's unambiguous\n        case .BREAK, .CATCH, .CONST, .CONTINUE, .ELSE, .FINALLY, .FOR, .IF, .RETURN, .TRY, .VAR, .WHILE {\n          return\n        }\n      }\n\n      context.next\n    }\n  }\n\n  def parseIntLiteral(log Log, range Range) Box<int> {\n    var text = range.toString\n    var isNegative = text.startsWith(\"-\") # Parse negative signs for use with the \"--define\" flag\n    var start = isNegative as int\n    var count = text.count\n    var doubleValue = 0.0\n    var intValue = 0\n    var base = 10\n\n    # Parse the base\n    if start + 2 < count && text[start] == '0' {\n      var c = text[start + 1]\n      if c == 'b' {\n        base = 2\n        start += 2\n      } else if c == 'o' {\n        base = 8\n        start += 2\n      } else if c == 'x' {\n        base = 16\n        start += 2\n      }\n    }\n\n    # There must be numbers after the base\n    if start == count {\n      return null\n    }\n\n    # Special-case hexadecimal since it's more complex\n    if base == 16 {\n      for i in start..count {\n        var c = text[i]\n        if (c < '0' || c > '9') && (c < 'A' || c > 'F') && (c < 'a' || c > 'f') {\n          return null\n        }\n        var delta = c - (c <= '9' ? '0' : c <= 'F' ? 'A' - 10 : 'a' - 10)\n        doubleValue = doubleValue * 16 + delta\n        intValue = intValue * 16 + delta\n      }\n    }\n\n    # All other bases are zero-relative\n    else {\n      for i in start..count {\n        var delta = text[i] - '0'\n        if delta < 0 || delta >= base {\n          return null\n        }\n        doubleValue = doubleValue * base + delta\n        intValue = intValue * base + delta\n      }\n    }\n\n    # Integer literals are only an error if they are outside both the signed and\n    # unsigned 32-bit integer ranges. Integers here are 32-bit signed integers\n    # but it can be convenient to write literals using unsigned notation and\n    # have the compiler do the wrapping (for example, all Mach-O files use a\n    # magic number of 0xFEEDFACE).\n    if doubleValue < -2147483648.0 || doubleValue > 4294967295.0 {\n      log.syntaxErrorIntegerLiteralTooLarge(range)\n      return Box<int>.new(intValue)\n    }\n\n    # Warn about decimal integers that start with \"0\" because other languages\n    # strangely treat these numbers as octal instead of decimal\n    if base == 10 && intValue != 0 && text[0] == '0' {\n      log.syntaxWarningOctal(range)\n    }\n\n    return Box<int>.new(isNegative ? -intValue : intValue)\n  }\n\n  def checkExtraParentheses(context ParserContext, node Node) {\n    if node.isInsideParentheses {\n      context.log.syntaxWarningExtraParentheses(node.range)\n    }\n  }\n\n  def _warnAboutIgnoredComments(context ParserContext, comments List<Comment>) {\n    if comments != null && context.warnAboutIgnoredComments {\n      for comment in comments {\n        context.log.syntaxWarningIgnoredCommentInParser(comment.range)\n      }\n    }\n  }\n\n  def parseTrailingComment(context ParserContext) List<Comment> {\n    switch context.current.kind {\n      case .NEWLINE, .END_OF_FILE, .RIGHT_PARENTHESIS, .RIGHT_BRACE, .RIGHT_BRACKET {\n        return context.stealComments\n      }\n    }\n    return null\n  }\n\n  def parseAnnotations(context ParserContext, annotations List<Node>) List<Node> {\n    while context.peek(.ANNOTATION) {\n      var range = context.next.range\n      var value = Node.createName(range.toString).withRange(range)\n\n      # Change \"@foo.bar.baz\" into \"foo.bar.@baz\"\n      if context.peek(.DOT) {\n        var root = value.asString\n        value.content = StringContent.new(root.slice(1))\n        while context.eat(.DOT) {\n          var name = context.current.range\n          if !context.expect(.IDENTIFIER) {\n            break\n          }\n          value = Node.createDot(value, name.toString).withRange(context.spanSince(range)).withInternalRange(name)\n        }\n        value.content = StringContent.new(\"@\" + value.asString)\n      }\n\n      # Parse parentheses if present\n      var token = context.current\n      if context.eat(.LEFT_PARENTHESIS) {\n        var call = Node.createCall(value)\n        parseCommaSeparatedList(context, call, .RIGHT_PARENTHESIS)\n        value = call.withRange(context.spanSince(range)).withInternalRange(context.spanSince(token.range))\n      }\n\n      # Parse a trailing if condition\n      var test Node = null\n      if context.eat(.IF) {\n        test = expressionParser.parse(context, .LOWEST)\n      }\n\n      # All annotations must end in a newline to avoid confusion with the trailing if\n      if !context.peek(.LEFT_BRACE) && !context.expect(.NEWLINE) {\n        scanForToken(context, .NEWLINE)\n      }\n\n      annotations.append(Node.createAnnotation(value, test).withRange(context.spanSince(range)))\n    }\n\n    return annotations\n  }\n\n  # When the type is present, this parses something like \"int x = 0\"\n  def parseVariables(context ParserContext, type Node) Node {\n    var variables = Node.createVariables\n    var token = context.current\n\n    # Skip \"var\" or \"const\" if present\n    if type == null {\n      context.next\n    }\n\n    while true {\n      var range = context.current.range\n\n      if !context.expect(.IDENTIFIER) {\n        return null\n      }\n\n      var symbol = VariableSymbol.new(.VARIABLE_LOCAL, range.toString)\n      symbol.range = range\n\n      if token.kind == .CONST {\n        symbol.flags |= .IS_CONST\n      }\n\n      if type != null {\n        symbol.type = type.clone\n      }\n\n      else {\n        if context.peek(.COLON) {\n          context.log.syntaxErrorExtraColonBeforeType(context.next.range)\n        }\n\n        if peekType(context) {\n          symbol.type = parseType(context)\n        }\n      }\n\n      if context.eat(.ASSIGN) {\n        symbol.value = expressionParser.parse(context, .LOWEST)\n      }\n\n      variables.appendChild(Node.createVariable(symbol).withRange(context.spanSince(range)))\n\n      if !context.eat(.COMMA) {\n        break\n      }\n    }\n\n    return variables.withRange(context.spanSince(type != null ? type.range : token.range))\n  }\n\n  def parseJump(context ParserContext) Node {\n    var token = context.next\n    return (token.kind == .BREAK ? Node.createBreak : Node.createContinue).withRange(token.range)\n  }\n\n  def parseReturn(context ParserContext) Node {\n    var token = context.next\n    var value Node = null\n\n    # Check for \"return;\" explicitly for a better error message\n    if !context.skipSemicolon && !context.peek(.NEWLINE) && !context.peek(.COMMENT) && !context.peek(.RIGHT_BRACE) {\n      value = expressionParser.parse(context, .LOWEST)\n      checkExtraParentheses(context, value)\n    }\n\n    return Node.createReturn(value).withRange(context.spanSince(token.range))\n  }\n\n  def parseSwitch(context ParserContext) Node {\n    var token = context.next\n    var value = expressionParser.parse(context, .LOWEST)\n    checkExtraParentheses(context, value)\n    var node = Node.createSwitch(value)\n\n    context.skipWhitespace\n    if !context.expect(.LEFT_BRACE) {\n      return null\n    }\n\n    context.eat(.NEWLINE)\n    while !context.peek(.RIGHT_BRACE) {\n      var comments = context.stealComments\n\n      # Ignore trailing comments\n      if context.peek(.RIGHT_BRACE) || context.peek(.END_OF_FILE) {\n        _warnAboutIgnoredComments(context, comments)\n        break\n      }\n\n      # Parse a new case\n      var child = Node.createCase\n      var start = context.current\n      var colon Range = null\n      if context.eat(.CASE) {\n        while true {\n          var constantComments = context.stealComments\n          var constant = expressionParser.parse(context, .LOWEST)\n          checkExtraParentheses(context, constant)\n          child.appendChild(constant)\n          constant.comments = Comment.concat(constantComments, parseTrailingComment(context))\n\n          # A colon isn't valid syntax here, but try to have a nice error message\n          if context.peek(.COLON) {\n            colon = context.next.range\n            context.skipWhitespace\n            if context.eat(.CASE) {\n              context.log.syntaxErrorExpectedCommaBetweenCases(context.spanSince(colon))\n              colon = null\n            } else {\n              break\n            }\n          }\n\n          # Commas separate multiple values\n          else if !context.eat(.COMMA) {\n            break\n          }\n\n          constant.comments = Comment.concat(constant.comments, parseTrailingComment(context))\n        }\n      }\n\n      # Default cases have no values\n      else {\n        if !context.eat(.DEFAULT) {\n          context.expect(.CASE)\n          return null\n        }\n\n        # A colon isn't valid syntax here, but try to have a nice error message\n        if context.peek(.COLON) {\n          colon = context.next.range\n        }\n      }\n\n      var block Node\n\n      # Use a block instead of requiring \"break\" at the end\n      if colon == null {\n        block = parseBlock(context)\n        if block == null {\n          return null\n        }\n      }\n\n      # If there was a syntax error, try to parse a C-style block\n      else {\n        var range = context.current.range\n        block = Node.createBlock\n        if !parseStatements(context, block, .C_STYLE_SWITCH) {\n          return null\n        }\n        var breakRange Range = null\n        if context.peek(.BREAK) {\n          breakRange = context.next.range\n          if context.skipSemicolon {\n            breakRange = context.spanSince(breakRange)\n          }\n        }\n        block.withRange(context.spanSince(range))\n        context.log.syntaxErrorColonAfterCaseOrDefault(colon, breakRange)\n        context.eat(.NEWLINE)\n      }\n\n      # Create the case\n      node.appendChild(child.appendChild(block).withRange(context.spanSince(start.range)))\n\n      # Parse trailing comments and/or newline\n      child.comments = Comment.concat(comments, parseTrailingComment(context))\n      if context.peek(.RIGHT_BRACE) || colon == null && !context.expect(.NEWLINE) {\n        break\n      }\n    }\n\n    if !context.expect(.RIGHT_BRACE) {\n      return null\n    }\n\n    return node.withRange(context.spanSince(token.range))\n  }\n\n  def parseFor(context ParserContext) Node {\n    var token = context.next\n    var parentheses = context.peek(.LEFT_PARENTHESIS) ? context.next : null\n\n    # Doing \"for var i = ...\" is an error\n    if context.peek(.VAR) {\n      context.log.syntaxErrorExtraVarInForLoop(context.next.range)\n    }\n\n    var initialNameRange = context.current.range\n    if !context.expect(.IDENTIFIER) {\n      return null\n    }\n\n    # for a in b {}\n    if context.eat(.IN) {\n      var symbol = VariableSymbol.new(.VARIABLE_LOCAL, initialNameRange.toString)\n      symbol.range = initialNameRange\n\n      var value = expressionParser.parse(context, .LOWEST)\n\n      if context.eat(.DOT_DOT) {\n        var second = expressionParser.parse(context, .LOWEST)\n        value = Node.createPair(value, second).withRange(Range.span(value.range, second.range))\n      }\n      checkExtraParentheses(context, value)\n\n      # Allow parentheses around the loop header\n      if parentheses != null {\n        if !context.expect(.RIGHT_PARENTHESIS) {\n          return null\n        }\n        context.log.syntaxWarningExtraParentheses(context.spanSince(parentheses.range))\n      }\n\n      var block = parseBlock(context)\n      if block == null {\n        return null\n      }\n\n      return Node.createForeach(symbol, value, block).withRange(context.spanSince(token.range))\n    }\n\n    # for a = 0; a < 10; a++ {}\n    var setup = Node.createVariables\n    context.undo\n\n    while true {\n      var nameRange = context.current.range\n\n      if !context.expect(.IDENTIFIER) {\n        return null\n      }\n\n      var symbol = VariableSymbol.new(.VARIABLE_LOCAL, nameRange.toString)\n      symbol.range = nameRange\n\n      if peekType(context) {\n        symbol.type = parseType(context)\n      }\n\n      if context.eat(.ASSIGN) {\n        symbol.value = expressionParser.parse(context, .LOWEST)\n        checkExtraParentheses(context, symbol.value)\n      }\n\n      setup.appendChild(Node.createVariable(symbol).withRange(context.spanSince(nameRange)))\n\n      if !context.eat(.COMMA) {\n        break\n      }\n    }\n    setup.range = context.spanSince(initialNameRange)\n\n    if !context.expect(.SEMICOLON) {\n      return null\n    }\n\n    var test = expressionParser.parse(context, .LOWEST)\n\n    if !context.expect(.SEMICOLON) {\n      return null\n    }\n\n    var update = expressionParser.parse(context, .LOWEST)\n\n    # This is the one place in the grammar that sequence expressions are allowed\n    if context.eat(.COMMA) {\n      update = Node.createSequence.appendChild(update)\n      while true {\n        var value = expressionParser.parse(context, .LOWEST)\n        update.appendChild(value)\n        if !context.eat(.COMMA) {\n          break\n        }\n      }\n    }\n\n    # Allow parentheses around the loop header\n    if parentheses != null {\n      if !context.expect(.RIGHT_PARENTHESIS) {\n        return null\n      }\n      context.log.syntaxWarningExtraParentheses(context.spanSince(parentheses.range))\n    }\n\n    var block = parseBlock(context)\n    if block == null {\n      return null\n    }\n\n    return Node.createFor(setup, test, update, block).withRange(context.spanSince(token.range))\n  }\n\n  def parseIf(context ParserContext) Node {\n    var token = context.next\n    var test = expressionParser.parse(context, .LOWEST)\n    checkExtraParentheses(context, test)\n\n    var trueBlock = parseBlock(context)\n    if trueBlock == null {\n      return null\n    }\n\n    return Node.createIf(test, trueBlock, null).withRange(context.spanSince(token.range))\n  }\n\n  def parseThrow(context ParserContext) Node {\n    var token = context.next\n    var value = expressionParser.parse(context, .LOWEST)\n    checkExtraParentheses(context, value)\n    return Node.createThrow(value).withRange(context.spanSince(token.range))\n  }\n\n  def parseTry(context ParserContext) Node {\n    var token = context.next\n    var tryBlock = parseBlock(context)\n    if tryBlock == null {\n      return null\n    }\n    return Node.createTry(tryBlock).withRange(context.spanSince(token.range))\n  }\n\n  def parseWhile(context ParserContext) Node {\n    var token = context.next\n    var test = expressionParser.parse(context, .LOWEST)\n    checkExtraParentheses(context, test)\n\n    var block = parseBlock(context)\n    if block == null {\n      return null\n    }\n\n    return Node.createWhile(test, block).withRange(context.spanSince(token.range))\n  }\n\n  def parseStatement(context ParserContext) Node {\n    var token = context.current\n\n    switch token.kind {\n      case .BREAK, .CONTINUE { return parseJump(context) }\n      case .CONST, .VAR { return parseVariables(context, null) }\n      case .FOR { return parseFor(context) }\n      case .IF { return parseIf(context) }\n      case .RETURN { return parseReturn(context) }\n      case .SWITCH { return parseSwitch(context) }\n      case .THROW { return parseThrow(context) }\n      case .TRY { return parseTry(context) }\n      case .WHILE { return parseWhile(context) }\n    }\n\n    var value = expressionParser.parse(context, .LOWEST)\n    checkExtraParentheses(context, value)\n\n    # A special case for better errors when users try to use C-style variable declarations\n    if !value.isInsideParentheses && looksLikeType(value) && context.peek(.IDENTIFIER) && context.canReportSyntaxError {\n      context.log.syntaxErrorVariableDeclarationNeedsVar(value.range, context.current.range)\n      return parseVariables(context, value)\n    }\n\n    var node = Node.createExpression(value).withRange(value.range)\n    return node\n  }\n\n  def looksLikeType(node Node) bool {\n    var kind = node.kind\n    return\n      kind == .NAME ||\n      kind == .TYPE ||\n      kind == .LAMBDA_TYPE ||\n      kind == .DOT && node.dotTarget != null && looksLikeType(node.dotTarget) ||\n      kind == .PARAMETERIZE && looksLikeType(node.parameterizeValue)\n  }\n\n  enum StatementsMode {\n    NORMAL\n    C_STYLE_SWITCH\n  }\n\n  def parseStatements(context ParserContext, parent Node, mode StatementsMode) bool {\n    var previous Node = null\n    var leading = parseTrailingComment(context)\n    context.eat(.NEWLINE)\n\n    while !context.peek(.RIGHT_BRACE) && !context.peek(.XML_START_CLOSE) && !context.peek(.END_OF_FILE) {\n      # The block may start with a trailing comment\n      var comments = Comment.concat(leading, context.stealComments)\n      leading = null\n\n      # When parsing a C-style switch, stop if it looks like the end of the case\n      if mode == .C_STYLE_SWITCH && (context.peek(.CASE) || context.peek(.DEFAULT) || context.peek(.BREAK)) {\n        _warnAboutIgnoredComments(context, comments)\n        break\n      }\n\n      # Merge \"else\" statements with the previous \"if\"\n      if context.peek(.ELSE) {\n        var isValid = previous != null && previous.kind == .IF && previous.ifFalse == null\n        if !isValid {\n          context.unexpectedToken\n        }\n        context.next\n\n        # Match \"else if\"\n        if context.peek(.IF) {\n          var statement = parseIf(context)\n          if statement == null {\n            return false\n          }\n\n          # Append to the if statement\n          var falseBlock = Node.createBlock.withRange(statement.range).appendChild(statement)\n          falseBlock.comments = comments\n          if isValid {\n            previous.appendChild(falseBlock)\n            previous = statement\n          } else {\n            previous = null\n          }\n        }\n\n        # Match \"else\"\n        else {\n          var falseBlock = parseBlock(context)\n          if falseBlock == null {\n            return false\n          }\n\n          # Append to the if statement\n          falseBlock.comments = comments\n          if isValid {\n            previous.appendChild(falseBlock)\n            previous = falseBlock\n          } else {\n            previous = null\n          }\n        }\n      }\n\n      # Merge \"catch\" statements with the previous \"try\"\n      else if context.peek(.CATCH) {\n        var isValid = previous != null && previous.kind == .TRY && previous.finallyBlock == null\n        if !isValid {\n          context.unexpectedToken\n        }\n        var catchToken = context.next\n        var symbol VariableSymbol = null\n        var nameRange = context.current.range\n\n        # Optional typed variable\n        if context.eat(.IDENTIFIER) {\n          symbol = VariableSymbol.new(.VARIABLE_LOCAL, nameRange.toString)\n          symbol.range = nameRange\n          symbol.type = parseType(context)\n        }\n\n        # Parse the block\n        var catchBlock = parseBlock(context)\n        if catchBlock == null {\n          return false\n        }\n\n        # Append to the try statement\n        var child = Node.createCatch(symbol, catchBlock).withRange(context.spanSince(catchToken.range))\n        child.comments = comments\n        if isValid {\n          previous.appendChild(child)\n        } else {\n          previous = null\n        }\n      }\n\n      # Merge \"finally\" statements with the previous \"try\"\n      else if context.peek(.FINALLY) {\n        var isValid = previous != null && previous.kind == .TRY && previous.finallyBlock == null\n        if !isValid {\n          context.unexpectedToken\n        }\n        context.next\n\n        # Parse the block\n        var finallyBlock = parseBlock(context)\n        if finallyBlock == null {\n          return false\n        }\n\n        # Append to the try statement\n        finallyBlock.comments = comments\n        if isValid {\n          previous.appendChild(finallyBlock)\n        } else {\n          previous = null\n        }\n      }\n\n      # Parse a new statement\n      else {\n        var current = context.current\n        var statement = parseStatement(context)\n        if statement == null {\n          scanForToken(context, .NEWLINE)\n          continue\n        }\n\n        # Prevent an infinite loop due to a syntax error at the start of an expression\n        if context.current == current {\n          context.next\n        }\n\n        previous = statement\n        statement.comments = comments\n        parent.appendChild(statement)\n      }\n\n      # Special-case semicolons before comments for better parser recovery\n      var semicolon = context.skipSemicolon\n\n      # Parse trailing comments and/or newline\n      var trailing = parseTrailingComment(context)\n      if trailing != null {\n        if previous != null {\n          previous.comments = Comment.concat(previous.comments, trailing)\n        } else {\n          _warnAboutIgnoredComments(context, trailing)\n        }\n      }\n      if context.peek(.RIGHT_BRACE) || context.peek(.XML_START_CLOSE) {\n        break\n      } else if !context.peek(.ELSE) && !context.peek(.CATCH) && !context.peek(.FINALLY) {\n        if semicolon {\n          context.eat(.NEWLINE)\n        } else {\n          context.expect(.NEWLINE)\n        }\n      }\n    }\n\n    # Convert trailing comments to blocks\n    var comments = Comment.concat(leading, context.stealComments)\n    if comments != null {\n      parent.appendChild(Node.createCommentBlock.withComments(comments))\n    }\n\n    return true\n  }\n\n  def parseBlock(context ParserContext) Node {\n    context.skipWhitespace\n    var comments = context.stealComments\n    var token = context.current\n    if !context.expect(.LEFT_BRACE) {\n      # Return a block to try to recover and continue parsing\n      return Node.createBlock\n    }\n    var block = Node.createBlock\n    if !parseStatements(context, block, .NORMAL) || !context.expect(.RIGHT_BRACE) {\n      return null\n    }\n    return block.withRange(context.spanSince(token.range)).withComments(comments)\n  }\n\n  def parseType(context ParserContext) Node {\n    return typeParser.parse(context, .LOWEST)\n  }\n\n  def peekType(context ParserContext) bool {\n    return context.peek(.IDENTIFIER) || context.peek(.DYNAMIC)\n  }\n\n  def parseFunctionBlock(context ParserContext, symbol FunctionSymbol) bool {\n    # \"=> x\" is the same as \"{ return x }\"\n    if symbol.kind == .FUNCTION_LOCAL {\n      if !context.expect(.ARROW) {\n        return false\n      }\n      if context.peek(.LEFT_BRACE) {\n        symbol.block = parseBlock(context)\n        if symbol.block == null {\n          return false\n        }\n      } else {\n        var value = expressionParser.parse(context, .LOWEST)\n        symbol.block = Node.createBlock.withRange(value.range).appendChild(Node.createReturn(value).withRange(value.range).withFlags(.IS_IMPLICIT_RETURN))\n      }\n    }\n\n    # Parse function body if present\n    else if context.peek(.LEFT_BRACE) {\n      symbol.block = parseBlock(context)\n      if symbol.block == null {\n        return false\n      }\n    }\n\n    return true\n  }\n\n  def parseFunctionArguments(context ParserContext, symbol FunctionSymbol) bool {\n    var leading = parseTrailingComment(context)\n    var usingTypes = false\n\n    while !context.eat(.RIGHT_PARENTHESIS) {\n      context.skipWhitespace\n      var comments = Comment.concat(leading, context.stealComments)\n      leading = null\n\n      var range = context.current.range\n      if !context.expect(.IDENTIFIER) {\n        scanForToken(context, .RIGHT_PARENTHESIS)\n        break\n      }\n\n      var arg = VariableSymbol.new(.VARIABLE_ARGUMENT, range.toString)\n      arg.range = range\n\n      # Parse argument type\n      if symbol.kind != .FUNCTION_LOCAL || (symbol.arguments.isEmpty ? peekType(context) || context.peek(.COLON) : usingTypes) {\n        if context.peek(.COLON) {\n          context.log.syntaxErrorExtraColonBeforeType(context.next.range)\n        }\n        arg.type = parseType(context)\n        usingTypes = true\n      }\n\n      # Optional arguments aren't supported yet\n      var assign = context.current.range\n      if context.eat(.ASSIGN) {\n        expressionParser.parse(context, .LOWEST)\n        context.log.syntaxErrorOptionalArgument(context.spanSince(assign))\n      }\n\n      symbol.arguments.append(arg)\n\n      if !context.peek(.RIGHT_PARENTHESIS) {\n        if !context.expect(.COMMA) {\n          scanForToken(context, .RIGHT_PARENTHESIS)\n          break\n        }\n      }\n\n      arg.comments = Comment.concat(comments, parseTrailingComment(context))\n    }\n    return true\n  }\n\n  def parseFunctionReturnTypeAndBlock(context ParserContext, symbol FunctionSymbol) bool {\n    if context.peek(.COLON) {\n      context.log.syntaxErrorExtraColonBeforeType(context.next.range)\n    }\n\n    if peekType(context) {\n      symbol.returnType = parseType(context)\n    }\n\n    if context.peek(.NEWLINE) && context.peek(.LEFT_BRACE, 1) {\n      context.next\n    }\n\n    return parseFunctionBlock(context, symbol)\n  }\n\n  def parseTypeParameters(context ParserContext, kind SymbolKind) List<ParameterSymbol> {\n    var parameters List<ParameterSymbol> = []\n    while true {\n      var range = context.current.range\n      var name = range.toString\n      if !context.expect(.IDENTIFIER) {\n        return null\n      }\n      var symbol = ParameterSymbol.new(kind, name)\n      symbol.range = range\n      parameters.append(symbol)\n      if !context.eat(.COMMA) {\n        break\n      }\n    }\n    if !context.expect(.PARAMETER_LIST_END) {\n      return null\n    }\n    return parameters\n  }\n\n  const identifierToSymbolKind StringMap<SymbolKind> = {\n    \"class\": .OBJECT_CLASS,\n    \"def\": .FUNCTION_GLOBAL,\n    \"enum\": .OBJECT_ENUM,\n    \"flags\": .OBJECT_FLAGS,\n    \"interface\": .OBJECT_INTERFACE,\n    \"namespace\": .OBJECT_NAMESPACE,\n    \"over\": .FUNCTION_GLOBAL,\n    \"type\": .OBJECT_WRAPPED,\n  }\n\n  const customOperators = {\n    TokenKind.ASSIGN_BITWISE_AND: 0,\n    TokenKind.ASSIGN_BITWISE_OR: 0,\n    TokenKind.ASSIGN_BITWISE_XOR: 0,\n    TokenKind.ASSIGN_DIVIDE: 0,\n    TokenKind.ASSIGN_INDEX: 0,\n    TokenKind.ASSIGN_MINUS: 0,\n    TokenKind.ASSIGN_MODULUS: 0,\n    TokenKind.ASSIGN_MULTIPLY: 0,\n    TokenKind.ASSIGN_PLUS: 0,\n    TokenKind.ASSIGN_POWER: 0,\n    TokenKind.ASSIGN_REMAINDER: 0,\n    TokenKind.ASSIGN_SHIFT_LEFT: 0,\n    TokenKind.ASSIGN_SHIFT_RIGHT: 0,\n    TokenKind.ASSIGN_UNSIGNED_SHIFT_RIGHT: 0,\n    TokenKind.BITWISE_AND: 0,\n    TokenKind.BITWISE_OR: 0,\n    TokenKind.BITWISE_XOR: 0,\n    TokenKind.COMPARE: 0,\n    TokenKind.DECREMENT: 0,\n    TokenKind.DIVIDE: 0,\n    TokenKind.IN: 0,\n    TokenKind.INCREMENT: 0,\n    TokenKind.INDEX: 0,\n    TokenKind.LIST: 0,\n    TokenKind.MINUS: 0,\n    TokenKind.MODULUS: 0,\n    TokenKind.MULTIPLY: 0,\n    TokenKind.NOT: 0,\n    TokenKind.PLUS: 0,\n    TokenKind.POWER: 0,\n    TokenKind.REMAINDER: 0,\n    TokenKind.SET: 0,\n    TokenKind.SHIFT_LEFT: 0,\n    TokenKind.SHIFT_RIGHT: 0,\n    TokenKind.TILDE: 0,\n    TokenKind.UNSIGNED_SHIFT_RIGHT: 0,\n    TokenKind.XML_CHILD: 0,\n  }\n\n  enum ForbiddenGroup {\n    ASSIGN\n    COMPARE\n    EQUAL\n    LOGICAL\n  }\n\n  const forbiddenCustomOperators IntMap<ForbiddenGroup> = {\n    TokenKind.ASSIGN: .ASSIGN,\n    TokenKind.EQUAL: .EQUAL,\n    TokenKind.GREATER_THAN: .COMPARE,\n    TokenKind.GREATER_THAN_OR_EQUAL: .COMPARE,\n    TokenKind.LESS_THAN: .COMPARE,\n    TokenKind.LESS_THAN_OR_EQUAL: .COMPARE,\n    TokenKind.LOGICAL_AND: .LOGICAL,\n    TokenKind.LOGICAL_OR: .LOGICAL,\n    TokenKind.NOT_EQUAL: .EQUAL,\n  }\n\n  # These are prefixed with \"the operator \\\"...\\\" is not customizable because \"\n  const forbiddenGroupDescription = {\n    ForbiddenGroup.ASSIGN: \"value types are not supported by the language\",\n    ForbiddenGroup.COMPARE: \"it's automatically implemented using the \\\"<=>\\\" operator (customize the \\\"<=>\\\" operator instead)\",\n    ForbiddenGroup.EQUAL: \"that wouldn't work with generics, which are implemented with type erasure\",\n    ForbiddenGroup.LOGICAL: \"of its special short-circuit evaluation behavior\",\n  }\n\n  def parseAfterBlock(context ParserContext) bool {\n    context.skipSemicolon # Check for  \";\" explicitly for a better error message\n    return context.peek(.END_OF_FILE) || context.peek(.RIGHT_BRACE) || context.expect(.NEWLINE)\n  }\n\n  const assignmentOperators IntMap<NodeKind> = {\n    TokenKind.ASSIGN: .ASSIGN,\n    TokenKind.ASSIGN_BITWISE_AND: .ASSIGN_BITWISE_AND,\n    TokenKind.ASSIGN_BITWISE_OR: .ASSIGN_BITWISE_OR,\n    TokenKind.ASSIGN_BITWISE_XOR: .ASSIGN_BITWISE_XOR,\n    TokenKind.ASSIGN_DIVIDE: .ASSIGN_DIVIDE,\n    TokenKind.ASSIGN_MINUS: .ASSIGN_SUBTRACT,\n    TokenKind.ASSIGN_MODULUS: .ASSIGN_MODULUS,\n    TokenKind.ASSIGN_MULTIPLY: .ASSIGN_MULTIPLY,\n    TokenKind.ASSIGN_PLUS: .ASSIGN_ADD,\n    TokenKind.ASSIGN_POWER: .ASSIGN_POWER,\n    TokenKind.ASSIGN_REMAINDER: .ASSIGN_REMAINDER,\n    TokenKind.ASSIGN_SHIFT_LEFT: .ASSIGN_SHIFT_LEFT,\n    TokenKind.ASSIGN_SHIFT_RIGHT: .ASSIGN_SHIFT_RIGHT,\n    TokenKind.ASSIGN_UNSIGNED_SHIFT_RIGHT: .ASSIGN_UNSIGNED_SHIFT_RIGHT,\n  }\n\n  def recursiveParseGuard(context ParserContext, parent ObjectSymbol, annotations List<Node>) Guard {\n    var test Node = null\n    if context.eat(.IF) {\n      test = expressionParser.parse(context, .LOWEST)\n    }\n    if !context.expect(.LEFT_BRACE) {\n      return null\n    }\n    var contents = ObjectSymbol.new(parent.kind, \"<conditional>\")\n    contents.flags |= .IS_GUARD_CONDITIONAL\n    contents.parent = parent\n    parseSymbols(context, contents, annotations)\n    if !context.expect(.RIGHT_BRACE) || !context.peek(.ELSE) && !parseAfterBlock(context) {\n      return null\n    }\n    var elseGuard Guard = null\n    if context.eat(.ELSE) {\n      elseGuard = recursiveParseGuard(context, parent, annotations)\n      if elseGuard == null {\n        return null\n      }\n    }\n    return Guard.new(parent, test, contents, elseGuard)\n  }\n\n  def parseSymbol(context ParserContext, parent ObjectSymbol, annotations List<Node>) bool {\n    # Parse comments before the symbol declaration\n    var comments = context.stealComments\n\n    # Ignore trailing comments\n    if context.peek(.RIGHT_BRACE) || context.peek(.END_OF_FILE) {\n      _warnAboutIgnoredComments(context, comments)\n      return false\n    }\n\n    # Parse a compile-time if statement\n    if context.peek(.IF) {\n      _warnAboutIgnoredComments(context, comments)\n      var guard = recursiveParseGuard(context, parent, annotations)\n      if guard == null {\n        return false\n      }\n      parent.guards ?= []\n      parent.guards.append(guard)\n      return true\n    }\n\n    # Parse annotations before the symbol declaration\n    if context.peek(.ANNOTATION) {\n      annotations = parseAnnotations(context, annotations != null ? annotations.clone : [])\n\n      # Parse an annotation block\n      if context.eat(.LEFT_BRACE) {\n        _warnAboutIgnoredComments(context, comments)\n        parseSymbols(context, parent, annotations)\n        return context.expect(.RIGHT_BRACE) && parseAfterBlock(context)\n      }\n    }\n\n    var token = context.current\n    var tokenKind = token.kind\n    var text = token.range.toString\n    var wasCorrected = false\n    var symbol Symbol = null\n    var kind = identifierToSymbolKind.get(text, .OBJECT_GLOBAL)\n\n    # Skip extra identifiers such as \"public\" in \"public var x = 0\"\n    while tokenKind == .IDENTIFIER && kind == .OBJECT_GLOBAL && (\n        context.peek(.IDENTIFIER, 1) || context.peek(.VAR, 1) || context.peek(.CONST, 1)) {\n      switch text {\n        case \"static\" { context.log.syntaxErrorStaticKeyword(token.range, parent.kind, parent.name) }\n        case \"public\" { context.log.syntaxErrorPublicKeyword(token.range) }\n        case \"protected\", \"private\" { context.log.syntaxErrorPrivateOrProtected(token.range) }\n        default { context.unexpectedToken }\n      }\n      context.next\n      token = context.current\n      tokenKind = token.kind\n      text = token.range.toString\n      kind = identifierToSymbolKind.get(text, .OBJECT_GLOBAL)\n    }\n\n    # Special-case a top-level \"x = 0\" and \"x: int = 0\" but avoid trying to make \"def =() {}\" into a variable\n    if tokenKind == .IDENTIFIER && (\n        context.peek(.ASSIGN, 1) && (!context.peek(.LEFT_PARENTHESIS, 2) || text != \"def\") ||\n        context.peek(.COLON, 1) && context.peek(.IDENTIFIER, 2)) {\n      context.log.syntaxErrorMissingVar(token.range)\n      tokenKind = .VAR\n      wasCorrected = true\n    }\n\n    # Special-case a top-level \"x() {}\"\n    else if tokenKind == .IDENTIFIER && context.peek(.LEFT_PARENTHESIS, 1) {\n      context.log.syntaxErrorMissingDef(token.range)\n      tokenKind = .IDENTIFIER\n      kind = .FUNCTION_GLOBAL\n      text = \"def\"\n      wasCorrected = true\n    }\n\n    # Special-case enum and flags symbols\n    if parent.kind.isEnumOrFlags && tokenKind == .IDENTIFIER && kind == .OBJECT_GLOBAL {\n      while true {\n        if text in identifierToSymbolKind || !context.expect(.IDENTIFIER) {\n          break\n        }\n\n        var variable = VariableSymbol.new(.VARIABLE_ENUM_OR_FLAGS, text)\n        variable.range = token.range\n        variable.parent = parent\n        variable.flags |= .IS_CONST\n        parent.variables.append(variable)\n        symbol = variable\n\n        var comma = context.current\n        if !context.eat(.COMMA) {\n          break\n        }\n\n        variable.annotations = annotations?.clone\n        variable.comments = comments\n        token = context.current\n        text = token.range.toString\n\n        if context.peek(.NEWLINE) || context.peek(.RIGHT_BRACE) {\n          context.log.syntaxWarningExtraComma(comma.range)\n          break\n        }\n      }\n    }\n\n    else {\n      # Parse the symbol kind\n      switch tokenKind {\n        case .CONST, .VAR {\n          kind = parent.kind.hasInstances ? .VARIABLE_INSTANCE : .VARIABLE_GLOBAL\n        }\n\n        # For symbol kinds that can't live inside functions, use contextual\n        # keywords instead of special keyword tokens. This means these names\n        # are still available to be used as regular symbols:\n        #\n        #   class div {\n        #     var class = \"\"\n        #   }\n        #\n        #   var example = <div class=\"header\"/>\n        #\n        case .IDENTIFIER {\n          if kind == .OBJECT_GLOBAL {\n            context.unexpectedToken\n            return false\n          }\n          if kind == .FUNCTION_GLOBAL && parent.kind.hasInstances {\n            kind = .FUNCTION_INSTANCE\n          }\n        }\n\n        default {\n          context.unexpectedToken\n          return false\n        }\n      }\n\n      if !wasCorrected {\n        context.next\n      }\n\n      var nameToken = context.current\n      var range = nameToken.range\n      var name = range.toString\n      var isOperator = false\n\n      # Only check for custom operators for instance functions\n      if kind == .FUNCTION_INSTANCE {\n        if nameToken.kind in customOperators {\n          isOperator = true\n        } else if nameToken.kind in forbiddenCustomOperators {\n          context.log.syntaxErrorBadOperatorCustomization(range, nameToken.kind,\n            forbiddenGroupDescription[forbiddenCustomOperators[nameToken.kind]])\n          isOperator = true\n        }\n      }\n\n      # Parse the symbol name\n      if isOperator {\n        context.next\n      } else if kind == .FUNCTION_GLOBAL && context.eat(.ANNOTATION) {\n        kind = .FUNCTION_ANNOTATION\n      } else if context.eat(.LIST_NEW) || context.eat(.SET_NEW) {\n        if kind == .FUNCTION_INSTANCE {\n          kind = .FUNCTION_CONSTRUCTOR\n        }\n      } else {\n        if !context.expect(.IDENTIFIER) {\n          return false\n        }\n        if kind == .FUNCTION_INSTANCE && name == \"new\" {\n          kind = .FUNCTION_CONSTRUCTOR\n        }\n      }\n\n      # Parse shorthand nested namespace declarations\n      if kind.isObject {\n        while context.eat(.DOT) {\n          var nextToken = context.current\n          if !context.expect(.IDENTIFIER) {\n            return false\n          }\n\n          # Wrap this declaration in a namespace\n          var nextParent = ObjectSymbol.new(.OBJECT_NAMESPACE, name)\n          nextParent.range = range\n          nextParent.parent = parent\n          parent.objects.append(nextParent)\n          parent = nextParent\n\n          # Update the declaration token\n          nameToken = nextToken\n          range = nextToken.range\n          name = range.toString\n        }\n      }\n\n      # Parse the symbol body\n      switch kind {\n        case .VARIABLE_GLOBAL, .VARIABLE_INSTANCE {\n          while true {\n            var variable = VariableSymbol.new(kind, name)\n            variable.range = range\n            variable.parent = parent\n\n            if tokenKind == .CONST {\n              variable.flags |= .IS_CONST\n            }\n\n            if context.peek(.COLON) {\n              context.log.syntaxErrorExtraColonBeforeType(context.next.range)\n            }\n\n            if peekType(context) {\n              variable.type = parseType(context)\n            }\n\n            if context.eat(.ASSIGN) {\n              variable.value = expressionParser.parse(context, .LOWEST)\n              checkExtraParentheses(context, variable.value)\n            }\n\n            parent.variables.append(variable)\n\n            if !context.eat(.COMMA) {\n              symbol = variable\n              break\n            }\n\n            variable.annotations = annotations?.clone\n            variable.comments = comments\n\n            nameToken = context.current\n            range = nameToken.range\n            name = range.toString\n\n            if !context.expect(.IDENTIFIER) {\n              return false\n            }\n          }\n        }\n\n        case .FUNCTION_ANNOTATION, .FUNCTION_CONSTRUCTOR, .FUNCTION_GLOBAL, .FUNCTION_INSTANCE {\n          var function = FunctionSymbol.new(kind, name)\n          function.range = range\n          function.parent = parent\n\n          if text == \"over\" {\n            function.flags |= .IS_OVER\n          }\n\n          # Check for setters like \"def foo=(x int) {}\" but don't allow a space\n          # between the name and the assignment operator\n          if kind != .FUNCTION_ANNOTATION && nameToken.kind == .IDENTIFIER && context.peek(.ASSIGN) && context.current.range.start == nameToken.range.end {\n            function.range = Range.span(function.range, context.next.range)\n            function.flags |= .IS_SETTER\n            function.name += \"=\"\n          }\n\n          # Parse type parameters\n          if context.eat(.PARAMETER_LIST_START) {\n            function.parameters = parseTypeParameters(context, .PARAMETER_FUNCTION)\n            if function.parameters == null {\n              return false\n            }\n          }\n\n          # Parse function arguments\n          var before = context.current\n          if context.eat(.LEFT_PARENTHESIS) {\n            if !parseFunctionArguments(context, function) {\n              return false\n            }\n\n            # Functions without arguments are \"getters\" and don't use parentheses\n            if function.arguments.isEmpty {\n              context.log.syntaxErrorEmptyFunctionParentheses(context.spanSince(before.range))\n            }\n          }\n\n          if kind != .FUNCTION_ANNOTATION && !parseFunctionReturnTypeAndBlock(context, function) {\n            return false\n          }\n\n          # Don't mark operators as getters to avoid confusion with unary operators and compiler-generated call expressions\n          if !isOperator && function.arguments.isEmpty {\n            function.flags |= .IS_GETTER\n          }\n\n          parent.functions.append(function)\n          symbol = function\n        }\n\n        case .OBJECT_CLASS, .OBJECT_ENUM, .OBJECT_FLAGS, .OBJECT_INTERFACE, .OBJECT_NAMESPACE, .OBJECT_WRAPPED {\n          var object = ObjectSymbol.new(kind, name)\n          object.range = range\n          object.parent = parent\n\n          if kind != .OBJECT_NAMESPACE && context.eat(.PARAMETER_LIST_START) {\n            object.parameters = parseTypeParameters(context, .PARAMETER_OBJECT)\n            if object.parameters == null {\n              return false\n            }\n          }\n\n          # Allow \"type Foo = int\"\n          if kind == .OBJECT_WRAPPED && context.eat(.ASSIGN) {\n            object.extends = parseType(context)\n            if object.extends == null {\n              return false\n            }\n          }\n\n          # Regular block structure \"type Foo : int {}\"\n          else {\n            # Base class\n            var isExtends = context.peek(.IDENTIFIER) && context.current.range.toString == \"extends\"\n            if isExtends {\n              context.log.syntaxErrorExtendsKeyword(context.next.range)\n            }\n            if isExtends || context.eat(.COLON) {\n              object.extends = parseType(context)\n              if object.extends == null {\n                return false\n              }\n            }\n\n            # Interfaces\n            var isImplements = context.peek(.IDENTIFIER) && context.current.range.toString == \"implements\"\n            if isImplements {\n              context.log.syntaxErrorImplementsKeyword(context.next.range)\n            }\n            if isImplements || context.eat(.DOUBLE_COLON) {\n              object.implements = []\n              while true {\n                var type = parseType(context)\n                object.implements.append(type)\n                if !context.eat(.COMMA) {\n                  break\n                }\n              }\n            }\n\n            context.skipWhitespace\n            if !context.expect(.LEFT_BRACE) {\n              scanForToken(context, .LEFT_BRACE)\n            }\n\n            parseSymbols(context, object, null)\n            object.commentsInsideEndOfBlock = context.stealComments\n\n            if !context.expect(.RIGHT_BRACE) {\n              return false\n            }\n          }\n\n          parent.objects.append(object)\n          symbol = object\n        }\n\n        default {\n          assert(false)\n        }\n      }\n\n      # Forbid certain kinds of symbols inside certain object types\n      if (parent.kind.isEnumOrFlags || parent.kind == .OBJECT_WRAPPED || parent.kind == .OBJECT_INTERFACE) && (\n          kind == .FUNCTION_CONSTRUCTOR || kind == .VARIABLE_INSTANCE) {\n        context.log.syntaxErrorBadDeclarationInsideType(context.spanSince(token.range))\n      }\n    }\n\n    symbol.annotations = annotations?.clone\n    symbol.comments = Comment.concat(comments, parseTrailingComment(context))\n\n    if !parseAfterBlock(context) {\n      return false\n    }\n\n    return true\n  }\n\n  def parseSymbols(context ParserContext, parent ObjectSymbol, annotations List<Node>) {\n    context.eat(.NEWLINE)\n\n    while !context.peek(.END_OF_FILE) && !context.peek(.RIGHT_BRACE) {\n      if !parseSymbol(context, parent, annotations) {\n        break\n      }\n    }\n  }\n\n  def parseCommaSeparatedList(context ParserContext, parent Node, stop TokenKind) {\n    var isFirst = true\n    var leading = parseTrailingComment(context)\n    context.skipWhitespace\n    while true {\n      var comments = Comment.concat(leading, context.stealComments)\n      leading = null\n      if isFirst && context.eat(stop) {\n        _warnAboutIgnoredComments(context, comments)\n        break\n      }\n      var value = expressionParser.parse(context, .LOWEST)\n      value.comments = Comment.concat(comments, parseTrailingComment(context))\n      context.skipWhitespace\n      parent.appendChild(value)\n      if context.eat(stop) {\n        break\n      }\n      if !context.expect(.COMMA) {\n        scanForToken(context, stop)\n        break\n      }\n      value.comments = Comment.concat(value.comments, parseTrailingComment(context))\n      context.skipWhitespace\n      isFirst = false\n    }\n  }\n\n  def parseHexCharacter(c int) int {\n    if c >= '0' && c <= '9' { return c - '0' }\n    if c >= 'A' && c <= 'F' { return c - 'A' + 10 }\n    if c >= 'a' && c <= 'f' { return c - 'a' + 10 }\n    return -1\n  }\n\n  def createStringNode(log Log, range Range) Node {\n    return Node.createString(parseStringLiteral(log, range)).withRange(range)\n  }\n\n  def parseStringLiteral(log Log, range Range) string {\n    var text = range.toString\n    var count = text.count\n    assert(count >= 2)\n    assert(text[0] == '\"' || text[0] == '\\'' || text[0] == ')')\n    assert(text[count - 1] == '\"' || text[count - 1] == '\\'' || text[count - 1] == '(')\n    var builder = StringBuilder.new\n    var start = 1\n    var stop = count - (text[count - 1] == '(' ? 2 : 1)\n    var i = start\n    while i < stop {\n      var c = text[i++]\n      if c == '\\\\' {\n        var escape = i - 1\n        builder.append(text.slice(start, escape))\n        if i < stop {\n          c = text[i++]\n          if c == 'n' {\n            builder.append(\"\\n\")\n            start = i\n          }\n          else if c == 'r' {\n            builder.append(\"\\r\")\n            start = i\n          }\n          else if c == 't' {\n            builder.append(\"\\t\")\n            start = i\n          }\n          else if c == '0' {\n            builder.append(\"\\0\")\n            start = i\n          }\n          else if c == '\\\\' || c == '\"' || c == '\\'' {\n            builder.append(string.fromCodeUnit(c))\n            start = i\n          }\n          else if c == 'x' {\n            if i < stop {\n              var c0 = parseHexCharacter(text[i++])\n              if i < stop {\n                var c1 = parseHexCharacter(text[i++])\n                if c0 != -1 && c1 != -1 {\n                  builder.append(string.fromCodeUnit(c0 << 4 | c1))\n                  start = i\n                }\n              }\n            }\n          }\n        }\n        if start < i {\n          log.syntaxErrorInvalidEscapeSequence(Range.new(range.source, range.start + escape, range.start + i))\n        }\n      }\n    }\n    builder.append(text.slice(start, i))\n    return builder.toString\n  }\n\n  const intLiteral = (context ParserContext, token Token) Node => Node.createInt(parseIntLiteral(context.log, token.range).value).withRange(token.range)\n  const stringLiteral = (context ParserContext, token Token) Node => createStringNode(context.log, token.range)\n\n  def boolLiteral(value bool) fn(ParserContext, Token) Node {\n    return (context, token) => Node.createBool(value).withRange(token.range)\n  }\n\n  def tokenLiteral(kind NodeKind) fn(ParserContext, Token) Node {\n    return (context, token) => Node.new(kind).withRange(token.range)\n  }\n\n  def unaryPrefix(kind NodeKind) fn(ParserContext, Token, Node) Node {\n    return (context, token, value) => Node.createUnary(kind, value).withRange(Range.span(token.range, value.range)).withInternalRange(token.range)\n  }\n\n  def unaryPostfix(kind NodeKind) fn(ParserContext, Node, Token) Node {\n    return (context, value, token) => Node.createUnary(kind, value).withRange(Range.span(value.range, token.range)).withInternalRange(token.range)\n  }\n\n  def binaryInfix(kind NodeKind) fn(ParserContext, Node, Token, Node) Node {\n    return (context, left, token, right) => {\n      if kind == .ASSIGN && left.kind == .INDEX {\n        left.appendChild(right)\n        left.kind = .ASSIGN_INDEX\n        return left.withRange(Range.span(left.range, right.range)).withInternalRange(Range.span(left.internalRange, right.range))\n      }\n      return Node.createBinary(kind, left, right).withRange(Range.span(left.range, right.range)).withInternalRange(token.range)\n    }\n  }\n\n  var dotInfixParselet = (context ParserContext, left Node) Node => {\n    var innerComments = context.stealComments\n    var token = context.next\n    var range = context.current.range\n    if !context.expect(.IDENTIFIER) {\n      # Create a empty range instead of using createParseError so IDE code completion still works\n      range = Range.new(token.range.source, token.range.end, token.range.end)\n    }\n    return Node.createDot(left, range.toString)\n      .withRange(context.spanSince(left.range))\n      .withInternalRange(range)\n      .withInnerComments(innerComments)\n  }\n\n  var initializerParselet = (context ParserContext) Node => {\n    var token = context.next\n    var kind NodeKind = token.kind == .LEFT_BRACE ? .INITIALIZER_MAP : .INITIALIZER_LIST\n    var node = Node.createInitializer(kind)\n\n    if token.kind == .LEFT_BRACE || token.kind == .LEFT_BRACKET {\n      var expectColon = kind != .INITIALIZER_LIST\n      var end TokenKind = expectColon ? .RIGHT_BRACE : .RIGHT_BRACKET\n\n      while true {\n        context.eat(.NEWLINE)\n        var comments = context.stealComments\n        if context.peek(end) {\n          _warnAboutIgnoredComments(context, comments)\n          break\n        }\n\n        var first = expressionParser.parse(context, .LOWEST)\n        var colon = context.current\n        if !expectColon {\n          node.appendChild(first)\n        } else {\n          if !context.expect(.COLON) {\n            break\n          }\n          var second = expressionParser.parse(context, .LOWEST)\n          first = Node.createPair(first, second).withRange(Range.span(first.range, second.range)).withInternalRange(colon.range)\n          node.appendChild(first)\n        }\n\n        first.comments = Comment.concat(comments, parseTrailingComment(context))\n        if !context.eat(.COMMA) {\n          break\n        }\n        first.comments = Comment.concat(first.comments, parseTrailingComment(context))\n      }\n\n      context.skipWhitespace\n      scanForToken(context, end)\n    }\n\n    else if token.kind == .LIST_NEW || token.kind == .SET_NEW {\n      node.appendChild(Node.createName(\"new\").withRange(Range.new(token.range.source, token.range.start + 1, token.range.end - 1)))\n    }\n\n    return node.withRange(context.spanSince(token.range))\n  }\n\n  var parameterizedParselet = (context ParserContext, left Node) Node => {\n    var value = Node.createParameterize(left)\n    var token = context.next\n    while true {\n      var type = parseType(context)\n      value.appendChild(type)\n      if !context.eat(.COMMA) {\n        break\n      }\n    }\n    scanForToken(context, .PARAMETER_LIST_END)\n    return value.withRange(context.spanSince(left.range)).withInternalRange(context.spanSince(token.range))\n  }\n\n  def createExpressionParser Pratt {\n    var pratt = Pratt.new\n\n    ########################################\n    # Literals\n    ########################################\n\n    pratt.literal(.DOUBLE, (context, token) => Node.createDouble(parseDoubleLiteral(token.range.toString)).withRange(token.range))\n    pratt.literal(.FALSE, boolLiteral(false))\n    pratt.literal(.INT, intLiteral)\n    pratt.literal(.INT_BINARY, intLiteral)\n    pratt.literal(.INT_HEX, intLiteral)\n    pratt.literal(.INT_OCTAL, intLiteral)\n    pratt.literal(.NULL, tokenLiteral(.NULL))\n    pratt.literal(.STRING, stringLiteral)\n    pratt.literal(.SUPER, tokenLiteral(.SUPER))\n    pratt.literal(.TRUE, boolLiteral(true))\n\n    pratt.literal(.CHARACTER, (context, token) => {\n      var result = parseStringLiteral(context.log, token.range)\n      var codePoint = 0\n\n      # There must be exactly one unicode code point\n      var iterator = Unicode.StringIterator.INSTANCE.reset(result, 0)\n      codePoint = iterator.nextCodePoint\n      if codePoint == -1 || iterator.nextCodePoint != -1 {\n        context.log.syntaxErrorInvalidCharacter(token.range)\n      }\n\n      # Don't return null when there's an error because that\n      # error won't affect the rest of the compilation\n      return Node.createInt(codePoint).withRange(token.range)\n    })\n\n    ########################################\n    # Unary expressions\n    ########################################\n\n    pratt.prefix(.MINUS, .UNARY_PREFIX, unaryPrefix(.NEGATIVE))\n    pratt.prefix(.NOT, .UNARY_PREFIX, unaryPrefix(.NOT))\n    pratt.prefix(.PLUS, .UNARY_PREFIX, unaryPrefix(.POSITIVE))\n    pratt.prefix(.TILDE, .UNARY_PREFIX, unaryPrefix(.COMPLEMENT))\n    pratt.prefix(.INCREMENT, .UNARY_PREFIX, unaryPrefix(.PREFIX_INCREMENT))\n    pratt.prefix(.DECREMENT, .UNARY_PREFIX, unaryPrefix(.PREFIX_DECREMENT))\n    pratt.postfix(.INCREMENT, .UNARY_PREFIX, unaryPostfix(.POSTFIX_INCREMENT))\n    pratt.postfix(.DECREMENT, .UNARY_PREFIX, unaryPostfix(.POSTFIX_DECREMENT))\n\n    ########################################\n    # Binary expressions\n    ########################################\n\n    pratt.infix(.BITWISE_AND, .BITWISE_AND, binaryInfix(.BITWISE_AND))\n    pratt.infix(.BITWISE_OR, .BITWISE_OR, binaryInfix(.BITWISE_OR))\n    pratt.infix(.BITWISE_XOR, .BITWISE_XOR, binaryInfix(.BITWISE_XOR))\n    pratt.infix(.COMPARE, .COMPARE, binaryInfix(.COMPARE))\n    pratt.infix(.DIVIDE, .MULTIPLY, binaryInfix(.DIVIDE))\n    pratt.infix(.EQUAL, .EQUAL, binaryInfix(.EQUAL))\n    pratt.infix(.GREATER_THAN, .COMPARE, binaryInfix(.GREATER_THAN))\n    pratt.infix(.GREATER_THAN_OR_EQUAL, .COMPARE, binaryInfix(.GREATER_THAN_OR_EQUAL))\n    pratt.infix(.IN, .COMPARE, binaryInfix(.IN))\n    pratt.infix(.LESS_THAN, .COMPARE, binaryInfix(.LESS_THAN))\n    pratt.infix(.LESS_THAN_OR_EQUAL, .COMPARE, binaryInfix(.LESS_THAN_OR_EQUAL))\n    pratt.infix(.LOGICAL_AND, .LOGICAL_AND, binaryInfix(.LOGICAL_AND))\n    pratt.infix(.LOGICAL_OR, .LOGICAL_OR, binaryInfix(.LOGICAL_OR))\n    pratt.infix(.MINUS, .ADD, binaryInfix(.SUBTRACT))\n    pratt.infix(.MODULUS, .MULTIPLY, binaryInfix(.MODULUS))\n    pratt.infix(.MULTIPLY, .MULTIPLY, binaryInfix(.MULTIPLY))\n    pratt.infix(.NOT_EQUAL, .EQUAL, binaryInfix(.NOT_EQUAL))\n    pratt.infix(.PLUS, .ADD, binaryInfix(.ADD))\n    pratt.infix(.POWER, .UNARY_PREFIX, binaryInfix(.POWER))\n    pratt.infix(.REMAINDER, .MULTIPLY, binaryInfix(.REMAINDER))\n    pratt.infix(.SHIFT_LEFT, .SHIFT, binaryInfix(.SHIFT_LEFT))\n    pratt.infix(.SHIFT_RIGHT, .SHIFT, binaryInfix(.SHIFT_RIGHT))\n    pratt.infix(.UNSIGNED_SHIFT_RIGHT, .SHIFT, binaryInfix(.UNSIGNED_SHIFT_RIGHT))\n\n    pratt.infixRight(.ASSIGN, .ASSIGN, binaryInfix(.ASSIGN))\n    pratt.infixRight(.ASSIGN_BITWISE_AND, .ASSIGN, binaryInfix(.ASSIGN_BITWISE_AND))\n    pratt.infixRight(.ASSIGN_BITWISE_OR, .ASSIGN, binaryInfix(.ASSIGN_BITWISE_OR))\n    pratt.infixRight(.ASSIGN_BITWISE_XOR, .ASSIGN, binaryInfix(.ASSIGN_BITWISE_XOR))\n    pratt.infixRight(.ASSIGN_DIVIDE, .ASSIGN, binaryInfix(.ASSIGN_DIVIDE))\n    pratt.infixRight(.ASSIGN_MINUS, .ASSIGN, binaryInfix(.ASSIGN_SUBTRACT))\n    pratt.infixRight(.ASSIGN_MODULUS, .ASSIGN, binaryInfix(.ASSIGN_MODULUS))\n    pratt.infixRight(.ASSIGN_MULTIPLY, .ASSIGN, binaryInfix(.ASSIGN_MULTIPLY))\n    pratt.infixRight(.ASSIGN_NULL, .ASSIGN, binaryInfix(.ASSIGN_NULL))\n    pratt.infixRight(.ASSIGN_PLUS, .ASSIGN, binaryInfix(.ASSIGN_ADD))\n    pratt.infixRight(.ASSIGN_POWER, .ASSIGN, binaryInfix(.ASSIGN_POWER))\n    pratt.infixRight(.ASSIGN_REMAINDER, .ASSIGN, binaryInfix(.ASSIGN_REMAINDER))\n    pratt.infixRight(.ASSIGN_SHIFT_LEFT, .ASSIGN, binaryInfix(.ASSIGN_SHIFT_LEFT))\n    pratt.infixRight(.ASSIGN_SHIFT_RIGHT, .ASSIGN, binaryInfix(.ASSIGN_SHIFT_RIGHT))\n    pratt.infixRight(.ASSIGN_UNSIGNED_SHIFT_RIGHT, .ASSIGN, binaryInfix(.ASSIGN_UNSIGNED_SHIFT_RIGHT))\n    pratt.infixRight(.NULL_JOIN, .NULL_JOIN, binaryInfix(.NULL_JOIN))\n\n    ########################################\n    # Other expressions\n    ########################################\n\n    pratt.parselet(.DOT, .MEMBER).infix = dotInfixParselet\n    pratt.parselet(.INDEX, .LOWEST).prefix = initializerParselet\n    pratt.parselet(.LEFT_BRACE, .LOWEST).prefix = initializerParselet\n    pratt.parselet(.LEFT_BRACKET, .LOWEST).prefix = initializerParselet\n    pratt.parselet(.LIST_NEW, .LOWEST).prefix = initializerParselet\n    pratt.parselet(.SET_NEW, .LOWEST).prefix = initializerParselet\n    pratt.parselet(.PARAMETER_LIST_START, .MEMBER).infix = parameterizedParselet\n\n    # String interpolation\n    pratt.parselet(.STRING_INTERPOLATION_START, .LOWEST).prefix = (context) => {\n      var token = context.next\n      var node = Node.createStringInterpolation.appendChild(createStringNode(context.log, token.range))\n      while true {\n        var value = expressionParser.parse(context, .LOWEST)\n        node.appendChild(value)\n        context.skipWhitespace\n        token = context.current\n        if !context.eat(.STRING_INTERPOLATION_CONTINUE) && !context.expect(.STRING_INTERPOLATION_END) {\n          return context.createParseError\n        }\n        node.appendChild(createStringNode(context.log, token.range))\n        if token.kind == .STRING_INTERPOLATION_END {\n          break\n        }\n      }\n      return node.withRange(context.spanSince(node.firstChild.range))\n    }\n\n    # \"x?.y\"\n    pratt.parselet(.NULL_DOT, .MEMBER).infix = (context, left) => {\n      context.next\n      var range = context.current.range\n      if !context.expect(.IDENTIFIER) {\n        return context.createParseError\n      }\n      return Node.createNullDot(left, range.toString).withRange(context.spanSince(left.range)).withInternalRange(range)\n    }\n\n    # Lambda expressions like \"=> x\"\n    pratt.parselet(.ARROW, .LOWEST).prefix = (context) => {\n      var token = context.current\n      var symbol = FunctionSymbol.new(.FUNCTION_LOCAL, \"<lambda>\")\n      if !parseFunctionBlock(context, symbol) {\n        return context.createParseError\n      }\n      symbol.range = context.spanSince(token.range)\n      return Node.createLambda(symbol).withRange(symbol.range)\n    }\n\n    # Cast expressions\n    pratt.parselet(.AS, .UNARY_PREFIX).infix = (context, left) => {\n      var token = context.next\n      var type = parseType(context)\n      return Node.createCast(left, type).withRange(context.spanSince(left.range)).withInternalRange(token.range)\n    }\n\n    # Using \".\" as a unary prefix operator accesses members off the inferred type\n    pratt.parselet(.DOT, .MEMBER).prefix = (context) => {\n      var token = context.next\n      var range = context.current.range\n      if !context.expect(.IDENTIFIER) {\n        return context.createParseError\n      }\n      return Node.createDot(null, range.toString).withRange(context.spanSince(token.range)).withInternalRange(range)\n    }\n\n    # Access members off of \"dynamic\" for untyped globals\n    pratt.parselet(.DYNAMIC, .LOWEST).prefix = (context) => {\n      var token = context.next\n      if !context.expect(.DOT) {\n        return context.createParseError\n      }\n      var range = context.current.range\n      if !context.expect(.IDENTIFIER) {\n        return context.createParseError\n      }\n      return Node.createDot(Node.createType(.DYNAMIC), range.toString).withRange(context.spanSince(token.range)).withInternalRange(range)\n    }\n\n    # Name expressions and lambda expressions like \"x => x * x\"\n    pratt.parselet(.IDENTIFIER, .LOWEST).prefix = (context) => {\n      var range = context.next.range\n      var name = range.toString\n\n      # Lambda expression\n      if context.peek(.ARROW) {\n        var symbol = FunctionSymbol.new(.FUNCTION_LOCAL, \"<lambda>\")\n        var argument = VariableSymbol.new(.VARIABLE_ARGUMENT, name)\n        argument.range = range\n        symbol.arguments.append(argument)\n        if !parseFunctionBlock(context, symbol) {\n          return context.createParseError\n        }\n        symbol.range = context.spanSince(range)\n        return Node.createLambda(symbol).withRange(symbol.range)\n      }\n\n      # New expression (an error, but still parsed for a better error message)\n      if context.peek(.IDENTIFIER) && name == \"new\" {\n        var type = parseType(context)\n        context.log.syntaxErrorNewOperator(context.spanSince(range), \"\\(type.range).new\")\n        return Node.createParseError.withRange(context.spanSince(range))\n      }\n\n      return Node.createName(name).withRange(range)\n    }\n\n    # Type check expressions\n    pratt.parselet(.IS, .COMPARE).infix = (context, left) => {\n      var token = context.next\n      var type = parseType(context)\n      return Node.createTypeCheck(left, type).withRange(context.spanSince(left.range)).withInternalRange(token.range)\n    }\n\n    # Index expressions\n    pratt.parselet(.LEFT_BRACKET, .MEMBER).infix = (context, left) => {\n      var token = context.next\n      var right = expressionParser.parse(context, .LOWEST)\n      scanForToken(context, .RIGHT_BRACKET)\n      return Node.createIndex(left, right).withRange(context.spanSince(left.range)).withInternalRange(context.spanSince(token.range))\n    }\n\n    # Parenthetic groups and lambda expressions like \"() => x\"\n    pratt.parselet(.LEFT_PARENTHESIS, .LOWEST).prefix = (context) => {\n      var token = context.next\n\n      # Try to parse a group\n      if !context.peek(.RIGHT_PARENTHESIS) {\n        var value = pratt.parse(context, .LOWEST)\n        if (value.kind != .NAME || !peekType(context)) && context.eat(.RIGHT_PARENTHESIS) {\n          if value.kind != .NAME || !context.peek(.ARROW) {\n            return value.withRange(context.spanSince(token.range)).withFlags(.IS_INSIDE_PARENTHESES)\n          }\n          context.undo\n        }\n        context.undo\n      }\n\n      # Parse a lambda instead\n      var symbol = FunctionSymbol.new(.FUNCTION_LOCAL, \"<lambda>\")\n      if !parseFunctionArguments(context, symbol) || !parseFunctionReturnTypeAndBlock(context, symbol) {\n        return context.createParseError\n      }\n      symbol.range = context.spanSince(token.range)\n      return Node.createLambda(symbol).withRange(symbol.range)\n    }\n\n    # Call expressions\n    pratt.parselet(.LEFT_PARENTHESIS, .UNARY_POSTFIX).infix = (context, left) => {\n      var node = Node.createCall(left)\n      var token = context.next\n      parseCommaSeparatedList(context, node, .RIGHT_PARENTHESIS)\n      return node.withRange(context.spanSince(left.range)).withInternalRange(context.spanSince(token.range))\n    }\n\n    # Hook expressions\n    pratt.parselet(.QUESTION_MARK, .ASSIGN).infix = (context, left) => {\n      context.next\n      var middle = pratt.parse(context, (Precedence.ASSIGN - 1) as Precedence)\n      if !context.expect(.COLON) {\n        return context.createParseError\n      }\n      var right = pratt.parse(context, (Precedence.ASSIGN - 1) as Precedence)\n      return Node.createHook(left, middle, right).withRange(context.spanSince(left.range))\n    }\n\n    # XML literals\n    pratt.parselet(.XML_START, .LOWEST).prefix = (context) => {\n      var token = context.next\n      var tag = parseDotChain(context)\n      if tag == null {\n        scanForToken(context, .XML_END)\n        return context.createParseError\n      }\n      var attributes = Node.createSequence\n\n      # Parse attributes\n      context.skipWhitespace\n      while context.peek(.IDENTIFIER) {\n        var name = parseDotChain(context)\n        var assignment = context.current\n        var kind = assignmentOperators.get(assignment.kind, .NULL)\n        if kind == .NULL {\n          context.expect(.ASSIGN)\n          scanForToken(context, .XML_END)\n          return context.createParseError\n        }\n        context.next\n        var value = expressionParser.parse(context, (Precedence.UNARY_PREFIX - 1) as Precedence)\n        attributes.appendChild(Node.createBinary(kind, name, value).withRange(context.spanSince(name.range)).withInternalRange(assignment.range))\n        context.skipWhitespace\n      }\n\n      # Parse end of tag\n      var block = Node.createBlock\n      var closingTag Node = null\n      context.skipWhitespace\n\n      # Check for children\n      if !context.eat(.XML_END_EMPTY) {\n        if !context.expect(.XML_END) {\n          scanForToken(context, .XML_END)\n          return context.createParseError\n        }\n\n        # Parse children\n        context.skipWhitespace\n        if !parseStatements(context, block, .NORMAL) || !context.expect(.XML_START_CLOSE) {\n          return context.createParseError\n        }\n        block.withRange(context.spanSince(token.range))\n\n        # Parse closing tag\n        closingTag = parseDotChain(context)\n        if closingTag == null {\n          scanForToken(context, .XML_END)\n          return context.createParseError\n        }\n        context.skipWhitespace\n        if !context.expect(.XML_END) {\n          scanForToken(context, .XML_END)\n          return context.createParseError\n        }\n\n        # Validate closing tag (not a fatal error)\n        if !tag.looksTheSameAs(closingTag) {\n          context.log.syntaxErrorXMLClosingTagMismatch(closingTag.range, dotChainToString(closingTag), dotChainToString(tag), tag.range)\n        }\n      }\n\n      return Node.createXML(tag, attributes, block, closingTag).withRange(context.spanSince(token.range))\n    }\n\n    return pratt\n  }\n\n  def dotChainToString(node Node) string {\n    assert(node.kind == .NAME || node.kind == .DOT)\n    if node.kind == .NAME { return node.asString }\n    return dotChainToString(node.dotTarget) + \".\" + node.asString\n  }\n\n  def parseDotChain(context ParserContext) Node {\n    var current = context.current\n    if !context.expect(.IDENTIFIER) {\n      return null\n    }\n    var chain = Node.createName(current.range.toString).withRange(current.range)\n    while context.eat(.DOT) {\n      current = context.current\n      if !context.expect(.IDENTIFIER) {\n        return null\n      }\n      chain = Node.createDot(chain, current.range.toString).withRange(context.spanSince(chain.range)).withInternalRange(current.range)\n    }\n    return chain\n  }\n\n  def createTypeParser Pratt {\n    var pratt = Pratt.new\n\n    pratt.literal(.DYNAMIC, (context, token) => Node.createType(.DYNAMIC).withRange(token.range))\n    pratt.parselet(.DOT, .MEMBER).infix = dotInfixParselet\n    pratt.parselet(.PARAMETER_LIST_START, .MEMBER).infix = parameterizedParselet\n\n    # Name expressions or lambda type expressions like \"fn(int) int\"\n    pratt.parselet(.IDENTIFIER, .LOWEST).prefix = (context) => {\n      var node = Node.createLambdaType\n      var returnType = node.lambdaReturnType\n      var token = context.next\n      var name = token.range.toString\n      var isFirst = true\n\n      if name != \"fn\" || !context.eat(.LEFT_PARENTHESIS) {\n        return Node.createName(name).withRange(token.range)\n      }\n\n      # Parse argument types\n      while !context.eat(.RIGHT_PARENTHESIS) {\n        if !isFirst && !context.expect(.COMMA) {\n          scanForToken(context, .RIGHT_PARENTHESIS)\n          return context.createParseError\n        }\n        node.insertChildBefore(returnType, parseType(context))\n        isFirst = false\n      }\n\n      # Parse return type if present\n      if peekType(context) {\n        returnType.replaceWith(parseType(context))\n      }\n\n      return node.withRange(context.spanSince(token.range))\n    }\n\n    # The \"Foo[]\" syntax is an error but parse it anyway\n    pratt.parselet(.INDEX, .MEMBER).infix = (context, left) => {\n      context.next\n      var range = context.spanSince(left.range)\n      context.log.syntaxErrorWrongListSyntax(range, \"List<\\(left.range)>\")\n      return Node.createParseError.withRange(range)\n    }\n\n    return pratt\n  }\n\n  def parseFile(log Log, tokens List<Token>, global ObjectSymbol, warnAboutIgnoredComments bool) {\n    expressionParser ?= createExpressionParser\n    typeParser ?= createTypeParser\n\n    var context = ParserContext.new(log, tokens, warnAboutIgnoredComments)\n    parseSymbols(context, global, null)\n    context.expect(.END_OF_FILE)\n  }\n}\n"
  },
  {
    "path": "src/frontend/pratt.sk",
    "content": "namespace Skew {\n  # The same operator precedence as C for the most part\n  enum Precedence {\n    LOWEST\n    COMMA\n    ASSIGN\n    NULL_JOIN\n    LOGICAL_OR\n    LOGICAL_AND\n    BITWISE_OR\n    BITWISE_XOR\n    BITWISE_AND\n    EQUAL\n    COMPARE\n    SHIFT\n    ADD\n    MULTIPLY\n    UNARY_PREFIX\n    UNARY_POSTFIX\n    MEMBER\n  }\n\n  class ParserContext {\n    var log Log\n    var inNonVoidFunction = false\n    var _tokens List<Token>\n    var _index = 0\n    const warnAboutIgnoredComments bool\n\n    # Keep track of the previous syntax error so only one syntax error is emitted\n    # per token when recovering from a parse error. For example:\n    #\n    #   int x = (1 + (2 +\n    #\n    # In the code above, the only syntax error should be about an unexpected\n    # end of file and not also about the two missing right parentheses.\n    var _previousSyntaxError = -1\n\n    def current Token {\n      return _tokens[_index]\n    }\n\n    def stealComments List<Comment> {\n      var token = current\n      var comments = token.comments\n      token.comments = null\n      return comments\n    }\n\n    def next Token {\n      var token = current\n      if warnAboutIgnoredComments && token.comments != null {\n        log.syntaxWarningIgnoredCommentInParser(token.comments.first.range)\n      }\n      if _index + 1 < _tokens.count {\n        _index++\n      }\n      return token\n    }\n\n    def spanSince(range Range) Range {\n      var previous = _tokens[_index > 0 ? _index - 1 : 0]\n      return previous.range.end < range.start ? range : Range.span(range, previous.range)\n    }\n\n    def peek(kind TokenKind) bool {\n      return current.kind == kind\n    }\n\n    def peek(kind TokenKind, skip int) bool {\n      assert(skip >= 1)\n      return _tokens[Math.min(_index + skip, _tokens.count - 1)].kind == kind\n    }\n\n    def eat(kind TokenKind) bool {\n      if peek(kind) {\n        next\n        return true\n      }\n      return false\n    }\n\n    def skipWhitespace {\n      eat(.NEWLINE)\n    }\n\n    def skipSemicolon bool {\n      if peek(.SEMICOLON) {\n        expect(.NEWLINE)\n        next\n        return true\n      }\n      return false\n    }\n\n    def undo {\n      assert(_index > 0)\n      _index--\n    }\n\n    def expect(kind TokenKind) bool {\n      if !eat(kind) {\n        if canReportSyntaxError {\n          log.syntaxErrorExpectedToken(current.range, current.kind, kind)\n        }\n        return false\n      }\n      return true\n    }\n\n    def unexpectedToken {\n      if canReportSyntaxError {\n        log.syntaxErrorUnexpectedToken(current)\n      }\n    }\n\n    def createParseError Node {\n      return Node.createParseError.withRange(current.range)\n    }\n\n    def canReportSyntaxError bool {\n      if _previousSyntaxError != _index {\n        _previousSyntaxError = _index\n        return true\n      }\n      return false\n    }\n  }\n\n  class Parselet {\n    var precedence Precedence\n    var prefix fn(ParserContext) Node = null\n    var infix fn(ParserContext, Node) Node = null\n  }\n\n  # A Pratt parser is a parser that associates up to two operations per token,\n  # each with its own precedence. Pratt parsers excel at parsing expression\n  # trees with deeply nested precedence levels. For an excellent writeup, see:\n  #\n  #   http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/\n  #\n  class Pratt {\n    var _table = IntMap<Parselet>.new\n\n    def parselet(kind TokenKind, precedence Precedence) Parselet {\n      var parselet = _table.get(kind, null)\n      if parselet == null {\n        var created = Parselet.new(precedence)\n        parselet = created\n        _table[kind] = created\n      } else if precedence > parselet.precedence {\n        parselet.precedence = precedence\n      }\n      return parselet\n    }\n\n    def parse(context ParserContext, precedence Precedence) Node {\n      context.skipWhitespace\n      var comments = context.stealComments\n      var token = context.current\n      var parselet = _table.get(token.kind, null)\n      if parselet == null || parselet.prefix == null {\n        context.unexpectedToken\n        return context.createParseError\n      }\n      var node = resume(context, precedence, parselet.prefix(context))\n      assert(node != null && node.range != null) # Parselets must set the range of every node\n      node.comments = Comment.concat(comments, node.comments)\n      return node\n    }\n\n    def resume(context ParserContext, precedence Precedence, left Node) Node {\n      while true {\n        var kind = context.current.kind\n        var parselet = _table.get(kind, null)\n        if parselet == null || parselet.infix == null || parselet.precedence <= precedence {\n          break\n        }\n        left = parselet.infix(context, left)\n        assert(left != null && left.range != null) # Parselets must set the range of every node\n      }\n      return left\n    }\n\n    def literal(kind TokenKind, callback fn(ParserContext, Token) Node) {\n      parselet(kind, .LOWEST).prefix = context => callback(context, context.next)\n    }\n\n    def prefix(kind TokenKind, precedence Precedence, callback fn(ParserContext, Token, Node) Node) {\n      parselet(kind, .LOWEST).prefix = context => {\n        var token = context.next\n        return callback(context, token, parse(context, precedence))\n      }\n    }\n\n    def postfix(kind TokenKind, precedence Precedence, callback fn(ParserContext, Node, Token) Node) {\n      parselet(kind, precedence).infix = (context, left) => callback(context, left, context.next)\n    }\n\n    def infix(kind TokenKind, precedence Precedence, callback fn(ParserContext, Node, Token, Node) Node) {\n      parselet(kind, precedence).infix = (context, left) => {\n        var token = context.next\n        var comments = context.stealComments\n        var right = parse(context, precedence)\n        right.comments = Comment.concat(comments, right.comments)\n        return callback(context, left, token, right)\n      }\n    }\n\n    def infixRight(kind TokenKind, precedence Precedence, callback fn(ParserContext, Node, Token, Node) Node) {\n      parselet(kind, precedence).infix = (context, left) => {\n        var token = context.next\n        return callback(context, left, token, parse(context, (precedence as int - 1) as Precedence)) # Subtract 1 for right-associativity\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/frontend/range.sk",
    "content": "namespace Skew {\n  class FormattedRange {\n    var line string\n    var range string\n  }\n\n  class Range {\n    const source Source\n    const start int\n    const end int\n\n    def toString string {\n      return source.contents.slice(start, end)\n    }\n\n    def locationString string {\n      var location = source.indexToLineColumn(start)\n      return \"\\(source.name):\\(location.line + 1):\\(location.column + 1)\"\n    }\n\n    def overlaps(range Range) bool {\n      return source == range.source && start < range.end && range.start < end\n    }\n\n    def touches(index int) bool {\n      return start <= index && index <= end\n    }\n\n    def format(maxLength int) FormattedRange {\n      assert(source != null)\n      var start = source.indexToLineColumn(self.start)\n      var end = source.indexToLineColumn(self.end)\n      var line = source.contentsOfLine(start.line)\n      var startColumn = start.column\n      var endColumn = end.line == start.line ? end.column : line.count\n\n      # Use a unicode iterator to count the actual code points so they don't get sliced through the middle\n      var iterator = Unicode.StringIterator.INSTANCE.reset(line, 0)\n      var codePoints List<int> = []\n      var a = 0\n      var b = 0\n\n      # Expand tabs into spaces\n      while true {\n        if iterator.index == startColumn {\n          a = codePoints.count\n        }\n        if iterator.index == endColumn {\n          b = codePoints.count\n        }\n        var codePoint = iterator.nextCodePoint\n        if codePoint < 0 {\n          break\n        }\n        if codePoint == '\\t' {\n          for space in 0..8 - codePoints.count % 8 {\n            codePoints.append(' ')\n          }\n        } else {\n          codePoints.append(codePoint)\n        }\n      }\n\n      # Ensure the line length doesn't exceed maxLength\n      var count = codePoints.count\n      if maxLength > 0 && count > maxLength {\n        var centeredWidth = Math.min(b - a, maxLength / 2)\n        var centeredStart = Math.max((maxLength - centeredWidth) / 2, 3)\n\n        # Left aligned\n        if a < centeredStart {\n          line = string.fromCodePoints(codePoints.slice(0, maxLength - 3)) + \"...\"\n          if b > maxLength - 3 {\n            b = maxLength - 3\n          }\n        }\n\n        # Right aligned\n        else if count - a < maxLength - centeredStart {\n          var offset = count - maxLength\n          line = \"...\" + string.fromCodePoints(codePoints.slice(offset + 3, count))\n          a -= offset\n          b -= offset\n        }\n\n        # Center aligned\n        else {\n          var offset = a - centeredStart\n          line = \"...\" + string.fromCodePoints(codePoints.slice(offset + 3, offset + maxLength - 3)) + \"...\"\n          a -= offset\n          b -= offset\n          if b > maxLength - 3 {\n            b = maxLength - 3\n          }\n        }\n      } else {\n        line = string.fromCodePoints(codePoints)\n      }\n\n      return FormattedRange.new(line, \" \".repeat(a) + (b - a < 2 ? \"^\" : \"~\".repeat(b - a)))\n    }\n\n    def fromStart(count int) Range {\n      assert(count >= 0 && count <= end - start)\n      return new(source, start, start + count)\n    }\n\n    def fromEnd(count int) Range {\n      assert(count >= 0 && count <= end - start)\n      return new(source, end - count, end)\n    }\n\n    def slice(offsetStart int, offsetEnd int) Range {\n      assert(offsetStart >= 0 && offsetStart <= offsetEnd && offsetEnd <= end - start)\n      return new(source, start + offsetStart, start + offsetEnd)\n    }\n\n    def rangeIncludingLeftWhitespace Range {\n      var index = start\n      var contents = source.contents\n      while index > 0 {\n        var c = contents[index - 1]\n        if c != ' ' && c != '\\t' {\n          break\n        }\n        index--\n      }\n      return new(source, index, end)\n    }\n\n    def rangeIncludingRightWhitespace Range {\n      var index = end\n      var contents = source.contents\n      while index < contents.count {\n        var c = contents[index]\n        if c != ' ' && c != '\\t' {\n          break\n        }\n        index++\n      }\n      return new(source, start, index)\n    }\n  }\n\n  namespace Range {\n    def span(start Range, end Range) Range {\n      assert(start.source == end.source)\n      assert(start.start <= end.end)\n      return new(start.source, start.start, end.end)\n    }\n\n    def inner(start Range, end Range) Range {\n      assert(start.source == end.source)\n      assert(start.end <= end.start)\n      return new(start.source, start.end, end.start)\n    }\n\n    def before(outer Range, inner Range) Range {\n      assert(outer.source == inner.source)\n      assert(outer.start <= inner.start)\n      assert(outer.end >= inner.end)\n      return new(outer.source, outer.start, inner.start)\n    }\n\n    def after(outer Range, inner Range) Range {\n      assert(outer.source == inner.source)\n      assert(outer.start <= inner.start)\n      assert(outer.end >= inner.end)\n      return new(outer.source, inner.end, outer.end)\n    }\n\n    def equal(left Range, right Range) bool {\n      return left.source == right.source && left.start == right.start && left.end == right.end\n    }\n  }\n}\n"
  },
  {
    "path": "src/frontend/source.sk",
    "content": "namespace Skew {\n  class LineColumn {\n    var line int # 0-based index\n    var column int # 0-based index\n  }\n\n  class Source {\n    var name string\n    var contents string\n\n    # This maps line numbers to indices within contents\n    var _lineOffsets List<int> = null\n\n    def entireRange Range {\n      return Range.new(self, 0, contents.count)\n    }\n\n    def lineCount int {\n      _computeLineOffsets\n      return _lineOffsets.count - 1 # Ignore the line offset at 0\n    }\n\n    def contentsOfLine(line int) string {\n      _computeLineOffsets\n      if line < 0 || line >= _lineOffsets.count {\n        return \"\"\n      }\n      var start = _lineOffsets[line]\n      var end = line + 1 < _lineOffsets.count ? _lineOffsets[line + 1] - 1 : contents.count\n      return contents.slice(start, end)\n    }\n\n    def indexToLineColumn(index int) LineColumn {\n      _computeLineOffsets\n\n      # Binary search to find the line\n      var count = _lineOffsets.count\n      var line = 0\n      while count > 0 {\n        var step = count / 2\n        var i = line + step\n        if _lineOffsets[i] <= index {\n          line = i + 1\n          count = count - step - 1\n        } else {\n          count = step\n        }\n      }\n\n      # Use the line to compute the column\n      var column = line > 0 ? index - _lineOffsets[line - 1] : index\n      return LineColumn.new(line - 1, column)\n    }\n\n    def lineColumnToIndex(line int, column int) int {\n      _computeLineOffsets\n      if line >= 0 && line < _lineOffsets.count {\n        var index = _lineOffsets[line]\n        if column >= 0 && index + column <= (line + 1 < _lineOffsets.count ? _lineOffsets[line + 1] : contents.count) {\n          return index + column\n        }\n      }\n      return -1\n    }\n\n    def _computeLineOffsets {\n      if _lineOffsets == null {\n        _lineOffsets = [0]\n        for i in 0..contents.count {\n          if contents[i] == '\\n' {\n            _lineOffsets.append(i + 1)\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/frontend/token.sk",
    "content": "namespace Skew {\n  enum PassKind {\n    LEXING\n  }\n\n  class LexingPass : Pass {\n    over kind PassKind {\n      return .LEXING\n    }\n\n    over run(context PassContext) {\n      for source in context.inputs {\n        context.tokens.append(tokenize(context.log, source))\n      }\n    }\n  }\n\n  class Comment {\n    var range Range\n    var lines List<string>\n    var hasGapBelow bool\n    var isTrailing bool\n  }\n\n  namespace Comment {\n    def concat(left List<Comment>, right List<Comment>) List<Comment> {\n      if left == null { return right }\n      if right == null { return left }\n      left.append(right)\n      return left\n    }\n\n    def lastTrailingComment(comments List<Comment>) Comment {\n      if comments != null {\n        var last = comments.last\n        if last.isTrailing && last.lines.count == 1 {\n          return last\n        }\n      }\n      return null\n    }\n\n    def withoutLastTrailingComment(comments List<Comment>) List<Comment> {\n      if comments != null {\n        var last = comments.last\n        if last.isTrailing && last.lines.count == 1 {\n          return comments.slice(0, comments.count - 1)\n        }\n      }\n      return comments\n    }\n\n    def firstTrailingComment(comments List<Comment>) Comment {\n      if comments != null {\n        var first = comments.first\n        if first.isTrailing && first.lines.count == 1 {\n          return first\n        }\n      }\n      return null\n    }\n\n    def withoutFirstTrailingComment(comments List<Comment>) List<Comment> {\n      if comments != null {\n        var first = comments.first\n        if first.isTrailing && first.lines.count == 1 {\n          return comments.slice(1)\n        }\n      }\n      return comments\n    }\n  }\n\n  class Token {\n    var range Range\n    var kind TokenKind\n    var comments List<Comment>\n  }\n\n  const REMOVE_WHITESPACE_BEFORE = {\n    TokenKind.COLON: 0,\n    TokenKind.COMMA: 0,\n    TokenKind.DOT: 0,\n    TokenKind.QUESTION_MARK: 0,\n    TokenKind.RIGHT_PARENTHESIS: 0,\n  }\n\n  const FORBID_XML_AFTER = {\n    TokenKind.CHARACTER: 0,\n    TokenKind.DECREMENT: 0,\n    TokenKind.DOUBLE: 0,\n    TokenKind.DYNAMIC: 0,\n    TokenKind.STRING_INTERPOLATION_END: 0,\n    TokenKind.FALSE: 0,\n    TokenKind.IDENTIFIER: 0,\n    TokenKind.INCREMENT: 0,\n    TokenKind.INT: 0,\n    TokenKind.INT_BINARY: 0,\n    TokenKind.INT_HEX: 0,\n    TokenKind.INT_OCTAL: 0,\n    TokenKind.NULL: 0,\n    TokenKind.RIGHT_BRACE: 0,\n    TokenKind.RIGHT_BRACKET: 0,\n    TokenKind.RIGHT_PARENTHESIS: 0,\n    TokenKind.STRING: 0,\n    TokenKind.SUPER: 0,\n    TokenKind.TRUE: 0,\n  }\n\n  # This is the inner loop from \"flex\", an ancient lexer generator. The output\n  # of flex is pretty bad (obfuscated variable names and the opposite of modular\n  # code) but it's fast and somewhat standard for compiler design. The code below\n  # replaces a simple hand-coded lexer and offers much better performance.\n  def tokenize(log Log, source Source) List<Token> {\n    var comments List<Comment> = null\n    var tokens List<Token> = []\n    var text = source.contents\n    var count = text.count\n    var previousKind TokenKind = .NULL\n    var previousWasComment = false\n    var stack List<Token> = []\n\n    # For backing up\n    var yy_last_accepting_state = 0\n    var yy_last_accepting_cpos = 0\n\n    # The current character pointer\n    var yy_cp = 0\n\n    while yy_cp < count {\n      var yy_current_state = 1 # Reset the NFA\n      var yy_bp = yy_cp # The pointer to the beginning of the token\n      var yy_act TokenKind = .ERROR\n\n      # Special-case string interpolation\n      var c = text[yy_cp]\n      var isStringInterpolation = c == '\"'\n      if c == ')' {\n        for i = stack.count - 1; i >= 0; i-- {\n          var kind = stack[i].kind\n          if kind == .STRING_INTERPOLATION_START {\n            isStringInterpolation = true\n          } else if kind != .LESS_THAN {\n            break\n          }\n        }\n      }\n      if isStringInterpolation {\n        var isExit = c == ')'\n        yy_cp++\n        while yy_cp < count {\n          c = text[yy_cp++]\n          if c == '\"' {\n            yy_act = isExit ? .STRING_INTERPOLATION_END : .STRING\n            break\n          }\n          if c == '\\\\' {\n            if yy_cp == count {\n              break\n            }\n            c = text[yy_cp++]\n            if c == '(' {\n              yy_act = isExit ? .STRING_INTERPOLATION_CONTINUE : .STRING_INTERPOLATION_START\n              break\n            }\n          }\n        }\n      }\n\n      # Special-case XML literals\n      else if c == '>' && !stack.isEmpty && stack.last.kind == .XML_START {\n        yy_cp++\n        yy_act = .XML_END\n      }\n\n      # Search for a match\n      else {\n        while yy_current_state != YY_JAM_STATE {\n          if yy_cp >= count {\n            break # This prevents syntax errors from causing infinite loops\n          }\n          c = text[yy_cp]\n          var index = c < 127 ? c : 127 # All of the interesting characters are ASCII\n          var yy_c = yy_ec[index]\n          if yy_accept[yy_current_state] != .YY_INVALID_ACTION {\n            yy_last_accepting_state = yy_current_state\n            yy_last_accepting_cpos = yy_cp\n          }\n          while yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state {\n            yy_current_state = yy_def[yy_current_state]\n            if yy_current_state >= YY_ACCEPT_LENGTH {\n              yy_c = yy_meta[yy_c]\n            }\n          }\n          yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]\n          yy_cp++\n        }\n\n        # Find the action\n        yy_act = yy_accept[yy_current_state]\n        while yy_act == .YY_INVALID_ACTION {\n          # Have to back up\n          yy_cp = yy_last_accepting_cpos\n          yy_current_state = yy_last_accepting_state\n          yy_act = yy_accept[yy_current_state]\n        }\n\n        # Ignore whitespace\n        if yy_act == .WHITESPACE {\n          continue\n        }\n\n        # Stop at the end of the file\n        if yy_act == .END_OF_FILE {\n          break\n        }\n      }\n\n      # Special-case XML literals\n      if yy_act == .LESS_THAN && !(previousKind in FORBID_XML_AFTER) {\n        yy_act = .XML_START\n      }\n\n      # This is the default action in flex, which is usually called ECHO\n      else if yy_act == .ERROR {\n        var iterator = Unicode.StringIterator.INSTANCE.reset(text, yy_bp)\n        iterator.nextCodePoint\n        var range = Range.new(source, yy_bp, iterator.index)\n        log.syntaxErrorExtraData(range, range.toString)\n        break\n      }\n\n      var token = Token.new(Range.new(source, yy_bp, yy_cp), yy_act, null)\n\n      # Have a nice error message for certain tokens\n      if yy_act == .COMMENT_ERROR {\n        log.syntaxErrorSlashComment(token.range)\n        token.kind = .COMMENT\n      } else if yy_act == .NOT_EQUAL_ERROR {\n        log.syntaxErrorOperatorTypo(token.range, \"!=\")\n        token.kind = .NOT_EQUAL\n      } else if yy_act == .EQUAL_ERROR {\n        log.syntaxErrorOperatorTypo(token.range, \"==\")\n        token.kind = .EQUAL\n      }\n\n      # Tokens that start with a greater than may need to be split, potentially multiple times\n      var loop = true\n      while loop {\n        var tokenStartsWithGreaterThan = text[token.range.start] == '>'\n        var tokenKind = token.kind\n        loop = false\n\n        # Remove tokens from the stack if they aren't working out\n        while !stack.isEmpty {\n          var top = stack.last\n          var topKind = top.kind\n\n          # Stop parsing a type if we find a token that no type expression uses\n          if topKind == .LESS_THAN && tokenKind != .LESS_THAN && tokenKind != .IDENTIFIER && tokenKind != .COMMA && tokenKind != .DYNAMIC &&\n              tokenKind != .DOT && tokenKind != .LEFT_PARENTHESIS && tokenKind != .RIGHT_PARENTHESIS && !tokenStartsWithGreaterThan {\n            stack.removeLast\n          } else {\n            break\n          }\n        }\n\n        # Group open\n        if tokenKind == .LEFT_PARENTHESIS || tokenKind == .LEFT_BRACE || tokenKind == .LEFT_BRACKET ||\n            tokenKind == .LESS_THAN || tokenKind == .STRING_INTERPOLATION_START || tokenKind == .XML_START {\n          stack.append(token)\n        }\n\n        # Group close\n        else if tokenKind == .RIGHT_PARENTHESIS || tokenKind == .RIGHT_BRACE || tokenKind == .RIGHT_BRACKET ||\n            tokenKind == .STRING_INTERPOLATION_END || tokenKind == .XML_END || tokenStartsWithGreaterThan {\n\n          # Search for a matching opposite token\n          while !stack.isEmpty {\n            var top = stack.last\n            var topKind = top.kind\n\n            # Don't match \">\" that don't work since they are just operators\n            if tokenStartsWithGreaterThan && topKind != .LESS_THAN {\n              break\n            }\n\n            # Consume the current token\n            stack.removeLast\n\n            # Stop if it's a match\n            if tokenKind == .RIGHT_PARENTHESIS && topKind == .LEFT_PARENTHESIS ||\n                tokenKind == .RIGHT_BRACKET && topKind == .LEFT_BRACKET ||\n                tokenKind == .RIGHT_BRACE && topKind == .LEFT_BRACE ||\n                tokenKind == .STRING_INTERPOLATION_END && topKind == .STRING_INTERPOLATION_START {\n              break\n            }\n\n            # Special-case angle brackets matches and ignore tentative matches that didn't work out\n            if topKind == .LESS_THAN && tokenStartsWithGreaterThan {\n\n              # Break apart operators that start with a closing angle bracket\n              if tokenKind != .GREATER_THAN {\n                var start = token.range.start\n                tokens.append(Token.new(Range.new(source, start, start + 1), .PARAMETER_LIST_END, null))\n                token.range = Range.new(source, start + 1, token.range.end)\n                token.kind =\n                  tokenKind == .SHIFT_RIGHT ? .GREATER_THAN :\n                  tokenKind == .UNSIGNED_SHIFT_RIGHT ? .SHIFT_RIGHT :\n                  tokenKind == .GREATER_THAN_OR_EQUAL ? .ASSIGN :\n                  tokenKind == .ASSIGN_SHIFT_RIGHT ? .GREATER_THAN_OR_EQUAL :\n                  tokenKind == .ASSIGN_UNSIGNED_SHIFT_RIGHT ? .ASSIGN_SHIFT_RIGHT :\n                  .NULL\n                assert(token.kind != .NULL)\n                loop = tokenKind != .GREATER_THAN_OR_EQUAL # Split this token again\n              } else {\n                token.kind = .PARAMETER_LIST_END\n              }\n\n              # Convert the \"<\" into a bound for type parameter lists\n              top.kind = .PARAMETER_LIST_START\n\n              # Stop the search since we found a match\n              break\n            }\n          }\n        }\n      }\n\n      # Remove newlines based on the previous token to enable line continuations.\n      # Make sure to be conservative. We want to be like Python, not like\n      # JavaScript ASI! Anything that is at all ambiguous should be disallowed.\n      #\n      # Examples:\n      # - \"var x = 0 \\n .toString\"\n      # - \"var x = 0 # comment \\n .toString\"\n      # - \"var x = 0 \\n # comment \\n .toString\"\n      # - \"var x = 0 \\n ### \\n multi-line comment \\n ### \\n return 0\"\n      #\n      if previousKind == .NEWLINE && token.kind == .NEWLINE {\n        if comments != null && !previousWasComment {\n          comments.last.hasGapBelow = true\n        }\n        previousWasComment = false\n        continue\n      } else if previousKind == .NEWLINE && token.kind in REMOVE_WHITESPACE_BEFORE {\n        var last = tokens.takeLast\n        if last.comments != null {\n          comments ?= []\n          comments.append(last.comments)\n        }\n      }\n\n      # Attach comments to tokens instead of having comments be tokens\n      previousWasComment = token.kind == .COMMENT\n      if previousWasComment {\n        comments ?= []\n        if comments.isEmpty || comments.last.hasGapBelow {\n          comments.append(Comment.new(token.range, [], false, false))\n        }\n        var range = token.range\n        var line = source.contents.slice(range.start + 1, range.end)\n        var hashes = 0\n        for j in 0..line.count {\n          if line[j] != '#' {\n            break\n          }\n          hashes++\n        }\n        if hashes != 0 {\n          line = \"/\".repeat(hashes) + line.slice(hashes)\n        }\n        comments.last.lines.append(line)\n        continue\n      }\n\n      previousKind = token.kind\n\n      if previousKind != .NEWLINE {\n        token.comments = comments\n        comments = null\n      }\n\n      # Capture trailing comments\n      if !tokens.isEmpty && comments != null && comments.count == 1 &&\n          comments.first.lines.count == 1 && !comments.first.hasGapBelow {\n        comments.first.isTrailing = true\n        token.comments = comments\n        comments = null\n      }\n\n      # Accumulate the token for this iteration\n      tokens.append(token)\n    }\n\n    # Every token stream ends in END_OF_FILE\n    tokens.append(Token.new(Range.new(source, yy_cp, yy_cp), .END_OF_FILE, comments))\n\n    # Also return preprocessor token presence so the preprocessor can be avoided\n    return tokens\n  }\n\n  enum TokenKind {\n    # Type parameters are surrounded by \"<\" and \">\"\n    PARAMETER_LIST_END\n    PARAMETER_LIST_START\n\n    # XML entities are surrounded by \"<\" and \">\" (or \"</\" and \"/>\" but those are defined by flex)\n    XML_END\n    XML_START\n\n    # String interpolation looks like \"start\\( 1 )continue( 2 )end\"\n    STRING_INTERPOLATION_CONTINUE\n    STRING_INTERPOLATION_END\n    STRING_INTERPOLATION_START\n\n    def toString string {\n      assert(self in _toString)\n      return _toString[self]\n    }\n  }\n\n  namespace TokenKind {\n    const _toString = {\n      COMMENT: \"comment\",\n      NEWLINE: \"newline\",\n      WHITESPACE: \"whitespace\",\n\n      AS: \"\\\"as\\\"\",\n      BREAK: \"\\\"break\\\"\",\n      CASE: \"\\\"case\\\"\",\n      CATCH: \"\\\"catch\\\"\",\n      CONST: \"\\\"const\\\"\",\n      CONTINUE: \"\\\"continue\\\"\",\n      DEFAULT: \"\\\"default\\\"\",\n      DYNAMIC: \"\\\"dynamic\\\"\",\n      ELSE: \"\\\"else\\\"\",\n      FALSE: \"\\\"false\\\"\",\n      FINALLY: \"\\\"finally\\\"\",\n      FOR: \"\\\"for\\\"\",\n      IF: \"\\\"if\\\"\",\n      IN: \"\\\"in\\\"\",\n      IS: \"\\\"is\\\"\",\n      NULL: \"\\\"null\\\"\",\n      RETURN: \"\\\"return\\\"\",\n      SUPER: \"\\\"super\\\"\",\n      SWITCH: \"\\\"switch\\\"\",\n      THROW: \"\\\"throw\\\"\",\n      TRUE: \"\\\"true\\\"\",\n      TRY: \"\\\"try\\\"\",\n      VAR: \"\\\"var\\\"\",\n      WHILE: \"\\\"while\\\"\",\n\n      ARROW: \"\\\"=>\\\"\",\n      ASSIGN: \"\\\"=\\\"\",\n      ASSIGN_BITWISE_AND: \"\\\"&=\\\"\",\n      ASSIGN_BITWISE_OR: \"\\\"|=\\\"\",\n      ASSIGN_BITWISE_XOR: \"\\\"^=\\\"\",\n      ASSIGN_DIVIDE: \"\\\"/=\\\"\",\n      ASSIGN_INDEX: \"\\\"[]=\\\"\",\n      ASSIGN_MINUS: \"\\\"-=\\\"\",\n      ASSIGN_MODULUS: \"\\\"%%=\\\"\",\n      ASSIGN_MULTIPLY: \"\\\"*=\\\"\",\n      ASSIGN_PLUS: \"\\\"+=\\\"\",\n      ASSIGN_POWER: \"\\\"**=\\\"\",\n      ASSIGN_REMAINDER: \"\\\"%=\\\"\",\n      ASSIGN_SHIFT_LEFT: \"\\\"<<=\\\"\",\n      ASSIGN_SHIFT_RIGHT: \"\\\">>=\\\"\",\n      ASSIGN_UNSIGNED_SHIFT_RIGHT: \"\\\">>>=\\\"\",\n      BITWISE_AND: \"\\\"&\\\"\",\n      BITWISE_OR: \"\\\"|\\\"\",\n      BITWISE_XOR: \"\\\"^\\\"\",\n      COLON: \"\\\":\\\"\",\n      COMMA: \"\\\",\\\"\",\n      COMPARE: \"\\\"<=>\\\"\",\n      DECREMENT: \"\\\"--\\\"\",\n      DIVIDE: \"\\\"/\\\"\",\n      DOT: \"\\\".\\\"\",\n      DOT_DOT: \"\\\"..\\\"\",\n      DOUBLE_COLON: \"\\\"::\\\"\",\n      EQUAL: \"\\\"==\\\"\",\n      GREATER_THAN: \"\\\">\\\"\",\n      GREATER_THAN_OR_EQUAL: \"\\\">=\\\"\",\n      INCREMENT: \"\\\"++\\\"\",\n      INDEX: \"\\\"[]\\\"\",\n      LEFT_BRACE: \"\\\"{\\\"\",\n      LEFT_BRACKET: \"\\\"[\\\"\",\n      LEFT_PARENTHESIS: \"\\\"(\\\"\",\n      LESS_THAN: \"\\\"<\\\"\",\n      LESS_THAN_OR_EQUAL: \"\\\"<=\\\"\",\n      LIST: \"\\\"[...]\\\"\",\n      LIST_NEW: \"\\\"[new]\\\"\",\n      LOGICAL_AND: \"\\\"&&\\\"\",\n      LOGICAL_OR: \"\\\"||\\\"\",\n      MINUS: \"\\\"-\\\"\",\n      MODULUS: \"\\\"%%\\\"\",\n      MULTIPLY: \"\\\"*\\\"\",\n      NOT: \"\\\"!\\\"\",\n      NOT_EQUAL: \"\\\"!=\\\"\",\n      NULL_DOT: \"\\\"?.\\\"\",\n      NULL_JOIN: \"\\\"??\\\"\",\n      PLUS: \"\\\"+\\\"\",\n      POWER: \"\\\"**\\\"\",\n      QUESTION_MARK: \"\\\"?\\\"\",\n      REMAINDER: \"\\\"%\\\"\",\n      RIGHT_BRACE: \"\\\"}\\\"\",\n      RIGHT_BRACKET: \"\\\"]\\\"\",\n      RIGHT_PARENTHESIS: \"\\\")\\\"\",\n      SEMICOLON: \"\\\";\\\"\",\n      SET: \"\\\"{...}\\\"\",\n      SET_NEW: \"\\\"{new}\\\"\",\n      SHIFT_LEFT: \"\\\"<<\\\"\",\n      SHIFT_RIGHT: \"\\\">>\\\"\",\n      TILDE: \"\\\"~\\\"\",\n      UNSIGNED_SHIFT_RIGHT: \"\\\">>>\\\"\",\n\n      ANNOTATION: \"annotation\",\n      CHARACTER: \"character\",\n      DOUBLE: \"double\",\n      END_OF_FILE: \"end of input\",\n      IDENTIFIER: \"identifier\",\n      INT: \"integer\",\n      INT_BINARY: \"integer\",\n      INT_HEX: \"integer\",\n      INT_OCTAL: \"integer\",\n      STRING: \"string\",\n\n      PARAMETER_LIST_END: \"\\\">\\\"\",\n      PARAMETER_LIST_START: \"\\\"<\\\"\",\n\n      XML_CHILD: \"\\\"<>...</>\\\"\",\n      XML_END: \"\\\">\\\"\",\n      XML_END_EMPTY: \"\\\"/>\\\"\",\n      XML_START: \"\\\"<\\\"\",\n      XML_START_CLOSE: \"\\\"</\\\"\",\n\n      STRING_INTERPOLATION_CONTINUE: \"string interpolation\",\n      STRING_INTERPOLATION_END: \"string interpolation\",\n      STRING_INTERPOLATION_START: \"string interpolation\",\n    }\n  }\n}\n"
  },
  {
    "path": "src/frontend/version.sk",
    "content": "namespace Skew {\n  const VERSION = \"0.9.19\"\n}\n"
  },
  {
    "path": "src/lib/build.sk",
    "content": "enum Build {\n  SKEWC\n  API\n  TEST\n}\n\nconst BUILD = Build.SKEWC\n"
  },
  {
    "path": "src/lib/io.sk",
    "content": "if TARGET == .JAVASCRIPT {\n  namespace IO {\n    def isDirectory(path string) bool {\n      try {\n        return dynamic.require(\"fs\").statSync(path).isDirectory()\n      }\n      return false\n    }\n\n    def readDirectory(path string) List<string> {\n      try {\n        var entries List<string> = dynamic.require(\"fs\").readdirSync(path)\n        entries.sort((a, b) => a <=> b)\n        return entries\n      }\n      return null\n    }\n\n    def readFile(path string) string {\n      try {\n        var contents string = dynamic.require(\"fs\").readFileSync(path, \"utf8\")\n        return contents.replaceAll(\"\\r\\n\", \"\\n\")\n      }\n      return null\n    }\n\n    def writeFile(path string, contents string) bool {\n      const fs = dynamic.require(\"fs\")\n      const p = dynamic.require(\"path\")\n      var mkdir_p fn(string)\n      mkdir_p = dir => {\n        if dir != p.dirname(dir) {\n          mkdir_p(p.dirname(dir))\n          try { fs.mkdirSync(dir) }\n        }\n      }\n      mkdir_p(p.dirname(path))\n      try {\n        fs.writeFileSync(path, contents)\n        return true\n      }\n      return false\n    }\n  }\n}\n\nelse if TARGET == .CSHARP {\n  namespace IO {\n    def isDirectory(path string) bool {\n      try {\n        return dynamic.System.IO.Directory.Exists(path)\n      }\n      return false\n    }\n\n    def readDirectory(path string) List<string> {\n      try {\n        var entries List<string> = dynamic.System.Linq.Enumerable.ToList(dynamic.System.IO.Directory.GetFileSystemEntries(path))\n        for i in 0..entries.count {\n          entries[i] = dynamic.System.IO.Path.GetFileName(entries[i])\n        }\n        entries.sort((a, b) => a <=> b)\n        return entries\n      }\n      return null\n    }\n\n    def readFile(path string) string {\n      try {\n        var contents string = dynamic.System.IO.File.ReadAllText(path)\n        return contents.replaceAll(\"\\r\\n\", \"\\n\")\n      }\n      return null\n    }\n\n    def writeFile(path string, contents string) bool {\n      try {\n        dynamic.System.IO.File.WriteAllText(path, contents)\n        return true\n      }\n      return false\n    }\n  }\n}\n\nelse {\n  @import\n  namespace IO {\n    def isDirectory(path string) bool\n    def readDirectory(path string) List<string>\n    def readFile(path string) string\n    def writeFile(path string, contents string) bool\n  }\n}\n"
  },
  {
    "path": "src/lib/terminal.sk",
    "content": "namespace Terminal {\n  enum Color {\n    DEFAULT\n    BOLD\n    GRAY\n    RED\n    GREEN\n    YELLOW\n    BLUE\n    MAGENTA\n    CYAN\n\n    def toEscapeCode int {\n      return colorToEscapeCode[self]\n    }\n  }\n\n  const colorToEscapeCode = {\n    Color.DEFAULT: 0,\n    Color.BOLD: 1,\n    Color.GRAY: 90,\n    Color.RED: 91,\n    Color.GREEN: 92,\n    Color.YELLOW: 93,\n    Color.BLUE: 94,\n    Color.MAGENTA: 95,\n    Color.CYAN: 96,\n  }\n\n  if TARGET == .JAVASCRIPT {\n    def setColor(color Color) {\n      if dynamic.process.stdout.isTTY {\n        write(\"\\x1B[0;\\(color.toEscapeCode)m\")\n      }\n    }\n\n    def width int {\n      return dynamic.process.stdout.columns\n    }\n\n    def height int {\n      return dynamic.process.stdout.rows\n    }\n\n    def print(text string) {\n      write(text + \"\\n\")\n    }\n\n    def flush {\n    }\n\n    def write(text string) {\n      dynamic.process.stdout.write(text)\n    }\n  }\n\n  else if TARGET == .CSHARP {\n    @using(\"System\")\n    def setColor(color Color) {\n      switch color {\n        case .BOLD, .DEFAULT { dynamic.Console.ResetColor() }\n        case .GRAY { dynamic.Console.ForegroundColor = dynamic.ConsoleColor.DarkGray }\n        case .RED { dynamic.Console.ForegroundColor = dynamic.ConsoleColor.Red }\n        case .GREEN { dynamic.Console.ForegroundColor = dynamic.ConsoleColor.Green }\n        case .YELLOW { dynamic.Console.ForegroundColor = dynamic.ConsoleColor.Yellow }\n        case .BLUE { dynamic.Console.ForegroundColor = dynamic.ConsoleColor.Blue }\n        case .MAGENTA { dynamic.Console.ForegroundColor = dynamic.ConsoleColor.Magenta }\n        case .CYAN { dynamic.Console.ForegroundColor = dynamic.ConsoleColor.Cyan }\n      }\n    }\n\n    @using(\"System\")\n    def width int {\n      return dynamic.Console.BufferWidth\n    }\n\n    @using(\"System\")\n    def height int {\n      return dynamic.Console.BufferHeight\n    }\n\n    @using(\"System\")\n    def print(text string) {\n      dynamic.Console.WriteLine(text)\n    }\n\n    def flush {\n    }\n\n    @using(\"System\")\n    def write(text string) {\n      dynamic.Console.Write(text)\n    }\n  }\n\n  else {\n    def setColor(color Color) {\n      _setColor(color.toEscapeCode)\n    }\n\n    @import {\n      def _setColor(escapeCode int)\n      def width int\n      def height int\n      def print(text string)\n      def flush\n      def write(text string)\n    }\n  }\n}\n"
  },
  {
    "path": "src/lib/timestamp.sk",
    "content": "namespace Timestamp {\n  if TARGET == .JAVASCRIPT {\n    def seconds double {\n      return (dynamic.typeof(dynamic.performance) != \"undefined\" && dynamic.performance.now ? dynamic.performance.now() : dynamic.Date.now()) / 1000\n    }\n  }\n\n  else if TARGET == .CSHARP {\n    @using(\"System\")\n    def seconds double {\n      return dynamic.DateTime.Now.Ticks / (dynamic.TimeSpan.TicksPerSecond as double)\n    }\n  }\n\n  else {\n    @import\n    def seconds double\n  }\n}\n"
  },
  {
    "path": "src/lib/unit.sk",
    "content": "namespace Unit {\n  enum Status {\n    FAILURE\n    SUCCESS\n    SKIPPED\n  }\n\n  class Report {\n    def begin(count int) {}\n    def completed(test Test, status Status) {}\n    def end {}\n  }\n\n  class Failure {\n    const expected string\n    const observed string\n  }\n\n  ################################################################################\n\n  class Test {\n    var _name = \"\"\n    var _shouldSkip = false\n    var _failure Failure = null\n\n    def new {\n      _all.append(self)\n    }\n\n    def name string { return _name }\n    def failure Failure { return _failure }\n    def shouldSkip bool { return _shouldSkip }\n\n    def rename(name string) { _name = name }\n    def skip { _shouldSkip = true }\n\n    def before {}\n    def after {}\n    def run\n\n    def expectString(expected string, observed string) {\n      if expected != observed {\n        _failure = Failure.new(expected, observed)\n        throw null\n      }\n    }\n\n    if TARGET == .JAVASCRIPT {\n      def _tryRun {\n        try {\n          run\n        } catch error dynamic {\n          _failure ?= Failure.new(\"\", ((error && error.stack || error) as dynamic) + \"\")\n        }\n      }\n    }\n\n    else if TARGET == .CSHARP {\n      def _tryRun {\n        try {\n          run\n        } catch error dynamic.System.Exception {\n          _failure ?= Failure.new(\"\", error.ToString())\n        }\n      }\n    }\n\n    else {\n      def _tryRun {\n        try {\n          run\n        } catch {\n          _failure ?= Failure.new(\"\", \"(runtime failure)\")\n        }\n      }\n    }\n  }\n\n  namespace Test {\n    def runAll(report Report) {\n      var tests = _all\n\n      _all = []\n      report.begin(tests.count)\n\n      for test in tests {\n        if test.shouldSkip {\n          report.completed(test, .SKIPPED)\n        } else {\n          test.before\n          test._tryRun\n          test.after\n          report.completed(test, test._failure == null ? .SUCCESS : .FAILURE)\n        }\n      }\n\n      report.end\n    }\n\n    var _all List<Test> = []\n  }\n\n  ################################################################################\n\n  class TerminalReport : Report {\n    var _failed List<Test> = []\n    var _wrapWidth = 0\n    var _startTime = 0.0\n    var _completed = 0\n    var _count = 0\n    var _skippedCount = 0\n\n    def skippedCount int {\n      return _skippedCount\n    }\n\n    def failedCount int {\n      return _failed.count\n    }\n\n    over begin(count int) {\n      _wrapWidth = Terminal.width * 3 / 4\n      _startTime = Timestamp.seconds\n      _count = count\n      _completed = 0\n      Terminal.write(\"\\n  \")\n    }\n\n    over completed(test Test, status Status) {\n      _completed++\n      switch status {\n        case .FAILURE {\n          _failed.append(test)\n          Terminal.setColor(.RED)\n          Terminal.write(\"x\")\n        }\n\n        case .SUCCESS {\n          Terminal.setColor(.GREEN)\n          Terminal.write(\".\")\n        }\n\n        case .SKIPPED {\n          _skippedCount++\n          Terminal.setColor(.YELLOW)\n          Terminal.write(\"s\")\n        }\n      }\n\n      if _completed < _count && _wrapWidth != 0 && _completed % _wrapWidth == 0 {\n        Terminal.write(\"\\n  \")\n      }\n\n      Terminal.setColor(.DEFAULT)\n      Terminal.flush\n    }\n\n    over end {\n      Terminal.print(\"\\n\")\n\n      # Print the summary\n      var totalTime = Math.floor((Timestamp.seconds - _startTime) * 10) as int\n      Terminal.setColor(.GREEN)\n      Terminal.write(\"  \\(_count - _failed.count) passing\")\n      Terminal.setColor(.GRAY)\n      Terminal.print(\"  (\\(totalTime / 10).\\(totalTime % 10)s)\")\n      if _failed.count != 0 {\n        Terminal.setColor(.RED)\n        Terminal.print(\"  \\(_failed.count) failing\")\n      }\n      if _skippedCount != 0 {\n        Terminal.setColor(.YELLOW)\n        Terminal.print(\"  \\(_skippedCount) skipped\")\n      }\n      Terminal.setColor(.DEFAULT)\n      Terminal.print(\"\")\n\n      # Print the failed tests\n      var indent = \" \".repeat(_failed.count.toString.count + 5)\n      for i in 0.._failed.count {\n        var test = _failed[i]\n        var text = \"  \\(i + 1))\"\n        var failure = test.failure\n        Terminal.setColor(.BOLD)\n        Terminal.print(text + \" \".repeat(indent.count - text.count) + test.name + \"\\n\")\n        _printDiff(indent,\n          failure.expected == null ? [] : failure.expected.split(\"\\n\"),\n          failure.observed == null ? [] : failure.observed.split(\"\\n\"))\n        Terminal.setColor(.DEFAULT)\n        Terminal.print(\"\")\n      }\n    }\n  }\n\n  namespace TerminalReport {\n    def _printDiff(indent string, expected List<string>, observed List<string>) {\n      var m = expected.count\n      var n = observed.count\n      var matrix List<int> = []\n\n      # Solve for the lowest common subsequence length\n      if true {\n        var ij = 0\n        for i in 0..m {\n          for j in 0..n {\n            matrix.append(expected[i] == observed[j]\n              ? i > 0 && j > 0 ? matrix[ij - n - 1] + 1 : 1\n              : Math.max(i > 0 ? matrix[ij - n] : 0, j > 0 ? matrix[ij - 1] : 0))\n            ij++\n          }\n        }\n      }\n\n      # Extract the diff in reverse\n      var reversed List<string> = []\n      if true {\n        var i = m - 1\n        var j = n - 1\n        while i >= 0 || j >= 0 {\n          var ij = i * n + j\n\n          # Common\n          if i >= 0 && j >= 0 && expected[i] == observed[j] {\n            reversed.append(\" \" + expected[i])\n            i--\n            j--\n          }\n\n          # Removal\n          else if j >= 0 && (i < 0 || (j > 0 ? matrix[ij - 1] : 0) > (i > 0 ? matrix[ij - n] : 0)) {\n            reversed.append(\"-\" + observed[j])\n            j--\n          }\n\n          # Insertion\n          else {\n            assert(i >= 0 && (j < 0 || (j > 0 ? matrix[ij - 1] : 0) <= (i > 0 ? matrix[ij - n] : 0)))\n            reversed.append(\"+\" + expected[i])\n            i--\n          }\n        }\n      }\n\n      # Print out the diff\n      for i in 0..reversed.count {\n        var text = reversed[reversed.count - i - 1]\n        var c = text[0]\n        Terminal.setColor(c == '+' ? .GREEN : c == '-' ? .RED : .GRAY)\n        Terminal.print(indent + text)\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/middle/callgraph.sk",
    "content": "namespace Skew {\n  enum PassKind {\n    CALL_GRAPH\n  }\n\n  class CallGraphPass : Pass {\n    over kind PassKind {\n      return .CALL_GRAPH\n    }\n\n    over run(context PassContext) {\n      context.callGraph = CallGraph.new(context.global)\n    }\n  }\n\n  class CallSite {\n    const callNode Node\n    const enclosingSymbol Symbol\n  }\n\n  class CallInfo {\n    const symbol FunctionSymbol\n    const callSites List<CallSite> = []\n  }\n\n  class CallGraph {\n    const callInfo List<CallInfo> = []\n    const symbolToInfoIndex IntMap<int> = {}\n\n    def new(global ObjectSymbol) {\n      _visitObject(global)\n    }\n\n    def callInfoForSymbol(symbol FunctionSymbol) CallInfo {\n      assert(symbol.id in symbolToInfoIndex)\n      return callInfo[symbolToInfoIndex[symbol.id]]\n    }\n\n    def _visitObject(symbol ObjectSymbol) {\n      for object in symbol.objects {\n        _visitObject(object)\n      }\n\n      for function in symbol.functions {\n        _recordCallSite(function, null, null)\n        _visitNode(function.block, function)\n      }\n\n      for variable in symbol.variables {\n        _visitNode(variable.value, variable)\n      }\n    }\n\n    def _visitNode(node Node, context Symbol) {\n      if node != null {\n        for child = node.firstChild; child != null; child = child.nextSibling {\n          _visitNode(child, context)\n        }\n\n        if node.kind == .CALL && node.symbol != null {\n          assert(node.symbol.kind.isFunction)\n          _recordCallSite(node.symbol.forwarded.asFunctionSymbol, node, context)\n        }\n      }\n    }\n\n    def _recordCallSite(symbol FunctionSymbol, node Node, context Symbol) {\n      var index = symbolToInfoIndex.get(symbol.id, -1)\n      var info = index < 0 ? CallInfo.new(symbol) : callInfo[index]\n      if index < 0 {\n        symbolToInfoIndex[symbol.id] = callInfo.count\n        callInfo.append(info)\n      }\n      if node != null {\n        info.callSites.append(CallSite.new(node, context))\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/middle/compiler.sk",
    "content": "namespace Skew {\n  class CompilerTarget {\n    def name string { return \"\" }\n    def extension string { return \"\" }\n    def stopAfterResolve bool { return true }\n    def requiresIntegerSwitchStatements bool { return false }\n    def supportsListForeach bool { return false }\n    def supportsNestedTypes bool { return false }\n    def needsLambdaLifting bool { return false }\n    def removeSingletonInterfaces bool { return false }\n    def stringEncoding Unicode.Encoding { return .UTF32 }\n    def editOptions(options CompilerOptions) {}\n    def includeSources(sources List<Source>) {}\n    def createEmitter(context PassContext) Emitter { return null }\n  }\n\n  class Define {\n    const name Range\n    const value Range\n  }\n\n  class CompletionContext {\n    const source Source\n    const index int\n    const _completions IntMap<Symbol> = {}\n    var range Range = null\n\n    def completions List<Symbol> {\n      var values = _completions.values\n      values.sort(Symbol.SORT_BY_NAME)\n      return values\n    }\n\n    def addCompletion(symbol Symbol) {\n      _completions[symbol.id] = symbol\n    }\n  }\n\n  class CompilerOptions {\n    var completionContext CompletionContext = null\n    var defines StringMap<Define> = {}\n    var foldAllConstants = false\n    var globalizeAllFunctions = false\n    var inlineAllFunctions = false\n    var isAlwaysInlinePresent = false # This is set by the resolver\n    var jsMangle = false\n    var jsMinify = false\n    var jsSourceMap = false\n    var outputDirectory string = null\n    var outputFile string = null\n    var passes List<Pass> = null\n    var stopAfterResolve = false\n    var target = CompilerTarget.new\n    var verbose = false\n    var warnAboutIgnoredComments = false\n    var warningsAreErrors = false\n\n    def new {\n      passes = [\n        LexingPass.new,\n        ParsingPass.new,\n        MergingPass.new,\n        ResolvingPass.new,\n        LambdaConversionPass.new.onlyRunWhen(=> _continueAfterResolve && target.needsLambdaLifting),\n        InterfaceRemovalPass.new.onlyRunWhen(=> _continueAfterResolve && target.removeSingletonInterfaces && globalizeAllFunctions),\n\n        # The call graph is used as a shortcut so the tree only needs to be scanned once for all call-based optimizations\n        CallGraphPass.new.onlyRunWhen(=> _continueAfterResolve),\n        GlobalizingPass.new.onlyRunWhen(=> _continueAfterResolve),\n        MotionPass.new.onlyRunWhen(=> _continueAfterResolve),\n        RenamingPass.new.onlyRunWhen(=> _continueAfterResolve),\n        FoldingPass.new.onlyRunWhen(=> _continueAfterResolve && foldAllConstants),\n        InliningPass.new.onlyRunWhen(=> _continueAfterResolve && (inlineAllFunctions || isAlwaysInlinePresent)),\n        FoldingPass.new.onlyRunWhen(=> _continueAfterResolve && (inlineAllFunctions || isAlwaysInlinePresent) && foldAllConstants),\n        EmittingPass.new.onlyRunWhen(=> !stopAfterResolve),\n      ]\n    }\n\n    def define(name string, value string) {\n      var range = Source.new(\"<internal>\", \"--define:\\(name)=\\(value)\").entireRange\n      defines[name] = Define.new(range.slice(9, 9 + name.count), range.fromEnd(value.count))\n    }\n\n    def _continueAfterResolve bool {\n      return !stopAfterResolve && !target.stopAfterResolve\n    }\n\n    def createTargetFromExtension bool {\n      if outputFile != null {\n        var dot = outputFile.lastIndexOf(\".\")\n        if dot != -1 {\n          switch outputFile.slice(dot + 1) {\n            case \"cpp\", \"cxx\", \"cc\" { target = CPlusPlusTarget.new }\n            case \"cs\" { target = CSharpTarget.new }\n            case \"ts\" { target = TypeScriptTarget.new }\n            case \"js\" { target = JavaScriptTarget.new }\n            default { return false }\n          }\n          return true\n        }\n      }\n      return false\n    }\n  }\n\n  class Timer {\n    var _isStarted = false\n    var _startTime = 0.0\n    var _totalSeconds = 0.0\n\n    def start {\n      assert(!_isStarted)\n      _isStarted = true\n      _startTime = Timestamp.seconds\n    }\n\n    def stop {\n      assert(_isStarted)\n      _isStarted = false\n      _totalSeconds += Timestamp.seconds - _startTime\n    }\n\n    def elapsedSeconds double {\n      return _totalSeconds\n    }\n\n    def elapsedMilliseconds string {\n      return formatNumber(_totalSeconds * 1000) + \"ms\"\n    }\n\n    def isZero bool {\n      return _totalSeconds == 0\n    }\n  }\n\n  enum PassKind {\n    # These values are defined near each pass\n  }\n\n  class PassContext {\n    var log Log\n    var options CompilerOptions\n    var inputs List<Source>\n    var cache = TypeCache.new\n    var global = ObjectSymbol.new(.OBJECT_GLOBAL, \"<global>\")\n    var callGraph CallGraph = null\n    var tokens List<List<Token>> = []\n    var outputs List<Source> = []\n    var isResolvePassComplete = false\n  }\n\n  class Pass {\n    var _shouldRun fn() bool = null\n\n    def kind PassKind\n    def run(context PassContext)\n\n    def shouldRun bool {\n      return _shouldRun != null ? _shouldRun() : true\n    }\n\n    def onlyRunWhen(callback fn() bool) Pass {\n      _shouldRun = callback\n      return self\n    }\n  }\n\n  class PassTimer {\n    var kind PassKind\n    var timer = Timer.new\n  }\n\n  enum StatisticsKind {\n    SHORT\n    LONG\n  }\n\n  class CompilerResult {\n    var cache TypeCache\n    var global ObjectSymbol\n    var outputs List<Source>\n    var passTimers List<PassTimer>\n    var totalTimer Timer\n\n    def statistics(inputs List<Source>, kind StatisticsKind) string {\n      var builder = StringBuilder.new\n      var totalTime = totalTimer.elapsedSeconds\n      var sourceStatistics = (name string, sources List<Source>) => {\n        var totalBytes = 0\n        var totalLines = 0\n        for source in sources {\n          totalBytes += source.contents.count\n          if kind == .LONG {\n            totalLines += source.lineCount\n          }\n        }\n        builder.append(\"\\(name)\\(PrettyPrint.plural(sources.count)): \")\n        builder.append(sources.count == 1 ? sources.first.name : \"\\(sources.count) files\")\n        builder.append(\" (\" + bytesToString(totalBytes))\n        builder.append(\", \" + bytesToString(Math.round(totalBytes / totalTime) as int) + \"/s\")\n        if kind == .LONG {\n          builder.append(\", \" + PrettyPrint.plural(totalLines, \"line\"))\n          builder.append(\", \" + PrettyPrint.plural(Math.round(totalLines / totalTime) as int, \"line\") + \"/s\")\n        }\n        builder.append(\")\\n\")\n      }\n\n      # Sources\n      sourceStatistics(\"input\", inputs)\n      sourceStatistics(\"output\", outputs)\n\n      # Compilation time\n      builder.append(\"time: \\(totalTimer.elapsedMilliseconds)\")\n      if kind == .LONG {\n        for passTimer in passTimers {\n          builder.append(\"\\n  \\(passTimer.kind): \\(passTimer.timer.elapsedMilliseconds)\")\n        }\n      }\n\n      return builder.toString\n    }\n  }\n\n  def compile(log Log, options CompilerOptions, inputs List<Source>) CompilerResult {\n    inputs = inputs.clone\n    options.target.includeSources(inputs)\n    options.target.editOptions(options)\n    inputs.prepend(Source.new(\"<unicode>\", UNICODE_LIBRARY))\n    inputs.prepend(Source.new(\"<native>\", NATIVE_LIBRARY))\n\n    var context = PassContext.new(log, options, inputs)\n    var passTimers List<PassTimer> = []\n    var totalTimer = Timer.new\n    totalTimer.start\n\n    # Run all passes, stop compilation if there are errors after resolving (wait until then to make IDE mode better)\n    for pass in options.passes {\n      if context.isResolvePassComplete && log.hasErrors {\n        break\n      }\n      if pass.shouldRun {\n        var passTimer = PassTimer.new(pass.kind)\n        passTimers.append(passTimer)\n        passTimer.timer.start\n        pass.run(context)\n        passTimer.timer.stop\n        context.verify\n      }\n    }\n\n    totalTimer.stop\n    return CompilerResult.new(context.cache, context.global, context.outputs, passTimers, totalTimer)\n  }\n\n  class PassContext {\n    @skip if RELEASE\n    def verify {\n      _verifyHierarchy(global)\n    }\n\n    def _verifySymbol(symbol Symbol) {\n      if !isResolvePassComplete {\n        return\n      }\n\n      # Special-case nested guards that aren't initialized when the outer guard has errors\n      if symbol.state != .INITIALIZED {\n        assert(symbol.kind.isObject)\n        assert(symbol.isGuardConditional)\n        assert(log.errorCount > 0)\n        return\n      }\n\n      assert(symbol.state == .INITIALIZED)\n      assert(symbol.resolvedType != null)\n\n      if symbol.kind.isObject || symbol.kind.isFunction || symbol.kind.isParameter {\n        if symbol.resolvedType == .DYNAMIC {\n          assert(log.errorCount > 0) # Ignore errors due to cyclic declarations\n        } else {\n          assert(symbol.resolvedType.kind == .SYMBOL)\n          assert(symbol.resolvedType.symbol == symbol)\n        }\n      }\n\n      if symbol.kind.isFunction && symbol.resolvedType.kind == .SYMBOL {\n        var function = symbol.asFunctionSymbol\n        assert(symbol.resolvedType.returnType == function.returnType?.resolvedType)\n        assert(symbol.resolvedType.argumentTypes.count == function.arguments.count)\n        for i in 0..function.arguments.count {\n          assert(symbol.resolvedType.argumentTypes[i] == function.arguments[i].resolvedType)\n        }\n      }\n\n      if symbol.kind.isVariable {\n        assert(symbol.resolvedType == symbol.asVariableSymbol.type.resolvedType)\n      }\n    }\n\n    def _verifyHierarchy(symbol ObjectSymbol) {\n      _verifySymbol(symbol)\n\n      for object in symbol.objects {\n        assert(object.parent == symbol)\n        _verifyHierarchy(object)\n\n        if object.extends != null {\n          _verifyHierarchy(object.extends, null)\n        }\n\n        if object.implements != null {\n          for node in object.implements {\n            _verifyHierarchy(node, null)\n          }\n        }\n      }\n\n      for function in symbol.functions {\n        assert(function.parent == symbol)\n        _verifySymbol(function)\n\n        if function.block != null {\n          _verifyHierarchy(function.block, null)\n        }\n      }\n\n      for variable in symbol.variables {\n        assert(variable.parent == symbol)\n        _verifySymbol(variable)\n\n        assert(variable.state != .INITIALIZED || variable.type != null)\n        if variable.type != null {\n          _verifyHierarchy(variable.type, null)\n        }\n\n        if variable.value != null {\n          _verifyHierarchy(variable.value, null)\n        }\n      }\n\n      if symbol.guards != null {\n        for guard in symbol.guards {\n          _verifyHierarchy(guard, symbol)\n        }\n      }\n    }\n\n    def _verifyHierarchy(node Node, parent Node) {\n      assert(node.parent == parent)\n\n      # All expressions must have a type after the type resolution pass\n      if isResolvePassComplete && node.kind.isExpression {\n        assert(node.resolvedType != null)\n      }\n\n      if node.kind == .VARIABLE {\n        assert(node.symbol != null)\n        assert(node.symbol.kind == .VARIABLE_LOCAL)\n\n        var variable = node.symbol.asVariableSymbol\n        assert(variable.value == node.variableValue)\n        _verifySymbol(variable)\n\n        assert(variable.state != .INITIALIZED || variable.type != null)\n        if variable.type != null {\n          _verifyHierarchy(variable.type, null)\n        }\n      }\n\n      else if node.kind == .LAMBDA {\n        assert(node.symbol != null)\n        assert(node.symbol.kind == .FUNCTION_LOCAL)\n        assert(node.symbol.asFunctionSymbol.block == node.lambdaBlock)\n        _verifySymbol(node.symbol)\n      }\n\n      for child = node.firstChild; child != null; child = child.nextSibling {\n        _verifyHierarchy(child, node)\n      }\n    }\n\n    def _verifyHierarchy(guard Guard, parent ObjectSymbol) {\n      assert(guard.parent == parent)\n      assert(guard.contents.parent == parent)\n\n      if guard.test != null {\n        _verifyHierarchy(guard.test, null)\n      }\n\n      _verifyHierarchy(guard.contents)\n\n      if guard.elseGuard != null {\n        _verifyHierarchy(guard.elseGuard, parent)\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/middle/controlflow.sk",
    "content": "namespace Skew {\n  # This does a simple control flow analysis without constructing a full\n  # control flow graph. The result of this analysis is setting the flag\n  # HAS_CONTROL_FLOW_AT_END on all blocks where control flow reaches the end.\n  #\n  # It makes a few assumptions around exceptions to make life easier. Normal\n  # code without throw statements is assumed not to throw. For example, all\n  # property accesses are assumed to succeed and not throw null pointer errors.\n  # This is mostly consistent with how C++ operates for better or worse, and\n  # is also consistent with how people read code. It also assumes flow always\n  # can enter every catch block. Otherwise, why is it there?\n  class ControlFlowAnalyzer {\n    var _isLoopBreakTarget List<bool> = []\n    var _isControlFlowLive List<bool> = []\n\n    def pushBlock(node Node) {\n      var parent = node.parent\n\n      # Push control flow\n      _isControlFlowLive.append(_isControlFlowLive.isEmpty || _isControlFlowLive.last)\n\n      # Push loop info\n      if parent != null && parent.kind.isLoop {\n        _isLoopBreakTarget.append(false)\n      }\n    }\n\n    def popBlock(node Node) {\n      var parent = node.parent\n\n      # Pop control flow\n      var isLive = _isControlFlowLive.takeLast\n      if isLive {\n        node.flags |= .HAS_CONTROL_FLOW_AT_END\n      }\n\n      # Pop loop info\n      if parent != null && parent.kind.isLoop && !_isLoopBreakTarget.takeLast && (\n          parent.kind == .WHILE && parent.whileTest.isTrue ||\n          parent.kind == .FOR && parent.forTest.isTrue) {\n        _isControlFlowLive.last = false\n      }\n    }\n\n    def visitStatementInPostOrder(node Node) {\n      if !_isControlFlowLive.last {\n        return\n      }\n\n      switch node.kind {\n        case .BREAK {\n          if !_isLoopBreakTarget.isEmpty {\n            _isLoopBreakTarget.last = true\n          }\n          _isControlFlowLive.last = false\n        }\n\n        case .RETURN, .THROW, .CONTINUE {\n          _isControlFlowLive.last = false\n        }\n\n        case .IF {\n          var test = node.ifTest\n          var trueBlock = node.ifTrue\n          var falseBlock = node.ifFalse\n\n          if test.isTrue {\n            if !trueBlock.hasControlFlowAtEnd {\n              _isControlFlowLive.last = false\n            }\n          }\n\n          else if test.isFalse && falseBlock != null {\n            if !falseBlock.hasControlFlowAtEnd {\n              _isControlFlowLive.last = false\n            }\n          }\n\n          else if trueBlock != null && falseBlock != null {\n            if !trueBlock.hasControlFlowAtEnd && !falseBlock.hasControlFlowAtEnd {\n              _isControlFlowLive.last = false\n            }\n          }\n        }\n\n        case .SWITCH {\n          var child = node.switchValue.nextSibling\n          var foundDefaultCase = false\n\n          while child != null && !child.caseBlock.hasControlFlowAtEnd {\n            if child.hasOneChild {\n              foundDefaultCase = true\n            }\n            child = child.nextSibling\n          }\n\n          if child == null && foundDefaultCase {\n            _isControlFlowLive.last = false\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/middle/folding.sk",
    "content": "namespace Skew {\n  enum PassKind {\n    FOLDING\n  }\n\n  class FoldingPass : Pass {\n    over kind PassKind {\n      return .FOLDING\n    }\n\n    over run(context PassContext) {\n      Folding.ConstantFolder.new(context.cache, context.options, null).visitObject(context.global)\n    }\n  }\n}\n\nnamespace Skew.Folding {\n  class ConstantFolder {\n    const _cache TypeCache\n    const _options CompilerOptions\n    const _prepareSymbol fn(Symbol)\n    const _constantCache IntMap<Content> = {}\n\n    def visitObject(symbol ObjectSymbol) {\n      for object in symbol.objects {\n        visitObject(object)\n      }\n\n      for function in symbol.functions {\n        if function.block != null {\n          foldConstants(function.block)\n        }\n      }\n\n      for variable in symbol.variables {\n        if variable.value != null {\n          foldConstants(variable.value)\n        }\n      }\n    }\n\n    # Use this instead of node.become(Node.createConstant(content)) to avoid more GC\n    def _flatten(node Node, content Content) {\n      node.removeChildren\n      node.kind = .CONSTANT\n      node.content = content\n      node.symbol = null\n    }\n\n    # Use this instead of node.become(Node.createBool(value)) to avoid more GC\n    def _flattenBool(node Node, value bool) {\n      assert(_cache.isEquivalentToBool(node.resolvedType) || node.resolvedType == .DYNAMIC)\n      _flatten(node, BoolContent.new(value))\n    }\n\n    # Use this instead of node.become(Node.createInt(value)) to avoid more GC\n    def _flattenInt(node Node, value int) {\n      assert(_cache.isEquivalentToInt(node.resolvedType) || node.resolvedType == .DYNAMIC)\n      _flatten(node, IntContent.new(value))\n    }\n\n    # Use this instead of node.become(Node.createDouble(value)) to avoid more GC\n    def _flattenDouble(node Node, value double) {\n      assert(_cache.isEquivalentToDouble(node.resolvedType) || node.resolvedType == .DYNAMIC)\n      _flatten(node, DoubleContent.new(value))\n    }\n\n    # Use this instead of node.become(Node.createString(value)) to avoid more GC\n    def _flattenString(node Node, value string) {\n      assert(_cache.isEquivalentToString(node.resolvedType) || node.resolvedType == .DYNAMIC)\n      _flatten(node, StringContent.new(value))\n    }\n\n    def foldConstants(node Node) {\n      var kind = node.kind\n\n      # Transform \"a + (b + c)\" => \"(a + b) + c\" before operands are folded\n      if kind == .ADD && node.resolvedType == _cache.stringType && node.binaryLeft.resolvedType == _cache.stringType && node.binaryRight.resolvedType == _cache.stringType {\n        _rotateStringConcatenation(node)\n      }\n\n      # Fold operands before folding this node\n      for child = node.firstChild; child != null; child = child.nextSibling {\n        foldConstants(child)\n      }\n\n      # Separating the case bodies into separate functions makes the JavaScript JIT go faster\n      switch kind {\n        case .BLOCK { _foldBlock(node) }\n        case .CALL { _foldCall(node) }\n        case .CAST { _foldCast(node) }\n        case .DOT { _foldDot(node) }\n        case .HOOK { _foldHook(node) }\n        case .NAME { _foldName(node) }\n        case .COMPLEMENT, .NEGATIVE, .NOT, .POSITIVE { _foldUnary(node) }\n        default {\n          if kind.isBinary { _foldBinary(node) }\n        }\n      }\n    }\n\n    def _rotateStringConcatenation(node Node) {\n      var left = node.binaryLeft\n      var right = node.binaryRight\n      assert(node.kind == .ADD)\n      assert(left.resolvedType == _cache.stringType || left.resolvedType == .DYNAMIC)\n      assert(right.resolvedType == _cache.stringType || right.resolvedType == .DYNAMIC)\n\n      # \"a + (b + c)\" => \"(a + b) + c\"\n      if right.kind == .ADD {\n        assert(right.binaryLeft.resolvedType == _cache.stringType || right.binaryLeft.resolvedType == .DYNAMIC)\n        assert(right.binaryRight.resolvedType == _cache.stringType || right.binaryRight.resolvedType == .DYNAMIC)\n        node.rotateBinaryRightToLeft\n      }\n    }\n\n    def _foldStringConcatenation(node Node) {\n      var left = node.binaryLeft\n      var right = node.binaryRight\n      assert(left.resolvedType == _cache.stringType || left.resolvedType == .DYNAMIC)\n      assert(right.resolvedType == _cache.stringType || right.resolvedType == .DYNAMIC)\n\n      if right.isString {\n        # \"a\" + \"b\" => \"ab\"\n        if left.isString {\n          _flattenString(node, left.asString + right.asString)\n        }\n\n        else if left.kind == .ADD {\n          var leftLeft = left.binaryLeft\n          var leftRight = left.binaryRight\n          assert(leftLeft.resolvedType == _cache.stringType || leftLeft.resolvedType == .DYNAMIC)\n          assert(leftRight.resolvedType == _cache.stringType || leftRight.resolvedType == .DYNAMIC)\n\n          # (a + \"b\") + \"c\" => a + \"bc\"\n          if leftRight.isString {\n            _flattenString(leftRight, leftRight.asString + right.asString)\n            node.become(left.remove)\n          }\n        }\n      }\n    }\n\n    def _foldTry(node Node) int {\n      var tryBlock = node.tryBlock\n      # var finallyBlock = node.finallyBlock\n\n      # A try block without any statements cannot possibly throw\n      if !tryBlock.hasChildren {\n        node.remove\n        return -1\n      }\n\n      return 0\n    }\n\n    def _foldIf(node Node) {\n      var test = node.ifTest\n      var trueBlock = node.ifTrue\n      var falseBlock = node.ifFalse\n\n      # No reason to keep an empty \"else\" block\n      if falseBlock != null && !falseBlock.hasChildren {\n        falseBlock.remove\n        falseBlock = null\n      }\n\n      # Always true if statement\n      if test.isTrue {\n        # Inline the contents of the true block\n        node.replaceWithChildrenFrom(trueBlock)\n      }\n\n      # Always false if statement\n      else if test.isFalse {\n        # Remove entirely\n        if falseBlock == null {\n          node.remove\n        }\n\n        # Inline the contents of the false block\n        else {\n          node.replaceWithChildrenFrom(falseBlock)\n        }\n      }\n\n      # Remove if statements with empty true blocks\n      else if !trueBlock.hasChildren {\n        # \"if (a) {} else b;\" => \"if (!a) b;\"\n        if falseBlock != null && falseBlock.hasChildren {\n          test.invertBooleanCondition(_cache)\n          trueBlock.remove\n        }\n\n        # \"if (a) {}\" => \"\"\n        else if test.hasNoSideEffects {\n          node.remove\n        }\n\n        # \"if (a) {}\" => \"a;\"\n        else {\n          node.become(Node.createExpression(test.remove))\n        }\n      }\n    }\n\n    def _foldSwitch(node Node) {\n      var value = node.switchValue\n      var defaultCase Node = null\n\n      # Check for a default case\n      for child = value.nextSibling; child != null; child = child.nextSibling {\n        if child.hasOneChild {\n          defaultCase = child\n          break\n        }\n      }\n\n      # Remove the default case if it's empty\n      if defaultCase != null && !defaultCase.caseBlock.hasChildren {\n        defaultCase.remove\n        defaultCase = null\n      }\n\n      # Check for a constant value and inline the corresponding case block\n      if value.kind == .CONSTANT {\n        var hasNonConstant = false\n\n        # Search all case blocks for a match\n        for child = value.nextSibling, nextChild Node = null; child != null; child = nextChild {\n          nextChild = child.nextSibling\n          var block = child.caseBlock\n\n          for caseValue = child.firstChild, nextCase Node = null; caseValue != block; caseValue = nextCase {\n            nextCase = caseValue.nextSibling\n\n            # If there's a non-constant value, we can't tell if it's taken or not\n            if caseValue.kind != .CONSTANT {\n              hasNonConstant = true\n            }\n\n            # Remove cases that definitely don't apply\n            else if !value.content.equals(caseValue.content) {\n              caseValue.remove\n            }\n\n            # Only inline this case if all previous values have been constants,\n            # otherwise we can't be sure that none of those would have matched\n            else if !hasNonConstant {\n              node.replaceWithChildrenFrom(block)\n              return\n            }\n          }\n\n          # Remove the case entirely if all values were trimmed\n          if child.hasOneChild && child != defaultCase {\n            child.remove\n          }\n        }\n\n        # Inline the default case if it's present and it can be proven to be taken\n        if !hasNonConstant {\n          if defaultCase != null {\n            node.replaceWithChildrenFrom(defaultCase.caseBlock)\n          } else {\n            node.remove\n          }\n          return\n        }\n      }\n\n      # If the default case is missing, all other empty cases can be removed too\n      if defaultCase == null {\n        for child = node.lastChild, previous Node = null; child != value; child = previous {\n          previous = child.previousSibling\n          if !child.caseBlock.hasChildren {\n            child.remove\n          }\n        }\n      }\n\n      # Replace \"switch (foo) {}\" with \"foo;\"\n      if node.hasOneChild {\n        node.become(Node.createExpression(value.remove).withRange(node.range))\n      }\n    }\n\n    def _foldVariables(node Node) {\n      # Remove symbols entirely that are being inlined everywhere\n      for child = node.firstChild, next Node = null; child != null; child = next {\n        assert(child.kind == .VARIABLE)\n        next = child.nextSibling\n        var symbol = child.symbol.asVariableSymbol\n        if symbol.isConst && constantForSymbol(symbol) != null {\n          child.remove\n        }\n      }\n\n      # Empty variable statements are not allowed\n      if !node.hasChildren {\n        node.remove\n      }\n    }\n\n    def _foldBlock(node Node) {\n      for child = node.firstChild, next Node = null; child != null; child = next {\n        next = child.nextSibling\n        var kind = child.kind\n\n        # Remove everything after a jump\n        if kind.isJump {\n          while child.nextSibling != null {\n            child.nextSibling.remove\n          }\n          break\n        }\n\n        # Remove constants and \"while false { ... }\" entirely\n        if kind == .EXPRESSION && child.expressionValue.hasNoSideEffects || kind == .WHILE && child.whileTest.isFalse {\n          child.remove\n        }\n\n        # Remove dead assignments\n        else if kind == .EXPRESSION && child.expressionValue.kind == .ASSIGN {\n          _foldAssignment(child)\n        }\n\n        else if kind == .VARIABLES {\n          _foldVariables(child)\n        }\n\n        # Remove unused try statements since they can cause deoptimizations\n        else if kind == .TRY {\n          _foldTry(child)\n        }\n\n        # Statically evaluate if statements where possible\n        else if kind == .IF {\n          _foldIf(child)\n        }\n\n        # Fold switch statements\n        else if kind == .SWITCH {\n          _foldSwitch(child)\n        }\n      }\n    }\n\n    # \"a = 0; b = 0; a = 1;\" => \"b = 0; a = 1;\"\n    def _foldAssignment(node Node) {\n      assert(node.kind == .EXPRESSION && node.expressionValue.kind == .ASSIGN)\n      var value = node.expressionValue\n      var left = value.binaryLeft\n      var right = value.binaryRight\n\n      # Only do this for simple variable assignments\n      var dotVariable = left.kind == .DOT && _isVariableReference(left.dotTarget) ? left.dotTarget.symbol : null\n      var variable = _isVariableReference(left) || dotVariable != null ? left.symbol : null\n      if variable == null {\n        return\n      }\n\n      # Make sure the assigned value doesn't need the previous value. We bail\n      # on expressions with side effects like function calls and on expressions\n      # that reference the variable.\n      if !right.hasNoSideEffects || _hasNestedReference(right, variable) {\n        return\n      }\n\n      # Scan backward over previous statements\n      var previous = node.previousSibling\n      while previous != null {\n        # Only pattern-match expressions\n        if previous.kind == .EXPRESSION {\n          var previousValue = previous.expressionValue\n\n          # Remove duplicate assignments\n          if previousValue.kind == .ASSIGN {\n            var previousLeft = previousValue.binaryLeft\n            var previousRight = previousValue.binaryRight\n            var previousDotVariable = previousLeft.kind == .DOT && _isVariableReference(previousLeft.dotTarget) ? previousLeft.dotTarget.symbol : null\n            var previousVariable = _isVariableReference(previousLeft) || previousDotVariable != null && previousDotVariable == dotVariable ? previousLeft.symbol : null\n\n            # Check for assignment to the same variable and remove the assignment\n            # if it's a match. Make sure to keep the assigned value around if it\n            # has side effects.\n            if previousVariable == variable {\n              if previousRight.hasNoSideEffects {\n                previous.remove\n              } else {\n                previousValue.replaceWith(previousRight.remove)\n              }\n              break\n            }\n\n            # Stop if we can't determine that this statement doesn't involve\n            # this variable's value. If it does involve this variable's value,\n            # then it isn't safe to remove duplicate assignments past this\n            # statement.\n            if !previousRight.hasNoSideEffects || _hasNestedReference(previousRight, variable) {\n              break\n            }\n          }\n\n          # Also stop here if we can't determine that this statement doesn't\n          # involve this variable's value\n          else if !previousValue.hasNoSideEffects {\n            break\n          }\n        }\n\n        # Also stop here if we can't determine that this statement doesn't\n        # involve this variable's value\n        else {\n          break\n        }\n\n        previous = previous.previousSibling\n      }\n    }\n\n    def _foldDot(node Node) {\n      var symbol = node.symbol\n\n      # Only replace this with a constant if the target has no side effects.\n      # This catches constants declared on imported types.\n      if _shouldFoldSymbol(symbol) && !node.isAssignTarget && (node.dotTarget == null || node.dotTarget.hasNoSideEffects) {\n        var content = constantForSymbol(symbol.asVariableSymbol)\n        if content != null {\n          _flatten(node, content)\n        }\n      }\n    }\n\n    def _foldName(node Node) {\n      var symbol = node.symbol\n\n      # Don't fold loop variables since they aren't actually constant across loop iterations\n      if _shouldFoldSymbol(symbol) && !node.isAssignTarget && !symbol.isLoopVariable {\n        var content = constantForSymbol(symbol.asVariableSymbol)\n        if content != null {\n          _flatten(node, content)\n        }\n      }\n    }\n\n    def _foldCall(node Node) {\n      var value = node.callValue\n      var symbol = value.symbol\n\n      # Fold instance function calls\n      if value.kind == .DOT {\n        var target = value.dotTarget\n\n        # Folding of double.toString can't be done in a platform-independent\n        # manner. The obvious cases are NaN and infinity, but even fractions\n        # are emitted differently on different platforms. Instead of having\n        # constant folding change how the code behaves, just don't fold double\n        # toString calls.\n        #\n        # \"bool.toString\"\n        # \"int.toString\"\n        #\n        if target != null && target.kind == .CONSTANT {\n          if _isKnownCall(symbol, _cache.boolToStringSymbol) { _flattenString(node, target.asBool.toString) }\n          else if _isKnownCall(symbol, _cache.intToStringSymbol) { _flattenString(node, target.asInt.toString) }\n        }\n      }\n\n      # Fold global function calls\n      else if value.kind == .NAME {\n        # \"\\\"abc\\\".count\" => \"3\"\n        if _isKnownCall(symbol, _cache.stringCountSymbol) && node.lastChild.isString {\n          _flattenInt(node, Unicode.codeUnitCountForCodePoints(node.lastChild.asString.codePoints, _options.target.stringEncoding))\n        }\n\n        # \"3 ** 2\" => \"9\"\n        else if _isKnownCall(symbol, _cache.intPowerSymbol) && node.lastChild.isInt && value.nextSibling.isInt {\n          _flattenInt(node, value.nextSibling.asInt ** node.lastChild.asInt)\n        }\n\n        # \"0.0625 ** 0.25\" => \"0.5\"\n        # \"Math.pow(0.0625, 0.25)\" => \"0.5\"\n        else if (_isKnownCall(symbol, _cache.doublePowerSymbol) || _isKnownCall(symbol, _cache.mathPowSymbol)) && node.lastChild.isDouble && value.nextSibling.isDouble {\n          _flattenDouble(node, value.nextSibling.asDouble ** node.lastChild.asDouble)\n        }\n\n        # \"string.fromCodePoint(100)\" => \"\\\"d\\\"\"\n        # \"string.fromCodeUnit(100)\" => \"\\\"d\\\"\"\n        else if (_isKnownCall(symbol, _cache.stringFromCodePointSymbol) || _isKnownCall(symbol, _cache.stringFromCodeUnitSymbol)) && node.lastChild.isInt {\n          _flattenString(node, string.fromCodePoint(node.lastChild.asInt)) # \"fromCodePoint\" is a superset of \"fromCodeUnit\"\n        }\n\n        # \"string.fromCodePoints([97, 98, 99])\" => \"\\\"abc\\\"\"\n        # \"string.fromCodeUnits([97, 98, 99])\" => \"\\\"abc\\\"\"\n        else if (_isKnownCall(symbol, _cache.stringFromCodePointsSymbol) || _isKnownCall(symbol, _cache.stringFromCodeUnitsSymbol)) && node.lastChild.kind == .INITIALIZER_LIST {\n          var codePoints List<int> = []\n          for child = node.lastChild.firstChild; child != null; child = child.nextSibling {\n            if !child.isInt {\n              return\n            }\n            codePoints.append(child.asInt)\n          }\n          _flattenString(node, string.fromCodePoints(codePoints)) # \"fromCodePoints\" is a superset of \"fromCodeUnits\"\n        }\n      }\n    }\n\n    def _foldCast(node Node) {\n      var type = node.castType.resolvedType\n      var value = node.castValue\n\n      if value.kind == .CONSTANT {\n        var content = value.content\n        var kind = content.kind\n\n        # Cast \"bool\" values\n        if kind == .BOOL {\n          if _cache.isEquivalentToBool(type) { _flattenBool(node, value.asBool) }\n          else if _cache.isEquivalentToInt(type) { _flattenInt(node, value.asBool as int) }\n          else if _cache.isEquivalentToDouble(type) { _flattenDouble(node, value.asBool as double) }\n        }\n\n        # Cast \"int\" values\n        else if kind == .INT {\n          if _cache.isEquivalentToBool(type) { _flattenBool(node, value.asInt as bool) }\n          else if _cache.isEquivalentToInt(type) { _flattenInt(node, value.asInt) }\n          else if _cache.isEquivalentToDouble(type) { _flattenDouble(node, value.asInt) }\n        }\n\n        # Cast \"double\" values\n        else if kind == .DOUBLE {\n          if _cache.isEquivalentToBool(type) { _flattenBool(node, value.asDouble as bool) }\n          else if _cache.isEquivalentToInt(type) { _flattenInt(node, value.asDouble as int) }\n          else if _cache.isEquivalentToDouble(type) { _flattenDouble(node, value.asDouble) }\n        }\n      }\n    }\n\n    def _foldUnary(node Node) {\n      var value = node.unaryValue\n      var kind = node.kind\n\n      if value.kind == .CONSTANT {\n        var content = value.content\n        var contentKind = content.kind\n\n        # Fold \"bool\" values\n        if contentKind == .BOOL {\n          if kind == .NOT { _flattenBool(node, !value.asBool) }\n        }\n\n        # Fold \"int\" values\n        else if contentKind == .INT {\n          if kind == .POSITIVE { _flattenInt(node, +value.asInt) }\n          else if kind == .NEGATIVE { _flattenInt(node, -value.asInt) }\n          else if kind == .COMPLEMENT { _flattenInt(node, ~value.asInt) }\n        }\n\n        # Fold \"float\" or \"double\" values\n        else if contentKind == .DOUBLE {\n          if kind == .POSITIVE { _flattenDouble(node, +value.asDouble) }\n          else if kind == .NEGATIVE { _flattenDouble(node, -value.asDouble) }\n        }\n      }\n\n      # Partial evaluation (\"!!x\" isn't necessarily \"x\" if we don't know the type)\n      else if kind == .NOT && value.resolvedType != .DYNAMIC {\n        switch value.kind {\n          case .NOT, .EQUAL, .NOT_EQUAL, .LOGICAL_OR, .LOGICAL_AND, .LESS_THAN, .GREATER_THAN, .LESS_THAN_OR_EQUAL, .GREATER_THAN_OR_EQUAL {\n            value.invertBooleanCondition(_cache)\n            node.become(value.remove)\n          }\n        }\n      }\n    }\n\n    def _foldConstantIntegerAddOrSubtract(node Node, variable Node, constant Node, delta int) {\n      var isAdd = node.kind == .ADD\n      var needsContentUpdate = delta != 0\n      var isRightConstant = constant == node.binaryRight\n      var shouldNegateConstant = !isAdd && isRightConstant\n      var value = constant.asInt\n\n      # Make this an add for simplicity\n      if shouldNegateConstant {\n        value = -value\n      }\n\n      # Include the delta from the parent node if present\n      value += delta\n\n      # 0 + a => a\n      # 0 - a => -a\n      # a + 0 => a\n      # a - 0 => a\n      if value == 0 {\n        node.become(isAdd || isRightConstant ? variable.remove : Node.createUnary(.NEGATIVE, variable.remove).withType(node.resolvedType))\n        return\n      }\n\n      # Check for nested addition or subtraction\n      if variable.kind == .ADD || variable.kind == .SUBTRACT {\n        var left = variable.binaryLeft\n        var right = variable.binaryRight\n        assert(left.resolvedType == _cache.intType || left.resolvedType == .DYNAMIC)\n        assert(right.resolvedType == _cache.intType || right.resolvedType == .DYNAMIC)\n\n        # (a + 1) + 2 => a + 3\n        var isLeftConstant = left.isInt\n        if isLeftConstant || right.isInt {\n          _foldConstantIntegerAddOrSubtract(variable, isLeftConstant ? right : left, isLeftConstant ? left : right, value)\n          node.become(variable.remove)\n          return\n        }\n      }\n\n      # Adjust the value so it has the correct sign\n      if shouldNegateConstant {\n        value = -value\n      }\n\n      # The negative sign can often be removed by code transformation\n      if value < 0 {\n        # a + -1 => a - 1\n        # a - -1 => a + 1\n        if isRightConstant {\n          node.kind = isAdd ? .SUBTRACT : .ADD\n          value = -value\n          needsContentUpdate = true\n        }\n\n        # -1 + a => a - 1\n        else if isAdd {\n          node.kind = .SUBTRACT\n          value = -value\n          variable.swapWith(constant)\n          needsContentUpdate = true\n        }\n      }\n\n      # Avoid extra allocations\n      if needsContentUpdate {\n        constant.content = IntContent.new(value)\n      }\n\n      # Also handle unary negation on \"variable\"\n      _foldAddOrSubtract(node)\n    }\n\n    def _foldAddOrSubtract(node Node) {\n      var isAdd = node.kind == .ADD\n      var left = node.binaryLeft\n      var right = node.binaryRight\n\n      # -a + b => b - a\n      if left.kind == .NEGATIVE && isAdd {\n        left.become(left.unaryValue.remove)\n        left.swapWith(right)\n        node.kind = .SUBTRACT\n      }\n\n      # a + -b => a - b\n      # a - -b => a + b\n      else if right.kind == .NEGATIVE {\n        right.become(right.unaryValue.remove)\n        node.kind = isAdd ? .SUBTRACT : .ADD\n      }\n\n      # 0 + a => a\n      # 0 - a => -a\n      else if left.isZero {\n        node.become(isAdd ? right.remove : Node.createUnary(.NEGATIVE, right.remove).withType(node.resolvedType))\n      }\n\n      # a + 0 => a\n      # a - 0 => a\n      else if right.isZero {\n        node.become(left.remove)\n      }\n    }\n\n    def _foldConstantIntegerMultiply(node Node, variable Node, constant Node) {\n      assert(constant.isInt)\n\n      # Apply identities\n      var variableIsInt = variable.resolvedType == _cache.intType\n      var value = constant.asInt\n\n      # Replacing values with 0 only works for integers. Doubles can be NaN and\n      # NaN times anything is NaN, zero included.\n      if value == 0 && variableIsInt {\n        if variable.hasNoSideEffects {\n          node.become(constant.remove)\n        }\n        return\n      }\n\n      # This identity works even with NaN\n      if value == 1 {\n        node.become(variable.remove)\n        return\n      }\n\n      # Multiply by a power of 2 should be a left-shift operation, which is\n      # more concise and always faster (or at least never slower) than the\n      # alternative. Division can't be replaced by a right-shift operation\n      # because that would lead to incorrect results for negative numbers.\n      if variableIsInt {\n        var shift = _logBase2(value)\n        if shift != -1 {\n          # \"x * 2 * 4\" => \"x << 3\"\n          if variable.kind == .SHIFT_LEFT && variable.binaryRight.isInt {\n            shift += variable.binaryRight.asInt\n            variable.replaceWith(variable.binaryLeft.remove)\n          }\n\n          constant.content = IntContent.new(shift)\n          node.kind = .SHIFT_LEFT\n        }\n      }\n    }\n\n    # \"((a >> 8) & 255) << 8\" => \"a & (255 << 8)\"\n    # \"((a >>> 8) & 255) << 8\" => \"a & (255 << 8)\"\n    # \"((a >> 7) & 255) << 8\" => \"(a << 1) & (255 << 8)\"\n    # \"((a >>> 7) & 255) << 8\" => \"(a << 1) & (255 << 8)\"\n    # \"((a >> 8) & 255) << 7\" => \"(a >> 1) & (255 << 7)\"\n    # \"((a >>> 8) & 255) << 7\" => \"(a >>> 1) & (255 << 7)\"\n    def _foldConstantBitwiseAndInsideShift(node Node, andLeft Node, andRight Node) {\n      assert(node.kind == .SHIFT_LEFT && node.binaryRight.isInt)\n\n      if andRight.isInt && (andLeft.kind == .SHIFT_RIGHT || andLeft.kind == .UNSIGNED_SHIFT_RIGHT) && andLeft.binaryRight.isInt {\n        var mask = andRight.asInt\n        var leftShift = node.binaryRight.asInt\n        var rightShift = andLeft.binaryRight.asInt\n        var value = andLeft.binaryLeft.remove\n\n        if leftShift < rightShift {\n          value = Node.createBinary(andLeft.kind, value, _cache.createInt(rightShift - leftShift)).withType(_cache.intType)\n        }\n\n        else if leftShift > rightShift {\n          value = Node.createBinary(.SHIFT_LEFT, value, _cache.createInt(leftShift - rightShift)).withType(_cache.intType)\n        }\n\n        node.become(Node.createBinary(.BITWISE_AND, value, _cache.createInt(mask << leftShift)).withType(node.resolvedType))\n      }\n    }\n\n    def _foldConstantBitwiseAndInsideBitwiseOr(node Node) {\n      assert(node.kind == .BITWISE_OR && node.binaryLeft.kind == .BITWISE_AND)\n\n      var left = node.binaryLeft\n      var right = node.binaryRight\n      var leftLeft = left.binaryLeft\n      var leftRight = left.binaryRight\n\n      # \"(a & b) | (a & c)\" => \"a & (b | c)\"\n      if right.kind == .BITWISE_AND {\n        var rightLeft = right.binaryLeft\n        var rightRight = right.binaryRight\n\n        if leftRight.isInt && rightRight.isInt && _isSameVariableReference(leftLeft, rightLeft) {\n          var mask = leftRight.asInt | rightRight.asInt\n          node.become(Node.createBinary(.BITWISE_AND, leftLeft.remove, _cache.createInt(mask)).withType(node.resolvedType))\n        }\n      }\n\n      # \"(a & b) | c\" => \"a | c\" when \"(a | b) == ~0\"\n      else if right.isInt && leftRight.isInt && (leftRight.asInt | right.asInt) == ~0 {\n        left.become(leftLeft.remove)\n      }\n    }\n\n    def _foldBinaryWithConstant(node Node, left Node, right Node) {\n      # There are lots of other folding opportunities for most binary operators\n      # here but those usually have a negligible performance and/or size impact\n      # on the generated code and instead slow the compiler down. Only certain\n      # ones are implemented below.\n      switch node.kind {\n        # These are important for dead code elimination\n        case .LOGICAL_AND {\n          if left.isFalse || right.isTrue { node.become(left.remove) }\n          else if left.isTrue { node.become(right.remove) }\n        }\n        case .LOGICAL_OR {\n          if left.isTrue || right.isFalse { node.become(left.remove) }\n          else if left.isFalse { node.become(right.remove) }\n        }\n\n        # Constants are often added up in compound expressions. Folding\n        # addition/subtraction improves minification in JavaScript and often\n        # helps with readability.\n        case .ADD, .SUBTRACT {\n          if left.isInt { _foldConstantIntegerAddOrSubtract(node, right, left, 0) }\n          else if right.isInt { _foldConstantIntegerAddOrSubtract(node, left, right, 0) }\n          else { _foldAddOrSubtract(node) }\n        }\n\n        # Multiplication is special-cased here because in JavaScript, optimizing\n        # away the general-purpose Math.imul function may result in large\n        # speedups when it's implemented with a polyfill.\n        case .MULTIPLY {\n          if right.isInt { _foldConstantIntegerMultiply(node, left, right) }\n        }\n\n        # This improves generated code for inlined bit packing functions\n        case .SHIFT_LEFT, .SHIFT_RIGHT, .UNSIGNED_SHIFT_RIGHT {\n          # \"x << 0\" => \"x\"\n          # \"x >> 0\" => \"x\"\n          # \"x >>> 0\" => \"x\"\n          if _cache.isEquivalentToInt(left.resolvedType) && right.isInt && right.asInt == 0 {\n            node.become(left.remove)\n          }\n\n          # Handle special cases of \"&\" nested inside \"<<\"\n          else if node.kind == .SHIFT_LEFT && left.kind == .BITWISE_AND && right.isInt {\n            _foldConstantBitwiseAndInsideShift(node, left.binaryLeft, left.binaryRight)\n          }\n\n          # \"x << 1 << 2\" => \"x << 3\"\n          # \"x >> 1 >> 2\" => \"x >> 3\"\n          # \"x >>> 1 >>> 2\" => \"x >>> 3\"\n          else if node.kind == left.kind && left.binaryRight.isInt && right.isInt {\n            _flattenInt(right, left.binaryRight.asInt + right.asInt)\n            left.replaceWith(left.binaryLeft.remove)\n          }\n        }\n        case .BITWISE_AND {\n          if right.isInt && _cache.isEquivalentToInt(left.resolvedType) {\n            var value = right.asInt\n\n            # \"x & ~0\" => \"x\"\n            if value == ~0 {\n              node.become(left.remove)\n            }\n\n            # \"x & 0\" => \"0\"\n            else if value == 0 && left.hasNoSideEffects {\n              node.become(right.remove)\n            }\n          }\n        }\n        case .BITWISE_OR {\n          if right.isInt && _cache.isEquivalentToInt(left.resolvedType) {\n            var value = right.asInt\n\n            # \"x | 0\" => \"x\"\n            if value == 0 {\n              node.become(left.remove)\n              return\n            }\n\n            # \"x | ~0\" => \"~0\"\n            else if value == ~0 && left.hasNoSideEffects {\n              node.become(right.remove)\n              return\n            }\n          }\n          if left.kind == .BITWISE_AND { _foldConstantBitwiseAndInsideBitwiseOr(node) }\n        }\n      }\n    }\n\n    def _foldBinary(node Node) {\n      var kind = node.kind\n      if kind == .ADD && node.resolvedType == _cache.stringType {\n        _foldStringConcatenation(node)\n        return\n      }\n\n      var left = node.binaryLeft\n      var right = node.binaryRight\n\n      # Canonicalize the order of commutative operators\n      if (kind == .MULTIPLY || kind == .BITWISE_AND || kind == .BITWISE_OR) && left.kind == .CONSTANT && right.kind != .CONSTANT {\n        var temp = left\n        left = right\n        right = temp\n        left.swapWith(right)\n      }\n\n      if left.kind == .CONSTANT && right.kind == .CONSTANT {\n        var leftContent = left.content\n        var rightContent = right.content\n        var leftKind = leftContent.kind\n        var rightKind = rightContent.kind\n\n        # Fold equality operators\n        if leftKind == .STRING && rightKind == .STRING {\n          switch kind {\n            case .EQUAL { _flattenBool(node, leftContent.asString == rightContent.asString) }\n            case .NOT_EQUAL { _flattenBool(node, leftContent.asString != rightContent.asString) }\n            case .LESS_THAN { _flattenBool(node, leftContent.asString < rightContent.asString) }\n            case .GREATER_THAN { _flattenBool(node, leftContent.asString > rightContent.asString) }\n            case .LESS_THAN_OR_EQUAL { _flattenBool(node, leftContent.asString <= rightContent.asString) }\n            case .GREATER_THAN_OR_EQUAL { _flattenBool(node, leftContent.asString >= rightContent.asString) }\n          }\n          return\n        }\n\n        # Fold \"bool\" values\n        else if leftKind == .BOOL && rightKind == .BOOL {\n          switch kind {\n            case .LOGICAL_AND { _flattenBool(node, leftContent.asBool && rightContent.asBool) }\n            case .LOGICAL_OR { _flattenBool(node, leftContent.asBool || rightContent.asBool) }\n            case .EQUAL { _flattenBool(node, leftContent.asBool == rightContent.asBool) }\n            case .NOT_EQUAL { _flattenBool(node, leftContent.asBool != rightContent.asBool) }\n          }\n          return\n        }\n\n        # Fold \"int\" values\n        else if leftKind == .INT && rightKind == .INT {\n          switch kind {\n            case .ADD { _flattenInt(node, leftContent.asInt + rightContent.asInt) }\n            case .BITWISE_AND { _flattenInt(node, leftContent.asInt & rightContent.asInt) }\n            case .BITWISE_OR { _flattenInt(node, leftContent.asInt | rightContent.asInt) }\n            case .BITWISE_XOR { _flattenInt(node, leftContent.asInt ^ rightContent.asInt) }\n            case .DIVIDE { _flattenInt(node, leftContent.asInt / rightContent.asInt) }\n            case .EQUAL { _flattenBool(node, leftContent.asInt == rightContent.asInt) }\n            case .GREATER_THAN { _flattenBool(node, leftContent.asInt > rightContent.asInt) }\n            case .GREATER_THAN_OR_EQUAL { _flattenBool(node, leftContent.asInt >= rightContent.asInt) }\n            case .LESS_THAN { _flattenBool(node, leftContent.asInt < rightContent.asInt) }\n            case .LESS_THAN_OR_EQUAL { _flattenBool(node, leftContent.asInt <= rightContent.asInt) }\n            case .MULTIPLY { _flattenInt(node, leftContent.asInt * rightContent.asInt) }\n            case .NOT_EQUAL { _flattenBool(node, leftContent.asInt != rightContent.asInt) }\n            case .REMAINDER { _flattenInt(node, leftContent.asInt % rightContent.asInt) }\n            case .SHIFT_LEFT { _flattenInt(node, leftContent.asInt << rightContent.asInt) }\n            case .SHIFT_RIGHT { _flattenInt(node, leftContent.asInt >> rightContent.asInt) }\n            case .SUBTRACT { _flattenInt(node, leftContent.asInt - rightContent.asInt) }\n            case .UNSIGNED_SHIFT_RIGHT { _flattenInt(node, leftContent.asInt >>> rightContent.asInt) }\n          }\n          return\n        }\n\n        # Fold \"double\" values\n        else if leftKind == .DOUBLE && rightKind == .DOUBLE {\n          switch kind {\n            case .ADD { _flattenDouble(node, leftContent.asDouble + rightContent.asDouble) }\n            case .SUBTRACT { _flattenDouble(node, leftContent.asDouble - rightContent.asDouble) }\n            case .MULTIPLY { _flattenDouble(node, leftContent.asDouble * rightContent.asDouble) }\n            case .DIVIDE { _flattenDouble(node, leftContent.asDouble / rightContent.asDouble) }\n            case .EQUAL { _flattenBool(node, leftContent.asDouble == rightContent.asDouble) }\n            case .NOT_EQUAL { _flattenBool(node, leftContent.asDouble != rightContent.asDouble) }\n            case .LESS_THAN { _flattenBool(node, leftContent.asDouble < rightContent.asDouble) }\n            case .GREATER_THAN { _flattenBool(node, leftContent.asDouble > rightContent.asDouble) }\n            case .LESS_THAN_OR_EQUAL { _flattenBool(node, leftContent.asDouble <= rightContent.asDouble) }\n            case .GREATER_THAN_OR_EQUAL { _flattenBool(node, leftContent.asDouble >= rightContent.asDouble) }\n          }\n          return\n        }\n      }\n\n      _foldBinaryWithConstant(node, left, right)\n    }\n\n    def _foldHook(node Node) {\n      var test = node.hookTest\n      if test.isTrue { node.become(node.hookTrue.remove) }\n      else if test.isFalse { node.become(node.hookFalse.remove) }\n    }\n\n    def constantForSymbol(symbol VariableSymbol) Content {\n      if symbol.id in _constantCache {\n        return _constantCache[symbol.id]\n      }\n\n      if _prepareSymbol != null {\n        _prepareSymbol(symbol)\n      }\n\n      var constant Content = null\n      var value = symbol.value\n\n      if symbol.isConst && value != null {\n        _constantCache[symbol.id] = null\n        value = value.clone\n        foldConstants(value)\n        if value.kind == .CONSTANT {\n          constant = value.content\n        }\n      }\n\n      _constantCache[symbol.id] = constant\n      return constant\n    }\n  }\n\n  namespace ConstantFolder {\n    def _isVariableReference(node Node) bool {\n      return node.kind == .NAME && node.symbol != null && node.symbol.kind.isVariable\n    }\n\n    def _isSameVariableReference(a Node, b Node) bool {\n      return\n        _isVariableReference(a) && _isVariableReference(b) && a.symbol == b.symbol ||\n        a.kind == .CAST && b.kind == .CAST && _isSameVariableReference(a.castValue, b.castValue)\n    }\n\n    def _hasNestedReference(node Node, symbol Symbol) bool {\n      assert(symbol != null)\n      if node.symbol == symbol {\n        return true\n      }\n      for child = node.firstChild; child != null; child = child.nextSibling {\n        if _hasNestedReference(child, symbol) {\n          return true\n        }\n      }\n      return false\n    }\n\n    def _shouldFoldSymbol(symbol Symbol) bool {\n      return symbol != null && symbol.isConst && (symbol.kind != .VARIABLE_INSTANCE || symbol.isImported)\n    }\n\n    def _isKnownCall(symbol Symbol, knownSymbol Symbol) bool {\n      return symbol == knownSymbol || symbol != null && symbol.kind.isFunction && (\n        symbol.asFunctionSymbol.overloaded == knownSymbol ||\n        knownSymbol.kind.isFunction && symbol.asFunctionSymbol.overloaded != null &&\n          symbol.asFunctionSymbol.overloaded == knownSymbol.asFunctionSymbol.overloaded &&\n          symbol.asFunctionSymbol.argumentOnlyType == knownSymbol.asFunctionSymbol.argumentOnlyType)\n    }\n\n    # Returns the log2(value) or -1 if log2(value) is not an integer\n    def _logBase2(value int) int {\n      if value < 1 || (value & (value - 1)) != 0 {\n        return -1\n      }\n      var result = 0\n      while value > 1 {\n        value >>= 1\n        result++\n      }\n      return result\n    }\n  }\n}\n"
  },
  {
    "path": "src/middle/globalizing.sk",
    "content": "namespace Skew {\n  enum PassKind {\n    GLOBALIZING\n  }\n\n  class GlobalizingPass : Pass {\n    over kind PassKind {\n      return .GLOBALIZING\n    }\n\n    over run(context PassContext) {\n      var globalizeAllFunctions = context.options.globalizeAllFunctions\n      var virtualLookup = globalizeAllFunctions || context.options.isAlwaysInlinePresent ? VirtualLookup.new(context.global) : null\n      var motionContext = Motion.Context.new\n\n      for info in context.callGraph.callInfo {\n        var symbol = info.symbol\n\n        # Turn certain instance functions into global functions\n        if symbol.kind == .FUNCTION_INSTANCE && (\n            symbol.parent.kind.isEnumOrFlags ||\n            symbol.parent.kind == .OBJECT_WRAPPED ||\n            symbol.parent.kind == .OBJECT_INTERFACE && symbol.block != null ||\n            symbol.parent.isImported && !symbol.isImported ||\n            (globalizeAllFunctions || symbol.isInliningForced) && !symbol.isImportedOrExported && !virtualLookup.isVirtual(symbol)) {\n\n          var function = symbol.asFunctionSymbol\n          function.kind = .FUNCTION_GLOBAL\n          function.arguments.prepend(function.this)\n          function.resolvedType.argumentTypes.prepend(function.this.resolvedType)\n          function.this = null\n\n          # The globalized function needs instance type parameters\n          if function.parent.asObjectSymbol.parameters != null {\n            function.parent.asObjectSymbol.functions.removeOne(function)\n            motionContext.moveSymbolIntoNewNamespace(function)\n          }\n\n          # Update all call sites\n          for callSite in info.callSites {\n            var value = callSite.callNode.callValue\n\n            # Rewrite \"super(foo)\" to \"bar(self, foo)\"\n            if value.kind == .SUPER {\n              var this = callSite.enclosingSymbol.asFunctionSymbol.this\n              value.replaceWith(Node.createSymbolReference(this))\n            }\n\n            # Rewrite \"self.foo(bar)\" to \"foo(self, bar)\"\n            else {\n              value.replaceWith((value.kind == .PARAMETERIZE ? value.parameterizeValue : value).dotTarget.remove)\n            }\n\n            callSite.callNode.prependChild(Node.createSymbolReference(function))\n          }\n        }\n      }\n\n      motionContext.finish\n    }\n  }\n\n  class VirtualLookup {\n    const _map IntMap<int> = {}\n\n    def new(global ObjectSymbol) {\n      _visitObject(global)\n    }\n\n    def isVirtual(symbol FunctionSymbol) bool {\n      return symbol.id in _map\n    }\n\n    def _visitObject(symbol ObjectSymbol) {\n      for object in symbol.objects {\n        _visitObject(object)\n      }\n\n      for function in symbol.functions {\n        if function.overridden != null {\n          _map[function.overridden.id] = 0\n          _map[function.id] = 0\n        }\n\n        if symbol.kind == .OBJECT_INTERFACE && function.kind == .FUNCTION_INSTANCE && function.forwardTo == null {\n          if function.implementations != null {\n            for implementation in function.implementations {\n              _map[implementation.id] = 0\n            }\n          }\n          _map[function.id] = 0\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/middle/ide.sk",
    "content": "namespace Skew.IDE {\n  class SymbolQuery {\n    const source Source\n    const index int\n\n    var resolvedType Type = null\n    var symbol Symbol = null\n    var range Range = null\n\n    def generateTooltip string {\n      if symbol == null {\n        return null\n      }\n\n      var text = \"\"\n      if symbol.comments != null {\n        for comment in symbol.comments {\n          if !comment.hasGapBelow {\n            for line in comment.lines {\n              text += \"#\\(line)\\n\"\n            }\n          }\n        }\n      }\n\n      switch symbol.kind {\n        case .FUNCTION_ANNOTATION, .FUNCTION_CONSTRUCTOR, .FUNCTION_GLOBAL, .FUNCTION_INSTANCE {\n          var arguments = symbol.asFunctionSymbol.arguments\n          text += \"\\(symbol.isOver ? \"over\" : \"def\") \\(symbol.name)\\(_parameters(symbol.asFunctionSymbol.parameters))\"\n          if resolvedType != null && resolvedType.argumentTypes != null {\n            if !arguments.isEmpty {\n              text += \"(\"\n              for i in 0..arguments.count {\n                if i != 0 {\n                  text += \", \"\n                }\n                text += \"\\(arguments[i].name) \\(resolvedType.argumentTypes[i])\"\n              }\n              text += \")\"\n            }\n            if resolvedType.returnType != null {\n              text += \" \\(resolvedType.returnType)\"\n            }\n          } else {\n            text += \" dynamic\"\n          }\n        }\n\n        case .VARIABLE_ARGUMENT, .VARIABLE_ENUM_OR_FLAGS, .VARIABLE_GLOBAL, .VARIABLE_INSTANCE, .VARIABLE_LOCAL {\n          var value = symbol.asVariableSymbol.value\n          text += \"\\(symbol.isConst ? \"const\" : \"var\") \\(symbol.name)\"\n          text += resolvedType != null ? \" \\(resolvedType)\" : \" dynamic\"\n          if symbol.isConst && !symbol.isLoopVariable && value != null && value.kind == .CONSTANT {\n            text += \" = \"\n            switch value.content.kind {\n              case .BOOL { text += value.asBool.toString }\n              case .DOUBLE { text += value.asDouble.toString }\n              case .INT { text += value.asInt.toString }\n              case .STRING { text += quoteString(value.asString, .DOUBLE, .NORMAL) }\n            }\n          }\n        }\n\n        case .OBJECT_CLASS {\n          text += \"class \\(symbol.name)\\(_parameters(symbol.asObjectSymbol.parameters))\"\n          if symbol.asObjectSymbol.baseType != null {\n            text += \" : \\(symbol.asObjectSymbol.baseType)\"\n          }\n          if symbol.asObjectSymbol.interfaceTypes != null {\n            var types = symbol.asObjectSymbol.interfaceTypes\n            for i in 0..types.count {\n              text += \"\\(i != 0 ? \", \" : \" :: \")\\(types[i])\"\n            }\n          }\n        }\n\n        case .OBJECT_WRAPPED {\n          text += \"type \\(symbol.name)\\(_parameters(symbol.asObjectSymbol.parameters))\"\n          if symbol.asObjectSymbol.wrappedType != null {\n            text += \" = \\(symbol.asObjectSymbol.wrappedType)\"\n          }\n        }\n\n        case .OBJECT_ENUM {\n          text += \"enum \\(symbol.name)\"\n        }\n\n        case .OBJECT_FLAGS {\n          text += \"flags \\(symbol.name)\"\n        }\n\n        case .OBJECT_INTERFACE {\n          text += \"interface \\(symbol.name)\\(_parameters(symbol.asObjectSymbol.parameters))\"\n        }\n\n        case .OBJECT_NAMESPACE {\n          text += \"namespace \\(symbol.name)\"\n        }\n\n        default {\n          text += symbol.name\n        }\n      }\n\n      return text\n    }\n\n    def run(global ObjectSymbol) {\n      var findSymbolInSymbol fn(Symbol) bool\n      var findSymbolInObject fn(ObjectSymbol) bool\n      var findSymbolInParameter fn(ParameterSymbol) bool\n      var findSymbolInFunction fn(FunctionSymbol) bool\n      var findSymbolInVariable fn(VariableSymbol) bool\n      var findSymbolInNode fn(Node) bool\n\n      findSymbolInSymbol = symbol => {\n        while true {\n          if symbol.annotations != null {\n            for node in symbol.annotations {\n              if findSymbolInNode(node) {\n                return true\n              }\n            }\n          }\n          if _findSymbolInRange(symbol.range, symbol) {\n            resolvedType = symbol.resolvedType\n            return true\n          }\n          if symbol.nextMergedSymbol == null {\n            return false\n          }\n          symbol = symbol.nextMergedSymbol\n        }\n      }\n\n      findSymbolInObject = symbol => {\n        return\n          findSymbolInSymbol(symbol) ||\n          symbol.objects.any(findSymbolInObject) ||\n          symbol.parameters != null && symbol.parameters.any(findSymbolInParameter) ||\n          symbol.functions.any(findSymbolInFunction) ||\n          symbol.variables.any(findSymbolInVariable) ||\n          findSymbolInNode(symbol.extends) ||\n          symbol.implements != null && symbol.implements.any(findSymbolInNode)\n      }\n\n      findSymbolInParameter = symbol => {\n        return findSymbolInSymbol(symbol)\n      }\n\n      findSymbolInFunction = symbol => {\n        if symbol.isAutomaticallyGenerated {\n          return false\n        }\n        return\n          findSymbolInSymbol(symbol) ||\n          symbol.parameters != null && symbol.parameters.any(findSymbolInParameter) ||\n          symbol.arguments.any(findSymbolInVariable) ||\n          findSymbolInNode(symbol.returnType) ||\n          findSymbolInNode(symbol.block)\n      }\n\n      findSymbolInVariable = symbol => {\n        return\n          findSymbolInSymbol(symbol) ||\n          findSymbolInNode(symbol.value) ||\n          findSymbolInNode(symbol.type)\n      }\n\n      findSymbolInNode = node => {\n        if node != null {\n          var kind = node.kind\n\n          if kind == .VARIABLE {\n            return findSymbolInVariable(node.symbol.asVariableSymbol)\n          }\n\n          for child = node.firstChild; child != null; child = child.nextSibling {\n            if findSymbolInNode(child) {\n              return true\n            }\n          }\n\n          if !node.isIgnoredByIDE {\n            if kind == .NAME && _findSymbolInRange(node.range, node.symbol) {\n              resolvedType = node.resolvedType\n              return true\n            }\n\n            if (kind == .DOT || kind.isUnary || kind.isBinary) && _findSymbolInRange(node.internalRangeOrRange, node.symbol) {\n              resolvedType = kind == .DOT ? node.resolvedType : node.symbol?.resolvedType\n              return true\n            }\n          }\n\n          if kind == .LAMBDA {\n            return\n              node.symbol.asFunctionSymbol.arguments.any(findSymbolInVariable) ||\n              findSymbolInNode(node.symbol.asFunctionSymbol.returnType)\n          }\n        }\n\n        return false\n      }\n\n      findSymbolInObject(global)\n    }\n\n    def _findSymbolInRange(queryRange Range, querySymbol Symbol) bool {\n      if queryRange != null && queryRange.source == source && queryRange.touches(index) {\n        symbol = querySymbol\n        range = queryRange\n        return true\n      }\n\n      return false\n    }\n\n    def _parameters(parameters List<ParameterSymbol>) string {\n      var text = \"\"\n      if parameters != null {\n        text += \"<\"\n        for i in 0..parameters.count {\n          if i != 0 {\n            text += \", \"\n          }\n          text += parameters[i].name\n        }\n        text += \">\"\n      }\n      return text\n    }\n  }\n\n  class SymbolsQuery {\n    const source Source\n    const symbols List<Symbol> = []\n\n    def run(symbol ObjectSymbol) {\n      _collectSymbol(symbol)\n\n      for object in symbol.objects {\n        run(object)\n      }\n\n      for function in symbol.functions {\n        _collectSymbol(function)\n      }\n\n      for variable in symbol.variables {\n        _collectSymbol(variable)\n      }\n    }\n\n    def _collectSymbol(symbol Symbol) {\n      if symbol.range != null && (source == null || symbol.range.source == source) && !symbol.isAutomaticallyGenerated {\n        symbols.append(symbol)\n      }\n    }\n  }\n\n  class RenameQuery {\n    const source Source\n    const index int\n    const ranges List<Range> = []\n    const _targets IntMap<int> = {}\n    var _targetName string = null\n\n    def run(global ObjectSymbol) {\n      var query = SymbolQuery.new(source, index)\n      query.run(global)\n      var symbol = query.symbol\n\n      if symbol != null {\n        _targetName = symbol.name\n        _targets[symbol.id] = 0\n\n        # Make sure interfaces and overridden methods are all renamed together\n        if symbol.kind.isFunction {\n          _includeRelatedFunctions(global, symbol.asFunctionSymbol)\n        }\n\n        _visitObject(global)\n\n        # Remove overlapping ranges since they are sometimes generated as a side effect of lowering\n        var current Range = null\n        ranges.sort((a, b) => a.source == b.source\n          ? a.start <=> b.start\n          : a.source.name <=> b.source.name)\n        ranges.removeIf(range => {\n          var previous = current\n          current = range\n          return previous != null && current.overlaps(previous)\n        })\n      }\n    }\n\n    def _includeRelatedFunctions(global ObjectSymbol, symbol FunctionSymbol) {\n      var functions List<FunctionSymbol> = []\n      var wasFound = false\n\n      # Gather all non-local functions\n      _searchForFunctions(global, functions)\n      var labels = UnionFind.new.allocate(functions.count)\n\n      # Assign each one an index\n      for i in 0..functions.count {\n        var function = functions[i]\n        function.namingGroup = i\n        if function == symbol {\n          wasFound = true\n        }\n      }\n\n      # Lambda functions won't be found\n      if wasFound {\n        # Merge related functions together (this is the O(n log n) way to find all related functions)\n        for function in functions {\n          if function.overridden != null {\n            labels.union(function.namingGroup, function.overridden.namingGroup)\n          }\n          if function.implementations != null {\n            for implementation in function.implementations {\n              labels.union(function.namingGroup, implementation.namingGroup)\n            }\n          }\n        }\n\n        # Extract the relevant functions\n        var label = labels.find(symbol.namingGroup)\n        for function in functions {\n          if labels.find(function.namingGroup) == label {\n            _targets[function.id] = 0\n          }\n        }\n      }\n    }\n\n    def _appendRange(range Range) {\n      # Sanity check the range to make sure it contains the target name\n      if range != null && range.toString == _targetName {\n        ranges.append(range)\n      }\n    }\n\n    def _visitSymbol(symbol Symbol) {\n      var isTarget = symbol.id in _targets\n\n      while symbol != null {\n        if symbol.annotations != null {\n          for node in symbol.annotations {\n            _visitNode(node)\n          }\n        }\n\n        if isTarget && symbol.range != null {\n          _appendRange(symbol.range)\n        }\n\n        symbol = symbol.nextMergedSymbol\n      }\n    }\n\n    def _visitObject(symbol ObjectSymbol) {\n      _visitSymbol(symbol)\n      _visitParameters(symbol.parameters)\n      _visitNode(symbol.extends)\n\n      for object in symbol.objects {\n        _visitObject(object)\n      }\n\n      for function in symbol.functions {\n        _visitFunction(function)\n      }\n\n      for variable in symbol.variables {\n        _visitVariable(variable)\n      }\n\n      if symbol.implements != null {\n        for node in symbol.implements {\n          _visitNode(node)\n        }\n      }\n    }\n\n    def _visitParameters(parameters List<ParameterSymbol>) {\n      if parameters != null {\n        for parameter in parameters {\n          _visitSymbol(parameter)\n        }\n      }\n    }\n\n    def _visitFunction(symbol FunctionSymbol) {\n      _visitSymbol(symbol)\n      _visitParameters(symbol.parameters)\n      _visitNode(symbol.returnType)\n      _visitNode(symbol.block)\n\n      for argument in symbol.arguments {\n        _visitVariable(argument)\n      }\n    }\n\n    def _visitVariable(symbol VariableSymbol) {\n      _visitSymbol(symbol)\n      _visitNode(symbol.type)\n      _visitNode(symbol.value)\n    }\n\n    def _visitNode(node Node) {\n      if node != null {\n        var kind = node.kind\n\n        if kind == .VARIABLE {\n          _visitVariable(node.symbol.asVariableSymbol)\n          return\n        }\n\n        for child = node.firstChild; child != null; child = child.nextSibling {\n          _visitNode(child)\n        }\n\n        if kind == .LAMBDA {\n          for argument in node.symbol.asFunctionSymbol.arguments {\n            _visitVariable(argument)\n          }\n          _visitNode(node.symbol.asFunctionSymbol.returnType)\n        }\n\n        else if node.symbol != null && node.symbol.id in _targets && !node.isIgnoredByIDE {\n          if kind == .NAME {\n            _appendRange(node.range)\n          }\n\n          else if kind == .DOT {\n            _appendRange(node.internalRange)\n          }\n        }\n      }\n    }\n  }\n\n  namespace RenameQuery {\n    def _searchForFunctions(symbol ObjectSymbol, functions List<FunctionSymbol>) {\n      for object in symbol.objects {\n        _searchForFunctions(object, functions)\n      }\n\n      for function in symbol.functions {\n        functions.append(function)\n      }\n    }\n  }\n\n  def completionType(symbol Symbol) string {\n    if symbol.kind.isFunction {\n      var text = \"(\"\n      var function = symbol.asFunctionSymbol\n      for argument in function.arguments {\n        if text != \"(\" {\n          text += \", \"\n        }\n        text += \"\\(argument.name) \\(argument.resolvedType)\"\n      }\n      text += \")\"\n      if function.resolvedType.returnType != null {\n        text += \" \\(function.resolvedType.returnType)\"\n      }\n      return text\n    }\n\n    if symbol.kind.isVariable {\n      return symbol.resolvedType.toString\n    }\n\n    switch symbol.kind {\n      case .OBJECT_CLASS { return \"class\" }\n      case .OBJECT_ENUM { return \"enum\" }\n      case .OBJECT_FLAGS { return \"flags\" }\n      case .OBJECT_INTERFACE { return \"interface\" }\n      case .OBJECT_NAMESPACE { return \"namespace\" }\n      case .OBJECT_WRAPPED { return \"type\" }\n    }\n\n    return null\n  }\n\n  class SignatureQuery {\n    const source Source\n    const index int\n    var signature FunctionSymbol = null\n    var argumentIndex = -1\n\n    def signatureString string {\n      if signature == null {\n        return null\n      }\n\n      var text = \"\\(signature.isOver ? \"over\" : \"def\") \\(signature.name)(\"\n      for i in 0..signature.arguments.count {\n        var argument = signature.arguments[i]\n        if i != 0 {\n          text += \", \"\n        }\n        text += \"\\(argument.name) \\(argument.resolvedType)\"\n      }\n      text += \")\"\n      if signature.resolvedType.returnType != null {\n        text += \" \\(signature.resolvedType.returnType)\"\n      }\n\n      return text\n    }\n\n    def argumentStrings List<string> {\n      var list List<string> = []\n      for argument in signature.arguments {\n        list.append(\"\\(argument.name) \\(argument.resolvedType)\")\n      }\n      return list\n    }\n\n    def run(global ObjectSymbol) {\n      var findSignatureInSymbol fn(Symbol) bool\n      var findSignatureInObject fn(ObjectSymbol) bool\n      var findSignatureInFunction fn(FunctionSymbol) bool\n      var findSignatureInVariable fn(VariableSymbol) bool\n      var findSignatureInNode fn(Node) bool\n\n      findSignatureInSymbol = symbol => {\n        while true {\n          if symbol.annotations != null {\n            for node in symbol.annotations {\n              if findSignatureInNode(node) {\n                return true\n              }\n            }\n          }\n          if symbol.nextMergedSymbol == null {\n            return false\n          }\n          symbol = symbol.nextMergedSymbol\n        }\n      }\n\n      findSignatureInObject = symbol => {\n        return\n          findSignatureInSymbol(symbol) ||\n          symbol.objects.any(findSignatureInObject) ||\n          symbol.functions.any(findSignatureInFunction) ||\n          symbol.variables.any(findSignatureInVariable) ||\n          findSignatureInNode(symbol.extends) ||\n          symbol.implements != null && symbol.implements.any(findSignatureInNode)\n      }\n\n      findSignatureInFunction = symbol => {\n        if symbol.isAutomaticallyGenerated {\n          return false\n        }\n        return\n          findSignatureInSymbol(symbol) ||\n          symbol.arguments.any(findSignatureInVariable) ||\n          findSignatureInNode(symbol.block)\n      }\n\n      findSignatureInVariable = symbol => {\n        return\n          findSignatureInSymbol(symbol) ||\n          findSignatureInNode(symbol.value)\n      }\n\n      findSignatureInNode = node => {\n        if node != null {\n          var kind = node.kind\n\n          if kind == .VARIABLE {\n            return findSignatureInVariable(node.symbol.asVariableSymbol)\n          }\n\n          for child = node.firstChild; child != null; child = child.nextSibling {\n            if findSignatureInNode(child) {\n              return true\n            }\n          }\n\n          if kind == .CALL && node.symbol != null && node.internalRange != null && node.internalRange.source == source && node.internalRange.touches(index) {\n            signature = node.symbol.asFunctionSymbol\n\n            # Find the argument containing the query location, if any\n            if !signature.arguments.isEmpty {\n              argumentIndex = 0\n              var limit = signature.arguments.count\n              for child = node.callValue.nextSibling; child != null; child = child.nextSibling {\n                if child.range != null && index <= child.range.end || argumentIndex + 1 >= limit {\n                  break\n                }\n                argumentIndex++\n              }\n            }\n\n            return true\n          }\n        }\n\n        return false\n      }\n\n      findSignatureInObject(global)\n    }\n  }\n}\n"
  },
  {
    "path": "src/middle/inlining.sk",
    "content": "namespace Skew {\n  enum PassKind {\n    INLINING\n  }\n\n  class InliningPass : Pass {\n    over kind PassKind {\n      return .INLINING\n    }\n\n    over run(context PassContext) {\n      var graph = Inlining.InliningGraph.new(context.callGraph, context.log, context.options.inlineAllFunctions)\n      for info in graph.inliningInfo {\n        Inlining.inlineSymbol(graph, info)\n      }\n    }\n  }\n}\n\nnamespace Skew.Inlining {\n  def inlineSymbol(graph InliningGraph, info InliningInfo) {\n    if !info.shouldInline {\n      return\n    }\n\n    # Inlining nested functions first is more efficient because it results in\n    # fewer inlining operations. This won't enter an infinite loop because\n    # inlining for all such functions has already been disabled.\n    for bodyCall in info.bodyCalls {\n      inlineSymbol(graph, bodyCall)\n    }\n\n    var spreadingAnnotations = info.symbol.spreadingAnnotations\n    for i in 0..info.callSites.count {\n      var callSite = info.callSites[i]\n\n      # Some calls may be reused for other node types during constant folding\n      if callSite == null || callSite.callNode.kind != .CALL {\n        continue\n      }\n\n      # Make sure the call site hasn't been tampered with. An example of where\n      # this can happen is constant folding \"false ? 0 : foo.foo\" to \"foo.foo\".\n      # The children of \"foo.foo\" are stolen and parented under the hook\n      # expression as part of a become() call. Skipping inlining in this case\n      # just means we lose out on those inlining opportunities. This isn't the\n      # end of the world and is a pretty rare occurrence.\n      var node = callSite.callNode\n      if node.childCount != info.symbol.arguments.count + 1 {\n        continue\n      }\n\n      # Propagate spreading annotations that must be preserved through inlining\n      if spreadingAnnotations != null {\n        var annotations = callSite.enclosingSymbol.annotations\n        if annotations == null {\n          annotations = []\n          callSite.enclosingSymbol.annotations = annotations\n        }\n        for annotation in spreadingAnnotations {\n          annotations.appendOne(annotation)\n        }\n      }\n\n      # Make sure each call site is inlined once by setting the call site to\n      # null. The call site isn't removed from the list since we don't want\n      # to mess up the indices of another call to inlineSymbol further up\n      # the call stack.\n      info.callSites[i] = null\n\n      # If there are unused arguments, drop those expressions entirely if\n      # they don't have side effects:\n      #\n      #   def bar(a int, b int) int {\n      #     return a\n      #   }\n      #\n      #   def test int {\n      #     return bar(0, foo(0)) + bar(1, 2)\n      #   }\n      #\n      # This should compile to:\n      #\n      #   def test int {\n      #     return bar(0, foo(0)) + 2\n      #   }\n      #\n      if !info.unusedArguments.isEmpty {\n        var hasSideEffects = false\n        for child = node.callValue.nextSibling; child != null; child = child.nextSibling {\n          if !child.hasNoSideEffects {\n            hasSideEffects = true\n            break\n          }\n        }\n        if hasSideEffects {\n          continue\n        }\n      }\n\n      info.symbol.inlinedCount++\n\n      var clone = info.inlineValue.clone\n      var value = node.firstChild.remove\n      var values List<Node> = []\n      while node.hasChildren {\n        assert(node.firstChild.resolvedType != null)\n        values.append(node.firstChild.remove)\n      }\n\n      # Make sure not to update the type if the function dynamic because the\n      # expression inside the function may have a more specific type that is\n      # necessary during code generation\n      if node.resolvedType != .DYNAMIC {\n        clone.resolvedType = node.resolvedType\n      }\n\n      assert((value.kind == .PARAMETERIZE ? value.parameterizeValue : value).kind == .NAME && value.symbol == info.symbol)\n      assert(clone.resolvedType != null)\n      node.become(clone)\n      recursivelySubstituteArguments(node, node, info.symbol.arguments, values)\n\n      # Remove the inlined result entirely if appropriate\n      var parent = node.parent\n      if parent != null && parent.kind == .EXPRESSION && node.hasNoSideEffects {\n        parent.remove\n      }\n    }\n  }\n\n  def recursivelyInlineFunctionCalls(graph InliningGraph, node Node) {\n    # Recursively inline child nodes first\n    for child = node.firstChild; child != null; child = child.nextSibling {\n      recursivelyInlineFunctionCalls(graph, child)\n    }\n\n    # Inline calls after all children have been processed\n    if node.kind == .CALL {\n      var symbol = node.callValue.symbol\n      if symbol != null {\n        var index = graph.symbolToInfoIndex.get(symbol.id, -1)\n        if index != -1 {\n          inlineSymbol(graph, graph.inliningInfo[index])\n        }\n      }\n    }\n  }\n\n  def recursivelySubstituteArguments(root Node, node Node, arguments List<VariableSymbol>, values List<Node>) {\n    # Substitute the argument if this is an argument name\n    var symbol = node.symbol\n    if symbol != null && symbol.kind.isVariable {\n      var index = arguments.indexOf(symbol.asVariableSymbol)\n      if index != -1 {\n        var parent = node.parent\n\n        # If we're in a wrapped type cast, replace the cast itself\n        if parent.kind == .CAST {\n          var valueType = parent.castValue.resolvedType\n          var targetType = parent.castType.resolvedType\n          if valueType.isWrapped && targetType.symbol != null &&\n              valueType.symbol.asObjectSymbol.wrappedType.symbol == targetType.symbol {\n            node = parent\n          }\n        }\n\n        if node == root {\n          node.become(values[index])\n        } else {\n          node.replaceWith(values[index])\n        }\n        return\n      }\n    }\n\n    # Otherwise, recursively search for substitutions in all child nodes\n    for child = node.firstChild, next Node = null; child != null; child = next {\n      next = child.nextSibling\n      recursivelySubstituteArguments(root, child, arguments, values)\n    }\n  }\n\n  class InliningInfo {\n    var symbol FunctionSymbol\n    var inlineValue Node\n    var callSites List<CallSite>\n    var unusedArguments List<int>\n    var shouldInline = true\n    var bodyCalls List<InliningInfo> = []\n  }\n\n  # Each node in the inlining graph is a symbol of an inlineable function and\n  # each directional edge is from a first function to a second function that is\n  # called directly within the body of the first function. Indirect function\n  # calls that may become direct calls through inlining can be discovered by\n  # traversing edges of this graph.\n  class InliningGraph {\n    var inliningInfo List<InliningInfo> = []\n    var symbolToInfoIndex IntMap<int> = {}\n\n    def new(graph CallGraph, log Log, inlineAllFunctions bool) {\n      # Create the nodes in the graph\n      for callInfo in graph.callInfo {\n        var symbol = callInfo.symbol\n        if symbol.isInliningPrevented {\n          continue\n        }\n        var info = _createInliningInfo(callInfo)\n        if info != null {\n          if inlineAllFunctions || symbol.isInliningForced {\n            symbolToInfoIndex[symbol.id] = inliningInfo.count\n            inliningInfo.append(info)\n          }\n        } else if symbol.isInliningForced {\n          log.semanticWarningInliningFailed(symbol.range, symbol.name)\n        }\n      }\n\n      # Create the edges in the graph\n      for info in inliningInfo {\n        for callSite in graph.callInfoForSymbol(info.symbol).callSites {\n          if callSite.enclosingSymbol.kind == .FUNCTION_GLOBAL {\n            var index = symbolToInfoIndex.get(callSite.enclosingSymbol.id, -1)\n            if index != -1 {\n              inliningInfo[index].bodyCalls.append(info)\n            }\n          }\n        }\n      }\n\n      # Detect and disable infinitely expanding inline operations\n      for info in inliningInfo {\n        info.shouldInline = !_containsInfiniteExpansion(info, [])\n      }\n    }\n  }\n\n  namespace InliningGraph {\n    def _containsInfiniteExpansion(info InliningInfo, symbols List<Symbol>) bool {\n      # This shouldn't get very long in normal programs so O(n) here is fine\n      if info.symbol in symbols {\n        return true\n      }\n\n      # Do a depth-first search on the graph and check for cycles\n      symbols.append(info.symbol)\n      for bodyCall in info.bodyCalls {\n        if _containsInfiniteExpansion(bodyCall, symbols) {\n          return true\n        }\n      }\n      symbols.removeLast\n      return false\n    }\n\n    def _createInliningInfo(info CallInfo) InliningInfo {\n      var symbol = info.symbol\n\n      # Inline functions consisting of a single return statement\n      if symbol.kind == .FUNCTION_GLOBAL {\n        var block = symbol.block\n        if block == null {\n          return null\n        }\n\n        # Replace functions with empty bodies with null\n        if !block.hasChildren {\n          var unusedArguments List<int> = []\n          for i in 0..symbol.arguments.count {\n            unusedArguments.append(i)\n          }\n          return InliningInfo.new(symbol, Node.createNull.withType(.NULL), info.callSites, unusedArguments)\n        }\n\n        var first = block.firstChild\n        var inlineValue Node = null\n\n        # If the first value in the function is a return statement, then the\n        # function body doesn't need to only have one statement. Subsequent\n        # statements are just dead code and will never be executed anyway.\n        if first.kind == .RETURN {\n          inlineValue = first.returnValue\n        }\n\n        # Otherwise, this statement must be a lone expression statement\n        else if first.kind == .EXPRESSION && first.nextSibling == null {\n          inlineValue = first.expressionValue\n        }\n\n        if inlineValue != null {\n          # Count the number of times each symbol is observed. Argument\n          # variables that are used more than once may need a let statement\n          # to avoid changing the semantics of the call site. For now, just\n          # only inline functions where each argument is used exactly once.\n          var argumentCounts IntMap<int> = {}\n          for argument in symbol.arguments {\n            argumentCounts[argument.id] = 0\n          }\n          if _recursivelyCountArgumentUses(inlineValue, argumentCounts) {\n            var unusedArguments List<int> = []\n            var isSimpleSubstitution = true\n            for i in 0..symbol.arguments.count {\n              var count = argumentCounts[symbol.arguments[i].id]\n              if count == 0 {\n                unusedArguments.append(i)\n              } else if count != 1 {\n                isSimpleSubstitution = false\n                break\n              }\n            }\n            if isSimpleSubstitution {\n              return InliningInfo.new(symbol, inlineValue, info.callSites, unusedArguments)\n            }\n          }\n        }\n      }\n\n      return null\n    }\n\n    # This returns false if inlining is impossible\n    def _recursivelyCountArgumentUses(node Node, argumentCounts IntMap<int>) bool {\n      # Prevent inlining of lambda expressions. They have their own function\n      # symbols that reference the original block and won't work with cloning.\n      # Plus inlining lambdas leads to code bloat.\n      if node.kind == .LAMBDA {\n        return false\n      }\n\n      # Inlining is impossible at this node if it's impossible for any child node\n      for child = node.firstChild; child != null; child = child.nextSibling {\n        if !_recursivelyCountArgumentUses(child, argumentCounts) {\n          return false\n        }\n      }\n\n      var symbol = node.symbol\n      if symbol != null {\n        var count = argumentCounts.get(symbol.id, -1)\n        if count != -1 {\n          argumentCounts[symbol.id] = count + 1\n\n          # Prevent inlining of functions that modify their arguments locally. For\n          # example, inlining this would lead to incorrect code:\n          #\n          #   def foo(x int, y int) {\n          #     x += y\n          #   }\n          #\n          #   def test {\n          #     foo(1, 2)\n          #   }\n          #\n          if node.isAssignTarget {\n            return false\n          }\n        }\n      }\n\n      return true\n    }\n  }\n}\n"
  },
  {
    "path": "src/middle/interfaceremoval.sk",
    "content": "namespace Skew {\n  enum PassKind {\n    INTERFACE_REMOVAL\n  }\n\n  class InterfaceRemovalPass : Pass {\n    const _interfaceImplementations IntMap<List<ObjectSymbol>> = {}\n    const _interfaces List<ObjectSymbol> = []\n\n    over kind PassKind {\n      return .INTERFACE_REMOVAL\n    }\n\n    over run(context PassContext) {\n      _scanForInterfaces(context.global)\n\n      for symbol in _interfaces {\n        if symbol.isImportedOrExported {\n          continue\n        }\n\n        var implementations = _interfaceImplementations.get(symbol.id, null)\n        if implementations == null || implementations.count == 1 {\n          symbol.kind = .OBJECT_NAMESPACE\n\n          # Remove this interface from its implementation\n          if implementations != null {\n            var object = implementations.first\n            for type in object.interfaceTypes {\n              if type.symbol == symbol {\n                object.interfaceTypes.removeOne(type)\n                break\n              }\n            }\n\n            # Mark these symbols as forwarded, which is used by the globalization\n            # pass and the JavaScript emitter to ignore this interface\n            for function in symbol.functions {\n              if function.implementations != null {\n                function.forwardTo = function.implementations.first\n              }\n            }\n            symbol.forwardTo = object\n          }\n        }\n      }\n    }\n\n    def _scanForInterfaces(symbol ObjectSymbol) {\n      for object in symbol.objects {\n        _scanForInterfaces(object)\n      }\n\n      if symbol.kind == .OBJECT_INTERFACE {\n        _interfaces.append(symbol)\n      }\n\n      if symbol.interfaceTypes != null {\n        for type in symbol.interfaceTypes {\n          var key = type.symbol.id\n          var implementations = _interfaceImplementations.get(key, null)\n          if implementations == null {\n            implementations = []\n            _interfaceImplementations[key] = implementations\n          }\n          implementations.append(symbol)\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/middle/lambdaconversion.sk",
    "content": "namespace Skew {\n  enum PassKind {\n    LAMBDA_CONVERSION\n  }\n\n  class LambdaConversionPass : Pass {\n    over kind PassKind {\n      return .LAMBDA_CONVERSION\n    }\n\n    over run(context PassContext) {\n      Skew.LambdaConversion.Converter.new(context.global, context.cache).run\n    }\n  }\n}\n\nnamespace Skew.LambdaConversion {\n  enum CaptureKind {\n    FUNCTION\n    LAMBDA\n    LOOP\n  }\n\n  class Definition {\n    const symbol VariableSymbol\n    const node Node\n    const scope Scope\n    var isCaptured = false\n\n    # If this symbol is captured, this contains the member variable on the\n    # environment object where this symbol's storage is moved to\n    var member VariableSymbol = null\n  }\n\n  class Use {\n    const definition Definition\n    const node Node\n  }\n\n  class Copy {\n    const scope Scope\n\n    # This contains the member variable on the environment containing this\n    # copy where a copy of the corresponding scope is stored\n    var member VariableSymbol = null\n  }\n\n  class Scope {\n    const id = ++_nextID\n    const kind CaptureKind\n    const node Node\n    const enclosingFunction FunctionSymbol\n    var parent Scope\n    var hasCapturedDefinitions = false\n    var hasCapturingUses = false\n    var environmentObject ObjectSymbol = null\n    var environmentVariable VariableSymbol = null\n    var environmentConstructor FunctionSymbol = null\n    var environmentConstructorCall Node = null\n    const definitions List<Definition> = []\n    const uses List<Use> = []\n    const copies List<Copy> = []\n    const definitionLookup IntMap<Definition> = {}\n    const copyLookup IntMap<Copy> = {}\n\n    def recordDefinition(symbol VariableSymbol, node Node) {\n      assert(!(symbol.id in definitionLookup))\n      var definition = Definition.new(symbol, node, self)\n      definitions.append(definition)\n      definitionLookup[symbol.id] = definition\n    }\n\n    def recordUse(symbol VariableSymbol, node Node) {\n      var isCaptured = false\n\n      # Walk up the scope chain\n      for scope = self; scope != null; scope = scope.parent {\n        var definition = scope.definitionLookup.get(symbol.id, null)\n\n        # Stop once the definition is found\n        if definition != null {\n          uses.append(Use.new(definition, node))\n          if isCaptured {\n            definition.isCaptured = true\n            scope.hasCapturedDefinitions = true\n            hasCapturingUses = true\n          }\n          break\n        }\n\n        # Variables are captured if a lambda is in the scope chain\n        if scope.kind == .LAMBDA {\n          isCaptured = true\n        }\n      }\n    }\n\n    def createReferenceToScope(scope Scope) Node {\n      # Skip to the enclosing scope with an environment\n      var target = self\n      while target.environmentObject == null {\n        assert(!target.hasCapturedDefinitions && target.kind != .LAMBDA)\n        target = target.parent\n      }\n\n      # Reference this scope\n      if scope == target {\n        return Node.createSymbolReference(target.environmentVariable)\n      }\n\n      # Reference a parent scope\n      var copy = target.copyLookup[scope.id]\n      return Node.createMemberReference(\n        Node.createSymbolReference(target.environmentVariable),\n        copy.member)\n    }\n  }\n\n  namespace Scope {\n    var _nextID = 0\n  }\n\n  class Converter {\n    const _global ObjectSymbol\n    const _cache TypeCache\n    const _scopes List<Scope> = []\n    const _stack List<Scope> = []\n    const _interfaces IntMap<ObjectSymbol> = {}\n    const _calls List<Node> = []\n    var _skewNamespace ObjectSymbol = null\n    var _enclosingFunction FunctionSymbol = null\n\n    def run {\n      _visitObject(_global)\n      _convertCalls\n      _convertLambdas\n    }\n\n    def _convertCalls {\n      var swap = Node.createNull\n      for node in _calls {\n        var value = node.callValue\n        var resolvedType = value.resolvedType\n\n        if resolvedType.kind == .LAMBDA {\n          var interfaceType = _interfaceTypeForLambdaType(resolvedType)\n          var interfaceRun = interfaceType.symbol.asObjectSymbol.functions.first\n          assert(interfaceRun.name == \"run\")\n          value.replaceWith(swap)\n          swap.replaceWith(Node.createMemberReference(value, interfaceRun))\n        }\n      }\n    }\n\n    def _convertLambdas {\n      # Propagate required environment copies up the scope chain\n      for scope in _scopes {\n        if scope.hasCapturingUses {\n          for use in scope.uses {\n            if use.definition.isCaptured {\n              var definingScope = use.definition.scope\n              for s = scope; s != definingScope; s = s.parent {\n                if !(definingScope.id in s.copyLookup) {\n                  var copy = Copy.new(definingScope)\n                  s.copies.append(copy)\n                  s.copyLookup[definingScope.id] = copy\n                }\n              }\n            }\n          }\n        }\n      }\n\n      for scope in _scopes {\n        if scope.hasCapturedDefinitions || scope.kind == .LAMBDA {\n          # Create an object to store the environment\n          var object = _createObject(.OBJECT_CLASS, _generateEnvironmentName(scope), _global)\n          var constructor = _createConstructor(object)\n          var constructorCall = Node.createCall(Node.createMemberReference(Node.createSymbolReference(object), constructor)).withType(object.resolvedType)\n\n          # The environment must store all captured variables\n          for definition in scope.definitions {\n            if definition.isCaptured {\n              definition.member = _createInstanceVariable(object.scope.generateName(definition.symbol.name), definition.symbol.resolvedType, object)\n            }\n          }\n\n          # Insert the constructor call declaration\n          switch scope.kind {\n            case .FUNCTION {\n              # Store the environment instance in a variable\n              var variable = _createVariable(.VARIABLE_LOCAL, scope.enclosingFunction.scope.generateName(\"env\"), object.resolvedType)\n              variable.value = constructorCall\n              scope.environmentVariable = variable\n\n              # Define the variable at the top of the function body\n              var variables = Node.createVariables.appendChild(Node.createVariable(variable))\n              scope.node.prependChild(variables) # TODO: Insert this after the call to \"super\"\n\n              # Assign captured arguments and \"self\" to the environment\n              # TODO: Remove the extra indirection to \"self\", copy it directly into environments instead\n              var previous = variables\n              for definition in scope.definitions {\n                if definition.isCaptured && (definition.symbol.kind == .VARIABLE_ARGUMENT || definition.symbol == scope.enclosingFunction.this) {\n                  var assignment = _createAssignment(variable, definition.member, definition.symbol)\n                  scope.node.insertChildAfter(previous, assignment)\n                  previous = assignment\n                }\n              }\n            }\n\n            case .LAMBDA {\n              var function = scope.node.symbol.asFunctionSymbol\n              function.kind = .FUNCTION_INSTANCE\n              function.name = \"run\"\n              function.this = _createVariable(.VARIABLE_LOCAL, \"self\", object.resolvedType)\n              function.parent = object\n              object.functions.append(function)\n              scope.node.become(constructorCall)\n              scope.environmentVariable = function.this\n              constructorCall = scope.node\n\n              # Lambdas introduce two scopes instead of one. All captured\n              # definitions for that lambda have to be in the nested scope,\n              # even lambda function arguments, because that nested scope\n              # needs to be different for each invocation of the lambda.\n              assert(!scope.hasCapturedDefinitions)\n\n              # Implement the lambda interface with the right type parameters\n              var interfaceType = _interfaceTypeForLambdaType(function.resolvedType)\n              var interfaceFunction = interfaceType.symbol.asObjectSymbol.functions.first\n              assert(interfaceFunction.name == \"run\")\n              object.implements = [Node.createType(interfaceType)]\n              object.interfaceTypes = [interfaceType]\n              interfaceFunction.implementations ?= []\n              interfaceFunction.implementations.append(function)\n            }\n\n            case .LOOP {\n              # Store the environment instance in a variable\n              var variable = _createVariable(.VARIABLE_LOCAL, scope.enclosingFunction.scope.generateName(\"env\"), object.resolvedType)\n              variable.value = constructorCall\n              scope.environmentVariable = variable\n\n              # Define the variable at the top of the function body\n              var variables = Node.createVariables.appendChild(Node.createVariable(variable))\n              var node = scope.node\n              var block =\n                node.kind == .FOR ? node.forBlock :\n                node.kind == .FOREACH ? node.foreachBlock :\n                node.kind == .WHILE ? node.whileBlock :\n                null\n              block.prependChild(variables)\n\n              # Assign captured loop variables\n              var previous = variables\n              for definition in scope.definitions {\n                if definition.isCaptured && definition.symbol.isLoopVariable {\n                  var assignment = _createAssignment(variable, definition.member, definition.symbol)\n                  block.insertChildAfter(previous, assignment)\n                  previous = assignment\n                }\n              }\n            }\n\n            default {\n              assert(false)\n            }\n          }\n\n          # These will be referenced later\n          scope.environmentObject = object\n          scope.environmentConstructor = constructor\n          scope.environmentConstructorCall = constructorCall\n        }\n\n        # Mutate the parent scope pointer to skip past irrelevant scopes\n        # (those without environments). This means everything necessary to\n        # access captured symbols can be found on the environment associated\n        # with the parent scope without needing to look at grandparent scopes.\n        #\n        # All parent scopes that need environments should already have them\n        # because scopes are iterated over using a pre-order traversal.\n        while scope.parent != null && scope.parent.environmentObject == null {\n          assert(!scope.parent.hasCapturedDefinitions && scope.parent.kind != .LAMBDA)\n          scope.parent = scope.parent.parent\n        }\n      }\n\n      # Make sure each environment has a copy of each parent environment that it or its children needs\n      for scope in _scopes {\n        var object = scope.environmentObject\n        var constructor = scope.environmentConstructor\n        var constructorCall = scope.environmentConstructorCall\n\n        if object != null {\n          for copy in scope.copies {\n            var name = object.scope.generateName(copy.scope.kind == .LAMBDA ? \"lambda\" : \"env\")\n            var member = _createInstanceVariable(name, copy.scope.environmentObject.resolvedType, object)\n            var argument = _createVariable(.VARIABLE_ARGUMENT, name, member.resolvedType)\n\n            copy.member = member\n            constructor.arguments.append(argument)\n            constructor.resolvedType.argumentTypes.append(argument.resolvedType)\n            constructor.block.appendChild(_createAssignment(constructor.this, member, argument))\n            constructorCall.appendChild(scope.parent.createReferenceToScope(copy.scope))\n          }\n        }\n      }\n\n      for scope in _scopes {\n        # Replace variable definitions of captured symbols with assignments to their environment\n        if scope.hasCapturedDefinitions {\n          for definition in scope.definitions {\n            if definition.isCaptured && definition.node != null {\n              assert(definition.node.kind == .VARIABLE)\n              assert(definition.node.parent.kind == .VARIABLES)\n              definition.node.extractVariableFromVariables\n              definition.node.parent.replaceWith(Node.createExpression(Node.createBinary(.ASSIGN,\n                Node.createMemberReference(Node.createSymbolReference(scope.environmentVariable), definition.member),\n                definition.symbol.value.remove).withType(definition.member.resolvedType)))\n            }\n          }\n        }\n\n        # Replace all references to captured variables with a member access from the appropriate environment\n        for use in scope.uses {\n          if use.definition.isCaptured {\n            use.node.become(Node.createMemberReference(\n              scope.createReferenceToScope(use.definition.scope),\n              use.definition.member))\n          }\n        }\n      }\n    }\n\n    def _visitObject(symbol ObjectSymbol) {\n      for object in symbol.objects {\n        _visitObject(object)\n      }\n\n      for function in symbol.functions {\n        _visitFunction(function)\n      }\n\n      for variable in symbol.variables {\n        _visitVariable(variable)\n      }\n    }\n\n    def _visitFunction(symbol FunctionSymbol) {\n      if symbol.block != null {\n        _enclosingFunction = symbol\n        var scope = _pushScope(.FUNCTION, symbol.block, null)\n\n        if symbol.this != null {\n          scope.recordDefinition(symbol.this, null)\n        }\n\n        for argument in symbol.arguments {\n          scope.recordDefinition(argument, null)\n        }\n\n        _visit(symbol.block)\n        _stack.removeLast\n        _enclosingFunction = null\n      }\n    }\n\n    def _visitVariable(symbol VariableSymbol) {\n      if symbol.value != null {\n        _visit(symbol.value)\n      }\n    }\n\n    def _visit(node Node) {\n      var kind = node.kind\n      var symbol = node.symbol\n      var oldEnclosingFunction = _enclosingFunction\n\n      if kind == .LAMBDA {\n        _enclosingFunction = symbol.asFunctionSymbol\n        var lambdaScope = _pushScope(.LAMBDA, node, _stack.isEmpty ? null : _stack.last)\n        var scope = _pushScope(.FUNCTION, node.lambdaBlock, lambdaScope)\n        for argument in symbol.asFunctionSymbol.arguments {\n          scope.recordDefinition(argument, null)\n        }\n      }\n\n      else if kind == .FOREACH {\n        # Visit loop header\n        _visit(node.foreachValue)\n\n        # Visit loop body\n        var scope = _pushScope(.LOOP, node, _stack.last)\n        scope.recordDefinition(symbol.asVariableSymbol, null)\n        _visit(node.foreachBlock)\n        _stack.removeLast\n        return\n      }\n\n      else if kind == .FOR || kind == .WHILE {\n        _pushScope(.LOOP, node, _stack.last)\n      }\n\n      else if kind == .VARIABLE {\n        _stack.last.recordDefinition(symbol.asVariableSymbol, node)\n      }\n\n      else if kind == .CATCH {\n        # TODO\n      }\n\n      else if kind == .CALL {\n        _calls.append(node)\n      }\n\n      else if kind == .NAME && symbol != null && (symbol.kind == .VARIABLE_ARGUMENT || symbol.kind == .VARIABLE_LOCAL) {\n        _stack.last.recordUse(symbol.asVariableSymbol, node)\n      }\n\n      for child = node.firstChild; child != null; child = child.nextSibling {\n        _visit(child)\n      }\n\n      if kind == .LAMBDA {\n        _stack.removeLast\n        _stack.removeLast\n        _enclosingFunction = oldEnclosingFunction\n      }\n\n      else if kind.isLoop {\n        _stack.removeLast\n      }\n    }\n\n    def _pushScope(kind CaptureKind, node Node, parent Scope) Scope {\n      var scope = Scope.new(kind, node, _enclosingFunction, parent)\n      _scopes.append(scope)\n      _stack.append(scope)\n      return scope\n    }\n\n    def _createObject(kind SymbolKind, name string, parent ObjectSymbol) ObjectSymbol {\n      var object = ObjectSymbol.new(kind, parent.scope.generateName(name))\n      object.scope = ObjectScope.new(parent.scope, object)\n      object.resolvedType = Type.new(.SYMBOL, object)\n      object.state = .INITIALIZED\n      object.parent = parent\n      parent.objects.append(object)\n      return object\n    }\n\n    def _ensureSkewNamespaceExists {\n      if _skewNamespace == null {\n        var symbol = _global.scope.find(\"Skew\", .NORMAL)\n\n        # Did the user's code define the namespace?\n        if symbol != null && symbol.kind.isObject {\n          _skewNamespace = symbol.asObjectSymbol\n        }\n\n        # It's missing or there's a conflict, define one ourselves\n        else {\n          _skewNamespace = _createObject(.OBJECT_NAMESPACE, \"Skew\", _global)\n          _skewNamespace.flags |= .IS_IMPORTED\n        }\n      }\n    }\n\n    def _createInterface(count int, hasReturnType bool) ObjectSymbol {\n      var key = count << 1 | hasReturnType as int\n      var object = _interfaces.get(key, null)\n\n      if object == null {\n        _ensureSkewNamespaceExists\n        object = _createObject(.OBJECT_INTERFACE, (hasReturnType ? \"Fn\" : \"FnVoid\") + count.toString, _skewNamespace)\n        object.flags |= .IS_IMPORTED\n        _interfaces[key] = object\n\n        var function = _createFunction(object, .FUNCTION_INSTANCE, \"run\", .ABSTRACT)\n        function.flags |= .IS_IMPORTED\n        function.resolvedType.argumentTypes = []\n\n        if hasReturnType {\n          var returnType = _createParameter(object, \"R\").resolvedType\n          function.resolvedType.returnType = returnType\n          function.returnType = Node.createType(returnType)\n        }\n\n        for i in 0..count {\n          var parameter = _createParameter(object, \"A\\(i + 1)\")\n          function.arguments.append(_createVariable(.VARIABLE_ARGUMENT, \"a\\(i + 1)\", parameter.resolvedType))\n          function.resolvedType.argumentTypes.append(parameter.resolvedType)\n        }\n      }\n\n      return object\n    }\n\n    def _interfaceTypeForLambdaType(lambdaType Type) Type {\n      var interface = _createInterface(lambdaType.argumentTypes.count, lambdaType.returnType != null)\n      var interfaceType = interface.resolvedType\n      var substitutions List<Type> = []\n      if lambdaType.returnType != null {\n        substitutions.append(lambdaType.returnType)\n      }\n      substitutions.append(lambdaType.argumentTypes)\n      if !substitutions.isEmpty {\n        interfaceType = _cache.substitute(interfaceType, _cache.createEnvironment(interface.parameters, substitutions))\n      }\n      return interfaceType\n    }\n  }\n\n  namespace Converter {\n    def _generateEnvironmentName(scope Scope) string {\n      var name = \"\"\n      var root = scope\n      while root.parent != null {\n        root = root.parent\n      }\n      for symbol Symbol = root.enclosingFunction; symbol != null && symbol.kind != .OBJECT_GLOBAL; symbol = symbol.parent {\n        if symbol.kind != .OBJECT_GLOBAL && !Renaming.isInvalidIdentifier(symbol.name) {\n          name = withUppercaseFirstLetter(symbol.name) + name\n        }\n      }\n      name += scope.kind == .LAMBDA ? \"Lambda\" : \"Env\"\n      return name\n    }\n\n    def _createConstructor(object ObjectSymbol) FunctionSymbol {\n      var function = _createFunction(object, .FUNCTION_CONSTRUCTOR, \"new\", .IMPLEMENTED)\n      function.resolvedType.returnType = object.resolvedType\n      function.returnType = Node.createType(object.resolvedType)\n      return function\n    }\n\n    enum Body {\n      ABSTRACT\n      IMPLEMENTED\n    }\n\n    def _createFunction(object ObjectSymbol, kind SymbolKind, name string, body Body) FunctionSymbol {\n      var function = FunctionSymbol.new(kind, name)\n      function.scope = FunctionScope.new(object.scope, function)\n      function.resolvedType = Type.new(.SYMBOL, function)\n      function.resolvedType.argumentTypes = []\n      function.state = .INITIALIZED\n      function.parent = object\n\n      if body == .IMPLEMENTED {\n        function.block = Node.createBlock\n        function.this = _createVariable(.VARIABLE_LOCAL, \"self\", object.resolvedType)\n      }\n\n      object.functions.append(function)\n      return function\n    }\n\n    def _createInstanceVariable(name string, type Type, object ObjectSymbol) VariableSymbol {\n      var variable = _createVariable(.VARIABLE_INSTANCE, name, type)\n      variable.parent = object\n      object.variables.append(variable)\n      return variable\n    }\n\n    def _createVariable(kind SymbolKind, name string, type Type) VariableSymbol {\n      var variable = VariableSymbol.new(kind, name)\n      variable.initializeWithType(type)\n      return variable\n    }\n\n    def _createParameter(parent ObjectSymbol, name string) ParameterSymbol {\n      var parameter = ParameterSymbol.new(.PARAMETER_OBJECT, name)\n      parameter.resolvedType = Type.new(.SYMBOL, parameter)\n      parameter.state = .INITIALIZED\n      parent.parameters ?= []\n      parent.parameters.append(parameter)\n      return parameter\n    }\n\n    def _createAssignment(object VariableSymbol, member VariableSymbol, variable VariableSymbol) Node {\n      return Node.createExpression(Node.createBinary(.ASSIGN,\n        Node.createMemberReference(Node.createSymbolReference(object), member),\n        Node.createSymbolReference(variable)).withType(member.resolvedType))\n    }\n  }\n}\n"
  },
  {
    "path": "src/middle/library.sk",
    "content": "namespace Skew {\n  const NATIVE_LIBRARY = \"\nconst RELEASE = false\nconst ASSERTS = !RELEASE\n\nenum Target {\n  NONE\n  CPLUSPLUS\n  CSHARP\n  JAVASCRIPT\n}\n\nconst TARGET Target = .NONE\n\ndef @alwaysinline\ndef @deprecated\ndef @deprecated(message string)\ndef @entry\ndef @export\ndef @import\ndef @neverinline\ndef @prefer\ndef @rename(name string)\ndef @skip\ndef @spreads\n\n@spreads {\n  def @using(name string) # For use with C#\n  def @include(name string) # For use with C++\n}\n\n@import if TARGET == .NONE\n@skip if !ASSERTS\ndef assert(truth bool)\n\n@import if TARGET == .NONE\nnamespace Math {\n  @prefer\n  def abs(x double) double\n  def abs(x int) int\n\n  def acos(x double) double\n  def asin(x double) double\n  def atan(x double) double\n  def atan2(x double, y double) double\n\n  def sin(x double) double\n  def cos(x double) double\n  def tan(x double) double\n\n  def floor(x double) double\n  def ceil(x double) double\n  def round(x double) double\n\n  def exp(x double) double\n  def log(x double) double\n  def pow(x double, y double) double\n  def random double\n  def randomInRange(min double, max double) double\n  def randomInRange(minInclusive int, maxExclusive int) int\n  def sqrt(x double) double\n\n  @prefer {\n    def max(x double, y double) double\n    def min(x double, y double) double\n    def max(x double, y double, z double) double\n    def min(x double, y double, z double) double\n    def max(x double, y double, z double, w double) double\n    def min(x double, y double, z double, w double) double\n    def clamp(x double, min double, max double) double\n  }\n\n  def max(x int, y int) int\n  def min(x int, y int) int\n  def max(x int, y int, z int) int\n  def min(x int, y int, z int) int\n  def max(x int, y int, z int, w int) int\n  def min(x int, y int, z int, w int) int\n  def clamp(x int, min int, max int) int\n\n  def E double        { return 2.718281828459045 }\n  def INFINITY double { return 1 / 0.0 }\n  def NAN double      { return 0 / 0.0 }\n  def PI double       { return 3.141592653589793 }\n  def SQRT_2 double   { return 2 ** 0.5 }\n}\n\n@import\nclass bool {\n  def ! bool\n  def toString string\n}\n\n@import\nclass int {\n  def + int\n  def - int\n  def ~ int\n\n  def +(x int) int\n  def -(x int) int\n  def *(x int) int\n  def /(x int) int\n  def %(x int) int\n  def **(x int) int\n  def <=>(x int) int\n  def <<(x int) int\n  def >>(x int) int\n  def >>>(x int) int\n  def &(x int) int\n  def |(x int) int\n  def ^(x int) int\n\n  def %%(x int) int {\n    return ((self % x) + x) % x\n  }\n\n  def <<=(x int) int\n  def >>=(x int) int\n  def &=(x int) int\n  def |=(x int) int\n  def ^=(x int) int\n\n  if TARGET != .CSHARP && TARGET != .CPLUSPLUS {\n    def >>>=(x int)\n  }\n\n  if TARGET != .JAVASCRIPT {\n    def ++ int\n    def -- int\n\n    def %=(x int) int\n    def +=(x int) int\n    def -=(x int) int\n    def *=(x int) int\n    def /=(x int) int\n  }\n\n  def toString string\n}\n\nnamespace int {\n  def MIN int { return -0x7FFFFFFF - 1 }\n  def MAX int { return 0x7FFFFFFF }\n}\n\n@import\nclass double {\n  def + double\n  def ++ double\n  def - double\n  def -- double\n\n  def *(x double) double\n  def +(x double) double\n  def -(x double) double\n  def /(x double) double\n  def **(x double) double\n  def <=>(x double) int\n\n  def %%(x double) double {\n    return self - Math.floor(self / x) * x\n  }\n\n  def *=(x double) double\n  def +=(x double) double\n  def -=(x double) double\n  def /=(x double) double\n\n  def isFinite bool\n  def isNaN bool\n\n  def toString string\n}\n\n@import\nclass string {\n  def +(x string) string\n  def +=(x string) string\n  def <=>(x string) int\n\n  def count int\n  def in(x string) bool\n  def indexOf(x string) int\n  def lastIndexOf(x string) int\n  def startsWith(x string) bool\n  def endsWith(x string) bool\n\n  def [](x int) int\n  def get(x int) string\n  def slice(start int) string\n  def slice(start int, end int) string\n  def codePoints List<int>\n  def codeUnits List<int>\n\n  def split(x string) List<string>\n  def join(x List<string>) string\n  def repeat(x int) string\n  def replaceAll(before string, after string) string\n\n  def toLowerCase string\n  def toUpperCase string\n  def toString string { return self }\n}\n\nnamespace string {\n  def fromCodePoint(x int) string\n  def fromCodePoints(x List<int>) string\n  def fromCodeUnit(x int) string\n  def fromCodeUnits(x List<int>) string\n}\n\n@import if TARGET == .NONE\nclass StringBuilder {\n  def new\n  def append(x string)\n  def toString string\n}\n\n@import\nclass List<T> {\n  def new\n  def [...](x T) List<T>\n\n  def [](x int) T\n  def []=(x int, y T) T\n\n  def count int\n  def isEmpty bool\n  def resize(count int, defaultValue T)\n\n  @prefer\n  def append(x T)\n  def append(x List<T>)\n  def appendOne(x T)\n\n  @prefer\n  def prepend(x T)\n  def prepend(x List<T>)\n\n  @prefer\n  def insert(x int, value T)\n  def insert(x int, values List<T>)\n\n  def removeAll(x T)\n  def removeAt(x int)\n  def removeDuplicates\n  def removeFirst\n  def removeIf(x fn(T) bool)\n  def removeLast\n  def removeOne(x T)\n  def removeRange(start int, end int)\n\n  def takeFirst T\n  def takeLast T\n  def takeAt(x int) T\n  def takeRange(start int, end int) List<T>\n\n  def first T\n  def first=(x T) T { return self[0] = x }\n  def last T\n  def last=(x T) T { return self[count - 1] = x }\n\n  def in(x T) bool\n  def indexOf(x T) int\n  def lastIndexOf(x T) int\n\n  def all(x fn(T) bool) bool\n  def any(x fn(T) bool) bool\n  def clone List<T>\n  def each(x fn(T))\n  def equals(x List<T>) bool\n  def filter(x fn(T) bool) List<T>\n  def map<R>(x fn(T) R) List<R>\n  def reverse\n  def shuffle\n  def slice(start int) List<T>\n  def slice(start int, end int) List<T>\n  def sort(x fn(T, T) int)\n  def swap(x int, y int)\n}\n\n@import\nclass StringMap<T> {\n  def new\n  def {...}(key string, value T) StringMap<T>\n\n  def [](key string) T\n  def []=(key string, value T) T\n\n  def count int\n  def isEmpty bool\n  def keys List<string>\n  def values List<T>\n\n  def clone StringMap<T>\n  def each(x fn(string, T))\n  def get(key string, defaultValue T) T\n  def in(key string) bool\n  def remove(key string)\n}\n\n@import\nclass IntMap<T> {\n  def new\n  def {...}(key int, value T) IntMap<T>\n\n  def [](key int) T\n  def []=(key int, value T) T\n\n  def count int\n  def isEmpty bool\n  def keys List<int>\n  def values List<T>\n\n  def clone IntMap<T>\n  def each(x fn(int, T))\n  def get(key int, defaultValue T) T\n  def in(key int) bool\n  def remove(key int)\n}\n\nclass Box<T> {\n  var value T\n}\n\n################################################################################\n# Implementations\n\nclass int {\n  def **(x int) int {\n    var y = self\n    var z = x < 0 ? 0 : 1\n    while x > 0 {\n      if (x & 1) != 0 { z *= y }\n      x >>= 1\n      y *= y\n    }\n    return z\n  }\n\n  def <=>(x int) int {\n    return ((x < self) as int) - ((x > self) as int)\n  }\n}\n\nclass double {\n  @alwaysinline\n  def **(x double) double {\n    return Math.pow(self, x)\n  }\n\n  def <=>(x double) int {\n    return ((x < self) as int) - ((x > self) as int)\n  }\n}\n\nclass List {\n  def resize(count int, defaultValue T) {\n    assert(count >= 0)\n    while self.count < count { append(defaultValue) }\n    while self.count > count { removeLast }\n  }\n\n  def removeAll(value T) {\n    var index = 0\n\n    # Remove elements in place\n    for i in 0..count {\n      if self[i] != value {\n        if index < i {\n          self[index] = self[i]\n        }\n        index++\n      }\n    }\n\n    # Shrink the array to the correct size\n    while index < count {\n      removeLast\n    }\n  }\n\n  def removeDuplicates {\n    var index = 0\n\n    # Remove elements in place\n    for i in 0..count {\n      var found = false\n      var value = self[i]\n      for j in 0..i {\n        if value == self[j] {\n          found = true\n          break\n        }\n      }\n      if !found {\n        if index < i {\n          self[index] = self[i]\n        }\n        index++\n      }\n    }\n\n    # Shrink the array to the correct size\n    while index < count {\n      removeLast\n    }\n  }\n\n  def shuffle {\n    var n = count\n    for i in 0..n - 1 {\n      swap(i, i + ((Math.random * (n - i)) as int))\n    }\n  }\n\n  def swap(i int, j int) {\n    assert(0 <= i && i < count)\n    assert(0 <= j && j < count)\n    var temp = self[i]\n    self[i] = self[j]\n    self[j] = temp\n  }\n}\n\nnamespace Math {\n  def randomInRange(min double, max double) double {\n    assert(min <= max)\n    var value = min + (max - min) * random\n    assert(min <= value && value <= max)\n    return value\n  }\n\n  def randomInRange(minInclusive int, maxExclusive int) int {\n    assert(minInclusive <= maxExclusive)\n    var value = minInclusive + ((maxExclusive - minInclusive) * random) as int\n    assert(minInclusive <= value && (minInclusive != maxExclusive ? value < maxExclusive : value == maxExclusive))\n    return value\n  }\n\n  if TARGET != .JAVASCRIPT {\n    def max(x double, y double, z double) double {\n      return max(max(x, y), z)\n    }\n\n    def min(x double, y double, z double) double {\n      return min(min(x, y), z)\n    }\n\n    def max(x int, y int, z int) int {\n      return max(max(x, y), z)\n    }\n\n    def min(x int, y int, z int) int {\n      return min(min(x, y), z)\n    }\n\n    def max(x double, y double, z double, w double) double {\n      return max(max(x, y), max(z, w))\n    }\n\n    def min(x double, y double, z double, w double) double {\n      return min(min(x, y), min(z, w))\n    }\n\n    def max(x int, y int, z int, w int) int {\n      return max(max(x, y), max(z, w))\n    }\n\n    def min(x int, y int, z int, w int) int {\n      return min(min(x, y), min(z, w))\n    }\n  }\n\n  def clamp(x double, min double, max double) double {\n    return x < min ? min : x > max ? max : x\n  }\n\n  def clamp(x int, min int, max int) int {\n    return x < min ? min : x > max ? max : x\n  }\n}\n\"\n}\n"
  },
  {
    "path": "src/middle/librarycpp.sk",
    "content": "namespace Skew {\n  const NATIVE_LIBRARY_CPP = \"\n@import {\n  def __doubleToString(x double) string\n  def __intToString(x int) string\n\n  @rename(\\\"std::isnan\\\")\n  def __doubleIsNaN(x double) bool\n\n  @rename(\\\"std::isfinite\\\")\n  def __doubleIsFinite(x double) bool\n}\n\nclass bool {\n  def toString string {\n    return self ? \\\"true\\\" : \\\"false\\\"\n  }\n}\n\nclass int {\n  def toString string {\n    return __intToString(self)\n  }\n\n  def >>>(x int) int {\n    return (self as dynamic.unsigned >> x) as int\n  }\n}\n\nclass double {\n  def toString string {\n    return __doubleToString(self)\n  }\n\n  def isNaN bool {\n    return __doubleIsNaN(self)\n  }\n\n  def isFinite bool {\n    return __doubleIsFinite(self)\n  }\n}\n\nclass string {\n  @rename(\\\"compare\\\")\n  def <=>(x string) int\n\n  @rename(\\\"contains\\\")\n  def in(x string) bool\n}\n\n@rename(\\\"Skew::List\\\")\nclass List {\n  @rename(\\\"contains\\\")\n  def in(x T) bool\n}\n\n@rename(\\\"Skew::StringMap\\\")\nclass StringMap {\n  @rename(\\\"contains\\\")\n  def in(x string) bool\n}\n\n@rename(\\\"Skew::IntMap\\\")\nclass IntMap {\n  @rename(\\\"contains\\\")\n  def in(x int) bool\n}\n\n@import\n@rename(\\\"Skew::StringBuilder\\\")\nclass StringBuilder {\n}\n\n@import\n@rename(\\\"Skew::Math\\\")\nnamespace Math {\n}\n\n@import\ndef assert(truth bool)\n\"\n}\n"
  },
  {
    "path": "src/middle/librarycs.sk",
    "content": "namespace Skew {\n  const NATIVE_LIBRARY_CS = \"\n@using(\\\"System.Diagnostics\\\")\ndef assert(truth bool) {\n  dynamic.Debug.Assert(truth)\n}\n\n@using(\\\"System\\\")\nvar __random dynamic.Random = null\n\n@using(\\\"System\\\")\n@import\nnamespace Math {\n  @rename(\\\"Abs\\\") if TARGET == .CSHARP\n  def abs(x double) double\n  @rename(\\\"Abs\\\") if TARGET == .CSHARP\n  def abs(x int) int\n\n  @rename(\\\"Acos\\\") if TARGET == .CSHARP\n  def acos(x double) double\n  @rename(\\\"Asin\\\") if TARGET == .CSHARP\n  def asin(x double) double\n  @rename(\\\"Atan\\\") if TARGET == .CSHARP\n  def atan(x double) double\n  @rename(\\\"Atan2\\\") if TARGET == .CSHARP\n  def atan2(x double, y double) double\n\n  @rename(\\\"Sin\\\") if TARGET == .CSHARP\n  def sin(x double) double\n  @rename(\\\"Cos\\\") if TARGET == .CSHARP\n  def cos(x double) double\n  @rename(\\\"Tan\\\") if TARGET == .CSHARP\n  def tan(x double) double\n\n  @rename(\\\"Floor\\\") if TARGET == .CSHARP\n  def floor(x double) double\n  @rename(\\\"Ceiling\\\") if TARGET == .CSHARP\n  def ceil(x double) double\n  @rename(\\\"Round\\\") if TARGET == .CSHARP\n  def round(x double) double\n\n  @rename(\\\"Exp\\\") if TARGET == .CSHARP\n  def exp(x double) double\n  @rename(\\\"Log\\\") if TARGET == .CSHARP\n  def log(x double) double\n  @rename(\\\"Pow\\\") if TARGET == .CSHARP\n  def pow(x double, y double) double\n  @rename(\\\"Sqrt\\\") if TARGET == .CSHARP\n  def sqrt(x double) double\n\n  @rename(\\\"Max\\\") if TARGET == .CSHARP\n  def max(x double, y double) double\n  @rename(\\\"Max\\\") if TARGET == .CSHARP\n  def max(x int, y int) int\n\n  @rename(\\\"Min\\\") if TARGET == .CSHARP\n  def min(x double, y double) double\n  @rename(\\\"Min\\\") if TARGET == .CSHARP\n  def min(x int, y int) int\n\n  def random double {\n    __random ?= dynamic.Random.new()\n    return __random.NextDouble()\n  }\n}\n\nclass double {\n  def isFinite bool {\n    return !isNaN && !dynamic.double.IsInfinity(self)\n  }\n\n  def isNaN bool {\n    return dynamic.double.IsNaN(self)\n  }\n}\n\n@using(\\\"System.Text\\\")\n@import\nclass StringBuilder {\n  @rename(\\\"Append\\\")\n  def append(x string)\n\n  @rename(\\\"ToString\\\")\n  def toString string\n}\n\nclass bool {\n  @rename(\\\"ToString\\\")\n  def toString string {\n    return self ? \\\"true\\\" : \\\"false\\\"\n  }\n}\n\nclass int {\n  @rename(\\\"ToString\\\")\n  def toString string\n\n  def >>>(x int) int {\n    return dynamic.unchecked(self as dynamic.uint >> x) as int\n  }\n}\n\nclass double {\n  @rename(\\\"ToString\\\")\n  def toString string\n}\n\nclass string {\n  @rename(\\\"CompareTo\\\")\n  def <=>(x string) int\n\n  @rename(\\\"StartsWith\\\")\n  def startsWith(x string) bool\n\n  @rename(\\\"EndsWith\\\")\n  def endsWith(x string) bool\n\n  @rename(\\\"Contains\\\")\n  def in(x string) bool\n\n  @rename(\\\"IndexOf\\\")\n  def indexOf(x string) int\n\n  @rename(\\\"LastIndexOf\\\")\n  def lastIndexOf(x string) int\n\n  @rename(\\\"Replace\\\")\n  def replaceAll(before string, after string) string\n\n  @rename(\\\"Substring\\\") {\n    def slice(start int) string\n    def slice(start int, end int) string\n  }\n\n  @rename(\\\"ToLower\\\")\n  def toLowerCase string\n\n  @rename(\\\"ToUpper\\\")\n  def toUpperCase string\n\n  def count int {\n    return (self as dynamic).Length\n  }\n\n  def get(index int) string {\n    return fromCodeUnit(self[index])\n  }\n\n  def repeat(times int) string {\n    var result = \\\"\\\"\n    for i in 0..times {\n      result += self\n    }\n    return result\n  }\n\n  @using(\\\"System.Linq\\\")\n  @using(\\\"System\\\")\n  def split(separator string) List<string> {\n    var separators = [separator]\n    return dynamic.Enumerable.ToList((self as dynamic).Split(dynamic.Enumerable.ToArray(separators as dynamic), dynamic.StringSplitOptions.None))\n  }\n\n  def join(parts List<string>) string {\n    return dynamic.string.Join(self, parts)\n  }\n\n  def slice(start int, end int) string {\n    return (self as dynamic).Substring(start, end - start)\n  }\n\n  def codeUnits List<int> {\n    var result List<int> = []\n    for i in 0..count {\n      result.append(self[i])\n    }\n    return result\n  }\n}\n\nnamespace string {\n  def fromCodeUnit(codeUnit int) string {\n    return dynamic.string.new(codeUnit as dynamic.char, 1)\n  }\n\n  def fromCodeUnits(codeUnits List<int>) string {\n    var builder = StringBuilder.new\n    for codeUnit in codeUnits {\n      builder.append(codeUnit as dynamic.char)\n    }\n    return builder.toString\n  }\n}\n\n@using(\\\"System.Collections.Generic\\\")\nclass List {\n  @rename(\\\"Contains\\\")\n  def in(x T) bool\n\n  @rename(\\\"Add\\\")\n  def append(value T)\n\n  @rename(\\\"AddRange\\\")\n  def append(value List<T>)\n\n  def sort(x fn(T, T) int) {\n    # C# doesn't allow an anonymous function to be passed directly\n    (self as dynamic).Sort((a T, b T) => x(a, b))\n  }\n\n  @rename(\\\"Reverse\\\")\n  def reverse\n\n  @rename(\\\"RemoveAll\\\")\n  def removeIf(x fn(T) bool)\n\n  @rename(\\\"RemoveAt\\\")\n  def removeAt(x int)\n\n  @rename(\\\"Remove\\\")\n  def removeOne(x T)\n\n  @rename(\\\"TrueForAll\\\")\n  def all(x fn(T) bool) bool\n\n  @rename(\\\"ForEach\\\")\n  def each(x fn(T))\n\n  @rename(\\\"FindAll\\\")\n  def filter(x fn(T) bool) List<T>\n\n  @rename(\\\"ConvertAll\\\")\n  def map<R>(x fn(T) R) List<R>\n\n  @rename(\\\"IndexOf\\\")\n  def indexOf(x T) int\n\n  @rename(\\\"LastIndexOf\\\")\n  def lastIndexOf(x T) int\n\n  @rename(\\\"Insert\\\")\n  def insert(x int, value T)\n\n  @rename(\\\"InsertRange\\\")\n  def insert(x int, value List<T>)\n\n  def appendOne(x T) {\n    if !(x in self) {\n      append(x)\n    }\n  }\n\n  def removeRange(start int, end int) {\n    (self as dynamic).RemoveRange(start, end - start)\n  }\n\n  @using(\\\"System.Linq\\\") {\n    @rename(\\\"SequenceEqual\\\")\n    def equals(x List<T>) bool\n\n    @rename(\\\"First\\\")\n    def first T\n\n    @rename(\\\"Last\\\")\n    def last T\n  }\n\n  def any(callback fn(T) bool) bool {\n    return !all(x => !callback(x))\n  }\n\n  def isEmpty bool {\n    return count == 0\n  }\n\n  def count int {\n    return (self as dynamic).Count\n  }\n\n  def prepend(value T) {\n    insert(0, value)\n  }\n\n  def prepend(values List<T>) {\n    var count = values.count\n    for i in 0..count {\n      prepend(values[count - i - 1])\n    }\n  }\n\n  def removeFirst {\n    removeAt(0)\n  }\n\n  def removeLast {\n    removeAt(count - 1)\n  }\n\n  def takeFirst T {\n    var value = first\n    removeFirst\n    return value\n  }\n\n  def takeLast T {\n    var value = last\n    removeLast\n    return value\n  }\n\n  def takeAt(x int) T {\n    var value = self[x]\n    removeAt(x)\n    return value\n  }\n\n  def takeRange(start int, end int) List<T> {\n    var value = slice(start, end)\n    removeRange(start, end)\n    return value\n  }\n\n  def slice(start int) List<T> {\n    return slice(start, count)\n  }\n\n  def slice(start int, end int) List<T> {\n    return (self as dynamic).GetRange(start, end - start)\n  }\n\n  def clone List<T> {\n    var clone = new\n    clone.append(self)\n    return clone\n  }\n}\n\n@using(\\\"System.Collections.Generic\\\")\n@rename(\\\"Dictionary\\\")\nclass StringMap {\n  def count int {\n    return (self as dynamic).Count\n  }\n\n  @rename(\\\"ContainsKey\\\")\n  def in(key string) bool\n\n  @rename(\\\"Remove\\\")\n  def remove(key string)\n\n  def isEmpty bool {\n    return count == 0\n  }\n\n  def {...}(key string, value T) StringMap<T> {\n    (self as dynamic).Add(key, value)\n    return self\n  }\n\n  def get(key string, value T) T {\n    return key in self ? self[key] : value\n  }\n\n  def keys List<string> {\n    return dynamic.System.Linq.Enumerable.ToList((self as dynamic).Keys)\n  }\n\n  def values List<T> {\n    return dynamic.System.Linq.Enumerable.ToList((self as dynamic).Values)\n  }\n\n  def clone StringMap<T> {\n    var clone = new\n    for key in keys {\n      clone[key] = self[key]\n    }\n    return clone\n  }\n\n  def each(x fn(string, T)) {\n    for pair in self as dynamic {\n      x(pair.Key, pair.Value)\n    }\n  }\n}\n\n@using(\\\"System.Collections.Generic\\\")\n@rename(\\\"Dictionary\\\")\nclass IntMap {\n  def count int {\n    return (self as dynamic).Count\n  }\n\n  @rename(\\\"ContainsKey\\\")\n  def in(key int) bool\n\n  @rename(\\\"Remove\\\")\n  def remove(key int)\n\n  def isEmpty bool {\n    return count == 0\n  }\n\n  def {...}(key int, value T) IntMap<T> {\n    (self as dynamic).Add(key, value)\n    return self\n  }\n\n  def get(key int, value T) T {\n    return key in self ? self[key] : value\n  }\n\n  def keys List<int> {\n    return dynamic.System.Linq.Enumerable.ToList((self as dynamic).Keys)\n  }\n\n  def values List<T> {\n    return dynamic.System.Linq.Enumerable.ToList((self as dynamic).Values)\n  }\n\n  def clone IntMap<T> {\n    var clone = new\n    for key in keys {\n      clone[key] = self[key]\n    }\n    return clone\n  }\n\n  def each(x fn(int, T)) {\n    for pair in self as dynamic {\n      x(pair.Key, pair.Value)\n    }\n  }\n}\n\"\n}\n"
  },
  {
    "path": "src/middle/libraryjs.sk",
    "content": "namespace Skew {\n  const NATIVE_LIBRARY_JS = \"\nconst __create fn(dynamic) dynamic = dynamic.Object.create ? dynamic.Object.create : prototype => {\n  return {\\\"__proto__\\\": prototype}\n}\n\nconst __extends = (derived dynamic, base dynamic) => {\n  derived.prototype = __create(base.prototype)\n  derived.prototype.constructor = derived\n}\n\nconst __imul fn(int, int) int = dynamic.Math.imul ? dynamic.Math.imul : (a, b) => {\n  return ((a as dynamic) * (b >>> 16) << 16) + (a as dynamic) * (b & 65535) | 0\n}\n\nconst __prototype dynamic\nconst __isInt = (value dynamic) => value == (value | 0)\nconst __isBool = (value dynamic) => value == !!value\nconst __isDouble = (value dynamic) => dynamic.typeof(value) == \\\"number\\\"\nconst __isString = (value dynamic) => dynamic.typeof(value) == \\\"string\\\"\nconst __asString = (value dynamic) => value == null ? value : value + \\\"\\\"\n\ndef assert(truth bool) {\n  if !truth {\n    throw dynamic.Error(\\\"Assertion failed\\\")\n  }\n}\n\n# Override this to true to remove asserts from many of the functions below so that they may be inlined\nconst JS_INLINE_NATIVE = false\n\n@import\nnamespace Math {}\n\n@rename(\\\"boolean\\\")\nclass bool {}\n\n@rename(\\\"number\\\")\nclass int {}\n\n@rename(\\\"number\\\")\nclass double {\n  @alwaysinline\n  def isFinite bool {\n    return dynamic.isFinite(self)\n  }\n\n  @alwaysinline\n  def isNaN bool {\n    return dynamic.isNaN(self)\n  }\n}\n\nclass string {\n  def <=>(x string) int {\n    return ((x as dynamic < self) as int) - ((x as dynamic > self) as int)\n  }\n\n  if JS_INLINE_NATIVE {\n    @alwaysinline\n    def slice(start int) string {\n      return (self as dynamic).slice(start)\n    }\n  } else {\n    def slice(start int) string {\n      assert(0 <= start && start <= count)\n      return (self as dynamic).slice(start)\n    }\n  }\n\n  if JS_INLINE_NATIVE {\n    @alwaysinline\n    def slice(start int, end int) string {\n      return (self as dynamic).slice(start, end)\n    }\n  } else {\n    def slice(start int, end int) string {\n      assert(0 <= start && start <= end && end <= count)\n      return (self as dynamic).slice(start, end)\n    }\n  }\n\n  @alwaysinline\n  def startsWith(text string) bool {\n    return (self as dynamic).startsWith(text)\n  }\n\n  @alwaysinline\n  def endsWith(text string) bool {\n    return (self as dynamic).endsWith(text)\n  }\n\n  @alwaysinline\n  def replaceAll(before string, after string) string {\n    return after.join(self.split(before))\n  }\n\n  @alwaysinline\n  def in(value string) bool {\n    return indexOf(value) != -1\n  }\n\n  @alwaysinline\n  def count int {\n    return (self as dynamic).length\n  }\n\n  if JS_INLINE_NATIVE {\n    @alwaysinline\n    def [](index int) int {\n      return (self as dynamic).charCodeAt(index)\n    }\n  } else {\n    def [](index int) int {\n      assert(0 <= index && index < count)\n      return (self as dynamic).charCodeAt(index)\n    }\n  }\n\n  if JS_INLINE_NATIVE {\n    @alwaysinline\n    def get(index int) string {\n      return (self as dynamic)[index]\n    }\n  } else {\n    def get(index int) string {\n      assert(0 <= index && index < count)\n      return (self as dynamic)[index]\n    }\n  }\n\n  def repeat(times int) string {\n    var result = \\\"\\\"\n    for i in 0..times {\n      result += self\n    }\n    return result\n  }\n\n  @alwaysinline\n  def join(parts List<string>) string {\n    return (parts as dynamic).join(self)\n  }\n\n  def codeUnits List<int> {\n    var result List<int> = []\n    for i in 0..count {\n      result.append(self[i])\n    }\n    return result\n  }\n}\n\nnamespace string {\n  @alwaysinline\n  def fromCodeUnit(codeUnit int) string {\n    return dynamic.String.fromCharCode(codeUnit)\n  }\n\n  def fromCodeUnits(codeUnits List<int>) string {\n    var result = \\\"\\\"\n    for codeUnit in codeUnits {\n      result += string.fromCodeUnit(codeUnit)\n    }\n    return result\n  }\n}\n\nclass StringBuilder {\n  var buffer = \\\"\\\"\n\n  def new {\n  }\n\n  @alwaysinline\n  def append(x string) {\n    buffer += x\n  }\n\n  @alwaysinline\n  def toString string {\n    return buffer\n  }\n}\n\n@rename(\\\"Array\\\")\nclass List {\n  @rename(\\\"unshift\\\")\n  def prepend(x T)\n\n  @rename(\\\"push\\\")\n  def append(x T)\n\n  @rename(\\\"every\\\")\n  def all(x fn(T) bool) bool\n\n  @rename(\\\"some\\\")\n  def any(x fn(T) bool) bool\n\n  @rename(\\\"slice\\\")\n  def clone List<T>\n\n  @rename(\\\"forEach\\\")\n  def each(x fn(T))\n\n  if JS_INLINE_NATIVE {\n    @alwaysinline\n    def slice(start int) List<T> {\n      return (self as dynamic).slice(start)\n    }\n  } else {\n    def slice(start int) List<T> {\n      assert(0 <= start && start <= count)\n      return (self as dynamic).slice(start)\n    }\n  }\n\n  if JS_INLINE_NATIVE {\n    @alwaysinline\n    def slice(start int, end int) List<T> {\n      return (self as dynamic).slice(start, end)\n    }\n  } else {\n    def slice(start int, end int) List<T> {\n      assert(0 <= start && start <= end && end <= count)\n      return (self as dynamic).slice(start, end)\n    }\n  }\n\n  if JS_INLINE_NATIVE {\n    @alwaysinline\n    def [](index int) T {\n      return (self as dynamic)[index]\n    }\n  } else {\n    def [](index int) T {\n      assert(0 <= index && index < count)\n      return (self as dynamic)[index]\n    }\n  }\n\n  if JS_INLINE_NATIVE {\n    @alwaysinline\n    def []=(index int, value T) T {\n      return (self as dynamic)[index] = value\n    }\n  } else {\n    def []=(index int, value T) T {\n      assert(0 <= index && index < count)\n      return (self as dynamic)[index] = value\n    }\n  }\n\n  @alwaysinline\n  def in(value T) bool {\n    return indexOf(value) != -1\n  }\n\n  @alwaysinline\n  def isEmpty bool {\n    return count == 0\n  }\n\n  @alwaysinline\n  def count int {\n    return (self as dynamic).length\n  }\n\n  if JS_INLINE_NATIVE {\n    @alwaysinline\n    def first T {\n      return self[0]\n    }\n  } else {\n    def first T {\n      assert(!isEmpty)\n      return self[0]\n    }\n  }\n\n  def last T {\n    assert(!isEmpty)\n    return self[count - 1]\n  }\n\n  def prepend(values List<T>) {\n    assert(values != self)\n    var count = values.count\n    for i in 0..count {\n      prepend(values[count - i - 1])\n    }\n  }\n\n  def append(values List<T>) {\n    assert(values != self)\n    for value in values {\n      append(value)\n    }\n  }\n\n  def insert(index int, values List<T>) {\n    assert(values != self)\n    for value in values {\n      insert(index, value)\n      index++\n    }\n  }\n\n  def insert(index int, value T) {\n    assert(0 <= index && index <= count)\n    (self as dynamic).splice(index, 0, value)\n  }\n\n  def removeFirst {\n    assert(!isEmpty)\n    (self as dynamic).shift()\n  }\n\n  if JS_INLINE_NATIVE {\n    @alwaysinline\n    def takeFirst T {\n      return (self as dynamic).shift()\n    }\n  } else {\n    def takeFirst T {\n      assert(!isEmpty)\n      return (self as dynamic).shift()\n    }\n  }\n\n  def removeLast {\n    assert(!isEmpty)\n    (self as dynamic).pop()\n  }\n\n  if JS_INLINE_NATIVE {\n    @alwaysinline\n    def takeLast T {\n      return (self as dynamic).pop()\n    }\n  } else {\n    def takeLast T {\n      assert(!isEmpty)\n      return (self as dynamic).pop()\n    }\n  }\n\n  def removeAt(index int) {\n    assert(0 <= index && index < count)\n    (self as dynamic).splice(index, 1)\n  }\n\n  if JS_INLINE_NATIVE {\n    @alwaysinline\n    def takeAt(index int) T {\n      return (self as dynamic).splice(index, 1)[0]\n    }\n  } else {\n    def takeAt(index int) T {\n      assert(0 <= index && index < count)\n      return (self as dynamic).splice(index, 1)[0]\n    }\n  }\n\n  def takeRange(start int, end int) List<T> {\n    assert(0 <= start && start <= end && end <= count)\n    return (self as dynamic).splice(start, end - start)\n  }\n\n  def appendOne(value T) {\n    if !(value in self) {\n      append(value)\n    }\n  }\n\n  def removeOne(value T) {\n    var index = indexOf(value)\n    if index >= 0 {\n      removeAt(index)\n    }\n  }\n\n  def removeRange(start int, end int) {\n    assert(0 <= start && start <= end && end <= count)\n    (self as dynamic).splice(start, end - start)\n  }\n\n  def removeIf(callback fn(T) bool) {\n    var index = 0\n\n    # Remove elements in place\n    for i in 0..count {\n      if !callback(self[i]) {\n        if index < i {\n          self[index] = self[i]\n        }\n        index++\n      }\n    }\n\n    # Shrink the array to the correct size\n    while index < count {\n      removeLast\n    }\n  }\n\n  def equals(other List<T>) bool {\n    if count != other.count {\n      return false\n    }\n    for i in 0..count {\n      if self[i] != other[i] {\n        return false\n      }\n    }\n    return true\n  }\n}\n\nnamespace List {\n  @alwaysinline\n  def new List<T> {\n    return [] as dynamic\n  }\n}\n\nnamespace StringMap {\n  @alwaysinline\n  def new StringMap<T> {\n    return dynamic.Map.new\n  }\n}\n\nclass StringMap {\n  if JS_INLINE_NATIVE {\n    @alwaysinline\n    def [](key string) T {\n      return (self as dynamic).get(key)\n    }\n  } else {\n    def [](key string) T {\n      assert(key in self)\n      return (self as dynamic).get(key)\n    }\n  }\n\n  def []=(key string, value T) T {\n    (self as dynamic).set(key, value)\n    return value\n  }\n\n  def {...}(key string, value T) StringMap<T> {\n    (self as dynamic).set(key, value)\n    return self\n  }\n\n  @alwaysinline\n  def in(key string) bool {\n    return (self as dynamic).has(key)\n  }\n\n  @alwaysinline\n  def count int {\n    return (self as dynamic).size\n  }\n\n  @alwaysinline\n  def isEmpty bool {\n    return count == 0\n  }\n\n  def get(key string, defaultValue T) T {\n    const value = (self as dynamic).get(key)\n    return value != dynamic.void(0) ? value : defaultValue # Compare against undefined so the key is only hashed once for speed\n  }\n\n  @alwaysinline\n  def keys List<string> {\n    return dynamic.Array.from((self as dynamic).keys())\n  }\n\n  @alwaysinline\n  def values List<T> {\n    return dynamic.Array.from((self as dynamic).values())\n  }\n\n  @alwaysinline\n  def clone StringMap<T> {\n    return dynamic.Map.new(self)\n  }\n\n  @alwaysinline\n  def remove(key string) {\n    (self as dynamic).delete(key)\n  }\n\n  def each(x fn(string, T)) {\n    (self as dynamic).forEach((value, key) => {\n      x(key, value)\n    })\n  }\n}\n\nnamespace IntMap {\n  @alwaysinline\n  def new IntMap<T> {\n    return dynamic.Map.new\n  }\n}\n\nclass IntMap {\n  if JS_INLINE_NATIVE {\n    @alwaysinline\n    def [](key int) T {\n      return (self as dynamic).get(key)\n    }\n  } else {\n    def [](key int) T {\n      assert(key in self)\n      return (self as dynamic).get(key)\n    }\n  }\n\n  def []=(key int, value T) T {\n    (self as dynamic).set(key, value)\n    return value\n  }\n\n  def {...}(key int, value T) IntMap<T> {\n    (self as dynamic).set(key, value)\n    return self\n  }\n\n  @alwaysinline\n  def in(key int) bool {\n    return (self as dynamic).has(key)\n  }\n\n  @alwaysinline\n  def count int {\n    return (self as dynamic).size\n  }\n\n  @alwaysinline\n  def isEmpty bool {\n    return count == 0\n  }\n\n  def get(key int, defaultValue T) T {\n    const value = (self as dynamic).get(key)\n    return value != dynamic.void(0) ? value : defaultValue # Compare against undefined so the key is only hashed once for speed\n  }\n\n  @alwaysinline\n  def keys List<int> {\n    return dynamic.Array.from((self as dynamic).keys())\n  }\n\n  @alwaysinline\n  def values List<T> {\n    return dynamic.Array.from((self as dynamic).values())\n  }\n\n  @alwaysinline\n  def clone IntMap<T> {\n    return dynamic.Map.new(self)\n  }\n\n  @alwaysinline\n  def remove(key int) {\n    (self as dynamic).delete(key)\n  }\n\n  def each(x fn(int, T)) {\n    (self as dynamic).forEach((value, key) => {\n      x(key, value)\n    })\n  }\n}\n\"\n}\n"
  },
  {
    "path": "src/middle/merging.sk",
    "content": "namespace Skew {\n  enum PassKind {\n    MERGING\n  }\n\n  class MergingPass : Pass {\n    over kind PassKind {\n      return .MERGING\n    }\n\n    over run(context PassContext) {\n      Merging.mergeObject(context.log, null, context.global, context.global)\n    }\n  }\n}\n\nnamespace Skew.Merging {\n  def mergeObject(log Log, parent ObjectSymbol, target ObjectSymbol, symbol ObjectSymbol) {\n    target.scope = ObjectScope.new(parent?.scope, target)\n    symbol.scope = target.scope\n    symbol.parent = parent\n\n    # This is a heuristic for getting the range to be from the primary definition\n    if symbol.kind == target.kind && symbol.variables.count > target.variables.count {\n      target.range = symbol.range\n    }\n\n    if symbol.parameters != null {\n      for parameter in symbol.parameters {\n        parameter.scope = parent.scope\n        parameter.parent = target\n\n        # Type parameters cannot merge with any members\n        var other = target.members.get(parameter.name, null)\n        if other != null {\n          log.semanticErrorDuplicateSymbol(parameter.range, parameter.name, other.range)\n          continue\n        }\n\n        target.members[parameter.name] = parameter\n      }\n    }\n\n    mergeObjects(log, target, symbol.objects)\n    mergeFunctions(log, target, symbol.functions, .NORMAL)\n    mergeVariables(log, target, symbol.variables)\n  }\n\n  def mergeObjects(log Log, parent ObjectSymbol, children List<ObjectSymbol>) {\n    var members = parent.members\n    children.removeIf(child => {\n      var other = members.get(child.name, null)\n\n      # Simple case: no merging\n      if other == null {\n        members[child.name] = child\n        mergeObject(log, parent, child, child)\n        return false\n      }\n\n      # Can only merge with another of the same kind or with a namespace\n      if other.kind == .OBJECT_NAMESPACE {\n        var swap = other.range\n        other.range = child.range\n        child.range = swap\n        other.kind = child.kind\n      } else if child.kind == .OBJECT_NAMESPACE {\n        child.kind = other.kind\n      } else if child.kind != other.kind {\n        log.semanticErrorDuplicateSymbol(child.range, child.name, other.range)\n        return true\n      }\n\n      # Classes can only have one base type\n      var object = other.asObjectSymbol\n      if child.extends != null {\n        if object.extends != null {\n          log.semanticErrorDuplicateBaseType(child.extends.range, child.name, object.extends.range)\n          return true\n        }\n        object.extends = child.extends\n      }\n\n      # Merge base interfaces\n      if child.implements != null {\n        if object.implements != null {\n          object.implements.append(child.implements)\n        } else {\n          object.implements = child.implements\n        }\n      }\n\n      # Cannot merge two objects that both have type parameters\n      if child.parameters != null && object.parameters != null {\n        log.semanticErrorDuplicateTypeParameters(rangeOfParameters(child.parameters), child.name, rangeOfParameters(object.parameters))\n        return true\n      }\n\n      # Merge \"child\" into \"other\"\n      mergeObject(log, parent, object, child)\n      object.mergeInformationFrom(child)\n      object.objects.append(child.objects)\n      object.functions.append(child.functions)\n      object.variables.append(child.variables)\n      if child.parameters != null {\n        object.parameters = child.parameters\n      }\n      if child.guards != null {\n        object.guards ?= []\n        for guard in child.guards {\n          for g = guard; g != null; g = g.elseGuard {\n            g.parent = object\n            g.contents.parent = object\n          }\n          object.guards.append(guard)\n        }\n      }\n      return true\n    })\n  }\n\n  enum MergeBehavior {\n    NORMAL\n    INTO_DERIVED_CLASS\n  }\n\n  def mergeFunctions(log Log, parent ObjectSymbol, children List<FunctionSymbol>, behavior MergeBehavior) {\n    var members = parent.members\n\n    for child in children {\n      var other = members.get(child.name, null)\n\n      # Create a scope for this function's type parameters\n      if behavior == .NORMAL {\n        var scope = FunctionScope.new(parent.scope, child)\n        child.scope = scope\n        child.parent = parent\n\n        if child.parameters != null {\n          for parameter in child.parameters {\n            parameter.scope = scope\n            parameter.parent = child\n\n            # Type parameters cannot merge with other parameters on this function\n            var previous = scope.parameters.get(parameter.name, null)\n            if previous != null {\n              log.semanticErrorDuplicateSymbol(parameter.range, parameter.name, previous.range)\n              continue\n            }\n\n            scope.parameters[parameter.name] = parameter\n          }\n        }\n      }\n\n      # Simple case: no merging\n      if other == null {\n        members[child.name] = child\n        continue\n      }\n\n      var childKind = overloadedKind(child.kind)\n      var otherKind = overloadedKind(other.kind)\n\n      # Merge with another symbol of the same overloaded group type\n      if childKind != otherKind || !childKind.isOverloadedFunction {\n        if behavior == .NORMAL {\n          log.semanticErrorDuplicateSymbol(child.range, child.name, other.range)\n        } else {\n          log.semanticErrorBadOverride(other.range, other.name, parent.baseType, child.range)\n        }\n        continue\n      }\n\n      # Merge with a group of overloaded functions\n      if other.kind.isOverloadedFunction {\n        other.asOverloadedFunctionSymbol.symbols.append(child)\n        if behavior == .NORMAL {\n          child.overloaded = other.asOverloadedFunctionSymbol\n        }\n        continue\n      }\n\n      # Create an overload group\n      var overloaded = OverloadedFunctionSymbol.new(childKind, child.name, [other.asFunctionSymbol, child])\n      members[child.name] = overloaded\n      other.asFunctionSymbol.overloaded = overloaded\n      if behavior == .NORMAL {\n        child.overloaded = overloaded\n      }\n      overloaded.scope = parent.scope\n      overloaded.parent = parent\n    }\n  }\n\n  def overloadedKind(kind SymbolKind) SymbolKind {\n    return\n      kind == .FUNCTION_CONSTRUCTOR || kind == .FUNCTION_GLOBAL ? .OVERLOADED_GLOBAL :\n      kind == .FUNCTION_ANNOTATION ? .OVERLOADED_ANNOTATION :\n      kind == .FUNCTION_INSTANCE ? .OVERLOADED_INSTANCE :\n      kind\n  }\n\n  def mergeVariables(log Log, parent ObjectSymbol, children List<VariableSymbol>) {\n    var members = parent.members\n\n    for child in children {\n      var other = members.get(child.name, null)\n      child.scope = VariableScope.new(parent.scope, child)\n      child.parent = parent\n\n      # Variables never merge\n      if other != null {\n        log.semanticErrorDuplicateSymbol(child.range, child.name, other.range)\n        continue\n      }\n\n      members[child.name] = child\n    }\n  }\n\n  def rangeOfParameters(parameters List<ParameterSymbol>) Range {\n    return Range.span(parameters.first.range, parameters.last.range)\n  }\n}\n"
  },
  {
    "path": "src/middle/motion.sk",
    "content": "namespace Skew {\n  enum PassKind {\n    MOTION\n  }\n\n  class MotionPass : Pass {\n    over kind PassKind {\n      return .MOTION\n    }\n\n    over run(context PassContext) {\n      var motionContext = Motion.Context.new\n      Motion.symbolMotion(context.global, context.options, motionContext)\n      motionContext.finish\n    }\n  }\n}\n\nnamespace Skew.Motion {\n  def symbolMotion(symbol ObjectSymbol, options CompilerOptions, context Context) {\n    # Move non-imported objects off imported objects\n    symbol.objects.removeIf(object => {\n      symbolMotion(object, options, context)\n      if symbol.isImported && !object.isImported || !options.target.supportsNestedTypes && !symbol.kind.isNamespaceOrGlobal {\n        context.moveSymbolIntoNewNamespace(object)\n        return true\n      }\n      return false\n    })\n\n    # Move global functions with implementations off of imported objects and interfaces\n    symbol.functions.removeIf(function => {\n      if function.kind == .FUNCTION_GLOBAL && (symbol.isImported && !function.isImported || symbol.kind == .OBJECT_INTERFACE) {\n        context.moveSymbolIntoNewNamespace(function)\n        return true\n      }\n      return false\n    })\n\n    # Move stuff off of enums and flags\n    if symbol.kind.isEnumOrFlags {\n      symbol.objects.each(object => context.moveSymbolIntoNewNamespace(object))\n      symbol.functions.each(function => context.moveSymbolIntoNewNamespace(function))\n      symbol.variables.removeIf(variable => {\n        if variable.kind != .VARIABLE_ENUM_OR_FLAGS {\n          context.moveSymbolIntoNewNamespace(variable)\n          return true\n        }\n        return false\n      })\n      symbol.objects = []\n      symbol.functions = []\n    }\n\n    # Move variables off of interfaces\n    else if symbol.kind == .OBJECT_INTERFACE {\n      symbol.variables.each(variable => context.moveSymbolIntoNewNamespace(variable))\n      symbol.variables = []\n    }\n  }\n\n  class Context {\n    var _namespaces = IntMap<ObjectSymbol>.new\n\n    # Avoid mutation during iteration\n    def finish {\n      var values = _namespaces.values\n      values.sort(Symbol.SORT_OBJECTS_BY_ID) # Sort so the order is deterministic\n      for object in values {\n        object.parent.asObjectSymbol.objects.append(object)\n      }\n    }\n\n    def moveSymbolIntoNewNamespace(symbol Symbol) {\n      var parent = symbol.parent\n      var namespace = _namespaces.get(parent.id, null)\n      var object = namespace?.asObjectSymbol\n\n      # Create a parallel namespace next to the parent\n      if namespace == null {\n        var common = parent.parent.asObjectSymbol\n        var name = \"in_\" + parent.name\n        var candidate = common.members.get(name, null)\n\n        if candidate != null && candidate.kind == .OBJECT_NAMESPACE {\n          object = candidate.asObjectSymbol\n        }\n\n        else {\n          object = ObjectSymbol.new(.OBJECT_NAMESPACE, common.scope.generateName(name))\n          object.range = parent.range\n          object.resolvedType = Type.new(.SYMBOL, object)\n          object.state = .INITIALIZED\n          object.scope = ObjectScope.new(common.scope, object)\n          object.parent = common\n          common.members[name] = object\n          _namespaces[parent.id] = object\n        }\n      }\n\n      # Move this function into that parallel namespace\n      symbol.parent = object\n\n      if symbol.kind.isObject {\n        object.objects.append(symbol.asObjectSymbol)\n      }\n\n      else if symbol.kind.isFunction {\n        object.functions.append(symbol.asFunctionSymbol)\n\n        # Inflate functions with type parameters from the parent (TODO: Need to inflate call sites too)\n        if parent.asObjectSymbol.parameters != null {\n          var function = symbol.asFunctionSymbol\n          function.parameters ?= []\n          function.parameters.prepend(parent.asObjectSymbol.parameters)\n        }\n      }\n\n      else if symbol.kind.isVariable {\n        object.variables.append(symbol.asVariableSymbol)\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "src/middle/renaming.sk",
    "content": "namespace Skew {\n  enum PassKind {\n    RENAMING\n  }\n\n  class RenamingPass : Pass {\n    over kind PassKind {\n      return .RENAMING\n    }\n\n    over run(context PassContext) {\n      Renaming.renameGlobal(context.log, context.global)\n    }\n  }\n}\n\nnamespace Skew.Renaming {\n  def renameGlobal(log Log, global ObjectSymbol) {\n    # Collect all functions\n    var functions List<FunctionSymbol> = []\n    collectFunctionAndRenameObjectsAndVariables(global, functions)\n\n    # Compute naming groups\n    var labels = UnionFind.new.allocate(functions.count)\n    var groups List<List<FunctionSymbol>> = []\n    var firstScopeForObject = IntMap<Scope>.new\n    for i in 0..functions.count {\n      functions[i].namingGroup = i\n      groups.append(null)\n    }\n    for function in functions {\n      if function.overridden != null {\n        labels.union(function.namingGroup, function.overridden.namingGroup)\n      }\n      if function.implementations != null {\n        for implementation in function.implementations {\n          labels.union(function.namingGroup, implementation.namingGroup)\n        }\n      }\n    }\n    for function in functions {\n      var label = labels.find(function.namingGroup)\n      var group = groups[label]\n      function.namingGroup = label\n      if group == null {\n        group = []\n        groups[label] = group\n      } else {\n        assert(function.name == group.first.name)\n      }\n      group.append(function)\n\n      # Certain parent objects such as namespaces may have multiple scopes.\n      # However, we want to resolve name collisions in the same scope to detect\n      # collisions across all scopes. Do this by using the first scope.\n      if !(function.parent.id in firstScopeForObject) {\n        firstScopeForObject[function.parent.id] = function.scope.parent\n      }\n    }\n\n    # Rename stuff\n    for group in groups {\n      if group == null {\n        continue\n      }\n\n      var isImportedOrExported = false\n      var shouldRename = false\n      var isInvalid = false\n      var rename string = null\n\n      for function in group {\n        if function.isImportedOrExported {\n          isImportedOrExported = true\n        }\n\n        # Make sure there isn't more than one renamed symbol\n        if function.rename != null {\n          if rename != null && rename != function.rename {\n            log.semanticErrorDuplicateRename(function.range, function.name, rename, function.rename)\n          }\n          rename = function.rename\n        }\n\n        # Rename functions with unusual names and make sure overloaded functions have unique names\n        if !shouldRename {\n          if isInvalidIdentifier(function.name) {\n            isInvalid = true\n            shouldRename = true\n          } else if function.overloaded != null && function.overloaded.symbols.count > 1 {\n            shouldRename = true\n          }\n        }\n      }\n\n      # Bake in the rename annotation now\n      if rename != null {\n        for function in group {\n          function.flags |= .IS_RENAMED\n          function.name = rename\n          function.rename = null\n        }\n        continue\n      }\n\n      # One function with a pinned name causes the whole group to avoid renaming\n      if !shouldRename || isImportedOrExported && !isInvalid {\n        continue\n      }\n\n      var first = group.first\n      var arguments = first.arguments.count\n      var count = 0\n      var start = first.name\n\n      if (arguments == 0 || arguments == 1 && first.kind == .FUNCTION_GLOBAL) && start in unaryPrefixes {\n        start = unaryPrefixes[start]\n      } else if start in prefixes {\n        start = prefixes[start]\n      } else {\n        if start.startsWith(\"@\") {\n          start = start.slice(1)\n        }\n        if isInvalidIdentifier(start) {\n          start = generateValidIdentifier(start)\n        }\n      }\n\n      # Generate a new name\n      var name = start\n      while group.any(function => firstScopeForObject[function.parent.id].isNameUsed(name)) {\n        count++\n        name = start + count.toString\n      }\n      for function in group {\n        firstScopeForObject[function.parent.id].reserveName(name, null)\n        function.name = name\n      }\n    }\n  }\n\n  def collectFunctionAndRenameObjectsAndVariables(symbol ObjectSymbol, functions List<FunctionSymbol>) {\n    for object in symbol.objects {\n      if object.rename != null {\n        object.name = object.rename\n        object.rename = null\n      }\n      collectFunctionAndRenameObjectsAndVariables(object, functions)\n    }\n\n    for function in symbol.functions {\n      functions.append(function)\n    }\n\n    for variable in symbol.variables {\n      if variable.rename != null {\n        variable.name = variable.rename\n        variable.rename = null\n      }\n    }\n  }\n\n  def isAlpha(c int) bool {\n    return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_'\n  }\n\n  def isNumber(c int) bool {\n    return c >= '0' && c <= '9'\n  }\n\n  def isInvalidIdentifier(name string) bool {\n    for i in 0..name.count {\n      var c = name[i]\n      if !isAlpha(c) && (i == 0 || !isNumber(c)) {\n        return true\n      }\n    }\n    return false\n  }\n\n  def generateValidIdentifier(name string) string {\n    var text = \"\"\n    for i in 0..name.count {\n      var c = name[i]\n      if isAlpha(c) || isNumber(c) {\n        text += name.get(i)\n      }\n    }\n    if text != \"\" && name.endsWith(\"=\") {\n      return \"set\" + withUppercaseFirstLetter(text)\n    }\n    return text == \"\" || !isAlpha(text[0]) ? \"_\" + text : text\n  }\n\n  const unaryPrefixes = {\n    \"!\": \"not\",\n    \"+\": \"positive\",\n    \"++\": \"increment\",\n    \"-\": \"negative\",\n    \"--\": \"decrement\",\n    \"~\": \"complement\",\n  }\n\n  const prefixes = {\n    # Binary operators\n    \"%\": \"remainder\",\n    \"%%\": \"modulus\",\n    \"&\": \"and\",\n    \"*\": \"multiply\",\n    \"**\": \"power\",\n    \"+\": \"add\",\n    \"-\": \"subtract\",\n    \"/\": \"divide\",\n    \"<<\": \"leftShift\",\n    \"<=>\": \"compare\",\n    \">>\": \"rightShift\",\n    \">>>\": \"unsignedRightShift\",\n    \"^\": \"xor\",\n    \"in\": \"contains\",\n    \"|\": \"or\",\n\n    # Binary assignment operators\n    \"%%=\": \"modulusUpdate\",\n    \"%=\": \"remainderUpdate\",\n    \"&=\": \"andUpdate\",\n    \"**=\": \"powerUpdate\",\n    \"*=\": \"multiplyUpdate\",\n    \"+=\": \"addUpdate\",\n    \"-=\": \"subtractUpdate\",\n    \"/=\": \"divideUpdate\",\n    \"<<=\": \"leftShiftUpdate\",\n    \">>=\": \"rightShiftUpdate\",\n    \"^=\": \"xorUpdate\",\n    \"|=\": \"orUpdate\",\n\n    # Index operators\n    \"[]\": \"get\",\n    \"[]=\": \"set\",\n\n    # Initializer operators\n    \"<>...</>\": \"append\",\n    \"[...]\": \"append\",\n    \"[new]\": \"new\",\n    \"{...}\": \"insert\",\n    \"{new}\": \"new\",\n  }\n}\n"
  },
  {
    "path": "src/middle/resolving.sk",
    "content": "namespace Skew {\n  enum PassKind {\n    RESOLVING\n  }\n\n  class ResolvingPass : Pass {\n    over kind PassKind {\n      return .RESOLVING\n    }\n\n    over run(context PassContext) {\n      context.cache.loadGlobals(context.log, context.global)\n      Resolving.Resolver.new(context.global, context.options, context.options.defines.clone, context.cache, context.log).resolve\n\n      # The tree isn't fully resolved for speed reasons if code completion is requested\n      if context.options.completionContext == null {\n        context.isResolvePassComplete = true\n      }\n    }\n  }\n}\n\nnamespace Skew.Resolving {\n  enum ConversionKind {\n    IMPLICIT\n    EXPLICIT\n  }\n\n  enum SymbolStatistic {\n    READ\n    WRITE\n  }\n\n  class LocalVariableStatistics {\n    var symbol VariableSymbol\n    var readCount = 0\n    var writeCount = 0\n  }\n\n  namespace LocalVariableStatistics {\n    const SORT_BY_ID = (a LocalVariableStatistics, b LocalVariableStatistics) => a.symbol.id <=> b.symbol.id\n  }\n\n  class Resolver {\n    const _global ObjectSymbol\n    const _options CompilerOptions\n    const _defines StringMap<Define>\n    const _cache TypeCache\n    const _log Log\n    const _foreachLoops List<Node> = []\n    const _localVariableStatistics IntMap<LocalVariableStatistics> = {}\n    const _controlFlow = ControlFlowAnalyzer.new\n    const _generatedGlobalVariables List<VariableSymbol> = []\n    var _constantFolder Folding.ConstantFolder = null\n    var _isMergingGuards = true\n\n    def resolve {\n      _constantFolder = Folding.ConstantFolder.new(_cache, _options, symbol => _initializeSymbol(symbol))\n      _initializeGlobals\n      _iterativelyMergeGuards\n      _resolveGlobal\n      _removeObsoleteFunctions(_global)\n      _global.variables.insert(0, _generatedGlobalVariables)\n    }\n\n    # Put the guts of the function inside another function because V8 doesn't\n    # optimize functions with try-catch statements\n    def _initializeSymbolSwitch(symbol Symbol) {\n      switch symbol.kind {\n        case .OBJECT_CLASS, .OBJECT_ENUM, .OBJECT_FLAGS, .OBJECT_GLOBAL, .OBJECT_INTERFACE, .OBJECT_NAMESPACE, .OBJECT_WRAPPED {\n          _initializeObject(symbol.asObjectSymbol)\n        }\n\n        case .FUNCTION_ANNOTATION, .FUNCTION_CONSTRUCTOR, .FUNCTION_GLOBAL, .FUNCTION_INSTANCE, .FUNCTION_LOCAL {\n          _initializeFunction(symbol.asFunctionSymbol)\n        }\n\n        case .VARIABLE_ARGUMENT, .VARIABLE_ENUM_OR_FLAGS, .VARIABLE_GLOBAL, .VARIABLE_INSTANCE, .VARIABLE_LOCAL {\n          _initializeVariable(symbol.asVariableSymbol)\n        }\n\n        case .PARAMETER_FUNCTION, .PARAMETER_OBJECT {\n          _initializeParameter(symbol.asParameterSymbol)\n        }\n\n        case .OVERLOADED_ANNOTATION, .OVERLOADED_GLOBAL, .OVERLOADED_INSTANCE {\n          _initializeOverloadedFunction(symbol.asOverloadedFunctionSymbol)\n        }\n\n        default {\n          assert(false)\n        }\n      }\n    }\n\n    def _initializeSymbol(symbol Symbol) {\n      # The scope should have been set by the merging pass (or by this pass for local variables)\n      assert(symbol.scope != null)\n\n      # Only initialize the symbol once\n      if symbol.state == .UNINITIALIZED {\n        symbol.state = .INITIALIZING\n\n        try {\n          _initializeSymbolSwitch(symbol)\n        }\n\n        # If guard merging failed, reset the type so we'll try again next time\n        catch failure GuardMergingFailure {\n          symbol.state = .UNINITIALIZED\n          throw failure\n        }\n\n        assert(symbol.resolvedType != null)\n        symbol.state = .INITIALIZED\n\n        if symbol.kind.isFunction {\n          var function = symbol.asFunctionSymbol\n          var overloaded = function.overloaded\n\n          # After initializing a function symbol, ensure the entire overload set is initialized\n          if overloaded != null && overloaded.state == .UNINITIALIZED {\n            _initializeSymbol(overloaded)\n          }\n        }\n      }\n\n      # Detect cyclic symbol references such as \"foo foo;\"\n      else if symbol.state == .INITIALIZING {\n        _log.semanticErrorCyclicDeclaration(symbol.range, symbol.name)\n        symbol.resolvedType = .DYNAMIC\n      }\n    }\n\n    def _validateEntryPoint(symbol FunctionSymbol) {\n      # Detect duplicate entry points\n      if _cache.entryPointSymbol != null {\n        _log.semanticErrorDuplicateEntryPoint(symbol.range, _cache.entryPointSymbol.range)\n        return\n      }\n\n      _cache.entryPointSymbol = symbol\n\n      # Only recognize a few entry point types\n      var type = symbol.resolvedType\n      if type != .DYNAMIC {\n        var argumentTypes = type.argumentTypes\n\n        # The argument list must be empty or one argument of type \"List<string>\"\n        if argumentTypes.count > 1 || argumentTypes.count == 1 && argumentTypes.first != _cache.createListType(_cache.stringType) {\n          _log.semanticErrorInvalidEntryPointArguments(Range.span(symbol.arguments.first.range, symbol.arguments.last.type.range), symbol.name)\n        }\n\n        # The return type must be nothing or \"int\"\n        else if type.returnType != null && type.returnType != _cache.intType {\n          _log.semanticErrorInvalidEntryPointReturnType(symbol.returnType.range, symbol.name)\n        }\n      }\n    }\n\n    def _resolveDefines(symbol VariableSymbol) {\n      var key = symbol.fullName\n      var define = _defines.get(key, null)\n\n      if define == null {\n        return\n      }\n\n      # Remove the define so we can tell what defines weren't used later on\n      _defines.remove(key)\n\n      var type = symbol.resolvedType\n      var range = define.value\n      var value = range.toString\n      var node Node = null\n\n      # Special-case booleans\n      if type == _cache.boolType {\n        if value == \"true\" || value == \"false\" {\n          node = Node.createBool(value == \"true\")\n        }\n      }\n\n      # Special-case doubles\n      else if type == _cache.doubleType {\n        var number = parseDoubleLiteral(value)\n        if !number.isNaN {\n          node = Node.createDouble(number)\n        }\n      }\n\n      # Special-case strings\n      else if type == _cache.stringType {\n        node = Node.createString(value)\n      }\n\n      # Special-case enums\n      else if type.isEnumOrFlags {\n        node = Node.createDot(null, value)\n      }\n\n      # Integers can also apply to doubles\n      if node == null && _cache.isNumeric(type) {\n        var box = Parsing.parseIntLiteral(_log, range)\n        if box != null {\n          node = Node.createInt(box.value)\n        }\n      }\n\n      # Stop if anything failed above\n      if node == null {\n        _log.semanticErrorInvalidDefine(range, value, type, key)\n        return\n      }\n\n      _resolveAsParameterizedExpressionWithConversion(node.withRange(range), _global.scope, type)\n      symbol.value = node\n    }\n\n    def _resolveAnnotations(symbol Symbol) {\n      var parent = symbol.parent\n      var annotations = symbol.annotations\n\n      # The import/export annotations are inherited, except import isn't inherited for implemented functions\n      if parent != null {\n        symbol.flags |= parent.flags & (symbol.kind.isFunction && symbol.asFunctionSymbol.block != null ? .IS_EXPORTED : .IS_IMPORTED | .IS_EXPORTED)\n      }\n\n      # Resolve annotations on this symbol after annotation inheritance. Don't\n      # use removeIf() since this annotation list may be shared elsewhere.\n      if annotations != null {\n        symbol.annotations = annotations.filter(annotation => _resolveAnnotation(annotation, symbol))\n      }\n\n      # Protected access used to be an annotation. It's now indicated with just\n      # a leading underscore.\n      if symbol.name.startsWith(\"_\") && !symbol.kind.isLocal {\n        symbol.flags |= .IS_PROTECTED\n      }\n    }\n\n    def _resolveParameters(parameters List<ParameterSymbol>) {\n      if parameters != null {\n        for parameter in parameters {\n          _resolveParameter(parameter)\n        }\n      }\n    }\n\n    def _initializeParameter(symbol ParameterSymbol) {\n      symbol.resolvedType ?= Type.new(.SYMBOL, symbol)\n      _resolveAnnotations(symbol)\n    }\n\n    def _resolveParameter(symbol ParameterSymbol) {\n      _initializeSymbol(symbol)\n    }\n\n    def _initializeObject(symbol ObjectSymbol) {\n      var kind = symbol.kind\n      var extends = symbol.extends\n      var implements = symbol.implements\n\n      symbol.resolvedType ?= Type.new(.SYMBOL, symbol)\n      _resolveParameters(symbol.parameters)\n\n      # Resolve the base type (only for classes and wrapped types)\n      if extends != null {\n        _resolveAsParameterizedType(extends, symbol.scope)\n        var baseType = extends.resolvedType\n\n        if kind == .OBJECT_WRAPPED {\n          symbol.wrappedType = baseType\n          symbol.resolvedType.environment = baseType.environment # Don't lose the type parameters from the base type\n        }\n\n        else if kind != .OBJECT_CLASS || (baseType != .DYNAMIC && (!baseType.isClass || baseType.symbol.isValueType)) {\n          _log.semanticErrorInvalidExtends(extends.range, baseType)\n        }\n\n        else if baseType != .DYNAMIC {\n          symbol.baseType = baseType\n          symbol.baseClass = baseType.symbol.asObjectSymbol\n          symbol.resolvedType.environment = baseType.environment # Don't lose the type parameters from the base type\n\n          # Copy members from the base type\n          var functions List<FunctionSymbol> = []\n          var members = symbol.baseClass.members.values\n          members.sort(Symbol.SORT_BY_ID) # Sort so the order is deterministic\n          for member in members {\n            var memberKind = member.kind\n\n            # Separate out functions\n            if memberKind.isFunction {\n              if memberKind != .FUNCTION_CONSTRUCTOR {\n                functions.append(member.asFunctionSymbol)\n              }\n            }\n\n            # Include overloaded functions individually\n            else if memberKind.isOverloadedFunction {\n              for function in member.asOverloadedFunctionSymbol.symbols {\n                if function.kind != .FUNCTION_CONSTRUCTOR {\n                  functions.append(function)\n                }\n              }\n            }\n\n            # Other kinds\n            else if !memberKind.isParameter {\n              var other = symbol.members.get(member.name, null)\n              if other != null {\n                _log.semanticErrorBadOverride(other.range, other.name, baseType, member.range)\n              } else {\n                symbol.members[member.name] = member\n              }\n            }\n          }\n\n          Merging.mergeFunctions(_log, symbol, functions, .INTO_DERIVED_CLASS)\n        }\n      }\n\n      # Wrapped types without something to wrap don't make sense\n      else if kind == .OBJECT_WRAPPED {\n        _log.semanticErrorMissingWrappedType(symbol.range, symbol.fullName)\n\n        # Make sure to fill out the wrapped type anyway so code that tries to\n        # access it doesn't crash. The dynamic type should ignore further errors.\n        symbol.wrappedType = .DYNAMIC\n      }\n\n      # Resolve the base interface types\n      if implements != null {\n        symbol.interfaceTypes = []\n        for i in 0..implements.count {\n          var type = implements[i]\n          _resolveAsParameterizedType(type, symbol.scope)\n\n          # Ignore the dynamic type, which will be from errors and dynamic expressions used for exports\n          var interfaceType = type.resolvedType\n          if interfaceType == .DYNAMIC {\n            continue\n          }\n\n          # Only classes can derive from interfaces\n          if kind != .OBJECT_CLASS || !interfaceType.isInterface {\n            _log.semanticErrorInvalidImplements(type.range, interfaceType)\n            continue\n          }\n\n          # An interface can only be implemented once\n          for j in 0..i {\n            var other = implements[j]\n            if other.resolvedType == interfaceType {\n              _log.semanticErrorDuplicateImplements(type.range, interfaceType, other.range)\n              break\n            }\n          }\n\n          symbol.interfaceTypes.append(interfaceType)\n        }\n      }\n\n      # Assign values for all enums and flags before they are initialized\n      if kind.isEnumOrFlags {\n        var nextValue = 0\n        for variable in symbol.variables {\n          if variable.kind == .VARIABLE_ENUM_OR_FLAGS {\n            if nextValue >= 32 && kind == .OBJECT_FLAGS {\n              _log.semanticErrorTooManyFlags(variable.range, symbol.name)\n            }\n            variable.value = Node.createInt(kind == .OBJECT_FLAGS ? 1 << nextValue : nextValue).withType(symbol.resolvedType).withRange(variable.range)\n            nextValue++\n          }\n        }\n        symbol.flags |= .IS_VALUE_TYPE\n      }\n\n      _resolveAnnotations(symbol)\n\n      # Create a default constructor if one doesn't exist\n      var constructor = symbol.members.get(\"new\", null)\n      if kind == .OBJECT_CLASS && !symbol.isImported && constructor == null {\n        var baseConstructor = symbol.baseClass?.members.get(\"new\", null)\n\n        # Unwrap the overload group if present\n        if baseConstructor != null && baseConstructor.kind == .OVERLOADED_GLOBAL {\n          var overloaded = baseConstructor.asOverloadedFunctionSymbol\n          for overload in overloaded.symbols {\n            if overload.kind == .FUNCTION_CONSTRUCTOR {\n              if baseConstructor.kind == .FUNCTION_CONSTRUCTOR {\n                baseConstructor = null # Signal that there isn't a single base constructor\n                break\n              }\n              baseConstructor = overload\n            }\n          }\n        }\n\n        # A default constructor can only be created if the base class has a single constructor\n        if symbol.baseClass == null || baseConstructor != null && baseConstructor.kind == .FUNCTION_CONSTRUCTOR {\n          var generated = FunctionSymbol.new(.FUNCTION_CONSTRUCTOR, \"new\")\n          generated.scope = FunctionScope.new(symbol.scope, generated)\n          generated.flags |= .IS_AUTOMATICALLY_GENERATED\n          generated.parent = symbol\n          generated.range = symbol.range\n          generated.overridden = baseConstructor?.asFunctionSymbol\n          symbol.functions.append(generated)\n          symbol.members[generated.name] = generated\n        }\n      }\n\n      # Create a default toString if one doesn't exist\n      if kind == .OBJECT_ENUM && !symbol.isImported && !(\"toString\" in symbol.members) {\n        var generated = FunctionSymbol.new(.FUNCTION_INSTANCE, \"toString\")\n        generated.scope = FunctionScope.new(symbol.scope, generated)\n        generated.flags |= .IS_AUTOMATICALLY_GENERATED | .IS_INLINING_FORCED\n        _options.isAlwaysInlinePresent = true\n        generated.parent = symbol\n        generated.range = symbol.range\n        symbol.functions.append(generated)\n        symbol.members[generated.name] = generated\n      }\n    }\n\n    def _checkInterfacesAndAbstractStatus(object ObjectSymbol, function FunctionSymbol) {\n      assert(function.kind == .FUNCTION_INSTANCE)\n      assert(function.state == .INITIALIZED)\n\n      if !object.isAbstract && !function.isImported && !function.isObsolete && function.block == null {\n        object.isAbstractBecauseOf = function\n      }\n    }\n\n    def _checkInterfacesAndAbstractStatus(symbol ObjectSymbol) {\n      assert(symbol.state == .INITIALIZED)\n\n      if symbol.hasCheckedInterfacesAndAbstractStatus || symbol.kind != .OBJECT_CLASS {\n        return\n      }\n\n      symbol.hasCheckedInterfacesAndAbstractStatus = true\n\n      # Check to see if this class is abstract (has unimplemented members)\n      var members = symbol.members.values\n      members.sort(Symbol.SORT_BY_ID) # Sort so the order is deterministic\n      for member in members {\n        if member.kind == .OVERLOADED_INSTANCE {\n          _initializeSymbol(member)\n          for function in member.asOverloadedFunctionSymbol.symbols {\n            _checkInterfacesAndAbstractStatus(symbol, function)\n          }\n        } else if member.kind == .FUNCTION_INSTANCE {\n          _initializeSymbol(member)\n          _checkInterfacesAndAbstractStatus(symbol, member.asFunctionSymbol)\n        }\n        if symbol.isAbstract {\n          break\n        }\n      }\n\n      # Check interfaces for missing implementations\n      if symbol.interfaceTypes != null {\n        for interfaceType in symbol.interfaceTypes {\n          for function in interfaceType.symbol.asObjectSymbol.functions {\n            if function.kind != .FUNCTION_INSTANCE || function.block != null {\n              continue\n            }\n            _initializeSymbol(function)\n\n            var member = symbol.members.get(function.name, null)\n            var match FunctionSymbol = null\n            var equivalence = TypeCache.Equivalence.NOT_EQUIVALENT\n\n            # Search for a matching function\n            if member != null {\n              _initializeSymbol(member)\n              if member.kind == .OVERLOADED_INSTANCE {\n                for other in member.asOverloadedFunctionSymbol.symbols {\n                  equivalence = _cache.areFunctionSymbolsEquivalent(function, interfaceType.environment, other, null)\n                  if equivalence != .NOT_EQUIVALENT {\n                    match = other\n                    break\n                  }\n                }\n              } else if member.kind == .FUNCTION_INSTANCE {\n                equivalence = _cache.areFunctionSymbolsEquivalent(function, interfaceType.environment, member.asFunctionSymbol, null)\n                if equivalence != .NOT_EQUIVALENT {\n                  match = member.asFunctionSymbol\n                }\n              }\n            }\n\n            # Validate use of the interface\n            if match == null {\n              _log.semanticErrorBadInterfaceImplementation(symbol.range, symbol.resolvedType, interfaceType, function.name, function.range)\n            } else if equivalence == .EQUIVALENT_EXCEPT_RETURN_TYPE {\n              var returnType = function.resolvedType.returnType\n              if returnType != null {\n                returnType = _cache.substitute(returnType, interfaceType.environment)\n              }\n              _log.semanticErrorBadInterfaceImplementationReturnType(match.range, match.name, match.resolvedType.returnType,\n                _cache.substituteFunctionParameters(returnType, match, function), interfaceType, function.range)\n            } else {\n              function.implementations ?= []\n              function.implementations.append(match)\n            }\n          }\n        }\n      }\n    }\n\n    def _initializeGlobals {\n      _initializeSymbol(_cache.boolType.symbol)\n      _initializeSymbol(_cache.doubleType.symbol)\n      _initializeSymbol(_cache.intMapType.symbol)\n      _initializeSymbol(_cache.intType.symbol)\n      _initializeSymbol(_cache.listType.symbol)\n      _initializeSymbol(_cache.stringMapType.symbol)\n      _initializeSymbol(_cache.stringType.symbol)\n    }\n\n    def _resolveGlobal {\n      _resolveObject(_global)\n      _scanLocalVariables\n      _convertForeachLoops\n      _discardUnusedDefines\n    }\n\n    # An obsolete function is one without an implementation that was dropped in\n    # favor of one with an implementation:\n    #\n    #   namespace Foo {\n    #     def foo {}\n    #\n    #     # This will be marked as obsolete\n    #     def foo\n    #   }\n    #\n    def _removeObsoleteFunctions(symbol ObjectSymbol) {\n      for object in symbol.objects {\n        _removeObsoleteFunctions(object)\n      }\n      symbol.functions.removeIf(function => function.isObsolete)\n    }\n\n    def _iterativelyMergeGuards {\n      var guards List<Guard>\n\n      # Iterate until a fixed point is reached\n      while true {\n        guards = []\n        _scanForGuards(_global, guards)\n        if guards.isEmpty {\n          break\n        }\n\n        # Each iteration must remove at least one guard to continue\n        if !_processGuards(guards) {\n          break\n        }\n      }\n\n      _isMergingGuards = false\n\n      # All remaining guards are errors\n      for guard in guards {\n        var count = _log.errorCount\n        _resolveAsParameterizedExpressionWithConversion(guard.test, guard.parent.scope, _cache.boolType)\n        if _log.errorCount == count {\n          _log.semanticErrorExpectedConstant(guard.test.range)\n        }\n      }\n    }\n\n    def _scanForGuards(symbol ObjectSymbol, guards List<Guard>) {\n      if symbol.guards != null {\n        guards.append(symbol.guards)\n      }\n\n      for object in symbol.objects {\n        _scanForGuards(object, guards)\n      }\n    }\n\n    if TARGET == .CSHARP {\n      class GuardMergingFailure : dynamic.System.Exception {\n      }\n    }\n\n    else {\n      class GuardMergingFailure {\n      }\n    }\n\n    def _reportGuardMergingFailure(node Node) {\n      if _isMergingGuards {\n        throw GuardMergingFailure.new\n      }\n    }\n\n    def _attemptToResolveGuardConstant(node Node, scope Scope) bool {\n      assert(scope != null)\n      try {\n        _resolveAsParameterizedExpressionWithConversion(node, scope, _cache.boolType)\n        _constantFolder.foldConstants(node)\n        return true\n      } catch failure GuardMergingFailure {\n      }\n      return false\n    }\n\n    def _processGuards(guards List<Guard>) bool {\n      var wasGuardRemoved = false\n\n      for guard in guards {\n        var test = guard.test\n        var parent = guard.parent\n\n        # If it's not a constant, we'll just try again in the next iteration\n        if !_attemptToResolveGuardConstant(test, parent.scope) {\n          continue\n        }\n\n        if test.isBool {\n          parent.guards.removeOne(guard)\n          wasGuardRemoved = true\n\n          if test.isTrue {\n            _mergeGuardIntoObject(guard, parent)\n          } else {\n            var elseGuard = guard.elseGuard\n            if elseGuard != null {\n              if elseGuard.test != null {\n                elseGuard.parent = parent\n                parent.guards.append(elseGuard)\n              } else {\n                _mergeGuardIntoObject(elseGuard, parent)\n              }\n            }\n          }\n        }\n      }\n\n      return wasGuardRemoved\n    }\n\n    def _mergeGuardIntoObject(guard Guard, object ObjectSymbol) {\n      var symbol = guard.contents\n      Merging.mergeObjects(_log, object, symbol.objects)\n      Merging.mergeFunctions(_log, object, symbol.functions, .NORMAL)\n      Merging.mergeVariables(_log, object, symbol.variables)\n      object.objects.append(symbol.objects)\n      object.functions.append(symbol.functions)\n      object.variables.append(symbol.variables)\n\n      # Handle nested guard clauses like this:\n      #\n      #   if true {\n      #     if true {\n      #       var foo = 0\n      #     }\n      #   }\n      #\n      if symbol.guards != null {\n        for nested in symbol.guards {\n          object.guards.append(nested)\n          for g = nested; g != null; g = g.elseGuard {\n            g.parent = object\n            g.contents.parent = object\n          }\n        }\n      }\n    }\n\n    # Foreach loops are converted to for loops after everything is resolved\n    # because that process needs to generate symbol names and it's much easier\n    # to generate non-conflicting symbol names after all local variables have\n    # been defined.\n    def _convertForeachLoops {\n      for node in _foreachLoops {\n        var symbol = node.symbol.asVariableSymbol\n        var scope = symbol.scope.findEnclosingFunctionOrLambda # Generate names at the function level to avoid conflicts with local scopes\n        var value = node.foreachValue\n        var block = node.foreachBlock\n\n        # Handle \"for i in 0..10\"\n        if value.kind == .PAIR {\n          var first = value.firstValue\n          var second = value.secondValue\n          symbol.flags &= ~.IS_CONST\n          symbol.value = first.remove\n          var setup = Node.createVariables.appendChild(Node.createVariable(symbol))\n          var symbolName = Node.createSymbolReference(symbol)\n          var update = Node.createUnary(.PREFIX_INCREMENT, symbolName)\n          var test Node\n\n          # Special-case constant iteration limits to generate simpler code\n          if second.kind == .CONSTANT || second.kind == .NAME && second.symbol != null && second.symbol.isConst {\n            test = Node.createBinary(.LESS_THAN, symbolName.clone, second.remove)\n          }\n\n          # Otherwise, save the iteration limit in case it changes during iteration\n          else {\n            var count = VariableSymbol.new(.VARIABLE_LOCAL, scope.generateName(\"count\"))\n            count.initializeWithType(_cache.intType)\n            count.value = second.remove\n            setup.appendChild(Node.createVariable(count))\n            test = Node.createBinary(.LESS_THAN, symbolName.clone, Node.createSymbolReference(count))\n          }\n\n          # Use a C-style for loop to implement this foreach loop\n          node.become(Node.createFor(setup, test, update, block.remove).withComments(node.comments).withRange(node.range))\n\n          # Make sure the new expressions are resolved\n          _resolveNode(test, symbol.scope, null)\n          _resolveNode(update, symbol.scope, null)\n        }\n\n        else if _cache.isList(value.resolvedType) && !_options.target.supportsListForeach {\n          # Create the index variable\n          var index = VariableSymbol.new(.VARIABLE_LOCAL, scope.generateName(\"i\"))\n          index.initializeWithType(_cache.intType)\n          index.value = _cache.createInt(0)\n          var setup = Node.createVariables.appendChild(Node.createVariable(index))\n          var indexName = Node.createSymbolReference(index)\n\n          # Create the list variable\n          var list VariableSymbol = null\n          if value.kind == .NAME && value.symbol != null && value.symbol.kind.isVariable && value.symbol.isConst {\n            list = value.symbol.asVariableSymbol\n          } else {\n            list = VariableSymbol.new(.VARIABLE_LOCAL, scope.generateName(\"list\"))\n            list.initializeWithType(value.resolvedType)\n            list.value = value.remove\n            setup.appendChild(Node.createVariable(list))\n          }\n          var listName = Node.createSymbolReference(list)\n\n          # Create the count variable\n          var count = VariableSymbol.new(.VARIABLE_LOCAL, scope.generateName(\"count\"))\n          count.initializeWithType(_cache.intType)\n          count.value = Node.createDot(listName, \"count\")\n          setup.appendChild(Node.createVariable(count))\n          var countName = Node.createSymbolReference(count)\n\n          # Move the loop variable into the loop body\n          symbol.value = Node.createIndex(listName.clone, indexName)\n          block.prependChild(Node.createVariables.appendChild(Node.createVariable(symbol)))\n\n          # Use a C-style for loop to implement this foreach loop\n          var test = Node.createBinary(.LESS_THAN, indexName.clone, countName)\n          var update = Node.createUnary(.PREFIX_INCREMENT, indexName.clone)\n          node.become(Node.createFor(setup, test, update, block.remove).withComments(node.comments).withRange(node.range))\n\n          # Make sure the new expressions are resolved\n          _resolveNode(symbol.value, symbol.scope, null)\n          _resolveNode(count.value, symbol.scope, null)\n          _resolveNode(test, symbol.scope, null)\n          _resolveNode(update, symbol.scope, null)\n        }\n      }\n    }\n\n    def _scanLocalVariables {\n      var values = _localVariableStatistics.values\n      values.sort(LocalVariableStatistics.SORT_BY_ID) # Sort so the order is deterministic\n      for info in values {\n        var symbol = info.symbol\n\n        # Variables that are never re-assigned can safely be considered constants for constant folding\n        if info.writeCount == 0 && _options.foldAllConstants {\n          symbol.flags |= .IS_CONST\n        }\n\n        # Unused local variables can safely be removed, but don't warn about \"for i in 0..10 {}\"\n        if info.readCount == 0 && !symbol.isLoopVariable && symbol.kind == .VARIABLE_LOCAL {\n          _log.semanticWarningUnreadLocalVariable(symbol.range, symbol.name)\n        }\n\n        # Rename local variables that conflict\n        var scope = symbol.scope\n        while scope.kind == .LOCAL {\n          scope = scope.parent\n        }\n        if scope.used != null && scope.used.get(symbol.name, null) != symbol {\n          symbol.name = scope.generateName(symbol.name)\n        }\n      }\n    }\n\n    def _discardUnusedDefines {\n      var keys = _defines.keys\n      keys.sort((a, b) => a <=> b) # Sort so the order is deterministic\n      for key in keys {\n        _log.semanticErrorInvalidDefine(_defines[key].name, key)\n      }\n    }\n\n    def _resolveObject(symbol ObjectSymbol) {\n      _initializeSymbol(symbol)\n\n      for object in symbol.objects {\n        _resolveObject(object)\n      }\n\n      for function in symbol.functions {\n        _resolveFunction(function)\n      }\n\n      for variable in symbol.variables {\n        _resolveVariable(variable)\n      }\n\n      _checkInterfacesAndAbstractStatus(symbol)\n    }\n\n    def _initializeFunction(symbol FunctionSymbol) {\n      symbol.resolvedType ?= Type.new(.SYMBOL, symbol)\n\n      # Referencing a normal variable instead of a special node kind for \"this\"\n      # makes many things much easier including lambda capture and devirtualization\n      if symbol.kind == .FUNCTION_INSTANCE || symbol.kind == .FUNCTION_CONSTRUCTOR {\n        var this = VariableSymbol.new(.VARIABLE_ARGUMENT, \"self\")\n        this.initializeWithType(_cache.parameterize(symbol.parent.resolvedType))\n        this.flags |= .IS_CONST\n        symbol.this = this\n      }\n\n      # Lazily-initialize automatically generated functions\n      if symbol.isAutomaticallyGenerated {\n        if symbol.kind == .FUNCTION_CONSTRUCTOR {\n          assert(symbol.name == \"new\")\n          _automaticallyGenerateClassConstructor(symbol)\n        } else if symbol.kind == .FUNCTION_INSTANCE {\n          assert(symbol.name == \"toString\")\n          _automaticallyGenerateEnumToString(symbol)\n        }\n      }\n\n      _resolveParameters(symbol.parameters)\n\n      # Resolve the argument variables\n      symbol.resolvedType.argumentTypes = []\n      for argument in symbol.arguments {\n        argument.scope = symbol.scope\n        _resolveVariable(argument)\n        symbol.resolvedType.argumentTypes.append(argument.resolvedType)\n      }\n      symbol.argumentOnlyType = _cache.createLambdaType(symbol.resolvedType.argumentTypes, null)\n\n      # Resolve the return type if present (no return type means \"void\")\n      var returnType Type = null\n      if symbol.returnType != null {\n        if symbol.kind == .FUNCTION_CONSTRUCTOR {\n          _log.semanticErrorConstructorReturnType(symbol.returnType.range)\n        }\n\n        # Explicitly handle a \"void\" return type for better error messages\n        else if symbol.returnType.kind == .NAME && symbol.returnType.asString == \"void\" && symbol.scope.find(\"void\", .NORMAL) == null {\n          _log.semanticErrorVoidReturnType(symbol.returnType.range)\n        }\n\n        else {\n          _resolveAsParameterizedType(symbol.returnType, symbol.scope)\n          returnType = symbol.returnType.resolvedType\n        }\n      }\n\n      # Constructors always return the type they construct\n      if symbol.kind == .FUNCTION_CONSTRUCTOR {\n        returnType = _cache.parameterize(symbol.parent.resolvedType)\n        symbol.returnType = Node.createType(returnType)\n      }\n\n      # The \"<=>\" operator must return a numeric value for comparison with zero\n      var count = symbol.arguments.count\n      if symbol.name == \"<=>\" {\n        if returnType == null || returnType != _cache.intType {\n          _log.semanticErrorComparisonOperatorNotInt(symbol.returnType != null ? symbol.returnType.range : symbol.range)\n          returnType = .DYNAMIC\n        } else if count != 1 {\n          _log.semanticErrorWrongArgumentCount(symbol.range, symbol.name, 1)\n        }\n      }\n\n      # Setters must have one argument\n      else if symbol.isSetter && count != 1 {\n        _log.semanticErrorWrongArgumentCount(symbol.range, symbol.name, 1)\n        symbol.flags &= ~.IS_SETTER\n      }\n\n      # Validate argument count\n      else {\n        var argumentCount = argumentCountForOperator(symbol.name)\n\n        if argumentCount != null && !(count in argumentCount) {\n          _log.semanticErrorWrongArgumentCountRange(symbol.range, symbol.name, argumentCount)\n        }\n\n        # Enforce that the initializer constructor operators take lists of\n        # values to avoid confusing error messages inside the code generated\n        # for initializer expressions\n        else if symbol.name == \"{new}\" || symbol.name == \"[new]\" {\n          for argument in symbol.arguments {\n            if argument.resolvedType != .DYNAMIC && !_cache.isList(argument.resolvedType) {\n              _log.semanticErrorExpectedList(argument.range, argument.name, argument.resolvedType)\n            }\n          }\n        }\n      }\n\n      symbol.resolvedType.returnType = returnType\n      _resolveAnnotations(symbol)\n\n      # Validate the entry point after this symbol has a type\n      if symbol.isEntryPoint {\n        _validateEntryPoint(symbol)\n      }\n    }\n\n    def _automaticallyGenerateClassConstructor(symbol FunctionSymbol) {\n      # Create the function body\n      var block = Node.createBlock\n      symbol.block = block\n\n      # Mirror the base constructor's arguments\n      if symbol.overridden != null {\n        _initializeSymbol(symbol.overridden)\n        var arguments = symbol.overridden.arguments\n        var base = Node.createSuper.withRange(symbol.overridden.range)\n        if arguments.isEmpty {\n          block.appendChild(Node.createExpression(base))\n        } else {\n          var call = Node.createCall(base)\n          for variable in arguments {\n            var argument = VariableSymbol.new(.VARIABLE_ARGUMENT, variable.name)\n            argument.range = variable.range\n            argument.initializeWithType(variable.resolvedType)\n            symbol.arguments.append(argument)\n            call.appendChild(Node.createSymbolReference(argument))\n          }\n          block.prependChild(Node.createExpression(call))\n        }\n      }\n\n      # Add an argument for every uninitialized variable\n      var parent = symbol.parent.asObjectSymbol\n      _initializeSymbol(parent)\n      for variable in parent.variables {\n        if variable.kind == .VARIABLE_INSTANCE {\n          _initializeSymbol(variable)\n          if variable.value == null {\n            var argument = VariableSymbol.new(.VARIABLE_ARGUMENT, variable.name)\n            argument.initializeWithType(variable.resolvedType)\n            argument.range = variable.range\n            symbol.arguments.append(argument)\n            block.appendChild(Node.createExpression(Node.createBinary(.ASSIGN,\n              Node.createMemberReference(Node.createSymbolReference(symbol.this), variable),\n              Node.createSymbolReference(argument)).withRange(variable.range)))\n          } else {\n            block.appendChild(Node.createExpression(Node.createBinary(.ASSIGN,\n              Node.createMemberReference(Node.createSymbolReference(symbol.this), variable),\n              variable.value.clone).withRange(variable.range)))\n          }\n        }\n      }\n\n      # Make constructors without arguments into getters\n      if symbol.arguments.isEmpty {\n        symbol.flags |= .IS_GETTER\n      }\n    }\n\n    def _automaticallyGenerateEnumToString(symbol FunctionSymbol) {\n      var parent = symbol.parent.asObjectSymbol\n      var names = Node.createList\n      _initializeSymbol(parent)\n\n      symbol.returnType = Node.createType(_cache.stringType)\n      symbol.flags |= .IS_GETTER\n\n      # TypeScript has special enum-to-string support that we can use instead\n      if _options.target is TypeScriptTarget {\n        const target = Node.createName(parent.name).withSymbol(parent).withType(.DYNAMIC)\n        symbol.block = Node.createBlock.appendChild(Node.createReturn(Node.createIndex(target, Node.createName(\"self\"))))\n        return\n      }\n\n      for variable in parent.variables {\n        if variable.kind == .VARIABLE_ENUM_OR_FLAGS {\n          assert(variable.value.asInt == names.childCount)\n          names.appendChild(Node.createString(variable.name))\n        }\n      }\n\n      var strings = VariableSymbol.new(.VARIABLE_GLOBAL, parent.scope.generateName(\"_strings\"))\n      strings.range = parent.range\n      strings.initializeWithType(_cache.createListType(_cache.stringType))\n      strings.value = names\n      strings.flags |= .IS_PROTECTED | .IS_CONST | .IS_AUTOMATICALLY_GENERATED\n      strings.parent = parent\n      strings.scope = parent.scope\n      parent.variables.append(strings)\n      _resolveAsParameterizedExpressionWithConversion(strings.value, strings.scope, strings.resolvedType)\n\n      symbol.block = Node.createBlock.appendChild(Node.createReturn(Node.createIndex(Node.createSymbolReference(strings), Node.createName(\"self\"))))\n    }\n\n    def _resolveFunction(symbol FunctionSymbol) {\n      _initializeSymbol(symbol)\n\n      # Validate use of \"def\" vs \"over\"\n      if !symbol.isObsolete {\n        if symbol.overridden != null && symbol.kind == .FUNCTION_INSTANCE {\n          if !symbol.isOver {\n            _log.semanticErrorModifierMissingOverride(symbol.range, symbol.name, symbol.overridden.range)\n          }\n        } else {\n          if symbol.isOver {\n            _log.semanticErrorModifierUnusedOverride(symbol.range, symbol.name)\n          }\n        }\n      }\n\n      var scope = LocalScope.new(symbol.scope, .NORMAL)\n      if symbol.this != null {\n        scope.define(symbol.this, _log)\n      }\n\n      # Default values for argument variables aren't resolved with this local\n      # scope since they are evaluated at the call site, not inside the\n      # function body, and shouldn't have access to other arguments\n      for argument in symbol.arguments {\n        scope.define(argument, _log)\n        _localVariableStatistics[argument.id] = LocalVariableStatistics.new(argument)\n      }\n\n      # The function is considered abstract if the body is missing\n      var block = symbol.block\n      if block != null {\n        var firstStatement = block.firstChild\n        if firstStatement != null && firstStatement.isSuperCallStatement {\n          firstStatement = firstStatement.nextSibling\n        }\n\n        # User-specified constructors have variable initializers automatically inserted\n        if symbol.kind == .FUNCTION_CONSTRUCTOR && !symbol.isAutomaticallyGenerated {\n          for variable in symbol.parent.asObjectSymbol.variables {\n            if variable.kind == .VARIABLE_INSTANCE {\n              _resolveVariable(variable)\n\n              # Attempt to create a default value if absent. Right now this\n              # avoids the problem of initializing type parameters:\n              #\n              #   class Foo<T> {\n              #     var foo T\n              #     def new {}\n              #     def use T { return foo }\n              #   }\n              #\n              # This should be fixed at some point.\n              if variable.value == null && !variable.resolvedType.isParameter {\n                variable.value = _createDefaultValueForType(variable.resolvedType, variable.range)\n              }\n\n              if variable.value != null {\n                block.insertChildBefore(firstStatement, Node.createExpression(Node.createBinary(.ASSIGN,\n                  Node.createMemberReference(Node.createSymbolReference(symbol.this), variable),\n                  variable.value.clone)))\n              }\n            }\n          }\n        }\n\n        # Skip resolving irrelevant function bodies to speed up code completion\n        var context = _options.completionContext\n        if context != null && block.range != null && block.range.source != context.source {\n          return\n        }\n\n        _resolveNode(block, scope, null)\n\n        # Missing a return statement is an error\n        if symbol.kind != .FUNCTION_CONSTRUCTOR {\n          var returnType = symbol.resolvedType.returnType\n          if returnType != null && !symbol.isDynamicLambda && block.hasControlFlowAtEnd {\n            _log.semanticErrorMissingReturn(symbol.range, symbol.name, returnType)\n          }\n        }\n\n        # Derived class constructors must start with a call to \"super\"\n        else if symbol.parent.asObjectSymbol.baseClass != null {\n          var first = block.firstChild\n          if first == null || !first.isSuperCallStatement {\n            _log.semanticErrorMissingSuper(firstStatement == null ? symbol.range : firstStatement.range)\n          }\n        }\n      }\n\n      # Global functions and functions on non-virtual types can't be abstract\n      else if !symbol.isImported && !symbol.isObsolete && (symbol.kind == .FUNCTION_GLOBAL || symbol.kind == .FUNCTION_CONSTRUCTOR ||\n          symbol.kind == .FUNCTION_INSTANCE && symbol.parent.kind != .OBJECT_CLASS && symbol.parent.kind != .OBJECT_INTERFACE) {\n        _log.semanticErrorUnimplementedFunction(symbol.range, symbol.name)\n      }\n    }\n\n    def _recordStatistic(symbol Symbol, statistic SymbolStatistic) {\n      if symbol != null && (symbol.kind == .VARIABLE_LOCAL || symbol.kind == .VARIABLE_ARGUMENT) {\n        var info = _localVariableStatistics.get(symbol.id, null)\n        if info != null {\n          switch statistic {\n            case .READ { info.readCount++ }\n            case .WRITE { info.writeCount++ }\n          }\n        }\n      }\n    }\n\n    def _initializeVariable(symbol VariableSymbol) {\n      var value = symbol.value\n\n      # Normal variables may omit the initializer if the type is present\n      if symbol.type != null {\n        _resolveAsParameterizedType(symbol.type, symbol.scope)\n        symbol.resolvedType = symbol.type.resolvedType\n        symbol.state = .INITIALIZED\n\n        # Resolve the constant now so initialized constants always have a value\n        if symbol.isConst && value != null {\n          _resolveAsParameterizedExpressionWithConversion(value, symbol.scope, symbol.resolvedType)\n        }\n      }\n\n      # Enums take their type from their parent\n      else if symbol.kind == .VARIABLE_ENUM_OR_FLAGS {\n        symbol.resolvedType = symbol.parent.resolvedType\n      }\n\n      # Implicitly-typed variables take their type from their initializer\n      else if value != null {\n        _resolveAsParameterizedExpression(value, symbol.scope)\n        var type = value.resolvedType\n        symbol.resolvedType = type\n\n        # Forbid certain types\n        if !_isValidVariableType(type) {\n          _log.semanticErrorBadImplicitVariableType(symbol.range, type)\n          symbol.resolvedType = .DYNAMIC\n        }\n      }\n\n      # Use a different error for constants which must have a type and lambda arguments which cannot have an initializer\n      else if symbol.isConst || symbol.scope.kind == .FUNCTION && symbol.scope.asFunctionScope.symbol.kind == .FUNCTION_LOCAL {\n        _log.semanticErrorVarMissingType(symbol.range, symbol.name)\n        symbol.resolvedType = .DYNAMIC\n      }\n\n      # Variables without a type are an error\n      else {\n        _log.semanticErrorVarMissingValue(symbol.range, symbol.name)\n        symbol.resolvedType = .DYNAMIC\n      }\n\n      # Make sure the symbol has a type node\n      symbol.type ?= Node.createType(symbol.resolvedType)\n\n      _resolveDefines(symbol)\n      _resolveAnnotations(symbol)\n\n      # Run post-annotation checks\n      if symbol.resolvedType != .DYNAMIC && symbol.isConst && !symbol.isImported && value == null && symbol.kind != .VARIABLE_ENUM_OR_FLAGS && symbol.kind != .VARIABLE_INSTANCE {\n        _log.semanticErrorConstMissingValue(symbol.range, symbol.name)\n      }\n    }\n\n    def _resolveVariable(symbol VariableSymbol) {\n      _initializeSymbol(symbol)\n\n      if symbol.value != null {\n        _resolveAsParameterizedExpressionWithConversion(symbol.value, symbol.scope, symbol.resolvedType)\n      }\n\n      # Default-initialize variables\n      else if symbol.kind != .VARIABLE_ARGUMENT && symbol.kind != .VARIABLE_INSTANCE && symbol.kind != .VARIABLE_ENUM_OR_FLAGS {\n        symbol.value = _createDefaultValueForType(symbol.resolvedType, symbol.range)\n      }\n    }\n\n    def _createDefaultValueForType(type Type, range Range) Node {\n      var unwrapped = _cache.unwrappedType(type)\n\n      if unwrapped == _cache.intType {\n        return Node.createInt(0).withType(type)\n      }\n\n      if unwrapped == _cache.doubleType {\n        return Node.createDouble(0).withType(type)\n      }\n\n      if unwrapped == _cache.boolType {\n        return Node.createBool(false).withType(type)\n      }\n\n      if unwrapped.isEnumOrFlags {\n        return Node.createCast(_cache.createInt(0), Node.createType(type)).withType(type)\n      }\n\n      if unwrapped.isParameter {\n        _log.semanticErrorNoDefaultValue(range, type)\n        return null\n      }\n\n      assert(unwrapped.isReference)\n      return Node.createNull.withType(type)\n    }\n\n    def _initializeOverloadedFunction(symbol OverloadedFunctionSymbol) {\n      var symbols = symbol.symbols\n      symbol.resolvedType ?= Type.new(.SYMBOL, symbol)\n\n      # Ensure no two overloads have the same argument types\n      var i = 0\n      while i < symbols.count {\n        var function = symbols[i]\n        _initializeSymbol(function)\n        symbol.flags |= function.flags & .IS_SETTER\n\n        var equivalence TypeCache.Equivalence = .NOT_EQUIVALENT\n        var index = -1\n        for j in 0..i {\n          equivalence = _cache.areFunctionSymbolsEquivalent(function, null, symbols[j], null)\n          if equivalence != .NOT_EQUIVALENT {\n            index = j\n            break\n          }\n        }\n\n        if index == -1 {\n          i++\n          continue\n        }\n\n        var other = symbols[index]\n        var parent = symbol.parent.asObjectSymbol\n        var isFromSameObject = function.parent == other.parent\n        var areReturnTypesDifferent = equivalence == .EQUIVALENT_EXCEPT_RETURN_TYPE && (isFromSameObject || symbol.kind == .OVERLOADED_INSTANCE)\n\n        # Symbols should be in the base type chain\n        assert(parent.isSameOrHasBaseClass(function.parent))\n        assert(parent.isSameOrHasBaseClass(other.parent))\n\n        # Forbid overloading by return type\n        if !isFromSameObject && areReturnTypesDifferent {\n          var derived = function.parent == parent ? function : other\n          var base = derived == function ? other : function\n          _log.semanticErrorBadOverrideReturnType(derived.range, derived.name, parent.baseType, base.range)\n          if isFromSameObject {\n            function.flags |= .IS_OBSOLETE\n          }\n        }\n\n        # Allow duplicate function declarations with the same type to merge\n        # as long as there are not two declarations that provide implementations.\n        # Mark the obsolete function as obsolete instead of removing it so it\n        # doesn't potentially mess up iteration in a parent call stack.\n        else if areReturnTypesDifferent || isFromSameObject && function.block != null && other.block != null {\n          _log.semanticErrorDuplicateOverload(function.range, symbol.name, other.range)\n          if isFromSameObject {\n            function.flags |= .IS_OBSOLETE\n          }\n        }\n\n        # Keep \"function\"\n        else if isFromSameObject ? function.block != null : function.parent.asObjectSymbol.hasBaseClass(other.parent) {\n          if function.parent == parent && other.parent == parent {\n            function.mergeInformationFrom(other)\n            function.flags |= function.block != null ? other.flags & ~.IS_IMPORTED : other.flags\n            other.flags |= .IS_OBSOLETE\n          } else if !isFromSameObject {\n            function.overridden = other\n          }\n          symbols[index] = function\n        }\n\n        # Keep \"other\"\n        else {\n          if function.parent == parent && other.parent == parent {\n            other.flags |= other.block != null ? function.flags & ~.IS_IMPORTED : function.flags\n            other.mergeInformationFrom(function)\n            function.flags |= .IS_OBSOLETE\n          } else if !isFromSameObject {\n            other.overridden = function\n          }\n        }\n\n        # Remove the symbol after the merge\n        symbols.removeAt(i)\n      }\n    }\n\n    # Put the guts of the function inside another function because V8 doesn't\n    # optimize functions with try-catch statements\n    def _resolveNodeSwitch(node Node, scope Scope, context Type) {\n      switch node.kind {\n        case .BLOCK { _resolveBlock(node, scope) }\n        case .PAIR { _resolvePair(node, scope, context) }\n\n        # Statements\n        case .BREAK, .CONTINUE { _resolveJump(node, scope) }\n        case .COMMENT_BLOCK {}\n        case .EXPRESSION { _resolveExpression(node, scope) }\n        case .FOR { _resolveFor(node, scope) }\n        case .FOREACH { _resolveForeach(node, scope) }\n        case .IF { _resolveIf(node, scope) }\n        case .RETURN { _resolveReturn(node, scope) }\n        case .SWITCH { _resolveSwitch(node, scope) }\n        case .THROW { _resolveThrow(node, scope) }\n        case .TRY { _resolveTry(node, scope) }\n        case .VARIABLE { _resolveVariable(node, scope) }\n        case .VARIABLES { _resolveVariables(node, scope) }\n        case .WHILE { _resolveWhile(node, scope) }\n\n        # Expressions\n        case .ASSIGN_INDEX { _resolveOperatorOverload(node, scope, context) }\n        case .CALL { _resolveCall(node, scope, context) }\n        case .CAST { _resolveCast(node, scope, context) }\n        case .COMPLEMENT, .NEGATIVE, .NOT, .POSITIVE, .POSTFIX_DECREMENT, .POSTFIX_INCREMENT, .PREFIX_DECREMENT, .PREFIX_INCREMENT {\n          _resolveOperatorOverload(node, scope, context)\n        }\n        case .CONSTANT { _resolveConstant(node, scope, context) }\n        case .DOT { _resolveDot(node, scope, context) }\n        case .HOOK { _resolveHook(node, scope, context) }\n        case .INDEX { _resolveOperatorOverload(node, scope, context) }\n        case .INITIALIZER_LIST, .INITIALIZER_MAP { _resolveInitializer(node, scope, context) }\n        case .LAMBDA { _resolveLambda(node, scope, context) }\n        case .LAMBDA_TYPE { _resolveLambdaType(node, scope) }\n        case .NAME { _resolveName(node, scope) }\n        case .NULL { node.resolvedType = .NULL }\n        case .NULL_DOT { _resolveNullDot(node, scope) }\n        case .PARAMETERIZE { _resolveParameterize(node, scope) }\n        case .PARSE_ERROR { node.resolvedType = .DYNAMIC }\n        case .SEQUENCE { _resolveSequence(node, scope, context) }\n        case .STRING_INTERPOLATION { _resolveStringInterpolation(node, scope) }\n        case .SUPER { _resolveSuper(node, scope) }\n        case .TYPE {}\n        case .TYPE_CHECK { _resolveTypeCheck(node, scope) }\n        case .XML { _resolveXML(node, scope) }\n\n        default {\n          if node.kind.isBinary { _resolveBinary(node, scope, context) }\n          else { assert(false) }\n        }\n      }\n    }\n\n    def _resolveNode(node Node, scope Scope, context Type) {\n      if node.resolvedType != null {\n        return # Only resolve once\n      }\n\n      node.resolvedType = .DYNAMIC\n      try {\n        _resolveNodeSwitch(node, scope, context)\n      }\n\n      # If guard merging failed, reset the type so we'll try again next time\n      catch failure GuardMergingFailure {\n        node.resolvedType = null\n        throw failure\n      }\n\n      assert(node.resolvedType != null)\n    }\n\n    def _resolveAsParameterizedType(node Node, scope Scope) {\n      assert(node.kind.isExpression)\n      node.flags |= .SHOULD_EXPECT_TYPE\n      _resolveNode(node, scope, null)\n      _checkIsType(node)\n      _checkIsParameterized(node)\n    }\n\n    def _resolveAsParameterizedExpression(node Node, scope Scope) {\n      assert(node.kind.isExpression)\n      _resolveNode(node, scope, null)\n      _checkIsInstance(node)\n      _checkIsParameterized(node)\n    }\n\n    def _resolveAsParameterizedExpressionWithTypeContext(node Node, scope Scope, type Type) {\n      assert(node.kind.isExpression)\n      _resolveNode(node, scope, type)\n      _checkIsInstance(node)\n      _checkIsParameterized(node)\n    }\n\n    def _resolveAsParameterizedExpressionWithConversion(node Node, scope Scope, type Type) {\n      _resolveAsParameterizedExpressionWithTypeContext(node, scope, type)\n      _checkConversion(node, type, .IMPLICIT)\n    }\n\n    def _resolveChildrenAsParameterizedExpressions(node Node, scope Scope) {\n      for child = node.firstChild; child != null; child = child.nextSibling {\n        _resolveAsParameterizedExpression(child, scope)\n      }\n    }\n\n    def _resolveChildrenAsParameterizedExpressionsWithDynamicTypeContext(node Node, scope Scope) {\n      for child = node.firstChild; child != null; child = child.nextSibling {\n        _resolveAsParameterizedExpressionWithTypeContext(child, scope, .DYNAMIC)\n      }\n    }\n\n    def _checkUnusedExpression(node Node) {\n      var kind = node.kind\n      if kind == .HOOK {\n        _checkUnusedExpression(node.hookTrue)\n        _checkUnusedExpression(node.hookFalse)\n      } else if node.range != null && node.resolvedType != .DYNAMIC && kind != .CALL && !kind.isAssign {\n        _log.semanticWarningUnusedExpression(node.range)\n      }\n    }\n\n    def _checkIsInstance(node Node) {\n      if node.resolvedType != .DYNAMIC && node.isType {\n        _log.semanticErrorUnexpectedType(node.range, node.resolvedType)\n        node.resolvedType = .DYNAMIC\n      }\n    }\n\n    def _checkIsType(node Node) {\n      if node.resolvedType != .DYNAMIC && !node.isType {\n        _log.semanticErrorUnexpectedExpression(node.range, node.resolvedType)\n        node.resolvedType = .DYNAMIC\n      }\n    }\n\n    def _checkIsParameterized(node Node) {\n      if node.resolvedType.parameters != null && !node.resolvedType.isParameterized {\n        _log.semanticErrorUnparameterizedType(node.range, node.resolvedType)\n        node.resolvedType = .DYNAMIC\n      }\n    }\n\n    def _checkStorage(node Node, scope Scope) {\n      var symbol = node.symbol\n\n      # Only allow storage to variables\n      if node.kind != .NAME && node.kind != .DOT && (node.kind != .INDEX || node.resolvedType != .DYNAMIC) || symbol != null && !symbol.kind.isVariable {\n        _log.semanticErrorBadStorage(node.range)\n      }\n\n      # Forbid storage to constants\n      else if symbol != null && symbol.isConst {\n        var function = scope.findEnclosingFunction\n\n        # Allow assignments to constants inside constructors\n        if function == null || function.symbol.kind != .FUNCTION_CONSTRUCTOR || function.symbol.parent != symbol.parent || symbol.kind != .VARIABLE_INSTANCE {\n          _log.semanticErrorStorageToConstSymbol(node.internalRangeOrRange, symbol.name)\n        }\n      }\n    }\n\n    def _checkAccess(node Node, range Range, scope Scope) {\n      var symbol = node.symbol\n      if symbol == null {\n        return\n      }\n\n      # Check access control\n      if symbol.isProtected {\n        while scope != null {\n          if scope.kind == .OBJECT {\n            var object = scope.asObjectScope.symbol\n            if object.isSameOrHasBaseClass(symbol.parent) {\n              return\n            }\n          }\n          scope = scope.parent\n        }\n        _log.semanticErrorAccessViolation(range, symbol.name)\n      }\n\n      # Deprecation annotations optionally provide a warning message\n      if symbol.isDeprecated {\n        for annotation in symbol.annotations {\n          if annotation.symbol != null && annotation.symbol.fullName == \"@deprecated\" {\n            var value = annotation.annotationValue\n            if value.kind == .CALL && value.hasTwoChildren {\n              var last = value.lastChild\n              if last.kind == .CONSTANT && last.content.kind == .STRING {\n                _log.append(_log.newWarning(range, last.content.asString))\n                return\n              }\n            }\n          }\n        }\n        _log.semanticWarningDeprecatedUsage(range, symbol.name)\n      }\n    }\n\n    def _checkConversion(node Node, to Type, kind ConversionKind) {\n      var from = node.resolvedType\n      assert(from != null)\n      assert(to != null)\n\n      # The \"dynamic\" type is a hole in the type system\n      if from == .DYNAMIC || to == .DYNAMIC {\n        return\n      }\n\n      # No conversion is needed for identical types\n      if from == to {\n        return\n      }\n\n      # The implicit conversion must be valid\n      if kind == .IMPLICIT && !_cache.canImplicitlyConvert(from, to) ||\n          kind == .EXPLICIT && !_cache.canExplicitlyConvert(from, to) {\n        _log.semanticErrorIncompatibleTypes(node.range, from, to, _cache.canExplicitlyConvert(from, to))\n        node.resolvedType = .DYNAMIC\n        return\n      }\n\n      # Make the implicit conversion explicit for convenience later on\n      if kind == .IMPLICIT {\n        node.become(Node.createCast(node.cloneAndStealChildren, Node.createType(to)).withType(to).withRange(node.range))\n      }\n    }\n\n    def _resolveAnnotation(node Node, symbol Symbol) bool {\n      var value = node.annotationValue\n      var test = node.annotationTest\n\n      _resolveNode(value, symbol.scope, null)\n      if test != null {\n        _resolveAsParameterizedExpressionWithConversion(test, symbol.scope, _cache.boolType)\n      }\n\n      # Terminate early when there were errors\n      if value.symbol == null {\n        return false\n      }\n\n      # Make sure annotations have the arguments they need\n      if value.kind != .CALL {\n        _log.semanticErrorArgumentCount(value.range, value.symbol.resolvedType.argumentTypes.count, 0, value.symbol.name, value.symbol.range)\n        return false\n      }\n\n      # Ensure all arguments are constants\n      var isValid = true\n      for child = value.callValue.nextSibling; child != null; child = child.nextSibling {\n        isValid = isValid && _recursivelyResolveAsConstant(child)\n      }\n      if !isValid {\n        return false\n      }\n\n      # Only store symbols for annotations with the correct arguments for ease of use\n      node.symbol = value.symbol\n\n      # Apply built-in annotation logic\n      var flag = _annotationSymbolFlags.get(value.symbol.fullName, 0)\n      if flag != 0 {\n        switch flag {\n          case .IS_DEPRECATED {}\n          case .IS_ENTRY_POINT { isValid = symbol.kind == .FUNCTION_GLOBAL }\n          case .IS_EXPORTED { isValid = !symbol.isImported }\n          case .IS_IMPORTED { isValid = !symbol.isExported && (!symbol.kind.isFunction || symbol.asFunctionSymbol.block == null) }\n          case .IS_INLINING_FORCED, .IS_INLINING_PREVENTED, .IS_PREFERRED { isValid = symbol.kind.isFunction }\n          case .IS_RENAMED {}\n          case .IS_SKIPPED { isValid = symbol.kind.isFunction && symbol.resolvedType.returnType == null }\n          case .SHOULD_SPREAD { isValid = symbol.kind == .FUNCTION_ANNOTATION }\n        }\n        if flag == .IS_INLINING_FORCED {\n          _options.isAlwaysInlinePresent = true\n        }\n        if !isValid {\n          _log.semanticErrorInvalidAnnotation(value.range, value.symbol.name, symbol.name)\n          return false\n        }\n\n        # Don't add an annotation when the test expression is false\n        if test != null && _recursivelyResolveAsConstant(test) && test.isFalse {\n          return false\n        }\n\n        # Only warn about duplicate annotations after checking the test expression\n        if (symbol.flags & flag) != 0 {\n          if (symbol.parent.flags & flag & (.IS_IMPORTED | .IS_EXPORTED)) != 0 {\n            _log.semanticWarningRedundantAnnotation(value.range, value.symbol.name, symbol.name, symbol.parent.name)\n          } else {\n            _log.semanticWarningDuplicateAnnotation(value.range, value.symbol.name, symbol.name)\n          }\n        }\n\n        symbol.flags |= flag\n\n        # Store the new name for later\n        if flag == .IS_RENAMED && value.hasTwoChildren {\n          symbol.rename = value.lastChild.asString\n        }\n      }\n\n      return true\n    }\n\n    def _recursivelyResolveAsConstant(node Node) bool {\n      _constantFolder.foldConstants(node)\n\n      if node.kind != .CONSTANT {\n        _log.semanticErrorExpectedConstant(node.range)\n        return false\n      }\n\n      return true\n    }\n\n    def _resolveBlock(node Node, scope Scope) {\n      assert(node.kind == .BLOCK)\n      _controlFlow.pushBlock(node)\n\n      for child = node.firstChild, next Node = null; child != null; child = next {\n        var prev = child.previousSibling\n        next = child.nextSibling\n\n        # There is a well-known ambiguity in languages like JavaScript where\n        # a return statement followed by a newline and a value can either be\n        # parsed as a single return statement with a value or as two\n        # statements, a return statement without a value and an expression\n        # statement. Luckily, we're better off than JavaScript since we know\n        # the type of the function. Parse a single statement in a non-void\n        # function but two statements in a void function.\n        if child.kind == .RETURN && next != null && child.returnValue == null && next.kind == .EXPRESSION {\n          var function = scope.findEnclosingFunctionOrLambda.symbol\n          if function.kind != .FUNCTION_CONSTRUCTOR && function.resolvedType.returnType != null {\n            var statement = next.remove\n            var value = statement.expressionValue.remove\n            child.appendChild(value)\n            var trailing = Comment.lastTrailingComment(statement.comments)\n            var notTrailing = Comment.withoutLastTrailingComment(statement.comments)\n            if trailing != null {\n              child.comments = Comment.concat(child.comments, [trailing])\n            }\n            value.comments = Comment.concat(notTrailing, value.comments)\n            next = child.nextSibling\n            assert(child.returnValue != null)\n          }\n        }\n\n        _resolveNode(child, scope, null)\n\n        # Visit control flow from the previous node to the next node, which\n        # should handle the case where this node was replaced with something\n        for n = prev != null ? prev.nextSibling : node.firstChild; n != next; n = n.nextSibling {\n          _controlFlow.visitStatementInPostOrder(n)\n        }\n\n        # Stop now if the child was removed\n        if child.parent == null {\n          continue\n        }\n\n        # The \"@skip\" annotation removes function calls after type checking\n        if child.kind == .EXPRESSION {\n          var value = child.expressionValue\n          if value.kind == .CALL && value.symbol != null && value.symbol.isSkipped {\n            child.remove\n          }\n        }\n      }\n\n      _controlFlow.popBlock(node)\n    }\n\n    def _resolvePair(node Node, scope Scope, context Type) {\n      # Allow resolving a pair with a type context of \"dynamic\" to\n      # deliberately silence errors around needing type context\n      if context == .DYNAMIC {\n        _resolveAsParameterizedExpressionWithConversion(node.firstValue, scope, context)\n        _resolveAsParameterizedExpressionWithConversion(node.secondValue, scope, context)\n        return\n      }\n\n      _resolveAsParameterizedExpression(node.firstValue, scope)\n      _resolveAsParameterizedExpression(node.secondValue, scope)\n    }\n\n    def _resolveJump(node Node, scope Scope) {\n      if scope.findEnclosingLoop == null {\n        _log.semanticErrorBadJump(node.range, node.kind == .BREAK ? \"break\" : \"continue\")\n      }\n    }\n\n    def _resolveExpressionOrImplicitReturn(node Node, value Node, scope Scope) {\n      var hook = _sinkNullDotIntoHook(value, scope, null)\n\n      # Turn top-level \"?.\" expressions into if statements\n      if hook != null {\n        var test = hook.hookTest\n        var yes = hook.hookTrue\n        var block = Node.createBlock.appendChild(Node.createExpression(yes.remove).withRange(yes.range)).withRange(yes.range)\n        node.become(Node.createIf(test.remove, block, null).withRange(node.range).withComments(node.comments))\n        _resolveNode(node, scope, null)\n      }\n\n      # Turn top-level \"?=\" expressions into if statements\n      else if value.kind == .ASSIGN_NULL {\n        var left = value.binaryLeft\n        var right = value.binaryRight\n        _resolveAsParameterizedExpressionWithTypeContext(left, scope, null)\n        _checkStorage(left, scope)\n        var test = Node.createBinary(.EQUAL, _extractExpressionForAssignment(left, scope), Node.createNull).withRange(left.range)\n        var assign = Node.createBinary(.ASSIGN, left.remove, right.remove).withRange(node.range).withFlags(.WAS_ASSIGN_NULL)\n        var block = Node.createBlock.appendChild(Node.createExpression(assign).withRange(node.range)).withRange(node.range)\n        node.become(Node.createIf(test, block, null).withRange(node.range).withComments(node.comments))\n        _resolveNode(node, scope, null)\n      }\n\n      # Normal expression statement\n      else {\n        _resolveAsParameterizedExpression(value, scope)\n      }\n    }\n\n    def _resolveExpression(node Node, scope Scope) {\n      var value = node.expressionValue\n      _resolveExpressionOrImplicitReturn(node, value, scope)\n\n      # Only continue this didn't get turned into an if statement due to a top-level \"?.\" or \"?=\" expression\n      if node.kind == .EXPRESSION {\n        _checkUnusedExpression(value)\n      }\n    }\n\n    def _resolveFor(node Node, scope Scope) {\n      var setup = node.forSetup\n      var update = node.forUpdate\n      scope = LocalScope.new(scope, .LOOP)\n      if setup.kind == .VARIABLES {\n        _resolveNode(setup, scope, null)\n\n        # All for loop variables must have the same type. This is a requirement\n        # for one-to-one code emission in the languages we want to target.\n        var type = setup.firstChild.symbol.resolvedType\n        for child = setup.firstChild.nextSibling; child != null; child = child.nextSibling {\n          var symbol = child.symbol\n          if symbol.resolvedType != type {\n            _log.semanticErrorForLoopDifferentType(symbol.range, symbol.name, symbol.resolvedType, type)\n            break\n          }\n        }\n      } else {\n        _resolveAsParameterizedExpression(setup, scope)\n      }\n      _resolveAsParameterizedExpressionWithConversion(node.forTest, scope, _cache.boolType)\n      _resolveAsParameterizedExpression(update, scope)\n      if update.kind == .SEQUENCE {\n        for child = update.firstChild; child != null; child = child.nextSibling {\n          _checkUnusedExpression(child)\n        }\n      }\n      _resolveBlock(node.forBlock, scope)\n    }\n\n    def _resolveForeach(node Node, scope Scope) {\n      var type Type = .DYNAMIC\n      scope = LocalScope.new(scope, .LOOP)\n\n      var value = node.foreachValue\n      _resolveAsParameterizedExpression(value, scope)\n\n      # Support \"for i in 0..10\"\n      if value.kind == .PAIR {\n        var first = value.firstValue\n        var second = value.secondValue\n        type = _cache.intType\n        _checkConversion(first, _cache.intType, .IMPLICIT)\n        _checkConversion(second, _cache.intType, .IMPLICIT)\n\n        # The \"..\" syntax only counts up, unlike CoffeeScript\n        if first.isInt && second.isInt && first.asInt >= second.asInt {\n          _log.semanticWarningEmptyRange(value.range)\n        }\n      }\n\n      # Support \"for i in [1, 2, 3]\"\n      else if _cache.isList(value.resolvedType) {\n        type = value.resolvedType.substitutions[0]\n      }\n\n      # Anything else is an error\n      else if value.resolvedType != .DYNAMIC {\n        _log.semanticErrorBadForValue(value.range, value.resolvedType)\n      }\n\n      # Special-case symbol initialization with the type\n      var symbol = node.symbol.asVariableSymbol\n      scope.asLocalScope.define(symbol, _log)\n      _localVariableStatistics[symbol.id] = LocalVariableStatistics.new(symbol)\n      symbol.initializeWithType(type)\n      symbol.flags |= .IS_CONST | .IS_LOOP_VARIABLE\n\n      _resolveBlock(node.foreachBlock, scope)\n\n      # Collect foreach loops and convert them in another pass\n      _foreachLoops.append(node)\n    }\n\n    def _resolveIf(node Node, scope Scope) {\n      var test = node.ifTest\n      var ifFalse = node.ifFalse\n      _resolveAsParameterizedExpressionWithConversion(test, scope, _cache.boolType)\n      _resolveBlock(node.ifTrue, LocalScope.new(scope, .NORMAL))\n      if ifFalse != null {\n        _resolveBlock(ifFalse, LocalScope.new(scope, .NORMAL))\n      }\n    }\n\n    def _resolveReturn(node Node, scope Scope) {\n      var value = node.returnValue\n      var function = scope.findEnclosingFunctionOrLambda.symbol\n      var returnType = function.kind != .FUNCTION_CONSTRUCTOR ? function.resolvedType.returnType : null\n\n      # Check for a returned value\n      if value == null {\n        if returnType != null && !function.isDynamicLambda {\n          _log.semanticErrorExpectedReturnValue(node.range, returnType)\n        }\n        return\n      }\n\n      # Check the type of the returned value\n      if returnType != null {\n        _resolveAsParameterizedExpressionWithConversion(value, scope, returnType)\n\n        if function.shouldInferReturnType && _isCallReturningVoid(value) {\n          node.kind = .EXPRESSION\n        }\n        return\n      }\n\n      # If there's no return type, still check for other errors\n      if node.isImplicitReturn {\n        _resolveExpressionOrImplicitReturn(node, value, scope)\n\n        # Stop now if this got turned into an if statement due to a top-level \"?.\" or \"?=\" expression\n        if node.kind != .RETURN {\n          return\n        }\n      } else {\n        _resolveAsParameterizedExpression(value, scope)\n      }\n\n      # Lambdas without a return type or an explicit \"return\" statement get special treatment\n      if !node.isImplicitReturn {\n        _log.semanticErrorUnexpectedReturnValue(value.range)\n        return\n      }\n\n      # Check for a return value of type \"void\"\n      if !function.shouldInferReturnType || _isCallReturningVoid(value) {\n        _checkUnusedExpression(value)\n        node.kind = .EXPRESSION\n        return\n      }\n\n      # Check for an invalid return type\n      var type = value.resolvedType\n      if !_isValidVariableType(type) {\n        _log.semanticErrorBadReturnType(value.range, type)\n        node.kind = .EXPRESSION\n        return\n      }\n\n      # Mutate the return type to the type from the returned value\n      function.returnType = Node.createType(type)\n      function.resolvedType.returnType = type\n    }\n\n    def _resolveSwitch(node Node, scope Scope) {\n      var duplicateCases IntMap<Range> = {}\n      var mustEnsureConstantIntegers = _options.target.requiresIntegerSwitchStatements\n      var allValuesAreIntegers = true\n      var value = node.switchValue\n      _resolveAsParameterizedExpression(value, scope)\n\n      for child = value.nextSibling; child != null; child = child.nextSibling {\n        var block = child.caseBlock\n\n        # Resolve all case values\n        for caseValue = child.firstChild; caseValue != block; caseValue = caseValue.nextSibling {\n          _resolveAsParameterizedExpressionWithConversion(caseValue, scope, value.resolvedType)\n\n          var symbol = caseValue.symbol\n          var integer = 0\n\n          # Check for a constant variable, which may just be read-only with a\n          # value determined at runtime\n          if symbol != null && (mustEnsureConstantIntegers ? symbol.kind == .VARIABLE_ENUM_OR_FLAGS : symbol.kind.isVariable && symbol.isConst) {\n            var constant = _constantFolder.constantForSymbol(symbol.asVariableSymbol)\n            if constant == null || constant.kind != .INT {\n              allValuesAreIntegers = false\n              continue\n            }\n            integer = constant.asInt\n          }\n\n          # Fall back to the constant folder only as a last resort because it\n          # mutates the syntax tree and harms readability\n          else {\n            _constantFolder.foldConstants(caseValue)\n            if !caseValue.isInt {\n              allValuesAreIntegers = false\n              continue\n            }\n            integer = caseValue.asInt\n          }\n\n          # Duplicate case detection\n          var previous = duplicateCases.get(integer, null)\n          if previous != null {\n            _log.semanticErrorDuplicateCase(caseValue.range, previous)\n          } else {\n            duplicateCases[integer] = caseValue.range\n          }\n        }\n\n        # The default case must be last, makes changing into an if chain easier later\n        if child.hasOneChild && child.nextSibling != null {\n          _log.semanticErrorDefaultCaseNotLast(child.range)\n        }\n\n        _resolveBlock(block, LocalScope.new(scope, .NORMAL))\n      }\n\n      # Fall back to an if statement if the case values aren't compile-time\n      # integer constants, which is requried by many language targets\n      if !allValuesAreIntegers && mustEnsureConstantIntegers {\n        _convertSwitchToIfChain(node, scope)\n      }\n    }\n\n    def _resolveThrow(node Node, scope Scope) {\n      var value = node.throwValue\n      _resolveAsParameterizedExpression(value, scope)\n    }\n\n    def _resolveVariable(node Node, scope Scope) {\n      var symbol = node.symbol.asVariableSymbol\n      scope.asLocalScope.define(symbol, _log)\n      _localVariableStatistics[symbol.id] = LocalVariableStatistics.new(symbol)\n      _resolveVariable(symbol)\n\n      # Make sure to parent any created values under the variable node\n      if !node.hasChildren && symbol.value != null {\n        node.appendChild(symbol.value)\n      }\n    }\n\n    def _resolveVariables(node Node, scope Scope) {\n      for child = node.firstChild; child != null; child = child.nextSibling {\n        _resolveVariable(child, scope)\n      }\n    }\n\n    def _resolveTry(node Node, scope Scope) {\n      var tryBlock = node.tryBlock\n      var finallyBlock = node.finallyBlock\n      _resolveBlock(tryBlock, LocalScope.new(scope, .NORMAL))\n\n      # Bare try statements catch all thrown values\n      if node.hasOneChild {\n        node.appendChild(Node.createCatch(null, Node.createBlock))\n      }\n\n      # Check catch statements\n      for child = tryBlock.nextSibling; child != finallyBlock; child = child.nextSibling {\n        var childScope = LocalScope.new(scope, .NORMAL)\n        if child.symbol != null {\n          var symbol = child.symbol.asVariableSymbol\n          childScope.define(symbol, _log)\n          _resolveVariable(symbol)\n        }\n        _resolveBlock(child.catchBlock, childScope)\n      }\n\n      # Check finally block\n      if finallyBlock != null {\n        _resolveBlock(finallyBlock, LocalScope.new(scope, .NORMAL))\n      }\n    }\n\n    def _resolveWhile(node Node, scope Scope) {\n      _resolveAsParameterizedExpressionWithConversion(node.whileTest, scope, _cache.boolType)\n      _resolveBlock(node.whileBlock, LocalScope.new(scope, .LOOP))\n    }\n\n    def _resolveCall(node Node, scope Scope, context Type) {\n      var hook = _sinkNullDotIntoHook(node, scope, context)\n      if hook != null {\n        node.become(hook)\n        _resolveAsParameterizedExpressionWithTypeContext(node, scope, context)\n        return\n      }\n\n      var value = node.callValue\n\n      # Take argument types from call argument values for immediately-invoked\n      # function expressions:\n      #\n      #   var foo = ((a, b) => a + b)(1, 2)\n      #   var bar int = ((a, b) => { return a + b })(1, 2)\n      #\n      if value.kind == .LAMBDA {\n        var symbol = value.symbol.asFunctionSymbol\n        var arguments = symbol.arguments\n        if node.childCount == arguments.count + 1 {\n          var child = value.nextSibling\n          for i in 0..arguments.count {\n            var argument = arguments[i]\n            if argument.type == null {\n              _resolveAsParameterizedExpression(child, scope)\n              argument.type = Node.createType(child.resolvedType)\n            }\n            child = child.nextSibling\n          }\n          if context != null && symbol.returnType == null {\n            symbol.returnType = Node.createType(context)\n          }\n        }\n      }\n\n      _resolveAsParameterizedExpression(value, scope)\n      var type = value.resolvedType\n\n      switch type.kind {\n        # Each function has its own type for simplicity\n        case .SYMBOL {\n          if _resolveSymbolCall(node, scope, type) {\n            return\n          }\n        }\n\n        # Lambda types look like \"fn(int, int) int\"\n        case .LAMBDA {\n          if _resolveFunctionCall(node, scope, type) {\n            return\n          }\n        }\n\n        # Can't call other types (the null type, for example)\n        default {\n          if type != .DYNAMIC {\n            _log.semanticErrorInvalidCall(node.internalRangeOrRange, value.resolvedType)\n          }\n        }\n      }\n\n      # If there was an error, resolve the arguments to check for further\n      # errors but use a dynamic type context to avoid introducing errors\n      for child = value.nextSibling; child != null; child = child.nextSibling {\n        _resolveAsParameterizedExpressionWithConversion(child, scope, .DYNAMIC)\n      }\n    }\n\n    def _resolveSymbolCall(node Node, scope Scope, type Type) bool {\n      var symbol = type.symbol\n\n      # Getters are called implicitly, so explicitly calling one is an error.\n      # This error prevents a getter returning a lambda which is then called.\n      # To overcome this, wrap the call in parentheses:\n      #\n      #   def foo fn()\n      #\n      #   def bar {\n      #     foo()   # Error\n      #     (foo)() # Correct\n      #   }\n      #\n      if symbol.isGetter && _isCallValue(node) && !node.callValue.isInsideParentheses {\n        if symbol.resolvedType.returnType != null && symbol.resolvedType.returnType.kind == .LAMBDA {\n          _log.semanticErrorGetterRequiresWrap(node.range, symbol.name, symbol.range)\n        } else {\n          _log.semanticErrorGetterCalledTwice(node.parent.internalRangeOrRange, symbol.name, symbol.range)\n        }\n        _resolveChildrenAsParameterizedExpressionsWithDynamicTypeContext(node, scope)\n        return false\n      }\n\n      # Check for calling a function directly\n      if symbol.kind.isFunction {\n        return _resolveFunctionCall(node, scope, type)\n      }\n\n      # Check for calling a set of functions, must not be ambiguous\n      if symbol.kind.isOverloadedFunction {\n        return _resolveOverloadedFunctionCall(node, scope, type)\n      }\n\n      # Can't call other symbols\n      _log.semanticErrorInvalidCall(node.internalRangeOrRange, node.callValue.resolvedType)\n      return false\n    }\n\n    def _resolveFunctionCall(node Node, scope Scope, type Type) bool {\n      var function = type.symbol?.asFunctionSymbol\n      var expected = type.argumentTypes.count\n      var count = node.childCount - 1\n      node.symbol = function\n\n      # Use the return type even if there were errors\n      if type.returnType != null {\n        node.resolvedType = type.returnType\n      }\n\n      # There is no \"void\" type, so make sure this return value isn't used\n      else if _isExpressionUsed(node) {\n        if function != null {\n          _log.semanticErrorUseOfVoidFunction(node.range, function.name, function.range)\n        } else {\n          _log.semanticErrorUseOfVoidLambda(node.range)\n        }\n      }\n\n      # Check argument count\n      if expected != count {\n        _log.semanticErrorArgumentCount(node.internalRangeOrRange, expected, count, function?.name, function?.range)\n        _resolveChildrenAsParameterizedExpressionsWithDynamicTypeContext(node, scope)\n        return false\n      }\n\n      # Check argument types\n      var value = node.firstChild\n      var child = value.nextSibling\n      for argumentType in type.argumentTypes {\n        _resolveAsParameterizedExpressionWithConversion(child, scope, argumentType)\n        child = child.nextSibling\n      }\n\n      # Forbid constructing an abstract type\n      if function != null && function.kind == .FUNCTION_CONSTRUCTOR && value.kind != .SUPER {\n        _checkInterfacesAndAbstractStatus(function.parent.asObjectSymbol)\n        var reason = function.parent.asObjectSymbol.isAbstractBecauseOf\n        if reason != null {\n          _log.semanticErrorAbstractNew(node.internalRangeOrRange, function.parent.resolvedType, reason.range, reason.name)\n        }\n      }\n\n      # Replace overloaded symbols with the chosen overload\n      if value.kind == .PARAMETERIZE {\n        value = value.parameterizeValue\n      }\n      if function != null && value.symbol != null && value.symbol.kind.isOverloadedFunction && function in value.symbol.asOverloadedFunctionSymbol.symbols {\n        value.symbol = function\n        value.resolvedType = type\n      }\n\n      return true\n    }\n\n    def _resolveOverloadedFunction(range Range, node Node, scope Scope, symbolType Type) Type {\n      var overloaded = symbolType.symbol.asOverloadedFunctionSymbol\n      var firstArgument = node.firstChild.nextSibling\n      var count = node.childCount - 1\n      var candidates List<Type> = []\n\n      # Filter by argument length and substitute using the current type environment\n      for symbol in overloaded.symbols {\n        if symbol.arguments.count == count || overloaded.symbols.count == 1 {\n          candidates.append(_cache.substitute(symbol.resolvedType, symbolType.environment))\n        }\n      }\n\n      # Check for matches\n      if candidates.isEmpty {\n        _log.semanticErrorNoMatchingOverload(range, overloaded.name, count, null)\n        return null\n      }\n\n      # Check for an unambiguous match\n      if candidates.count == 1 {\n        return candidates[0]\n      }\n\n      # First filter by syntactic structure impossibilities. This helps break\n      # the chicken-and-egg problem of needing to resolve argument types to\n      # get a match and needing a match to resolve argument types. For example,\n      # a list literal needs type context to resolve correctly.\n      var index = 0\n      while index < candidates.count {\n        var child = firstArgument\n        for type in candidates[index].argumentTypes {\n          var kind = child.kind\n          if kind == .NULL && !type.isReference ||\n              kind == .INITIALIZER_LIST && _findMember(type, \"[new]\") == null && _findMember(type, \"[...]\") == null ||\n              kind == .INITIALIZER_MAP && _findMember(type, \"{new}\") == null && _findMember(type, \"{...}\") == null ||\n              kind == .LAMBDA && (type.kind != .LAMBDA || type.argumentTypes.count != child.symbol.asFunctionSymbol.arguments.count) {\n            candidates.removeAt(index)\n            index--\n            break\n          }\n          child = child.nextSibling\n        }\n        index++\n      }\n\n      # Check for an unambiguous match\n      if candidates.count == 1 {\n        return candidates[0]\n      }\n\n      # If that still didn't work, resolve the arguments without type context\n      for child = firstArgument; child != null; child = child.nextSibling {\n        _resolveAsParameterizedExpression(child, scope)\n      }\n\n      # Try again, this time discarding all implicit conversion failures\n      index = 0\n      while index < candidates.count {\n        var child = firstArgument\n        for type in candidates[index].argumentTypes {\n          if !_cache.canImplicitlyConvert(child.resolvedType, type) {\n            candidates.removeAt(index)\n            index--\n            break\n          }\n          child = child.nextSibling\n        }\n        index++\n      }\n\n      # Check for an unambiguous match\n      if candidates.count == 1 {\n        return candidates[0]\n      }\n\n      # Extract argument types for an error if there is one\n      var childTypes List<Type> = []\n      for child = firstArgument; child != null; child = child.nextSibling {\n        childTypes.append(child.resolvedType)\n      }\n\n      # Give up without a match\n      if candidates.isEmpty {\n        _log.semanticErrorNoMatchingOverload(range, overloaded.name, count, childTypes)\n        return null\n      }\n\n      # If that still didn't work, try type equality\n      for type in candidates {\n        var isMatch = true\n        for i in 0..count {\n          if childTypes[i] != type.argumentTypes[i] {\n            isMatch = false\n            break\n          }\n        }\n        if isMatch {\n          return type\n        }\n      }\n\n      # If that still didn't work, try picking the preferred overload\n      var firstPreferred Type = null\n      var secondPreferred Type = null\n      for type in candidates {\n        if type.symbol.isPreferred {\n          secondPreferred = firstPreferred\n          firstPreferred = type\n        }\n      }\n\n      # Check for a single preferred overload\n      if firstPreferred != null && secondPreferred == null {\n        return firstPreferred\n      }\n\n      # Give up since the overload is ambiguous\n      _log.semanticErrorAmbiguousOverload(range, overloaded.name, count, childTypes)\n      return null\n    }\n\n    def _resolveOverloadedFunctionCall(node Node, scope Scope, type Type) bool {\n      var match = _resolveOverloadedFunction(node.callValue.range, node, scope, type)\n      if match != null && _resolveFunctionCall(node, scope, match) {\n        _checkAccess(node, node.callValue.internalRangeOrRange, scope)\n        return true\n      }\n      return false\n    }\n\n    def _resolveCast(node Node, scope Scope, context Type) {\n      var value = node.castValue\n      var type = node.castType\n      var neededTypeContext = _needsTypeContext(value)\n\n      _resolveAsParameterizedType(type, scope)\n      _resolveAsParameterizedExpressionWithTypeContext(value, scope, type.resolvedType)\n      _checkConversion(value, type.resolvedType, .EXPLICIT)\n      node.resolvedType = type.resolvedType\n\n      # Warn about unnecessary casts\n      var range = node.internalRangeOrRange\n      if range != null && type.resolvedType != .DYNAMIC && value.resolvedType != .DYNAMIC && !neededTypeContext && (\n          value.resolvedType == type.resolvedType || context == type.resolvedType && _cache.canImplicitlyConvert(value.resolvedType, type.resolvedType)) {\n        _log.semanticWarningExtraCast(Range.span(range, type.range), value.resolvedType, type.resolvedType)\n      }\n    }\n\n    def _resolveConstant(node Node, scope Scope, context Type) {\n      switch node.content.kind {\n        case .BOOL { node.resolvedType = _cache.boolType }\n        case .DOUBLE { node.resolvedType = _cache.doubleType }\n        case .STRING { node.resolvedType = _cache.stringType }\n\n        # The literal \"0\" represents the empty set for \"flags\" types\n        case .INT { node.resolvedType = context != null && context.isFlags && node.asInt == 0 ? context : _cache.intType }\n\n        default { assert(false) }\n      }\n    }\n\n    def _findMember(type Type, name string) Symbol {\n      if type.kind == .SYMBOL {\n        var symbol = type.symbol\n\n        if symbol.kind.isObject {\n          var member = symbol.asObjectSymbol.members.get(name, null)\n\n          if member != null {\n            _initializeSymbol(member)\n            return member\n          }\n        }\n      }\n\n      return null\n    }\n\n    def _sinkNullDotIntoHook(node Node, scope Scope, context Type) Node {\n      var nullDot = node\n\n      # Search down the chain of dot accesses and calls for \"?.\" expression\n      while true {\n        if nullDot.kind == .DOT && nullDot.dotTarget != null {\n          nullDot = nullDot.dotTarget\n        } else if nullDot.kind == .CALL {\n          nullDot = nullDot.callValue\n        } else {\n          break\n        }\n      }\n\n      # Stop if this isn't a \"?.\" expression after all\n      if nullDot.kind != .NULL_DOT {\n        return null\n      }\n\n      # Wrap everything in a null check\n      var target = nullDot.dotTarget.remove\n      _resolveAsParameterizedExpression(target, scope)\n      var test = Node.createBinary(.NOT_EQUAL, _extractExpression(target, scope), Node.createNull.withRange(nullDot.internalRange)).withRange(target.range)\n      var dot = Node.createDot(target, nullDot.asString).withRange(nullDot.range).withInternalRange(nullDot.internalRange)\n      var hook = Node.createHook(test, dot, Node.createNull.withRange(nullDot.internalRangeOrRange)).withRange(nullDot.range)\n      nullDot.become(hook.hookTrue.clone)\n      node.resolvedType = null # This is necessary to trigger the resolve below\n      hook.hookTrue.become(node.cloneAndStealChildren)\n      return hook\n    }\n\n    enum CompletionCheck {\n      NORMAL\n      INSTANCE_ONLY\n      GLOBAL_ONLY\n    }\n\n    def _checkForMemberCompletions(type Type, range Range, name string, check CompletionCheck) {\n      assert(type != null)\n      var completionContext = _options.completionContext\n\n      if completionContext != null && range != null && range.source == completionContext.source &&\n          range.touches(completionContext.index) && type.kind == .SYMBOL && type.symbol.kind.isObject {\n        var prefix = name.slice(0, completionContext.index - range.start)\n        var object = type.symbol.asObjectSymbol\n\n        _initializeSymbol(object)\n        completionContext.range = range\n\n        for member in object.members.values {\n          var isOnInstances = member.kind.isOnInstances\n          if (check == .INSTANCE_ONLY ? isOnInstances : check == .GLOBAL_ONLY ? !isOnInstances : true) && _matchCompletion(member, prefix) {\n            _initializeSymbol(member)\n            completionContext.addCompletion(member)\n          }\n        }\n      }\n    }\n\n    def _checkForScopeCompletions(scope Scope, range Range, name string, thisObject ObjectSymbol) {\n      var completionContext = _options.completionContext\n\n      if completionContext != null && range != null && range.source == completionContext.source && range.touches(completionContext.index) {\n        var prefix = name.slice(0, completionContext.index - range.start)\n\n        completionContext.range = range\n\n        while scope != null {\n          switch scope.kind {\n            case .OBJECT {\n              var object = scope.asObjectScope.symbol\n              for symbol in object.members.values {\n                if _matchCompletion(symbol, prefix) && (!symbol.kind.isOnInstances || object == thisObject) {\n                  _initializeSymbol(symbol)\n                  completionContext.addCompletion(symbol)\n                }\n              }\n            }\n\n            case .FUNCTION {\n              for symbol in scope.asFunctionScope.parameters.values {\n                if _matchCompletion(symbol, prefix) {\n                  _initializeSymbol(symbol)\n                  completionContext.addCompletion(symbol)\n                }\n              }\n            }\n\n            case .LOCAL {\n              for symbol in scope.asLocalScope.locals.values {\n                if _matchCompletion(symbol, prefix) {\n                  _initializeSymbol(symbol)\n                  completionContext.addCompletion(symbol)\n                }\n              }\n            }\n          }\n\n          scope = scope.parent\n        }\n      }\n    }\n\n    def _resolveDot(node Node, scope Scope, context Type) {\n      var hook = _sinkNullDotIntoHook(node, scope, context)\n      if hook != null {\n        node.become(hook)\n        _resolveAsParameterizedExpressionWithTypeContext(node, scope, context)\n        return\n      }\n\n      var target = node.dotTarget\n      var name = node.asString\n\n      # Resolve the target if present\n      if target != null {\n        _resolveNode(target, scope, null)\n\n        # Support IDE code completion\n        _checkForMemberCompletions(target.resolvedType, node.internalRange, name, target.isType ? .GLOBAL_ONLY : .INSTANCE_ONLY)\n      }\n\n      # Ignore parse errors (the syntax tree is kept around for code completion)\n      if name == \"\" {\n        return\n      }\n\n      # Infer the target from the type context if it's omitted\n      if target == null {\n        if context == null {\n          _log.semanticErrorMissingDotContext(node.range, name)\n          return\n        }\n        target = Node.createType(context)\n        node.appendChild(target)\n        assert(node.dotTarget == target)\n\n        # Support IDE code completion\n        _checkForMemberCompletions(target.resolvedType, node.internalRange, name, target.isType ? .GLOBAL_ONLY : .INSTANCE_ONLY)\n      }\n\n      # Search for a setter first, then search for a normal member\n      var symbol Symbol = null\n      if _shouldCheckForSetter(node) {\n        symbol = _findMember(target.resolvedType, name + \"=\")\n      }\n      if symbol == null {\n        symbol = _findMember(target.resolvedType, name)\n        if symbol == null {\n          # Symbol lookup failure\n          if target.resolvedType != .DYNAMIC {\n            var type = target.resolvedType\n            var correction = type.kind != .SYMBOL || !type.symbol.kind.isObject ? null :\n              type.symbol.asObjectSymbol.scope.findWithFuzzyMatching(name, target.isType ? .GLOBAL_ONLY : .INSTANCE_ONLY, .SELF_ONLY)\n            _reportGuardMergingFailure(node)\n            _log.semanticErrorUnknownMemberSymbol(node.internalRangeOrRange, name, target.resolvedType, correction?.name, correction?.range)\n          }\n\n          # Dynamic symbol access\n          else {\n            # Make sure to warn when accessing a symbol at statement level without using it\n            if node.parent != null && node.parent.kind == .EXPRESSION {\n              _log.semanticWarningUnusedExpression(node.range)\n            }\n\n            # \"dynamic.foo\" => \"foo\"\n            if target.kind == .TYPE {\n              node.kind = .NAME\n              node.removeChildren\n            }\n\n            # \"Foo.new\" => \"Foo.new()\"\n            # \"Foo.new()\" => \"Foo.new()\"\n            else if name == \"new\" && !_isCallValue(node) {\n              node.become(Node.createCall(node.cloneAndStealChildren).withType(.DYNAMIC).withRange(node.range))\n            }\n          }\n\n          return\n        }\n      }\n\n      # Forbid referencing a base class global or constructor function from a derived class\n      if _isBaseGlobalReference(target.resolvedType.symbol, symbol) {\n        _log.semanticErrorUnknownMemberSymbol(node.range, name, target.resolvedType, symbol.fullName, symbol.range)\n        return\n      }\n\n      var isType = target.isType\n      var needsType = !symbol.kind.isOnInstances\n\n      # Make sure the global/instance context matches the intended usage\n      if isType {\n        if !needsType {\n          _log.semanticErrorMemberUnexpectedInstance(node.internalRangeOrRange, symbol.name)\n        } else if symbol.kind.isFunctionOrOverloadedFunction {\n          _checkIsParameterized(target)\n        } else if target.resolvedType.isParameterized {\n          _log.semanticErrorParameterizedType(target.range, target.resolvedType)\n        }\n      } else if needsType {\n        _log.semanticErrorMemberUnexpectedGlobal(node.internalRangeOrRange, symbol.name)\n      }\n\n      # Always access referenced globals directly\n      if !_options.stopAfterResolve && symbol.kind.isGlobalReference {\n        node.kind = .NAME\n        node.removeChildren\n      }\n\n      node.symbol = symbol\n      node.resolvedType = _cache.substitute(symbol.resolvedType, target.resolvedType.environment)\n      _automaticallyCallGetter(node, scope)\n    }\n\n    def _resolveHook(node Node, scope Scope, context Type) {\n      _resolveAsParameterizedExpressionWithConversion(node.hookTest, scope, _cache.boolType)\n\n      var trueValue = node.hookTrue\n      var falseValue = node.hookFalse\n\n      # Use the type context from the parent\n      if context != null {\n        _resolveAsParameterizedExpressionWithConversion(trueValue, scope, context)\n        _resolveAsParameterizedExpressionWithConversion(falseValue, scope, context)\n        node.resolvedType = context\n      }\n\n      # Find the common type from both branches\n      else {\n        _resolveAsParameterizedExpression(trueValue, scope)\n        _resolveAsParameterizedExpression(falseValue, scope)\n        var commonType = _cache.commonImplicitType(trueValue.resolvedType, falseValue.resolvedType)\n\n        # Insert casts if needed since some targets can't perform this type inference\n        if commonType != null {\n          _checkConversion(trueValue, commonType, .IMPLICIT)\n          _checkConversion(falseValue, commonType, .IMPLICIT)\n          node.resolvedType = commonType\n        } else {\n          _log.semanticErrorNoCommonType(Range.span(trueValue.range, falseValue.range), trueValue.resolvedType, falseValue.resolvedType)\n        }\n      }\n\n      # Check for likely bugs where both branches look the same\n      if trueValue.looksTheSameAs(falseValue) {\n        _log.semanticWarningIdenticalOperands(Range.span(trueValue.range, falseValue.range), node.wasNullJoin ? \"??\" : \":\")\n      }\n    }\n\n    def _resolveInitializer(node Node, scope Scope, context Type) {\n      # Make sure to resolve the children even if the initializer is invalid\n      if context != null {\n        if context == .DYNAMIC || !_resolveInitializerWithContext(node, scope, context) {\n          _resolveChildrenAsParameterizedExpressionsWithDynamicTypeContext(node, scope)\n        }\n        return\n      }\n\n      # First pass: only children with type context, second pass: all children\n      for pass in 0..2 {\n        switch node.kind {\n          case .INITIALIZER_LIST {\n            var type Type = null\n\n            # Resolve all children for this pass\n            for child = node.firstChild; child != null; child = child.nextSibling {\n              if pass != 0 || !_needsTypeContext(child) {\n                _resolveAsParameterizedExpression(child, scope)\n                type = _mergeCommonType(type, child)\n              }\n            }\n\n            # Resolve remaining children using the type context if valid\n            if type != null && _isValidVariableType(type) {\n              _resolveInitializerWithContext(node, scope, _cache.createListType(type))\n              return\n            }\n          }\n\n          case .INITIALIZER_MAP {\n            var keyType Type = null\n            var valueType Type = null\n\n            # Resolve all children for this pass\n            for child = node.firstChild; child != null; child = child.nextSibling {\n              var key = child.firstValue\n              var value = child.secondValue\n              if pass != 0 || !_needsTypeContext(key) {\n                _resolveAsParameterizedExpression(key, scope)\n                keyType = _mergeCommonType(keyType, key)\n              }\n              if pass != 0 || !_needsTypeContext(value) {\n                _resolveAsParameterizedExpression(value, scope)\n                valueType = _mergeCommonType(valueType, value)\n              }\n            }\n\n            # Resolve remaining children using the type context if valid\n            if keyType != null && valueType != null && _isValidVariableType(valueType) {\n              assert(!_cache.isEquivalentToInt(keyType) || !_cache.isEquivalentToString(keyType))\n              if _cache.isEquivalentToInt(keyType) {\n                _resolveInitializerWithContext(node, scope, _cache.createIntMapType(valueType))\n                return\n              }\n              if _cache.isEquivalentToString(keyType) {\n                _resolveInitializerWithContext(node, scope, _cache.createStringMapType(valueType))\n                return\n              }\n            }\n          }\n        }\n      }\n\n      _log.semanticErrorInitializerTypeInferenceFailed(node.range)\n      _resolveChildrenAsParameterizedExpressionsWithDynamicTypeContext(node, scope)\n    }\n\n    def _resolveInitializerWithContext(node Node, scope Scope, context Type) bool {\n      var isList = node.kind == .INITIALIZER_LIST\n      var new = _findMember(context, isList ? \"[new]\" : \"{new}\")\n      var add = _findMember(context, isList ? \"[...]\" : \"{...}\")\n\n      # Special-case imported literals to prevent an infinite loop for list literals\n      if add != null && add.isImported {\n        var function = add.asFunctionSymbol\n        if function.arguments.count == (isList ? 1 : 2) {\n          var functionType = _cache.substitute(function.resolvedType, context.environment)\n          for child = node.firstChild; child != null; child = child.nextSibling {\n            if child.kind == .PAIR {\n              _resolveAsParameterizedExpressionWithConversion(child.firstValue, scope, functionType.argumentTypes[0])\n              _resolveAsParameterizedExpressionWithConversion(child.secondValue, scope, functionType.argumentTypes[1])\n              child.resolvedType = .DYNAMIC\n            } else {\n              _resolveAsParameterizedExpressionWithConversion(child, scope, functionType.argumentTypes[0])\n            }\n          }\n          node.resolvedType = context\n          return true\n        }\n      }\n\n      # Use simple call chaining when there's an add operator present\n      if add != null {\n        var type = Node.createType(context).withRange(node.range).withFlags(.IS_IGNORED_BY_IDE)\n        var chain = Node.createDot(type, new != null ? new.name : \"new\").withRange(node.range).withFlags(.IS_IGNORED_BY_IDE)\n        while node.hasChildren {\n          var child = node.firstChild.remove\n          var dot = Node.createDot(chain, add.name).withRange(child.range).withFlags(.IS_IGNORED_BY_IDE)\n          chain = Node.createCall(dot).withRange(child.range).withFlags(.IS_IGNORED_BY_IDE)\n          if child.kind == .PAIR {\n            chain.appendChildrenFrom(child)\n          } else {\n            chain.appendChild(child)\n          }\n        }\n        node.become(chain)\n        _resolveAsParameterizedExpressionWithConversion(node, scope, context)\n        return true\n      }\n\n      # Make sure there's a constructor to call\n      if new == null {\n        # Avoid emitting an extra error when the constructor doesn't have the right type:\n        #\n        #   def main Foo {\n        #     return []\n        #   }\n        #\n        #   class Foo {\n        #     def [new](x int) {}\n        #   }\n        #\n        if !node.isInitializerExpansion {\n          _log.semanticErrorInitializerTypeInferenceFailed(node.range)\n        }\n        return false\n      }\n\n      # Avoid infinite expansion\n      if node.isInitializerExpansion {\n        _log.semanticErrorInitializerRecursiveExpansion(node.range, new.range)\n        return false\n      }\n\n      var dot = Node.createDot(Node.createType(context).withRange(node.range), new.name).withRange(node.range)\n\n      # Call the initializer constructor\n      if node.kind == .INITIALIZER_MAP {\n        var firstValues = Node.createList.withFlags(.IS_INITIALIZER_EXPANSION).withRange(node.range)\n        var secondValues = Node.createList.withFlags(.IS_INITIALIZER_EXPANSION).withRange(node.range)\n        for child = node.firstChild; child != null; child = child.nextSibling {\n          var first = child.firstValue\n          var second = child.secondValue\n          firstValues.appendChild(first.remove)\n          secondValues.appendChild(second.remove)\n        }\n        node.become(Node.createCall(dot).withRange(node.range).appendChild(firstValues).appendChild(secondValues))\n      } else {\n        var values = Node.createList.withFlags(.IS_INITIALIZER_EXPANSION).withRange(node.range)\n        node.become(Node.createCall(dot).withRange(node.range).appendChild(values.appendChildrenFrom(node)))\n      }\n      _resolveAsParameterizedExpressionWithConversion(node, scope, context)\n      return true\n    }\n\n    def _mergeCommonType(commonType Type, child Node) Type {\n      if commonType == null || child.resolvedType == .DYNAMIC {\n        return child.resolvedType\n      }\n\n      var result = _cache.commonImplicitType(commonType, child.resolvedType)\n      if result != null {\n        return result\n      }\n\n      _log.semanticErrorNoCommonType(child.range, commonType, child.resolvedType)\n      return .DYNAMIC\n    }\n\n    def _resolveLambda(node Node, scope Scope, context Type) {\n      var symbol = node.symbol.asFunctionSymbol\n      symbol.scope = FunctionScope.new(scope, symbol)\n\n      # Use type context to implicitly set missing types\n      if context != null && context.kind == .LAMBDA {\n\n        # Copy over the argument types if they line up\n        if context.argumentTypes.count == symbol.arguments.count {\n          for i in 0..symbol.arguments.count {\n            symbol.arguments[i].type ?= Node.createType(context.argumentTypes[i])\n          }\n        }\n\n        # Copy over the return type\n        if symbol.returnType == null && context.returnType != null {\n          symbol.returnType = Node.createType(context.returnType)\n        }\n      }\n\n      else {\n        # Only infer non-void return types if there's no type context\n        if symbol.returnType == null {\n          symbol.flags |= .SHOULD_INFER_RETURN_TYPE\n        }\n\n        # If there's dynamic type context, treat all arguments as dynamic\n        if context == .DYNAMIC {\n          for argument in symbol.arguments {\n            argument.type ?= Node.createType(.DYNAMIC)\n          }\n          symbol.returnType ?= Node.createType(.DYNAMIC)\n          symbol.flags |= .IS_DYNAMIC_LAMBDA\n        }\n      }\n\n      _resolveFunction(symbol)\n\n      # Use a LambdaType instead of a SymbolType for the node\n      var argumentTypes List<Type> = []\n      var returnType = symbol.returnType\n      for argument in symbol.arguments {\n        argumentTypes.append(argument.resolvedType)\n      }\n      node.resolvedType = _cache.createLambdaType(argumentTypes, returnType?.resolvedType)\n    }\n\n    def _resolveLambdaType(node Node, scope Scope) {\n      var lambdaReturnType = node.lambdaReturnType\n      var argumentTypes List<Type> = []\n      var returnType Type = null\n\n      for child = node.firstChild; child != lambdaReturnType; child = child.nextSibling {\n        _resolveAsParameterizedType(child, scope)\n        argumentTypes.append(child.resolvedType)\n      }\n\n      # An empty return type is signaled by the type \"null\"\n      if lambdaReturnType.kind != .TYPE || lambdaReturnType.resolvedType != .NULL {\n        _resolveAsParameterizedType(lambdaReturnType, scope)\n        returnType = lambdaReturnType.resolvedType\n      }\n\n      node.resolvedType = _cache.createLambdaType(argumentTypes, returnType)\n    }\n\n    def _resolveName(node Node, scope Scope) {\n      var enclosingFunction = scope.findEnclosingFunction\n      var thisVariable = enclosingFunction?.symbol.this\n      var name = node.asString\n\n      # Support IDE code completion\n      _checkForScopeCompletions(scope, node.range, name, thisVariable != null ? enclosingFunction.symbol.parent.asObjectSymbol : null)\n      if thisVariable != null {\n        _checkForMemberCompletions(thisVariable.resolvedType, node.range, name, .NORMAL)\n      }\n\n      var symbol = scope.find(name, _shouldCheckForSetter(node) ? .ALSO_CHECK_FOR_SETTER : .NORMAL)\n\n      if symbol == null {\n        _reportGuardMergingFailure(node)\n\n        if name == \"this\" && thisVariable != null {\n          _log.semanticErrorUndeclaredSelfSymbol(node.range, name)\n        }\n\n        else {\n          var correction = scope.findWithFuzzyMatching(name, node.shouldExpectType ? .TYPE_ONLY : thisVariable != null ? .EVERYTHING : .GLOBAL_ONLY, .SELF_AND_PARENTS)\n          _log.semanticErrorUndeclaredSymbol(node.range, name, correction == null ? null : enclosingFunction != null &&\n            _isBaseGlobalReference(enclosingFunction.symbol.parent, correction) ? correction.fullName : correction.name, correction?.range)\n        }\n        return\n      }\n\n      _initializeSymbol(symbol)\n\n      # Track reads and writes of local variables for later use\n      if node.isAssignTarget {\n        _recordStatistic(symbol, .WRITE)\n\n        # Also track reads for assignments\n        if _isExpressionUsed(node.parent) {\n          _recordStatistic(symbol, .READ)\n        }\n      } else {\n        _recordStatistic(symbol, .READ)\n      }\n\n      # Forbid referencing a base class global or constructor function from a derived class\n      if enclosingFunction != null && _isBaseGlobalReference(enclosingFunction.symbol.parent, symbol) {\n        _log.semanticErrorUndeclaredSymbol(node.range, name, symbol.fullName, symbol.range)\n        return\n      }\n\n      # Automatically insert \"self.\" before instance symbols\n      var resolvedType = symbol.resolvedType\n      if symbol.kind.isOnInstances {\n        if thisVariable != null && enclosingFunction.symbol.parent.asObjectSymbol.isSameOrHasBaseClass(symbol.parent) {\n          node.become(Node.createDot(Node.createSymbolReference(thisVariable), name).withRange(node.range).withInternalRange(node.range))\n          resolvedType = _cache.substitute(resolvedType, thisVariable.resolvedType.environment)\n        } else {\n          _log.semanticErrorMemberUnexpectedInstance(node.range, symbol.name)\n        }\n      }\n\n      # Type parameters for objects may only be used in certain circumstances\n      else if symbol.kind == .PARAMETER_OBJECT {\n        var parent = scope\n        var isValid = false\n\n        while parent != null {\n          switch parent.kind {\n            case .OBJECT {\n              isValid = parent.asObjectScope.symbol == symbol.parent\n              break\n            }\n\n            case .FUNCTION {\n              var function = parent.asFunctionScope.symbol\n              if function.kind != .FUNCTION_LOCAL {\n                isValid = function.parent == symbol.parent\n                break\n              }\n            }\n\n            case .VARIABLE {\n              var variable = parent.asVariableScope.symbol\n              isValid = variable.kind == .VARIABLE_INSTANCE && variable.parent == symbol.parent\n              break\n            }\n          }\n\n          parent = parent.parent\n        }\n\n        if !isValid {\n          _log.semanticErrorMemberUnexpectedTypeParameter(node.range, symbol.name)\n        }\n      }\n\n      node.symbol = symbol\n      node.resolvedType = resolvedType\n      _automaticallyCallGetter(node, scope)\n    }\n\n    def _resolveNullDot(node Node, scope Scope) {\n      node.become(_sinkNullDotIntoHook(node, scope, null))\n      _resolveAsParameterizedExpression(node, scope)\n    }\n\n    def _resolveParameterize(node Node, scope Scope) {\n      var value = node.parameterizeValue\n      _resolveNode(value, scope, null)\n\n      # Resolve parameter types\n      var substitutions List<Type> = []\n      var count = 0\n      for child = value.nextSibling; child != null; child = child.nextSibling {\n        _resolveAsParameterizedType(child, scope)\n        substitutions.append(child.resolvedType)\n        count++\n      }\n\n      var type = value.resolvedType\n      var parameters = type.parameters\n\n      # If this is an overloaded symbol, try to pick an overload just using the parameter count\n      if parameters == null && type.kind == .SYMBOL && type.symbol.kind.isOverloadedFunction {\n        var match FunctionSymbol = null\n        for candidate in type.symbol.asOverloadedFunctionSymbol.symbols {\n          if candidate.parameters != null && candidate.parameters.count == count {\n            if match != null {\n              match = null\n              break\n            }\n            match = candidate\n          }\n        }\n        if match != null {\n          type = _cache.substitute(match.resolvedType, type.environment)\n          parameters = type.parameters\n        }\n      }\n\n      # Check for type parameters\n      if parameters == null || type.isParameterized {\n        if type != .DYNAMIC {\n          _log.semanticErrorCannotParameterize(node.range, type)\n        }\n        value.resolvedType = .DYNAMIC\n        return\n      }\n\n      # Check parameter count\n      var expected = parameters.count\n      if count != expected {\n        _log.semanticErrorParameterCount(node.internalRangeOrRange, expected, count)\n        value.resolvedType = .DYNAMIC\n        return\n      }\n\n      # Make sure all parameters have types\n      for parameter in parameters {\n        _initializeSymbol(parameter)\n      }\n\n      # Include the symbol for use with Node.isType\n      node.resolvedType = _cache.substitute(type, _cache.mergeEnvironments(type.environment, _cache.createEnvironment(parameters, substitutions), null))\n      node.symbol = value.symbol\n    }\n\n    def _resolveSequence(node Node, scope Scope, context Type) {\n      for child = node.firstChild; child != null; child = child.nextSibling {\n        _resolveAsParameterizedExpressionWithTypeContext(child, scope, child.nextSibling == null ? context : null)\n      }\n\n      if node.hasChildren {\n        node.resolvedType = node.lastChild.resolvedType\n      }\n    }\n\n    def _resolveStringInterpolation(node Node, scope Scope) {\n      assert(node.childCount % 2 == 1)\n      _resolveChildrenAsParameterizedExpressions(node, scope)\n\n      # TypeScript supports string interpolation natively\n      if _options.target is TypeScriptTarget {\n        for child = node.firstChild; child != null; child = child.nextSibling {\n          if child.resolvedType != .DYNAMIC && child.resolvedType != _cache.stringType {\n            var temp = Node.createNull\n            child.replaceWith(temp)\n            child = Node.createDot(child, \"toString\").withRange(child.range).withFlags(.IS_IGNORED_BY_IDE)\n            temp.replaceWith(child)\n          }\n          _resolveAsParameterizedExpressionWithConversion(child, scope, _cache.stringType)\n        }\n        node.resolvedType = _cache.stringType\n        return\n      }\n\n      # Convert the string interpolation into a series of string concatenations\n      var joined Node = null\n      while node.hasChildren {\n        var child = node.firstChild.remove\n        if child.isString && child.asString == \"\" {\n          continue\n        } else if child.resolvedType != .DYNAMIC && child.resolvedType != _cache.stringType {\n          child = Node.createDot(child, \"toString\").withRange(child.range).withFlags(.IS_IGNORED_BY_IDE)\n          _resolveAsParameterizedExpressionWithConversion(child, scope, _cache.stringType)\n        }\n        joined = joined != null ? Node.createBinary(.ADD, joined, child).withRange(Range.span(joined.range, child.range)).withFlags(.IS_IGNORED_BY_IDE) : child\n        _resolveAsParameterizedExpressionWithConversion(joined, scope, _cache.stringType)\n      }\n      node.become(joined != null ? joined : Node.createString(\"\"))\n      _resolveAsParameterizedExpressionWithConversion(node, scope, _cache.stringType)\n    }\n\n    def _resolveSuper(node Node, scope Scope) {\n      var function = scope.findEnclosingFunction\n      var symbol = function?.symbol\n      var baseType = symbol?.parent.asObjectSymbol.baseType\n      var overridden = baseType == null ? null : _findMember(baseType, symbol.name)\n\n      if overridden == null {\n        _log.semanticErrorBadSuper(node.range)\n        return\n      }\n\n      # Calling a static method doesn't need special handling\n      if overridden.kind == .FUNCTION_GLOBAL {\n        node.kind = .NAME\n      }\n\n      node.resolvedType = overridden.resolvedType\n      node.symbol = overridden\n      _automaticallyCallGetter(node, scope)\n    }\n\n    def _resolveTypeCheck(node Node, scope Scope) {\n      var value = node.typeCheckValue\n      var type = node.typeCheckType\n\n      _resolveAsParameterizedExpression(value, scope)\n      _resolveAsParameterizedType(type, scope)\n      _checkConversion(value, type.resolvedType, .EXPLICIT)\n      node.resolvedType = _cache.boolType\n\n      # Type checks don't work against interfaces\n      if type.resolvedType.isInterface {\n        _log.semanticWarningBadTypeCheck(type.range, type.resolvedType)\n      }\n\n      # Warn about unnecessary type checks\n      else if value.resolvedType != .DYNAMIC && _cache.canImplicitlyConvert(value.resolvedType, type.resolvedType) && (type.resolvedType != .DYNAMIC || type.kind == .TYPE) {\n        _log.semanticWarningExtraTypeCheck(node.range, value.resolvedType, type.resolvedType)\n      }\n    }\n\n    def _resolveXML(node Node, scope Scope) {\n      var tag = node.xmlTag\n      var attributes = node.xmlAttributes\n      var children = node.xmlChildren\n      var closingTag = node.xmlClosingTag?.remove\n      var initialErrorCount = _log.errorCount\n      _resolveAsParameterizedType(tag, scope)\n\n      # Make sure there's a constructor to call\n      if _findMember(tag.resolvedType, \"new\") == null {\n        attributes.removeChildren\n        children.removeChildren\n        attributes.resolvedType = .DYNAMIC\n\n        # Only report an error if there isn't one already\n        if _log.errorCount == initialErrorCount {\n          _log.semanticErrorXMLCannotConstruct(node.range, tag.resolvedType)\n        }\n        return\n      }\n\n      # Call the constructor\n      var value = Node.createDot(tag.clone, \"new\").withRange(node.range).withFlags(.IS_IGNORED_BY_IDE)\n      var needsSequence = attributes.hasChildren || children.hasChildren\n      var result = value\n      _resolveAsParameterizedExpression(value, scope)\n      if needsSequence {\n        result = Node.createSequence.withRange(node.range).appendChild(_extractExpression(value, scope).withFlags(.IS_IGNORED_BY_IDE))\n      }\n\n      # Assign to attributes if necessary\n      while attributes.hasChildren {\n        var child = attributes.firstChild.remove\n        var name = child.binaryLeft\n        while name.kind == .DOT {\n          name = name.dotTarget\n        }\n        assert(name.kind == .NAME)\n        name.replaceWith(Node.createDot(value.clone, name.asString).withRange(name.range))\n        result.appendChild(child)\n      }\n\n      # Make sure there's an append function to call if needed\n      if children.hasChildren && _findMember(tag.resolvedType, \"<>...</>\") == null {\n        _log.semanticErrorXMLMissingAppend(children.firstChild.range, tag.resolvedType)\n        children.removeChildren\n      }\n\n      # Append children\n      else {\n        # Don't need a closure if all children are expressions\n        var isJustExpressions = true\n        for child = children.firstChild; child != null; child = child.nextSibling {\n          if child.kind != .EXPRESSION {\n            isJustExpressions = false\n            break\n          }\n        }\n\n        # All expression statements get passed as arguments to \"<>...</>\"\n        _recursivelyReplaceExpressionsInXML(children, value)\n\n        # Add to the sequence\n        if isJustExpressions {\n          for child = children.firstChild; child != null; child = child.nextSibling {\n            result.appendChild(child.expressionValue.remove)\n          }\n        }\n\n        # Wrap in a closure\n        else {\n          var symbol = FunctionSymbol.new(.FUNCTION_LOCAL, \"<lambda>\")\n          symbol.range = children.range\n          symbol.block = children.remove\n          result.appendChild(Node.createCall(Node.createLambda(symbol).withRange(symbol.range)).withRange(symbol.range))\n        }\n      }\n\n      # Resolve the closing tag for IDE tooltips\n      if closingTag != null {\n        _resolveAsParameterizedType(closingTag, scope)\n        value = Node.createCast(value, closingTag)\n      }\n\n      # Resolve the value\n      node.become(needsSequence ? result.appendChild(value) : value)\n      _resolveAsParameterizedExpression(node, scope)\n    }\n\n    def _recursivelyReplaceExpressionsInXML(node Node, reference Node) {\n      assert(node.kind == .BLOCK)\n\n      for child = node.firstChild; child != null; child = child.nextSibling {\n        switch child.kind {\n          case .EXPRESSION {\n            child.appendChild(Node.createCall(Node.createDot(reference.clone, \"<>...</>\").withRange(child.range).withFlags(.IS_IGNORED_BY_IDE))\n              .appendChild(child.expressionValue.remove).withRange(child.range))\n          }\n\n          case .FOR {\n            _recursivelyReplaceExpressionsInXML(child.forBlock, reference)\n          }\n\n          case .FOREACH {\n            _recursivelyReplaceExpressionsInXML(child.foreachBlock, reference)\n          }\n\n          case .IF {\n            _recursivelyReplaceExpressionsInXML(child.ifTrue, reference)\n            if child.ifFalse != null {\n              _recursivelyReplaceExpressionsInXML(child.ifFalse, reference)\n            }\n          }\n\n          case .SWITCH {\n            for nested = child.switchValue.nextSibling; nested != null; nested = nested.nextSibling {\n              _recursivelyReplaceExpressionsInXML(nested.caseBlock, reference)\n            }\n          }\n\n          case .TRY {\n            var tryBlock = child.tryBlock\n            var finallyBlock = child.finallyBlock\n            _recursivelyReplaceExpressionsInXML(tryBlock, reference)\n            for nested = tryBlock.nextSibling; nested != finallyBlock; nested = nested.nextSibling {\n              _recursivelyReplaceExpressionsInXML(nested.catchBlock, reference)\n            }\n            if finallyBlock != null {\n              _recursivelyReplaceExpressionsInXML(finallyBlock, reference)\n            }\n          }\n\n          case .WHILE {\n            _recursivelyReplaceExpressionsInXML(child.whileBlock, reference)\n          }\n        }\n      }\n    }\n\n    def _resolveBinary(node Node, scope Scope, context Type) {\n      var kind = node.kind\n      var left = node.binaryLeft\n      var right = node.binaryRight\n\n      # Special-case the \"??\" operator\n      if kind == .NULL_JOIN {\n        _resolveAsParameterizedExpressionWithTypeContext(left, scope, context)\n        _resolveAsParameterizedExpressionWithTypeContext(right, scope, context ?? left.resolvedType)\n        var test = Node.createBinary(.NOT_EQUAL, _extractExpressionForAssignment(left, scope), Node.createNull).withRange(left.range)\n        node.become(Node.createHook(test, left.remove, right.remove).withRange(node.range).withFlags(.WAS_NULL_JOIN))\n        _resolveAsParameterizedExpressionWithTypeContext(node, scope, context)\n        return\n      }\n\n      # Special-case the \"?=\" operator\n      if kind == .ASSIGN_NULL {\n        _resolveAsParameterizedExpressionWithTypeContext(left, scope, context)\n        _checkStorage(left, scope)\n        var test = Node.createBinary(.NOT_EQUAL, _extractExpressionForAssignment(left, scope), Node.createNull).withRange(left.range)\n        var assign = Node.createBinary(.ASSIGN, left.remove, right.remove).withRange(node.range).withFlags(.WAS_ASSIGN_NULL)\n        node.become(Node.createHook(test, left.clone, assign).withRange(node.range))\n        _resolveAsParameterizedExpressionWithTypeContext(node, scope, context)\n        return\n      }\n\n      # Special-case the equality operators\n      if kind == .EQUAL || kind == .NOT_EQUAL {\n        if _needsTypeContext(left) {\n          _resolveAsParameterizedExpression(right, scope)\n          _resolveAsParameterizedExpressionWithTypeContext(left, scope, right.resolvedType)\n        } else if _needsTypeContext(right) {\n          _resolveAsParameterizedExpression(left, scope)\n          _resolveAsParameterizedExpressionWithTypeContext(right, scope, left.resolvedType)\n        } else {\n          _resolveAsParameterizedExpression(left, scope)\n          _resolveAsParameterizedExpression(right, scope)\n        }\n\n        # Check for likely bugs \"x == x\" or \"x != x\", except when this is used to test for NaN\n        if left.looksTheSameAs(right) && left.hasNoSideEffects && right.hasNoSideEffects &&\n            !_cache.isEquivalentToDouble(left.resolvedType) && left.resolvedType != .DYNAMIC {\n          _log.semanticWarningIdenticalOperands(node.range, kind == .EQUAL ? \"==\" : \"!=\")\n        }\n\n        # The two types must be compatible\n        var commonType = _cache.commonImplicitType(left.resolvedType, right.resolvedType)\n        if commonType == null {\n          _log.semanticErrorNoCommonType(node.range, left.resolvedType, right.resolvedType)\n        } else {\n          node.resolvedType = _cache.boolType\n\n          # Make sure type casts are inserted\n          _checkConversion(left, commonType, .IMPLICIT)\n          _checkConversion(right, commonType, .IMPLICIT)\n        }\n\n        return\n      }\n\n      # Special-case assignment since it's not overridable\n      if kind == .ASSIGN {\n        _resolveAsParameterizedExpression(left, scope)\n\n        # Automatically call setters\n        if left.symbol != null && left.symbol.isSetter {\n          node.become(Node.createCall(left.remove).withRange(node.range).withInternalRange(right.range).appendChild(right.remove))\n          _resolveAsParameterizedExpression(node, scope)\n        }\n\n        # Resolve the right side using type context from the left side\n        else {\n          _resolveAsParameterizedExpressionWithConversion(right, scope, left.resolvedType)\n          node.resolvedType = left.resolvedType\n          _checkStorage(left, scope)\n\n          # Check for likely bugs \"x = x\"\n          if left.looksTheSameAs(right) && left.hasNoSideEffects && right.hasNoSideEffects {\n            _log.semanticWarningIdenticalOperands(node.range, node.wasAssignNull ? \"?=\" : \"=\")\n          }\n\n          # Check for likely bugs \"x = y\" instead of \"x == y\" based on type context\n          else if node.internalRange != null && context != null && context != .DYNAMIC && left.resolvedType == .DYNAMIC &&\n              right.resolvedType != .DYNAMIC && !_cache.canImplicitlyConvert(right.resolvedType, context) {\n            _log.semanticWarningSuspiciousAssignmentLocation(node.internalRangeOrRange)\n          }\n\n          # Check for likely bugs \"x = y\" instead of \"x == y\" based on expression context\n          else if node.internalRange != null && node.parent != null {\n            var parent = node.parent\n            var parentKind = parent.kind\n            if parentKind == .IF || parentKind == .WHILE || parentKind == .LOGICAL_AND || parentKind == .LOGICAL_OR || parentKind == .NOT ||\n                parentKind == .RETURN && !parent.isImplicitReturn || parentKind == .HOOK && node == parent.hookTest {\n              _log.semanticWarningSuspiciousAssignmentLocation(node.internalRangeOrRange)\n            }\n          }\n        }\n\n        return\n      }\n\n      # Special-case short-circuit logical operators since they aren't overridable\n      if kind == .LOGICAL_AND || kind == .LOGICAL_OR {\n        _resolveAsParameterizedExpressionWithConversion(left, scope, _cache.boolType)\n        _resolveAsParameterizedExpressionWithConversion(right, scope, _cache.boolType)\n        node.resolvedType = _cache.boolType\n\n        # Check for likely bugs \"x && x\" or \"x || x\"\n        if left.looksTheSameAs(right) && left.hasNoSideEffects && right.hasNoSideEffects && (!left.isBool || !right.isBool) {\n          _log.semanticWarningIdenticalOperands(node.range, kind == .LOGICAL_AND ? \"&&\" : \"||\")\n        }\n        return\n      }\n\n      _resolveOperatorOverload(node, scope, context)\n    }\n\n    def _generateReference(scope Scope, type Type) Node {\n      var enclosingFunction = scope.findEnclosingFunctionOrLambda\n      var symbol VariableSymbol = null\n\n      # Add a local variable\n      if enclosingFunction != null {\n        var block = enclosingFunction.symbol.block\n\n        # Make sure the call to \"super\" is still the first statement\n        var after = block.firstChild\n        if after.isSuperCallStatement {\n          after = after.nextSibling\n        }\n\n        # Add the new variable to the top of the function\n        symbol = VariableSymbol.new(.VARIABLE_LOCAL, enclosingFunction.generateName(\"ref\"))\n        block.insertChildBefore(after, Node.createVariables.appendChild(Node.createVariable(symbol)))\n      }\n\n      # Otherwise, add a global variable\n      else {\n        symbol = VariableSymbol.new(.VARIABLE_GLOBAL, _global.scope.generateName(\"ref\"))\n        symbol.parent = _global\n        _generatedGlobalVariables.append(symbol)\n      }\n\n      # Force-initialize the symbol\n      symbol.initializeWithType(type)\n      return Node.createSymbolReference(symbol)\n    }\n\n    def _extractExpression(node Node, scope Scope) Node {\n      assert(node.resolvedType != null)\n\n      if node.kind == .NAME || node.kind == .CONSTANT {\n        return node.clone\n      }\n\n      # Replace the original expression with a reference\n      var reference = _generateReference(scope, node.resolvedType).withRange(node.range).withFlags(.IS_IGNORED_BY_IDE)\n      var setup = node.cloneAndStealChildren\n      node.become(reference)\n      return Node.createBinary(.ASSIGN, reference, setup).withType(node.resolvedType).withRange(node.range)\n    }\n\n    # Expressions with side effects must be stored to temporary variables\n    # if they need to be duplicated in an expression. This does the variable\n    # allocation and storage and returns a partial assigment.\n    #\n    # Examples:\n    #\n    #    \"a\" stays \"a\" and returns \"a\"\n    #    \"a.b\" stays \"a.b\" and returns \"a.b\"\n    #    \"a[0]\" stays \"a[0]\" and returns \"a[0]\"\n    #    \"a().b\" becomes \"ref.b\" and returns \"(ref = a()).b\"\n    #    \"a()[0]\" becomes \"ref[0]\" and returns \"(ref = a())[0]\"\n    #    \"a()[b()]\" becomes \"ref[ref2]\" and returns \"(ref = a())[ref2 = b()]\"\n    #\n    def _extractExpressionForAssignment(node Node, scope Scope) Node {\n      assert(node.resolvedType != null)\n\n      # Handle dot expressions\n      if node.kind == .DOT && node.symbol != null {\n        return Node.createDot(_extractExpression(node.dotTarget, scope), node.asString).withSymbol(node.symbol)\n          .withType(node.resolvedType).withRange(node.range).withInternalRange(node.internalRange)\n      }\n\n      # Handle index expressions\n      if node.kind == .INDEX {\n        var left = _extractExpression(node.indexLeft, scope)\n        return Node.createIndex(left, _extractExpression(node.indexRight, scope)).withRange(node.range)\n      }\n\n      # Handle name expressions\n      if node.kind == .NAME {\n        return node.clone\n      }\n\n      # Handle everything else\n      return _extractExpression(node, scope)\n    }\n\n    def _resolveOperatorOverload(node Node, scope Scope, context Type) {\n      # The order of operands are reversed for the \"in\" operator\n      var kind = node.kind\n      var reverseBinaryOrder = kind == .IN\n      var first = node.firstChild\n      var second = first.nextSibling\n      var target = reverseBinaryOrder ? second : first\n      var other = kind.isBinary ? reverseBinaryOrder ? first : second : null\n      var isBitOperation = kind.isBitOperation\n      var bitContext = isBitOperation && context != null && context.isFlags ? context : null\n\n      # Allow \"foo in [.FOO, .BAR]\"\n      if kind == .IN && target.kind == .INITIALIZER_LIST && !_needsTypeContext(other) {\n        _resolveAsParameterizedExpression(other, scope)\n        _resolveAsParameterizedExpressionWithTypeContext(target, scope, other.resolvedType != .DYNAMIC ? _cache.createListType(other.resolvedType) : null)\n      }\n\n      # Resolve just the target since the other arguments may need type context from overload resolution\n      else {\n        _resolveAsParameterizedExpressionWithTypeContext(target, scope, bitContext)\n      }\n\n      # Warn about shifting by 0 in the original source code, since that doesn't\n      # do anything when the arguments are integers and so is likely a mistake\n      if kind.isShift && _cache.isEquivalentToInt(target.resolvedType) && other.isInt && other.asInt == 0 {\n        _log.semanticWarningShiftByZero(node.range)\n      }\n\n      # Can't do overload resolution on the dynamic type\n      var type = target.resolvedType\n      if type == .DYNAMIC {\n        if kind.isAssign && kind != .ASSIGN_INDEX {\n          _checkStorage(target, scope)\n        }\n        _resolveChildrenAsParameterizedExpressions(node, scope)\n        return\n      }\n\n      # Check if the operator can be overridden at all\n      var info = operatorInfo[kind]\n      if info.kind != .OVERRIDABLE {\n        _log.semanticErrorUnknownMemberSymbol(node.internalRangeOrRange, info.text, type, null, null)\n        _resolveChildrenAsParameterizedExpressions(node, scope)\n        return\n      }\n\n      # Numeric conversions\n      var enumFlagsType Type = null\n\n      # Binary operations\n      if other != null {\n        # Assignment operations aren't symmetric\n        if !kind.isBinaryAssign {\n          if type == _cache.intType {\n            _resolveAsParameterizedExpression(other, scope)\n\n            # Auto-convert doubles to ints\n            if other.resolvedType == _cache.doubleType {\n              _checkConversion(target, _cache.doubleType, .IMPLICIT)\n              type = _cache.doubleType\n            }\n          }\n\n          # Check if the target is an enum\n          else if type.isEnumOrFlags {\n            _resolveAsParameterizedExpressionWithTypeContext(other, scope, bitContext ?? ((isBitOperation || kind == .IN) && type.isFlags ? type : null))\n\n            # Auto-convert enums to ints when both operands can be converted\n            if _cache.isNumeric(other.resolvedType) {\n              type = _cache.commonImplicitType(type, other.resolvedType)\n              assert(type != null)\n              if type.isEnumOrFlags {\n                if type.isFlags {\n                  enumFlagsType = type\n                }\n                type = _cache.intType\n              }\n              _checkConversion(target, type, .IMPLICIT)\n              _checkConversion(other, type, .IMPLICIT)\n            }\n          }\n        }\n\n        # Allow certain operations on \"flags\" types\n        else if isBitOperation && type.isFlags {\n          _resolveAsParameterizedExpressionWithTypeContext(other, scope, type)\n          enumFlagsType = type\n          type = _cache.intType\n          _checkConversion(other, type, .IMPLICIT)\n        }\n      }\n\n      # Allow \"~x\" on \"flags\" types\n      else if kind == .COMPLEMENT && type.isEnumOrFlags {\n        if type.isFlags {\n          enumFlagsType = type\n        }\n        type = _cache.intType\n        _checkConversion(target, type, .IMPLICIT)\n      }\n\n      # Find the operator method\n      var isComparison = kind.isBinaryComparison\n      var name = isComparison ? \"<=>\" : info.text\n      var symbol = _findMember(type, name)\n      var extracted Node = null\n      var wasUnaryPostfix = false\n\n      # Convert operators like \"+=\" to a \"+\" inside a \"=\"\n      if symbol == null && info.assignKind != .NULL {\n        symbol = _findMember(type, operatorInfo[info.assignKind].text)\n        if symbol != null {\n          extracted = _extractExpressionForAssignment(target, scope)\n          if kind == .PREFIX_INCREMENT || kind == .PREFIX_DECREMENT || kind == .POSTFIX_INCREMENT || kind == .POSTFIX_DECREMENT {\n            node.appendChild(_cache.createInt(1).withRange(node.internalRangeOrRange))\n            node.internalRange = null # This no longer makes sense\n          }\n          wasUnaryPostfix = kind.isUnaryPostfix && _isExpressionUsed(node)\n          kind = info.assignKind\n          node.kind = kind\n        }\n      }\n\n      # Special-case the \"in\" operator on \"flags\" types\n      if symbol == null && kind == .IN && enumFlagsType != null {\n        node.become(Node.createBinary(.NOT_EQUAL, Node.createBinary(.BITWISE_AND, other.remove, target.remove).withRange(node.range), _cache.createInt(0)).withRange(node.range))\n        _resolveAsParameterizedExpression(node, scope)\n        return\n      }\n\n      # Fail if the operator wasn't found\n      if symbol == null {\n        _log.semanticErrorUnknownMemberSymbol(node.internalRangeOrRange, name, type, null, null)\n        _resolveChildrenAsParameterizedExpressions(node, scope)\n        return\n      }\n      var symbolType = _cache.substitute(symbol.resolvedType, type.environment)\n\n      # Resolve the overload now so the symbol's properties can be inspected\n      if symbol.kind.isOverloadedFunction {\n        if reverseBinaryOrder {\n          first.swapWith(second)\n        }\n        symbolType = _resolveOverloadedFunction(node.internalRangeOrRange, node, scope, symbolType)\n        if reverseBinaryOrder {\n          first.swapWith(second)\n        }\n        if symbolType == null {\n          _resolveChildrenAsParameterizedExpressions(node, scope)\n          return\n        }\n        symbol = symbolType.symbol\n      }\n\n      var isRawImport = symbol.isImported && !symbol.isRenamed\n      node.symbol = symbol\n      _checkAccess(node, node.internalRangeOrRange, scope)\n\n      # Check for a valid storage location for imported operators\n      if kind.isAssign && kind != .ASSIGN_INDEX && symbol.isImported && extracted == null {\n        _checkStorage(target, scope)\n      }\n\n      # \"<\", \">\", \"<=\", or \">=\"\n      if isComparison && (isRawImport || type == _cache.intType || type == _cache.doubleType) {\n        _resolveChildrenAsParameterizedExpressions(node, scope)\n        node.resolvedType = _cache.boolType\n        node.symbol = null\n      }\n\n      # Don't replace the operator with a call if it's just used for type checking\n      else if isRawImport {\n        if reverseBinaryOrder {\n          first.swapWith(second)\n        }\n        if !_resolveFunctionCall(node, scope, symbolType) {\n          _resolveChildrenAsParameterizedExpressions(node, scope)\n        }\n        if reverseBinaryOrder {\n          first.swapWith(second)\n        }\n\n        # Handle \"flags\" types\n        if isBitOperation && enumFlagsType != null {\n          node.resolvedType = enumFlagsType\n        }\n      }\n\n      else {\n        # Resolve the method call\n        if reverseBinaryOrder {\n          first.swapWith(second)\n        }\n        node.prependChild(Node.createMemberReference(target.remove, symbol).withRange(node.internalRangeOrRange))\n\n        # Implement the logic for the \"<=>\" operator\n        if isComparison {\n          var call = Node.new(.CALL).appendChildrenFrom(node).withRange(node.range)\n          node.appendChild(call)\n          node.appendChild(_cache.createInt(0))\n          node.resolvedType = _cache.boolType\n          _resolveFunctionCall(call, scope, symbolType)\n        }\n\n        # All other operators are just normal method calls\n        else {\n          node.kind = .CALL\n          _resolveFunctionCall(node, scope, symbolType)\n        }\n      }\n\n      if extracted != null {\n        # The expression used to initialize the assignment must return a value\n        if symbolType.returnType == null {\n          _log.semanticErrorUseOfVoidFunction(node.range, symbol.name, symbol.range)\n        }\n\n        # Wrap everything in an assignment if the assignment target was extracted\n        _promoteToAssignment(node, extracted)\n        _resolveAsParameterizedExpression(node, scope)\n\n        # Handle custom unary postfix operators\n        if wasUnaryPostfix {\n          node.become(Node.createBinary(kind, node.cloneAndStealChildren,\n            _cache.createInt(-1).withRange(node.internalRangeOrRange)).withRange(node.range))\n          _resolveAsParameterizedExpression(node, scope)\n        }\n      }\n\n      # Handle custom unary assignment operators\n      else if kind.isUnaryAssign && !isRawImport {\n        # \"foo(x++)\" => \"foo((ref = x, x = ref.increment(), ref))\"\n        if kind.isUnaryPostfix && _isExpressionUsed(node) {\n          var reference = _generateReference(scope, target.resolvedType).withRange(target.range)\n          var original = _extractExpressionForAssignment(target, scope)\n          target.replaceWith(reference)\n          _promoteToAssignment(node, target)\n          node.become(Node.createSequence\n            .appendChild(Node.createBinary(.ASSIGN, reference.clone, original).withRange(node.range))\n            .appendChild(node.cloneAndStealChildren)\n            .appendChild(reference.clone)\n            .withRange(node.range))\n          _resolveAsParameterizedExpression(node, scope)\n        }\n\n        # \"foo(++x)\" => \"foo(x = x.increment())\"\n        else {\n          _promoteToAssignment(node, _extractExpressionForAssignment(target, scope))\n          _resolveAsParameterizedExpression(node, scope)\n        }\n      }\n    }\n\n    def _promoteToAssignment(node Node, extracted Node) {\n      assert(extracted.parent == null)\n\n      if extracted.kind == .INDEX {\n        extracted.kind = .ASSIGN_INDEX\n        extracted.appendChild(node.cloneAndStealChildren)\n        node.become(extracted)\n      } else {\n        node.become(Node.createBinary(.ASSIGN, extracted, node.cloneAndStealChildren).withRange(node.range))\n      }\n    }\n\n    def _automaticallyCallGetter(node Node, scope Scope) bool {\n      var symbol = node.symbol\n      if symbol == null {\n        return false\n      }\n      var kind = symbol.kind\n      var parent = node.parent\n\n      # Never call a getter if type parameters are present\n      if parent != null && parent.kind == .PARAMETERIZE && _isCallValue(parent) {\n        return false\n      }\n\n      # The check for getters is complicated by overloaded functions\n      if !symbol.isGetter && kind.isOverloadedFunction && (!_isCallValue(node) || parent.hasOneChild) {\n        var overloaded = symbol.asOverloadedFunctionSymbol\n        for getter in overloaded.symbols {\n\n          # Just return the first getter assuming errors for duplicate getters\n          # were already logged when the overloaded symbol was initialized\n          if getter.isGetter {\n            node.resolvedType = _cache.substitute(getter.resolvedType, node.resolvedType.environment)\n            node.symbol = getter\n            symbol = getter\n            break\n          }\n        }\n      }\n\n      _checkAccess(node, node.internalRangeOrRange, scope)\n\n      # Automatically wrap the getter in a call expression\n      if symbol.isGetter {\n        node.become(Node.createCall(node.cloneAndStealChildren).withRange(node.range))\n        _resolveAsParameterizedExpression(node, scope)\n        return true\n      }\n\n      # Forbid bare function references\n      if !symbol.isSetter && node.resolvedType != .DYNAMIC && kind.isFunctionOrOverloadedFunction && kind != .FUNCTION_ANNOTATION &&\n          !_isCallValue(node) && (parent == null || parent.kind != .PARAMETERIZE || !_isCallValue(parent)) {\n        var lower = 0x7FFFFFFF\n        var upper = -1\n        if kind.isFunction {\n          lower = upper = symbol.asFunctionSymbol.arguments.count\n        } else {\n          for function in symbol.asOverloadedFunctionSymbol.symbols {\n            var count = function.arguments.count\n            if count < lower { lower = count }\n            if count > upper { upper = count }\n          }\n        }\n        _log.semanticErrorMustCallFunction(node.internalRangeOrRange, symbol.name, lower, upper)\n        node.resolvedType = .DYNAMIC\n      }\n\n      return false\n    }\n\n    def _convertSwitchToIfChain(node Node, scope Scope) {\n      var variable = VariableSymbol.new(.VARIABLE_LOCAL, scope.generateName(\"value\"))\n      var value = node.switchValue.remove\n      var block Node = null\n\n      # Stash the variable being switched over so it's only evaluated once\n      variable.initializeWithType(value.resolvedType)\n      variable.value = value\n      node.parent.insertChildBefore(node, Node.createVariables.appendChild(Node.createVariable(variable)))\n\n      # Build the chain in reverse starting with the last case\n      for child = node.lastChild; child != null; child = child.previousSibling {\n        var caseBlock = child.caseBlock.remove\n        var test Node = null\n\n        # Combine adjacent cases in a \"||\" chain\n        while child.hasChildren {\n          var caseValue = Node.createBinary(.EQUAL, Node.createSymbolReference(variable), child.firstChild.remove).withType(_cache.boolType)\n          test = test != null ? Node.createBinary(.LOGICAL_OR, test, caseValue).withType(_cache.boolType) : caseValue\n        }\n\n        # Chain if-else statements together\n        block = test != null ? Node.createBlock.appendChild(Node.createIf(test, caseBlock, block)) : caseBlock\n      }\n\n      # Replace the switch statement with the if chain\n      if block != null {\n        node.replaceWithChildrenFrom(block)\n      } else {\n        node.remove\n      }\n    }\n  }\n\n  namespace Resolver {\n    const _annotationSymbolFlags StringMap<SymbolFlags> = {\n      \"@alwaysinline\": .IS_INLINING_FORCED,\n      \"@deprecated\": .IS_DEPRECATED,\n      \"@entry\": .IS_ENTRY_POINT,\n      \"@export\": .IS_EXPORTED,\n      \"@import\": .IS_IMPORTED,\n      \"@neverinline\": .IS_INLINING_PREVENTED,\n      \"@prefer\": .IS_PREFERRED,\n      \"@rename\": .IS_RENAMED,\n      \"@skip\": .IS_SKIPPED,\n      \"@spreads\": .SHOULD_SPREAD,\n    }\n\n    def _shouldCheckForSetter(node Node) bool {\n      return node.parent != null && node.parent.kind == .ASSIGN && node == node.parent.binaryLeft\n    }\n\n    def _isExpressionUsed(node Node) bool {\n      # Check for a null parent to handle variable initializers\n      var parent = node.parent\n      return parent == null || parent.kind != .EXPRESSION && !parent.isImplicitReturn &&\n        (parent.kind != .ANNOTATION || node != parent.annotationValue) &&\n        (parent.kind != .FOR || node != parent.forUpdate) &&\n        parent.kind != .SEQUENCE\n    }\n\n    def _isValidVariableType(type Type) bool {\n      return type != .NULL && (type.kind != .SYMBOL || !type.symbol.kind.isFunctionOrOverloadedFunction)\n    }\n\n    def _isBaseGlobalReference(parent Symbol, member Symbol) bool {\n      return parent != null && parent.kind == .OBJECT_CLASS && member.kind.isGlobalReference && member.parent != parent &&\n        member.parent.kind == .OBJECT_CLASS && parent.asObjectSymbol.hasBaseClass(member.parent)\n    }\n\n    def _isCallValue(node Node) bool {\n      var parent = node.parent\n      return parent != null && parent.kind == .CALL && node == parent.callValue\n    }\n\n    def _isCallReturningVoid(node Node) bool {\n      return node.kind == .CALL && (\n        node.symbol != null && node.symbol.resolvedType.returnType == null ||\n        node.callValue.resolvedType.kind == .LAMBDA && node.callValue.resolvedType.returnType == null)\n    }\n\n    def _needsTypeContext(node Node) bool {\n      return\n        node.kind == .DOT && node.dotTarget == null ||\n        node.kind == .HOOK && _needsTypeContext(node.hookTrue) && _needsTypeContext(node.hookFalse) ||\n        node.kind.isInitializer\n    }\n\n    def _ensureFunctionIsOverloaded(symbol FunctionSymbol) {\n      if symbol.overloaded == null {\n        var overloaded = OverloadedFunctionSymbol.new(Merging.overloadedKind(symbol.kind), symbol.name, [symbol])\n        overloaded.parent = symbol.parent\n        overloaded.scope = overloaded.parent.scope\n        symbol.overloaded = overloaded\n      }\n    }\n\n    def _matchCompletion(symbol Symbol, prefix string) bool {\n      if symbol.state == .INITIALIZING {\n        return false\n      }\n      var name = symbol.name.toLowerCase\n      if name[0] == '_' && prefix[0] != '_' {\n        name = name.slice(1)\n      }\n      return name.startsWith(prefix.toLowerCase)\n    }\n  }\n}\n"
  },
  {
    "path": "src/middle/scope.sk",
    "content": "namespace Skew {\n  enum ScopeKind {\n    FUNCTION\n    LOCAL\n    OBJECT\n    VARIABLE\n  }\n\n  enum ScopeSearch {\n    NORMAL\n    ALSO_CHECK_FOR_SETTER\n  }\n\n  enum FuzzyScopeSearch {\n    SELF_ONLY\n    SELF_AND_PARENTS\n  }\n\n  class Scope {\n    var parent Scope\n    var used StringMap<VariableSymbol> = null\n    var _enclosingFunctionOrLambda FunctionScope = null\n    var _enclosingFunction FunctionScope = null\n    var _enclosingLoop LocalScope = null\n\n    def kind ScopeKind\n    def _find(name string) Symbol { return null }\n    def _findWithFuzzyMatching(matcher FuzzySymbolMatcher) {}\n\n    # Need to check for a setter at the same time as for a normal symbol\n    # because the one in the closer scope must be picked. If both are in\n    # the same scope, pick the setter.\n    def find(name string, search ScopeSearch) Symbol {\n      var symbol Symbol = null\n      var setterName = search == .ALSO_CHECK_FOR_SETTER ? name + \"=\" : null\n      for scope = self; scope != null && symbol == null; scope = scope.parent {\n        if setterName != null {\n          symbol = scope._find(setterName)\n        }\n        symbol ?= scope._find(name)\n      }\n      return symbol\n    }\n\n    def findWithFuzzyMatching(name string, kind FuzzySymbolKind, search FuzzyScopeSearch) Symbol {\n      var matcher = FuzzySymbolMatcher.new(name, kind)\n      for scope = self; scope != null; scope = scope.parent {\n        scope._findWithFuzzyMatching(matcher)\n        if search == .SELF_ONLY {\n          break\n        }\n      }\n      return matcher.bestSoFar\n    }\n\n    def asObjectScope ObjectScope {\n      assert(kind == .OBJECT)\n      return self as ObjectScope\n    }\n\n    def asFunctionScope FunctionScope {\n      assert(kind == .FUNCTION)\n      return self as FunctionScope\n    }\n\n    def asVariableScope VariableScope {\n      assert(kind == .VARIABLE)\n      return self as VariableScope\n    }\n\n    def asLocalScope LocalScope {\n      assert(kind == .LOCAL)\n      return self as LocalScope\n    }\n\n    def findEnclosingFunctionOrLambda FunctionScope {\n      if _enclosingFunctionOrLambda != null {\n        return _enclosingFunctionOrLambda\n      }\n      var scope = self\n      while scope != null {\n        if scope.kind == .FUNCTION {\n          _enclosingFunctionOrLambda = scope.asFunctionScope\n          return _enclosingFunctionOrLambda\n        }\n        scope = scope.parent\n      }\n      return null\n    }\n\n    def findEnclosingFunction FunctionScope {\n      if _enclosingFunction != null {\n        return _enclosingFunction\n      }\n      var scope Scope = findEnclosingFunctionOrLambda\n      while scope != null {\n        if scope.kind == .FUNCTION && scope.asFunctionScope.symbol.kind != .FUNCTION_LOCAL {\n          _enclosingFunction = scope.asFunctionScope\n          return _enclosingFunction\n        }\n        scope = scope.parent\n      }\n      return null\n    }\n\n    def findEnclosingLoop LocalScope {\n      if _enclosingLoop != null {\n        return _enclosingLoop\n      }\n      var scope = self\n      while scope != null && scope.kind == .LOCAL {\n        if scope.asLocalScope.type == .LOOP {\n          _enclosingLoop = scope.asLocalScope\n          return _enclosingLoop\n        }\n        scope = scope.parent\n      }\n      return null\n    }\n\n    def generateName(prefix string) string {\n      var count = 0\n      var name = prefix\n      while isNameUsed(name) {\n        name = prefix + (++count).toString\n      }\n      reserveName(name, null)\n      return name\n    }\n\n    def reserveName(name string, symbol VariableSymbol) {\n      used ?= {}\n      if !(name in used) {\n        used[name] = symbol\n      }\n    }\n\n    def isNameUsed(name string) bool {\n      if find(name, .NORMAL) != null {\n        return true\n      }\n      for scope = self; scope != null; scope = scope.parent {\n        if scope.used != null && name in scope.used {\n          return true\n        }\n      }\n      return false\n    }\n  }\n\n  class ObjectScope : Scope {\n    var symbol ObjectSymbol\n\n    over kind ScopeKind {\n      return .OBJECT\n    }\n\n    over _find(name string) Symbol {\n      return symbol.members.get(name, null)\n    }\n\n    over _findWithFuzzyMatching(matcher FuzzySymbolMatcher) {\n      symbol.members.each((name, member) => matcher.include(member))\n    }\n  }\n\n  class FunctionScope : Scope {\n    var symbol FunctionSymbol\n    var parameters StringMap<ParameterSymbol> = {}\n\n    over kind ScopeKind {\n      return .FUNCTION\n    }\n\n    over _find(name string) Symbol {\n      return parameters.get(name, null)\n    }\n\n    over _findWithFuzzyMatching(matcher FuzzySymbolMatcher) {\n      parameters.each((name, parameter) => matcher.include(parameter))\n    }\n  }\n\n  class VariableScope : Scope {\n    var symbol VariableSymbol\n\n    over kind ScopeKind {\n      return .VARIABLE\n    }\n  }\n\n  enum LocalType {\n    LOOP\n    NORMAL\n  }\n\n  class LocalScope : Scope {\n    var locals StringMap<VariableSymbol> = {}\n    var type LocalType\n\n    over kind ScopeKind {\n      return .LOCAL\n    }\n\n    over _find(name string) Symbol {\n      return locals.get(name, null)\n    }\n\n    over _findWithFuzzyMatching(matcher FuzzySymbolMatcher) {\n      locals.each((name, local) => matcher.include(local))\n    }\n\n    def define(symbol VariableSymbol, log Log) {\n      symbol.scope = self\n\n      # Check for duplicates\n      var other = locals.get(symbol.name, null)\n      if other != null {\n        log.semanticErrorDuplicateSymbol(symbol.range, symbol.name, other.range)\n        return\n      }\n\n      # Check for shadowing\n      var scope = parent\n      while scope.kind == .LOCAL {\n        var local = scope.asLocalScope.locals.get(symbol.name, null)\n        if local != null {\n          log.semanticErrorShadowedSymbol(symbol.range, symbol.name, local.range)\n          return\n        }\n        scope = scope.parent\n      }\n\n      scope.reserveName(symbol.name, symbol)\n      locals[symbol.name] = symbol\n    }\n  }\n}\n"
  },
  {
    "path": "src/middle/shaking.sk",
    "content": "namespace Skew {\n  enum ShakingMode {\n    USE_TYPES\n    IGNORE_TYPES\n  }\n\n  # Remove all code that isn't reachable from the entry point or from an\n  # imported or exported symbol. This is called tree shaking here but is also\n  # known as dead code elimination. Tree shaking is perhaps a better name\n  # because this pass doesn't remove dead code inside functions.\n  def shakingPass(global ObjectSymbol, entryPoint FunctionSymbol, mode ShakingMode) {\n    var graph = UsageGraph.new(global, mode)\n    var symbols List<Symbol> = []\n    Shaking.collectExportedSymbols(global, symbols, entryPoint)\n    var usages = graph.usagesForSymbols(symbols)\n    if usages != null {\n      Shaking.removeUnusedSymbols(global, usages)\n    }\n  }\n\n  # This stores a mapping from every symbol to its immediate dependencies and\n  # uses that to provide a mapping from a subset of symbols to their complete\n  # dependencies. This is useful for dead code elimination.\n  class UsageGraph {\n    var _mode ShakingMode\n    var context Symbol = null\n    var _currentUsages IntMap<Symbol> = null\n    var _overridesForSymbol IntMap<List<Symbol>> = {}\n    var _usages IntMap<List<Symbol>> = {}\n\n    def new(global ObjectSymbol, mode ShakingMode) {\n      _mode = mode\n      _visitObject(global)\n      _changeContext(null)\n    }\n\n    def usagesForSymbols(symbols List<Symbol>) IntMap<Symbol> {\n      var overridesToCheck IntMap<List<Symbol>> = {}\n      var combinedUsages IntMap<Symbol> = {}\n      var stack List<Symbol> = []\n      stack.append(symbols)\n\n      # Iterate until a fixed point is reached\n      while !stack.isEmpty {\n        var symbol = stack.takeLast\n\n        if !(symbol.id in combinedUsages) {\n          combinedUsages[symbol.id] = symbol\n          var symbolUsages = _usages.get(symbol.id, null)\n\n          if symbolUsages != null {\n            stack.append(symbolUsages)\n          }\n\n          # Handle function overrides\n          if symbol.kind.isFunction {\n            var overridden = symbol.asFunctionSymbol.overridden\n            var symbolOverrides = _overridesForSymbol.get(symbol.id, null)\n\n            # Automatically include all overridden functions in case the use\n            # of this type is polymorphic, which is a conservative estimate\n            if overridden != null {\n              stack.append(overridden)\n            }\n\n            # Check function overrides too\n            if symbolOverrides != null {\n              for override in symbolOverrides {\n                var key = override.parent.id\n\n                # Queue this override immediately if the parent type is used\n                if key in combinedUsages {\n                  stack.append(override)\n                }\n\n                # Otherwise, remember this override for later if the parent type ends up being used\n                else {\n                  var overrides = overridesToCheck.get(key, null)\n                  if overrides == null {\n                    overrides = []\n                    overridesToCheck[key] = overrides\n                  }\n                  overrides.append(override)\n                }\n              }\n            }\n          }\n\n          # Handle overrides dependent on this type\n          else if symbol.kind.isType {\n            var overrides = overridesToCheck.get(symbol.id, null)\n            if overrides != null {\n              stack.append(overrides)\n            }\n          }\n        }\n      }\n\n      return combinedUsages\n    }\n\n    def _changeContext(symbol Symbol) {\n      if context != null {\n        var values = _currentUsages.values\n        values.sort(Symbol.SORT_BY_ID) # Sort so the order is deterministic\n        _usages[context.id] = values\n      }\n      _currentUsages = {}\n      if symbol != null {\n        _includeSymbol(symbol)\n        _currentUsages[symbol.id] = symbol\n      }\n      context = symbol\n    }\n\n    def _recordOverride(base FunctionSymbol, derived FunctionSymbol) {\n      var overrides = _overridesForSymbol.get(base.id, null)\n      if overrides == null {\n        overrides = []\n        _overridesForSymbol[base.id] = overrides\n      }\n      overrides.append(derived)\n    }\n\n    def _recordUsage(symbol Symbol) {\n      _includeSymbol(symbol)\n      if !symbol.kind.isLocal {\n        _currentUsages[symbol.id] = symbol\n      }\n    }\n\n    def _visitObject(symbol ObjectSymbol) {\n      for object in symbol.objects {\n        _changeContext(object)\n        _recordUsage(symbol)\n\n        # Always pull the base class in\n        if object.baseClass != null {\n          _recordUsage(object.baseClass)\n        }\n\n        # Only pull interfaces in for typed targets (interfaces disappear entirely for untyped targets)\n        if _mode != .IGNORE_TYPES && object.interfaceTypes != null {\n          for type in object.interfaceTypes {\n            if type.symbol != null {\n              _recordUsage(type.symbol)\n            }\n          }\n        }\n\n        # If an imported type is used, automatically assume all functions and\n        # variables for that type are used too\n        if object.isImported {\n          for function in object.functions {\n            _recordUsage(function)\n          }\n          for variable in object.functions {\n            _recordUsage(variable)\n          }\n        }\n\n        _visitObject(object)\n      }\n\n      for function in symbol.functions {\n        _changeContext(function)\n\n        # Instance functions shouldn't cause their instance type to be emitted for dynamically-typed targets\n        if _mode != .IGNORE_TYPES || function.kind != .FUNCTION_INSTANCE {\n          _recordUsage(symbol)\n        }\n\n        _visitFunction(function)\n      }\n\n      for variable in symbol.variables {\n        _changeContext(variable)\n\n        # Instance variables shouldn't require the class to be present because\n        # accessing an instance variable already requires a constructed instance\n        if variable.kind != .VARIABLE_INSTANCE {\n          _recordUsage(symbol)\n        }\n\n        _visitVariable(variable)\n      }\n    }\n\n    def _visitFunction(symbol FunctionSymbol) {\n      for argument in symbol.arguments {\n        _visitVariable(argument)\n      }\n\n      _visitType(symbol.resolvedType.returnType)\n      _visitNode(symbol.block)\n\n      # Remember which functions are overridden for later\n      if symbol.overridden != null {\n        _recordOverride(symbol.overridden, symbol)\n      }\n\n      # Remember which functions are overridden for later\n      if symbol.implementations != null {\n        for function in symbol.implementations {\n          _recordOverride(symbol, function)\n          _recordOverride(function, symbol)\n        }\n      }\n    }\n\n    def _visitVariable(symbol VariableSymbol) {\n      _visitType(symbol.resolvedType)\n      _visitNode(symbol.value)\n    }\n\n    def _visitNode(node Node) {\n      if node == null {\n        return\n      }\n\n      if node.kind == .CAST {\n        _visitNode(node.castValue)\n        _visitType(node.castType.resolvedType)\n      }\n\n      # This is necessary to preserve the types of constant-folded enums in typed languages\n      else if node.kind == .CONSTANT && _mode == .USE_TYPES {\n        _visitType(node.resolvedType)\n      }\n\n      else {\n        for child = node.firstChild; child != null; child = child.nextSibling {\n          _visitNode(child)\n        }\n      }\n\n      if node.symbol != null {\n        _recordUsage(node.symbol)\n      }\n\n      switch node.kind {\n        # The function block is a child node and has already been visited\n        case .LAMBDA {\n          var function = node.symbol.asFunctionSymbol\n          for argument in function.arguments {\n            _visitVariable(argument)\n          }\n          _visitType(function.resolvedType.returnType)\n        }\n\n        # The variable value is a child node and has already been visited\n        case .VARIABLE {\n          _visitType(node.symbol.asVariableSymbol.resolvedType)\n        }\n      }\n    }\n\n    def _visitType(type Type) {\n      if _mode == .USE_TYPES && type != null && type.symbol != null {\n        _recordUsage(type.symbol)\n\n        # This should be a tree too, so infinite loops should not happen\n        if type.isParameterized {\n          for substitution in type.substitutions {\n            _visitType(substitution)\n          }\n        }\n      }\n    }\n  }\n}\n\nnamespace Skew.Shaking {\n  def collectExportedSymbols(symbol ObjectSymbol, symbols List<Symbol>, entryPoint FunctionSymbol) {\n    for object in symbol.objects {\n      collectExportedSymbols(object, symbols, entryPoint)\n      if object.isExported {\n        symbols.append(object)\n      }\n    }\n\n    for function in symbol.functions {\n      if function.isExported || function == entryPoint {\n        symbols.append(function)\n      }\n    }\n\n    for variable in symbol.variables {\n      if variable.isExported {\n        symbols.append(variable)\n      }\n    }\n  }\n\n  def removeUnusedSymbols(symbol ObjectSymbol, usages IntMap<Symbol>) {\n    symbol.objects.removeIf(object => !(object.id in usages))\n    symbol.functions.removeIf(function => !(function.id in usages))\n    symbol.variables.removeIf(variable => !(variable.id in usages))\n\n    for object in symbol.objects {\n      removeUnusedSymbols(object, usages)\n    }\n  }\n}\n\n# Only enable toString in debug mode because of tracking overhead\nif !RELEASE {\n  class Skew.UsageGraph {\n    var _allSymbols IntMap<Symbol> = {}\n\n    def _includeSymbol(symbol Symbol) {\n      _allSymbols[symbol.id] = symbol\n    }\n\n    def toString string {\n      var symbols = _allSymbols.values\n      symbols.sort(Symbol.SORT_BY_ID) # Sort so the order is deterministic\n      var text = \"\"\n      for symbol in symbols {\n        var implies = _usages.get(symbol.id, null)\n        if text != \"\" { text += \"\\n\" }\n        text += symbol.fullName + \" => [\" + (implies != null ? \", \".join(implies.map<string>(s => s.fullName)) : \"\") + \"]\"\n      }\n      return text\n    }\n  }\n}\n\nelse {\n  class Skew.UsageGraph {\n    def _includeSymbol(symbol Symbol) {\n    }\n  }\n}\n"
  },
  {
    "path": "src/middle/type.sk",
    "content": "namespace Skew {\n  enum TypeKind {\n    LAMBDA\n    SPECIAL\n    SYMBOL\n  }\n\n  class Type {\n    const id = _createID\n    var kind TypeKind\n    var symbol Symbol\n    var environment Environment = null\n    var substitutions List<Type> = null\n    var argumentTypes List<Type> = null\n    var returnType Type = null\n    var substitutionCache IntMap<Type> = null # Maps a type environment id to this type in that environment\n\n    def parameters List<ParameterSymbol> {\n      return\n        symbol == null ? null :\n        symbol.kind.isObject ? symbol.asObjectSymbol.parameters :\n        symbol.kind.isFunction ? symbol.asFunctionSymbol.parameters :\n        null\n    }\n\n    def isParameterized bool {\n      return substitutions != null\n    }\n\n    def isWrapped bool {\n      return symbol != null && symbol.kind == .OBJECT_WRAPPED\n    }\n\n    def isClass bool {\n      return symbol != null && symbol.kind == .OBJECT_CLASS\n    }\n\n    def isInterface bool {\n      return symbol != null && symbol.kind == .OBJECT_INTERFACE\n    }\n\n    def isEnumOrFlags bool {\n      return symbol != null && symbol.kind.isEnumOrFlags\n    }\n\n    def isFlags bool {\n      return symbol != null && symbol.kind == .OBJECT_FLAGS\n    }\n\n    def isParameter bool {\n      return symbol != null && symbol.kind.isParameter\n    }\n\n    # Type parameters are not guaranteed to be nullable since generics are\n    # implemented through type erasure and the substituted type may be \"int\"\n    def isReference bool {\n      return symbol == null || !symbol.isValueType && !symbol.kind.isParameter && (symbol.kind != .OBJECT_WRAPPED || symbol.asObjectSymbol.wrappedType.isReference)\n    }\n\n    def toString string {\n      if kind == .SYMBOL {\n        if isParameterized {\n          var name = symbol.fullName + \"<\"\n          for i in 0..substitutions.count {\n            if i != 0 {\n              name += \", \"\n            }\n            name += substitutions[i].toString\n          }\n          return name + \">\"\n        }\n        return symbol.fullName\n      }\n\n      if kind == .LAMBDA {\n        var result = \"fn(\"\n        for i in 0..argumentTypes.count {\n          if i != 0 {\n            result += \", \"\n          }\n          result += argumentTypes[i].toString\n        }\n        return result + (returnType != null ? \") \\(returnType)\" : \")\")\n      }\n\n      return self == DYNAMIC ? \"dynamic\" : \"null\"\n    }\n\n    def baseType Type {\n      return isClass ? symbol.asObjectSymbol.baseType : null\n    }\n\n    def interfaceTypes List<Type> {\n      return isClass ? symbol.asObjectSymbol.interfaceTypes : null\n    }\n  }\n\n  namespace Type {\n    var DYNAMIC = Type.new(.SPECIAL, null)\n    var NULL = Type.new(.SPECIAL, null)\n\n    def _createID int {\n      return ++_nextID\n    }\n\n    var _nextID = 0\n  }\n\n  class Environment {\n    const id = _createID\n    const parameters List<ParameterSymbol>\n    const substitutions List<Type>\n    const mergeCache IntMap<Environment> = null\n\n    # This is just for debugging\n    def toString string {\n      var text = \"(\"\n      for i in 0..parameters.count {\n        if i != 0 {\n          text += \", \"\n        }\n        text += \"\\(parameters[i].name) => \\(substitutions[i])\"\n      }\n      return text + \")\"\n    }\n  }\n\n  namespace Environment {\n    def _createID int {\n      return ++_nextID\n    }\n\n    var _nextID = 0\n  }\n}\n"
  },
  {
    "path": "src/middle/typecache.sk",
    "content": "namespace Skew {\n  class TypeCache {\n    var boolType Type = null\n    var boxType Type = null\n    var doubleType Type = null\n    var intMapType Type = null\n    var intType Type = null\n    var listType Type = null\n    var mathType Type = null\n    var stringMapType Type = null\n    var stringType Type = null\n\n    var boolToStringSymbol Symbol = null\n    var doublePowerSymbol Symbol = null\n    var doubleToStringSymbol Symbol = null\n    var intPowerSymbol Symbol = null\n    var intToStringSymbol Symbol = null\n    var mathPowSymbol Symbol = null\n    var stringCountSymbol Symbol = null\n    var stringFromCodePointsSymbol Symbol = null\n    var stringFromCodePointSymbol Symbol = null\n    var stringFromCodeUnitsSymbol Symbol = null\n    var stringFromCodeUnitSymbol Symbol = null\n\n    var entryPointSymbol FunctionSymbol = null\n    const _environments = IntMap<List<Environment>>.new\n    const _lambdaTypes = IntMap<List<Type>>.new\n    const _parameters List<Type> = []\n\n    def loadGlobals(log Log, global ObjectSymbol) {\n      boolType = _loadGlobalObject(global, \"bool\", .OBJECT_CLASS, .IS_VALUE_TYPE)\n      boxType = _loadGlobalObject(global, \"Box\", .OBJECT_CLASS, 0)\n      doubleType = _loadGlobalObject(global, \"double\", .OBJECT_CLASS, .IS_VALUE_TYPE)\n      intMapType = _loadGlobalObject(global, \"IntMap\", .OBJECT_CLASS, 0)\n      intType = _loadGlobalObject(global, \"int\", .OBJECT_CLASS, .IS_VALUE_TYPE)\n      listType = _loadGlobalObject(global, \"List\", .OBJECT_CLASS, 0)\n      mathType = _loadGlobalObject(global, \"Math\", .OBJECT_NAMESPACE, 0)\n      stringMapType = _loadGlobalObject(global, \"StringMap\", .OBJECT_CLASS, 0)\n      stringType = _loadGlobalObject(global, \"string\", .OBJECT_CLASS, 0)\n\n      boolToStringSymbol = _loadInstanceFunction(boolType, \"toString\")\n      doublePowerSymbol = _loadInstanceFunction(doubleType, \"**\")\n      doubleToStringSymbol = _loadInstanceFunction(doubleType, \"toString\")\n      intPowerSymbol = _loadInstanceFunction(intType, \"**\")\n      intToStringSymbol = _loadInstanceFunction(intType, \"toString\")\n      mathPowSymbol = _loadGlobalFunction(mathType, \"pow\")\n      stringCountSymbol = _loadInstanceFunction(stringType, \"count\")\n      stringFromCodePointsSymbol = _loadGlobalFunction(stringType, \"fromCodePoints\")\n      stringFromCodePointSymbol = _loadGlobalFunction(stringType, \"fromCodePoint\")\n      stringFromCodeUnitsSymbol = _loadGlobalFunction(stringType, \"fromCodeUnits\")\n      stringFromCodeUnitSymbol = _loadGlobalFunction(stringType, \"fromCodeUnit\")\n    }\n\n    def isEquivalentToBool(type Type) bool {\n      return unwrappedType(type) == boolType\n    }\n\n    def isEquivalentToInt(type Type) bool {\n      return isInteger(unwrappedType(type))\n    }\n\n    def isEquivalentToDouble(type Type) bool {\n      return unwrappedType(type) == doubleType\n    }\n\n    def isEquivalentToString(type Type) bool {\n      return unwrappedType(type) == stringType\n    }\n\n    def isInteger(type Type) bool {\n      return type == intType || type.isEnumOrFlags\n    }\n\n    def isNumeric(type Type) bool {\n      return isInteger(type) || type == doubleType\n    }\n\n    def isBox(type Type) bool {\n      return type.symbol == boxType.symbol\n    }\n\n    def isList(type Type) bool {\n      return type.symbol == listType.symbol\n    }\n\n    def isIntMap(type Type) bool {\n      return type.symbol == intMapType.symbol\n    }\n\n    def isStringMap(type Type) bool {\n      return type.symbol == stringMapType.symbol\n    }\n\n    def isBaseType(derived Type, base Type) bool {\n      if derived.isClass && base.isClass {\n        while true {\n          var baseType = derived.baseType\n          if baseType == null {\n            break\n          }\n          derived = substitute(baseType, derived.environment)\n          if derived == base {\n            return true\n          }\n        }\n      }\n      return false\n    }\n\n    def isImplementedInterface(classType Type, interfaceType Type) bool {\n      if classType.isClass && interfaceType.isInterface {\n        while classType != null {\n          var interfaceTypes = classType.interfaceTypes\n          if interfaceTypes != null {\n            for type in interfaceTypes {\n              if substitute(type, classType.environment) == interfaceType {\n                return true\n              }\n            }\n          }\n          var baseType = classType.baseType\n          if baseType == null {\n            break\n          }\n          classType = substitute(baseType, classType.environment)\n        }\n      }\n      return false\n    }\n\n    def unwrappedType(type Type) Type {\n      if type.isWrapped {\n        var inner = type.symbol.asObjectSymbol.wrappedType\n        if inner != null {\n          return unwrappedType(substitute(inner, type.environment))\n        }\n      }\n      return type\n    }\n\n    def canImplicitlyConvert(from Type, to Type) bool {\n      if from == to { return true }\n      if from == .DYNAMIC || to == .DYNAMIC { return true }\n      if from == .NULL && to.isReference { return true }\n      if from == intType && to == doubleType { return true }\n      if isBaseType(from, to) { return true }\n      if isImplementedInterface(from, to) { return true }\n      if from.isEnumOrFlags && !to.isEnumOrFlags && isNumeric(to) { return true }\n      return false\n    }\n\n    def canExplicitlyConvert(from Type, to Type) bool {\n      from = unwrappedType(from)\n      to = unwrappedType(to)\n      if canImplicitlyConvert(from, to) { return true }\n      if _canCastToNumeric(from) && _canCastToNumeric(to) { return true }\n      if isBaseType(to, from) { return true }\n      if isImplementedInterface(to, from) { return true }\n      if to.isEnumOrFlags && isNumeric(from) { return true }\n      return false\n    }\n\n    def commonImplicitType(left Type, right Type) Type {\n      # Short-circuit early for identical types\n      if left == right { return left }\n\n      # Dynamic is a hole in the type system\n      if left == .DYNAMIC || right == .DYNAMIC { return .DYNAMIC }\n\n      # Check implicit conversions\n      if canImplicitlyConvert(left, right) { return right }\n      if canImplicitlyConvert(right, left) { return left }\n\n      # Implement common implicit types for numeric types\n      if isNumeric(left) && isNumeric(right) {\n        return isInteger(left) && isInteger(right) ? intType : doubleType\n      }\n\n      # Check for a common base class\n      if left.isClass && right.isClass {\n        return _commonBaseType(left, right)\n      }\n\n      return null\n    }\n\n    def createBool(value bool) Node {\n      return Node.createBool(value).withType(boolType)\n    }\n\n    def createInt(value int) Node {\n      return Node.createInt(value).withType(intType)\n    }\n\n    def createDouble(value double) Node {\n      return Node.createDouble(value).withType(doubleType)\n    }\n\n    def createString(value string) Node {\n      return Node.createString(value).withType(stringType)\n    }\n\n    def createListType(itemType Type) Type {\n      return substitute(listType, createEnvironment(listType.parameters, [itemType]))\n    }\n\n    def createIntMapType(valueType Type) Type {\n      return substitute(intMapType, createEnvironment(intMapType.parameters, [valueType]))\n    }\n\n    def createStringMapType(valueType Type) Type {\n      return substitute(stringMapType, createEnvironment(stringMapType.parameters, [valueType]))\n    }\n\n    def createEnvironment(parameters List<ParameterSymbol>, substitutions List<Type>) Environment {\n      assert(parameters.count == substitutions.count)\n\n      # Hash the inputs\n      var hash = _hashTypes(_hashParameters(parameters), substitutions)\n      var bucket = _environments.get(hash, null)\n\n      # Check existing environments in the bucket for a match\n      if bucket != null {\n        for existing in bucket {\n          if parameters.equals(existing.parameters) && substitutions.equals(existing.substitutions) {\n            return existing\n          }\n        }\n      }\n\n      # Make a new bucket\n      else {\n        bucket = []\n        _environments[hash] = bucket\n      }\n\n      # Make a new environment\n      var environment = Environment.new(parameters, substitutions)\n      bucket.append(environment)\n      return environment\n    }\n\n    def createLambdaType(argumentTypes List<Type>, returnType Type) Type {\n      assert(returnType != .NULL) # This is used as a sentinel on LAMBDA_TYPE nodes\n\n      var hash = _hashTypes(returnType != null ? returnType.id : -1, argumentTypes)\n      var bucket = _lambdaTypes.get(hash, null)\n\n      # Check existing types in the bucket for a match\n      if bucket != null {\n        for existing in bucket {\n          if argumentTypes.equals(existing.argumentTypes) && returnType == existing.returnType {\n            return existing\n          }\n        }\n      }\n\n      # Make a new bucket\n      else {\n        bucket = []\n        _lambdaTypes[hash] = bucket\n      }\n\n      # Make a new lambda type\n      var type = Type.new(.LAMBDA, null)\n      type.argumentTypes = argumentTypes.clone # Make a copy in case the caller mutates this later\n      type.returnType = returnType\n      bucket.append(type)\n      return type\n    }\n\n    def mergeEnvironments(a Environment, b Environment, restrictions List<ParameterSymbol>) Environment {\n      if a == null { return b }\n      if b == null { return a }\n      var parameters = a.parameters.clone\n      var substitutions = substituteAll(a.substitutions, b)\n      for i in 0..b.parameters.count {\n        var parameter = b.parameters[i]\n        var substitution = b.substitutions[i]\n        if !(parameter in parameters) && (restrictions == null || parameter in restrictions) {\n          parameters.append(parameter)\n          substitutions.append(substitution)\n        }\n      }\n      return createEnvironment(parameters, substitutions)\n    }\n\n    def parameterize(type Type) Type {\n      var parameters = type.parameters\n      if parameters == null {\n        return type\n      }\n      assert(!type.isParameterized)\n      var substitutions List<Type> = []\n      for parameter in parameters {\n        substitutions.append(parameter.resolvedType)\n      }\n      return substitute(type, createEnvironment(parameters, substitutions))\n    }\n\n    def substituteAll(types List<Type>, environment Environment) List<Type> {\n      var substitutions List<Type> = []\n      for type in types {\n        substitutions.append(substitute(type, environment))\n      }\n      return substitutions\n    }\n\n    def substitute(type Type, environment Environment) Type {\n      var existing = type.environment\n      if environment == null || environment == existing {\n        return type\n      }\n\n      # Merge the type environments (this matters for nested generics). For\n      # object types, limit the parameters in the environment to just those\n      # on this type and the base type.\n      var parameters = type.parameters\n      if existing != null {\n        environment = mergeEnvironments(existing, environment, type.kind == .SYMBOL && type.symbol.kind.isFunctionOrOverloadedFunction ? null : parameters)\n      }\n\n      # Check to see if this has been computed before\n      var rootType = type.kind == .SYMBOL ? type.symbol.resolvedType : type\n      rootType.substitutionCache ?= {}\n      var substituted = rootType.substitutionCache.get(environment.id, null)\n      if substituted != null {\n        return substituted\n      }\n      substituted = type\n\n      if type.kind == .LAMBDA {\n        var argumentTypes List<Type> = []\n        var returnType Type = null\n\n        # Substitute function arguments\n        for argumentType in type.argumentTypes {\n          argumentTypes.append(substitute(argumentType, environment))\n        }\n\n        # Substitute return type\n        if type.returnType != null {\n          returnType = substitute(type.returnType, environment)\n        }\n\n        substituted = createLambdaType(argumentTypes, returnType)\n      }\n\n      else if type.kind == .SYMBOL {\n        var symbol = type.symbol\n\n        # Parameters just need simple substitution\n        if symbol.kind.isParameter {\n          var index = environment.parameters.indexOf(symbol.asParameterSymbol)\n          if index != -1 {\n            substituted = environment.substitutions[index]\n          }\n        }\n\n        # Symbols with type parameters are more complicated\n        else {\n          # Overloaded functions are also included even though they don't have\n          # type parameters because the type environment needs to be bundled\n          # for later substitution into individual matched overloads\n          if parameters != null || symbol.kind.isFunctionOrOverloadedFunction {\n            substituted = Type.new(.SYMBOL, symbol)\n            substituted.environment = environment\n\n            # Generate type substitutions\n            if parameters != null {\n              var found = true\n              for parameter in parameters {\n                found = parameter in environment.parameters\n                if !found {\n                  break\n                }\n              }\n              if found {\n                substituted.substitutions = []\n                for parameter in parameters {\n                  substituted.substitutions.append(substitute(parameter.resolvedType, environment))\n                }\n              }\n            }\n\n            # Substitute function arguments\n            if type.argumentTypes != null {\n              substituted.argumentTypes = []\n              for argumentType in type.argumentTypes {\n                substituted.argumentTypes.append(substitute(argumentType, environment))\n              }\n            }\n\n            # Substitute return type\n            if type.returnType != null {\n              substituted.returnType = substitute(type.returnType, environment)\n            }\n          }\n        }\n      }\n\n      rootType.substitutionCache[environment.id] = substituted\n      return substituted\n    }\n\n    # Substitute the type parameters from one function into the other\n    def substituteFunctionParameters(type Type, from FunctionSymbol, to FunctionSymbol) Type {\n      if from.parameters != null && to.parameters != null && from.parameters.count == to.parameters.count {\n        var substitutions List<Type> = []\n        for parameter in from.parameters {\n          substitutions.append(parameter.resolvedType)\n        }\n        type = substitute(type, createEnvironment(to.parameters, substitutions))\n      }\n      return type\n    }\n\n    enum Equivalence {\n      EQUIVALENT\n      EQUIVALENT_EXCEPT_RETURN_TYPE\n      NOT_EQUIVALENT\n    }\n\n    def areFunctionSymbolsEquivalent(left FunctionSymbol, leftEnvironment Environment, right FunctionSymbol, rightEnvironment Environment) Equivalence {\n      var leftType = left.resolvedType\n      var rightType = right.resolvedType\n      var leftReturn = leftType.returnType\n      var rightReturn = rightType.returnType\n\n      # Account for return types of functions from generic base types\n      if leftReturn != null {\n        leftReturn = substitute(leftReturn, leftEnvironment)\n      }\n      if rightReturn != null {\n        rightReturn = substitute(rightReturn, rightEnvironment)\n      }\n\n      # Overloading by return type is not allowed, so only compare argument types\n      if substitute(left.argumentOnlyType, leftEnvironment) == substitute(right.argumentOnlyType, rightEnvironment) {\n        return leftReturn == rightReturn ? .EQUIVALENT : .EQUIVALENT_EXCEPT_RETURN_TYPE\n      }\n\n      # For generic functions, substitute dummy type parameters into both\n      # functions and then compare. For example, these are equivalent:\n      #\n      #   def foo<X>(bar X)\n      #   def foo<Y>(baz Y)\n      #\n      if left.parameters != null && right.parameters != null {\n        var leftArguments = leftType.argumentTypes\n        var rightArguments = rightType.argumentTypes\n        var argumentCount = leftArguments.count\n        var parameterCount = left.parameters.count\n\n        if argumentCount == rightArguments.count && parameterCount == right.parameters.count {\n          # Generate enough dummy type parameters\n          for i in _parameters.count..parameterCount {\n            var symbol = ParameterSymbol.new(.PARAMETER_FUNCTION, \"T\\(i)\")\n            symbol.resolvedType = Type.new(.SYMBOL, symbol)\n            symbol.state = .INITIALIZED\n            _parameters.append(symbol.resolvedType)\n          }\n\n          # Substitute the same type parameters into both functions\n          var parameters = _parameters.count == parameterCount ? _parameters : _parameters.slice(0, parameterCount)\n          var leftParametersEnvironment = createEnvironment(left.parameters, parameters)\n          var rightParametersEnvironment = createEnvironment(right.parameters, parameters)\n\n          # Compare each argument\n          for i in 0..argumentCount {\n            if substitute(substitute(leftArguments[i], leftEnvironment), leftParametersEnvironment) !=\n                substitute(substitute(rightArguments[i], rightEnvironment), rightParametersEnvironment) {\n              return .NOT_EQUIVALENT\n            }\n          }\n\n          return\n            leftReturn == null && rightReturn == null ||\n            leftReturn != null && rightReturn != null &&\n            substitute(leftReturn, leftParametersEnvironment) ==\n            substitute(rightReturn, rightParametersEnvironment)\n            ? .EQUIVALENT\n            : .EQUIVALENT_EXCEPT_RETURN_TYPE\n        }\n      }\n\n      return .NOT_EQUIVALENT\n    }\n\n    def _canCastToNumeric(type Type) bool {\n      return type == intType || type == doubleType || type == boolType\n    }\n  }\n\n  namespace TypeCache {\n    def _loadGlobalObject(global ObjectSymbol, name string, kind SymbolKind, flags SymbolFlags) Type {\n      assert(kind.isObject)\n      var symbol = global.members.get(name, null)\n      assert(symbol != null)\n      assert(symbol.kind == kind)\n      var type = Type.new(.SYMBOL, symbol.asObjectSymbol)\n      symbol.resolvedType = type\n      symbol.flags |= flags\n      return type\n    }\n\n    def _loadInstanceFunction(type Type, name string) Symbol {\n      var symbol = type.symbol.asObjectSymbol.members.get(name, null)\n      assert(symbol != null)\n      assert(symbol.kind == .FUNCTION_INSTANCE || symbol.kind == .OVERLOADED_INSTANCE)\n      return symbol\n    }\n\n    def _loadGlobalFunction(type Type, name string) Symbol {\n      var symbol = type.symbol.asObjectSymbol.members.get(name, null)\n      assert(symbol != null)\n      assert(symbol.kind == .FUNCTION_GLOBAL || symbol.kind == .OVERLOADED_GLOBAL)\n      return symbol\n    }\n\n    def _hashParameters(parameters List<ParameterSymbol>) int {\n      var hash = 0\n      for parameter in parameters {\n        hash = hashCombine(hash, parameter.id)\n      }\n      return hash\n    }\n\n    def _hashTypes(hash int, types List<Type>) int {\n      for type in types {\n        hash = hashCombine(hash, type.id)\n      }\n      return hash\n    }\n\n    def _commonBaseType(left Type, right Type) Type {\n      var a = left\n      while a != null {\n        var b = right\n        while b != null {\n          if a == b {\n            return a\n          }\n          b = b.baseType\n        }\n        a = a.baseType\n      }\n      return null\n    }\n  }\n}\n"
  },
  {
    "path": "src/middle/unicode.sk",
    "content": "namespace Skew {\n  const UNICODE_LIBRARY = \"\nnamespace Unicode {\n  enum Encoding {\n    UTF8\n    UTF16\n    UTF32\n  }\n\n  const STRING_ENCODING Encoding =\n    TARGET == .CPLUSPLUS ? .UTF8 :\n    TARGET == .CSHARP || TARGET == .JAVASCRIPT ? .UTF16 :\n    .UTF32\n\n  class StringIterator {\n    var value = \\\"\\\"\n    var index = 0\n    var stop = 0\n\n    def reset(text string, start int) StringIterator {\n      value = text\n      index = start\n      stop = text.count\n      return self\n    }\n\n    def countCodePointsUntil(stop int) int {\n      var count = 0\n      while index < stop && nextCodePoint >= 0 {\n        count++\n      }\n      return count\n    }\n\n    def previousCodePoint int\n    def nextCodePoint int\n\n    if STRING_ENCODING == .UTF8 {\n      def previousCodePoint int {\n        if index <= 0 { return -1 }\n        var a = value[--index]\n        if (a & 0xC0) != 0x80 { return a }\n        if index <= 0 { return -1 }\n        var b = value[--index]\n        if (b & 0xC0) != 0x80 { return ((b & 0x1F) << 6) | (a & 0x3F) }\n        if index <= 0 { return -1 }\n        var c = value[--index]\n        if (c & 0xC0) != 0x80 { return ((c & 0x0F) << 12) | ((b & 0x3F) << 6) | (a & 0x3F) }\n        if index >= stop { return -1 }\n        var d = value[--index]\n        return ((d & 0x07) << 18) | ((c & 0x3F) << 12) | ((b & 0x3F) << 6) | (a & 0x3F)\n      }\n\n      def nextCodePoint int {\n        if index >= stop { return -1 }\n        var a = value[index++]\n        if a < 0xC0 { return a }\n        if index >= stop { return -1 }\n        var b = value[index++]\n        if a < 0xE0 { return ((a & 0x1F) << 6) | (b & 0x3F) }\n        if index >= stop { return -1 }\n        var c = value[index++]\n        if a < 0xF0 { return ((a & 0x0F) << 12) | ((b & 0x3F) << 6) | (c & 0x3F) }\n        if index >= stop { return -1 }\n        var d = value[index++]\n        return ((a & 0x07) << 18) | ((b & 0x3F) << 12) | ((c & 0x3F) << 6) | (d & 0x3F)\n      }\n    }\n\n    else if STRING_ENCODING == .UTF16 {\n      def previousCodePoint int {\n        if index <= 0 { return -1 }\n        var a = value[--index]\n        if (a & 0xFC00) != 0xDC00 { return a }\n        if index <= 0 { return -1 }\n        var b = value[--index]\n        return (b << 10) + a + (0x10000 - (0xD800 << 10) - 0xDC00)\n      }\n\n      def nextCodePoint int {\n        if index >= stop { return -1 }\n        var a = value[index++]\n        if (a & 0xFC00) != 0xD800 { return a }\n        if index >= stop { return -1 }\n        var b = value[index++]\n        return (a << 10) + b + (0x10000 - (0xD800 << 10) - 0xDC00)\n      }\n    }\n\n    else {\n      def previousCodePoint int {\n        if index <= 0 { return -1 }\n        return value[--index]\n      }\n\n      def nextCodePoint int {\n        if index >= stop { return -1 }\n        return value[index++]\n      }\n    }\n  }\n\n  namespace StringIterator {\n    const INSTANCE = StringIterator.new\n  }\n\n  def codeUnitCountForCodePoints(codePoints List<int>, encoding Encoding) int {\n    var count = 0\n\n    switch encoding {\n      case .UTF8 {\n        for codePoint in codePoints {\n          if codePoint < 0x80 { count++ }\n          else if codePoint < 0x800 { count += 2 }\n          else if codePoint < 0x10000 { count += 3 }\n          else { count += 4 }\n        }\n      }\n\n      case .UTF16 {\n        for codePoint in codePoints {\n          if codePoint < 0x10000 { count++ }\n          else { count += 2 }\n        }\n      }\n\n      case .UTF32 {\n        count = codePoints.count\n      }\n    }\n\n    return count\n  }\n}\n\nclass string {\n  if Unicode.STRING_ENCODING == .UTF32 {\n    def codePoints List<int> {\n      return codeUnits\n    }\n  }\n\n  else {\n    def codePoints List<int> {\n      var codePoints List<int> = []\n      var instance = Unicode.StringIterator.INSTANCE\n      instance.reset(self, 0)\n\n      while true {\n        var codePoint = instance.nextCodePoint\n        if codePoint < 0 {\n          return codePoints\n        }\n        codePoints.append(codePoint)\n      }\n    }\n  }\n}\n\nnamespace string {\n  def fromCodePoints(codePoints List<int>) string {\n    var builder = StringBuilder.new\n    for codePoint in codePoints {\n      builder.append(fromCodePoint(codePoint))\n    }\n    return builder.toString\n  }\n\n  if Unicode.STRING_ENCODING == .UTF8 {\n    def fromCodePoint(codePoint int) string {\n      return\n        codePoint < 0x80 ? fromCodeUnit(codePoint) : (\n          codePoint < 0x800 ? fromCodeUnit(((codePoint >> 6) & 0x1F) | 0xC0) : (\n            codePoint < 0x10000 ? fromCodeUnit(((codePoint >> 12) & 0x0F) | 0xE0) : (\n              fromCodeUnit(((codePoint >> 18) & 0x07) | 0xF0)\n            ) + fromCodeUnit(((codePoint >> 12) & 0x3F) | 0x80)\n          ) + fromCodeUnit(((codePoint >> 6) & 0x3F) | 0x80)\n        ) + fromCodeUnit((codePoint & 0x3F) | 0x80)\n    }\n  }\n\n  else if Unicode.STRING_ENCODING == .UTF16 {\n    def fromCodePoint(codePoint int) string {\n      return codePoint < 0x10000 ? fromCodeUnit(codePoint) :\n        fromCodeUnit(((codePoint - 0x10000) >> 10) + 0xD800) +\n        fromCodeUnit(((codePoint - 0x10000) & ((1 << 10) - 1)) + 0xDC00)\n    }\n  }\n\n  else {\n    def fromCodePoint(codePoint int) string {\n      return fromCodeUnit(codePoint)\n    }\n  }\n}\n\"\n}\n"
  },
  {
    "path": "tests/cplusplus.sk",
    "content": "namespace Skew.Tests {\n  def testCPlusPlus {\n\n# Test entry point\ntest(\"\n@entry\ndef test {}\n\", \"\nvoid main() {\n}\n\").cpp\n\n# Test entry point\ntest(\"\n@entry\ndef test int {\n  return 0\n}\n\", \"\nint main() {\n  return 0;\n}\n\").cpp\n\n# Test entry point\ntest(\"\n@entry\ndef test(x List<string>) {\n}\n\", \"\nvoid main(int argc, char** argv) {\n  Skew::List<Skew::string> *x = new Skew::List<Skew::string>();\n\n  if (*argv++) {\n    while (*argv) {\n      x->append(*argv++);\n    }\n  }\n}\n\").cpp\n\n# Test entry point\ntest(\"\n@entry\ndef test(x List<string>) int {\n  return x.count\n}\n\", \"\nint main(int argc, char** argv) {\n  Skew::List<Skew::string> *x = new Skew::List<Skew::string>();\n\n  if (*argv++) {\n    while (*argv) {\n      x->append(*argv++);\n    }\n  }\n\n  return x->count();\n}\n\").cpp\n\n# Test entry point inside a namespace\ntest(\"\nnamespace ns {\n  @entry\n  def test(x List<string>) int {\n    test([])\n    return x.count\n  }\n}\n\", \"\nint main(int argc, char** argv) {\n  Skew::List<Skew::string> *x = new Skew::List<Skew::string>();\n\n  if (*argv++) {\n    while (*argv) {\n      x->append(*argv++);\n    }\n  }\n\n  main(new Skew::List<Skew::string>());\n  return x->count();\n}\n\").cpp\n\n# Test entry point name collisions\ntest(\"\n@entry\ndef main(x List<string>) int {\n  var argc = 0\n  var argv = 0\n  return argc + argv\n}\n\", \"\nint main(int argc1, char** argv1) {\n  Skew::List<Skew::string> *x = new Skew::List<Skew::string>();\n\n  if (*argv1++) {\n    while (*argv1) {\n      x->append(*argv1++);\n    }\n  }\n\n  int argc = 0;\n  int argv = 0;\n  return argc + argv;\n}\n\").cpp\n\n# Basic class hierarchy\ntest(\"\n@export\nclass Foo {\n  const instanceVariable1 int\n  const instanceVariable2 = 0\n  def instanceMethod {}\n  def instanceMethod2 {}\n}\n\nnamespace Foo {\n  const staticVariable = 0\n}\n\n@export\nclass Bar : Foo {\n  const instanceVariable3 int\n  const instanceVariable4 = 0\n  over instanceMethod { super }\n  def instanceMethod3 {}\n}\n\nnamespace Bar {\n  const staticVariable2 = 0\n}\n\", \"\nstruct Foo;\nstruct Bar;\n\nstruct Foo : virtual Skew::Object {\n  virtual void instanceMethod();\n  void instanceMethod2();\n  Foo(int instanceVariable1);\n\n  int instanceVariable1;\n  int instanceVariable2;\n  static int staticVariable;\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nstruct Bar : Foo {\n  virtual void instanceMethod() override;\n  void instanceMethod3();\n  Bar(int instanceVariable1, int instanceVariable3);\n\n  int instanceVariable3;\n  int instanceVariable4;\n  static int staticVariable2;\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nint Foo::staticVariable = 0;\nint Bar::staticVariable2 = 0;\n\nvoid Foo::instanceMethod() {\n}\n\nvoid Foo::instanceMethod2() {\n}\n\nFoo::Foo(int instanceVariable1) {\n  this->instanceVariable1 = instanceVariable1;\n  this->instanceVariable2 = 0;\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void Foo::__gc_mark() {\n  }\n#endif\n\nvoid Bar::instanceMethod() {\n  Foo::instanceMethod();\n}\n\nvoid Bar::instanceMethod3() {\n}\n\nBar::Bar(int instanceVariable1, int instanceVariable3) : Foo::Foo(instanceVariable1) {\n  this->instanceVariable3 = instanceVariable3;\n  this->instanceVariable4 = 0;\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void Bar::__gc_mark() {\n    Foo::__gc_mark();\n  }\n#endif\n\").cpp\n\n# Basic interface usage\ntest(\"\n@export\nclass Foo :: Bar, Baz {\n  def instanceMethod {}\n  def instanceMethod(x int) {}\n  def instanceMethod2 {}\n}\n\ninterface Bar {\n  def instanceMethod\n  def instanceMethod(x int)\n}\n\ninterface Baz {\n  def instanceMethod\n  def instanceMethod2\n}\n\", \"\nstruct Bar;\n\nstruct Baz;\n\nstruct Foo;\n\nstruct Bar : virtual Skew::Object {\n  virtual void instanceMethod() = 0;\n  virtual void instanceMethod(int x) = 0;\n};\n\nstruct Baz : virtual Skew::Object {\n  virtual void instanceMethod() = 0;\n  virtual void instanceMethod2() = 0;\n};\n\nstruct Foo : Bar, Baz {\n  virtual void instanceMethod();\n  virtual void instanceMethod(int x);\n  virtual void instanceMethod2();\n  Foo();\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nvoid Foo::instanceMethod() {\n}\n\nvoid Foo::instanceMethod(int x) {\n}\n\nvoid Foo::instanceMethod2() {\n}\n\nFoo::Foo() {\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void Foo::__gc_mark() {\n  }\n#endif\n\").cpp\n\n# Interface usage with tree shaking\ntest(\"\nclass Foo :: Bar, Baz {\n  def instanceMethod {}\n  def instanceMethod(x int) {}\n  def instanceMethod2 {}\n}\n\ninterface Bar {\n  def instanceMethod\n  def instanceMethod(x int)\n}\n\ninterface Baz {\n  def instanceMethod\n  def instanceMethod2\n}\n\n@export\ndef test {\n  var foo = Foo.new\n  foo.instanceMethod\n}\n\", \"\nstruct Bar;\n\nstruct Baz;\n\nstruct Foo;\n\nstruct Bar : virtual Skew::Object {\n  virtual void instanceMethod1() = 0;\n};\n\nstruct Baz : virtual Skew::Object {\n  virtual void instanceMethod1() = 0;\n};\n\nstruct Foo : Bar, Baz {\n  virtual void instanceMethod1();\n  Foo();\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nvoid test() {\n  Foo *foo = new Foo();\n  foo->instanceMethod1();\n}\n\nvoid Foo::instanceMethod1() {\n}\n\nFoo::Foo() {\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void Foo::__gc_mark() {\n  }\n#endif\n\").cpp\n\n# Type wrapping\ntest(\"\ntype Foo : double {\n  def scaleBy(scale Foo) Foo {\n    return ((self as double) * (scale as double)) as Foo\n  }\n}\n\nnamespace Foo {\n  const FOO = 0.5 as Foo\n}\n\n@export\ndef test(x double) Foo {\n  return (x as Foo).scaleBy(Foo.FOO)\n}\n\", \"\nnamespace Foo {\n  double scaleBy(double self, double scale);\n\n  extern double FOO;\n}\n\nnamespace Foo {\n  double FOO = 0.5;\n}\n\ndouble test(double x) {\n  return Foo::scaleBy(x, Foo::FOO);\n}\n\ndouble Foo::scaleBy(double self, double scale) {\n  return self * scale;\n}\n\").cpp\n\n# Casting between enums and integers must be explicit\ntest(\"\nenum Foo {\n  FOO\n}\n\n@export\ndef test Foo {\n  var x = Foo.FOO\n  return ((x as int) * 1) as Foo\n}\n\", \"\nenum struct Foo {\n  FOO = 0,\n};\n\nFoo test() {\n  Foo x = Foo::FOO;\n  return (Foo)((int)x * 1);\n}\n\").cpp\n\n# Lists and maps\ntest(\"\n@export\ndef foo {\n  var x = [1, 2, 3]\n  var y = {1: 2, 3: 4}\n  var z = {\\\"1\\\": 2, \\\"3\\\": 4}\n}\n\", \"\n#include <utility>\n\nvoid foo() {\n  Skew::List<int> *x = new Skew::List<int>({1, 2, 3});\n  Skew::IntMap<int> *y = new Skew::IntMap<int>({std::make_pair(1, 2), std::make_pair(3, 4)});\n  Skew::StringMap<int> *z = new Skew::StringMap<int>({std::make_pair(\\\"1\\\"_s, 2), std::make_pair(\\\"3\\\"_s, 4)});\n}\n\").cpp\n\n# Test math constants\ntest(\"\n@export\ndef main {\n  dynamic.foo(Math.NAN, Math.INFINITY, -Math.INFINITY)\n  dynamic.foo(Math.NAN.toString, Math.INFINITY.toString, (-Math.INFINITY).toString)\n}\n\", \"\nvoid main() {\n  foo(0.0 / 0.0, 1.0 / 0.0, -(1.0 / 0.0));\n  foo(__doubleToString(0.0 / 0.0), __doubleToString(1.0 / 0.0), __doubleToString(-(1.0 / 0.0)));\n}\n\").cpp.inlineAllFunctions\n\n# Test math constants\ntest(\"\n@export\ndef main {\n  dynamic.foo(Math.NAN, Math.INFINITY, -Math.INFINITY)\n  dynamic.foo(Math.NAN.toString, Math.INFINITY.toString, (-Math.INFINITY).toString)\n}\n\", \"\n#include <math.h>\n\nvoid main() {\n  foo(NAN, INFINITY, -INFINITY);\n  foo(__doubleToString(NAN), __doubleToString(INFINITY), __doubleToString(-INFINITY));\n}\n\").cpp.inlineAllFunctions.foldAllConstants\n\n# Test math toString\ntest(\"\n@export\ndef main {\n  dynamic.foo(0.toString, 1.0.toString, (-1.0).toString, 0.5.toString, (-0.5).toString)\n}\n\", \"\nvoid main() {\n  foo(__intToString(0), __doubleToString(1.0), __doubleToString(-1.0), __doubleToString(0.5), __doubleToString(-0.5));\n}\n\").cpp.inlineAllFunctions\n\n# Double literals must be emitted with a decimal point\ntest(\"\n@export\ndef main(x double) {\n  x = 1.0 / 2.0\n  x = 1e100 / 2e100\n  x = 1e-100 / 2e-100\n  x = 1.5 / 2.5\n  x = 1.5e100 / 2.5e100\n  x = 1.5e-100 / 2.5e-100\n}\n\", \"\nvoid main(double x) {\n  x = 1.0 / 2.0;\n  x = 1.0e+100 / 2.0e+100;\n  x = 1.0e-100 / 2.0e-100;\n  x = 1.5 / 2.5;\n  x = 1.5e+100 / 2.5e+100;\n  x = 1.5e-100 / 2.5e-100;\n}\n\").cpp\n\n# Check for a crash when converting switch statements to if chains\ntest(\"\n@export\ndef main {\n  switch \\\"a\\\" {\n    case \\\"b\\\" {}\n    case \\\"c\\\" {}\n    default {}\n  }\n}\n\", \"\nvoid main() {\n  Skew::string value = \\\"a\\\"_s;\n\n  if (value == \\\"b\\\"_s) {\n  }\n\n  else if (value == \\\"c\\\"_s) {\n  }\n\n  else {\n  }\n}\n\").cpp\n\n# Check different integer types\ntest(\"\nenum Foo {\n  A, B\n\n  def foo {}\n}\n\nflags Bar {\n  C, D\n\n  def foo {}\n}\n\ntype Baz : int {\n  def foo {}\n}\n\nnamespace Baz {\n  const X = 0 as Baz\n}\n\n@export\ndef test int {\n  var a = Foo.A\n  var c = Bar.C\n  var x = 0 as Baz\n  a.foo\n  c.foo\n  x.foo\n  return a + c + x as int + Foo.B + Bar.D + Baz.X as int\n}\n\", \"\nenum struct Foo {\n  A = 0,\n  B = 1,\n};\n\nnamespace Bar {\n  enum {\n    C = 1,\n    D = 2,\n  };\n}\n\nnamespace Baz {\n  void foo(int self);\n\n  extern int X;\n}\n\nnamespace in_Foo {\n  void foo(Foo self);\n}\n\nnamespace in_Bar {\n  void foo(int self);\n}\n\nnamespace Baz {\n  int X = 0;\n}\n\nint test() {\n  Foo a = Foo::A;\n  int c = Bar::C;\n  int x = 0;\n  in_Foo::foo(a);\n  in_Bar::foo(c);\n  Baz::foo(x);\n  return (int)a + c + x + (int)Foo::B + Bar::D + Baz::X;\n}\n\nvoid Baz::foo(int self) {\n}\n\nvoid in_Foo::foo(Foo self) {\n}\n\nvoid in_Bar::foo(int self) {\n}\n\").cpp\n\n# Check code generation for flags types\ntest(\"\nflags Foo {\n  X0\n  X1\n  X2\n  X3\n  X4\n  X5\n  X6\n  X7\n  X8\n  X9\n\n  X10\n  X11\n  X12\n  X13\n  X14\n  X15\n  X16\n  X17\n  X18\n  X19\n\n  X20\n  X21\n  X22\n  X23\n  X24\n  X25\n  X26\n  X27\n  X28\n  X29\n\n  X30\n  X31\n}\n\n@export\ndef test {\n  if !((.X0 | .X1) in (Foo.X30 | .X31)) {\n    var x = Foo.X0\n    x = .X1 | .X2\n    x &= ~.X3\n  }\n}\n\", \"\nnamespace Foo {\n  enum {\n    X0 = 1,\n    X1 = 2,\n    X2 = 4,\n    X3 = 8,\n    X30 = 1073741824,\n    X31 = -2147483648,\n  };\n}\n\nvoid test() {\n  if (!(((Foo::X0 | Foo::X1) & (Foo::X30 | Foo::X31)) != 0)) {\n    int x = Foo::X0;\n    x = Foo::X1 | Foo::X2;\n    x &= ~Foo::X3;\n  }\n}\n\").cpp\n\n# Check dynamic types\ntest(\"\n@export\ndef test(foo dynamic.Foo) dynamic.Bar {\n  return foo as dynamic.Bar + 0 as dynamic.Int + 0 as dynamic\n}\n\", \"\nBar test(Foo foo) {\n  return (Bar)foo + (Int)0 + 0;\n}\n\").cpp\n\n# Check bit shifts\ntest(\"\n@export\ndef test(x int) {\n  x = x << x\n  x = x >> x\n  x = x >>> x\n  x <<= x\n  x >>= x\n  x >>>= x\n}\n\", \"\nnamespace in_int {\n  int unsignedRightShift(int self, int x);\n}\n\nvoid test(int x) {\n  x = x << x;\n  x = x >> x;\n  x = in_int::unsignedRightShift(x, x);\n  x <<= x;\n  x >>= x;\n  x = in_int::unsignedRightShift(x, x);\n}\n\nint in_int::unsignedRightShift(int self, int x) {\n  return (int)((unsigned)self >> x);\n}\n\").cpp\n\n# Test lambda conversion with scope capture and currying\ntest(\"\n@export\nclass Foo {\n  var value = 0\n\n  def test(x int) int {\n    var y = 0\n    var f = (a int) => => (b int) => => value + x + y + a + b\n    return f(1)()(2)()\n  }\n}\n\", \"\nstruct Foo;\nstruct FooTestEnv;\nstruct FooTestLambda;\nstruct FooTestEnv1;\nstruct FooTestLambda1;\nstruct FooTestLambda2;\nstruct FooTestEnv2;\nstruct FooTestLambda3;\n\nstruct Foo : virtual Skew::Object {\n  int test(int x);\n  Foo();\n\n  int value;\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nstruct FooTestEnv : virtual Skew::Object {\n  FooTestEnv();\n\n  Foo *self;\n  int x;\n  int y;\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nstruct FooTestLambda : Skew::Fn1<Skew::Fn0<Skew::Fn1<Skew::Fn0<int> *, int> *> *, int> {\n  FooTestLambda(FooTestEnv *env);\n  virtual Skew::Fn0<Skew::Fn1<Skew::Fn0<int> *, int> *> *run(int a);\n\n  FooTestEnv *env;\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nstruct FooTestEnv1 : virtual Skew::Object {\n  FooTestEnv1(FooTestEnv *env);\n\n  int a;\n  FooTestEnv *env;\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nstruct FooTestLambda1 : Skew::Fn0<Skew::Fn1<Skew::Fn0<int> *, int> *> {\n  FooTestLambda1(FooTestEnv *env, FooTestEnv1 *env1);\n  virtual Skew::Fn1<Skew::Fn0<int> *, int> *run();\n\n  FooTestEnv *env;\n  FooTestEnv1 *env1;\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nstruct FooTestLambda2 : Skew::Fn1<Skew::Fn0<int> *, int> {\n  FooTestLambda2(FooTestEnv *env, FooTestEnv1 *env1);\n  virtual Skew::Fn0<int> *run(int b);\n\n  FooTestEnv *env;\n  FooTestEnv1 *env1;\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nstruct FooTestEnv2 : virtual Skew::Object {\n  FooTestEnv2(FooTestEnv *env, FooTestEnv1 *env1);\n\n  int b;\n  FooTestEnv *env;\n  FooTestEnv1 *env1;\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nstruct FooTestLambda3 : Skew::Fn0<int> {\n  FooTestLambda3(FooTestEnv *env, FooTestEnv1 *env1, FooTestEnv2 *env2);\n  virtual int run();\n\n  FooTestEnv *env;\n  FooTestEnv1 *env1;\n  FooTestEnv2 *env2;\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nint Foo::test(int x) {\n  FooTestEnv *env = new FooTestEnv();\n  env->self = this;\n  env->x = x;\n  env->y = 0;\n  Skew::Fn1<Skew::Fn0<Skew::Fn1<Skew::Fn0<int> *, int> *> *, int> *f = new FooTestLambda(env);\n  return f->run(1)->run()->run(2)->run();\n}\n\nFoo::Foo() {\n  this->value = 0;\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void Foo::__gc_mark() {\n  }\n#endif\n\nFooTestEnv::FooTestEnv() {\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void FooTestEnv::__gc_mark() {\n    Skew::GC::mark(self);\n  }\n#endif\n\nFooTestLambda::FooTestLambda(FooTestEnv *env) {\n  this->env = env;\n}\n\nSkew::Fn0<Skew::Fn1<Skew::Fn0<int> *, int> *> *FooTestLambda::run(int a) {\n  FooTestEnv1 *env1 = new FooTestEnv1(this->env);\n  env1->a = a;\n  return new FooTestLambda1(env1->env, env1);\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void FooTestLambda::__gc_mark() {\n    Skew::GC::mark(env);\n  }\n#endif\n\nFooTestEnv1::FooTestEnv1(FooTestEnv *env) {\n  this->env = env;\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void FooTestEnv1::__gc_mark() {\n    Skew::GC::mark(env);\n  }\n#endif\n\nFooTestLambda1::FooTestLambda1(FooTestEnv *env, FooTestEnv1 *env1) {\n  this->env = env;\n  this->env1 = env1;\n}\n\nSkew::Fn1<Skew::Fn0<int> *, int> *FooTestLambda1::run() {\n  return new FooTestLambda2(this->env, this->env1);\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void FooTestLambda1::__gc_mark() {\n    Skew::GC::mark(env);\n    Skew::GC::mark(env1);\n  }\n#endif\n\nFooTestLambda2::FooTestLambda2(FooTestEnv *env, FooTestEnv1 *env1) {\n  this->env = env;\n  this->env1 = env1;\n}\n\nSkew::Fn0<int> *FooTestLambda2::run(int b) {\n  FooTestEnv2 *env2 = new FooTestEnv2(this->env, this->env1);\n  env2->b = b;\n  return new FooTestLambda3(env2->env, env2->env1, env2);\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void FooTestLambda2::__gc_mark() {\n    Skew::GC::mark(env);\n    Skew::GC::mark(env1);\n  }\n#endif\n\nFooTestEnv2::FooTestEnv2(FooTestEnv *env, FooTestEnv1 *env1) {\n  this->env = env;\n  this->env1 = env1;\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void FooTestEnv2::__gc_mark() {\n    Skew::GC::mark(env);\n    Skew::GC::mark(env1);\n  }\n#endif\n\nFooTestLambda3::FooTestLambda3(FooTestEnv *env, FooTestEnv1 *env1, FooTestEnv2 *env2) {\n  this->env = env;\n  this->env1 = env1;\n  this->env2 = env2;\n}\n\nint FooTestLambda3::run() {\n  return this->env->self->value + this->env->x + this->env->y + this->env1->a + this->env2->b;\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void FooTestLambda3::__gc_mark() {\n    Skew::GC::mark(env);\n    Skew::GC::mark(env1);\n    Skew::GC::mark(env2);\n  }\n#endif\n\").cpp\n\n# Test lambda conversion at global scope\ntest(\"\nvar f = (x int) => (y int) => x + y\n\n@entry\ndef test int {\n  return f(1)(2)\n}\n\", \"\nstruct Lambda;\nstruct LambdaRunEnv;\nstruct LambdaRunLambda;\n\nstruct Lambda : Skew::Fn1<Skew::Fn1<int, int> *, int> {\n  Lambda();\n  virtual Skew::Fn1<int, int> *run(int x);\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nstruct LambdaRunEnv : virtual Skew::Object {\n  LambdaRunEnv();\n\n  int x;\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nstruct LambdaRunLambda : Skew::Fn1<int, int> {\n  LambdaRunLambda(LambdaRunEnv *env);\n  virtual int run(int y);\n\n  LambdaRunEnv *env;\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nSkew::Root<Skew::Fn1<Skew::Fn1<int, int> *, int>> f = new Lambda();\n\nint main() {\n  return f->run(1)->run(2);\n}\n\nLambda::Lambda() {\n}\n\nSkew::Fn1<int, int> *Lambda::run(int x) {\n  LambdaRunEnv *env = new LambdaRunEnv();\n  env->x = x;\n  return new LambdaRunLambda(env);\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void Lambda::__gc_mark() {\n  }\n#endif\n\nLambdaRunEnv::LambdaRunEnv() {\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void LambdaRunEnv::__gc_mark() {\n  }\n#endif\n\nLambdaRunLambda::LambdaRunLambda(LambdaRunEnv *env) {\n  this->env = env;\n}\n\nint LambdaRunLambda::run(int y) {\n  return this->env->x + y;\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void LambdaRunLambda::__gc_mark() {\n    Skew::GC::mark(env);\n  }\n#endif\n\").cpp\n\n# Check for a crash with nested loop handling\ntest(\"\n@export\ndef test {\n  var foo = 0\n  var bar = () int => {\n    while true {\n      for baz in [1] {\n        return foo + baz\n      }\n    }\n  }\n  bar()\n}\n\", \"\nstruct TestEnv;\nstruct TestLambda;\n\nstruct TestEnv : virtual Skew::Object {\n  TestEnv();\n\n  int foo;\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nstruct TestLambda : Skew::Fn0<int> {\n  TestLambda(TestEnv *env);\n  virtual int run();\n\n  TestEnv *env;\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nvoid test() {\n  TestEnv *env = new TestEnv();\n  env->foo = 0;\n  Skew::Fn0<int> *bar = new TestLambda(env);\n  bar->run();\n}\n\nTestEnv::TestEnv() {\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void TestEnv::__gc_mark() {\n  }\n#endif\n\nTestLambda::TestLambda(TestEnv *env) {\n  this->env = env;\n}\n\nint TestLambda::run() {\n  while (true) {\n    for (int baz : *new Skew::List<int>({1})) {\n      return this->env->foo + baz;\n    }\n  }\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void TestLambda::__gc_mark() {\n    Skew::GC::mark(env);\n  }\n#endif\n\").cpp\n\n# Check that recursive lambdas work\ntest(\"\n@export\ndef main {\n  var f fn()\n  f = => f()\n  f()\n}\n\", \"\nstruct MainEnv;\nstruct MainLambda;\n\nstruct MainEnv : virtual Skew::Object {\n  MainEnv();\n\n  Skew::FnVoid0 *f;\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nstruct MainLambda : Skew::FnVoid0 {\n  MainLambda(MainEnv *env);\n  virtual void run();\n\n  MainEnv *env;\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nvoid main() {\n  MainEnv *env = new MainEnv();\n  env->f = nullptr;\n  env->f = new MainLambda(env);\n  env->f->run();\n}\n\nMainEnv::MainEnv() {\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void MainEnv::__gc_mark() {\n    Skew::GC::mark(f);\n  }\n#endif\n\nMainLambda::MainLambda(MainEnv *env) {\n  this->env = env;\n}\n\nvoid MainLambda::run() {\n  this->env->f->run();\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void MainLambda::__gc_mark() {\n    Skew::GC::mark(env);\n  }\n#endif\n\").cpp\n\n# Check for a crash in captured variable substitution\ntest(\"\n@export\ndef main {\n  var x = [1]\n  var f = => x\n  for y in x {}\n  f()\n}\n\", \"\nstruct MainEnv;\nstruct MainLambda;\n\nstruct MainEnv : virtual Skew::Object {\n  MainEnv();\n\n  Skew::List<int> *x;\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nstruct MainLambda : Skew::Fn0<Skew::List<int> *> {\n  MainLambda(MainEnv *env);\n  virtual Skew::List<int> *run();\n\n  MainEnv *env;\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nvoid main() {\n  MainEnv *env = new MainEnv();\n  env->x = new Skew::List<int>({1});\n  Skew::Fn0<Skew::List<int> *> *f = new MainLambda(env);\n\n  for (int y : *env->x) {\n  }\n\n  f->run();\n}\n\nMainEnv::MainEnv() {\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void MainEnv::__gc_mark() {\n    Skew::GC::mark(x);\n  }\n#endif\n\nMainLambda::MainLambda(MainEnv *env) {\n  this->env = env;\n}\n\nSkew::List<int> *MainLambda::run() {\n  return this->env->x;\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void MainLambda::__gc_mark() {\n    Skew::GC::mark(env);\n  }\n#endif\n\").cpp\n\n# Test break statements inside a switch\ntest(\"\n@export\ndef test(x int, y bool) {\n  while true {\n    switch x {\n      case 0 {\n        if y {\n          break\n        }\n      }\n    }\n  }\n}\n\", \"\nvoid test(int x, bool y) {\n  while (true) {\n    switch (x) {\n      case 0: {\n        if (y) {\n          goto label;\n        }\n        break;\n      }\n    }\n  }\n  label:;\n}\n\").cpp\n\n# Avoid emitting an empty anonymous enum to avoid a clang warning\ntest(\"\n@export {\n  flags Foo {\n    FOO # Comment 1\n\n    # Comment 2\n    BAR\n    BAZ\n  }\n  flags Bar {}\n}\n\", \"\nnamespace Foo {\n  enum {\n    // Comment 1\n    FOO = 1,\n\n    // Comment 2\n    BAR = 2,\n    BAZ = 4,\n  };\n}\n\nnamespace Bar {\n}\n\").cpp\n\n# Check for accidental mutation of argument types during globalization\ntest(\"\nclass Foo {\n  def test(foo Foo) {}\n}\n\ndef foo {\n  var visit fn(Foo)\n  visit = foo => visit(foo)\n}\n\n@export\ndef test {\n  Foo.new.test(null)\n  foo\n}\n\", \"\nstruct Foo;\nstruct FooEnv;\nstruct FooLambda;\n\nstruct Foo : virtual Skew::Object {\n  static void test(Foo *self, Foo *foo);\n  Foo();\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nstruct FooEnv : virtual Skew::Object {\n  FooEnv();\n\n  Skew::FnVoid1<Foo *> *visit;\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nstruct FooLambda : Skew::FnVoid1<Foo *> {\n  FooLambda(FooEnv *env);\n  virtual void run(Foo *foo);\n\n  FooEnv *env;\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nvoid foo() {\n  FooEnv *env = new FooEnv();\n  env->visit = nullptr;\n  env->visit = new FooLambda(env);\n}\n\nvoid test() {\n  Foo::test(new Foo(), (Foo *)nullptr);\n  foo();\n}\n\nvoid Foo::test(Foo *self, Foo *foo) {\n}\n\nFoo::Foo() {\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void Foo::__gc_mark() {\n  }\n#endif\n\nFooEnv::FooEnv() {\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void FooEnv::__gc_mark() {\n    Skew::GC::mark(visit);\n  }\n#endif\n\nFooLambda::FooLambda(FooEnv *env) {\n  this->env = env;\n}\n\nvoid FooLambda::run(Foo *foo) {\n  this->env->visit->run(foo);\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void FooLambda::__gc_mark() {\n    Skew::GC::mark(env);\n  }\n#endif\n\").cpp.globalizeAllFunctions\n\n# Test dead code elimination and imports\ntest(\"\n@import {\n  var a fn()\n  def b(x fn(int))\n}\n\nvar c fn(int, int)\ndef d(x fn(int, int, int)) {}\n\n@export\ndef test {\n  a = => {}\n  b(x => {})\n  c = (x, y) => {}\n  d((x, y, z) => {})\n}\n\", \"\nstruct TestLambda;\nstruct TestLambda1;\nstruct TestLambda2;\nstruct TestLambda3;\n\nstruct TestLambda : Skew::FnVoid0 {\n  TestLambda();\n  virtual void run();\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nstruct TestLambda1 : Skew::FnVoid1<int> {\n  TestLambda1();\n  virtual void run(int x);\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nstruct TestLambda2 : Skew::FnVoid2<int, int> {\n  TestLambda2();\n  virtual void run(int x, int y);\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nstruct TestLambda3 : Skew::FnVoid3<int, int, int> {\n  TestLambda3();\n  virtual void run(int x, int y, int z);\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nSkew::Root<Skew::FnVoid2<int, int>> c = nullptr;\n\nvoid d(Skew::FnVoid3<int, int, int> *x) {\n}\n\nvoid test() {\n  a = new TestLambda();\n  b(new TestLambda1());\n  c = new TestLambda2();\n  d(new TestLambda3());\n}\n\nTestLambda::TestLambda() {\n}\n\nvoid TestLambda::run() {\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void TestLambda::__gc_mark() {\n  }\n#endif\n\nTestLambda1::TestLambda1() {\n}\n\nvoid TestLambda1::run(int x) {\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void TestLambda1::__gc_mark() {\n  }\n#endif\n\nTestLambda2::TestLambda2() {\n}\n\nvoid TestLambda2::run(int x, int y) {\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void TestLambda2::__gc_mark() {\n  }\n#endif\n\nTestLambda3::TestLambda3() {\n}\n\nvoid TestLambda3::run(int x, int y, int z) {\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void TestLambda3::__gc_mark() {\n  }\n#endif\n\").cpp\n\n# Test lambda conversion in loops\ntest(\"\n@export\ndef test(list List<int>) {\n  (=> list)()\n  for i in list {\n    (=> list.append(i))()\n  }\n}\n\", \"\nstruct TestEnv;\nstruct TestLambda;\nstruct TestEnv1;\nstruct TestLambda1;\n\nstruct TestEnv : virtual Skew::Object {\n  TestEnv();\n\n  Skew::List<int> *list;\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nstruct TestLambda : Skew::Fn0<Skew::List<int> *> {\n  TestLambda(TestEnv *env);\n  virtual Skew::List<int> *run();\n\n  TestEnv *env;\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nstruct TestEnv1 : virtual Skew::Object {\n  TestEnv1(TestEnv *env);\n\n  int i;\n  TestEnv *env;\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nstruct TestLambda1 : Skew::FnVoid0 {\n  TestLambda1(TestEnv *env, TestEnv1 *env1);\n  virtual void run();\n\n  TestEnv *env;\n  TestEnv1 *env1;\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nvoid test(Skew::List<int> *list) {\n  TestEnv *env = new TestEnv();\n  env->list = list;\n  (new TestLambda(env))->run();\n\n  for (int i : *env->list) {\n    TestEnv1 *env1 = new TestEnv1(env);\n    env1->i = i;\n    (new TestLambda1(env1->env, env1))->run();\n  }\n}\n\nTestEnv::TestEnv() {\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void TestEnv::__gc_mark() {\n    Skew::GC::mark(list);\n  }\n#endif\n\nTestLambda::TestLambda(TestEnv *env) {\n  this->env = env;\n}\n\nSkew::List<int> *TestLambda::run() {\n  return this->env->list;\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void TestLambda::__gc_mark() {\n    Skew::GC::mark(env);\n  }\n#endif\n\nTestEnv1::TestEnv1(TestEnv *env) {\n  this->env = env;\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void TestEnv1::__gc_mark() {\n    Skew::GC::mark(env);\n  }\n#endif\n\nTestLambda1::TestLambda1(TestEnv *env, TestEnv1 *env1) {\n  this->env = env;\n  this->env1 = env1;\n}\n\nvoid TestLambda1::run() {\n  this->env->list->append(this->env1->i);\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void TestLambda1::__gc_mark() {\n    Skew::GC::mark(env);\n    Skew::GC::mark(env1);\n  }\n#endif\n\").cpp\n\n# Constructors on dynamic types shouldn't need parentheses\ntest(\"\n@export\ndef test {\n  dynamic.Foo.new\n  dynamic.Foo.new()\n  dynamic.Foo.new.test\n  dynamic.Foo.new().test\n  dynamic.Foo<dynamic.Bar>.new.test\n  dynamic.Foo<dynamic.Bar>.new().test\n\n  var a = dynamic.Foo.new\n  var b = dynamic.Foo.new()\n  var c = dynamic.Foo.new.test\n  var d = dynamic.Foo.new().test\n  var e = dynamic.Foo<dynamic.Bar>.new.test\n  var f = dynamic.Foo<dynamic.Bar>.new().test\n}\n\", \"\nvoid test() {\n  new Foo();\n  new Foo();\n  (new Foo())->test;\n  (new Foo())->test;\n  (new Foo<Bar>())->test;\n  (new Foo<Bar>())->test;\n  void *a = new Foo();\n  void *b = new Foo();\n  void *c = (new Foo())->test;\n  void *d = (new Foo())->test;\n  void *e = (new Foo<Bar>())->test;\n  void *f = (new Foo<Bar>())->test;\n}\n\").cpp\n\n# Check preserving enum types for constant-folded enum values\ntest(\"\nenum Foo {\n  FOO\n  BAR\n}\n\ndef foo(x Foo) {\n  bar(x)\n}\n\n@import\ndef bar(x int)\n\n@export\ndef test(x bool) {\n  foo(x ? .BAR : .FOO)\n}\n\", \"\nenum struct Foo {\n};\n\nvoid test(bool x) {\n  bar((int)(x ? (Foo)1 : (Foo)0));\n}\n\").cpp.foldAllConstants.inlineAllFunctions\n\n# Test parentheses generation to avoid C++ compiler warnings\ntest(\"\n@export\ndef test(x int, y int) {\n  x = x == 0 && y == 1 || x == 2 ? 1 : 0\n  x = x & y | x\n\n  # ^\n  x = x + y ^ x\n  x = x - y ^ x\n  x = x * y ^ x\n  x = x / y ^ x\n\n  # |\n  x = x + y | x\n  x = x - y | x\n  x = x * y | x\n  x = x / y | x\n\n  # &\n  x = x + y & x\n  x = x - y & x\n  x = x * y & x\n  x = x / y & x\n\n  # <<\n  x = x + y << x\n  x = x - y << x\n  x = x * y << x\n  x = x / y << x\n\n  # >>\n  x = x + y >> x\n  x = x - y >> x\n  x = x * y >> x\n  x = x / y >> x\n}\n\", \"\nvoid test(int x, int y) {\n  x = (x == 0 && y == 1) || x == 2 ? 1 : 0;\n  x = (x & y) | x;\n\n  // ^\n  x = (x + y) ^ x;\n  x = (x - y) ^ x;\n  x = x * y ^ x;\n  x = x / y ^ x;\n\n  // |\n  x = (x + y) | x;\n  x = (x - y) | x;\n  x = x * y | x;\n  x = x / y | x;\n\n  // &\n  x = (x + y) & x;\n  x = (x - y) & x;\n  x = x * y & x;\n  x = x / y & x;\n\n  // <<\n  x = (x + y) << x;\n  x = (x - y) << x;\n  x = x * y << x;\n  x = x / y << x;\n\n  // >>\n  x = (x + y) >> x;\n  x = (x - y) >> x;\n  x = x * y >> x;\n  x = x / y >> x;\n}\n\").cpp\n\n# Check forward-declaration of global variables\ntest(\"\nnamespace Foo {\n  const FOO = 0\n}\n\nconst foo = Foo.FOO\n\n@export\ndef test {\n  foo\n}\n\", \"\nnamespace Foo {\n  extern int FOO;\n}\n\nint foo = Foo::FOO;\n\nnamespace Foo {\n  int FOO = 0;\n}\n\nvoid test() {\n  foo;\n}\n\").cpp\n\n# Check that exporting wrapped types with constructors is feasible\ntest(\"\n@export\ntype Foo : int {\n  def foo int {\n    return self as int * 2\n  }\n}\n\nnamespace Foo {\n  def new(x int) Foo {\n    return (x / 2) as Foo\n  }\n}\n\n@export\ndef test {\n  Foo.new(0).foo\n}\n\", \"\nnamespace Foo {\n  int foo(int self);\n  int _new(int x);\n}\n\nvoid test() {\n  Foo::foo(Foo::_new(0));\n}\n\nint Foo::foo(int self) {\n  return self * 2;\n}\n\nint Foo::_new(int x) {\n  return x / 2;\n}\n\").cpp\n\n# Check for a validation error with types inside exported classes\ntest(\"\n@export\nclass Foo {\n  enum Bar {\n    BAZ\n  }\n}\n\n@export\ndef test {\n  Foo.Bar.BAZ\n}\n\", \"\nstruct Foo;\n\nnamespace in_Foo {\n  enum struct Bar {\n    BAZ = 0,\n  };\n}\n\nstruct Foo : virtual Skew::Object {\n  Foo();\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nnamespace in_Bar {\n  Skew::string toString(in_Foo::Bar self);\n\n  extern Skew::Root<Skew::List<Skew::string>> _strings;\n}\n\nnamespace in_Foo {\n}\n\nnamespace in_Bar {\n  Skew::Root<Skew::List<Skew::string>> _strings = new Skew::List<Skew::string>({\\\"BAZ\\\"_s});\n}\n\nvoid test() {\n  in_Foo::Bar::BAZ;\n}\n\nFoo::Foo() {\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void Foo::__gc_mark() {\n  }\n#endif\n\nSkew::string in_Bar::toString(in_Foo::Bar self) {\n  return (*in_Bar::_strings.get())[(int)self];\n}\n\").cpp\n\n# Check wrapped types with type parameters\ntest(\"\ntype Foo<T> : List<T> {\n  def size int {\n    return (self as List<T>).count\n  }\n}\n\n@entry\ndef main {\n  (List<int>.new as Foo<int>).size\n}\n\", \"\nnamespace Foo {\n}\n\nnamespace in_Foo {\n  template <typename T>\n  int size(Skew::List<T> *self);\n}\n\nvoid main() {\n  in_Foo::size(new Skew::List<int>());\n}\n\ntemplate <typename T>\nint in_Foo::size(Skew::List<T> *self) {\n  return self->count();\n}\n\").cpp\n\n# Check the \"is\" operator\ntest(\"\nclass Foo {}\nclass Bar : Foo {}\n\n@entry\ndef main {\n  Foo.new is Bar == true || true == Foo.new is Bar\n}\n\", \"\nstruct Foo;\nstruct Bar;\n\nstruct Foo : virtual Skew::Object {\n  Foo();\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nstruct Bar : Foo {\n  Bar();\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nvoid main() {\n  dynamic_cast<Bar *>(new Foo()) != nullptr == true || true == (dynamic_cast<Bar *>(new Foo()) != nullptr);\n}\n\nFoo::Foo() {\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void Foo::__gc_mark() {\n  }\n#endif\n\nBar::Bar() : Foo::Foo() {\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void Bar::__gc_mark() {\n    Foo::__gc_mark();\n  }\n#endif\n\").cpp\n\n# Need to emit \".get()\" for global variables inside roots\ntest(\"\nclass Foo {}\n\nvar foo = Foo.new\n\n@entry\ndef main {\n  var x = Foo.new\n  x = foo ?? x\n  foo = x ?? foo\n}\n\", \"\nstruct Foo;\n\nstruct Foo : virtual Skew::Object {\n  Foo();\n\n  #ifdef SKEW_GC_MARK_AND_SWEEP\n    virtual void __gc_mark() override;\n  #endif\n};\n\nSkew::Root<Foo> foo = new Foo();\n\nvoid main() {\n  Foo *x = new Foo();\n  x = foo.get() != (Foo *)nullptr ? foo.get() : x;\n  foo = x != (Foo *)nullptr ? x : foo.get();\n}\n\nFoo::Foo() {\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void Foo::__gc_mark() {\n  }\n#endif\n\").cpp\n\n# Make sure to fully specify the base class in __gc_mark() for derived classes to avoid infinite recursion\ntest(\"\nclass A.Foo {}\n\n@export\nclass B.Foo : A.Foo {}\n\", \"\nnamespace A {\n  struct Foo;\n}\n\nnamespace B {\n  struct Foo;\n}\n\nnamespace A {\n  struct Foo : virtual Skew::Object {\n    Foo();\n\n    #ifdef SKEW_GC_MARK_AND_SWEEP\n      virtual void __gc_mark() override;\n    #endif\n  };\n}\n\nnamespace B {\n  struct Foo : A::Foo {\n    Foo();\n\n    #ifdef SKEW_GC_MARK_AND_SWEEP\n      virtual void __gc_mark() override;\n    #endif\n  };\n}\n\nA::Foo::Foo() {\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void A::Foo::__gc_mark() {\n  }\n#endif\n\nB::Foo::Foo() : A::Foo::Foo() {\n}\n\n#ifdef SKEW_GC_MARK_AND_SWEEP\n  void B::Foo::__gc_mark() {\n    A::Foo::__gc_mark();\n  }\n#endif\n\").cpp\n\n# Check block comments before a statement\ntest(\"\n@entry\ndef main {\n  # This is\n  # a block\n  # comment\n\n  return\n}\n\", \"\nvoid main() {\n  // This is\n  // a block\n  // comment\n\n  return;\n}\n\").cpp\n\n# Check trailing block comments\ntest(\"\n@entry\ndef main {\n  # This is\n  # a block\n  # comment\n}\n\", \"\nvoid main() {\n  // This is\n  // a block\n  // comment\n}\n\").cpp\n\n  }\n}\n"
  },
  {
    "path": "tests/csharp.sk",
    "content": "namespace Skew.Tests {\n  def testCSharp {\n\n# Test entry point\ntest(\"\n@entry\ndef test {}\n\", \"\npublic class Globals\n{\n    public static void Main()\n    {\n    }\n}\n\").csharp\n\n# Test entry point\ntest(\"\n@entry\ndef test int {\n  return 0\n}\n\", \"\npublic class Globals\n{\n    public static int Main()\n    {\n        return 0;\n    }\n}\n\").csharp\n\n# Test entry point\ntest(\"\n@entry\ndef test(x List<string>) {\n}\n\", \"\nusing System.Collections.Generic;\n\npublic class Globals\n{\n    public static void Main(string[] x1)\n    {\n        List<string> x = new List<string>(x1);\n    }\n}\n\").csharp.inlineAllFunctions\n\n# Test entry point\ntest(\"\n@entry\ndef test(x List<string>) int {\n  return x.count\n}\n\", \"\nusing System.Collections.Generic;\n\npublic class Globals\n{\n    public static int Main(string[] x1)\n    {\n        List<string> x = new List<string>(x1);\n        return x.Count;\n    }\n}\n\").csharp.inlineAllFunctions\n\n# Test entry point inside a namespace\ntest(\"\nnamespace ns {\n  @entry\n  def test(x List<string>) int {\n    test([])\n    return x.count\n  }\n}\n\", \"\nusing System.Collections.Generic;\n\npublic class ns\n{\n    public static int Main(string[] x1)\n    {\n        List<string> x = new List<string>(x1);\n        ns.Main(new List<string>());\n        return x.Count;\n    }\n}\n\").csharp.inlineAllFunctions\n\n# Basic class hierarchy\ntest(\"\n@export\nclass Foo {\n  const instanceVariable1 int\n  const instanceVariable2 = 0\n  def instanceMethod {}\n  def instanceMethod2 {}\n}\n\nnamespace Foo {\n  const staticVariable = 0\n}\n\n@export\nclass Bar : Foo {\n  const instanceVariable3 int\n  const instanceVariable4 = 0\n  over instanceMethod { super }\n  def instanceMethod3 {}\n}\n\nnamespace Bar {\n  const staticVariable2 = 0\n}\n\", \"\npublic class Foo\n{\n    public int instanceVariable1;\n    public int instanceVariable2 = 0;\n    public static int staticVariable = 0;\n\n    public virtual void instanceMethod()\n    {\n    }\n\n    public void instanceMethod2()\n    {\n    }\n\n    public Foo(int instanceVariable1)\n    {\n        this.instanceVariable1 = instanceVariable1;\n        this.instanceVariable2 = 0;\n    }\n}\n\npublic class Bar : Foo\n{\n    public int instanceVariable3;\n    public int instanceVariable4 = 0;\n    public static int staticVariable2 = 0;\n\n    public override void instanceMethod()\n    {\n        base.instanceMethod();\n    }\n\n    public void instanceMethod3()\n    {\n    }\n\n    public Bar(int instanceVariable1, int instanceVariable3) : base(instanceVariable1)\n    {\n        this.instanceVariable3 = instanceVariable3;\n        this.instanceVariable4 = 0;\n    }\n}\n\").csharp\n\n# Basic interface usage\ntest(\"\n@export\nclass Foo :: Bar, Baz {\n  def instanceMethod {}\n  def instanceMethod(x int) {}\n  def instanceMethod2 {}\n}\n\ninterface Bar {\n  def instanceMethod\n  def instanceMethod(x int)\n}\n\ninterface Baz {\n  def instanceMethod\n  def instanceMethod2\n}\n\", \"\npublic class Foo : Bar, Baz\n{\n    public virtual void instanceMethod()\n    {\n    }\n\n    public virtual void instanceMethod(int x)\n    {\n    }\n\n    public virtual void instanceMethod2()\n    {\n    }\n\n    public Foo()\n    {\n    }\n}\n\npublic interface Bar\n{\n    void instanceMethod();\n\n    void instanceMethod(int x);\n}\n\npublic interface Baz\n{\n    void instanceMethod();\n\n    void instanceMethod2();\n}\n\").csharp\n\n# Interface usage with tree shaking\ntest(\"\nclass Foo :: Bar, Baz {\n  def instanceMethod {}\n  def instanceMethod(x int) {}\n  def instanceMethod2 {}\n}\n\ninterface Bar {\n  def instanceMethod\n  def instanceMethod(x int)\n}\n\ninterface Baz {\n  def instanceMethod\n  def instanceMethod2\n}\n\n@export\ndef test {\n  var foo = Foo.new\n  foo.instanceMethod\n}\n\", \"\npublic class Foo : Bar, Baz\n{\n    public virtual void instanceMethod1()\n    {\n    }\n\n    public Foo()\n    {\n    }\n}\n\npublic interface Bar\n{\n    void instanceMethod1();\n}\n\npublic interface Baz\n{\n    void instanceMethod1();\n}\n\npublic class Globals\n{\n    public static void test()\n    {\n        Foo foo = new Foo();\n        foo.instanceMethod1();\n    }\n}\n\").csharp\n\n# Type wrapping\ntest(\"\ntype Foo : double {\n  def scaleBy(scale Foo) Foo {\n    return ((self as double) * (scale as double)) as Foo\n  }\n}\n\nnamespace Foo {\n  const FOO = 0.5 as Foo\n}\n\n@export\ndef test(x double) Foo {\n  return (x as Foo).scaleBy(Foo.FOO)\n}\n\", \"\npublic static class Foo\n{\n    public static double FOO = 0.5;\n\n    public static double scaleBy(double self, double scale)\n    {\n        return self * scale;\n    }\n}\n\npublic class Globals\n{\n    public static double test(double x)\n    {\n        return Foo.scaleBy(x, Foo.FOO);\n    }\n}\n\").csharp\n\n# Casting between enums and integers must be explicit\ntest(\"\nenum Foo {\n  FOO\n}\n\n@export\ndef test Foo {\n  var x = Foo.FOO\n  return ((x as int) * 1) as Foo\n}\n\", \"\npublic enum Foo\n{\n    FOO = 0,\n}\n\npublic class Globals\n{\n    public static Foo test()\n    {\n        Foo x = Foo.FOO;\n        return (Foo)((int)x * 1);\n    }\n}\n\").csharp\n\n# Lists and maps\ntest(\"\n@export\ndef foo {\n  var x = [1, 2, 3]\n  var y = {1: 2, 3: 4}\n  var z = {\\\"1\\\": 2, \\\"3\\\": 4}\n}\n\", \"\nusing System.Collections.Generic;\n\npublic class in_StringMap\n{\n    public static Dictionary<string, T> insert<T>(Dictionary<string, T> self, string key, T value)\n    {\n        self.Add(key, value);\n        return self;\n    }\n}\n\npublic class in_IntMap\n{\n    public static Dictionary<int, T> insert<T>(Dictionary<int, T> self, int key, T value)\n    {\n        self.Add(key, value);\n        return self;\n    }\n}\n\npublic class Globals\n{\n    public static void foo()\n    {\n        List<int> x = new List<int> { 1, 2, 3 };\n        Dictionary<int, int> y = in_IntMap.insert(in_IntMap.insert(new Dictionary<int, int>(), 1, 2), 3, 4);\n        Dictionary<string, int> z = in_StringMap.insert(in_StringMap.insert(new Dictionary<string, int>(), \\\"1\\\", 2), \\\"3\\\", 4);\n    }\n}\n\").csharp\n\n# Inheriting from a dynamically-specified type\ntest(\"\n@export\nclass Error : dynamic.System.Exception {\n}\n\", \"\npublic class Error : System.Exception\n{\n    public Error()\n    {\n    }\n}\n\").csharp\n\n# Test math constants\ntest(\"\n@export\ndef main {\n  dynamic.foo(Math.NAN, Math.INFINITY, -Math.INFINITY)\n  dynamic.foo(Math.NAN.toString, Math.INFINITY.toString, (-Math.INFINITY).toString)\n}\n\", \"\npublic class Globals\n{\n    public static void main()\n    {\n        foo(0.0 / 0.0, 1.0 / 0.0, -(1.0 / 0.0));\n        foo((0.0 / 0.0).ToString(), (1.0 / 0.0).ToString(), (-(1.0 / 0.0)).ToString());\n    }\n}\n\").csharp.inlineAllFunctions\n\n# Test math constants\ntest(\"\n@export\ndef main {\n  dynamic.foo(Math.NAN, Math.INFINITY, -Math.INFINITY)\n  dynamic.foo(Math.NAN.toString, Math.INFINITY.toString, (-Math.INFINITY).toString)\n}\n\", \"\nusing System;\n\npublic class Globals\n{\n    public static void main()\n    {\n        foo(Double.NaN, Double.PositiveInfinity, Double.NegativeInfinity);\n        foo(Double.NaN.ToString(), Double.PositiveInfinity.ToString(), Double.NegativeInfinity.ToString());\n    }\n}\n\").csharp.inlineAllFunctions.foldAllConstants\n\n# Test math toString\ntest(\"\n@export\ndef main {\n  dynamic.foo(0.toString, 1.0.toString, (-1.0).toString, 0.5.toString, (-0.5).toString)\n}\n\", \"\npublic class Globals\n{\n    public static void main()\n    {\n        foo(0.ToString(), 1.0.ToString(), (-1.0).ToString(), 0.5.ToString(), (-0.5).ToString());\n    }\n}\n\").csharp\n\n# Test math toString\ntest(\"\n@export\ndef main {\n  dynamic.foo(0.toString, 1.0.toString, (-1.0).toString, 0.5.toString, (-0.5).toString)\n}\n\", \"\npublic class Globals\n{\n    public static void main()\n    {\n        foo(\\\"0\\\", 1.0.ToString(), (-1.0).ToString(), 0.5.ToString(), (-0.5).ToString());\n    }\n}\n\").csharp.foldAllConstants\n\n# Double literals must be emitted with a decimal point\ntest(\"\n@export\ndef main(x double) {\n  x = 1.0 / 2.0\n  x = 1e100 / 2e100\n  x = 1e-100 / 2e-100\n  x = 1.5 / 2.5\n  x = 1.5e100 / 2.5e100\n  x = 1.5e-100 / 2.5e-100\n}\n\", \"\npublic class Globals\n{\n    public static void main(double x)\n    {\n        x = 1.0 / 2.0;\n        x = 1.0e+100 / 2.0e+100;\n        x = 1.0e-100 / 2.0e-100;\n        x = 1.5 / 2.5;\n        x = 1.5e+100 / 2.5e+100;\n        x = 1.5e-100 / 2.5e-100;\n    }\n}\n\").csharp\n\n# Check for a crash when converting switch statements to if chains\ntest(\"\n@export\ndef main {\n  switch \\\"a\\\" {\n    case \\\"b\\\" {}\n    case \\\"c\\\" {}\n    default {}\n  }\n}\n\", \"\npublic class Globals\n{\n    public static void main()\n    {\n        string value = \\\"a\\\";\n\n        if (value == \\\"b\\\")\n        {\n        }\n        else if (value == \\\"c\\\")\n        {\n        }\n        else\n        {\n        }\n    }\n}\n\").csharp\n\n# Check different integer types\ntest(\"\nenum Foo {\n  A, B\n\n  def foo {}\n}\n\nflags Bar {\n  C, D\n\n  def foo {}\n}\n\ntype Baz : int {\n  def foo {}\n}\n\nnamespace Baz {\n  const X = 0 as Baz\n}\n\n@export\ndef test int {\n  var a = Foo.A\n  var c = Bar.C\n  var x = 0 as Baz\n  a.foo\n  c.foo\n  x.foo\n  return a + c + x as int + Foo.B + Bar.D + Baz.X as int\n}\n\", \"\npublic enum Foo\n{\n    A = 0,\n    B = 1,\n}\n\npublic static class Bar\n{\n    public const int C = 1;\n    public const int D = 2;\n}\n\npublic static class Baz\n{\n    public static int X = 0;\n\n    public static void foo(int self)\n    {\n    }\n}\n\npublic class in_Foo\n{\n    public static void foo(Foo self)\n    {\n    }\n}\n\npublic class in_Bar\n{\n    public static void foo(int self)\n    {\n    }\n}\n\npublic class Globals\n{\n    public static int test()\n    {\n        Foo a = Foo.A;\n        int c = Bar.C;\n        int x = 0;\n        in_Foo.foo(a);\n        in_Bar.foo(c);\n        Baz.foo(x);\n        return (int)a + c + x + (int)Foo.B + Bar.D + Baz.X;\n    }\n}\n\").csharp\n\n# Check code generation for flags types\ntest(\"\nflags Foo {\n  X0\n  X1\n  X2\n  X3\n  X4\n  X5\n  X6\n  X7\n  X8\n  X9\n\n  X10\n  X11\n  X12\n  X13\n  X14\n  X15\n  X16\n  X17\n  X18\n  X19\n\n  X20\n  X21\n  X22\n  X23\n  X24\n  X25\n  X26\n  X27\n  X28\n  X29\n\n  X30\n  X31\n}\n\n@export\ndef test {\n  if !((.X0 | .X1) in (Foo.X30 | .X31)) {\n    var x = Foo.X0\n    x = .X1 | .X2\n    x &= ~.X3\n  }\n}\n\", \"\npublic static class Foo\n{\n    public const int X0 = 1;\n    public const int X1 = 2;\n    public const int X2 = 4;\n    public const int X3 = 8;\n    public const int X30 = 1073741824;\n    public const int X31 = -2147483648;\n}\n\npublic class Globals\n{\n    public static void test()\n    {\n        if (!(((Foo.X0 | Foo.X1) & (Foo.X30 | Foo.X31)) != 0))\n        {\n            int x = Foo.X0;\n            x = Foo.X1 | Foo.X2;\n            x &= ~Foo.X3;\n        }\n    }\n}\n\").csharp\n\n# Check dynamic types\ntest(\"\n@export\ndef test(foo dynamic.Foo) dynamic.Bar {\n  return foo as dynamic.Bar + 0 as dynamic.Int + 0 as dynamic\n}\n\", \"\npublic class Globals\n{\n    public static Bar test(Foo foo)\n    {\n        return (Bar)foo + (Int)0 + 0;\n    }\n}\n\").csharp\n\n# Check bit shifts\ntest(\"\n@export\ndef test(x int) {\n  x = x << x\n  x = x >> x\n  x = x >>> x\n  x <<= x\n  x >>= x\n  x >>>= x\n}\n\", \"\npublic class in_int\n{\n    public static int unsignedRightShift(int self, int x)\n    {\n        return (int)unchecked((uint)self >> x);\n    }\n}\n\npublic class Globals\n{\n    public static void test(int x)\n    {\n        x = x << x;\n        x = x >> x;\n        x = in_int.unsignedRightShift(x, x);\n        x <<= x;\n        x >>= x;\n        x = in_int.unsignedRightShift(x, x);\n    }\n}\n\").csharp\n\n# Test lambda code generation\ntest(\"\n@export\ndef test {\n  var a = => {}\n  var b = (x int) => {}\n  var c = (x int, y int) => x == y\n  a()\n  b(1)\n  c(2, 3)\n}\n\", \"\npublic class Globals\n{\n    public static void test()\n    {\n        System.Action a = () =>\n        {\n        };\n        System.Action<int> b = (int x) =>\n        {\n        };\n        System.Func<int, int, bool> c = (int x, int y) =>\n        {\n            return x == y;\n        };\n        a();\n        b(1);\n        c(2, 3);\n    }\n}\n\").csharp\n\n# Test lambda conversion with scope capture and currying\ntest(\"\n@export\nclass Foo {\n  var value = 0\n\n  def test(x int) int {\n    var y = 0\n    var f = (a int) => => (b int) => => value + x + y + a + b\n    return f(1)()(2)()\n  }\n}\n\", \"\npublic class Foo\n{\n    public int value = 0;\n\n    public int test(int x)\n    {\n        int y = 0;\n        System.Func<int, System.Func<System.Func<int, System.Func<int>>>> f = (int a) =>\n        {\n            return () =>\n            {\n                return (int b) =>\n                {\n                    return () =>\n                    {\n                        return this.value + x + y + a + b;\n                    };\n                };\n            };\n        };\n        return f(1)()(2)();\n    }\n\n    public Foo()\n    {\n        this.value = 0;\n    }\n}\n\").csharp\n\n# Test break statements inside a switch\ntest(\"\n@export\ndef test(x int, y bool) {\n  while true {\n    switch x {\n      case 0 {\n        if y {\n          break\n        }\n      }\n    }\n  }\n}\n\", \"\npublic class Globals\n{\n    public static void test(int x, bool y)\n    {\n        while (true)\n        {\n            switch (x)\n            {\n                case 0:\n                {\n                    if (y)\n                    {\n                        goto label;\n                    }\n                    break;\n                }\n            }\n        }\n        label:;\n    }\n}\n\").csharp\n\n# Constructors on dynamic types shouldn't need parentheses\ntest(\"\n@export\ndef test {\n  dynamic.Foo.new\n  dynamic.Foo.new()\n  dynamic.Foo.new.test\n  dynamic.Foo.new().test\n  dynamic.Foo<dynamic.Bar>.new.test\n  dynamic.Foo<dynamic.Bar>.new().test\n\n  var a = dynamic.Foo.new\n  var b = dynamic.Foo.new()\n  var c = dynamic.Foo.new.test\n  var d = dynamic.Foo.new().test\n  var e = dynamic.Foo<dynamic.Bar>.new.test\n  var f = dynamic.Foo<dynamic.Bar>.new().test\n}\n\", \"\npublic class Globals\n{\n    public static void test()\n    {\n        new Foo();\n        new Foo();\n        new Foo().test;\n        new Foo().test;\n        new Foo<Bar>().test;\n        new Foo<Bar>().test;\n        dynamic a = new Foo();\n        dynamic b = new Foo();\n        dynamic c = new Foo().test;\n        dynamic d = new Foo().test;\n        dynamic e = new Foo<Bar>().test;\n        dynamic f = new Foo<Bar>().test;\n    }\n}\n\").csharp\n\n# Check preserving enum types for constant-folded enum values\ntest(\"\nenum Foo {\n  FOO\n  BAR\n}\n\ndef foo(x Foo) {\n  bar(x)\n}\n\n@import\ndef bar(x int)\n\n@export\ndef test(x bool) {\n  foo(x ? .BAR : .FOO)\n}\n\", \"\npublic enum Foo\n{\n}\n\npublic class Globals\n{\n    public static void test(bool x)\n    {\n        bar((int)(x ? (Foo)1 : (Foo)0));\n    }\n}\n\").csharp.foldAllConstants.inlineAllFunctions\n\n# Check wrapped types with type parameters\ntest(\"\ntype Foo<T> : List<T> {\n  def size int {\n    return (self as List<T>).count\n  }\n}\n\n@entry\ndef main {\n  (List<int>.new as Foo<int>).size\n}\n\", \"\nusing System.Collections.Generic;\n\npublic static class Foo<T>\n{\n}\n\npublic class in_List\n{\n    public static int count<T>(List<T> self)\n    {\n        return self.Count;\n    }\n}\n\npublic class in_Foo\n{\n    public static int size<T>(List<T> self)\n    {\n        return in_List.count(self);\n    }\n}\n\npublic class Globals\n{\n    public static void Main()\n    {\n        in_Foo.size(new List<int>());\n    }\n}\n\").csharp\n\n# Check the \"is\" operator\ntest(\"\nclass Foo {}\nclass Bar : Foo {}\n\n@entry\ndef main {\n  Foo.new is Bar == true || true == Foo.new is Bar\n}\n\", \"\npublic class Foo\n{\n    public Foo()\n    {\n    }\n}\n\npublic class Bar : Foo\n{\n    public Bar() : base()\n    {\n    }\n}\n\npublic class Globals\n{\n    public static void Main()\n    {\n        new Foo() is Bar == true || true == new Foo() is Bar;\n    }\n}\n\").csharp\n\n# Check block comments before a statement\ntest(\"\n@entry\ndef main {\n  # This is\n  # a block\n  # comment\n\n  return\n}\n\", \"\npublic class Globals\n{\n    public static void Main()\n    {\n        // This is\n        // a block\n        // comment\n\n        return;\n    }\n}\n\").csharp\n\n# Check trailing block comments\ntest(\"\n@entry\ndef main {\n  # This is\n  # a block\n  # comment\n}\n\", \"\npublic class Globals\n{\n    public static void Main()\n    {\n        // This is\n        // a block\n        // comment\n    }\n}\n\").csharp\n\n# CFG must-return check on a switch statement converted to an if-else chain\ntest(\"\n@export\ndef test(x string) int {\n  switch x {\n    case \\\"y\\\" { return 1 }\n    default { throw x }\n  }\n}\n\", \"\npublic class Globals\n{\n    public static int test(string x)\n    {\n        string value = x;\n\n        if (value == \\\"y\\\")\n        {\n            return 1;\n        }\n        else\n        {\n            throw x;\n        }\n    }\n}\n\").csharp\n\n  }\n}\n"
  },
  {
    "path": "tests/formatting.sk",
    "content": "namespace Skew.Tests {\n  def testFormatting {\n\ntestFormat(\"\n01234abcde56789\n\", \"\n01234abcde56789\n     ~~~~~\n\", 5, 10, 15)\n\ntestFormat(\"\nabcde0123456789\n\", \"\nabcde01...\n~~~~~\n\", 0, 5, 10)\n\ntestFormat(\"\n0123456789abcde\n\", \"\n...89abcde\n     ~~~~~\n\", 10, 15, 10)\n\ntestFormat(\"\n01234abcde56789\n\", \"\n...abcd...\n   ~~~~\n\", 5, 10, 10)\n\ntestFormat(\"\n01234abcde56789\n\", \"\n...abcde...\n   ~~~~~\n\", 5, 10, 11)\n\ntestFormat(\"\nabcdefghij0123456789klmnopqrst\n\", \"\n...ij0123456789kl...\n     ~~~~~~~~~~\n\", 10, 20, 20)\n\ntestFormat(\"\n0123456789\n\", \"\n01234...\n ~~~~\n\", 1, 7, 8)\n\ntestFormat(\"\n0123456789\n\", \"\n01234...\n  ~~~\n\", 2, 6, 8)\n\ntestFormat(\"\n0123456789\n\", \"\n...34...\n   ~~\n\", 3, 5, 8)\n\ntestFormat(\"\n01234💩💩💩💩💩01234\n\", \"\n01234💩💩💩💩💩01234\n     ~~~~~\n\", \"01234\".count, \"01234💩💩💩💩💩\".count, 20)\n\ntestFormat(\"\n💩💩💩💩💩01234012340123401234\n\", \"\n💩💩💩💩💩01...\n~~~~~\n\", 0, \"💩💩💩💩💩\".count, 10)\n\ntestFormat(\"\n01234012340123401234💩💩💩💩💩\n\", \"\n...34💩💩💩💩💩\n     ~~~~~\n\", \"01234012340123401234\".count, \"01234012340123401234💩💩💩💩💩\".count, 10)\n\ntestFormat(\"\n😄😉😍😗😜😔😞😢😭😪😥😰😅😓😩😨😱😠😡😎\n\", \"\n😄😉😍😗😜😔😞...\n~~~~~\n\", 0, \"😄😉😍😗😜\".count, 10)\n\ntestFormat(\"\n😄😉😍😗😜😔😞😢😭😪😥😰😅😓😩😨😱😠😡😎\n\", \"\n...😓😩😨😱😠😡😎\n     ~~~~~\n\", \"😄😉😍😗😜😔😞😢😭😪😥😰😅😓😩\".count, \"😄😉😍😗😜😔😞😢😭😪😥😰😅😓😩😨😱😠😡😎\".count, 10)\n\ntestFormat(\"\n😄😉😍😗😜😔😞😢😭😪😥😰😅😓😩😨😱😠😡😎\n\", \"\n...😔😞😢😭...\n   ~~~~\n\", \"😄😉😍😗😜\".count, \"😄😉😍😗😜😔😞😢😭😪😥😰😅😓😩\".count, 10)\n\ntestFormat(\"\n\\ta\\tab\\tabc\\tabcd\\tabcde\\tabcdef\\tabcdefg\\tabcdefgh\\tx\n\", \"\n        a       ab      abc     abcd    abcde   abcdef  abcdefg abcdefgh        x\n~~~~~~~~\n\", 0, 1, 0)\n\ntestFormat(\"\n\\t0\\t1\\t2\\t3\\t4\n\", \"\n...  2       3       4\n              ~~~~~~~\n\", 8, 9, 22)\n\n  }\n}\n"
  },
  {
    "path": "tests/ide.sk",
    "content": "namespace Skew.Tests {\n  def testIDE {\n\n# Tooltips: basic test of globals and formatting\ntestIDE(\"\ndef @annotation ( x int ) # Comment for annotation\ndef globalFunction ( x int ) bool { return false } # Comment for globalFunction\n# Comment for globalVariable\nvar globalVariable = 0 # Comment 2 for globalVariable\n\", (ide, expect) => {\n  expect(\"\", ide.tooltipQuery(0, 3))\n  expect(\"# Comment for annotation\\ndef @annotation(x int)\", ide.tooltipQuery(0, 4))\n  expect(\"# Comment for annotation\\ndef @annotation(x int)\", ide.tooltipQuery(0, 15))\n  expect(\"\", ide.tooltipQuery(0, 16))\n\n  expect(\"\", ide.tooltipQuery(1, 3))\n  expect(\"# Comment for globalFunction\\ndef globalFunction(x int) bool\", ide.tooltipQuery(1, 4))\n  expect(\"# Comment for globalFunction\\ndef globalFunction(x int) bool\", ide.tooltipQuery(1, 18))\n  expect(\"\", ide.tooltipQuery(1, 19))\n\n  expect(\"\", ide.tooltipQuery(1, 20))\n  expect(\"var x int\", ide.tooltipQuery(1, 21))\n  expect(\"var x int\", ide.tooltipQuery(1, 22))\n  expect(\"class int\", ide.tooltipQuery(1, 23))\n  expect(\"class int\", ide.tooltipQuery(1, 26))\n  expect(\"\", ide.tooltipQuery(1, 27))\n\n  expect(\"\", ide.tooltipQuery(1, 28))\n  expect(\"class bool\", ide.tooltipQuery(1, 29))\n  expect(\"class bool\", ide.tooltipQuery(1, 33))\n  expect(\"\", ide.tooltipQuery(1, 34))\n\n  expect(\"\", ide.tooltipQuery(3, 3))\n  expect(\"# Comment for globalVariable\\n# Comment 2 for globalVariable\\nvar globalVariable int\", ide.tooltipQuery(3, 4))\n  expect(\"# Comment for globalVariable\\n# Comment 2 for globalVariable\\nvar globalVariable int\", ide.tooltipQuery(3, 18))\n  expect(\"\", ide.tooltipQuery(3, 19))\n})\n\n# Tooltips: test object types\ntestIDE(\"\nclass Derived : Base :: I {\n  const foo Foo = .FOO # Comment for foo\n  over instanceFunction {}\n}\n\nclass Base {\n  def instanceFunction {}\n}\n\ninterface I {\n}\n\nenum Foo {\n  FOO # Comment for FOO\n}\n\", (ide, expect) => {\n  expect(\"\", ide.tooltipQuery(0, 5))\n  expect(\"class Derived : Base :: I\", ide.tooltipQuery(0, 6))\n  expect(\"class Derived : Base :: I\", ide.tooltipQuery(0, 13))\n  expect(\"\", ide.tooltipQuery(0, 14))\n\n  expect(\"\", ide.tooltipQuery(0, 15))\n  expect(\"class Base\", ide.tooltipQuery(0, 16))\n  expect(\"class Base\", ide.tooltipQuery(0, 20))\n  expect(\"\", ide.tooltipQuery(0, 21))\n\n  expect(\"\", ide.tooltipQuery(0, 23))\n  expect(\"interface I\", ide.tooltipQuery(0, 24))\n  expect(\"interface I\", ide.tooltipQuery(0, 25))\n  expect(\"\", ide.tooltipQuery(0, 26))\n\n  expect(\"\", ide.tooltipQuery(1, 7))\n  expect(\"# Comment for foo\\nconst foo Foo\", ide.tooltipQuery(1, 8))\n  expect(\"# Comment for foo\\nconst foo Foo\", ide.tooltipQuery(1, 11))\n  expect(\"enum Foo\", ide.tooltipQuery(1, 12))\n  expect(\"enum Foo\", ide.tooltipQuery(1, 15))\n  expect(\"\", ide.tooltipQuery(1, 16))\n\n  expect(\"\", ide.tooltipQuery(1, 18))\n  expect(\"# Comment for FOO\\nconst FOO Foo = 0\", ide.tooltipQuery(1, 19))\n  expect(\"# Comment for FOO\\nconst FOO Foo = 0\", ide.tooltipQuery(1, 22))\n  expect(\"\", ide.tooltipQuery(1, 23))\n\n  expect(\"\", ide.tooltipQuery(2, 6))\n  expect(\"over instanceFunction\", ide.tooltipQuery(2, 7))\n  expect(\"over instanceFunction\", ide.tooltipQuery(2, 23))\n  expect(\"\", ide.tooltipQuery(2, 24))\n\n  expect(\"\", ide.tooltipQuery(6, 5))\n  expect(\"def instanceFunction\", ide.tooltipQuery(6, 6))\n  expect(\"def instanceFunction\", ide.tooltipQuery(6, 22))\n  expect(\"\", ide.tooltipQuery(6, 23))\n\n  expect(\"\", ide.tooltipQuery(13, 1))\n  expect(\"# Comment for FOO\\nconst FOO Foo = 0\", ide.tooltipQuery(13, 2))\n  expect(\"# Comment for FOO\\nconst FOO Foo = 0\", ide.tooltipQuery(13, 5))\n  expect(\"\", ide.tooltipQuery(13, 6))\n})\n\n# Tooltips: test flags\ntestIDE(\"\nflags Flags {\n  FOO # FOO\n}\n\nvar f Flags = .FOO | .FOO # f\n\", (ide, expect) => {\n  expect(\"\", ide.tooltipQuery(0, 5))\n  expect(\"flags Flags\", ide.tooltipQuery(0, 6))\n  expect(\"flags Flags\", ide.tooltipQuery(0, 11))\n  expect(\"\", ide.tooltipQuery(0, 12))\n\n  expect(\"\", ide.tooltipQuery(1, 1))\n  expect(\"# FOO\\nconst FOO Flags = 1\", ide.tooltipQuery(1, 2))\n  expect(\"# FOO\\nconst FOO Flags = 1\", ide.tooltipQuery(1, 5))\n  expect(\"\", ide.tooltipQuery(1, 6))\n\n  expect(\"\", ide.tooltipQuery(4, 3))\n  expect(\"# f\\nvar f Flags\", ide.tooltipQuery(4, 4))\n  expect(\"# f\\nvar f Flags\", ide.tooltipQuery(4, 5))\n  expect(\"flags Flags\", ide.tooltipQuery(4, 6))\n  expect(\"flags Flags\", ide.tooltipQuery(4, 11))\n  expect(\"\", ide.tooltipQuery(4, 12))\n\n  expect(\"\", ide.tooltipQuery(4, 14))\n  expect(\"# FOO\\nconst FOO Flags = 1\", ide.tooltipQuery(4, 15))\n  expect(\"# FOO\\nconst FOO Flags = 1\", ide.tooltipQuery(4, 18))\n  expect(\"def |(x int) int\", ide.tooltipQuery(4, 19))\n  expect(\"def |(x int) int\", ide.tooltipQuery(4, 20))\n  expect(\"\", ide.tooltipQuery(4, 21))\n  expect(\"# FOO\\nconst FOO Flags = 1\", ide.tooltipQuery(4, 22))\n  expect(\"# FOO\\nconst FOO Flags = 1\", ide.tooltipQuery(4, 25))\n  expect(\"\", ide.tooltipQuery(4, 26))\n})\n\n# Tooltips: test generics\ntestIDE(\"\ndef test<X>(foo List<Foo<X>>, bar X) X {\n  foo.append(null)\n  return null in foo ? foo.first.bar : bar\n}\n\nclass Foo<Y> {\n  var bar Y\n}\n\", (ide, expect) => {\n  expect(\"\", ide.tooltipQuery(0, 3))\n  expect(\"def test<X>(foo List<Foo<X>>, bar X) X\", ide.tooltipQuery(0, 4))\n  expect(\"def test<X>(foo List<Foo<X>>, bar X) X\", ide.tooltipQuery(0, 8))\n  expect(\"X\", ide.tooltipQuery(0, 9))\n  expect(\"X\", ide.tooltipQuery(0, 10))\n  expect(\"\", ide.tooltipQuery(0, 11))\n  expect(\"var foo List<Foo<X>>\", ide.tooltipQuery(0, 12))\n  expect(\"var foo List<Foo<X>>\", ide.tooltipQuery(0, 15))\n  expect(\"class List<T>\", ide.tooltipQuery(0, 16))\n  expect(\"class List<T>\", ide.tooltipQuery(0, 20))\n  expect(\"class Foo<Y>\", ide.tooltipQuery(0, 21))\n  expect(\"class Foo<Y>\", ide.tooltipQuery(0, 24))\n  expect(\"X\", ide.tooltipQuery(0, 25))\n  expect(\"X\", ide.tooltipQuery(0, 26))\n  expect(\"\", ide.tooltipQuery(0, 27))\n\n  expect(\"\", ide.tooltipQuery(1, 1))\n  expect(\"var foo List<Foo<X>>\", ide.tooltipQuery(1, 2))\n  expect(\"var foo List<Foo<X>>\", ide.tooltipQuery(1, 5))\n  expect(\"def append(x Foo<X>)\", ide.tooltipQuery(1, 6))\n  expect(\"def append(x Foo<X>)\", ide.tooltipQuery(1, 12))\n  expect(\"\", ide.tooltipQuery(1, 13))\n\n  expect(\"\", ide.tooltipQuery(2, 13))\n  expect(\"def in(x T) bool\", ide.tooltipQuery(2, 14))\n  expect(\"def in(x T) bool\", ide.tooltipQuery(2, 16))\n  expect(\"var foo List<Foo<X>>\", ide.tooltipQuery(2, 17))\n  expect(\"var foo List<Foo<X>>\", ide.tooltipQuery(2, 20))\n  expect(\"\", ide.tooltipQuery(2, 21))\n\n  expect(\"\", ide.tooltipQuery(2, 22))\n  expect(\"var foo List<Foo<X>>\", ide.tooltipQuery(2, 23))\n  expect(\"var foo List<Foo<X>>\", ide.tooltipQuery(2, 26))\n  expect(\"def first Foo<X>\", ide.tooltipQuery(2, 27))\n  expect(\"def first Foo<X>\", ide.tooltipQuery(2, 32))\n  expect(\"var bar X\", ide.tooltipQuery(2, 33))\n  expect(\"var bar X\", ide.tooltipQuery(2, 36))\n  expect(\"\", ide.tooltipQuery(2, 37))\n\n  expect(\"\", ide.tooltipQuery(5, 5))\n  expect(\"class Foo<Y>\", ide.tooltipQuery(5, 6))\n  expect(\"class Foo<Y>\", ide.tooltipQuery(5, 9))\n  expect(\"Y\", ide.tooltipQuery(5, 10))\n  expect(\"Y\", ide.tooltipQuery(5, 11))\n  expect(\"\", ide.tooltipQuery(5, 12))\n})\n\n# Tooltips: test wrapped types, casts, and self\ntestIDE(\"\ntype Foo : int {\n  def foo Foo {\n    return self as int as Foo #\n  }\n}\n\", (ide, expect) => {\n  expect(\"\", ide.tooltipQuery(0, 4))\n  expect(\"type Foo = int\", ide.tooltipQuery(0, 5))\n  expect(\"type Foo = int\", ide.tooltipQuery(0, 8))\n  expect(\"\", ide.tooltipQuery(0, 9))\n\n  expect(\"\", ide.tooltipQuery(0, 10))\n  expect(\"class int\", ide.tooltipQuery(0, 11))\n  expect(\"class int\", ide.tooltipQuery(0, 14))\n  expect(\"\", ide.tooltipQuery(0, 15))\n\n  expect(\"\", ide.tooltipQuery(1, 5))\n  expect(\"def foo Foo\", ide.tooltipQuery(1, 6))\n  expect(\"def foo Foo\", ide.tooltipQuery(1, 9))\n  expect(\"type Foo = int\", ide.tooltipQuery(1, 10))\n  expect(\"type Foo = int\", ide.tooltipQuery(1, 13))\n  expect(\"\", ide.tooltipQuery(1, 14))\n\n  expect(\"\", ide.tooltipQuery(2, 10))\n  expect(\"const self Foo\", ide.tooltipQuery(2, 11))\n  expect(\"const self Foo\", ide.tooltipQuery(2, 15))\n  expect(\"\", ide.tooltipQuery(2, 16))\n\n  expect(\"\", ide.tooltipQuery(2, 18))\n  expect(\"class int\", ide.tooltipQuery(2, 19))\n  expect(\"class int\", ide.tooltipQuery(2, 22))\n  expect(\"\", ide.tooltipQuery(2, 23))\n\n  expect(\"\", ide.tooltipQuery(2, 25))\n  expect(\"type Foo = int\", ide.tooltipQuery(2, 26))\n  expect(\"type Foo = int\", ide.tooltipQuery(2, 29))\n  expect(\"\", ide.tooltipQuery(2, 30))\n})\n\n# Tooltips: test function merging\ntestIDE(\"\ndef foo #\ndef foo {}\ndef bar {}\ndef bar #\n\", (ide, expect) => {\n  expect(\"\", ide.tooltipQuery(0, 3))\n  expect(\"#\\ndef foo\", ide.tooltipQuery(0, 4))\n  expect(\"#\\ndef foo\", ide.tooltipQuery(0, 7))\n  expect(\"\", ide.tooltipQuery(0, 8))\n\n  expect(\"\", ide.tooltipQuery(1, 3))\n  expect(\"#\\ndef foo\", ide.tooltipQuery(1, 4))\n  expect(\"#\\ndef foo\", ide.tooltipQuery(1, 7))\n  expect(\"\", ide.tooltipQuery(1, 8))\n\n  expect(\"\", ide.tooltipQuery(2, 3))\n  expect(\"#\\ndef bar\", ide.tooltipQuery(2, 4))\n  expect(\"#\\ndef bar\", ide.tooltipQuery(2, 7))\n  expect(\"\", ide.tooltipQuery(2, 8))\n\n  expect(\"\", ide.tooltipQuery(3, 3))\n  expect(\"#\\ndef bar\", ide.tooltipQuery(3, 4))\n  expect(\"#\\ndef bar\", ide.tooltipQuery(3, 7))\n  expect(\"\", ide.tooltipQuery(3, 8))\n})\n\n# Tooltips: test object merging\ntestIDE(\"\nnamespace Foo {}\nclass Foo {}\nclass Bar {}\nnamespace Bar {}\n\", (ide, expect) => {\n  expect(\"\", ide.tooltipQuery(0, 9))\n  expect(\"class Foo\", ide.tooltipQuery(0, 10))\n  expect(\"class Foo\", ide.tooltipQuery(0, 13))\n  expect(\"\", ide.tooltipQuery(0, 14))\n\n  expect(\"\", ide.tooltipQuery(1, 5))\n  expect(\"class Foo\", ide.tooltipQuery(1, 6))\n  expect(\"class Foo\", ide.tooltipQuery(1, 9))\n  expect(\"\", ide.tooltipQuery(1, 10))\n\n  expect(\"\", ide.tooltipQuery(2, 5))\n  expect(\"class Bar\", ide.tooltipQuery(2, 6))\n  expect(\"class Bar\", ide.tooltipQuery(2, 9))\n  expect(\"\", ide.tooltipQuery(2, 10))\n\n  expect(\"\", ide.tooltipQuery(3, 9))\n  expect(\"class Bar\", ide.tooltipQuery(3, 10))\n  expect(\"class Bar\", ide.tooltipQuery(3, 13))\n  expect(\"\", ide.tooltipQuery(3, 14))\n})\n\n# Tooltips: test rewriting operators\ntestIDE(\"\ndef test(foo Foo) {\n  foo = foo?.bar ?? foo #\n  foo = foo.bar?.bar ?? foo #\n}\n\nclass Foo {\n  var bar Foo\n}\n\", (ide, expect) => {\n  expect(\"\", ide.tooltipQuery(1, 1))\n  expect(\"var foo Foo\", ide.tooltipQuery(1, 2))\n  expect(\"var foo Foo\", ide.tooltipQuery(1, 5))\n  expect(\"\", ide.tooltipQuery(1, 6))\n\n  expect(\"\", ide.tooltipQuery(1, 7))\n  expect(\"var foo Foo\", ide.tooltipQuery(1, 8))\n  expect(\"var foo Foo\", ide.tooltipQuery(1, 11))\n  expect(\"\", ide.tooltipQuery(1, 12))\n  expect(\"var bar Foo\", ide.tooltipQuery(1, 13))\n  expect(\"var bar Foo\", ide.tooltipQuery(1, 16))\n  expect(\"\", ide.tooltipQuery(1, 17))\n\n  expect(\"\", ide.tooltipQuery(1, 19))\n  expect(\"var foo Foo\", ide.tooltipQuery(1, 20))\n  expect(\"var foo Foo\", ide.tooltipQuery(1, 23))\n  expect(\"\", ide.tooltipQuery(1, 24))\n\n  expect(\"\", ide.tooltipQuery(2, 1))\n  expect(\"var foo Foo\", ide.tooltipQuery(2, 2))\n  expect(\"var foo Foo\", ide.tooltipQuery(2, 5))\n  expect(\"\", ide.tooltipQuery(2, 6))\n\n  expect(\"\", ide.tooltipQuery(2, 7))\n  expect(\"var foo Foo\", ide.tooltipQuery(2, 8))\n  expect(\"var foo Foo\", ide.tooltipQuery(2, 11))\n  expect(\"var bar Foo\", ide.tooltipQuery(2, 12))\n  expect(\"var bar Foo\", ide.tooltipQuery(2, 15))\n  expect(\"\", ide.tooltipQuery(2, 16))\n  expect(\"var bar Foo\", ide.tooltipQuery(2, 17))\n  expect(\"var bar Foo\", ide.tooltipQuery(2, 20))\n  expect(\"\", ide.tooltipQuery(2, 21))\n\n  expect(\"\", ide.tooltipQuery(2, 23))\n  expect(\"var foo Foo\", ide.tooltipQuery(2, 24))\n  expect(\"var foo Foo\", ide.tooltipQuery(2, 27))\n  expect(\"\", ide.tooltipQuery(2, 28))\n})\n\n# Tooltips: test string interpolation\ntestIDE(\"\ndef test string {\n  return \\\"\\\\(test) + \\\\(test)\\\"\n}\n\", (ide, expect) => {\n  expect(\"\", ide.tooltipQuery(1, 11))\n  expect(\"def test string\", ide.tooltipQuery(1, 12))\n  expect(\"def test string\", ide.tooltipQuery(1, 16))\n  expect(\"\", ide.tooltipQuery(1, 17))\n\n  expect(\"\", ide.tooltipQuery(1, 21))\n  expect(\"def test string\", ide.tooltipQuery(1, 22))\n  expect(\"def test string\", ide.tooltipQuery(1, 26))\n  expect(\"\", ide.tooltipQuery(1, 27))\n})\n\n# Tooltips: test XML literals\ntestIDE(\"\nclass Foo.Bar {\n  var foo Foo.Bar = <Foo.Bar foo=null><Foo.Bar foo=null/></Foo.Bar>\n  def <>...</>(x Foo.Bar) {}\n}\n\", (ide, expect) => {\n  expect(\"\", ide.tooltipQuery(1, 5))\n  expect(\"var foo Foo.Bar\", ide.tooltipQuery(1, 6))\n  expect(\"var foo Foo.Bar\", ide.tooltipQuery(1, 9))\n  expect(\"namespace Foo\", ide.tooltipQuery(1, 10))\n  expect(\"namespace Foo\", ide.tooltipQuery(1, 13))\n  expect(\"class Bar\", ide.tooltipQuery(1, 14))\n  expect(\"class Bar\", ide.tooltipQuery(1, 17))\n  expect(\"\", ide.tooltipQuery(1, 18))\n\n  expect(\"\", ide.tooltipQuery(1, 20))\n  expect(\"namespace Foo\", ide.tooltipQuery(1, 21))\n  expect(\"namespace Foo\", ide.tooltipQuery(1, 24))\n  expect(\"class Bar\", ide.tooltipQuery(1, 25))\n  expect(\"class Bar\", ide.tooltipQuery(1, 28))\n  expect(\"var foo Foo.Bar\", ide.tooltipQuery(1, 29))\n  expect(\"var foo Foo.Bar\", ide.tooltipQuery(1, 32))\n  expect(\"\", ide.tooltipQuery(1, 33))\n\n  expect(\"\", ide.tooltipQuery(1, 38))\n  expect(\"namespace Foo\", ide.tooltipQuery(1, 39))\n  expect(\"namespace Foo\", ide.tooltipQuery(1, 42))\n  expect(\"class Bar\", ide.tooltipQuery(1, 43))\n  expect(\"class Bar\", ide.tooltipQuery(1, 46))\n  expect(\"var foo Foo.Bar\", ide.tooltipQuery(1, 47))\n  expect(\"var foo Foo.Bar\", ide.tooltipQuery(1, 50))\n  expect(\"\", ide.tooltipQuery(1, 51))\n\n  expect(\"\", ide.tooltipQuery(1, 58))\n  expect(\"namespace Foo\", ide.tooltipQuery(1, 59))\n  expect(\"namespace Foo\", ide.tooltipQuery(1, 62))\n  expect(\"class Bar\", ide.tooltipQuery(1, 63))\n  expect(\"class Bar\", ide.tooltipQuery(1, 66))\n  expect(\"\", ide.tooltipQuery(1, 67))\n})\n\n# Definitions: test object merging\ntestIDE(\"\nnamespace Foo {}\nclass Foo {}\nclass Bar {}\nnamespace Bar {}\ndef test(foo Foo, bar Bar) {}\n\", (ide, expect) => {\n  expect(\"<stdin>:2:7\", ide.definitionQuery(4, 13))\n  expect(\"<stdin>:3:7\", ide.definitionQuery(4, 22))\n})\n\n# Definitions: test function merging\ntestIDE(\"\ndef foo\ndef foo {}\ndef bar {}\ndef bar\ndef test {\n  foo\n  bar\n}\n\", (ide, expect) => {\n  expect(\"<stdin>:2:5\", ide.definitionQuery(5, 2))\n  expect(\"<stdin>:3:5\", ide.definitionQuery(6, 2))\n})\n\n# Renaming: test function arguments\ntestIDE(\"\nvar x = 0\ndef foo(x int) {\n  var y = x\n  x += x\n  var z = (x bool) => x ? y : -y\n  z(x == y)\n}\n\", (ide, expect) => {\n  expect(\"<stdin>:2:9, <stdin>:3:11, <stdin>:4:3, <stdin>:4:8, <stdin>:6:5\", ide.renameQuery(3, 2))\n})\n\n# Renaming: test local variables\ntestIDE(\"\nvar x = 0\ndef foo {\n  var x = 0\n  x += x\n  var z = (x bool) => x ? 1 : -1\n  z(x == 1)\n}\n\", (ide, expect) => {\n  expect(\"<stdin>:3:7, <stdin>:4:3, <stdin>:4:8, <stdin>:6:5\", ide.renameQuery(3, 2))\n})\n\n# Renaming: test instance variables\ntestIDE(\"\nvar x = 0\nclass Foo {\n  var x = 0\n  def foo {\n    x += x\n    var z = (x bool) => x ? 1 : -1\n    z(x == 1)\n  }\n}\n\", (ide, expect) => {\n  expect(\"<stdin>:3:7, <stdin>:5:5, <stdin>:5:10, <stdin>:7:7\", ide.renameQuery(4, 4))\n})\n\n# Renaming: test global variables\ntestIDE(\"\nvar x = 0\nnamespace Foo {\n  var x = 0\n  def foo {\n    x += x\n    var z = (x bool) => x ? 1 : -1\n    z(x == 1)\n  }\n}\n\", (ide, expect) => {\n  expect(\"<stdin>:3:7, <stdin>:5:5, <stdin>:5:10, <stdin>:7:7\", ide.renameQuery(4, 4))\n})\n\n# Renaming: test instance functions without arguments\ntestIDE(\"\ndef foo {\n  foo\n}\nclass Foo {\n  def foo {\n    foo\n    var bar = (foo int) int => {\n      new.foo\n      return foo\n    }\n    bar(0)\n  }\n}\n\", (ide, expect) => {\n  expect(\"<stdin>:5:7, <stdin>:6:5, <stdin>:8:11\", ide.renameQuery(5, 4))\n})\n\n# Renaming: test instance functions with arguments\ntestIDE(\"\ndef foo(x int) {\n  foo(x)\n}\nclass Foo {\n  def foo(x int) {\n    foo(x)\n    var bar = (foo int) int => {\n      new.foo(x)\n      return foo\n    }\n    bar(0)\n  }\n}\n\", (ide, expect) => {\n  expect(\"<stdin>:5:7, <stdin>:6:5, <stdin>:8:11\", ide.renameQuery(5, 4))\n})\n\n# Renaming: test instance functions without arguments\ntestIDE(\"\ndef foo {\n  foo\n}\nnamespace Foo {\n  def foo {\n    foo\n    var bar = (foo int) int => {\n      Foo.foo\n      return foo\n    }\n    bar(0)\n  }\n}\n\", (ide, expect) => {\n  expect(\"<stdin>:5:7, <stdin>:6:5, <stdin>:8:11\", ide.renameQuery(5, 4))\n})\n\n# Renaming: test instance functions with arguments\ntestIDE(\"\ndef foo(x int) {\n  foo(x)\n}\nnamespace Foo {\n  def foo(x int) {\n    foo(x)\n    var bar = (foo int) int => {\n      Foo.foo(x)\n      return foo\n    }\n    bar(0)\n  }\n}\n\", (ide, expect) => {\n  expect(\"<stdin>:5:7, <stdin>:6:5, <stdin>:8:11\", ide.renameQuery(5, 4))\n})\n\n# Renaming: test classes\ntestIDE(\"\nclass Foo.Bar {}\nnamespace Foo.Bar {\n  def new Bar {\n    var bar Bar = <Bar/>\n    var baz Baz.Bar = null\n    baz = baz ?? Baz.Bar.new\n    return bar\n  }\n}\nclass Baz.Bar {}\n\", (ide, expect) => {\n  expect(\"<stdin>:1:11, <stdin>:2:15, <stdin>:3:11, <stdin>:4:13, <stdin>:4:20\", ide.renameQuery(2, 10))\n})\n\n# Renaming: test overridden instance methods\ntestIDE(\"\nclass Foo :: IFoo {\n  def foo {}\n  def foo(x int) {}\n}\nclass Bar : Foo {\n  over foo {}\n  over foo(x int) {}\n}\nclass Baz : Bar {\n  over foo {}\n  over foo(x int) {}\n}\nclass Nope {\n  def foo {}\n  def foo(x int) {}\n}\ninterface IFoo {\n  def foo\n  def foo(x int)\n}\n\", (ide, expect) => {\n  expect(\"<stdin>:2:7, <stdin>:6:8, <stdin>:10:8, <stdin>:18:7\", ide.renameQuery(5, 7))\n})\n\n# Renaming: test overloaded interface methods\ntestIDE(\"\ninterface Foo {\n  def foo\n  def foo(x int) {}\n}\nclass Bar :: Foo {\n  def foo {}\n  def foo(x int) {}\n}\nclass Baz :: Foo {\n  def foo {}\n  def foo(x int) {}\n}\nclass Nope {\n  def foo {}\n  def foo(x int) {}\n}\n\", (ide, expect) => {\n  expect(\"<stdin>:2:7, <stdin>:6:7, <stdin>:10:7\", ide.renameQuery(1, 6))\n})\n\n# Completion: variable type\ntestCompletion(\"\nvar x i\nvar y = 0\n\", 0, 7, \"\n<stdin>:1:7: error: \\\"i\\\" is not declared\nvar x i\n      ^\n<stdin>:1:7: completions:\nvar x i\n      ^\n      [IntMap] # \\\"class\\\"\n      [int] # \\\"class\\\"\n\")\n\n# Completion: variable inside instance function\ntestCompletion(\"\nclass Foo {\n  var bar = 0\n\n  def baz {\n    ba\n  }\n}\n\", 4, 6, \"\n<stdin>:5:5: error: \\\"ba\\\" is not declared, did you mean \\\"bar\\\"?\n    ba\n    ~~\n<stdin>:2:7: note: \\\"bar\\\" is defined here\n  var bar = 0\n      ~~~\n<stdin>:5:5: completions:\n    ba\n    ~~\n    [bar] # \\\"int\\\"\n    [baz] # \\\"()\\\"\n\")\n\n# Completion: global inside instance function\ntestCompletion(\"\nclass Foo {\n  var bar = 0\n\n  def baz {\n    n\n  }\n}\n\nnamespace Foo {\n  var nox = 0\n}\n\", 4, 5, \"\n<stdin>:5:5: error: \\\"n\\\" is not declared\n    n\n    ^\n<stdin>:5:5: completions:\n    n\n    ^\n    [new] # \\\"() Foo\\\"\n    [nox] # \\\"int\\\"\n\")\n\n# Completion: instance inside global function\ntestCompletion(\"\nclass Foo {\n  var bar = 0\n}\n\nnamespace Foo {\n  def foo {\n    ba\n  }\n\n  var baz = 0\n}\n\", 6, 6, \"\n<stdin>:7:5: error: \\\"ba\\\" is not declared, did you mean \\\"baz\\\"?\n    ba\n    ~~\n<stdin>:10:7: note: \\\"baz\\\" is defined here\n  var baz = 0\n      ~~~\n<stdin>:7:5: completions:\n    ba\n    ~~\n    [baz] # \\\"int\\\"\n\")\n\n# Completion: multi-level instance check\ntestCompletion(\"\nclass Foo {\n  var bar = 0\n\n  class Bar {\n    var baz = 0\n\n    def foo {\n      ba\n    }\n  }\n\n  namespace Bar {\n    var ban = 0\n  }\n}\n\nnamespace Foo {\n  var bax = 0\n}\n\nvar bat = 0\n\", 7, 8, \"\n<stdin>:8:7: error: \\\"ba\\\" is not declared, did you mean \\\"bar\\\"?\n      ba\n      ~~\n<stdin>:2:7: note: \\\"bar\\\" is defined here\n  var bar = 0\n      ~~~\n<stdin>:8:7: completions:\n      ba\n      ~~\n      [Bar] # \\\"class\\\"\n      [ban] # \\\"int\\\"\n      [bat] # \\\"int\\\"\n      [bax] # \\\"int\\\"\n      [baz] # \\\"int\\\"\n\")\n\n# Completion: empty dot access\ntestCompletion(\"\ndef main(foo Foo) {\n  foo.\n}\n\nclass Foo {\n  var foo = 0\n  var bar = 0\n  var baz = 0\n}\n\", 1, 6, \"\n<stdin>:2:7: error: Expected identifier but found newline\n  foo.\n      ^\n<stdin>:2:7: completions:\n  foo.\n      ^\n      [bar] # \\\"int\\\"\n      [baz] # \\\"int\\\"\n      [foo] # \\\"int\\\"\n\")\n\n# Completion: partial dot access\ntestCompletion(\"\ndef main(foo Foo) {\n  foo.bar\n}\n\nclass Foo {\n  var foo = 0\n  var bar = 0\n  var baz = 0\n}\n\", 1, 6, \"\n<stdin>:2:3: warning: Unused expression\n  foo.bar\n  ~~~~~~~\n<stdin>:2:7: completions:\n  foo.bar\n      ~~~\n      [bar] # \\\"int\\\"\n      [baz] # \\\"int\\\"\n      [foo] # \\\"int\\\"\n\")\n\n# Completion: partial dot access\ntestCompletion(\"\ndef main(foo Foo) {\n  foo.bar\n}\n\nclass Foo {\n  var foo = 0\n  var bar = 0\n  var baz = 0\n}\n\", 1, 8, \"\n<stdin>:2:3: warning: Unused expression\n  foo.bar\n  ~~~~~~~\n<stdin>:2:7: completions:\n  foo.bar\n      ~~~\n      [bar] # \\\"int\\\"\n      [baz] # \\\"int\\\"\n\")\n\n# Completion: dot access\ntestCompletion(\"\ndef main(foo Foo) {\n  foo.bar\n}\n\nclass Foo {\n  var foo = 0\n  var bar = 0\n  var baz = 0\n}\n\", 1, 9, \"\n<stdin>:2:3: warning: Unused expression\n  foo.bar\n  ~~~~~~~\n<stdin>:2:7: completions:\n  foo.bar\n      ~~~\n      [bar] # \\\"int\\\"\n\")\n\n# Completion: global dot access\ntestCompletion(\"\ndef main {\n  Foo.\n}\n\nclass Foo {\n  var foo = 0\n  var bar = 0\n}\n\nnamespace Foo {\n  var baz = 0\n}\n\", 1, 6, \"\n<stdin>:2:7: error: Expected identifier but found newline\n  Foo.\n      ^\n<stdin>:2:7: completions:\n  Foo.\n      ^\n      [baz] # \\\"int\\\"\n      [new] # \\\"() Foo\\\"\n\")\n\n# Completion: comments\ntestCompletion(\"\n# This is the\n# first paragraph\n# of text.\n#\n# This is the\n# second paragraph\n# of text.\ndef main {\n  ma\n}\n\", 8, 4, \"\n<stdin>:9:3: error: \\\"ma\\\" is not declared\n  ma\n  ~~\n<stdin>:9:3: completions:\n  ma\n  ~~\n  [Math] # \\\"namespace\\\"\n  [main] # \\\"()\\\"\n         # This is the\n         # first paragraph\n         # of text.\n         #\n         # This is the\n         # second paragraph\n         # of text.\n\")\n\n# Completion: class object\ntestCompletion(\"\nclass Foo {}\nvar foo F\n\", 1, 9, \"\n<stdin>:2:9: error: \\\"F\\\" is not declared\nvar foo F\n        ^\n<stdin>:2:9: completions:\nvar foo F\n        ^\n        [Foo] # \\\"class\\\"\n\")\n\n# Completion: interface object\ntestCompletion(\"\ninterface Foo {}\nvar foo F\n\", 1, 9, \"\n<stdin>:2:9: error: \\\"F\\\" is not declared\nvar foo F\n        ^\n<stdin>:2:9: completions:\nvar foo F\n        ^\n        [Foo] # \\\"interface\\\"\n\")\n\n# Completion: namespace object\ntestCompletion(\"\nnamespace Foo {}\nvar foo F\n\", 1, 9, \"\n<stdin>:2:9: error: \\\"F\\\" is not declared\nvar foo F\n        ^\n<stdin>:2:9: completions:\nvar foo F\n        ^\n        [Foo] # \\\"namespace\\\"\n\")\n\n# Completion: enum object\ntestCompletion(\"\nenum Foo {}\nvar foo F\n\", 1, 9, \"\n<stdin>:2:9: error: \\\"F\\\" is not declared\nvar foo F\n        ^\n<stdin>:2:9: completions:\nvar foo F\n        ^\n        [Foo] # \\\"enum\\\"\n\")\n\n# Completion: flags object\ntestCompletion(\"\nflags Foo {}\nvar foo F\n\", 1, 9, \"\n<stdin>:2:9: error: \\\"F\\\" is not declared\nvar foo F\n        ^\n<stdin>:2:9: completions:\nvar foo F\n        ^\n        [Foo] # \\\"flags\\\"\n\")\n\n# Completion: wrapped object\ntestCompletion(\"\ntype Foo : int {}\nvar foo F\n\", 1, 9, \"\n<stdin>:2:9: error: \\\"F\\\" is not declared\nvar foo F\n        ^\n<stdin>:2:9: completions:\nvar foo F\n        ^\n        [Foo] # \\\"type\\\"\n\")\n\n# Completion: enum with inferred target\ntestCompletion(\"\nenum Foo { FOO }\nvar foo Foo = .F\n\", 1, 15, \"\n<stdin>:2:16: error: \\\"F\\\" is not declared on type \\\"Foo\\\"\nvar foo Foo = .F\n               ^\n<stdin>:2:16: completions:\nvar foo Foo = .F\n               ^\n               [FOO] # \\\"Foo\\\"\n\")\n\n# Completion: inside partial if statement\ntestCompletion(\"\ndef foo {\n  if f\n}\n\", 1, 6, \"\n<stdin>:3:1: error: Expected \\\"{\\\" but found \\\"}\\\"\n}\n^\n<stdin>:2:6: error: \\\"f\\\" is not declared\n  if f\n     ^\n<stdin>:2:6: completions:\n  if f\n     ^\n     [foo] # \\\"()\\\"\n\")\n\n# Signatures: test basic signature queries\ntestIDE(\"\ndef test(foo int, bar bool) double {\n  return test(foo, bar)\n}\n\", (ide, expect) => {\n  expect(\"\", ide.signatureQuery(1, 12))\n  expect(\"def test([foo int], bar bool) double\", ide.signatureQuery(1, 13))\n  expect(\"def test([foo int], bar bool) double\", ide.signatureQuery(1, 17))\n  expect(\"def test(foo int, [bar bool]) double\", ide.signatureQuery(1, 18))\n  expect(\"def test(foo int, [bar bool]) double\", ide.signatureQuery(1, 23))\n})\n\n  }\n}\n"
  },
  {
    "path": "tests/javascript.mangle.sk",
    "content": "namespace Skew.Tests {\n  def testJavaScriptMangle {\n\n# Test falsy values\ntest(\"\nclass Foo {\n}\n\n@entry\ndef main {\n  var i int\n  var s string\n  var d double\n  var b bool\n  var f Foo\n  var y dynamic\n\n  if i != 0 { dynamic.foo() }\n  if s != \\\"\\\" { dynamic.foo() }\n  if s != null { dynamic.foo() }\n  if d != 0.0 { dynamic.foo() }\n  if b != false { dynamic.foo() }\n  if f != null { dynamic.foo() }\n\n  if y != 0 { dynamic.foo() }\n  if y != \\\"\\\" { dynamic.foo() }\n  if y != 0.0 { dynamic.foo() }\n  if y != false { dynamic.foo() }\n  if y != null { dynamic.foo() }\n}\n\", \"\n(function() {\n  function g() {\n    var c = 0, b = null, d = 0, e = !1, f = null, a = null;\n    c && foo(), b != '' && foo(), b != null && foo(), d != 0 && foo(), e != !1 && foo(), f && foo(), a !== 0 && foo(), a !== '' && foo(), a !== 0 && foo(), a !== !1 && foo(), a !== null && foo();\n  }\n\n  g();\n})();\n\").jsMangle\n\n# Test default values\ntest(\"\n@entry\ndef main {\n  var i int\n  var s string\n  var d double\n  var b bool\n  var f Foo\n  var r = i.toString + d.toString + b.toString + s + f.toString\n}\n\nclass Foo {\n  def toString string\n}\n\", \"\n(function() {\n  function e() {\n    var a = null, b = null, d = '0' + 0 + 'false' + a + b.c();\n  }\n\n  e();\n})();\n\").jsMangle.foldAllConstants\n\n# Test associative operator rotation\ntest(\"\ndef foo {\n  dynamic.test(dynamic.a + (dynamic.b + dynamic.c))\n  dynamic.test(dynamic.a - (dynamic.b - dynamic.c))\n  dynamic.test(dynamic.a * (dynamic.b * dynamic.c))\n  dynamic.test(dynamic.a / (dynamic.b / dynamic.c))\n  dynamic.test(dynamic.a & (dynamic.b & dynamic.c))\n  dynamic.test(dynamic.a | (dynamic.b | dynamic.c))\n  dynamic.test(dynamic.a ^ (dynamic.b ^ dynamic.c))\n  dynamic.test(dynamic.a && (dynamic.b && dynamic.c))\n  dynamic.test(dynamic.a || (dynamic.b || dynamic.c))\n}\n\n@entry\ndef bar {\n  dynamic.test(dynamic.a & ((dynamic.b | dynamic.c) & (dynamic.d & (dynamic.e & dynamic.f))))\n  foo\n}\n\", \"\n(function() {\n  function a() {\n    test(a + (b + c)), test(a - (b - c)), test(a * (b * c)), test(a / (b / c)), test(a & b & c), test(a | b | c), test(a ^ b ^ c), test(a && b && c), test(a || b || c);\n  }\n\n  function b() {\n    test(a & (b | c) & d & e & f), a();\n  }\n\n  b();\n})();\n\").jsMangle\n\n# Test if statement folding\ntest(\"\n@entry\ndef main {\n  if dynamic.a() {}\n  if dynamic.b() { dynamic.c() }\n  if dynamic.d() {}\n  else { dynamic.e() }\n  if dynamic.f() { dynamic.g() }\n  else { dynamic.h() }\n}\n\", \"\n(function() {\n  function a() {\n    a(), b() && c(), d() || e(), f() ? g() : h();\n  }\n\n  a();\n})();\n\").jsMangle.foldAllConstants\n\n# Test if statement return folding\ntest(\"\ndef foo bool {\n  if dynamic.a { return true }\n  if dynamic.b && dynamic.c { return true }\n  if dynamic.d { return true }\n  if dynamic.e && dynamic.f { return true }\n  return false\n}\n\ndef bar bool {\n  if dynamic.a { return true }\n  else if dynamic.b && dynamic.c { return true }\n  else if dynamic.d { return true }\n  else if dynamic.e && dynamic.f { return true }\n  else { return false }\n}\n\ndef baz bool {\n  if dynamic.a || dynamic.b {\n    if dynamic.c || dynamic.d {\n      return true\n    }\n  }\n  return false\n}\n\n@entry\ndef main {\n  foo\n  bar\n  baz\n}\n\", \"\n(function() {\n  function a() {\n    return a || b && c || d || e && f ? !0 : !1;\n  }\n\n  function b() {\n    return a || b && c || d || e && f ? !0 : !1;\n  }\n\n  function c() {\n    return (a || b) && (c || d) ? !0 : !1;\n  }\n\n  function d() {\n    a(), b(), c();\n  }\n\n  d();\n})();\n\").jsMangle\n\n# More tests for if statement return folding\ntest(\"\ndef foo(x dynamic) dynamic {\n  x.foo(1)\n  if x.y {\n    x.foo(2)\n    if x.y {\n      x.foo(0)\n      return x\n    }\n  }\n  x.foo(3)\n  if x.y {\n    x.foo(4)\n    if x.y {\n      x.foo(0)\n      return x\n    }\n  }\n  return 0\n}\n\ndef bar(x double) int {\n  if x < 0 { return 0 }\n  if x > 1 { return 1 }\n  return 2\n}\n\n@entry\ndef main {\n  foo(0)\n  bar(0)\n}\n\", \"\n(function() {\n  function b(a) {\n    return (a.foo(1), a.y && (a.foo(2), a.y)) || (a.foo(3), a.y && (a.foo(4), a.y)) ? (a.foo(0), a) : 0;\n  }\n\n  function c(a) {\n    return a < 0 ? 0 : a > 1 ? 1 : 2;\n  }\n\n  function d() {\n    b(0), c(0);\n  }\n\n  d();\n})();\n\").jsMangle\n\n# Test integer comparison special cases\ntest(\"\ndef foo(bar int, baz fn()) {\n  if bar < 1 { baz() }\n  if bar <= 1 { baz() }\n  if bar > 1 { baz() }\n  if bar >= 1 { baz() }\n  if bar == 1 { baz() }\n  if bar != 1 { baz() }\n}\n\ndef bar(foo int, baz fn()) {\n  if 1 < foo { baz() }\n  if 1 <= foo { baz() }\n  if 1 > foo { baz() }\n  if 1 >= foo { baz() }\n  if 1 == foo { baz() }\n  if 1 != foo { baz() }\n}\n\n@entry\ndef main {\n  foo(0, null)\n  bar(0, null)\n}\n\", \"\n(function() {\n  function c(a, b) {\n    a < 1 && b(), a < 2 && b(), a > 1 && b(), a > 0 && b(), a ^ 1 || b(), a ^ 1 && b();\n  }\n\n  function d(a, b) {\n    1 < a && b(), 0 < a && b(), 1 > a && b(), 2 > a && b(), 1 ^ a || b(), 1 ^ a && b();\n  }\n\n  function e() {\n    c(0, null), d(0, null);\n  }\n\n  e();\n})();\n\").jsMangle\n\n# Test enum comparison special cases\ntest(\"\ndef foo(bar Foo, baz fn()) {\n  if bar < Foo.BAR { baz() }\n  if bar <= Foo.BAR { baz() }\n  if bar > Foo.BAR { baz() }\n  if bar >= Foo.BAR { baz() }\n  if bar == Foo.FOO { baz() }\n  if bar != Foo.FOO { baz() }\n  if bar == Foo.BAR { baz() }\n  if bar != Foo.BAR { baz() }\n}\n\ndef bar(foo Foo, baz fn()) {\n  if Foo.BAR < foo { baz() }\n  if Foo.BAR <= foo { baz() }\n  if Foo.BAR > foo { baz() }\n  if Foo.BAR >= foo { baz() }\n  if Foo.FOO == foo { baz() }\n  if Foo.FOO != foo { baz() }\n  if Foo.BAR == foo { baz() }\n  if Foo.BAR != foo { baz() }\n}\n\n@entry\ndef main {\n  foo(.FOO, null)\n  bar(.BAR, null)\n}\n\nenum Foo {\n  FOO\n  BAR\n}\n\", \"\n(function() {\n  function c(a, b) {\n    a < 1 && b(), a < 2 && b(), a > 1 && b(), a > 0 && b(), a || b(), a && b(), a ^ 1 || b(), a ^ 1 && b();\n  }\n\n  function d(a, b) {\n    1 < a && b(), 0 < a && b(), 1 > a && b(), 2 > a && b(), a || b(), a && b(), 1 ^ a || b(), 1 ^ a && b();\n  }\n\n  function e() {\n    c(0, null), d(1, null);\n  }\n\n  e();\n})();\n\").jsMangle.foldAllConstants\n\n# Doubles should not trigger integer comparison special cases\ntest(\"\ndef foo(bar double, baz fn()) {\n  if bar < 1 { baz() }\n  if bar <= 1 { baz() }\n  if bar > 1 { baz() }\n  if bar >= 1 { baz() }\n  if bar == 1 { baz() }\n  if bar != 1 { baz() }\n}\n\ndef bar(foo double, baz fn()) {\n  if 1 < foo { baz() }\n  if 1 <= foo { baz() }\n  if 1 > foo { baz() }\n  if 1 >= foo { baz() }\n  if 1 == foo { baz() }\n  if 1 != foo { baz() }\n}\n\n@entry\ndef main {\n  foo(0, null)\n  bar(0, null)\n}\n\", \"\n(function() {\n  function c(a, b) {\n    a < 1 && b(), a <= 1 && b(), a > 1 && b(), a >= 1 && b(), a == 1 && b(), a != 1 && b();\n  }\n\n  function d(a, b) {\n    1 < a && b(), 1 <= a && b(), 1 > a && b(), 1 >= a && b(), 1 == a && b(), 1 != a && b();\n  }\n\n  function e() {\n    c(0, null), d(0, null);\n  }\n\n  e();\n})();\n\").jsMangle\n\n# Test a special case for comparison with -1\ntest(\"\ndef foo(bar string) {\n  if \\\"foo\\\" in bar { dynamic.bar() }\n}\n\n@entry\ndef main {\n  foo(null)\n}\n\", \"\n(function() {\n  function a(b) {\n    ~b.indexOf('foo') && bar();\n  }\n\n  function c() {\n    a(null);\n  }\n\n  c();\n})();\n\").jsMangle.inlineAllFunctions.foldAllConstants\n\n# Test index to member conversions\ntest(\"\ndef foo(map StringMap<int>) {\n  dynamic.test(map[\\\"x\\\"])\n  dynamic.test(map[\\\"_\\\"])\n  dynamic.test(map[\\\"0\\\"])\n  dynamic.test(map[\\\"x0\\\"])\n  dynamic.test(map[\\\"if\\\"])\n}\n\ndef bar(map StringMap<int>) {\n  map[\\\"x\\\"] = dynamic.test()\n  map[\\\"_\\\"] = dynamic.test()\n  map[\\\"0\\\"] = dynamic.test()\n  map[\\\"x0\\\"] = dynamic.test()\n  map[\\\"if\\\"] = dynamic.test()\n}\n\n@entry\ndef main {\n  foo(null)\n  bar(null)\n}\n\", \"\n(function() {\n  function d(a) {\n    test(a.get('x')), test(a.get('_')), test(a.get('0')), test(a.get('x0')), test(a.get('if'));\n  }\n\n  function e(a) {\n    b(a, 'x', test()), b(a, '_', test()), b(a, '0', test()), b(a, 'x0', test()), b(a, 'if', test());\n  }\n\n  function g() {\n    d(null), e(null);\n  }\n\n  function b(f, a, c) {\n    return f.set(a, c), c;\n  }\n\n  g();\n})();\n\").jsMangle.inlineAllFunctions.foldAllConstants\n\n# Test dead code elimination with constants\ntest(\"\nenum Foo {\n  FOO\n  BAR\n  BAZ\n}\n\nconst foo = Foo.BAZ\n\n@entry\ndef bar {\n  if foo == .FOO { dynamic.test(\\\"FOO\\\") }\n  else if foo == .BAR { dynamic.test(\\\"BAR\\\") }\n  else if foo == .BAZ { dynamic.test(\\\"BAZ\\\") }\n  else { dynamic.test(\\\"FAIL\\\") }\n}\n\", \"\n(function() {\n  function a() {\n    test('BAZ');\n  }\n\n  a();\n})();\n\").jsMangle.foldAllConstants\n\n# Test return statement collapsing\ntest(\"\n@entry\ndef foo {\n  if dynamic.x {\n    dynamic.y()\n    return\n  }\n}\n\", \"\n(function() {\n  function a() {\n    if (x) {\n      y();\n    }\n  }\n\n  a();\n})();\n\").jsMangle\n\n# Test return statement collapsing\ntest(\"\n@entry\ndef foo {\n  if dynamic.x { return }\n  dynamic.y()\n  dynamic.y()\n}\n\", \"\n(function() {\n  function a() {\n    x || (y(), y());\n  }\n\n  a();\n})();\n\").jsMangle\n\n# Test return statement collapsing\ntest(\"\n@entry\ndef foo {\n  if dynamic.x { return }\n  dynamic.y()\n  if dynamic.x { return }\n  dynamic.y()\n}\n\", \"\n(function() {\n  function a() {\n    x || (y(), x || y());\n  }\n\n  a();\n})();\n\").jsMangle\n\n# Test return statement collapsing\ntest(\"\n@entry\ndef foo {\n  if dynamic.x {\n    if dynamic.y { return }\n    dynamic.z()\n    dynamic.z()\n  }\n}\n\", \"\n(function() {\n  function a() {\n    x && (y || (z(), z()));\n  }\n\n  a();\n})();\n\").jsMangle\n\n# Test return statement collapsing\ntest(\"\n@entry\ndef foo {\n  if dynamic.x {\n    if dynamic.y { return }\n    dynamic.z()\n    dynamic.z()\n  }\n  dynamic.z()\n}\n\", \"\n(function() {\n  function a() {\n    if (x) {\n      if (y) {\n        return;\n      }\n\n      z(), z();\n    }\n\n    z();\n  }\n\n  a();\n})();\n\").jsMangle\n\n# Test return statement collapsing\ntest(\"\n@entry\ndef foo {\n  while dynamic.x {\n    if dynamic.y { return }\n    dynamic.z()\n    dynamic.z()\n  }\n}\n\", \"\n(function() {\n  function a() {\n    for (; x;) {\n      if (y) {\n        return;\n      }\n\n      z(), z();\n    }\n  }\n\n  a();\n})();\n\").jsMangle\n\n# Test return statement collapsing\ntest(\"\ndef foo {\n  dynamic.a()\n  dynamic.b()\n  if dynamic.c() {\n    if dynamic.d() { return }\n    dynamic.e()\n    dynamic.f()\n  }\n}\n\n@entry\ndef bar {\n  dynamic.a()\n  dynamic.b()\n  if dynamic.c() {\n    if dynamic.d() { return }\n    dynamic.e()\n    dynamic.f()\n  }\n  foo\n}\n\", \"\n(function() {\n  function a() {\n    a(), b(), c() && (d() || (e(), f()));\n  }\n\n  function b() {\n    if (a(), b(), c()) {\n      if (d()) {\n        return;\n      }\n\n      e(), f();\n    }\n\n    a();\n  }\n\n  b();\n})();\n\").jsMangle\n\n# Test continue statement collapsing\ntest(\"\n@entry\ndef foo {\n  while dynamic.x {\n    if dynamic.y {\n      dynamic.z()\n      continue\n    }\n  }\n}\n\", \"\n(function() {\n  function a() {\n    for (; x;) {\n      if (y) {\n        z();\n      }\n    }\n  }\n\n  a();\n})();\n\").jsMangle\n\n# Test continue statement collapsing\ntest(\"\n@entry\ndef foo {\n  while dynamic.x {\n    if dynamic.y { continue }\n    dynamic.z()\n    dynamic.z()\n  }\n}\n\", \"\n(function() {\n  function a() {\n    for (; x;) {\n      y || (z(), z());\n    }\n  }\n\n  a();\n})();\n\").jsMangle\n\n# Test continue statement collapsing\ntest(\"\n@entry\ndef foo {\n  while dynamic.x {\n    if dynamic.y { continue }\n    dynamic.z()\n    if dynamic.y { continue }\n    dynamic.z()\n  }\n}\n\", \"\n(function() {\n  function a() {\n    for (; x;) {\n      y || (z(), y || z());\n    }\n  }\n\n  a();\n})();\n\").jsMangle\n\n# Test continue statement collapsing\ntest(\"\n@entry\ndef foo {\n  while dynamic.x {\n    if dynamic.y {\n      dynamic.z()\n      if dynamic.y { continue }\n      dynamic.z()\n      dynamic.z()\n    }\n  }\n}\n\", \"\n(function() {\n  function a() {\n    for (; x;) {\n      y && (z(), y || (z(), z()));\n    }\n  }\n\n  a();\n})();\n\").jsMangle\n\n# Test continue statement collapsing\ntest(\"\n@entry\ndef foo {\n  while dynamic.x {\n    if dynamic.y {\n      dynamic.z()\n      if dynamic.y { continue }\n      dynamic.z()\n      dynamic.z()\n    }\n    dynamic.z()\n  }\n}\n\", \"\n(function() {\n  function a() {\n    for (; x;) {\n      if (y) {\n        if (z(), y) {\n          continue;\n        }\n\n        z(), z();\n      }\n\n      z();\n    }\n  }\n\n  a();\n})();\n\").jsMangle\n\n# Test continue statement collapsing\ntest(\"\n@entry\ndef foo {\n  while dynamic.x {\n    if dynamic.y {\n      dynamic.z()\n      continue\n    }\n    dynamic.z()\n    dynamic.z()\n  }\n}\n\", \"\n(function() {\n  function a() {\n    for (; x;) {\n      y ? z() : (z(), z());\n    }\n  }\n\n  a();\n})();\n\").jsMangle\n\n# Test continue statement collapsing\ntest(\"\ndef foo {\n  while dynamic.x {\n    dynamic.a()\n    dynamic.b()\n    if dynamic.c() {\n      if dynamic.d() { continue }\n      dynamic.e()\n      dynamic.f()\n    }\n  }\n}\n\n@entry\ndef bar {\n  while dynamic.x {\n    dynamic.a()\n    dynamic.b()\n    if dynamic.c() {\n      if dynamic.d() { continue }\n      dynamic.e()\n      dynamic.f()\n    }\n    foo\n  }\n}\n\", \"\n(function() {\n  function a() {\n    for (; x;) {\n      a(), b(), c() && (d() || (e(), f()));\n    }\n  }\n\n  function b() {\n    for (; x;) {\n      if (a(), b(), c()) {\n        if (d()) {\n          continue;\n        }\n\n        e(), f();\n      }\n\n      a();\n    }\n  }\n\n  b();\n})();\n\").jsMangle\n\n# Test mangling the \"self\" variable\ntest(\"\n@export\nclass Foo {\n  var x = 100\n\n  def foo fn() int {\n    var y = dynamic.get()\n    return => x + y\n  }\n\n  def bar fn() int {\n    var y = dynamic.get()\n    while true {\n      return => x + y\n    }\n  }\n\n  def baz fn() int {\n    while true {\n      return => x\n    }\n  }\n\n  def test fn() int {\n    return => x\n  }\n}\n\", \"\n(function(d) {\n  var c;\n\n  d.Foo = function() {\n    this.x = 100;\n  };\n\n  c = d.Foo.prototype;\n\n  c.foo = function() {\n    var b = this, a = get();\n    return function() {\n      return b.x + a;\n    };\n  };\n\n  c.bar = function() {\n    for (var b = this, a = get();;) {\n      return function() {\n        return b.x + a;\n      };\n    }\n  };\n\n  c.baz = function() {\n    for (var a = this;;) {\n      return function() {\n        return a.x;\n      };\n    }\n  };\n\n  c.test = function() {\n    var a = this;\n    return function() {\n      return a.x;\n    };\n  };\n})(this);\n\").jsMangle\n\n# Test a loop special case\ntest(\"\ndef foo {\n  while true {\n    dynamic.a()\n    if dynamic.b() {\n      break\n    }\n  }\n}\n\ndef bar {\n  while dynamic.a() {\n    dynamic.b()\n    if dynamic.c() {\n      break\n    }\n  }\n}\n\n@entry\ndef main {\n  foo\n  bar\n}\n\", \"\n(function() {\n  function a() {\n    for (; a(), !b();) {\n    }\n  }\n\n  function b() {\n    for (; a() && (b(), !c());) {\n    }\n  }\n\n  function c() {\n    a(), b();\n  }\n\n  c();\n})();\n\").jsMangle\n\n# Test mangling the name of catch variables\ntest(\"\n@entry\ndef foo {\n  try {\n  } catch foo dynamic {\n  }\n}\n\", \"\n(function() {\n  function b() {\n    try {\n    }\n\n    catch (a) {\n    }\n  }\n\n  b();\n})();\n\").jsMangle\n\ntest(\"\n@entry\ndef foo {\n  while true {\n    switch dynamic.x {\n      case 0 { break }\n      case 1 { switch dynamic.y { case 0 { break } } }\n    }\n  }\n\n  for i = 0; i < 10; i++ {\n    switch dynamic.x {\n      case 0 { break }\n      case 1 { switch dynamic.y { case 0 { break } } }\n    }\n  }\n\n  for i in 0..10 {\n    switch dynamic.x {\n      case 0 { break }\n      case 1 { switch dynamic.y { case 0 { break } } }\n    }\n  }\n}\n\", \"\n(function() {\n  function c() {\n    d: for (;;) {\n      switch (x) {\n        case 0: {\n          break d;\n        }\n\n        case 1: {\n          if (y === 0) {\n            break d;\n          }\n          break;\n        }\n      }\n    }\n\n    e: for (var a = 0; a < 10; a = a + 1 | 0) {\n      switch (x) {\n        case 0: {\n          break e;\n        }\n\n        case 1: {\n          if (y === 0) {\n            break e;\n          }\n          break;\n        }\n      }\n    }\n\n    f: for (var b = 0; b < 10; b = b + 1 | 0) {\n      switch (x) {\n        case 0: {\n          break f;\n        }\n\n        case 1: {\n          if (y === 0) {\n            break f;\n          }\n          break;\n        }\n      }\n    }\n  }\n\n  c();\n})();\n\").jsMangle\n\n# Test moving the default case outside the switch statement\ntest(\"\n@entry\ndef foo {\n  switch dynamic.a {\n    case 0 { return }\n    default {\n      dynamic.b1()\n      dynamic.b2()\n    }\n  }\n\n  switch dynamic.a {\n    case 0 { dynamic.c() }\n    default {\n      dynamic.d1()\n      dynamic.d2()\n    }\n  }\n\n  dynamic.e()\n}\n\", \"\n(function() {\n  function a() {\n    a !== 0 && (b1(), b2(), a === 0 ? c() : (d1(), d2()), e());\n  }\n\n  a();\n})();\n\").jsMangle\n\n# Test inline identifiers in object literals\ntest(\"\n@export\ndef foo dynamic {\n  return {\\\"a\\\": 0, \\\"0\\\": 0, \\\" \\\": 0}\n}\n\", \"\n(function(a) {\n  a.foo = function() {\n    return {a: 0, '0': 0, ' ': 0};\n  };\n})(this);\n\").jsMangle\n\n# Test sequence hook rotation\ntest(\"\n@export\ndef foo dynamic {\n  return () bool => {\n    dynamic.x()\n    if dynamic.q {\n      dynamic.x()\n      return true\n    }\n    return false\n  }\n}\n\", \"\n(function(a) {\n  a.foo = function() {\n    return function() {\n      return x(), q ? (x(), !0) : !1;\n    };\n  };\n})(this);\n\").jsMangle\n\n# Test toString() removal\ntest(\"\n@export\ndef foo(x int, f Foo, b Bar) {\n  var z = Baz.new\n  dynamic.t(\\\"\\\" + x.toString)\n  dynamic.t(dynamic.q + x.toString)\n  dynamic.t(x.toString + \\\"\\\")\n  dynamic.t(x.toString + x.toString)\n  dynamic.t(f.toString + \\\"\\\")\n  dynamic.t(b.toString(0) + \\\"\\\")\n  dynamic.t(z.toString + \\\"\\\")\n}\n\n@import\nclass Foo {\n  def toString string\n}\n\n@import\nclass Bar {\n  def toString(x int) string\n}\n\nclass Baz {\n  def toString string { return \\\"\\\" }\n}\n\", \"\n(function(g) {\n  function f() {\n  }\n\n  f.prototype.c = function() {\n    return '';\n  };\n\n  g.foo = function(a, d, e) {\n    var b = new f;\n    t('' + a), t(q + a.toString()), t(a + ''), t(a.toString() + a), t(d + ''), t(e.toString(0) + ''), t(b.c() + '');\n  };\n})(this);\n\").jsMangle\n\n# Make sure folding doesn't leave extra variables in this case\ntest(\"\n@export\ndef foo int {\n  var a = 0, b = 0\n  var c = 0\n  return a + b + c\n}\n\", \"\n(function(a) {\n  a.foo = function() {\n    return 0;\n  };\n})(this);\n\").jsMangle.foldAllConstants\n\n# Make sure special runtime function names and definitions are mangled\ntest(\"\nclass Foo {}\nclass Bar : Foo {}\n\n@entry\ndef main(args List<string>) int {\n  Bar.new\n  return args.count * 100\n}\n\", \"\n(function() {\n  var c = Object.create || function(a) {\n    return {__proto__: a};\n  };\n\n  function d(a, b) {\n    a.prototype = c(b.prototype), a.prototype.constructor = a;\n  }\n\n  var e = Math.imul || function(a, b) {\n    return (a * (b >>> 16) << 16) + a * (b & 65535) | 0;\n  };\n\n  function h(a) {\n    return new g, e(a.length, 100);\n  }\n\n  function f() {\n  }\n\n  function g() {\n    f.call(this);\n  }\n\n  d(g, f);\n\n  process.exit(h(process.argv.slice(2)));\n})();\n\").jsMangle\n\n# Make sure casting doesn't cause the enum declaration to be emitted\ntest(\"\nenum Foo { FOO }\n\n@entry\ndef main int {\n  return 0 as Foo\n}\n\", \"\n(function() {\n  function a() {\n    return 0;\n  }\n\n  process.exit(a());\n})();\n\").jsMangle\n\n# Make sure constant folding folds string lengths\ntest(\"\n@entry\ndef foo int {\n  return \\\"abc\\\".count\n}\n\", \"\n(function() {\n  function a() {\n    return 3;\n  }\n\n  process.exit(a());\n})();\n\").jsMangle.foldAllConstants\n\n# Lock down the name generation algorithm\ntest(\"\n@import {\n  def x int\n  def y\n}\n\n@entry\ndef main {\n  var a0 = x, a1 = x, a2 = x, a3 = x, a4 = x, a5 = x, a6 = x, a7 = x, a8 = x, a9 = x\n  y\n  var b0 = x, b1 = x, b2 = x, b3 = x, b4 = x, b5 = x, b6 = x, b7 = x, b8 = x, b9 = x\n  y\n  var c0 = x, c1 = x, c2 = x, c3 = x, c4 = x, c5 = x, c6 = x, c7 = x, c8 = x, c9 = x\n  y\n  var d0 = x, d1 = x, d2 = x, d3 = x, d4 = x, d5 = x, d6 = x, d7 = x, d8 = x, d9 = x\n  y\n  var e0 = x, e1 = x, e2 = x, e3 = x, e4 = x, e5 = x, e6 = x, e7 = x, e8 = x, e9 = x\n  y\n  var f0 = x, f1 = x, f2 = x, f3 = x, f4 = x, f5 = x, f6 = x, f7 = x, f8 = x, f9 = x\n  y\n  var g0 = x, g1 = x, g2 = x, g3 = x, g4 = x, g5 = x, g6 = x, g7 = x, g8 = x, g9 = x\n  y\n  var h0 = x, h1 = x, h2 = x, h3 = x, h4 = x, h5 = x, h6 = x, h7 = x, h8 = x, h9 = x\n  y\n  var i0 = x, i1 = x, i2 = x, i3 = x, i4 = x, i5 = x, i6 = x, i7 = x, i8 = x, i9 = x\n  y\n  var j0 = x, j1 = x, j2 = x, j3 = x, j4 = x, j5 = x, j6 = x, j7 = x, j8 = x, j9 = x\n  y\n  var k0 = x, k1 = x, k2 = x, k3 = x, k4 = x, k5 = x, k6 = x, k7 = x, k8 = x, k9 = x\n}\n\", \"\n(function() {\n  function eb() {\n    var a = x(), b = x(), c = x(), d = x(), e = x(), f = x(), g = x(), h = x(), i = x(), j = x();\n    y();\n    var k = x(), l = x(), m = x(), n = x(), o = x(), p = x(), q = x(), r = x(), s = x(), t = x();\n    y();\n    var u = x(), v = x(), w = x(), z = x(), A = x(), B = x(), C = x(), D = x(), E = x(), F = x();\n    y();\n    var G = x(), H = x(), I = x(), J = x(), K = x(), L = x(), M = x(), N = x(), O = x(), P = x();\n    y();\n    var Q = x(), R = x(), S = x(), T = x(), U = x(), V = x(), W = x(), X = x(), Y = x(), Z = x();\n    y();\n    var _ = x(), $ = x(), aa = x(), ba = x(), ca = x(), da = x(), ea = x(), fa = x(), ga = x(), ha = x();\n    y();\n    var ia = x(), ja = x(), ka = x(), la = x(), ma = x(), na = x(), oa = x(), pa = x(), qa = x(), ra = x();\n    y();\n    var sa = x(), ta = x(), ua = x(), va = x(), wa = x(), xa = x(), ya = x(), za = x(), Aa = x(), Ba = x();\n    y();\n    var Ca = x(), Da = x(), Ea = x(), Fa = x(), Ga = x(), Ha = x(), Ia = x(), Ja = x(), Ka = x(), La = x();\n    y();\n    var Ma = x(), Na = x(), Oa = x(), Pa = x(), Qa = x(), Ra = x(), Sa = x(), Ta = x(), Ua = x(), Va = x();\n    y();\n    var Wa = x(), Xa = x(), Ya = x(), Za = x(), _a = x(), $a = x(), ab = x(), bb = x(), cb = x(), db = x();\n  }\n\n  eb();\n})();\n\").jsMangle\n\n# Make sure it's possible to not clobber over jQuery\ntest(\"\n@import {\n  def x int\n  def y\n\n  @rename(\\\"$\\\")\n  var jQuery dynamic\n}\n\n@entry\ndef main {\n  var a0 = x, a1 = x, a2 = x, a3 = x, a4 = x, a5 = x, a6 = x, a7 = x, a8 = x, a9 = x\n  y\n  var b0 = x, b1 = x, b2 = x, b3 = x, b4 = x, b5 = x, b6 = x, b7 = x, b8 = x, b9 = x\n  y\n  var c0 = x, c1 = x, c2 = x, c3 = x, c4 = x, c5 = x, c6 = x, c7 = x, c8 = x, c9 = x\n  y\n  var d0 = x, d1 = x, d2 = x, d3 = x, d4 = x, d5 = x, d6 = x, d7 = x, d8 = x, d9 = x\n  y\n  var e0 = x, e1 = x, e2 = x, e3 = x, e4 = x, e5 = x, e6 = x, e7 = x, e8 = x, e9 = x\n  y\n  var f0 = x, f1 = x, f2 = x, f3 = x, f4 = x, f5 = x, f6 = x, f7 = x, f8 = x, f9 = x\n  jQuery()\n}\n\", \"\n(function() {\n  function ja() {\n    var a = x(), b = x(), c = x(), d = x(), e = x(), f = x(), g = x(), h = x(), i = x(), j = x();\n    y();\n    var k = x(), l = x(), m = x(), n = x(), o = x(), p = x(), q = x(), r = x(), s = x(), t = x();\n    y();\n    var u = x(), v = x(), w = x(), z = x(), A = x(), B = x(), C = x(), D = x(), E = x(), F = x();\n    y();\n    var G = x(), H = x(), I = x(), J = x(), K = x(), L = x(), M = x(), N = x(), O = x(), P = x();\n    y();\n    var Q = x(), R = x(), S = x(), T = x(), U = x(), V = x(), W = x(), X = x(), Y = x(), Z = x();\n    y();\n    var _ = x(), aa = x(), ba = x(), ca = x(), da = x(), ea = x(), fa = x(), ga = x(), ha = x(), ia = x();\n    $();\n  }\n\n  ja();\n})();\n\").jsMangle\n\n# Make sure inlined helper functions are also constant folded\ntest(\"\ndef bar(a int, b int) int {\n  return 'A' | a << 8 | 'B' << 16 | b << 24\n}\n\n@entry\ndef main int {\n  const a = 1\n  const b = 2\n  const foo = bar(a, b)\n  return foo\n}\n\", \"\n(function() {\n  function a() {\n    return 37880129;\n  }\n\n  process.exit(a());\n})();\n\").jsMangle.foldAllConstants.inlineAllFunctions\n\n# This tests a bug where overloaded imported constructors were emitted incorrectly\ntest(\"\n@entry\ndef main {\n  foo(Foo.new([]))\n}\n\ndef foo(bar Foo) Foo {\n  return Foo.new(0)\n}\n\n@import\nclass Foo {\n  def new(length int)\n  def new(array List<int>)\n}\n\", \"\n(function() {\n  function c() {\n    a(new Foo([]));\n  }\n\n  function a(b) {\n    return new Foo(0);\n  }\n\n  c();\n})();\n\").jsMangle\n\n# Make sure the 32-bit integer negation special-case is handled correctly\ntest(\"\ndef foo List<int> {\n  return [0x7FFFFFFF, -0x7FFFFFFF, 0x80000000, -0x80000000]\n}\n\n@entry\ndef main {\n  foo\n}\n\", \"\n(function() {\n  function a() {\n    return [2147483647, -2147483647, 1 << 31, -(1 << 31) | 0];\n  }\n\n  function b() {\n    a();\n  }\n\n  b();\n})();\n\").jsMangle\n\n# Make sure the 32-bit integer negation special-case is handled correctly\ntest(\"\ndef foo List<int> {\n  return [0x7FFFFFFF, -0x7FFFFFFF, 0x80000000, -0x80000000]\n}\n\n@entry\ndef main {\n  foo\n}\n\", \"\n(function() {\n  function a() {\n    return [2147483647, -2147483647, 1 << 31, 1 << 31];\n  }\n\n  function b() {\n    a();\n  }\n\n  b();\n})();\n\").jsMangle.foldAllConstants\n\n# Test left shift substitution\ntest(\"\ndef foo List<int> {\n  return [\n    16384,\n    131072,\n    1073741824,\n    -2147483648,\n    0xFF000,\n    0xFF0000,\n    0xFF00000,\n    0xFF000000,\n  ]\n}\n\n@entry\ndef main {\n  foo\n}\n\", \"\n(function() {\n  function a() {\n    return [16384, 1 << 17, 1 << 30, 1 << 31, 1044480, 255 << 16, 255 << 20, 255 << 24];\n  }\n\n  function b() {\n    a();\n  }\n\n  b();\n})();\n\").jsMangle.foldAllConstants\n\n# Wrapping shouldn't introduce casts\ntest(\"\ntype Foo = int\n\n@entry\ndef main int {\n  return 0 as Foo as int as Foo as int\n}\n\", \"\n(function() {\n  function a() {\n    return 0;\n  }\n\n  process.exit(a());\n})();\n\").jsMangle\n\n# Wrapping should work with constant folding\ntest(\"\n@entry\ndef main {\n  dynamic.foo((0 as Foo) == (1 as Foo))\n  dynamic.foo((0 as int) == (1 as int))\n  dynamic.foo(0 == 1)\n}\n\ntype Foo = int\n\", \"\n(function() {\n  function a() {\n    foo(!1), foo(!1), foo(!1);\n  }\n\n  a();\n})();\n\").jsMangle.foldAllConstants\n\n# Check that empty switch statements are removed\ntest(\"\n@entry\ndef main {\n  switch dynamic.x { default { dynamic.y() } }\n}\n\", \"\n(function() {\n  function a() {\n    y();\n  }\n\n  a();\n})();\n\").jsMangle\n\n# Check that empty switch statements are removed\ntest(\"\n@entry\ndef main {\n  switch dynamic.x() { default { dynamic.y() } }\n}\n\", \"\n(function() {\n  function a() {\n    x(), y();\n  }\n\n  a();\n})();\n\").jsMangle\n\n# Check that switch statements have a single element turn into if statements, which are then further optimized\ntest(\"\n@entry\ndef main {\n  switch dynamic.x { case X { dynamic.foo() } }\n  switch dynamic.y { case Y { dynamic.bar() } }\n}\n\ntype Foo = int\nconst X = 0\nconst Y = 0 as Foo\n\", \"\n(function() {\n  function a() {\n    x === 0 && foo(), y === 0 && bar();\n  }\n\n  a();\n})();\n\").jsMangle.foldAllConstants\n\n# Check that switch statements that become single-element after other optimizations turn into if statements\ntest(\"\n@entry\ndef main {\n  switch dynamic.x {\n    case 0 { return }\n    default { dynamic.y() }\n  }\n}\n\", \"\n(function() {\n  function a() {\n    x !== 0 && y();\n  }\n\n  a();\n})();\n\").jsMangle\n\n# Check that double-element switch statements turn into if statements and are optimized further\ntest(\"\n@entry\ndef main {\n  switch dynamic.x {\n    case 0 { dynamic.y() }\n    default { dynamic.z() }\n  }\n}\n\", \"\n(function() {\n  function a() {\n    x === 0 ? y() : z();\n  }\n\n  a();\n})();\n\").jsMangle\n\n# Check that pass-through switch statements are optimized\ntest(\"\nenum Foo {\n  FOO\n  BAR\n  BAZ\n}\n\ndef a(x int) Foo {\n  switch x {\n    case 0 { return .FOO }\n    case 1 { return .BAR }\n    case 2 { return .BAZ }\n    default { return .FOO }\n  }\n}\n\ndef b(x int) Foo {\n  switch x {\n    case 1 { return .FOO }\n    case 2 { return .BAR }\n    case 3 { return .BAZ }\n    default { return .FOO }\n  }\n}\n\ndef c(x int) Foo {\n  switch x {\n    case 0 { return .BAR }\n    case 1 { return .BAZ }\n    default { return .FOO }\n  }\n}\n\ndef d(x Foo) int {\n  switch x {\n    case .FOO { return 0 }\n    case .BAR { return 1 }\n    case .BAZ { return 2 }\n    default { return 0 }\n  }\n}\n\ndef e(x Foo) int {\n  switch x {\n    case .FOO { return 1 }\n    case .BAR { return 2 }\n    case .BAZ { return 3 }\n    default { return 0 }\n  }\n}\n\ndef f(x Foo) int {\n  switch x {\n    case .BAR { return 0 }\n    case .BAZ { return 1 }\n    default { return 0 }\n  }\n}\n\ndef g(x int) Foo {\n  switch x {\n    case 1 { return .BAR }\n    case 0 { return .FOO }\n    default { return .FOO }\n  }\n}\n\ndef h(x int) Foo {\n  switch x {\n    case 0 { return .BAR }\n    case 1 { return .FOO }\n    default { return .FOO }\n  }\n}\n\ndef i(x int) Foo {\n  switch x {\n    case 0 { return .FOO }\n    case 2 { return .BAZ }\n    default { return .FOO }\n  }\n}\n\n@entry\ndef main {\n  a(0)\n  b(0)\n  c(0)\n  d(.FOO)\n  e(.BAR)\n  f(.BAZ)\n  g(0)\n  h(0)\n  i(0)\n}\n\", \"\n(function() {\n  function b(a) {\n    return a > -1 && a < 3 ? a : 0;\n  }\n\n  function c(a) {\n    return a > 0 && a < 4 ? a - 1 | 0 : 0;\n  }\n\n  function d(a) {\n    return a > -1 && a < 2 ? a + 1 | 0 : 0;\n  }\n\n  function e(a) {\n    return a > -1 && a < 3 ? a : 0;\n  }\n\n  function f(a) {\n    return a > -1 && a < 3 ? a + 1 | 0 : 0;\n  }\n\n  function g(a) {\n    return a > 0 && a < 3 ? a - 1 | 0 : 0;\n  }\n\n  function h(a) {\n    return a > -1 && a < 2 ? a : 0;\n  }\n\n  function i(a) {\n    switch (a) {\n      case 0: {\n        return 1;\n      }\n\n      case 1: {\n        return 0;\n      }\n    }\n\n    return 0;\n  }\n\n  function j(a) {\n    switch (a) {\n      case 0:\n      case 2: {\n        return a;\n      }\n    }\n\n    return 0;\n  }\n\n  function k() {\n    b(0), c(0), d(0), e(0), f(1), g(2), h(0), i(0), j(0);\n  }\n\n  k();\n})();\n\").jsMangle.foldAllConstants\n\n# Check parentheses omission for object creation\ntest(\"\n@entry\ndef main {\n  dynamic.Foo.new()\n  dynamic.Foo.new(100)\n  dynamic.Foo.new().foo\n  dynamic.Foo.new(100).foo\n}\n\", \"\n(function() {\n  function a() {\n    new Foo, new Foo(100), new Foo().foo, new Foo(100).foo;\n  }\n\n  a();\n})();\n\").jsMangle\n\n# Test equivalence of function and lambda folding\ntest(\"\ndef foo(x int) {\n  if x == 0 { return }\n  dynamic.use(x)\n}\n\nvar bar = (x int) => {\n  if x == 0 { return }\n  dynamic.use(x)\n}\n\n@entry\ndef main {\n  foo(0)\n  bar(0)\n}\n\", \"\n(function() {\n  function b(a) {\n    a && use(a);\n  }\n\n  function d() {\n    b(0), c(0);\n  }\n\n  var c = function(a) {\n    a && use(a);\n  };\n\n  d();\n})();\n\").jsMangle\n\ntest(\"\nclass Class {}\nenum Enum {}\ntype Type = int\n\n@entry\ndef main {\n  dynamic.foo(dynamic.bar is dynamic)\n  dynamic.foo(dynamic.bar is fn())\n\n  dynamic.foo(dynamic.bar is bool)\n  dynamic.foo(dynamic.bar is double)\n  dynamic.foo(dynamic.bar is Enum)\n  dynamic.foo(dynamic.bar is int)\n  dynamic.foo(dynamic.bar is Type)\n  dynamic.foo(dynamic.bar is string)\n\n  dynamic.foo(dynamic.bar is Class)\n  dynamic.foo(dynamic.bar is dynamic.Dynamic)\n}\n\", \"\n(function() {\n  var b;\n\n  function f(a) {\n    return a === (a | 0);\n  }\n\n  function g(a) {\n    return a === !!a;\n  }\n\n  function h(a) {\n    return typeof a === 'number';\n  }\n\n  function i(a) {\n    return typeof a === 'string';\n  }\n\n  function j() {\n    foo(bar), foo(bar instanceof Function), foo(g(bar)), foo(h(bar)), foo(f(bar)), foo(f(bar)), foo(f(bar)), foo(i(bar)), foo(bar instanceof c), foo(bar instanceof Dynamic);\n  }\n\n  var c = {};\n  var d = {};\n\n  var e = {};\n\n  j();\n})();\n\").jsMangle\n\n# Test default values for wrapped types\ntest(\"\n@entry\ndef main {\n  var a Bool\n  var b Int\n  var c Double\n  var d String\n  var e Bar\n}\n\ntype Bool = bool\ntype Int = int\ntype Double = double\ntype String = string\ntype Bar = Foo\nenum Foo {}\n\", \"\n(function() {\n  function f() {\n    var a = !1, b = 0, c = 0, d = null, e = 0;\n  }\n\n  f();\n})();\n\").jsMangle\n\n# This used to be a crash during globalization\ntest(\"\nclass Foo {\n  def foo<T>(foo fn(Foo) T) T {\n    return foo(self)\n  }\n}\n\n@entry\ndef main {\n  var foo fn(Foo) dynamic = bar => bar.foo<dynamic>(foo)\n}\n\", \"\n(function() {\n  function d() {\n    var a = function(b) {\n      return c(b, a);\n    };\n  }\n\n  function c(b, a) {\n    return a(b);\n  }\n\n  d();\n})();\n\").jsMangle.globalizeAllFunctions\n\ntest(\"\nclass Foo {}\n\nnamespace Foo {\n  def foo<T>(self Foo, baz fn(Foo) T) T { return baz(self) }\n}\n\n@entry\ndef main {\n  var foo fn(Foo) dynamic = x => Foo.foo<dynamic>(x, foo)\n  foo(Foo.new)\n}\n\", \"\n(function() {\n  function d() {\n    var a = function(b) {\n      return a(b);\n    };\n    a(new c);\n  }\n\n  function c() {\n  }\n\n  d();\n})();\n\").jsMangle.inlineAllFunctions\n\n# There used to be a bug where generic inlineable functions were still emitted\ntest(\"\nclass Foo {\n  var bar List<Foo> = []\n  def foo<T>(baz fn(Foo) T) List<T> { return bar.map<T>(baz) }\n}\n\n@entry\ndef main {\n  var foo fn(Foo) dynamic = bar => bar.foo<dynamic>(foo)\n  foo(Foo.new)\n}\n\", \"\n(function() {\n  function e() {\n    var a = function(c) {\n      return c.a.map(a);\n    };\n    a(new d);\n  }\n\n  function d() {\n    this.a = [];\n  }\n\n  e();\n})();\n\").jsMangle.inlineAllFunctions.globalizeAllFunctions\n\n# Make sure wrapped types are unwrapped before using \"instanceof\"\ntest(\"\nclass Foo {}\ntype Bar = Foo\n\n@entry\ndef main {\n  var foo = Foo.new\n  var bar = foo is Foo || foo is Bar\n}\n\", \"\n(function() {\n  function e() {\n    var a = new b, d = a instanceof b || a instanceof b;\n  }\n\n  function b() {\n  }\n\n  var c = {};\n\n  e();\n})();\n\").jsMangle\n\n# Basic usage of interfaces\ntest(\"\ninterface IFoo {\n  def foo\n}\n\nclass Foo :: IFoo {\n  def foo {}\n}\n\n@entry\ndef main {\n  var foo = Foo.new\n  var ifoo = foo as IFoo\n  foo.foo\n  ifoo.foo\n}\n\", \"\n(function() {\n  function e() {\n    var b = new d, c = b;\n    b.a(), c.a();\n  }\n\n  function d() {\n  }\n\n  d.prototype.a = function() {\n  };\n\n  e();\n})();\n\").jsMangle\n\n# Basic usage of interfaces\ntest(\"\ninterface IFoo {\n  def foo\n}\n\nclass Foo :: IFoo {\n  def foo {}\n}\n\nclass Bar :: IFoo {\n  def foo {}\n}\n\n@entry\ndef main {\n  var foo = Foo.new\n  var bar = Foo.new\n  var ifoo = foo as IFoo\n  foo.foo\n  bar.foo\n  ifoo.foo\n  ifoo = bar\n  ifoo.foo\n}\n\", \"\n(function() {\n  function f() {\n    var c = new e, d = new e, b = c;\n    c.a(), d.a(), b.a(), b = d, b.a();\n  }\n\n  function e() {\n  }\n\n  e.prototype.a = function() {\n  };\n\n  f();\n})();\n\").jsMangle\n\n# Interface removal with globalization\ntest(\"\ninterface IFoo {\n  def foo\n}\n\nclass Foo :: IFoo {\n  def foo {}\n}\n\n@entry\ndef main {\n  var foo = Foo.new\n  var ifoo = foo as IFoo\n  foo.foo\n  ifoo.foo\n}\n\", \"\n(function() {\n  function e() {\n    var b = new d, c = b;\n    a(b), a(c);\n  }\n\n  function a(b) {\n  }\n\n  function d() {\n  }\n\n  e();\n})();\n\").jsMangle.globalizeAllFunctions\n\n# Interface removal should not trigger even with globalization\ntest(\"\ninterface IFoo {\n  def foo\n}\n\nclass Foo :: IFoo {\n  def foo {}\n}\n\nclass Bar :: IFoo {\n  def foo {}\n}\n\n@entry\ndef main {\n  var foo = Foo.new\n  var bar = Bar.new\n  var ifoo = foo as IFoo\n  foo.foo\n  bar.foo\n  ifoo.foo\n  ifoo = bar\n  ifoo.foo\n}\n\", \"\n(function() {\n  function g() {\n    var c = new e, d = new f, b = c;\n    c.a(), d.a(), b.a(), b = d, b.a();\n  }\n\n  function e() {\n  }\n\n  e.prototype.a = function() {\n  };\n\n  function f() {\n  }\n\n  f.prototype.a = function() {\n  };\n\n  g();\n})();\n\").jsMangle.globalizeAllFunctions\n\n# Check overloaded functions when an interface is present\ntest(\"\ninterface I {\n  def foo(x int) # I.foo(x int)\n  def foo(x bool) # I.foo(x bool)\n}\n\nclass Foo :: I {\n  def foo(x int) {} # Foo.foo(x int)\n  def foo(x bool) {} # Foo.foo(x bool)\n}\n\nclass Bar :: I {\n  def foo(x string) {} # Bar.foo(x string)\n  def foo(x int) {} # Bar.foo(x int)\n  def foo(x bool) {} # Bar.foo(x bool)\n}\n\n@entry\ndef main {\n  var foo = Foo.new\n  var bar = Bar.new\n  foo.foo(0)\n  foo.foo(false)\n  bar.foo(0)\n  bar.foo(false)\n}\n\", \"\n(function() {\n  var e;\n\n  function h() {\n    var c = new f, d = new g;\n    c.a(0), c.b(!1), d.a(0), d.b(!1);\n  }\n\n  function f() {\n  }\n\n  e = f.prototype;\n\n  // Foo.foo(x int)\n  e.a = function(c) {\n  };\n\n  // Foo.foo(x bool)\n  e.b = function(c) {\n  };\n\n  function g() {\n  }\n\n  e = g.prototype;\n\n  // Bar.foo(x int)\n  e.a = function(c) {\n  };\n\n  // Bar.foo(x bool)\n  e.b = function(c) {\n  };\n\n  h();\n})();\n\").jsMangle\n\n# Check shortening of long reciprocals\ntest(\"\n@entry\ndef foo {\n  var x = 0\n  var y = 0.3333333333333333 + x * 1.3333333333333333\n}\n\", \"\n(function() {\n  function c() {\n    var a = 0, b = 1 / 3 + a * (4 / 3);\n  }\n\n  c();\n})();\n\").jsMangle\n\n# Check inlining of instance constants\ntest(\"\nclass Foo {\n  const foo = 1\n}\n\n@import\nclass Bar {\n  const bar = 2\n}\n\ndef test(foo Foo, bar Bar) int {\n  return foo.foo + bar.bar\n}\n\n@entry\ndef main {\n  test(null, null)\n}\n\", \"\n(function() {\n  function b(a, c) {\n    return a.a + 2 | 0;\n  }\n\n  function d() {\n    b(null, null);\n  }\n\n  d();\n})();\n\").jsMangle.foldAllConstants\n\n# Check lambda cloning when mangling is active\ntest(\"\nclass Foo {\n  const f = (x int) => x\n  def new {}\n  def new(x int) {}\n}\n\n@entry\ndef main {\n  Foo.new\n  Foo.new(0)\n}\n\", \"\n(function() {\n  function e() {\n    new d, new d.b(0);\n  }\n\n  function d() {\n    this.a = function(a) {\n      return a;\n    };\n  }\n\n  d.b = function(a) {\n    this.a = function(c) {\n      return c;\n    };\n  };\n\n  d.b.prototype = d.prototype;\n\n  e();\n})();\n\").jsMangle\n\n# Basic constant folding check\ntest(\"\nclass Foo {\n  const foo = 0\n}\n\n@entry\ndef main {\n  Foo.new\n}\n\", \"\n(function() {\n  function c() {\n    new b;\n  }\n\n  function b() {\n    this.a = 0;\n  }\n\n  c();\n})();\n\").jsMangle.foldAllConstants\n\n# Check constant folding when the constant is defined in the constructor\ntest(\"\nclass Foo {\n  const foo int\n  def new { foo = 1 }\n}\n\n@entry\ndef main int {\n  var x = Foo.new\n  return x.foo\n}\n\", \"\n(function() {\n  function c() {\n    var a = new b;\n    return a.a;\n  }\n\n  function b() {\n    this.a = 1;\n  }\n\n  process.exit(c());\n})();\n\").jsMangle.foldAllConstants\n\n# Check mangling with typed catch blocks\ntest(\"\nclass Foo {\n}\n\n@entry\ndef main {\n  try {\n    throw Foo.new\n  } catch e Foo {\n    throw e\n  }\n}\n\", \"\n(function() {\n  function c() {\n    try {\n      throw new b;\n    }\n\n    catch (a) {\n      if (a instanceof b) {\n        throw a;\n      }\n\n      else {\n        throw a;\n      }\n    }\n  }\n\n  function b() {\n  }\n\n  c();\n})();\n\").jsMangle\n\n# Check mangling of global variables\ntest(\"\n@export\ndef main double {\n  return a + ns1.b + c + x + ns2.y + z\n}\n\nvar a = 0.0\nnamespace ns1 {\n  var b = 0.0\n}\nvar c = 0.0\n\n@export\nvar x = 0.0\n@export\nnamespace ns2 {\n  var y = 0.0\n}\nvar z = 0.0\n\", \"\n(function(f) {\n  f.main = function() {\n    return a + b + c + f.x + f.ns2.y + d;\n  };\n\n  f.ns2 = {};\n\n  f.x = 0;\n  f.ns2.y = 0;\n  var a = 0, c = 0, d = 0, b = 0;\n})(this);\n\").jsMangle\n\n# Check mangling of hook expressions containing assignments\ntest(\"\nclass Foo {\n  var y Foo = null\n}\n\n@export\ndef test(x Foo) Foo {\n  return (x = x.y) != null ? x : Foo.new\n}\n\", \"\n(function(c) {\n  function b() {\n    this.a = null;\n  }\n\n  c.test = function(a) {\n    return (a = a.a) || new b;\n  };\n})(this);\n\").jsMangle\n\n# Interface removal with an instance variable shouldn't prevent dead code stripping a class constructor\ntest(\"\ninterface IFoo {\n  def foo\n}\n\nclass Foo :: IFoo {\n  const _foo fn(Foo)\n\n  def foo {\n    _foo(self)\n  }\n}\n\n@export\ndef test(foo Foo) {\n  foo.foo\n}\n\", \"\n(function(c) {\n  function b(a) {\n    a.a(a);\n  }\n\n  c.test = function(a) {\n    b(a);\n  };\n})(this);\n\").jsMangle.globalizeAllFunctions\n\n# Check for a crash due to a cast with a resolved type of null after inlining\ntest(\"\nclass Foo {}\n\nnamespace Foo {\n  def new(x bool) Foo {\n    return x as dynamic\n  }\n}\n\n@entry\ndef test {\n  var foo = Foo.new(false)\n}\n\", \"\n(function() {\n  function b() {\n    var a = !1;\n  }\n\n  b();\n})();\n\").jsMangle.inlineAllFunctions\n\n# Check for prototype caching for secondary constructors\ntest(\"\nclass Foo {\n  def new {}\n  def new(x int) {}\n  def foo {}\n}\n\nclass Bar {\n  def new {}\n  def foo {}\n}\n\nclass Baz {\n  def new {}\n  def new(x int) {}\n}\n\n@entry\ndef main {\n  Foo.new.foo\n  Foo.new(0).foo\n  Bar.new.foo\n  Baz.new\n  Baz.new(0)\n}\n\", \"\n(function() {\n  var e;\n\n  function j() {\n    new g().a(), new g.b(0).a(), new h().c(), new i, new i.d(0);\n  }\n\n  function g() {\n  }\n\n  e = g.prototype;\n\n  g.b = function(f) {\n  };\n\n  g.b.prototype = e;\n\n  e.a = function() {\n  };\n\n  function h() {\n  }\n\n  h.prototype.c = function() {\n  };\n\n  function i() {\n  }\n\n  i.d = function(f) {\n  };\n\n  i.d.prototype = i.prototype;\n\n  j();\n})();\n\").jsMangle\n\n# Test assignment collapsing\ntest(\"\ndef foo(a int, b int, c int, f fn() int) {\n  a = 1\n  b = 1\n  c = 1\n\n  a = 1\n  b = 2\n  c = 3\n\n  a = f()\n  b = f()\n  c = f()\n}\n\ndef bar(a dynamic, f fn() int) {\n  a[0] = 1\n  a[1] = 1\n  a[2] = 1\n\n  a[0] = 1\n  a[1] = 2\n  a[2] = 3\n\n  a[0] = f()\n  a[1] = f()\n  a[2] = f()\n}\n\ndef baz(a dynamic, f fn() int) {\n  a.x = 1\n  a[1] = 1\n  a[\\\"y\\\"] = 1\n\n  a.x = 1\n  a[1] = 2\n  a[\\\"y\\\"] = 3\n\n  a.x = f()\n  a[1] = f()\n  a[\\\"y\\\"] = f()\n}\n\n@entry\ndef main {\n  foo(0, 0, 0, null)\n  bar(0, null)\n  baz(0, null)\n}\n\", \"\n(function() {\n  function e(a, b, c, d) {\n    a = 1, b = 1, c = 1, a = 1, b = 2, c = 3, a = d(), b = d(), c = d();\n  }\n\n  function f(a, b) {\n    a[0] = 1, a[1] = 1, a[2] = 1, a[0] = 1, a[1] = 2, a[2] = 3, a[0] = b(), a[1] = b(), a[2] = b();\n  }\n\n  function g(a, b) {\n    a.x = 1, a[1] = 1, a.y = 1, a.x = 1, a[1] = 2, a.y = 3, a.x = b(), a[1] = b(), a.y = b();\n  }\n\n  function h() {\n    e(0, 0, 0, null), f(0, null), g(0, null);\n  }\n\n  h();\n})();\n\").jsMangle\n\n# Test that the number shorterer that turns \"33554432\" into \"1 << 25\" doesn't cause a crash for enum values\ntest(\"\nflags Foo {\n  A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z\n}\n\n@entry\ndef test int {\n  return Foo.Z\n}\n\", \"\n(function() {\n  function c() {\n    return b.a;\n  }\n\n  var b = {\n    a: 1 << 25\n  };\n\n  process.exit(c());\n})();\n\").jsMangle\n\n# Check that int casts aren't inserted when != turns into ^\ntest(\"\n@entry\ndef test {\n  var a = 0, b = 0, c = 0, d = 0\n  while a - b != c - d {}\n  while ((a - b) ^ (c - d)) != 0 {}\n  while (a - b | 0) != (c - d | 0) {}\n  while (a - b | 1) != (c - d | 1) {}\n}\n\", \"\n(function() {\n  function e() {\n    for (var a = 0, b = 0, c = 0, d = 0; a - b ^ c - d;) {\n    }\n\n    for (; a - b ^ c - d;) {\n    }\n\n    for (; a - b ^ c - d;) {\n    }\n\n    for (; (a - b | 1) ^ (c - d | 1);) {\n    }\n  }\n\n  e();\n})();\n\").jsMangle\n\n# Check mangled map constructors\ntest(\"\n@entry\ndef test {\n  var a = {1: 2, 3: 4}\n  var b = {\\\"1\\\": 2, \\\"3\\\": 4}\n}\n\", \"\n(function() {\n  function f() {\n    var d = c(c(new Map, 1, 2), 3, 4), e = b(b(new Map, '1', 2), '3', 4);\n  }\n\n  function b(a, d, e) {\n    return a.set(d, e), a;\n  }\n\n  function c(a, d, e) {\n    return a.set(d, e), a;\n  }\n\n  f();\n})();\n\").jsMangle.inlineAllFunctions\n\n# Check export syntax\ntest(\"\n@export {\n  class Class { def foo { new } }\n  enum Enum { def toString { Namespace.foo } }\n  namespace Namespace { def foo { (0 as Enum).toString } }\n  def Function {}\n  var Variable = 0\n}\n\", \"\n(function(c) {\n  var b = {};\n\n  b.toString = function(a) {\n    c.Namespace.foo();\n  };\n\n  c.Function = function() {\n  };\n\n  c.Class = function() {\n  };\n\n  c.Class.prototype.foo = function() {\n    new c.Class;\n  };\n\n  c.Enum = {};\n\n  c.Namespace = {};\n\n  c.Namespace.foo = function() {\n    b.toString(0);\n  };\n\n  c.Variable = 0;\n})(this);\n\").jsMangle\n\n# Check parenthesis removal for new expressions in cast expressions\ntest(\"\n@export\ndef foo dynamic {\n  return (dynamic.Foo.new as dynamic).foo\n}\n\", \"\n(function(a) {\n  a.foo = function() {\n    return new Foo().foo;\n  };\n})(this);\n\").jsMangle\n\n# Check parenthesis removal for new expressions in parameterized expressions\ntest(\"\n@export\ndef foo dynamic {\n  return dynamic.Foo.new<int>.foo\n}\n\", \"\n(function(c) {\n  var a;\n\n  c.foo = function() {\n    return new Foo().foo;\n  };\n})(this);\n\").jsMangle\n\ntest(\"\n@entry\ndef main int {\n  var x dynamic = 1\n  x = x + 1\n  x = x + 1\n  return x\n}\n\", \"\n(function() {\n  function b() {\n    var a = 1;\n    return a = a + 1, a = a + 1, a;\n  }\n\n  process.exit(b());\n})();\n\").jsMangle\n\ntest(\"\n@entry\ndef main int {\n  var x = 1\n  x++\n  x++\n  return x\n}\n\", \"\n(function() {\n  function b() {\n    var a = 1;\n    return a = a + 1 | 0, a = a + 1 | 0, a;\n  }\n\n  process.exit(b());\n})();\n\").jsMangle\n\ntest(\"\nclass Foo {\n  var value double\n}\n\n@export\ndef main double {\n  var x = Foo.new(1)\n  var y = x\n  x.value = y.value + 1\n  x.value = y.value + 1\n  return x.value\n}\n\", \"\n(function(d) {\n  function c(a) {\n    this.a = a;\n  }\n\n  d.main = function() {\n    var a = new c(1), b = a;\n    return a.a = b.a + 1, a.a = b.a + 1, a.a;\n  };\n})(this);\n\").jsMangle\n\ntest(\"\n@entry\ndef main int {\n  var x dynamic = [1]\n  var y = x\n  x[0] = y[0] + 1\n  x[0] = y[0] + 1\n  return x[0]\n}\n\", \"\n(function() {\n  function c() {\n    var a = [1], b = a;\n    return a[0] = b[0] + 1, a[0] = b[0] + 1, a[0];\n  }\n\n  process.exit(c());\n})();\n\").jsMangle\n\n# Check block comments before a statement\ntest(\"\n@entry\ndef main {\n  # This is\n  # a block\n  # comment\n\n  return\n}\n\", \"\n(function() {\n  function a() {\n    // This is\n    // a block\n    // comment\n\n    return;\n  }\n\n  a();\n})();\n\").jsMangle\n\n# Check trailing block comments\ntest(\"\n@entry\ndef main {\n  # This is\n  # a block\n  # comment\n}\n\", \"\n(function() {\n  function a() {\n  }\n\n  a();\n})();\n\").jsMangle\n\n# Check block comments in else statements\ntest(\"\n@export\ndef main(x bool) {\n  if x {\n    x = false\n  } else {\n    # This is\n    # a block\n    # comment\n  }\n}\n\", \"\n(function(b) {\n  b.main = function(a) {\n    a && (a = !1);\n  };\n})(this);\n\").jsMangle\n\n  }\n}\n"
  },
  {
    "path": "tests/javascript.minify.sk",
    "content": "namespace Skew.Tests {\n  def testJavaScriptMinify {\n\n# Strings should be emitted using the shortest representation\ntest(\"\n@entry\ndef main {\n  dynamic.a(\\\"'\\\" + \\\"\\\\\\\"\\\")\n}\n\", \"\n(function(){function main(){a(\\\"'\\\"+'\\\"')}main()})();\n\").jsMinify\n\n# Check for various whitespace issues\ntest(\"\ndef foo dynamic {\n  dynamic.a(dynamic.b + +dynamic.c)\n  dynamic.a(dynamic.b + -dynamic.c)\n  dynamic.a(dynamic.b - +dynamic.c)\n  dynamic.a(dynamic.b - -dynamic.c)\n  return \\\"\\\"\n  return dynamic.a\n  return dynamic.a + dynamic.b\n  return -dynamic.a\n  return ~dynamic.a\n  return !dynamic.a\n  return []\n  return {}\n}\n\n@entry\ndef main {\n  foo\n}\n\", \"\n(function(){function foo(){a(b+ +c);a(b+-c);a(b-+c);a(b- -c);return'';return a;return a+b;return-a;return~a;return!a;return[];return{}}function main(){foo()}main()})();\n\").jsMinify\n\n# Check for whitespace with numeric literals\ntest(\"\ndef foo dynamic {\n  return -1\n}\n\ndef bar dynamic {\n  return -1.5\n}\n\ndef baz dynamic {\n  return 0\n}\n\n@entry\ndef main {\n  foo\n  bar\n  baz\n}\n\", \"\n(function(){function foo(){return-1}function bar(){return-1.5}function baz(){return 0}function main(){foo();bar();baz()}main()})();\n\").jsMinify.foldAllConstants\n\n# Check for omitting the leading zero\ntest(\"\n@entry\ndef foo {\n  var x = [-1.5, -1.0, -0.5, -0.0, 0.0, 0.5, 1.0, 1.5]\n}\n\", \"\n(function(){function foo(){var x=[-1.5,-1,-.5,0,0,.5,1,1.5]}foo()})();\n\").jsMinify.foldAllConstants\n\n# There is no \"dangling if\" ambiguity here\ntest(\"\n@entry\ndef main {\n  if dynamic.a() {\n    if dynamic.b() {\n      var c = dynamic.d()\n      dynamic.e(c, c)\n    } else {\n      var f = dynamic.g()\n      dynamic.h(f, f)\n    }\n  } else {\n    dynamic.i()\n  }\n}\n\", \"\n(function(){function main(){if(a()){if(b()){var c=d();e(c,c)}else{var f=g();h(f,f)}}else i()}main()})();\n\").jsMinify\n\n# This must be careful about the \"dangling if\" ambiguity\ntest(\"\n@entry\ndef main {\n  if dynamic.a() {\n    if dynamic.b() {\n      if dynamic.c() {\n        var d = dynamic.e()\n        dynamic.f(d, d)\n      } else {\n        var g = dynamic.h()\n        dynamic.i(g, g)\n      }\n    }\n  } else {\n    dynamic.j()\n  }\n}\n\", \"\n(function(){function main(){if(a()){if(b())if(c()){var d=e();f(d,d)}else{var g=h();i(g,g)}}else j()}main()})();\n\").jsMinify\n\n# Another \"dangling if\" variant\ntest(\"\n@entry\ndef main {\n  if dynamic.a() {\n    if dynamic.b() {\n      var c = dynamic.d()\n      dynamic.e(c, c)\n    } else if dynamic.f() {\n      var g = dynamic.h()\n      dynamic.i(g, g)\n    }\n  } else {\n    var j = dynamic.k()\n    dynamic.l(j, j)\n  }\n}\n\", \"\n(function(){function main(){if(a()){if(b()){var c=d();e(c,c)}else if(f()){var g=h();i(g,g)}}else{var j=k();l(j,j)}}main()})();\n\").jsMinify\n\n# A tricky \"dangling if\" issue\ntest(\"\n@entry\ndef main {\n  if dynamic.a() {\n    while true {\n      if dynamic.b() { break }\n    }\n  } else {\n    dynamic.c()\n  }\n}\n\", \"\n(function(){function main(){if(a()){while(true)if(b())break}else c()}main()})();\n\").jsMinify\n\n# Check that minification doesn't remove constants in switch statements unless necessary\ntest(\"\n@export\nconst C = 2\n\n@export\ndef main(x int, y Foo) {\n  switch x {\n    case C { dynamic.a() }\n    case C + 3 { dynamic.a() }\n  }\n  switch y { case .FOO { dynamic.b() } }\n}\n\nenum Foo { FOO }\n\", \"\n(function(exports){var Foo={FOO:0};exports.main=function(x,y){switch(x){case exports.C:a();break;case 5:a();break}switch(y){case Foo.FOO:b();break}};exports.C=2})(this);\n\").jsMinify\n\ntest(\"\ndef foo string {\n  return 0.toString\n}\n\n@entry\ndef main {\n  foo\n}\n\", \"\n(function(){function foo(){return (0).toString()}function main(){foo()}main()})();\n\").jsMinify\n\n# Make sure null is allowed to convert to string\ntest(\"\ndef foo string {\n  return null\n}\n\n@entry\ndef main {\n  foo\n}\n\", \"\n(function(){function foo(){return null}function main(){foo()}main()})();\n\").jsMinify\n\n# Avoid a space after \"case\" if possible\ntest(\"\n@entry\ndef main {\n  var x = \\\"\\\"\n  switch x {\n    case \\\"x\\\" {}\n    case x {}\n  }\n}\n\", \"\n(function(){function main(){var x='';switch(x){case'x':break;case x:break}}main()})();\n\").jsMinify\n\n# Check complex post-keyword space removal\ntest(\"\n@entry\ndef main int {\n  var x = 0\n  if x == -1 { dynamic.foo() }\n  else { dynamic.bar() }\n  return 0\n}\n\", \"\n(function(){function b(){var a=0;return~a?bar():foo(),0}process.exit(b())})();\n\").jsMinify.jsMangle\n\n# Check nested negation minification\ntest(\"\n@entry\ndef main {\n  var x = 0.0\n  var y = x - (-x) * 2 + x + (-x) * 2\n}\n\", \"\n(function(){function main(){var x=0;var y=x- -x*2+x+-x*2}main()})();\n\").jsMinify\n\n# Check nested negation minification\ntest(\"\n@entry\ndef main {\n  var x = dynamic.z as double\n  var y = x - (-2) * 2 + x + (-2) * 2\n}\n\", \"\n(function(){function main(){var x=+z;var y=x- -4+x+-4}main()})();\n\").jsMinify.foldAllConstants\n\n# Remove the space before the \"in\" operator\ntest(\"\n@entry\ndef test {\n  dynamic.foo(dynamic.x in dynamic.y)\n  dynamic.foo(\\\"x\\\" in dynamic.y)\n}\n\", \"\n(function(){function test(){foo(x in y);foo('x'in y)}test()})();\n\").jsMinify\n\n# Check block comments before a statement\ntest(\"\n@entry\ndef main {\n  # This is\n  # a block\n  # comment\n\n  return\n}\n\", \"\n(function(){function main(){return}main()})();\n\").jsMinify\n\n# Check trailing block comments\ntest(\"\n@entry\ndef main {\n  # This is\n  # a block\n  # comment\n}\n\", \"\n(function(){function main(){}main()})();\n\").jsMinify\n\n# Check block comments in else statements\ntest(\"\n@export\ndef main(x bool) {\n  if x {\n    x = false\n  } else {\n    # This is\n    # a block\n    # comment\n  }\n}\n\", \"\n(function(exports){exports.main=function(x){if(x)x=false;else{}}})(this);\n\").jsMinify\n\n  }\n}\n"
  },
  {
    "path": "tests/javascript.sk",
    "content": "namespace Skew.Tests {\n  def testJavaScript {\n\n# Check special cases for keyword operators\ntest(\"\n@entry\ndef main {\n  dynamic.foo(dynamic.void(0))\n  dynamic.foo(dynamic.typeof(0))\n  dynamic.foo(dynamic.typeof(0).length)\n  dynamic.foo(dynamic.delete(dynamic.foo.bar))\n}\n\", \"\n(function() {\n  function main() {\n    foo(void 0);\n    foo(typeof 0);\n    foo((typeof 0).length);\n    foo(delete foo.bar);\n  }\n\n  main();\n})();\n\").js\n\n# Check primitive casting for dynamic values\ntest(\"\n@entry\ndef test {\n  dynamic.foo(dynamic.x as bool)\n  dynamic.foo(dynamic.x as int)\n  dynamic.foo(dynamic.x as double)\n  dynamic.foo(dynamic.x as string)\n}\n\", \"\n(function() {\n  function __asString(value) {\n    return value === null ? value : value + '';\n  }\n\n  function test() {\n    foo(!!x);\n    foo(x | 0);\n    foo(+x);\n    foo(__asString(x));\n  }\n\n  test();\n})();\n\").js\n\n# Dynamic base classes should still work\ntest(\"\n@export\nclass DerivedClass : dynamic.BaseClass {}\n\", \"\n(function(exports) {\n  var __create = Object.create ? Object.create : function(prototype) {\n    return {'__proto__': prototype};\n  };\n\n  function __extends(derived, base) {\n    derived.prototype = __create(base.prototype);\n    derived.prototype.constructor = derived;\n  }\n\n  exports.DerivedClass = function() {\n  };\n\n  __extends(exports.DerivedClass, BaseClass);\n})(this);\n\").js\n\n# Make sure classes with unused constructors are still emitted\ntest(\"\nclass A.B.C {}\n\nnamespace A.B.C {\n  def foo {}\n}\n\nnamespace D.E.F {\n  def foo {}\n}\n\n@entry\ndef main {\n  A.B.C.foo\n  D.E.F.foo\n}\n\", \"\n(function() {\n  function main() {\n    A.B.C.foo();\n    D.E.F.foo();\n  }\n\n  var A = {};\n  A.B = {};\n  A.B.C = {};\n  A.B.C.foo = function() {\n  };\n\n  var D = {};\n  D.E = {};\n  D.E.F = {};\n\n  D.E.F.foo = function() {\n  };\n\n  main();\n})();\n\").js\n\n# Check renaming across inherited scopes\ntest(\"\nclass Foo {\n  def foo(x int) {} # Foo.foo(x int)\n  def foo(x bool) {} # Foo.foo(x bool)\n}\n\nclass Bar : Foo {\n  def foo1(x string) {} # Bar.foo1(x string)\n  over foo(x int) {} # Bar.foo(x int)\n}\n\n@entry\ndef main {\n  var foo = Foo.new\n  var bar = Bar.new\n  foo.foo(0)\n  foo.foo(false)\n  bar.foo(0)\n  bar.foo1(null)\n}\n\", \"\n(function() {\n  var __create = Object.create ? Object.create : function(prototype) {\n    return {'__proto__': prototype};\n  };\n\n  function __extends(derived, base) {\n    derived.prototype = __create(base.prototype);\n    derived.prototype.constructor = derived;\n  }\n\n  function main() {\n    var foo = new Foo();\n    var bar = new Bar();\n    foo.foo2(0);\n    foo.foo1(false);\n    bar.foo2(0);\n    bar.foo1(null);\n  }\n\n  function Foo() {\n  }\n\n  // Foo.foo(x int)\n  Foo.prototype.foo2 = function(x) {\n  };\n\n  // Foo.foo(x bool)\n  Foo.prototype.foo1 = function(x) {\n  };\n\n  function Bar() {\n    Foo.call(this);\n  }\n\n  __extends(Bar, Foo);\n\n  // Bar.foo1(x string)\n  Bar.prototype.foo1 = function(x) {\n  };\n\n  // Bar.foo(x int)\n  Bar.prototype.foo2 = function(x) {\n  };\n\n  main();\n})();\n\").js\n\n# Check overloaded functions with identical names across types\ntest(\"\nclass Foo {\n  def foo(x int) {} # Foo.foo(x int)\n  def foo(x bool) {} # Foo.foo(x bool)\n}\n\nclass Bar {\n  def foo(x string) {} # Bar.foo(x string)\n  def foo(x int) {} # Bar.foo(x int)\n  def foo(x bool) {} # Bar.foo(x bool)\n}\n\n@entry\ndef main {\n  var foo = Foo.new\n  var bar = Bar.new\n  foo.foo(0)\n  foo.foo(false)\n  bar.foo(0)\n  bar.foo(false)\n}\n\", \"\n(function() {\n  function main() {\n    var foo = new Foo();\n    var bar = new Bar();\n    foo.foo1(0);\n    foo.foo2(false);\n    bar.foo2(0);\n    bar.foo3(false);\n  }\n\n  function Foo() {\n  }\n\n  // Foo.foo(x int)\n  Foo.prototype.foo1 = function(x) {\n  };\n\n  // Foo.foo(x bool)\n  Foo.prototype.foo2 = function(x) {\n  };\n\n  function Bar() {\n  }\n\n  // Bar.foo(x int)\n  Bar.prototype.foo2 = function(x) {\n  };\n\n  // Bar.foo(x bool)\n  Bar.prototype.foo3 = function(x) {\n  };\n\n  main();\n})();\n\").js\n\n# Check overloaded functions when an interface is present\ntest(\"\ninterface I {\n  def foo(x int) # I.foo(x int)\n  def foo(x bool) # I.foo(x bool)\n}\n\nclass Foo :: I {\n  def foo(x int) {} # Foo.foo(x int)\n  def foo(x bool) {} # Foo.foo(x bool)\n}\n\nclass Bar :: I {\n  def foo(x string) {} # Bar.foo(x string)\n  def foo(x int) {} # Bar.foo(x int)\n  def foo(x bool) {} # Bar.foo(x bool)\n}\n\n@entry\ndef main {\n  var foo = Foo.new\n  var bar = Bar.new\n  foo.foo(0)\n  foo.foo(false)\n  bar.foo(0)\n  bar.foo(false)\n}\n\", \"\n(function() {\n  function main() {\n    var foo = new Foo();\n    var bar = new Bar();\n    foo.foo2(0);\n    foo.foo3(false);\n    bar.foo2(0);\n    bar.foo3(false);\n  }\n\n  function Foo() {\n  }\n\n  // Foo.foo(x int)\n  Foo.prototype.foo2 = function(x) {\n  };\n\n  // Foo.foo(x bool)\n  Foo.prototype.foo3 = function(x) {\n  };\n\n  function Bar() {\n  }\n\n  // Bar.foo(x int)\n  Bar.prototype.foo2 = function(x) {\n  };\n\n  // Bar.foo(x bool)\n  Bar.prototype.foo3 = function(x) {\n  };\n\n  main();\n})();\n\").js.globalizeAllFunctions\n\n# Interface removal with globalization\ntest(\"\ninterface IFoo {\n  def foo\n}\n\nnamespace IFoo {\n  const FOO = 0\n}\n\nclass Foo :: IFoo {\n  def foo {}\n}\n\n@entry\ndef main int {\n  var foo = Foo.new\n  var ifoo = foo as IFoo\n  foo.foo\n  ifoo.foo\n  return IFoo.FOO\n}\n\", \"\n(function() {\n  function main() {\n    var foo = new Foo();\n    var ifoo = foo;\n    Foo.foo(foo);\n    Foo.foo(ifoo);\n    return Foo.FOO;\n  }\n\n  function Foo() {\n  }\n\n  Foo.foo = function(self) {\n  };\n\n  Foo.FOO = 0;\n\n  process.exit(main());\n})();\n\").js.globalizeAllFunctions\n\n# Interface removal should not trigger even with globalization\ntest(\"\ninterface IFoo {\n  def foo\n}\n\nnamespace IFoo {\n  const FOO = 0\n}\n\nclass Foo :: IFoo {\n  def foo {}\n}\n\nclass Bar :: IFoo {\n  def foo {}\n}\n\n@entry\ndef main int {\n  var foo = Foo.new\n  var bar = Bar.new\n  var ifoo = foo as IFoo\n  foo.foo\n  bar.foo\n  ifoo.foo\n  ifoo = bar\n  ifoo.foo\n  return IFoo.FOO\n}\n\", \"\n(function() {\n  function main() {\n    var foo = new Foo();\n    var bar = new Bar();\n    var ifoo = foo;\n    foo.foo();\n    bar.foo();\n    ifoo.foo();\n    ifoo = bar;\n    ifoo.foo();\n    return in_IFoo.FOO;\n  }\n\n  function Foo() {\n  }\n\n  Foo.prototype.foo = function() {\n  };\n\n  function Bar() {\n  }\n\n  Bar.prototype.foo = function() {\n  };\n\n  var in_IFoo = {};\n\n  in_IFoo.FOO = 0;\n\n  process.exit(main());\n})();\n\").js.globalizeAllFunctions\n\n# Check interface removal with an inlineable function\ntest(\"\n@entry\ndef main int {\n  var ifoo IFoo = Foo.new(0)\n  return ifoo.x\n}\n\nclass Foo :: IFoo {\n  var _x int\n  def x int { return _x }\n}\n\ninterface IFoo {\n  def x int\n}\n\", \"\n(function() {\n  function main() {\n    var ifoo = new Foo(0);\n    return ifoo.x();\n  }\n\n  function Foo(_x) {\n    this._x = _x;\n  }\n\n  Foo.prototype.x = function() {\n    return this._x;\n  };\n\n  process.exit(main());\n})();\n\").js\n\n# Check interface removal with an inlineable function\ntest(\"\n@entry\ndef main int {\n  var ifoo IFoo = Foo.new(0)\n  return ifoo.x\n}\n\nclass Foo :: IFoo {\n  var _x int\n  def x int { return _x }\n}\n\ninterface IFoo {\n  def x int\n}\n\", \"\n(function() {\n  function main() {\n    var ifoo = new Foo(0);\n    return Foo.x(ifoo);\n  }\n\n  function Foo(_x) {\n    this._x = _x;\n  }\n\n  Foo.x = function(self) {\n    return self._x;\n  };\n\n  process.exit(main());\n})();\n\").js.globalizeAllFunctions\n\n# Check interface removal with an inlineable function\ntest(\"\n@entry\ndef main int {\n  var ifoo IFoo = Foo.new(0)\n  return ifoo.x\n}\n\nclass Foo :: IFoo {\n  var _x int\n  def x int { return _x }\n}\n\ninterface IFoo {\n  def x int\n}\n\", \"\n(function() {\n  function main() {\n    var ifoo = new Foo(0);\n    return ifoo._x;\n  }\n\n  function Foo(_x) {\n    this._x = _x;\n  }\n\n  process.exit(main());\n})();\n\").js.globalizeAllFunctions.inlineAllFunctions\n\n# Conflicting rename annotations should be an error\ntest(\"\nclass Foo {\n  @rename(\\\"a\\\")\n  def foo\n}\n\nclass Bar : Foo {\n  @rename(\\\"b\\\")\n  over foo\n}\n\", \"\n<stdin>:8:8: error: Cannot rename \\\"foo\\\" to both \\\"a\\\" and \\\"b\\\"\n  over foo\n       ~~~\n\").js\n\n# Check map literal inlining\ntest(\"\n@entry\ndef main {\n  dynamic.bar(foo(foo([], 1, 2), \\\"3\\\", \\\"4\\\"))\n}\n\ndef foo(map dynamic, key dynamic, value dynamic) dynamic {\n  map[key] = value\n  return map\n}\n\", \"\n(function() {\n  function main() {\n    bar(foo(foo([], 1, 2), '3', '4'));\n  }\n\n  function foo(map, key, value) {\n    map[key] = value;\n    return map;\n  }\n\n  main();\n})();\n\").js.inlineAllFunctions\n\n# Check map literal inlining\ntest(\"\n@entry\ndef main {\n  dynamic.bar(foo(foo({}, 1, 2), \\\"3\\\", \\\"4\\\"))\n}\n\ndef foo(map dynamic, key dynamic, value dynamic) dynamic {\n  map[key] = value\n  return map\n}\n\", \"\n(function() {\n  function main() {\n    bar({1: 2, '3': '4'});\n  }\n\n  main();\n})();\n\").js.inlineAllFunctions\n\n# Check map literal inlining\ntest(\"\ndef foo<T>(map IntMap<T>, key int, value T) IntMap<T> {\n  map[key] = value\n  return map\n}\n\n@entry\ndef main {\n  dynamic.bar(foo<int>(foo<int>({}, 1, 2), 3, 4))\n}\n\", \"\n(function() {\n  function foo(map, key, value) {\n    in_IntMap.set(map, key, value);\n    return map;\n  }\n\n  function main() {\n    bar(foo(foo(new Map(), 1, 2), 3, 4));\n  }\n\n  var in_IntMap = {};\n\n  in_IntMap.set = function(self, key, value) {\n    self.set(key, value);\n    return value;\n  };\n\n  main();\n})();\n\").js.inlineAllFunctions\n\n# Check map literal inlining\ntest(\"\n@entry\ndef main {\n  var x = 0\n  dynamic.bar(foo(foo(foo(foo({}, 1, 2), 3, 4), x, 5), 6, 7))\n}\n\ndef foo(map dynamic, key int, value int) dynamic {\n  map[key] = value\n  return map\n}\n\", \"\n(function() {\n  function main() {\n    var x = 0;\n    bar(foo(foo({1: 2, 3: 4}, x, 5), 6, 7));\n  }\n\n  function foo(map, key, value) {\n    map[key] = value;\n    return map;\n  }\n\n  main();\n})();\n\").js.inlineAllFunctions\n\n# Check map literal inlining\ntest(\"\n@entry\ndef main {\n  var x = 0\n  dynamic.bar({1: 2, 3: 4, x: 5, 6: 7} as Foo)\n}\n\n@import\nclass Foo {\n  def []=(key int, value int) {\n    (self as dynamic)[key] = value\n  }\n\n  def {...}(key int, value int) Foo {\n    self[key] = value\n    return self\n  }\n}\n\nnamespace Foo {\n  def new Foo {\n    return {} as dynamic\n  }\n}\n\", \"\n(function() {\n  function main() {\n    var x = 0;\n    bar(in_Foo.insert(in_Foo.insert({1: 2, 3: 4}, x, 5), 6, 7));\n  }\n\n  var in_Foo = {};\n\n  in_Foo.insert = function(self, key, value) {\n    self[key] = value;\n    return self;\n  };\n\n  main();\n})();\n\").js.inlineAllFunctions\n\n# Check list literal inlining\ntest(\"\n@entry\ndef main {\n  dynamic.bar(foo(foo([], 1), 2))\n}\n\ndef foo(list dynamic, value dynamic) dynamic {\n  list.push(value)\n  return list\n}\n\", \"\n(function() {\n  function main() {\n    bar([1, 2]);\n  }\n\n  main();\n})();\n\").js.inlineAllFunctions\n\n# Check list literal inlining\ntest(\"\n@entry\ndef main {\n  dynamic.bar(foo(foo([], 1), 2))\n}\n\ndef foo(list dynamic, value dynamic) dynamic {\n  list.unshift(value)\n  return list\n}\n\", \"\n(function() {\n  function main() {\n    bar(foo(foo([], 1), 2));\n  }\n\n  function foo(list, value) {\n    list.unshift(value);\n    return list;\n  }\n\n  main();\n})();\n\").js.inlineAllFunctions\n\n# Check list literal inlining\ntest(\"\n@entry\ndef main {\n  dynamic.bar(foo(foo({}, 1), 2))\n}\n\ndef foo(list dynamic, value dynamic) dynamic {\n  list.push(value)\n  return list\n}\n\", \"\n(function() {\n  function main() {\n    bar(foo(foo({}, 1), 2));\n  }\n\n  function foo(list, value) {\n    list.push(value);\n    return list;\n  }\n\n  main();\n})();\n\").js.inlineAllFunctions\n\n# Check list literal inlining\ntest(\"\n@entry\ndef main {\n  var x = 0\n  dynamic.bar([1, \\\"2\\\", x, false] as Foo)\n}\n\n@import\nclass Foo {\n  def append(value dynamic) {\n    (self as dynamic).push(value)\n  }\n\n  def [...](value dynamic) Foo {\n    append(value)\n    return self\n  }\n}\n\nnamespace Foo {\n  def new Foo {\n    return [] as dynamic\n  }\n}\n\", \"\n(function() {\n  function main() {\n    var x = 0;\n    bar([1, '2', x, false]);\n  }\n\n  main();\n})();\n\").js.inlineAllFunctions\n\n# Check that order doesn't matter when inlining list literals\ntest(\"\n@import\nclass Foo {\n  def [...](value int) Foo {\n    (self as dynamic).push(value)\n    return self\n  }\n\n  def [...](value bool) Foo {\n    (self as dynamic).push(value)\n    return self\n  }\n}\n\nnamespace Foo {\n  def [new] Foo {\n    return [] as dynamic\n  }\n}\n\n@entry\ndef main {\n  [1, false] as Foo\n}\n\", \"\n(function() {\n  function main() {\n    [1, false];\n  }\n\n  main();\n})();\n\").js.inlineAllFunctions\n\n# Check that order doesn't matter when inlining list literals\ntest(\"\n@import\nclass Foo {\n  def [...](value bool) Foo {\n    (self as dynamic).push(value)\n    return self\n  }\n\n  def [...](value int) Foo {\n    (self as dynamic).push(value)\n    return self\n  }\n}\n\nnamespace Foo {\n  def [new] Foo {\n    return [] as dynamic\n  }\n}\n\n@entry\ndef main {\n  [1, false] as Foo\n}\n\", \"\n(function() {\n  function main() {\n    [1, false];\n  }\n\n  main();\n})();\n\").js.inlineAllFunctions\n\n# Check for a bug where merged functions weren't emitted sometimes\ntest(\"\nclass Bar : Foo {\n}\n\nclass Foo {\n  def foo\n  def foo {}\n}\n\n@entry\ndef main {\n  Foo.new.foo\n}\n\", \"\n(function() {\n  function main() {\n    new Foo().foo();\n  }\n\n  function Foo() {\n  }\n\n  Foo.prototype.foo = function() {\n  };\n\n  main();\n})();\n\").js\n\n# Check for a bug where merged functions weren't emitted sometimes\ntest(\"\nclass Foo {\n  def foo\n  def foo {}\n}\n\nclass Bar : Foo {\n}\n\n@entry\ndef main {\n  Foo.new.foo\n}\n\", \"\n(function() {\n  function main() {\n    new Foo().foo();\n  }\n\n  function Foo() {\n  }\n\n  Foo.prototype.foo = function() {\n  };\n\n  main();\n})();\n\").js\n\n# Implemented instance functions should be pulled off of interfaces\ntest(\"\nclass Foo :: IFoo {\n  def foo {}\n}\n\ninterface IFoo {\n  def bar {}\n}\n\n@entry\ndef main {\n  var foo = Foo.new\n  var ifoo = foo as IFoo\n  foo.foo\n  ifoo.bar\n}\n\", \"\n(function() {\n  function main() {\n    var foo = new Foo();\n    var ifoo = foo;\n    foo.foo();\n    in_IFoo.bar(ifoo);\n  }\n\n  function Foo() {\n  }\n\n  Foo.prototype.foo = function() {\n  };\n\n  var in_IFoo = {};\n\n  in_IFoo.bar = function(self) {\n  };\n\n  main();\n})();\n\").js\n\n# Check folding of the \"**\" operator\ntest(\"\n@entry\ndef main {\n  var x dynamic = [\n    2 ** 2,\n    2 ** 3,\n    3 ** 2,\n    2 ** 0,\n    2 ** -2,\n    0.25 ** 0.5,\n    Math.pow(0.25, 0.5),\n  ]\n}\n\", \"\n(function() {\n  function main() {\n    var x = [4, 8, 9, 1, 0, 0.5, 0.5];\n  }\n\n  main();\n})();\n\").js.foldAllConstants\n\n# Make sure variable initialization works with multiple user-defined constructors\ntest(\"\nclass Foo {\n  var foo = \\\"\\\"\n  var bar = [1, 2, 3]\n  def new {}\n  def new(x int) {}\n}\n\n@entry\ndef main {\n  Foo.new\n  Foo.new(1)\n}\n\", \"\n(function() {\n  function main() {\n    new Foo();\n    new Foo.new2(1);\n  }\n\n  function Foo() {\n    this.foo = '';\n    this.bar = [1, 2, 3];\n  }\n\n  Foo.new2 = function(x) {\n    this.foo = '';\n    this.bar = [1, 2, 3];\n  };\n\n  Foo.new2.prototype = Foo.prototype;\n\n  main();\n})();\n\").js\n\n# Make sure constant folding of compile-time guards doesn't change code emission of the variables involved\ntest(\"\nenum Foo { FOO }\nif BAR == 0 {\n  @export\n  def main {}\n}\n@export\nconst BAR = Foo.FOO\n\", \"\n(function(exports) {\n  var Foo = {\n    FOO: 0\n  };\n\n  exports.main = function() {\n  };\n\n  exports.BAR = Foo.FOO;\n})(this);\n\").js\n\n# Check for integer casting\ntest(\"\n@entry\ndef main {\n  var x = 0\n  dynamic.foo(x + 1)\n  dynamic.foo(x - 1)\n  dynamic.foo(x * 2)\n  dynamic.foo(x / 2)\n  dynamic.foo(x % 2)\n  dynamic.foo(x % 0)\n  dynamic.foo(x % x)\n  dynamic.foo(x << 1)\n  dynamic.foo(x >> 1)\n  dynamic.foo(x >>> 1)\n  dynamic.foo(x >>> 0)\n  dynamic.foo(x >>> x)\n}\n\", \"\n(function() {\n  var __imul = Math.imul ? Math.imul : function(a, b) {\n    return (a * (b >>> 16) << 16) + a * (b & 65535) | 0;\n  };\n\n  function main() {\n    var x = 0;\n    foo(x + 1 | 0);\n    foo(x - 1 | 0);\n    foo(__imul(x, 2));\n    foo(x / 2 | 0);\n    foo(x % 2);\n    foo(x % 0 | 0);\n    foo(x % x | 0);\n    foo(x << 1);\n    foo(x >> 1);\n    foo(x >>> 1);\n    foo(x >>> 0 | 0);\n    foo(x >>> x | 0);\n  }\n\n  main();\n})();\n\").js\n\n# This caused an assert to fail during inlining\ntest(\"\ninterface Foo {\n  def foo int\n}\n\nclass Bar :: Foo {\n  def foo int { return 0 }\n}\n\nclass Baz {\n  def foo(foo Foo) int {\n    return false ? 0 : foo.foo\n  }\n}\n\n@entry\ndef main {\n  Baz.new.foo(null)\n}\n\", \"\n(function() {\n  function main() {\n    Baz.foo(new Baz(), null);\n  }\n\n  var Bar = {};\n  Bar.foo = function(self) {\n    return 0;\n  };\n\n  function Baz() {\n  }\n\n  Baz.foo = function(self, foo) {\n    return Bar.foo(foo);\n  };\n\n  main();\n})();\n\").js.inlineAllFunctions.foldAllConstants.globalizeAllFunctions\n\n# Check a case of assignment folding\ntest(\"\n@export\ndef main(x int, y int) int {\n  x = 0\n  x = 1\n  return x + y\n}\n\", \"\n(function(exports) {\n  exports.main = function(x, y) {\n    x = 1;\n    return x + y | 0;\n  };\n})(this);\n\").js.foldAllConstants\n\n# Check a case of assignment folding\ntest(\"\n@export\ndef main(x int, y int) int {\n  x = 0\n  x = x + 1\n  return x + y\n}\n\", \"\n(function(exports) {\n  exports.main = function(x, y) {\n    x = 0;\n    x = x + 1 | 0;\n    return x + y | 0;\n  };\n})(this);\n\").js.foldAllConstants\n\n# Check a case of assignment folding\ntest(\"\n@export\ndef main(x int, y int) int {\n  x = 0\n  y = 0\n  x = 1\n  return x + y\n}\n\", \"\n(function(exports) {\n  exports.main = function(x, y) {\n    y = 0;\n    x = 1;\n    return x + y | 0;\n  };\n})(this);\n\").js.foldAllConstants\n\n# Check a case of assignment folding\ntest(\"\n@export\ndef main(x int, y int) int {\n  x = 0\n  dynamic.foo()\n  x = 1\n  return x + y\n}\n\", \"\n(function(exports) {\n  exports.main = function(x, y) {\n    x = 0;\n    foo();\n    x = 1;\n    return x + y | 0;\n  };\n})(this);\n\").js.foldAllConstants\n\n# Check a case of assignment folding\ntest(\"\n@export\ndef main(x int, y int) int {\n  x = 0\n  y = x\n  x = 1\n  return x + y\n}\n\", \"\n(function(exports) {\n  exports.main = function(x, y) {\n    x = 0;\n    y = x;\n    x = 1;\n    return x + y | 0;\n  };\n})(this);\n\").js.foldAllConstants\n\n# Check a case of assignment folding\ntest(\"\n@export\ndef main(x int, y int) int {\n  x = 0\n  y = dynamic.foo ? x : x + 1\n  x = 1\n  return x + y\n}\n\", \"\n(function(exports) {\n  exports.main = function(x, y) {\n    x = 0;\n    y = foo ? x : x + 1 | 0;\n    x = 1;\n    return x + y | 0;\n  };\n})(this);\n\").js.foldAllConstants\n\n# Check a case of assignment folding\ntest(\"\nclass Foo {\n  var x = 0\n}\n\n@entry\ndef main int {\n  var foo = Foo.new\n  foo.x = 1\n  foo.x = 2\n  return foo.x\n}\n\", \"\n(function() {\n  function main() {\n    var foo = new Foo();\n    foo.x = 2;\n    return foo.x;\n  }\n\n  function Foo() {\n    this.x = 0;\n  }\n\n  process.exit(main());\n})();\n\").js.foldAllConstants\n\n# Check a case of assignment folding\ntest(\"\nclass Foo {\n  var x = 0\n  def foo {}\n}\n\n@entry\ndef main int {\n  var foo = Foo.new\n  var y Foo = null\n  var z = 0\n  foo.x = 1\n  y = foo\n  z = y.x\n  foo.x = 2\n  return foo.x\n}\n\", \"\n(function() {\n  function main() {\n    var foo = new Foo();\n    var y = null;\n    var z = 0;\n    foo.x = 1;\n    y = foo;\n    z = y.x;\n    foo.x = 2;\n    return foo.x;\n  }\n\n  function Foo() {\n    this.x = 0;\n  }\n\n  process.exit(main());\n})();\n\").js.foldAllConstants\n\n# Check a case of assignment folding\ntest(\"\nclass Foo {\n  var x = 0\n  def foo int { return x }\n}\n\n@entry\ndef main int {\n  var foo = Foo.new\n  foo.x = foo.foo + 1\n  foo.x = foo.foo + 2\n  return foo.x\n}\n\", \"\n(function() {\n  function main() {\n    var foo = new Foo();\n    foo.x = foo.foo() + 1 | 0;\n    foo.x = foo.foo() + 2 | 0;\n    return foo.x;\n  }\n\n  function Foo() {\n    this.x = 0;\n  }\n\n  Foo.prototype.foo = function() {\n    return this.x;\n  };\n\n  process.exit(main());\n})();\n\").js.foldAllConstants\n\n# Check a case of assignment folding\ntest(\"\nclass Foo {\n  var x = 0\n  def foo {}\n}\n\n@entry\ndef main int {\n  var foo = Foo.new\n  var bar = Foo.new\n  foo.x = 1\n  bar.x = 2\n  foo.x = 3\n  return foo.x\n}\n\", \"\n(function() {\n  function main() {\n    var foo = new Foo();\n    var bar = new Foo();\n    bar.x = 2;\n    foo.x = 3;\n    return foo.x;\n  }\n\n  function Foo() {\n    this.x = 0;\n  }\n\n  process.exit(main());\n})();\n\").js.foldAllConstants\n\n# Check constant folding of switch statements\ntest(\"\n@export\ndef main string {\n  switch 0 {\n    case 0 { return \\\"0\\\" }\n    case 1 { return \\\"1\\\" }\n    default { return null }\n  }\n}\n\", \"\n(function(exports) {\n  exports.main = function() {\n    return '0';\n  };\n})(this);\n\").js.foldAllConstants\n\n# Check constant folding of switch statements\ntest(\"\n@export\ndef main string {\n  switch 2 {\n    case 0 { return \\\"0\\\" }\n    case 1 { return \\\"1\\\" }\n    default { return null }\n  }\n}\n\", \"\n(function(exports) {\n  exports.main = function() {\n    return null;\n  };\n})(this);\n\").js.foldAllConstants\n\n# Check constant folding of switch statements\ntest(\"\n@export\ndef main(x int) string {\n  switch 0 {\n    case 0 { return \\\"0\\\" }\n    case x { return \\\"1\\\" }\n    default { return null }\n  }\n}\n\", \"\n(function(exports) {\n  exports.main = function(x) {\n    return '0';\n  };\n})(this);\n\").js.foldAllConstants\n\n# Check constant folding of switch statements\ntest(\"\n@export\ndef main(x int) string {\n  switch 1 {\n    case x { return \\\"0\\\" }\n    case 1 { return \\\"1\\\" }\n    case 2 { return \\\"2\\\" }\n    default { return null }\n  }\n}\n\", \"\n(function(exports) {\n  exports.main = function(x) {\n    switch (1) {\n      case x: {\n        return '0';\n      }\n\n      case 1: {\n        return '1';\n      }\n\n      default: {\n        return null;\n      }\n    }\n  };\n})(this);\n\").js.foldAllConstants\n\n# Check IIFE parentheses\ntest(\"\n@entry\ndef main {\n  (=> dynamic.this)().foo[\\\"bar\\\"] = (=> dynamic.this)().foo[\\\"bar\\\"]\n}\n\", \"\n(function() {\n  function main() {\n    (function() {\n      return this;\n    })().foo['bar'] = function() {\n      return this;\n    }().foo['bar'];\n  }\n\n  main();\n})();\n\").js.foldAllConstants\n\n# Check constant folding of a bitwise \"and\" nested between two shifts\ntest(\"\n@export\ndef main(x int) int {\n  x = (((x >> 8) & 255) << 8) + (((x >>> 8) & 255) << 8)\n  x = (((x >> 7) & 255) << 8) + (((x >>> 7) & 255) << 8)\n  x = (((x >> 8) & 255) << 7) + (((x >>> 8) & 255) << 7)\n  return x\n}\n\", \"\n(function(exports) {\n  exports.main = function(x) {\n    x = (x & 65280) + (x & 65280) | 0;\n    x = (x << 1 & 65280) + (x << 1 & 65280) | 0;\n    x = (x >> 1 & 32640) + (x >>> 1 & 32640) | 0;\n    return x;\n  };\n})(this);\n\").js.foldAllConstants\n\n# Check constant folding of two adjacent bitwise \"and\" operations inside a bitwise \"or\"\ntest(\"\n@export\ndef main(x int) int {\n  return x & 17 | 257 & x\n}\n\", \"\n(function(exports) {\n  exports.main = function(x) {\n    return x & 273;\n  };\n})(this);\n\").js.foldAllConstants\n\n# Check constant folding of a single \"and\" inside a bitwise \"or\"\ntest(\"\n@export\ndef main(x int) int {\n  x = (x & 0xFF000000) | 0xFFFFFF\n  x = (x & 0x7F000000) | 0xFFFFFF\n  x = 0xFFFFFF | (0xFF0000FF & x)\n  x = 0xFFFFFF | (0x7F0000FF & x)\n  return x\n}\n\", \"\n(function(exports) {\n  exports.main = function(x) {\n    x = x | 16777215;\n    x = x & 2130706432 | 16777215;\n    x = x | 16777215;\n    x = x & 2130706687 | 16777215;\n    return x;\n  };\n})(this);\n\").js.foldAllConstants\n\n# Check constant folding of identity operations\ntest(\"\n@export\ndef main(x int, y fn() int) {\n  # Multiplication (be careful about expressions with side effects and about NaN for dynamic values)\n  dynamic.foo(x * 0)\n  dynamic.foo(x * 1)\n  dynamic.foo(x * 2)\n  dynamic.foo(y() * 0)\n  dynamic.foo(y() * 1)\n  dynamic.foo(y() * 2)\n  dynamic.foo(dynamic.z * 0)\n  dynamic.foo(dynamic.z * 1)\n  dynamic.foo(dynamic.z * 2)\n\n  # Bitwise operations with an integer reference\n  dynamic.foo(x & 0)\n  dynamic.foo(x | 0)\n  dynamic.foo(x & ~0)\n  dynamic.foo(x | ~0)\n  dynamic.foo(x << 0)\n  dynamic.foo(x >> 0)\n  dynamic.foo(x >>> 0)\n\n  # Bitwise operations with an integer expression with side effects\n  dynamic.foo(y() & 0)\n  dynamic.foo(y() | 0)\n  dynamic.foo(y() & ~0)\n  dynamic.foo(y() | ~0)\n\n  # Bitwise operations with a dynamically typed expression with side effects, may be a non-integer\n  dynamic.foo(dynamic.z() & 0)\n  dynamic.foo(dynamic.z() | 0)\n  dynamic.foo(dynamic.z() & ~0)\n  dynamic.foo(dynamic.z() | ~0)\n  dynamic.foo(dynamic.z() << 0)\n  dynamic.foo(dynamic.z() >> 0)\n  dynamic.foo(dynamic.z() >>> 0)\n}\n\", \"\n(function(exports) {\n  var __imul = Math.imul ? Math.imul : function(a, b) {\n    return (a * (b >>> 16) << 16) + a * (b & 65535) | 0;\n  };\n\n  exports.main = function(x, y) {\n    // Multiplication (be careful about expressions with side effects and about NaN for dynamic values)\n    foo(0);\n    foo(x);\n    foo(x << 1);\n    foo(__imul(y(), 0));\n    foo(y());\n    foo(y() << 1);\n    foo(z * 0);\n    foo(z);\n    foo(z * 2);\n\n    // Bitwise operations with an integer reference\n    foo(0);\n    foo(x);\n    foo(x);\n    foo(-1);\n    foo(x);\n    foo(x);\n    foo(x);\n\n    // Bitwise operations with an integer expression with side effects\n    foo(y() & 0);\n    foo(y());\n    foo(y());\n    foo(y() | -1);\n\n    // Bitwise operations with a dynamically typed expression with side effects, may be a non-integer\n    foo(z() & 0);\n    foo(z() | 0);\n    foo(z() & -1);\n    foo(z() | -1);\n    foo(z() << 0);\n    foo(z() >> 0);\n    foo(z() >>> 0);\n  };\n})(this);\n\").js.foldAllConstants.inlineAllFunctions\n\n# Check constant folding of bitwise operations and inlining\ntest(\"\ntype Color : int {\n  def r int { return (self as int) & 255 }\n  def g int { return ((self as int) >> 8) & 255 }\n  def b int { return ((self as int) >> 16) & 255 }\n  def a int { return (self as int) >>> 24 }\n\n  def opaque Color {\n    return new(r, g, b, 255)\n  }\n}\n\nnamespace Color {\n  def new(r int, g int, b int, a int) Color {\n    return (r | g << 8 | b << 16 | a << 24) as Color\n  }\n}\n\n@export\ndef isOrange(color Color) bool {\n  return color.opaque == Color.new(255, 127, 0, 255)\n}\n\", \"\n(function(exports) {\n  var Color = {};\n\n  Color.opaque = function(self) {\n    return self | -16777216;\n  };\n\n  exports.isOrange = function(color) {\n    return Color.opaque(color) == -16744449;\n  };\n})(this);\n\").js.foldAllConstants.inlineAllFunctions\n\n# Check that compile-time if statements work\ntest(\"\n@export {\n  if FOO == .FOO {\n    const FOO_YES = true\n  } else {\n    const FOO_NO = false\n  }\n\n  if FOO == .BAR {\n    const BAR_YES = true\n  } else {\n    const BAR_NO = false\n  }\n}\n\nconst FOO = Foo.FOO\n\nenum Foo {\n  FOO\n  BAR\n}\n\", \"\n(function(exports) {\n  exports.FOO_YES = true;\n  exports.BAR_NO = false;\n})(this);\n\").js\n\n# Check that nested compile-time if statements work\ntest(\"\nif true {\n  @export {\n    if FOO == .FOO {\n      const FOO_YES = true\n    } else {\n      const FOO_NO = false\n    }\n\n    if FOO == .BAR {\n      const BAR_YES = true\n    } else {\n      const BAR_NO = false\n    }\n  }\n}\n\nconst FOO = Foo.FOO\n\nenum Foo {\n  FOO\n  BAR\n}\n\", \"\n(function(exports) {\n  exports.FOO_YES = true;\n  exports.BAR_NO = false;\n})(this);\n\").js\n\n# Check constant folding of unicode string factory functions\ntest(\"\n@export\ndef main string {\n  return\n    string.fromCodePoint('😄') +\n    string.fromCodeUnit('x') +\n    string.fromCodePoints(['💾', '💿']) +\n    string.fromCodeUnits(['y', 'z'])\n}\n\", \"\n(function(exports) {\n  exports.main = function() {\n    return '😄x💾💿yz';\n  };\n})(this);\n\").js.foldAllConstants\n\n# Check constant folding of unicode string factory functions\ntest(\"\n@export\ndef main(x int) string {\n  return\n    string.fromCodePoint(x) +\n    string.fromCodeUnit(x) +\n    string.fromCodePoints(['x', x]) +\n    string.fromCodeUnits([x, x])\n}\n\", \"\n(function(exports) {\n  function assert(truth) {\n    if (!truth) {\n      throw Error('Assertion failed');\n    }\n  }\n\n  function StringBuilder() {\n    this.buffer = '';\n  }\n\n  var in_List = {};\n\n  in_List.get = function(self, index) {\n    assert(0 <= index && index < self.length);\n    return self[index];\n  };\n\n  var in_string = {};\n\n  in_string.fromCodePoints = function(codePoints) {\n    var builder = new StringBuilder();\n\n    for (var i = 0, count1 = codePoints.length; i < count1; i = i + 1 | 0) {\n      var codePoint = in_List.get(codePoints, i);\n      builder.buffer += in_string.fromCodePoint(codePoint);\n    }\n\n    return builder.buffer;\n  };\n\n  in_string.fromCodeUnits = function(codeUnits) {\n    var result = '';\n\n    for (var i = 0, count1 = codeUnits.length; i < count1; i = i + 1 | 0) {\n      var codeUnit = in_List.get(codeUnits, i);\n      result += String.fromCharCode(codeUnit);\n    }\n\n    return result;\n  };\n\n  in_string.fromCodePoint = function(codePoint) {\n    return codePoint < 65536 ? String.fromCharCode(codePoint) : String.fromCharCode((codePoint - 65536 >> 10) + 55296 | 0) + String.fromCharCode((codePoint - 65536 & 1023) + 56320 | 0);\n  };\n\n  exports.main = function(x) {\n    return in_string.fromCodePoint(x) + String.fromCharCode(x) + in_string.fromCodePoints([120, x]) + in_string.fromCodeUnits([x, x]);\n  };\n})(this);\n\").js.foldAllConstants.inlineAllFunctions\n\n# Check that iterating over a local constant doesn't generate an extra variable\ntest(\"\n@export\ndef main {\n  var foo = [0, 1, 2]\n  var bar = [0, 1, 2]\n  bar = []\n\n  for i in foo {}\n  for i in bar {}\n}\n\", \"\n(function(exports) {\n  function assert(truth) {\n    if (!truth) {\n      throw Error('Assertion failed');\n    }\n  }\n\n  var in_List = {};\n\n  in_List.get = function(self, index) {\n    assert(0 <= index && index < self.length);\n    return self[index];\n  };\n\n  exports.main = function() {\n    var foo = [0, 1, 2];\n    var bar = [0, 1, 2];\n    bar = [];\n\n    for (var i2 = 0, count = foo.length; i2 < count; i2 = i2 + 1 | 0) {\n      var i = in_List.get(foo, i2);\n    }\n\n    for (var i3 = 0, list = bar, count1 = list.length; i3 < count1; i3 = i3 + 1 | 0) {\n      var i1 = in_List.get(list, i3);\n    }\n  };\n})(this);\n\").js.foldAllConstants.inlineAllFunctions\n\n# Check for a bug with bounded for loops\ntest(\"\n@export\ndef main {\n  var foo = 0\n  var bar = 5\n  for i in foo..bar {}\n}\n\", \"\n(function(exports) {\n  exports.main = function() {\n    for (var i = 0; i < 5; i = i + 1 | 0) {\n    }\n  };\n})(this);\n\").js.foldAllConstants\n\n# Test @neverinline\ntest(\"\ndef foo {\n  dynamic.Foo()\n}\n\n@neverinline\ndef bar {\n  dynamic.Bar()\n}\n\n@entry\ndef main {\n  foo\n  bar\n}\n\", \"\n(function() {\n  function bar() {\n    Bar();\n  }\n\n  function main() {\n    Foo();\n    bar();\n  }\n\n  main();\n})();\n\").js.inlineAllFunctions\n\n# Test @alwaysinline\ntest(\"\ndef foo {\n  dynamic.Foo()\n}\n\n@alwaysinline\ndef bar {\n  dynamic.Bar()\n}\n\nclass Foo {\n  def foo { dynamic.Foo(self) }\n\n  @alwaysinline\n  def bar { dynamic.Bar(self) }\n}\n\n@entry\ndef main {\n  foo\n  bar\n\n  Foo.new.foo\n  Foo.new.bar\n}\n\", \"\n(function() {\n  function foo() {\n    Foo();\n  }\n\n  function main() {\n    foo();\n    Bar();\n    new Foo().foo();\n    Bar(new Foo());\n  }\n\n  function Foo() {\n  }\n\n  Foo.prototype.foo = function() {\n    Foo(this);\n  };\n\n  main();\n})();\n\").js\n\n# Test obscure bug with super class calls\ntest(\"\nclass Baz : Bar {\n}\n\n@entry\ndef main {\n  Baz2.new.foo(0)\n}\n\nclass Bar : Foo {\n  over foo(bar int) {}\n}\n\nclass Foo {\n  def foo(bar int) {}\n}\n\nclass Baz2 : Bar {\n  over foo(bar int) {\n    super(bar)\n  }\n}\n\", \"\n(function() {\n  var __create = Object.create ? Object.create : function(prototype) {\n    return {'__proto__': prototype};\n  };\n\n  function __extends(derived, base) {\n    derived.prototype = __create(base.prototype);\n    derived.prototype.constructor = derived;\n  }\n\n  function main() {\n    new Baz2().foo(0);\n  }\n\n  function Foo() {\n  }\n\n  Foo.prototype.foo = function(bar) {\n  };\n\n  function Bar() {\n    Foo.call(this);\n  }\n\n  __extends(Bar, Foo);\n\n  Bar.prototype.foo = function(bar) {\n  };\n\n  function Baz2() {\n    Bar.call(this);\n  }\n\n  __extends(Baz2, Bar);\n\n  Baz2.prototype.foo = function(bar) {\n    Bar.prototype.foo.call(this, bar);\n  };\n\n  main();\n})();\n\").js\n\n# Test obscure bug with super class calls\ntest(\"\n@entry\ndef main {\n  Baz2.new.foo(0)\n}\n\nclass Foo {\n  def foo(bar int) {}\n}\n\nclass Bar : Foo {\n  over foo(bar int) {}\n}\n\nclass Baz : Bar {\n}\n\nclass Baz2 : Bar {\n  over foo(bar int) {\n    super(bar)\n  }\n}\n\", \"\n(function() {\n  var __create = Object.create ? Object.create : function(prototype) {\n    return {'__proto__': prototype};\n  };\n\n  function __extends(derived, base) {\n    derived.prototype = __create(base.prototype);\n    derived.prototype.constructor = derived;\n  }\n\n  function main() {\n    new Baz2().foo(0);\n  }\n\n  function Foo() {\n  }\n\n  Foo.prototype.foo = function(bar) {\n  };\n\n  function Bar() {\n    Foo.call(this);\n  }\n\n  __extends(Bar, Foo);\n\n  Bar.prototype.foo = function(bar) {\n  };\n\n  function Baz2() {\n    Bar.call(this);\n  }\n\n  __extends(Baz2, Bar);\n\n  Baz2.prototype.foo = function(bar) {\n    Bar.prototype.foo.call(this, bar);\n  };\n\n  main();\n})();\n\").js\n\n# Test math constants\ntest(\"\n@export\ndef main {\n  dynamic.foo(Math.NAN, Math.INFINITY, -Math.INFINITY)\n  dynamic.foo(Math.NAN.toString, Math.INFINITY.toString, (-Math.INFINITY).toString)\n}\n\", \"\n(function(exports) {\n  exports.main = function() {\n    foo(0 / 0, 1 / 0, -(1 / 0));\n    foo((0 / 0).toString(), (1 / 0).toString(), (-(1 / 0)).toString());\n  };\n})(this);\n\").js.inlineAllFunctions\n\n# Test math constants\ntest(\"\n@export\ndef main {\n  dynamic.foo(Math.NAN, Math.INFINITY, -Math.INFINITY)\n  dynamic.foo(Math.NAN.toString, Math.INFINITY.toString, (-Math.INFINITY).toString)\n}\n\", \"\n(function(exports) {\n  exports.main = function() {\n    foo(NaN, Infinity, -Infinity);\n    foo(NaN.toString(), Infinity.toString(), (-Infinity).toString());\n  };\n})(this);\n\").js.inlineAllFunctions.foldAllConstants\n\n# Test math toString\ntest(\"\n@export\ndef main {\n  dynamic.foo(0.toString, 1.0.toString, (-1.0).toString, 0.5.toString, (-0.5).toString)\n}\n\", \"\n(function(exports) {\n  exports.main = function() {\n    foo((0).toString(), (1).toString(), (-1).toString(), (0.5).toString(), (-0.5).toString());\n  };\n})(this);\n\").js\n\n# Test math toString\ntest(\"\n@export\ndef main {\n  dynamic.foo(0.toString, 1.0.toString, (-1.0).toString, 0.5.toString, (-0.5).toString)\n}\n\", \"\n(function(exports) {\n  exports.main = function() {\n    foo('0', (1).toString(), (-1).toString(), (0.5).toString(), (-0.5).toString());\n  };\n})(this);\n\").js.foldAllConstants\n\n# Double literals must be emitted with the right format\ntest(\"\n@export\ndef main(x double) {\n  x = 1.0 / 2.0\n  x = 1e100 / 2e100\n  x = 1e-100 / 2e-100\n  x = 1.5 / 2.5\n  x = 1.5e100 / 2.5e100\n  x = 1.5e-100 / 2.5e-100\n}\n\", \"\n(function(exports) {\n  exports.main = function(x) {\n    x = 1 / 2;\n    x = 1e+100 / 2e+100;\n    x = 1e-100 / 2e-100;\n    x = 1.5 / 2.5;\n    x = 1.5e+100 / 2.5e+100;\n    x = 1.5e-100 / 2.5e-100;\n  };\n})(this);\n\").js\n\n# Test folding of nested shifts\ntest(\"\n@export\ndef main(x int) {\n  dynamic.foo(x * 32 * 64)\n  dynamic.foo(x * 32.0 * 64)\n  dynamic.foo(x * 32 * 64.0)\n  dynamic.foo(x << 5 << 6)\n  dynamic.foo(x >> 5 >> 6)\n  dynamic.foo(x >>> 5 >>> 6)\n  dynamic.foo(x << 5 >> 6)\n  dynamic.foo(x << 5 >>> 6)\n  dynamic.foo(x >> 5 >>> 6)\n  dynamic.foo(x >>> 5 >> 6)\n}\n\", \"\n(function(exports) {\n  exports.main = function(x) {\n    foo(x << 11);\n    foo(x * 32 * 64);\n    foo((x << 5) * 64);\n    foo(x << 11);\n    foo(x >> 11);\n    foo(x >>> 11);\n    foo(x << 5 >> 6);\n    foo(x << 5 >>> 6);\n    foo(x >> 5 >>> 6);\n    foo(x >>> 5 >> 6);\n  };\n})(this);\n\").js.foldAllConstants\n\n# Test renaming with symbol merging\ntest(\"\n@import\nclass Foo {\n  def new\n  def foo(x int)\n}\n\nclass Foo {\n  @rename(\\\"bar\\\")\n  def foo(x int)\n}\n\n@export\ndef main {\n  Foo.new.foo(0)\n}\n\", \"\n(function(exports) {\n  exports.main = function() {\n    new Foo().bar(0);\n  };\n})(this);\n\").js\n\n# Test renaming with symbol merging\ntest(\"\n@import\nclass Foo {\n  def new\n  @rename(\\\"bar\\\")\n  def foo(x int)\n}\n\nclass Foo {\n  def foo(x int)\n}\n\n@export\ndef main {\n  Foo.new.foo(0)\n}\n\", \"\n(function(exports) {\n  exports.main = function() {\n    new Foo().bar(0);\n  };\n})(this);\n\").js\n\n# Test renaming with symbol merging and generics\ntest(\"\n@import\nclass Foo<X> {\n  def new\n\n  @rename(\\\"baz\\\")\n  def foo<Y>(x Y)\n  def foo<Z>(x Z)\n\n  def bar<Y>(x Y)\n  @rename(\\\"baz\\\")\n  def bar<Z>(x Z)\n}\n\n@export\ndef main {\n  Foo<int>.new.foo<int>(0)\n  Foo<int>.new.bar<int>(0)\n}\n\", \"\n(function(exports) {\n  exports.main = function() {\n    new Foo().baz(0);\n    new Foo().baz(0);\n  };\n})(this);\n\").js\n\n# Test imported auto-implemented operators\ntest(\"\n@import\nclass Foo {\n  def *(x int) Foo\n}\n\n@export\ndef main(foo Foo) {\n  foo *= 2\n}\n\", \"\n(function(exports) {\n  exports.main = function(foo) {\n    foo = foo * 2;\n  };\n})(this);\n\").js.inlineAllFunctions\n\n# Test side-effect preservation for auto-implemented operators\ntest(\"\nclass Foo {\n  var x = 0.0\n  var y = 0\n  var z = [0.0]\n}\n\ndef bar Foo {\n  return Foo.new\n}\n\n@export\ndef main(foo Foo) {\n  foo.x **= 2\n  foo.z[0] **= 2\n  foo.z[foo.y] **= 2\n\n  bar.x **= 2\n  bar.z[0] **= 2\n  bar.z[bar.y] **= 2\n}\n\", \"\n(function(exports) {\n  exports.main = function(foo) {\n    var ref6;\n    var ref5;\n    var ref4;\n    var ref3;\n    var ref2;\n    var ref1;\n    var ref;\n    foo.x = Math.pow(foo.x, 2);\n    (ref = foo.z)[0] = Math.pow(ref[0], 2);\n    (ref1 = foo.z)[ref2 = foo.y] = Math.pow(ref1[ref2], 2);\n    (ref3 = new Foo()).x = Math.pow(ref3.x, 2);\n    (ref4 = new Foo().z)[0] = Math.pow(ref4[0], 2);\n    (ref5 = new Foo().z)[ref6 = new Foo().y] = Math.pow(ref5[ref6], 2);\n  };\n\n  function Foo() {\n    this.x = 0;\n    this.y = 0;\n    this.z = [0];\n  }\n})(this);\n\").js.inlineAllFunctions.skip # Skipped because rewriting assignment operators doesn't work with non-imported functions yet\n\n# Test the null join operator\ntest(\"\nclass Foo {\n  var x Foo = null\n}\n\ndef bar Foo {\n  return Foo.new\n}\n\n@export\ndef main(foo Foo) {\n  foo ?? bar\n  foo.x ?? foo.x\n  bar.x ?? bar.x\n  bar.x ?? bar ?? foo.x ?? foo\n}\n\", \"\n(function(exports) {\n  function bar() {\n    return new Foo();\n  }\n\n  function Foo() {\n    this.x = null;\n  }\n\n  exports.main = function(foo) {\n    var ref2;\n    var ref1;\n    var ref;\n    foo != null ? foo : bar();\n    foo.x != null ? foo.x : foo.x;\n    (ref = bar()).x != null ? ref.x : bar().x;\n    (ref2 = bar()).x != null ? ref2.x : (ref1 = bar()) != null ? ref1 : foo.x != null ? foo.x : foo;\n  };\n})(this);\n\").js\n\n# Test the null dot operator\ntest(\"\nclass Foo {\n  var a Foo = null\n  def b Foo { return self }\n  var c fn() Foo = => null\n  def d(x int) Foo { return self }\n}\n\ndef bar Foo {\n  return Foo.new\n}\n\n@export\ndef main(foo Foo) {\n  dynamic.use(foo?.a.a)\n  dynamic.use(foo?.b.b)\n  dynamic.use(foo?.c().c())\n  dynamic.use(foo?.d(0).d(0))\n\n  dynamic.use(foo?.a?.a)\n  dynamic.use(foo?.b?.b)\n  dynamic.use(foo?.c()?.c())\n  dynamic.use(foo?.d(0)?.d(0))\n\n  dynamic.use(bar?.a.a)\n  dynamic.use(bar?.b.b)\n  dynamic.use(bar?.c().c())\n  dynamic.use(bar?.d(0).d(0))\n\n  dynamic.use(bar?.a?.a)\n  dynamic.use(bar?.b?.b)\n  dynamic.use(bar?.c()?.c())\n  dynamic.use(bar?.d(0)?.d(0))\n}\n\", \"\n(function(exports) {\n  function bar() {\n    return new Foo();\n  }\n\n  function Foo() {\n    this.a = null;\n    this.c = function() {\n      return null;\n    };\n  }\n\n  Foo.prototype.b = function() {\n    return this;\n  };\n\n  Foo.prototype.d = function(x) {\n    return this;\n  };\n\n  exports.main = function(foo) {\n    var ref15;\n    var ref14;\n    var ref13;\n    var ref12;\n    var ref11;\n    var ref10;\n    var ref9;\n    var ref8;\n    var ref7;\n    var ref6;\n    var ref5;\n    var ref4;\n    var ref3;\n    var ref2;\n    var ref1;\n    var ref;\n    use(foo != null ? foo.a.a : null);\n    use(foo != null ? foo.b().b() : null);\n    use(foo != null ? foo.c().c() : null);\n    use(foo != null ? foo.d(0).d(0) : null);\n    use((ref = foo != null ? foo.a : null) != null ? ref.a : null);\n    use((ref1 = foo != null ? foo.b() : null) != null ? ref1.b() : null);\n    use((ref2 = foo != null ? foo.c() : null) != null ? ref2.c() : null);\n    use((ref3 = foo != null ? foo.d(0) : null) != null ? ref3.d(0) : null);\n    use((ref4 = bar()) != null ? ref4.a.a : null);\n    use((ref5 = bar()) != null ? ref5.b().b() : null);\n    use((ref6 = bar()) != null ? ref6.c().c() : null);\n    use((ref7 = bar()) != null ? ref7.d(0).d(0) : null);\n    use((ref9 = (ref8 = bar()) != null ? ref8.a : null) != null ? ref9.a : null);\n    use((ref11 = (ref10 = bar()) != null ? ref10.b() : null) != null ? ref11.b() : null);\n    use((ref13 = (ref12 = bar()) != null ? ref12.c() : null) != null ? ref13.c() : null);\n    use((ref15 = (ref14 = bar()) != null ? ref14.d(0) : null) != null ? ref15.d(0) : null);\n  };\n})(this);\n\").js\n\n# Test top-level use of the null dot operator\ntest(\"\nclass Foo {\n  var a Foo = null\n  def b Foo { return self }\n  var c fn() Foo = => null\n  def d(x int) Foo { return self }\n}\n\ndef bar Foo {\n  return Foo.new\n}\n\n@export\ndef main(foo Foo) {\n  foo?.a.a\n  foo?.b.b\n  foo?.c().c()\n  foo?.d(0).d(0)\n\n  foo?.a?.a\n  foo?.b?.b\n  foo?.c()?.c()\n  foo?.d(0)?.d(0)\n\n  bar?.a.a\n  bar?.b.b\n  bar?.c().c()\n  bar?.d(0).d(0)\n\n  bar?.a?.a\n  bar?.b?.b\n  bar?.c()?.c()\n  bar?.d(0)?.d(0)\n}\n\", \"\n(function(exports) {\n  function bar() {\n    return new Foo();\n  }\n\n  function Foo() {\n    this.a = null;\n    this.c = function() {\n      return null;\n    };\n  }\n\n  Foo.prototype.b = function() {\n    return this;\n  };\n\n  Foo.prototype.d = function(x) {\n    return this;\n  };\n\n  exports.main = function(foo) {\n    var ref15;\n    var ref14;\n    var ref13;\n    var ref12;\n    var ref11;\n    var ref10;\n    var ref9;\n    var ref8;\n    var ref7;\n    var ref6;\n    var ref5;\n    var ref4;\n    var ref3;\n    var ref2;\n    var ref1;\n    var ref;\n\n    if (foo != null) {\n      foo.a.a;\n    }\n\n    if (foo != null) {\n      foo.b().b();\n    }\n\n    if (foo != null) {\n      foo.c().c();\n    }\n\n    if (foo != null) {\n      foo.d(0).d(0);\n    }\n\n    if ((ref = foo != null ? foo.a : null) != null) {\n      ref.a;\n    }\n\n    if ((ref1 = foo != null ? foo.b() : null) != null) {\n      ref1.b();\n    }\n\n    if ((ref2 = foo != null ? foo.c() : null) != null) {\n      ref2.c();\n    }\n\n    if ((ref3 = foo != null ? foo.d(0) : null) != null) {\n      ref3.d(0);\n    }\n\n    if ((ref4 = bar()) != null) {\n      ref4.a.a;\n    }\n\n    if ((ref5 = bar()) != null) {\n      ref5.b().b();\n    }\n\n    if ((ref6 = bar()) != null) {\n      ref6.c().c();\n    }\n\n    if ((ref7 = bar()) != null) {\n      ref7.d(0).d(0);\n    }\n\n    if ((ref9 = (ref8 = bar()) != null ? ref8.a : null) != null) {\n      ref9.a;\n    }\n\n    if ((ref11 = (ref10 = bar()) != null ? ref10.b() : null) != null) {\n      ref11.b();\n    }\n\n    if ((ref13 = (ref12 = bar()) != null ? ref12.c() : null) != null) {\n      ref13.c();\n    }\n\n    if ((ref15 = (ref14 = bar()) != null ? ref14.d(0) : null) != null) {\n      ref15.d(0);\n    }\n  };\n})(this);\n\").js\n\n# Test unary assignment operators\ntest(\"\nclass Foo {\n  var x = 0\n}\n\ndef foo Foo {\n  return Foo.new\n}\n\n@export\ndef main {\n  var x = 0\n  var y = 0.0\n\n  x++\n  ++x\n  x--\n  --x\n\n  y++\n  ++y\n  y--\n  --y\n\n  foo.x++\n  ++foo.x\n  foo.x--\n  --foo.x\n\n  dynamic.use(x++)\n  dynamic.use(++x)\n  dynamic.use(x--)\n  dynamic.use(--x)\n\n  dynamic.use(y++)\n  dynamic.use(++y)\n  dynamic.use(y--)\n  dynamic.use(--y)\n\n  dynamic.use(foo.x++)\n  dynamic.use(++foo.x)\n  dynamic.use(foo.x--)\n  dynamic.use(--foo.x)\n}\n\", \"\n(function(exports) {\n  function foo() {\n    return new Foo();\n  }\n\n  function Foo() {\n    this.x = 0;\n  }\n\n  exports.main = function() {\n    var ref7;\n    var ref6;\n    var ref5;\n    var ref4;\n    var ref3;\n    var ref2;\n    var ref1;\n    var ref;\n    var x = 0;\n    var y = 0;\n    x = x + 1 | 0;\n    x = x + 1 | 0;\n    x = x - 1 | 0;\n    x = x - 1 | 0;\n    y++;\n    ++y;\n    y--;\n    --y;\n    (ref = foo()).x = ref.x + 1 | 0;\n    (ref1 = foo()).x = ref1.x + 1 | 0;\n    (ref2 = foo()).x = ref2.x - 1 | 0;\n    (ref3 = foo()).x = ref3.x - 1 | 0;\n    use((x = x + 1 | 0) - 1 | 0);\n    use(x = x + 1 | 0);\n    use((x = x - 1 | 0) + 1 | 0);\n    use(x = x - 1 | 0);\n    use(y++);\n    use(++y);\n    use(y--);\n    use(--y);\n    use(((ref4 = foo()).x = ref4.x + 1 | 0) - 1 | 0);\n    use((ref5 = foo()).x = ref5.x + 1 | 0);\n    use(((ref6 = foo()).x = ref6.x - 1 | 0) + 1 | 0);\n    use((ref7 = foo()).x = ref7.x - 1 | 0);\n  };\n})(this);\n\").js.foldAllConstants\n\n# Test custom unary assignment operators\ntest(\"\nclass Foo {\n  var foo Foo = null\n  var bar List<Foo> = []\n  def ++ Foo { return self }\n}\n\ndef bar Foo {\n  return Foo.new\n}\n\ndef baz int {\n  return 0\n}\n\n@export\ndef main {\n  var foo = Foo.new\n\n  foo++\n  ++foo\n  bar.foo++\n  ++bar.foo\n  bar.bar[baz]++\n  ++bar.bar[baz]\n\n  dynamic.use(foo++)\n  dynamic.use(++foo)\n  dynamic.use(bar.foo++)\n  dynamic.use(++bar.foo)\n  dynamic.use(bar.bar[baz]++)\n  dynamic.use(++bar.bar[baz])\n}\n\", \"\n(function(exports) {\n  function bar() {\n    return new Foo();\n  }\n\n  function baz() {\n    return 0;\n  }\n\n  function Foo() {\n    this.foo = null;\n    this.bar = [];\n  }\n\n  Foo.prototype.increment = function() {\n    return this;\n  };\n\n  exports.main = function() {\n    var ref14;\n    var ref13;\n    var ref12;\n    var ref11;\n    var ref10;\n    var ref9;\n    var ref8;\n    var ref7;\n    var ref6;\n    var ref5;\n    var ref4;\n    var ref3;\n    var ref2;\n    var ref1;\n    var ref;\n    var foo = new Foo();\n    foo = foo.increment();\n    foo = foo.increment();\n    (ref = bar()).foo = ref.foo.increment();\n    (ref1 = bar()).foo = ref1.foo.increment();\n    (ref2 = bar().bar)[ref3 = baz()] = ref2[ref3].increment();\n    (ref4 = bar().bar)[ref5 = baz()] = ref4[ref5].increment();\n    use((ref6 = foo, foo = ref6.increment(), ref6));\n    use(foo = foo.increment());\n    use((ref7 = (ref8 = bar()).foo, ref8.foo = ref7.increment(), ref7));\n    use((ref9 = bar()).foo = ref9.foo.increment());\n    use((ref10 = (ref11 = bar().bar)[ref12 = baz()], ref11[ref12] = ref10.increment(), ref10));\n    use((ref13 = bar().bar)[ref14 = baz()] = ref13[ref14].increment());\n  };\n})(this);\n\").js.skip # Skipped because rewriting assignment operators doesn't work with non-imported functions yet\n\n# Test null assignment operator\ntest(\"\nclass Foo {\n  var x Foo = null\n}\n\ndef foo Foo {\n  return Foo.new\n}\n\ndef bar(foo Foo) {\n}\n\n@export\ndef main(baz Foo) {\n  baz ?? foo\n  baz ?= foo\n  baz.x ?? foo\n  baz.x ?= foo\n  foo.x ?? foo\n  foo.x ?= foo\n\n  bar(baz ?? foo)\n  bar(baz ?= foo)\n  bar(baz.x ?? foo)\n  bar(baz.x ?= foo)\n  bar(foo.x ?? foo)\n  bar(foo.x ?= foo)\n}\n\", \"\n(function(exports) {\n  function foo() {\n    return new Foo();\n  }\n\n  function bar(foo) {\n  }\n\n  function Foo() {\n    this.x = null;\n  }\n\n  exports.main = function(baz) {\n    var ref3;\n    var ref2;\n    var ref1;\n    var ref;\n    baz != null ? baz : foo();\n\n    if (baz == null) {\n      baz = foo();\n    }\n\n    baz.x != null ? baz.x : foo();\n\n    if (baz.x == null) {\n      baz.x = foo();\n    }\n\n    (ref = foo()).x != null ? ref.x : foo();\n\n    if ((ref1 = foo()).x == null) {\n      ref1.x = foo();\n    }\n\n    bar(baz != null ? baz : foo());\n    bar(baz != null ? baz : baz = foo());\n    bar(baz.x != null ? baz.x : foo());\n    bar(baz.x != null ? baz.x : baz.x = foo());\n    bar((ref2 = foo()).x != null ? ref2.x : foo());\n    bar((ref3 = foo()).x != null ? ref3.x : ref3.x = foo());\n  };\n})(this);\n\").js\n\n# Test null assignment operator with dynamic values\ntest(\"\n@export\ndef main {\n  dynamic.use(dynamic.foo[dynamic.bar] ?? \\\"1\\\")\n  dynamic.use(dynamic.foo[dynamic.bar] ?= \\\"2\\\")\n  dynamic.use(dynamic.foo()[dynamic.bar()] ?? \\\"3\\\")\n  dynamic.use(dynamic.foo()[dynamic.bar()] ?= \\\"4\\\")\n}\n\", \"\n(function(exports) {\n  exports.main = function() {\n    var ref3;\n    var ref2;\n    var ref1;\n    var ref;\n    use(foo[bar] !== null ? foo[bar] : '1');\n    use(foo[bar] !== null ? foo[bar] : foo[bar] = '2');\n    use((ref = foo())[ref1 = bar()] !== null ? ref[ref1] : '3');\n    use((ref2 = foo())[ref3 = bar()] !== null ? ref2[ref3] : ref2[ref3] = '4');\n  };\n})(this);\n\").js\n\n# Test \"?=\" and \"?.\" with comments when converted to if statements\ntest(\"\nclass Foo {\n  var foo Foo\n}\n\n@export\ndef main(foo Foo) {\n  foo ?= foo # This comment should be kept\n  foo?.foo # This comment should be kept too\n}\n\", \"\n(function(exports) {\n  exports.main = function(foo) {\n    // This comment should be kept\n    if (foo == null) {\n      foo = foo;\n    }\n\n    // This comment should be kept too\n    if (foo != null) {\n      foo.foo;\n    }\n  };\n})(this);\n\").js\n\n# Test string interpolation empty string omission\ntest(\"\n@export {\n  var a = \\\"\\\\(1)\\\"\n  var b = \\\"a\\\\(1)\\\"\n  var c = \\\"\\\\(1)b\\\"\n  var d = \\\"a\\\\(1)b\\\"\n  var e = \\\"\\\\(\\\"\\\")\\\\(\\\"\\\")\\\"\n  var f = \\\"\\\\(\\\"\\\")\\\\(\\\"\\\")\\\\(1)\\\\(\\\"\\\")\\\\(\\\"\\\")\\\"\n}\n\", \"\n(function(exports) {\n  exports.a = (1).toString();\n  exports.b = 'a' + (1).toString();\n  exports.c = (1).toString() + 'b';\n  exports.d = 'a' + (1).toString() + 'b';\n  exports.e = '';\n  exports.f = (1).toString();\n})(this);\n\").js\n\n# Test string interpolation toString insertion\ntest(\"\n@import {\n  def x int\n  def y dynamic\n}\n\n@export\nvar z = \\\"\\\\(x)\\\\(y)\\\"\n\", \"\n(function(exports) {\n  exports.z = x().toString() + y();\n})(this);\n\").js\n\n# Test nested string interpolation\ntest(\"\nvar x = => \\\"\\\"\n\n@export\nvar y =\n  \\\"\\\\(1)\\\\(\\\"a\\\")\\\\(\n    \\\"\\\\(x())\\\\((x()))\\\\(\n      \\\"\\\\(\\\"b\\\" + x() + \\\"c\\\")\\\\((x() + \\\"d\\\" + x()))\\\"\n    )\\\"\n  )\\\"\n\", \"\n(function(exports) {\n  var x = function() {\n    return '';\n  };\n  exports.y = (1).toString() + 'a' + (x() + x() + ('b' + x() + 'c' + (x() + 'd' + x())));\n})(this);\n\").js\n\n# Test string interpolation order without constant folding\ntest(\"\n@import\ndef x string\n\n@export {\n  var y = x + \\\"\\\\(x)\\\\(x)\\\"\n  var z = \\\"a\\\\(x)b\\\" + \\\"c\\\\(x)d\\\"\n}\n\", \"\n(function(exports) {\n  exports.y = x() + (x() + x());\n  exports.z = 'a' + x() + 'b' + ('c' + x() + 'd');\n})(this);\n\").js\n\n# Test string interpolation order with constant folding\ntest(\"\n@import\ndef x string\n\n@export {\n  var y = x + \\\"\\\\(x)\\\\(x)\\\"\n  var z = \\\"a\\\\(x)b\\\" + \\\"c\\\\(x)d\\\"\n}\n\", \"\n(function(exports) {\n  exports.y = x() + x() + x();\n  exports.z = 'a' + x() + 'bc' + x() + 'd';\n})(this);\n\").js.foldAllConstants\n\n# Check assignment operators inside global variable initializers\ntest(\"\nclass Foo {\n  var y Foo = null\n  var z = 0\n}\n\nvar x = Foo.new\n\n@export\nvar y = x.y.z += 2\n\", \"\n(function(exports) {\n  function Foo() {\n    this.y = null;\n    this.z = 0;\n  }\n\n  var ref;\n  var x = new Foo();\n  exports.y = (ref = x.y).z = ref.z + 2 | 0;\n})(this);\n\").js\n\n# Check for a crash when inlining an XML-style literal that calls a global function\ntest(\"\n@export\nvar foo = <Foo/>\n\nclass Foo {\n  def new(x int) {}\n}\n\nnamespace Foo {\n  def new Foo {\n    return Foo.new(0)\n  }\n}\n\", \"\n(function(exports) {\n  function Foo(x) {\n  }\n\n  exports.foo = new Foo(0);\n})(this);\n\").js.inlineAllFunctions\n\n# Check correct XML literal output for variable assignments\ntest(\"\n@export\nvar foo = <Foo foo=0 bar=<Foo bar=<Foo/> foo=1><Foo foo=2/></Foo>/>\n\nclass Foo {\n  var foo = 0\n  def <>...</>(x Foo) Foo { return self }\n  def bar=(x Foo) {}\n}\n\", \"\n(function(exports) {\n  function Foo() {\n    this.foo = 0;\n  }\n\n  Foo.prototype.append = function(x) {\n    return this;\n  };\n\n  Foo.prototype.setBar = function(x) {\n  };\n\n  var ref;\n  var ref1;\n  var ref2;\n  exports.foo = (ref = new Foo(), ref.foo = 0, ref.setBar((ref1 = new Foo(), ref1.setBar(new Foo()), ref1.foo = 1, ref1.append((ref2 = new Foo(), ref2.foo = 2, ref2)), ref1)), ref);\n})(this);\n\").js\n\n# Check correct XML literal output for generated closures\ntest(\"\n@export\nvar foo = <Foo>\n  for i in 0..5 {\n    <Foo foo=i/>\n  }\n</Foo>\n\nclass Foo {\n  var foo = 0\n  def <>...</>(x Foo) {}\n}\n\", \"\n(function(exports) {\n  function Foo() {\n    this.foo = 0;\n  }\n\n  Foo.prototype.append = function(x) {\n  };\n\n  var ref;\n  exports.foo = (ref = new Foo(), (function() {\n    var ref1;\n\n    for (var i = 0; i < 5; i = i + 1 | 0) {\n      ref.append((ref1 = new Foo(), ref1.foo = i, ref1));\n    }\n  })(), ref);\n})(this);\n\").js\n\n# Unused interface implementations should not be emitted\ntest(\"\ninterface IFoo {\n  def foo\n}\n\nclass Foo :: IFoo {\n  const _foo fn(Foo)\n\n  def foo {\n    _foo(self)\n  }\n}\n\n@export\ndef test(foo Foo) {\n  foo.foo\n}\n\", \"\n(function(exports) {\n  exports.test = function(foo) {\n    foo.foo();\n  };\n})(this);\n\").js\n\n# Check code generation of contextual keywords\ntest(\"\nclass Foo {\n  var class = 0\n  var def = 0\n  var enum = 0\n  var interface = 0\n  var namespace = 0\n  var over = 0\n}\n\n@export\ndef test Foo {\n  var class = 0\n  var def = 0\n  var enum = 0\n  var interface = 0\n  var namespace = 0\n  var over = 0\n  return Foo.new\n}\n\", \"\n(function(exports) {\n  function Foo() {\n    this.$class = 0;\n    this.def = 0;\n    this.$enum = 0;\n    this.$interface = 0;\n    this.namespace = 0;\n    this.over = 0;\n  }\n\n  exports.test = function() {\n    var $class = 0;\n    var def = 0;\n    var $enum = 0;\n    var $interface = 0;\n    var namespace = 0;\n    var over = 0;\n    return new Foo();\n  };\n})(this);\n\").js\n\n# Check for a crash due to a variable value changing unexpectedly after inlining\ntest(\"\ndef foo(x bool) dynamic {\n  return x\n}\n\n@entry\ndef test {\n  var bar = foo(false)\n}\n\", \"\n(function() {\n  function test() {\n    var bar = false;\n  }\n\n  test();\n})();\n\").js.inlineAllFunctions\n\n# Check code generation for flags types\ntest(\"\nflags Foo {\n  X0\n  X1\n  X2\n  X3\n  X4\n  X5\n  X6\n  X7\n  X8\n  X9\n\n  X10\n  X11\n  X12\n  X13\n  X14\n  X15\n  X16\n  X17\n  X18\n  X19\n\n  X20\n  X21\n  X22\n  X23\n  X24\n  X25\n  X26\n  X27\n  X28\n  X29\n\n  X30\n  X31\n}\n\n@entry\ndef test {\n  if (.X0 | .X1) in (Foo.X30 | .X31) {\n    var x = Foo.X0\n    x = .X1 | .X2\n    x &= ~.X3\n  }\n}\n\", \"\n(function() {\n  function test() {\n    if (((Foo.X0 | Foo.X1) & (Foo.X30 | Foo.X31)) != 0) {\n      var x = Foo.X0;\n      x = Foo.X1 | Foo.X2;\n      x &= ~Foo.X3;\n    }\n  }\n\n  var Foo = {\n    X0: 1,\n    X1: 2,\n    X2: 4,\n    X3: 8,\n    X30: 1073741824,\n    X31: -2147483648\n  };\n\n  test();\n})();\n\").js\n\n# Make sure lambda functions with dynamic type context don't return values that are known to be undefined\ntest(\"\n@entry\ndef test {\n  var a = => {}\n  var b = => a()\n  var c dynamic = => b()\n  var d dynamic = => c()\n}\n\", \"\n(function() {\n  function test() {\n    var a = function() {\n    };\n    var b = function() {\n      a();\n    };\n    var c = function() {\n      b();\n    };\n    var d = function() {\n      return c();\n    };\n  }\n\n  test();\n})();\n\").js\n\n\n# Check for constant folding a subtraction identity\ntest(\"\n@export\ndef test(x int, y double) {\n  dynamic.foo(0 + x)\n  dynamic.foo(0 - x)\n  dynamic.foo(0 + y)\n  dynamic.foo(0 - y)\n\n  dynamic.bar(x + 0)\n  dynamic.bar(x - 0)\n  dynamic.bar(y + 0)\n  dynamic.bar(y - 0)\n}\n\", \"\n(function(exports) {\n  exports.test = function(x, y) {\n    foo(x);\n    foo(-x | 0);\n    foo(y);\n    foo(-y);\n    bar(x);\n    bar(x);\n    bar(y);\n    bar(y);\n  };\n})(this);\n\").js.foldAllConstants\n\n# There's no way operator overloading will work with JavaScript, but make sure it at least generates valid JavaScript\ntest(\"\n@export\nclass Foo {\n  def + {\n    +new\n  }\n}\n\", \"\n(function(exports) {\n  exports.Foo = function() {\n  };\n\n  exports.Foo.prototype.positive = function() {\n    new exports.Foo().positive();\n  };\n})(this);\n\").js\n\n# Check for parentheses in a stupid JavaScript corner case\ntest(\"\n@export\ndef test(z dynamic) {\n  for x = 0 in z; x; x = !x {}\n  for x2 in z {}\n  var x3 = 0 in z\n}\n\", \"\n(function(exports) {\n  exports.test = function(z) {\n    for (var x = (0 in z); x; x = !x) {\n    }\n\n    for (var x2 in z) {\n    }\n\n    var x3 = 0 in z;\n  };\n})(this);\n\").js\n\n# The null dot operator shouldn't require a value inside a lambda expression\ntest(\"\n@export\ndef test(x Foo, y Foo) {\n  x?.z\n  (=> x?.z)()\n\n  x ?= y\n  (=> x ?= y)()\n}\n\nclass Foo {\n  def z {}\n}\n\", \"\n(function(exports) {\n  exports.test = function(x, y) {\n    if (x != null) {\n      x.z();\n    }\n\n    (function() {\n      if (x != null) {\n        x.z();\n      }\n    })();\n\n    if (x == null) {\n      x = y;\n    }\n\n    (function() {\n      if (x == null) {\n        x = y;\n      }\n    })();\n  };\n})(this);\n\").js\n\n# Constructors on dynamic types shouldn't need parentheses\ntest(\"\n@entry\ndef test {\n  dynamic.Foo.new\n  dynamic.Foo.new()\n  dynamic.Foo.new.test\n  dynamic.Foo.new().test\n  dynamic.Foo<dynamic.Bar>.new.test\n  dynamic.Foo<dynamic.Bar>.new().test\n\n  var a = dynamic.Foo.new\n  var b = dynamic.Foo.new()\n  var c = dynamic.Foo.new.test\n  var d = dynamic.Foo.new().test\n  var e = dynamic.Foo<dynamic.Bar>.new.test\n  var f = dynamic.Foo<dynamic.Bar>.new().test\n}\n\", \"\n(function() {\n  function test() {\n    new Foo();\n    new Foo();\n    new Foo().test;\n    new Foo().test;\n    new Foo().test;\n    new Foo().test;\n    var a = new Foo();\n    var b = new Foo();\n    var c = new Foo().test;\n    var d = new Foo().test;\n    var e = new Foo().test;\n    var f = new Foo().test;\n  }\n\n  test();\n})();\n\").js\n\ntest(\"\n@export\nvar foo = [\n  0,\n  0x7FFFFFFF,\n  -0x7FFFFFFF,\n  0x80000000,\n]\n\", \"\n(function(exports) {\n  exports.foo = [0, 2147483647, -2147483647, -2147483648];\n})(this);\n\").js\n\n# Check export syntax\ntest(\"\n@export {\n  class Class { def foo { new } }\n  enum Enum { def toString { Namespace.foo } }\n  namespace Namespace { def foo { (0 as Enum).toString } }\n  def Function {}\n  var Variable = 0\n}\n\", \"\n(function(exports) {\n  var in_Enum = {};\n\n  in_Enum.toString = function(self) {\n    exports.Namespace.foo();\n  };\n\n  exports.Function = function() {\n  };\n\n  exports.Class = function() {\n  };\n\n  exports.Class.prototype.foo = function() {\n    new exports.Class();\n  };\n\n  exports.Enum = {};\n\n  exports.Namespace = {};\n\n  exports.Namespace.foo = function() {\n    in_Enum.toString(0);\n  };\n\n  exports.Variable = 0;\n})(this);\n\").js\n\n# Check export name collisions\ntest(\"\n@export\nvar exports = 0\n\", \"\n(function(exports1) {\n  exports1.exports = 0;\n})(this);\n\").js\n\n# Make sure not to overwrite the in_IntMap namespace when generating sibling namespaces in separate passes\ntest(\"\n@entry\ndef main {\n  var x = IntMap<int>.new\n  var y = {0: 1}\n}\n\", \"\n(function() {\n  function main() {\n    var x = new Map();\n    var y = in_IntMap.insert(new Map(), 0, 1);\n  }\n\n  var in_IntMap = {};\n\n  in_IntMap.insert = function(self, key, value) {\n    self.set(key, value);\n    return self;\n  };\n\n  main();\n})();\n\").js\n\n# Check multiline comments (removed)\ntest(\"\n@entry\ndef main int {\n  ##\n  return 0\n  ##\n\n  ###\n  return 1\n  ###\n\n  ###\n  return 2\n  ### foo\n\n  ### foo\n  return 3\n  ###\n}\n\", \"\n(function() {\n  function main() {\n    ///\n    return 0;\n\n    ///\n\n    ////\n    return 1;\n\n    ////\n\n    ////\n    return 2;\n\n    //// foo\n\n    //// foo\n    return 3;\n\n    ////\n  }\n\n  process.exit(main());\n})();\n\").js\n\n# Check block comments before a statement\ntest(\"\n@entry\ndef main {\n  # This is\n  # a block\n  # comment\n\n  return\n}\n\", \"\n(function() {\n  function main() {\n    // This is\n    // a block\n    // comment\n\n    return;\n  }\n\n  main();\n})();\n\").js\n\n# Check trailing block comments\ntest(\"\n@entry\ndef main {\n  # This is\n  # a block\n  # comment\n}\n\", \"\n(function() {\n  function main() {\n    // This is\n    // a block\n    // comment\n  }\n\n  main();\n})();\n\").js\n\n# Check block comments in else statements\ntest(\"\n@export\ndef main(x bool) {\n  if x {\n    x = false\n  } else {\n    # This is\n    # a block\n    # comment\n  }\n}\n\", \"\n(function(exports) {\n  exports.main = function(x) {\n    if (x) {\n      x = false;\n    }\n\n    else {\n      // This is\n      // a block\n      // comment\n    }\n  };\n})(this);\n\").js\n\n# Comments in comma-separated lists\ntest(\"\n@entry\ndef main {\n  var x = [\n    # leading\n    # comment\n    0,\n    1, # trailing comment\n    # leading and\n    2 # trailing comment\n  ]\n}\n\", \"\n(function() {\n  function main() {\n    var x = [\n      // leading\n      // comment\n      0,\n      // trailing comment\n      1,\n      // leading and\n      // trailing comment\n      2\n    ];\n  }\n\n  main();\n})();\n\").js\n\n# Comments on case values\ntest(\"\n@export\ndef main(x int) {\n  switch x {\n    # before\n    case\n      0, # 0\n      1, # 1\n      2 # 2\n    {}\n  }\n}\n\", \"\n(function(exports) {\n  exports.main = function(x) {\n    switch (x) {\n      // before\n      // 0\n      case 0:\n      // 1\n      case 1:\n      // 2\n      case 2: {\n        break;\n      }\n    }\n  };\n})(this);\n\").js\n\n# Comments in binary expressions\ntest(\"\n@entry\ndef main int {\n  return\n    # 1\n    1 +\n    # 2\n    2 +\n    # 3\n    3\n}\n\", \"\n(function() {\n  function main() {\n    return (1 +\n      // 2\n      2 | 0) +\n      // 3\n      3 | 0;\n  }\n\n  process.exit(main());\n})();\n\").js\n\n# Comments in hook expressions\ntest(\"\n@export\ndef main(x bool) int {\n  return\n    # x\n    x ?\n    # 1\n    1 :\n    # 2\n    2\n}\n\", \"\n(function(exports) {\n  exports.main = function(x) {\n    return (\n      // x\n      x ?\n        // 1\n        1 :\n        // 2\n        2);\n  };\n})(this);\n\").js\n\n# Avoid name collisions across namespaces\ntest(\"\nnamespace A {\n  def foo { foo(1) }\n  def foo(x int) {}\n}\n\nnamespace B {\n  def foo { foo(1) }\n}\nnamespace B {\n  def foo(x int) {}\n}\n\n@entry\ndef main {\n  A.foo\n  B.foo\n}\n\", \"\n(function() {\n  function main() {\n    A.foo1();\n    B.foo1();\n  }\n\n  var A = {};\n\n  A.foo1 = function() {\n    A.foo2(1);\n  };\n\n  A.foo2 = function(x) {\n  };\n\n  var B = {};\n\n  B.foo1 = function() {\n    B.foo2(1);\n  };\n\n  B.foo2 = function(x) {\n  };\n\n  main();\n})();\n\").js\n\n  }\n}\n"
  },
  {
    "path": "tests/library.sk",
    "content": "namespace Skew.Tests {\n  def testLibrary {\n    testExpect(\"sanity check\", => toString([1, 2, 3]), \"[1, 2, 3]\")\n    testExpect(\"sanity check\", => toString([\"1\", \"2\", \"3\"]), \"[1, 2, 3]\")\n    testExpect(\"sanity check\", => toString({1: 0.5, 2: -0.5}), \"{1: 0.5, 2: -0.5}\")\n    testExpect(\"sanity check\", => toString({\"a\": 0.5, \"b\": -0.5}), \"{a: 0.5, b: -0.5}\")\n\n    # Verify lambda environment capture\n    testExpect(\"sanity check\", () string => {\n      var x = (y int) => => y\n      var a = x(1)\n      var b = x(2)\n      return (a() + b()).toString\n    }, \"3\")\n    testExpect(\"sanity check\", () string => {\n      var x = (y int) => => => => y\n      var a = x(1)\n      var b = x(2)\n      return (a()()() + b()()()).toString\n    }, \"3\")\n\n    ################################################################################\n    # Math\n\n    testExpect(\"Math.abs(2.5)\", => Math.abs(2.5), 2.5)\n    testExpect(\"Math.abs(-2.5)\", => Math.abs(-2.5), 2.5)\n    testExpect(\"Math.abs(2)\", => Math.abs(2), 2)\n    testExpect(\"Math.abs(-2)\", => Math.abs(-2), 2)\n\n    testExpect(\"Math.acos(-1)\", => Math.acos(-1), Math.PI)\n    testExpect(\"Math.acos(0)\", => Math.acos(0), Math.PI / 2)\n    testExpect(\"Math.acos(1)\", => Math.acos(1), 0)\n\n    testExpect(\"Math.asin(-1)\", => Math.asin(-1), -Math.PI / 2)\n    testExpect(\"Math.asin(0)\", => Math.asin(0), 0)\n    testExpect(\"Math.asin(1)\", => Math.asin(1), Math.PI / 2)\n\n    testExpect(\"Math.atan(0)\", => Math.atan(0), 0)\n\n    testExpect(\"Math.atan2(0, 1)\", => Math.atan2(0, 1), 0)\n    testExpect(\"Math.atan2(1, 0)\", => Math.atan2(1, 0), Math.PI / 2)\n    testExpect(\"Math.atan2(0, -1)\", => Math.atan2(0, -1), Math.PI)\n    testExpect(\"Math.atan2(-1, 0)\", => Math.atan2(-1, 0), -Math.PI / 2)\n\n    testExpect(\"Math.sin(0)\", => Math.sin(0), 0)\n    testExpect(\"Math.cos(0)\", => Math.cos(0), 1)\n    testExpect(\"Math.tan(0)\", => Math.tan(0), 0)\n\n    testExpect(\"Math.floor(1.5)\", => Math.floor(1.5), 1)\n    testExpect(\"Math.floor(-1.5)\", => Math.floor(-1.5), -2)\n    testExpect(\"Math.ceil(1.5)\", => Math.ceil(1.5), 2)\n    testExpect(\"Math.ceil(-1.5)\", => Math.ceil(-1.5), -1)\n    testExpect(\"Math.round(1.25)\", => Math.round(1.25), 1)\n    testExpect(\"Math.round(-1.25)\", => Math.round(-1.25), -1)\n    testExpect(\"Math.round(1.75)\", => Math.round(1.75), 2)\n    testExpect(\"Math.round(-1.75)\", => Math.round(-1.75), -2)\n\n    testExpect(\"Math.exp(0)\", => Math.exp(0), 1)\n    testExpect(\"Math.exp(1)\", => Math.exp(1), Math.E)\n    testExpect(\"Math.log(1)\", => Math.log(1), 0)\n    testExpect(\"Math.log(Math.E)\", => Math.log(Math.E), 1)\n    testExpect(\"Math.pow(2, 3)\", => Math.pow(2, 3), 8)\n    testExpect(\"Math.sqrt(4)\", => Math.sqrt(4), 2)\n\n    testExpect(\"0 <= Math.random < 1\", () bool => {\n      for i in 0..1000 {\n        var value = Math.random\n        if value < 0 || value >= 1 {\n          return false\n        }\n      }\n      return true\n    }, true)\n\n    testExpect(\"a <= Math.randomInRange(a, b) <= b\", () bool => {\n      for i in 0..1000 {\n        var a = Math.random\n        var b = a + Math.random\n        var value = Math.randomInRange(a, b)\n        if value < a || value > b {\n          return false\n        }\n      }\n      return true\n    }, true)\n\n    testExpect(\"a <= Math.randomInRange(a, b) < b\", () bool => {\n      for i in 0..1000 {\n        var a = (Math.random * 100) as int\n        var b = a + (Math.random * 100) as int\n        var value int = Math.randomInRange(a, b)\n        if value < a || (a != b ? value >= b : value != b) {\n          return false\n        }\n      }\n      return true\n    }, true)\n\n    testExpect(\"Math.max(-2.0, 3.0)\", => Math.max(-2.0, 3.0), 3)\n    testExpect(\"Math.min(-2.0, 3.0)\", => Math.min(-2.0, 3.0), -2)\n    testExpect(\"Math.max(3.0, -2.0)\", => Math.max(3.0, -2.0), 3)\n    testExpect(\"Math.min(3.0, -2.0)\", => Math.min(3.0, -2.0), -2)\n    testExpect(\"Math.max(-2, 3)\", => Math.max(-2, 3), 3)\n    testExpect(\"Math.min(-2, 3)\", => Math.min(-2, 3), -2)\n    testExpect(\"Math.max(3, -2)\", => Math.max(3, -2), 3)\n    testExpect(\"Math.min(3, -2)\", => Math.min(3, -2), -2)\n\n    testExpect(\"Math.max(-2.0, 0.0, 3.0)\", => Math.max(-2.0, 0.0, 3.0), 3)\n    testExpect(\"Math.min(-2.0, 0.0, 3.0)\", => Math.min(-2.0, 0.0, 3.0), -2)\n    testExpect(\"Math.max(3.0, -2.0, 0.0)\", => Math.max(3.0, -2.0, 0.0), 3)\n    testExpect(\"Math.min(3.0, -2.0, 0.0)\", => Math.min(3.0, -2.0, 0.0), -2)\n    testExpect(\"Math.max(0.0, 3.0, -2.0)\", => Math.max(0.0, 3.0, -2.0), 3)\n    testExpect(\"Math.min(0.0, 3.0, -2.0)\", => Math.min(0.0, 3.0, -2.0), -2)\n    testExpect(\"Math.max(-2, 0, 3)\", => Math.max(-2, 0, 3), 3)\n    testExpect(\"Math.min(-2, 0, 3)\", => Math.min(-2, 0, 3), -2)\n    testExpect(\"Math.max(3, -2, 0)\", => Math.max(3, -2, 0), 3)\n    testExpect(\"Math.min(3, -2, 0)\", => Math.min(3, -2, 0), -2)\n    testExpect(\"Math.max(0, 3, -2)\", => Math.max(0, 3, -2), 3)\n    testExpect(\"Math.min(0, 3, -2)\", => Math.min(0, 3, -2), -2)\n\n    testExpect(\"Math.max(-1.0, 2.0, -3.0, 4.0)\", => Math.max(-1.0, 2.0, -3.0, 4.0), 4)\n    testExpect(\"Math.min(-1.0, 2.0, -3.0, 4.0)\", => Math.min(-1.0, 2.0, -3.0, 4.0), -3)\n    testExpect(\"Math.max(4.0, -1.0, 2.0, -3.0)\", => Math.max(4.0, -1.0, 2.0, -3.0), 4)\n    testExpect(\"Math.min(4.0, -1.0, 2.0, -3.0)\", => Math.min(4.0, -1.0, 2.0, -3.0), -3)\n    testExpect(\"Math.max(-3.0, 4.0, -1.0, 2.0)\", => Math.max(-3.0, 4.0, -1.0, 2.0), 4)\n    testExpect(\"Math.min(-3.0, 4.0, -1.0, 2.0)\", => Math.min(-3.0, 4.0, -1.0, 2.0), -3)\n    testExpect(\"Math.max(2.0, -3.0, 4.0, -1.0)\", => Math.max(2.0, -3.0, 4.0, -1.0), 4)\n    testExpect(\"Math.min(2.0, -3.0, 4.0, -1.0)\", => Math.min(2.0, -3.0, 4.0, -1.0), -3)\n    testExpect(\"Math.max(-1, 2, -3, 4)\", => Math.max(-1, 2, -3, 4), 4)\n    testExpect(\"Math.min(-1, 2, -3, 4)\", => Math.min(-1, 2, -3, 4), -3)\n    testExpect(\"Math.max(4, -1, 2, -3)\", => Math.max(4, -1, 2, -3), 4)\n    testExpect(\"Math.min(4, -1, 2, -3)\", => Math.min(4, -1, 2, -3), -3)\n    testExpect(\"Math.max(-3, 4, -1, 2)\", => Math.max(-3, 4, -1, 2), 4)\n    testExpect(\"Math.min(-3, 4, -1, 2)\", => Math.min(-3, 4, -1, 2), -3)\n    testExpect(\"Math.max(2, -3, 4, -1)\", => Math.max(2, -3, 4, -1), 4)\n    testExpect(\"Math.min(2, -3, 4, -1)\", => Math.min(2, -3, 4, -1), -3)\n\n    testExpect(\"Math.clamp(-3.0, -1.0, 2.0)\", => Math.clamp(-3.0, -1.0, 2.0), -1)\n    testExpect(\"Math.clamp(3.0, -1.0, 2.0)\", => Math.clamp(3.0, -1.0, 2.0), 2)\n    testExpect(\"Math.clamp(-3, -1, 2)\", => Math.clamp(-3, -1, 2), -1)\n    testExpect(\"Math.clamp(3, -1, 2)\", => Math.clamp(3, -1, 2), 2)\n\n    testExpect(\"Math.E\", => Math.E, 2.718281828459045)\n    testExpect(\"Math.INFINITY\", => Math.INFINITY, 1 / 0.0)\n    testExpect(\"Math.NAN\", => Math.NAN, 0 / 0.0)\n    testExpect(\"Math.PI\", => Math.PI, 3.141592653589793)\n    testExpect(\"Math.SQRT_2\", => Math.SQRT_2, 1.4142135623730951)\n\n    ################################################################################\n    # bool\n\n    # Unary\n    testExpect(\"!false\", => !false, true)\n    testExpect(\"!true\", => !true, false)\n\n    # Binary\n    testExpect(\"false && false\", => false && false, false)\n    testExpect(\"false && true\", => false && true, false)\n    testExpect(\"true && false\", => true && false, false)\n    testExpect(\"true && true\", => true && true, true)\n    testExpect(\"false || false\", => false || false, false)\n    testExpect(\"false || true\", => false || true, true)\n    testExpect(\"true || false\", => true || false, true)\n    testExpect(\"true || true\", => true || true, true)\n\n    # Short-circuit\n    testExpect(\"true || (=> { throw null })()\", => (true || (=> { throw null })()).toString, \"true\")\n    testExpect(\"false && (=> { throw null })()\", => (false && (=> { throw null })()).toString, \"false\")\n\n    # toString\n    testExpect(\"false.toString\", => false.toString, \"false\")\n    testExpect(\"true.toString\", => true.toString, \"true\")\n\n    ################################################################################\n    # int\n\n    # Literals\n    testExpect(\"'a'\", => 'a', 97)\n    testExpect(\"0b101\", => 0b101, 5)\n    testExpect(\"-0b101\", => -0b101, -5)\n    testExpect(\"0o123\", => 0o123, 83)\n    testExpect(\"-0o123\", => -0o123, -83)\n    testExpect(\"0x123\", => 0x123, 291)\n    testExpect(\"-0x123\", => -0x123, -291)\n\n    # Unary\n    testExpect(\"+2\", => +2, 2)\n    testExpect(\"3++\", () int => {\n      var x = 3\n      x++\n      return x\n    }, 4)\n    testExpect(\"++3\", () int => {\n      var x = 3\n      ++x\n      return x\n    }, 4)\n    testExpect(\"-2\", => -2, -2)\n    testExpect(\"3--\", () int => {\n      var x = 3\n      x--\n      return x\n    }, 2)\n    testExpect(\"--3\", () int => {\n      var x = 3\n      --x\n      return x\n    }, 2)\n    testExpect(\"~2\", => ~2, -3)\n\n    # Binary\n    testExpect(\"5 + 3\", => 5 + 3, 8)\n    testExpect(\"5 - 3\", => 5 - 3, 2)\n    testExpect(\"5 * 3\", => 5 * 3, 15)\n    testExpect(\"5 / 3\", => 5 / 3, 1)\n    testExpect(\"5 % 3\", => 5 % 3, 2)\n    testExpect(\"-5 % 3\", => -5 % 3, -2)\n    testExpect(\"5 %% 3\", => 5 %% 3, 2)\n    testExpect(\"-5 %% 3\", => -5 %% 3, 1)\n    testExpect(\"5 %% -3\", => 5 %% -3, -1)\n    testExpect(\"-5 %% -3\", => -5 %% -3, -2)\n    testExpect(\"5 << 3\", => 5 << 3, 40)\n    testExpect(\"5 >> 1\", => 5 >> 1, 2)\n    testExpect(\"-5 >> 1\", => -5 >> 1, -3)\n    testExpect(\"5 >>> 1\", => 5 >>> 1, 2)\n    testExpect(\"-5 >>> 1\", => -5 >>> 1, 0x7FFFFFFD)\n    testExpect(\"2 ** 3\", => 2 ** 3, 8)\n    testExpect(\"44 | 33\", => 44 | 33, 45)\n    testExpect(\"44 & 33\", => 44 & 33, 32)\n    testExpect(\"44 ^ 33\", => 44 ^ 33, 13)\n    testExpect(\"-44 | 33\", => -44 | 33, -11)\n    testExpect(\"-44 & 33\", => -44 & 33, 0)\n    testExpect(\"-44 ^ 33\", => -44 ^ 33, -11)\n    testExpect(\"-44 | -33\", => -44 | -33, -33)\n    testExpect(\"-44 & -33\", => -44 & -33, -44)\n    testExpect(\"-44 ^ -33\", => -44 ^ -33, 11)\n    testExpect(\"2 <=> 5\", => 2 <=> 5, -1)\n    testExpect(\"2 <=> 2\", => 2 <=> 2, 0)\n    testExpect(\"5 <=> 2\", => 5 <=> 2, 1)\n    testExpect(\"-0x7FFFFFFF <=> 0x7FFFFFFF\", => -0x7FFFFFFF <=> 0x7FFFFFFF, -1)\n\n    # 32-bit integer multiplication\n    var imul = (a int, b int) => a * b\n    testExpect(\"0x12345678 * 0x87654321\", => imul(0x12345678, 0x87654321), 0x70B88D78)\n    testExpect(\"0x12345678 * -0x87654321\", => imul(0x12345678, -0x87654321), -0x70B88D78)\n    testExpect(\"-0xDEADF00D * -0xCAFEBABE\", => imul(-0xDEADF00D, -0xCAFEBABE), 0x14679BA6)\n\n    # Binary assignment\n    testExpect(\"5 += 3\", () int => {\n      var x = 5\n      x += 3\n      return x\n    }, 8)\n    testExpect(\"5 -= 3\", () int => {\n      var x = 5\n      x -= 3\n      return x\n    }, 2)\n    testExpect(\"5 *= 3\", () int => {\n      var x = 5\n      x *= 3\n      return x\n    }, 15)\n    testExpect(\"5 /= 3\", () int => {\n      var x = 5\n      x /= 3\n      return x\n    }, 1)\n    testExpect(\"5 %= 3\", () int => {\n      var x = 5\n      x %= 3\n      return x\n    }, 2)\n    testExpect(\"-5 %%= 3\", () int => {\n      var x = -5\n      x %%= 3\n      return x\n    }, 1)\n    testExpect(\"2 **= 3\", () int => {\n      var x = 2\n      x **= 3\n      return x\n    }, 8)\n    testExpect(\"44 |= 33\", () int => {\n      var x = 44\n      x |= 33\n      return x\n    }, 45)\n    testExpect(\"44 &= 33\", () int => {\n      var x = 44\n      x &= 33\n      return x\n    }, 32)\n    testExpect(\"44 ^= 33\", () int => {\n      var x = 44\n      x ^= 33\n      return x\n    }, 13)\n    testExpect(\"5 <<= 3\", () int => {\n      var x = 5\n      x <<= 3\n      return x\n    }, 40)\n    testExpect(\"5 >>= 1\", () int => {\n      var x = 5\n      x >>= 1\n      return x\n    }, 2)\n    testExpect(\"-5 >>= 1\", () int => {\n      var x = -5\n      x >>= 1\n      return x\n    }, -3)\n    testExpect(\"5 >>>= 1\", () int => {\n      var x = 5\n      x >>>= 1\n      return x\n    }, 2)\n    testExpect(\"-5 >>>= 1\", () int => {\n      var x = -5\n      x >>>= 1\n      return x\n    }, 0x7FFFFFFD)\n\n    testExpect(\"int.MIN\", => int.MIN, -0x7FFFFFFF - 1)\n    testExpect(\"int.MAX\", => int.MAX, 0x7FFFFFFF)\n\n    ################################################################################\n    # double\n\n    # Unary\n    testExpect(\"+2.0\", => +2.0, 2.0)\n    testExpect(\"x++\", () double => {\n      var x = 3.5\n      x++\n      return x\n    }, 4.5)\n    testExpect(\"++x\", () double => {\n      var x = 3.5\n      ++x\n      return x\n    }, 4.5)\n    testExpect(\"-2.0\", => -2.0, -2.0)\n    testExpect(\"x--\", () double => {\n      var x = 3.5\n      x--\n      return x\n    }, 2.5)\n    testExpect(\"--x\", () double => {\n      var x = 3.5\n      --x\n      return x\n    }, 2.5)\n\n    # Binary\n    testExpect(\"5.5 + 3.0\", => 5.5 + 3.0, 8.5)\n    testExpect(\"5.5 - 3.0\", => 5.5 - 3.0, 2.5)\n    testExpect(\"5.5 * 3.0\", => 5.5 * 3.0, 16.5)\n    testExpect(\"5.0 / 3.0\", => 5.0 / 3.0, 1.6666666666666667)\n    testExpect(\"5.0 %% 3.5\", => 5.0 %% 3.5, 1.5)\n    testExpect(\"-5.0 %% 3.5\", => -5.0 %% 3.5, 2)\n    testExpect(\"5.0 %% -3.5\", => 5.0 %% -3.5, -2)\n    testExpect(\"-5.0 %% -3.5\", => -5.0 %% -3.5, -1.5)\n    testExpect(\"2.0 ** 3.0\", => 2.0 ** 3.0, 8)\n    testExpect(\"2.0 ** 0.5\", => 2.0 ** 0.5, 1.4142135623730951)\n    testExpect(\"2.0 <=> 5.5\", => 2.0 <=> 5.5, -1)\n    testExpect(\"2.0 <=> 2.0\", => 2.0 <=> 2.0, 0)\n    testExpect(\"5.5 <=> 2.0\", => 5.5 <=> 2.0, 1)\n\n    # Binary assignment\n    testExpect(\"5.5 += 3.0\", () double => {\n      var x = 5.5\n      x += 3.0\n      return x\n    }, 8.5)\n    testExpect(\"5.5 -= 3.0\", () double => {\n      var x = 5.5\n      x -= 3.0\n      return x\n    }, 2.5)\n    testExpect(\"5.5 *= 3.0\", () double => {\n      var x = 5.5\n      x *= 3.0\n      return x\n    }, 16.5)\n    testExpect(\"5.0 /= 3.0\", () double => {\n      var x = 5.0\n      x /= 3.0\n      return x\n    }, 1.6666666666666667)\n    testExpect(\"-5.0 %%= 3.5\", () double => {\n      var x = -5.0\n      x %%= 3.5\n      return x\n    }, 2)\n    testExpect(\"2.0 **= 3.0\", () double => {\n      var x = 2.0\n      x **= 3\n      return x\n    }, 8)\n\n    # isFinite\n    testExpect(\"0.0.isFinite\", => 0.0.isFinite, true)\n    testExpect(\"Math.NAN.isFinite\", => Math.NAN.isFinite, false)\n    testExpect(\"Math.INFINITY.isFinite\", => Math.INFINITY.isFinite, false)\n    testExpect(\"(-Math.INFINITY).isFinite\", => (-Math.INFINITY).isFinite, false)\n\n    # isNaN\n    testExpect(\"0.0.isNaN\", => 0.0.isNaN, false)\n    testExpect(\"Math.NAN.isNaN\", => Math.NAN.isNaN, true)\n    testExpect(\"Math.INFINITY.isNaN\", => Math.INFINITY.isNaN, false)\n    testExpect(\"(-Math.INFINITY).isNaN\", => (-Math.INFINITY).isNaN, false)\n\n    ################################################################################\n    # string\n\n    # Literals\n    testExpect(\"\", => \"\", \"\")\n    testExpect(\"\\\\0\", => \"\\0\", \"\\0\")\n    testExpect(\"\\\\x00\", => \"\\x00\", \"\\0\")\n    testExpect(\"\\\\01\", => \"\\01\", \"\\0\" + \"1\")\n    testExpect(\"\\\\x001\", => \"\\x001\", \"\\0\" + \"1\")\n\n    # Binary\n    testExpect(\"\\\"a\\\\0b\\\" + \\\"x\\\\0y\\\"\", => \"a\\0b\" + \"x\\0y\", \"a\\0bx\\0y\")\n    testExpect(\"\\\"a\\\\0b\\\" += \\\"x\\\\0y\\\"\", () string => {\n      var x = \"a\\0b\"\n      x += \"x\\0y\"\n      return x\n    }, \"a\\0bx\\0y\")\n    testExpect(\"\\\"\\\\0a\\\" <=> \\\"\\\\0x\\\"\", => \"\\0a\" <=> \"\\0x\", -1)\n    testExpect(\"\\\"\\\\0a\\\" <=> \\\"\\\\0a\\\"\", => \"\\0a\" <=> \"\\0a\", 0)\n    testExpect(\"\\\"\\\\0x\\\" <=> \\\"\\\\0a\\\"\", => \"\\0x\" <=> \"\\0a\", 1)\n\n    # count\n    testExpect(\"\\\"a\\\\0b\\\".count\", => \"a\\0b\".count, 3)\n\n    # in\n    testExpect(\"\\\"a\\\\0b\\\" in \\\"a\\\\0\\\"\", => \"a\\0b\" in \"a\\0\", false)\n    testExpect(\"\\\"a\\\\0b\\\" in \\\"a\\\\0b\\\"\", => \"a\\0b\" in \"a\\0b\", true)\n    testExpect(\"\\\"a\\\\0b\\\" in \\\"a\\\\0bc\\\"\", => \"a\\0b\" in \"a\\0bc\", true)\n    testExpect(\"\\\"a\\\\0b\\\" in \\\" a\\\\0b\\\"\", => \"a\\0b\" in \" a\\0b\", true)\n    testExpect(\"\\\"a\\\\0b\\\" in \\\" a\\\\0bc\\\"\", => \"a\\0b\" in \" a\\0bc\", true)\n\n    # indexOf\n    testExpect(\"\\\"a\\\\0\\\".indexOf(\\\"a\\\\0b\\\")\", => \"a\\0\".indexOf(\"a\\0b\"), -1)\n    testExpect(\"\\\"a\\\\0b\\\".indexOf(\\\"a\\\\0b\\\")\", => \"a\\0b\".indexOf(\"a\\0b\"), 0)\n    testExpect(\"\\\" a\\\\0b \\\".indexOf(\\\"a\\\\0b\\\")\", => \" a\\0b \".indexOf(\"a\\0b\"), 1)\n    testExpect(\"\\\" a\\\\0b a\\\\0b \\\".indexOf(\\\"a\\\\0b\\\")\", => \" a\\0b a\\0b \".indexOf(\"a\\0b\"), 1)\n\n    # lastIndexOf\n    testExpect(\"\\\"a\\\\0\\\".lastIndexOf(\\\"a\\\\0b\\\")\", => \"a\\0\".lastIndexOf(\"a\\0b\"), -1)\n    testExpect(\"\\\"a\\\\0b\\\".lastIndexOf(\\\"a\\\\0b\\\")\", => \"a\\0b\".lastIndexOf(\"a\\0b\"), 0)\n    testExpect(\"\\\" a\\\\0b \\\".lastIndexOf(\\\"a\\\\0b\\\")\", => \" a\\0b \".lastIndexOf(\"a\\0b\"), 1)\n    testExpect(\"\\\" a\\\\0b a\\\\0b \\\".lastIndexOf(\\\"a\\\\0b\\\")\", => \" a\\0b a\\0b \".lastIndexOf(\"a\\0b\"), 5)\n\n    # startsWith\n    testExpect(\"\\\"a\\\\0\\\".startsWith(\\\"a\\\\0b\\\")\", => \"a\\0\".startsWith(\"a\\0b\"), false)\n    testExpect(\"\\\"a\\\\0b\\\".startsWith(\\\"a\\\\0b\\\")\", => \"a\\0b\".startsWith(\"a\\0b\"), true)\n    testExpect(\"\\\"a\\\\0bc\\\".startsWith(\\\"a\\\\0b\\\")\", => \"a\\0bc\".startsWith(\"a\\0b\"), true)\n    testExpect(\"\\\" a\\\\0b\\\".startsWith(\\\"a\\\\0b\\\")\", => \" a\\0b\".startsWith(\"a\\0b\"), false)\n\n    # endsWith\n    testExpect(\"\\\"a\\\\0\\\".endsWith(\\\"a\\\\0b\\\")\", => \"a\\0\".endsWith(\"a\\0b\"), false)\n    testExpect(\"\\\"a\\\\0b\\\".endsWith(\\\"a\\\\0b\\\")\", => \"a\\0b\".endsWith(\"a\\0b\"), true)\n    testExpect(\"\\\"a\\\\0bc\\\".endsWith(\\\"a\\\\0b\\\")\", => \"a\\0bc\".endsWith(\"a\\0b\"), false)\n    testExpect(\"\\\" a\\\\0b\\\".endsWith(\\\"a\\\\0b\\\")\", => \" a\\0b\".endsWith(\"a\\0b\"), true)\n\n    # []\n    testExpect(\"\\\"a\\\\0b\\\"[0]\", => \"a\\0b\"[0], 'a')\n    testExpect(\"\\\"a\\\\0b\\\"[1]\", => \"a\\0b\"[1], '\\0')\n    testExpect(\"\\\"a\\\\0b\\\"[2]\", => \"a\\0b\"[2], 'b')\n\n    # get\n    testExpect(\"\\\"a\\\\0b\\\".get(0)\", => \"a\\0b\".get(0), \"a\")\n    testExpect(\"\\\"a\\\\0b\\\".get(1)\", => \"a\\0b\".get(1), \"\\0\")\n    testExpect(\"\\\"a\\\\0b\\\".get(2)\", => \"a\\0b\".get(2), \"b\")\n\n    # slice\n    testExpect(\"\\\"a\\\\0b\\\".slice(1)\", => \"a\\0b\".slice(1), \"\\0b\")\n    testExpect(\"\\\"a\\\\0b\\\".slice(1, 2)\", => \"a\\0b\".slice(1, 2), \"\\0\")\n\n    # Unicode\n    testExpect(\"\\\"a\\\\0b\\\".codePoints\", => \"a\\0b\".codePoints, ['a', '\\0', 'b'])\n    testExpect(\"\\\"a\\\\0b\\\".codeUnits\", => \"a\\0b\".codeUnits, ['a', '\\0', 'b'])\n    testExpect(\"string.fromCodePoint('\\\\0')\", => string.fromCodePoint('\\0'), \"\\0\")\n    testExpect(\"string.fromCodePoint('a')\", => string.fromCodePoint('a'), \"a\")\n    testExpect(\"string.fromCodeUnit('\\\\0')\", => string.fromCodeUnit('\\0'), \"\\0\")\n    testExpect(\"string.fromCodeUnit('a')\", => string.fromCodeUnit('a'), \"a\")\n    testExpect(\"string.fromCodePoints(['a', '\\\\0', 'b'])\", => string.fromCodePoints(['a', '\\0', 'b']), \"a\\0b\")\n    testExpect(\"string.fromCodeUnits(['a', '\\\\0', 'b'])\", => string.fromCodeUnits(['a', '\\0', 'b']), \"a\\0b\")\n\n    # Other\n    testExpect(\"\\\"a \\\\0 b\\\".split(\\\" \\\")\", => \"a \\0 b\".split(\" \"), [\"a\", \"\\0\", \"b\"])\n    testExpect(\"\\\" a \\\\0 b \\\".split(\\\" \\\")\", => \" a \\0 b \".split(\" \"), [\"\", \"a\", \"\\0\", \"b\", \"\"])\n    testExpect(\"\\\" \\\".join([\\\"a\\\", \\\"\\\\0\\\", \\\"b\\\"])\", => \" \".join([\"a\", \"\\0\", \"b\"]), \"a \\0 b\")\n    testExpect(\"\\\" \\\".join([\\\"\\\", \\\"a\\\", \\\"\\\\0\\\", \\\"b\\\", \\\"\\\"])\", => \" \".join([\"\", \"a\", \"\\0\", \"b\", \"\"]), \" a \\0 b \")\n    testExpect(\"\\\"a\\\\0b\\\".repeat(3)\", => \"a\\0b\".repeat(3), \"a\\0ba\\0ba\\0b\")\n    testExpect(\"\\\"a\\\\0b\\\\0c\\\".replaceAll(\\\"\\\\0\\\", \\\"\\\\0\\\\0\\\")\", => \"a\\0b\\0c\".replaceAll(\"\\0\", \"\\0\\0\"), \"a\\0\\0b\\0\\0c\")\n    testExpect(\"\\\"a\\\\0B\\\\0c\\\\0D\\\".toUpperCase\", => \"a\\0B\\0c\\0D\".toUpperCase, \"A\\0B\\0C\\0D\")\n    testExpect(\"\\\"a\\\\0B\\\\0c\\\\0D\\\".toLowerCase\", => \"a\\0B\\0c\\0D\".toLowerCase, \"a\\0b\\0c\\0d\")\n    testExpect(\"\\\"a\\\\0B\\\\0c\\\\0D\\\".toString\", => \"a\\0B\\0c\\0D\".toString, \"a\\0B\\0c\\0D\")\n\n    ################################################################################\n    # List<T>\n\n    # new\n    testExpect(\"[] as List<int>\", => [] as List<int>, [] as List<int>)\n    testExpect(\"List<int>.new\", => List<int>.new, [] as List<int>)\n    testExpect(\"[1, 2, 3]\", => [1, 2, 3], [1, 2, 3])\n\n    # [] and []=\n    testExpect(\"[1, 2, 3][1]\", => [1, 2, 3][1], 2)\n    testExpect(\"[1, 2, 3][1] = 4\", () List<int> => {\n      var x = [1, 2, 3]\n      x[1] = 4\n      return x\n    }, [1, 4, 3])\n    testExpect(\"[1, 2, 3][1] = 4\", => [1, 2, 3][1] = 4, 4)\n\n    # count\n    testExpect(\"[1, 2, 3].count\", => [1, 2, 3].count, 3)\n\n    # isEmpty\n    testExpect(\"List<int>.new.isEmpty\", => List<int>.new.isEmpty, true)\n    testExpect(\"[1, 2, 3].isEmpty\", => [1, 2, 3].isEmpty, false)\n\n    # resize\n    testExpect(\"[1, 2, 3].resize(5, -1)\", () List<int> => {\n      var x = [1, 2, 3]\n      x.resize(5, -1)\n      return x\n    }, [1, 2, 3, -1, -1])\n    testExpect(\"[1, 2, 3].resize(1, -1)\", () List<int> => {\n      var x = [1, 2, 3]\n      x.resize(1, -1)\n      return x\n    }, [1])\n\n    # append\n    testExpect(\"[1, 2, 3].append(4)\", () List<int> => {\n      var x = [1, 2, 3]\n      x.append(4)\n      return x\n    }, [1, 2, 3, 4])\n    testExpect(\"[1, 2, 3].append([4, 5])\", () List<int> => {\n      var x = [1, 2, 3]\n      x.append([4, 5])\n      return x\n    }, [1, 2, 3, 4, 5])\n    testExpect(\"[1, 2, 3].appendOne(4)\", () List<int> => {\n      var x = [1, 2, 3]\n      x.appendOne(4)\n      return x\n    }, [1, 2, 3, 4])\n    testExpect(\"[1, 2, 3].appendOne(2)\", () List<int> => {\n      var x = [1, 2, 3]\n      x.appendOne(2)\n      return x\n    }, [1, 2, 3])\n\n    # prepend\n    testExpect(\"[1, 2, 3].prepend(4)\", () List<int> => {\n      var x = [1, 2, 3]\n      x.prepend(4)\n      return x\n    }, [4, 1, 2, 3])\n    testExpect(\"[1, 2, 3].prepend([4, 5])\", () List<int> => {\n      var x = [1, 2, 3]\n      x.prepend([4, 5])\n      return x\n    }, [4, 5, 1, 2, 3])\n\n    # insert\n    testExpect(\"[1, 2, 3].insert(1, 4)\", () List<int> => {\n      var x = [1, 2, 3]\n      x.insert(1, 4)\n      return x\n    }, [1, 4, 2, 3])\n    testExpect(\"[1, 2, 3].insert(1, [4, 5])\", () List<int> => {\n      var x = [1, 2, 3]\n      x.insert(1, [4, 5])\n      return x\n    }, [1, 4, 5, 2, 3])\n    testExpect(\"[1, 2, 3].insert(3, 4)\", () List<int> => {\n      var x = [1, 2, 3]\n      x.insert(3, 4)\n      return x\n    }, [1, 2, 3, 4])\n    testExpect(\"[1, 2, 3].insert(3, [4, 5])\", () List<int> => {\n      var x = [1, 2, 3]\n      x.insert(3, [4, 5])\n      return x\n    }, [1, 2, 3, 4, 5])\n\n    # remove\n    testExpect(\"[1, 2, 1, 3, 1].removeAll(1)\", () List<int> => {\n      var x = [1, 2, 1, 3, 1]\n      x.removeAll(1)\n      return x\n    }, [2, 3])\n    testExpect(\"[1, 2, 1, 3, 1].removeAll(0)\", () List<int> => {\n      var x = [1, 2, 1, 3, 1]\n      x.removeAll(0)\n      return x\n    }, [1, 2, 1, 3, 1])\n    testExpect(\"[1, 2, 3].removeAt(1)\", () List<int> => {\n      var x = [1, 2, 3]\n      x.removeAt(1)\n      return x\n    }, [1, 3])\n    testExpect(\"[1, 2, 1, 3, 1].removeDuplicates\", () List<int> => {\n      var x = [1, 2, 1, 3, 1]\n      x.removeDuplicates\n      return x\n    }, [1, 2, 3])\n    testExpect(\"[1, 2, 3].removeFirst\", () List<int> => {\n      var x = [1, 2, 3]\n      x.removeFirst\n      return x\n    }, [2, 3])\n    testExpect(\"[1, 2, 1, 3, 1].removeIf(y => y == 1)\", () List<int> => {\n      var x = [1, 2, 1, 3, 1]\n      x.removeIf(y => y == 1)\n      return x\n    }, [2, 3])\n    testExpect(\"[1, 2, 3].removeLast\", () List<int> => {\n      var x = [1, 2, 3]\n      x.removeLast\n      return x\n    }, [1, 2])\n    testExpect(\"[1, 2, 1, 3, 1].removeOne(1)\", () List<int> => {\n      var x = [1, 2, 1, 3, 1]\n      x.removeOne(1)\n      return x\n    }, [2, 1, 3, 1])\n    testExpect(\"[1, 2, 1, 3, 1].removeOne(0)\", () List<int> => {\n      var x = [1, 2, 1, 3, 1]\n      x.removeOne(0)\n      return x\n    }, [1, 2, 1, 3, 1])\n    testExpect(\"[1, 2, 1, 3, 1].removeRange(1, 4)\", () List<int> => {\n      var x = [1, 2, 1, 3, 1]\n      x.removeRange(1, 4)\n      return x\n    }, [1, 1])\n\n    # take\n    testExpect(\"[1, 2, 3].takeFirst\", => [1, 2, 3].takeFirst, 1)\n    testExpect(\"[1, 2, 3].takeLast\", => [1, 2, 3].takeLast, 3)\n    testExpect(\"[1, 2, 3].takeAt(1)\", => [1, 2, 3].takeAt(1), 2)\n    testExpect(\"[1, 2, 3, 4, 5].takeRange(1, 4)\", => [1, 2, 3, 4, 5].takeRange(1, 4), [2, 3, 4])\n    testExpect(\"[1, 2, 3].takeFirst\", () List<int> => {\n      var x = [1, 2, 3]\n      x.takeFirst\n      return x\n    }, [2, 3])\n    testExpect(\"[1, 2, 3].takeLast\", () List<int> => {\n      var x = [1, 2, 3]\n      x.takeLast\n      return x\n    }, [1, 2])\n    testExpect(\"[1, 2, 3].takeAt(1)\", () List<int> => {\n      var x = [1, 2, 3]\n      x.takeAt(1)\n      return x\n    }, [1, 3])\n    testExpect(\"[1, 2, 3, 4, 5].takeRange(1, 4)\", () List<int> => {\n      var x = [1, 2, 3, 4, 5]\n      x.takeRange(1, 4)\n      return x\n    }, [1, 5])\n\n    # first\n    testExpect(\"[1, 2, 3].first\", => [1, 2, 3].first, 1)\n    testExpect(\"[1, 2, 3].first = 4\", () List<int> => {\n      var x = [1, 2, 3]\n      x.first = 4\n      return x\n    }, [4, 2, 3])\n    testExpect(\"[1, 2, 3].first = 4\", => [1, 2, 3].first = 4, 4)\n\n    # last\n    testExpect(\"[1, 2, 3].last\", => [1, 2, 3].last, 3)\n    testExpect(\"[1, 2, 3].last = 4\", () List<int> => {\n      var x = [1, 2, 3]\n      x.last = 4\n      return x\n    }, [1, 2, 4])\n    testExpect(\"[1, 2, 3].last = 4\", => [1, 2, 3].last = 4, 4)\n\n    # in\n    testExpect(\"0 in [1, 2, 3]\", => 0 in [1, 2, 3], false)\n    testExpect(\"1 in [1, 2, 3]\", => 1 in [1, 2, 3], true)\n\n    # indexOf\n    testExpect(\"[1, 2, 3, 2, 1].indexOf(0)\", => [1, 2, 3, 2, 1].indexOf(0), -1)\n    testExpect(\"[1, 2, 3, 2, 1].indexOf(2)\", => [1, 2, 3, 2, 1].indexOf(2), 1)\n\n    # lastIndexOf\n    testExpect(\"[1, 2, 3, 2, 1].lastIndexOf(0)\", => [1, 2, 3, 2, 1].lastIndexOf(0), -1)\n    testExpect(\"[1, 2, 3, 2, 1].lastIndexOf(2)\", => [1, 2, 3, 2, 1].lastIndexOf(2), 3)\n\n    # all\n    testExpect(\"[1, 2, 3].all(x => x < 0)\", => [1, 2, 3].all(x => x < 0), false)\n    testExpect(\"[1, 2, 3].all(x => x > 0)\", => [1, 2, 3].all(x => x > 0), true)\n    testExpect(\"[1, 2, 3].all(x => x > 1)\", => [1, 2, 3].all(x => x > 1), false)\n\n    # any\n    testExpect(\"[1, 2, 3].any(x => x < 0)\", => [1, 2, 3].any(x => x < 0), false)\n    testExpect(\"[1, 2, 3].any(x => x > 0)\", => [1, 2, 3].any(x => x > 0), true)\n    testExpect(\"[1, 2, 3].any(x => x > 1)\", => [1, 2, 3].any(x => x > 1), true)\n\n    # clone\n    testExpect(\"[1, 2, 3].clone\", => [1, 2, 3].clone, [1, 2, 3])\n    testExpect(\"(x => x != x.clone)([1, 2, 3])\", => (x => x != x.clone)([1, 2, 3]), true)\n\n    # each\n    testExpect(\"[1, 2, 3].each(x => y += x)\", () int => {\n      var y = 0\n      [1, 2, 3].each(x => y += x)\n      return y\n    }, 6)\n\n    # equals\n    testExpect(\"[1, 2, 3].equals([1, 2, 3])\", => [1, 2, 3].equals([1, 2, 3]), true)\n    testExpect(\"[1, 2, 3].equals([3, 2, 1])\", => [1, 2, 3].equals([3, 2, 1]), false)\n    testExpect(\"[1, 2, 3, 4].equals([1, 2, 3])\", => [1, 2, 3, 4].equals([1, 2, 3]), false)\n    testExpect(\"[1, 2, 3].equals([1, 2, 3, 4])\", => [1, 2, 3].equals([1, 2, 3, 4]), false)\n\n    # filter\n    testExpect(\"[1, 2, 3, 2, 1].filter(x => x != 2)\", => [1, 2, 3, 2, 1].filter(x => x != 2), [1, 3, 1])\n    testExpect(\"(x => x != x.filter(y => true))([1, 2, 3])\", => (x => x != x.filter(y => true))([1, 2, 3]), true)\n\n    # map\n    testExpect(\"[1, 2, 3, 2, 1].map<int>(x => x + 1)\", => [1, 2, 3, 2, 1].map<int>(x => x + 1), [2, 3, 4, 3, 2])\n    testExpect(\"(x => x != x.map<int>(y => y))([1, 2, 3])\", => (x => x != x.map<int>(y => y))([1, 2, 3]), true)\n\n    # reverse\n    testExpect(\"[1, 2, 3].reverse\", () List<int> => {\n      var x = [1, 2, 3]\n      x.reverse\n      return x\n    }, [3, 2, 1])\n\n    # shuffle\n    testExpect(\"[1, 2, 3, 4, 5].shuffle\", () int => {\n      var x = [1, 2, 3, 4, 5]\n      var y = 0\n      x.shuffle\n      x.each(z => y += z)\n      return y\n    }, 1 + 2 + 3 + 4 + 5)\n\n    # slice\n    testExpect(\"[1, 2, 3].slice(1)\", => [1, 2, 3].slice(1), [2, 3])\n    testExpect(\"[1, 2, 3].slice(1, 2)\", => [1, 2, 3].slice(1, 2), [2])\n\n    # sort\n    testExpect(\"[2, 1, 3].sort((a, b) => a <=> b)\", () List<int> => {\n      var x = [2, 1, 3]\n      x.sort((a, b) => a <=> b)\n      return x\n    }, [1, 2, 3])\n\n    # swap\n    testExpect(\"[1, 2, 3].swap(0, 2)\", () List<int> => {\n      var x = [1, 2, 3]\n      x.swap(0, 2)\n      return x\n    }, [3, 2, 1])\n\n    ################################################################################\n    # IntMap<T>\n\n    # new\n    testExpect(\"{} as IntMap<double>\", => ({}) as IntMap<double>, {} as IntMap<double>)\n    testExpect(\"IntMap<double>.new\", => IntMap<double>.new, {} as IntMap<double>)\n    testExpect(\"{1: 0.5, 2: -0.5}\", => ({1: 0.5, 2: -0.5}), {1: 0.5, 2: -0.5})\n\n    # [] and []=\n    testExpect(\"{1: 0.5}[1]\", => ({1: 0.5})[1], 0.5)\n    testExpect(\"{1: 0.5}[1] = -0.5\", () IntMap<double> => {\n      var x = {1: 0.5}\n      x[1] = -0.5\n      return x\n    }, {1: -0.5})\n    testExpect(\"{1: 0.5}[1] = -0.5\", => ({1: 0.5})[1] = -0.5, -0.5)\n\n    # count\n    testExpect(\"{1: 0.5, 2: -0.5}.count\", => ({1: 0.5, 2: -0.5}).count, 2)\n\n    # isEmpty\n    testExpect(\"IntMap<double>.new.isEmpty\", => IntMap<double>.new.isEmpty, true)\n    testExpect(\"{1: 0.5, 2: -0.5}.isEmpty\", => ({1: 0.5, 2: -0.5}).isEmpty, false)\n\n    # keys\n    testExpect(\"{1: 0.5, 2: -0.5}.keys\", () List<int> => {\n      var x = {1: 0.5, 2: -0.5}.keys\n      x.sort((a, b) => a <=> b) # Sort so the order is deterministic\n      return x\n    }, [1, 2])\n\n    # values\n    testExpect(\"{1: 0.5, 2: -0.5}.values\", () List<double> => {\n      var x = {1: 0.5, 2: -0.5}.values\n      x.sort((a, b) => a <=> b) # Sort so the order is deterministic\n      return x\n    }, [-0.5, 0.5])\n\n    # clone\n    testExpect(\"{1: 0.5, 2: -0.5}.clone\", => ({1: 0.5, 2: -0.5}).clone, {1: 0.5, 2: -0.5})\n    testExpect(\"(x => x != x.clone)({1: 0.5, 2: -0.5})\", => (x => x != x.clone)({1: 0.5, 2: -0.5}), true)\n\n    # each\n    testExpect(\"{1: 0.5, 2: -0.5}.each((k, v) => x += k)\", () int => {\n      var x = 0\n      {1: 0.5, 2: -0.5}.each((k, v) => x += k)\n      return x\n    }, 3)\n    testExpect(\"{1: 0.5, 2: -1.0}.each((k, v) => x += v)\", () double => {\n      var x = 0.0\n      {1: 0.5, 2: -1.0}.each((k, v) => x += v)\n      return x\n    }, -0.5)\n\n    # get\n    testExpect(\"{1: 0.5, 2: -0.5}.get(1, -1)\", => ({1: 0.5, 2: -0.5}).get(1, -1), 0.5)\n    testExpect(\"{1: 0.5, 2: -0.5}.get(0, -1)\", => ({1: 0.5, 2: -0.5}).get(0, -1), -1)\n\n    # in\n    testExpect(\"0 in {1: 0.5, 2: -0.5}\", => 0 in {1: 0.5, 2: -0.5}, false)\n    testExpect(\"1 in {1: 0.5, 2: -0.5}\", => 1 in {1: 0.5, 2: -0.5}, true)\n\n    # remove\n    testExpect(\"{1: 0.5, 2: -0.5}.remove(1)\", () IntMap<double> => {\n      var x = {1: 0.5, 2: -0.5}\n      x.remove(1)\n      return x\n    }, {2: -0.5})\n    testExpect(\"{1: 0.5, 2: -0.5}.remove(0)\", () IntMap<double> => {\n      var x = {1: 0.5, 2: -0.5}\n      x.remove(0)\n      return x\n    }, {1: 0.5, 2: -0.5})\n\n    ################################################################################\n    # StringMap<T>\n\n    # new\n    testExpect(\"{} as StringMap<double>\", => ({}) as StringMap<double>, {} as StringMap<double>)\n    testExpect(\"StringMap<double>.new\", => StringMap<double>.new, {} as StringMap<double>)\n    testExpect(\"{\\\"\\\": 0.5, \\\"\\\\0\\\": -0.5}\", => ({\"\": 0.5, \"\\0\": -0.5}), {\"\": 0.5, \"\\0\": -0.5})\n\n    # [] and []=\n    testExpect(\"{\\\"\\\": 0.5}[\\\"\\\"]\", => ({\"\": 0.5})[\"\"], 0.5)\n    testExpect(\"{\\\"\\\": 0.5}[\\\"\\\"] = -0.5\", () StringMap<double> => {\n      var x = {\"\": 0.5}\n      x[\"\"] = -0.5\n      return x\n    }, {\"\": -0.5})\n    testExpect(\"{\\\"\\\": 0.5}[\\\"\\\"] = -0.5\", => ({\"\": 0.5})[\"\"] = -0.5, -0.5)\n\n    # count\n    testExpect(\"{\\\"\\\": 0.5, \\\"\\\\0\\\": -0.5}.count\", => ({\"\": 0.5, \"\\0\": -0.5}).count, 2)\n\n    # isEmpty\n    testExpect(\"StringMap<double>.new.isEmpty\", => StringMap<double>.new.isEmpty, true)\n    testExpect(\"{\\\"\\\": 0.5, \\\"\\\\0\\\": -0.5}.isEmpty\", => ({\"\": 0.5, \"\\0\": -0.5}).isEmpty, false)\n\n    # keys\n    testExpect(\"{\\\"\\\": 0.5, \\\"\\\\0\\\": -0.5}.keys\", () List<string> => {\n      var x = {\"\": 0.5, \"\\0\": -0.5}.keys\n      x.sort((a, b) => a <=> b) # Sort so the order is deterministic\n      return x\n    }, [\"\", \"\\0\"])\n\n    # values\n    testExpect(\"{\\\"\\\": 0.5, \\\"\\\\0\\\": -0.5}.values\", () List<double> => {\n      var x = {\"\": 0.5, \"\\0\": -0.5}.values\n      x.sort((a, b) => a <=> b) # Sort so the order is deterministic\n      return x\n    }, [-0.5, 0.5])\n\n    # clone\n    testExpect(\"{\\\"\\\": 0.5, \\\"\\\\0\\\": -0.5}.clone\", => ({\"\": 0.5, \"\\0\": -0.5}).clone, {\"\": 0.5, \"\\0\": -0.5})\n    testExpect(\"(x => x != x.clone)({\\\"\\\": 0.5, \\\"\\\\0\\\": -0.5})\", => (x => x != x.clone)({\"\": 0.5, \"\\0\": -0.5}), true)\n\n    # each\n    testExpect(\"{\\\"\\\": 0.5, \\\"\\\\0\\\": -0.5, \\\"a\\\": 0}.each((k, v) => x += k)\", () bool => {\n      var x = \"\"\n      {\"\": 0.5, \"\\0\": -0.5, \"a\": 0}.each((k, v) => x += k)\n      return x == \"a\\0\" || x == \"\\0a\"\n    }, true)\n    testExpect(\"{\\\"\\\": 0.5, \\\"\\\\0\\\": -1.0}.each((k, v) => x += v)\", () double => {\n      var x = 0.0\n      {\"\": 0.5, \"\\0\": -1.0}.each((k, v) => x += v)\n      return x\n    }, -0.5)\n\n    # get\n    testExpect(\"{\\\"\\\": 0.5, \\\"\\\\0\\\": -0.5}.get(\\\"\\\\0\\\", -1)\", => ({\"\": 0.5, \"\\0\": -0.5}).get(\"\\0\", -1), -0.5)\n    testExpect(\"{\\\"\\\": 0.5, \\\"\\\\0\\\": -0.5}.get(\\\"\\\", -1)\", => ({\"\": 0.5, \"\\0\": -0.5}).get(\"\", -1), 0.5)\n    testExpect(\"{\\\"\\\": 0.5, \\\"\\\\0\\\": -0.5}.get(\\\"x\\\", -1)\", => ({\"\": 0.5, \"\\0\": -0.5}).get(\"x\", -1), -1)\n\n    # in\n    testExpect(\"\\\"x\\\" in {\\\"\\\": 0.5, \\\"\\\\0\\\": -0.5}\", => \"x\" in {\"\": 0.5, \"\\0\": -0.5}, false)\n    testExpect(\"\\\"\\\" in {\\\"\\\": 0.5, \\\"\\\\0\\\": -0.5}\", => \"\" in {\"\": 0.5, \"\\0\": -0.5}, true)\n    testExpect(\"\\\"\\\\0\\\" in {\\\"\\\": 0.5, \\\"\\\\0\\\": -0.5}\", => \"\\0\" in {\"\": 0.5, \"\\0\": -0.5}, true)\n\n    # remove\n    testExpect(\"{\\\"\\\": 0.5, \\\"\\\\0\\\": -0.5}.remove(\\\"\\\")\", () StringMap<double> => {\n      var x = {\"\": 0.5, \"\\0\": -0.5}\n      x.remove(\"\")\n      return x\n    }, {\"\\0\": -0.5})\n    testExpect(\"{\\\"\\\": 0.5, \\\"\\\\0\\\": -0.5}.remove(\\\"x\\\")\", () StringMap<double> => {\n      var x = {\"\": 0.5, \"\\0\": -0.5}\n      x.remove(\"x\")\n      return x\n    }, {\"\": 0.5, \"\\0\": -0.5})\n\n    ################################################################################\n    # StringBuilder\n\n    testExpect(\"StringBuilder 1\", () string => {\n      var builder = StringBuilder.new\n      builder.append(\"abc\")\n      builder.append(\"\\0\")\n      builder.append(\"def\")\n      builder.append(\"\")\n      builder.append(\"xyz\")\n      return builder.toString\n    }, \"abc\\0defxyz\")\n\n    testExpect(\"StringBuilder 2\", () string => {\n      var builder = StringBuilder.new\n      builder.append(\"abc\")\n      builder.append(\"\\0\")\n      builder.toString # Calling append after toString must still append\n      builder.append(\"def\")\n      builder.append(\"\")\n      builder.append(\"xyz\")\n      return builder.toString\n    }, \"abc\\0defxyz\")\n  }\n}\n"
  },
  {
    "path": "tests/node.sk",
    "content": "enum Skew.NodeKind {\n  A\n  B\n  C\n  D\n  E\n  F\n  G\n}\n\nnamespace Skew.Tests {\n  def testNode {\n    var visit fn(Node)\n\n    visit = node => {\n      assert(node.previousSibling == null || node.previousSibling.nextSibling == node)\n      assert(node.nextSibling == null || node.nextSibling.previousSibling == node)\n      assert(node.firstChild == null || node.firstChild.previousSibling == null)\n      assert(node.lastChild == null || node.lastChild.nextSibling == null)\n\n      for child = node.firstChild; child != null; child = child.nextSibling {\n        assert(child.parent == node)\n        visit(child)\n      }\n    }\n\n    var verify = (root Node) string => {\n      if root != null {\n        visit(root)\n      }\n\n      return toString(root)\n    }\n\n    ################################################################################\n    # lastChild/previousSibling\n\n    test(\"previousSibling\", expect => {\n      expect(verify(Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C)).previousSibling), \"null\")\n    })\n\n    test(\"lastChild\", expect => {\n      expect(verify(Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C)).lastChild), \"[C]\")\n    })\n\n    test(\"lastChild.lastChild\", expect => {\n      expect(verify(Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C)).lastChild.lastChild), \"null\")\n    })\n\n    test(\"lastChild.previousSibling\", expect => {\n      expect(verify(Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C)).lastChild.previousSibling), \"[B]\")\n    })\n\n    test(\"lastChild.previousSibling.previousSibling\", expect => {\n      expect(verify(Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C)).lastChild.previousSibling.previousSibling), \"null\")\n    })\n\n    ################################################################################\n    # firstChild/nextSibling\n\n    test(\"nextSibling\", expect => {\n      expect(verify(Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C)).nextSibling), \"null\")\n    })\n\n    test(\"firstChild\", expect => {\n      expect(verify(Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C)).firstChild), \"[B]\")\n    })\n\n    test(\"firstChild.firstChild\", expect => {\n      expect(verify(Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C)).firstChild.firstChild), \"null\")\n    })\n\n    test(\"firstChild.nextSibling\", expect => {\n      expect(verify(Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C)).firstChild.nextSibling), \"[C]\")\n    })\n\n    test(\"firstChild.nextSibling.nextSibling\", expect => {\n      expect(verify(Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C)).firstChild.nextSibling.nextSibling), \"null\")\n    })\n\n    ################################################################################\n    # prependChild\n\n    test(\"prependChild 1\", expect => {\n      expect(verify(Node.new(.A).prependChild(Node.new(.B))), \"[A, [B]]\")\n    })\n\n    test(\"prependChild 2\", expect => {\n      expect(verify(Node.new(.A).prependChild(Node.new(.B)).prependChild(Node.new(.C))), \"[A, [C], [B]]\")\n    })\n\n    ################################################################################\n    # appendChild\n\n    test(\"appendChild 1\", expect => {\n      expect(verify(Node.new(.A).appendChild(Node.new(.B))), \"[A, [B]]\")\n    })\n\n    test(\"appendChild 2\", expect => {\n      expect(verify(Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C))), \"[A, [B], [C]]\")\n    })\n\n    ################################################################################\n    # appendChildrenFrom\n\n    test(\"appendChildrenFrom 1\", expect => {\n      var ABC = Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C))\n      var D = Node.new(.D)\n\n      expect((ABC == ABC.appendChildrenFrom(D)).toString, \"true\")\n      expect(verify(ABC), \"[A, [B], [C]]\")\n      expect(verify(D), \"[D]\")\n    })\n\n    test(\"appendChildrenFrom 2\", expect => {\n      var ABC = Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C))\n      var DEF = Node.new(.D).appendChild(Node.new(.E)).appendChild(Node.new(.F))\n\n      expect((ABC == ABC.appendChildrenFrom(DEF)).toString, \"true\")\n      expect(verify(ABC), \"[A, [B], [C], [E], [F]]\")\n      expect(verify(DEF), \"[D]\")\n    })\n\n    ################################################################################\n    # insertChildBefore\n\n    test(\"insertChildBefore 1\", expect => {\n      var A = Node.new(.A)\n      var B = Node.new(.B)\n\n      expect((A == A.insertChildBefore(null, null)).toString, \"true\")\n      expect(verify(A), \"[A]\")\n      expect(verify(B), \"[B]\")\n    })\n\n    test(\"insertChildBefore 2\", expect => {\n      var A = Node.new(.A)\n      var B = Node.new(.B)\n\n      expect((A == A.insertChildBefore(null, B)).toString, \"true\")\n      expect(verify(A), \"[A, [B]]\")\n      expect(verify(B), \"[B]\")\n    })\n\n    test(\"insertChildBefore 3\", expect => {\n      var AB = Node.new(.A).appendChild(Node.new(.B))\n      var C = Node.new(.C)\n\n      expect((AB == AB.insertChildBefore(null, C)).toString, \"true\")\n      expect(verify(AB), \"[A, [B], [C]]\")\n      expect(verify(C), \"[C]\")\n    })\n\n    test(\"insertChildBefore 4\", expect => {\n      var AB = Node.new(.A).appendChild(Node.new(.B))\n      var C = Node.new(.C)\n\n      expect((AB == AB.insertChildBefore(AB.firstChild, C)).toString, \"true\")\n      expect(verify(AB), \"[A, [C], [B]]\")\n      expect(verify(C), \"[C]\")\n    })\n\n    ################################################################################\n    # insertChildAfter\n\n    test(\"insertChildAfter 1\", expect => {\n      var A = Node.new(.A)\n      var B = Node.new(.B)\n\n      expect((A == A.insertChildAfter(null, null)).toString, \"true\")\n      expect(verify(A), \"[A]\")\n      expect(verify(B), \"[B]\")\n    })\n\n    test(\"insertChildAfter 2\", expect => {\n      var A = Node.new(.A)\n      var B = Node.new(.B)\n\n      expect((A == A.insertChildAfter(null, B)).toString, \"true\")\n      expect(verify(A), \"[A, [B]]\")\n      expect(verify(B), \"[B]\")\n    })\n\n    test(\"insertChildAfter 3\", expect => {\n      var AB = Node.new(.A).appendChild(Node.new(.B))\n      var C = Node.new(.C)\n\n      expect((AB == AB.insertChildAfter(null, C)).toString, \"true\")\n      expect(verify(AB), \"[A, [C], [B]]\")\n      expect(verify(C), \"[C]\")\n    })\n\n    test(\"insertChildAfter 4\", expect => {\n      var AB = Node.new(.A).appendChild(Node.new(.B))\n      var C = Node.new(.C)\n\n      expect((AB == AB.insertChildAfter(AB.firstChild, C)).toString, \"true\")\n      expect(verify(AB), \"[A, [B], [C]]\")\n      expect(verify(C), \"[C]\")\n    })\n\n    ################################################################################\n    # insertChildrenAfterFrom\n\n    test(\"insertChildrenAfterFrom 1\", expect => {\n      var A = Node.new(.A)\n      var BCD = Node.new(.B).appendChild(Node.new(.C)).appendChild(Node.new(.D))\n\n      A.insertChildrenAfterFrom(BCD, null)\n      expect(verify(A), \"[A, [C], [D]]\")\n      expect(verify(BCD), \"[B]\")\n    })\n\n    test(\"insertChildrenAfterFrom 2\", expect => {\n      var AB = Node.new(.A).appendChild(Node.new(.B))\n      var CDE = Node.new(.C).appendChild(Node.new(.D)).appendChild(Node.new(.E))\n\n      AB.insertChildrenAfterFrom(CDE, null)\n      expect(verify(AB), \"[A, [D], [E], [B]]\")\n      expect(verify(CDE), \"[C]\")\n    })\n\n    test(\"insertChildrenAfterFrom 3\", expect => {\n      var AB = Node.new(.A).appendChild(Node.new(.B))\n      var CDE = Node.new(.C).appendChild(Node.new(.D)).appendChild(Node.new(.E))\n\n      AB.insertChildrenAfterFrom(CDE, AB.firstChild)\n      expect(verify(AB), \"[A, [B], [D], [E]]\")\n      expect(verify(CDE), \"[C]\")\n    })\n\n    ################################################################################\n    # remove\n\n    test(\"remove 1\", expect => {\n      var ABC = Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C))\n      var B = ABC.firstChild.remove\n\n      expect(verify(B), \"[B]\")\n      expect(verify(ABC), \"[A, [C]]\")\n    })\n\n    test(\"remove 2\", expect => {\n      var ABC = Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C))\n      var C = ABC.lastChild.remove\n\n      expect(verify(C), \"[C]\")\n      expect(verify(ABC), \"[A, [B]]\")\n    })\n\n    ################################################################################\n    # removeChildren\n\n    test(\"removeChildren 1\", expect => {\n      var A = Node.new(.A)\n\n      A.removeChildren\n      expect(verify(A), \"[A]\")\n    })\n\n    test(\"removeChildren 2\", expect => {\n      var ABC = Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C))\n\n      ABC.removeChildren\n      expect(verify(ABC), \"[A]\")\n    })\n\n    ################################################################################\n    # replaceWith\n\n    test(\"replaceWith 1\", expect => {\n      var ABC = Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C))\n      var D = Node.new(.D)\n      var B = ABC.firstChild.replaceWith(D)\n\n      expect(verify(ABC), \"[A, [D], [C]]\")\n      expect(verify(D), \"[D]\")\n      expect(verify(B), \"[B]\")\n    })\n\n    test(\"replaceWith 2\", expect => {\n      var ABC = Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C))\n      var D = Node.new(.D)\n      var C = ABC.lastChild.replaceWith(D)\n\n      expect(verify(ABC), \"[A, [B], [D]]\")\n      expect(verify(D), \"[D]\")\n      expect(verify(C), \"[C]\")\n    })\n\n    test(\"replaceWith 3\", expect => {\n      var ABC = Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C))\n      var DEF = Node.new(.D).appendChild(Node.new(.E)).appendChild(Node.new(.F))\n      var B = ABC.firstChild.replaceWith(DEF)\n\n      expect(verify(ABC), \"[A, [D, [E], [F]], [C]]\")\n      expect(verify(DEF), \"[D, [E], [F]]\")\n      expect(verify(B), \"[B]\")\n    })\n\n    test(\"replaceWith 4\", expect => {\n      var ABC = Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C))\n      var DEF = Node.new(.D).appendChild(Node.new(.E)).appendChild(Node.new(.F))\n      var C = ABC.lastChild.replaceWith(DEF)\n\n      expect(verify(ABC), \"[A, [B], [D, [E], [F]]]\")\n      expect(verify(DEF), \"[D, [E], [F]]\")\n      expect(verify(C), \"[C]\")\n    })\n\n    ################################################################################\n    # replaceWithChildrenFrom\n\n    test(\"replaceWithChildrenFrom 1\", expect => {\n      var ABCD = Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C)).appendChild(Node.new(.D))\n      var EFG = Node.new(.E).appendChild(Node.new(.F)).appendChild(Node.new(.G))\n      var B = ABCD.firstChild.replaceWithChildrenFrom(EFG)\n\n      expect(verify(ABCD), \"[A, [F], [G], [C], [D]]\")\n      expect(verify(EFG), \"[E]\")\n      expect(verify(B), \"[B]\")\n    })\n\n    test(\"replaceWithChildrenFrom 2\", expect => {\n      var ABCD = Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C)).appendChild(Node.new(.D))\n      var EFG = Node.new(.E).appendChild(Node.new(.F)).appendChild(Node.new(.G))\n      var C = ABCD.firstChild.nextSibling.replaceWithChildrenFrom(EFG)\n\n      expect(verify(ABCD), \"[A, [B], [F], [G], [D]]\")\n      expect(verify(EFG), \"[E]\")\n      expect(verify(C), \"[C]\")\n    })\n\n    test(\"replaceWithChildrenFrom 3\", expect => {\n      var ABCD = Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C)).appendChild(Node.new(.D))\n      var EFG = Node.new(.E).appendChild(Node.new(.F)).appendChild(Node.new(.G))\n      var D = ABCD.lastChild.replaceWithChildrenFrom(EFG)\n\n      expect(verify(ABCD), \"[A, [B], [C], [F], [G]]\")\n      expect(verify(EFG), \"[E]\")\n      expect(verify(D), \"[D]\")\n    })\n\n    test(\"replaceWithChildrenFrom 4\", expect => {\n      var ABC = Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C))\n      var D = Node.new(.D)\n      var B = ABC.firstChild.replaceWithChildrenFrom(D)\n\n      expect(verify(ABC), \"[A, [C]]\")\n      expect(verify(D), \"[D]\")\n      expect(verify(B), \"[B]\")\n    })\n\n    test(\"replaceWithChildrenFrom 5\", expect => {\n      var ABC = Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C))\n      var D = Node.new(.D)\n      var C = ABC.lastChild.replaceWithChildrenFrom(D)\n\n      expect(verify(ABC), \"[A, [B]]\")\n      expect(verify(D), \"[D]\")\n      expect(verify(C), \"[C]\")\n    })\n\n    ################################################################################\n    # swapWith\n\n    test(\"swapWith 1\", expect => {\n      var ABC = Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C))\n\n      ABC.firstChild.swapWith(ABC.lastChild)\n      expect(verify(ABC), \"[A, [C], [B]]\")\n    })\n\n    test(\"swapWith 2\", expect => {\n      var ABC = Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C))\n\n      ABC.lastChild.swapWith(ABC.firstChild)\n      expect(verify(ABC), \"[A, [C], [B]]\")\n    })\n\n    test(\"swapWith 3\", expect => {\n      var ABCD = Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C)).appendChild(Node.new(.D))\n\n      ABCD.firstChild.swapWith(ABCD.lastChild)\n      expect(verify(ABCD), \"[A, [D], [C], [B]]\")\n    })\n\n    test(\"swapWith 4\", expect => {\n      var ABCD = Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C)).appendChild(Node.new(.D))\n\n      ABCD.lastChild.swapWith(ABCD.firstChild)\n      expect(verify(ABCD), \"[A, [D], [C], [B]]\")\n    })\n\n    test(\"swapWith 5\", expect => {\n      var ABCD = Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C)).appendChild(Node.new(.D))\n\n      ABCD.firstChild.swapWith(ABCD.firstChild.nextSibling)\n      expect(verify(ABCD), \"[A, [C], [B], [D]]\")\n    })\n\n    test(\"swapWith 6\", expect => {\n      var ABCD = Node.new(.A).appendChild(Node.new(.B)).appendChild(Node.new(.C)).appendChild(Node.new(.D))\n\n      ABCD.lastChild.swapWith(ABCD.lastChild.previousSibling)\n      expect(verify(ABCD), \"[A, [B], [D], [C]]\")\n    })\n  }\n}\n"
  },
  {
    "path": "tests/other.sk",
    "content": "namespace Skew.Tests {\n  def testLevenshteinEditDistance {\n    var check = (a string, b string, expected double) => {\n      testExpect(\"caseAwareLevenshteinEditDistance(\\(a), \\(b))\", => caseAwareLevenshteinEditDistance(a, b), expected)\n      testExpect(\"caseAwareLevenshteinEditDistance(\\(b), \\(a))\", => caseAwareLevenshteinEditDistance(b, a), expected)\n    }\n\n    check(\"\", \"\", 0)\n\n    check(\"x\", \"\", 1)\n    check(\"xy\", \"\", 2)\n    check(\"xyz\", \"\", 3)\n\n    check(\"x\", \"x\", 0)\n    check(\"xy\", \"x\", 1)\n    check(\"xyz\", \"x\", 2)\n\n    check(\"x\", \"z\", 1)\n    check(\"xy\", \"z\", 2)\n    check(\"xyz\", \"z\", 2)\n\n    check(\"xyz\", \"yz\", 1)\n    check(\"xyz\", \"xz\", 1)\n    check(\"xyz\", \"xy\", 1)\n\n    check(\"xyz\", \"Xyz\", 0.5)\n    check(\"xyz\", \"xYz\", 0.5)\n    check(\"xyz\", \"xyZ\", 0.5)\n\n    check(\"xyz\", \"Xyz\", 0.5)\n    check(\"xyz\", \"XYz\", 1)\n    check(\"xyz\", \"XYZ\", 1.5)\n\n    check(\"xyz\", \"1xyz\", 1)\n    check(\"xyz\", \"x1yz\", 1)\n    check(\"xyz\", \"xy1z\", 1)\n    check(\"xyz\", \"xyz1\", 1)\n\n    check(\"xxx\", \"x\", 2)\n    check(\"xxx\", \"xx\", 1)\n    check(\"xxx\", \"xxx\", 0)\n    check(\"xxx\", \"xxxx\", 1)\n    check(\"xxx\", \"xxxxx\", 2)\n\n    check(\"1xy2xy3xy4\", \"xyxyxy\", 4)\n    check(\"1xy2xy3xy4\", \"4xy3xy2xy1\", 4)\n    check(\"programming\", \"language\", 9)\n    check(\"testing\", \"(TeStInG)\", 4)\n  }\n\n  def testQuoteReplacement {\n    var check = (input string, expected string) => {\n      testExpect(\"replaceSingleQuotesWithDoubleQuotes(\\(quoteString(input, .DOUBLE, .NORMAL))) == \\(quoteString(expected, .DOUBLE, .NORMAL))\",\n        => replaceSingleQuotesWithDoubleQuotes(input), expected)\n    }\n\n    check(\"''\", \"\\\"\\\"\")\n    check(\"'abc'\", \"\\\"abc\\\"\")\n\n    # Translate quotes\n    check(\"'abc\\\\'xyz'\", \"\\\"abc'xyz\\\"\")\n    check(\"'abc\\\"xyz'\", \"\\\"abc\\\\\\\"xyz\\\"\")\n    check(\"'abc\\\\\\\"xyz'\", \"\\\"abc\\\\\\\"xyz\\\"\")\n\n    # Don't translate other escape sequences\n    check(\"'abc\\nxyz'\", \"\\\"abc\\nxyz\\\"\")\n    check(\"'abc\\\\nxyz'\", \"\\\"abc\\\\nxyz\\\"\")\n    check(\"'abc\\\\x20xyz'\", \"\\\"abc\\\\x20xyz\\\"\")\n  }\n\n  def testRanges {\n    testExpect(\"Range('abc', 0, 3).toString\", => Range.new(Source.new(\"\", \"abc\"), 0, 3).toString, \"abc\")\n    testExpect(\"Range('abc', 1, 2).toString\", => Range.new(Source.new(\"\", \"abc\"), 1, 2).toString, \"b\")\n\n    testExpect(\"Range('abc', 0, 3).rangeIncludingLeftWhitespace.toString\", => Range.new(Source.new(\"\", \"abc\"), 0, 3).rangeIncludingLeftWhitespace.toString, \"abc\")\n    testExpect(\"Range('abc', 0, 3).rangeIncludingRightWhitespace.toString\", => Range.new(Source.new(\"\", \"abc\"), 0, 3).rangeIncludingRightWhitespace.toString, \"abc\")\n\n    testExpect(\"Range('abc', 0, 3).rangeIncludingLeftWhitespace.toString\", => Range.new(Source.new(\"\", \"abc\"), 0, 3).rangeIncludingLeftWhitespace.toString, \"abc\")\n    testExpect(\"Range('abc', 1, 2).rangeIncludingRightWhitespace.toString\", => Range.new(Source.new(\"\", \"abc\"), 1, 2).rangeIncludingRightWhitespace.toString, \"b\")\n\n    testExpect(\"Range(' abc ', 1, 4).rangeIncludingLeftWhitespace.toString\", => Range.new(Source.new(\"\", \" abc \"), 1, 4).rangeIncludingLeftWhitespace.toString, \" abc\")\n    testExpect(\"Range(' abc ', 1, 4).rangeIncludingRightWhitespace.toString\", => Range.new(Source.new(\"\", \" abc \"), 1, 4).rangeIncludingRightWhitespace.toString, \"abc \")\n\n    testExpect(\"Range('[ abc ]', 2, 5).rangeIncludingLeftWhitespace.toString\", => Range.new(Source.new(\"\", \"[ abc ]\"), 2, 5).rangeIncludingLeftWhitespace.toString, \" abc\")\n    testExpect(\"Range('[ abc ]', 2, 5).rangeIncludingRightWhitespace.toString\", => Range.new(Source.new(\"\", \"[ abc ]\"), 2, 5).rangeIncludingRightWhitespace.toString, \"abc \")\n\n    testExpect(\"Range('[  abc  ]', 3, 6).rangeIncludingLeftWhitespace.toString\", => Range.new(Source.new(\"\", \"[  abc  ]\"), 3, 6).rangeIncludingLeftWhitespace.toString, \"  abc\")\n    testExpect(\"Range('[  abc  ]', 3, 6).rangeIncludingRightWhitespace.toString\", => Range.new(Source.new(\"\", \"[  abc  ]\"), 3, 6).rangeIncludingRightWhitespace.toString, \"abc  \")\n  }\n\n  class Foo {}\n  class Bar : Foo {}\n  class Baz : Bar {}\n\n  def testRuntime {\n    testExpect(\"Foo.new is Foo\", => Foo.new is Foo, true)\n    testExpect(\"Bar.new is Bar\", => Bar.new is Bar, true)\n    testExpect(\"Foo.new is Bar\", => Foo.new is Bar, false)\n    testExpect(\"Bar.new is Foo\", => Bar.new is Foo, true)\n    testExpect(\"Bar.new is Baz\", => Bar.new is Baz, false)\n  }\n}\n"
  },
  {
    "path": "tests/parsing.sk",
    "content": "namespace Skew.Tests {\n  def testParsing {\n\ntest(\"\nvar x = ''\nvar y = '1'\nvar z = '12'\n\", \"\n<stdin>:1:9: error: Use double quotes for strings (single quotes are for character literals)\nvar x = ''\n        ~~\n<stdin>:3:9: error: Use double quotes for strings (single quotes are for character literals)\nvar z = '12'\n        ~~~~\n<stdin>:1:9: fix: Replace single quotes with double quotes\nvar x = ''\n        ~~\n        [\\\"\\\"]\n<stdin>:3:9: fix: Replace single quotes with double quotes\nvar z = '12'\n        ~~~~\n        [\\\"12\\\"]\n\")\n\ntest(\"\nvar foo = [\n  0x7FFFFFFF,\n  -0x7FFFFFFF,\n  0x80000000,\n  -0x80000000,\n  0xFFFFFFFF,\n  -0xFFFFFFFF,\n  0x100000000,\n  -0x100000000,\n  0xFFFFFFFFFFFFFFFF,\n  -0xFFFFFFFFFFFFFFFF,\n]\nvar bar = [\n  2147483647,\n  -2147483647,\n  2147483648,\n  -2147483648,\n  2147483648,\n  -2147483648,\n  4294967295,\n  -4294967295,\n  4294967296,\n  -4294967296,\n  12345678901234567890,\n  -12345678901234567890,\n]\n\", \"\n<stdin>:8:3: error: Integer literal is too big to fit in 32 bits\n  0x100000000,\n  ~~~~~~~~~~~\n<stdin>:9:4: error: Integer literal is too big to fit in 32 bits\n  -0x100000000,\n   ~~~~~~~~~~~\n<stdin>:10:3: error: Integer literal is too big to fit in 32 bits\n  0xFFFFFFFFFFFFFFFF,\n  ~~~~~~~~~~~~~~~~~~\n<stdin>:11:4: error: Integer literal is too big to fit in 32 bits\n  -0xFFFFFFFFFFFFFFFF,\n   ~~~~~~~~~~~~~~~~~~\n<stdin>:22:3: error: Integer literal is too big to fit in 32 bits\n  4294967296,\n  ~~~~~~~~~~\n<stdin>:23:4: error: Integer literal is too big to fit in 32 bits\n  -4294967296,\n   ~~~~~~~~~~\n<stdin>:24:3: error: Integer literal is too big to fit in 32 bits\n  12345678901234567890,\n  ~~~~~~~~~~~~~~~~~~~~\n<stdin>:25:4: error: Integer literal is too big to fit in 32 bits\n  -12345678901234567890,\n   ~~~~~~~~~~~~~~~~~~~~\n\")\n\ntest(\"\ndef foo {\n  0;\n  var x = 0;\n  ;\n  if true {};\n  return;\n}\n\", \"\n<stdin>:2:4: error: Expected newline but found \\\";\\\"\n  0;\n   ^\n<stdin>:3:12: error: Expected newline but found \\\";\\\"\n  var x = 0;\n           ^\n<stdin>:4:3: error: Unexpected \\\";\\\"\n  ;\n  ^\n<stdin>:5:13: error: Expected newline but found \\\";\\\"\n  if true {};\n            ^\n<stdin>:6:9: error: Expected newline but found \\\";\\\"\n  return;\n        ^\n<stdin>:2:3: warning: Unused expression\n  0;\n  ^\n<stdin>:3:7: warning: Local variable \\\"x\\\" is never read\n  var x = 0;\n      ^\n<stdin>:2:4: fix: Remove \\\";\\\"\n  0;\n   ^\n   []\n<stdin>:3:12: fix: Remove \\\";\\\"\n  var x = 0;\n           ^\n           []\n<stdin>:5:13: fix: Remove \\\";\\\"\n  if true {};\n            ^\n            []\n<stdin>:6:9: fix: Remove \\\";\\\"\n  return;\n        ^\n        []\n\")\n\ntest(\"\nvar x = 0;\nvar y = 0;\n\", \"\n<stdin>:1:10: error: Expected newline but found \\\";\\\"\nvar x = 0;\n         ^\n<stdin>:2:10: error: Expected newline but found \\\";\\\"\nvar y = 0;\n         ^\n<stdin>:1:10: fix: Remove \\\";\\\"\nvar x = 0;\n         ^\n         []\n<stdin>:2:10: fix: Remove \\\";\\\"\nvar y = 0;\n         ^\n         []\n\")\n\ntest(\"\ndef main {\n  while true {} else {}\n}\n\", \"\n<stdin>:2:17: error: Unexpected \\\"else\\\"\n  while true {} else {}\n                ~~~~\n\")\n\ntest(\"\nvar x = 0b2\n\", \"\n<stdin>:1:10: error: Expected newline but found identifier\nvar x = 0b2\n         ~~\n\")\n\ntest(\"\nvar x = 0b02\n\", \"\n<stdin>:1:12: error: Expected newline but found integer\nvar x = 0b02\n           ^\n\")\n\ntest(\"\nvar x = 0o8\n\", \"\n<stdin>:1:10: error: Expected newline but found identifier\nvar x = 0o8\n         ~~\n\")\n\ntest(\"\nvar x = 0o08\n\", \"\n<stdin>:1:12: error: Expected newline but found integer\nvar x = 0o08\n           ^\n\")\n\ntest(\"\nvar x = 0xG\n\", \"\n<stdin>:1:10: error: Expected newline but found identifier\nvar x = 0xG\n         ~~\n\")\n\ntest(\"\nvar x = 0x0G\n\", \"\n<stdin>:1:12: error: Expected newline but found identifier\nvar x = 0x0G\n           ^\n\")\n\ntest(\"\nvar ns.foo int\n\", \"\n<stdin>:1:7: error: Expected newline but found \\\".\\\"\nvar ns.foo int\n      ^\n<stdin>:1:5: error: The implicitly typed variable \\\"ns\\\" must be initialized\nvar ns.foo int\n    ~~\n\")\n\ntest(\"\ndef ns.foo int\n\", \"\n<stdin>:1:7: error: Expected newline but found \\\".\\\"\ndef ns.foo int\n      ^\n<stdin>:1:5: error: Non-imported function \\\"ns\\\" is missing an implementation (use the \\\"@import\\\" annotation if it's implemented externally)\ndef ns.foo int\n    ~~\n\")\n\ntest(\"\ndef main {\n  var foo = dynamic\n}\n\", \"\n<stdin>:2:20: error: Expected \\\".\\\" but found newline\n  var foo = dynamic\n                   ^\n<stdin>:2:7: warning: Local variable \\\"foo\\\" is never read\n  var foo = dynamic\n      ~~~\n\")\n\n# Test splitting the \">>\" token\ntest(\"\nvar x List<int>>\n\", \"\n<stdin>:1:16: error: Expected newline but found \\\">\\\"\nvar x List<int>>\n               ^\n\")\n\n# Test splitting the \">=\" token\ntest(\"\nvar x List<int>==\n\", \"\n<stdin>:1:17: error: Unexpected \\\"=\\\"\nvar x List<int>==\n                ^\n\")\n\n# Test splitting the \">>>\" token\ntest(\"\nvar x List<int>>>\n\", \"\n<stdin>:1:16: error: Expected newline but found \\\">>\\\"\nvar x List<int>>>\n               ~~\n\")\n\n# Test splitting the \">>=\" token\ntest(\"\nvar x List<int>>=\n\", \"\n<stdin>:1:16: error: Expected newline but found \\\">=\\\"\nvar x List<int>>=\n               ~~\n\")\n\n# Test splitting the \">>>=\" token\ntest(\"\nvar x List<int>>>=\n\", \"\n<stdin>:1:16: error: Expected newline but found \\\">>=\\\"\nvar x List<int>>>=\n               ~~~\n\")\n\n# Test a string interpolation error case\ntest(\"\nvar x = \\\"\\\\()\\\"\n\", \"\n<stdin>:1:12: error: Unexpected string interpolation\nvar x = \\\"\\\\()\\\"\n           ~~\n\")\n\n# Test a string interpolation error case\ntest(\"\nvar x = \\\"\\\\(1)\\\\()\\\"\n\", \"\n<stdin>:1:16: error: Unexpected string interpolation\nvar x = \\\"\\\\(1)\\\\()\\\"\n               ~~\n\")\n\n# Test a string interpolation error case\ntest(\"\nvar x = \\\"\\\\([)\\\\(])\\\"\n\", \"\n<stdin>:1:14: error: Syntax error \\\"\\\\\\\"\nvar x = \\\"\\\\([)\\\\(])\\\"\n             ^\n<stdin>:1:13: error: Unexpected \\\")\\\"\nvar x = \\\"\\\\([)\\\\(])\\\"\n            ^\n\")\n\n# Test a string interpolation error case\ntest(\"\nvar x = \\\"\\\\({)\\\\(})\\\"\n\", \"\n<stdin>:1:14: error: Syntax error \\\"\\\\\\\"\nvar x = \\\"\\\\({)\\\\(})\\\"\n             ^\n<stdin>:1:13: error: Unexpected \\\")\\\"\nvar x = \\\"\\\\({)\\\\(})\\\"\n            ^\n\")\n\n# Test a string interpolation error case\ntest(\"\nvar x = \\\"\\\\(()\\\\())\\\"\n\", \"\n<stdin>:1:14: error: Syntax error \\\"\\\\\\\"\nvar x = \\\"\\\\(()\\\\())\\\"\n             ^\n<stdin>:1:15: error: Expected \\\"=>\\\" but found end of input\nvar x = \\\"\\\\(()\\\\())\\\"\n              ^\n\n\")\n\n# Test XML tag mismatch\ntest(\"\nvar foo = <Foo></Foo.Bar>\n\", \"\n<stdin>:1:18: error: Expected \\\"Foo\\\" but found \\\"Foo.Bar\\\" in XML literal\nvar foo = <Foo></Foo.Bar>\n                 ~~~~~~~\n<stdin>:1:12: note: Attempted to match opening tag here\nvar foo = <Foo></Foo.Bar>\n           ~~~\n<stdin>:1:12: error: \\\"Foo\\\" is not declared\nvar foo = <Foo></Foo.Bar>\n           ~~~\n\")\n\n# Test XML literals\ntest(\"\nvar foo = <dynamic.Foo/>\n\", \"\n<stdin>:1:12: error: Expected identifier but found \\\"dynamic\\\"\nvar foo = <dynamic.Foo/>\n           ~~~~~~~\n\")\n\n# Test XML attribute precedence\ntest(\"\nvar foo = <Foo\n  foo=bar\n  foo=++bar\n  foo=bar++\n  foo=(bar + bar)\n  foo=bar + bar\n/>\n\", \"\n<stdin>:6:11: error: Expected \\\">\\\" but found \\\"+\\\"\n  foo=bar + bar\n          ^\n\")\n\n# Test parsing XML being typed\ntest(\"\nclass Foo {\n  var foo Foo = <Foo><</Foo>\n  def <>...</>(x Foo) {}\n}\n\", \"\n<stdin>:2:22: error: Unexpected \\\"<<\\\"\n  var foo Foo = <Foo><</Foo>\n                     ~~\n<stdin>:2:24: error: Expected newline but found \\\"/\\\"\n  var foo Foo = <Foo><</Foo>\n                       ^\n<stdin>:2:25: error: Expected newline but found identifier\n  var foo Foo = <Foo><</Foo>\n                        ~~~\n<stdin>:2:28: error: Expected newline but found \\\">\\\"\n  var foo Foo = <Foo><</Foo>\n                           ^\n<stdin>:3:7: error: Expected newline but found \\\"<>...</>\\\"\n  def <>...</>(x Foo) {}\n      ~~~~~~~~\n<stdin>:3:15: error: Expected newline but found \\\"(\\\"\n  def <>...</>(x Foo) {}\n              ^\n<stdin>:3:23: error: Expected \\\"=>\\\" but found \\\"{\\\"\n  def <>...</>(x Foo) {}\n                      ^\n<stdin>:4:1: error: Expected \\\"</\\\" but found \\\"}\\\"\n}\n^\n\")\n\n# Test parsing recovery at obvious statement boundaries\ntest(\"\ndef test {\n  foo(\n  var x = 0\n  foo(\n  const y = 0\n  foo(\n  while true {}\n  foo(\n  for i in 0..5 {}\n  foo(\n  if true {}\n  foo(\n  else {}\n  foo(\n  return\n  foo(\n  break\n  foo(\n  continue\n  foo(\n  try {}\n  foo(\n  catch e dynamic {}\n  foo(\n  finally {}\n}\n\", \"\n<stdin>:3:3: error: Unexpected \\\"var\\\"\n  var x = 0\n  ~~~\n<stdin>:5:3: error: Unexpected \\\"const\\\"\n  const y = 0\n  ~~~~~\n<stdin>:7:3: error: Unexpected \\\"while\\\"\n  while true {}\n  ~~~~~\n<stdin>:9:3: error: Unexpected \\\"for\\\"\n  for i in 0..5 {}\n  ~~~\n<stdin>:11:3: error: Unexpected \\\"if\\\"\n  if true {}\n  ~~\n<stdin>:13:3: error: Unexpected \\\"else\\\"\n  else {}\n  ~~~~\n<stdin>:15:3: error: Unexpected \\\"return\\\"\n  return\n  ~~~~~~\n<stdin>:17:3: error: Unexpected \\\"break\\\"\n  break\n  ~~~~~\n<stdin>:19:3: error: Unexpected \\\"continue\\\"\n  continue\n  ~~~~~~~~\n<stdin>:21:3: error: Unexpected \\\"try\\\"\n  try {}\n  ~~~\n<stdin>:23:3: error: Unexpected \\\"catch\\\"\n  catch e dynamic {}\n  ~~~~~\n<stdin>:25:3: error: Unexpected \\\"finally\\\"\n  finally {}\n  ~~~~~~~\n<stdin>:2:3: error: \\\"foo\\\" is not declared\n  foo(\n  ~~~\n<stdin>:4:3: error: \\\"foo\\\" is not declared\n  foo(\n  ~~~\n<stdin>:6:3: error: \\\"foo\\\" is not declared\n  foo(\n  ~~~\n<stdin>:8:3: error: \\\"foo\\\" is not declared\n  foo(\n  ~~~\n<stdin>:10:3: error: \\\"foo\\\" is not declared\n  foo(\n  ~~~\n<stdin>:12:3: error: \\\"foo\\\" is not declared\n  foo(\n  ~~~\n<stdin>:14:3: error: \\\"foo\\\" is not declared\n  foo(\n  ~~~\n<stdin>:16:3: error: \\\"foo\\\" is not declared\n  foo(\n  ~~~\n<stdin>:17:3: error: Cannot use \\\"break\\\" outside a loop\n  break\n  ~~~~~\n<stdin>:18:3: error: \\\"foo\\\" is not declared\n  foo(\n  ~~~\n<stdin>:19:3: error: Cannot use \\\"continue\\\" outside a loop\n  continue\n  ~~~~~~~~\n<stdin>:20:3: error: \\\"foo\\\" is not declared\n  foo(\n  ~~~\n<stdin>:22:3: error: \\\"foo\\\" is not declared\n  foo(\n  ~~~\n<stdin>:24:3: error: \\\"foo\\\" is not declared\n  foo(\n  ~~~\n<stdin>:3:7: warning: Local variable \\\"x\\\" is never read\n  var x = 0\n      ^\n<stdin>:5:9: warning: Local variable \\\"y\\\" is never read\n  const y = 0\n        ^\n\")\n\n# Test parsing recovery after \"var\" and \"const\"\ntest(\"\ndef test {\n  var\n  var x = 0\n  const\n  const y = 0\n}\n\", \"\n<stdin>:2:6: error: Expected identifier but found newline\n  var\n     ^\n<stdin>:4:8: error: Expected identifier but found newline\n  const\n       ^\n<stdin>:3:7: warning: Local variable \\\"x\\\" is never read\n  var x = 0\n      ^\n<stdin>:5:9: warning: Local variable \\\"y\\\" is never read\n  const y = 0\n        ^\n\")\n\n# Test partial statement presence during parsing recovery\ntest(\"\n@export\ndef test {\n  var x = [\n  var y = x # This should not be a reference error about \\\"x\\\"\n}\n\", \"\n<stdin>:4:3: error: Unexpected \\\"var\\\"\n  var y = x # This should not be a reference error about \\\"x\\\"\n  ~~~\n<stdin>:4:7: warning: Local variable \\\"y\\\" is never read\n  var y = x # This should not be a reference error about \\\"x\\\"\n      ^\n\")\n\n# This should not infinite loop\ntest(\"\ndef test {\n  f(\n}\n\", \"\n<stdin>:3:1: error: Unexpected \\\"}\\\"\n}\n^\n<stdin>:2:3: error: \\\"f\\\" is not declared\n  f(\n  ^\n\")\n\n# Check for a special error message when attempting to use C-style variable declarations (complex cases aren't handled but are still tested)\ntest(\"\ndef test {\n  # Bad\n  int a = 0\n  List<int> b = []\n  fn(int) int c = x => x\n  dynamic d = null\n\n  # Good\n  var w int = 0\n  var x List<int> = []\n  var y fn(int) int = x => x\n  var z dynamic = null\n}\n\", \"\n<stdin>:3:3: error: Declare variables using \\\"var\\\" and put the type after the variable name\n  int a = 0\n  ~~~\n<stdin>:4:3: error: Declare variables using \\\"var\\\" and put the type after the variable name\n  List<int> b = []\n  ~~~~~~~~~\n<stdin>:5:11: error: Expected newline but found identifier\n  fn(int) int c = x => x\n          ~~~\n<stdin>:5:11: error: Declare variables using \\\"var\\\" and put the type after the variable name\n  fn(int) int c = x => x\n          ~~~\n<stdin>:6:11: error: Expected \\\".\\\" but found identifier\n  dynamic d = null\n          ^\n<stdin>:5:3: error: \\\"fn\\\" is not declared\n  fn(int) int c = x => x\n  ~~\n<stdin>:5:6: error: Unexpected type \\\"int\\\"\n  fn(int) int c = x => x\n     ~~~\n<stdin>:5:19: error: Unable to determine the type of \\\"x\\\"\n  fn(int) int c = x => x\n                  ^\n<stdin>:5:19: error: Cannot convert from type \\\"fn(dynamic) dynamic\\\" to type \\\"int\\\"\n  fn(int) int c = x => x\n                  ~~~~~~\n<stdin>:6:11: error: \\\"d\\\" is not declared\n  dynamic d = null\n          ^\n<stdin>:3:7: warning: Local variable \\\"a\\\" is never read\n  int a = 0\n      ^\n<stdin>:4:13: warning: Local variable \\\"b\\\" is never read\n  List<int> b = []\n            ^\n<stdin>:5:15: warning: Local variable \\\"c\\\" is never read\n  fn(int) int c = x => x\n              ^\n<stdin>:9:7: warning: Local variable \\\"w\\\" is never read\n  var w int = 0\n      ^\n<stdin>:10:7: warning: Local variable \\\"x\\\" is never read\n  var x List<int> = []\n      ^\n<stdin>:11:7: warning: Local variable \\\"y\\\" is never read\n  var y fn(int) int = x => x\n      ^\n<stdin>:12:7: warning: Local variable \\\"z\\\" is never read\n  var z dynamic = null\n      ^\n<stdin>:3:3: fix: Declare \\\"a\\\" correctly\n  int a = 0\n  ~~~~~\n  [var a int]\n<stdin>:4:3: fix: Declare \\\"b\\\" correctly\n  List<int> b = []\n  ~~~~~~~~~~~\n  [var b List<int>]\n<stdin>:5:11: fix: Declare \\\"c\\\" correctly\n  fn(int) int c = x => x\n          ~~~~~\n          [var c int]\n\")\n\n# Check for issues with parsing type parameters and string interpolation\ntest(\"\nvar a = \\\"\\\\(x > y)\\\"\nvar b = \\\"\\\\(x < y)\\\"\nvar c = \\\"\\\\(x <= y)\\\"\nvar d = \\\"\\\\(x >= y)\\\"\nvar e = \\\"\\\\(x <=> y)\\\"\n\", \"\n<stdin>:1:12: error: \\\"x\\\" is not declared\nvar a = \\\"\\\\(x > y)\\\"\n           ^\n<stdin>:1:16: error: \\\"y\\\" is not declared\nvar a = \\\"\\\\(x > y)\\\"\n               ^\n<stdin>:2:12: error: \\\"x\\\" is not declared\nvar b = \\\"\\\\(x < y)\\\"\n           ^\n<stdin>:2:16: error: \\\"y\\\" is not declared\nvar b = \\\"\\\\(x < y)\\\"\n               ^\n<stdin>:3:12: error: \\\"x\\\" is not declared\nvar c = \\\"\\\\(x <= y)\\\"\n           ^\n<stdin>:3:17: error: \\\"y\\\" is not declared\nvar c = \\\"\\\\(x <= y)\\\"\n                ^\n<stdin>:4:12: error: \\\"x\\\" is not declared\nvar d = \\\"\\\\(x >= y)\\\"\n           ^\n<stdin>:4:17: error: \\\"y\\\" is not declared\nvar d = \\\"\\\\(x >= y)\\\"\n                ^\n<stdin>:5:12: error: \\\"x\\\" is not declared\nvar e = \\\"\\\\(x <=> y)\\\"\n           ^\n<stdin>:5:18: error: \\\"y\\\" is not declared\nvar e = \\\"\\\\(x <=> y)\\\"\n                 ^\n\")\n\n# Check that comma separated variables are parsed correctly\ntest(\"\nvar a int, b int\nvar c = 1, d = 2\nconst e = 3, f = 4\n\nclass Foo {\n  var a int, b int\n  var c = 1, d = 2\n  const e = 3, f = 4\n}\n\ndef test {\n  var a int, b int\n  var c = 1, d = 2\n  const e = 3, f = 4\n}\n\", \"\n<stdin>:12:7: warning: Local variable \\\"a\\\" is never read\n  var a int, b int\n      ^\n<stdin>:12:14: warning: Local variable \\\"b\\\" is never read\n  var a int, b int\n             ^\n<stdin>:13:7: warning: Local variable \\\"c\\\" is never read\n  var c = 1, d = 2\n      ^\n<stdin>:13:14: warning: Local variable \\\"d\\\" is never read\n  var c = 1, d = 2\n             ^\n<stdin>:14:9: warning: Local variable \\\"e\\\" is never read\n  const e = 3, f = 4\n        ^\n<stdin>:14:16: warning: Local variable \\\"f\\\" is never read\n  const e = 3, f = 4\n               ^\n\")\n\n# Check that using braces on the next line works\ntest(\"\nclass Foo : int\n{\n  def test\n  {\n    if true\n    {\n    }\n\n    else if false\n    {\n    }\n\n    else\n    {\n    }\n\n    while true\n    {\n    }\n\n    for x = 0; x < 1; x++\n    {\n    }\n\n    for x in 1..2\n    {\n    }\n\n    switch 0\n    {\n      case 0\n      {\n      }\n\n      case 1, 2\n      {\n      }\n\n      default\n      {\n      }\n    }\n\n    try\n    {\n    }\n\n    catch e dynamic\n    {\n    }\n\n    finally\n    {\n    }\n\n    =>\n    {\n    }\n  }\n}\n\", \"\n<stdin>:1:13: error: Cannot extend type \\\"int\\\"\nclass Foo : int\n            ~~~\n<stdin>:57:5: error: Cannot infer a type for this literal\n    {\n    ^\n<stdin>:56:5: warning: Unused expression\n    =>\n    ~~\n\")\n\n# Check for a crash due to a type comparison on a dot expression with an implicit target\ntest(\"\ndef test {\n  switch 0 {\n    case .X {\n    case .Y {}\n  }\n}\n\", \"\n<stdin>:4:5: error: Unexpected \\\"case\\\"\n    case .Y {}\n    ~~~~\n<stdin>:4:10: error: Expected newline but found \\\".\\\"\n    case .Y {}\n         ^\n<stdin>:4:13: error: Expected newline but found \\\"{\\\"\n    case .Y {}\n            ^\n<stdin>:6:2: error: Expected newline but found end of input\n}\n ^\n\")\n\n# Allow commas between enums and allow enums between other declarations\ntest(\"\nenum Foo {\n  def x {}\n  A, B\n  X, Y\n  def y {}\n}\n\", \"\n\")\n\n# Forbid invalid enum names\ntest(\"\nenum Foo {\n  def, A\n}\n\", \"\n<stdin>:2:6: error: Expected identifier but found \\\",\\\"\n  def, A\n     ^\n\")\n\n# Forbid invalid enum names\ntest(\"\nenum Foo {\n  A, def\n}\n\", \"\n<stdin>:2:6: error: Expected newline but found identifier\n  A, def\n     ~~~\n\")\n\n# Warn about extra commas\ntest(\"\nenum Foo {\n  A, B,\n  X, Y,\n}\nenum Bar { A, B, }\n\", \"\n<stdin>:2:7: warning: Unnecessary comma\n  A, B,\n      ^\n<stdin>:3:7: warning: Unnecessary comma\n  X, Y,\n      ^\n<stdin>:5:16: warning: Unnecessary comma\nenum Bar { A, B, }\n               ^\n<stdin>:2:7: fix: Remove comma\n  A, B,\n      ^\n      []\n<stdin>:3:7: fix: Remove comma\n  X, Y,\n      ^\n      []\n<stdin>:5:16: fix: Remove comma\nenum Bar { A, B, }\n               ^\n               []\n\")\n\n# Test comment removal inside expressions\ntest(\"\ndef test {\n  0\n    .foo\n\n  0 # x\n    .foo\n\n  0\n    # x\n    .foo\n\n  0 # x\n    # x\n    .foo\n\n  true\n    ? 0\n    : 0\n\n  true # x\n    ? 0 # x\n    : 0\n\n  true\n    # x\n    ? 0\n    # x\n    : 0\n\n  true # x\n    # x\n    ? 0 # x\n    # x\n    : 0\n\n  foo(\n    0\n    , 1\n    )\n\n  foo(\n    0 # x\n    , 1 # x\n    )\n\n  foo(\n    0\n    # x\n    , 1\n    # x\n    )\n\n  foo(\n    0 # x\n    # x\n    , 1 # x\n    # x\n    )\n\n  [\n    null\n    , 1\n    ]\n\n  [\n    null # x\n    , 1 # x\n    ]\n\n  [\n    null\n    # x\n    , 1\n    # x\n    ]\n\n  [\n    null # x\n    # x\n    , 1 # x\n    # x\n    ]\n}\n\", \"\n<stdin>:3:6: error: \\\"foo\\\" is not declared on type \\\"int\\\"\n    .foo\n     ~~~\n<stdin>:6:6: error: \\\"foo\\\" is not declared on type \\\"int\\\"\n    .foo\n     ~~~\n<stdin>:10:6: error: \\\"foo\\\" is not declared on type \\\"int\\\"\n    .foo\n     ~~~\n<stdin>:14:6: error: \\\"foo\\\" is not declared on type \\\"int\\\"\n    .foo\n     ~~~\n<stdin>:17:7: warning: Both sides of \\\":\\\" are identical, is this a bug?\n    ? 0\n      ^\n<stdin>:17:7: warning: Unused expression\n    ? 0\n      ^\n<stdin>:18:7: warning: Unused expression\n    : 0\n      ^\n<stdin>:21:7: warning: Both sides of \\\":\\\" are identical, is this a bug?\n    ? 0 # x\n      ~~~~~\n<stdin>:21:7: warning: Unused expression\n    ? 0 # x\n      ^\n<stdin>:22:7: warning: Unused expression\n    : 0\n      ^\n<stdin>:26:7: warning: Both sides of \\\":\\\" are identical, is this a bug?\n    ? 0\n      ^\n<stdin>:26:7: warning: Unused expression\n    ? 0\n      ^\n<stdin>:28:7: warning: Unused expression\n    : 0\n      ^\n<stdin>:32:7: warning: Both sides of \\\":\\\" are identical, is this a bug?\n    ? 0 # x\n      ~~~~~\n<stdin>:32:7: warning: Unused expression\n    ? 0 # x\n      ^\n<stdin>:34:7: warning: Unused expression\n    : 0\n      ^\n<stdin>:36:3: error: \\\"foo\\\" is not declared\n  foo(\n  ~~~\n<stdin>:41:3: error: \\\"foo\\\" is not declared\n  foo(\n  ~~~\n<stdin>:46:3: error: \\\"foo\\\" is not declared\n  foo(\n  ~~~\n<stdin>:53:3: error: \\\"foo\\\" is not declared\n  foo(\n  ~~~\n<stdin>:62:7: error: No common type for \\\"null\\\" and \\\"int\\\"\n    , 1\n      ^\n<stdin>:60:3: warning: Unused expression\n  [\n  ^\n<stdin>:67:7: error: No common type for \\\"null\\\" and \\\"int\\\"\n    , 1 # x\n      ^\n<stdin>:65:3: warning: Unused expression\n  [\n  ^\n<stdin>:73:7: error: No common type for \\\"null\\\" and \\\"int\\\"\n    , 1\n      ^\n<stdin>:70:3: warning: Unused expression\n  [\n  ^\n<stdin>:80:7: error: No common type for \\\"null\\\" and \\\"int\\\"\n    , 1 # x\n      ^\n<stdin>:77:3: warning: Unused expression\n  [\n  ^\n\")\n\n# Check comment corrections\ntest(\"\nvar x int = false //this is a test\nvar y int = false // this is also a test\n//////////\n\", \"\n<stdin>:1:19: error: Comments start with \\\"#\\\" instead of \\\"//\\\"\nvar x int = false //this is a test\n                  ~~~~~~~~~~~~~~~~\n<stdin>:2:19: error: Comments start with \\\"#\\\" instead of \\\"//\\\"\nvar y int = false // this is also a test\n                  ~~~~~~~~~~~~~~~~~~~~~~\n<stdin>:3:1: error: Comments start with \\\"#\\\" instead of \\\"//\\\"\n//////////\n~~~~~~~~~~\n<stdin>:1:13: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\nvar x int = false //this is a test\n            ~~~~~\n<stdin>:2:13: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\nvar y int = false // this is also a test\n            ~~~~~\n<stdin>:1:19: fix: Replace \\\"//\\\" with \\\"#\\\"\nvar x int = false //this is a test\n                  ~~~~~~~~~~~~~~~~\n                  [#this is a test]\n<stdin>:2:19: fix: Replace \\\"//\\\" with \\\"#\\\"\nvar y int = false // this is also a test\n                  ~~~~~~~~~~~~~~~~~~~~~~\n                  [# this is also a test]\n<stdin>:3:1: fix: Replace \\\"//\\\" with \\\"#\\\"\n//////////\n~~~~~~~~~~\n[#########]\n\")\n\n# Check == and != corrections\ntest(\"\nvar x = 0 === 1\nvar y = 0 !== 1\n\", \"\n<stdin>:1:11: error: Use the \\\"==\\\" operator instead\nvar x = 0 === 1\n          ~~~\n<stdin>:2:11: error: Use the \\\"!=\\\" operator instead\nvar y = 0 !== 1\n          ~~~\n<stdin>:1:11: fix: Replace with \\\"==\\\"\nvar x = 0 === 1\n          ~~~\n          [==]\n<stdin>:2:11: fix: Replace with \\\"!=\\\"\nvar y = 0 !== 1\n          ~~~\n          [!=]\n\")\n\n# Check List<T> corrections\ntest(\"\nvar a int[] = []\nvar b Foo.Bar.Baz[] = []\nvar c Foo<T, fn() int>[] = []\nvar d fn() int[] = null\n\", \"\n<stdin>:1:7: error: The array type is \\\"List<T>\\\"\nvar a int[] = []\n      ~~~~~\n<stdin>:2:7: error: The array type is \\\"List<T>\\\"\nvar b Foo.Bar.Baz[] = []\n      ~~~~~~~~~~~~~\n<stdin>:3:7: error: The array type is \\\"List<T>\\\"\nvar c Foo<T, fn() int>[] = []\n      ~~~~~~~~~~~~~~~~~~\n<stdin>:4:12: error: The array type is \\\"List<T>\\\"\nvar d fn() int[] = null\n           ~~~~~\n<stdin>:1:7: fix: Replace with \\\"List<int>\\\"\nvar a int[] = []\n      ~~~~~\n      [List<int>]\n<stdin>:2:7: fix: Replace with \\\"List<Foo.Bar.Baz>\\\"\nvar b Foo.Bar.Baz[] = []\n      ~~~~~~~~~~~~~\n      [List<Foo.Bar.Baz>]\n<stdin>:3:7: fix: Replace with \\\"List<Foo<T, fn() int>>\\\"\nvar c Foo<T, fn() int>[] = []\n      ~~~~~~~~~~~~~~~~~~\n      [List<Foo<T, fn() int>>]\n<stdin>:4:12: fix: Replace with \\\"List<int>\\\"\nvar d fn() int[] = null\n           ~~~~~\n           [List<int>]\n\")\n\n# Check parentheses corrections on statements\ntest(\"\ndef test {\n  while (true) {}\n  for (i in 0..5) {}\n  for (i in [1, 2, 3]) {}\n  for (i = 0; i < 10; i++) {}\n  for (var i = 0; i < 10; i++) {}\n  for var i = 0; i < 10; i++ {}\n  if (true) {} else if (true) {}\n\n  while(true) {}\n  for(i in 0..5) {}\n  for(i in [1, 2, 3]) {}\n  for(i = 0; i < 10; i++) {}\n  for(var i = 0; i < 10; i++) {}\n  if(true) {} else if(true) {}\n}\n\", \"\n<stdin>:2:9: warning: Unnecessary parentheses\n  while (true) {}\n        ~~~~~~\n<stdin>:3:7: warning: Unnecessary parentheses\n  for (i in 0..5) {}\n      ~~~~~~~~~~~\n<stdin>:4:7: warning: Unnecessary parentheses\n  for (i in [1, 2, 3]) {}\n      ~~~~~~~~~~~~~~~~\n<stdin>:5:7: warning: Unnecessary parentheses\n  for (i = 0; i < 10; i++) {}\n      ~~~~~~~~~~~~~~~~~~~~\n<stdin>:6:8: error: The \\\"var\\\" keyword is unnecessary here since for loops automatically declare their variables\n  for (var i = 0; i < 10; i++) {}\n       ~~~\n<stdin>:6:7: warning: Unnecessary parentheses\n  for (var i = 0; i < 10; i++) {}\n      ~~~~~~~~~~~~~~~~~~~~~~~~\n<stdin>:7:7: error: The \\\"var\\\" keyword is unnecessary here since for loops automatically declare their variables\n  for var i = 0; i < 10; i++ {}\n      ~~~\n<stdin>:8:6: warning: Unnecessary parentheses\n  if (true) {} else if (true) {}\n     ~~~~~~\n<stdin>:8:24: warning: Unnecessary parentheses\n  if (true) {} else if (true) {}\n                       ~~~~~~\n<stdin>:10:8: warning: Unnecessary parentheses\n  while(true) {}\n       ~~~~~~\n<stdin>:11:6: warning: Unnecessary parentheses\n  for(i in 0..5) {}\n     ~~~~~~~~~~~\n<stdin>:12:6: warning: Unnecessary parentheses\n  for(i in [1, 2, 3]) {}\n     ~~~~~~~~~~~~~~~~\n<stdin>:13:6: warning: Unnecessary parentheses\n  for(i = 0; i < 10; i++) {}\n     ~~~~~~~~~~~~~~~~~~~~\n<stdin>:14:7: error: The \\\"var\\\" keyword is unnecessary here since for loops automatically declare their variables\n  for(var i = 0; i < 10; i++) {}\n      ~~~\n<stdin>:14:6: warning: Unnecessary parentheses\n  for(var i = 0; i < 10; i++) {}\n     ~~~~~~~~~~~~~~~~~~~~~~~~\n<stdin>:15:5: warning: Unnecessary parentheses\n  if(true) {} else if(true) {}\n    ~~~~~~\n<stdin>:15:22: warning: Unnecessary parentheses\n  if(true) {} else if(true) {}\n                     ~~~~~~\n<stdin>:2:9: fix: Remove parentheses\n  while (true) {}\n        ~~~~~~\n        [true]\n<stdin>:3:7: fix: Remove parentheses\n  for (i in 0..5) {}\n      ~~~~~~~~~~~\n      [i in 0..5]\n<stdin>:4:7: fix: Remove parentheses\n  for (i in [1, 2, 3]) {}\n      ~~~~~~~~~~~~~~~~\n      [i in [1, 2, 3]]\n<stdin>:5:7: fix: Remove parentheses\n  for (i = 0; i < 10; i++) {}\n      ~~~~~~~~~~~~~~~~~~~~\n      [i = 0; i < 10; i++]\n<stdin>:6:8: fix: Remove \\\"var\\\"\n  for (var i = 0; i < 10; i++) {}\n       ~~~~\n       []\n<stdin>:6:7: fix: Remove parentheses\n  for (var i = 0; i < 10; i++) {}\n      ~~~~~~~~~~~~~~~~~~~~~~~~\n      [var i = 0; i < 10; i++]\n<stdin>:7:7: fix: Remove \\\"var\\\"\n  for var i = 0; i < 10; i++ {}\n      ~~~~\n      []\n<stdin>:8:6: fix: Remove parentheses\n  if (true) {} else if (true) {}\n     ~~~~~~\n     [true]\n<stdin>:8:24: fix: Remove parentheses\n  if (true) {} else if (true) {}\n                       ~~~~~~\n                       [true]\n<stdin>:10:8: fix: Remove parentheses\n  while(true) {}\n       ~~~~~~\n       [ true]\n<stdin>:11:6: fix: Remove parentheses\n  for(i in 0..5) {}\n     ~~~~~~~~~~~\n     [ i in 0..5]\n<stdin>:12:6: fix: Remove parentheses\n  for(i in [1, 2, 3]) {}\n     ~~~~~~~~~~~~~~~~\n     [ i in [1, 2, 3]]\n<stdin>:13:6: fix: Remove parentheses\n  for(i = 0; i < 10; i++) {}\n     ~~~~~~~~~~~~~~~~~~~~\n     [ i = 0; i < 10; i++]\n<stdin>:14:7: fix: Remove \\\"var\\\"\n  for(var i = 0; i < 10; i++) {}\n      ~~~~\n      []\n<stdin>:14:6: fix: Remove parentheses\n  for(var i = 0; i < 10; i++) {}\n     ~~~~~~~~~~~~~~~~~~~~~~~~\n     [ var i = 0; i < 10; i++]\n<stdin>:15:5: fix: Remove parentheses\n  if(true) {} else if(true) {}\n    ~~~~~~\n    [ true]\n<stdin>:15:22: fix: Remove parentheses\n  if(true) {} else if(true) {}\n                     ~~~~~~\n                     [ true]\n\")\n\n# Check for colon-before-type corrections\ntest(\"\nvar a: int, b: int\n\ndef c(d: int, e: int): int {\n  var f: int, g: int\n  var h = (i: int, j: int) => {}\n}\n\", \"\n<stdin>:1:6: error: Do not use a colon before a type expression\nvar a: int, b: int\n     ^\n<stdin>:1:14: error: Do not use a colon before a type expression\nvar a: int, b: int\n             ^\n<stdin>:3:8: error: Do not use a colon before a type expression\ndef c(d: int, e: int): int {\n       ^\n<stdin>:3:16: error: Do not use a colon before a type expression\ndef c(d: int, e: int): int {\n               ^\n<stdin>:3:22: error: Do not use a colon before a type expression\ndef c(d: int, e: int): int {\n                     ^\n<stdin>:4:8: error: Do not use a colon before a type expression\n  var f: int, g: int\n       ^\n<stdin>:4:16: error: Do not use a colon before a type expression\n  var f: int, g: int\n               ^\n<stdin>:5:13: error: Do not use a colon before a type expression\n  var h = (i: int, j: int) => {}\n            ^\n<stdin>:5:21: error: Do not use a colon before a type expression\n  var h = (i: int, j: int) => {}\n                    ^\n<stdin>:3:5: error: All control paths for \\\"c\\\" must return a value of type \\\"int\\\"\ndef c(d: int, e: int): int {\n    ^\n<stdin>:4:7: warning: Local variable \\\"f\\\" is never read\n  var f: int, g: int\n      ^\n<stdin>:4:15: warning: Local variable \\\"g\\\" is never read\n  var f: int, g: int\n              ^\n<stdin>:5:7: warning: Local variable \\\"h\\\" is never read\n  var h = (i: int, j: int) => {}\n      ^\n<stdin>:1:6: fix: Remove the colon\nvar a: int, b: int\n     ^\n     []\n<stdin>:1:14: fix: Remove the colon\nvar a: int, b: int\n             ^\n             []\n<stdin>:3:8: fix: Remove the colon\ndef c(d: int, e: int): int {\n       ^\n       []\n<stdin>:3:16: fix: Remove the colon\ndef c(d: int, e: int): int {\n               ^\n               []\n<stdin>:3:22: fix: Remove the colon\ndef c(d: int, e: int): int {\n                     ^\n                     []\n<stdin>:4:8: fix: Remove the colon\n  var f: int, g: int\n       ^\n       []\n<stdin>:4:16: fix: Remove the colon\n  var f: int, g: int\n               ^\n               []\n<stdin>:5:13: fix: Remove the colon\n  var h = (i: int, j: int) => {}\n            ^\n            []\n<stdin>:5:21: fix: Remove the colon\n  var h = (i: int, j: int) => {}\n                    ^\n                    []\n\")\n\n# Check for colon-before-type corrections\ntest(\"\ndef test {\n  var a = new Foo\n  var b = new Foo().foo\n  var c = new Foo.Bar<T>.Baz().foo\n}\n\", \"\n<stdin>:2:11: error: There is no \\\"new\\\" operator, use \\\"Foo.new\\\" instead\n  var a = new Foo\n          ~~~~~~~\n<stdin>:3:11: error: There is no \\\"new\\\" operator, use \\\"Foo.new\\\" instead\n  var b = new Foo().foo\n          ~~~~~~~\n<stdin>:4:11: error: There is no \\\"new\\\" operator, use \\\"Foo.Bar<T>.Baz.new\\\" instead\n  var c = new Foo.Bar<T>.Baz().foo\n          ~~~~~~~~~~~~~~~~~~\n<stdin>:2:7: warning: Local variable \\\"a\\\" is never read\n  var a = new Foo\n      ^\n<stdin>:3:7: warning: Local variable \\\"b\\\" is never read\n  var b = new Foo().foo\n      ^\n<stdin>:4:7: warning: Local variable \\\"c\\\" is never read\n  var c = new Foo.Bar<T>.Baz().foo\n      ^\n<stdin>:2:11: fix: Replace with \\\"Foo.new\\\"\n  var a = new Foo\n          ~~~~~~~\n          [Foo.new]\n<stdin>:3:11: fix: Replace with \\\"Foo.new\\\"\n  var b = new Foo().foo\n          ~~~~~~~\n          [Foo.new]\n<stdin>:4:11: fix: Replace with \\\"Foo.Bar<T>.Baz.new\\\"\n  var c = new Foo.Bar<T>.Baz().foo\n          ~~~~~~~~~~~~~~~~~~\n          [Foo.Bar<T>.Baz.new]\n\")\n\n# Check for Java-style class keyword corrections\ntest(\"\nclass Foo extends Bar implements Baz {}\n\", \"\n<stdin>:1:11: error: Use \\\":\\\" instead of \\\"extends\\\" to indicate a base class\nclass Foo extends Bar implements Baz {}\n          ~~~~~~~\n<stdin>:1:23: error: Use \\\"::\\\" instead of \\\"implements\\\" to indicate implemented interfaces\nclass Foo extends Bar implements Baz {}\n                      ~~~~~~~~~~\n<stdin>:1:19: error: \\\"Bar\\\" is not declared\nclass Foo extends Bar implements Baz {}\n                  ~~~\n<stdin>:1:34: error: \\\"Baz\\\" is not declared\nclass Foo extends Bar implements Baz {}\n                                 ~~~\n<stdin>:1:11: fix: Replace \\\"extends\\\" with \\\":\\\"\nclass Foo extends Bar implements Baz {}\n          ~~~~~~~\n          [:]\n<stdin>:1:23: fix: Replace \\\"implements\\\" with \\\"::\\\"\nclass Foo extends Bar implements Baz {}\n                      ~~~~~~~~~~\n                      [::]\n\")\n\n# Check for TypeScript-style variable and function declarations\ntest(\"\nclass Foo {\n  a = 0\n  b: int\n  c = 0\n\n  d() {}\n  e(): int {}\n  f() {}\n}\n\", \"\n<stdin>:2:3: error: Use \\\"var\\\" before variable declarations\n  a = 0\n  ^\n<stdin>:3:3: error: Use \\\"var\\\" before variable declarations\n  b: int\n  ^\n<stdin>:3:4: error: Do not use a colon before a type expression\n  b: int\n   ^\n<stdin>:4:3: error: Use \\\"var\\\" before variable declarations\n  c = 0\n  ^\n<stdin>:6:3: error: Use \\\"def\\\" before function declarations\n  d() {}\n  ^\n<stdin>:6:4: error: Functions without arguments do not use parentheses\n  d() {}\n   ~~\n<stdin>:7:3: error: Use \\\"def\\\" before function declarations\n  e(): int {}\n  ^\n<stdin>:7:4: error: Functions without arguments do not use parentheses\n  e(): int {}\n   ~~\n<stdin>:7:6: error: Do not use a colon before a type expression\n  e(): int {}\n     ^\n<stdin>:8:3: error: Use \\\"def\\\" before function declarations\n  f() {}\n  ^\n<stdin>:8:4: error: Functions without arguments do not use parentheses\n  f() {}\n   ~~\n<stdin>:7:3: error: All control paths for \\\"e\\\" must return a value of type \\\"int\\\"\n  e(): int {}\n  ^\n<stdin>:2:3: fix: Insert \\\"var\\\"\n  a = 0\n  ^\n  [var a]\n<stdin>:3:3: fix: Insert \\\"var\\\"\n  b: int\n  ^\n  [var b]\n<stdin>:3:4: fix: Remove the colon\n  b: int\n   ^\n   []\n<stdin>:4:3: fix: Insert \\\"var\\\"\n  c = 0\n  ^\n  [var c]\n<stdin>:6:3: fix: Insert \\\"def\\\"\n  d() {}\n  ^\n  [def d]\n<stdin>:6:4: fix: Remove parentheses\n  d() {}\n   ~~\n   []\n<stdin>:7:3: fix: Insert \\\"def\\\"\n  e(): int {}\n  ^\n  [def e]\n<stdin>:7:4: fix: Remove parentheses\n  e(): int {}\n   ~~\n   []\n<stdin>:7:6: fix: Remove the colon\n  e(): int {}\n     ^\n     []\n<stdin>:8:3: fix: Insert \\\"def\\\"\n  f() {}\n  ^\n  [def f]\n<stdin>:8:4: fix: Remove parentheses\n  f() {}\n   ~~\n   []\n\")\n\n# Don't stop the whole parse if a function argument has invalid syntax\ntest(\"\ndef x(a b c) {}\ndef y(a b c) {}\n\", \"\n<stdin>:1:11: error: Expected \\\",\\\" but found identifier\ndef x(a b c) {}\n          ^\n<stdin>:2:11: error: Expected \\\",\\\" but found identifier\ndef y(a b c) {}\n          ^\n<stdin>:1:9: error: \\\"b\\\" is not declared\ndef x(a b c) {}\n        ^\n<stdin>:2:9: error: \\\"b\\\" is not declared\ndef y(a b c) {}\n        ^\n\")\n\n# Skip over top-level identifiers\ntest(\"\nclass Foo {\n  nonsense var a = 0\n  static var b = 0\n  public c int = 0\n  private d: int = 0\n  protected e() {}\n\n  var nonsense = 0\n  var static = 0\n  var public = 0\n  var private = 0\n  var protected = 0\n}\n\", \"\n<stdin>:2:3: error: Unexpected identifier\n  nonsense var a = 0\n  ~~~~~~~~\n<stdin>:3:3: error: There is no \\\"static\\\" keyword (declare this symbol in a namespace called \\\"Foo\\\" instead)\n  static var b = 0\n  ~~~~~~\n<stdin>:4:3: error: There is no \\\"public\\\" keyword\n  public c int = 0\n  ~~~~~~\n<stdin>:4:10: error: Unexpected identifier\n  public c int = 0\n         ^\n<stdin>:4:12: error: Use \\\"var\\\" before variable declarations\n  public c int = 0\n           ~~~\n<stdin>:5:3: error: There is no \\\"private\\\" keyword (to give something protected access, use a name starting with \\\"_\\\" instead)\n  private d: int = 0\n  ~~~~~~~\n<stdin>:5:11: error: Use \\\"var\\\" before variable declarations\n  private d: int = 0\n          ^\n<stdin>:5:12: error: Do not use a colon before a type expression\n  private d: int = 0\n           ^\n<stdin>:6:3: error: There is no \\\"protected\\\" keyword (to give something protected access, use a name starting with \\\"_\\\" instead)\n  protected e() {}\n  ~~~~~~~~~\n<stdin>:6:13: error: Use \\\"def\\\" before function declarations\n  protected e() {}\n            ^\n<stdin>:6:14: error: Functions without arguments do not use parentheses\n  protected e() {}\n             ~~\n<stdin>:5:14: error: Cannot access instance member \\\"int\\\" from a global context\n  private d: int = 0\n             ~~~\n<stdin>:5:14: error: Unexpected expression of type \\\"int\\\"\n  private d: int = 0\n             ~~~\n<stdin>:4:12: fix: Insert \\\"var\\\"\n  public c int = 0\n           ~~~\n           [var int]\n<stdin>:5:11: fix: Insert \\\"var\\\"\n  private d: int = 0\n          ^\n          [var d]\n<stdin>:5:12: fix: Remove the colon\n  private d: int = 0\n           ^\n           []\n<stdin>:6:13: fix: Insert \\\"def\\\"\n  protected e() {}\n            ^\n            [def e]\n<stdin>:6:14: fix: Remove parentheses\n  protected e() {}\n             ~~\n             []\n\")\n\n# Check for parser recovery on a C-style switch statement\ntest(\"\ndef test {\n  switch 0 {\n    case 1: x = 0; y = 0; break;\n    case 2: case 3: x = 0; y = 0; break;\n    case 4:\n    case 5:\n      x = 0;\n      y = 0;\n      break;\n    default:\n      x = 0;\n      y = 0;\n  }\n}\n\", \"\n<stdin>:3:18: error: Expected newline but found \\\";\\\"\n    case 1: x = 0; y = 0; break;\n                 ^\n<stdin>:3:25: error: Expected newline but found \\\";\\\"\n    case 1: x = 0; y = 0; break;\n                        ^\n<stdin>:3:32: error: Expected newline but found \\\";\\\"\n    case 1: x = 0; y = 0; break;\n                               ^\n<stdin>:3:11: error: Surround the body of case and default statements with \\\"{\\\" and \\\"}\\\" instead of \\\":\\\" and \\\"break\\\"\n    case 1: x = 0; y = 0; break;\n          ^\n<stdin>:4:11: error: Use a comma between multiple values in a case statement (example: \\\"case 1, 2, 3 { ... }\\\")\n    case 2: case 3: x = 0; y = 0; break;\n          ~~~~~~\n<stdin>:4:26: error: Expected newline but found \\\";\\\"\n    case 2: case 3: x = 0; y = 0; break;\n                         ^\n<stdin>:4:33: error: Expected newline but found \\\";\\\"\n    case 2: case 3: x = 0; y = 0; break;\n                                ^\n<stdin>:4:40: error: Expected newline but found \\\";\\\"\n    case 2: case 3: x = 0; y = 0; break;\n                                       ^\n<stdin>:4:19: error: Surround the body of case and default statements with \\\"{\\\" and \\\"}\\\" instead of \\\":\\\" and \\\"break\\\"\n    case 2: case 3: x = 0; y = 0; break;\n                  ^\n<stdin>:5:11: error: Use a comma between multiple values in a case statement (example: \\\"case 1, 2, 3 { ... }\\\")\n    case 4:\n          ^\n<stdin>:7:12: error: Expected newline but found \\\";\\\"\n      x = 0;\n           ^\n<stdin>:8:12: error: Expected newline but found \\\";\\\"\n      y = 0;\n           ^\n<stdin>:9:12: error: Expected newline but found \\\";\\\"\n      break;\n           ^\n<stdin>:6:11: error: Surround the body of case and default statements with \\\"{\\\" and \\\"}\\\" instead of \\\":\\\" and \\\"break\\\"\n    case 5:\n          ^\n<stdin>:11:12: error: Expected newline but found \\\";\\\"\n      x = 0;\n           ^\n<stdin>:12:12: error: Expected newline but found \\\";\\\"\n      y = 0;\n           ^\n<stdin>:10:12: error: Surround the body of case and default statements with \\\"{\\\" and \\\"}\\\" instead of \\\":\\\" and \\\"break\\\"\n    default:\n           ^\n<stdin>:3:13: error: \\\"x\\\" is not declared\n    case 1: x = 0; y = 0; break;\n            ^\n<stdin>:3:20: error: \\\"y\\\" is not declared\n    case 1: x = 0; y = 0; break;\n                   ^\n<stdin>:4:21: error: \\\"x\\\" is not declared\n    case 2: case 3: x = 0; y = 0; break;\n                    ^\n<stdin>:4:28: error: \\\"y\\\" is not declared\n    case 2: case 3: x = 0; y = 0; break;\n                           ^\n<stdin>:7:7: error: \\\"x\\\" is not declared\n      x = 0;\n      ^\n<stdin>:8:7: error: \\\"y\\\" is not declared\n      y = 0;\n      ^\n<stdin>:11:7: error: \\\"x\\\" is not declared\n      x = 0;\n      ^\n<stdin>:12:7: error: \\\"y\\\" is not declared\n      y = 0;\n      ^\n<stdin>:3:18: fix: Remove \\\";\\\"\n    case 1: x = 0; y = 0; break;\n                 ^\n                 []\n<stdin>:3:25: fix: Remove \\\";\\\"\n    case 1: x = 0; y = 0; break;\n                        ^\n                        []\n<stdin>:3:32: fix: Remove \\\";\\\"\n    case 1: x = 0; y = 0; break;\n                               ^\n                               []\n<stdin>:3:11: fix: Replace \\\":\\\" and \\\"break\\\" with \\\"{\\\" and \\\"}\\\"\n    case 1: x = 0; y = 0; break;\n          ~~~~~~~~~~~~~~~~~~~~~~\n          [ { x = 0; y = 0; }]\n<stdin>:4:11: fix: Replace this with a comma\n    case 2: case 3: x = 0; y = 0; break;\n          ~~~~~~\n          [,]\n<stdin>:4:26: fix: Remove \\\";\\\"\n    case 2: case 3: x = 0; y = 0; break;\n                         ^\n                         []\n<stdin>:4:33: fix: Remove \\\";\\\"\n    case 2: case 3: x = 0; y = 0; break;\n                                ^\n                                []\n<stdin>:4:40: fix: Remove \\\";\\\"\n    case 2: case 3: x = 0; y = 0; break;\n                                       ^\n                                       []\n<stdin>:4:19: fix: Replace \\\":\\\" and \\\"break\\\" with \\\"{\\\" and \\\"}\\\"\n    case 2: case 3: x = 0; y = 0; break;\n                  ~~~~~~~~~~~~~~~~~~~~~~\n                  [ { x = 0; y = 0; }]\n<stdin>:5:11: fix: Replace this with a comma\n    case 4:\n          ^\n          [,]\n<stdin>:7:12: fix: Remove \\\";\\\"\n      x = 0;\n           ^\n           []\n<stdin>:8:12: fix: Remove \\\";\\\"\n      y = 0;\n           ^\n           []\n<stdin>:9:12: fix: Remove \\\";\\\"\n      break;\n           ^\n           []\n<stdin>:6:11: fix: Replace \\\":\\\" and \\\"break\\\" with \\\"{\\\" and \\\"}\\\"\n    case 5:\n          ^\n          [ {\n      x = 0;\n      y = 0;\n    }]\n<stdin>:11:12: fix: Remove \\\";\\\"\n      x = 0;\n           ^\n           []\n<stdin>:12:12: fix: Remove \\\";\\\"\n      y = 0;\n           ^\n           []\n\")\n\n# Check for an infinite loop due to a parse error\ntest(\"\ndef test {\n  switch 0 {\n    case 1: blah;\n    case 2: case 3: blah;\n  }\n}\n\", \"\n<stdin>:3:17: error: Expected newline but found \\\";\\\"\n    case 1: blah;\n                ^\n<stdin>:3:11: error: Surround the body of case and default statements with \\\"{\\\" and \\\"}\\\" instead of \\\":\\\" and \\\"break\\\"\n    case 1: blah;\n          ^\n<stdin>:4:11: error: Use a comma between multiple values in a case statement (example: \\\"case 1, 2, 3 { ... }\\\")\n    case 2: case 3: blah;\n          ~~~~~~\n<stdin>:4:25: error: Expected newline but found \\\";\\\"\n    case 2: case 3: blah;\n                        ^\n<stdin>:4:19: error: Surround the body of case and default statements with \\\"{\\\" and \\\"}\\\" instead of \\\":\\\" and \\\"break\\\"\n    case 2: case 3: blah;\n                  ^\n<stdin>:3:13: error: \\\"blah\\\" is not declared\n    case 1: blah;\n            ~~~~\n<stdin>:4:21: error: \\\"blah\\\" is not declared\n    case 2: case 3: blah;\n                    ~~~~\n<stdin>:3:17: fix: Remove \\\";\\\"\n    case 1: blah;\n                ^\n                []\n<stdin>:4:11: fix: Replace this with a comma\n    case 2: case 3: blah;\n          ~~~~~~\n          [,]\n<stdin>:4:25: fix: Remove \\\";\\\"\n    case 2: case 3: blah;\n                        ^\n                        []\n\")\n\n  }\n}\n"
  },
  {
    "path": "tests/simple.sk",
    "content": "namespace Skew.Tests {\n  def testSimple {\n\ntest(\"\nvar foo Foo<dynamic> = null\n\", \"\n<stdin>:1:9: error: \\\"Foo\\\" is not declared\nvar foo Foo<dynamic> = null\n        ~~~\n\")\n\ntest(\"\ndef main List<double> {\n  return [\n    0,\n    0b10,\n    0o76543210,\n    0xFEDBCA98,\n    0.5,\n    1e100,\n    1e+100,\n    1e-100,\n    0.5e100,\n    0.5e+100,\n    0.5e-100,\n    0.toString,\n    0.5.toString,\n    1e100.toString,\n    1e+100.toString,\n    1e-100.toString,\n    0.5e100.toString,\n    0.5e+100.toString,\n    0.5e-100.toString,\n    01,\n  ]\n}\n\", \"\n<stdin>:22:5: warning: Number interpreted as decimal (use the prefix \\\"0o\\\" for octal numbers)\n    01,\n    ~~\n<stdin>:14:5: error: Cannot convert from type \\\"string\\\" to type \\\"double\\\"\n    0.toString,\n    ~~~~~~~~~~\n<stdin>:15:5: error: Cannot convert from type \\\"string\\\" to type \\\"double\\\"\n    0.5.toString,\n    ~~~~~~~~~~~~\n<stdin>:16:5: error: Cannot convert from type \\\"string\\\" to type \\\"double\\\"\n    1e100.toString,\n    ~~~~~~~~~~~~~~\n<stdin>:17:5: error: Cannot convert from type \\\"string\\\" to type \\\"double\\\"\n    1e+100.toString,\n    ~~~~~~~~~~~~~~~\n<stdin>:18:5: error: Cannot convert from type \\\"string\\\" to type \\\"double\\\"\n    1e-100.toString,\n    ~~~~~~~~~~~~~~~\n<stdin>:19:5: error: Cannot convert from type \\\"string\\\" to type \\\"double\\\"\n    0.5e100.toString,\n    ~~~~~~~~~~~~~~~~\n<stdin>:20:5: error: Cannot convert from type \\\"string\\\" to type \\\"double\\\"\n    0.5e+100.toString,\n    ~~~~~~~~~~~~~~~~~\n<stdin>:21:5: error: Cannot convert from type \\\"string\\\" to type \\\"double\\\"\n    0.5e-100.toString,\n    ~~~~~~~~~~~~~~~~~\n<stdin>:22:5: fix: Remove the leading zeros to avoid confusion\n    01,\n    ~~\n    [1]\n<stdin>:22:5: fix: Add the prefix \\\"0o\\\" to interpret the number as octal\n    01,\n    ~~\n    [0o1]\n\")\n\ntest(\"\nclass Foo<T> {\n  def foo T\n}\n\nclass Bar<T> {\n  def bar T\n}\n\ndef main {\n  var x Foo<Bar<Foo<int>>>\n  var a bool = x\n  var b bool = x.foo\n  var c bool = x.foo.bar\n  var d bool = x.foo.bar.foo\n}\n\", \"\n<stdin>:11:16: error: Cannot convert from type \\\"Foo<Bar<Foo<int>>>\\\" to type \\\"bool\\\"\n  var a bool = x\n               ^\n<stdin>:12:16: error: Cannot convert from type \\\"Bar<Foo<int>>\\\" to type \\\"bool\\\"\n  var b bool = x.foo\n               ~~~~~\n<stdin>:13:16: error: Cannot convert from type \\\"Foo<int>\\\" to type \\\"bool\\\"\n  var c bool = x.foo.bar\n               ~~~~~~~~~\n<stdin>:14:16: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n  var d bool = x.foo.bar.foo\n               ~~~~~~~~~~~~~\n<stdin>:11:7: warning: Local variable \\\"a\\\" is never read\n  var a bool = x\n      ^\n<stdin>:12:7: warning: Local variable \\\"b\\\" is never read\n  var b bool = x.foo\n      ^\n<stdin>:13:7: warning: Local variable \\\"c\\\" is never read\n  var c bool = x.foo.bar\n      ^\n<stdin>:14:7: warning: Local variable \\\"d\\\" is never read\n  var d bool = x.foo.bar.foo\n      ^\n\")\n\ntest(\"\nclass Foo {\n  def new {}\n}\n\nnamespace Foo {\n  def new(x int) Foo {\n    return new\n  }\n}\n\", \"\n\")\n\ntest(\"\nclass Foo<T> {\n  def size int\n  def pop T\n  def shift T\n  def push(value T)\n  def unshift(value T)\n  def map<R>(callback fn(T) R) Foo<R>\n  def filter(callback fn(T) bool) Foo<T>\n}\n\ndef main {\n  var x Foo<int>\n  x.push(x.size)\n  x.filter(1.0)\n  x.map(1.0)\n  x.map<string>(1.0)\n  x.filter(x => x + 100)\n  x.map(x => x + 100)\n  var y int = x.map<string>(1.0)\n}\n\", \"\n<stdin>:14:12: error: Cannot convert from type \\\"double\\\" to type \\\"fn(int) bool\\\"\n  x.filter(1.0)\n           ~~~\n<stdin>:15:3: error: Cannot use unparameterized type \\\"Foo.map\\\" here\n  x.map(1.0)\n  ~~~~~\n<stdin>:16:17: error: Cannot convert from type \\\"double\\\" to type \\\"fn(int) string\\\"\n  x.map<string>(1.0)\n                ~~~\n<stdin>:17:17: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n  x.filter(x => x + 100)\n                ~~~~~~~\n<stdin>:18:3: error: Cannot use unparameterized type \\\"Foo.map\\\" here\n  x.map(x => x + 100)\n  ~~~~~\n<stdin>:19:29: error: Cannot convert from type \\\"double\\\" to type \\\"fn(int) string\\\"\n  var y int = x.map<string>(1.0)\n                            ~~~\n<stdin>:19:15: error: Cannot convert from type \\\"Foo<string>\\\" to type \\\"int\\\"\n  var y int = x.map<string>(1.0)\n              ~~~~~~~~~~~~~~~~~~\n<stdin>:19:7: warning: Local variable \\\"y\\\" is never read\n  var y int = x.map<string>(1.0)\n      ^\n\")\n\ntest(\"\nclass Foo {\n  def new {}\n  def foo<T>(t T) Foo { return self }\n}\n\ndef main {\n  Foo.new.foo(0).foo(0.0)\n  Foo.new.foo<bool>(0).foo<int>(0.0)\n}\n\", \"\n<stdin>:7:3: error: Cannot use unparameterized type \\\"Foo.foo\\\" here\n  Foo.new.foo(0).foo(0.0)\n  ~~~~~~~~~~~\n<stdin>:8:21: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n  Foo.new.foo<bool>(0).foo<int>(0.0)\n                    ^\n<stdin>:8:33: error: Cannot convert from type \\\"double\\\" to type \\\"int\\\" without a cast\n  Foo.new.foo<bool>(0).foo<int>(0.0)\n                                ~~~\n\")\n\ntest(\"\nclass Foo {\n  def new {}\n  def foo Foo { return self }\n  def bar {}\n}\n\ndef main {\n  var x int = => Foo.new\n  var y int = => Foo.new.foo\n  var z int = => Foo.new.bar\n}\n\", \"\n<stdin>:8:15: error: Cannot convert from type \\\"fn() Foo\\\" to type \\\"int\\\"\n  var x int = => Foo.new\n              ~~~~~~~~~~\n<stdin>:9:15: error: Cannot convert from type \\\"fn() Foo\\\" to type \\\"int\\\"\n  var y int = => Foo.new.foo\n              ~~~~~~~~~~~~~~\n<stdin>:10:15: error: Cannot convert from type \\\"fn()\\\" to type \\\"int\\\"\n  var z int = => Foo.new.bar\n              ~~~~~~~~~~~~~~\n<stdin>:8:7: warning: Local variable \\\"x\\\" is never read\n  var x int = => Foo.new\n      ^\n<stdin>:9:7: warning: Local variable \\\"y\\\" is never read\n  var y int = => Foo.new.foo\n      ^\n<stdin>:10:7: warning: Local variable \\\"z\\\" is never read\n  var z int = => Foo.new.bar\n      ^\n\")\n\ntest(\"\ndef main(x int) {\n  main\n  x\n  x + 1\n  x ? x : x\n}\n\", \"\n<stdin>:2:3: error: The function \\\"main\\\" takes 1 argument and must be called\n  main\n  ~~~~\n<stdin>:3:3: warning: Unused expression\n  x\n  ^\n<stdin>:4:3: warning: Unused expression\n  x + 1\n  ~~~~~\n<stdin>:5:3: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n  x ? x : x\n  ^\n<stdin>:5:7: warning: Both sides of \\\":\\\" are identical, is this a bug?\n  x ? x : x\n      ~~~~~\n<stdin>:5:7: warning: Unused expression\n  x ? x : x\n      ^\n<stdin>:5:11: warning: Unused expression\n  x ? x : x\n          ^\n\")\n\n# Check unused expression warnings for lambdas that return nothing\ntest(\"\ndef main {\n  bar(x => foo(x))\n  bar(x => x + 1)\n  bar(x => x)\n}\n\ndef foo(x int) int {\n  return 0\n}\n\ndef bar(x fn(int)) {\n}\n\", \"\n<stdin>:3:12: warning: Unused expression\n  bar(x => x + 1)\n           ~~~~~\n<stdin>:4:12: warning: Unused expression\n  bar(x => x)\n           ^\n\")\n\n# Test return statement checks in the presence of the dynamic type\ntest(\"\ndef main {\n  x => x\n  => {}\n  => { return }\n  => { return 0 }\n  var a dynamic = x => x\n  var b dynamic = => {}\n  var c dynamic = => { return }\n  var d dynamic = => { return 0 }\n  var e fn() dynamic = x => x\n  var f fn() dynamic = => {}\n  var g fn() dynamic = => { return }\n  var h fn() dynamic = => { return 0 }\n}\n\ndef a dynamic {}\ndef b dynamic { return }\ndef c dynamic { return 0 }\n\", \"\n<stdin>:2:3: error: Unable to determine the type of \\\"x\\\"\n  x => x\n  ^\n<stdin>:2:3: warning: Unused expression\n  x => x\n  ~~~~~~\n<stdin>:3:3: warning: Unused expression\n  => {}\n  ~~~~~\n<stdin>:4:3: warning: Unused expression\n  => { return }\n  ~~~~~~~~~~~~~\n<stdin>:5:15: error: Cannot return a value inside a function without a return type\n  => { return 0 }\n              ^\n<stdin>:5:3: warning: Unused expression\n  => { return 0 }\n  ~~~~~~~~~~~~~~~\n<stdin>:10:24: error: Unable to determine the type of \\\"x\\\"\n  var e fn() dynamic = x => x\n                       ^\n<stdin>:10:24: error: Cannot convert from type \\\"fn(dynamic) dynamic\\\" to type \\\"fn() dynamic\\\"\n  var e fn() dynamic = x => x\n                       ~~~~~~\n<stdin>:11:24: error: All control paths for \\\"<lambda>\\\" must return a value of type \\\"dynamic\\\"\n  var f fn() dynamic = => {}\n                       ~~~~~\n<stdin>:12:29: error: Must return a value of type \\\"dynamic\\\"\n  var g fn() dynamic = => { return }\n                            ~~~~~~\n<stdin>:16:5: error: All control paths for \\\"a\\\" must return a value of type \\\"dynamic\\\"\ndef a dynamic {}\n    ^\n<stdin>:17:17: error: Must return a value of type \\\"dynamic\\\"\ndef b dynamic { return }\n                ~~~~~~\n<stdin>:6:7: warning: Local variable \\\"a\\\" is never read\n  var a dynamic = x => x\n      ^\n<stdin>:7:7: warning: Local variable \\\"b\\\" is never read\n  var b dynamic = => {}\n      ^\n<stdin>:8:7: warning: Local variable \\\"c\\\" is never read\n  var c dynamic = => { return }\n      ^\n<stdin>:9:7: warning: Local variable \\\"d\\\" is never read\n  var d dynamic = => { return 0 }\n      ^\n<stdin>:10:7: warning: Local variable \\\"e\\\" is never read\n  var e fn() dynamic = x => x\n      ^\n<stdin>:11:7: warning: Local variable \\\"f\\\" is never read\n  var f fn() dynamic = => {}\n      ^\n<stdin>:12:7: warning: Local variable \\\"g\\\" is never read\n  var g fn() dynamic = => { return }\n      ^\n<stdin>:13:7: warning: Local variable \\\"h\\\" is never read\n  var h fn() dynamic = => { return 0 }\n      ^\n\")\n\ntest(\"\ndef main {\n  var x = null\n  var y = => null\n}\n\", \"\n<stdin>:2:7: error: Implicitly typed variables cannot be of type \\\"null\\\"\n  var x = null\n      ^\n<stdin>:3:14: error: Cannot create a function with a return type of \\\"null\\\"\n  var y = => null\n             ~~~~\n<stdin>:2:7: warning: Local variable \\\"x\\\" is never read\n  var x = null\n      ^\n<stdin>:3:7: warning: Local variable \\\"y\\\" is never read\n  var y = => null\n      ^\n\")\n\ntest(\"\ndef main {\n  var a = => 0\n  var b = => {}\n  var c = () => 0\n  var d = () => {}\n  var e = () int => 0\n  var f = () int => { return 0 }\n  var g fn(int) = x => 0\n  var h fn(int) = x => {}\n  var i fn(int) int = (x) => 0\n  var j fn(int) int = (x) => { return 0 }\n  var k = (x int) => 0\n  var l = (x int) => {}\n  var m = (x int) int => 0\n  var n = (x int) int => { return 0 }\n}\n\", \"\n<stdin>:8:24: warning: Unused expression\n  var g fn(int) = x => 0\n                       ^\n<stdin>:2:7: warning: Local variable \\\"a\\\" is never read\n  var a = => 0\n      ^\n<stdin>:3:7: warning: Local variable \\\"b\\\" is never read\n  var b = => {}\n      ^\n<stdin>:4:7: warning: Local variable \\\"c\\\" is never read\n  var c = () => 0\n      ^\n<stdin>:5:7: warning: Local variable \\\"d\\\" is never read\n  var d = () => {}\n      ^\n<stdin>:6:7: warning: Local variable \\\"e\\\" is never read\n  var e = () int => 0\n      ^\n<stdin>:7:7: warning: Local variable \\\"f\\\" is never read\n  var f = () int => { return 0 }\n      ^\n<stdin>:8:7: warning: Local variable \\\"g\\\" is never read\n  var g fn(int) = x => 0\n      ^\n<stdin>:9:7: warning: Local variable \\\"h\\\" is never read\n  var h fn(int) = x => {}\n      ^\n<stdin>:10:7: warning: Local variable \\\"i\\\" is never read\n  var i fn(int) int = (x) => 0\n      ^\n<stdin>:11:7: warning: Local variable \\\"j\\\" is never read\n  var j fn(int) int = (x) => { return 0 }\n      ^\n<stdin>:12:7: warning: Local variable \\\"k\\\" is never read\n  var k = (x int) => 0\n      ^\n<stdin>:13:7: warning: Local variable \\\"l\\\" is never read\n  var l = (x int) => {}\n      ^\n<stdin>:14:7: warning: Local variable \\\"m\\\" is never read\n  var m = (x int) int => 0\n      ^\n<stdin>:15:7: warning: Local variable \\\"n\\\" is never read\n  var n = (x int) int => { return 0 }\n      ^\n\")\n\ntest(\"\nclass Foo<T> {\n  def new {}\n}\n\ndef main {\n  var foo Foo<int> = Foo<int>.new\n  var bar Foo<bool> = Foo<int>.new\n}\n\", \"\n<stdin>:7:23: error: Cannot convert from type \\\"Foo<int>\\\" to type \\\"Foo<bool>\\\"\n  var bar Foo<bool> = Foo<int>.new\n                      ~~~~~~~~~~~~\n<stdin>:6:7: warning: Local variable \\\"foo\\\" is never read\n  var foo Foo<int> = Foo<int>.new\n      ~~~\n<stdin>:7:7: warning: Local variable \\\"bar\\\" is never read\n  var bar Foo<bool> = Foo<int>.new\n      ~~~\n\")\n\ntest(\"\nclass Foo {\n  def in(x int) bool\n}\n\ndef main(foo Foo) {\n  false in foo\n  0 in foo\n}\n\", \"\n<stdin>:6:3: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n  false in foo\n  ~~~~~\n\")\n\ntest(\"\nnamespace foo {\n  namespace bar {\n    def @baz\n  }\n}\n\n@foo.bar.bax\n@foo.bar.baz\ndef main {}\n\", \"\n<stdin>:7:10: error: \\\"@bax\\\" is not declared on type \\\"foo.bar\\\", did you mean \\\"@baz\\\"?\n@foo.bar.bax\n         ~~~\n<stdin>:3:9: note: \\\"@baz\\\" is defined here\n    def @baz\n        ~~~~\n<stdin>:7:10: fix: Replace with \\\"@baz\\\"\n@foo.bar.bax\n         ~~~\n         [@baz]\n\")\n\ntest(\"\ndef @foo(x int)\ndef @bar\n\n@foo\n@foo(1, 2)\n@bar(1)\ndef main {}\n\", \"\n<stdin>:4:1: error: Expected 1 argument but found 0 arguments when calling \\\"@foo\\\"\n@foo\n~~~~\n<stdin>:1:5: note: The function declaration is here\ndef @foo(x int)\n    ~~~~\n<stdin>:5:5: error: Expected 1 argument but found 2 arguments when calling \\\"@foo\\\"\n@foo(1, 2)\n    ~~~~~~\n<stdin>:1:5: note: The function declaration is here\ndef @foo(x int)\n    ~~~~\n<stdin>:6:5: error: Cannot call the value returned from the function \\\"@bar\\\" (this function was called automatically because it takes no arguments)\n@bar(1)\n    ~~~\n<stdin>:2:5: note: The function declaration is here\ndef @bar\n    ~~~~\n\")\n\n# These shouldn't cause missing newline errors\ntest(\"\ndef @foo\n\nclass foo {\n  def -\n  def new {}\n}\n\nclass bar {\n  def -\n\n  @foo\n  def new {}\n}\n\nclass baz {\n  def -\n\n  # foo\n  def new {}\n}\n\ndef main bool {\n  return 1 -\n    1\n}\n\", \"\n<stdin>:23:10: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n  return 1 -\n         ~~~\n\")\n\ntest(\"\nclass Foo {\n  def foo {\n    var self int\n  }\n\n  def bar(self int) {\n  }\n\n  def baz {\n    if true {\n      var self int\n    }\n  }\n}\n\", \"\n<stdin>:3:9: error: \\\"self\\\" is already declared\n    var self int\n        ~~~~\n<stdin>:6:11: error: \\\"self\\\" is already declared\n  def bar(self int) {\n          ~~~~\n<stdin>:11:11: error: \\\"self\\\" shadows a previous declaration\n      var self int\n          ~~~~\n<stdin>:3:9: warning: Local variable \\\"self\\\" is never read\n    var self int\n        ~~~~\n<stdin>:11:11: warning: Local variable \\\"self\\\" is never read\n      var self int\n          ~~~~\n\")\n\ntest(\"\nnamespace a {\n  class Foo.Bar {}\n  class Foo.Baz {}\n  class Foo {}\n  def main(foo Foo.Bar, bar Foo.Baz) {}\n}\nnamespace b {\n  class Foo {\n    class Bar {}\n    class Baz {}\n  }\n  def main(foo Foo.Bar, bar Foo.Baz) {}\n}\n\", \"\n\")\n\ntest(\"\nclass ns1.Foo {}\nvar ns1 int\nvar ns2 int\nclass ns2.Foo {}\n\", \"\n<stdin>:2:5: error: \\\"ns1\\\" is already declared\nvar ns1 int\n    ~~~\n<stdin>:1:7: note: The previous declaration is here\nclass ns1.Foo {}\n      ~~~\n<stdin>:3:5: error: \\\"ns2\\\" is already declared\nvar ns2 int\n    ~~~\n<stdin>:4:7: note: The previous declaration is here\nclass ns2.Foo {}\n      ~~~\n\")\n\ntest(\"\n@skip\nvar a int\n\n@skip {\n  var x int\n  var y int\n}\n\n@skip\n@skip\ndef b {}\n\n@skip\n@skip {\n  def c {}\n}\n\", \"\n<stdin>:10:1: warning: Duplicate annotation \\\"@skip\\\" on \\\"b\\\"\n@skip\n~~~~~\n<stdin>:14:1: warning: Duplicate annotation \\\"@skip\\\" on \\\"c\\\"\n@skip {\n~~~~~\n<stdin>:1:1: error: Cannot use the annotation \\\"@skip\\\" on \\\"a\\\"\n@skip\n~~~~~\n<stdin>:4:1: error: Cannot use the annotation \\\"@skip\\\" on \\\"x\\\"\n@skip {\n~~~~~\n<stdin>:4:1: error: Cannot use the annotation \\\"@skip\\\" on \\\"y\\\"\n@skip {\n~~~~~\n\")\n\ntest(\"\nclass Foo {\n  const a\n  const b int\n  const c = 0\n  const d bool = 0\n}\n\n@import\nclass Bar {\n  const a\n  const b int\n  const c = 0\n  const d bool = 0\n}\n\nconst a\nconst b int\nconst c = 0\nconst d bool = 0\n\n@import {\n  const w\n  const x int\n  const y = 0\n  const z bool = 0\n}\n\", \"\n<stdin>:2:9: error: Unable to determine the type of \\\"a\\\"\n  const a\n        ^\n<stdin>:5:18: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n  const d bool = 0\n                 ^\n<stdin>:10:9: error: Unable to determine the type of \\\"a\\\"\n  const a\n        ^\n<stdin>:13:18: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n  const d bool = 0\n                 ^\n<stdin>:16:7: error: Unable to determine the type of \\\"a\\\"\nconst a\n      ^\n<stdin>:17:7: error: The constant \\\"b\\\" must be initialized\nconst b int\n      ^\n<stdin>:19:16: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\nconst d bool = 0\n               ^\n<stdin>:22:9: error: Unable to determine the type of \\\"w\\\"\n  const w\n        ^\n<stdin>:25:18: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n  const z bool = 0\n                 ^\n\")\n\ntest(\"\nconst a = 0\nvar b = 0\n\nclass Foo {\n  const x = 0\n}\n\ndef main(foo Foo) {\n  const y = 0\n  a = 0\n  b = 0\n  foo.x = 0\n  y = 0\n}\n\", \"\n<stdin>:10:3: error: Cannot store to constant symbol \\\"a\\\"\n  a = 0\n  ^\n<stdin>:12:7: error: Cannot store to constant symbol \\\"x\\\"\n  foo.x = 0\n      ^\n<stdin>:13:3: error: Cannot store to constant symbol \\\"y\\\"\n  y = 0\n  ^\n<stdin>:9:9: warning: Local variable \\\"y\\\" is never read\n  const y = 0\n        ^\n\")\n\ntest(\"\nclass _Foo {\n  var _x int\n  var _bar _Bar\n\n  def _foo {\n    _x = 0\n    _foo\n    var _y = => _x\n  }\n\n  class _Bar {}\n}\n\ndef _main(_foo _Foo) {\n  _foo._x = 0\n  _foo._foo\n  var _x = => _foo._x\n  var _y = => _foo._foo\n  var _z _Foo._Bar\n}\n\", \"\n<stdin>:15:8: error: Cannot access protected symbol \\\"_x\\\" here\n  _foo._x = 0\n       ~~\n<stdin>:16:8: error: Cannot access protected symbol \\\"_foo\\\" here\n  _foo._foo\n       ~~~~\n<stdin>:17:20: error: Cannot access protected symbol \\\"_x\\\" here\n  var _x = => _foo._x\n                   ~~\n<stdin>:18:20: error: Cannot access protected symbol \\\"_foo\\\" here\n  var _y = => _foo._foo\n                   ~~~~\n<stdin>:19:15: error: Cannot access protected symbol \\\"_Bar\\\" here\n  var _z _Foo._Bar\n              ~~~~\n<stdin>:8:9: warning: Local variable \\\"_y\\\" is never read\n    var _y = => _x\n        ~~\n<stdin>:17:7: warning: Local variable \\\"_x\\\" is never read\n  var _x = => _foo._x\n      ~~\n<stdin>:18:7: warning: Local variable \\\"_y\\\" is never read\n  var _y = => _foo._foo\n      ~~\n<stdin>:19:7: warning: Local variable \\\"_z\\\" is never read\n  var _z _Foo._Bar\n      ~~\n\")\n\ntest(\"\nclass bool {\n  def +(x int, y int)\n  def -(x int, y int) {}\n}\n\ndef main {\n  false + false\n  false - false\n}\n\", \"\n<stdin>:2:7: error: Expected \\\"+\\\" to take at most 1 argument\n  def +(x int, y int)\n      ^\n<stdin>:3:7: error: Expected \\\"-\\\" to take at most 1 argument\n  def -(x int, y int) {}\n      ^\n<stdin>:7:9: error: Expected 2 arguments but found 1 argument when calling \\\"+\\\"\n  false + false\n        ^\n<stdin>:2:7: note: The function declaration is here\n  def +(x int, y int)\n      ^\n<stdin>:8:9: error: Expected 2 arguments but found 1 argument when calling \\\"-\\\"\n  false - false\n        ^\n<stdin>:3:7: note: The function declaration is here\n  def -(x int, y int) {}\n      ^\n\")\n\ntest(\"\nclass bool {\n  def +(x bool)\n  def -(x bool) {}\n}\n\ndef main {\n  false + false + false\n  false - false - false\n}\n\", \"\n<stdin>:7:3: error: The function \\\"+\\\" does not return a value\n  false + false + false\n  ~~~~~~~~~~~~~\n<stdin>:2:7: note: The function declaration is here\n  def +(x bool)\n      ^\n<stdin>:8:3: error: The function \\\"-\\\" does not return a value\n  false - false - false\n  ~~~~~~~~~~~~~\n<stdin>:3:7: note: The function declaration is here\n  def -(x bool) {}\n      ^\n\")\n\ntest(\"\ndef main {\n  0 + 0\n  0 + 0.5\n  0.5 + 0\n  0.5 + 0.5\n}\n\", \"\n<stdin>:2:3: warning: Unused expression\n  0 + 0\n  ~~~~~\n<stdin>:3:3: warning: Unused expression\n  0 + 0.5\n  ~~~~~~~\n<stdin>:4:3: warning: Unused expression\n  0.5 + 0\n  ~~~~~~~\n<stdin>:5:3: warning: Unused expression\n  0.5 + 0.5\n  ~~~~~~~~~\n\")\n\ntest(\"\nclass Foo {\n  def *\n  def -(x int, y int)\n  def <=> int\n  def [...]\n  def []\n  def []=\n  def foo=\n  def !(x int)\n  def {...}\n}\n\", \"\n<stdin>:2:7: error: Expected \\\"*\\\" to take 1 argument\n  def *\n      ^\n<stdin>:3:7: error: Expected \\\"-\\\" to take at most 1 argument\n  def -(x int, y int)\n      ^\n<stdin>:4:7: error: Expected \\\"<=>\\\" to take 1 argument\n  def <=> int\n      ~~~\n<stdin>:5:7: error: Expected \\\"[...]\\\" to take 1 argument\n  def [...]\n      ~~~~~\n<stdin>:6:7: error: Expected \\\"[]\\\" to take 1 argument\n  def []\n      ~~\n<stdin>:7:7: error: Expected \\\"[]=\\\" to take 2 arguments\n  def []=\n      ~~~\n<stdin>:8:7: error: Expected \\\"foo=\\\" to take 1 argument\n  def foo=\n      ~~~~\n<stdin>:9:7: error: Expected \\\"!\\\" to take 0 arguments\n  def !(x int)\n      ^\n<stdin>:10:7: error: Expected \\\"{...}\\\" to take 2 arguments\n  def {...}\n      ~~~~~\n\")\n\ntest(\"\ndef main(x List<double>) {\n  var y bool = x[false]\n}\n\", \"\n<stdin>:2:18: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n  var y bool = x[false]\n                 ~~~~~\n<stdin>:2:16: error: Cannot convert from type \\\"double\\\" to type \\\"bool\\\" without a cast\n  var y bool = x[false]\n               ~~~~~~~~\n<stdin>:2:7: warning: Local variable \\\"y\\\" is never read\n  var y bool = x[false]\n      ^\n\")\n\ntest(\"\ndef main(i int) {\n  for i in false..false {\n    i = false\n  }\n  for i in List<string>.new {\n    i = false\n  }\n  for i in 0 {\n    i = false\n  }\n  for j in 0..10 {}\n  for j in 10..0 {}\n}\n\", \"\n<stdin>:2:12: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n  for i in false..false {\n           ~~~~~\n<stdin>:2:19: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n  for i in false..false {\n                  ~~~~~\n<stdin>:2:7: error: \\\"i\\\" shadows a previous declaration\n  for i in false..false {\n      ^\n<stdin>:1:10: note: The previous declaration is here\ndef main(i int) {\n         ^\n<stdin>:3:9: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n    i = false\n        ~~~~~\n<stdin>:5:7: error: \\\"i\\\" shadows a previous declaration\n  for i in List<string>.new {\n      ^\n<stdin>:1:10: note: The previous declaration is here\ndef main(i int) {\n         ^\n<stdin>:6:9: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n    i = false\n        ~~~~~\n<stdin>:8:12: error: Cannot iterate over type \\\"int\\\"\n  for i in 0 {\n           ^\n<stdin>:8:7: error: \\\"i\\\" shadows a previous declaration\n  for i in 0 {\n      ^\n<stdin>:1:10: note: The previous declaration is here\ndef main(i int) {\n         ^\n<stdin>:9:9: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n    i = false\n        ~~~~~\n<stdin>:12:12: warning: This range is empty\n  for j in 10..0 {}\n           ~~~~~\n\")\n\ntest(\"\ndef main {\n  var foo = true ? false : 0\n  var bar bool = true ? 0 : 0.5\n}\n\", \"\n<stdin>:2:20: error: No common type for \\\"bool\\\" and \\\"int\\\"\n  var foo = true ? false : 0\n                   ~~~~~~~~~\n<stdin>:3:25: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n  var bar bool = true ? 0 : 0.5\n                        ^\n<stdin>:3:29: error: Cannot convert from type \\\"double\\\" to type \\\"bool\\\" without a cast\n  var bar bool = true ? 0 : 0.5\n                            ~~~\n<stdin>:2:7: warning: Local variable \\\"foo\\\" is never read\n  var foo = true ? false : 0\n      ~~~\n<stdin>:3:7: warning: Local variable \\\"bar\\\" is never read\n  var bar bool = true ? 0 : 0.5\n      ~~~\n\")\n\ntest(\"\ndef main {\n  var a int = [false]\n  var b List<int> = [false]\n  var c List<List<int>> = [[false]]\n  var d int = {1: 2}\n  var e IntMap<bool> = {\\\"a\\\": \\\"b\\\"}\n  var f StringMap<bool> = {1: 2}\n  [false, 0]\n  [0, 0.5] - 1\n  [null, [1], [0.5]]\n  [null]\n  []\n  {0: 1} - 1\n  {\\\"a\\\": 1} - 1\n  {0.5: 1} - 1\n  [foo]\n}\n\ndef foo(x int) {\n}\n\", \"\n<stdin>:2:15: error: Cannot infer a type for this literal\n  var a int = [false]\n              ~~~~~~~\n<stdin>:3:22: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n  var b List<int> = [false]\n                     ~~~~~\n<stdin>:4:29: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n  var c List<List<int>> = [[false]]\n                            ~~~~~\n<stdin>:5:15: error: Cannot infer a type for this literal\n  var d int = {1: 2}\n              ~~~~~~\n<stdin>:6:25: error: Cannot convert from type \\\"string\\\" to type \\\"int\\\"\n  var e IntMap<bool> = {\\\"a\\\": \\\"b\\\"}\n                        ~~~\n<stdin>:6:30: error: Cannot convert from type \\\"string\\\" to type \\\"bool\\\"\n  var e IntMap<bool> = {\\\"a\\\": \\\"b\\\"}\n                             ~~~\n<stdin>:7:28: error: Cannot convert from type \\\"int\\\" to type \\\"string\\\"\n  var f StringMap<bool> = {1: 2}\n                           ^\n<stdin>:7:31: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n  var f StringMap<bool> = {1: 2}\n                              ^\n<stdin>:8:11: error: No common type for \\\"bool\\\" and \\\"int\\\"\n  [false, 0]\n          ^\n<stdin>:8:3: warning: Unused expression\n  [false, 0]\n  ~~~~~~~~~~\n<stdin>:9:12: error: \\\"-\\\" is not declared on type \\\"List<double>\\\"\n  [0, 0.5] - 1\n           ^\n<stdin>:10:15: error: No common type for \\\"List<int>\\\" and \\\"List<double>\\\"\n  [null, [1], [0.5]]\n              ~~~~~\n<stdin>:10:3: warning: Unused expression\n  [null, [1], [0.5]]\n  ~~~~~~~~~~~~~~~~~~\n<stdin>:11:3: error: Cannot infer a type for this literal\n  [null]\n  ~~~~~~\n<stdin>:12:3: error: Cannot infer a type for this literal\n  []\n  ~~\n<stdin>:13:10: error: \\\"-\\\" is not declared on type \\\"IntMap<int>\\\"\n  {0: 1} - 1\n         ^\n<stdin>:14:12: error: \\\"-\\\" is not declared on type \\\"StringMap<int>\\\"\n  {\\\"a\\\": 1} - 1\n           ^\n<stdin>:15:3: error: Cannot infer a type for this literal\n  {0.5: 1} - 1\n  ~~~~~~~~\n<stdin>:16:4: error: The function \\\"foo\\\" takes 1 argument and must be called\n  [foo]\n   ~~~\n<stdin>:16:3: warning: Unused expression\n  [foo]\n  ~~~~~\n<stdin>:2:7: warning: Local variable \\\"a\\\" is never read\n  var a int = [false]\n      ^\n<stdin>:3:7: warning: Local variable \\\"b\\\" is never read\n  var b List<int> = [false]\n      ^\n<stdin>:4:7: warning: Local variable \\\"c\\\" is never read\n  var c List<List<int>> = [[false]]\n      ^\n<stdin>:5:7: warning: Local variable \\\"d\\\" is never read\n  var d int = {1: 2}\n      ^\n<stdin>:6:7: warning: Local variable \\\"e\\\" is never read\n  var e IntMap<bool> = {\\\"a\\\": \\\"b\\\"}\n      ^\n<stdin>:7:7: warning: Local variable \\\"f\\\" is never read\n  var f StringMap<bool> = {1: 2}\n      ^\n\")\n\ntest(\"\nclass A {}\n\nclass B {\n  def [...] {}\n}\n\nclass C {\n  def new {}\n  def [...] {}\n}\n\nclass D {\n  def new {}\n  def [...](x bool) D { return self }\n}\n\ndef main {\n  var a A = [1, 2]\n  var b B = [1, 2]\n  var c C = [1, 2]\n  var d D = [1, 2]\n}\n\", \"\n<stdin>:4:7: error: Expected \\\"[...]\\\" to take 1 argument\n  def [...] {}\n      ~~~~~\n<stdin>:9:7: error: Expected \\\"[...]\\\" to take 1 argument\n  def [...] {}\n      ~~~~~\n<stdin>:18:13: error: Cannot infer a type for this literal\n  var a A = [1, 2]\n            ~~~~~~\n<stdin>:19:14: error: The function \\\"[...]\\\" does not return a value\n  var b B = [1, 2]\n             ^\n<stdin>:4:7: note: The function declaration is here\n  def [...] {}\n      ~~~~~\n<stdin>:19:14: error: Expected 0 arguments but found 1 argument when calling \\\"[...]\\\"\n  var b B = [1, 2]\n             ^\n<stdin>:4:7: note: The function declaration is here\n  def [...] {}\n      ~~~~~\n<stdin>:20:14: error: The function \\\"[...]\\\" does not return a value\n  var c C = [1, 2]\n             ^\n<stdin>:9:7: note: The function declaration is here\n  def [...] {}\n      ~~~~~\n<stdin>:20:14: error: Expected 0 arguments but found 1 argument when calling \\\"[...]\\\"\n  var c C = [1, 2]\n             ^\n<stdin>:9:7: note: The function declaration is here\n  def [...] {}\n      ~~~~~\n<stdin>:21:14: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n  var d D = [1, 2]\n             ^\n<stdin>:21:17: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n  var d D = [1, 2]\n                ^\n<stdin>:18:7: warning: Local variable \\\"a\\\" is never read\n  var a A = [1, 2]\n      ^\n<stdin>:19:7: warning: Local variable \\\"b\\\" is never read\n  var b B = [1, 2]\n      ^\n<stdin>:20:7: warning: Local variable \\\"c\\\" is never read\n  var c C = [1, 2]\n      ^\n<stdin>:21:7: warning: Local variable \\\"d\\\" is never read\n  var d D = [1, 2]\n      ^\n\")\n\ntest(\"\nclass Foo {\n  def [new](x int, y int, z int) int {}\n  def {new}(x int, y int, z int) int {}\n}\n\", \"\n<stdin>:2:34: error: Constructors cannot have a return type\n  def [new](x int, y int, z int) int {}\n                                 ~~~\n<stdin>:2:7: error: Expected \\\"[new]\\\" to take at most 1 argument\n  def [new](x int, y int, z int) int {}\n      ~~~~~\n<stdin>:3:34: error: Constructors cannot have a return type\n  def {new}(x int, y int, z int) int {}\n                                 ~~~\n<stdin>:3:7: error: Expected \\\"{new}\\\" to take either 0 or 2 arguments\n  def {new}(x int, y int, z int) int {}\n      ~~~~~\n<stdin>:2:33: fix: Remove the return type\n  def [new](x int, y int, z int) int {}\n                                ~~~~\n                                []\n<stdin>:3:33: fix: Remove the return type\n  def {new}(x int, y int, z int) int {}\n                                ~~~~\n                                []\n\")\n\ntest(\"\nclass Foo {\n  def foo int {\n    return Bar<int>.new.foo\n  }\n\n  def bar List<int> {\n    return Bar<int>.new.foo\n  }\n}\n\nclass Bar<X> {\n  def new {}\n  def foo List<X> { return null }\n}\n\", \"\n<stdin>:3:12: error: Cannot convert from type \\\"List<int>\\\" to type \\\"int\\\"\n    return Bar<int>.new.foo\n           ~~~~~~~~~~~~~~~~\n\")\n\ntest(\"\nclass Foo {\n  def foo int { return 0 }\n  def foo double { return 0 }\n  def bar(x int) {}\n  def bar(x double) {}\n  def bar(x int) {}\n}\n\", \"\n<stdin>:3:7: error: Duplicate overloaded function \\\"foo\\\"\n  def foo double { return 0 }\n      ~~~\n<stdin>:2:7: note: The previous declaration is here\n  def foo int { return 0 }\n      ~~~\n<stdin>:6:7: error: Duplicate overloaded function \\\"bar\\\"\n  def bar(x int) {}\n      ~~~\n<stdin>:4:7: note: The previous declaration is here\n  def bar(x int) {}\n      ~~~\n\")\n\ntest(\"\nclass Bar : Foo {\n  over foo\n}\n\nclass Foo {\n  def foo\n}\n\", \"\n\")\n\ntest(\"\nclass Foo {\n  def foo\n}\n\nclass Bar : Foo {\n  over foo\n}\n\", \"\n\")\n\ntest(\"\nclass Bar : Foo {\n  over foo\n}\n\nclass Foo {\n  def foo {}\n  def foo {}\n}\n\", \"\n<stdin>:7:7: error: Duplicate overloaded function \\\"foo\\\"\n  def foo {}\n      ~~~\n<stdin>:6:7: note: The previous declaration is here\n  def foo {}\n      ~~~\n\")\n\ntest(\"\nclass Foo {\n  def foo {}\n  def foo {}\n}\n\nclass Bar : Foo {\n  over foo\n}\n\", \"\n<stdin>:3:7: error: Duplicate overloaded function \\\"foo\\\"\n  def foo {}\n      ~~~\n<stdin>:2:7: note: The previous declaration is here\n  def foo {}\n      ~~~\n\")\n\ntest(\"\nclass Bar : Foo {\n  over foo {}\n  over foo {}\n}\n\nclass Foo {\n  def foo\n}\n\", \"\n<stdin>:3:8: error: Duplicate overloaded function \\\"foo\\\"\n  over foo {}\n       ~~~\n<stdin>:2:8: note: The previous declaration is here\n  over foo {}\n       ~~~\n\")\n\ntest(\"\nclass Foo {\n  def foo\n}\n\nclass Bar : Foo {\n  over foo {}\n  over foo {}\n}\n\", \"\n<stdin>:7:8: error: Duplicate overloaded function \\\"foo\\\"\n  over foo {}\n       ~~~\n<stdin>:6:8: note: The previous declaration is here\n  over foo {}\n       ~~~\n\")\n\ntest(\"\nclass Bar : Foo {\n  over foo {}\n  over foo {}\n}\n\nclass Foo {\n  def foo {}\n  def foo {}\n}\n\", \"\n<stdin>:3:8: error: Duplicate overloaded function \\\"foo\\\"\n  over foo {}\n       ~~~\n<stdin>:2:8: note: The previous declaration is here\n  over foo {}\n       ~~~\n<stdin>:8:7: error: Duplicate overloaded function \\\"foo\\\"\n  def foo {}\n      ~~~\n<stdin>:7:7: note: The previous declaration is here\n  def foo {}\n      ~~~\n\")\n\ntest(\"\nclass Foo {\n  def foo {}\n  def foo {}\n}\n\nclass Bar : Foo {\n  over foo {}\n  over foo {}\n}\n\", \"\n<stdin>:3:7: error: Duplicate overloaded function \\\"foo\\\"\n  def foo {}\n      ~~~\n<stdin>:2:7: note: The previous declaration is here\n  def foo {}\n      ~~~\n<stdin>:8:8: error: Duplicate overloaded function \\\"foo\\\"\n  over foo {}\n       ~~~\n<stdin>:7:8: note: The previous declaration is here\n  over foo {}\n       ~~~\n\")\n\ntest(\"\ndef bar(x int) int { return 0 }\ndef bar(x double) double { return 0 }\ndef bar(x List<int>) List<int> { return null }\n\ndef main {\n  var w bool = bar(null)\n  var x bool = bar(0)\n  var y bool = bar(0.5)\n  var z bool = bar([])\n}\n\", \"\n<stdin>:6:16: error: Cannot convert from type \\\"List<int>\\\" to type \\\"bool\\\"\n  var w bool = bar(null)\n               ~~~~~~~~~\n<stdin>:7:16: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n  var x bool = bar(0)\n               ~~~~~~\n<stdin>:8:16: error: Cannot convert from type \\\"double\\\" to type \\\"bool\\\" without a cast\n  var y bool = bar(0.5)\n               ~~~~~~~~\n<stdin>:9:16: error: Cannot convert from type \\\"List<int>\\\" to type \\\"bool\\\"\n  var z bool = bar([])\n               ~~~~~~~\n<stdin>:6:7: warning: Local variable \\\"w\\\" is never read\n  var w bool = bar(null)\n      ^\n<stdin>:7:7: warning: Local variable \\\"x\\\" is never read\n  var x bool = bar(0)\n      ^\n<stdin>:8:7: warning: Local variable \\\"y\\\" is never read\n  var y bool = bar(0.5)\n      ^\n<stdin>:9:7: warning: Local variable \\\"z\\\" is never read\n  var z bool = bar([])\n      ^\n\")\n\ntest(\"\nnamespace Foo {\n  def [new](x List<int>) {}\n}\n\nclass Foo {}\n\ndef main(foo Foo) {\n  foo = []\n}\n\", \"\n<stdin>:8:9: error: The function \\\"[new]\\\" does not return a value\n  foo = []\n        ~~\n<stdin>:2:7: note: The function declaration is here\n  def [new](x List<int>) {}\n      ~~~~~\n\")\n\ntest(\"\nnamespace Foo {\n  def foo {}\n  var bar = 0\n}\n\nclass Foo<T> {\n  def new {}\n  def ifoo {}\n  var ibar = 0\n}\n\ndef main(foo Foo<int>) {\n  foo.new\n  Foo.new\n  Foo<int>.new\n\n  foo.foo\n  Foo.foo\n  Foo<int>.foo\n\n  foo.bar = 0\n  Foo.bar = 0\n  Foo<int>.bar = 0\n\n  foo.ifoo\n  Foo.ifoo\n  Foo<int>.ifoo\n\n  foo.ibar = 0\n  Foo.ibar = 0\n  Foo<int>.ibar = 0\n}\n\", \"\n<stdin>:13:7: error: Cannot access global member \\\"new\\\" from an instance context\n  foo.new\n      ~~~\n<stdin>:14:3: error: Cannot use unparameterized type \\\"Foo\\\" here\n  Foo.new\n  ~~~\n<stdin>:17:7: error: Cannot access global member \\\"foo\\\" from an instance context\n  foo.foo\n      ~~~\n<stdin>:18:3: error: Cannot use unparameterized type \\\"Foo\\\" here\n  Foo.foo\n  ~~~\n<stdin>:21:7: error: Cannot access global member \\\"bar\\\" from an instance context\n  foo.bar = 0\n      ~~~\n<stdin>:23:3: error: Cannot use parameterized type \\\"Foo<int>\\\" here\n  Foo<int>.bar = 0\n  ~~~~~~~~\n<stdin>:26:7: error: Cannot access instance member \\\"ifoo\\\" from a global context\n  Foo.ifoo\n      ~~~~\n<stdin>:27:12: error: Cannot access instance member \\\"ifoo\\\" from a global context\n  Foo<int>.ifoo\n           ~~~~\n<stdin>:30:7: error: Cannot access instance member \\\"ibar\\\" from a global context\n  Foo.ibar = 0\n      ~~~~\n<stdin>:31:12: error: Cannot access instance member \\\"ibar\\\" from a global context\n  Foo<int>.ibar = 0\n           ~~~~\n\")\n\ntest(\"\nclass Foo {\n  class Bar { def bar int { return foo + baz } }\n  def baz int { return 0 }\n  var foo = 0\n}\n\", \"\n<stdin>:2:36: error: Cannot access instance member \\\"foo\\\" from a global context\n  class Bar { def bar int { return foo + baz } }\n                                   ~~~\n<stdin>:2:42: error: Cannot access instance member \\\"baz\\\" from a global context\n  class Bar { def bar int { return foo + baz } }\n                                         ~~~\n\")\n\ntest(\"\nclass Foo { class Bar {} }\nnamespace Foo {\n  namespace Bar { def bar int { return foo + baz } }\n  def baz int { return 0 }\n  var foo = 0\n}\n\", \"\n\")\n\ntest(\"\nclass Foo : int {}\nclass Bar : fn() {}\nclass Baz : Baz {}\n\", \"\n<stdin>:1:13: error: Cannot extend type \\\"int\\\"\nclass Foo : int {}\n            ~~~\n<stdin>:2:13: error: Cannot extend type \\\"fn()\\\"\nclass Bar : fn() {}\n            ~~~~\n<stdin>:3:7: error: Cyclic declaration of \\\"Baz\\\"\nclass Baz : Baz {}\n      ~~~\n\")\n\ntest(\"\nclass Foo { def foo {} }\nclass Bar : Foo { def bar {} }\nclass Baz : Foo { def baz {} }\n\ndef main(foo Foo, bar Bar, baz Baz) {\n  foo.foo\n  foo.bar\n  bar.foo\n  bar.bar\n  baz.foo\n  baz.bar\n}\n\", \"\n<stdin>:7:7: error: \\\"bar\\\" is not declared on type \\\"Foo\\\"\n  foo.bar\n      ~~~\n<stdin>:11:7: error: \\\"bar\\\" is not declared on type \\\"Baz\\\", did you mean \\\"baz\\\"?\n  baz.bar\n      ~~~\n<stdin>:3:23: note: \\\"baz\\\" is defined here\nclass Baz : Foo { def baz {} }\n                      ~~~\n<stdin>:11:7: fix: Replace with \\\"baz\\\"\n  baz.bar\n      ~~~\n      [baz]\n\")\n\ntest(\"\nclass Foo { def new {} }\nclass Bar : Foo { def new { super } }\nclass Baz : Foo { def new { super } }\n\ndef main {\n  var a Foo = Foo.new\n  var b Foo = Bar.new\n  var c Foo = Baz.new\n  var d Bar = Foo.new\n  var e Bar = Bar.new\n  var f Bar = Baz.new\n}\n\", \"\n<stdin>:9:15: error: Cannot convert from type \\\"Foo\\\" to type \\\"Bar\\\" without a cast\n  var d Bar = Foo.new\n              ~~~~~~~\n<stdin>:11:15: error: Cannot convert from type \\\"Baz\\\" to type \\\"Bar\\\"\n  var f Bar = Baz.new\n              ~~~~~~~\n<stdin>:6:7: warning: Local variable \\\"a\\\" is never read\n  var a Foo = Foo.new\n      ^\n<stdin>:7:7: warning: Local variable \\\"b\\\" is never read\n  var b Foo = Bar.new\n      ^\n<stdin>:8:7: warning: Local variable \\\"c\\\" is never read\n  var c Foo = Baz.new\n      ^\n<stdin>:9:7: warning: Local variable \\\"d\\\" is never read\n  var d Bar = Foo.new\n      ^\n<stdin>:10:7: warning: Local variable \\\"e\\\" is never read\n  var e Bar = Bar.new\n      ^\n<stdin>:11:7: warning: Local variable \\\"f\\\" is never read\n  var f Bar = Baz.new\n      ^\n\")\n\ntest(\"\nclass Foo<T> { def new {} }\nclass Bar : Foo<int> { def new { super } }\nclass Baz : Foo<int> { def new { super } }\n\ndef main {\n  var foo = true ? Bar.new : Baz.new\n  var bar int = foo\n}\n\", \"\n<stdin>:7:17: error: Cannot convert from type \\\"Foo<int>\\\" to type \\\"int\\\"\n  var bar int = foo\n                ~~~\n<stdin>:7:7: warning: Local variable \\\"bar\\\" is never read\n  var bar int = foo\n      ~~~\n\")\n\ntest(\"\nclass Foo<T> { def new {} }\nclass Bar : Foo<int> { def new { super } }\nclass Baz : Foo<bool> { def new { super } }\n\ndef main {\n  var foo = true ? Bar.new : Baz.new\n  var bar int = foo\n}\n\", \"\n<stdin>:6:20: error: No common type for \\\"Bar\\\" and \\\"Baz\\\"\n  var foo = true ? Bar.new : Baz.new\n                   ~~~~~~~~~~~~~~~~~\n<stdin>:7:7: warning: Local variable \\\"bar\\\" is never read\n  var bar int = foo\n      ~~~\n\")\n\ntest(\"\nclass Foo<A, B> {\n  def foo(a A) Foo<A, B> { return self }\n  def bar(b B) A { return b as dynamic }\n}\n\nclass Bar<T> : Foo<int, T> {\n}\n\nclass Baz : Bar<bool> {\n  def new { super }\n}\n\ndef foo string {\n  return Baz.new.foo(0.5).bar(null)\n}\n\", \"\n<stdin>:14:22: error: Cannot convert from type \\\"double\\\" to type \\\"int\\\" without a cast\n  return Baz.new.foo(0.5).bar(null)\n                     ~~~\n<stdin>:14:31: error: Cannot convert from type \\\"null\\\" to type \\\"bool\\\"\n  return Baz.new.foo(0.5).bar(null)\n                              ~~~~\n<stdin>:14:10: error: Cannot convert from type \\\"int\\\" to type \\\"string\\\"\n  return Baz.new.foo(0.5).bar(null)\n         ~~~~~~~~~~~~~~~~~~~~~~~~~~\n\")\n\ntest(\"\nvar a = 0 # a\nvar b = 0 # b\n# comment\nvar c = 0 # c\n\n# comment\nvar d = 0 # d\n\", \"\n\")\n\ntest(\"\nclass Foo<T> {\n  def foo(x T)\n  def foo(x int)\n}\n\ndef foo(foo Foo<bool>) {\n  foo.foo(0)\n  foo.foo(0.5)\n  foo.foo(false)\n}\n\", \"\n<stdin>:8:3: error: No overload of \\\"foo\\\" was found that takes 1 argument of type double\n  foo.foo(0.5)\n  ~~~~~~~\n\")\n\ntest(\"\nclass Foo {\n  def +=(x int)\n  def +=(x List<int>)\n}\n\ndef foo(foo Foo) {\n  foo += false\n  foo += []\n  foo += [false]\n  foo += {}\n  foo += {false: false}\n}\n\", \"\n<stdin>:7:7: error: No overload of \\\"+=\\\" was found that takes 1 argument of type bool\n  foo += false\n      ~~\n<stdin>:9:11: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n  foo += [false]\n          ~~~~~\n<stdin>:10:10: error: Cannot infer a type for this literal\n  foo += {}\n         ~~\n<stdin>:10:7: error: No overload of \\\"+=\\\" was found that takes 1 argument of type dynamic\n  foo += {}\n      ~~\n<stdin>:11:10: error: Cannot infer a type for this literal\n  foo += {false: false}\n         ~~~~~~~~~~~~~~\n<stdin>:11:7: error: No overload of \\\"+=\\\" was found that takes 1 argument of type dynamic\n  foo += {false: false}\n      ~~\n\")\n\ntest(\"\nclass Foo {\n  def +=(x dynamic)\n  def +=(x List<int>)\n}\n\ndef foo(foo Foo) {\n  foo += false\n  foo += [false]\n}\n\", \"\n<stdin>:8:11: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n  foo += [false]\n          ~~~~~\n\")\n\ntest(\"\nclass Foo {\n  def +=(x dynamic)\n  def +=(x double)\n}\n\ndef foo(foo Foo) {\n  foo += 0\n}\n\", \"\n<stdin>:7:7: error: Multiple matching overloads of \\\"+=\\\" were found that can take 1 argument of type int\n  foo += 0\n      ~~\n\")\n\ntest(\"\nclass Foo {\n  def +=(x dynamic) int\n  @prefer\n  def +=(x double) double\n}\n\ndef foo(foo Foo) {\n  var bar bool = foo += 0\n}\n\", \"\n<stdin>:8:18: error: Cannot convert from type \\\"double\\\" to type \\\"bool\\\" without a cast\n  var bar bool = foo += 0\n                 ~~~~~~~~\n<stdin>:8:7: warning: Local variable \\\"bar\\\" is never read\n  var bar bool = foo += 0\n      ~~~\n\")\n\ntest(\"\nclass Foo {\n  def new {}\n  def <=>(x Foo) int { return 0 }\n}\n\nvar foo int = Foo.new < Foo.new\nvar bar bool = Foo.new <=> Foo.new\nvar baz int = 1 < 2\n\", \"\n<stdin>:6:15: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\nvar foo int = Foo.new < Foo.new\n              ~~~~~~~~~~~~~~~~~\n<stdin>:7:16: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\nvar bar bool = Foo.new <=> Foo.new\n               ~~~~~~~~~~~~~~~~~~~\n<stdin>:8:15: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\nvar baz int = 1 < 2\n              ~~~~~\n\")\n\ntest(\"\ndef main(x List<List<int>>) {\n  var foo = [false] in x\n}\n\", \"\n<stdin>:2:14: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n  var foo = [false] in x\n             ~~~~~\n<stdin>:2:7: warning: Local variable \\\"foo\\\" is never read\n  var foo = [false] in x\n      ~~~\n\")\n\ntest(\"\ndef main {\n  for i in 0..10 {\n    0 += 1\n    0 = 1\n    i += 1\n    i = 1\n  }\n}\n\", \"\n<stdin>:3:5: error: Cannot store to this location\n    0 += 1\n    ^\n<stdin>:4:5: error: Cannot store to this location\n    0 = 1\n    ^\n<stdin>:5:5: error: Cannot store to constant symbol \\\"i\\\"\n    i += 1\n    ^\n<stdin>:6:5: error: Cannot store to constant symbol \\\"i\\\"\n    i = 1\n    ^\n\")\n\ntest(\"\ndef main {\n  for i in 0..10 {\n    0 += 1\n    0 = 1\n    i += 1\n    i = 1\n  }\n}\n\", \"\n<stdin>:3:5: error: Cannot store to this location\n    0 += 1\n    ^\n<stdin>:4:5: error: Cannot store to this location\n    0 = 1\n    ^\n<stdin>:5:5: error: Cannot store to constant symbol \\\"i\\\"\n    i += 1\n    ^\n<stdin>:6:5: error: Cannot store to constant symbol \\\"i\\\"\n    i = 1\n    ^\n\")\n\ntest(\"\nclass Foo {\n  def foo(x int)\n}\n\nclass Bar : Foo {\n  def foo(x bool)\n}\n\ndef main(x Bar) {\n  x.foo(0)\n  x.foo(0.5)\n  x.foo(false)\n}\n\", \"\n<stdin>:11:3: error: No overload of \\\"foo\\\" was found that takes 1 argument of type double\n  x.foo(0.5)\n  ~~~~~\n\")\n\ntest(\"\nclass Foo {\n  def foo(x string)\n  def foo(x int)\n}\n\nclass Bar : Foo {\n  def foo(x bool)\n}\n\ndef main(x Bar) {\n  x.foo(0)\n  x.foo(\\\"\\\")\n  x.foo(0.5)\n  x.foo(false)\n}\n\", \"\n<stdin>:13:3: error: No overload of \\\"foo\\\" was found that takes 1 argument of type double\n  x.foo(0.5)\n  ~~~~~\n\")\n\ntest(\"\nclass Foo {\n  def foo(x int)\n}\n\nclass Bar : Foo {\n  def foo(x string)\n  def foo(x bool)\n}\n\ndef main(x Bar) {\n  x.foo(0)\n  x.foo(\\\"\\\")\n  x.foo(0.5)\n  x.foo(false)\n}\n\", \"\n<stdin>:13:3: error: No overload of \\\"foo\\\" was found that takes 1 argument of type double\n  x.foo(0.5)\n  ~~~~~\n\")\n\ntest(\"\nclass Foo {\n  def foo(x Foo)\n  def foo(x int)\n}\n\nclass Bar : Foo {\n  def foo(x string)\n  def foo(x bool)\n}\n\ndef main(x Bar) {\n  x.foo(0)\n  x.foo(\\\"\\\")\n  x.foo(0.5)\n  x.foo(null)\n  x.foo(false)\n}\n\", \"\n<stdin>:14:3: error: No overload of \\\"foo\\\" was found that takes 1 argument of type double\n  x.foo(0.5)\n  ~~~~~\n<stdin>:15:3: error: Multiple matching overloads of \\\"foo\\\" were found that can take 1 argument of type null\n  x.foo(null)\n  ~~~~~\n\")\n\ntest(\"\nclass Foo<T> {\n  var foo int\n}\n\nclass Bar : Foo<int> {\n  def foo\n}\n\", \"\n<stdin>:6:7: error: \\\"foo\\\" overrides another declaration with the same name in base type \\\"Foo<int>\\\"\n  def foo\n      ~~~\n<stdin>:2:7: note: The overridden declaration is here\n  var foo int\n      ~~~\n\")\n\ntest(\"\nclass Foo<T> {\n  def foo\n}\n\nclass Bar : Foo<int> {\n  var foo int\n}\n\", \"\n<stdin>:6:7: error: \\\"foo\\\" overrides another declaration with the same name in base type \\\"Foo<int>\\\"\n  var foo int\n      ~~~\n<stdin>:2:7: note: The overridden declaration is here\n  def foo\n      ~~~\n\")\n\ntest(\"\nclass Foo<T> {\n  class foo {}\n}\n\nclass Bar : Foo<int> {\n  def foo\n}\n\", \"\n<stdin>:6:7: error: \\\"foo\\\" overrides another declaration with the same name in base type \\\"Foo<int>\\\"\n  def foo\n      ~~~\n<stdin>:2:9: note: The overridden declaration is here\n  class foo {}\n        ~~~\n\")\n\ntest(\"\nclass Foo<T> {\n  def foo\n}\n\nclass Bar : Foo<int> {\n  class foo {}\n}\n\", \"\n<stdin>:6:9: error: \\\"foo\\\" overrides another declaration with the same name in base type \\\"Foo<int>\\\"\n  class foo {}\n        ~~~\n<stdin>:2:7: note: The overridden declaration is here\n  def foo\n      ~~~\n\")\n\ntest(\"\nclass Foo<T> {\n}\n\nnamespace Foo {\n  def foo {}\n}\n\nclass Bar : Foo<int> {\n  def foo\n}\n\", \"\n<stdin>:9:7: error: \\\"foo\\\" overrides another declaration with the same name in base type \\\"Foo<int>\\\"\n  def foo\n      ~~~\n<stdin>:5:7: note: The overridden declaration is here\n  def foo {}\n      ~~~\n\")\n\ntest(\"\nclass Foo<T> {\n  def foo\n}\n\nclass Bar : Foo<int> {\n}\n\nnamespace Bar {\n  def foo {}\n}\n\", \"\n<stdin>:9:7: error: \\\"foo\\\" overrides another declaration with the same name in base type \\\"Foo<int>\\\"\n  def foo {}\n      ~~~\n<stdin>:2:7: note: The overridden declaration is here\n  def foo\n      ~~~\n\")\n\ntest(\"\nclass Foo<T> {\n  def new {}\n  def foo\n}\n\nclass Bar : Foo<int> {\n  def new { super }\n  over foo\n}\n\nnamespace Foo {\n  def bar {}\n}\n\nnamespace Bar {\n  def bar {}\n}\n\", \"\n\")\n\ntest(\"\nclass Foo<T> {\n  def foo int\n}\n\nclass Bar : Foo<int> {\n  def foo bool\n}\n\", \"\n<stdin>:6:7: error: \\\"foo\\\" overrides another function with the same name and argument types but a different return type in base type \\\"Foo<int>\\\"\n  def foo bool\n      ~~~\n<stdin>:2:7: note: The overridden function is here\n  def foo int\n      ~~~\n\")\n\ntest(\"\nclass Foo<T> {\n  def foo int\n}\n\nclass Bar : Foo<int> {\n  def foo bool\n  def bar int\n}\n\", \"\n<stdin>:6:7: error: \\\"foo\\\" overrides another function with the same name and argument types but a different return type in base type \\\"Foo<int>\\\"\n  def foo bool\n      ~~~\n<stdin>:2:7: note: The overridden function is here\n  def foo int\n      ~~~\n\")\n\ntest(\"\nclass Foo<T> {\n  def foo int\n  def bar int\n}\n\nclass Bar : Foo<int> {\n  def foo bool\n}\n\", \"\n<stdin>:7:7: error: \\\"foo\\\" overrides another function with the same name and argument types but a different return type in base type \\\"Foo<int>\\\"\n  def foo bool\n      ~~~\n<stdin>:2:7: note: The overridden function is here\n  def foo int\n      ~~~\n\")\n\ntest(\"\nclass Foo<T> {\n  def foo int\n  def bar bool\n}\n\nclass Bar : Foo<int> {\n  def foo bool\n  def bar int\n}\n\", \"\n<stdin>:7:7: error: \\\"foo\\\" overrides another function with the same name and argument types but a different return type in base type \\\"Foo<int>\\\"\n  def foo bool\n      ~~~\n<stdin>:2:7: note: The overridden function is here\n  def foo int\n      ~~~\n<stdin>:8:7: error: \\\"bar\\\" overrides another function with the same name and argument types but a different return type in base type \\\"Foo<int>\\\"\n  def bar int\n      ~~~\n<stdin>:3:7: note: The overridden function is here\n  def bar bool\n      ~~~\n\")\n\ntest(\"\ninterface Foo<A, B> {\n  def foo(x A) B\n}\n\nclass Bar :: Foo<int, double> {\n  def foo(x int) double {\n    return 0\n  }\n}\n\nclass Bar2 :: Foo<int, double> {\n  def foo(x double) int {\n    return 0\n  }\n}\n\", \"\n<stdin>:11:7: error: Type \\\"Bar2\\\" is missing an implementation of function \\\"foo\\\" from interface \\\"Foo<int, double>\\\"\nclass Bar2 :: Foo<int, double> {\n      ~~~~\n<stdin>:2:7: note: The function declaration is here\n  def foo(x A) B\n      ~~~\n\")\n\ntest(\"\ninterface Foo<A> {\n  def foo<B>(x A, y B) B\n}\n\nclass Bar :: Foo<int> {\n  def foo<T>(x int, y T) T {\n    return y\n  }\n}\n\nclass Bar2 :: Foo<int> {\n  def foo<T>(x double, y T) int {\n    return 0\n  }\n}\n\nclass Bar3 :: Foo<int> {\n  def foo<T>(x int, y T) int {\n    return 0\n  }\n}\n\", \"\n<stdin>:11:7: error: Type \\\"Bar2\\\" is missing an implementation of function \\\"foo\\\" from interface \\\"Foo<int>\\\"\nclass Bar2 :: Foo<int> {\n      ~~~~\n<stdin>:2:7: note: The function declaration is here\n  def foo<B>(x A, y B) B\n      ~~~\n<stdin>:18:7: error: Function \\\"foo\\\" has unexpected return type \\\"int\\\", expected return type \\\"T\\\" to match the function with the same name and argument types from interface \\\"Foo<int>\\\"\n  def foo<T>(x int, y T) int {\n      ~~~\n<stdin>:2:7: note: The function declaration is here\n  def foo<B>(x A, y B) B\n      ~~~\n\")\n\ntest(\"\nvar x = super\ndef foo { super }\n\nclass Foo {\n  def new { super }\n  def foo { super }\n}\n\nnamespace Foo {\n  def bar { super }\n}\n\nclass Bar : Foo {\n  def new { super }\n  over foo { super }\n}\n\nnamespace Bar {\n  def bar { super }\n}\n\", \"\n<stdin>:5:13: error: Cannot use \\\"super\\\" here\n  def new { super }\n            ~~~~~\n<stdin>:6:13: error: Cannot use \\\"super\\\" here\n  def foo { super }\n            ~~~~~\n<stdin>:10:13: error: Cannot use \\\"super\\\" here\n  def bar { super }\n            ~~~~~\n<stdin>:2:11: error: Cannot use \\\"super\\\" here\ndef foo { super }\n          ~~~~~\n<stdin>:1:9: error: Cannot use \\\"super\\\" here\nvar x = super\n        ~~~~~\n\")\n\ntest(\"\nclass Foo {\n  def new(x int) {}\n  def foo(x int) {}\n}\n\nnamespace Foo {\n  def bar(x int) {}\n}\n\nclass Bar : Foo {\n  def new(x int) { super() }\n  over foo(x int) { super() }\n}\n\nnamespace Bar {\n  def bar(x int) { super() }\n}\n\", \"\n<stdin>:11:25: error: Expected 1 argument but found 0 arguments when calling \\\"new\\\"\n  def new(x int) { super() }\n                        ~~\n<stdin>:2:7: note: The function declaration is here\n  def new(x int) {}\n      ~~~\n<stdin>:12:26: error: Expected 1 argument but found 0 arguments when calling \\\"foo\\\"\n  over foo(x int) { super() }\n                         ~~\n<stdin>:3:7: note: The function declaration is here\n  def foo(x int) {}\n      ~~~\n<stdin>:16:25: error: Expected 1 argument but found 0 arguments when calling \\\"bar\\\"\n  def bar(x int) { super() }\n                        ~~\n<stdin>:7:7: note: The function declaration is here\n  def bar(x int) {}\n      ~~~\n\")\n\ntest(\"\nclass Foo {\n  def new(x int) {}\n}\n\nclass Bar : Foo {\n  def new(x bool) {\n    super(x)\n  }\n}\n\", \"\n<stdin>:7:11: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n    super(x)\n          ^\n\")\n\ntest(\"\nclass Foo {\n  def new(x int) {}\n}\n\nclass Bar : Foo {\n  def new {\n    super(1, 2)\n  }\n}\n\", \"\n<stdin>:7:10: error: Expected 1 argument but found 2 arguments when calling \\\"new\\\"\n    super(1, 2)\n         ~~~~~~\n<stdin>:2:7: note: The function declaration is here\n  def new(x int) {}\n      ~~~\n\")\n\ntest(\"\nclass Foo {\n  def new(x int) {}\n  def new(x int, y int) {}\n}\n\nclass Bar : Foo {\n  def new(z int) {\n    super(false)\n  }\n\n  def new(y int, z int) {\n    super(false, y)\n  }\n\n  def new(x int, y int, z int) {\n    super(x, y, z)\n  }\n}\n\", \"\n<stdin>:8:11: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n    super(false)\n          ~~~~~\n<stdin>:12:11: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n    super(false, y)\n          ~~~~~\n<stdin>:16:5: error: No overload of \\\"new\\\" was found that takes 3 arguments\n    super(x, y, z)\n    ~~~~~\n\")\n\ntest(\"\nclass Foo {\n  def new(x int) {\n    super\n  }\n}\n\", \"\n<stdin>:3:5: error: Cannot use \\\"super\\\" here\n    super\n    ~~~~~\n\")\n\ntest(\"\nclass Foo {\n  def foo(x int) {}\n  def foo {}\n}\n\nclass Bar : Foo {\n  over foo { super(false) }\n  over foo(x int) { super }\n  def foo(x int, y int) { super(x, y) }\n}\n\", \"\n<stdin>:7:20: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n  over foo { super(false) }\n                   ~~~~~\n<stdin>:9:27: error: No overload of \\\"foo\\\" was found that takes 2 arguments\n  def foo(x int, y int) { super(x, y) }\n                          ~~~~~\n\")\n\ntest(\"\nenum Foo {\n  FOO\n  BAR\n}\n\ndef main {\n  var foo int = Foo.FOO == .BAR\n  var bar int = .FOO == Foo.BAR\n  var baz int = .FOO == .BAR\n}\n\", \"\n<stdin>:7:17: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n  var foo int = Foo.FOO == .BAR\n                ~~~~~~~~~~~~~~~\n<stdin>:8:17: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n  var bar int = .FOO == Foo.BAR\n                ~~~~~~~~~~~~~~~\n<stdin>:9:25: error: Cannot access \\\"BAR\\\" without type context\n  var baz int = .FOO == .BAR\n                        ~~~~\n<stdin>:9:17: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n  var baz int = .FOO == .BAR\n                ~~~~~~~~~~~~\n<stdin>:7:7: warning: Local variable \\\"foo\\\" is never read\n  var foo int = Foo.FOO == .BAR\n      ~~~\n<stdin>:8:7: warning: Local variable \\\"bar\\\" is never read\n  var bar int = .FOO == Foo.BAR\n      ~~~\n<stdin>:9:7: warning: Local variable \\\"baz\\\" is never read\n  var baz int = .FOO == .BAR\n      ~~~\n\")\n\ntest(\"\nenum Foo {\n  var foo\n  def bar\n  def new\n}\n\nnamespace Foo {\n  var foo2\n  def bar2\n}\n\", \"\n<stdin>:2:3: error: Cannot use this declaration here\n  var foo\n  ~~~~~~~\n<stdin>:4:3: error: Cannot use this declaration here\n  def new\n  ~~~~~~~\n<stdin>:3:7: error: Non-imported function \\\"bar\\\" is missing an implementation (use the \\\"@import\\\" annotation if it's implemented externally)\n  def bar\n      ~~~\n<stdin>:4:7: error: Non-imported function \\\"new\\\" is missing an implementation (use the \\\"@import\\\" annotation if it's implemented externally)\n  def new\n      ~~~\n<stdin>:9:7: error: Non-imported function \\\"bar2\\\" is missing an implementation (use the \\\"@import\\\" annotation if it's implemented externally)\n  def bar2\n      ~~~~\n<stdin>:2:7: error: The implicitly typed variable \\\"foo\\\" must be initialized\n  var foo\n      ~~~\n<stdin>:8:7: error: The implicitly typed variable \\\"foo2\\\" must be initialized\n  var foo2\n      ~~~~\n\")\n\ntest(\"\nenum Foo {\n  FOO\n}\n\ndef main {\n  var a bool = Foo.FOO as string\n  var b bool = Foo.FOO as int\n  var c bool = Foo.FOO as double\n  var d bool = \\\"FOO\\\" as Foo\n  var e bool = 0 as Foo\n  var f bool = 0.0 as Foo\n  var g bool = Foo.FOO.toString\n  var h int = Foo.FOO\n}\n\", \"\n<stdin>:6:16: error: Cannot convert from type \\\"Foo\\\" to type \\\"string\\\"\n  var a bool = Foo.FOO as string\n               ~~~~~~~\n<stdin>:6:16: error: Cannot convert from type \\\"string\\\" to type \\\"bool\\\"\n  var a bool = Foo.FOO as string\n               ~~~~~~~~~~~~~~~~~\n<stdin>:7:16: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n  var b bool = Foo.FOO as int\n               ~~~~~~~~~~~~~~\n<stdin>:8:16: error: Cannot convert from type \\\"double\\\" to type \\\"bool\\\" without a cast\n  var c bool = Foo.FOO as double\n               ~~~~~~~~~~~~~~~~~\n<stdin>:9:16: error: Cannot convert from type \\\"string\\\" to type \\\"Foo\\\"\n  var d bool = \\\"FOO\\\" as Foo\n               ~~~~~\n<stdin>:9:16: error: Cannot convert from type \\\"Foo\\\" to type \\\"bool\\\"\n  var d bool = \\\"FOO\\\" as Foo\n               ~~~~~~~~~~~~\n<stdin>:10:16: error: Cannot convert from type \\\"Foo\\\" to type \\\"bool\\\"\n  var e bool = 0 as Foo\n               ~~~~~~~~\n<stdin>:11:16: error: Cannot convert from type \\\"Foo\\\" to type \\\"bool\\\"\n  var f bool = 0.0 as Foo\n               ~~~~~~~~~~\n<stdin>:12:16: error: Cannot convert from type \\\"string\\\" to type \\\"bool\\\"\n  var g bool = Foo.FOO.toString\n               ~~~~~~~~~~~~~~~~\n<stdin>:6:7: warning: Local variable \\\"a\\\" is never read\n  var a bool = Foo.FOO as string\n      ^\n<stdin>:7:7: warning: Local variable \\\"b\\\" is never read\n  var b bool = Foo.FOO as int\n      ^\n<stdin>:8:7: warning: Local variable \\\"c\\\" is never read\n  var c bool = Foo.FOO as double\n      ^\n<stdin>:9:7: warning: Local variable \\\"d\\\" is never read\n  var d bool = \\\"FOO\\\" as Foo\n      ^\n<stdin>:10:7: warning: Local variable \\\"e\\\" is never read\n  var e bool = 0 as Foo\n      ^\n<stdin>:11:7: warning: Local variable \\\"f\\\" is never read\n  var f bool = 0.0 as Foo\n      ^\n<stdin>:12:7: warning: Local variable \\\"g\\\" is never read\n  var g bool = Foo.FOO.toString\n      ^\n<stdin>:13:7: warning: Local variable \\\"h\\\" is never read\n  var h int = Foo.FOO\n      ^\n\")\n\ntest(\"\ndef main {\n  if true {} else if true {} else {}\n\n  # A\n  if true {} # AA\n\n  # B\n  else if true {} # BB\n\n  # C\n  else {} # CC\n}\n\", \"\n\")\n\ntest(\"\ndef main {\n  while true {\n    break\n    continue\n  }\n\n  break\n  continue\n\n  if true {\n    break\n    continue\n  }\n\n  while true {\n    if true {\n      break\n      continue\n    }\n  }\n}\n\", \"\n<stdin>:7:3: error: Cannot use \\\"break\\\" outside a loop\n  break\n  ~~~~~\n<stdin>:8:3: error: Cannot use \\\"continue\\\" outside a loop\n  continue\n  ~~~~~~~~\n<stdin>:11:5: error: Cannot use \\\"break\\\" outside a loop\n    break\n    ~~~~~\n<stdin>:12:5: error: Cannot use \\\"continue\\\" outside a loop\n    continue\n    ~~~~~~~~\n\")\n\ntest(\"\ndef main {\n  while true {\n    var x = => {\n      break\n      continue\n    }\n  }\n}\n\", \"\n<stdin>:4:7: error: Cannot use \\\"break\\\" outside a loop\n      break\n      ~~~~~\n<stdin>:5:7: error: Cannot use \\\"continue\\\" outside a loop\n      continue\n      ~~~~~~~~\n<stdin>:3:9: warning: Local variable \\\"x\\\" is never read\n    var x = => {\n        ^\n\")\n\ntest(\"\nenum Foo {\n  FOO\n  BAR\n}\n\ndef main {\n  switch Foo.FOO {\n    case .FOO, .BAR, .BAZ {}\n    case 0 {}\n    default {}\n  }\n}\n\", \"\n<stdin>:8:23: error: \\\"BAZ\\\" is not declared on type \\\"Foo\\\", did you mean \\\"BAR\\\"?\n    case .FOO, .BAR, .BAZ {}\n                      ~~~\n<stdin>:3:3: note: \\\"BAR\\\" is defined here\n  BAR\n  ~~~\n<stdin>:9:10: error: Cannot convert from type \\\"int\\\" to type \\\"Foo\\\" without a cast\n    case 0 {}\n         ^\n<stdin>:9:10: error: Duplicate case value\n    case 0 {}\n         ^\n<stdin>:8:10: note: The first occurrence is here\n    case .FOO, .BAR, .BAZ {}\n         ~~~~\n<stdin>:8:23: fix: Replace with \\\"BAR\\\"\n    case .FOO, .BAR, .BAZ {}\n                      ~~~\n                      [BAR]\n\")\n\ntest(\"\ndef main(x Foo) {\n  switch 0 {\n    case 0, 1, 2 {}\n    case 0, 2 {}\n    case 1 {}\n  }\n\n  switch x {\n    case .FOO, .BAR, .BAZ {}\n    case .FOO, .BAZ {}\n    case .BAR {}\n  }\n}\n\nenum Foo {\n  FOO\n  BAR\n  BAZ\n}\n\", \"\n<stdin>:4:10: error: Duplicate case value\n    case 0, 2 {}\n         ^\n<stdin>:3:10: note: The first occurrence is here\n    case 0, 1, 2 {}\n         ^\n<stdin>:4:13: error: Duplicate case value\n    case 0, 2 {}\n            ^\n<stdin>:3:16: note: The first occurrence is here\n    case 0, 1, 2 {}\n               ^\n<stdin>:5:10: error: Duplicate case value\n    case 1 {}\n         ^\n<stdin>:3:13: note: The first occurrence is here\n    case 0, 1, 2 {}\n            ^\n<stdin>:10:10: error: Duplicate case value\n    case .FOO, .BAZ {}\n         ~~~~\n<stdin>:9:10: note: The first occurrence is here\n    case .FOO, .BAR, .BAZ {}\n         ~~~~\n<stdin>:10:16: error: Duplicate case value\n    case .FOO, .BAZ {}\n               ~~~~\n<stdin>:9:22: note: The first occurrence is here\n    case .FOO, .BAR, .BAZ {}\n                     ~~~~\n<stdin>:11:10: error: Duplicate case value\n    case .BAR {}\n         ~~~~\n<stdin>:9:16: note: The first occurrence is here\n    case .FOO, .BAR, .BAZ {}\n               ~~~~\n\")\n\ntest(\"\ndef foo(x double, y double) double { return 0 }\ndef foo(x int, y int) int { return 0 }\n\n@prefer\ndef bar(x double, y double) double { return 0 }\ndef bar(x int, y int) int { return 0 }\n\ndef main {\n  var a bool = foo(1, 2)\n  var b bool = foo(1, 2.0)\n  var c bool = foo(1, 2 as dynamic)\n\n  var x bool = bar(1, 2)\n  var y bool = bar(1, 2.0)\n  var z bool = bar(1, 2 as dynamic)\n}\n\", \"\n<stdin>:9:16: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n  var a bool = foo(1, 2)\n               ~~~~~~~~~\n<stdin>:10:16: error: Cannot convert from type \\\"double\\\" to type \\\"bool\\\" without a cast\n  var b bool = foo(1, 2.0)\n               ~~~~~~~~~~~\n<stdin>:11:16: error: Multiple matching overloads of \\\"foo\\\" were found that can take 2 arguments of types int and dynamic\n  var c bool = foo(1, 2 as dynamic)\n               ~~~\n<stdin>:13:16: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n  var x bool = bar(1, 2)\n               ~~~~~~~~~\n<stdin>:14:16: error: Cannot convert from type \\\"double\\\" to type \\\"bool\\\" without a cast\n  var y bool = bar(1, 2.0)\n               ~~~~~~~~~~~\n<stdin>:15:16: error: Cannot convert from type \\\"double\\\" to type \\\"bool\\\" without a cast\n  var z bool = bar(1, 2 as dynamic)\n               ~~~~~~~~~~~~~~~~~~~~\n<stdin>:9:7: warning: Local variable \\\"a\\\" is never read\n  var a bool = foo(1, 2)\n      ^\n<stdin>:10:7: warning: Local variable \\\"b\\\" is never read\n  var b bool = foo(1, 2.0)\n      ^\n<stdin>:11:7: warning: Local variable \\\"c\\\" is never read\n  var c bool = foo(1, 2 as dynamic)\n      ^\n<stdin>:13:7: warning: Local variable \\\"x\\\" is never read\n  var x bool = bar(1, 2)\n      ^\n<stdin>:14:7: warning: Local variable \\\"y\\\" is never read\n  var y bool = bar(1, 2.0)\n      ^\n<stdin>:15:7: warning: Local variable \\\"z\\\" is never read\n  var z bool = bar(1, 2 as dynamic)\n      ^\n\")\n\ntest(\"\nclass Foo {\n  var a bool\n  var b = 0\n}\n\nclass Bar : Foo {\n  var c double\n  var d = \\\"\\\"\n}\n\ndef main {\n  var foo int = Foo.new(0)\n  var bar int = Bar.new(0, 1)\n}\n\", \"\n<stdin>:12:25: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n  var foo int = Foo.new(0)\n                        ^\n<stdin>:12:17: error: Cannot convert from type \\\"Foo\\\" to type \\\"int\\\"\n  var foo int = Foo.new(0)\n                ~~~~~~~~~~\n<stdin>:13:25: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n  var bar int = Bar.new(0, 1)\n                        ^\n<stdin>:13:17: error: Cannot convert from type \\\"Bar\\\" to type \\\"int\\\"\n  var bar int = Bar.new(0, 1)\n                ~~~~~~~~~~~~~\n<stdin>:12:7: warning: Local variable \\\"foo\\\" is never read\n  var foo int = Foo.new(0)\n      ~~~\n<stdin>:13:7: warning: Local variable \\\"bar\\\" is never read\n  var bar int = Bar.new(0, 1)\n      ~~~\n\")\n\ntest(\"\nclass Foo {\n  const x int\n  def new {\n    x = 100\n  }\n}\n\nclass Bar : Foo {\n  const y int\n  def new {\n    super\n    x = 0\n    y = 100\n  }\n}\n\", \"\n<stdin>:12:5: error: Cannot store to constant symbol \\\"x\\\"\n    x = 0\n    ^\n\")\n\ntest(\"\n@import\nclass Foo {\n  def new\n  def foo { new }\n}\n\n@import\nclass Bar : Foo {\n  over foo { new }\n}\n\n@import\nclass Baz : Foo {\n  def new\n  over foo { new }\n}\n\ndef main {\n  Foo.new\n  Bar.new\n  Baz.new\n}\n\", \"\n<stdin>:9:14: error: \\\"new\\\" is not declared\n  over foo { new }\n             ~~~\n<stdin>:20:7: error: \\\"new\\\" is not declared on type \\\"Bar\\\"\n  Bar.new\n      ~~~\n\")\n\ntest(\"\nclass Foo {\n  var x int\n}\n\nclass Bar : Foo {\n  var y int\n}\n\ndef main {\n  Foo.new(0)\n  Bar.new(0)\n  Bar.new(0, 1)\n}\n\", \"\n<stdin>:11:10: error: Expected 2 arguments but found 1 argument when calling \\\"new\\\"\n  Bar.new(0)\n         ~~~\n<stdin>:5:7: note: The function declaration is here\nclass Bar : Foo {\n      ~~~\n\")\n\ntest(\"\nclass Foo {}\n\nnamespace Foo {\n  const x = 0\n}\n\ndef main {\n  Foo.new\n}\n\", \"\n\")\n\ntest(\"\nclass Foo {\n  var foo = Foo.new\n}\n\nclass Bar {\n}\n\nnamespace Bar {\n  var foo = Bar.new\n}\n\", \"\n<stdin>:1:7: error: Cyclic declaration of \\\"new\\\"\nclass Foo {\n      ~~~\n\")\n\ntest(\"\nclass Foo {\n}\n\nclass Bar : Foo {\n}\n\nclass Baz : Foo {\n}\n\ndef main {\n  Foo.new\n  Bar.new\n  Baz.new\n}\n\", \"\n\")\n\ntest(\"\nclass Foo {}\nclass Bar : Foo {}\n\ndef main {\n  var a Foo = null as Foo\n  var b = null as Bar\n  var c = a as Foo\n  var d = a as Bar\n  var e int = 0.5 as int\n  var f double = 0 as double\n}\n\", \"\n<stdin>:5:20: warning: Unnecessary cast from type \\\"null\\\" to type \\\"Foo\\\"\n  var a Foo = null as Foo\n                   ~~~~~~\n<stdin>:7:13: warning: Unnecessary cast from type \\\"Foo\\\" to type \\\"Foo\\\"\n  var c = a as Foo\n            ~~~~~~\n<stdin>:10:20: warning: Unnecessary cast from type \\\"int\\\" to type \\\"double\\\"\n  var f double = 0 as double\n                   ~~~~~~~~~\n<stdin>:6:7: warning: Local variable \\\"b\\\" is never read\n  var b = null as Bar\n      ^\n<stdin>:7:7: warning: Local variable \\\"c\\\" is never read\n  var c = a as Foo\n      ^\n<stdin>:8:7: warning: Local variable \\\"d\\\" is never read\n  var d = a as Bar\n      ^\n<stdin>:9:7: warning: Local variable \\\"e\\\" is never read\n  var e int = 0.5 as int\n      ^\n<stdin>:10:7: warning: Local variable \\\"f\\\" is never read\n  var f double = 0 as double\n      ^\n<stdin>:5:19: fix: Remove the cast\n  var a Foo = null as Foo\n                  ~~~~~~~\n                  []\n<stdin>:7:12: fix: Remove the cast\n  var c = a as Foo\n           ~~~~~~~\n           []\n<stdin>:10:19: fix: Remove the cast\n  var f double = 0 as double\n                  ~~~~~~~~~~\n                  []\n\")\n\ntest(\"\n@import\ndef foo\ndef foo\n\", \"\n\")\n\ntest(\"\ndef foo\n@import\ndef foo\n\", \"\n\")\n\ntest(\"\ndef foo {}\ndef foo\n\", \"\n\")\n\ntest(\"\ndef foo\ndef foo {}\n\", \"\n\")\n\ntest(\"\ndef foo\ndef foo {}\ndef foo\n\", \"\n\")\n\ntest(\"\ndef foo {}\ndef foo\ndef foo {}\ndef foo\n\", \"\n<stdin>:3:5: error: Duplicate overloaded function \\\"foo\\\"\ndef foo {}\n    ~~~\n<stdin>:1:5: note: The previous declaration is here\ndef foo {}\n    ~~~\n\")\n\ntest(\"\ndef foo {}\ndef foo {}\n\", \"\n<stdin>:2:5: error: Duplicate overloaded function \\\"foo\\\"\ndef foo {}\n    ~~~\n<stdin>:1:5: note: The previous declaration is here\ndef foo {}\n    ~~~\n\")\n\ntest(\"\ndef foo int\ndef foo double { return 0 }\n\", \"\n<stdin>:2:5: error: Duplicate overloaded function \\\"foo\\\"\ndef foo double { return 0 }\n    ~~~\n<stdin>:1:5: note: The previous declaration is here\ndef foo int\n    ~~~\n<stdin>:1:5: error: Non-imported function \\\"foo\\\" is missing an implementation (use the \\\"@import\\\" annotation if it's implemented externally)\ndef foo int\n    ~~~\n\")\n\ntest(\"\ndef foo(x int)\ndef foo(x double)\n\ndef foo(x int) {}\ndef foo(x double) {}\n\ndef main {\n  foo(null as dynamic)\n}\n\", \"\n<stdin>:8:3: error: Multiple matching overloads of \\\"foo\\\" were found that can take 1 argument of type dynamic\n  foo(null as dynamic)\n  ~~~\n\")\n\ntest(\"\n@prefer\ndef foo(x int)\ndef foo(x double)\n\ndef foo(x int) {}\ndef foo(x double) {}\n\ndef main {\n  foo(null as dynamic)\n}\n\", \"\n\")\n\ntest(\"\ndef foo(x int) {}\ndef foo(x double) {}\n\n@prefer\ndef foo(x int)\ndef foo(x double)\n\ndef main {\n  foo(null as dynamic)\n}\n\", \"\n\")\n\ntest(\"\nclass Foo {\n  def new(x int) {}\n  def foo(x int) {}\n  def foo(x double) {}\n}\n\ndef main {\n  Foo.new\n  Foo.new(0).foo\n}\n\", \"\n<stdin>:8:7: error: The function \\\"new\\\" takes 1 argument and must be called\n  Foo.new\n      ~~~\n<stdin>:9:14: error: The function \\\"foo\\\" takes 1 argument and must be called\n  Foo.new(0).foo\n             ~~~\n\")\n\ntest(\"\nclass Foo {\n}\n\nnamespace Foo {\n  def new(x int) Foo {\n    return null\n  }\n}\n\ndef main {\n  var foo = Foo.new\n}\n\", \"\n<stdin>:11:17: error: The function \\\"new\\\" takes 1 argument and must be called\n  var foo = Foo.new\n                ~~~\n<stdin>:11:7: warning: Local variable \\\"foo\\\" is never read\n  var foo = Foo.new\n      ~~~\n\")\n\ntest(\"\nclass Foo {\n  var foo = 0\n  var bar = foo\n}\n\", \"\n<stdin>:3:13: error: Cannot access instance member \\\"foo\\\" from a global context\n  var bar = foo\n            ~~~\n\")\n\ntest(\"\nclass Foo<T> {\n  var foo T\n\n  class Bar {\n    var foo T\n  }\n\n  namespace Bar {\n    var bar T\n  }\n}\n\nnamespace Foo {\n  var bar T\n}\n\", \"\n<stdin>:5:13: error: Cannot access type parameter \\\"T\\\" here\n    var foo T\n            ^\n<stdin>:9:13: error: Cannot access type parameter \\\"T\\\" here\n    var bar T\n            ^\n<stdin>:9:9: error: Cannot construct a default value of type \\\"T\\\"\n    var bar T\n        ~~~\n<stdin>:14:11: error: Cannot access type parameter \\\"T\\\" here\n  var bar T\n          ^\n<stdin>:14:7: error: Cannot construct a default value of type \\\"T\\\"\n  var bar T\n      ~~~\n\")\n\ntest(\"\n# Nested uses of T should be fine inside instance functions\nclass Foo<T> {\n  def new {\n    var x = (a T) => {\n      var y = (b T) => {}\n    }\n  }\n}\n\nnamespace Foo {\n  var x = (a T) => {\n    var y = (b T) => {}\n  }\n}\n\", \"\n<stdin>:11:14: error: Cannot access type parameter \\\"T\\\" here\n  var x = (a T) => {\n             ^\n<stdin>:12:16: error: Cannot access type parameter \\\"T\\\" here\n    var y = (b T) => {}\n               ^\n<stdin>:4:9: warning: Local variable \\\"x\\\" is never read\n    var x = (a T) => {\n        ^\n<stdin>:5:11: warning: Local variable \\\"y\\\" is never read\n      var y = (b T) => {}\n          ^\n<stdin>:12:9: warning: Local variable \\\"y\\\" is never read\n    var y = (b T) => {}\n        ^\n\")\n\ntest(\"\nclass Foo<T> {\n}\n\nnamespace Foo {\n  def new(x T) T {\n    var y Foo<T>\n    return x\n  }\n\n  def foo {\n    var y Foo<T>\n  }\n}\n\", \"\n<stdin>:6:9: warning: Local variable \\\"y\\\" is never read\n    var y Foo<T>\n        ^\n<stdin>:11:9: warning: Local variable \\\"y\\\" is never read\n    var y Foo<T>\n        ^\n\")\n\ntest(\"\nclass Foo<T> {\n}\n\nnamespace Foo {\n  def foo {}\n  def bar T { return dynamic.t }\n}\n\ndef main {\n  Foo.foo\n  Foo<int>.foo\n  Foo.bar\n  Foo<int>.bar\n}\n\", \"\n<stdin>:10:3: error: Cannot use unparameterized type \\\"Foo\\\" here\n  Foo.foo\n  ~~~\n<stdin>:12:3: error: Cannot use unparameterized type \\\"Foo\\\" here\n  Foo.bar\n  ~~~\n\")\n\ntest(\"\nclass Foo<A, B, C> {\n}\n\nclass Foo<X, Y> {\n}\n\", \"\n<stdin>:4:11: error: \\\"Foo\\\" already has type parameters\nclass Foo<X, Y> {\n          ~~~~\n<stdin>:1:11: note: Type parameters were previously declared here\nclass Foo<A, B, C> {\n          ~~~~~~~\n\")\n\ntest(\"\nclass Foo<T> {\n  def [new](t List<T>) {}\n}\n\nclass Bar<T> {\n  def [new](t T) {}\n}\n\ndef main {\n  var foo Foo<int> = [0]\n  var bar Foo<int> = [0]\n}\n\", \"\n<stdin>:6:13: error: Expected argument \\\"t\\\" to be of type \\\"List<T>\\\" instead of type \\\"T\\\"\n  def [new](t T) {}\n            ^\n<stdin>:10:7: warning: Local variable \\\"foo\\\" is never read\n  var foo Foo<int> = [0]\n      ~~~\n<stdin>:11:7: warning: Local variable \\\"bar\\\" is never read\n  var bar Foo<int> = [0]\n      ~~~\n\")\n\ntest(\"\nclass Foo<K, V> {\n  def {new}(k List<K>, v List<V>) {}\n}\n\nclass Bar<K, V> {\n  def {new}(k K, v V) {}\n}\n\ndef main {\n  var foo Foo<int, bool> = {1: false}\n  var bar Foo<int, bool> = {1: false}\n}\n\", \"\n<stdin>:6:13: error: Expected argument \\\"k\\\" to be of type \\\"List<T>\\\" instead of type \\\"K\\\"\n  def {new}(k K, v V) {}\n            ^\n<stdin>:6:18: error: Expected argument \\\"v\\\" to be of type \\\"List<T>\\\" instead of type \\\"V\\\"\n  def {new}(k K, v V) {}\n                 ^\n<stdin>:10:7: warning: Local variable \\\"foo\\\" is never read\n  var foo Foo<int, bool> = {1: false}\n      ~~~\n<stdin>:11:7: warning: Local variable \\\"bar\\\" is never read\n  var bar Foo<int, bool> = {1: false}\n      ~~~\n\")\n\ntest(\"\nclass Foo<K, V> {\n  def []=(key K, value V) {}\n}\n\nnamespace Foo {\n  def {new}(keys List<K>, values List<V>) Foo<K, V> {\n    var foo = Foo<K, V>.new\n    for i in 0..keys.count {\n      foo[keys[i]] = values[i]\n    }\n    return foo\n  }\n}\n\ndef main {\n  var foo Foo<int, bool> = {false: 1}\n}\n\", \"\n<stdin>:16:29: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n  var foo Foo<int, bool> = {false: 1}\n                            ~~~~~\n<stdin>:16:36: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n  var foo Foo<int, bool> = {false: 1}\n                                   ^\n<stdin>:16:7: warning: Local variable \\\"foo\\\" is never read\n  var foo Foo<int, bool> = {false: 1}\n      ~~~\n\")\n\ntest(\"\nclass Foo<T> {\n  def new {}\n  def {...}(x int, y T) Foo<T> { return self }\n}\n\nclass Bar<T> {\n  def {...}(x int, y T) Bar<T> { return self }\n}\n\nnamespace Bar {\n  def new Bar<T> { return null }\n}\n\ndef main {\n  var foo Foo<int> = {0: 1}\n  var bar Bar<int> = {0: 1}\n}\n\", \"\n<stdin>:15:7: warning: Local variable \\\"foo\\\" is never read\n  var foo Foo<int> = {0: 1}\n      ~~~\n<stdin>:16:7: warning: Local variable \\\"bar\\\" is never read\n  var bar Bar<int> = {0: 1}\n      ~~~\n\")\n\n# Check list literal error messages\ntest(\"\ndef main Foo {\n  return []\n}\n\nclass Foo {\n  def [new](x int) {}\n}\n\", \"\n<stdin>:6:13: error: Expected argument \\\"x\\\" to be of type \\\"List<T>\\\" instead of type \\\"int\\\"\n  def [new](x int) {}\n            ^\n\")\n\n# Check map literal error messages\ntest(\"\ndef main Foo {\n  return {}\n}\n\nclass Foo {\n  def {new}(x int, y int) {}\n}\n\", \"\n<stdin>:6:13: error: Expected argument \\\"x\\\" to be of type \\\"List<T>\\\" instead of type \\\"int\\\"\n  def {new}(x int, y int) {}\n            ^\n<stdin>:6:20: error: Expected argument \\\"y\\\" to be of type \\\"List<T>\\\" instead of type \\\"int\\\"\n  def {new}(x int, y int) {}\n                   ^\n\")\n\n# Check for stack overflow due to infinite list literal recursion\ntest(\"\ndef main Foo {\n  return []\n}\n\nclass Foo {\n  def [new](x Foo) {}\n}\n\", \"\n<stdin>:6:13: error: Expected argument \\\"x\\\" to be of type \\\"List<T>\\\" instead of type \\\"Foo\\\"\n  def [new](x Foo) {}\n            ^\n<stdin>:2:10: error: Attempting to resolve this literal led to recursive expansion\n  return []\n         ~~\n<stdin>:6:7: note: The constructor that was called recursively is here\n  def [new](x Foo) {}\n      ~~~~~\n\")\n\ntest(\"\nclass Foo {\n  var ivar = 0\n  def ifun {}\n}\nclass Bar : Foo {}\nclass Baz : Bar {\n  over ifun {}\n}\n\nnamespace Foo {\n  var gvar = 0\n  def gfun {}\n}\nnamespace Bar {}\nnamespace Baz {\n  def gfun {}\n}\n\ndef main {\n  Foo.new.ivar = 0\n  Bar.new.ivar = 0\n  Baz.new.ivar = 0\n\n  Foo.new.ifun\n  Bar.new.ifun\n  Baz.new.ifun\n\n  Foo.gvar = 0\n  Bar.gvar = 0\n  Baz.gvar = 0\n\n  Foo.gfun\n  Bar.gfun\n  Baz.gfun\n}\n\", \"\n<stdin>:29:3: error: \\\"gvar\\\" is not declared on type \\\"Bar\\\", did you mean \\\"Foo.gvar\\\"?\n  Bar.gvar = 0\n  ~~~~~~~~\n<stdin>:11:7: note: \\\"Foo.gvar\\\" is defined here\n  var gvar = 0\n      ~~~~\n<stdin>:30:3: error: \\\"gvar\\\" is not declared on type \\\"Baz\\\", did you mean \\\"Foo.gvar\\\"?\n  Baz.gvar = 0\n  ~~~~~~~~\n<stdin>:11:7: note: \\\"Foo.gvar\\\" is defined here\n  var gvar = 0\n      ~~~~\n<stdin>:33:3: error: \\\"gfun\\\" is not declared on type \\\"Bar\\\", did you mean \\\"Foo.gfun\\\"?\n  Bar.gfun\n  ~~~~~~~~\n<stdin>:12:7: note: \\\"Foo.gfun\\\" is defined here\n  def gfun {}\n      ~~~~\n<stdin>:29:3: fix: Replace with \\\"Foo.gvar\\\"\n  Bar.gvar = 0\n  ~~~~~~~~\n  [Foo.gvar]\n<stdin>:30:3: fix: Replace with \\\"Foo.gvar\\\"\n  Baz.gvar = 0\n  ~~~~~~~~\n  [Foo.gvar]\n<stdin>:33:3: fix: Replace with \\\"Foo.gfun\\\"\n  Bar.gfun\n  ~~~~~~~~\n  [Foo.gfun]\n\")\n\ntest(\"\ndef main {\n  var bar = dynamic.foo\n}\n\", \"\n<stdin>:2:7: warning: Local variable \\\"bar\\\" is never read\n  var bar = dynamic.foo\n      ~~~\n\")\n\ntest(\"\nclass Bar : Foo {\n  var y int\n}\n\nclass Foo {\n  var x int\n}\n\ndef main {\n  Bar.new(0, 1) # This used to fail when Bar came before Foo since Foo.new wasn't initialized first and so had no arguments\n}\n\", \"\n\")\n\ntest(\"\nenum Foo {\n  FOO\n  BAR\n}\n\ndef main {\n  if Foo.FOO in [.FOO, .BAR] {}\n  if .FOO in [Foo.FOO, Foo.BAR] {}\n}\n\", \"\n\")\n\ntest(\"\ndef main {\n  var a = [.FOO, .BAR]\n  var b = [Foo.FOO, .BAR]\n  var c = [.FOO, Foo.BAR]\n  var d = [Foo.FOO, Foo.BAR]\n}\n\nenum Foo {\n  FOO\n  BAR\n}\n\", \"\n<stdin>:2:12: error: Cannot access \\\"FOO\\\" without type context\n  var a = [.FOO, .BAR]\n           ~~~~\n<stdin>:2:18: error: Cannot access \\\"BAR\\\" without type context\n  var a = [.FOO, .BAR]\n                 ~~~~\n<stdin>:2:7: warning: Local variable \\\"a\\\" is never read\n  var a = [.FOO, .BAR]\n      ^\n<stdin>:3:7: warning: Local variable \\\"b\\\" is never read\n  var b = [Foo.FOO, .BAR]\n      ^\n<stdin>:4:7: warning: Local variable \\\"c\\\" is never read\n  var c = [.FOO, Foo.BAR]\n      ^\n<stdin>:5:7: warning: Local variable \\\"d\\\" is never read\n  var d = [Foo.FOO, Foo.BAR]\n      ^\n\")\n\ntest(\"\ndef main(x int) {\n  switch x {\n    case 0 { var foo = 0 }\n    case 1 { var foo = false }\n  }\n}\n\", \"\n<stdin>:3:18: warning: Local variable \\\"foo\\\" is never read\n    case 0 { var foo = 0 }\n                 ~~~\n<stdin>:4:18: warning: Local variable \\\"foo\\\" is never read\n    case 1 { var foo = false }\n                 ~~~\n\")\n\n# This tests a special case in the globalizing pass for super calls\ntest(\"\n@import\nclass Foo {\n  def foo {}\n  def foo(x int) {}\n}\nclass Bar : Foo {\n  over foo { super }\n  over foo(x int) { super(x) }\n}\n\", \"\n\")\n\ntest(\"\nclass Foo {\n  @deprecated {\n    def foo\n    def bar(x int)\n    def baz\n    def baz(x int)\n  }\n}\n\ndef main(foo Foo) {\n  foo.foo\n  foo.bar(0)\n  foo.baz\n  foo.baz(0)\n}\n\", \"\n<stdin>:11:7: warning: Use of deprecated symbol \\\"foo\\\"\n  foo.foo\n      ~~~\n<stdin>:12:7: warning: Use of deprecated symbol \\\"bar\\\"\n  foo.bar(0)\n      ~~~\n<stdin>:13:7: warning: Use of deprecated symbol \\\"baz\\\"\n  foo.baz\n      ~~~\n<stdin>:14:7: warning: Use of deprecated symbol \\\"baz\\\"\n  foo.baz(0)\n      ~~~\n\")\n\ntest(\"\nclass Foo {\n  @deprecated {\n    def +\n    def +(x int)\n    def -(x int)\n    def -(x bool)\n  }\n}\n\ndef main(foo Foo) {\n  +foo\n  foo + 0\n  foo - 0\n  foo - false\n}\n\", \"\n<stdin>:11:3: warning: Use of deprecated symbol \\\"+\\\"\n  +foo\n  ^\n<stdin>:12:7: warning: Use of deprecated symbol \\\"+\\\"\n  foo + 0\n      ^\n<stdin>:13:7: warning: Use of deprecated symbol \\\"-\\\"\n  foo - 0\n      ^\n<stdin>:14:7: warning: Use of deprecated symbol \\\"-\\\"\n  foo - false\n      ^\n\")\n\ntest(\"\nclass Foo {\n  @deprecated\n  def foo {}\n}\n\nclass Bar : Foo {\n  over foo { super }\n}\n\", \"\n<stdin>:7:14: warning: Use of deprecated symbol \\\"foo\\\"\n  over foo { super }\n             ~~~~~\n\")\n\ntest(\"\n@deprecated\nclass Foo {}\n\ndef main {\n  Foo.new\n}\n\", \"\n<stdin>:5:3: warning: Use of deprecated symbol \\\"Foo\\\"\n  Foo.new\n  ~~~\n\")\n\ntest(\"\n@deprecated(\\\"Why are you using this?\\\")\ndef test {}\n\ndef main {\n  test\n}\n\", \"\n<stdin>:5:3: warning: Why are you using this?\n  test\n  ~~~~\n\")\n\ntest(\"\nclass Foo {\n  def ++\n}\n\ndef main(x Foo) {\n  var foo = ++x\n  var bar = x++\n}\n\", \"\n<stdin>:6:13: error: The function \\\"++\\\" does not return a value\n  var foo = ++x\n            ~~~\n<stdin>:2:7: note: The function declaration is here\n  def ++\n      ~~\n<stdin>:7:13: error: The function \\\"++\\\" does not return a value\n  var bar = x++\n            ~~~\n<stdin>:2:7: note: The function declaration is here\n  def ++\n      ~~\n<stdin>:6:7: warning: Local variable \\\"foo\\\" is never read\n  var foo = ++x\n      ~~~\n<stdin>:7:7: warning: Local variable \\\"bar\\\" is never read\n  var bar = x++\n      ~~~\n\")\n\ntest(\"\ndef foo int {}\n\", \"\n<stdin>:1:5: error: All control paths for \\\"foo\\\" must return a value of type \\\"int\\\"\ndef foo int {}\n    ~~~\n\")\n\ntest(\"\ndef foo(x bool) int {\n  if x {\n    return 0\n  }\n}\n\", \"\n<stdin>:1:5: error: All control paths for \\\"foo\\\" must return a value of type \\\"int\\\"\ndef foo(x bool) int {\n    ~~~\n\")\n\ntest(\"\ndef foo(x bool) int {\n  if x {\n  } else {\n    return 0\n  }\n}\n\", \"\n<stdin>:1:5: error: All control paths for \\\"foo\\\" must return a value of type \\\"int\\\"\ndef foo(x bool) int {\n    ~~~\n\")\n\ntest(\"\ndef foo(x bool) int {\n  if x {\n    return 0\n  } else {\n    return 0\n  }\n}\n\", \"\n\")\n\ntest(\"\ndef foo int {\n  if false {\n  }\n  if true {\n  }\n}\n\", \"\n<stdin>:1:5: error: All control paths for \\\"foo\\\" must return a value of type \\\"int\\\"\ndef foo int {\n    ~~~\n\")\n\n\ntest(\"\ndef foo int {\n  if true {\n    return 0\n  }\n}\n\", \"\n\")\n\ntest(\"\ndef foo int {\n  if false {\n  } else {\n    return 0\n  }\n}\n\", \"\n\")\n\ntest(\"\ndef foo int {\n  while true {}\n}\n\", \"\n\")\n\ntest(\"\ndef foo int {\n  while true {\n    return 0\n  }\n}\n\", \"\n\")\n\ntest(\"\ndef foo int {\n  while true {\n    break\n  }\n}\n\", \"\n<stdin>:1:5: error: All control paths for \\\"foo\\\" must return a value of type \\\"int\\\"\ndef foo int {\n    ~~~\n\")\n\ntest(\"\ndef foo int {\n  for i = 0; true; i = i + 1 {}\n}\n\", \"\n\")\n\ntest(\"\ndef foo int {\n  for i = 0; true; i = i + 1 {\n    return 0\n  }\n}\n\", \"\n\")\n\ntest(\"\ndef foo int {\n  for i = 0; true; i = i + 1 {\n    break\n  }\n}\n\", \"\n<stdin>:1:5: error: All control paths for \\\"foo\\\" must return a value of type \\\"int\\\"\ndef foo int {\n    ~~~\n\")\n\ntest(\"\ndef foo int {\n  switch dynamic.bar {\n    case 0 { return 0 }\n    default { return 0 }\n  }\n}\n\", \"\n\")\n\ntest(\"\ndef foo int {\n  switch dynamic.bar {\n    case 0 { return 0 }\n    default {}\n  }\n}\n\", \"\n<stdin>:1:5: error: All control paths for \\\"foo\\\" must return a value of type \\\"int\\\"\ndef foo int {\n    ~~~\n\")\n\ntest(\"\ndef foo int {\n  switch dynamic.bar {\n    case 0 { return 0 }\n  }\n}\n\", \"\n<stdin>:1:5: error: All control paths for \\\"foo\\\" must return a value of type \\\"int\\\"\ndef foo int {\n    ~~~\n\")\n\ntest(\"\ndef main {\n  0--\n  0 += 1\n  [1][2]=3\n}\n\", \"\n<stdin>:2:3: error: Cannot store to this location\n  0--\n  ^\n<stdin>:3:3: error: Cannot store to this location\n  0 += 1\n  ^\n\")\n\ntest(\"\nclass Foo {\n  class Bar {\n    def foo Foo\n    def bar Bar\n  }\n}\n\", \"\n\")\n\ntest(\"\nvar a = [\n  # comment\n]\nvar b = [\n  100\n  # comment\n]\nvar c = [\n  # comment\n  100\n]\nvar d = [\n  100,\n  # comment\n]\nvar e = [\n  # comment\n  100,\n]\nvar f = [\n  # comment\n  100,\n  # comment\n]\nvar g = [\n  100,\n  # comment\n  100,\n]\n\", \"\n<stdin>:1:9: error: Cannot infer a type for this literal\nvar a = [\n        ^\n\")\n\ntest(\"\ndef main {\n  try {}\n  catch x dynamic {}\n  catch x dynamic {}\n}\n\", \"\n\")\n\ntest(\"\nif true {\n  if true {\n    var foo = false\n  }\n}\n\ndef main int {\n  return foo\n}\n\", \"\n<stdin>:8:10: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n  return foo\n         ~~~\n\")\n\ntest(\"\nif true {\n  if false {\n  } else {\n    var foo = false\n  }\n}\n\ndef main int {\n  return foo\n}\n\", \"\n<stdin>:9:10: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n  return foo\n         ~~~\n\")\n\ntest(\"\nif true {\n  if false {\n    var foo = 0.0\n  }\n\n  else {\n    var foo = false\n  }\n}\n\ndef main int {\n  return foo\n}\n\", \"\n<stdin>:12:10: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n  return foo\n         ~~~\n\")\n\ntest(\"\nif true {\n  if false {\n    var foo = 0.0\n  } else if true {\n    var foo = false\n  }\n}\n\ndef main int {\n  return foo\n}\n\", \"\n<stdin>:10:10: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n  return foo\n         ~~~\n\")\n\ntest(\"\nif true {\n  if false {\n    var foo = 0.0\n  } else if false {\n    var foo = \\\"\\\"\n  } else {\n    var foo = false\n  }\n}\n\ndef main int {\n  return foo\n}\n\", \"\n<stdin>:12:10: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n  return foo\n         ~~~\n\")\n\ntest(\"\nclass Foo {\n  def foo\n}\n\ndef main {\n  Foo.new\n}\n\", \"\n<stdin>:6:3: error: Cannot construct abstract type \\\"Foo\\\"\n  Foo.new\n  ~~~~~~~\n<stdin>:2:7: note: The type \\\"Foo\\\" is abstract due to member \\\"foo\\\"\n  def foo\n      ~~~\n\")\n\ntest(\"\nclass Foo {\n  def foo\n}\n\nclass Bar : Foo {\n}\n\ndef main {\n  Bar.new\n}\n\", \"\n<stdin>:9:3: error: Cannot construct abstract type \\\"Bar\\\"\n  Bar.new\n  ~~~~~~~\n<stdin>:2:7: note: The type \\\"Bar\\\" is abstract due to member \\\"foo\\\"\n  def foo\n      ~~~\n\")\n\ntest(\"\nclass Foo {\n  def foo\n}\n\nclass Bar : Foo {\n}\n\nclass Baz : Foo {\n}\n\ndef main {\n  Baz.new\n}\n\", \"\n<stdin>:12:3: error: Cannot construct abstract type \\\"Baz\\\"\n  Baz.new\n  ~~~~~~~\n<stdin>:2:7: note: The type \\\"Baz\\\" is abstract due to member \\\"foo\\\"\n  def foo\n      ~~~\n\")\n\ntest(\"\nclass Foo {\n  def foo\n}\n\nclass Bar : Foo {\n  def foo(x int)\n}\n\nclass Baz : Bar {\n}\n\ndef main {\n  Baz.new\n}\n\", \"\n<stdin>:13:3: error: Cannot construct abstract type \\\"Baz\\\"\n  Baz.new\n  ~~~~~~~\n<stdin>:6:7: note: The type \\\"Baz\\\" is abstract due to member \\\"foo\\\"\n  def foo(x int)\n      ~~~\n\")\n\ntest(\"\nclass Foo {\n  def foo\n}\n\nclass Bar : Foo {\n  def foo(x int) {}\n}\n\nclass Baz : Bar {\n}\n\ndef main {\n  Baz.new\n}\n\", \"\n<stdin>:13:3: error: Cannot construct abstract type \\\"Baz\\\"\n  Baz.new\n  ~~~~~~~\n<stdin>:2:7: note: The type \\\"Baz\\\" is abstract due to member \\\"foo\\\"\n  def foo\n      ~~~\n\")\n\ntest(\"\nclass Foo {\n  def foo {}\n}\n\nclass Bar : Foo {\n  def foo(x int)\n}\n\nclass Baz : Bar {\n}\n\ndef main {\n  Baz.new\n}\n\", \"\n<stdin>:13:3: error: Cannot construct abstract type \\\"Baz\\\"\n  Baz.new\n  ~~~~~~~\n<stdin>:6:7: note: The type \\\"Baz\\\" is abstract due to member \\\"foo\\\"\n  def foo(x int)\n      ~~~\n\")\n\ntest(\"\nclass Foo {\n  def foo\n}\n\nclass Bar : Foo {\n  over foo {}\n}\n\ndef main {\n  Bar.new\n}\n\", \"\n\")\n\ntest(\"\nclass Foo {\n}\n\nclass Bar : Foo {\n  def foo\n}\n\ndef main {\n  Foo.new\n}\n\", \"\n\")\n\ntest(\"\nclass Foo {\n}\n\nclass Bar : Foo {\n  def foo\n}\n\ndef main {\n  Bar.new\n}\n\", \"\n<stdin>:9:3: error: Cannot construct abstract type \\\"Bar\\\"\n  Bar.new\n  ~~~~~~~\n<stdin>:5:7: note: The type \\\"Bar\\\" is abstract due to member \\\"foo\\\"\n  def foo\n      ~~~\n\")\n\ntest(\"\nclass Foo<T> {\n  def foo T {\n    var bar T\n    return bar\n  }\n}\n\", \"\n<stdin>:3:9: error: Cannot construct a default value of type \\\"T\\\"\n    var bar T\n        ~~~\n\")\n\ntest(\"\ndef main {\n  List<bool>.new.sort((a, b) => a <=> b)\n  List<int>.new.sort((a, b) => a <=> b)\n  List<double>.new.sort((a, b) => a <=> b)\n  List<string>.new.sort((a, b) => a <=> b)\n}\n\", \"\n<stdin>:2:35: error: \\\"<=>\\\" is not declared on type \\\"bool\\\"\n  List<bool>.new.sort((a, b) => a <=> b)\n                                  ~~~\n\")\n\ntest(\"\ndef foo fn() { return null }\ndef bar {}\n\ndef main {\n  foo()\n  (foo)()\n  bar()\n  bar(1)\n  bar\n}\n\", \"\n<stdin>:5:3: error: Wrap calls to the function \\\"foo\\\" in parentheses to call the returned lambda\n  foo()\n  ~~~\n<stdin>:1:5: note: The function declaration is here\ndef foo fn() { return null }\n    ~~~\n<stdin>:7:6: error: Cannot call the value returned from the function \\\"bar\\\" (this function was called automatically because it takes no arguments)\n  bar()\n     ~~\n<stdin>:2:5: note: The function declaration is here\ndef bar {}\n    ~~~\n<stdin>:8:6: error: Cannot call the value returned from the function \\\"bar\\\" (this function was called automatically because it takes no arguments)\n  bar(1)\n     ~~~\n<stdin>:2:5: note: The function declaration is here\ndef bar {}\n    ~~~\n<stdin>:7:6: fix: Remove the unnecessary \\\"()\\\"\n  bar()\n     ~~\n     []\n\")\n\ntest(\"\ndef main {\n  ((a, b) => a + b)(1, false)\n  var foo bool = ((a, b) => a + b)(1, 2)\n  var bar bool = ((a, b) => { return a + b })(1, 2)\n}\n\", \"\n<stdin>:2:18: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n  ((a, b) => a + b)(1, false)\n                 ^\n<stdin>:3:29: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n  var foo bool = ((a, b) => a + b)(1, 2)\n                            ~~~~~\n<stdin>:4:38: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n  var bar bool = ((a, b) => { return a + b })(1, 2)\n                                     ~~~~~\n<stdin>:3:7: warning: Local variable \\\"foo\\\" is never read\n  var foo bool = ((a, b) => a + b)(1, 2)\n      ~~~\n<stdin>:4:7: warning: Local variable \\\"bar\\\" is never read\n  var bar bool = ((a, b) => { return a + b })(1, 2)\n      ~~~\n\")\n\ntest(\"\nclass Foo {\n  def foo=(x int) {}\n}\n\ndef main {\n  Foo.new.foo = false\n}\n\", \"\n<stdin>:6:17: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n  Foo.new.foo = false\n                ~~~~~\n\")\n\n# Make sure the uncalled function error doesn't trigger for overloaded setter calls\ntest(\"\nclass Foo {\n  def foo=(x int) {}\n  def foo=(x double) {}\n}\n\ndef main {\n  Foo.new.foo = 0\n}\n\", \"\n\")\n\ntest(\"\ndef main {\n  for i = 0, b = false; true; 0, 1 {}\n}\n\", \"\n<stdin>:2:14: error: Expected loop variable \\\"b\\\" to be of type \\\"int\\\" instead of type \\\"bool\\\"\n  for i = 0, b = false; true; 0, 1 {}\n             ^\n<stdin>:2:31: warning: Unused expression\n  for i = 0, b = false; true; 0, 1 {}\n                              ^\n<stdin>:2:34: warning: Unused expression\n  for i = 0, b = false; true; 0, 1 {}\n                                 ^\n<stdin>:2:7: warning: Local variable \\\"i\\\" is never read\n  for i = 0, b = false; true; 0, 1 {}\n      ^\n<stdin>:2:14: warning: Local variable \\\"b\\\" is never read\n  for i = 0, b = false; true; 0, 1 {}\n             ^\n\")\n\ntest(\"\ntype Foo = int\ntype Foo = int\ntype Foo : int {}\n\", \"\n<stdin>:2:12: error: \\\"Foo\\\" already has a base type\ntype Foo = int\n           ~~~\n<stdin>:1:12: note: The previous base type is here\ntype Foo = int\n           ~~~\n<stdin>:3:12: error: \\\"Foo\\\" already has a base type\ntype Foo : int {}\n           ~~~\n<stdin>:1:12: note: The previous base type is here\ntype Foo = int\n           ~~~\n\")\n\ntest(\"\nclass Foo {\n  def foo {}\n}\n\ntype Bar = Foo\n\ntype Bar {\n  def bar {}\n}\n\ntype Baz : Foo {\n  def bar {}\n}\n\ndef main {\n  var foo = Foo.new\n  var bar = foo as Bar\n  var baz = foo as Baz\n  foo.foo\n  foo.bar\n  bar.foo\n  bar.bar\n  baz.foo\n  baz.bar\n}\n\", \"\n<stdin>:20:7: error: \\\"bar\\\" is not declared on type \\\"Foo\\\"\n  foo.bar\n      ~~~\n<stdin>:21:7: error: \\\"foo\\\" is not declared on type \\\"Bar\\\"\n  bar.foo\n      ~~~\n<stdin>:23:7: error: \\\"foo\\\" is not declared on type \\\"Baz\\\"\n  baz.foo\n      ~~~\n\")\n\ntest(\"\ntype Foo {\n}\n\", \"\n<stdin>:1:6: error: Missing base type for wrapped type \\\"Foo\\\"\ntype Foo {\n     ~~~\n\")\n\ntest(\"\nclass Foo : Bar {}\ntype Bar = int\n\", \"\n<stdin>:1:13: error: Cannot extend type \\\"Bar\\\"\nclass Foo : Bar {}\n            ~~~\n\")\n\ntest(\"\nvar foo int\ntype Foo = fn()\ntype Bar = foo\ntype Baz = dynamic\ntype Bat = Foo\n\ndef main {\n  var foo Foo = => {}\n  var foo2 Foo = => {} as Foo\n  var bat Bat = foo\n  var bat2 Bat = foo as Bat\n}\n\", \"\n<stdin>:3:12: error: Unexpected expression of type \\\"int\\\"\ntype Bar = foo\n           ~~~\n<stdin>:8:17: error: Cannot convert from type \\\"fn()\\\" to type \\\"Foo\\\" without a cast\n  var foo Foo = => {}\n                ~~~~~\n<stdin>:10:17: error: Cannot convert from type \\\"Foo\\\" to type \\\"Bat\\\" without a cast\n  var bat Bat = foo\n                ~~~\n<stdin>:9:7: warning: Local variable \\\"foo2\\\" is never read\n  var foo2 Foo = => {} as Foo\n      ~~~~\n<stdin>:10:7: warning: Local variable \\\"bat\\\" is never read\n  var bat Bat = foo\n      ~~~\n<stdin>:11:7: warning: Local variable \\\"bat2\\\" is never read\n  var bat2 Bat = foo as Bat\n      ~~~~\n\")\n\ntest(\"\ntype Foo : int {\n  var foo\n  def bar\n  def new\n}\n\nnamespace Foo {\n  var foo2\n  def bar2\n}\n\", \"\n<stdin>:2:3: error: Cannot use this declaration here\n  var foo\n  ~~~~~~~\n<stdin>:4:3: error: Cannot use this declaration here\n  def new\n  ~~~~~~~\n<stdin>:3:7: error: Non-imported function \\\"bar\\\" is missing an implementation (use the \\\"@import\\\" annotation if it's implemented externally)\n  def bar\n      ~~~\n<stdin>:4:7: error: Non-imported function \\\"new\\\" is missing an implementation (use the \\\"@import\\\" annotation if it's implemented externally)\n  def new\n      ~~~\n<stdin>:9:7: error: Non-imported function \\\"bar2\\\" is missing an implementation (use the \\\"@import\\\" annotation if it's implemented externally)\n  def bar2\n      ~~~~\n<stdin>:2:7: error: The implicitly typed variable \\\"foo\\\" must be initialized\n  var foo\n      ~~~\n<stdin>:8:7: error: The implicitly typed variable \\\"foo2\\\" must be initialized\n  var foo2\n      ~~~~\n\")\n\ntest(\"\nclass Foo<T> {\n}\n\nclass Bar<T> : Foo<T> {\n}\n\ndef main {\n  var foo = Foo<int>.new\n  var bar = foo as Bar<bool>\n  var baz = foo as Bar<int>\n  var bat = bar as Bar<int>\n}\n\", \"\n<stdin>:9:13: error: Cannot convert from type \\\"Foo<int>\\\" to type \\\"Bar<bool>\\\"\n  var bar = foo as Bar<bool>\n            ~~~\n<stdin>:11:13: error: Cannot convert from type \\\"Bar<bool>\\\" to type \\\"Bar<int>\\\"\n  var bat = bar as Bar<int>\n            ~~~\n<stdin>:10:7: warning: Local variable \\\"baz\\\" is never read\n  var baz = foo as Bar<int>\n      ~~~\n<stdin>:11:7: warning: Local variable \\\"bat\\\" is never read\n  var bat = bar as Bar<int>\n      ~~~\n\")\n\ntest(\"\nclass Foo<T> {\n}\n\ntype Bar<T> : Foo<T> {\n}\n\ndef main {\n  var foo = Foo<int>.new\n  var bar = foo as Bar<bool>\n  var baz = foo as Bar<int>\n  var bat = bar as Bar<int>\n}\n\", \"\n<stdin>:9:13: error: Cannot convert from type \\\"Foo<int>\\\" to type \\\"Bar<bool>\\\"\n  var bar = foo as Bar<bool>\n            ~~~\n<stdin>:11:13: error: Cannot convert from type \\\"Bar<bool>\\\" to type \\\"Bar<int>\\\"\n  var bat = bar as Bar<int>\n            ~~~\n<stdin>:10:7: warning: Local variable \\\"baz\\\" is never read\n  var baz = foo as Bar<int>\n      ~~~\n<stdin>:11:7: warning: Local variable \\\"bat\\\" is never read\n  var bat = bar as Bar<int>\n      ~~~\n\")\n\ntest(\"\ntype Foo = Bar\ntype Bar = Foo\n\", \"\n<stdin>:1:6: error: Cyclic declaration of \\\"Foo\\\"\ntype Foo = Bar\n     ~~~\n\")\n\ntest(\"\ntype Foo {}\n\ndef main {\n  var foo = 0 as Foo\n  var bar = null as Foo\n}\n\", \"\n<stdin>:1:6: error: Missing base type for wrapped type \\\"Foo\\\"\ntype Foo {}\n     ~~~\n<stdin>:4:7: warning: Local variable \\\"foo\\\" is never read\n  var foo = 0 as Foo\n      ~~~\n<stdin>:5:7: warning: Local variable \\\"bar\\\" is never read\n  var bar = null as Foo\n      ~~~\n\")\n\ntest(\"\ntype Foo : List<int> {\n  def +=(foo int) {\n    (self as List<int>).append(foo)\n  }\n}\n\nnamespace Foo {\n  def new Foo {\n    return List<int>.new as Foo\n  }\n}\n\ndef foo Foo {\n  return Foo.new\n}\n\ndef main {\n  foo += 0\n  foo += false\n}\n\", \"\n<stdin>:19:10: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n  foo += false\n         ~~~~~\n\")\n\ntest(\"\nclass Foo :: Baz {}\nclass Bar : Foo {}\ninterface Baz {}\n\n@export\ndef main {\n  dynamic.foo(Foo.new is dynamic)\n  dynamic.foo(Foo.new is dynamic.Test)\n  dynamic.foo(Foo.new is Foo)\n  dynamic.foo(Foo.new is Bar)\n  dynamic.foo(Foo.new is Baz)\n  dynamic.foo(Bar.new is Foo)\n  dynamic.foo(Bar.new is Bar)\n  dynamic.foo(Bar.new is Baz)\n}\n\", \"\n<stdin>:7:15: warning: Unnecessary type check, type \\\"Foo\\\" is always type \\\"dynamic\\\"\n  dynamic.foo(Foo.new is dynamic)\n              ~~~~~~~~~~~~~~~~~~\n<stdin>:9:15: warning: Unnecessary type check, type \\\"Foo\\\" is always type \\\"Foo\\\"\n  dynamic.foo(Foo.new is Foo)\n              ~~~~~~~~~~~~~~\n<stdin>:11:26: error: Cannot check against interface type \\\"Baz\\\"\n  dynamic.foo(Foo.new is Baz)\n                         ~~~\n<stdin>:12:15: warning: Unnecessary type check, type \\\"Bar\\\" is always type \\\"Foo\\\"\n  dynamic.foo(Bar.new is Foo)\n              ~~~~~~~~~~~~~~\n<stdin>:13:15: warning: Unnecessary type check, type \\\"Bar\\\" is always type \\\"Bar\\\"\n  dynamic.foo(Bar.new is Bar)\n              ~~~~~~~~~~~~~~\n<stdin>:14:26: error: Cannot check against interface type \\\"Baz\\\"\n  dynamic.foo(Bar.new is Baz)\n                         ~~~\n\")\n\ntest(\"\nvar a Bool = null\nvar b Int = null\nvar c Double = null\nvar d String = null\nvar e Bar = null\n\ntype Bool = bool\ntype Int = int\ntype Double = double\ntype String = string\ntype Bar = Foo\nenum Foo {}\n\", \"\n<stdin>:1:14: error: Cannot convert from type \\\"null\\\" to type \\\"Bool\\\"\nvar a Bool = null\n             ~~~~\n<stdin>:2:13: error: Cannot convert from type \\\"null\\\" to type \\\"Int\\\"\nvar b Int = null\n            ~~~~\n<stdin>:3:16: error: Cannot convert from type \\\"null\\\" to type \\\"Double\\\"\nvar c Double = null\n               ~~~~\n<stdin>:5:13: error: Cannot convert from type \\\"null\\\" to type \\\"Bar\\\"\nvar e Bar = null\n            ~~~~\n\")\n\ntest(\"\ninterface I {}\nclass C :: I {}\ninterface I2 :: I {}\nnamespace N :: I {}\ntype T : C :: I {}\nenum E :: I {}\n\", \"\n<stdin>:3:17: error: Cannot implement type \\\"I\\\"\ninterface I2 :: I {}\n                ^\n<stdin>:4:16: error: Cannot implement type \\\"I\\\"\nnamespace N :: I {}\n               ^\n<stdin>:5:15: error: Cannot implement type \\\"I\\\"\ntype T : C :: I {}\n              ^\n<stdin>:6:11: error: Cannot implement type \\\"I\\\"\nenum E :: I {}\n          ^\n\")\n\ntest(\"\ninterface I {}\nclass C :: I, I2, I, I2 {}\ninterface I2 {}\n\", \"\n<stdin>:2:19: error: Duplicate implemented type \\\"I\\\"\nclass C :: I, I2, I, I2 {}\n                  ^\n<stdin>:2:12: note: The first occurrence is here\nclass C :: I, I2, I, I2 {}\n           ^\n<stdin>:2:22: error: Duplicate implemented type \\\"I2\\\"\nclass C :: I, I2, I, I2 {}\n                     ~~\n<stdin>:2:15: note: The first occurrence is here\nclass C :: I, I2, I, I2 {}\n              ~~\n\")\n\ntest(\"\nclass Foo :: IFoo {}\ninterface IFoo {}\ninterface IBar {}\n\ndef main(foo Foo, ifoo IFoo, ibar IBar) {\n  foo = ifoo\n  foo = ibar\n  ifoo = foo\n  ifoo = ibar\n  ibar = foo\n  ibar = ifoo\n}\n\", \"\n<stdin>:6:9: error: Cannot convert from type \\\"IFoo\\\" to type \\\"Foo\\\" without a cast\n  foo = ifoo\n        ~~~~\n<stdin>:7:9: error: Cannot convert from type \\\"IBar\\\" to type \\\"Foo\\\"\n  foo = ibar\n        ~~~~\n<stdin>:9:10: error: Cannot convert from type \\\"IBar\\\" to type \\\"IFoo\\\"\n  ifoo = ibar\n         ~~~~\n<stdin>:10:10: error: Cannot convert from type \\\"Foo\\\" to type \\\"IBar\\\"\n  ibar = foo\n         ~~~\n<stdin>:11:10: error: Cannot convert from type \\\"IFoo\\\" to type \\\"IBar\\\"\n  ibar = ifoo\n         ~~~~\n\")\n\ntest(\"\nclass Foo :: IFoo<int> {}\ninterface IFoo<T> {}\n\ndef main(foo Foo, ifoo_int IFoo<int>, ifoo_bool IFoo<bool>) {\n  foo = ifoo_int\n  foo = ifoo_bool\n  ifoo_int = foo\n  ifoo_int = ifoo_bool\n  ifoo_bool = foo\n  ifoo_bool = ifoo_int\n}\n\", \"\n<stdin>:5:9: error: Cannot convert from type \\\"IFoo<int>\\\" to type \\\"Foo\\\" without a cast\n  foo = ifoo_int\n        ~~~~~~~~\n<stdin>:6:9: error: Cannot convert from type \\\"IFoo<bool>\\\" to type \\\"Foo\\\"\n  foo = ifoo_bool\n        ~~~~~~~~~\n<stdin>:8:14: error: Cannot convert from type \\\"IFoo<bool>\\\" to type \\\"IFoo<int>\\\"\n  ifoo_int = ifoo_bool\n             ~~~~~~~~~\n<stdin>:9:15: error: Cannot convert from type \\\"Foo\\\" to type \\\"IFoo<bool>\\\"\n  ifoo_bool = foo\n              ~~~\n<stdin>:10:15: error: Cannot convert from type \\\"IFoo<int>\\\" to type \\\"IFoo<bool>\\\"\n  ifoo_bool = ifoo_int\n              ~~~~~~~~\n\")\n\ntest(\"\nclass Foo<T> :: IFoo<T> {}\ninterface IFoo<T> {}\n\ndef main(foo_int Foo<int>, ifoo_int IFoo<int>, ifoo_bool IFoo<bool>) {\n  foo_int = ifoo_int\n  foo_int = ifoo_bool\n  ifoo_int = foo_int\n  ifoo_int = ifoo_bool\n  ifoo_bool = foo_int\n  ifoo_bool = ifoo_int\n}\n\", \"\n<stdin>:5:13: error: Cannot convert from type \\\"IFoo<int>\\\" to type \\\"Foo<int>\\\" without a cast\n  foo_int = ifoo_int\n            ~~~~~~~~\n<stdin>:6:13: error: Cannot convert from type \\\"IFoo<bool>\\\" to type \\\"Foo<int>\\\"\n  foo_int = ifoo_bool\n            ~~~~~~~~~\n<stdin>:8:14: error: Cannot convert from type \\\"IFoo<bool>\\\" to type \\\"IFoo<int>\\\"\n  ifoo_int = ifoo_bool\n             ~~~~~~~~~\n<stdin>:9:15: error: Cannot convert from type \\\"Foo<int>\\\" to type \\\"IFoo<bool>\\\"\n  ifoo_bool = foo_int\n              ~~~~~~~\n<stdin>:10:15: error: Cannot convert from type \\\"IFoo<int>\\\" to type \\\"IFoo<bool>\\\"\n  ifoo_bool = ifoo_int\n              ~~~~~~~~\n\")\n\ntest(\"\nclass Foo :: IFoo {}\ninterface IFoo { def foo }\n\", \"\n<stdin>:1:7: error: Type \\\"Foo\\\" is missing an implementation of function \\\"foo\\\" from interface \\\"IFoo\\\"\nclass Foo :: IFoo {}\n      ~~~\n<stdin>:2:22: note: The function declaration is here\ninterface IFoo { def foo }\n                     ~~~\n\")\n\ntest(\"\nclass Foo :: IFoo { def foo int }\ninterface IFoo { def foo bool }\n\", \"\n<stdin>:1:25: error: Function \\\"foo\\\" has unexpected return type \\\"int\\\", expected return type \\\"bool\\\" to match the function with the same name and argument types from interface \\\"IFoo\\\"\nclass Foo :: IFoo { def foo int }\n                        ~~~\n<stdin>:2:22: note: The function declaration is here\ninterface IFoo { def foo bool }\n                     ~~~\n\")\n\ntest(\"\nclass Foo :: IFoo { def foo }\ninterface IFoo { def foo bool }\n\", \"\n<stdin>:1:25: error: Expected the return type of function \\\"foo\\\" to match the function with the same name and argument types from interface \\\"IFoo\\\"\nclass Foo :: IFoo { def foo }\n                        ~~~\n<stdin>:2:22: note: The function declaration is here\ninterface IFoo { def foo bool }\n                     ~~~\n\")\n\ntest(\"\nclass Foo :: IFoo { def foo int }\ninterface IFoo { def foo }\n\", \"\n<stdin>:1:25: error: Expected the return type of function \\\"foo\\\" to match the function with the same name and argument types from interface \\\"IFoo\\\"\nclass Foo :: IFoo { def foo int }\n                        ~~~\n<stdin>:2:22: note: The function declaration is here\ninterface IFoo { def foo }\n                     ~~~\n\")\n\ntest(\"\nclass Foo :: IFoo { var foo int }\ninterface IFoo { def foo bool }\n\", \"\n<stdin>:1:7: error: Type \\\"Foo\\\" is missing an implementation of function \\\"foo\\\" from interface \\\"IFoo\\\"\nclass Foo :: IFoo { var foo int }\n      ~~~\n<stdin>:2:22: note: The function declaration is here\ninterface IFoo { def foo bool }\n                     ~~~\n\")\n\ntest(\"\nclass Foo {\n  over foo\n}\n\", \"\n<stdin>:2:8: error: \\\"foo\\\" is declared using \\\"over\\\" instead of \\\"def\\\" but does not override anything\n  over foo\n       ~~~\n\")\n\ntest(\"\nclass Foo {\n  def foo\n}\n\nclass Bar : Foo {\n  def foo\n}\n\", \"\n<stdin>:6:7: error: \\\"foo\\\" overrides another symbol with the same name but is declared using \\\"def\\\" instead of \\\"over\\\"\n  def foo\n      ~~~\n<stdin>:2:7: note: The overridden declaration is here\n  def foo\n      ~~~\n\")\n\ntest(\"\nclass Foo {\n  def new {}\n}\n\nclass Bar : Foo {\n  def new {}\n}\n\", \"\n<stdin>:6:7: error: Constructors for derived types must start with a call to \\\"super\\\"\n  def new {}\n      ~~~\n\")\n\ntest(\"\nclass Foo {\n  def new {}\n}\n\nclass Bar : Foo {\n  def new { super }\n}\n\", \"\n\")\n\ntest(\"\nclass Foo {\n  def new(x int) {}\n}\n\nclass Bar : Foo {\n  def new { super }\n}\n\", \"\n<stdin>:6:13: error: The function \\\"new\\\" takes 1 argument and must be called\n  def new { super }\n            ~~~~~\n\")\n\ntest(\"\nclass Foo {\n  def new(x int) {}\n}\n\nclass Bar : Foo {\n  def new { super(1) }\n}\n\", \"\n\")\n\n# Parser whitespace test\ntest(\"\nvar x = 0 ?\n# Comment\n1 :\n# Comment\n2\nvar y = z(\n  # Comment\n)\n\", \"\n<stdin>:1:9: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\nvar x = 0 ?\n        ^\n<stdin>:6:9: error: \\\"z\\\" is not declared\nvar y = z(\n        ^\n\")\n\n# Parser whitespace test\ntest(\"\ndef main {\n  if 0\n  {\n  }\n  else\n  {\n  }\n}\n\", \"\n<stdin>:2:6: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n  if 0\n     ^\n\")\n\n# Parser whitespace test\ntest(\"\ndef main(\n  a int,\n  b int\n) int {\n}\n\", \"\n<stdin>:1:5: error: All control paths for \\\"main\\\" must return a value of type \\\"int\\\"\ndef main(\n    ~~~~\n\")\n\n# Parser whitespace test\ntest(\"\nvar foo = a\n  .b\n  .c\n\", \"\n<stdin>:1:11: error: \\\"a\\\" is not declared\nvar foo = a\n          ^\n\")\n\n# Test for an operator overload resolution bug with integer promotion to double\ntest(\"\ndef foo(count int) {\n  count + 0.0\n  count += 0.0\n}\n\", \"\n<stdin>:2:3: warning: Unused expression\n  count + 0.0\n  ~~~~~~~~~~~\n<stdin>:3:12: error: Cannot convert from type \\\"double\\\" to type \\\"int\\\" without a cast\n  count += 0.0\n           ~~~\n\")\n\n# Test for enum promotion to integer for comparison operators\ntest(\"\nenum Foo {}\nenum Bar {}\n\ndef foo(foo Foo, bar Bar) bool {\n  return\n    (foo < 0 || foo > 0 || foo <= 0 || foo >= 0 || foo == 0 || foo != 0) &&\n    (0 < foo || 0 > foo || 0 <= foo || 0 >= foo || 0 == foo || 0 != foo) &&\n\n    (foo < 0.0 || foo > 0.0 || foo <= 0.0 || foo >= 0.0 || foo == 0.0 || foo != 0.0) &&\n    (0.0 < foo || 0.0 > foo || 0.0 <= foo || 0.0 >= foo || 0.0 == foo || 0.0 != foo) &&\n\n    (foo < foo || foo > foo || foo <= foo || foo >= foo || foo == foo || foo != foo) &&\n    (foo < bar || foo > bar || foo <= bar || foo >= bar || foo == bar || foo != bar) &&\n\n    (foo < false || foo > false || foo <= false || foo >= false || foo == false || foo != false) &&\n    (false < foo || false > foo || false <= foo || false >= foo || false == foo || false != foo)\n}\n\", \"\n<stdin>:12:60: warning: Both sides of \\\"==\\\" are identical, is this a bug?\n    (foo < foo || foo > foo || foo <= foo || foo >= foo || foo == foo || foo != foo) &&\n                                                           ~~~~~~~~~~\n<stdin>:12:74: warning: Both sides of \\\"!=\\\" are identical, is this a bug?\n    (foo < foo || foo > foo || foo <= foo || foo >= foo || foo == foo || foo != foo) &&\n                                                                         ~~~~~~~~~~\n<stdin>:15:10: error: \\\"<=>\\\" is not declared on type \\\"Foo\\\"\n    (foo < false || foo > false || foo <= false || foo >= false || foo == false || foo != false) &&\n         ^\n<stdin>:15:25: error: \\\"<=>\\\" is not declared on type \\\"Foo\\\"\n    (foo < false || foo > false || foo <= false || foo >= false || foo == false || foo != false) &&\n                        ^\n<stdin>:15:40: error: \\\"<=>\\\" is not declared on type \\\"Foo\\\"\n    (foo < false || foo > false || foo <= false || foo >= false || foo == false || foo != false) &&\n                                       ~~\n<stdin>:15:56: error: \\\"<=>\\\" is not declared on type \\\"Foo\\\"\n    (foo < false || foo > false || foo <= false || foo >= false || foo == false || foo != false) &&\n                                                       ~~\n<stdin>:15:68: error: No common type for \\\"Foo\\\" and \\\"bool\\\"\n    (foo < false || foo > false || foo <= false || foo >= false || foo == false || foo != false) &&\n                                                                   ~~~~~~~~~~~~\n<stdin>:15:84: error: No common type for \\\"Foo\\\" and \\\"bool\\\"\n    (foo < false || foo > false || foo <= false || foo >= false || foo == false || foo != false) &&\n                                                                                   ~~~~~~~~~~~~\n<stdin>:16:12: error: \\\"<=>\\\" is not declared on type \\\"bool\\\"\n    (false < foo || false > foo || false <= foo || false >= foo || false == foo || false != foo)\n           ^\n<stdin>:16:27: error: \\\"<=>\\\" is not declared on type \\\"bool\\\"\n    (false < foo || false > foo || false <= foo || false >= foo || false == foo || false != foo)\n                          ^\n<stdin>:16:42: error: \\\"<=>\\\" is not declared on type \\\"bool\\\"\n    (false < foo || false > foo || false <= foo || false >= foo || false == foo || false != foo)\n                                         ~~\n<stdin>:16:58: error: \\\"<=>\\\" is not declared on type \\\"bool\\\"\n    (false < foo || false > foo || false <= foo || false >= foo || false == foo || false != foo)\n                                                         ~~\n<stdin>:16:68: error: No common type for \\\"bool\\\" and \\\"Foo\\\"\n    (false < foo || false > foo || false <= foo || false >= foo || false == foo || false != foo)\n                                                                   ~~~~~~~~~~~~\n<stdin>:16:84: error: No common type for \\\"bool\\\" and \\\"Foo\\\"\n    (false < foo || false > foo || false <= foo || false >= foo || false == foo || false != foo)\n                                                                                   ~~~~~~~~~~~~\n\")\n\n# Test for enum promotion to integer for other operators\ntest(\"\nenum Foo {}\nenum Bar {}\n\ndef foo(foo Foo, bar Bar) List<bool> {\n  return [\n    foo + 0, foo - 0, foo * 0, foo / 0, foo % 0, foo & 0, foo | 0, foo ^ 0, foo << 0, foo >> 0, foo >>> 0, foo <=> 0,\n    0 + foo, 0 - foo, 0 * foo, 0 / foo, 0 % foo, 0 & foo, 0 | foo, 0 ^ foo, 0 << foo, 0 >> foo, 0 >>> foo, 0 <=> foo,\n\n    foo + 0.0, foo - 0.0, foo * 0.0, foo / 0.0, foo % 0.0, foo & 0.0, foo | 0.0, foo ^ 0.0, foo << 0.0, foo >> 0.0, foo >>> 0.0, foo <=> 0.0,\n    0.0 + foo, 0.0 - foo, 0.0 * foo, 0.0 / foo, 0.0 % foo, 0.0 & foo, 0.0 | foo, 0.0 ^ foo, 0.0 << foo, 0.0 >> foo, 0.0 >>> foo, 0.0 <=> foo,\n\n    foo + foo, foo - foo, foo * foo, foo / foo, foo % foo, foo & foo, foo | foo, foo ^ foo, foo << foo, foo >> foo, foo >>> foo, foo <=> foo,\n    foo + foo, foo - foo, foo * foo, foo / foo, foo % foo, foo & foo, foo | foo, foo ^ foo, foo << foo, foo >> foo, foo >>> foo, foo <=> foo,\n\n    foo + bar, foo - bar, foo * bar, foo / bar, foo % bar, foo & bar, foo | bar, foo ^ bar, foo << bar, foo >> bar, foo >>> bar, foo <=> bar,\n    bar + foo, bar - foo, bar * foo, bar / foo, bar % foo, bar & foo, bar | foo, bar ^ foo, bar << foo, bar >> foo, bar >>> foo, bar <=> foo,\n  ]\n}\n\", \"\n<stdin>:6:5: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + 0, foo - 0, foo * 0, foo / 0, foo % 0, foo & 0, foo | 0, foo ^ 0, foo << 0, foo >> 0, foo >>> 0, foo <=> 0,\n    ~~~~~~~\n<stdin>:6:14: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + 0, foo - 0, foo * 0, foo / 0, foo % 0, foo & 0, foo | 0, foo ^ 0, foo << 0, foo >> 0, foo >>> 0, foo <=> 0,\n             ~~~~~~~\n<stdin>:6:23: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + 0, foo - 0, foo * 0, foo / 0, foo % 0, foo & 0, foo | 0, foo ^ 0, foo << 0, foo >> 0, foo >>> 0, foo <=> 0,\n                      ~~~~~~~\n<stdin>:6:32: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + 0, foo - 0, foo * 0, foo / 0, foo % 0, foo & 0, foo | 0, foo ^ 0, foo << 0, foo >> 0, foo >>> 0, foo <=> 0,\n                               ~~~~~~~\n<stdin>:6:41: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + 0, foo - 0, foo * 0, foo / 0, foo % 0, foo & 0, foo | 0, foo ^ 0, foo << 0, foo >> 0, foo >>> 0, foo <=> 0,\n                                        ~~~~~~~\n<stdin>:6:50: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + 0, foo - 0, foo * 0, foo / 0, foo % 0, foo & 0, foo | 0, foo ^ 0, foo << 0, foo >> 0, foo >>> 0, foo <=> 0,\n                                                 ~~~~~~~\n<stdin>:6:59: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + 0, foo - 0, foo * 0, foo / 0, foo % 0, foo & 0, foo | 0, foo ^ 0, foo << 0, foo >> 0, foo >>> 0, foo <=> 0,\n                                                          ~~~~~~~\n<stdin>:6:68: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + 0, foo - 0, foo * 0, foo / 0, foo % 0, foo & 0, foo | 0, foo ^ 0, foo << 0, foo >> 0, foo >>> 0, foo <=> 0,\n                                                                   ~~~~~~~\n<stdin>:6:77: warning: Shifting an integer by zero doesn't do anything, is this a bug?\n    foo + 0, foo - 0, foo * 0, foo / 0, foo % 0, foo & 0, foo | 0, foo ^ 0, foo << 0, foo >> 0, foo >>> 0, foo <=> 0,\n                                                                            ~~~~~~~~\n<stdin>:6:77: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + 0, foo - 0, foo * 0, foo / 0, foo % 0, foo & 0, foo | 0, foo ^ 0, foo << 0, foo >> 0, foo >>> 0, foo <=> 0,\n                                                                            ~~~~~~~~\n<stdin>:6:87: warning: Shifting an integer by zero doesn't do anything, is this a bug?\n    foo + 0, foo - 0, foo * 0, foo / 0, foo % 0, foo & 0, foo | 0, foo ^ 0, foo << 0, foo >> 0, foo >>> 0, foo <=> 0,\n                                                                                      ~~~~~~~~\n<stdin>:6:87: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + 0, foo - 0, foo * 0, foo / 0, foo % 0, foo & 0, foo | 0, foo ^ 0, foo << 0, foo >> 0, foo >>> 0, foo <=> 0,\n                                                                                      ~~~~~~~~\n<stdin>:6:97: warning: Shifting an integer by zero doesn't do anything, is this a bug?\n    foo + 0, foo - 0, foo * 0, foo / 0, foo % 0, foo & 0, foo | 0, foo ^ 0, foo << 0, foo >> 0, foo >>> 0, foo <=> 0,\n                                                                                                ~~~~~~~~~\n<stdin>:6:97: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + 0, foo - 0, foo * 0, foo / 0, foo % 0, foo & 0, foo | 0, foo ^ 0, foo << 0, foo >> 0, foo >>> 0, foo <=> 0,\n                                                                                                ~~~~~~~~~\n<stdin>:6:108: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + 0, foo - 0, foo * 0, foo / 0, foo % 0, foo & 0, foo | 0, foo ^ 0, foo << 0, foo >> 0, foo >>> 0, foo <=> 0,\n                                                                                                           ~~~~~~~~~\n<stdin>:7:5: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    0 + foo, 0 - foo, 0 * foo, 0 / foo, 0 % foo, 0 & foo, 0 | foo, 0 ^ foo, 0 << foo, 0 >> foo, 0 >>> foo, 0 <=> foo,\n    ~~~~~~~\n<stdin>:7:14: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    0 + foo, 0 - foo, 0 * foo, 0 / foo, 0 % foo, 0 & foo, 0 | foo, 0 ^ foo, 0 << foo, 0 >> foo, 0 >>> foo, 0 <=> foo,\n             ~~~~~~~\n<stdin>:7:23: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    0 + foo, 0 - foo, 0 * foo, 0 / foo, 0 % foo, 0 & foo, 0 | foo, 0 ^ foo, 0 << foo, 0 >> foo, 0 >>> foo, 0 <=> foo,\n                      ~~~~~~~\n<stdin>:7:32: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    0 + foo, 0 - foo, 0 * foo, 0 / foo, 0 % foo, 0 & foo, 0 | foo, 0 ^ foo, 0 << foo, 0 >> foo, 0 >>> foo, 0 <=> foo,\n                               ~~~~~~~\n<stdin>:7:41: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    0 + foo, 0 - foo, 0 * foo, 0 / foo, 0 % foo, 0 & foo, 0 | foo, 0 ^ foo, 0 << foo, 0 >> foo, 0 >>> foo, 0 <=> foo,\n                                        ~~~~~~~\n<stdin>:7:50: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    0 + foo, 0 - foo, 0 * foo, 0 / foo, 0 % foo, 0 & foo, 0 | foo, 0 ^ foo, 0 << foo, 0 >> foo, 0 >>> foo, 0 <=> foo,\n                                                 ~~~~~~~\n<stdin>:7:59: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    0 + foo, 0 - foo, 0 * foo, 0 / foo, 0 % foo, 0 & foo, 0 | foo, 0 ^ foo, 0 << foo, 0 >> foo, 0 >>> foo, 0 <=> foo,\n                                                          ~~~~~~~\n<stdin>:7:68: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    0 + foo, 0 - foo, 0 * foo, 0 / foo, 0 % foo, 0 & foo, 0 | foo, 0 ^ foo, 0 << foo, 0 >> foo, 0 >>> foo, 0 <=> foo,\n                                                                   ~~~~~~~\n<stdin>:7:77: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    0 + foo, 0 - foo, 0 * foo, 0 / foo, 0 % foo, 0 & foo, 0 | foo, 0 ^ foo, 0 << foo, 0 >> foo, 0 >>> foo, 0 <=> foo,\n                                                                            ~~~~~~~~\n<stdin>:7:87: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    0 + foo, 0 - foo, 0 * foo, 0 / foo, 0 % foo, 0 & foo, 0 | foo, 0 ^ foo, 0 << foo, 0 >> foo, 0 >>> foo, 0 <=> foo,\n                                                                                      ~~~~~~~~\n<stdin>:7:97: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    0 + foo, 0 - foo, 0 * foo, 0 / foo, 0 % foo, 0 & foo, 0 | foo, 0 ^ foo, 0 << foo, 0 >> foo, 0 >>> foo, 0 <=> foo,\n                                                                                                ~~~~~~~~~\n<stdin>:7:108: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    0 + foo, 0 - foo, 0 * foo, 0 / foo, 0 % foo, 0 & foo, 0 | foo, 0 ^ foo, 0 << foo, 0 >> foo, 0 >>> foo, 0 <=> foo,\n                                                                                                           ~~~~~~~~~\n<stdin>:9:5: error: Cannot convert from type \\\"double\\\" to type \\\"bool\\\" without a cast\n    foo + 0.0, foo - 0.0, foo * 0.0, foo / 0.0, foo % 0.0, foo & 0.0, foo | 0.0, foo ^ 0.0, foo << 0.0, foo >> 0.0, foo >>> 0.0, foo <=> 0.0,\n    ~~~~~~~~~\n<stdin>:9:16: error: Cannot convert from type \\\"double\\\" to type \\\"bool\\\" without a cast\n    foo + 0.0, foo - 0.0, foo * 0.0, foo / 0.0, foo % 0.0, foo & 0.0, foo | 0.0, foo ^ 0.0, foo << 0.0, foo >> 0.0, foo >>> 0.0, foo <=> 0.0,\n               ~~~~~~~~~\n<stdin>:9:27: error: Cannot convert from type \\\"double\\\" to type \\\"bool\\\" without a cast\n    foo + 0.0, foo - 0.0, foo * 0.0, foo / 0.0, foo % 0.0, foo & 0.0, foo | 0.0, foo ^ 0.0, foo << 0.0, foo >> 0.0, foo >>> 0.0, foo <=> 0.0,\n                          ~~~~~~~~~\n<stdin>:9:38: error: Cannot convert from type \\\"double\\\" to type \\\"bool\\\" without a cast\n    foo + 0.0, foo - 0.0, foo * 0.0, foo / 0.0, foo % 0.0, foo & 0.0, foo | 0.0, foo ^ 0.0, foo << 0.0, foo >> 0.0, foo >>> 0.0, foo <=> 0.0,\n                                     ~~~~~~~~~\n<stdin>:9:53: error: \\\"%\\\" is not declared on type \\\"double\\\"\n    foo + 0.0, foo - 0.0, foo * 0.0, foo / 0.0, foo % 0.0, foo & 0.0, foo | 0.0, foo ^ 0.0, foo << 0.0, foo >> 0.0, foo >>> 0.0, foo <=> 0.0,\n                                                    ^\n<stdin>:9:64: error: \\\"&\\\" is not declared on type \\\"double\\\"\n    foo + 0.0, foo - 0.0, foo * 0.0, foo / 0.0, foo % 0.0, foo & 0.0, foo | 0.0, foo ^ 0.0, foo << 0.0, foo >> 0.0, foo >>> 0.0, foo <=> 0.0,\n                                                               ^\n<stdin>:9:75: error: \\\"|\\\" is not declared on type \\\"double\\\"\n    foo + 0.0, foo - 0.0, foo * 0.0, foo / 0.0, foo % 0.0, foo & 0.0, foo | 0.0, foo ^ 0.0, foo << 0.0, foo >> 0.0, foo >>> 0.0, foo <=> 0.0,\n                                                                          ^\n<stdin>:9:86: error: \\\"^\\\" is not declared on type \\\"double\\\"\n    foo + 0.0, foo - 0.0, foo * 0.0, foo / 0.0, foo % 0.0, foo & 0.0, foo | 0.0, foo ^ 0.0, foo << 0.0, foo >> 0.0, foo >>> 0.0, foo <=> 0.0,\n                                                                                     ^\n<stdin>:9:97: error: \\\"<<\\\" is not declared on type \\\"double\\\"\n    foo + 0.0, foo - 0.0, foo * 0.0, foo / 0.0, foo % 0.0, foo & 0.0, foo | 0.0, foo ^ 0.0, foo << 0.0, foo >> 0.0, foo >>> 0.0, foo <=> 0.0,\n                                                                                                ~~\n<stdin>:9:109: error: \\\">>\\\" is not declared on type \\\"double\\\"\n    foo + 0.0, foo - 0.0, foo * 0.0, foo / 0.0, foo % 0.0, foo & 0.0, foo | 0.0, foo ^ 0.0, foo << 0.0, foo >> 0.0, foo >>> 0.0, foo <=> 0.0,\n                                                                                                            ~~\n<stdin>:9:121: error: \\\">>>\\\" is not declared on type \\\"double\\\"\n    foo + 0.0, foo - 0.0, foo * 0.0, foo / 0.0, foo % 0.0, foo & 0.0, foo | 0.0, foo ^ 0.0, foo << 0.0, foo >> 0.0, foo >>> 0.0, foo <=> 0.0,\n                                                                                                                        ~~~\n<stdin>:9:130: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + 0.0, foo - 0.0, foo * 0.0, foo / 0.0, foo % 0.0, foo & 0.0, foo | 0.0, foo ^ 0.0, foo << 0.0, foo >> 0.0, foo >>> 0.0, foo <=> 0.0,\n                                                                                                                                 ~~~~~~~~~~~\n<stdin>:10:5: error: Cannot convert from type \\\"double\\\" to type \\\"bool\\\" without a cast\n    0.0 + foo, 0.0 - foo, 0.0 * foo, 0.0 / foo, 0.0 % foo, 0.0 & foo, 0.0 | foo, 0.0 ^ foo, 0.0 << foo, 0.0 >> foo, 0.0 >>> foo, 0.0 <=> foo,\n    ~~~~~~~~~\n<stdin>:10:16: error: Cannot convert from type \\\"double\\\" to type \\\"bool\\\" without a cast\n    0.0 + foo, 0.0 - foo, 0.0 * foo, 0.0 / foo, 0.0 % foo, 0.0 & foo, 0.0 | foo, 0.0 ^ foo, 0.0 << foo, 0.0 >> foo, 0.0 >>> foo, 0.0 <=> foo,\n               ~~~~~~~~~\n<stdin>:10:27: error: Cannot convert from type \\\"double\\\" to type \\\"bool\\\" without a cast\n    0.0 + foo, 0.0 - foo, 0.0 * foo, 0.0 / foo, 0.0 % foo, 0.0 & foo, 0.0 | foo, 0.0 ^ foo, 0.0 << foo, 0.0 >> foo, 0.0 >>> foo, 0.0 <=> foo,\n                          ~~~~~~~~~\n<stdin>:10:38: error: Cannot convert from type \\\"double\\\" to type \\\"bool\\\" without a cast\n    0.0 + foo, 0.0 - foo, 0.0 * foo, 0.0 / foo, 0.0 % foo, 0.0 & foo, 0.0 | foo, 0.0 ^ foo, 0.0 << foo, 0.0 >> foo, 0.0 >>> foo, 0.0 <=> foo,\n                                     ~~~~~~~~~\n<stdin>:10:53: error: \\\"%\\\" is not declared on type \\\"double\\\"\n    0.0 + foo, 0.0 - foo, 0.0 * foo, 0.0 / foo, 0.0 % foo, 0.0 & foo, 0.0 | foo, 0.0 ^ foo, 0.0 << foo, 0.0 >> foo, 0.0 >>> foo, 0.0 <=> foo,\n                                                    ^\n<stdin>:10:64: error: \\\"&\\\" is not declared on type \\\"double\\\"\n    0.0 + foo, 0.0 - foo, 0.0 * foo, 0.0 / foo, 0.0 % foo, 0.0 & foo, 0.0 | foo, 0.0 ^ foo, 0.0 << foo, 0.0 >> foo, 0.0 >>> foo, 0.0 <=> foo,\n                                                               ^\n<stdin>:10:75: error: \\\"|\\\" is not declared on type \\\"double\\\"\n    0.0 + foo, 0.0 - foo, 0.0 * foo, 0.0 / foo, 0.0 % foo, 0.0 & foo, 0.0 | foo, 0.0 ^ foo, 0.0 << foo, 0.0 >> foo, 0.0 >>> foo, 0.0 <=> foo,\n                                                                          ^\n<stdin>:10:86: error: \\\"^\\\" is not declared on type \\\"double\\\"\n    0.0 + foo, 0.0 - foo, 0.0 * foo, 0.0 / foo, 0.0 % foo, 0.0 & foo, 0.0 | foo, 0.0 ^ foo, 0.0 << foo, 0.0 >> foo, 0.0 >>> foo, 0.0 <=> foo,\n                                                                                     ^\n<stdin>:10:97: error: \\\"<<\\\" is not declared on type \\\"double\\\"\n    0.0 + foo, 0.0 - foo, 0.0 * foo, 0.0 / foo, 0.0 % foo, 0.0 & foo, 0.0 | foo, 0.0 ^ foo, 0.0 << foo, 0.0 >> foo, 0.0 >>> foo, 0.0 <=> foo,\n                                                                                                ~~\n<stdin>:10:109: error: \\\">>\\\" is not declared on type \\\"double\\\"\n    0.0 + foo, 0.0 - foo, 0.0 * foo, 0.0 / foo, 0.0 % foo, 0.0 & foo, 0.0 | foo, 0.0 ^ foo, 0.0 << foo, 0.0 >> foo, 0.0 >>> foo, 0.0 <=> foo,\n                                                                                                            ~~\n<stdin>:10:121: error: \\\">>>\\\" is not declared on type \\\"double\\\"\n    0.0 + foo, 0.0 - foo, 0.0 * foo, 0.0 / foo, 0.0 % foo, 0.0 & foo, 0.0 | foo, 0.0 ^ foo, 0.0 << foo, 0.0 >> foo, 0.0 >>> foo, 0.0 <=> foo,\n                                                                                                                        ~~~\n<stdin>:10:130: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    0.0 + foo, 0.0 - foo, 0.0 * foo, 0.0 / foo, 0.0 % foo, 0.0 & foo, 0.0 | foo, 0.0 ^ foo, 0.0 << foo, 0.0 >> foo, 0.0 >>> foo, 0.0 <=> foo,\n                                                                                                                                 ~~~~~~~~~~~\n<stdin>:12:5: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + foo, foo - foo, foo * foo, foo / foo, foo % foo, foo & foo, foo | foo, foo ^ foo, foo << foo, foo >> foo, foo >>> foo, foo <=> foo,\n    ~~~~~~~~~\n<stdin>:12:16: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + foo, foo - foo, foo * foo, foo / foo, foo % foo, foo & foo, foo | foo, foo ^ foo, foo << foo, foo >> foo, foo >>> foo, foo <=> foo,\n               ~~~~~~~~~\n<stdin>:12:27: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + foo, foo - foo, foo * foo, foo / foo, foo % foo, foo & foo, foo | foo, foo ^ foo, foo << foo, foo >> foo, foo >>> foo, foo <=> foo,\n                          ~~~~~~~~~\n<stdin>:12:38: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + foo, foo - foo, foo * foo, foo / foo, foo % foo, foo & foo, foo | foo, foo ^ foo, foo << foo, foo >> foo, foo >>> foo, foo <=> foo,\n                                     ~~~~~~~~~\n<stdin>:12:49: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + foo, foo - foo, foo * foo, foo / foo, foo % foo, foo & foo, foo | foo, foo ^ foo, foo << foo, foo >> foo, foo >>> foo, foo <=> foo,\n                                                ~~~~~~~~~\n<stdin>:12:60: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + foo, foo - foo, foo * foo, foo / foo, foo % foo, foo & foo, foo | foo, foo ^ foo, foo << foo, foo >> foo, foo >>> foo, foo <=> foo,\n                                                           ~~~~~~~~~\n<stdin>:12:71: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + foo, foo - foo, foo * foo, foo / foo, foo % foo, foo & foo, foo | foo, foo ^ foo, foo << foo, foo >> foo, foo >>> foo, foo <=> foo,\n                                                                      ~~~~~~~~~\n<stdin>:12:82: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + foo, foo - foo, foo * foo, foo / foo, foo % foo, foo & foo, foo | foo, foo ^ foo, foo << foo, foo >> foo, foo >>> foo, foo <=> foo,\n                                                                                 ~~~~~~~~~\n<stdin>:12:93: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + foo, foo - foo, foo * foo, foo / foo, foo % foo, foo & foo, foo | foo, foo ^ foo, foo << foo, foo >> foo, foo >>> foo, foo <=> foo,\n                                                                                            ~~~~~~~~~~\n<stdin>:12:105: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + foo, foo - foo, foo * foo, foo / foo, foo % foo, foo & foo, foo | foo, foo ^ foo, foo << foo, foo >> foo, foo >>> foo, foo <=> foo,\n                                                                                                        ~~~~~~~~~~\n<stdin>:12:117: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + foo, foo - foo, foo * foo, foo / foo, foo % foo, foo & foo, foo | foo, foo ^ foo, foo << foo, foo >> foo, foo >>> foo, foo <=> foo,\n                                                                                                                    ~~~~~~~~~~~\n<stdin>:12:130: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + foo, foo - foo, foo * foo, foo / foo, foo % foo, foo & foo, foo | foo, foo ^ foo, foo << foo, foo >> foo, foo >>> foo, foo <=> foo,\n                                                                                                                                 ~~~~~~~~~~~\n<stdin>:13:5: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + foo, foo - foo, foo * foo, foo / foo, foo % foo, foo & foo, foo | foo, foo ^ foo, foo << foo, foo >> foo, foo >>> foo, foo <=> foo,\n    ~~~~~~~~~\n<stdin>:13:16: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + foo, foo - foo, foo * foo, foo / foo, foo % foo, foo & foo, foo | foo, foo ^ foo, foo << foo, foo >> foo, foo >>> foo, foo <=> foo,\n               ~~~~~~~~~\n<stdin>:13:27: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + foo, foo - foo, foo * foo, foo / foo, foo % foo, foo & foo, foo | foo, foo ^ foo, foo << foo, foo >> foo, foo >>> foo, foo <=> foo,\n                          ~~~~~~~~~\n<stdin>:13:38: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + foo, foo - foo, foo * foo, foo / foo, foo % foo, foo & foo, foo | foo, foo ^ foo, foo << foo, foo >> foo, foo >>> foo, foo <=> foo,\n                                     ~~~~~~~~~\n<stdin>:13:49: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + foo, foo - foo, foo * foo, foo / foo, foo % foo, foo & foo, foo | foo, foo ^ foo, foo << foo, foo >> foo, foo >>> foo, foo <=> foo,\n                                                ~~~~~~~~~\n<stdin>:13:60: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + foo, foo - foo, foo * foo, foo / foo, foo % foo, foo & foo, foo | foo, foo ^ foo, foo << foo, foo >> foo, foo >>> foo, foo <=> foo,\n                                                           ~~~~~~~~~\n<stdin>:13:71: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + foo, foo - foo, foo * foo, foo / foo, foo % foo, foo & foo, foo | foo, foo ^ foo, foo << foo, foo >> foo, foo >>> foo, foo <=> foo,\n                                                                      ~~~~~~~~~\n<stdin>:13:82: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + foo, foo - foo, foo * foo, foo / foo, foo % foo, foo & foo, foo | foo, foo ^ foo, foo << foo, foo >> foo, foo >>> foo, foo <=> foo,\n                                                                                 ~~~~~~~~~\n<stdin>:13:93: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + foo, foo - foo, foo * foo, foo / foo, foo % foo, foo & foo, foo | foo, foo ^ foo, foo << foo, foo >> foo, foo >>> foo, foo <=> foo,\n                                                                                            ~~~~~~~~~~\n<stdin>:13:105: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + foo, foo - foo, foo * foo, foo / foo, foo % foo, foo & foo, foo | foo, foo ^ foo, foo << foo, foo >> foo, foo >>> foo, foo <=> foo,\n                                                                                                        ~~~~~~~~~~\n<stdin>:13:117: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + foo, foo - foo, foo * foo, foo / foo, foo % foo, foo & foo, foo | foo, foo ^ foo, foo << foo, foo >> foo, foo >>> foo, foo <=> foo,\n                                                                                                                    ~~~~~~~~~~~\n<stdin>:13:130: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + foo, foo - foo, foo * foo, foo / foo, foo % foo, foo & foo, foo | foo, foo ^ foo, foo << foo, foo >> foo, foo >>> foo, foo <=> foo,\n                                                                                                                                 ~~~~~~~~~~~\n<stdin>:15:5: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + bar, foo - bar, foo * bar, foo / bar, foo % bar, foo & bar, foo | bar, foo ^ bar, foo << bar, foo >> bar, foo >>> bar, foo <=> bar,\n    ~~~~~~~~~\n<stdin>:15:16: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + bar, foo - bar, foo * bar, foo / bar, foo % bar, foo & bar, foo | bar, foo ^ bar, foo << bar, foo >> bar, foo >>> bar, foo <=> bar,\n               ~~~~~~~~~\n<stdin>:15:27: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + bar, foo - bar, foo * bar, foo / bar, foo % bar, foo & bar, foo | bar, foo ^ bar, foo << bar, foo >> bar, foo >>> bar, foo <=> bar,\n                          ~~~~~~~~~\n<stdin>:15:38: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + bar, foo - bar, foo * bar, foo / bar, foo % bar, foo & bar, foo | bar, foo ^ bar, foo << bar, foo >> bar, foo >>> bar, foo <=> bar,\n                                     ~~~~~~~~~\n<stdin>:15:49: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + bar, foo - bar, foo * bar, foo / bar, foo % bar, foo & bar, foo | bar, foo ^ bar, foo << bar, foo >> bar, foo >>> bar, foo <=> bar,\n                                                ~~~~~~~~~\n<stdin>:15:60: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + bar, foo - bar, foo * bar, foo / bar, foo % bar, foo & bar, foo | bar, foo ^ bar, foo << bar, foo >> bar, foo >>> bar, foo <=> bar,\n                                                           ~~~~~~~~~\n<stdin>:15:71: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + bar, foo - bar, foo * bar, foo / bar, foo % bar, foo & bar, foo | bar, foo ^ bar, foo << bar, foo >> bar, foo >>> bar, foo <=> bar,\n                                                                      ~~~~~~~~~\n<stdin>:15:82: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + bar, foo - bar, foo * bar, foo / bar, foo % bar, foo & bar, foo | bar, foo ^ bar, foo << bar, foo >> bar, foo >>> bar, foo <=> bar,\n                                                                                 ~~~~~~~~~\n<stdin>:15:93: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + bar, foo - bar, foo * bar, foo / bar, foo % bar, foo & bar, foo | bar, foo ^ bar, foo << bar, foo >> bar, foo >>> bar, foo <=> bar,\n                                                                                            ~~~~~~~~~~\n<stdin>:15:105: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + bar, foo - bar, foo * bar, foo / bar, foo % bar, foo & bar, foo | bar, foo ^ bar, foo << bar, foo >> bar, foo >>> bar, foo <=> bar,\n                                                                                                        ~~~~~~~~~~\n<stdin>:15:117: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + bar, foo - bar, foo * bar, foo / bar, foo % bar, foo & bar, foo | bar, foo ^ bar, foo << bar, foo >> bar, foo >>> bar, foo <=> bar,\n                                                                                                                    ~~~~~~~~~~~\n<stdin>:15:130: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    foo + bar, foo - bar, foo * bar, foo / bar, foo % bar, foo & bar, foo | bar, foo ^ bar, foo << bar, foo >> bar, foo >>> bar, foo <=> bar,\n                                                                                                                                 ~~~~~~~~~~~\n<stdin>:16:5: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    bar + foo, bar - foo, bar * foo, bar / foo, bar % foo, bar & foo, bar | foo, bar ^ foo, bar << foo, bar >> foo, bar >>> foo, bar <=> foo,\n    ~~~~~~~~~\n<stdin>:16:16: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    bar + foo, bar - foo, bar * foo, bar / foo, bar % foo, bar & foo, bar | foo, bar ^ foo, bar << foo, bar >> foo, bar >>> foo, bar <=> foo,\n               ~~~~~~~~~\n<stdin>:16:27: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    bar + foo, bar - foo, bar * foo, bar / foo, bar % foo, bar & foo, bar | foo, bar ^ foo, bar << foo, bar >> foo, bar >>> foo, bar <=> foo,\n                          ~~~~~~~~~\n<stdin>:16:38: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    bar + foo, bar - foo, bar * foo, bar / foo, bar % foo, bar & foo, bar | foo, bar ^ foo, bar << foo, bar >> foo, bar >>> foo, bar <=> foo,\n                                     ~~~~~~~~~\n<stdin>:16:49: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    bar + foo, bar - foo, bar * foo, bar / foo, bar % foo, bar & foo, bar | foo, bar ^ foo, bar << foo, bar >> foo, bar >>> foo, bar <=> foo,\n                                                ~~~~~~~~~\n<stdin>:16:60: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    bar + foo, bar - foo, bar * foo, bar / foo, bar % foo, bar & foo, bar | foo, bar ^ foo, bar << foo, bar >> foo, bar >>> foo, bar <=> foo,\n                                                           ~~~~~~~~~\n<stdin>:16:71: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    bar + foo, bar - foo, bar * foo, bar / foo, bar % foo, bar & foo, bar | foo, bar ^ foo, bar << foo, bar >> foo, bar >>> foo, bar <=> foo,\n                                                                      ~~~~~~~~~\n<stdin>:16:82: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    bar + foo, bar - foo, bar * foo, bar / foo, bar % foo, bar & foo, bar | foo, bar ^ foo, bar << foo, bar >> foo, bar >>> foo, bar <=> foo,\n                                                                                 ~~~~~~~~~\n<stdin>:16:93: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    bar + foo, bar - foo, bar * foo, bar / foo, bar % foo, bar & foo, bar | foo, bar ^ foo, bar << foo, bar >> foo, bar >>> foo, bar <=> foo,\n                                                                                            ~~~~~~~~~~\n<stdin>:16:105: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    bar + foo, bar - foo, bar * foo, bar / foo, bar % foo, bar & foo, bar | foo, bar ^ foo, bar << foo, bar >> foo, bar >>> foo, bar <=> foo,\n                                                                                                        ~~~~~~~~~~\n<stdin>:16:117: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    bar + foo, bar - foo, bar * foo, bar / foo, bar % foo, bar & foo, bar | foo, bar ^ foo, bar << foo, bar >> foo, bar >>> foo, bar <=> foo,\n                                                                                                                    ~~~~~~~~~~~\n<stdin>:16:130: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    bar + foo, bar - foo, bar * foo, bar / foo, bar % foo, bar & foo, bar | foo, bar ^ foo, bar << foo, bar >> foo, bar >>> foo, bar <=> foo,\n                                                                                                                                 ~~~~~~~~~~~\n\")\n\n# Test for recursive propagation of dynamic type context for list literals\ntest(\"\nconst foo dynamic = [1, [1, null]]\n\", \"\n\")\n\n# Test for recursive propagation of dynamic type context for map literals\ntest(\"\nconst foo dynamic = {\n  \\\"a\\\": 1,\n  \\\"b\\\": {\n    \\\"c\\\": 1,\n    \\\"d\\\": null\n  }\n}\n\", \"\n\")\n\n# Check that enums work with IntMap type inference\ntest(\"\nenum Foo {\n  FOO\n}\n\ndef test bool {\n  var foo = {Foo.FOO: \\\"\\\"}\n  return foo\n}\n\", \"\n<stdin>:7:10: error: Cannot convert from type \\\"IntMap<string>\\\" to type \\\"bool\\\"\n  return foo\n         ~~~\n\")\n\n# Check for a crash due to a bug with nested guards\ntest(\"\nif true {\n  if FOO == .BAR {\n  }\n}\n\nenum Foo {\n  FOO\n}\n\nconst FOO = Foo.FOO\n\", \"\n<stdin>:2:14: error: \\\"BAR\\\" is not declared on type \\\"Foo\\\"\n  if FOO == .BAR {\n             ~~~\n\")\n\n# Check for a crash due to a bug with nested guards\ntest(\"\nif true {\n  if FOO == .BAR {\n  } else {\n  }\n}\n\nconst FOO = Foo.FOO\n\", \"\n<stdin>:7:13: error: \\\"Foo\\\" is not declared\nconst FOO = Foo.FOO\n            ~~~\n\")\n\n# Check cyclic declarations involving lambdas\ntest(\"\n# Cyclic declaration\nconst a = => a()\nconst b = (=> b() + 1)()\nconst c = => { c() }\n\n# Not cyclic declarations\nconst d fn() = => d()\nconst e fn() = => { e() }\n\", \"\n<stdin>:2:7: error: Cyclic declaration of \\\"a\\\"\nconst a = => a()\n      ^\n<stdin>:3:7: error: Cyclic declaration of \\\"b\\\"\nconst b = (=> b() + 1)()\n      ^\n<stdin>:4:7: error: Cyclic declaration of \\\"c\\\"\nconst c = => { c() }\n      ^\n\")\n\n# Check equality operator warnings meant to prevent bugs, but don't warn on values that may be NaN\ntest(\"\ndef main(i int, d double, y dynamic, f fn() int, foo Foo) bool {\n  return\n    i + 2 == i + 2 && i + 2 != i + 2 ||\n    d + 2 == d + 2 && d + 2 != d + 2 ||\n    y + 2 == y + 2 && y + 2 != y + 2 ||\n    f() + 2 == f() + 2 && f() + 2 != f() + 2 ||\n    foo.i == foo.i && foo.i != foo.i ||\n    foo.d == foo.d && foo.d != foo.d ||\n    foo.y == foo.y && foo.y != foo.y ||\n    foo.f() == foo.f() && foo.f() != foo.f()\n}\n\nclass Foo {\n  var i int\n  var d double\n  var y dynamic\n  var f fn() int\n}\n\", \"\n<stdin>:3:5: warning: Both sides of \\\"==\\\" are identical, is this a bug?\n    i + 2 == i + 2 && i + 2 != i + 2 ||\n    ~~~~~~~~~~~~~~\n<stdin>:3:23: warning: Both sides of \\\"!=\\\" are identical, is this a bug?\n    i + 2 == i + 2 && i + 2 != i + 2 ||\n                      ~~~~~~~~~~~~~~\n<stdin>:7:5: warning: Both sides of \\\"==\\\" are identical, is this a bug?\n    foo.i == foo.i && foo.i != foo.i ||\n    ~~~~~~~~~~~~~~\n<stdin>:7:23: warning: Both sides of \\\"!=\\\" are identical, is this a bug?\n    foo.i == foo.i && foo.i != foo.i ||\n                      ~~~~~~~~~~~~~~\n\")\n\n# Check logical boolean operator warnings meant to prevent bugs\ntest(\"\ndef main int {\n  return\n    (1 + 2 == 3 && 1 + 2 == 3 ? 1 : 0) +\n    (1 + 2 == 3 || 1 + 2 == 3 ? 1 : 0) +\n    (dynamic.foo && dynamic.foo ? 1 : 0) +\n    (dynamic.foo || dynamic.foo ? 1 : 0) +\n    (dynamic.bar() && dynamic.bar() ? 1 : 0) +\n    (dynamic.bar() || dynamic.bar() ? 1 : 0) +\n    (true ? 0 : 0) +\n    (true ? dynamic.bar() : dynamic.bar())\n}\n\", \"\n<stdin>:3:6: warning: Both sides of \\\"&&\\\" are identical, is this a bug?\n    (1 + 2 == 3 && 1 + 2 == 3 ? 1 : 0) +\n     ~~~~~~~~~~~~~~~~~~~~~~~~\n<stdin>:4:6: warning: Both sides of \\\"||\\\" are identical, is this a bug?\n    (1 + 2 == 3 || 1 + 2 == 3 ? 1 : 0) +\n     ~~~~~~~~~~~~~~~~~~~~~~~~\n<stdin>:5:6: warning: Both sides of \\\"&&\\\" are identical, is this a bug?\n    (dynamic.foo && dynamic.foo ? 1 : 0) +\n     ~~~~~~~~~~~~~~~~~~~~~~~~~~\n<stdin>:6:6: warning: Both sides of \\\"||\\\" are identical, is this a bug?\n    (dynamic.foo || dynamic.foo ? 1 : 0) +\n     ~~~~~~~~~~~~~~~~~~~~~~~~~~\n<stdin>:9:13: warning: Both sides of \\\":\\\" are identical, is this a bug?\n    (true ? 0 : 0) +\n            ~~~~~\n<stdin>:10:13: warning: Both sides of \\\":\\\" are identical, is this a bug?\n    (true ? dynamic.bar() : dynamic.bar())\n            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\")\n\n# Make sure redundant inherited import/export annotations have appropriate warnings\ntest(\"\n@import\nclass Foo {\n  def foo\n}\n\nclass Foo {\n  @import\n  def foo(x int)\n}\n\n@export\nclass Bar {\n  def foo {}\n}\n\nclass Bar {\n  @export\n  def foo(x int) {}\n}\n\n@rename(\\\"Baz\\\")\nclass Baz {\n  def foo {}\n}\n\nclass Baz {\n  @rename(\\\"foo\\\")\n  def foo(x int) {}\n}\n\", \"\n<stdin>:7:3: warning: Redundant annotation \\\"@import\\\" on \\\"foo\\\" is already inherited from type \\\"Foo\\\"\n  @import\n  ~~~~~~~\n<stdin>:17:3: warning: Redundant annotation \\\"@export\\\" on \\\"foo\\\" is already inherited from type \\\"Bar\\\"\n  @export\n  ~~~~~~~\n\")\n\ntest(\"\nclass Foo {\n  def foo int {\n    return this + that\n  }\n}\n\nnamespace Foo {\n  def bar int {\n    return this + that\n  }\n}\n\", \"\n<stdin>:3:12: error: \\\"this\\\" is not declared (use \\\"self\\\" to refer to the object instance)\n    return this + that\n           ~~~~\n<stdin>:3:19: error: \\\"that\\\" is not declared\n    return this + that\n                  ~~~~\n<stdin>:9:12: error: \\\"this\\\" is not declared\n    return this + that\n           ~~~~\n<stdin>:9:19: error: \\\"that\\\" is not declared\n    return this + that\n                  ~~~~\n<stdin>:3:12: fix: Replace \\\"this\\\" with \\\"self\\\"\n    return this + that\n           ~~~~\n           [self]\n\")\n\ntest(\"\ndef foo<T>(x T) { foo }\ndef foo { foo<bool>(0) }\n\ndef bar<T>(x T) { bar(0, 1) }\ndef bar(x bool, y bool) { bar<bool>(0) }\n\", \"\n<stdin>:2:21: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\ndef foo { foo<bool>(0) }\n                    ^\n<stdin>:4:23: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\ndef bar<T>(x T) { bar(0, 1) }\n                      ^\n<stdin>:4:26: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\ndef bar<T>(x T) { bar(0, 1) }\n                         ^\n<stdin>:5:37: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\ndef bar(x bool, y bool) { bar<bool>(0) }\n                                    ^\n\")\n\ntest(\"\ndef foo<T>(x T) {}\ndef main { foo<int> }\n\", \"\n<stdin>:2:12: error: The function \\\"foo\\\" takes 1 argument and must be called\ndef main { foo<int> }\n           ~~~\n\")\n\n# Make sure overload filtering takes into account lambda arity\ntest(\"\nclass Foo {\n  def foo(arg fn(int))\n  def foo(arg fn())\n  def bar(arg fn(int))\n  def baz(arg fn())\n}\n\ndef main(foo Foo) {\n  foo.foo(x => {})\n  foo.foo(=> {})\n  foo.bar(x => {})\n  foo.bar(=> {})\n  foo.baz(x => {})\n  foo.baz(=> {})\n}\n\", \"\n<stdin>:12:11: error: Cannot convert from type \\\"fn()\\\" to type \\\"fn(int)\\\"\n  foo.bar(=> {})\n          ~~~~~\n<stdin>:13:11: error: Unable to determine the type of \\\"x\\\"\n  foo.baz(x => {})\n          ^\n<stdin>:13:11: error: Cannot convert from type \\\"fn(dynamic)\\\" to type \\\"fn()\\\"\n  foo.baz(x => {})\n          ~~~~~~~\n\")\n\n# Make sure type context is propagated from implicit \"self\" references\ntest(\"\nclass Foo<T> {\n  def foo(arg T)\n}\n\nclass Bar : Foo<int> {\n  def bar {\n    foo(false)\n    self.foo(false)\n  }\n}\n\", \"\n<stdin>:7:9: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n    foo(false)\n        ~~~~~\n<stdin>:8:14: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n    self.foo(false)\n             ~~~~~\n\")\n\n# Check for a crash when initializing an overloaded function\ntest(\"\nclass Baz : Bar {\n}\n\nclass Foo {\n  def foo bool\n}\n\nclass Bar : Foo {\n  over foo bool {\n    return 0\n  }\n}\n\", \"\n<stdin>:10:12: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    return 0\n           ^\n\")\n\n# Check for a crash when initializing an overloaded function\ntest(\"\nclass Baz : Bar {\n}\n\nclass Bar : Foo {\n  over foo bool {\n    return 0\n  }\n}\n\nclass Foo {\n  def foo bool\n}\n\", \"\n<stdin>:6:12: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    return 0\n           ^\n\")\n\n# Check for suspicious assignment warnings\ntest(\"\nclass Foo {\n  var z int\n}\n\ndef foo Foo {\n  return null\n}\n\ndef main(x int, y Foo) {\n  x = x\n  y.z = y.z\n  foo.z = foo.z\n}\n\", \"\n<stdin>:10:3: warning: Both sides of \\\"=\\\" are identical, is this a bug?\n  x = x\n  ~~~~~\n<stdin>:11:3: warning: Both sides of \\\"=\\\" are identical, is this a bug?\n  y.z = y.z\n  ~~~~~~~~~\n\")\n\n# Check for suspicious assignment placement warnings\ntest(\"\ndef main(x dynamic, y dynamic) dynamic {\n  var d1 dynamic = x = 1\n  var d2 dynamic = x = false\n  var d3 dynamic = x = y\n\n  var b1 bool = x = 1\n  var b2 bool = x = false\n  var b3 bool = x = y\n\n  var i1 int = x = 1\n  var i2 int = x = false\n  var i3 int = x = y\n\n  if x = 1 {}\n  if x = false {}\n  if x = y {}\n\n  if !(x = 1) {}\n  if !(x = false) {}\n  if !(x = y) {}\n\n  if (x = 1) || (x = 2) {}\n  if (x = true) || (x = false) {}\n  if (x = y) || (y = x) {}\n\n  while x = 1 {}\n  while x = false {}\n  while x = y {}\n\n  x = (x = 1) ? x = 0 : x = 1\n  x = (x = false) ? x = 0 : x = 1\n  x = (x = y) ? x = 0 : x = 1\n\n  x = y = 1\n  x = y = true\n  x = y = x\n\n  return x = 1\n  return x = true\n  return x = y\n\n  return x++\n  return ++x\n\n  (=> x = 1)()\n  (=> x = true)()\n  (=> x = y)()\n}\n\", \"\n<stdin>:6:19: warning: Use of \\\"=\\\" here looks like a bug, did you mean to use \\\"==\\\"?\n  var b1 bool = x = 1\n                  ^\n<stdin>:11:18: warning: Use of \\\"=\\\" here looks like a bug, did you mean to use \\\"==\\\"?\n  var i2 int = x = false\n                 ^\n<stdin>:14:8: warning: Use of \\\"=\\\" here looks like a bug, did you mean to use \\\"==\\\"?\n  if x = 1 {}\n       ^\n<stdin>:15:8: warning: Use of \\\"=\\\" here looks like a bug, did you mean to use \\\"==\\\"?\n  if x = false {}\n       ^\n<stdin>:16:8: warning: Use of \\\"=\\\" here looks like a bug, did you mean to use \\\"==\\\"?\n  if x = y {}\n       ^\n<stdin>:18:10: warning: Use of \\\"=\\\" here looks like a bug, did you mean to use \\\"==\\\"?\n  if !(x = 1) {}\n         ^\n<stdin>:19:10: warning: Use of \\\"=\\\" here looks like a bug, did you mean to use \\\"==\\\"?\n  if !(x = false) {}\n         ^\n<stdin>:20:10: warning: Use of \\\"=\\\" here looks like a bug, did you mean to use \\\"==\\\"?\n  if !(x = y) {}\n         ^\n<stdin>:22:9: warning: Use of \\\"=\\\" here looks like a bug, did you mean to use \\\"==\\\"?\n  if (x = 1) || (x = 2) {}\n        ^\n<stdin>:22:20: warning: Use of \\\"=\\\" here looks like a bug, did you mean to use \\\"==\\\"?\n  if (x = 1) || (x = 2) {}\n                   ^\n<stdin>:23:9: warning: Use of \\\"=\\\" here looks like a bug, did you mean to use \\\"==\\\"?\n  if (x = true) || (x = false) {}\n        ^\n<stdin>:23:23: warning: Use of \\\"=\\\" here looks like a bug, did you mean to use \\\"==\\\"?\n  if (x = true) || (x = false) {}\n                      ^\n<stdin>:24:9: warning: Use of \\\"=\\\" here looks like a bug, did you mean to use \\\"==\\\"?\n  if (x = y) || (y = x) {}\n        ^\n<stdin>:24:20: warning: Use of \\\"=\\\" here looks like a bug, did you mean to use \\\"==\\\"?\n  if (x = y) || (y = x) {}\n                   ^\n<stdin>:26:11: warning: Use of \\\"=\\\" here looks like a bug, did you mean to use \\\"==\\\"?\n  while x = 1 {}\n          ^\n<stdin>:27:11: warning: Use of \\\"=\\\" here looks like a bug, did you mean to use \\\"==\\\"?\n  while x = false {}\n          ^\n<stdin>:28:11: warning: Use of \\\"=\\\" here looks like a bug, did you mean to use \\\"==\\\"?\n  while x = y {}\n          ^\n<stdin>:30:10: warning: Use of \\\"=\\\" here looks like a bug, did you mean to use \\\"==\\\"?\n  x = (x = 1) ? x = 0 : x = 1\n         ^\n<stdin>:31:10: warning: Use of \\\"=\\\" here looks like a bug, did you mean to use \\\"==\\\"?\n  x = (x = false) ? x = 0 : x = 1\n         ^\n<stdin>:32:10: warning: Use of \\\"=\\\" here looks like a bug, did you mean to use \\\"==\\\"?\n  x = (x = y) ? x = 0 : x = 1\n         ^\n<stdin>:38:12: warning: Use of \\\"=\\\" here looks like a bug, did you mean to use \\\"==\\\"?\n  return x = 1\n           ^\n<stdin>:39:12: warning: Use of \\\"=\\\" here looks like a bug, did you mean to use \\\"==\\\"?\n  return x = true\n           ^\n<stdin>:40:12: warning: Use of \\\"=\\\" here looks like a bug, did you mean to use \\\"==\\\"?\n  return x = y\n           ^\n<stdin>:2:7: warning: Local variable \\\"d1\\\" is never read\n  var d1 dynamic = x = 1\n      ~~\n<stdin>:3:7: warning: Local variable \\\"d2\\\" is never read\n  var d2 dynamic = x = false\n      ~~\n<stdin>:4:7: warning: Local variable \\\"d3\\\" is never read\n  var d3 dynamic = x = y\n      ~~\n<stdin>:6:7: warning: Local variable \\\"b1\\\" is never read\n  var b1 bool = x = 1\n      ~~\n<stdin>:7:7: warning: Local variable \\\"b2\\\" is never read\n  var b2 bool = x = false\n      ~~\n<stdin>:8:7: warning: Local variable \\\"b3\\\" is never read\n  var b3 bool = x = y\n      ~~\n<stdin>:10:7: warning: Local variable \\\"i1\\\" is never read\n  var i1 int = x = 1\n      ~~\n<stdin>:11:7: warning: Local variable \\\"i2\\\" is never read\n  var i2 int = x = false\n      ~~\n<stdin>:12:7: warning: Local variable \\\"i3\\\" is never read\n  var i3 int = x = y\n      ~~\n\")\n\n# Check math functions with dynamic inputs, overloads shouldn't be ambiguous\ntest(\"\ndef main(x dynamic, y dynamic) {\n  Math.abs(x)\n  Math.acos(x)\n  Math.asin(x)\n  Math.atan(x)\n  Math.atan2(x, y)\n  Math.ceil(x)\n  Math.cos(x)\n  Math.exp(x)\n  Math.floor(x)\n  Math.log(x)\n  Math.max(x, y)\n  Math.min(x, y)\n  Math.pow(x, y)\n  Math.round(x)\n  Math.sin(x)\n  Math.sqrt(x)\n  Math.tan(x)\n}\n\", \"\n\")\n\n# Check storage with dynamic variables\ntest(\"\ndef main(x dynamic, y string, z int) {\n  x = x\n  x += x\n  x[0] += z\n  x++\n  ++x\n  y = y\n  y += y\n  y[0] += z\n  z++\n  ++z\n}\n\", \"\n<stdin>:2:3: warning: Both sides of \\\"=\\\" are identical, is this a bug?\n  x = x\n  ~~~~~\n<stdin>:7:3: warning: Both sides of \\\"=\\\" are identical, is this a bug?\n  y = y\n  ~~~~~\n<stdin>:9:3: error: Cannot store to this location\n  y[0] += z\n  ~~~~\n\")\n\n# Check setter scope lookup\ntest(\"\nclass Foo {\n  var foo = 0\n  var bar = 0\n  def test {\n    foo = false\n    bar = false\n  }\n}\n\ndef foo=(x string) {}\ndef bar double { return 0 }\ndef bar=(x string) {}\n\nvar _foo = 0\nvar _bar = 0\n\nclass Bar {\n  def test {\n    foo = false\n    bar = false\n    _foo = false\n    _bar = false\n  }\n\n  def _foo=(x string) {}\n  def _bar double { return 0 }\n  def _bar=(x string) {}\n}\n\nclass Baz : Bar {\n  over test {\n    _foo = false\n    _bar = false\n  }\n}\n\", \"\n<stdin>:5:11: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n    foo = false\n          ~~~~~\n<stdin>:6:11: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n    bar = false\n          ~~~~~\n<stdin>:19:11: error: Cannot convert from type \\\"bool\\\" to type \\\"string\\\"\n    foo = false\n          ~~~~~\n<stdin>:20:11: error: Cannot convert from type \\\"bool\\\" to type \\\"string\\\"\n    bar = false\n          ~~~~~\n<stdin>:21:12: error: Cannot convert from type \\\"bool\\\" to type \\\"string\\\"\n    _foo = false\n           ~~~~~\n<stdin>:22:12: error: Cannot convert from type \\\"bool\\\" to type \\\"string\\\"\n    _bar = false\n           ~~~~~\n<stdin>:32:12: error: Cannot convert from type \\\"bool\\\" to type \\\"string\\\"\n    _foo = false\n           ~~~~~\n<stdin>:33:12: error: Cannot convert from type \\\"bool\\\" to type \\\"string\\\"\n    _bar = false\n           ~~~~~\n\")\n\n# Forbid default values in function arguments\ntest(\"\ndef foo(x bool = true) {}\n\", \"\n<stdin>:1:16: error: Optional arguments aren't supported yet\ndef foo(x bool = true) {}\n               ~~~~~~\n\")\n\n# Forbid default values in function arguments\ntest(\"\nvar foo = (x bool = true) => {}\n\", \"\n<stdin>:1:19: error: Optional arguments aren't supported yet\nvar foo = (x bool = true) => {}\n                  ~~~~~~\n\")\n\n# Merging shouldn't be allowed between enums and flags\ntest(\"\nenum Foo { A, B }\nflags Foo { C, D }\nflags Bar { A, B }\nenum Bar { C, D }\n\", \"\n<stdin>:2:7: error: \\\"Foo\\\" is already declared\nflags Foo { C, D }\n      ~~~\n<stdin>:1:6: note: The previous declaration is here\nenum Foo { A, B }\n     ~~~\n<stdin>:4:6: error: \\\"Bar\\\" is already declared\nenum Bar { C, D }\n     ~~~\n<stdin>:3:7: note: The previous declaration is here\nflags Bar { A, B }\n      ~~~\n\")\n\n# Check for bugs with symbol merging and generics\ntest(\"\nclass Foo<X> {\n  def foo<Y>(cb fn(X, Y) Y) Foo<Y>\n  def foo<Z>(cb fn(X, Z) Z) Foo<Z>\n}\n\ndef main(x Foo<int>) {\n  x.foo<bool>((x, y) => x)\n}\n\", \"\n<stdin>:7:25: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n  x.foo<bool>((x, y) => x)\n                        ^\n\")\n\n# Check for bugs with symbol merging and generics\ntest(\"\nclass Foo<X> {\n  def foo<Y>(x Y)\n  def foo<Z>(x Z) Foo<Z>\n\n  def bar<Y>(x Y) Foo<Y>\n  def bar<Z>(x Z)\n}\n\", \"\n<stdin>:3:7: error: Duplicate overloaded function \\\"foo\\\"\n  def foo<Z>(x Z) Foo<Z>\n      ~~~\n<stdin>:2:7: note: The previous declaration is here\n  def foo<Y>(x Y)\n      ~~~\n<stdin>:6:7: error: Duplicate overloaded function \\\"bar\\\"\n  def bar<Z>(x Z)\n      ~~~\n<stdin>:5:7: note: The previous declaration is here\n  def bar<Y>(x Y) Foo<Y>\n      ~~~\n\")\n\n# Test storage check for auto-implemented operators\ntest(\"\n@import\nclass Foo {\n  def *(x int) Foo\n  def foo Foo\n}\n\ndef main(foo Foo) {\n  foo.foo *= 2\n}\n\", \"\n<stdin>:8:3: error: Cannot store to this location\n  foo.foo *= 2\n  ~~~~~~~\n\")\n\n# Test storage check for auto-implemented operators\ntest(\"\n@import\nclass Foo {\n  def new\n  def *(x int) Foo\n}\n\ndef main {\n  const foo = Foo.new\n  foo *= 2\n}\n\", \"\n<stdin>:9:3: error: Cannot store to constant symbol \\\"foo\\\"\n  foo *= 2\n  ~~~\n<stdin>:8:9: warning: Local variable \\\"foo\\\" is never read\n  const foo = Foo.new\n        ~~~\n\")\n\n# Test auto-implemented index operator\ntest(\"\n@import\nclass Foo {\n}\n\ndef main(foo Foo) {\n  foo[0] *= 2\n}\n\", \"\n<stdin>:6:6: error: \\\"[]\\\" is not declared on type \\\"Foo\\\"\n  foo[0] *= 2\n     ~~~\n\")\n\n# Test auto-implemented index operator\ntest(\"\n@import\nclass Foo {\n  def [](x int) int\n}\n\ndef main(foo Foo) {\n  foo[0] *= 2\n}\n\", \"\n<stdin>:7:3: error: Cannot store to this location\n  foo[0] *= 2\n  ~~~~~~\n\")\n\n# Test auto-implemented index operator\ntest(\"\n@import\nclass Foo {\n  def *(x int) int\n  def [](x int) Foo\n  def []=(x int, y bool)\n}\n\ndef main(foo Foo) {\n  foo[0] *= 2\n}\n\", \"\n<stdin>:9:3: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n  foo[0] *= 2\n  ~~~~~~~~~~~\n\")\n\n# Test auto-implemented index operator\ntest(\"\n@import\nclass Foo {\n  def *(x int)\n  def [](x int) Foo\n  def []=(x int, y bool)\n}\n\ndef main(foo Foo) {\n  foo[0] *= 2\n}\n\", \"\n<stdin>:9:3: error: The function \\\"*\\\" does not return a value\n  foo[0] *= 2\n  ~~~~~~~~~~~\n<stdin>:3:7: note: The function declaration is here\n  def *(x int)\n      ^\n\")\n\n# Test auto-implemented unary assignment operators\ntest(\"\nclass Foo {\n  def +(x int) bool\n  def -(x int) string\n}\n\nclass Bar {\n  def +(x bool) Bar\n  def -(x string) Bar\n}\n\ndef main(foo Foo, bar Bar) {\n  foo++\n  foo--\n  bar++\n  bar--\n}\n\", \"\n<stdin>:12:3: error: Cannot convert from type \\\"bool\\\" to type \\\"Foo\\\"\n  foo++\n  ~~~~~\n<stdin>:13:3: error: Cannot convert from type \\\"string\\\" to type \\\"Foo\\\"\n  foo--\n  ~~~~~\n<stdin>:14:6: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n  bar++\n     ~~\n<stdin>:15:6: error: Cannot convert from type \\\"int\\\" to type \\\"string\\\"\n  bar--\n     ~~\n\")\n\n# Test that assignment operators don't trigger \"local variable is never read\" warnings\ntest(\"\nclass Foo {\n}\n\ndef test {\n  var a = Foo.new\n  var b = Foo.new\n  a = null\n  a = b = null\n}\n\", \"\n<stdin>:5:7: warning: Local variable \\\"a\\\" is never read\n  var a = Foo.new\n      ^\n\")\n\n# Test that auto-implemented assignment operators don't trigger \"local variable is never read\" warnings\ntest(\"\nclass Foo {\n  def +(x int) Foo { return self }\n}\n\ndef test {\n  var a = Foo.new\n  var b = Foo.new\n  a += 1\n  a = b += 1\n}\n\", \"\n<stdin>:6:7: warning: Local variable \\\"a\\\" is never read\n  var a = Foo.new\n      ^\n\")\n\n# Test the null join operator on primitive types\ntest(\"\ndef main(foo int) {\n  foo = foo ?? 0\n}\n\", \"\n<stdin>:2:9: error: No common type for \\\"int\\\" and \\\"null\\\"\n  foo = foo ?? 0\n        ~~~\n\")\n\n# Test the null join operator\ntest(\"\nclass Foo {\n}\n\ndef main(foo Foo) Foo {\n  return foo ?? Foo.new\n}\n\", \"\n\")\n\n# Test type context for the null join operator\ntest(\"\nclass Foo {\n}\n\ndef main(foo Foo) int {\n  return foo ?? Foo.new\n}\n\", \"\n<stdin>:5:10: error: Cannot convert from type \\\"Foo\\\" to type \\\"int\\\"\n  return foo ?? Foo.new\n         ~~~\n<stdin>:5:17: error: Cannot convert from type \\\"Foo\\\" to type \\\"int\\\"\n  return foo ?? Foo.new\n                ~~~~~~~\n\")\n\n# Test warnings for the null join operator\ntest(\"\nclass Foo {\n  var x Foo = null\n}\n\ndef main(foo Foo) {\n  foo ?? foo\n  foo ?? foo.x\n  foo.x ?? foo\n  foo.x ?? foo.x\n}\n\", \"\n<stdin>:6:3: warning: Both sides of \\\"??\\\" are identical, is this a bug?\n  foo ?? foo\n  ~~~~~~~~~~\n<stdin>:6:3: warning: Unused expression\n  foo ?? foo\n  ~~~\n<stdin>:6:10: warning: Unused expression\n  foo ?? foo\n         ~~~\n<stdin>:7:3: warning: Unused expression\n  foo ?? foo.x\n  ~~~\n<stdin>:7:10: warning: Unused expression\n  foo ?? foo.x\n         ~~~~~\n<stdin>:8:3: warning: Unused expression\n  foo.x ?? foo\n  ~~~~~\n<stdin>:8:12: warning: Unused expression\n  foo.x ?? foo\n           ~~~\n<stdin>:9:3: warning: Both sides of \\\"??\\\" are identical, is this a bug?\n  foo.x ?? foo.x\n  ~~~~~~~~~~~~~~\n<stdin>:9:3: warning: Unused expression\n  foo.x ?? foo.x\n  ~~~~~\n<stdin>:9:12: warning: Unused expression\n  foo.x ?? foo.x\n           ~~~~~\n\")\n\n# Test warnings for the null dot operator\ntest(\"\nclass Foo {\n  var a Foo = null\n  def b Foo { return self }\n  def d(x int) Foo { return self }\n  var c fn() Foo = => null\n}\n\ndef main(foo Foo) {\n  foo?.a?.a\n  foo?.b?.b\n  foo?.c()?.c()\n  foo?.d(0)?.d(0)\n}\n\", \"\n<stdin>:9:3: warning: Unused expression\n  foo?.a?.a\n  ~~~~~~~~~\n\")\n\n# Test warnings for the null assignment operator\ntest(\"\nclass Foo {\n  var x Foo = null\n}\n\ndef main(foo Foo) {\n  foo ?= foo\n  foo ?= foo.x\n  foo.x ?= foo\n  foo.x ?= foo.x\n\n  main(foo ?= foo)\n  main(foo ?= foo.x)\n  main(foo.x ?= foo)\n  main(foo.x ?= foo.x)\n}\n\", \"\n<stdin>:6:3: warning: Both sides of \\\"?=\\\" are identical, is this a bug?\n  foo ?= foo\n  ~~~~~~~~~~\n<stdin>:9:3: warning: Both sides of \\\"?=\\\" are identical, is this a bug?\n  foo.x ?= foo.x\n  ~~~~~~~~~~~~~~\n<stdin>:11:8: warning: Both sides of \\\"?=\\\" are identical, is this a bug?\n  main(foo ?= foo)\n       ~~~~~~~~~~\n<stdin>:14:8: warning: Both sides of \\\"?=\\\" are identical, is this a bug?\n  main(foo.x ?= foo.x)\n       ~~~~~~~~~~~~~~\n\")\n\n# Test top-level use of the null dot operator\ntest(\"\nclass Foo {\n  def foo {}\n  def bar int { return 0 }\n  def baz string { return null }\n}\n\ndef main(foo Foo) {\n  foo?.foo\n  foo?.bar\n  foo?.baz\n}\n\", \"\n\")\n\n# Test unary increment operators on strings\ntest(\"\ndef main {\n  var x = \\\"x\\\"\n  x[0]++\n  x[0]--\n  ++x[0]\n  --x[0]\n}\n\", \"\n<stdin>:3:3: error: Cannot store to this location\n  x[0]++\n  ~~~~\n<stdin>:4:3: error: Cannot store to this location\n  x[0]--\n  ~~~~\n<stdin>:5:5: error: Cannot store to this location\n  ++x[0]\n    ~~~~\n<stdin>:6:5: error: Cannot store to this location\n  --x[0]\n    ~~~~\n\")\n\n# Test null assignment operator\ntest(\"\nclass Foo {\n}\n\ndef foo Foo {\n  return Foo.new\n}\n\ndef main {\n  foo ?= foo\n  var bar = foo ?= foo\n}\n\", \"\n<stdin>:9:3: error: Cannot store to this location\n  foo ?= foo\n  ~~~\n<stdin>:10:13: error: Cannot store to this location\n  var bar = foo ?= foo\n            ~~~\n<stdin>:10:7: warning: Local variable \\\"bar\\\" is never read\n  var bar = foo ?= foo\n      ~~~\n\")\n\n# Test string interpolation on different types\ntest(\"\nclass NoToString {}\nclass WrongToString { def toString NoToString { return null } }\nclass CorrectToString { def toString string { return null } }\n\nvar x = \\\"\\\\(NoToString.new)\\\"\nvar y = \\\"\\\\(WrongToString.new)\\\"\nvar z = \\\"\\\\(CorrectToString.new)\\\"\n\", \"\n<stdin>:5:12: error: \\\"toString\\\" is not declared on type \\\"NoToString\\\"\nvar x = \\\"\\\\(NoToString.new)\\\"\n           ~~~~~~~~~~~~~~\n<stdin>:6:12: error: Cannot convert from type \\\"NoToString\\\" to type \\\"string\\\"\nvar y = \\\"\\\\(WrongToString.new)\\\"\n           ~~~~~~~~~~~~~~~~~\n\")\n\n# Test error messages about forbidden operator customizations\ntest(\"\nclass Foo {\n  def ==(x bool)\n  def !=(x bool)\n  def <(x bool)\n  def >(x bool)\n  def <=(x bool)\n  def >=(x bool)\n  def &&(x bool)\n  def ||(x bool)\n  def =(x bool)\n}\n\", \"\n<stdin>:2:7: error: The \\\"==\\\" operator is not customizable because that wouldn't work with generics, which are implemented with type erasure\n  def ==(x bool)\n      ~~\n<stdin>:3:7: error: The \\\"!=\\\" operator is not customizable because that wouldn't work with generics, which are implemented with type erasure\n  def !=(x bool)\n      ~~\n<stdin>:4:7: error: The \\\"<\\\" operator is not customizable because it's automatically implemented using the \\\"<=>\\\" operator (customize the \\\"<=>\\\" operator instead)\n  def <(x bool)\n      ^\n<stdin>:5:7: error: The \\\">\\\" operator is not customizable because it's automatically implemented using the \\\"<=>\\\" operator (customize the \\\"<=>\\\" operator instead)\n  def >(x bool)\n      ^\n<stdin>:6:7: error: The \\\"<=\\\" operator is not customizable because it's automatically implemented using the \\\"<=>\\\" operator (customize the \\\"<=>\\\" operator instead)\n  def <=(x bool)\n      ~~\n<stdin>:7:7: error: The \\\">=\\\" operator is not customizable because it's automatically implemented using the \\\"<=>\\\" operator (customize the \\\"<=>\\\" operator instead)\n  def >=(x bool)\n      ~~\n<stdin>:8:7: error: The \\\"&&\\\" operator is not customizable because of its special short-circuit evaluation behavior\n  def &&(x bool)\n      ~~\n<stdin>:9:7: error: The \\\"||\\\" operator is not customizable because of its special short-circuit evaluation behavior\n  def ||(x bool)\n      ~~\n<stdin>:10:7: error: The \\\"=\\\" operator is not customizable because value types are not supported by the language\n  def =(x bool)\n      ^\n\")\n\n# Test the argument count error for incorrect implicit calls\ntest(\"\nclass Foo {\n  def foo(x int)\n  def bar(x int)\n  def bar(x int) {}\n  def baz(x int)\n  def baz(x double) {}\n  def baz2(x int, y int, z int)\n  def baz2(x double, y double) {}\n  def baz3(x int, y int)\n  def baz3(x double, y double, z double) {}\n}\n\ndef main(foo Foo) {\n  foo.foo\n  foo.bar\n  foo.baz\n  foo.baz2\n  foo.baz3\n}\n\", \"\n<stdin>:14:7: error: The function \\\"foo\\\" takes 1 argument and must be called\n  foo.foo\n      ~~~\n<stdin>:15:7: error: The function \\\"bar\\\" takes 1 argument and must be called\n  foo.bar\n      ~~~\n<stdin>:16:7: error: The function \\\"baz\\\" takes 1 argument and must be called\n  foo.baz\n      ~~~\n<stdin>:17:7: error: The function \\\"baz2\\\" takes between 2 and 3 arguments and must be called\n  foo.baz2\n      ~~~~\n<stdin>:18:7: error: The function \\\"baz3\\\" takes between 2 and 3 arguments and must be called\n  foo.baz3\n      ~~~~\n\")\n\n# Test XML literals\ntest(\"\nvar foo = <Foo/>\nvar foo2 = <Foo></Foo>\nvar bar = <Foo.Bar/>\nvar bar2 = <Foo.Bar></Foo.Bar>\nvar baz = <Foo.Baz/>\nvar baz2 = <Foo.Baz></Foo.Baz>\nvar i = <int/>\nvar nope = <Nope/>\n\nclass Foo {\n  class Bar {\n  }\n}\n\n@import\nvar Nope dynamic\n\", \"\n<stdin>:5:16: error: \\\"Baz\\\" is not declared on type \\\"Foo\\\", did you mean \\\"Bar\\\"?\nvar baz = <Foo.Baz/>\n               ~~~\n<stdin>:11:9: note: \\\"Bar\\\" is defined here\n  class Bar {\n        ~~~\n<stdin>:6:17: error: \\\"Baz\\\" is not declared on type \\\"Foo\\\", did you mean \\\"Bar\\\"?\nvar baz2 = <Foo.Baz></Foo.Baz>\n                ~~~\n<stdin>:11:9: note: \\\"Bar\\\" is defined here\n  class Bar {\n        ~~~\n<stdin>:7:9: error: Cannot construct type \\\"int\\\"\nvar i = <int/>\n        ~~~~~~\n<stdin>:8:12: error: Cannot construct type \\\"dynamic\\\"\nvar nope = <Nope/>\n           ~~~~~~~\n<stdin>:5:16: fix: Replace with \\\"Bar\\\"\nvar baz = <Foo.Baz/>\n               ~~~\n               [Bar]\n<stdin>:6:17: fix: Replace with \\\"Bar\\\"\nvar baz2 = <Foo.Baz></Foo.Baz>\n                ~~~\n                [Bar]\n\")\n\n# Test child element function error\ntest(\"\nvar foo = <Foo/>\nvar foo2 = <Foo>1</Foo>\nvar bar = <Bar/>\nvar bar2 = <Bar>1</Bar>\n\nclass Foo {\n}\n\nclass Bar {\n  def <>...</>(x int) {}\n}\n\", \"\n<stdin>:2:17: error: Implement a function called \\\"<>...</>\\\" on type \\\"Foo\\\" to add support for child elements\nvar foo2 = <Foo>1</Foo>\n                ^\n\")\n\n# Test XML literal return types\ntest(\"\nvar foo = <Foo/>.foo\nvar foo2 = <Foo></Foo>.foo\nvar foo3 = <Foo><Foo/></Foo>.foo\nvar foo4 = <Foo foo=1/>.foo\n\nclass Foo {\n  def <>...</>(x Foo) {}\n}\n\", \"\n<stdin>:1:18: error: \\\"foo\\\" is not declared on type \\\"Foo\\\"\nvar foo = <Foo/>.foo\n                 ~~~\n<stdin>:2:24: error: \\\"foo\\\" is not declared on type \\\"Foo\\\"\nvar foo2 = <Foo></Foo>.foo\n                       ~~~\n<stdin>:3:30: error: \\\"foo\\\" is not declared on type \\\"Foo\\\"\nvar foo3 = <Foo><Foo/></Foo>.foo\n                             ~~~\n<stdin>:4:17: error: \\\"foo\\\" is not declared on type \\\"Foo\\\"\nvar foo4 = <Foo foo=1/>.foo\n                ~~~\n<stdin>:4:25: error: \\\"foo\\\" is not declared on type \\\"Foo\\\"\nvar foo4 = <Foo foo=1/>.foo\n                        ~~~\n\")\n\n# Test multi-line XML literals\ntest(\"\nvar foo = <\nFoo/>\n\", \"\n<stdin>:1:12: error: Expected identifier but found newline\nvar foo = <\n           ^\n\")\n\n# Test multi-line XML literals\ntest(\"\nvar foo = <Foo></\nFoo>\n\", \"\n<stdin>:1:18: error: Expected identifier but found newline\nvar foo = <Foo></\n                 ^\n\")\n\n# Test multi-line XML literals\ntest(\"\nvar foo =\n  <Foo>\n    <Foo/>\n    <Foo>\n      <Foo\n      />\n    </Foo\n    >\n    <Foo/>\n  </Foo>\n\nclass Foo {\n  def <>...</>(x Foo) {}\n}\n\", \"\n\")\n\n# Test XML literal with child comment\ntest(\"\nvar foo =\n  <Foo>\n    null # Comment\n  </Foo>\n\", \"\n<stdin>:2:4: error: \\\"Foo\\\" is not declared\n  <Foo>\n   ~~~\n\")\n\n# Test XML literal with child comment\ntest(\"\nvar foo =\n  <Foo>\n    null\n    # Comment\n  </Foo>\n\", \"\n<stdin>:2:4: error: \\\"Foo\\\" is not declared\n  <Foo>\n   ~~~\n\")\n\n# Test XML literal with child comment\ntest(\"\nvar foo =\n  <Foo>\n    # Comment\n    null\n  </Foo>\n\", \"\n<stdin>:2:4: error: \\\"Foo\\\" is not declared\n  <Foo>\n   ~~~\n\")\n\n# Test XML children precedence\ntest(\"\nvar foo =\n  <Foo>\n    <Foo>bar</Foo>\n    <Foo>bar.bar</Foo>\n    <Foo>++bar</Foo>\n    <Foo>bar++</Foo>\n    <Foo>bar + bar</Foo>\n    <Foo>(bar + bar)</Foo>\n    <Foo>\n      bar\n      +bar # This is the second of two expressions, not a single expression\n    </Foo>\n    <Foo>if true { bar + bar }</Foo>\n  </Foo>\nvar bar = 0\n\nclass Foo {\n  def <>...</>(x Foo) {}\n}\n\", \"\n<stdin>:8:10: warning: Unnecessary parentheses\n    <Foo>(bar + bar)</Foo>\n         ~~~~~~~~~~~\n<stdin>:3:10: error: Cannot convert from type \\\"int\\\" to type \\\"Foo\\\"\n    <Foo>bar</Foo>\n         ~~~\n<stdin>:4:14: error: \\\"bar\\\" is not declared on type \\\"int\\\"\n    <Foo>bar.bar</Foo>\n             ~~~\n<stdin>:5:10: error: Cannot convert from type \\\"int\\\" to type \\\"Foo\\\"\n    <Foo>++bar</Foo>\n         ~~~~~\n<stdin>:6:10: error: Cannot convert from type \\\"int\\\" to type \\\"Foo\\\"\n    <Foo>bar++</Foo>\n         ~~~~~\n<stdin>:7:10: error: Cannot convert from type \\\"int\\\" to type \\\"Foo\\\"\n    <Foo>bar + bar</Foo>\n         ~~~~~~~~~\n<stdin>:8:10: error: Cannot convert from type \\\"int\\\" to type \\\"Foo\\\"\n    <Foo>(bar + bar)</Foo>\n         ~~~~~~~~~~~\n<stdin>:10:7: error: Cannot convert from type \\\"int\\\" to type \\\"Foo\\\"\n      bar\n      ~~~\n<stdin>:11:7: error: Cannot convert from type \\\"int\\\" to type \\\"Foo\\\"\n      +bar # This is the second of two expressions, not a single expression\n      ~~~~\n<stdin>:13:20: error: Cannot convert from type \\\"int\\\" to type \\\"Foo\\\"\n    <Foo>if true { bar + bar }</Foo>\n                   ~~~~~~~~~\n<stdin>:8:10: fix: Remove parentheses\n    <Foo>(bar + bar)</Foo>\n         ~~~~~~~~~~~\n         [ bar + bar ]\n\")\n\n# Test XML nested children\ntest(\"\nvar foo =\n  <Foo>\n    if true { 0 }\n    else if true { 1 }\n    else { 2 }\n    for i = 0; i < 5; i++ {\n      i\n    }\n    for i in [0, 1, 2, 3, 4] {\n      i\n    }\n    for i in 0..5 {\n      i\n    }\n    while Math.random < 0.5 {\n      0\n    }\n    switch (Math.random * 3) as int {\n      case 0 { 0 }\n      case 1, 2 { 1 }\n      default { 2 }\n    }\n    try { 0 }\n    catch e dynamic { 1 }\n    finally { 2 }\n    (=> { 0 })()\n  </Foo>\n\nclass Foo {\n  def <>...</>(x bool) {}\n}\n\", \"\n<stdin>:3:15: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    if true { 0 }\n              ^\n<stdin>:4:20: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    else if true { 1 }\n                   ^\n<stdin>:5:12: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    else { 2 }\n           ^\n<stdin>:7:7: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n      i\n      ^\n<stdin>:10:7: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n      i\n      ^\n<stdin>:13:7: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n      i\n      ^\n<stdin>:16:7: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n      0\n      ^\n<stdin>:19:16: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n      case 0 { 0 }\n               ^\n<stdin>:20:19: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n      case 1, 2 { 1 }\n                  ^\n<stdin>:21:17: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n      default { 2 }\n                ^\n<stdin>:23:11: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    try { 0 }\n          ^\n<stdin>:24:23: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    catch e dynamic { 1 }\n                      ^\n<stdin>:25:15: error: Cannot convert from type \\\"int\\\" to type \\\"bool\\\" without a cast\n    finally { 2 }\n              ^\n<stdin>:26:11: warning: Unused expression\n    (=> { 0 })()\n          ^\n<stdin>:26:6: error: All control paths for \\\"<lambda>\\\" must return a value of type \\\"bool\\\"\n    (=> { 0 })()\n     ~~~~~~~~\n\")\n\n# Test XML attribute type checking\ntest(\"\nvar foo = <Foo\n  foo=false\n  bar=false\n  baz=false\n  nope=0\n  foo=0\n  bar=.BAR\n  baz=0\n/>\n\nclass Foo {\n  var foo = 0\n  var bar Bar = .FOO\n  def baz=(x int) {}\n}\n\nenum Bar {\n  FOO\n  BAR\n}\n\", \"\n<stdin>:2:7: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n  foo=false\n      ~~~~~\n<stdin>:3:7: error: Cannot convert from type \\\"bool\\\" to type \\\"Bar\\\"\n  bar=false\n      ~~~~~\n<stdin>:4:7: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n  baz=false\n      ~~~~~\n<stdin>:5:3: error: \\\"nope\\\" is not declared on type \\\"Foo\\\"\n  nope=0\n  ~~~~\n\")\n\n# Test complex XML-like attributes\ntest(\"\nvar foo = <Foo\n  foo.bar=100\n  baz+=false\n/>\n\nclass Foo {\n  var foo Foo = null\n  var bar Foo = null\n  var baz = 0\n}\n\", \"\n<stdin>:2:11: error: Cannot convert from type \\\"int\\\" to type \\\"Foo\\\"\n  foo.bar=100\n          ~~~\n<stdin>:3:8: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n  baz+=false\n       ~~~~~\n\")\n\n# Check that comments are allowed in different places in a call expression\ntest(\"\ndef main {\n  foo(\n    # 1\n    2,\n    # 3\n    4\n    # 5\n    , 6\n    # 7\n  )\n}\n\", \"\n<stdin>:2:3: error: \\\"foo\\\" is not declared\n  foo(\n  ~~~\n\")\n\n# Check return statements with a newline between the keyword and the value\ntest(\"\ndef foo int {\n  return\n  false\n}\n\ndef foo2 int {\n  return\n}\n\ndef bar {\n  return\n  false\n}\n\ndef bar2 {\n  return\n}\n\", \"\n<stdin>:3:3: error: Cannot convert from type \\\"bool\\\" to type \\\"int\\\" without a cast\n  false\n  ~~~~~\n<stdin>:7:3: error: Must return a value of type \\\"int\\\"\n  return\n  ~~~~~~\n<stdin>:12:3: warning: Unused expression\n  false\n  ~~~~~\n\")\n\n# Check parsing of contextual keywords\ntest(\"\nclass Foo {\n  var class = 0\n  var def = 0\n  var enum = 0\n  var interface = 0\n  var namespace = 0\n  var over = 0\n}\n\nvar foo = <Foo\n  class=1\n  def=1\n  enum=1\n  interface=1\n  namespace=1\n  over=1\n/>\n\ndef bar {\n  var class = 2\n  var def = 2\n  var enum = 2\n  var interface = 2\n  var namespace = 2\n  var over = 2\n\n  class = 3\n  def = 3\n  enum = 3\n  interface = 3\n  namespace = 3\n  over = 3\n}\n\", \"\n<stdin>:20:7: warning: Local variable \\\"class\\\" is never read\n  var class = 2\n      ~~~~~\n<stdin>:21:7: warning: Local variable \\\"def\\\" is never read\n  var def = 2\n      ~~~\n<stdin>:22:7: warning: Local variable \\\"enum\\\" is never read\n  var enum = 2\n      ~~~~\n<stdin>:23:7: warning: Local variable \\\"interface\\\" is never read\n  var interface = 2\n      ~~~~~~~~~\n<stdin>:24:7: warning: Local variable \\\"namespace\\\" is never read\n  var namespace = 2\n      ~~~~~~~~~\n<stdin>:25:7: warning: Local variable \\\"over\\\" is never read\n  var over = 2\n      ~~~~\n\")\n\n# The keyword \"var\" is a token, not a contextual keyword\ntest(\"\nvar var = 0\n\", \"\n<stdin>:1:5: error: Expected identifier but found \\\"var\\\"\nvar var = 0\n    ~~~\n\")\n\n# The keyword \"const\" is a token, not a contextual keyword\ntest(\"\nvar const = 0\n\", \"\n<stdin>:1:5: error: Expected identifier but found \\\"const\\\"\nvar const = 0\n    ~~~~~\n\")\n\n# Check for flags overflow\ntest(\"\nflags Foo {\n  X0\n  X1\n  X2\n  X3\n  X4\n  X5\n  X6\n  X7\n  X8\n  X9\n\n  X10\n  X11\n  X12\n  X13\n  X14\n  X15\n  X16\n  X17\n  X18\n  X19\n\n  X20\n  X21\n  X22\n  X23\n  X24\n  X25\n  X26\n  X27\n  X28\n  X29\n\n  X30\n  X31\n  X32\n  X33\n}\n\nflags Bar {\n  X0\n  X1\n  X2\n  X3\n  X4\n  X5\n  X6\n  X7\n  X8\n  X9\n}\n\nflags Bar {\n  X10\n  X11\n  X12\n  X13\n  X14\n  X15\n  X16\n  X17\n  X18\n  X19\n}\n\nflags Bar {\n  X20\n  X21\n  X22\n  X23\n  X24\n  X25\n  X26\n  X27\n  X28\n  X29\n}\n\nflags Bar {\n  X30\n  X31\n  X32\n  X33\n}\n\", \"\n<stdin>:37:3: error: The type \\\"Foo\\\" cannot have more than 32 flags\n  X32\n  ~~~\n<stdin>:38:3: error: The type \\\"Foo\\\" cannot have more than 32 flags\n  X33\n  ~~~\n<stdin>:83:3: error: The type \\\"Bar\\\" cannot have more than 32 flags\n  X32\n  ~~~\n<stdin>:84:3: error: The type \\\"Bar\\\" cannot have more than 32 flags\n  X33\n  ~~~\n\")\n\n# Check for flags type conversions\ntest(\"\nflags Foo {\n  FOO\n  BAR\n}\n\n@export\ndef test List<Foo> {\n  var foo = Foo.FOO\n  foo |= 0\n  foo |= ~0\n  foo |= 1\n  foo |= .FOO\n  foo |= ~.FOO\n  foo &= ~.FOO\n  foo ^= ~.FOO\n  foo += ~.FOO\n  return [\n    0,\n    ~0,\n    1,\n    -1,\n    ~.FOO,\n    .FOO in Foo.BAR,\n    .FOO & .BAR,\n    .FOO | .BAR,\n    .FOO ^ .BAR,\n    foo |= ~.FOO,\n    foo &= ~.FOO,\n    foo ^= ~.FOO,\n    foo += ~.FOO,\n  ]\n}\n\", \"\n<stdin>:16:7: error: \\\"+=\\\" is not declared on type \\\"Foo\\\"\n  foo += ~.FOO\n      ~~\n<stdin>:16:11: error: Cannot access \\\"FOO\\\" without type context\n  foo += ~.FOO\n          ~~~~\n<stdin>:20:5: error: Cannot convert from type \\\"int\\\" to type \\\"Foo\\\" without a cast\n    1,\n    ^\n<stdin>:21:5: error: Cannot convert from type \\\"int\\\" to type \\\"Foo\\\" without a cast\n    -1,\n    ~~\n<stdin>:23:5: error: Cannot convert from type \\\"bool\\\" to type \\\"Foo\\\"\n    .FOO in Foo.BAR,\n    ~~~~~~~~~~~~~~~\n<stdin>:30:9: error: \\\"+=\\\" is not declared on type \\\"Foo\\\"\n    foo += ~.FOO,\n        ~~\n<stdin>:30:13: error: Cannot access \\\"FOO\\\" without type context\n    foo += ~.FOO,\n            ~~~~\n\")\n\n# Check for flags-style enum type conversions\ntest(\"\nenum Foo {\n  FOO\n  BAR\n}\n\n@export\ndef test List<Foo> {\n  var foo = Foo.FOO\n  foo |= 0\n  foo |= ~0\n  foo |= 1\n  foo |= .FOO\n  foo |= ~.FOO\n  foo &= ~.FOO\n  foo ^= ~.FOO\n  foo += ~.FOO\n  return [\n    0,\n    ~0,\n    1,\n    -1,\n    ~.FOO,\n    .FOO in Foo.BAR,\n    .FOO & .BAR,\n    .FOO | .BAR,\n    .FOO ^ .BAR,\n    foo |= ~.FOO,\n    foo &= ~.FOO,\n    foo ^= ~.FOO,\n    foo += ~.FOO,\n  ]\n}\n\", \"\n<stdin>:9:7: error: \\\"|=\\\" is not declared on type \\\"Foo\\\"\n  foo |= 0\n      ~~\n<stdin>:10:7: error: \\\"|=\\\" is not declared on type \\\"Foo\\\"\n  foo |= ~0\n      ~~\n<stdin>:11:7: error: \\\"|=\\\" is not declared on type \\\"Foo\\\"\n  foo |= 1\n      ~~\n<stdin>:12:7: error: \\\"|=\\\" is not declared on type \\\"Foo\\\"\n  foo |= .FOO\n      ~~\n<stdin>:12:10: error: Cannot access \\\"FOO\\\" without type context\n  foo |= .FOO\n         ~~~~\n<stdin>:13:7: error: \\\"|=\\\" is not declared on type \\\"Foo\\\"\n  foo |= ~.FOO\n      ~~\n<stdin>:13:11: error: Cannot access \\\"FOO\\\" without type context\n  foo |= ~.FOO\n          ~~~~\n<stdin>:14:7: error: \\\"&=\\\" is not declared on type \\\"Foo\\\"\n  foo &= ~.FOO\n      ~~\n<stdin>:14:11: error: Cannot access \\\"FOO\\\" without type context\n  foo &= ~.FOO\n          ~~~~\n<stdin>:15:7: error: \\\"^=\\\" is not declared on type \\\"Foo\\\"\n  foo ^= ~.FOO\n      ~~\n<stdin>:15:11: error: Cannot access \\\"FOO\\\" without type context\n  foo ^= ~.FOO\n          ~~~~\n<stdin>:16:7: error: \\\"+=\\\" is not declared on type \\\"Foo\\\"\n  foo += ~.FOO\n      ~~\n<stdin>:16:11: error: Cannot access \\\"FOO\\\" without type context\n  foo += ~.FOO\n          ~~~~\n<stdin>:18:5: error: Cannot convert from type \\\"int\\\" to type \\\"Foo\\\" without a cast\n    0,\n    ^\n<stdin>:19:5: error: Cannot convert from type \\\"int\\\" to type \\\"Foo\\\" without a cast\n    ~0,\n    ~~\n<stdin>:20:5: error: Cannot convert from type \\\"int\\\" to type \\\"Foo\\\" without a cast\n    1,\n    ^\n<stdin>:21:5: error: Cannot convert from type \\\"int\\\" to type \\\"Foo\\\" without a cast\n    -1,\n    ~~\n<stdin>:22:6: error: Cannot access \\\"FOO\\\" without type context\n    ~.FOO,\n     ~~~~\n<stdin>:23:5: error: Cannot access \\\"FOO\\\" without type context\n    .FOO in Foo.BAR,\n    ~~~~\n<stdin>:23:10: error: \\\"in\\\" is not declared on type \\\"Foo\\\"\n    .FOO in Foo.BAR,\n         ~~\n<stdin>:24:5: error: Cannot access \\\"FOO\\\" without type context\n    .FOO & .BAR,\n    ~~~~\n<stdin>:24:12: error: Cannot access \\\"BAR\\\" without type context\n    .FOO & .BAR,\n           ~~~~\n<stdin>:25:5: error: Cannot access \\\"FOO\\\" without type context\n    .FOO | .BAR,\n    ~~~~\n<stdin>:25:12: error: Cannot access \\\"BAR\\\" without type context\n    .FOO | .BAR,\n           ~~~~\n<stdin>:26:5: error: Cannot access \\\"FOO\\\" without type context\n    .FOO ^ .BAR,\n    ~~~~\n<stdin>:26:12: error: Cannot access \\\"BAR\\\" without type context\n    .FOO ^ .BAR,\n           ~~~~\n<stdin>:27:9: error: \\\"|=\\\" is not declared on type \\\"Foo\\\"\n    foo |= ~.FOO,\n        ~~\n<stdin>:27:13: error: Cannot access \\\"FOO\\\" without type context\n    foo |= ~.FOO,\n            ~~~~\n<stdin>:28:9: error: \\\"&=\\\" is not declared on type \\\"Foo\\\"\n    foo &= ~.FOO,\n        ~~\n<stdin>:28:13: error: Cannot access \\\"FOO\\\" without type context\n    foo &= ~.FOO,\n            ~~~~\n<stdin>:29:9: error: \\\"^=\\\" is not declared on type \\\"Foo\\\"\n    foo ^= ~.FOO,\n        ~~\n<stdin>:29:13: error: Cannot access \\\"FOO\\\" without type context\n    foo ^= ~.FOO,\n            ~~~~\n<stdin>:30:9: error: \\\"+=\\\" is not declared on type \\\"Foo\\\"\n    foo += ~.FOO,\n        ~~\n<stdin>:30:13: error: Cannot access \\\"FOO\\\" without type context\n    foo += ~.FOO,\n            ~~~~\n\")\n\n# Test for a crash due to a missing symbol initialization\ntest(\"\nnamespace Baz {\n  def test {\n    Bar.new\n  }\n}\n\nclass Bar :: Foo {\n  def foo\n  def bar\n}\n\ninterface Foo {\n  def foo\n  def bar\n}\n\", \"\n<stdin>:3:5: error: Cannot construct abstract type \\\"Bar\\\"\n    Bar.new\n    ~~~~~~~\n<stdin>:8:7: note: The type \\\"Bar\\\" is abstract due to member \\\"foo\\\"\n  def foo\n      ~~~\n\")\n\n# The null dot operator shouldn't require a value inside a lambda expression\ntest(\"\ndef test(x Foo, y Foo) {\n  x?.z\n  (=> x?.z)()\n  (() int => x?.z)()\n\n  x ?= y\n  (=> x ?= y)()\n  (() int => x ?= y)()\n}\n\nclass Foo {\n  def z {}\n}\n\", \"\n<stdin>:4:14: error: The function \\\"z\\\" does not return a value\n  (() int => x?.z)()\n             ~~~~\n<stdin>:12:7: note: The function declaration is here\n  def z {}\n      ^\n<stdin>:8:14: error: Cannot convert from type \\\"Foo\\\" to type \\\"int\\\"\n  (() int => x ?= y)()\n             ^\n<stdin>:8:14: error: Cannot convert from type \\\"Foo\\\" to type \\\"int\\\"\n  (() int => x ?= y)()\n             ~~~~~~\n\")\n\n# Check member typo corrections\ntest(\"\ndef test(x Foo) {\n  x.string\n  x.toStrong\n  x.tostring\n  x.to_string\n\n  x.to\n  x.blah\n  x.blong\n  x.tostr\n  x.toStr\n  x.to_str\n  x.bloblobloblob\n}\n\nclass Foo {\n  def toString string {\n    return \\\"\\\"\n  }\n}\n\", \"\n<stdin>:2:5: error: \\\"string\\\" is not declared on type \\\"Foo\\\", did you mean \\\"toString\\\"?\n  x.string\n    ~~~~~~\n<stdin>:17:7: note: \\\"toString\\\" is defined here\n  def toString string {\n      ~~~~~~~~\n<stdin>:3:5: error: \\\"toStrong\\\" is not declared on type \\\"Foo\\\", did you mean \\\"toString\\\"?\n  x.toStrong\n    ~~~~~~~~\n<stdin>:17:7: note: \\\"toString\\\" is defined here\n  def toString string {\n      ~~~~~~~~\n<stdin>:4:5: error: \\\"tostring\\\" is not declared on type \\\"Foo\\\", did you mean \\\"toString\\\"?\n  x.tostring\n    ~~~~~~~~\n<stdin>:17:7: note: \\\"toString\\\" is defined here\n  def toString string {\n      ~~~~~~~~\n<stdin>:5:5: error: \\\"to_string\\\" is not declared on type \\\"Foo\\\", did you mean \\\"toString\\\"?\n  x.to_string\n    ~~~~~~~~~\n<stdin>:17:7: note: \\\"toString\\\" is defined here\n  def toString string {\n      ~~~~~~~~\n<stdin>:7:5: error: \\\"to\\\" is not declared on type \\\"Foo\\\"\n  x.to\n    ~~\n<stdin>:8:5: error: \\\"blah\\\" is not declared on type \\\"Foo\\\"\n  x.blah\n    ~~~~\n<stdin>:9:5: error: \\\"blong\\\" is not declared on type \\\"Foo\\\"\n  x.blong\n    ~~~~~\n<stdin>:10:5: error: \\\"tostr\\\" is not declared on type \\\"Foo\\\"\n  x.tostr\n    ~~~~~\n<stdin>:11:5: error: \\\"toStr\\\" is not declared on type \\\"Foo\\\"\n  x.toStr\n    ~~~~~\n<stdin>:12:5: error: \\\"to_str\\\" is not declared on type \\\"Foo\\\"\n  x.to_str\n    ~~~~~~\n<stdin>:13:5: error: \\\"bloblobloblob\\\" is not declared on type \\\"Foo\\\"\n  x.bloblobloblob\n    ~~~~~~~~~~~~~\n<stdin>:2:5: fix: Replace with \\\"toString\\\"\n  x.string\n    ~~~~~~\n    [toString]\n<stdin>:3:5: fix: Replace with \\\"toString\\\"\n  x.toStrong\n    ~~~~~~~~\n    [toString]\n<stdin>:4:5: fix: Replace with \\\"toString\\\"\n  x.tostring\n    ~~~~~~~~\n    [toString]\n<stdin>:5:5: fix: Replace with \\\"toString\\\"\n  x.to_string\n    ~~~~~~~~~\n    [toString]\n\")\n\n# Avoid typo corrections for mismatched static/instance contexts\ntest(\"\ndef test(x Foo) {\n  x.bar\n  Foo.Foo\n}\n\nclass Foo {\n  var foo = 0\n\n  namespace Bar {\n  }\n}\n\", \"\n<stdin>:2:5: error: \\\"bar\\\" is not declared on type \\\"Foo\\\"\n  x.bar\n    ~~~\n<stdin>:3:7: error: \\\"Foo\\\" is not declared on type \\\"Foo\\\"\n  Foo.Foo\n      ~~~\n\")\n\n# Type corrections for global names from the derived class\ntest(\"\nclass Foo : Bar {\n  def test {\n    abc\n    xyz\n    abb\n    xyy\n  }\n}\n\nclass Bar {\n}\n\nnamespace Bar {\n  var abc int\n  def xyz {}\n}\n\", \"\n<stdin>:3:5: error: \\\"abc\\\" is not declared, did you mean \\\"Bar.abc\\\"?\n    abc\n    ~~~\n<stdin>:14:7: note: \\\"Bar.abc\\\" is defined here\n  var abc int\n      ~~~\n<stdin>:4:5: error: \\\"xyz\\\" is not declared, did you mean \\\"Bar.xyz\\\"?\n    xyz\n    ~~~\n<stdin>:15:7: note: \\\"Bar.xyz\\\" is defined here\n  def xyz {}\n      ~~~\n<stdin>:5:5: error: \\\"abb\\\" is not declared, did you mean \\\"Bar.abc\\\"?\n    abb\n    ~~~\n<stdin>:14:7: note: \\\"Bar.abc\\\" is defined here\n  var abc int\n      ~~~\n<stdin>:6:5: error: \\\"xyy\\\" is not declared, did you mean \\\"Bar.xyz\\\"?\n    xyy\n    ~~~\n<stdin>:15:7: note: \\\"Bar.xyz\\\" is defined here\n  def xyz {}\n      ~~~\n<stdin>:3:5: fix: Replace with \\\"Bar.abc\\\"\n    abc\n    ~~~\n    [Bar.abc]\n<stdin>:4:5: fix: Replace with \\\"Bar.xyz\\\"\n    xyz\n    ~~~\n    [Bar.xyz]\n<stdin>:5:5: fix: Replace with \\\"Bar.abc\\\"\n    abb\n    ~~~\n    [Bar.abc]\n<stdin>:6:5: fix: Replace with \\\"Bar.xyz\\\"\n    xyy\n    ~~~\n    [Bar.xyz]\n\")\n\n# Check name typo corrections\ntest(\"\nclass Foo {\n  def test {\n    var x Foot = Foot.new\n    var y tset # This shouldn't match because it's a type context\n    Foot\n    tset # This should match because this is an instance context\n  }\n}\n\nnamespace Foo {\n  def foo {\n    var x Foot = Foot.new\n    var y tset # This shouldn't match because it's a type context\n    Foot\n    tset # This shouldn't match because this isn't an instance context\n  }\n}\n\", \"\n<stdin>:3:11: error: \\\"Foot\\\" is not declared, did you mean \\\"Foo\\\"?\n    var x Foot = Foot.new\n          ~~~~\n<stdin>:1:7: note: \\\"Foo\\\" is defined here\nclass Foo {\n      ~~~\n<stdin>:3:18: error: \\\"Foot\\\" is not declared, did you mean \\\"Foo\\\"?\n    var x Foot = Foot.new\n                 ~~~~\n<stdin>:1:7: note: \\\"Foo\\\" is defined here\nclass Foo {\n      ~~~\n<stdin>:4:11: error: \\\"tset\\\" is not declared\n    var y tset # This shouldn't match because it's a type context\n          ~~~~\n<stdin>:5:5: error: \\\"Foot\\\" is not declared, did you mean \\\"Foo\\\"?\n    Foot\n    ~~~~\n<stdin>:1:7: note: \\\"Foo\\\" is defined here\nclass Foo {\n      ~~~\n<stdin>:6:5: error: \\\"tset\\\" is not declared, did you mean \\\"test\\\"?\n    tset # This should match because this is an instance context\n    ~~~~\n<stdin>:2:7: note: \\\"test\\\" is defined here\n  def test {\n      ~~~~\n<stdin>:12:11: error: \\\"Foot\\\" is not declared, did you mean \\\"Foo\\\"?\n    var x Foot = Foot.new\n          ~~~~\n<stdin>:1:7: note: \\\"Foo\\\" is defined here\nclass Foo {\n      ~~~\n<stdin>:12:18: error: \\\"Foot\\\" is not declared, did you mean \\\"Foo\\\"?\n    var x Foot = Foot.new\n                 ~~~~\n<stdin>:1:7: note: \\\"Foo\\\" is defined here\nclass Foo {\n      ~~~\n<stdin>:13:11: error: \\\"tset\\\" is not declared\n    var y tset # This shouldn't match because it's a type context\n          ~~~~\n<stdin>:14:5: error: \\\"Foot\\\" is not declared, did you mean \\\"Foo\\\"?\n    Foot\n    ~~~~\n<stdin>:1:7: note: \\\"Foo\\\" is defined here\nclass Foo {\n      ~~~\n<stdin>:15:5: error: \\\"tset\\\" is not declared\n    tset # This shouldn't match because this isn't an instance context\n    ~~~~\n<stdin>:3:9: warning: Local variable \\\"x\\\" is never read\n    var x Foot = Foot.new\n        ^\n<stdin>:4:9: warning: Local variable \\\"y\\\" is never read\n    var y tset # This shouldn't match because it's a type context\n        ^\n<stdin>:12:9: warning: Local variable \\\"x\\\" is never read\n    var x Foot = Foot.new\n        ^\n<stdin>:13:9: warning: Local variable \\\"y\\\" is never read\n    var y tset # This shouldn't match because it's a type context\n        ^\n<stdin>:3:11: fix: Replace with \\\"Foo\\\"\n    var x Foot = Foot.new\n          ~~~~\n          [Foo]\n<stdin>:3:18: fix: Replace with \\\"Foo\\\"\n    var x Foot = Foot.new\n                 ~~~~\n                 [Foo]\n<stdin>:5:5: fix: Replace with \\\"Foo\\\"\n    Foot\n    ~~~~\n    [Foo]\n<stdin>:6:5: fix: Replace with \\\"test\\\"\n    tset # This should match because this is an instance context\n    ~~~~\n    [test]\n<stdin>:12:11: fix: Replace with \\\"Foo\\\"\n    var x Foot = Foot.new\n          ~~~~\n          [Foo]\n<stdin>:12:18: fix: Replace with \\\"Foo\\\"\n    var x Foot = Foot.new\n                 ~~~~\n                 [Foo]\n<stdin>:14:5: fix: Replace with \\\"Foo\\\"\n    Foot\n    ~~~~\n    [Foo]\n\")\n\n# Type corrections shouldn't suggest symbols that are currently being initialized\ntest(\"\nvar foo = Bar\nvar bar = Bar\nvar fooo = Fooo\n\", \"\n<stdin>:1:11: error: \\\"Bar\\\" is not declared, did you mean \\\"bar\\\"?\nvar foo = Bar\n          ~~~\n<stdin>:2:5: note: \\\"bar\\\" is defined here\nvar bar = Bar\n    ~~~\n<stdin>:2:11: error: \\\"Bar\\\" is not declared\nvar bar = Bar\n          ~~~\n<stdin>:3:12: error: \\\"Fooo\\\" is not declared, did you mean \\\"foo\\\"?\nvar fooo = Fooo\n           ~~~~\n<stdin>:1:5: note: \\\"foo\\\" is defined here\nvar foo = Bar\n    ~~~\n<stdin>:1:11: fix: Replace with \\\"bar\\\"\nvar foo = Bar\n          ~~~\n          [bar]\n<stdin>:3:12: fix: Replace with \\\"foo\\\"\nvar fooo = Fooo\n           ~~~~\n           [foo]\n\")\n\n# Check case-sensitive typo corrections\ntest(\"\nvar Foo = 0\nvar FOo = 0\nvar bar = 0\nvar a = foo\nvar b = FOO\nvar c = fOO\nvar d = foO\nvar e = BAR\n\", \"\n<stdin>:4:9: error: \\\"foo\\\" is not declared, did you mean \\\"Foo\\\"?\nvar a = foo\n        ~~~\n<stdin>:1:5: note: \\\"Foo\\\" is defined here\nvar Foo = 0\n    ~~~\n<stdin>:5:9: error: \\\"FOO\\\" is not declared, did you mean \\\"FOo\\\"?\nvar b = FOO\n        ~~~\n<stdin>:2:5: note: \\\"FOo\\\" is defined here\nvar FOo = 0\n    ~~~\n<stdin>:6:9: error: \\\"fOO\\\" is not declared, did you mean \\\"FOo\\\"?\nvar c = fOO\n        ~~~\n<stdin>:2:5: note: \\\"FOo\\\" is defined here\nvar FOo = 0\n    ~~~\n<stdin>:7:9: error: \\\"foO\\\" is not declared, did you mean \\\"Foo\\\"?\nvar d = foO\n        ~~~\n<stdin>:1:5: note: \\\"Foo\\\" is defined here\nvar Foo = 0\n    ~~~\n<stdin>:8:9: error: \\\"BAR\\\" is not declared, did you mean \\\"bar\\\"?\nvar e = BAR\n        ~~~\n<stdin>:3:5: note: \\\"bar\\\" is defined here\nvar bar = 0\n    ~~~\n<stdin>:4:9: fix: Replace with \\\"Foo\\\"\nvar a = foo\n        ~~~\n        [Foo]\n<stdin>:5:9: fix: Replace with \\\"FOo\\\"\nvar b = FOO\n        ~~~\n        [FOo]\n<stdin>:6:9: fix: Replace with \\\"FOo\\\"\nvar c = fOO\n        ~~~\n        [FOo]\n<stdin>:7:9: fix: Replace with \\\"Foo\\\"\nvar d = foO\n        ~~~\n        [Foo]\n<stdin>:8:9: fix: Replace with \\\"bar\\\"\nvar e = BAR\n        ~~~\n        [bar]\n\")\n\n# Check the \"void\" correction\ntest(\"\ndef foo void {}\ndef bar(x int) void {}\n\", \"\n<stdin>:1:9: error: There is no explicit \\\"void\\\" return type (to indicate that there's nothing to return, just don't put a return type)\ndef foo void {}\n        ~~~~\n<stdin>:2:16: error: There is no explicit \\\"void\\\" return type (to indicate that there's nothing to return, just don't put a return type)\ndef bar(x int) void {}\n               ~~~~\n<stdin>:1:8: fix: Remove \\\"void\\\"\ndef foo void {}\n       ~~~~~\n       []\n<stdin>:2:15: fix: Remove \\\"void\\\"\ndef bar(x int) void {}\n              ~~~~~\n              []\n\")\n\n# Check the \"void\" correction\ntest(\"\nclass void {}\ndef foo void { return null }\ndef bar(x int) void { return null }\n\", \"\n\")\n\n# Check for type context with the \"??\" operator\ntest(\"\nclass Foo {}\n\nnamespace Foo {\n  const FOO = new\n}\n\ndef test(foo Foo) {\n  (foo ?? .FOO) + 2\n}\n\", \"\n<stdin>:8:17: error: \\\"+\\\" is not declared on type \\\"Foo\\\"\n  (foo ?? .FOO) + 2\n                ^\n\")\n\n# Abstract functions are only allowed on certain types\ntest(\"\nclass C { def foo }\nenum E { def foo }\nflags F { def foo }\ninterface I { def foo }\nnamespace N { def foo }\ntype T : int { def foo }\n\", \"\n<stdin>:2:14: error: Non-imported function \\\"foo\\\" is missing an implementation (use the \\\"@import\\\" annotation if it's implemented externally)\nenum E { def foo }\n             ~~~\n<stdin>:3:15: error: Non-imported function \\\"foo\\\" is missing an implementation (use the \\\"@import\\\" annotation if it's implemented externally)\nflags F { def foo }\n              ~~~\n<stdin>:5:19: error: Non-imported function \\\"foo\\\" is missing an implementation (use the \\\"@import\\\" annotation if it's implemented externally)\nnamespace N { def foo }\n                  ~~~\n<stdin>:6:20: error: Non-imported function \\\"foo\\\" is missing an implementation (use the \\\"@import\\\" annotation if it's implemented externally)\ntype T : int { def foo }\n                   ~~~\n\")\n\n# Forward-declaring a function should not count as abstract\ntest(\"\nclass C { def foo }\nenum E { def foo }\nflags F { def foo }\ninterface I { def foo }\nnamespace N { def foo }\ntype T : int { def foo }\n\nclass C { def foo {} }\nenum E { def foo {} }\nflags F { def foo {} }\ninterface I { def foo {} }\nnamespace N { def foo {} }\ntype T { def foo {} }\n\", \"\n\")\n\n# Forward-declaring a function should not count as abstract\ntest(\"\nclass C { def foo {} }\nenum E { def foo {} }\nflags F { def foo {} }\ninterface I { def foo {} }\nnamespace N { def foo {} }\ntype T : int { def foo {} }\n\nclass C { def foo }\nenum E { def foo }\nflags F { def foo }\ninterface I { def foo }\nnamespace N { def foo }\ntype T { def foo }\n\", \"\n\")\n\n# Warn on statement-level dynamic property access\ntest(\"\ndef test(foo dynamic) {\n  var bar = foo.bar\n  foo.bar\n  foo.bar = 1\n  foo.bar - 2\n}\n\", \"\n<stdin>:3:3: warning: Unused expression\n  foo.bar\n  ~~~~~~~\n<stdin>:2:7: warning: Local variable \\\"bar\\\" is never read\n  var bar = foo.bar\n      ~~~\n\")\n\n  }\n}\n"
  },
  {
    "path": "tests/unicode.sk",
    "content": "namespace Skew.Tests {\n  def testUnicodeText(text string, codePoints List<int>) {\n    test(\"codePoints \" + text, expectString => expectString(toString(codePoints), toString(text.codePoints)))\n    test(\"fromCodePoints \" + text, expectString => expectString(text, string.fromCodePoints(codePoints)))\n    test(\"codeUnits \" + text, expectString => expectString(text, string.fromCodeUnits(text.codeUnits)))\n\n    # Call fromCodePoint() for each code point\n    for codePoint in codePoints {\n      test(\"fromCodePoint \" + codePoint.toString, expectString =>\n        expectString(toString([codePoint]), toString(string.fromCodePoint(codePoint).codePoints)))\n    }\n\n    # Check forward iteration\n    var nextCodePoints = codePoints.clone\n    nextCodePoints.append(-1)\n    testExpect(\"StringIterator.nextCodePoint \" + text, () List<int> => {\n      var iterator = Unicode.StringIterator.INSTANCE.reset(text, 0)\n      var observedCodePoints List<int> = []\n      for codePoint in 0..codePoints.count + 1 {\n        observedCodePoints.append(iterator.nextCodePoint)\n      }\n      return observedCodePoints\n    }, nextCodePoints)\n\n    # Check backward iteration\n    var previousCodePoints = codePoints.clone\n    previousCodePoints.reverse\n    previousCodePoints.append(-1)\n    testExpect(\"StringIterator.previousCodePoint \" + text, () List<int> => {\n      var iterator = Unicode.StringIterator.INSTANCE.reset(text, text.count)\n      var observedCodePoints List<int> = []\n      for codePoint in 0..codePoints.count + 1 {\n        observedCodePoints.append(iterator.previousCodePoint)\n      }\n      return observedCodePoints\n    }, previousCodePoints)\n  }\n\n  def testUnicodeCount(text string, count int) {\n    test(\"count \" + text, expectString => expectString(count.toString, text.count.toString))\n  }\n\n  def testUnicode {\n    # Make sure encoding and decoding works\n    testUnicodeText(\"Цлїςσδε\", [1062, 1083, 1111, 962, 963, 948, 949])\n    testUnicodeText(\"ﾌﾑｱﾑｶﾓｹﾓ\", [65420, 65425, 65393, 65425, 65398, 65427, 65401, 65427])\n    testUnicodeText(\"フムヤムカモケモ\", [12501, 12512, 12516, 12512, 12459, 12514, 12465, 12514])\n    testUnicodeText(\"㊀㊁㊂㊃㊄\", [12928, 12929, 12930, 12931, 12932])\n    testUnicodeText(\"☳☶☲\", [9779, 9782, 9778])\n    testUnicodeText(\"𡇙𝌆\", [135641, 119558])\n    testUnicodeText(\"🙉🙈🙊\", [128585, 128584, 128586])\n\n    # Make sure target-specific constant folding of string.count works correctly\n    testUnicodeCount(\"Цлїςσδε\", \"Цлїςσδε\".count)\n    testUnicodeCount(\"ﾌﾑｱﾑｶﾓｹﾓ\", \"ﾌﾑｱﾑｶﾓｹﾓ\".count)\n    testUnicodeCount(\"フムヤムカモケモ\", \"フムヤムカモケモ\".count)\n    testUnicodeCount(\"㊀㊁㊂㊃㊄\", \"㊀㊁㊂㊃㊄\".count)\n    testUnicodeCount(\"☳☶☲\", \"☳☶☲\".count)\n    testUnicodeCount(\"𡇙𝌆\", \"𡇙𝌆\".count)\n  }\n}\n"
  },
  {
    "path": "www/benchmark.html",
    "content": "<canvas width=\"800\" height=\"600\" style=\"background:#EEE;\"></canvas>\n<script>\n\n(function() {\n\n  function draw(context, times, count) {\n    var scale = 1 / (3 * 1000);\n\n    // Reset the canvas\n    var width = context.canvas.width;\n    var height = context.canvas.height;\n    var plotWidth = width - 100;\n    context.clearRect(0, 0, width, height);\n\n    // Skip the first few times so we can measure the time after the JIT has warmed up\n    var ignore = 2;\n\n    // Compute the average\n    var average = 0;\n    var included = 0;\n    for (var i = Math.min(ignore, times.length - 1); i < times.length; i++) {\n      average += times[i];\n      included++;\n    }\n    average /= included;\n\n    // Draw the times\n    for (var i = 0; i < times.length; i++) {\n      var x0 = (i + 0.2) * plotWidth / count;\n      var x1 = (i + 0.8) * plotWidth / count;\n      var y0 = height * (1 - times[i] * scale);\n      var y1 = height;\n      context.fillStyle = i < ignore ? '#777' : '#000';\n      context.fillRect(x0, y0, x1 - x0, y1 - y0);\n    }\n    context.fillStyle = '#000';\n\n    // Draw second lines\n    context.globalAlpha = 0.25;\n    for (var i = 1000; i <= 0.999 / scale; i += 1000) {\n      var y = height * (1 - i * scale);\n      context.beginPath();\n      context.moveTo(0, y);\n      context.lineTo(width, y);\n      context.stroke();\n    }\n    context.globalAlpha = 1;\n\n    // Draw average line\n    var y = height * (1 - average * scale);\n    context.beginPath();\n    context.moveTo(0, y);\n    context.lineTo(plotWidth, y);\n    context.stroke();\n\n    // Draw average text\n    context.textBaseline = 'middle';\n    context.fillText('Average: ' + Math.round(average) + 'ms', plotWidth, y);\n  }\n\n  function fetch(url, callback) {\n    var xhr = new XMLHttpRequest;\n    xhr.open('GET', url);\n    xhr.onload = function() {\n      callback(xhr.responseText);\n    };\n    xhr.send();\n  }\n\n  function webWorkerMain() {\n    onmessage = function(e) {\n      var data = e.data;\n\n      // Load the API\n      Skew = {};\n      Skew.handleWorkerMessages = false;\n      eval(data.api);\n\n      function compile() {\n        var options = {};\n        options.target = 'js';\n        options.outputFile = 'compiled.js';\n        options.inputs = [{name: '<stdin>', contents: data.all}];\n        options.foldAllConstants = true;\n        options.inlineAllFunctions = true;\n        options.globalizeAllFunctions = true;\n        options.jsMangle = true;\n        options.jsMinify = true;\n        options.defines = {RELEASE: 'true'};\n        var result = compiler.compile(options);\n\n        // Compilation must succeed\n        if (result.log.diagnostics.length > 0 || result.outputs.length !== 1) {\n          throw new Error('Expected compilation to succeed cleanly\\n\\n' + result.log.text);\n        }\n\n        // Compilation must be identical\n        if (result.outputs[0].contents !== data.api) {\n          throw new Error('Expected compiled output to be the same');\n        }\n\n        postMessage('done');\n      }\n\n      var compiler = Skew.create();\n      for (var i = 0; i < data.count; i++) {\n        compile();\n      }\n    };\n  }\n\n  fetch('../out/benchmark.sk', function(all) {\n    fetch('../out/benchmark.js', function(api) {\n      var canvas = document.querySelector('canvas');\n      var context = canvas.getContext('2d');\n      var now = window.performance && performance.now\n        ? function() { return performance.now(); }\n        : function() { return +new Date; };\n      var times = [];\n      var count = 64;\n\n      // Use a web worker to avoid letting the browser cheat by doing GC while updating the progress plot\n      var worker = new Worker(URL.createObjectURL(new Blob([webWorkerMain + ';webWorkerMain();'])));\n      worker.onmessage = function() {\n        var after = now();\n        times.push(after - before);\n        draw(context, times, count);\n        before = after;\n      };\n\n      var before = now();\n      worker.postMessage({\n        all: all,\n        api: api,\n        count: count\n      });\n    });\n  });\n\n})();\n\n</script>\n"
  },
  {
    "path": "www/index.html",
    "content": "<title>Skew Compiler</title>\n<link rel=\"stylesheet\" href=\"style.css\">\n<div>\n  <h2>Input</h2>\n  <textarea id=\"input\" rows=\"10\" spellcheck=\"false\" autofocus></textarea>\n</div>\n<div>\n  <h2>Log</h2>\n  <textarea id=\"outputLog\" rows=\"10\" spellcheck=\"false\" readonly></textarea>\n  <p>\n    <span id=\"compileTime\">Loading...</span>\n    Target: <span id=\"targetArea\"></span>\n    <span id=\"optionArea\"></span>\n  </p>\n  <h2>Code</h2>\n  <textarea id=\"outputCode\" rows=\"20\" spellcheck=\"false\" readonly></textarea>\n</div>\n<script src=\"../out/skew-api.js\" id=\"skew-api\"></script>\n<script src=\"index.js\"></script>\n"
  },
  {
    "path": "www/index.js",
    "content": "(function() {\n\n  var compileTime = document.getElementById('compileTime');\n  var input = document.getElementById('input');\n  var optionArea = document.getElementById('optionArea');\n  var outputCode = document.getElementById('outputCode');\n  var outputLog = document.getElementById('outputLog');\n  var targetArea = document.getElementById('targetArea');\n\n  var targets = [\n    {name: 'JavaScript', option: 'js', extension: 'js'},\n    {name: 'TypeScript', option: 'ts', extension: 'ts'},\n    {name: 'C#', option: 'c#', extension: 'cs'},\n    {name: 'C++', option: 'c++', extension: 'cpp'},\n    {name: 'Lisp Tree', option: 'lisp-tree', extension: 'lisp'},\n  ];\n  var targetNames = targets.map(function(target) {\n    return target.name;\n  });\n\n  var TARGET_INDEX = 'TARGET_INDEX';\n  var CONSTANT_FOLDING = 'CONSTANT_FOLDING';\n  var FUNCTION_INLINING = 'FUNCTION_INLINING';\n  var GLOBALIZE = 'GLOBALIZE';\n  var MANGLE = 'MANGLE';\n  var MINIFY = 'MINIFY';\n  var MULTIPLE_OUTPUTS = 'MULTIPLE_OUTPUTS';\n  var SHOW_SYNTAX_TREE = 'SHOW_SYNTAX_TREE';\n  var SOURCE_MAP = 'SOURCE_MAP';\n  var STOP_AFTER_RESOLVE = 'STOP_AFTER_RESOLVE';\n  var USE_WEB_WORKER = 'USE_WEB_WORKER';\n  var SET_RELEASE = 'SET_RELEASE';\n\n  var compiler = null;\n  var start = null;\n  var worker = null;\n  var isBusy = false;\n  var pendingMessage = null;\n\n  function configGetBool(name) {\n    return configGet(name) === 'true';\n  }\n\n  function configGet(name) {\n    return localStorage.getItem(name);\n  }\n\n  function configSet(name, index) {\n    localStorage.setItem(name, index);\n  }\n\n  function now() {\n    return window.performance && performance.now ? performance.now() : +new Date;\n  }\n\n  function handleResult(result) {\n    outputLog.value = result.log.text;\n    outputCode.value = result.outputs.length === 1 ? result.outputs[0].contents :\n      result.outputs.map(function(source) { return '[' + source.name + ']\\n' + source.contents; }).join('\\n');\n    compileTime.textContent = +(now() - start).toFixed(1) + 'ms';\n  }\n\n  function update() {\n    var index = targetNames.indexOf(configGet(TARGET_INDEX));\n    var target = targets[index === -1 ? 0 : index];\n    var options = {};\n    options.outputFile = 'compiled.' + target.extension;\n    options.inputs = [{name: '<stdin>', contents: input.value}];\n    if (configGetBool(CONSTANT_FOLDING)) options.foldAllConstants = true;\n    if (configGetBool(FUNCTION_INLINING)) options.inlineAllFunctions = true;\n    if (configGetBool(GLOBALIZE)) options.globalizeAllFunctions = true;\n    if (configGetBool(MANGLE)) options.jsMangle = true;\n    if (configGetBool(MINIFY)) options.jsMinify = true;\n    if (configGetBool(SOURCE_MAP)) options.jsSourceMap = true;\n    if (configGetBool(STOP_AFTER_RESOLVE)) options.stopAfterResolve = true;\n    if (configGetBool(MULTIPLE_OUTPUTS)) options.outputDirectory = 'output';\n    if (configGetBool(SET_RELEASE)) options.defines = {RELEASE: 'true'};\n    if (configGetBool(USE_WEB_WORKER)) {\n      if (!worker) {\n        worker = new Worker(document.getElementById('skew-api').src);\n        worker.onmessage = function(e) {\n          if (pendingMessage) {\n            start = now();\n            worker.postMessage(pendingMessage);\n            pendingMessage = null;\n          } else {\n            isBusy = false;\n            handleResult(e.data);\n          }\n        };\n      }\n      options.type = 'compile';\n      if (isBusy) {\n        pendingMessage = options;\n      } else {\n        start = now();\n        worker.postMessage(options);\n        isBusy = true;\n      }\n    } else {\n      start = now();\n      if (compiler === null) {\n        compiler = Skew.create();\n      }\n      handleResult(compiler.compile(options));\n    }\n  }\n\n  function createSelect(values, name) {\n    var element = document.createElement('select');\n    for (var i = 0; i < values.length; i++) {\n      var option = document.createElement('option');\n      option.textContent = values[i];\n      element.appendChild(option);\n    }\n    element.selectedIndex = values.indexOf(configGet(name));\n    element.onchange = function() {\n      configSet(name, values[element.selectedIndex]);\n      update();\n    };\n    return element;\n  }\n\n  function createCheckbox(label, name) {\n    var element = document.createElement('label');\n    var checkbox = document.createElement('input');\n    checkbox.type = 'checkbox';\n    checkbox.checked = configGetBool(name);\n    checkbox.onchange = function() {\n      configSet(name, checkbox.checked);\n      update();\n    };\n    element.appendChild(checkbox);\n    element.appendChild(document.createTextNode(' ' + label));\n    return element;\n  }\n\n  function main() {\n    targetArea.appendChild(createSelect(targetNames, TARGET_INDEX));\n    optionArea.appendChild(createCheckbox('Constant folding', CONSTANT_FOLDING));\n    optionArea.appendChild(createCheckbox('Inlining', FUNCTION_INLINING));\n    optionArea.appendChild(createCheckbox('Mangle', MANGLE));\n    optionArea.appendChild(createCheckbox('Minify', MINIFY));\n    optionArea.appendChild(createCheckbox('Globalize', GLOBALIZE));\n    optionArea.appendChild(createCheckbox('Syntax tree', SHOW_SYNTAX_TREE));\n    optionArea.appendChild(createCheckbox('Source map', SOURCE_MAP));\n    optionArea.appendChild(createCheckbox('IDE mode (no output)', STOP_AFTER_RESOLVE));\n    optionArea.appendChild(createCheckbox('Multiple outputs', MULTIPLE_OUTPUTS));\n    optionArea.appendChild(createCheckbox('Use a web worker', USE_WEB_WORKER));\n    optionArea.appendChild(createCheckbox('Set RELEASE', SET_RELEASE));\n    input.oninput = update;\n    update();\n  }\n\n  main();\n\n})();\n"
  },
  {
    "path": "www/style.css",
    "content": "body {\n  font: 12px/15px 'Lucida Grande', sans-serif;\n  margin: 20px;\n}\n\ntextarea {\n  font: 12px Monaco, monospace;\n  width: 600px;\n}\n\ndiv {\n  display: inline-block;\n  vertical-align: top;\n  margin: 20px;\n}\n\nselect {\n  width: 100px;\n}\n\n#compileTime {\n  float: right;\n}\n\nlabel {\n  cursor: default;\n  -webkit-user-select: none;\n  -moz-user-select: -moz-none;\n  margin-right: 10px;\n}\n\n#optionArea {\n  display: block;\n  margin-top: 10px;\n  width: 600px;\n}\n\n#input {\n  height: 600px;\n}\n"
  }
]